@sema-agent/core 7.11.2 → 7.13.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.
Files changed (91) hide show
  1. package/CHANGELOG.md +86 -13
  2. package/dist/core/ask-origin.d.ts +55 -0
  3. package/dist/core/ask-origin.js +21 -0
  4. package/dist/core/auto-mode-arming.d.ts +10 -14
  5. package/dist/core/auto-mode-arming.js +3 -9
  6. package/dist/core/auto-mode-defaults.d.ts +0 -2
  7. package/dist/core/auto-mode-defaults.js +0 -1
  8. package/dist/core/auto-mode-rebuild.d.ts +6 -13
  9. package/dist/core/auto-mode-rebuild.js +0 -2
  10. package/dist/core/auto-mode.d.ts +30 -89
  11. package/dist/core/auto-mode.js +12 -59
  12. package/dist/core/checkpoint-store.d.ts +1 -3
  13. package/dist/core/engine-notice.d.ts +18 -0
  14. package/dist/core/gate-fold.js +1 -9
  15. package/dist/core/gate-lanes.d.ts +0 -40
  16. package/dist/core/gate-lanes.js +18 -26
  17. package/dist/core/governance-codes.d.ts +1 -1
  18. package/dist/core/governance-codes.js +2 -0
  19. package/dist/core/hooks.d.ts +7 -1
  20. package/dist/core/hooks.js +1 -1
  21. package/dist/core/runner/assemble-result.d.ts +45 -1
  22. package/dist/core/runner/assemble-result.js +4 -1
  23. package/dist/core/runner/compaction-seams.d.ts +42 -0
  24. package/dist/core/runner/compaction-seams.js +80 -0
  25. package/dist/core/runner/contracts.d.ts +85 -15
  26. package/dist/core/runner/denial-limit-arms.d.ts +10 -13
  27. package/dist/core/runner/denial-limit-arms.js +12 -9
  28. package/dist/core/runner/gate-exit.js +9 -1
  29. package/dist/core/runner/permission-rule-lanes.d.ts +2 -1
  30. package/dist/core/runner/permission-rule-lanes.js +2 -1
  31. package/dist/core/runner/prepare-caps-and-workflow.d.ts +1 -1
  32. package/dist/core/runner/prepare-caps-and-workflow.js +0 -5
  33. package/dist/core/runner/prepare-policy-chain.js +3 -2
  34. package/dist/core/runner/prepare-protocol-tools.js +5 -0
  35. package/dist/core/runner/prepare-safety-scan.js +11 -16
  36. package/dist/core/runner/prepare-suspend-saga.d.ts +0 -2
  37. package/dist/core/runner/prepare-suspend-saga.js +2 -10
  38. package/dist/core/runner/prepare-task.d.ts +9 -1
  39. package/dist/core/runner/prepare-task.js +7 -2
  40. package/dist/core/runner/prepare-wiring-manifest.d.ts +1 -1
  41. package/dist/core/runner/prepare-wiring-manifest.js +1 -8
  42. package/dist/core/runner/resume-claim.d.ts +2 -2
  43. package/dist/core/runner/resume-preflight.d.ts +2 -2
  44. package/dist/core/runner/run-attachment-seats.d.ts +6 -4
  45. package/dist/core/runner/run-attachment-seats.js +2 -2
  46. package/dist/core/runner/run-git-lane.d.ts +1 -1
  47. package/dist/core/runner/run-harness-handlers.js +2 -0
  48. package/dist/core/runner/run-identity-wiring.d.ts +21 -33
  49. package/dist/core/runner/run-identity-wiring.js +6 -3
  50. package/dist/core/runner/run-leg.d.ts +108 -0
  51. package/dist/core/runner/run-leg.js +713 -0
  52. package/dist/core/runner/run-notification-lane.d.ts +56 -0
  53. package/dist/core/runner/run-notification-lane.js +128 -0
  54. package/dist/core/runner/run-reasoning-seat.d.ts +5 -5
  55. package/dist/core/runner/run-reasoning-seat.js +7 -7
  56. package/dist/core/runner/run-recovery-lanes.d.ts +4 -17
  57. package/dist/core/runner/run-recovery-lanes.js +5 -4
  58. package/dist/core/runner/run-settle-and-teardown.d.ts +113 -0
  59. package/dist/core/runner/run-settle-and-teardown.js +432 -0
  60. package/dist/core/runner/run-stop-and-final-verify.d.ts +2 -2
  61. package/dist/core/runner/run-terminal-adoption.d.ts +99 -0
  62. package/dist/core/runner/run-terminal-adoption.js +200 -0
  63. package/dist/core/runner/run-turn-boundary.js +5 -4
  64. package/dist/core/runner/runtask.d.ts +10 -79
  65. package/dist/core/runner/runtask.js +83 -1557
  66. package/dist/core/runner/stream-lifecycle-verbs.js +10 -1
  67. package/dist/core/runner-deps.d.ts +4 -14
  68. package/dist/core/store-contracts/workflow-journal-store-contract.d.ts +7 -0
  69. package/dist/core/store-contracts/workflow-journal-store-contract.js +85 -0
  70. package/dist/core/task-stream.d.ts +10 -1
  71. package/dist/core/tool-face.d.ts +8 -0
  72. package/dist/core/tool-face.js +1 -0
  73. package/dist/core/tool-policy.d.ts +42 -96
  74. package/dist/core/tool-policy.js +1 -11
  75. package/dist/core/tool-registry.d.ts +11 -3
  76. package/dist/core/tool-registry.js +7 -1
  77. package/dist/core/tool-roster.d.ts +26 -0
  78. package/dist/core/tool-roster.js +38 -7
  79. package/dist/core/trace.d.ts +6 -7
  80. package/dist/core/wiring-manifest.d.ts +5 -22
  81. package/dist/core/wiring-manifest.js +3 -11
  82. package/dist/core/workflow-journal-store.d.ts +35 -4
  83. package/dist/core/workflow-journal-store.js +19 -2
  84. package/dist/index.d.ts +6 -5
  85. package/dist/index.js +6 -5
  86. package/dist/orchestration/workflow.js +2 -0
  87. package/dist/server/http.js +2 -1
  88. package/dist/stores/file/workflow-journal-store.d.ts +7 -10
  89. package/dist/stores/file/workflow-journal-store.js +2 -4
  90. package/package.json +1 -1
  91. package/test/export-surface.snapshot.json +21 -11
