@sema-agent/core 5.7.0 → 5.9.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +79 -0
- package/dist/agents/cascade.d.ts +1 -1
- package/dist/agents/cascade.js +24 -0
- package/dist/agents/subagent.d.ts +7 -7
- package/dist/agents/subagent.js +74 -33
- package/dist/agents/teacher.js +3 -3
- package/dist/agents/team.d.ts +1 -1
- package/dist/agents/team.js +1 -1
- package/dist/agents/verify.js +1 -1
- package/dist/brain/anthropic.js +24 -35
- package/dist/brain/open-responses.d.ts +11 -0
- package/dist/brain/open-responses.js +721 -0
- package/dist/brain/openai.js +22 -33
- package/dist/brain/request-params.d.ts +1 -0
- package/dist/brain/request-params.js +16 -0
- package/dist/brain/stream-engine.d.ts +0 -2
- package/dist/brain/stream-engine.js +5 -47
- package/dist/brain/stream-shared.d.ts +0 -10
- package/dist/brain/stream-shared.js +0 -23
- package/dist/brain/terminal-cause.d.ts +0 -1
- package/dist/brain/terminal-cause.js +0 -3
- package/dist/brain/timeout.d.ts +4 -2
- package/dist/brain/timeout.js +4 -14
- package/dist/config/catalog.d.ts +3 -11
- package/dist/config/catalog.js +30 -69
- package/dist/config/defaults.d.ts +0 -3
- package/dist/config/defaults.js +0 -3
- package/dist/core/auto-compaction.d.ts +2 -11
- package/dist/core/auto-compaction.js +3 -67
- package/dist/core/checkpoint-store.d.ts +10 -8
- package/dist/core/checkpoint-store.js +7 -7
- package/dist/core/fs-write-gate-policy.js +2 -2
- package/dist/core/lsp-diagnostics.d.ts +3 -2
- package/dist/core/lsp-diagnostics.js +20 -7
- package/dist/core/memory-engine/file-backend.js +20 -17
- package/dist/core/memory-engine/layout.d.ts +5 -0
- package/dist/core/memory-engine/layout.js +72 -47
- package/dist/core/runner/assemble-result.d.ts +3 -8
- package/dist/core/runner/assemble-result.js +24 -18
- package/dist/core/runner/prepare-task.d.ts +27 -6
- package/dist/core/runner/prepare-task.js +209 -144
- package/dist/core/runner/runtask.d.ts +0 -2
- package/dist/core/runner/runtask.js +228 -266
- package/dist/core/runner/session-rule-policy.d.ts +1 -0
- package/dist/core/runner/session-rule-policy.js +4 -3
- package/dist/core/session-policy-store.d.ts +5 -0
- package/dist/core/session-policy-store.js +3 -1
- package/dist/core/store-contracts/checkpoint-store-contract.js +2 -2
- package/dist/core/task-registry-agent.d.ts +2 -0
- package/dist/core/task-registry-agent.js +33 -1
- package/dist/core/task-registry-shared.d.ts +0 -1
- package/dist/core/task-registry.d.ts +2 -0
- package/dist/core/task-registry.js +9 -1
- package/dist/core/tool-errors.js +10 -2
- package/dist/core/tool-policy.d.ts +8 -0
- package/dist/core/tool-policy.js +11 -0
- package/dist/core/trace.d.ts +1 -10
- package/dist/core/types.d.ts +27 -30
- package/dist/core/usage-window-store.d.ts +39 -0
- package/dist/core/usage-window-store.js +115 -0
- package/dist/engine/execution-env/node-execution-env.js +0 -22
- package/dist/engine/harness/agent-harness.d.ts +1 -7
- package/dist/engine/harness/agent-harness.js +16 -53
- package/dist/engine/harness/types.d.ts +3 -15
- package/dist/engine/llm/types.d.ts +3 -75
- package/dist/engine/loop/agent-loop.d.ts +1 -1
- package/dist/engine/loop/agent-loop.js +7 -173
- package/dist/engine/loop/types.d.ts +1 -18
- package/dist/engine/session/repo-utils.d.ts +1 -2
- package/dist/engine/session/repo-utils.js +0 -7
- package/dist/index.d.ts +13 -7
- package/dist/index.js +10 -5
- package/dist/internal/llm.d.ts +1 -1
- package/dist/orchestration/goal.js +1 -5
- package/dist/orchestration/run-workflow-tool.d.ts +1 -1
- package/dist/orchestration/run-workflow-tool.js +1 -2
- package/dist/orchestration/workflow-governance.d.ts +6 -6
- package/dist/orchestration/workflow-governance.js +33 -47
- package/dist/orchestration/workflow.js +14 -5
- package/dist/prompt-assembly/event-registry.js +2 -3
- package/dist/stores/cc/lockfile.js +9 -11
- package/dist/stores/cc/mailbox-store.js +49 -38
- package/dist/stores/file/index.d.ts +3 -0
- package/dist/stores/file/index.js +4 -0
- package/dist/stores/file/usage-window-store.d.ts +9 -0
- package/dist/stores/file/usage-window-store.js +86 -0
- package/dist/tools/fs/fs-bash.d.ts +1 -10
- package/dist/tools/fs/fs-bash.js +20 -60
- package/dist/tools/fs/index.d.ts +0 -2
- package/dist/tools/fs/index.js +1 -2
- package/dist/tools/web.js +20 -19
- package/package.json +4 -5
- package/dist/bin/sema-tb.d.ts +0 -31
- package/dist/bin/sema-tb.js +0 -448
- package/dist/bin/tb-env.d.ts +0 -2
- package/dist/bin/tb-env.js +0 -17
- package/dist/brain/walltime.d.ts +0 -1
- package/dist/brain/walltime.js +0 -1
- package/dist/core/runner/call-cap.d.ts +0 -67
- package/dist/core/runner/call-cap.js +0 -145
- package/dist/core/runner/cut-kill.d.ts +0 -10
- package/dist/core/runner/cut-kill.js +0 -37
|
@@ -8,7 +8,6 @@ import type { SessionStore } from "../session.js";
|
|
|
8
8
|
import { SubagentRetainLedger } from "../../agents/retain-ledger.js";
|
|
9
9
|
import type { OnAsk, ToolPolicy } from "../tool-policy.js";
|
|
10
10
|
import { type ActiveSkillFrame } from "./active-skill-scope.js";
|
|
11
|
-
import { type CutKillRegistry } from "./cut-kill.js";
|
|
12
11
|
import type { SessionPermissionRules } from "../session-policy-store.js";
|
|
13
12
|
import { CacheBreakDetector, type ToolFingerprintInput } from "../cache-break-detector.js";
|
|
14
13
|
import { type BrainCallGuardrailRef } from "../../brain/timeout.js";
|
|
@@ -19,10 +18,23 @@ import type { TaskNotificationPayload } from "../task-notification.js";
|
|
|
19
18
|
import { type CwdRef } from "../../tools/fs/index.js";
|
|
20
19
|
import { type WorkflowSizeGuideline } from "../../orchestration/workflow-size-guideline.js";
|
|
21
20
|
import type { Runner } from "./runtask.js";
|
|
22
|
-
import { type CheckpointGate, type CheckpointState, type CheckpointToken, type ResourceLedger, type ResourceLimitReason } from "../checkpoint-store.js";
|
|
21
|
+
import { type CheckpointGate, type CheckpointState, type CheckpointToken, type ResourceLedger, type PlatformLimitReason, type ResourceLimitReason } from "../checkpoint-store.js";
|
|
23
22
|
import type { ActiveWorktreeSession, AgentMessage, AgentTool, ExecutionEnv } from "../../internal/harness.js";
|
|
24
|
-
import type { NestedUsageAccum, RunnerDeps, TaskEvent, TaskResult, TaskSpec, ToolActivity, ToolEffect } from "../types.js";
|
|
23
|
+
import type { NestedUsageAccum, RunnerDeps, TaskEvent, TaskLimits, TaskResult, TaskSpec, ToolActivity, ToolEffect } from "../types.js";
|
|
25
24
|
import type { RepairBundle } from "../../agents/repair-loop.js";
|
|
25
|
+
export declare function resolveTaskLimits(limits: TaskLimits | undefined): TaskLimits | undefined;
|
|
26
|
+
export declare const ENV_LIFETIME_SUSPEND_MARGIN_MS = 60000;
|
|
27
|
+
export declare const USAGE_WINDOW_REAP_MARGIN_MS: number;
|
|
28
|
+
export interface UsageGovernance {
|
|
29
|
+
readonly key: string;
|
|
30
|
+
check(now: number): Promise<number | undefined>;
|
|
31
|
+
commit(cumulativeTokens: number, now: number): Promise<void>;
|
|
32
|
+
}
|
|
33
|
+
export declare function resolveEnvLifetimeExpiry(env: ExecutionEnv, observedAt: number | undefined): {
|
|
34
|
+
expiresAt: number;
|
|
35
|
+
} | {
|
|
36
|
+
unanchored: true;
|
|
37
|
+
} | undefined;
|
|
26
38
|
export declare const DEFAULT_IRREVERSIBLE_SCOPE = "irreversible";
|
|
27
39
|
export declare function checkpointScopeOf(spec: {
|
|
28
40
|
durableApproval?: {
|
|
@@ -132,9 +144,17 @@ export interface Prepared {
|
|
|
132
144
|
turns: number;
|
|
133
145
|
walltimeMs: number;
|
|
134
146
|
}) => Promise<boolean>;
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
147
|
+
suspendForPlatformLimit?: (reason: PlatformLimitReason, sliceSpend: {
|
|
148
|
+
costMicroUsd: number;
|
|
149
|
+
tokens: number;
|
|
150
|
+
turns: number;
|
|
151
|
+
walltimeMs: number;
|
|
152
|
+
}, hint?: {
|
|
153
|
+
resumeAfterMs: number;
|
|
154
|
+
}) => Promise<boolean>;
|
|
155
|
+
envLifetimeSuspendAt?: number;
|
|
156
|
+
usageGovernance?: UsageGovernance;
|
|
157
|
+
callIssuedAtRef: {
|
|
138
158
|
current?: number;
|
|
139
159
|
};
|
|
140
160
|
brainCallGuardrailRef: BrainCallGuardrailRef;
|
|
@@ -179,6 +199,7 @@ export interface Prepared {
|
|
|
179
199
|
lspDiagnostics?: {
|
|
180
200
|
registry: import("../lsp-diagnostics.js").LspDiagnosticsRegistry;
|
|
181
201
|
nudge: (rawPath: string) => void;
|
|
202
|
+
runIdent: string;
|
|
182
203
|
};
|
|
183
204
|
planModeRef: {
|
|
184
205
|
active: boolean;
|
|
@@ -17,10 +17,8 @@ import { createSubagentWorktreeHelper, forkGovernanceDenial } from "../../agents
|
|
|
17
17
|
import { createAgentTranscriptTool, AGENT_TRANSCRIPT_TOOL_NAME } from "../../agents/agent-transcript-tool.js";
|
|
18
18
|
import { createSendMessageTool, SEND_MESSAGE_TOOL_NAME } from "../../agents/send-message-tool.js";
|
|
19
19
|
import { SubagentRetainLedger } from "../../agents/retain-ledger.js";
|
|
20
|
-
import { combinePolicies, createTranscriptIntegrityPolicy, createUnverifiableDeletePolicy, refuseOutOfContractDecision, resolveAsk, toolPolicyNameSets } from "../tool-policy.js";
|
|
20
|
+
import { askApproverIdentity, combinePolicies, createTranscriptIntegrityPolicy, createUnverifiableDeletePolicy, refuseOutOfContractDecision, resolveAsk, toolPolicyNameSets } from "../tool-policy.js";
|
|
21
21
|
import { ActiveSkillScope, createActiveSkillScopePolicy } from "./active-skill-scope.js";
|
|
22
|
-
import { computeCallCap, createCallCapRef, softExecDeadlineMs, toolCutDeadlineMs, WALLTIME_STALL_CONNECT_MS, WALLTIME_STALL_FIRST_TOKEN_MS, WALLTIME_STALL_IDLE_MS } from "./call-cap.js";
|
|
23
|
-
import { createCutKillRegistry } from "./cut-kill.js";
|
|
24
22
|
import { CHANGED_FILES_MTIME_EPS_MS, fenceMcpServerInstructions, renderAgentListingDelta } from "./turn-attachments.js";
|
|
25
23
|
import { inlineUntrusted } from "../untrusted-text.js";
|
|
26
24
|
import { emitTrace } from "../trace.js";
|
|
@@ -29,7 +27,7 @@ import { cloneObserverInput, formatHookFeedback, runToolGate } from "../hooks.js
|
|
|
29
27
|
import { reconcileInterruptedSession } from "../session-reconcile.js";
|
|
30
28
|
import { CacheBreakDetector, toolsToFingerprintInputs } from "../cache-break-detector.js";
|
|
31
29
|
import { reservedCollisions, reservedFor } from "../../brain/request-params.js";
|
|
32
|
-
import { resolveBrainCallGuardrailMs, withBrainCallGuardrail } from "../../brain/timeout.js";
|
|
30
|
+
import { resolveBrainCallGuardrailMs, STALL_CONNECT_MS, STALL_FIRST_TOKEN_MS, STALL_IDLE_MS, withBrainCallGuardrail } from "../../brain/timeout.js";
|
|
33
31
|
import { defineTool, isDefineToolProduct } from "../tools.js";
|
|
34
32
|
import { RETIRED_TOOL_NAMES } from "../tool-name-aliases.js";
|
|
35
33
|
import { protocolOf, PROTOCOL_TABLE } from "../protocol-table.js";
|
|
@@ -69,13 +67,96 @@ import { createRunWorkflowTool, RUN_WORKFLOW_TOOL_NAME } from "../../orchestrati
|
|
|
69
67
|
import { resolveWorkflowSizeGuideline } from "../../orchestration/workflow-size-guideline.js";
|
|
70
68
|
import { createLspTool, gitCheckIgnoreFilter, resolveLspPath } from "../lsp.js";
|
|
71
69
|
import { resolveKey } from "../../tools/fs/safety.js";
|
|
72
|
-
import { BINDING_CHECKPOINT_VERSION, mintCheckpointToken, RESOURCE_CHECKPOINT_VERSION,
|
|
70
|
+
import { BINDING_CHECKPOINT_VERSION, mintCheckpointToken, RESOURCE_CHECKPOINT_VERSION, TOKEN_CHECKPOINT_VERSION, buildRiskDescriptor, debitLedger, remainingBudgetMicroUsd, } from "../checkpoint-store.js";
|
|
73
71
|
import { boundInputHashOf } from "../canonical-json.js";
|
|
72
|
+
import { GLOBAL_USAGE_KEY, resolveUsageWindows, usageRetryAfterMs } from "../usage-window-store.js";
|
|
74
73
|
const RECONCILE_MAX_RETRIES = 3;
|
|
75
74
|
const DEFAULT_MAX_SUSPENDS = 5;
|
|
76
|
-
const
|
|
75
|
+
const TASK_LIMIT_KEYS = [
|
|
76
|
+
"maxTokens",
|
|
77
|
+
"maxCostUsd",
|
|
78
|
+
"maxTurns",
|
|
79
|
+
"maxWalltimeMs",
|
|
80
|
+
"maxOutputTokens",
|
|
81
|
+
"approachNotice",
|
|
82
|
+
"budgetStreamCancel",
|
|
83
|
+
"degrade",
|
|
84
|
+
"brainCallGuardrailMs",
|
|
85
|
+
];
|
|
86
|
+
const NUMERIC_TASK_LIMIT_KEYS = ["maxTokens", "maxCostUsd", "maxTurns", "maxWalltimeMs", "maxOutputTokens"];
|
|
87
|
+
const RETIRED_TASK_LIMIT_KEYS = {
|
|
88
|
+
timeoutSec: "maxWalltimeMs (milliseconds, not seconds)",
|
|
89
|
+
deadlineNudge: "approachNotice",
|
|
90
|
+
callCapByDeadline: "(retired — no replacement)",
|
|
91
|
+
gracefulFinalize: "(retired — the approach notice is the only end-of-budget prompt)",
|
|
92
|
+
};
|
|
93
|
+
function limitConfigError(code, message) {
|
|
94
|
+
const e = new Error(message);
|
|
95
|
+
e.code = code;
|
|
96
|
+
return e;
|
|
97
|
+
}
|
|
98
|
+
export function resolveTaskLimits(limits) {
|
|
99
|
+
if (limits === undefined)
|
|
100
|
+
return undefined;
|
|
101
|
+
if (typeof limits !== "object" || Array.isArray(limits)) {
|
|
102
|
+
throw limitConfigError("config.limit_invalid", `TaskSpec.limits must be an object (got ${Array.isArray(limits) ? "an array" : typeof limits})`);
|
|
103
|
+
}
|
|
104
|
+
const raw = limits;
|
|
105
|
+
const legal = TASK_LIMIT_KEYS;
|
|
106
|
+
for (const key of Object.keys(raw)) {
|
|
107
|
+
if (legal.includes(key))
|
|
108
|
+
continue;
|
|
109
|
+
const replacement = RETIRED_TASK_LIMIT_KEYS[key];
|
|
110
|
+
throw limitConfigError("config.limit_unknown_key", `TaskSpec.limits.${key} is not a limit this engine reads` +
|
|
111
|
+
(replacement !== undefined ? ` — it was replaced by \`${replacement}\`` : "") +
|
|
112
|
+
`. Legal keys: ${TASK_LIMIT_KEYS.join(", ")}. Refused rather than ignored: a limit that is silently dropped reads to the caller as an armed ceiling.`);
|
|
113
|
+
}
|
|
114
|
+
for (const key of NUMERIC_TASK_LIMIT_KEYS) {
|
|
115
|
+
const value = raw[key];
|
|
116
|
+
if (value === undefined)
|
|
117
|
+
continue;
|
|
118
|
+
if (typeof value !== "number" || !Number.isFinite(value) || value < 0) {
|
|
119
|
+
throw limitConfigError("config.limit_invalid", `TaskSpec.limits.${key} must be a finite, non-negative number (got ${String(value)}) — an unevaluable ceiling is not a ceiling, and folding it to a default would run the task under a limit nobody chose.`);
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
const notice = raw.approachNotice;
|
|
123
|
+
if (notice !== undefined && notice !== false) {
|
|
124
|
+
if (typeof notice !== "object" || notice === null || Array.isArray(notice)) {
|
|
125
|
+
throw limitConfigError("config.limit_invalid", `TaskSpec.limits.approachNotice must be \`false\` or { at?: [first, second] } (got ${String(notice)})`);
|
|
126
|
+
}
|
|
127
|
+
const at = notice.at;
|
|
128
|
+
if (at !== undefined) {
|
|
129
|
+
const ok = Array.isArray(at) &&
|
|
130
|
+
at.length === 2 &&
|
|
131
|
+
at.every((n) => typeof n === "number" && Number.isFinite(n) && n > 0 && n <= 1) &&
|
|
132
|
+
at[0] <= at[1];
|
|
133
|
+
if (!ok) {
|
|
134
|
+
throw limitConfigError("config.limit_invalid", `TaskSpec.limits.approachNotice.at must be two fractions in (0, 1] with first <= second (got ${JSON.stringify(at)})`);
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
return limits;
|
|
139
|
+
}
|
|
77
140
|
const ULTRA_REASONING_TIERS = new Set(["xhigh", "max"]);
|
|
78
141
|
const DEFAULT_RESOURCE_TTL_MS = 30 * 24 * 60 * 60 * 1000;
|
|
142
|
+
export const ENV_LIFETIME_SUSPEND_MARGIN_MS = 60_000;
|
|
143
|
+
export const USAGE_WINDOW_REAP_MARGIN_MS = 60 * 60 * 1000;
|
|
144
|
+
export function resolveEnvLifetimeExpiry(env, observedAt) {
|
|
145
|
+
const lifetimeMs = env.lifetimeMs;
|
|
146
|
+
if (lifetimeMs === undefined)
|
|
147
|
+
return undefined;
|
|
148
|
+
if (typeof lifetimeMs !== "number" || !Number.isFinite(lifetimeMs) || lifetimeMs <= 0) {
|
|
149
|
+
throw limitConfigError("config.env_lifetime_invalid", `ExecutionEnv.lifetimeMs must be a finite number of milliseconds > 0 (got ${String(lifetimeMs)}) — an unevaluable lifetime is not a lifetime, and treating it as absent would run the task with no protection against the platform reclaiming its environment.`);
|
|
150
|
+
}
|
|
151
|
+
const declaredStart = env.lifetimeStartedAt;
|
|
152
|
+
if (declaredStart !== undefined && (typeof declaredStart !== "number" || !Number.isFinite(declaredStart))) {
|
|
153
|
+
throw limitConfigError("config.env_lifetime_invalid", `ExecutionEnv.lifetimeStartedAt must be a finite epoch-ms timestamp (got ${String(declaredStart)}).`);
|
|
154
|
+
}
|
|
155
|
+
const anchor = declaredStart ?? observedAt;
|
|
156
|
+
if (anchor === undefined)
|
|
157
|
+
return { unanchored: true };
|
|
158
|
+
return { expiresAt: anchor + lifetimeMs };
|
|
159
|
+
}
|
|
79
160
|
const DEFAULT_UNATTENDED_APPROVAL_TTL_MS = 30 * 24 * 60 * 60 * 1000;
|
|
80
161
|
function sanitizedTtlMs(ttlMs) {
|
|
81
162
|
if (ttlMs === undefined)
|
|
@@ -237,6 +318,8 @@ export async function prepareTask(spec, deps, sessions, resume, internals, runne
|
|
|
237
318
|
e.code = "config.empty_objective";
|
|
238
319
|
throw e;
|
|
239
320
|
}
|
|
321
|
+
resolveTaskLimits(spec.limits);
|
|
322
|
+
const usageWindows = resolveUsageWindows(deps.usageWindows);
|
|
240
323
|
const brainCallGuardrailRef = {};
|
|
241
324
|
const brainCallGuardrailMs = resolveBrainCallGuardrailMs(spec.limits?.brainCallGuardrailMs ?? deps.brainCallGuardrailMs);
|
|
242
325
|
if (spec.agents !== undefined && spec.agents.length > 0) {
|
|
@@ -497,6 +580,7 @@ export async function prepareTask(spec, deps, sessions, resume, internals, runne
|
|
|
497
580
|
throw e;
|
|
498
581
|
}
|
|
499
582
|
let ownedEnv;
|
|
583
|
+
let ownedEnvObservedAt;
|
|
500
584
|
let mcp;
|
|
501
585
|
let a2a;
|
|
502
586
|
if (internals?.requestedCwd !== undefined && deps.executionEnvFactory === undefined) {
|
|
@@ -514,6 +598,8 @@ export async function prepareTask(spec, deps, sessions, resume, internals, runne
|
|
|
514
598
|
...(internals?.parentCwd ? { parentCwd: internals.parentCwd } : {}),
|
|
515
599
|
})
|
|
516
600
|
: undefined;
|
|
601
|
+
if (ownedEnv !== undefined)
|
|
602
|
+
ownedEnvObservedAt = Date.now();
|
|
517
603
|
}
|
|
518
604
|
catch (factoryErr) {
|
|
519
605
|
await settleTeardownLeg(() => forgetOnThrow(), "forgetOnThrow (env-factory-throw leg)", (err) => deps.onError?.(err, { phase: "config", sessionId }));
|
|
@@ -552,6 +638,11 @@ export async function prepareTask(spec, deps, sessions, resume, internals, runne
|
|
|
552
638
|
if (spec.signal?.aborted)
|
|
553
639
|
abortController.abort();
|
|
554
640
|
try {
|
|
641
|
+
const envLifetime = resolveEnvLifetimeExpiry(executionEnv, ownedEnvObservedAt);
|
|
642
|
+
if (envLifetime !== undefined && "unanchored" in envLifetime) {
|
|
643
|
+
deps.onError?.(new Error("ExecutionEnv.lifetimeMs is declared but NOT enforceable: this env was not minted by the run's executionEnvFactory and reports no `lifetimeStartedAt`, so the engine cannot tell how old it is. The run will NOT suspend before the platform reclaims the environment — have the adapter report `lifetimeStartedAt`."), { phase: "config", sessionId });
|
|
644
|
+
}
|
|
645
|
+
const envLifetimeSuspendAt = envLifetime !== undefined && "expiresAt" in envLifetime ? envLifetime.expiresAt - ENV_LIFETIME_SUSPEND_MARGIN_MS : undefined;
|
|
555
646
|
if (internals?.isolation === "worktree") {
|
|
556
647
|
const failIsolation = (reason) => {
|
|
557
648
|
const e = new Error(`isolation "worktree" was requested but cannot be honored: ${reason}. The sub-agent was not started (fail-closed — no silent fallback to the shared working tree).`);
|
|
@@ -853,6 +944,7 @@ export async function prepareTask(spec, deps, sessions, resume, internals, runne
|
|
|
853
944
|
model: harnessRef.current?.getModel(),
|
|
854
945
|
thinkingLevel: harnessRef.current?.getThinkingLevel(),
|
|
855
946
|
principal: spec.principal,
|
|
947
|
+
...(frozenOnAsk !== undefined ? { onAsk: frozenOnAsk } : {}),
|
|
856
948
|
oneShot: spec.oneShot,
|
|
857
949
|
clientContext: spec.clientContext,
|
|
858
950
|
excludeTools: toolFaceSnapshot.exclude,
|
|
@@ -1034,12 +1126,12 @@ export async function prepareTask(spec, deps, sessions, resume, internals, runne
|
|
|
1034
1126
|
};
|
|
1035
1127
|
const priorSuspendCount = resume?.priorSuspendCount ?? 0;
|
|
1036
1128
|
const maxSuspends = spec.maxSuspends ?? deps.maxSuspends ?? DEFAULT_MAX_SUSPENDS;
|
|
1037
|
-
const maxSlices = spec.resourceSuspend?.maxSlices
|
|
1129
|
+
const maxSlices = spec.resourceSuspend?.maxSlices;
|
|
1038
1130
|
const priorLedger = resume?.priorLedger;
|
|
1039
1131
|
const resourceTotal = spec.resourceSuspend
|
|
1040
1132
|
? {
|
|
1041
1133
|
totalBudgetMicroUsd: spec.resourceSuspend.totalBudgetUsd !== undefined ? Math.round(spec.resourceSuspend.totalBudgetUsd * 1e6) : undefined,
|
|
1042
|
-
|
|
1134
|
+
totalTokens: spec.resourceSuspend.totalTokens,
|
|
1043
1135
|
}
|
|
1044
1136
|
: undefined;
|
|
1045
1137
|
const budgetSnapshot = {
|
|
@@ -1058,6 +1150,7 @@ export async function prepareTask(spec, deps, sessions, resume, internals, runne
|
|
|
1058
1150
|
let worktreeSessionRef;
|
|
1059
1151
|
let backgroundTaskToolsActive = false;
|
|
1060
1152
|
let suspendForResource;
|
|
1153
|
+
let suspendForPlatformLimit;
|
|
1061
1154
|
let suspendForReview;
|
|
1062
1155
|
const outputRef = {};
|
|
1063
1156
|
if (resume?.seed.outputRef) {
|
|
@@ -1212,29 +1305,7 @@ export async function prepareTask(spec, deps, sessions, resume, internals, runne
|
|
|
1212
1305
|
}
|
|
1213
1306
|
tools.push(...a2a.tools.map((t) => remoteToolOffload(t)));
|
|
1214
1307
|
foldProtocolAxes(a2a.toolAxes, "A2A");
|
|
1215
|
-
const callCapOn = spec.limits?.callCapByDeadline !== false;
|
|
1216
|
-
const callCapRef = spec.limits?.timeoutSec &&
|
|
1217
|
-
spec.limits.timeoutSec > 0 &&
|
|
1218
|
-
(callCapOn || spec.limits.gracefulFinalize !== false)
|
|
1219
|
-
? createCallCapRef()
|
|
1220
|
-
: undefined;
|
|
1221
|
-
if (callCapRef) {
|
|
1222
|
-
callCapRef.staticCapTokens =
|
|
1223
|
-
spec.limits?.maxOutputTokens !== undefined && spec.limits.maxOutputTokens > 0
|
|
1224
|
-
? spec.limits.maxOutputTokens
|
|
1225
|
-
: model.maxTokens;
|
|
1226
|
-
}
|
|
1227
|
-
const cutKills = callCapRef ? createCutKillRegistry() : undefined;
|
|
1228
1308
|
const callIssuedAtRef = {};
|
|
1229
|
-
const execClamp = callCapRef
|
|
1230
|
-
? {
|
|
1231
|
-
deadlineMs: () => softExecDeadlineMs(callCapRef),
|
|
1232
|
-
onClamp: () => {
|
|
1233
|
-
callCapRef.toolClamps = (callCapRef.toolClamps ?? 0) + 1;
|
|
1234
|
-
},
|
|
1235
|
-
...(cutKills ? { registerKillHandle: cutKills.register } : {}),
|
|
1236
|
-
}
|
|
1237
|
-
: undefined;
|
|
1238
1309
|
const memoryWriteGateRef = {};
|
|
1239
1310
|
const additionalRootsCanonical = [];
|
|
1240
1311
|
let attachmentRootCanonical;
|
|
@@ -1317,7 +1388,6 @@ export async function prepareTask(spec, deps, sessions, resume, internals, runne
|
|
|
1317
1388
|
...(sessionId !== undefined ? { sessionId } : {}),
|
|
1318
1389
|
...(internals?.onTaskNotification !== undefined ? { taskNotification: internals.onTaskNotification } : {}),
|
|
1319
1390
|
...(internals?.detachHub !== undefined ? { detachHub: internals.detachHub } : {}),
|
|
1320
|
-
...(execClamp !== undefined ? { execClamp } : {}),
|
|
1321
1391
|
pdfModelCapabilities: pdfModelCapabilitiesOf(model),
|
|
1322
1392
|
...(deps.hands?.bashReadonlyAllow !== undefined ? { bashReadonlyAllow: deps.hands.bashReadonlyAllow } : {}),
|
|
1323
1393
|
...(deps.hands?.commitCoAuthor !== undefined ? { commitCoAuthor: deps.hands.commitCoAuthor } : {}),
|
|
@@ -1366,7 +1436,7 @@ export async function prepareTask(spec, deps, sessions, resume, internals, runne
|
|
|
1366
1436
|
if (backgroundTaskToolsActive || workflowToolsActive) {
|
|
1367
1437
|
toolEffects.set("TaskOutput", "read");
|
|
1368
1438
|
toolEffects.set("TaskStop", "write");
|
|
1369
|
-
tools.push(firstPartyOffload(createTaskOutputTool({ registry: defaultTaskRegistry, owner: hostTaskId, scope: taskScope, sessionId, workflowStore: deps.workflowRunStore, agentStore: deps.backgroundAgentStore, notificationWired: internals?.onTaskNotification !== undefined, oneShot: spec.oneShot, toolResultStore: offloadStore
|
|
1439
|
+
tools.push(firstPartyOffload(createTaskOutputTool({ registry: defaultTaskRegistry, owner: hostTaskId, scope: taskScope, sessionId, workflowStore: deps.workflowRunStore, agentStore: deps.backgroundAgentStore, notificationWired: internals?.onTaskNotification !== undefined, oneShot: spec.oneShot, toolResultStore: offloadStore })), firstPartyOffload(createTaskStopTool({ registry: defaultTaskRegistry, owner: hostTaskId, scope: taskScope, sessionId, workflowStore: deps.workflowRunStore, agentStore: deps.backgroundAgentStore })));
|
|
1370
1440
|
if (runnerSelf && !(spec.tools ?? []).some((t) => t.name === SEND_MESSAGE_TOOL_NAME)) {
|
|
1371
1441
|
const delegationForRevive = (spec.tools ?? []).find((t) => t.agentListing !== undefined);
|
|
1372
1442
|
const reviveSpawn = delegationForRevive !== undefined && deps.backgroundAgentStore !== undefined && deps.mailboxStore !== undefined
|
|
@@ -1493,11 +1563,12 @@ export async function prepareTask(spec, deps, sessions, resume, internals, runne
|
|
|
1493
1563
|
const lspDiagnostics = spec.lspDiagnostics !== false && lspManager?.diagnostics !== undefined && handsEnabled && spec.handsReadOnly !== true
|
|
1494
1564
|
? lspManager.diagnostics
|
|
1495
1565
|
: undefined;
|
|
1566
|
+
const lspRunIdent = sessionId;
|
|
1496
1567
|
const nudgeLspOnEdit = lspDiagnostics
|
|
1497
1568
|
? (rawPath) => {
|
|
1498
1569
|
const baseDir = handsCwdRef?.current ?? taskRootPath;
|
|
1499
1570
|
const filePath = resolveLspPath(rawPath, baseDir);
|
|
1500
|
-
lspDiagnostics.fileEdited(pathToUri(filePath));
|
|
1571
|
+
lspDiagnostics.fileEdited(lspRunIdent, pathToUri(filePath));
|
|
1501
1572
|
void lspManager
|
|
1502
1573
|
.sessionFor(filePath, undefined, executionEnv)
|
|
1503
1574
|
.then((session) => session?.notifyFileChanged?.(filePath))
|
|
@@ -2134,49 +2205,14 @@ export async function prepareTask(spec, deps, sessions, resume, internals, runne
|
|
|
2134
2205
|
? { legDate: envFacts.date, today: () => formatLocalDate(new Date(), tzValid ? userTz : undefined) }
|
|
2135
2206
|
: undefined;
|
|
2136
2207
|
const harness = new AgentHarness({
|
|
2208
|
+
abortResultDetails: () => suspendRef.token !== undefined || reviewRef.token !== undefined ? { code: "gate.parked" } : undefined,
|
|
2137
2209
|
...(spec.limits?.maxOutputTokens !== undefined && spec.limits.maxOutputTokens > 0
|
|
2138
2210
|
? { maxOutputTokens: spec.limits.maxOutputTokens }
|
|
2139
2211
|
: {}),
|
|
2140
|
-
|
|
2141
|
-
|
|
2142
|
-
|
|
2143
|
-
|
|
2144
|
-
return undefined;
|
|
2145
|
-
const cap = computeCallCap(callCapRef, Date.now(), (thinking ?? "off") !== "off");
|
|
2146
|
-
if (cap !== undefined)
|
|
2147
|
-
callCapRef.shrinks = (callCapRef.shrinks ?? 0) + 1;
|
|
2148
|
-
return cap;
|
|
2149
|
-
},
|
|
2150
|
-
}
|
|
2151
|
-
: {}),
|
|
2152
|
-
...(callCapRef !== undefined
|
|
2153
|
-
? {
|
|
2154
|
-
callDeadlineMsPerCall: () => {
|
|
2155
|
-
callIssuedAtRef.current = Date.now();
|
|
2156
|
-
return softExecDeadlineMs(callCapRef);
|
|
2157
|
-
},
|
|
2158
|
-
stallTimeoutsPerCall: () => softExecDeadlineMs(callCapRef) !== undefined
|
|
2159
|
-
? { connectMs: WALLTIME_STALL_CONNECT_MS, firstTokenMs: WALLTIME_STALL_FIRST_TOKEN_MS, idleMs: WALLTIME_STALL_IDLE_MS }
|
|
2160
|
-
: undefined,
|
|
2161
|
-
}
|
|
2162
|
-
: {}),
|
|
2163
|
-
...(callCapRef !== undefined
|
|
2164
|
-
? {
|
|
2165
|
-
toolDeadline: {
|
|
2166
|
-
deadlineMs: () => toolCutDeadlineMs(callCapRef, Date.now()),
|
|
2167
|
-
onCut: (info) => {
|
|
2168
|
-
callCapRef.toolCuts = (callCapRef.toolCuts ?? 0) + 1;
|
|
2169
|
-
if (callCapRef.finalizeMode === true && cutKills !== undefined) {
|
|
2170
|
-
cutKills.killFor(info.toolCallId);
|
|
2171
|
-
}
|
|
2172
|
-
callCapRef.pendingCutTools = (callCapRef.pendingCutTools ?? 0) + 1;
|
|
2173
|
-
void info.settled.then(() => {
|
|
2174
|
-
callCapRef.pendingCutTools = (callCapRef.pendingCutTools ?? 0) - 1;
|
|
2175
|
-
});
|
|
2176
|
-
},
|
|
2177
|
-
},
|
|
2178
|
-
}
|
|
2179
|
-
: {}),
|
|
2212
|
+
stallTimeoutsPerCall: () => {
|
|
2213
|
+
callIssuedAtRef.current = Date.now();
|
|
2214
|
+
return { connectMs: STALL_CONNECT_MS, firstTokenMs: STALL_FIRST_TOKEN_MS, idleMs: STALL_IDLE_MS };
|
|
2215
|
+
},
|
|
2180
2216
|
...(spec.resilience !== undefined ? { resilience: spec.resilience } : {}),
|
|
2181
2217
|
loopTrace: (step) => {
|
|
2182
2218
|
if (step.kind !== "continue")
|
|
@@ -2642,11 +2678,11 @@ export async function prepareTask(spec, deps, sessions, resume, internals, runne
|
|
|
2642
2678
|
const blockedTracked = Boolean(hooks?.postToolUse || hooks?.preToolUse || hooks?.postToolUseFailure || hooks?.postToolBatch);
|
|
2643
2679
|
const restoreSurfaceGap = ownedEnv !== undefined && isRemoteExecutionEnv(ownedEnv) && ownedEnv.capabilities.suspendable ? missingRestoreSurface(ownedEnv) : [];
|
|
2644
2680
|
const incompleteSuspendAdapter = restoreSurfaceGap.length > 0 ? restoreSurfaceGap : undefined;
|
|
2645
|
-
const
|
|
2646
|
-
(spec.checkpointStore ?? deps.checkpointStore) !== undefined &&
|
|
2681
|
+
const durableSuspendInfraReady = (spec.checkpointStore ?? deps.checkpointStore) !== undefined &&
|
|
2647
2682
|
!(offloadStore !== undefined && isVolatileOffloadStore(offloadStore)) &&
|
|
2648
2683
|
(ownedEnv === undefined || isRemoteExecutionEnv(ownedEnv)) &&
|
|
2649
2684
|
incompleteSuspendAdapter === undefined;
|
|
2685
|
+
const resourceSuspendEligible = spec.resourceSuspend !== undefined && durableSuspendInfraReady;
|
|
2650
2686
|
if (spec.resourceSuspend !== undefined && !resourceSuspendEligible) {
|
|
2651
2687
|
const why = (spec.checkpointStore ?? deps.checkpointStore) === undefined
|
|
2652
2688
|
? "no CheckpointStore is wired"
|
|
@@ -2660,7 +2696,33 @@ export async function prepareTask(spec, deps, sessions, resume, internals, runne
|
|
|
2660
2696
|
sessionId,
|
|
2661
2697
|
});
|
|
2662
2698
|
}
|
|
2663
|
-
|
|
2699
|
+
const usageGovernance = (() => {
|
|
2700
|
+
if (usageWindows === undefined || usageWindows.length === 0)
|
|
2701
|
+
return undefined;
|
|
2702
|
+
const store = deps.usageWindowStore;
|
|
2703
|
+
if (store === undefined) {
|
|
2704
|
+
deps.onError?.(new Error("RunnerDeps.usageWindows is set but INACTIVE: no `usageWindowStore` is wired, so cross-task usage cannot be counted and no window can be enforced. Wire InMemoryUsageWindowStore (process-local) or FileUsageWindowStore (restart-surviving)."), { phase: "config", sessionId });
|
|
2705
|
+
return undefined;
|
|
2706
|
+
}
|
|
2707
|
+
const key = spec.principal || GLOBAL_USAGE_KEY;
|
|
2708
|
+
const windows = usageWindows;
|
|
2709
|
+
let charged = 0;
|
|
2710
|
+
return {
|
|
2711
|
+
key,
|
|
2712
|
+
async check(now) {
|
|
2713
|
+
return usageRetryAfterMs(await store.read(key, windows, now));
|
|
2714
|
+
},
|
|
2715
|
+
async commit(cumulativeTokens, now) {
|
|
2716
|
+
const delta = cumulativeTokens - charged;
|
|
2717
|
+
if (delta <= 0)
|
|
2718
|
+
return;
|
|
2719
|
+
await store.charge(key, delta, now, windows);
|
|
2720
|
+
charged = cumulativeTokens;
|
|
2721
|
+
},
|
|
2722
|
+
};
|
|
2723
|
+
})();
|
|
2724
|
+
const platformSuspendArmed = durableSuspendInfraReady && (envLifetimeSuspendAt !== undefined || usageGovernance !== undefined);
|
|
2725
|
+
if (effectivePolicy || hooks?.preToolUse || egressTools.size > 0 || irreversibleTools.size > 0 || resourceSuspendEligible || platformSuspendArmed || spec.enablePlanMode === true) {
|
|
2664
2726
|
const adjudicate = effectivePolicy
|
|
2665
2727
|
? (req) => raceAbort(Promise.resolve(effectivePolicy.check({ ...req, budget: budgetSnapshot }, abortController.signal)), abortController.signal, () => ({
|
|
2666
2728
|
action: "deny",
|
|
@@ -2715,7 +2777,7 @@ export async function prepareTask(spec, deps, sessions, resume, internals, runne
|
|
|
2715
2777
|
}
|
|
2716
2778
|
if (decision.decisionReason === undefined || decision.decisionReason === "rule") {
|
|
2717
2779
|
const grant = inheritedAskGrants.get(req.toolCallId);
|
|
2718
|
-
if (grant !== undefined && grant.approver === onAsk && grant.argsJson === askGrantShapeOf(req.args)) {
|
|
2780
|
+
if (grant !== undefined && askApproverIdentity(grant.approver) === askApproverIdentity(onAsk) && grant.argsJson === askGrantShapeOf(req.args)) {
|
|
2719
2781
|
inheritedAskGrants.delete(req.toolCallId);
|
|
2720
2782
|
humanReviewRef.count += 1;
|
|
2721
2783
|
humanReviewRef.totalWaitMs += grant.waitMs;
|
|
@@ -2883,6 +2945,8 @@ export async function prepareTask(spec, deps, sessions, resume, internals, runne
|
|
|
2883
2945
|
ref.scope = scope;
|
|
2884
2946
|
};
|
|
2885
2947
|
const suspendLoopCapHit = (count, cap, detail) => {
|
|
2948
|
+
if (cap === undefined)
|
|
2949
|
+
return false;
|
|
2886
2950
|
if (count + 1 <= cap)
|
|
2887
2951
|
return false;
|
|
2888
2952
|
suspendLoopRef.hit = true;
|
|
@@ -2903,73 +2967,74 @@ export async function prepareTask(spec, deps, sessions, resume, internals, runne
|
|
|
2903
2967
|
const { snapshotId: _lineage, ...identity } = env.workspaceHandle();
|
|
2904
2968
|
return { ...identity, restoreMode: "park_only" };
|
|
2905
2969
|
};
|
|
2906
|
-
|
|
2907
|
-
|
|
2908
|
-
|
|
2909
|
-
|
|
2910
|
-
|
|
2911
|
-
|
|
2912
|
-
|
|
2913
|
-
|
|
2914
|
-
|
|
2915
|
-
|
|
2916
|
-
|
|
2917
|
-
|
|
2918
|
-
|
|
2919
|
-
|
|
2920
|
-
|
|
2921
|
-
|
|
2922
|
-
|
|
2923
|
-
|
|
2924
|
-
|
|
2925
|
-
|
|
2926
|
-
|
|
2927
|
-
|
|
2928
|
-
return false;
|
|
2929
|
-
}
|
|
2930
|
-
remoteHandle = { ...suspendableEnv.workspaceHandle(), snapshotId: snap.value };
|
|
2931
|
-
}
|
|
2932
|
-
else if (parkOnlyRemoteEnv !== undefined) {
|
|
2933
|
-
if (hasBackgroundShell(parkOnlyRemoteEnv) && spec.retainBackgroundProcesses !== true)
|
|
2934
|
-
await sweepBackgroundShells(parkOnlyRemoteEnv, defaultTaskRegistry);
|
|
2935
|
-
remoteHandle = parkOnlyHandle(parkOnlyRemoteEnv);
|
|
2936
|
-
}
|
|
2937
|
-
const token = mintCheckpointToken();
|
|
2938
|
-
const gate = { kind: "resource_limit", reason };
|
|
2939
|
-
const resourceLedgerOut = debitLedger(priorLedger, sliceSpend, resourceTotal);
|
|
2940
|
-
const mintedAt = Date.now();
|
|
2941
|
-
const cp = {
|
|
2942
|
-
token,
|
|
2943
|
-
version: resourceLedgerOut.totalWalltimeSec !== undefined ? WALLTIME_CHECKPOINT_VERSION : RESOURCE_CHECKPOINT_VERSION,
|
|
2944
|
-
scope: rs.scope,
|
|
2945
|
-
sessionId,
|
|
2946
|
-
leafId,
|
|
2947
|
-
gate,
|
|
2948
|
-
pendingAction: { kind: "resource_limit", reason },
|
|
2949
|
-
state: serializeCheckpointState(remoteHandle),
|
|
2950
|
-
status: "pending",
|
|
2951
|
-
createdAt: mintedAt,
|
|
2952
|
-
deadline: mintedAt + (sanitizedTtlMs(rs.ttlMs) ?? DEFAULT_RESOURCE_TTL_MS),
|
|
2953
|
-
suspendCount: priorSuspendCount,
|
|
2954
|
-
humanReview: humanReviewRef.count > 0
|
|
2955
|
-
? { count: humanReviewRef.count, totalWaitMs: humanReviewRef.totalWaitMs, gates: [...humanReviewRef.gates] }
|
|
2956
|
-
: undefined,
|
|
2957
|
-
resourceLedger: resourceLedgerOut,
|
|
2958
|
-
...(spec.durableApproval !== undefined ? { durableApproval: { ...spec.durableApproval } } : {}),
|
|
2959
|
-
};
|
|
2960
|
-
if (!(await commitSuspendSaga(token, cp, suspendableEnv, remoteHandle)))
|
|
2970
|
+
const mintResourceSuspend = async (reason, sliceSpend, hint) => {
|
|
2971
|
+
const rs = spec.resourceSuspend;
|
|
2972
|
+
if (!checkpointStore)
|
|
2973
|
+
return false;
|
|
2974
|
+
const scope = rs?.scope ?? checkpointScopeOf(spec);
|
|
2975
|
+
if (abortController.signal.aborted)
|
|
2976
|
+
return false;
|
|
2977
|
+
if (suspendLoopCapHit(priorLedger?.sliceCount ?? 0, maxSlices, " (resource slice limit)"))
|
|
2978
|
+
return false;
|
|
2979
|
+
const leafId = await session.getLeafId();
|
|
2980
|
+
if (!leafId)
|
|
2981
|
+
return false;
|
|
2982
|
+
if (abortController.signal.aborted)
|
|
2983
|
+
return false;
|
|
2984
|
+
let remoteHandle;
|
|
2985
|
+
if (suspendableEnv !== undefined) {
|
|
2986
|
+
if (hasBackgroundShell(suspendableEnv))
|
|
2987
|
+
await sweepBackgroundShells(suspendableEnv, defaultTaskRegistry);
|
|
2988
|
+
const snap = await suspendableEnv.suspendVM({ abortSignal: abortController.signal });
|
|
2989
|
+
if (!snap.ok) {
|
|
2990
|
+
remoteEnvFailures.push(remoteEnvFailureNote("suspendVM", snap.error, 1));
|
|
2991
|
+
deps.onError?.(new Error(`resource suspendVM failed (${snap.error.code}): ${snap.error.message}`, { cause: snap.error }), { phase: "config", sessionId });
|
|
2961
2992
|
return false;
|
|
2962
|
-
publishCommittedSuspend(token, gate, rs.scope, remoteHandle);
|
|
2963
|
-
try {
|
|
2964
|
-
await sessions.pin?.(sessionId);
|
|
2965
2993
|
}
|
|
2966
|
-
|
|
2967
|
-
|
|
2968
|
-
|
|
2969
|
-
|
|
2970
|
-
|
|
2994
|
+
remoteHandle = { ...suspendableEnv.workspaceHandle(), snapshotId: snap.value };
|
|
2995
|
+
}
|
|
2996
|
+
else if (parkOnlyRemoteEnv !== undefined) {
|
|
2997
|
+
if (hasBackgroundShell(parkOnlyRemoteEnv) && spec.retainBackgroundProcesses !== true)
|
|
2998
|
+
await sweepBackgroundShells(parkOnlyRemoteEnv, defaultTaskRegistry);
|
|
2999
|
+
remoteHandle = parkOnlyHandle(parkOnlyRemoteEnv);
|
|
3000
|
+
}
|
|
3001
|
+
const token = mintCheckpointToken();
|
|
3002
|
+
const gate = { kind: "resource_limit", reason, ...(hint !== undefined ? { resumeAfterMs: hint.resumeAfterMs } : {}) };
|
|
3003
|
+
const resourceLedgerOut = debitLedger(priorLedger, sliceSpend, resourceTotal);
|
|
3004
|
+
const mintedAt = Date.now();
|
|
3005
|
+
const cp = {
|
|
3006
|
+
token,
|
|
3007
|
+
version: resourceLedgerOut.totalTokens !== undefined ? TOKEN_CHECKPOINT_VERSION : RESOURCE_CHECKPOINT_VERSION,
|
|
3008
|
+
scope,
|
|
3009
|
+
sessionId,
|
|
3010
|
+
leafId,
|
|
3011
|
+
gate,
|
|
3012
|
+
pendingAction: { kind: "resource_limit", reason },
|
|
3013
|
+
state: serializeCheckpointState(remoteHandle),
|
|
3014
|
+
status: "pending",
|
|
3015
|
+
createdAt: mintedAt,
|
|
3016
|
+
deadline: mintedAt + Math.max(sanitizedTtlMs(rs?.ttlMs) ?? DEFAULT_RESOURCE_TTL_MS, hint !== undefined ? hint.resumeAfterMs + USAGE_WINDOW_REAP_MARGIN_MS : 0),
|
|
3017
|
+
suspendCount: priorSuspendCount,
|
|
3018
|
+
humanReview: humanReviewRef.count > 0
|
|
3019
|
+
? { count: humanReviewRef.count, totalWaitMs: humanReviewRef.totalWaitMs, gates: [...humanReviewRef.gates] }
|
|
3020
|
+
: undefined,
|
|
3021
|
+
resourceLedger: resourceLedgerOut,
|
|
3022
|
+
...(spec.durableApproval !== undefined ? { durableApproval: { ...spec.durableApproval } } : {}),
|
|
3023
|
+
};
|
|
3024
|
+
if (!(await commitSuspendSaga(token, cp, suspendableEnv, remoteHandle)))
|
|
3025
|
+
return false;
|
|
3026
|
+
publishCommittedSuspend(token, gate, scope, remoteHandle);
|
|
3027
|
+
try {
|
|
3028
|
+
await sessions.pin?.(sessionId);
|
|
2971
3029
|
}
|
|
2972
|
-
|
|
3030
|
+
catch (pinErr) {
|
|
3031
|
+
deps.onError?.(pinErr, { phase: "config", sessionId });
|
|
3032
|
+
}
|
|
3033
|
+
harness.requestStopAfterTurn();
|
|
3034
|
+
return true;
|
|
3035
|
+
};
|
|
3036
|
+
suspendForResource = resourceSuspendEligible ? mintResourceSuspend : undefined;
|
|
3037
|
+
suspendForPlatformLimit = durableSuspendInfraReady ? mintResourceSuspend : undefined;
|
|
2973
3038
|
suspendForReview = checkpointStore
|
|
2974
3039
|
? async (reason) => {
|
|
2975
3040
|
if (!checkpointStore)
|
|
@@ -3021,7 +3086,7 @@ export async function prepareTask(spec, deps, sessions, resume, internals, runne
|
|
|
3021
3086
|
const mintedAt = Date.now();
|
|
3022
3087
|
const cp = {
|
|
3023
3088
|
token,
|
|
3024
|
-
version: reviewLedger.
|
|
3089
|
+
version: reviewLedger.totalTokens !== undefined ? TOKEN_CHECKPOINT_VERSION : BINDING_CHECKPOINT_VERSION,
|
|
3025
3090
|
scope,
|
|
3026
3091
|
sessionId,
|
|
3027
3092
|
leafId,
|
|
@@ -3146,7 +3211,7 @@ export async function prepareTask(spec, deps, sessions, resume, internals, runne
|
|
|
3146
3211
|
const mintedAt = Date.now();
|
|
3147
3212
|
cp = {
|
|
3148
3213
|
token,
|
|
3149
|
-
version: approvalLedger.
|
|
3214
|
+
version: approvalLedger.totalTokens !== undefined ? TOKEN_CHECKPOINT_VERSION : BINDING_CHECKPOINT_VERSION,
|
|
3150
3215
|
scope,
|
|
3151
3216
|
sessionId,
|
|
3152
3217
|
leafId,
|
|
@@ -3537,7 +3602,7 @@ export async function prepareTask(spec, deps, sessions, resume, internals, runne
|
|
|
3537
3602
|
: undefined;
|
|
3538
3603
|
overheadState.promptChars = systemPrompt.length;
|
|
3539
3604
|
const preparedHolder = {};
|
|
3540
|
-
const buildPrepared = () => ({ harness, session, sessionId, taskRootPath, model, thinking, compModel, mcp: mcp, ...(a2a !== undefined && a2a.tools.length > 0 ? { a2a } : {}), blockedRef, outputRef, abortController, conflictRef, blockedToolCalls, nestedStats, ...(rewindNotes.length > 0 ? { rewindNotes } : {}), cwdRef: handsCwdRef, ...(worktreeSessionRef !== undefined ? { worktreeSessionRef } : {}), ...(workspaceStateSettle !== undefined ? { workspaceStateSettle } : {}), denyNarrowingPolicy, ...(basePolicyForResumeEdit !== undefined ? { basePolicyForResumeEdit } : {}), releaseSignal, cacheBreakDetector, cacheFingerprint, promptManifest, epochDeclaredSections, activeTools, ...(deferred.size > 0 ? { deferredToolNames: deferred } : {}), ownedEnv, suspendRef, reviewRef, remoteEnvFailures, reviewRequestRef, suspendLoopRef, suspendForResource, ...(
|
|
3605
|
+
const buildPrepared = () => ({ harness, session, sessionId, taskRootPath, model, thinking, compModel, mcp: mcp, ...(a2a !== undefined && a2a.tools.length > 0 ? { a2a } : {}), blockedRef, outputRef, abortController, conflictRef, blockedToolCalls, nestedStats, ...(rewindNotes.length > 0 ? { rewindNotes } : {}), cwdRef: handsCwdRef, ...(worktreeSessionRef !== undefined ? { worktreeSessionRef } : {}), ...(workspaceStateSettle !== undefined ? { workspaceStateSettle } : {}), denyNarrowingPolicy, ...(basePolicyForResumeEdit !== undefined ? { basePolicyForResumeEdit } : {}), releaseSignal, cacheBreakDetector, cacheFingerprint, promptManifest, epochDeclaredSections, activeTools, ...(deferred.size > 0 ? { deferredToolNames: deferred } : {}), ownedEnv, suspendRef, reviewRef, remoteEnvFailures, reviewRequestRef, suspendLoopRef, suspendForResource, ...(suspendForPlatformLimit !== undefined ? { suspendForPlatformLimit } : {}), ...(envLifetimeSuspendAt !== undefined ? { envLifetimeSuspendAt } : {}), ...(usageGovernance !== undefined ? { usageGovernance } : {}), callIssuedAtRef, brainCallGuardrailRef, suspendForReview, resourceLedger: priorLedger, liveSpendRef, humanReviewRef, now, tools, toolEffects, promptOverheadTokens, readTaskFile, recentlyReadFiles, normalizeAttachmentPath, isDedupStubResult, ...(onCompactionApplied ? { onCompactionApplied } : {}), compactionReuseRef, trimPressureRef, ...(memoryEngineSession ? { memoryEngineSession } : {}), ...(subagentRetain ? { subagentRetain } : {}), ...(lspDiagnostics && nudgeLspOnEdit ? { lspDiagnostics: { registry: lspDiagnostics, nudge: nudgeLspOnEdit, runIdent: lspRunIdent } } : {}), planModeRef, ...(dateChange ? { dateChange } : {}), ...(instructionSources ? { instructionSources } : {}), ...(workflowSizeGuideline ? { workflowSizeGuideline } : {}), ...(detectExternalChanges ? { detectExternalChanges } : {}), ...(toolsDeltaRef ? { toolsDeltaRef } : {}), ...(agentListing ? { agentListing } : {}), ...(skillsListing ? { skillsListing } : {}), announcedListingsRef, listBackgroundTasks, ...(turnSnapshotRef.current !== undefined ? { turnSnapshot: turnSnapshotRef.current } : {}), ...(centerCompactionCandidate !== undefined ? { centerCompactionCandidate } : {}) });
|
|
3541
3606
|
const prepared = buildPrepared();
|
|
3542
3607
|
preparedHolder.current = prepared;
|
|
3543
3608
|
return prepared;
|
|
@@ -5,8 +5,6 @@ import { type TaskOutcome } from "../task-outcome.js";
|
|
|
5
5
|
import { type SideQuerySpec, type SideQueryResult } from "../side-query.js";
|
|
6
6
|
import type { SessionStore } from "../session.js";
|
|
7
7
|
import type { AgentDefinition, RunnerDeps, TaskEvent, TaskResult, TaskSpec, TaskStream } from "../types.js";
|
|
8
|
-
import { DEFAULT_MAX_TURNS } from "../../config/defaults.js";
|
|
9
|
-
export { DEFAULT_MAX_TURNS };
|
|
10
8
|
export type ResumeTaskConfig = Omit<TaskSpec, "objective" | "sessionId">;
|
|
11
9
|
interface ResumeRun {
|
|
12
10
|
cp: Checkpoint;
|