fix(status): keep default JSON scan lean

Default `openclaw status --json` stays on the lean health-probe path while preserving the JSON task summary, local update/install metadata, explicit probe timeouts, and configured gateway handshake timeouts. Deeper memory, registry, remote git, and local status-RPC diagnostics remain behind `status --json --all`.

Also keeps generated diffs viewer output in its built form and ignores it in oxfmt so `pnpm build` leaves a clean tree.

Proof:
- `node scripts/run-vitest.mjs src/commands/status.scan.fast-json.test.ts src/commands/status-json-payload.test.ts src/commands/status.scan.shared.test.ts`
- `OPENCLAW_LOCAL_CHECK=0 node scripts/run-oxlint-shards.mjs --threads=8`
- `node scripts/run-tsgo.mjs -p test/tsconfig/tsconfig.core.test.json --incremental --tsBuildInfoFile .artifacts/tsgo-cache/core-test.tsbuildinfo`
- `node scripts/run-tsgo.mjs -p test/tsconfig/tsconfig.extensions.test.json --incremental --tsBuildInfoFile .artifacts/tsgo-cache/extensions-test.tsbuildinfo`
- `.agents/skills/autoreview/scripts/autoreview --mode branch --base origin/main`
- GitHub checks green for head `47a63f87ea7c2351994fdb71e8cc18041aa0b64e`

Thanks @andyylin.

Co-authored-by: Andy <andyylin@users.noreply.github.com>
This commit is contained in:
Andy
2026-05-28 09:28:49 +08:00
committed by GitHub
parent 5846878924
commit d2319d718c
15 changed files with 233 additions and 17397 deletions

View File

@@ -30,6 +30,7 @@
"docker-compose.yml",
"dist/",
"docs/_layouts/",
"extensions/diffs/assets/viewer-runtime.js",
"**/*.json",
"node_modules/",
"patches/",

File diff suppressed because one or more lines are too long

View File