@@ -0,0 +1,200 @@
1
+ import { DEFAULT_COMPACTION_INSTRUCTIONS, maybeCompact } from "../auto-compaction.js";
2
+ import { DEFAULT_COMPACTION_SETTINGS } from "../../internal/harness.js";
3
+ import { eventDefaultOn } from "../../prompt-assembly/event-registry.js";
4
+ import { appendInterruptionMarker, reconcileInterruptedSession } from "../session-reconcile.js";
5
+ import { emitTrace } from "../trace.js";
6
+ import { deliverEngineNotice, undrainedUserInputNotices } from "../types.js";
7
+ import { answerSettled, errorCodeOf } from "./assemble-result.js";
8
+ import { awaitChargeWithSlowDisclosure, discloseUnevaluableWindow } from "./clock-and-limits.js";
9
+ import { buildWorkingFileAttachments, centerAdoptionOption, contextInstructionFilesOption, emitInputTruncated, forkContextOption } from "./compaction-call-options.js";
10
+ import { compactionHookOptions, recordCompactionReuse, seamCCompactionOptions } from "./compaction-seams.js";
11
+ import { gitRestateOption } from "./git-leg-delivery.js";
12
+ import { MAX_CONSECUTIVE_COMPACTION_FAILURES } from "./compaction-knobs.js";
13
+ import { reconciledToolEndBody } from "./tool-end-body.js";
14
+ export async function runTerminalAdoption(input) {
15
+ const { spec, queue, prepared, rs, stats, ident, emitCommitted, startedToolCallIds, toolLabels, timeout, compactionBrain, compactionBreaker, windowSafetyOptions, undrainedUserAtEnd, userInputLostAtEnd, final, abortedLive, userInterruptedLive, runner, sessions, next } = input;
16
+ let { threw } = input;
17
+ const settled = answerSettled(final, userInputLostAtEnd.current || prepared.workCutRef.continuation || prepared.workCutRef.abortedBeforeTurnEnd);
18
+ if (threw === undefined && prepared.brainCallGuardrailRef.timedOut !== undefined) {
19
+ threw = prepared.brainCallGuardrailRef.timedOut;
20
+ }
21
+ if (threw === undefined && prepared.gateStopRef.terminal !== undefined) {
22
+ threw = prepared.gateStopRef.terminal;
23
+ }
24
+ if (rs.limits.platformTerminal !== undefined) {
25
+ threw = rs.limits.platformTerminal;
26
+ }
27
+ if (prepared.usageGovernance !== undefined) {
28
+ try {
29
+ await awaitChargeWithSlowDisclosure(prepared.usageGovernance.commit(stats.tokens, rs.telemetry.unpricedSpend ? undefined : stats.costMicroUsd, Date.now()), () => runner.deps.onError?.(new Error("the usage ledger's FINAL charge has not settled after 10s — still waiting (a charge is never abandoned: walking away would double-charge on a later flush). A wedged ledger store wedges this teardown, now visibly."), { phase: "config", sessionId: prepared.sessionId }));
30
+ }
31
+ catch (flushErr) {
32
+ runner.deps.onError?.(flushErr, { phase: "config", sessionId: prepared.sessionId });
33
+ }
34
+ }
35
+ const committedPause = prepared.pausedRef.current;
36
+ const durablyPaused = committedPause !== undefined;
37
+ const interrupted = !durablyPaused &&
38
+ (threw !== undefined || timeout.fired || rs.limits.turnsExceeded || rs.limits.budgetHit !== undefined || abortedLive || final?.stopReason === "aborted");
39
+ let orphansClosed = 0;
40
+ let reconcileComplete = false;
41
+ if (interrupted) {
42
+ try {
43
+ const report = await reconcileInterruptedSession(prepared.session, prepared.toolEffects, undefined, startedToolCallIds);
44
+ orphansClosed = report.recovered.length;
45
+ for (const orphan of report.recovered) {
46
+ queue.push({ type: "tool_end", toolCallId: orphan.toolCallId, toolName: orphan.toolName, ...(toolLabels.has(orphan.toolName) ? { label: toolLabels.get(orphan.toolName) } : {}), isError: true, ...reconciledToolEndBody(orphan, prepared.structuredProjector), ...ident() });
47
+ emitCommitted(orphan.entryId, "toolResult", orphan.toolCallId);
48
+ }
49
+ reconcileComplete = true;
50
+ }
51
+ catch (reconcileErr) {
52
+ runner.deps.onError?.(reconcileErr instanceof Error ? reconcileErr : new Error(String(reconcileErr)), {
53
+ phase: "interrupt-reconcile",
54
+ sessionId: prepared.sessionId,
55
+ });
56
+ }
57
+ try {
58
+ await prepared.harness.flushQueuedSessionWrites();
59
+ }
60
+ catch (flushErr) {
61
+ runner.deps.onError?.(flushErr instanceof Error ? flushErr : new Error(String(flushErr)), {
62
+ phase: "interrupt-reconcile",
63
+ sessionId: prepared.sessionId,
64
+ });
65
+ }
66
+ }
67
+ if (interrupted && userInterruptedLive && reconcileComplete && !settled) {
68
+ try {
69
+ const entryId = await appendInterruptionMarker(prepared.session, { toolUseInFlight: orphansClosed > 0 });
70
+ emitCommitted(entryId, "user");
71
+ }
72
+ catch (markerErr) {
73
+ runner.deps.onError?.(markerErr instanceof Error ? markerErr : new Error(String(markerErr)), {
74
+ phase: "interrupt-reconcile",
75
+ sessionId: prepared.sessionId,
76
+ });
77
+ }
78
+ }
79
+ let migratedParked = { steer: 0, followUp: 0 };
80
+ if (committedPause !== undefined && runner.deps.checkpointStore !== undefined) {
81
+ const parkToken = committedPause.cause.token;
82
+ const parkScope = committedPause.scope;
83
+ const store = runner.deps.checkpointStore;
84
+ const carried = [];
85
+ for (const record of prepared.harness.readParkableUserInputs()) {
86
+ try {
87
+ if (!(await store.setPendingSteer(parkToken, parkScope, record)))
88
+ break;
89
+ carried.push(record);
90
+ }
91
+ catch (parkErr) {
92
+ runner.deps.onError?.(parkErr instanceof Error ? parkErr : new Error(String(parkErr)), {
93
+ phase: "config",
94
+ sessionId: prepared.sessionId,
95
+ });
96
+ const parkCode = errorCodeOf(parkErr);
97
+ if (parkCode === "steering.invalid_content" || parkCode === "steering.queue_full")
98
+ continue;
99
+ break;
100
+ }
101
+ }
102
+ migratedParked = prepared.harness.dropParkedUserInputs(carried);
103
+ }
104
+ if (undrainedUserAtEnd.current !== undefined) {
105
+ const remaining = {
106
+ steer: Math.max(0, undrainedUserAtEnd.current.steer - migratedParked.steer),
107
+ followUp: Math.max(0, undrainedUserAtEnd.current.followUp - migratedParked.followUp),
108
+ };
109
+ for (const notice of undrainedUserInputNotices(remaining, spec.taskId ?? prepared.sessionId, prepared.sessionId, prepared.runId)) {
110
+ deliverEngineNotice(runner.deps.onNotice, notice);
111
+ }
112
+ }
113
+ if (rs.attach.attachState?.postCompactPending === true && (rs.attach.attachmentsCfg?.backgroundTasks ?? eventDefaultOn("background_tasks")) === true) {
114
+ emitTrace(rs.telemetry.tracer, () => ({ kind: "compaction.announce_dropped", version: 1, taskId: rs.telemetry.taskId, ts: Date.now() }));
115
+ }
116
+ const comp = await finish(spec, prepared, {
117
+ telemetry: { tracer: rs.telemetry.tracer, taskId: rs.telemetry.taskId },
118
+ skipCompaction: durablyPaused || (abortedLive && settled) || compactionBreaker.failures >= MAX_CONSECUTIVE_COMPACTION_FAILURES,
119
+ minTokens: rs.counters.compactionFloor,
120
+ brain: compactionBrain,
121
+ windowSafety: windowSafetyOptions(prepared.model),
122
+ onCompactionFailed: (reason) => queue.push({ type: "compaction_outcome", outcome: "failed", trigger: "auto", reason, ...ident() }),
123
+ cancelled: abortedLive,
124
+ }, runner, sessions);
125
+ return await next({ threw, comp, answerSettled: settled });
126
+ }
127
+ async function finish(spec, prepared, opts, runner, sessions) {
128
+ let comp;
129
+ if (!opts?.skipCompaction) {
130
+ try {
131
+ const finishComp = await maybeCompact({
132
+ session: prepared.session,
133
+ epochDeclaredSections: prepared.epochDeclaredSections,
134
+ ...centerAdoptionOption(prepared),
135
+ model: prepared.model,
136
+ compactionModel: prepared.compModel,
137
+ ...forkContextOption(prepared, false),
138
+ brain: opts?.brain ?? runner.deps.brain,
139
+ getApiKeyAndHeaders: spec.getApiKeyAndHeaders,
140
+ thinking: prepared.thinking,
141
+ settings: { ...DEFAULT_COMPACTION_SETTINGS, ...spec.compaction },
142
+ customInstructions: spec.compaction?.instructions ?? DEFAULT_COMPACTION_INSTRUCTIONS,
143
+ minTokens: opts?.minTokens,
144
+ overheadTokens: prepared.promptOverheadTokens,
145
+ ...(prepared.activeTools.size > 0 ? { activeTools: [...prepared.activeTools] } : {}),
146
+ onInputTruncated: emitInputTruncated(opts?.telemetry?.tracer ?? spec.tracer ?? runner.deps.tracer, opts?.telemetry?.taskId ?? spec.taskId ?? prepared.sessionId),
147
+ ...(opts?.windowSafety ?? {}),
148
+ workingFileAttachments: buildWorkingFileAttachments(spec, prepared),
149
+ ...contextInstructionFilesOption(prepared),
150
+ ...(prepared.onCompactionApplied ? { onApplied: prepared.onCompactionApplied } : {}),
151
+ ...seamCCompactionOptions(runner, prepared),
152
+ ...gitRestateOption(prepared),
153
+ ...compactionHookOptions(runner, spec, prepared.sessionId, "auto", prepared.hookIdentity, {
154
+ timeoutMs: prepared.hookTimeoutMs,
155
+ ...(opts?.cancelled === true ? { signal: prepared.abortController.signal } : {}),
156
+ }),
157
+ });
158
+ recordCompactionReuse(runner, prepared, finishComp);
159
+ if (finishComp.unevaluableWindow) {
160
+ discloseUnevaluableWindow(finishComp.unevaluableWindow, prepared, opts?.telemetry?.tracer ?? spec.tracer ?? runner.deps.tracer, opts?.telemetry?.taskId ?? spec.taskId ?? prepared.sessionId, runner.deps.onError);
161
+ }
162
+ comp = finishComp;
163
+ }
164
+ catch (err) {
165
+ const failMsg = String(err instanceof Error ? err.message : err);
166
+ const failReason = failMsg.length > 512 ? `${failMsg.slice(0, 512)}…` : failMsg;
167
+ emitTrace(opts?.telemetry?.tracer ?? spec.tracer ?? runner.deps.tracer, () => ({
168
+ kind: "compaction.failed",
169
+ version: 1,
170
+ taskId: opts?.telemetry?.taskId ?? spec.taskId ?? prepared.sessionId,
171
+ trigger: "auto",
172
+ reason: failReason,
173
+ ts: Date.now(),
174
+ }));
175
+ opts?.onCompactionFailed?.(failReason);
176
+ runner.deps.onError?.(err, { phase: "compaction", sessionId: prepared.sessionId });
177
+ }
178
+ }
179
+ try {
180
+ await sessions.touch(prepared.sessionId);
181
+ }
182
+ catch (err) {
183
+ runner.deps.onError?.(err, { phase: "config", sessionId: prepared.sessionId });
184
+ }
185
+ try {
186
+ await prepared.mcp.dispose();
187
+ }
188
+ catch (err) {
189
+ runner.deps.onError?.(err, { phase: "mcp", sessionId: prepared.sessionId });
190
+ }
191
+ if (prepared.a2a !== undefined) {
192
+ try {
193
+ await prepared.a2a.dispose();
194
+ }
195
+ catch (err) {
196
+ runner.deps.onError?.(err, { phase: "a2a", sessionId: prepared.sessionId });
197
+ }
198
+ }
199
+ return comp;
200
+ }
@@ -14,11 +14,12 @@ import { workflowSizeGuidelineChangeNotice } from "../../orchestration/workflow-
14
14
  import { awaitChargeWithSlowDisclosure, discloseUnevaluableWindow, ENV_DUE_GOVERNANCE_READ_BUDGET_MS, GOVERNANCE_READ_STALLED, LIMIT_APPROACH_DEFAULT_THRESHOLDS, limitApproachFrames, platformLimitTerminal, raceUntilDeadline } from "./clock-and-limits.js";
