@sema-agent/core 7.5.2 → 7.6.1

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.
Files changed (138) hide show
  1. package/CHANGELOG.md +67 -0
  2. package/dist/agents/agent-transcript-tool.d.ts +2 -2
  3. package/dist/agents/cascade.d.ts +4 -5
  4. package/dist/agents/cascade.js +12 -10
  5. package/dist/agents/repair-loop.d.ts +7 -5
  6. package/dist/agents/repair-loop.js +13 -15
  7. package/dist/agents/retain-ledger.d.ts +2 -3
  8. package/dist/agents/send-message-tool.d.ts +2 -2
  9. package/dist/agents/session-util.d.ts +2 -2
  10. package/dist/agents/subagent.d.ts +27 -46
  11. package/dist/agents/subagent.js +119 -105
  12. package/dist/agents/suspend-guard.d.ts +31 -19
  13. package/dist/agents/suspend-guard.js +14 -8
  14. package/dist/agents/teacher.d.ts +2 -2
  15. package/dist/agents/teacher.js +9 -9
  16. package/dist/agents/team.d.ts +6 -5
  17. package/dist/agents/team.js +10 -8
  18. package/dist/agents/verify.d.ts +8 -9
  19. package/dist/agents/verify.js +17 -17
  20. package/dist/core/a2a.js +2 -1
  21. package/dist/core/agent-definition.d.ts +172 -0
  22. package/dist/core/agent-definition.js +1 -0
  23. package/dist/core/ask-origin.d.ts +60 -7
  24. package/dist/core/ask-origin.js +26 -1
  25. package/dist/core/checkpoint-store.d.ts +78 -76
  26. package/dist/core/checkpoint-store.js +17 -1
  27. package/dist/core/delegation-frames.d.ts +298 -0
  28. package/dist/core/delegation-frames.js +21 -0
  29. package/dist/core/engine-notice.d.ts +555 -0
  30. package/dist/core/engine-notice.js +55 -0
  31. package/dist/core/gate-fold.d.ts +12 -0
  32. package/dist/core/gate-fold.js +158 -0
  33. package/dist/core/gate-lanes.d.ts +93 -0
  34. package/dist/core/gate-lanes.js +626 -0
  35. package/dist/core/gate-outcome.d.ts +189 -0
  36. package/dist/core/gate-outcome.js +70 -0
  37. package/dist/core/hands-band.d.ts +134 -0
  38. package/dist/core/hands-band.js +1 -0
  39. package/dist/core/hooks.d.ts +22 -177
  40. package/dist/core/hooks.js +53 -851
  41. package/dist/core/mcp-failure.d.ts +142 -0
  42. package/dist/core/mcp-failure.js +145 -0
  43. package/dist/core/mcp-server-spec.d.ts +217 -0
  44. package/dist/core/mcp-server-spec.js +1 -0
  45. package/dist/core/mcp.d.ts +21 -77
  46. package/dist/core/mcp.js +76 -150
  47. package/dist/core/model-seat.d.ts +99 -0
  48. package/dist/core/model-seat.js +1 -0
  49. package/dist/core/pause-registry.d.ts +131 -0
  50. package/dist/core/pause-registry.js +27 -0
  51. package/dist/core/reminder-mint.d.ts +10 -0
  52. package/dist/core/reminder-mint.js +3 -0
  53. package/dist/core/runner/assemble-result.d.ts +32 -41
  54. package/dist/core/runner/assemble-result.js +55 -74
  55. package/dist/core/runner/contracts.d.ts +427 -69
  56. package/dist/core/runner/denial-limit-arms.d.ts +1 -1
  57. package/dist/core/runner/denial-limit-arms.js +3 -3
  58. package/dist/core/runner/gate-exit.d.ts +242 -0
  59. package/dist/core/runner/gate-exit.js +124 -0
  60. package/dist/core/runner/park-commit.d.ts +17 -23
  61. package/dist/core/runner/park-commit.js +14 -15
  62. package/dist/core/runner/prepare-ask-lane.d.ts +0 -3
  63. package/dist/core/runner/prepare-ask-lane.js +3 -5
  64. package/dist/core/runner/prepare-boundary-parks.d.ts +3 -6
  65. package/dist/core/runner/prepare-boundary-parks.js +3 -3
  66. package/dist/core/runner/prepare-caps-and-workflow.d.ts +2 -7
  67. package/dist/core/runner/prepare-caps-and-workflow.js +1 -1
  68. package/dist/core/runner/prepare-delegation-surface.d.ts +2 -7
  69. package/dist/core/runner/prepare-gate-stations.d.ts +4 -7
  70. package/dist/core/runner/prepare-gate-stations.js +29 -54
  71. package/dist/core/runner/prepare-inherited-gate.js +1 -1
  72. package/dist/core/runner/prepare-memory.d.ts +44 -26
  73. package/dist/core/runner/prepare-park-ask.d.ts +2 -4
  74. package/dist/core/runner/prepare-park-ask.js +5 -5
  75. package/dist/core/runner/prepare-task.d.ts +2 -2
  76. package/dist/core/runner/prepare-task.js +8 -9
  77. package/dist/core/runner/prepare-wiring-manifest.d.ts +7 -15
  78. package/dist/core/runner/prepare-wiring-manifest.js +9 -10
  79. package/dist/core/runner/runtask.d.ts +20 -102
  80. package/dist/core/runner/runtask.js +119 -121
  81. package/dist/core/runner/terminal-projection.d.ts +22 -0
  82. package/dist/core/runner/terminal-projection.js +28 -0
  83. package/dist/core/runner-deps.d.ts +1416 -0
  84. package/dist/core/runner-deps.js +1 -0
  85. package/dist/core/runtime-caps.d.ts +164 -0
  86. package/dist/core/runtime-caps.js +1 -0
  87. package/dist/core/store-contracts/checkpoint-store-contract.d.ts +4 -1
  88. package/dist/core/store-contracts/checkpoint-store-contract.js +8 -2
  89. package/dist/core/task-event.d.ts +910 -0
  90. package/dist/core/task-event.js +1 -0
  91. package/dist/core/task-limits.d.ts +110 -0
  92. package/dist/core/task-limits.js +1 -0
  93. package/dist/core/task-result.d.ts +809 -0
  94. package/dist/core/task-result.js +1 -0
  95. package/dist/core/task-spec.d.ts +1370 -0
  96. package/dist/core/task-spec.js +1 -0
  97. package/dist/core/task-stream.d.ts +382 -0
  98. package/dist/core/task-stream.js +1 -0
  99. package/dist/core/terminal-cause.d.ts +137 -0
  100. package/dist/core/terminal-cause.js +9 -0
  101. package/dist/core/tool-policy.d.ts +43 -139
  102. package/dist/core/tool-policy.js +79 -112
  103. package/dist/core/tool-spec.d.ts +1174 -0
  104. package/dist/core/tool-spec.js +1 -0
  105. package/dist/core/types.d.ts +27 -7789
  106. package/dist/core/types.js +2 -76
  107. package/dist/core/warm-resume.d.ts +2 -2
  108. package/dist/core/wiring-manifest.d.ts +6 -3
  109. package/dist/core/workflow-journal-store.js +3 -4
  110. package/dist/engine/harness/agent-harness.d.ts +1 -1
  111. package/dist/index.d.ts +12 -8
  112. package/dist/index.js +9 -6
  113. package/dist/orchestration/builtin-workflows.d.ts +2 -2
  114. package/dist/orchestration/builtin-workflows.js +1 -1
  115. package/dist/orchestration/goal.d.ts +2 -2
  116. package/dist/orchestration/goal.js +8 -7
  117. package/dist/orchestration/run-spec.d.ts +2 -2
  118. package/dist/orchestration/run-spec.js +5 -3
  119. package/dist/orchestration/run-workflow-tool.d.ts +4 -4
  120. package/dist/orchestration/run-workflow-tool.js +4 -4
  121. package/dist/orchestration/workflow-governance.d.ts +4 -4
  122. package/dist/orchestration/workflow-governance.js +4 -2
  123. package/dist/orchestration/workflow-primitives.d.ts +1 -1
  124. package/dist/orchestration/workflow-primitives.js +1 -1
  125. package/dist/orchestration/workflow.d.ts +15 -4
  126. package/dist/orchestration/workflow.js +64 -39
  127. package/dist/prompts/supervisor.d.ts +1 -1
  128. package/dist/prompts/supervisor.js +3 -3
  129. package/dist/scenarios/scenario-registry.d.ts +3 -3
  130. package/dist/scenarios/scenario-registry.js +1 -1
  131. package/dist/scenarios/teacher-quickstart.d.ts +2 -2
  132. package/dist/server/http.d.ts +2 -2
  133. package/dist/stores/file/fs-atomic.d.ts +88 -12
  134. package/dist/stores/file/fs-atomic.js +184 -55
  135. package/dist/stores/file/index.d.ts +1 -0
  136. package/dist/stores/file/index.js +1 -0
  137. package/package.json +3 -1
  138. package/test/export-surface.snapshot.json +82 -22
