openclaw
Version:
Multi-channel AI gateway with extensible messaging integrations
1,665 lines • 71.8 kB
JavaScript
import { c as normalizeOptionalString } from "./string-coerce-mnp54Vah.js";
import { y as parseStrictNonNegativeInteger } from "./number-coercion-CJQ8TR--.js";
import "./parse-finite-number-Z7n6tXLk.js";
import { t as sanitizeForLog } from "./ansi-BI9w76Cm.js";
import { i as formatErrorMessage } from "./errors-BXgSefBE.js";
import { t as formatCliCommand } from "./command-format-CKGmlpAQ.js";
import { t as createLazyImportLoader } from "./lazy-promise-BONnzNfb.js";
import { p as resolveUserPath } from "./utils-CCC-BEJH.js";
import { c as isSecretRef } from "./types.secrets-_0JOMGE5.js";
import { n as defaultRuntime } from "./runtime-B4lgFmsS.js";
import { t as createSubsystemLogger } from "./subsystem-BzXSmsuh.js";
import { s as normalizePluginsConfig } from "./config-state-CikNNz7T.js";
import { a as markAutoFallbackPrimaryProbe, h as resolveEffectiveModelFallbacks, i as hasLegacyAutoFallbackWithoutOrigin, m as resolveAutoFallbackPrimaryProbe, n as entryMatchesAutoFallbackPrimaryProbe, t as clearAutoFallbackPrimaryProbeSelection, v as resolveSessionAgentId, w as hasSessionAutoModelFallbackProvenance } from "./agent-scope-MrLta7Pq.js";
import { a as isSubagentSessionKey } from "./session-key-utils-Bx3apsJ3.js";
import { c as isUnscopedSessionKeySentinel, f as resolveAgentIdFromSessionKey, g as scopeLegacySessionKeyToAgent, s as classifySessionKeyShape, u as normalizeAgentId } from "./session-key-B_NoIfpX.js";
import { t as resolveEffectiveAgentSkillFilter } from "./agent-filter-Ckm_ksHY.js";
import { a as resolveAgentDir, c as resolveDefaultAgentId, n as listAgentIds, o as resolveAgentWorkspaceDir, r as resolveAgentConfig } from "./agent-scope-config-CgCYpZfK.js";
import { d as readConfigFileSnapshotForWrite, i as getRuntimeConfig } from "./io-Gi7-pyU-.js";
import { r as resolveProviderIdForAuth } from "./provider-auth-aliases-BNZrcvHv.js";
import { i as listOpenAIAuthProfileProvidersForAgentRuntime } from "./openai-routing-DXJmS9CT.js";
import { n as DEFAULT_MODEL, r as DEFAULT_PROVIDER } from "./defaults-mDjiWzE5.js";
import { g as normalizeVerboseLevel, n as isThinkingLevelSupported, o as resolveSupportedThinkingLevel, p as normalizeThinkLevel, t as formatThinkingLevels } from "./thinking-OG7pb4lf.js";
import { v as setRuntimeConfigSnapshot } from "./runtime-snapshot-D93_HOsR.js";
import { n as ensureAuthProfileStore } from "./store-C8spD0DG.js";
import { s as loadManifestMetadataSnapshot } from "./manifest-contract-eligibility-DEeoLRlM.js";
import { i as emitAgentEvent, t as clearAgentRunContext, u as registerAgentRunContext } from "./agent-events-C1B8VhOg.js";
import { o as normalizeDeliveryContext } from "./delivery-context.shared-CpAdEETO.js";
import "./message-channel-constants-CgI32lqD.js";
import { o as resolveMessageChannel, t as isDeliverableMessageChannel } from "./message-channel-normalize-BLLf0ubu.js";
import "./message-channel-BiOeMu0l.js";
import { n as withPluginRuntimeGatewayRequestScope, t as getPluginRuntimeGatewayRequestScope } from "./gateway-request-scope-BAEdAUQ6.js";
import { n as isStoredCredentialCompatibleWithAuthProvider } from "./order-CdBVYd7c.js";
import { g as resolveConfiguredModelRef, i as buildModelAliasIndex, r as buildConfiguredModelCatalog, y as resolveModelRefFromString } from "./model-selection-shared-b32cUYts.js";
import { r as normalizeConfiguredProviderCatalogModelId } from "./model-ref-shared-CqcindZs.js";
import { a as normalizeModelRef, i as modelKey, o as normalizeProviderId } from "./model-selection-normalize-roKDxQ9_.js";
import { t as resolveThinkingDefault } from "./model-thinking-default-dIc9T64G.js";
import { c as resolveDefaultModelForAgent } from "./model-selection-CA_65iXi.js";
import { t as loadManifestModelCatalog } from "./model-catalog-0-HKr2yW.js";
import { d as ensureAgentWorkspace } from "./workspace-B0bmoo98.js";
import { t as resolveAgentTimeoutMs } from "./timeout-Drw0_zOv.js";
import { t as sanitizePendingFinalDeliveryText } from "./pending-final-delivery-BsRuDnJV.js";
import { n as resolveSendPolicy } from "./send-policy-CfC5ATxp.js";
import { K as createTrajectoryRuntimeRecorder, t as resolveAvailableAgentHarnessPolicy } from "./selection-BP0T9R9I.js";
import { s as normalizeSpawnedRunMetadata } from "./subagent-spawn-plan-DY8rBX1m.js";
import { t as buildOutboundSessionContext } from "./session-context-Bz96-75Y.js";
import { r as resolveMessageChannelSelection } from "./channel-selection-MKj8pvsX.js";
import { f as LiveSessionModelSwitchError, o as runWithModelFallback } from "./model-fallback-BvQwEryh.js";
import { n as resolveSession } from "./session-CKACMDmr.js";
import { t as getAgentRuntimeCommandSecretTargetIds } from "./command-secret-targets-DY8QOUoE.js";
import { n as repairProviderWrappedModelOverride, t as applyModelOverrideToSessionEntry } from "./model-overrides-D5WaLvcp.js";
import { n as createModelVisibilityPolicy } from "./model-visibility-policy-B8VgY13t.js";
import { t as AGENT_LANE_SUBAGENT } from "./lanes-CI0_P-yC.js";
import { t as prepareInternalSessionEffectsTranscript } from "./internal-session-effects-D37ZLYJ5.js";
import { t as resolveChannelModelOverride } from "./model-overrides-B2QijQ9o.js";
import { t as ensureSelectedAgentHarnessPlugin } from "./runtime-plugin-CzEDIZOU.js";
import "./live-model-switch-t4Dv5htR.js";
import { t as classifyEmbeddedAgentRunResultForModelFallback } from "./result-fallback-classifier-vfh2jCL6.js";
import { r as resolveInlineAgentImageAttachments } from "./agent-turn-attachments-BVNZMNvw.js";
import { t as resolveFastModeState } from "./fast-mode-CmAyxTkZ.js";
import { t as clearSessionAuthProfileOverride } from "./session-override-Bjia8kVD.js";
import { t as NodeRegistry } from "./node-registry-DzMBNLUj.js";
import { r as resolveAgentOutboundTarget, t as resolveAgentDeliveryPlan } from "./agent-delivery-DgS5lONr.js";
import { n as applyVerboseOverride } from "./level-overrides-D6cD7r8A.js";
import { a as resolveInternalEventTranscriptBody, i as resolveAcpPromptBody, n as persistSessionEntry$1, r as prependInternalEventContext, t as resolveAgentRunContext } from "./run-context-BebY4598.js";
//#region src/gateway/local-request-context.ts
function cronUnavailable() {
throw new Error("Cron is unavailable in local embedded agent gateway context.");
}
const unavailableCron = {
start: async () => {
cronUnavailable();
},
stop: () => {},
status: async () => cronUnavailable(),
list: async () => cronUnavailable(),
listPage: async () => cronUnavailable(),
add: async () => cronUnavailable(),
update: async () => cronUnavailable(),
remove: async () => cronUnavailable(),
run: async () => cronUnavailable(),
enqueueRun: async () => cronUnavailable(),
getJob: () => void 0,
readJob: async () => void 0,
getDefaultAgentId: () => void 0,
wake: () => ({
ok: false,
reason: "unwakeable-session-key"
})
};
/** Creates the minimal gateway context used by embedded local agent execution. */
function createLocalGatewayRequestContext(params) {
const logGateway = createSubsystemLogger("gateway/local");
const sessionEvents = /* @__PURE__ */ new Set();
const chatRuns = /* @__PURE__ */ new Map();
const chatRunBuffers = /* @__PURE__ */ new Map();
const chatDeltaSentAt = /* @__PURE__ */ new Map();
const chatDeltaLastBroadcastLen = /* @__PURE__ */ new Map();
const chatDeltaLastBroadcastText = /* @__PURE__ */ new Map();
const agentDeltaSentAt = /* @__PURE__ */ new Map();
const bufferedAgentEvents = /* @__PURE__ */ new Map();
const clearChatRunState = (runId) => {
chatRunBuffers.delete(runId);
chatDeltaSentAt.delete(runId);
chatDeltaLastBroadcastLen.delete(runId);
chatDeltaLastBroadcastText.delete(runId);
for (const key of [
runId,
`${runId}:assistant`,
`${runId}:thinking`
]) {
agentDeltaSentAt.delete(key);
bufferedAgentEvents.delete(key);
}
};
return {
deps: params.deps,
cron: unavailableCron,
cronStorePath: "",
getRuntimeConfig: params.getRuntimeConfig,
loadGatewayModelCatalog: async () => loadManifestModelCatalog({ config: params.getRuntimeConfig() }),
getHealthCache: () => null,
refreshHealthSnapshot: async () => ({}),
logHealth: { error: (message) => logGateway.error(message) },
logGateway,
incrementPresenceVersion: () => 0,
getHealthVersion: () => 0,
broadcast: () => {},
broadcastToConnIds: () => {},
nodeSendToSession: () => {},
nodeSendToAllSubscribed: () => {},
nodeSubscribe: () => {},
nodeUnsubscribe: () => {},
nodeUnsubscribeAll: () => {},
hasConnectedTalkNode: () => false,
nodeRegistry: new NodeRegistry(),
agentRunSeq: /* @__PURE__ */ new Map(),
chatAbortControllers: /* @__PURE__ */ new Map(),
chatAbortedRuns: /* @__PURE__ */ new Map(),
chatRunBuffers,
chatDeltaSentAt,
chatDeltaLastBroadcastLen,
chatDeltaLastBroadcastText,
agentDeltaSentAt,
bufferedAgentEvents,
clearChatRunState,
addChatRun: (sessionId, entry) => {
chatRuns.set(sessionId, entry);
},
removeChatRun: (sessionId, clientRunId, sessionKey) => {
const entry = chatRuns.get(sessionId);
if (!entry || entry.clientRunId !== clientRunId) return;
if (sessionKey !== void 0 && entry.sessionKey !== sessionKey) return;
chatRuns.delete(sessionId);
return entry;
},
subscribeSessionEvents: (connId) => {
sessionEvents.add(connId);
},
unsubscribeSessionEvents: (connId) => {
sessionEvents.delete(connId);
},
subscribeSessionMessageEvents: () => {},
unsubscribeSessionMessageEvents: () => {},
unsubscribeAllSessionEvents: (connId) => {
sessionEvents.delete(connId);
},
getSessionEventSubscriberConnIds: () => sessionEvents,
registerToolEventRecipient: () => {},
dedupe: /* @__PURE__ */ new Map(),
wizardSessions: /* @__PURE__ */ new Map(),
findRunningWizard: () => null,
purgeWizardSession: () => {},
getRuntimeSnapshot: () => ({}),
startChannel: async () => {
throw new Error("Channel start is unavailable in local embedded agent gateway context.");
},
stopChannel: async () => {
throw new Error("Channel stop is unavailable in local embedded agent gateway context.");
},
markChannelLoggedOut: () => {},
wizardRunner: async () => {
throw new Error("Onboarding wizard is unavailable in local embedded agent gateway context.");
},
broadcastVoiceWakeChanged: () => {},
broadcastVoiceWakeRoutingChanged: () => {},
unavailableGatewayMethods: /* @__PURE__ */ new Set()
};
}
/** Runs code inside a local gateway request scope unless an outer scope already exists. */
function withLocalGatewayRequestScope(params, run) {
const existing = getPluginRuntimeGatewayRequestScope();
if (existing?.context) return run();
const context = createLocalGatewayRequestContext(params);
return withPluginRuntimeGatewayRequestScope({
...existing,
context,
isWebchatConnect: existing?.isWebchatConnect ?? (() => false)
}, run);
}
//#endregion
//#region src/agents/agent-runtime-config.ts
/** Resolves agent runtime config, including SecretRef materialization for agent command use. */
/** Loads runtime/source config and resolves command SecretRefs when the agent path needs them. */
async function resolveAgentRuntimeConfig(runtime, params) {
const loadedRaw = getRuntimeConfig();
const includeChannelTargets = params?.runtimeTargetsChannelSecrets === true;
const hasRuntimeSecretRefs = hasAgentRuntimeSecretRefs({
config: loadedRaw,
includeChannelTargets
});
const sourceConfig = await (async () => {
try {
const { snapshot } = await readConfigFileSnapshotForWrite();
if (snapshot.valid) return snapshot.resolved;
} catch {}
return loadedRaw;
})();
const cfg = hasRuntimeSecretRefs ? (await (await import("./command-config-resolution.runtime.js")).resolveCommandConfigWithSecrets({
config: loadedRaw,
commandName: "agent",
targetIds: getAgentRuntimeCommandSecretTargetIds({ includeChannelTargets }),
runtime
})).resolvedConfig : loadedRaw;
setRuntimeConfigSnapshot(cfg, sourceConfig);
return {
loadedRaw,
sourceConfig,
cfg
};
}
function hasNestedSecretRef(value) {
if (isSecretRef(value)) return true;
if (Array.isArray(value)) return value.some((entry) => hasNestedSecretRef(entry));
if (!value || typeof value !== "object") return false;
return Object.values(value).some((entry) => hasNestedSecretRef(entry));
}
function hasAgentRuntimeSecretRefs(params) {
const { config } = params;
if (hasNestedSecretRef(config.models?.providers)) return true;
if (hasNestedSecretRef(config.agents?.defaults?.memorySearch?.remote?.apiKey)) return true;
if (Array.isArray(config.agents?.list) && config.agents.list.some((agent) => hasNestedSecretRef(agent?.memorySearch?.remote?.apiKey))) return true;
if (hasNestedSecretRef(config.messages?.tts?.providers)) return true;
if (hasNestedSecretRef(config.skills?.entries)) return true;
if (hasNestedSecretRef(config.tools?.web?.search)) return true;
if (config.plugins?.entries && Object.values(config.plugins.entries).some((entry) => hasNestedSecretRef({
webSearch: entry?.config?.webSearch,
webFetch: entry?.config?.webFetch
}))) return true;
return params.includeChannelTargets ? hasNestedSecretRef(config.channels) : false;
}
//#endregion
//#region src/agents/command/attempt-callbacks.ts
/** Creates callbacks that update lifecycle flags for persistence decisions. */
function createAgentAttemptLifecycleCallbacks(state) {
return {
onUserMessagePersisted: () => {
state.currentTurnUserMessagePersisted = true;
},
onAgentEvent: (evt) => {
if (evt.stream !== "lifecycle" || typeof evt.data?.phase !== "string") return;
if (evt.data.phase === "finishing") {
state.lifecycleFinishing = true;
return;
}
if (evt.data.phase === "end" || evt.data.phase === "error") state.lifecycleEnded = true;
}
};
}
//#endregion
//#region src/agents/agent-command.ts
/** Main agent command orchestration for sessions, model selection, delivery, and attempts. */
const log = createSubsystemLogger("agents/agent-command");
function hasExactConfiguredProviderModel(params) {
const normalizedProvider = normalizeProviderId(params.provider);
const model = params.model.trim();
if (!normalizedProvider || !model) return false;
for (const [providerId, providerConfig] of Object.entries(params.cfg.models?.providers ?? {})) {
if (normalizeProviderId(providerId) !== normalizedProvider) continue;
return (providerConfig.models ?? []).some((entry) => entry.id.trim() === model);
}
return false;
}
function hasConfiguredProvider(params) {
const normalizedProvider = normalizeProviderId(params.provider);
if (!normalizedProvider) return false;
return Object.keys(params.cfg.models?.providers ?? {}).some((providerId) => normalizeProviderId(providerId) === normalizedProvider);
}
function allowPluginModelNormalizationForRef(params) {
if (!normalizePluginsConfig(params.cfg.plugins).enabled && hasConfiguredProvider(params)) return false;
return !hasExactConfiguredProviderModel(params);
}
function normalizeAgentCommandModelRef(cfg, provider, model, modelManifestContext) {
return normalizeModelRef(provider, model, {
...modelManifestContext,
allowPluginNormalization: allowPluginModelNormalizationForRef({
cfg,
provider,
model
})
});
}
function normalizeAgentCommandDefaultModelRef(cfg, provider, model, modelManifestContext) {
const normalizedProvider = normalizeProviderId(provider);
if (hasConfiguredProvider({
cfg,
provider: normalizedProvider
})) return {
provider: normalizedProvider,
model: normalizeConfiguredProviderCatalogModelId(normalizedProvider, model, { manifestPlugins: modelManifestContext.manifestPlugins })
};
return normalizeAgentCommandModelRef(cfg, provider, model, modelManifestContext);
}
function parseAgentCommandModelRef(cfg, raw, defaultProvider, modelManifestContext) {
const parsed = resolveModelRefFromString({
cfg,
raw,
defaultProvider,
aliasIndex: buildModelAliasIndex({
cfg,
defaultProvider,
...modelManifestContext,
allowPluginNormalization: false
}),
...modelManifestContext,
allowPluginNormalization: false
})?.ref;
return parsed ? normalizeAgentCommandModelRef(cfg, parsed.provider, parsed.model, modelManifestContext) : null;
}
const attemptExecutionRuntimeLoader = createLazyImportLoader(() => import("./attempt-execution.runtime.js"));
const acpManagerRuntimeLoader = createLazyImportLoader(() => import("./acp/control-plane/manager.js"));
const acpPolicyRuntimeLoader = createLazyImportLoader(() => import("./policy-WHbnUIqa.js"));
const acpRuntimeErrorsRuntimeLoader = createLazyImportLoader(() => import("./errors-C6KFZ2tP.js"));
const acpSessionIdentifiersRuntimeLoader = createLazyImportLoader(() => import("./acp-core/runtime/session-identifiers.js"));
const deliveryRuntimeLoader = createLazyImportLoader(() => import("./delivery.runtime.js"));
const sessionStoreRuntimeLoader = createLazyImportLoader(() => import("./session-store.runtime.js"));
const cliCompactionRuntimeLoader = createLazyImportLoader(() => import("./cli-compaction-DBT3u8Yy.js"));
const transcriptResolveRuntimeLoader = createLazyImportLoader(() => import("./transcript-resolve.runtime.js"));
const cliDepsRuntimeLoader = createLazyImportLoader(() => import("./deps-CU5NS34E.js"));
const execDefaultsRuntimeLoader = createLazyImportLoader(() => import("./exec-defaults-BdOVWCEe.js"));
const skillsRuntimeLoader = createLazyImportLoader(async () => {
const [remote, sessionSnapshot] = await Promise.all([import("./remote-BmS7hfeI.js"), import("./session-snapshot-CCwADDJ5.js")]);
return {
getRemoteSkillEligibility: remote.getRemoteSkillEligibility,
resolveReusableWorkspaceSkillSnapshot: sessionSnapshot.resolveReusableWorkspaceSkillSnapshot
};
});
function loadAttemptExecutionRuntime() {
return attemptExecutionRuntimeLoader.load();
}
function loadAcpManagerRuntime() {
return acpManagerRuntimeLoader.load();
}
function loadAcpPolicyRuntime() {
return acpPolicyRuntimeLoader.load();
}
function loadAcpRuntimeErrorsRuntime() {
return acpRuntimeErrorsRuntimeLoader.load();
}
function loadAcpSessionIdentifiersRuntime() {
return acpSessionIdentifiersRuntimeLoader.load();
}
function loadDeliveryRuntime() {
return deliveryRuntimeLoader.load();
}
function loadSessionStoreRuntime() {
return sessionStoreRuntimeLoader.load();
}
function loadCliCompactionRuntime() {
return cliCompactionRuntimeLoader.load();
}
function loadTranscriptResolveRuntime() {
return transcriptResolveRuntimeLoader.load();
}
function loadCliDepsRuntime() {
return cliDepsRuntimeLoader.load();
}
function loadExecDefaultsRuntime() {
return execDefaultsRuntimeLoader.load();
}
function loadSkillsRuntime() {
return skillsRuntimeLoader.load();
}
async function resolveAgentCommandDeps(deps) {
if (deps) return deps;
const { createDefaultDeps } = await loadCliDepsRuntime();
return createDefaultDeps();
}
const OVERRIDE_FIELDS_CLEARED_BY_DELETE = [
"providerOverride",
"modelOverride",
"modelOverrideSource",
"modelOverrideFallbackOriginProvider",
"modelOverrideFallbackOriginModel",
"authProfileOverride",
"authProfileOverrideSource",
"authProfileOverrideCompactionCount",
"fallbackNoticeSelectedModel",
"fallbackNoticeActiveModel",
"fallbackNoticeReason",
"claudeCliSessionId"
];
const OVERRIDE_VALUE_MAX_LENGTH = 256;
async function persistSessionEntry(params) {
return await persistSessionEntry$1({
...params,
clearedFields: OVERRIDE_FIELDS_CLEARED_BY_DELETE
});
}
function clearPendingFinalDeliveryFields(entry, updatedAt) {
return {
...entry,
pendingFinalDelivery: void 0,
pendingFinalDeliveryText: void 0,
pendingFinalDeliveryCreatedAt: void 0,
pendingFinalDeliveryLastAttemptAt: void 0,
pendingFinalDeliveryAttemptCount: void 0,
pendingFinalDeliveryLastError: void 0,
pendingFinalDeliveryContext: void 0,
pendingFinalDeliveryIntentId: void 0,
updatedAt
};
}
async function resolveCurrentRunDeliveryContext(params) {
const { cfg, opts, sessionEntry } = params;
if (opts.deliver !== true) return;
const deliveryPlan = resolveAgentDeliveryPlan({
sessionEntry,
requestedChannel: opts.replyChannel ?? opts.channel,
explicitTo: opts.replyTo ?? opts.to,
explicitThreadId: opts.threadId,
accountId: opts.replyAccountId ?? opts.accountId,
wantsDelivery: true,
turnSourceChannel: opts.runContext?.messageChannel ?? opts.messageChannel,
turnSourceTo: opts.runContext?.currentChannelId ?? opts.to,
turnSourceAccountId: opts.runContext?.accountId ?? opts.accountId,
turnSourceThreadId: opts.runContext?.currentThreadTs ?? opts.threadId
});
const explicitChannelHint = normalizeOptionalString(opts.replyChannel ?? opts.channel);
const explicitThreadId = opts.threadId != null && opts.threadId !== "" ? opts.threadId : void 0;
let effectivePlan = deliveryPlan;
if (deliveryPlan.resolvedChannel === "webchat" && !explicitChannelHint) try {
const selection = await resolveMessageChannelSelection({ cfg });
effectivePlan = {
...deliveryPlan,
resolvedChannel: selection.channel,
deliveryTargetMode: deliveryPlan.deliveryTargetMode ?? "implicit"
};
} catch {
return;
}
if (!isDeliverableMessageChannel(effectivePlan.resolvedChannel)) return;
const targetMode = opts.deliveryTargetMode ?? effectivePlan.deliveryTargetMode ?? (opts.to ? "explicit" : "implicit");
const resolvedTo = effectivePlan.resolvedTo ?? resolveAgentOutboundTarget({
cfg,
plan: effectivePlan,
targetMode,
validateExplicitTarget: false
}).resolvedTo;
if (!resolvedTo) return;
const threadId = targetMode === "explicit" ? explicitThreadId ?? (effectivePlan.baseDelivery.threadIdSource === "explicit" ? effectivePlan.resolvedThreadId : void 0) : effectivePlan.resolvedThreadId;
return normalizeDeliveryContext({
channel: effectivePlan.resolvedChannel,
to: resolvedTo,
accountId: effectivePlan.resolvedAccountId,
threadId
});
}
function shouldPersistCurrentRunSessionCleanup(current, sessionId) {
return current !== void 0 && current.sessionId === sessionId && current.abortedLastRun !== true;
}
function shouldPersistRestartRecoveryContextClaim(current, sessionId, runId, allowCreate) {
if (!current) return allowCreate;
if (!shouldPersistCurrentRunSessionCleanup(current, sessionId)) return false;
return current.restartRecoveryDeliveryRunId === void 0 || current.restartRecoveryDeliveryRunId === runId;
}
function shouldPersistRestartRecoveryCleanup(current, sessionId, runId) {
return shouldPersistCurrentRunSessionCleanup(current, sessionId) && current?.restartRecoveryDeliveryRunId === runId;
}
function containsControlCharacters(value) {
for (const char of value) {
const code = char.codePointAt(0);
if (code === void 0) continue;
if (code <= 31 || code >= 127 && code <= 159) return true;
}
return false;
}
function normalizeExplicitOverrideInput(raw, kind) {
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;
}
function createAgentCommandSessionWorkingCopy(params) {
const result = {};
if (params.sessionEntry) result.sessionEntry = { ...params.sessionEntry };
if (params.sessionStore || params.sessionKey) result.sessionStore = {};
if (params.sessionKey && result.sessionEntry && result.sessionStore) result.sessionStore[params.sessionKey] = result.sessionEntry;
return result;
}
function resolveExplicitAgentCommandSessionKey(params) {
if (isUnscopedSessionKeySentinel(params.rawExplicitSessionKey) && !params.agentIdOverride && !params.shouldScopeDefaultAgentKey) return params.rawExplicitSessionKey;
return scopeLegacySessionKeyToAgent({
agentId: params.agentIdOverride ?? (params.shouldScopeDefaultAgentKey ? resolveDefaultAgentId(params.cfg) : void 0),
sessionKey: params.rawExplicitSessionKey,
mainKey: params.cfg.session?.mainKey
});
}
async function prepareAgentCommandExecution(opts, runtime) {
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();
if (!opts.to && !opts.sessionId && !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 });
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) : void 0;
if (agentIdOverride) {
if (!listAgentIds(cfg).includes(agentIdOverride)) throw new Error(`Unknown agent id "${agentIdOverrideRaw}". Use "${formatCliCommand("openclaw agents list")}" to see configured agents.`);
}
const explicitSessionKey = resolveExplicitAgentCommandSessionKey({
rawExplicitSessionKey,
agentIdOverride,
shouldScopeDefaultAgentKey: Boolean(rawExplicitSessionKey && !agentIdOverride && classifySessionKeyShape(rawExplicitSessionKey) === "legacy_or_alias" && !isUnscopedSessionKeySentinel(rawExplicitSessionKey)),
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}".`);
}
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 isSubagentLane = (normalizeOptionalString(opts.lane) ?? "") === AGENT_LANE_SUBAGENT;
const hasExplicitTimeoutOption = opts.timeout !== void 0;
const timeoutSecondsRaw = hasExplicitTimeoutOption ? parseStrictNonNegativeInteger(opts.timeout) ?? NaN : isSubagentLane ? 0 : void 0;
if (timeoutSecondsRaw !== void 0 && (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 : void 0;
const sessionResolution = resolveSession({
cfg,
to: opts.to,
sessionId: opts.sessionId,
sessionKey: explicitSessionKey,
agentId: agentIdOverride,
clone: false
});
const { sessionId, sessionKey, storePath, isNewSession, persistedThinking, persistedVerbose } = sessionResolution;
const { sessionEntry: sessionEntryRaw, sessionStore } = createAgentCommandSessionWorkingCopy({
sessionKey,
sessionEntry: sessionResolution.sessionEntry,
sessionStore: sessionResolution.sessionStore
});
const sessionAgentId = agentIdOverride ?? resolveSessionAgentId({
sessionKey: sessionKey ?? explicitSessionKey,
config: cfg
});
const outboundSession = buildOutboundSessionContext({
cfg,
agentId: sessionAgentId,
sessionKey
});
const workspaceDirRaw = normalizedSpawned.workspaceDir ?? resolveAgentWorkspaceDir(cfg, sessionAgentId);
const workspaceDir = resolveUserPath(workspaceDirRaw);
const cwd = normalizeOptionalString(opts.cwd) ?? normalizeOptionalString(sessionEntryRaw?.spawnedCwd);
const agentDir = resolveAgentDir(cfg, sessionAgentId);
const pluginsEnabled = normalizePluginsConfig(cfg.plugins).enabled;
const manifestMetadataSnapshot = pluginsEnabled ? loadManifestMetadataSnapshot({
config: cfg,
workspaceDir,
env: process.env
}) : void 0;
const modelManifestContext = { manifestPlugins: manifestMetadataSnapshot?.plugins ?? [] };
const configuredModel = resolveConfiguredModelRef({
cfg,
defaultProvider: DEFAULT_PROVIDER,
defaultModel: DEFAULT_MODEL,
allowPluginNormalization: pluginsEnabled,
...modelManifestContext
});
const configuredThinkingCatalog = buildConfiguredModelCatalog({
cfg,
workspaceDir,
...modelManifestContext
});
const thinkingLevelsHint = formatThinkingLevels(configuredModel.provider, configuredModel.model, ", ", configuredThinkingCatalog.length > 0 ? configuredThinkingCatalog : void 0);
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}.`);
await ensureAgentWorkspace({
dir: workspaceDirRaw,
ensureBootstrapFiles: !agentCfg?.skipBootstrap,
skipOptionalBootstrapFiles: agentCfg?.skipOptionalBootstrapFiles
});
const runId = opts.runId?.trim() || sessionId;
const { getAcpSessionManager } = await loadAcpManagerRuntime();
const acpManager = getAcpSessionManager();
const acpResolution = sessionKey ? acpManager.resolveSession({
cfg,
sessionKey
}) : null;
return {
body: !isRawModelRun && acpResolution?.kind === "ready" ? resolveAcpPromptBody(message, opts.internalEvents) : prependInternalEventContext(message, opts.internalEvents),
transcriptBody: opts.transcriptMessage ?? resolveInternalEventTranscriptBody(message, opts.internalEvents),
cfg,
configuredThinkingCatalog,
normalizedSpawned,
agentCfg,
thinkOverride,
thinkOnce,
verboseOverride,
timeoutMs,
runTimeoutOverrideMs,
sessionId,
sessionKey,
sessionEntry: sessionEntryRaw,
sessionStore,
storePath,
isNewSession,
persistedThinking,
persistedVerbose,
sessionAgentId,
outboundSession,
workspaceDir,
cwd: cwd ? resolveUserPath(cwd) : void 0,
agentDir,
pluginsEnabled,
manifestMetadataSnapshot,
modelManifestContext,
runId,
acpManager,
acpResolution
};
}
async function agentCommandInternal(opts, runtime = defaultRuntime, deps) {
const resolvedDeps = await resolveAgentCommandDeps(deps);
const isRawModelRun = opts.modelRun === true || opts.promptMode === "none";
const suppressVisibleSessionEffects = opts.sessionEffects === "internal";
const preserveUserFacingSessionModelState = opts.preserveUserFacingSessionModelState === true;
const prepared = await prepareAgentCommandExecution(opts, runtime);
const { body, transcriptBody, cfg, configuredThinkingCatalog, normalizedSpawned, agentCfg, thinkOverride, thinkOnce, verboseOverride, timeoutMs, runTimeoutOverrideMs, sessionId, sessionKey, sessionStore, storePath, isNewSession, persistedThinking, persistedVerbose, sessionAgentId, outboundSession, workspaceDir, cwd, agentDir, runId, acpManager, acpResolution, pluginsEnabled, manifestMetadataSnapshot, modelManifestContext } = prepared;
const effectiveCwd = cwd ? resolveUserPath(cwd) : workspaceDir;
let sessionEntry = prepared.sessionEntry;
let trackedRestartRecoveryDeliveryContext = false;
let currentRunDeliveryContext;
try {
if (opts.deliver === true) {
if (resolveSendPolicy({
cfg,
entry: sessionEntry,
sessionKey,
channel: sessionEntry?.channel,
chatType: sessionEntry?.chatType
}) === "deny") throw new Error("send blocked by session policy");
}
if (!isRawModelRun && acpResolution?.kind === "stale") throw acpResolution.error;
if (sessionStore && sessionKey && !suppressVisibleSessionEffects && !isSubagentSessionKey(sessionKey)) {
const now = Date.now();
const currentStoreEntry = sessionStore[sessionKey];
const allowCreateRestartRecoveryEntry = currentStoreEntry === void 0 && sessionEntry === void 0;
const entry = currentStoreEntry ?? sessionEntry ?? {
sessionId,
updatedAt: now,
sessionStartedAt: now
};
currentRunDeliveryContext = await resolveCurrentRunDeliveryContext({
cfg,
opts,
sessionEntry: entry
});
const persisted = await persistSessionEntry({
sessionStore,
sessionKey,
storePath,
entry: {
...entry,
sessionId,
updatedAt: now,
restartRecoveryDeliveryContext: currentRunDeliveryContext,
restartRecoveryDeliveryRunId: currentRunDeliveryContext ? runId : void 0
},
shouldPersist: (current) => shouldPersistRestartRecoveryContextClaim(current, sessionId, runId, allowCreateRestartRecoveryEntry)
});
sessionEntry = persisted ?? sessionEntry;
trackedRestartRecoveryDeliveryContext = Boolean(persisted?.restartRecoveryDeliveryContext) && persisted?.restartRecoveryDeliveryRunId === runId;
}
if (!isRawModelRun && acpResolution?.kind === "ready" && sessionKey) {
const attemptExecutionRuntime = await loadAttemptExecutionRuntime();
const startedAt = Date.now();
registerAgentRunContext(runId, suppressVisibleSessionEffects ? { isControlUiVisible: false } : {
sessionKey,
sessionId
});
attemptExecutionRuntime.emitAcpLifecycleStart({
runId,
startedAt
});
const visibleTextAccumulator = attemptExecutionRuntime.createAcpVisibleTextAccumulator();
let stopReason;
try {
const { resolveAcpAgentPolicyError, resolveAcpDispatchPolicyError, resolveAcpExplicitTurnPolicyError } = await loadAcpPolicyRuntime();
const turnPolicyError = opts.acpTurnSource === "manual_spawn" ? resolveAcpExplicitTurnPolicyError(cfg) : resolveAcpDispatchPolicyError(cfg);
if (turnPolicyError) throw turnPolicyError;
const agentPolicyError = resolveAcpAgentPolicyError(cfg, normalizeAgentId(acpResolution.meta.agent || resolveAgentIdFromSessionKey(sessionKey)));
if (agentPolicyError) throw agentPolicyError;
const acpImageAttachments = resolveInlineAgentImageAttachments(opts.images);
await acpManager.runTurn({
cfg,
sessionKey,
text: body,
attachments: acpImageAttachments.length > 0 ? acpImageAttachments : void 0,
mode: "prompt",
requestId: runId,
signal: opts.abortSignal,
onLifecycle: (event) => {
if (event.type === "prompt_submitted") attemptExecutionRuntime.emitAcpPromptSubmitted({
runId,
sessionKey,
at: event.at
});
},
onEvent: (event) => {
if (event.type !== "text_delta") attemptExecutionRuntime.emitAcpRuntimeEvent({
runId,
sessionKey,
event
});
if (event.type === "done") {
stopReason = event.stopReason;
return;
}
if (event.type !== "text_delta") return;
if (event.stream && event.stream !== "output") return;
if (!event.text) return;
const visibleUpdate = visibleTextAccumulator.consume(event.text);
if (!visibleUpdate) return;
attemptExecutionRuntime.emitAcpAssistantDelta({
runId,
text: visibleUpdate.text,
delta: visibleUpdate.delta
});
}
});
} catch (error) {
const { toAcpRuntimeError } = await loadAcpRuntimeErrorsRuntime();
const acpError = toAcpRuntimeError({
error,
fallbackCode: "ACP_TURN_FAILED",
fallbackMessage: "ACP turn failed before completion."
});
attemptExecutionRuntime.emitAcpLifecycleError({
runId,
error: acpError,
sessionKey
});
throw acpError;
}
attemptExecutionRuntime.emitAcpLifecycleEnd({ runId });
const finalTextRaw = visibleTextAccumulator.finalizeRaw();
const finalText = visibleTextAccumulator.finalize();
try {
const [{ resolveAcpSessionCwd }, { resolveSessionTranscriptFile }] = await Promise.all([loadAcpSessionIdentifiersRuntime(), loadTranscriptResolveRuntime()]);
const internalSource = suppressVisibleSessionEffects ? await resolveSessionTranscriptFile({
sessionId,
sessionKey,
sessionEntry,
agentId: sessionAgentId,
threadId: opts.threadId
}) : void 0;
const internalSessionFile = suppressVisibleSessionEffects ? await prepareInternalSessionEffectsTranscript({
sessionFile: internalSource?.sessionFile,
runId
}) : void 0;
const transcriptSessionEntry = internalSessionFile ? {
...sessionEntry ?? {
sessionId,
updatedAt: Date.now(),
sessionStartedAt: Date.now()
},
sessionId,
sessionFile: internalSessionFile
} : sessionEntry;
sessionEntry = await attemptExecutionRuntime.persistAcpTurnTranscript({
body,
transcriptBody,
finalText: finalTextRaw,
sessionId,
sessionKey,
sessionEntry: transcriptSessionEntry,
sessionStore: suppressVisibleSessionEffects ? void 0 : sessionStore,
storePath: suppressVisibleSessionEffects ? void 0 : storePath,
sessionAgentId,
threadId: opts.threadId,
sessionCwd: resolveAcpSessionCwd(acpResolution.meta) ?? workspaceDir,
config: cfg
});
if (internalSessionFile) sessionEntry = prepared.sessionEntry;
} catch (error) {
log.warn(`ACP transcript persistence failed for ${sessionKey}: ${formatErrorMessage(error)}`);
}
const result = attemptExecutionRuntime.buildAcpResult({
payloadText: finalText,
startedAt,
stopReason,
abortSignal: opts.abortSignal
});
const payloads = result.payloads;
const { deliverAgentCommandResult } = await loadDeliveryRuntime();
return await deliverAgentCommandResult({
cfg,
deps: resolvedDeps,
runtime,
opts,
outboundSession,
sessionEntry,
result,
payloads
});
}
let resolvedThinkLevel = thinkOnce ?? thinkOverride ?? persistedThinking;
const resolvedVerboseLevel = verboseOverride ?? persistedVerbose ?? agentCfg?.verboseDefault;
if (sessionKey || suppressVisibleSessionEffects) registerAgentRunContext(runId, {
...sessionKey && !suppressVisibleSessionEffects ? {
sessionKey,
sessionId
} : {},
verboseLevel: resolvedVerboseLevel,
isControlUiVisible: !suppressVisibleSessionEffects
});
const skillFilter = resolveEffectiveAgentSkillFilter(cfg, sessionAgentId);
const currentSkillsSnapshot = sessionEntry?.skillsSnapshot;
const [{ getRemoteSkillEligibility, resolveReusableWorkspaceSkillSnapshot }, { canExecRequestNode }] = await Promise.all([loadSkillsRuntime(), loadExecDefaultsRuntime()]);
const skillSnapshotState = resolveReusableWorkspaceSkillSnapshot({
workspaceDir,
config: cfg,
agentId: sessionAgentId,
existingSnapshot: isNewSession ? void 0 : currentSkillsSnapshot,
skillFilter,
eligibility: { remote: getRemoteSkillEligibility({ advertiseExecNode: canExecRequestNode({
cfg,
sessionEntry,
sessionKey,
agentId: sessionAgentId
}) }) },
watch: false
});
const needsSkillsSnapshot = isNewSession || !currentSkillsSnapshot || skillSnapshotState.shouldRefresh;
const skillsSnapshot = skillSnapshotState.snapshot;
if (skillsSnapshot && sessionStore && sessionKey && needsSkillsSnapshot && !suppressVisibleSessionEffects) {
const now = Date.now();
const current = sessionEntry ?? {
sessionId,
updatedAt: now,
sessionStartedAt: now
};
const next = {
...current,
sessionId,
updatedAt: now,
sessionStartedAt: current.sessionStartedAt ?? now,
skillsSnapshot
};
await persistSessionEntry({
sessionStore,
sessionKey,
storePath,
entry: next
});
sessionEntry = next;
}
const hasInitialSessionOverrides = Boolean(thinkOverride || verboseOverride);
const shouldPersistInitialSessionTouch = opts.skipInitialSessionTouch !== true || hasInitialSessionOverrides;
if (sessionStore && sessionKey && !suppressVisibleSessionEffects && shouldPersistInitialSessionTouch) {
const now = Date.now();
const entry = sessionStore[sessionKey] ?? sessionEntry ?? {
sessionId,
updatedAt: now,
sessionStartedAt: now
};
const next = {
...entry,
sessionId,
updatedAt: now,
sessionStartedAt: entry.sessionStartedAt ?? now,
lastInteractionAt: now
};
if (thinkOverride) next.thinkingLevel = thinkOverride;
applyVerboseOverride(next, verboseOverride);
await persistSessionEntry({
sessionStore,
sessionKey,
storePath,
entry: next
});
sessionEntry = next;
}
const configuredDefaultRef = resolveDefaultModelForAgent({
cfg,
agentId: sessionAgentId,
allowPluginNormalization: pluginsEnabled,
...modelManifestContext
});
const runContext = resolveAgentRunContext(opts);
const { provider: defaultProvider, model: defaultModel } = normalizeAgentCommandDefaultModelRef(cfg, configuredDefaultRef.provider, configuredDefaultRef.model, modelManifestContext);
let provider = defaultProvider;
let model = defaultModel;
const hasAllowlist = agentCfg?.models && Object.keys(agentCfg.models).length > 0;
const hasStoredOverride = Boolean(sessionEntry?.modelOverride || sessionEntry?.providerOverride);
let storedModelOverrideSource = hasStoredOverride ? sessionEntry?.modelOverrideSource : void 0;
const hasStoredAutoFallbackProvenance = hasStoredOverride && hasSessionAutoModelFallbackProvenance(sessionEntry);
const hasLegacyAutoFallbackOverrideWithoutOrigin = hasStoredOverride && hasLegacyAutoFallbackWithoutOrigin(sessionEntry);
const explicitProviderOverride = typeof opts.provider === "string" ? normalizeExplicitOverrideInput(opts.provider, "provider") : void 0;
const explicitModelOverride = typeof opts.model === "string" ? normalizeExplicitOverrideInput(opts.model, "model") : void 0;
const hasExplicitRunOverride = Boolean(explicitProviderOverride || explicitModelOverride);
if (hasExplicitRunOverride && opts.allowModelOverride !== true) throw new Error("Model override is not authorized for this caller.");
const needsModelCatalog = Boolean(hasAllowlist);
let allowedModelCatalog = [];
let modelCatalog = null;
let visibilityPolicy = createModelVisibilityPolicy({
cfg,
catalog: [],
defaultProvider,
defaultModel,
allowManifestNormalization: true,
allowPluginNormalization: pluginsEnabled,
...modelManifestContext
});
if (needsModelCatalog) {
modelCatalog = pluginsEnabled ? loadManifestModelCatalog({
config: cfg,
workspaceDir
}) : [];
visibilityPolicy = createModelVisibilityPolicy({
cfg,
catalog: modelCatalog,
defaultProvider,
defaultModel,
agentId: sessionAgentId,
allowManifestNormalization: true,
allowPluginNormalization: pluginsEnabled,
...modelManifestContext
});
allowedModelCatalog = visibilityPolicy.allowedCatalog;
}
if (sessionEntry && sessionStore && sessionKey && hasStoredOverride && !suppressVisibleSessionEffects) {
const entry = sessionEntry;
if (hasLegacyAutoFallbackOverrideWithoutOrigin) {
const { updated } = applyModelOverrideToSessionEntry({
entry,
selection: {
provider: defaultProvider,
model: defaultModel,
isDefault: true
}
});
if (updated) {
storedModelOverrideSource = void 0;
await persistSessionEntry({
sessionStore,
sessionKey,
storePath,
entry
});
}
}
if (repairProviderWrappedModelOverride({
entry,
defaultProvider,
defaultModel
}).updated) await persistSessionEntry({
sessionStore,
sessionKey,
storePath,
entry
});
const overrideProvider = sessionEntry.providerOverride?.trim() || defaultProvider;
const overrideModel = sessionEntry.modelOverride?.trim();
if (overrideModel) {
const normalizedOverride = normalizeAgentCommandModelRef(cfg, overrideProvider, overrideModel, modelManifestContext);
const key = modelKey(normalizedOverride.provider, normalizedOverride.model);
if (!visibilityPolicy.allowsKey(key)) {
const { updated } = applyModelOverrideToSessionEntry({
entry,
selection: {
provider: defaultProvider,
model: defaultModel,
isDefault: true
}
});
if (updated) await persistSessionEntry({
sessionStore,
sessionKey,
storePath,
entry
});
}
}
}
const storedProviderOverride = hasLegacyAutoFallbackOverrideWithoutOrigin ? void 0 : sessionEntry?.providerOverride?.trim();
let storedModelOverride = hasLegacyAutoFallbackOverrideWithoutOrigin ? void 0 : sessionEntry?.modelOverride?.trim();
const currentRunModelChannel = [
runContext.messageChannel,
opts.replyChannel,
opts.channel
].find((channel) => Boolean(channel && isDeliverableMessageChannel(channel)));
const channelOverrideGroupId = currentRunModelChannel ? runContext.groupId ?? sessionEntry?.groupId ?? runContext.currentChannelId : sessionEntry?.groupId ?? runContext.groupId ?? runContext.currentChannelId;
const channelModelOverride = cfg.channels?.modelByChannel && !hasExplicitRunOverride ? resolveChannelModelOverride({
cfg,
channel: currentRunModelChannel ?? sessionEntry?.channel ?? sessionEntry?.lastChannel ?? sessionEntry?.origin?.provider,
groupId: channelOverrideGroupId,
groupChatType: sessionEntry?.chatType ?? sessionEntry?.origin?.chatType,
groupChannel: runContext.groupChannel ?? sessionEntry?.groupChannel,
groupSubject: sessionEntry?.subject,
parentSessionKey: sessionEntry?.parentSessionKey ?? sessionKey
}) : null;
const normalizedChannelOverride = channelModelOverride ? parseAgentCommandModelRef(cfg, channelModelOverride.model, defaultProvider, modelManifestContext) : null;
const primaryProvider = normalizedChannelOverride?.provider ?? defaultProvider;
const primaryModel = normalizedChannelOverride?.model ?? defaultModel;
if (normalizedChannelOverride && !Boolean(storedProviderOverride || storedModelOverride)) {
provider = normalizedChannelOverride.provider;
model = normalizedChannelOverride.model;
}
if (storedModelOverride) {
const normalizedStored = normalizeAgentCommandModelRef(cfg, storedProviderOverride || defaultProvider, storedModelOverride, modelManifestContext);
const key = modelKey(normalizedStored.provider, normalizedStored.model);
if (visibilityPolicy.allowsKey(key)) {
provider = normalizedStored.provider;
model = normalizedStored.model;
}
}
const autoFallbackPrimaryProbe = !hasExplicitRunOverride ? resolveAutoFallbackPrimaryProbe({
entry: sessionEntry,
sessionKey,
primaryProvider,
primaryModel
}) : void 0;
let autoFallbackPrimaryProbeSessionEntry;
if (autoFallbackPrimaryProbe && sessionEntry) {
provider = autoFallbackPrimaryProbe.provider;
model = autoFallbackPrimaryProbe.model;
autoFallbackPrimaryProbeSessionEntry = { ...sessionEntry };
clearAutoFallbackPrimaryProbeSelection(autoFallbackPrimaryProbeSessionEntry);
}
let providerForAuthProfileValidation = provider;
if (hasExplicitRunOverride) {
const explicitRef = explicitModelOverride ? explicitProviderOverride ? normalizeAgentCommandModelRef(cfg, explicitProviderOverride, explicitModelOverride, modelManifestContext) : parseAgentCommandModelRef(cfg, explicitModelOverride, provider, modelManifestContext) : explicitProviderOverride ? normalizeAgentCommandModelRef(cfg, explicitProviderOverride, model, modelManifestContext) : null;
if (!explicitRef) throw new Error("Invalid model override.");
const explicitKey = modelKey(explicitRef.provider, explicitRef.model);
if (!visibilityPolicy.allowsKey(explicitKey)) throw new Error(`Model override "${sanitizeForLog(explicitRef.provider)}/${sanitizeForLog(explicitRef.model)}" is not allowed for agent "${sessionAgentId}".`);
provider = explicitRef.provider;
model = explicitRef.model;
}
const allowedInitialSelection = visibilityPolicy.resolveSelection({
provider,
model
});
if (!allowedInitialSelection) throw new Error(`Configured default model "${modelKey(provider, model)}" is not allowed by agents.defaults.models, and no allowed model is available.`);
provider = allowedInitialSelection.provider;
model = allowedInitialSelection.model;
providerForAuthProfileValidation = provider;
await ensureSelectedAgentHarnessPlugin({
config: cfg,
provider,
modelId: model,
agentId: sessionAgentId,
sessionKey,
workspaceDir
});
let sessionEntryForAttempt = autoFallbackPrimaryProbeSessionEntry ?? sessionEntry;
if (sessionEntryForAttempt) {
const authProfileId = sessionEntryForAttempt.authProfileOverride;
if (authProfileId) {
const entry = sessionEntryForAttempt;
const profile = ensureAuthProfileStore().profiles[authProfileId];
const validationHarnessPolicy = resolveAvailableAgentHarnessPolicy({
provider: providerForAuthProfileValidation,
modelId: model,
config: cfg,
agentId: sessionAgentId,
sessionKey
});
const acceptedAuthProviders = listOpenAIAuthProfileProvidersForAgentRuntime({
provider: providerForAuthProfileValidation,
harnessRuntime: validationHarnessPolicy.runtime,
config: cfg
}).map((candidateProvider) => pluginsEnabled ? resolveProviderIdForAuth(candidateProvider, {
config: cfg,
workspaceDir,
...manifestMetadataSnapshot ? { metadataSnapshot: manifestMetadataSnapshot } : {}
}) : candidateProvider);
const authAliasLookupParams = pluginsEnabled ? {
config: cfg,
workspaceDir,
...manifestMetadataSnapshot ? { metadataSnapshot: manifestMetadataSnapshot } : {}
} : {
config: cfg,
workspaceDir,
metadataSnapshot: { plugins: [] }
};
if (!(profile && acceptedAuthProviders.some((candidateProvider) => isStoredCredentialCompatibleWithAuthProvider({
cfg,
authAliasLookupParams,
provider: candidateProvider,
credential: profile
})))) {
if (hasExplicitRunOverride || autoFallbackPrimaryProbe) sessionEntryForAttempt = {
...entry,
authProfileOverride: void 0,
authProfileOverrideSource: void 0,
authProfileOverrideCompactionCount: void 0
};
else if (sessionStore && sessionKey && !suppressVisibleSessionEffects) await clearSessionAuthProfileOverride({
sessionEntry: entry,
sessionStore,
sessionKey,
storePath
});
}
}
}
const catalogForThinking = allowedModelCatalog.length > 0 ? allowedModelCatalog : modelCatalog && modelCatalog.length > 0 ? modelCatalog : configuredThinkingCatalog;
const thinkingCatalog = catalogForThinking.length > 0 ? catalogForThinking : void 0;
if (!resolvedThinkLevel) resolvedThinkLevel = normalizeThinkLevel(resolveAgentConfig(cfg, sessionAgentId)?.thinkingDefault) ?? resolveThinkingDefault({
cfg,
provider,
model,
catalog: thinkingCatalog
});
if (!isThinkingLevelSupported({
provider,
model,
level: resolvedThinkLevel,
catalog: thinkingCatalog
})) {
if (Boolean(thinkOnce || thinkOverride)) throw new Error(`Thinking level "${resolvedThinkLevel}" is not supported for ${provider}/${model}. Use one of: ${formatThinkingLevels(provider, model, ", ", thinkingCatalog)}.`);
const fallbackThinkLevel = resolveSupportedThinkingLevel({
provider,
model,
level: resolvedThinkLevel,
catalog: thinkingCatalog
});
if (fallbackThinkLevel !== resolvedThinkLevel) resolvedThinkLevel = fallbackThinkLevel;
}
const { resolveSessionTranscriptFile } = await loadTranscriptResolveRuntime();
let sessionFile;
if (sessionStore && sessionKey) {
const resolvedSessionFile = await resolveSessionTranscriptFile({
sessionId,
sessionKey,
sessionStore: suppressVisibleSessionEffects ? void 0 : sessionStore,
storePath: suppressVisibleSessionEffects ? void 0 : storePath,
sessionEntry,
agentId: sessionAgentId,
threadId: opts.threadId
});
sessionFile = resolvedSessionFile.sessionFile;
sessionEntry = resolvedSessionFile.sessionEntry;
}
if (!sessionFile) {
const resolvedSessionFile = await resolveSessionTranscriptFile({
sessionId,
sessionKey: sessionKey ?? sessionId,
storePath,
sessionEntry,
agentId: sessionAgentId,
threadId: opts.threadId
});
sessionFile = resolvedSessionFile.sessionFile;
sessionEntry = resolvedSessionFile.sessionEntry;
}
const attemptSessionFile = suppressVisibleSessionEffects ? await prepareInternalSessionEffectsTranscript({
sessionFile,
runId
}) : sessionFile;
const startedAt = Date.now();
const attemptLifecycleState = {
currentTurnUserMessagePersisted: false,
lifecycleFinishing: false,
lifecycleEnded: false
};
const attemptLifecycleCallbacks = createAgentAttemptLifecycleCallbacks(attemptLifecycleState);
let lifecycleFinishingEmitted = false;
const emitLifecycleFinishing = (runResult) => {
if (attemptLifecycleState.lifecycleEnded || attemptLifecycleState.lifecycleFinishing || lifecycleFinishingEmitted) return;
lifecycleFinishingEmitted = true;
attemptLifecycleState.lifecycleFinishing = true;
emitAgentEvent({
runId,
stream: "lifecycle",
data: {
phase: "finishing",
startedAt,
endedAt: Date.now(),
aborted: runResult.meta.aborted ?? false,
stopReason: runResult.meta.stopReason
}
});
};
const emitLifecycleEnd = (runResult) => {
if (attemptLifecycleState.lifecycleEnded) return;
attemptLifecycleState.lifecycleEnded = true;
const stopReason = runResult.meta.stopReason;
if (stopReason && stopReason !== "end_turn") console.error(`[agent] run ${runId} ended with stopReason=${stopReason}`);
emitAgentEvent({
runId,
stream: "lifecycle",
data: {
phase: "end",
startedAt,
endedAt: Date.now(),
aborted: runResult.meta.aborted ?? false,
stopReason
}
});
};
const emitLifecyclePostTurnError = (error) => {
if (attemptLifecycleState.lifecycleEnded) return;
attemptLifecycleState.lifecycleEnded = true;
emitAgentEvent({
runId,
stream: "lifecycle",
data: {
phase: "error",
startedAt,
endedAt: Date.now(),
error: error instanceof Error ? error.message : "Agent run failed"
}
});
};
const attemptExecutionRuntime = await loadAttemptExecutionRuntime();
const messageChannel = resolveMessageChannel(runContext.messageChannel, opts.replyChannel ?? opts.channel);
let result;
let fallbackProvider = provider;
let fallbackModel = model;
const MAX_LIVE_SWITCH_RETRIES = 5;
let liveSwitchRetries = 0;
let autoFallbackPrimaryProbeInterruptedByLiveSwitch = false;
const fallbackTrajectoryRecorder = createTrajectoryRuntimeRecorder({
cfg,
runId,
sessionId,
sessionKey,
sessionFile,
provider,
modelId: model,
workspaceDir
});
for (;;) try {
const spawnedBy = normalizedSpawned.spawnedBy ?? sessionEntry?.spawnedBy;
const effectiveFallbacksOverride = resolveEffectiveModelFallbacks({
cfg,
agentId: sessionAgentId,
sessionKey,
hasSessionModelOverride: hasExplicitRunOverride || Boolean(storedProviderOverride || storedModelOverride),
modelOverrideSource: hasExplicitRunOverride ? "user" : storedModelOverrideSource,
hasAutoFallbackProvenance: hasExplicitRunOverride ? false : hasStoredAutoFallbackProvenance
});
let fallbackAttemptIndex = 0;
attemptLifecycleState.currentTurnUserMessagePersisted = false;
const fallbackResult = await runWithModelFallback({
cfg,
provider,
model,
...modelManifestContext,
runId,
agentDir,
agentId: sessionAgentId,
sessionId,
sessionKey: sessionKey ?? sessionId,
prepareAgentHarnessRuntime: async ({ provider: providerValue, model: modelValue, agentHarnessRuntimeOverride }) => {
await ensureSelectedAgentHarnessPlugin({
config: cfg,
provider: providerValue,
modelId: modelValue,
agentId: sessionAgentId,
sessionKey,
agentHarnessRuntimeOverride,
workspaceDir
});
},
fallbacksOverride: effectiveFallbacksOverride,
onFallbackStep: (step) => {
fallbackTrajectoryRecorder?.recordEvent("model.fallback_step", step);
},
classifyResult: ({ provider: providerLocal, model: modelLocal, result: resultLocal }) => classifyEmbeddedAgentRunResultForModelFallback({
provider: providerLocal,
model: modelLocal,
result: resultLocal
}),
abortSignal: opts.abortSignal,
run: async (providerOverride, modelOverride, runOptions) => {
const isAutoFallbackPrimaryProbeCandidate = autoFallbackPrimaryProbe && providerOverride === autoFallbackPrimaryProbe.provider && modelOverride === autoFallbackPrimaryProbe.model;
const attemptSessionEntry = autoFallbackPrimaryProbe && providerOverride === autoFallbackPrimaryProbe.fallbackProvider && !isAutoFallbackPrimaryProbeCandidate ? sessionEntry : sessionEntryForAttempt;
if (isAutoFallbackPrimaryProbeCandidate) markAutoFallbackPrimaryProbe({
probe: autoFallbackPrimaryProbe,
sessionKey
});
const isFallbackRetry = fallbackAttemptIndex > 0;
fallbackAttemptIndex += 1;
opts.onActiveModelSelected?.({
provider: providerOverride,
model: modelOverride
});
return attemptExecutionRuntime.runAgentAttempt({
providerOverride,
modelOverride,
modelFallbacksOverride: effectiveFallbacksOverride,
originalProvider: provider,
cfg,
sessionEntry: attemptSessionEntry,
sessionId,
sessionKey,
sessionAgentId,
sessionFile: attemptSessionFile,
workspaceDir,
cwd,
body,
isFallbackRetry,
resolvedThinkLevel,
fastMode: resolveFastModeState({
cfg,
provider: providerOverride,
model: modelOverride,
agentId: sessionAgentId,
sessionEntry
}).enabled,
timeoutMs,
runTimeoutOverrideMs,
runId,
opts,
runContext,
spawnedBy,
messageChannel,
skillsSnapshot,
resolvedVerboseLevel,
agentDir,
authProfileProvider: providerForAuthProfileValidation,
sessionStore: suppressVisibleSessionEffects ? void 0 : sessionStore,
storePath: suppressVisibleSessionEffects ? void 0 : storePath,
pluginsEnabled,
...manifestMetadataSnapshot ? { metadataSnapshot: manifestMetadataSnapshot } : {},
allowTransientCooldownProbe: runOptions?.allowTransientCooldownProbe,
sessionHasHistory: !isNewSession || await attemptExecutionRuntime.sessionFileHasContent(attemptSessionFile),
suppressPromptPersistenceOnRetry: opts.suppressPromptPersistence === true || isFallbackRetry && attemptLifecycleState.currentTurnUserMessagePersisted,
onUserMessagePersisted: attemptLifecycleCallbacks.onUserMessagePersisted,
onAgentEvent: attemptLifecycleCallbacks.onAgentEvent,
deferTerminalLifecycleEnd: true
});
}
});
result = fallbackResult.result;
fallbackProvider = fallbackResult.provider;
fallbackModel = fallbackResult.model;
if (autoFallbackPrimaryProbe && !autoFallbackPrimaryProbeInterruptedByLiveSwitch && sessionEntry && sessionStore && sessionKey && !suppressVisibleSessionEffects && !preserveUserFacingSessionModelState && entryMatchesAutoFallbackPrimaryProbe(sessionEntry, autoFallbackPrimaryProbe)) {
const nextSessionEntry = { ...sessionEntry };
if (fallbackProvider === autoFallbackPrimaryProbe.provider && fallbackModel === autoFallbackPrimaryProbe.model) clearAutoFallbackPrimaryProbeSelection(nextSessionEntry);
else {
nextSessionEntry.providerOverride = fallbackProvider;
nextSessionEntry.modelOverride = fallbackModel;
nextSessionEntry.modelOverrideSource = "auto";
nextSessionEntry.modelOverrideFallbackOriginProvider = autoFallbackPrimaryProbe.provider;
nextSessionEntry.modelOverrideFallbackOriginModel = autoFallbackPrimaryProbe.model;
if (nextSessionEntry.authProfileOverrideSource === "auto" && fallbackProvider !== autoFallbackPrimaryProbe.fallbackProvider) {
delete nextSessionEntry.authProfileOverride;
delete nextSessionEntry.authProfileOverrideSource;
delete nextSessionEntry.authProfileOverrideCompactionCount;
}
nextSessionEntry.updatedAt = Date.now();
}
sessionEntry = await persistSessionEntry({
sessionStore,
sessionKey,
storePath,
entry: nextSessionEntry,
shouldPersist: (current) => Boolean(current && entryMatchesAutoFallbackPrimaryProbe(current, autoFallbackPrimaryProbe))
}) ?? sessionEntry;
}
if (fallbackResult.attempts.length > 0 && result.meta.agentMeta) result = {
...result,
meta: {
...result.meta,
agentMeta: {
...result.meta.agentMeta,
fallbackAttempts: fallbackResult.attempts
}
}
};
emitLifecycleFinishing(result);
break;
} catch (err) {
if (err instanceof LiveSessionModelSwitchError) {
liveSwitchRetries++;
if (liveSwitchRetries > MAX_LIVE_SWITCH_RETRIES) {
log.error(`Live session model switch in subagent run ${runId}: exceeded maximum retries (${MAX_LIVE_SWITCH_RETRIES})`);
if (!attemptLifecycleState.lifecycleEnded) emitAgentEvent({
runId,
stream: "lifecycle",
data: {
phase: "error",
startedAt,
endedAt: Date.now(),
error: "Agent run failed"
}
});
await fallbackTrajectoryRecorder?.flush();
throw new Error(`Exceeded maximum live model switch retries (${MAX_LIVE_SWITCH_RETRIES})`, { cause: err });
}
const switchRef = normalizeAgentCommandModelRef(cfg, err.provider, err.model, modelManifestContext);
const switchKey = modelKey(switchRef.provider, switchRef.model);
if (!visibilityPolicy.allowsKey(switchKey)) {
log.info(`Live session model switch in subagent run ${runId}: rejected ${sanitizeForLog(err.provider)}/${sanitizeForLog(err.model)} (not in allowlist)`);
if (!attemptLifecycleState.lifecycleEnded) emitAgentEvent({
runId,
stream: "lifecycle",
data: {
phase: "error",
startedAt,
endedAt: Date.now(),
error: "Agent run failed"
}
});
await fallbackTrajectoryRecorder?.flush();
throw new Error(`Live model switch rejected: ${sanitizeForLog(err.provider)}/${sanitizeForLog(err.model)} is not in the agent allowlist`, { cause: err });
}
const previousProvider = provider;
const previousModel = model;
if (autoFallbackPrimaryProbe) autoFallbackPrimaryProbeInterruptedByLiveSwitch = true;
provider = err.provider;
model = err.model;
fallbackProvider = err.provider;
fallbackModel = err.model;
providerForAuthProfileValidation = err.provider;
if (sessionEntry) {
sessionEntry = { ...sessionEntry };
sessionEntry.authProfileOverride = err.authProfileId;
sessionEntry.authProfileOverrideSource = err.authProfileId ? err.authProfileIdSource : void 0;
sessionEntry.authProfileOverrideCompactionCount = void 0;
}
if (storedModelOverride || err.model !== previousModel || err.provider !== previousProvider) {
storedModelOverride = err.model;
storedModelOverrideSource = "user";
}
attemptLifecycleState.lifecycleEnded = false;
log.info(`Live session model switch in subagent run ${runId}: switching to ${sanitizeForLog(err.provider)}/${sanitizeForLog(err.model)}`);
continue;
}
if (!attemptLifecycleState.lifecycleEnded) emitAgentEvent({
runId,
stream: "lifecycle",
data: {
phase: "error",
startedAt,
endedAt: Date.now(),
error: err instanceof Error ? err.message : "Agent run failed"
}
});
await fallbackTrajectoryRecorder?.flush();
throw err;
}
try {
await fallbackTrajectoryRecorder?.flush();
const rotatedSessionFile = result.meta.agentMeta?.sessionFile;
const effectiveSessionId = rotatedSessionFile ? result.meta.agentMeta?.sessionId ?? sessionId : sessionId;
const effectiveSessionFile = rotatedSessionFile ?? attemptSessionFile;
if (sessionStore && sessionKey && !suppressVisibleSessionEffects) {
const { updateSessionStoreAfterAgentRun } = await loadSessionStoreRuntime();
await updateSessionStoreAfterAgentRun({
cfg,
contextTokensOverride: agentCfg?.contextTokens,
sessionId: effectiveSessionId,
sessionKey,
storePath,
sessionStore,
defaultProvider: provider,
defaultModel: model,
fallbackProvider,
fallbackModel,
result,
touchInteraction: opts.bootstrapContextRunKind !== "cron" && opts.bootstrapContextRunKind !== "heartbeat" && !opts.internalEvents?.length,
preserveRuntimeModel: opts.bootstrapContextRunKind === "heartbeat" || preserveUserFacingSessionModelState,
preserveUserFacingSessionModelState
});
sessionEntry = sessionStore[sessionKey] ?? sessionEntry;
}
const transcriptPersistenceRunner = result.meta.executionTrace?.runner;
const embeddedAssistantGapFill = transcriptPersistenceRunner === "embedded" || transcriptPersistenceRunner === void 0 && Boolean(result.meta.finalAssistantVisibleText?.trim());
if (transcriptPersistenceRunner === "cli" || embeddedAssistantGapFill) {
let persistedCliTurnTranscript = false;
try {
const transcriptSessionEntry = suppressVisibleSessionEffects ? {
...sessionEntry ?? {
sessionId: effectiveSessionId,
updatedAt: Date.now(),
sessionStartedAt: Date.now()
},
sessionId: effectiveSessionId,
sessionFile: effectiveSessionFile
} : sessionEntry;
sessionEntry = await attemptExecutionRuntime.persistCliTurnTranscript({
body,
transcriptBody,
result,
sessionId: effectiveSessionId,
sessionKey: sessionKey ?? effectiveSessionId,
sessionEntry: transcriptSessionEntry,
sessionStore: suppressVisibleSessionEffects ? void 0 : sessionStore,
storePath: suppressVisibleSessionEffects ? void 0 : storePath,
sessionAgentId,
threadId: opts.threadId,
sessionCwd: effectiveCwd,
config: cfg,
embeddedAssistantGapFill
});
if (suppressVisibleSessionEffects) sessionEntry = prepared.sessionEntry;
persistedCliTurnTranscript = true;
} catch (error) {
log.warn(`Turn transcript persistence failed for ${sessionKey ?? sessionId}: ${error instanceof Error ? error.message : String(error)}`);
}
if (persistedCliTurnTranscript && !suppressVisibleSessionEffects) sessionEntry = await (await loadCliCompactionRuntime()).runCliTurnCompactionLifecycle({
cfg,
sessionId: effectiveSessionId,
sessionKey: sessionKey ?? effectiveSessionId,
sessionEntry,
sessionStore,
storePath,
sessionAgentId,
workspaceDir,
cwd: effectiveCwd,
agentDir,
provider: result.meta.agentMeta?.provider ?? provider,
model: result.meta.agentMeta?.model ?? model,
skillsSnapshot,
messageChannel,
agentAccountId: runContext.accountId,
senderIsOwner: opts.senderIsOwner,
thinkLevel: resolvedThinkLevel,
extraSystemPrompt: opts.extraSystemPrompt
});
}
const payloads = result.payloads ?? [];
let pendingFinalDeliveryTextForThisRun;
if (opts.deliver === true && sessionStore && sessionKey && !suppressVisibleSessionEffects && payloads.length > 0 && !isSubagentSessionKey(sessionKey)) {
const now = Date.now();
const combinedPayload = sanitizePendingFinalDeliveryText(payloads.map((p) => typeof p.text === "string" ? p.text : "").filter(Boolean).join("\n\n"));
pendingFinalDeliveryTextForThisRun = combinedPayload || void 0;
if (combinedPayload) sessionEntry = await persistSessionEntry({
sessionStore,
sessionKey,
storePath,
entry: {
...sessionStore[sessionKey] ?? sessionEntry,
pendingFinalDelivery: true,
pendingFinalDeliveryText: combinedPayload,
pendingFinalDeliveryContext: currentRunDeliveryContext,
pendingFinalDeliveryCreatedAt: now,
updatedAt: now
},
shouldPersist: (current) => shouldPersistCurrentRunSessionCleanup(current, sessionId)
}) ?? sessionEntry;
}
const { deliverAgentCommandResult } = await loadDeliveryRuntime();
const resolveFreshSessionEntryForDelivery = sessionStore && sessionKey && !suppressVisibleSessionEffects ? async () => {
const { loadSessionStore } = await loadSessionStoreRuntime();
const freshEntry = loadSessionStore(storePath, {
skipCache: true,
clone: false
})[sessionKey];
if (!freshEntry || freshEntry.sessionId !== effectiveSessionId) return;
sessionStore[sessionKey] = freshEntry;
return freshEntry;
} : void 0;
const deliveryParams = {
cfg,
deps: resolvedDeps,
runtime,
opts,
outboundSession,
sessionEntry,
result,
payloads
};
const deliveryResult = await deliverAgentCommandResult(resolveFreshSessionEntryForDelivery ? {
...deliveryParams,
expectedSessionIdForFreshDelivery: effectiveSessionId,
resolveFreshSessionEntryForDelivery
} : deliveryParams);
if (sessionStore && sessionKey && !isSubagentSessionKey(sessionKey) && !suppressVisibleSessionEffects) {
const entry = sessionStore[sessionKey] ?? sessionEntry;
const noPendingTextForThisRun = opts.deliver === true && pendingFinalDeliveryTextForThisRun === void 0 && entry.pendingFinalDelivery === true && !entry.pendingFinalDeliveryText;
if (deliveryResult?.deliverySucceeded === true || noPendingTextForThisRun) sessionEntry = await persistSessionEntry({
sessionStore,
sessionKey,
storePath,
entry: clearPendingFinalDeliveryFields(entry, Date.now()),
shouldPersist: (current) => shouldPersistCurrentRunSessionCleanup(current, sessionId)
}) ?? sessionEntry;
}
emitLifecycleEnd(result);
return deliveryResult;
} catch (error) {
emitLifecyclePostTurnError(error);
throw error;
}
} finally {
if (trackedRestartRecoveryDeliveryContext && sessionStore && sessionKey) try {
const entry = sessionStore[sessionKey] ?? sessionEntry;
if (entry?.restartRecoveryDeliveryContext && entry.restartRecoveryDeliveryRunId === runId) sessionEntry = await persistSessionEntry({
sessionStore,
sessionKey,
storePath,
entry: {
...entry,
restartRecoveryDeliveryContext: void 0,
restartRecoveryDeliveryRunId: void 0,
updatedAt: Date.now()
},
shouldPersist: (current) => shouldPersistRestartRecoveryCleanup(current, sessionId, runId)
}) ?? sessionEntry;
} catch (error) {
log.warn(`failed to clear restart recovery delivery context for ${sessionKey}: ${error instanceof Error ? error.message : String(error)}`);
}
clearAgentRunContext(runId);
}
}
/** Runs an agent turn from CLI/runtime options against the resolved session and model policy. */
async function agentCommand(opts, runtime = defaultRuntime, deps) {
const resolvedDeps = await resolveAgentCommandDeps(deps);
return await withLocalGatewayRequestScope({
deps: resolvedDeps,
getRuntimeConfig
}, async () => await agentCommandInternal({
...opts,
senderIsOwner: opts.senderIsOwner ?? true,
allowModelOverride: opts.allowModelOverride ?? true
}, runtime, resolvedDeps));
}
/** Runs an agent turn from an inbound channel/gateway ingress context. */
async function agentCommandFromIngress(opts, runtime = defaultRuntime, deps) {
if (typeof opts.allowModelOverride !== "boolean") throw new Error("allowModelOverride must be explicitly set for ingress agent runs.");
return await agentCommandInternal({
...opts,
senderIsOwner: opts.senderIsOwner === true
}, runtime, deps);
}
const testing = {
resolveAgentRuntimeConfig,
prepareAgentCommandExecution,
resolveExplicitAgentCommandSessionKey
};
//#endregion
export { agentCommandFromIngress as n, testing as r, agentCommand as t };