15
15
  import { gitRestateOption } from "./git-leg-delivery.js";
16
16
  import { COMPACTION_FREED_EPSILON, COMPACTION_REGROWTH_FACTOR, MAX_CONSECUTIVE_COMPACTION_FAILURES } from "./compaction-knobs.js";
17
+ import { compactionHookOptions, recordCompactionReuse, seamCCompactionOptions } from "./compaction-seams.js";
17
18
  const BATCH_CONTEXT_MIN_KEEP_BYTES = 160;
18
19
  const BATCH_TRUNCATION_MARKER = "\n…[truncated]";
19
20
  export function createTurnBoundary(input) {
20
21
  const { prepared, stats, rs, deps } = input;
21
- const { spec, queue, manualCompactRef, todoToolMounted, taskToolsMounted, walltimeMonotonicDeadline, timeout, ident, postToolBatchHook, batchArgs, compactionBrain, withinTaskCompaction, compactionBreaker, windowSafetyOptions, rapidRefill, drainManualCompact, runnerHooks } = deps;
22
+ const { spec, queue, manualCompactRef, todoToolMounted, taskToolsMounted, walltimeMonotonicDeadline, timeout, ident, postToolBatchHook, batchArgs, compactionBrain, withinTaskCompaction, compactionBreaker, windowSafetyOptions, rapidRefill, drainManualCompact, runnerHooks, runner } = deps;
22
23
  let finalVerifySeenAtLastBoundary = 0;
23
24
  const onTurnBoundary = async (event) => {
24
25
  let boundarySteered = false;
@@ -560,10 +561,10 @@ export function createTurnBoundary(input) {
560
561
  workingFileAttachments: buildWorkingFileAttachments(spec, prepared),
561
562
  ...contextInstructionFilesOption(prepared),
562
563
  ...(prepared.onCompactionApplied ? { onApplied: prepared.onCompactionApplied } : {}),
563
- ...runnerHooks.seamCCompactionOptions(prepared),
564
+ ...seamCCompactionOptions(runner, prepared),
564
565
  ...gitRestateOption(prepared),
565
566
  ...windowSafetyOptions(event.model),
566
- ...runnerHooks.compactionHookOptions(spec, prepared.sessionId, passTrigger),
567
+ ...compactionHookOptions(runner, spec, prepared.sessionId, passTrigger, prepared.hookIdentity, { timeoutMs: prepared.hookTimeoutMs, signal: prepared.abortController.signal }),
567
568
  });
568
569
  if (comp.blocked) {
569
570
  emitTrace(rs.telemetry.tracer, () => ({
@@ -618,7 +619,7 @@ export function createTurnBoundary(input) {
618
619
  queue.push({ type: "compaction_outcome", outcome, trigger: passTrigger, ...ident() });
619
620
  }
620
621
  }
621
- runnerHooks.recordCompactionReuse(prepared, comp);
622
+ recordCompactionReuse(runner, prepared, comp);
622
623
  if (comp.compacted) {
623
624
  queue.push({
624
625
  type: "compacted",
@@ -21,9 +21,6 @@ export declare class Runner implements RunnerSelfSeat {
21
21
  * authority: a durable resume's checkpoint seed wins on its leg, and a miss (cross-process,
22
22
  * evicted) falls back to the transcript-replay rung. See {@link SessionReadFileStates}. */
23
23
  private readonly sessionReadStates;
24
- /** #616 — the per-session breaker read face's record (see {@link RunInternals.autoModeBreakerLedger}). Runner-lived:
25
- * a trip in one leg is what the session's next leg reports. */
26
- private readonly autoModeBreakerLedger;
27
24
  /** task notifications born BETWEEN turns (run torn down / harness already idle), parked
28
25
  * per session and drained into the session's next run at its first boundary. Runner-lived (outlives any
29
26
  * single run, like the registry handles that produce into it); bounded + drop-disclosing, see
@@ -135,13 +132,18 @@ export declare class Runner implements RunnerSelfSeat {
135
132
  * on first iteration — you do NOT need to pull events for the run (and its `finish()`/env teardown) to
136
133
  * happen. Iterating just observes events (the buffer is backpressure-free); `.result()` awaits completion. */
137
134
  runTaskStream(spec: TaskSpec, resume?: ResumeRun, internals?: RunInternals): TaskStream;
138
- private runLocked;
139
135
  /**
140
- * design/100 §E12 — the post-completion prompt-suggestion pass. Never throws (failures route to
141
- * `onError(phase:"suggestions")` and resolve to `[]`), so it is fire-and-forget safe and `suggestions()`
142
- * never rejects. Also fills the budget-excluded `stats.suggestions` line.
136
+ * design/393 S7 (#674) — the run body as ONE driver method: `runLocked`'s signature, the lane order, and the two assemblies
137
+ * the driver keeps (the harness handlers, the turn boundary). The lanes' products are threaded under the names they hand
138
+ * back; the two continuations the S6 driver spelled as private methods (`runSeatLanes` / `runAssembliesAndLegs`, joined by
139
+ * a `RunSeatsHandoff` re-spelling of two lanes' Results) are the `next` closures of the two async lanes they follow — the
140
+ * notification lane's (R0) and the attachment seats' (R3) — because a closure sees what the lanes before it bound, so
141
+ * nothing is re-spelled and nothing is re-destructured. Neither this method nor either closure is `async`: each lane's
142
+ * own promise IS this method's, so a prepare that throws reaches the run IIFE's catch / finally (the failure backstop,
143
+ * the session lock's release) on the tick it did, and each successor is entered on the tick its lane's last await
144
+ * resolved on (the S6 TICKS pin holds unchanged: no first host read moved off the tick the one-function body read it on).
143
145
  */
144
- private suggestNextPrompts;
146
+ private runLocked;
145
147
  /** Run a task to completion and return a machine-readable result. */
146
148
  runTask(spec: TaskSpec, internals?: RunInternals): Promise<TaskResult>;
147
149
  /**
@@ -249,77 +251,6 @@ export declare class Runner implements RunnerSelfSeat {
249
251
  * twin. Entered in the claim rung's last continuation, so its first statement runs on the tick the win was read.
250
252
  */
251
253
  private resumeHandoff;
252
- /**
253
- * design/45 resume step: with the harness idle and the branch rewound to the suspension leaf, resolve
254
- * the gated tool call and close the rest of the suspended batch, all by appending `toolResult`s to the
255
- * session (the next `harness.prompt(continuation)` replays them as context).
256
- * - `allow` → execute the pending tool ONCE (re-validating `updatedInput`/captured post-hook args),
257
- * append its real result. This deliberately bypasses the tool gate (the human already adjudicated)
258
- * and the PostToolUse hook (documented v1 gap — rare, acceptable).
259
- * - `deny` → append a model-readable denial result instead.
260
- * - the remaining batch siblings (#k+1..N) → deferred-reissue results (v1 doesn't blind-run them).
261
- */
262
- private applyResumeDecision;
263
- /** Resolve the single gated call of a resumed batch (design/45): execute it once on `allow`, or inject
264
- * a model-readable denial on `deny`. Appends exactly one `toolResult` for `pendingAction.toolCallId`.
265
- * `emit` streams `tool_start`/`tool_end` for the resolved call so a `resumeStream` observer sees the
266
- * approved tool actually execute (API#2 observability parity — service [15]/[37]; the gated call never
267
- * emitted execution events in the original run, it suspended at the gate before running).
268
- *
269
- * RB-22 RULING (2026-07-18, deliberate — the $ counterpart of RB-21's walltime question): a HUMAN-
270
- * APPROVED call executes even when the $ budget is already exhausted (`maxCostMicroUsd` ≤ spent).
271
- * The tool execution itself consumes no model spend — the budget's coordinate is LLM cost, and the
272
- * very next turn boundary's budget gate stops the run — so the overrun is ≈0 while refusing would
273
- * WASTE the human approval (the review effort is already sunk). This deliberately differs from the
274
- * walltime ruling (RB-21: NOT exempt) on principle: wall-clock exhaustion endangers the write-out
275
- * window (time cannot be clawed back), $ exhaustion after an approved no-spend action endangers
276
- * nothing. Pinned in resume tests; do not "fix" this into a pre-execution budget check. */
277
- private resolvePendingCall;
278
- /**
279
- * design/84 Seam C — the cost-optimization compaction options threaded into BOTH `maybeCompact` call
280
- * sites (within-task turn boundary + `finish()`). All three fields come from `RunnerDeps` (a trusted
281
- * FUNCTION seam — never `TaskSpec`, which is serializable/durable-resumable/untrusted-caller). The
282
- * Runner OWNS the consecutive-reuse counter (`prepared.compactionReuseRef`) so the
283
- * `maxConsecutiveProviderReuse` drift guard spans the whole task across both sites: it FEEDS the current
284
- * count in as `consecutiveProviderReuse`, and {@link recordCompactionReuse} updates it from the result.
285
- * Returns `undefined` when no provider is wired (so the call site spreads nothing → byte-identical to
286
- * the pre-design/84 behavior).
287
- */
288
- private seamCCompactionOptions;
289
- /** design/134 §3.2 — resolve the pre/postCompact lifecycle callbacks (whole-slot `spec.hooks ??
290
- * deps.hooks`, same resolution as the stop hook) and wrap each in a SWALLOW+TRACE shell before
291
- * threading them into maybeCompact. The wrapper owns the observability half of the R3 MED contract
292
- * (maybeCompact swallows defensively too, but has no sink): a throwing callback is reported via
293
- * `onError(phase:"hook")` and treated as absent; a `block` returned under a "forced" trigger is
294
- * reported as ignored (maybeCompact enforces the ignore — blocking a compaction the provider/trim
295
- * layer already demanded would kill the run). */
296
- private compactionHookOptions;
297
- /** design/84 Seam C — fold a finished compaction's `reused` flag into the run-scoped consecutive-reuse
298
- * counter: a reused (provider) summary increments it, a real (LLM) summary resets it to 0. A no-op
299
- * compaction (`compacted:false`) leaves the counter untouched. No-op when no provider is wired. */
300
- private recordCompactionReuse;
301
- private finish;
302
- /**
303
- * design/48 remote seam +: tear down a per-task env minted by `executionEnvFactory` (e.g. a
304
- * remote container, or a `withWorktreeIsolation` worktree) — this task owned its lifetime. Best-effort, like
305
- * `mcp.dispose`: a `destroy()` failure must not break the run. Only `ownedEnv` (factory-produced) is destroyed;
306
- * a caller-owned static `deps.executionEnv` outlives the task and is left untouched. The service control plane's
307
- * reaper is the backstop for an env orphaned by a rare pre-teardown throw (same posture as `mcp`).
308
- *
309
- * Runs from the run-loop tail AFTER every env-reader (finish()'s compaction `attachWorkingFiles` +
310
- * the file-history boundary settle), so the working tree is still readable when they run. This ORDER is
311
- * the fix for a teardown-order defect: the old in-`finish` destroy ran BEFORE the capture seat, so a
312
- * factory-minted remote/worktree lane captured an already-destroyed env (plain host/static lanes were
313
- * false-green).
314
- *
315
- * design/49 v1.5 / design/76 §2.5: a committed durable pause (`pausedRef.current`, any gate kind)
316
- * `suspendVM`-paused the env and persisted its `workspaceHandle` into the checkpoint — destroying it would
317
- * discard the paused VM and make resume fail to restore. Skip teardown; `resume()` rebuilds + `resumeVM`s it. A
318
- * cancelled pause is reaped via `TaskStream.destroy()` (design/51); an abandoned one is the service container
319
- * reaper's backstop. The gate here MIRRORS the tail's reap-stash (same durable fact
320
- * `pausedRef.current === undefined`), so exactly one path owns the env's fate.
321
- */
322
- private teardownOwnedEnv;
323
254
  }
324
255
  /** Convenience: one-shot run with explicit deps (creates a throwaway Runner). */
325
256
  export declare function runTask(spec: TaskSpec, deps: RunnerDeps): Promise<TaskResult>;