@@ -25,7 +25,8 @@ import type { LockedPreflight } from "../locked-config.js";
25
25
  import type { MaterializedMcp } from "../mcp.js";
26
26
  import type { SessionStore } from "../session.js";
27
27
  import { type ToolResultStore } from "../tool-result-store.js";
28
- import { type ApprovalSettledBy, type OnAsk, type ToolPolicy } from "../tool-policy.js";
28
+ import { type OnAsk, type ToolPolicy } from "../tool-policy.js";
29
+ import type { GateOutcome } from "../gate-outcome.js";
29
30
  import type { RunnerDeps, RuntimeCaps, TaskSpec, ToolEffect, ToolExecuteContext } from "../types.js";
30
31
  import { type UsageWindow } from "../usage-window-store.js";
31
32
  import { type AutoModeArmReason, type WiringManifest, type WiringManifestMcpEntry } from "../wiring-manifest.js";
@@ -113,9 +114,7 @@ export interface PrepareWiringManifestInput {
113
114
  /** borrowed-readonly — the built harness the peer drain binds to. */
114
115
  harness: AgentHarness;
115
116
  /** borrowed-readonly — the durable-suspend holder; the drain's parked predicate reads `token` at run time. Not written here. */
116
- suspendRef: Prepared["suspendRef"];
117
- /** borrowed-readonly — the review holder; same read. Not written here. */
118
- reviewRef: Prepared["reviewRef"];
117
+ pausedRef: Prepared["pausedRef"];
119
118
  /** borrowed-readonly — the FROZEN approver seat (the notice's liveApprover fact). */
120
119
  frozenOnAsk: OnAsk | undefined;
121
120
  /** borrowed-readonly — the LIVE half of the inherited chain (the notice reads its content mandates). */
@@ -134,16 +133,9 @@ export interface PrepareWiringManifestResult {
134
133
  /** borrowed-mutable — the call ids the gate blocked or suspended (`Prepared.blockedToolCalls`). Writers: the gate; readers
135
134
  * delete one-shot. */
136
135
  blockedToolCalls: Set<string>;
137
- /** borrowed-mutable — the settlement sideband (`Prepared.approvalSettlement`). Writer: the gate; the frame mint reads and
136
+ /** borrowed-mutable — the gate-outcome sideband (`Prepared.gateOutcomes`). Writer: the gate station; the frame mint reads and
138
137
  * deletes. Nothing else may write it. */
139
- approvalSettlement: Map<string, {
140
- settledBy?: ApprovalSettledBy;
141
- approver?: string;
142
- resolution?: import("../tool-policy.js").AskDenyResolution;
143
- autoDenied?: true;
144
- }>;
145
- /** borrowed-mutable — the bare-human-rejection sideband. Writer: resolveAskBound; the gate handler consumes one-shot. */
146
- humanBareRejections: Set<string>;
138
+ gateOutcomes: Map<string, GateOutcome>;
147
139
  /** borrowed-mutable — the turn's halt fact (`Prepared.batchHaltRef`). Writer: the judgment site; cleared at the next request. */
148
140
  batchHaltRef: Prepared["batchHaltRef"];
149
141
  /** owned — whether any consumer of the blocked set is wired (populate only then). */
@@ -178,8 +170,8 @@ export interface PrepareWiringManifestResult {
178
170
  * server the leg's FROZEN entry snapshot declared, in declaration order, joined by name to this leg's
179
171
  * materialization statuses. Pure projection — no connection logic, no second look at any transport:
180
172
  * · a status `connected` ⇒ `connected` with the mounted roster size (the intake's post-filter count);
181
- * · a status `failed` ⇒ `failed` with the class the materialization stamped ({@link McpFailureCode})
182
- * and the remote text SECRET-REDACTED (an HTTP endpoint's error body rides the SDK's message
173
+ * · a status `failed` ⇒ `failed` with the failure record the materialization stamped (`errorCode`/`delivered`/
174
+ * `httpStatus` = the MCP vocabulary's `McpFailure` spread flat) and the remote text SECRET-REDACTED (an HTTP endpoint's error body rides the SDK's message
183
175
  * verbatim, and a body that echoes the bearer it rejected must not reach a stream consumer),
184
176
  * then neutralized + bounded to the reminder's own 240 (the same bound the once-per-session
185
177
  * ledger applies to that text — one face, one width);
@@ -22,7 +22,7 @@ export function mcpManifestEntries(entries, statuses) {
22
22
  name: entry.name,
23
23
  ...source,
24
24
  status: "failed",
25
- ...(status.errorCode !== undefined ? { errorCode: status.errorCode } : {}),
25
+ ...(status.errorCode !== undefined ? { errorCode: status.errorCode, delivered: status.delivered, ...(status.httpStatus !== undefined ? { httpStatus: status.httpStatus } : {}) } : {}),
26
26
  ...(status.error !== undefined ? { error: inlineUntrusted(status.error, 240) } : {}),
27
27
  toolCount: 0,
28
28
  };
@@ -87,17 +87,17 @@ const ungatedWarnedShapes = new WeakMap();
87
87
  function announceDurableGateUnavailable(args) {
88
88
  if (!args.forceDurableGate || args.storeWired)
89
89
  return;
90
- const cause = args.taskStoreNull ? "task_store_null" : "no_deployment_store";
90
+ const cause = args.taskStoreDisabled ? "task_store_disabled" : "no_deployment_store";
91
91
  const inheritedContentMandate = (args.parentConstraints ?? []).some((pc) => pc.contentMandate === true);
92
92
  const liveQuestionFace = args.liveQuestionFace && !inheritedContentMandate;
93
93
  deliverEngineNotice(args.onNotice, {
94
94
  code: "config.durable_gate_unavailable",
95
95
  message: `Durable approval gate mandated but unavailable: the runtime entitlement forceDurableGate is in force for this ` +
96
- `principal, but ${cause === "task_store_null" ? "this task disabled the checkpoint store (checkpointStore: null)" : "this deployment wired no checkpoint store"}, ` +
96
+ `principal, but ${cause === "task_store_disabled" ? 'this task disabled the checkpoint store (checkpointStore: "disabled")' : "this deployment wired no checkpoint store"}, ` +
97
97
  `so no interactive ask of this task can be parked for a durable answer. Asks resolve on the live chain instead ` +
98
98
  `(${args.liveApprover ? "a live approver answers permission asks in-stream" : "permission asks are denied fail-closed — no live approver is wired"}; ` +
99
99
  `${liveQuestionFace ? "a live question face answers AskUserQuestion in-stream" : args.liveQuestionFace ? "AskUserQuestion is withheld from the live face by an inherited durable mandate and refused" : "AskUserQuestion has no live face and is refused"}) ` +
100
- `and NO durable approval record is written. ${cause === "task_store_null" ? "Run this task with its store, or withdraw the entitlement for principals whose runs are machine-started." : "Wire a checkpoint store on this deployment, or withdraw the entitlement for principals served here."}`,
100
+ `and NO durable approval record is written. ${cause === "task_store_disabled" ? "Run this task with its store, or withdraw the entitlement for principals whose runs are machine-started." : "Wire a checkpoint store on this deployment, or withdraw the entitlement for principals served here."}`,
101
101
  detail: {
102
102
  sessionId: args.sessionId,
103
103
  runId: args.runId,
@@ -109,7 +109,7 @@ function announceDurableGateUnavailable(args) {
109
109
  });
110
110
  }
111
111
  export function prepareWiringManifest(input) {
112
- const { spec, deps, internals, resume, sessionId, runId, hostTaskId, taskScope, hooks, preToolUseObservational, policyLayers, effectivePolicy, handsEnabled, mcp, irreversibleTools, egressTools, toolEffects, ownedEnv, executionEnv, offloadStore, onceLedger, usageWindows, envLifetimeSuspendAt, runtimeCaps, resolvedInteractionPosture, durableQuestionFace, liveQuestionFace, checkpointStore, sessions, modelGateManifest, autoModeArmReason, lockedPreflight, peerLaneRefs, peerLaneActive, harness, suspendRef, reviewRef, frozenOnAsk, liveInheritedGate, delegation } = input;
112
+ const { spec, deps, internals, resume, sessionId, runId, hostTaskId, taskScope, hooks, preToolUseObservational, policyLayers, effectivePolicy, handsEnabled, mcp, irreversibleTools, egressTools, toolEffects, ownedEnv, executionEnv, offloadStore, onceLedger, usageWindows, envLifetimeSuspendAt, runtimeCaps, resolvedInteractionPosture, durableQuestionFace, liveQuestionFace, checkpointStore, sessions, modelGateManifest, autoModeArmReason, lockedPreflight, peerLaneRefs, peerLaneActive, harness, pausedRef, frozenOnAsk, liveInheritedGate, delegation } = input;
113
113
  const onAsk = spec.onAsk ?? deps.onAsk;
114
114
  const handWriteTools = handsEnabled && spec.handsReadOnly !== true
115
115
  ? Object.keys(HAND_TOOL_EFFECTS).filter((name) => {
@@ -144,8 +144,7 @@ export function prepareWiringManifest(input) {
144
144
  }
145
145
  const preToolContexts = new Map();
146
146
  const blockedToolCalls = new Set();
147
- const approvalSettlement = new Map();
148
- const humanBareRejections = new Set();
147
+ const gateOutcomes = new Map();
149
148
  const batchHaltRef = {};
150
149
  const blockedTracked = Boolean(hooks?.postToolUse || hooks?.preToolUse || hooks?.postToolUseFailure || hooks?.postToolBatch);
151
150
  const restoreSurfaceGap = ownedEnv !== undefined && isRemoteExecutionEnv(ownedEnv) && ownedEnv.capabilities.suspendable ? missingRestoreSurface(ownedEnv) : [];
@@ -220,7 +219,7 @@ export function prepareWiringManifest(input) {
220
219
  ownTokens: () => internals?.peerSelfRef?.current.ownTokens ?? [],
221
220
  refs: peerLaneRefs,
222
221
  selfName: () => internals?.explicitAgentName,
223
- parked: () => suspendRef.token !== undefined || reviewRef.token !== undefined,
222
+ parked: () => pausedRef.current !== undefined,
224
223
  });
225
224
  }
226
225
  const parkLaneArmed = wiringManifest.parkLane.effective === true;
@@ -231,7 +230,7 @@ export function prepareWiringManifest(input) {
231
230
  resourceSuspendEligible ||
232
231
  platformSuspendArmed ||
233
232
  spec.enablePlanMode === true;
234
- announceDurableGateUnavailable({ onNotice: deps.onNotice, forceDurableGate: runtimeCaps?.forceDurableGate === true, storeWired: checkpointStore !== undefined, taskStoreNull: spec.checkpointStore === null, liveApprover: isLiveApproverSeat(frozenOnAsk), liveQuestionFace: liveQuestionFace !== undefined, parentConstraints: liveInheritedGate?.parentConstraints, sessionId, runId, principal: spec.principal });
233
+ announceDurableGateUnavailable({ onNotice: deps.onNotice, forceDurableGate: runtimeCaps?.forceDurableGate === true, storeWired: checkpointStore !== undefined, taskStoreDisabled: spec.checkpointStore === "disabled", liveApprover: isLiveApproverSeat(frozenOnAsk), liveQuestionFace: liveQuestionFace !== undefined, parentConstraints: liveInheritedGate?.parentConstraints, sessionId, runId, principal: spec.principal });
235
234
  const hookIdentity = mintHookInvocationIdentity({
236
235
  sessionId,
237
236
  taskId: hostTaskId,
@@ -243,5 +242,5 @@ export function prepareWiringManifest(input) {
243
242
  });
244
243
  const hookContextConsumerWired = hooks?.preToolUse !== undefined || hooks?.postToolUse !== undefined || hooks?.postToolUseFailure !== undefined;
245
244
  const hookEnvFace = hookContextConsumerWired && (ownedEnv ?? deps.executionEnv) != null ? createHookEnvCapabilities(executionEnv) : undefined;
246
- return { onAsk, preToolContexts, blockedToolCalls, approvalSettlement, humanBareRejections, batchHaltRef, blockedTracked, incompleteSuspendAdapter, durableSuspendInfraReady, resourceSuspendEligible, usageGovernance, platformSuspendArmed, durableApproval, wiringManifest, parkLaneArmed, gateMachineryActive, hookIdentity, hookEnvFace };
245
+ return { onAsk, preToolContexts, blockedToolCalls, gateOutcomes, batchHaltRef, blockedTracked, incompleteSuspendAdapter, durableSuspendInfraReady, resourceSuspendEligible, usageGovernance, platformSuspendArmed, durableApproval, wiringManifest, parkLaneArmed, gateMachineryActive, hookIdentity, hookEnvFace };
247
246
  }
@@ -1,124 +1,42 @@
1
1
  import { type Model } from "../../internal/llm.js";
2
- import { type Checkpoint, type CheckpointToken, type PendingSteerEntry, type ReopenReason, type ResumeOutcome } from "../checkpoint-store.js";
3
- import type { RunInternals } from "./prepare-task.js";
2
+ import { type CheckpointToken, type ResumeOutcome } from "../checkpoint-store.js";
4
3
  import { type TaskOutcome } from "../task-outcome.js";
5
4
  import { type SideQuerySpec, type SideQueryResult } from "../side-query.js";
6
5
  import type { SessionStore } from "../session.js";
7
6
  import { type RecoveredOrphan } from "../session-reconcile.js";
8
- import { type ApprovalSettledBy } from "../tool-policy.js";
7
+ import type { GateOutcome } from "../gate-outcome.js";
8
+ import { type McpDelivered } from "../mcp-failure.js";
9
9
  import type { AgentDefinition, ModelRef, RunnerDeps, TaskEvent, TaskResult, TaskSpec, TaskStream } from "../types.js";
10
- /**
11
- * Config re-supplied to {@link Runner.resume} (design/45). A suspended task's tools / model / policy /
12
- * hooks cannot be reconstructed from a checkpoint token (the session stores neither tool implementations
13
- * nor the hand band), so the caller's trusted control plane re-supplies the same {@link TaskSpec} it ran
14
- * with — minus the conversation bits: `sessionId` comes from the checkpoint and `objective` is replaced by
15
- * an internally-generated continuation, so both are omitted.
16
- */
17
- export type ResumeTaskConfig = Omit<TaskSpec, "objective" | "sessionId">;
18
- /** design/45 resume plan threaded from {@link Runner.resume} into the shared run loop. */
19
- interface ResumeRun {
20
- cp: Checkpoint;
21
- /**
22
- * RB-152 (2026-07-25, 按面收口): did the APPROVED ACTION actually begin executing?
23
- *
24
- * The reopen compensation used to key on an error-code whitelist (`resume.env_failed` /
25
- * `resume.session_not_found` / `resume.tool_unavailable`). That is a proxy for the thing that actually
26
- * matters, and every time a NEW way to exit without running the action appeared, the whitelist did not
27
- * know about it: a caller's abort landing anywhere between the CAS and `tool.execute` — across
28
- * `SessionStore.acquire` (pluggable, cross-network on a durable backend), the MCP reconnect, the env
29
- * rebuild, `resumeVM`, tool materialization — produced a `failed` result with NO errorCode, no reopen,
30
- * and a human approval consumed for work that never happened. Two rounds of fixes (RB-77, RB-109) each
31
- * moved that window rather than closing it, because both extended the whitelist.
32
- *
33
- * This binds the compensation to the FACT instead: set the instant before `tool.execute` for the gated
34
- * call (the same `onExecuteStart` signal the orphan-reconcile split already trusts). Every terminal —
35
- * throw OR returned result — asks one question: was the checkpoint consumed while this stayed false?
36
- */
37
- pendingActionStarted?: boolean;
38
- /** Validated against `cp.gate.kind` at the resume entry: human/irreversible_ask→`policy_ask`,
39
- * resource_limit→`resource_limit` (design/74), needs_review→`dry_run_review` (design/76 §2.5),
40
- * plan_review→`plan_review` (design/80 D-B). The gate-match guard in `resumeStream` enforces the
41
- * correlation. design/144 §3: `wake` is the NON-GATE arm — only a checkpoint awaiting NO gate
42
- * decision passes the resume entry with it (gate purity, `wake.gate_pending`); the run loop skips
43
- * `applyResumeDecision` for it (no pending action to resolve) and re-enters via the continuation +
44
- * pendingSteer tail alone. */
45
- outcome: Extract<ResumeOutcome, {
46
- gate: "policy_ask" | "resource_limit" | "dry_run_review" | "plan_review" | "wake";
47
- }>;
48
- /** design/144 §3 (X5) — the wake's own operator message, validated (`validatePendingSteer`) at the
49
- * resume entry and carried SEPARATELY from the checkpoint's parked `pendingSteer`: a message-bearing
50
- * wake of a checkpoint that ALSO holds a parked steer must deliver BOTH (park order: parked first,
51
- * wake message second), each under its own trusted framing — the old merge-into-the-slot shape
52
- * silently DISPLACED the parked (undelivered) supervisor steer. Wake outcomes only. */
53
- wakeMessage?: Omit<PendingSteerEntry, "seq">;
54
- /** design/373 §4.3 (D2) — the userPromptSubmit screen's `additionalContext` for {@link wakeMessage},
55
- * captured at the resume ENTRY (the message is screened once, pre-CAS, on the resuming process's
56
- * hook) and delivered by the drain as the engine's own reminder AHEAD of the wake frame — carrying
57
- * it forward is what keeps the hook single-run (re-screening at the drain would be the double-run
58
- * §4.3-3 reserves for the cross-process parked leg). Present only when a wake message passed a
59
- * screen that supplied context. */
60
- wakeMessageHookContext?: string;
61
- /** Compensation hook (design/45/49): called iff the resumed run fails with `resume.env_failed` (post-CAS
62
- * workspace `resumeVM` failed) OR `resume.tool_unavailable` (P-7: the approved tool vanished) — in both
63
- * the CAS already consumed the checkpoint but the pending action never ran. `resumeStream` supplies a
64
- * closure that reopens the checkpoint (`resolved → pending`) so a retry re-resumes the SAME suspended work
65
- * instead of losing it to a forced "re-initiate". design/80 D-1 (reopen-by-reason): the `reason` is
66
- * recorded on the reopened row so the next re-resume validates per reason — an `env_failed` reopen must
67
- * replay the persisted winner (a system retry of the approved action), while a `tool_unavailable` reopen
68
- * lets a human re-decide with the tool present (a fresh decision is allowed — preserves P-7). */
69
- onEnvRestoreFailed?: (reason: ReopenReason) => Promise<void>;
70
- /** RB-471/FR-C1 — set in the run body right after `applyResumeDecision` completes: the negative-
71
- * decision twin of `pendingActionStarted`. A reject/deny consumes its gate BY BEING DELIVERED, and
72
- * this bit is the delivery fact — every throw-arm cause (prepare failure, `session_not_found`, a
73
- * pre-delivery abort) and the walltime-exhausted settle fire BEFORE it is set, so an undelivered
74
- * negative decision still reopens as `env_failed` (the retry replays the persisted decision; it
75
- * never re-asks — design/80 D-1), closing the RB-152/RB-70 loss class the first RB-471 cut reopened. */
76
- decisionDelivered?: boolean;
77
- }
10
+ import type { ResumeRun, ResumeTaskConfig, RunInternals, RunnerSelfSeat } from "./contracts.js";
11
+ export type { ResumeTaskConfig } from "./contracts.js";
78
12
  /** The `tool_end` body fields projected from a harness tool result — output/truncated/totalChars via
79
13
  * {@link toolOutputFrom} and the CC card via {@link structuredFrom}. Single construction point for BOTH
80
14
  * the live loop's frames and the resumed batch's frames (`resolvePendingCall` + the deferred-sibling
81
15
  * close): the resumed frames used to carry only `isError`, so a client rendering tool output from frames
82
16
  * showed an empty body for every durable-approved call. Same projection = same source as the transcript.
83
- * Also the one place `settledBy` reaches a frame — see the parameter. */
17
+ * Also the one place the gate outcome reaches a frame — see the parameter. */
84
18
  declare function toolEndBodyFrom(result: unknown, isError: boolean,
85
- /** What ended the approval this call was waiting on, supplied by the CALLER of this projection — the
86
- * live loop reads it off the gate's per-call sideband, the resumed leg off the decide. Deliberately
87
- * a parameter and never derived from `result`: a tool's own `details` (which post-tool hooks may
88
- * also replace) is writable by layers that adjudicate nothing, so reading provenance out of it would
89
- * let a failing tool claim a person approved it. Omitted ⇒ the caller supplied no source: the call
90
- * settled no approval, OR an approval settled whose decider named none (a caller predating the
91
- * field) — absence is not a fact about the call (see the `tool_end.settledBy` doc, the one home). */
92
- settledBy?: ApprovalSettledBy,
93
- /** design/252 G-7 — WHOSE settlement, from the same caller and the same channel as `settledBy`, and
94
- * for the same reason it is a parameter: an attribution read out of a tool's own result would let a
95
- * tool name the person who approved it. Omitted ⇒ this call's settlement named nobody. */
96
- approver?: string,
97
- /** The ask resolver's deny-arm classification — same caller, same engine-owned channel and the same
98
- * never-derived-from-`result` posture as the two above. Omitted ⇒ not an ask-resolution deny. */
99
- resolution?: import("../tool-policy.js").AskDenyResolution,
19
+ /** The gate's record of the pass that admitted or refused this call, supplied by the CALLER of this
20
+ * projection — the live loop reads it off the gate's per-call sideband, the resumed leg off the decide's
21
+ * minted record. Deliberately a parameter and never derived from `result`: a tool's own `details`
22
+ * (which post-tool hooks may also replace) is writable by layers that adjudicate nothing, so reading
23
+ * provenance out of it would let a failing tool claim a person approved it. Omitted ⇒ the call never
24
+ * went through the gate (see the `tool_end.gate` doc, the one home). */
25
+ gate?: GateOutcome,
100
26
  /** WHICH call this run's committed durable park is holding ({@link gatedCallIdOf}), for the frames the
101
- * abort short-circuits. Same never-derived-from-`result` posture as the three above, and for the
27
+ * abort short-circuits. Same never-derived-from-`result` posture as the outcome above, and for the
102
28
  * sharpest version of that reason: this one is an assertion about a DIFFERENT call, so a tool able to
103
29
  * author it could point an approval UI at a call nobody is waiting on. Omitted ⇒ no park is holding a
104
30
  * call (nothing parked, or the park that did holds none), and the frame then carries no id at all. */
105
- gatedCallIdOfRun?: string,
106
- /** #557 — the classifier denial-limit fallback's own auto-deny marker, from the same engine-owned
107
- * settlement sideband as `resolution` (same never-derived-from-`result` posture). Omitted ⇒ absent.
108
- * The pair `settledBy:"timeout"` + `resolution:"window_expired"` WITHOUT this bit is the approval
109
- * factory's own `approvalTimeoutMs` window; a durable park's expiry is neither — the decide lane's
110
- * emitter passes no `resolution` at all (see the `tool_end.autoDenied` doc on the event type). */
111
- autoDenied?: true): {
31
+ gatedCallIdOfRun?: string): {
112
32
  output?: unknown;
113
33
  truncated?: boolean;
114
34
  totalChars?: number;
115
35
  structured?: unknown;
116
36
  errorCode?: string;
37
+ delivered?: McpDelivered;
117
38
  gatedCallId?: string;
118
- settledBy?: ApprovalSettledBy;
119
- approver?: string;
120
- resolution?: import("../tool-policy.js").AskDenyResolution;
121
- autoDenied?: true;
39
+ gate?: GateOutcome;
122
40
  };
123
41
  /**
124
42
  * scan-1/A1 — the BODY of the synthetic `tool_end` that closes a reconcile-recovered orphan. ONE
@@ -160,7 +78,7 @@ export declare function raceUntilDeadline<T>(p: Promise<T>, deadline: number): P
160
78
  * A stateless task runner. Holds shared deps (the external brain, model catalog) and an
161
79
  * in-memory session store so that passing a `sessionId` continues a prior conversation.
162
80
  */
163
- export declare class Runner {
81
+ export declare class Runner implements RunnerSelfSeat {
164
82
  private deps;
165
83
  readonly sessions: SessionStore;
166
84
  /** Per-sessionId serialization so two tasks never mutate one session concurrently. */
@@ -440,12 +358,12 @@ export declare class Runner {
440
358
  * factory-minted remote/worktree lane captured an already-destroyed env (plain host/static lanes were
441
359
  * false-green).
442
360
  *
443
- * design/49 v1.5 / design/76 §2.5: a SUSPENDED (`suspendRef.token`) or `needs_review` (`reviewRef.token`) pause
361
+ * design/49 v1.5 / design/76 §2.5: a committed durable pause (`pausedRef.current`, any gate kind)
444
362
  * `suspendVM`-paused the env and persisted its `workspaceHandle` into the checkpoint — destroying it would
445
363
  * discard the paused VM and make resume fail to restore. Skip teardown; `resume()` rebuilds + `resumeVM`s it. A
446
364
  * cancelled pause is reaped via `TaskStream.destroy()` (design/51); an abandoned one is the service container
447
365
  * reaper's backstop. The gate here MIRRORS the tail's reap-stash (same durable fact
448
- * `suspendRef.token===undefined && reviewRef.token===undefined`), so exactly one path owns the env's fate.
366
+ * `pausedRef.current === undefined`), so exactly one path owns the env's fate.
449
367
  */
450
368
  private teardownOwnedEnv;
451
369
  }