@@ -237,8 +237,8 @@ vi.mock("openclaw/plugin-sdk/reply-runtime", () => ({
deliver: (payload: unknown, info: { kind: "block" | "final" }) => Promise<void> | void;
onError?: (err: unknown, info: { kind: "block" | "final" }) => void;
transformReplyPayload?: (payload: ReplyPayload) => ReplyPayload | null;
onSettled?: () => Promise<unknown> | unknown;
onFreshSettledDelivery?: () => Promise<unknown> | unknown;
onSettled?: () => unknown;
onFreshSettledDelivery?: () => unknown;
};
ctx?: unknown;
replyOptions?: DispatchInboundParams["replyOptions"];

View File

@@ -177,7 +177,10 @@ describe("sendMessage", () => {
await settleTimers(sendMessage("https://nas.example.com/incoming", "Hello", "42abc"));
const request = vi.mocked(https.request).mock.results[0]?.value as ClientRequest | undefined;
const body = vi.mocked(request?.write).mock.calls[0]?.[0];
if (!request) {
throw new Error("expected Synology Chat webhook request");
}
const body = vi.mocked(request.write).mock.calls[0]?.[0];
if (typeof body !== "string") {
throw new Error("expected Synology Chat webhook body");
}

View File

@@ -373,7 +373,9 @@ describe("TwilioProvider", () => {
const event = provider.parseWebhookEvent(ctx).events[0];
const parsed = requireEvent(event, "expected speech event from Twilio webhook");
expect(parsed.type).toBe("call.speech");
if (parsed.type !== "call.speech") {
throw new Error("expected speech event from Twilio webhook");
}
expect(parsed.confidence).toBe(0.9);
});

View File

@@ -13,6 +13,8 @@ import {
import { loadStatusScanCommandConfig } from "./status.scan.config-shared.js";
import type { GatewayProbeSnapshot } from "./status.scan.shared.js";
type StatusGatewayProbeTimeoutResolver = (cfg: OpenClawConfig) => number | undefined;
const statusScanDepsRuntimeModuleLoader = createLazyImportLoader(
() => import("./status.scan.deps.runtime.js"),
);
@@ -144,6 +146,8 @@ export async function collectStatusScanOverview(params: {
) => boolean | Promise<boolean>;
includeChannelsData?: boolean;
includeLiveChannelStatus?: boolean;
includeLocalStatusRpcFallback?: boolean;
gatewayProbeTimeoutMs?: number | StatusGatewayProbeTimeoutResolver;
includeChannelSetupRuntimeFallback?: boolean;
channelCredentialResolutionSkipped?: boolean;
useGatewayCallOverridesForChannelsStatus?: boolean;
@@ -203,6 +207,10 @@ export async function collectStatusScanOverview(params: {
}),
);
const osSummary = resolveOsSummary();
const gatewayProbeTimeoutMs =
typeof params.gatewayProbeTimeoutMs === "function"
? params.gatewayProbeTimeoutMs(cfg)
: params.gatewayProbeTimeoutMs;
const bootstrap = await createStatusScanCoreBootstrap<
Awaited<ReturnType<typeof getAgentLocalStatusesFn>>
>({
@@ -213,6 +221,8 @@ export async function collectStatusScanOverview(params: {
skipUpdateCheck: params.skipUpdateCheck,
fetchGitUpdate: params.fetchGitUpdate,
includeRegistryUpdate: params.includeRegistryUpdate,
includeLocalStatusRpcFallback: params.includeLocalStatusRpcFallback,
gatewayProbeTimeoutMs,
getTailnetHostname: async (runner) =>
await loadStatusScanDepsRuntimeModule().then(({ getTailnetHostname }) =>
getTailnetHostname(runner),

View File

@@ -65,6 +65,8 @@ type StatusScanCoreBootstrapParams<TAgentStatus> = {
skipUpdateCheck?: boolean;
fetchGitUpdate?: boolean;
includeRegistryUpdate?: boolean;
includeLocalStatusRpcFallback?: boolean;
gatewayProbeTimeoutMs?: number;
getTailnetHostname: (runner: StatusScanExecRunner) => Promise<string | null>;
getUpdateCheckResult: (params: {
timeoutMs: number;
@@ -84,13 +86,15 @@ export async function createStatusScanCoreBootstrap<TAgentStatus>(
hasConfiguredChannels: params.hasConfiguredChannels,
all: params.opts.all,
});
const updateTimeoutMs = params.opts.all ? 6500 : 2500;
const statusTimeoutMs = params.opts.timeoutMs ?? 10_000;
const updateTimeoutMs = Math.min(params.opts.all ? 6500 : 2500, statusTimeoutMs);
const tailscaleTimeoutMs = Math.min(1200, statusTimeoutMs);
const tailscaleDnsPromise =
tailscaleMode === "off"
? Promise.resolve<string | null>(null)
: params
.getTailnetHostname((cmd, args) =>
runExec(cmd, args, { timeoutMs: 1200, maxBuffer: 200_000 }),
runExec(cmd, args, { timeoutMs: tailscaleTimeoutMs, maxBuffer: 200_000 }),
)
.catch(() => null);
const skipNetworkUpdate = skipColdStartNetworkChecks || params.skipUpdateCheck === true;
@@ -109,7 +113,11 @@ export async function createStatusScanCoreBootstrap<TAgentStatus>(
cfg: params.cfg,
opts: {
...params.opts,
...(params.gatewayProbeTimeoutMs !== undefined
? { timeoutMs: params.gatewayProbeTimeoutMs }
: {}),
...(skipColdStartNetworkChecks ? { skipProbe: true } : {}),
localStatusRpcFallback: params.includeLocalStatusRpcFallback !== false,
},
});

View File

@@ -11,6 +11,7 @@ import {
const mocks = {
...createStatusScanSharedMocks("status-fast-json"),
callGateway: vi.fn(),
getStatusCommandSecretTargetIds: vi.fn(() => []),
resolveMemorySearchConfig: vi.fn(),
};
@@ -112,6 +113,85 @@ describe("scanStatusJsonFast", () => {
expect(mocks.buildPluginCompatibilityNotices).not.toHaveBeenCalled();
});
it("keeps default fast JSON update scans local-only", async () => {
mocks.hasPotentialConfiguredChannels.mockReturnValue(true);
await scanStatusJsonFast({ timeoutMs: 1234 }, {} as never);
expect(mocks.getUpdateCheckResult).toHaveBeenCalledWith(
expect.objectContaining({
timeoutMs: 1234,
fetchGit: false,
includeRegistry: false,
}),
);
});
it("restores registry-backed update checks and remote git fetches when --all is requested", async () => {
mocks.hasPotentialConfiguredChannels.mockReturnValue(true);
await scanStatusJsonFast({ all: true }, {} as never);
expect(mocks.getUpdateCheckResult).toHaveBeenCalledWith(
expect.objectContaining({
timeoutMs: 6500,
fetchGit: true,
includeRegistry: true,
}),
);
});
it("keeps the local status RPC fallback off the default fast JSON path", async () => {
mocks.hasPotentialConfiguredChannels.mockReturnValue(true);
mocks.callGateway.mockResolvedValue({ sessions: 1 });
await scanStatusJsonFast({}, {} as never);
expect(mocks.probeGateway).toHaveBeenCalledWith(expect.objectContaining({ timeoutMs: 1000 }));
expect(mocks.callGateway).not.toHaveBeenCalled();
});
it("honors explicit gateway probe timeouts on the lean JSON path", async () => {
mocks.hasPotentialConfiguredChannels.mockReturnValue(true);
await scanStatusJsonFast({ timeoutMs: 5000 }, {} as never);
expect(mocks.probeGateway).toHaveBeenCalledWith(expect.objectContaining({ timeoutMs: 5000 }));
});
it("keeps configured gateway handshake timeouts on the lean JSON path", async () => {
mocks.hasPotentialConfiguredChannels.mockReturnValue(true);
applyStatusScanDefaults(mocks, {
resolvedConfig: {
...createStatusMemorySearchConfig(),
gateway: { handshakeTimeoutMs: 30_000 },
} as never,
});
await scanStatusJsonFast({}, {} as never);
expect(mocks.probeGateway).toHaveBeenCalledWith(
expect.objectContaining({
preauthHandshakeTimeoutMs: 30_000,
timeoutMs: 30_000,
}),
);
});
it("restores the local status RPC fallback when --all is requested", async () => {
mocks.hasPotentialConfiguredChannels.mockReturnValue(true);
mocks.callGateway.mockResolvedValue({ sessions: 1 });
await scanStatusJsonFast({ all: true }, {} as never);
expect(mocks.callGateway).toHaveBeenCalledWith(
expect.objectContaining({
method: "status",
timeoutMs: 2000,
}),
);
});
it("keeps the fast JSON summary off the channel plugin summary path", async () => {
mocks.hasPotentialConfiguredChannels.mockReturnValue(true);
@@ -171,7 +251,7 @@ describe("scanStatusJsonFast", () => {
expect(mocks.probeGateway).not.toHaveBeenCalled();
});
it("keeps cold-start probes when a channel is configured from manifest env vars", async () => {
it("keeps cold-start gateway probes with local-only updates when a channel is configured from manifest env vars", async () => {
await withTemporaryEnv(
{
OPENCLAW_TWITCH_ACCESS_TOKEN: "token",
@@ -184,7 +264,12 @@ describe("scanStatusJsonFast", () => {
},
);
expect(mocks.getUpdateCheckResult).toHaveBeenCalled();
expect(mocks.getUpdateCheckResult).toHaveBeenCalledWith(
expect.objectContaining({
fetchGit: false,
includeRegistry: false,
}),
);
expect(mocks.probeGateway).toHaveBeenCalled();
});
});

View File

@@ -24,6 +24,10 @@ type StatusJsonScanPolicy = {
commandName: string;
allowMissingConfigFastPath?: boolean;
includeChannelSummary?: boolean;
fetchGitUpdate?: boolean;
includeRegistryUpdate?: boolean;
includeLocalStatusRpcFallback?: boolean;
gatewayProbeTimeoutMs?: number | ((cfg: OpenClawConfig) => number | undefined);
resolveHasConfiguredChannels: (
cfg: OpenClawConfig,
sourceConfig: OpenClawConfig,
@@ -90,6 +94,10 @@ export async function scanStatusJsonWithPolicy(
includeChannelsData: false,
includeChannelSecretTargets: false,
skipConfigPluginValidation: true,
fetchGitUpdate: policy.fetchGitUpdate,
includeRegistryUpdate: policy.includeRegistryUpdate,
includeLocalStatusRpcFallback: policy.includeLocalStatusRpcFallback,
gatewayProbeTimeoutMs: policy.gatewayProbeTimeoutMs,
});
return await executeStatusScanFromOverview({
overview,
@@ -115,6 +123,13 @@ export async function scanStatusJsonFast(
commandName: "status --json",
allowMissingConfigFastPath: true,
includeChannelSummary: false,
fetchGitUpdate: opts.all === true,
includeRegistryUpdate: opts.all === true,
includeLocalStatusRpcFallback: opts.all === true,
gatewayProbeTimeoutMs:
opts.all === true
? undefined
: (cfg) => opts.timeoutMs ?? Math.max(1000, cfg.gateway?.handshakeTimeoutMs ?? 0),
resolveHasConfiguredChannels: (cfg) => hasPotentialConfiguredChannelsForStatusJson(cfg),
resolveMemory: async ({ cfg, agentStatus, memoryPlugin }) =>
opts.all

View File

@@ -120,7 +120,11 @@ async function applyLocalStatusRpcFallback(params: {
};
timeoutMs: number;
timeoutMsExplicit: boolean;
enabled?: boolean;
}): Promise<GatewayProbeResult | null> {
if (params.enabled === false) {
return params.gatewayProbe;
}
if (!shouldTryLocalStatusRpcFallback(params)) {
return params.gatewayProbe;
}
@@ -148,6 +152,8 @@ async function applyLocalStatusRpcFallback(params: {
...params.gatewayProbe,
ok: true,
status,
...(auth
? {
auth:
auth.capability === "unknown"
? {
@@ -155,6 +161,8 @@ async function applyLocalStatusRpcFallback(params: {
capability: "read_only",
}
: auth,
}
: {}),
};
}
@@ -193,6 +201,7 @@ export async function resolveGatewayProbeSnapshot(params: {
probeWhenRemoteUrlMissing?: boolean;
resolveAuthWhenRemoteUrlMissing?: boolean;
mergeAuthWarningIntoProbeError?: boolean;
localStatusRpcFallback?: boolean;
};
}): Promise<GatewayProbeSnapshot> {
const gatewayConnection = buildGatewayConnectionDetailsWithResolvers({ config: params.cfg });
@@ -236,6 +245,7 @@ export async function resolveGatewayProbeSnapshot(params: {
gatewayProbeAuth: gatewayProbeAuthResolution.auth,
timeoutMs: probeTimeoutMs,
timeoutMsExplicit,
enabled: params.opts.localStatusRpcFallback !== false,
});
if (
(params.opts.mergeAuthWarningIntoProbeError ?? true) &&

View File

@@ -6,6 +6,7 @@ const statusSummaryMocks = vi.hoisted(() => ({
hasConfiguredChannelsForReadOnlyScope: vi.fn(() => true),
buildChannelSummary: vi.fn(async () => ["ok"]),
readSessionStoreReadOnly: vi.fn(() => ({})),
configureTaskRegistryMaintenance: vi.fn(),
taskRegistrySummary: {
total: 0,
active: 0,
@@ -27,6 +28,7 @@ const statusSummaryMocks = vi.hoisted(() => ({
cron: 0,
},
} as TaskRegistrySummary,
getInspectableTaskRegistrySummary: vi.fn(() => statusSummaryMocks.taskRegistrySummary),
taskAuditFindings: [
{
severity: "warn",
@@ -46,6 +48,7 @@ const statusSummaryMocks = vi.hoisted(() => ({
},
},
] as TaskAuditFinding[],
getInspectableTaskAuditFindings: vi.fn(() => statusSummaryMocks.taskAuditFindings),
}));
vi.mock("../plugins/channel-plugin-ids.js", () => ({
@@ -114,22 +117,9 @@ vi.mock("../infra/system-events.js", () => ({
}));
vi.mock("../tasks/task-registry.maintenance.js", () => ({
configureTaskRegistryMaintenance: vi.fn(),
getInspectableTaskRegistrySummary: vi.fn(() => statusSummaryMocks.taskRegistrySummary),
getInspectableTaskAuditSummary: vi.fn(() => ({
total: 1,
warnings: 1,
errors: 0,
byCode: {
stale_queued: 0,
stale_running: 0,
lost: 0,
delivery_failed: 1,
missing_cleanup: 0,
inconsistent_timestamps: 0,
},
})),
getInspectableTaskAuditFindings: vi.fn(() => statusSummaryMocks.taskAuditFindings),
configureTaskRegistryMaintenance: statusSummaryMocks.configureTaskRegistryMaintenance,
getInspectableTaskRegistrySummary: statusSummaryMocks.getInspectableTaskRegistrySummary,
getInspectableTaskAuditFindings: statusSummaryMocks.getInspectableTaskAuditFindings,
}));
vi.mock("../routing/session-key.js", () => ({

View File

@@ -1,177 +1,25 @@
import "./isolated-agent.mocks.js";
import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
import { clearAllBootstrapSnapshots } from "../agents/bootstrap-cache.js";
import { runEmbeddedAgent } from "../agents/embedded-agent.js";
import { clearSessionStoreCacheForTest } from "../config/sessions/store.js";
import type { OpenClawConfig } from "../config/types.openclaw.js";
import { resetAgentRunContextForTest } from "../infra/agent-events.js";
import { createCliDeps, mockAgentPayloads } from "./isolated-agent.delivery.test-helpers.js";
import { runCronIsolatedAgentTurn } from "./isolated-agent.js";
import {
makeCfg,
makeJob,
withTempCronHome,
writeSessionStoreEntries,
} from "./isolated-agent.test-harness.js";
function lastEmbeddedCall(): { runTimeoutOverrideMs?: number; timeoutMs?: number } {
const calls = vi.mocked(runEmbeddedAgent).mock.calls;
expect(calls.length).toBeGreaterThan(0);
return calls.at(-1)?.[0] as { runTimeoutOverrideMs?: number; timeoutMs?: number };
}
function makeTimeoutTestCfg(
home: string,
storePath: string,
timeoutSeconds: number,
): OpenClawConfig {
return makeCfg(home, storePath, {
agents: { defaults: { timeoutSeconds } },
models: {
providers: {
openai: {
baseUrl: "https://api.openai.com/v1",
agentRuntime: { id: "openclaw" },
models: [],
},
},
},
});
}
const envSnapshot = {
HOME: process.env.HOME,
USERPROFILE: process.env.USERPROFILE,
HOMEDRIVE: process.env.HOMEDRIVE,
HOMEPATH: process.env.HOMEPATH,
OPENCLAW_HOME: process.env.OPENCLAW_HOME,
OPENCLAW_STATE_DIR: process.env.OPENCLAW_STATE_DIR,
} as const;
function restoreSnapshotEnv() {
for (const [key, value] of Object.entries(envSnapshot)) {
if (value === undefined) {
delete process.env[key];
} else {
process.env[key] = value;
}
}
}
describe("runCronIsolatedAgentTurn — explicit per-run timeout signal", () => {
beforeEach(() => {
vi.mocked(runEmbeddedAgent).mockClear();
});
afterEach(() => {
restoreSnapshotEnv();
vi.doUnmock("../agents/embedded-agent.js");
vi.doUnmock("../agents/model-catalog.js");
vi.doUnmock("../agents/model-selection.js");
vi.doUnmock("../agents/subagent-announce.js");
vi.doUnmock("../gateway/call.js");
clearSessionStoreCacheForTest();
resetAgentRunContextForTest();
clearAllBootstrapSnapshots();
vi.restoreAllMocks();
vi.resetModules();
});
import { describe, expect, it } from "vitest";
import { resolveCronRunTimeoutOverrideMs } from "./isolated-agent/run-timeout.js";
describe("resolveCronRunTimeoutOverrideMs", () => {
// Regression: when a cron job's payload `timeoutSeconds` numerically equals
// `agents.defaults.timeoutSeconds`, the run is still an *explicit* per-run
// override. The embedded runner used to detect "explicit" by comparing
// `params.timeoutMs !== resolveAgentTimeoutMs({cfg})` — which collapses to
// `false` in this case, stripping the runTimeoutMs signal and letting the
// LLM idle watchdog fall back to the implicit 120s cap.
// Fix: forward `runTimeoutOverrideMs` from the cron entry point so the
// explicit-vs-default distinction survives the merge into `timeoutMs`.
it("forwards runTimeoutOverrideMs when payload.timeoutSeconds equals the agent default", async () => {
await withTempCronHome(async (home) => {
const storePath = await writeSessionStoreEntries(home, {
"agent:main:main": {
sessionId: "main-session",
updatedAt: Date.now(),
lastProvider: "webchat",
lastTo: "",
},
});
mockAgentPayloads([{ text: "ok" }]);
const cfg = makeTimeoutTestCfg(home, storePath, 300);
await runCronIsolatedAgentTurn({
cfg,
deps: createCliDeps(),
job: {
...makeJob({ kind: "agentTurn", message: "do it", timeoutSeconds: 300 }),
delivery: { mode: "none" },
},
message: "do it",
sessionKey: "cron:job-1",
// the configured agent default, `timeoutMs !== defaultTimeoutMs` collapses to
// `false` in the embedded runner. The cron entry point must carry a separate
// explicit-timeout signal so the LLM idle watchdog does not fall back to its
// implicit 120s cap.
it("preserves explicit payload timeoutSeconds even when it equals the agent default", () => {
expect(resolveCronRunTimeoutOverrideMs(300)).toBe(300_000);
});
const call = lastEmbeddedCall();
expect(call.runTimeoutOverrideMs).toBe(300_000);
});
it("preserves explicit payload timeoutSeconds when it differs from the agent default", () => {
expect(resolveCronRunTimeoutOverrideMs(600)).toBe(600_000);
});
it("forwards runTimeoutOverrideMs when payload.timeoutSeconds differs from the agent default", async () => {
await withTempCronHome(async (home) => {
const storePath = await writeSessionStoreEntries(home, {
"agent:main:main": {
sessionId: "main-session",
updatedAt: Date.now(),
lastProvider: "webchat",
lastTo: "",
},
});
mockAgentPayloads([{ text: "ok" }]);
const cfg = makeTimeoutTestCfg(home, storePath, 300);
await runCronIsolatedAgentTurn({
cfg,
deps: createCliDeps(),
job: {
...makeJob({ kind: "agentTurn", message: "do it", timeoutSeconds: 600 }),
delivery: { mode: "none" },
},
message: "do it",
sessionKey: "cron:job-1",
});
const call = lastEmbeddedCall();
expect(call.runTimeoutOverrideMs).toBe(600_000);
});
});
it("leaves runTimeoutOverrideMs undefined when payload omits timeoutSeconds", async () => {
await withTempCronHome(async (home) => {
const storePath = await writeSessionStoreEntries(home, {
"agent:main:main": {
sessionId: "main-session",
updatedAt: Date.now(),
lastProvider: "webchat",
lastTo: "",
},
});
mockAgentPayloads([{ text: "ok" }]);
const cfg = makeTimeoutTestCfg(home, storePath, 300);
await runCronIsolatedAgentTurn({
cfg,
deps: createCliDeps(),
job: {
...makeJob({ kind: "agentTurn", message: "do it" }),
delivery: { mode: "none" },
},
message: "do it",
sessionKey: "cron:job-1",
});
const call = lastEmbeddedCall();
expect(call.runTimeoutOverrideMs).toBeUndefined();
});
it("omits the signal when the cron payload has no positive numeric timeout", () => {
expect(resolveCronRunTimeoutOverrideMs(undefined)).toBeUndefined();
expect(resolveCronRunTimeoutOverrideMs(0)).toBeUndefined();
expect(resolveCronRunTimeoutOverrideMs(-1)).toBeUndefined();
expect(resolveCronRunTimeoutOverrideMs(Number.NaN)).toBeUndefined();
expect(resolveCronRunTimeoutOverrideMs("300")).toBeUndefined();
});
});

View File

@@ -0,0 +1,5 @@
export function resolveCronRunTimeoutOverrideMs(timeoutSeconds: unknown): number | undefined {
return typeof timeoutSeconds === "number" && Number.isFinite(timeoutSeconds) && timeoutSeconds > 0
? timeoutSeconds * 1000
: undefined;
}

View File

@@ -63,6 +63,7 @@ import {
type MutableCronSession,
type PersistCronSessionEntry,
} from "./run-session-state.js";
import { resolveCronRunTimeoutOverrideMs } from "./run-timeout.js";
import {
DEFAULT_CONTEXT_TOKENS,
deriveSessionTotalTokens,
@@ -704,12 +705,7 @@ async function prepareCronRunContext(params: {
// explicit-vs-default distinction without this companion field, which would
// otherwise force the implicit 120 s cap whenever the cron payload's
// `timeoutSeconds` happens to numerically equal `agents.defaults.timeoutSeconds`.
const runTimeoutOverrideMs =
typeof explicitTimeoutSeconds === "number" &&
Number.isFinite(explicitTimeoutSeconds) &&
explicitTimeoutSeconds > 0
? explicitTimeoutSeconds * 1000
: undefined;
const runTimeoutOverrideMs = resolveCronRunTimeoutOverrideMs(explicitTimeoutSeconds);
const agentPayload = input.job.payload.kind === "agentTurn" ? input.job.payload : null;
const { deliveryPlan, deliveryRequested, resolvedDelivery, sourceDelivery } =
await resolveCronDeliveryContext({