openclaw
Version:
Multi-channel AI gateway with extensible messaging integrations
1,132 lines (1,131 loc) • 48.5 kB
JavaScript
import { c as normalizeOptionalString } from "./string-coerce-mnp54Vah.js";
import { p as finiteSecondsToTimerSafeMilliseconds } from "./number-coercion-CJQ8TR--.js";
import { t as createLazyImportLoader } from "./lazy-promise-BONnzNfb.js";
import { l as isDiagnosticsEnabled } from "./diagnostic-events-Chmz2PSy.js";
import { i as resolveAgentModelPrimaryValue } from "./model-input-B2zxl6MM.js";
import { x as resolveSubagentModelConfigSelectionResult } from "./agent-scope-MrLta7Pq.js";
import { u as normalizeAgentId } from "./session-key-B_NoIfpX.js";
import { a as resolveAgentDir, c as resolveDefaultAgentId, o as resolveAgentWorkspaceDir, r as resolveAgentConfig } from "./agent-scope-config-CgCYpZfK.js";
import { a as logWarn } from "./logger-lqqYRtFw.js";
import { i as listOpenAIAuthProfileProvidersForAgentRuntime } from "./openai-routing-DXJmS9CT.js";
import { n as resolveAgentHarnessPolicy } from "./harness-runtimes-B7OdBY2U.js";
import { n as DEFAULT_MODEL, r as DEFAULT_PROVIDER } from "./defaults-mDjiWzE5.js";
import { n as isThinkingLevelSupported, o as resolveSupportedThinkingLevel, p as normalizeThinkLevel } from "./thinking-OG7pb4lf.js";
import { _ as selectApplicableRuntimeConfig, i as getRuntimeConfigSnapshot, s as getRuntimeConfigSourceSnapshot } from "./runtime-snapshot-D93_HOsR.js";
import "./config-C9RxTsn1.js";
import { t as clearAgentRunContext } from "./agent-events-C1B8VhOg.js";
import { o as resolveSessionTranscriptPath } from "./paths-NEwU8m3X.js";
import { d as setSessionRuntimeModel } from "./types-D8S_uNvu.js";
import { t as hasAnyAuthProfileStoreSource } from "./source-check-DlvZuh4h.js";
import { d as normalizeModelSelection, g as resolveConfiguredModelRef, v as resolveHooksGmailModel } from "./model-selection-shared-b32cUYts.js";
import { i as resolveAllowedModelRef, r as getModelRefStatus, t as resolveThinkingDefault } from "./model-thinking-default-dIc9T64G.js";
import { h as isCliProvider } from "./model-selection-CA_65iXi.js";
import { n as loadModelCatalog } from "./model-catalog-0-HKr2yW.js";
import { d as ensureAgentWorkspace } from "./workspace-B0bmoo98.js";
import { t as resolveAgentTimeoutMs } from "./timeout-Drw0_zOv.js";
import { i as hasNonzeroUsage, r as deriveSessionTotalTokens } from "./usage-C67Kbb7n.js";
import { d as isCommandLaneTaskTimeoutError } from "./command-queue-DGvXlE4p.js";
import { h as normalizeToolName, p as expandToolGroups } from "./tool-policy-CpBMaMTY.js";
import { n as createCronRunDiagnosticsFromError, r as mergeCronRunDiagnostics, t as createCronRunDiagnosticsFromAgentResult } from "./run-diagnostics-DTgU7PXH.js";
import { u as retireSessionMcpRuntime } from "./agent-bundle-mcp-runtime-Bf36JLIh.js";
import "./agent-bundle-mcp-tools-tGjdbeEf.js";
import { n as resolveSourceDeliveryOutcome, t as createSourceDeliveryPlan } from "./source-delivery-plan-BDfkj2A9.js";
import { n as mapHookExternalContentSource, r as resolveHookExternalContentSource, t as isExternalHookSession } from "./external-content-source-CO610hNP.js";
import { n as resolveCronStyleNow } from "./current-time-D-ClLmMh.js";
import { t as createDiagnosticMessageLifecycle } from "./message-lifecycle-DEcJUFL7.js";
import { n as resolveCronDeliveryPlan, t as hasExplicitCronDeliveryTarget } from "./delivery-plan-DfZrCSUq.js";
import { i as persistCronSkillsSnapshotIfChanged, n as createPersistCronSessionEntry, r as markCronSessionPreRun, s as resolveCronPreflightCandidates, t as adoptCronRunSessionMetadata, u as resolveCronChannelOutputPolicy } from "./run-session-state-D2OnW1-O.js";
import { a as resolveHeartbeatAckMaxChars, i as resolveCronPayloadOutcome, t as isHeartbeatOnlyResponse } from "./helpers-CYQZyDV5.js";
import { t as resolveCronAgentSessionKey } from "./session-key-4BY9Me1I.js";
import { t as resolveCronSession } from "./session-CviofQGc.js";
//#region src/skills/runtime/cron-snapshot.ts
const skillsSnapshotRuntimeLoader = createLazyImportLoader(() => import("./cron-snapshot.runtime.js"));
async function loadSkillsSnapshotRuntime() {
return await skillsSnapshotRuntimeLoader.load();
}
async function resolveCronSkillsSnapshot(params) {
if (params.isFastTestEnv) return params.existingSnapshot ?? {
prompt: "",
skills: []
};
const runtime = await loadSkillsSnapshotRuntime();
const skillFilter = runtime.resolveEffectiveAgentSkillFilter(params.config, params.agentId);
return runtime.resolveReusableWorkspaceSkillSnapshot({
workspaceDir: params.workspaceDir,
config: params.config,
agentId: params.agentId,
existingSnapshot: params.existingSnapshot,
skillFilter,
eligibility: { remote: runtime.getRemoteSkillEligibility({ advertiseExecNode: runtime.canExecRequestNode({
cfg: params.config,
agentId: params.agentId
}) }) },
watch: false,
hydrateExisting: false
}).snapshot;
}
//#endregion
//#region src/cron/isolated-agent/model-selection.ts
function formatAllowedModelRefs(params) {
const configured = params.cfg.agents?.defaults?.models;
if (configured && typeof configured === "object" && Object.keys(configured).length > 0) return Object.keys(configured).toSorted().join(", ");
return "(none configured)";
}
function formatCronPayloadModelRejection(params) {
const { modelOverride, error } = params;
if (error.startsWith("model not allowed:")) return `cron payload.model '${modelOverride}' rejected by agents.defaults.models allowlist: ${error.slice(18).trim()} is not in [${formatAllowedModelRefs({ cfg: params.cfg })}]`;
return `cron payload.model '${modelOverride}' rejected: ${error}`;
}
/** Resolves the effective model for an isolated cron run across defaults, agents, hooks, payload, and session state. */
async function resolveCronModelSelection(params) {
const resolvedDefault = resolveConfiguredModelRef({
cfg: params.cfgWithAgentDefaults,
defaultProvider: DEFAULT_PROVIDER,
defaultModel: DEFAULT_MODEL
});
let provider = resolvedDefault.provider;
let model = resolvedDefault.model;
let modelSource = "default";
let catalog;
const loadCatalogOnce = async () => {
if (!catalog) catalog = await loadModelCatalog({ config: params.cfgWithAgentDefaults });
return catalog;
};
const subagentModelConfigSelection = resolveSubagentModelConfigSelectionResult({
cfg: params.cfg,
agentId: params.agentId,
agentConfigOverride: params.agentConfigOverride
});
const subagentModelRaw = normalizeModelSelection(subagentModelConfigSelection?.raw);
const subagentModelSource = subagentModelConfigSelection?.source === "agent" ? "agent" : "subagent";
if (subagentModelRaw) {
const resolvedSubagent = resolveAllowedModelRef({
cfg: params.cfgWithAgentDefaults,
catalog: await loadCatalogOnce(),
raw: subagentModelRaw,
defaultProvider: resolvedDefault.provider,
defaultModel: resolvedDefault.model
});
if (!("error" in resolvedSubagent)) {
provider = resolvedSubagent.ref.provider;
model = resolvedSubagent.ref.model;
modelSource = subagentModelSource;
}
}
let hooksGmailModelApplied = false;
const hooksGmailModelRef = params.isGmailHook ? resolveHooksGmailModel({
cfg: params.cfg,
defaultProvider: DEFAULT_PROVIDER
}) : null;
if (hooksGmailModelRef) {
if (getModelRefStatus({
cfg: params.cfg,
catalog: await loadCatalogOnce(),
ref: hooksGmailModelRef,
defaultProvider: resolvedDefault.provider,
defaultModel: resolvedDefault.model
}).allowed) {
provider = hooksGmailModelRef.provider;
model = hooksGmailModelRef.model;
hooksGmailModelApplied = true;
modelSource = "hook";
}
}
const modelOverrideRaw = params.payload.kind === "agentTurn" ? params.payload.model : void 0;
const modelOverride = typeof modelOverrideRaw === "string" ? modelOverrideRaw.trim() : void 0;
if (modelOverride !== void 0 && modelOverride.length > 0) {
const resolvedOverride = resolveAllowedModelRef({
cfg: params.cfgWithAgentDefaults,
catalog: await loadCatalogOnce(),
raw: modelOverride,
defaultProvider: resolvedDefault.provider,
defaultModel: resolvedDefault.model
});
if ("error" in resolvedOverride) return {
ok: false,
error: formatCronPayloadModelRejection({
cfg: params.cfgWithAgentDefaults,
modelOverride,
error: resolvedOverride.error
})
};
provider = resolvedOverride.ref.provider;
model = resolvedOverride.ref.model;
modelSource = "payload";
}
if (!modelOverride && !hooksGmailModelApplied) {
const sessionModelOverride = params.sessionEntry.modelOverride?.trim();
if (sessionModelOverride) {
const sessionProviderOverride = params.sessionEntry.providerOverride?.trim() || resolvedDefault.provider;
const resolvedSessionOverride = resolveAllowedModelRef({
cfg: params.cfgWithAgentDefaults,
catalog: await loadCatalogOnce(),
raw: `${sessionProviderOverride}/${sessionModelOverride}`,
defaultProvider: resolvedDefault.provider,
defaultModel: resolvedDefault.model
});
if (!("error" in resolvedSessionOverride)) {
provider = resolvedSessionOverride.ref.provider;
model = resolvedSessionOverride.ref.model;
modelSource = "session";
}
}
}
return {
ok: true,
provider,
model,
modelSource
};
}
//#endregion
//#region src/cron/isolated-agent/run-config.ts
function extractCronAgentDefaultsOverride(agentConfigOverride) {
const { model: overrideModel, sandbox: _agentSandboxOverride, ...agentOverrideRest } = agentConfigOverride ?? {};
return {
overrideModel,
definedOverrides: Object.fromEntries(Object.entries(agentOverrideRest).filter(([, value]) => value !== void 0))
};
}
function mergeCronAgentModelOverride(params) {
const nextDefaults = { ...params.defaults };
const existingModel = nextDefaults.model && typeof nextDefaults.model === "object" ? nextDefaults.model : {};
if (typeof params.overrideModel === "string") nextDefaults.model = {
...existingModel,
primary: params.overrideModel
};
else if (params.overrideModel) nextDefaults.model = {
...existingModel,
...params.overrideModel
};
return nextDefaults;
}
/** Builds the agent defaults snapshot used by isolated cron runs. */
function buildCronAgentDefaultsConfig(params) {
const { overrideModel, definedOverrides } = extractCronAgentDefaultsOverride(params.agentConfigOverride);
return mergeCronAgentModelOverride({
defaults: Object.assign({}, params.defaults, definedOverrides),
overrideModel
});
}
//#endregion
//#region src/cron/isolated-agent/run-timeout.ts
/** Converts cron payload timeout overrides into embedded-runner timeout signals. */
/** Converts explicit cron payload timeoutSeconds into a timer-safe millisecond override signal. */
function resolveCronRunTimeoutOverrideMs(timeoutSeconds) {
return finiteSecondsToTimerSafeMilliseconds(timeoutSeconds);
}
//#endregion
//#region src/cron/isolated-agent/run.ts
/** Orchestrates isolated cron agent turn setup, execution, delivery, and cleanup. */
const sessionStoreRuntimeLoader = createLazyImportLoader(() => import("./store.runtime.js"));
const cronExecutorRuntimeLoader = createLazyImportLoader(() => import("./run-executor.runtime.js"));
const cronExternalContentRuntimeLoader = createLazyImportLoader(() => import("./run-external-content.runtime.js"));
const cronAuthProfileRuntimeLoader = createLazyImportLoader(() => import("./run-auth-profile.runtime.js"));
const cronContextRuntimeLoader = createLazyImportLoader(() => import("./run-context.runtime.js"));
const cronModelCatalogRuntimeLoader = createLazyImportLoader(() => import("./run-model-catalog.runtime.js"));
const cronDeliveryRuntimeLoader = createLazyImportLoader(() => import("./run-delivery.runtime.js"));
const cronModelPreflightRuntimeLoader = createLazyImportLoader(() => import("./model-preflight.runtime.js"));
const runtimePluginsLoader = createLazyImportLoader(() => import("./runtime-plugins.runtime.js"));
async function loadSessionStoreRuntime() {
return await sessionStoreRuntimeLoader.load();
}
async function loadCronExecutorRuntime() {
return await cronExecutorRuntimeLoader.load();
}
async function loadCronExternalContentRuntime() {
return await cronExternalContentRuntimeLoader.load();
}
async function loadCronAuthProfileRuntime() {
return await cronAuthProfileRuntimeLoader.load();
}
async function loadCronContextRuntime() {
return await cronContextRuntimeLoader.load();
}
async function loadCronModelCatalogRuntime() {
return await cronModelCatalogRuntimeLoader.load();
}
async function loadCronDeliveryRuntime() {
return await cronDeliveryRuntimeLoader.load();
}
async function loadCronModelPreflightRuntime() {
return await cronModelPreflightRuntimeLoader.load();
}
async function loadRuntimePlugins() {
return await runtimePluginsLoader.load();
}
function hasConfiguredAuthProfiles(cfg) {
return Boolean(cfg.auth?.profiles && Object.keys(cfg.auth.profiles).length > 0) || Boolean(cfg.auth?.order && Object.keys(cfg.auth.order).length > 0);
}
function resolveNonNegativeNumber(value) {
return typeof value === "number" && Number.isFinite(value) && value >= 0 ? value : void 0;
}
function isCronNestedLaneTaskTimeoutError(err) {
return isCommandLaneTaskTimeoutError(err, "cron-nested");
}
async function retireRolledCronSessionMcpRuntime(params) {
if (params.job.sessionTarget === "isolated") return;
const previousSessionId = normalizeOptionalString(params.cronSession.previousSessionId);
const currentSessionId = normalizeOptionalString(params.cronSession.sessionEntry.sessionId);
if (!previousSessionId || previousSessionId === currentSessionId) return;
await retireSessionMcpRuntime({
sessionId: previousSessionId,
reason: "cron-session-rollover",
onError: (error, sessionId) => {
logWarn(`[cron:${params.job.id}] Failed to dispose retired bundle MCP runtime for session ${sessionId}: ${String(error)}`);
}
});
}
function normalizeCronTraceTarget(target) {
if (!target) return;
return {
...target.channel ? { channel: target.channel } : {},
...target.to !== void 0 ? { to: target.to } : {},
...target.accountId ? { accountId: target.accountId } : {},
...target.threadId !== void 0 ? { threadId: target.threadId } : {},
...target.source ? { source: target.source } : {}
};
}
function normalizeMessagingToolTarget(delivery, resolvedDelivery) {
const { target } = delivery;
const channel = target.provider?.trim();
if (!channel) return;
return {
channel: channel === "message" && resolvedDelivery.ok && delivery.verifiedTarget ? resolvedDelivery.channel : channel,
...target.to ? { to: target.to } : {},
...target.accountId ? { accountId: target.accountId } : {},
...target.threadId ? { threadId: target.threadId } : {}
};
}
function buildResolvedCronTraceTarget(resolvedDelivery) {
if (resolvedDelivery.ok) return {
ok: true,
...normalizeCronTraceTarget({
channel: resolvedDelivery.channel,
to: resolvedDelivery.to,
accountId: resolvedDelivery.accountId,
threadId: resolvedDelivery.threadId,
source: resolvedDelivery.mode === "implicit" ? "last" : "explicit"
})
};
return {
ok: false,
...normalizeCronTraceTarget({
channel: resolvedDelivery.channel,
to: resolvedDelivery.to ?? null,
accountId: resolvedDelivery.accountId,
threadId: resolvedDelivery.threadId,
source: resolvedDelivery.mode === "implicit" ? "last" : "explicit"
}),
error: resolvedDelivery.error.message
};
}
function buildCronDeliveryTrace(params) {
const intended = normalizeCronTraceTarget({
channel: params.deliveryPlan.channel ?? "last",
to: params.deliveryPlan.to ?? null,
accountId: params.deliveryPlan.accountId,
threadId: params.deliveryPlan.threadId,
source: params.deliveryPlan.channel === "last" || !params.deliveryPlan.channel ? "last" : "explicit"
});
const resolved = params.deliveryPlan.mode !== "none" || hasExplicitCronDeliveryTarget(params.deliveryPlan) ? buildResolvedCronTraceTarget(params.resolvedDelivery) : void 0;
const messageToolSentTo = params.sourceDeliveryOutcome.visibleDeliveries.map((delivery) => normalizeMessagingToolTarget(delivery, params.resolvedDelivery)).filter((target) => Boolean(target));
return {
...intended ? { intended } : {},
...resolved ? { resolved } : {},
...messageToolSentTo.length > 0 ? { messageToolSentTo } : {},
fallbackUsed: params.fallbackUsed,
delivered: params.delivered
};
}
function resolveCronSourceDeliveryPlan(params) {
const target = {
channel: params.resolvedDelivery.channel,
to: params.resolvedDelivery.to,
accountId: params.resolvedDelivery.accountId,
threadId: params.resolvedDelivery.threadId
};
if (params.deliveryPlan.mode === "webhook") return createSourceDeliveryPlan({
owner: "none",
reason: "cron_webhook",
messageToolEnabled: false,
directFallback: false
});
if (params.deliveryPlan.mode === "none") return createSourceDeliveryPlan({
owner: "none",
reason: "cron_none",
target,
messageToolEnabled: true,
messageToolForced: false,
directFallback: false
});
return createSourceDeliveryPlan({
owner: "direct_fallback",
reason: "cron_announce",
target,
messageToolEnabled: true,
messageToolForced: false,
directFallback: true,
skipFallbackWhenMessageToolSentToTarget: params.resolvedDelivery.ok
});
}
function canPromptForMessageTool(params) {
if (!params.sourceDelivery.messageTool.enabled) return false;
const normalizedToolsAllow = params.toolsAllow ? expandToolGroups(params.toolsAllow).map((toolName) => normalizeToolName(toolName)) : void 0;
return params.toolsAllow === void 0 || normalizedToolsAllow?.includes("*") === true || normalizedToolsAllow?.includes("message") === true;
}
async function resolveCronDeliveryContext(params) {
const deliveryPlan = resolveCronDeliveryPlan(params.job);
if (deliveryPlan.mode === "webhook") {
const resolvedDelivery = {
ok: false,
channel: void 0,
to: void 0,
accountId: void 0,
threadId: void 0,
mode: "implicit",
error: /* @__PURE__ */ new Error("webhook delivery has no chat target")
};
return {
deliveryPlan,
deliveryRequested: deliveryPlan.requested,
resolvedDelivery,
sourceDelivery: resolveCronSourceDeliveryPlan({
deliveryPlan,
resolvedDelivery
})
};
}
if (deliveryPlan.mode === "none" && !hasExplicitCronDeliveryTarget(deliveryPlan)) {
const resolvedDelivery = {
ok: false,
channel: void 0,
to: void 0,
accountId: void 0,
threadId: void 0,
mode: "implicit",
error: /* @__PURE__ */ new Error("delivery is disabled")
};
return {
deliveryPlan,
deliveryRequested: false,
resolvedDelivery,
sourceDelivery: resolveCronSourceDeliveryPlan({
deliveryPlan,
resolvedDelivery
})
};
}
const { resolveDeliveryTarget } = await loadCronDeliveryRuntime();
const resolvedDelivery = await resolveDeliveryTarget(params.cfg, params.agentId, {
channel: deliveryPlan.channel ?? "last",
to: deliveryPlan.to,
threadId: deliveryPlan.threadId,
accountId: deliveryPlan.accountId,
sessionKey: params.job.sessionKey
});
return {
deliveryPlan,
deliveryRequested: deliveryPlan.requested,
resolvedDelivery,
sourceDelivery: resolveCronSourceDeliveryPlan({
deliveryPlan,
resolvedDelivery
})
};
}
function appendCronDeliveryInstruction(params) {
if (!params.deliveryRequested) return params.commandBody;
if (params.messageToolEnabled) {
const targetHint = params.resolvedDeliveryOk ? "for the current chat" : "with an explicit target";
return `${params.commandBody}\n\nUse the message tool if you need to notify the user directly ${targetHint}. If you do not send directly, your final plain-text reply will be delivered automatically.`.trim();
}
return `${params.commandBody}\n\nReturn your response as plain text; it will be delivered automatically. If the task explicitly calls for messaging a specific external recipient, note who/where it should go instead of sending it yourself.`.trim();
}
function resolvePositiveContextTokens(value) {
return typeof value === "number" && Number.isFinite(value) && value > 0 ? value : void 0;
}
async function loadCliRunnerRuntime() {
return await import("./cli-runner.runtime.js");
}
async function loadUsageFormatRuntime() {
return await import("./usage-format-CCb6QRAg.js");
}
function resolveCronAgentTurnMessage(input) {
if (input.job.payload.kind === "agentTurn") return input.job.payload.message;
return input.message;
}
function resolveCronActiveRuntimeConfig(cfg) {
const runtimeConfig = getRuntimeConfigSnapshot();
const runtimeSourceConfig = getRuntimeConfigSourceSnapshot();
if (!runtimeConfig || !runtimeSourceConfig) return cfg;
return selectApplicableRuntimeConfig({
inputConfig: cfg,
runtimeConfig,
runtimeSourceConfig
}) ?? cfg;
}
async function prepareCronRunContext(params) {
const { input } = params;
const runtimeCfg = resolveCronActiveRuntimeConfig(input.cfg);
const defaultAgentId = resolveDefaultAgentId(runtimeCfg);
const requestedAgentId = typeof input.agentId === "string" && input.agentId.trim() ? input.agentId : typeof input.job.agentId === "string" && input.job.agentId.trim() ? input.job.agentId : void 0;
const normalizedRequested = requestedAgentId ? normalizeAgentId(requestedAgentId) : void 0;
const agentId = normalizedRequested ?? defaultAgentId;
const selectedAgentConfig = resolveAgentConfig(runtimeCfg, agentId);
const agentConfigOverride = normalizedRequested ? selectedAgentConfig : void 0;
const matchesDefaultFallbackAgentStringModel = typeof selectedAgentConfig?.model === "string" && resolveAgentModelPrimaryValue(selectedAgentConfig.model) === resolveAgentModelPrimaryValue(runtimeCfg.agents?.defaults?.model);
const agentCfg = buildCronAgentDefaultsConfig({
defaults: runtimeCfg.agents?.defaults,
agentConfigOverride
});
const cfgWithAgentDefaults = {
...runtimeCfg,
agents: Object.assign({}, runtimeCfg.agents, { defaults: agentCfg })
};
let catalog;
const loadCatalog = async () => {
if (!catalog) catalog = await (await loadCronModelCatalogRuntime()).loadModelCatalog({ config: cfgWithAgentDefaults });
return catalog;
};
const baseSessionKey = (input.sessionKey?.trim() || `cron:${input.job.id}`).trim();
const agentSessionKey = resolveCronAgentSessionKey({
sessionKey: baseSessionKey,
agentId,
mainKey: input.cfg.session?.mainKey,
cfg: input.cfg
});
const hookExternalContentSource = (input.job.payload.kind === "agentTurn" ? input.job.payload.externalContentSource : void 0) ?? resolveHookExternalContentSource(baseSessionKey);
const workspaceDirRaw = resolveAgentWorkspaceDir(input.cfg, agentId);
const agentDir = resolveAgentDir(input.cfg, agentId);
const workspaceDir = (await ensureAgentWorkspace({
dir: workspaceDirRaw,
ensureBootstrapFiles: !agentCfg?.skipBootstrap && !params.isFastTestEnv,
skipOptionalBootstrapFiles: agentCfg?.skipOptionalBootstrapFiles
})).dir;
const { ensureRuntimePluginsLoaded } = await loadRuntimePlugins();
ensureRuntimePluginsLoaded({
config: cfgWithAgentDefaults,
workspaceDir,
allowGatewaySubagentBinding: true
});
const isGmailHook = hookExternalContentSource === "gmail";
const now = Date.now();
const cronSession = resolveCronSession({
cfg: input.cfg,
sessionKey: agentSessionKey,
agentId,
nowMs: now,
forceNew: input.job.sessionTarget === "isolated"
});
const runSessionId = cronSession.sessionEntry.sessionId;
const currentRunSessionId = () => cronSession.sessionEntry.sessionId ?? runSessionId;
if (!cronSession.sessionEntry.sessionFile?.trim()) cronSession.sessionEntry.sessionFile = resolveSessionTranscriptPath(runSessionId, agentId);
const runSessionKey = baseSessionKey.startsWith("cron:") ? `${agentSessionKey}:run:${runSessionId}` : agentSessionKey;
const persistSessionEntry = createPersistCronSessionEntry({
isFastTestEnv: params.isFastTestEnv,
cronSession,
agentSessionKey,
updateSessionStore: async (storePath, update) => {
const { updateSessionStore } = await loadSessionStoreRuntime();
await updateSessionStore(storePath, update);
}
});
const withRunSession = (result) => ({
...result,
sessionId: currentRunSessionId(),
sessionKey: runSessionKey
});
if (!cronSession.sessionEntry.label?.trim() && baseSessionKey.startsWith("cron:")) {
const labelSuffix = typeof input.job.name === "string" && input.job.name.trim() ? input.job.name.trim() : input.job.id;
cronSession.sessionEntry.label = `Cron: ${labelSuffix}`;
}
const resolvedModelSelection = await resolveCronModelSelection({
cfg: input.cfg,
cfgWithAgentDefaults,
agentConfigOverride,
sessionEntry: cronSession.sessionEntry,
payload: input.job.payload,
isGmailHook,
agentId
});
if (!resolvedModelSelection.ok) return {
ok: false,
result: withRunSession({
status: "error",
error: resolvedModelSelection.error,
diagnostics: createCronRunDiagnosticsFromError("cron-preflight", resolvedModelSelection.error)
})
};
let provider = resolvedModelSelection.provider;
let model = resolvedModelSelection.model;
const useSubagentFallbacks = resolvedModelSelection.modelSource === "subagent";
const inheritDefaultFallbacksForAgentStringModel = matchesDefaultFallbackAgentStringModel && (resolvedModelSelection.modelSource === "default" || resolvedModelSelection.modelSource === "agent");
const modelPreflightRuntime = await loadCronModelPreflightRuntime();
const preflightCandidates = resolveCronPreflightCandidates({
cfg: cfgWithAgentDefaults,
job: input.job,
agentId,
provider,
model,
useSubagentFallbacks,
inheritDefaultFallbacksForAgentStringModel
});
let selectedPreflightCandidate;
let selectedPreflightCandidateIndex = -1;
let firstUnavailablePreflight;
for (const [index, candidate] of preflightCandidates.entries()) {
const candidatePreflight = await modelPreflightRuntime.preflightCronModelProvider({
cfg: cfgWithAgentDefaults,
provider: candidate.provider,
model: candidate.model
});
if (candidatePreflight.status === "available") {
selectedPreflightCandidate = candidate;
selectedPreflightCandidateIndex = index;
break;
}
firstUnavailablePreflight ??= candidatePreflight;
}
if (!selectedPreflightCandidate && firstUnavailablePreflight?.status === "unavailable") {
logWarn(`[cron:${input.job.id}] ${firstUnavailablePreflight.reason}`);
return {
ok: false,
result: withRunSession({
status: "skipped",
error: firstUnavailablePreflight.reason,
diagnostics: createCronRunDiagnosticsFromError("model-preflight", firstUnavailablePreflight.reason, { severity: "warn" }),
provider,
model
})
};
}
const modelFallbacksOverride = selectedPreflightCandidate && (selectedPreflightCandidate.provider !== provider || selectedPreflightCandidate.model !== model) ? preflightCandidates.slice(selectedPreflightCandidateIndex + 1).map((candidate) => `${candidate.provider}/${candidate.model}`) : void 0;
if (selectedPreflightCandidate && modelFallbacksOverride) {
if (firstUnavailablePreflight?.status === "unavailable") logWarn(`[cron:${input.job.id}] Local provider preflight failed for ${firstUnavailablePreflight.provider}/${firstUnavailablePreflight.model} at ${firstUnavailablePreflight.baseUrl}; continuing with fallback ${selectedPreflightCandidate.provider}/${selectedPreflightCandidate.model}.`);
provider = selectedPreflightCandidate.provider;
model = selectedPreflightCandidate.model;
}
const hooksGmailThinking = isGmailHook ? normalizeThinkLevel(input.cfg.hooks?.gmail?.thinking) : void 0;
let thinkLevel = normalizeThinkLevel((input.job.payload.kind === "agentTurn" ? input.job.payload.thinking : void 0) ?? void 0) ?? hooksGmailThinking;
if (!thinkLevel) {
const thinkingCatalog = await loadCatalog();
thinkLevel = resolveThinkingDefault({
cfg: cfgWithAgentDefaults,
provider,
model,
catalog: thinkingCatalog
});
}
const thinkingCatalog = await loadCatalog();
if (!isThinkingLevelSupported({
provider,
model,
level: thinkLevel,
catalog: thinkingCatalog
})) {
const fallbackThinkLevel = resolveSupportedThinkingLevel({
provider,
model,
level: thinkLevel,
catalog: thinkingCatalog
});
if (fallbackThinkLevel !== thinkLevel) {
logWarn(`[cron:${input.job.id}] Thinking level "${thinkLevel}" is not supported for ${provider}/${model}; downgrading to "${fallbackThinkLevel}".`);
thinkLevel = fallbackThinkLevel;
}
}
const explicitTimeoutSeconds = input.job.payload.kind === "agentTurn" ? input.job.payload.timeoutSeconds : void 0;
const timeoutMs = resolveAgentTimeoutMs({
cfg: cfgWithAgentDefaults,
overrideSeconds: explicitTimeoutSeconds
});
const runTimeoutOverrideMs = resolveCronRunTimeoutOverrideMs(explicitTimeoutSeconds);
const agentPayload = input.job.payload.kind === "agentTurn" ? input.job.payload : null;
const { deliveryPlan, deliveryRequested, resolvedDelivery, sourceDelivery } = await resolveCronDeliveryContext({
cfg: cfgWithAgentDefaults,
job: input.job,
agentId
});
const { formattedTime, timeLine } = resolveCronStyleNow(input.cfg, now);
const message = resolveCronAgentTurnMessage(input);
const base = `[cron:${input.job.id} ${input.job.name}] ${message}`.trim();
const isExternalHook = hookExternalContentSource !== void 0 || isExternalHookSession(baseSessionKey);
const allowUnsafeExternalContent = agentPayload?.allowUnsafeExternalContent === true || isGmailHook && input.cfg.hooks?.gmail?.allowUnsafeExternalContent === true;
const shouldWrapExternal = isExternalHook && !allowUnsafeExternalContent;
let commandBody;
if (isExternalHook) {
const { detectSuspiciousPatterns } = await loadCronExternalContentRuntime();
const suspiciousPatterns = detectSuspiciousPatterns(message);
if (suspiciousPatterns.length > 0) logWarn(`[security] Suspicious patterns detected in external hook content (session=${baseSessionKey}, patterns=${suspiciousPatterns.length}): ${suspiciousPatterns.slice(0, 3).join(", ")}`);
}
if (shouldWrapExternal) {
const { buildSafeExternalPrompt } = await loadCronExternalContentRuntime();
commandBody = `${buildSafeExternalPrompt({
content: message,
source: mapHookExternalContentSource(hookExternalContentSource ?? "webhook"),
jobName: input.job.name,
jobId: input.job.id,
timestamp: formattedTime
})}\n\n${timeLine}`.trim();
} else commandBody = `${base}\n${timeLine}`.trim();
commandBody = appendCronDeliveryInstruction({
commandBody,
deliveryRequested,
messageToolEnabled: canPromptForMessageTool({
sourceDelivery,
toolsAllow: agentPayload?.toolsAllow
}),
resolvedDeliveryOk: resolvedDelivery.ok
});
const skillsSnapshot = await resolveCronSkillsSnapshot({
workspaceDir,
config: cfgWithAgentDefaults,
agentId,
existingSnapshot: cronSession.sessionEntry.skillsSnapshot,
isFastTestEnv: params.isFastTestEnv
});
await persistCronSkillsSnapshotIfChanged({
isFastTestEnv: params.isFastTestEnv,
cronSession,
skillsSnapshot,
nowMs: Date.now(),
persistSessionEntry
});
markCronSessionPreRun({
entry: cronSession.sessionEntry,
provider,
model
});
try {
await persistSessionEntry();
} catch (err) {
logWarn(`[cron:${input.job.id}] Failed to persist pre-run session entry: ${String(err)}`);
}
await retireRolledCronSessionMcpRuntime({
job: input.job,
cronSession
});
const authProfileId = !Boolean(cronSession.sessionEntry.authProfileOverride?.trim()) && !hasConfiguredAuthProfiles(cfgWithAgentDefaults) && !hasAnyAuthProfileStoreSource(agentDir) ? void 0 : await (await loadCronAuthProfileRuntime()).resolveSessionAuthProfileOverride({
cfg: cfgWithAgentDefaults,
provider,
acceptedProviderIds: listOpenAIAuthProfileProvidersForAgentRuntime({
provider,
harnessRuntime: resolveAgentHarnessPolicy({
provider,
modelId: model,
config: cfgWithAgentDefaults,
agentId,
sessionKey: agentSessionKey
}).runtime,
config: cfgWithAgentDefaults
}),
agentDir,
sessionEntry: cronSession.sessionEntry,
sessionStore: cronSession.store,
sessionKey: agentSessionKey,
storePath: cronSession.storePath,
isNewSession: cronSession.isNewSession && input.job.sessionTarget !== "isolated"
});
const liveSelection = {
provider,
model,
authProfileId,
authProfileIdSource: authProfileId ? cronSession.sessionEntry.authProfileOverrideSource : void 0
};
return {
ok: true,
context: {
input,
cfgWithAgentDefaults,
agentId,
agentCfg,
agentDir,
agentSessionKey,
runSessionId,
currentRunSessionId,
runSessionKey,
workspaceDir,
commandBody,
cronSession,
persistSessionEntry,
withRunSession,
agentPayload,
deliveryPlan,
resolvedDelivery,
deliveryRequested,
sourceDelivery,
suppressExecNotifyOnExit: deliveryPlan.mode === "none",
skillsSnapshot,
liveSelection,
useSubagentFallbacks,
inheritDefaultFallbacksForAgentStringModel,
modelFallbacksOverride,
thinkLevel,
timeoutMs,
runTimeoutOverrideMs
}
};
}
async function finalizeCronRun(params) {
const { prepared, execution } = params;
const finalRunResult = execution.runResult;
const payloads = finalRunResult.payloads ?? [];
let telemetry;
if (finalRunResult.meta?.systemPromptReport) prepared.cronSession.sessionEntry.systemPromptReport = finalRunResult.meta.systemPromptReport;
adoptCronRunSessionMetadata({
entry: prepared.cronSession.sessionEntry,
sessionKey: prepared.agentSessionKey,
runMeta: finalRunResult.meta?.agentMeta
});
const usage = finalRunResult.meta?.agentMeta?.usage;
const lastCallUsage = finalRunResult.meta?.agentMeta?.lastCallUsage;
const promptTokens = finalRunResult.meta?.agentMeta?.promptTokens;
const modelUsed = finalRunResult.meta?.agentMeta?.model ?? execution.fallbackModel ?? execution.liveSelection.model;
const providerUsed = finalRunResult.meta?.agentMeta?.provider ?? execution.fallbackProvider ?? execution.liveSelection.provider;
const contextTokens = resolvePositiveContextTokens(prepared.agentCfg?.contextTokens) ?? (await loadCronContextRuntime()).lookupContextTokens(modelUsed, { allowAsyncLoad: false }) ?? resolvePositiveContextTokens(prepared.cronSession.sessionEntry.contextTokens) ?? 2e5;
setSessionRuntimeModel(prepared.cronSession.sessionEntry, {
provider: providerUsed,
model: modelUsed
});
prepared.cronSession.sessionEntry.contextTokens = contextTokens;
if (isCliProvider(providerUsed, prepared.cfgWithAgentDefaults)) {
const cliSessionId = finalRunResult.meta?.agentMeta?.sessionId?.trim();
if (finalRunResult.meta?.agentMeta?.clearCliSessionBinding === true) {
const { clearCliSession } = await loadCliRunnerRuntime();
clearCliSession(prepared.cronSession.sessionEntry, providerUsed);
} else if (cliSessionId) {
const { setCliSessionId } = await loadCliRunnerRuntime();
setCliSessionId(prepared.cronSession.sessionEntry, providerUsed, cliSessionId);
}
}
if (hasNonzeroUsage(usage)) {
const { estimateUsageCost, resolveModelCostConfig } = await loadUsageFormatRuntime();
const input = usage.input ?? 0;
const output = usage.output ?? 0;
const lastCallTotalTokens = deriveSessionTotalTokens({
usage: lastCallUsage,
contextTokens,
promptTokens
});
const totalTokens = typeof lastCallTotalTokens === "number" && lastCallTotalTokens > 0 ? lastCallTotalTokens : deriveSessionTotalTokens({
usage,
contextTokens,
promptTokens
});
const runEstimatedCostUsd = resolveNonNegativeNumber(estimateUsageCost({
usage,
cost: resolveModelCostConfig({
provider: providerUsed,
model: modelUsed,
config: prepared.cfgWithAgentDefaults
})
}));
prepared.cronSession.sessionEntry.inputTokens = input;
prepared.cronSession.sessionEntry.outputTokens = output;
const telemetryUsage = {
input_tokens: input,
output_tokens: output
};
const aggregateTotalTokens = input + output + (usage.cacheRead ?? 0) + (usage.cacheWrite ?? 0);
if (aggregateTotalTokens > 0) telemetryUsage.total_tokens = aggregateTotalTokens;
if (typeof totalTokens === "number" && Number.isFinite(totalTokens) && totalTokens > 0) {
prepared.cronSession.sessionEntry.totalTokens = totalTokens;
prepared.cronSession.sessionEntry.totalTokensFresh = true;
} else {
prepared.cronSession.sessionEntry.totalTokens = void 0;
prepared.cronSession.sessionEntry.totalTokensFresh = false;
}
prepared.cronSession.sessionEntry.cacheRead = usage.cacheRead ?? 0;
prepared.cronSession.sessionEntry.cacheWrite = usage.cacheWrite ?? 0;
if (runEstimatedCostUsd !== void 0) prepared.cronSession.sessionEntry.estimatedCostUsd = runEstimatedCostUsd;
telemetry = {
model: modelUsed,
provider: providerUsed,
usage: telemetryUsage
};
} else telemetry = {
model: modelUsed,
provider: providerUsed
};
await prepared.persistSessionEntry();
if (params.isAborted()) return prepared.withRunSession({
status: "error",
error: params.abortReason(),
diagnostics: mergeCronRunDiagnostics(createCronRunDiagnosticsFromAgentResult(finalRunResult, { finalStatus: "error" }), createCronRunDiagnosticsFromError("cron-setup", params.abortReason())),
...telemetry
});
const cronPayloadOutcome = resolveCronPayloadOutcome({
payloads,
runLevelError: finalRunResult.meta?.error,
failureSignal: finalRunResult.meta?.failureSignal,
finalAssistantVisibleText: finalRunResult.meta?.finalAssistantVisibleText,
preferFinalAssistantVisibleText: (await resolveCronChannelOutputPolicy(prepared.resolvedDelivery.channel, { deliveryRequested: prepared.deliveryRequested })).preferFinalAssistantVisibleText
});
const { synthesizedText, deliveryPayloads, deliveryPayloadHasStructuredContent, hasFatalStructuredErrorPayload, pendingPresentationWarningError } = cronPayloadOutcome;
let { summary, outputText, hasFatalErrorPayload, embeddedRunError } = cronPayloadOutcome;
const agentDiagnostics = createCronRunDiagnosticsFromAgentResult(finalRunResult, { finalStatus: hasFatalErrorPayload ? "error" : "ok" });
const resolveRunOutcome = (result) => prepared.withRunSession({
status: hasFatalErrorPayload ? "error" : "ok",
...hasFatalErrorPayload ? { error: embeddedRunError ?? "cron isolated run returned an error payload" } : {},
summary,
outputText,
delivered: result?.delivered,
deliveryAttempted: result?.deliveryAttempted,
delivery: result?.delivery,
diagnostics: hasFatalErrorPayload ? mergeCronRunDiagnostics(agentDiagnostics, createCronRunDiagnosticsFromError("agent-run", embeddedRunError ?? "cron isolated run returned an error payload")) : agentDiagnostics,
...telemetry
});
const failPendingPresentationWarningUnlessDelivered = (delivered) => {
if (pendingPresentationWarningError && delivered !== true) {
hasFatalErrorPayload = true;
embeddedRunError = pendingPresentationWarningError;
}
};
const skipHeartbeatDelivery = prepared.deliveryRequested && !hasFatalErrorPayload && isHeartbeatOnlyResponse(deliveryPayloads, resolveHeartbeatAckMaxChars(prepared.agentCfg));
const sourceDeliveryOutcome = resolveSourceDeliveryOutcome(prepared.sourceDelivery, {
didSendViaMessageTool: finalRunResult.didSendViaMessagingTool,
messageToolSentTargets: finalRunResult.messagingToolSentTargets
});
if (hasFatalStructuredErrorPayload && prepared.deliveryRequested) {
const { cleanupDirectCronSession } = await loadCronDeliveryRuntime();
await cleanupDirectCronSession({
job: prepared.input.job,
agentSessionKey: prepared.agentSessionKey,
sessionId: prepared.currentRunSessionId(),
retireReason: "cron-delete-after-run-fatal-error"
});
const deliveryTrace = buildCronDeliveryTrace({
deliveryPlan: prepared.deliveryPlan,
resolvedDelivery: prepared.resolvedDelivery,
sourceDeliveryOutcome,
fallbackUsed: false,
delivered: sourceDeliveryOutcome.verifiedMessageToolDelivery
});
return resolveRunOutcome({
delivered: sourceDeliveryOutcome.verifiedMessageToolDelivery,
deliveryAttempted: sourceDeliveryOutcome.verifiedMessageToolDelivery,
delivery: deliveryTrace
});
}
const { dispatchCronDelivery, resolveCronDeliveryBestEffort } = await loadCronDeliveryRuntime();
const deliveryResult = await dispatchCronDelivery({
cfg: prepared.input.cfg,
cfgWithAgentDefaults: prepared.cfgWithAgentDefaults,
deps: prepared.input.deps,
job: prepared.input.job,
agentId: prepared.agentId,
agentSessionKey: prepared.agentSessionKey,
runSessionKey: prepared.runSessionKey,
sessionId: prepared.currentRunSessionId(),
runStartedAt: execution.runStartedAt,
runEndedAt: execution.runEndedAt,
timeoutMs: prepared.timeoutMs,
resolvedDelivery: prepared.resolvedDelivery,
deliveryRequested: prepared.deliveryRequested,
skipHeartbeatDelivery,
sourceDeliveryOutcome,
deliveryBestEffort: resolveCronDeliveryBestEffort(prepared.input.job),
deliveryPayloadHasStructuredContent,
deliveryPayloads,
synthesizedText,
ttsAuto: prepared.cronSession.sessionEntry.ttsAuto,
summary,
outputText,
telemetry,
abortSignal: prepared.input.abortSignal ?? prepared.input.signal,
isAborted: params.isAborted,
abortReason: params.abortReason,
withRunSession: prepared.withRunSession
});
const deliveryTrace = buildCronDeliveryTrace({
deliveryPlan: prepared.deliveryPlan,
resolvedDelivery: prepared.resolvedDelivery,
sourceDeliveryOutcome,
fallbackUsed: prepared.deliveryRequested && deliveryResult.deliveryAttempted && !sourceDeliveryOutcome.satisfiesSourceDelivery,
delivered: deliveryResult.delivered
});
if (deliveryResult.result) {
const resultWithDeliveryMeta = {
...deliveryResult.result,
deliveryAttempted: deliveryResult.result.deliveryAttempted ?? deliveryResult.deliveryAttempted,
delivery: deliveryTrace,
diagnostics: mergeCronRunDiagnostics(agentDiagnostics, deliveryResult.result.diagnostics, deliveryResult.result.status === "error" && deliveryResult.result.error ? createCronRunDiagnosticsFromError("delivery", deliveryResult.result.error) : void 0)
};
failPendingPresentationWarningUnlessDelivered(resultWithDeliveryMeta.delivered ?? deliveryResult.delivered);
if (!hasFatalErrorPayload || deliveryResult.result.status !== "ok") return resultWithDeliveryMeta;
return resolveRunOutcome({
delivered: deliveryResult.result.delivered,
deliveryAttempted: resultWithDeliveryMeta.deliveryAttempted,
delivery: deliveryTrace
});
}
summary = deliveryResult.summary;
outputText = deliveryResult.outputText;
failPendingPresentationWarningUnlessDelivered(deliveryResult.delivered);
return resolveRunOutcome({
delivered: deliveryResult.delivered,
deliveryAttempted: deliveryResult.deliveryAttempted,
delivery: deliveryTrace
});
}
/**
* Release runtime references held by a completed isolated cron run.
*
* After the final durable write and delivery complete, the cron session store
* and run context are no longer needed in memory. This shallow disposal prevents
* the heap-retention pattern described in #85019 where ~113k copies of the skill
* prompt string accumulated through cron run contexts that were never released.
*
* O(1) — nulls known large fields without deep traversal. MUST run after the
* final `persistSessionEntry()` and delivery construction, never before.
*/
async function disposeCronRunContext(params) {
if (params.ownsRunContext) {
clearAgentRunContext(params.sessionId);
await retireSessionMcpRuntime({
sessionId: params.sessionId,
reason: "isolated-cron-dispose",
onError: (error, sid) => {
logWarn(`[cron] Failed to retire MCP runtime during isolated cron dispose ${sid}: ${String(error)}`);
}
}).catch(() => {});
}
params.cronSession.store = void 0;
}
/** Runs one isolated cron agent turn, including setup, execution, delivery, and persistence. */
async function runCronIsolatedAgentTurn(params) {
const abortSignal = params.abortSignal ?? params.signal;
const isAborted = () => abortSignal?.aborted === true;
const abortReason = () => {
const reason = abortSignal?.reason;
return typeof reason === "string" && reason.trim() ? reason.trim() : "cron: job execution timed out";
};
const prepared = await prepareCronRunContext({
input: params,
isFastTestEnv: process.env.OPENCLAW_TEST_FAST === "1"
});
if (!prepared.ok) return prepared.result;
const notifyExecutionStarted = () => params.onExecutionStarted?.({
jobId: params.job.id,
agentId: prepared.context.agentId,
sessionId: prepared.context.currentRunSessionId(),
sessionKey: prepared.context.runSessionKey,
phase: "runner_entered",
provider: prepared.context.liveSelection.provider,
model: prepared.context.liveSelection.model
});
const notifyExecutionPhase = (info) => {
params.onExecutionPhase?.({
jobId: params.job.id,
agentId: prepared.context.agentId,
sessionId: prepared.context.currentRunSessionId(),
sessionKey: prepared.context.runSessionKey,
provider: prepared.context.liveSelection.provider,
model: prepared.context.liveSelection.model,
...info
});
};
const initialSessionId = prepared.context.cronSession.sessionEntry.sessionId;
const turnStartedAtMs = Date.now();
const messageLifecycle = createDiagnosticMessageLifecycle({
enabled: isDiagnosticsEnabled(params.cfg),
sessionId: prepared.context.runSessionId,
sessionKey: prepared.context.runSessionKey,
channel: "cron",
source: "cron-isolated",
startedAtMs: turnStartedAtMs,
trackSessionState: true
});
messageLifecycle.markProcessing();
let outcome = "completed";
let outcomeError;
try {
const { executeCronRun } = await loadCronExecutorRuntime();
const execution = await executeCronRun({
cfg: params.cfg,
cfgWithAgentDefaults: prepared.context.cfgWithAgentDefaults,
job: params.job,
agentId: prepared.context.agentId,
agentDir: prepared.context.agentDir,
agentSessionKey: prepared.context.agentSessionKey,
runSessionKey: prepared.context.runSessionKey,
workspaceDir: prepared.context.workspaceDir,
lane: params.lane,
resolvedDelivery: {
channel: prepared.context.resolvedDelivery.channel,
to: prepared.context.resolvedDelivery.to,
accountId: prepared.context.resolvedDelivery.accountId,
threadId: prepared.context.resolvedDelivery.threadId
},
deliveryRequested: prepared.context.deliveryRequested,
sourceDelivery: prepared.context.sourceDelivery,
skillsSnapshot: prepared.context.skillsSnapshot,
agentPayload: prepared.context.agentPayload,
useSubagentFallbacks: prepared.context.useSubagentFallbacks,
inheritDefaultFallbacksForAgentStringModel: prepared.context.inheritDefaultFallbacksForAgentStringModel,
modelFallbacksOverride: prepared.context.modelFallbacksOverride,
agentVerboseDefault: prepared.context.agentCfg?.verboseDefault,
liveSelection: prepared.context.liveSelection,
cronSession: prepared.context.cronSession,
commandBody: prepared.context.commandBody,
persistSessionEntry: prepared.context.persistSessionEntry,
abortSignal,
onExecutionStarted: notifyExecutionStarted,
onExecutionPhase: notifyExecutionPhase,
abortReason,
isAborted,
thinkLevel: prepared.context.thinkLevel,
timeoutMs: prepared.context.timeoutMs,
runTimeoutOverrideMs: prepared.context.runTimeoutOverrideMs,
suppressExecNotifyOnExit: prepared.context.suppressExecNotifyOnExit
});
if (isAborted()) {
outcome = "error";
outcomeError = abortReason();
return prepared.context.withRunSession({
status: "error",
error: abortReason(),
diagnostics: createCronRunDiagnosticsFromError("cron-setup", abortReason())
});
}
const finalized = await finalizeCronRun({
prepared: prepared.context,
execution,
abortReason,
isAborted
});
if (finalized.status === "error") {
outcome = "error";
outcomeError = finalized.error;
}
return finalized;
} catch (err) {
const isCronLaneTimeout = isAborted() || isCronNestedLaneTaskTimeoutError(err);
const error = isCronLaneTimeout ? abortReason() : String(err);
outcome = "error";
outcomeError = error;
return prepared.context.withRunSession({
status: "error",
error,
diagnostics: createCronRunDiagnosticsFromError(isCronLaneTimeout ? "cron-setup" : "agent-run", isCronLaneTimeout ? error : err)
});
} finally {
const finalSessionRef = {
sessionId: prepared.context.currentRunSessionId(),
sessionKey: prepared.context.runSessionKey
};
messageLifecycle.markIdle(void 0, finalSessionRef);
messageLifecycle.markProcessed(outcome, {
...finalSessionRef,
error: outcomeError
});
await disposeCronRunContext({
sessionId: initialSessionId,
cronSession: prepared.context.cronSession,
ownsRunContext: params.job.sessionTarget === "isolated"
});
}
}
//#endregion
export { runCronIsolatedAgentTurn as t };