Download src/agents/command/prepare.ts from SaylorTwift/openclaw: direct link, hf CLI and curl.
- Browser
- Download file 18.2 kB
-
https://huggingface.co/SaylorTwift/openclaw/resolve/main/src/agents/command/prepare.ts
- Command line
-
hf download hf://SaylorTwift/openclaw/src/agents/command/prepare.ts
-
curl -L -o prepare.ts https://huggingface.co/SaylorTwift/openclaw/resolve/main/src/agents/command/prepare.ts
18.2 kB
| import { parseStrictNonNegativeInteger } from "@openclaw/normalization-core/number-coercion"; | |
| import { normalizeOptionalString } from "@openclaw/normalization-core/string-coerce"; | |
| import { resolveSessionStableReplyMode } from "../../auto-reply/reply/session-stable-reply-mode.js"; | |
| import { isSyntheticSourceReplyTurn } from "../../auto-reply/reply/source-reply-delivery-mode.js"; | |
| import { | |
| formatThinkingLevels, | |
| normalizeThinkLevel, | |
| normalizeVerboseLevel, | |
| } from "../../auto-reply/thinking.js"; | |
| import { formatCliCommand } from "../../cli/command-format.js"; | |
| import type { InternalSessionEntry } from "../../config/sessions/types.js"; | |
| import type { OpenClawConfig } from "../../config/types.openclaw.js"; | |
| import { resolveAgentExplicitRecipientSession } from "../../infra/outbound/agent-delivery.js"; | |
| import { buildOutboundSessionContext } from "../../infra/outbound/session-context.js"; | |
| import { resolvePluginMetadataSnapshot } from "../../plugins/plugin-metadata-snapshot.js"; | |
| import { | |
| classifySessionKeyShape, | |
| isUnscopedSessionKeySentinel, | |
| normalizeAgentId, | |
| resolveAgentIdFromSessionKey, | |
| } from "../../routing/session-key.js"; | |
| import type { RuntimeEnv } from "../../runtime.js"; | |
| import { | |
| AGENT_HARNESS_MODEL_RUN_FORBIDDEN_MESSAGE, | |
| resolveAgentHarnessSessionContextError, | |
| } from "../../sessions/agent-harness-session-key.js"; | |
| import { | |
| assertAgentDatabaseAdmitted, | |
| evaluateAgentDatabaseAdmissions, | |
| hasAgentDatabaseAdmissions, | |
| recordAgentDatabaseAdmissions, | |
| } from "../../state/agent-database-admission.js"; | |
| import { resolveUserPath } from "../../utils.js"; | |
| import { isDeliverableMessageChannel, resolveMessageChannel } from "../../utils/message-channel.js"; | |
| import { resolveAgentRuntimeConfig } from "../agent-runtime-config.js"; | |
| import { resolveAgentRunCwd } from "../agent-scope-config.js"; | |
| import { | |
| listAgentIds, | |
| resolveAgentDir, | |
| resolveSessionAgentId, | |
| resolveAgentWorkspaceDir, | |
| } from "../agent-scope.js"; | |
| import { DEFAULT_MODEL, DEFAULT_PROVIDER } from "../defaults.js"; | |
| import { | |
| resolveAcpPromptBody, | |
| prependInternalEventContext, | |
| resolveInternalEventTranscriptBody, | |
| } from "../internal-events.js"; | |
| import { AGENT_LANE_SUBAGENT } from "../lanes.js"; | |
| import type { ModelManifestNormalizationContext } from "../model-ref-shared.js"; | |
| import { buildConfiguredModelCatalog, resolveConfiguredModelRef } from "../model-selection.js"; | |
| import type { PreparedModelRuntimePluginGeneration } from "../prepared-model-runtime.types.js"; | |
| import { normalizeSpawnedRunMetadata } from "../spawned-context.js"; | |
| import { resolveEffectiveAgentRuntime } from "../thinking-runtime.js"; | |
| import { resolveAgentTimeoutMs } from "../timeout.js"; | |
| import { ensureAgentWorkspace } from "../workspace.js"; | |
| import { acquireWorktreeRunLease, resolveWorktreeIdForPath } from "../worktrees/run-lease.js"; | |
| import { resolveExplicitAgentCommandSessionKey } from "./explicit-session-key.js"; | |
| import { loadAcpManagerRuntime } from "./runtime-loaders.js"; | |
| import { resolveSession } from "./session.js"; | |
| import type { AgentCommandOpts } from "./types.js"; | |
| const OVERRIDE_VALUE_MAX_LENGTH = 256; | |
| function containsControlCharacters(value: string): boolean { | |
| for (const char of value) { | |
| const code = char.codePointAt(0); | |
| if (code === undefined) { | |
| continue; | |
| } | |
| if (code <= 0x1f || (code >= 0x7f && code <= 0x9f)) { | |
| return true; | |
| } | |
| } | |
| return false; | |
| } | |
| export function normalizeExplicitOverrideInput(raw: string, kind: "provider" | "model"): string { | |
| const trimmed = raw.trim(); | |
| const label = kind === "provider" ? "Provider" : "Model"; | |
| if (!trimmed) { | |
| throw new Error(`${label} override must be non-empty.`); | |
| } | |
| if (trimmed.length > OVERRIDE_VALUE_MAX_LENGTH) { | |
| throw new Error(`${label} override exceeds ${String(OVERRIDE_VALUE_MAX_LENGTH)} characters.`); | |
| } | |
| if (containsControlCharacters(trimmed)) { | |
| throw new Error(`${label} override contains invalid control characters.`); | |
| } | |
| return trimmed; | |
| } | |
| export type PreparedAgentCommandRuntimeContext = Readonly<{ | |
| config: OpenClawConfig; | |
| pluginGeneration: PreparedModelRuntimePluginGeneration; | |
| }>; | |
| export async function prepareAgentCommandExecution( | |
| opts: AgentCommandOpts, | |
| runtime: RuntimeEnv, | |
| runtimeContext?: PreparedAgentCommandRuntimeContext, | |
| ) { | |
| const isRawModelRun = opts.modelRun === true || opts.promptMode === "none"; | |
| const message = opts.message ?? ""; | |
| if (!message.trim()) { | |
| throw new Error("Message (--message) is required"); | |
| } | |
| const rawExplicitSessionKey = opts.sessionKey?.trim(); | |
| const requestedSessionId = opts.sessionId?.trim() || undefined; | |
| const rawTo = opts.to?.trim(); | |
| const toSessionKey = | |
| !rawExplicitSessionKey && !requestedSessionId && classifySessionKeyShape(rawTo) === "agent" | |
| ? rawTo | |
| : undefined; | |
| const recipientChannel = resolveMessageChannel(opts.channel); | |
| const shouldResolveExplicitRecipientSession = Boolean( | |
| !rawExplicitSessionKey && | |
| !requestedSessionId && | |
| !toSessionKey && | |
| opts.agentId?.trim() && | |
| recipientChannel && | |
| isDeliverableMessageChannel(recipientChannel) && | |
| rawTo, | |
| ); | |
| if (!opts.to && !requestedSessionId && !rawExplicitSessionKey && !opts.agentId) { | |
| throw new Error( | |
| "Pass --to <E.164>, --session-key, --session-id, or --agent to choose a session", | |
| ); | |
| } | |
| const cfg = await resolveAgentRuntimeConfig(runtime, { | |
| runtimeTargetsChannelSecrets: opts.deliver === true, | |
| runtimeChannelSecretScope: | |
| opts.deliver !== true && shouldResolveExplicitRecipientSession && recipientChannel | |
| ? { channel: recipientChannel, accountId: opts.accountId } | |
| : undefined, | |
| }); | |
| const normalizedSpawned = normalizeSpawnedRunMetadata({ | |
| spawnedBy: opts.spawnedBy, | |
| groupId: opts.groupId, | |
| groupChannel: opts.groupChannel, | |
| groupSpace: opts.groupSpace, | |
| workspaceDir: opts.workspaceDir, | |
| }); | |
| const agentIdOverrideRaw = opts.agentId?.trim(); | |
| const agentIdOverride = agentIdOverrideRaw ? normalizeAgentId(agentIdOverrideRaw) : undefined; | |
| if (agentIdOverride) { | |
| const knownAgents = listAgentIds(cfg); | |
| if (!knownAgents.includes(agentIdOverride)) { | |
| throw new Error( | |
| `Unknown agent id "${agentIdOverrideRaw}". Use "${formatCliCommand("openclaw agents list")}" to see configured agents.`, | |
| ); | |
| } | |
| } | |
| const shouldScopeDefaultAgentKey = Boolean( | |
| rawExplicitSessionKey && | |
| !agentIdOverride && | |
| classifySessionKeyShape(rawExplicitSessionKey) === "legacy_or_alias" && | |
| !isUnscopedSessionKeySentinel(rawExplicitSessionKey), | |
| ); | |
| const explicitSessionKey = | |
| toSessionKey ?? | |
| resolveExplicitAgentCommandSessionKey({ | |
| rawExplicitSessionKey, | |
| agentIdOverride, | |
| shouldScopeDefaultAgentKey, | |
| cfg, | |
| }); | |
| if (explicitSessionKey && classifySessionKeyShape(explicitSessionKey) === "malformed_agent") { | |
| throw new Error( | |
| `Invalid --session-key "${explicitSessionKey}". Agent-prefixed session keys must use agent:<agent-id>:<session-key>.`, | |
| ); | |
| } | |
| if ( | |
| agentIdOverride && | |
| explicitSessionKey && | |
| classifySessionKeyShape(explicitSessionKey) === "agent" | |
| ) { | |
| const sessionAgentId = resolveAgentIdFromSessionKey(explicitSessionKey); | |
| if (sessionAgentId !== agentIdOverride) { | |
| throw new Error( | |
| `Agent id "${agentIdOverrideRaw}" does not match session key agent "${sessionAgentId}".`, | |
| ); | |
| } | |
| } | |
| if (agentIdOverride || explicitSessionKey) { | |
| if (!hasAgentDatabaseAdmissions()) { | |
| recordAgentDatabaseAdmissions(await evaluateAgentDatabaseAdmissions(cfg)); | |
| } | |
| assertAgentDatabaseAdmitted( | |
| agentIdOverride ?? resolveSessionAgentId({ sessionKey: explicitSessionKey, config: cfg }), | |
| ); | |
| } | |
| const agentCfg = cfg.agents?.defaults; | |
| const verboseOverride = normalizeVerboseLevel(opts.verbose); | |
| if (opts.verbose && !verboseOverride) { | |
| throw new Error('Invalid verbose level. Use "on", "full", or "off".'); | |
| } | |
| const laneRaw = normalizeOptionalString(opts.lane) ?? ""; | |
| const subagentLane: string = AGENT_LANE_SUBAGENT; | |
| const isSubagentLane = laneRaw === subagentLane; | |
| const hasExplicitTimeoutOption = opts.timeout !== undefined; | |
| const timeoutSecondsRaw = hasExplicitTimeoutOption | |
| ? (parseStrictNonNegativeInteger(opts.timeout) ?? Number.NaN) | |
| : isSubagentLane | |
| ? 0 | |
| : undefined; | |
| if ( | |
| timeoutSecondsRaw !== undefined && | |
| (Number.isNaN(timeoutSecondsRaw) || timeoutSecondsRaw < 0) | |
| ) { | |
| throw new Error("--timeout must be a non-negative integer (seconds; 0 means no timeout)"); | |
| } | |
| const timeoutMs = resolveAgentTimeoutMs({ cfg, overrideSeconds: timeoutSecondsRaw }); | |
| const runTimeoutOverrideMs = hasExplicitTimeoutOption ? timeoutMs : undefined; | |
| const selectedCommandOpts = toSessionKey | |
| ? { ...opts, to: undefined, sessionKey: explicitSessionKey } | |
| : opts; | |
| const explicitRecipientSession = | |
| shouldResolveExplicitRecipientSession && agentIdOverride && recipientChannel && rawTo | |
| ? await resolveAgentExplicitRecipientSession({ | |
| cfg, | |
| agentId: agentIdOverride, | |
| channel: recipientChannel, | |
| to: rawTo, | |
| accountId: selectedCommandOpts.accountId, | |
| threadId: selectedCommandOpts.threadId, | |
| }) | |
| : undefined; | |
| if (explicitRecipientSession?.error) { | |
| throw explicitRecipientSession.error; | |
| } | |
| let commandOpts: AgentCommandOpts = explicitRecipientSession?.sessionKey | |
| ? { | |
| ...selectedCommandOpts, | |
| channel: explicitRecipientSession.channel, | |
| to: explicitRecipientSession.to, | |
| accountId: explicitRecipientSession.accountId, | |
| threadId: explicitRecipientSession.threadId, | |
| } | |
| : selectedCommandOpts; | |
| const sessionResolution = resolveSession({ | |
| cfg, | |
| to: commandOpts.to, | |
| sessionId: commandOpts.sessionId, | |
| sessionKey: explicitSessionKey ?? explicitRecipientSession?.sessionKey, | |
| agentId: agentIdOverride, | |
| }); | |
| const { | |
| sessionId, | |
| sessionKey, | |
| sessionEntry: sessionEntryRaw, | |
| storePath, | |
| isNewSession, | |
| previousSessionId, | |
| persistedThinking, | |
| persistedVerbose, | |
| } = sessionResolution; | |
| const harnessSessionError = sessionKey | |
| ? resolveAgentHarnessSessionContextError(sessionKey, sessionEntryRaw) | |
| : undefined; | |
| if (harnessSessionError) { | |
| throw new Error(harnessSessionError); | |
| } | |
| const isOneShotModelRun = opts.modelRun === true || opts.promptMode === "none"; | |
| if (isOneShotModelRun && sessionKey && sessionEntryRaw?.modelSelectionLocked === true) { | |
| throw new Error(AGENT_HARNESS_MODEL_RUN_FORBIDDEN_MESSAGE); | |
| } | |
| const sessionStore: Record<string, InternalSessionEntry> = | |
| sessionKey && sessionEntryRaw ? { [sessionKey]: sessionEntryRaw } : {}; | |
| const sessionAgentId = | |
| agentIdOverride ?? | |
| resolveSessionAgentId({ sessionKey: sessionKey ?? explicitSessionKey, config: cfg }); | |
| assertAgentDatabaseAdmitted(sessionAgentId); | |
| const outboundSession = buildOutboundSessionContext({ | |
| cfg, | |
| agentId: sessionAgentId, | |
| sessionKey, | |
| }); | |
| const workspaceDirRaw = | |
| normalizedSpawned.workspaceDir ?? resolveAgentWorkspaceDir(cfg, sessionAgentId); | |
| const workspaceDir = resolveUserPath(workspaceDirRaw); | |
| const { getAcpSessionManager } = await loadAcpManagerRuntime(); | |
| const acpManager = getAcpSessionManager(); | |
| const acpResolution = sessionKey | |
| ? acpManager.resolveSession({ cfg, sessionKey, agentId: sessionAgentId }) | |
| : null; | |
| // Configured run cwd is a Gateway-local path; ACP-placed sessions ("ready" or | |
| // "stale") execute on their own node with a node-owned execCwd, so the config | |
| // fallback applies only to ordinary sessions and never bridges into a node. | |
| const isAcpPlacedSession = acpResolution !== null && acpResolution.kind !== "none"; | |
| const cwd = | |
| normalizeOptionalString(opts.cwd) ?? | |
| normalizeOptionalString(sessionEntryRaw?.spawnedCwd) ?? | |
| (isAcpPlacedSession ? undefined : resolveAgentRunCwd(cfg, sessionAgentId)); | |
| const agentDir = resolveAgentDir(cfg, sessionAgentId); | |
| const pluginsEnabled = cfg.plugins?.enabled !== false; | |
| const preparedMetadataSnapshot = runtimeContext?.pluginGeneration.pluginMetadataSnapshot; | |
| const manifestMetadataSnapshot = pluginsEnabled | |
| ? (preparedMetadataSnapshot ?? | |
| resolvePluginMetadataSnapshot({ config: cfg, env: process.env, workspaceDir })) | |
| : undefined; | |
| const modelManifestContext = { | |
| manifestPlugins: manifestMetadataSnapshot ?? [], | |
| } satisfies ModelManifestNormalizationContext; | |
| const configuredModel = resolveConfiguredModelRef({ | |
| cfg, | |
| agentId: sessionAgentId, | |
| defaultProvider: DEFAULT_PROVIDER, | |
| defaultModel: DEFAULT_MODEL, | |
| allowPluginNormalization: pluginsEnabled, | |
| ...modelManifestContext, | |
| }); | |
| const configuredThinkingCatalog = buildConfiguredModelCatalog({ | |
| cfg, | |
| workspaceDir, | |
| ...modelManifestContext, | |
| }); | |
| const configuredThinkingRuntime = resolveEffectiveAgentRuntime({ | |
| cfg, | |
| provider: configuredModel.provider, | |
| modelId: configuredModel.model, | |
| agentId: sessionAgentId, | |
| sessionKey, | |
| sessionEntry: sessionEntryRaw, | |
| }); | |
| if ( | |
| sessionEntryRaw && | |
| commandOpts.cliSessionBindingFacts === undefined && | |
| isSyntheticSourceReplyTurn({ | |
| inputProvenance: commandOpts.inputProvenance, | |
| isHeartbeat: commandOpts.bootstrapContextRunKind === "heartbeat", | |
| }) | |
| ) { | |
| commandOpts = { | |
| ...commandOpts, | |
| cliSessionBindingFacts: { | |
| sourceReplyDeliveryMode: resolveSessionStableReplyMode({ | |
| cfg, | |
| ctx: { CommandAuthorized: false }, | |
| sessionEntry: sessionEntryRaw, | |
| sessionAgentId, | |
| sessionKey, | |
| }), | |
| }, | |
| }; | |
| } | |
| const thinkingLevelsHint = formatThinkingLevels( | |
| configuredModel.provider, | |
| configuredModel.model, | |
| ", ", | |
| configuredThinkingCatalog.length > 0 ? configuredThinkingCatalog : undefined, | |
| configuredThinkingRuntime, | |
| ); | |
| const thinkOverride = normalizeThinkLevel(opts.thinking); | |
| const thinkOnce = normalizeThinkLevel(opts.thinkingOnce); | |
| if (opts.thinking && !thinkOverride) { | |
| throw new Error(`Invalid thinking level. Use one of: ${thinkingLevelsHint}.`); | |
| } | |
| if (opts.thinkingOnce && !thinkOnce) { | |
| throw new Error(`Invalid one-shot thinking level. Use one of: ${thinkingLevelsHint}.`); | |
| } | |
| const resolvedCwd = cwd ? resolveUserPath(cwd) : undefined; | |
| const worktreeId = await resolveWorktreeIdForPath({ | |
| sessionEntry: sessionEntryRaw, | |
| candidatePaths: [resolvedCwd ?? workspaceDir, workspaceDir], | |
| }); | |
| const runLease = worktreeId ? await acquireWorktreeRunLease(worktreeId) : undefined; | |
| try { | |
| const { resolveAcpAgentWorkspaceProvisioningForTurn } = | |
| await import("../acp-workspace-provisioning.js"); | |
| const workspaceProvisioning = await resolveAcpAgentWorkspaceProvisioningForTurn({ | |
| cfg, | |
| agentId: sessionAgentId, | |
| workspaceDir, | |
| cwd: resolvedCwd, | |
| sessionKey: sessionKey ?? undefined, | |
| sessionEntry: sessionEntryRaw ?? undefined, | |
| }); | |
| await ensureAgentWorkspace({ | |
| dir: workspaceDirRaw, | |
| ensureBootstrapFiles: !agentCfg?.skipBootstrap, | |
| skipOptionalBootstrapFiles: agentCfg?.skipOptionalBootstrapFiles, | |
| provisioning: workspaceProvisioning, | |
| }); | |
| const runId = opts.runId?.trim() || sessionId; | |
| let promptMessage = message; | |
| if (!isRawModelRun && (message.includes("$") || message.trimStart().startsWith("/"))) { | |
| const { | |
| expandExplicitSkillReferences, | |
| hasSkillReferenceCandidate, | |
| listSkillCommandsForWorkspace, | |
| resolveEffectiveAgentSkillFilter, | |
| } = await import("../../skills/discovery/chat-commands.runtime.js"); | |
| const hasExplicitSkillCandidate = | |
| message.trimStart().startsWith("/") || hasSkillReferenceCandidate(message); | |
| if (hasExplicitSkillCandidate) { | |
| const skillFilter = resolveEffectiveAgentSkillFilter(cfg, sessionAgentId); | |
| const commandParams = { | |
| workspaceDir, | |
| cfg, | |
| agentId: sessionAgentId, | |
| sessionEntry: sessionEntryRaw, | |
| sessionKey, | |
| ...(preparedMetadataSnapshot ? { pluginMetadataSnapshot: preparedMetadataSnapshot } : {}), | |
| ...(skillFilter ? { skillFilter } : {}), | |
| }; | |
| const skillCommands = listSkillCommandsForWorkspace(commandParams); | |
| const allSkillCommands = skillFilter | |
| ? listSkillCommandsForWorkspace({ ...commandParams, includeAllowlistHidden: true }) | |
| : skillCommands; | |
| const expansion = expandExplicitSkillReferences({ | |
| text: message, | |
| skillCommands, | |
| allSkillCommands, | |
| }); | |
| if (expansion.error) { | |
| throw new Error(expansion.error); | |
| } | |
| promptMessage = expansion.body; | |
| } | |
| } | |
| const body = | |
| !isRawModelRun && acpResolution?.kind === "ready" | |
| ? resolveAcpPromptBody(promptMessage, opts.internalEvents, opts.inputProvenance) | |
| : prependInternalEventContext(promptMessage, opts.internalEvents, opts.inputProvenance); | |
| const transcriptBody = | |
| opts.transcriptMessage ?? | |
| resolveInternalEventTranscriptBody(message, opts.internalEvents, opts.inputProvenance); | |
| const prepared = { | |
| opts: commandOpts, | |
| body, | |
| transcriptBody, | |
| cfg, | |
| configuredThinkingCatalog, | |
| normalizedSpawned, | |
| agentCfg, | |
| thinkOverride, | |
| thinkOnce, | |
| verboseOverride, | |
| timeoutMs, | |
| runTimeoutOverrideMs, | |
| sessionId, | |
| sessionKey, | |
| sessionEntry: sessionEntryRaw, | |
| sessionStore, | |
| storePath, | |
| isNewSession, | |
| previousSessionId, | |
| persistedThinking, | |
| persistedVerbose, | |
| sessionAgentId, | |
| outboundSession, | |
| workspaceDir, | |
| cwd: resolvedCwd, | |
| agentDir, | |
| pluginsEnabled, | |
| manifestMetadataSnapshot, | |
| ...(runtimeContext ? { commandRuntimeContext: runtimeContext } : {}), | |
| modelManifestContext, | |
| runId, | |
| isSubagentLane, | |
| acpManager, | |
| acpResolution, | |
| runLease, | |
| }; | |
| return prepared; | |
| } catch (error) { | |
| await runLease?.release(); | |
| throw error; | |
| } | |
| } | |
| export type PreparedAgentCommandExecution = Awaited< | |
| ReturnType<typeof prepareAgentCommandExecution> | |
| >; | |