@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,56 @@
1
+ import { type PeerInboundChainRef } from "../../agents/peer-admission.js";
2
+ import type { PushQueue } from "../push-queue.js";
3
+ import type { SessionStore } from "../session.js";
4
+ import { type PendingSessionNotifications, type SystemInjectionPriority, type TaskNotificationPayload } from "../task-notification.js";
5
+ import type { RunnerDeps, TaskEvent, TaskSpec } from "../types.js";
6
+ import type { SessionReadFileStates } from "./prepare-hands-readface.js";
7
+ import type { NotificationLaneBindings, Prepared, PrepareTaskFn, ResumeRun, RunInternals, RunnerDepsSeat, RunnerSelfSeat, TaskIdRef } from "./contracts.js";
8
+ export interface RunNotificationLaneInput<R> {
9
+ /** borrowed-readonly — the task spec: prepare's input, and the principal the peer scope is minted from. */
10
+ spec: TaskSpec;
11
+ /** borrowed-mutable — the run's event queue: the routed `task_notification` frames are pushed here. */
12
+ queue: PushQueue<TaskEvent>;
13
+ /** borrowed-readonly — the resume plan when this leg resumes a checkpoint (prepare's resume seed is derived from it). */
14
+ resume: ResumeRun | undefined;
15
+ /** borrowed-readonly — the trusted run-scoped channel: the detach hub, the uplink, the root / parent anchors, the peer refs, the upstream notification observer. */
16
+ internals: RunInternals | undefined;
17
+ /** borrowed-mutable — the stream layer's backstop carrier, handed to prepare so a prepare THROW still names its run. */
18
+ taskIdRef: TaskIdRef | undefined;
19
+ /** borrowed-readonly — the Runner's deployment deps, read LIVE (`onError` in the park closure — after the run, on a swapped
20
+ * catalog it is still the CURRENT sink; `models` and prepare's `deps` at the natural-snapshot pin); the one home of why it
21
+ * is a seat and not a captured object is {@link RunnerDepsSeat}. */
22
+ runner: RunnerDepsSeat;
23
+ /** borrowed-readonly — the TRUSTED Runner self-reference prepare mounts the `run_workflow` tool over (never a TaskSpec field). */
24
+ self: RunnerSelfSeat;
25
+ /** borrowed-readonly — the session store prepare acquires / creates the leg's session through. */
26
+ sessions: SessionStore;
27
+ /** borrowed-mutable — the Runner's own per-session read-state seat, ALWAYS this Runner's (a caller-supplied one is overridden). */
28
+ sessionReadStates: SessionReadFileStates;
29
+ /** borrowed-mutable — the Runner's per-session parked-notification store: the torn-down lane and the escalation pend here. */
30
+ pendingSessionNotifications: PendingSessionNotifications;
31
+ /** borrowed-readonly — the orchestrator's entry (a lane may not name the orchestrator; the driver hands it in), as the ONE
32
+ * contract the orchestrator's own declaration is pinned to ({@link PrepareTaskFn}, contracts.ts — design/393 S7, #675). */
33
+ prepareTask: PrepareTaskFn;
34
+ /** borrowed-readonly — the lanes after this one, entered in this lane's last continuation with what it prepared and bound. */
35
+ next: (lane: RunNotificationLaneResult) => Promise<R>;
36
+ }
37
+ /** What the lane prepared and bound — the seats every lane after it reads. */
38
+ export interface RunNotificationLaneResult {
39
+ /** The leg's prepared seat. */
40
+ prepared: Prepared;
41
+ /** The ONE injection entry every notification producer rides (the identity lane binds the notify() bridge to it). */
42
+ injectTaskNotification: (notification: TaskNotificationPayload, opts?: {
43
+ priority?: SystemInjectionPriority;
44
+ }) => Promise<"queued" | "parked" | "dropped_duplicate">;
45
+ /** The turn-open dedup set (the cross-layer double-park dedup): the identity lane registers a redelivered frame's key here. */
46
+ deliveredAtTurnOpen: Set<string>;
47
+ /** design/176: the peer inbound chain ref this run carries (the spawn chain's, or a fresh one). */
48
+ peerInboundChainRef: PeerInboundChainRef;
49
+ /** The model catalog pinned BEFORE prepare (the natural-snapshot closure for swapDeps): the budget seats resolve against it. */
50
+ modelCatalog: RunnerDeps["models"];
51
+ /** The lane's bindings as one seat over its own variables — see {@link NotificationLaneBindings}. */
52
+ notificationLane: NotificationLaneBindings;
53
+ /** The queue subscription's release; the leg lane's finally calls it right after flipping `live`. */
54
+ unsubscribeTaskNotifications: () => void;
55
+ }
56
+ export declare function runNotificationLane<R>(input: RunNotificationLaneInput<R>): Promise<R>;
@@ -0,0 +1,128 @@
1
+ import { createPeerInboundChainRef, createPeerSelfRef } from "../../agents/peer-admission.js";
2
+ import { boundInputHashOf } from "../canonical-json.js";
3
+ import { isDelegatedAgentTerminal, isTerminalTaskNotification, renderTaskNotificationXml, SystemInjectionQueue, taskNotificationDedupKey } from "../task-notification.js";
4
+ import { ToolDetachHub } from "../tool-detach.js";
5
+ import { pendingContentAskCallId } from "./decide-continuation.js";
6
+ export async function runNotificationLane(input) {
7
+ const { spec, queue, resume, internals, taskIdRef, runner, self, sessions, sessionReadStates, pendingSessionNotifications, prepareTask, next } = input;
8
+ const prepareResume = resume
9
+ ? {
10
+ leafId: resume.cp.leafId,
11
+ suspendedBatch: new Set(resume.cp.pendingAction.kind === "tool_approval" ? resume.cp.pendingAction.batchToolCallIds : []),
12
+ seed: resume.cp.state,
13
+ priorSuspendCount: resume.cp.suspendCount,
14
+ priorLedger: resume.cp.resourceLedger,
15
+ priorHumanReview: resume.cp.humanReview,
16
+ workspaceHandle: resume.cp.state.workspaceHandle,
17
+ executesApprovedAction: resume.cp.pendingAction.kind === "tool_approval" &&
18
+ resume.outcome.gate !== "wake" &&
19
+ resume.outcome.decision === "allow",
20
+ ...(resume.outcome.gate !== "wake" && resume.outcome.decision === "allow" && pendingContentAskCallId(resume.cp) !== undefined
21
+ ? {
22
+ redeemedContentAskCallId: pendingContentAskCallId(resume.cp),
23
+ redeemedContentAskQuestionsHash: boundInputHashOf(resume.cp.pendingAction.args?.questions),
24
+ }
25
+ : {}),
26
+ }
27
+ : undefined;
28
+ const taskNotificationQueue = new SystemInjectionQueue();
29
+ const detachHub = internals?.detachHub ?? new ToolDetachHub();
30
+ let notificationHarness;
31
+ let notificationIdent = () => ({});
32
+ let notificationLaneLive = true;
33
+ let notificationSessionId;
34
+ let descendantAnchorDisclosed = false;
35
+ const parkTaskNotification = (payload, priority) => {
36
+ if (notificationSessionId !== undefined)
37
+ pendingSessionNotifications.pend(notificationSessionId, payload, priority);
38
+ if (!isDelegatedAgentTerminal(payload))
39
+ return;
40
+ const uplink = internals?.parentNotify;
41
+ if (uplink !== undefined) {
42
+ try {
43
+ uplink(payload, { priority });
44
+ }
45
+ catch (e) {
46
+ runner.deps.onError?.(e, { phase: "degraded", sessionId: notificationSessionId ?? "", classification: "descendant-terminal-uplink" });
47
+ }
48
+ return;
49
+ }
50
+ const rootAnchor = internals?.rootSessionId;
51
+ if (rootAnchor !== undefined && rootAnchor !== notificationSessionId) {
52
+ pendingSessionNotifications.pend(rootAnchor, payload, priority);
53
+ return;
54
+ }
55
+ if (internals?.parentSessionId !== undefined && !descendantAnchorDisclosed) {
56
+ descendantAnchorDisclosed = true;
57
+ runner.deps.onError?.(new Error(`background-agent terminal ${payload.task_id} parked on this run's own session — the delegation tree's root session is not reachable from this run (no uplink, no root anchor)`), { phase: "degraded", sessionId: notificationSessionId ?? "", classification: "descendant-terminal-unrouted" });
58
+ }
59
+ };
60
+ const unsubscribeTaskNotifications = taskNotificationQueue.subscribe((item) => {
61
+ queue.push({ type: "task_notification", notification: item.payload, priority: item.priority, ...notificationIdent() });
62
+ if (notificationHarness && prepared.batchHaltRef.current === undefined) {
63
+ const xml = renderTaskNotificationXml(item.payload);
64
+ const noteOptions = {
65
+ provenance: "engine-note",
66
+ enginePayload: item.payload,
67
+ ...(item.payload.task_type !== "external" && isTerminalTaskNotification(item.payload) ? { capPreferred: true } : {}),
68
+ };
69
+ const deliver = item.priority === "later"
70
+ ? notificationHarness.followUp(xml, noteOptions)
71
+ : notificationHarness.steer(xml, { ...noteOptions, ...(item.priority === "now" ? { immediate: true } : {}) });
72
+ void deliver.then(() => item.onDisposition?.("queued"), () => {
73
+ parkTaskNotification(item.payload, item.priority);
74
+ item.onDisposition?.("parked");
75
+ });
76
+ }
77
+ else {
78
+ parkTaskNotification(item.payload, item.priority);
79
+ item.onDisposition?.("parked");
80
+ }
81
+ });
82
+ const upstreamTaskNotification = internals?.onTaskNotification;
83
+ const deliveredAtTurnOpen = new Set();
84
+ const injectTaskNotification = (notification, opts) => {
85
+ if (deliveredAtTurnOpen.has(taskNotificationDedupKey(notification)))
86
+ return Promise.resolve("dropped_duplicate");
87
+ if (!notificationLaneLive) {
88
+ parkTaskNotification(notification, opts?.priority ?? "later");
89
+ return Promise.resolve("parked");
90
+ }
91
+ return new Promise((resolve) => {
92
+ const accepted = taskNotificationQueue.enqueue({
93
+ kind: "task_notification",
94
+ priority: opts?.priority ?? "later",
95
+ dedupKey: taskNotificationDedupKey(notification),
96
+ payload: notification,
97
+ onDisposition: resolve,
98
+ });
99
+ if (!accepted)
100
+ resolve("queued");
101
+ });
102
+ };
103
+ const peerSelfRef = internals?.peerSelfRef ?? createPeerSelfRef(internals?.registryScope ?? spec.principal ?? "default");
104
+ const peerInboundChainRef = internals?.peerInboundChainRef ?? createPeerInboundChainRef();
105
+ const modelCatalog = runner.deps.models;
106
+ const prepared = await prepareTask(spec, runner.deps, sessions, prepareResume, {
107
+ ...(internals ?? {}),
108
+ peerSelfRef,
109
+ peerInboundChainRef,
110
+ detachHub,
111
+ sessionReadStates,
112
+ onTaskNotification: (notification, opts) => {
113
+ try {
114
+ upstreamTaskNotification?.(notification, opts);
115
+ }
116
+ catch {
117
+ }
118
+ injectTaskNotification(notification, opts);
119
+ },
120
+ }, self, taskIdRef);
121
+ const notificationLane = {
122
+ get harness() { return notificationHarness; }, set harness(h) { notificationHarness = h; },
123
+ get sessionId() { return notificationSessionId; }, set sessionId(s) { notificationSessionId = s; },
124
+ get ident() { return notificationIdent; }, set ident(f) { notificationIdent = f; },
125
+ get live() { return notificationLaneLive; }, set live(v) { notificationLaneLive = v; },
126
+ };
127
+ return await next({ prepared, injectTaskNotification, deliveredAtTurnOpen, peerInboundChainRef, modelCatalog, notificationLane, unsubscribeTaskNotifications });
128
+ }
@@ -14,14 +14,14 @@ export interface RunReasoningSeatInput {
14
14
  rs: RunState;
15
15
  /** borrowed-mutable — the stream layer's backstop carrier: `effectiveReasoning` is published here at every mint. */
16
16
  taskIdRef: TaskIdRef | undefined;
17
- /** borrowed-mutable — the driver's resolution cell (the `let` the result assembly reads): the leg-entry mint and
18
- * the first-committed-request correction are written here, and the dedupe reads it back. */
19
- reasoningResolution: {
20
- current: ResolvedReasoning | undefined;
21
- };
22
17
  }
23
18
  export interface RunReasoningSeatResult {
24
19
  /** The CONSUMPTION half of {@link ReasoningWireFacts} — installed as the third brain ALS sink. */
25
20
  observeReasoningWireFacts: (facts: ReasoningWireFacts) => void;
21
+ /** #327 — the leg's resolution as a READ FACE over this lane's own `let` (the leg-entry mint, then at most one
22
+ * first-committed-request correction): the settle lane's result assembly reads it for `effectiveReasoning`. */
23
+ reasoningResolution: {
24
+ readonly current: ResolvedReasoning | undefined;
25
+ };
26
26
  }
27
27
  export declare function runReasoningSeat(input: RunReasoningSeatInput): RunReasoningSeatResult;
@@ -1,10 +1,10 @@
1
1
  import { resolveReasoning } from "../../brain/reasoning.js";
2
2
  import { emitTrace } from "../trace.js";
3
3
  export function runReasoningSeat(input) {
4
- const { prepared, rs, taskIdRef, reasoningResolution } = input;
5
- reasoningResolution.current = prepared.thinking && prepared.thinking !== "off" ? resolveReasoning(prepared.thinking, prepared.model) : undefined;
4
+ const { prepared, rs, taskIdRef } = input;
5
+ let reasoningResolution = prepared.thinking && prepared.thinking !== "off" ? resolveReasoning(prepared.thinking, prepared.model) : undefined;
6
6
  const publishReasoningResolution = (r) => {
7
- reasoningResolution.current = r;
7
+ reasoningResolution = r;
8
8
  if (taskIdRef)
9
9
  taskIdRef.effectiveReasoning = r;
10
10
  emitTrace(rs.telemetry.tracer, () => ({
@@ -22,8 +22,8 @@ export function runReasoningSeat(input) {
22
22
  ts: Date.now(),
23
23
  }));
24
24
  };
25
- if (reasoningResolution.current !== undefined)
26
- publishReasoningResolution(reasoningResolution.current);
25
+ if (reasoningResolution !== undefined)
26
+ publishReasoningResolution(reasoningResolution);
27
27
  let reasoningFactsConsumed = false;
28
28
  const observeReasoningWireFacts = (facts) => {
29
29
  if (reasoningFactsConsumed)
@@ -32,7 +32,7 @@ export function runReasoningSeat(input) {
32
32
  if (prepared.thinking === undefined || prepared.thinking === "off")
33
33
  return;
34
34
  const next = resolveReasoning(prepared.thinking, prepared.model, facts);
35
- const current = reasoningResolution.current;
35
+ const current = reasoningResolution;
36
36
  if (current !== undefined &&
37
37
  current.effective === next.effective &&
38
38
  current.graded === next.graded &&
@@ -44,5 +44,5 @@ export function runReasoningSeat(input) {
44
44
  }
45
45
  publishReasoningResolution(next);
46
46
  };
47
- return { observeReasoningWireFacts };
47
+ return { observeReasoningWireFacts, reasoningResolution: { get current() { return reasoningResolution; } } };
48
48
  }
@@ -1,9 +1,8 @@
1
1
  import type { Model } from "../../internal/llm.js";
2
2
  import { type MaybeCompactOptions } from "../auto-compaction.js";
3
- import type { HookInvocationIdentity } from "../hooks.js";
4
3
  import type { PushQueue } from "../push-queue.js";
5
4
  import type { Brain, TaskEvent, TaskSpec } from "../types.js";
6
- import type { Prepared, RunnerDepsSeat, RunState } from "./contracts.js";
5
+ import type { InstallingPhaseResult, Prepared, RunnerDepsSeat, RunState } from "./contracts.js";
7
6
  export interface RunRecoveryLanesInput {
8
7
  /** borrowed-readonly — the task spec: the compaction settings / instructions and the key-and-headers seat. */
9
8
  spec: TaskSpec;
@@ -31,24 +30,12 @@ export interface RunRecoveryLanesInput {
31
30
  };
32
31
  /** borrowed-readonly — the window-safety option builder (the compaction-machinery lane's), per pass. */
33
32
  windowSafetyOptions: (mainModel: Model) => Pick<MaybeCompactOptions, "fallbackBudget" | "onWindowSafety">;
34
- /** borrowed-readonly — the Runner's deployment deps, read LIVE (`onError`). */
33
+ /** borrowed-readonly — the Runner's deployment deps, read LIVE (`onError`; the compaction seams the pass reaches down
34
+ * for — compaction-seams.ts — read the summary provider and the hooks slot through it on every pass). */
35
35
  runner: RunnerDepsSeat;
36
- /** borrowed-readonly — the Runner's three compaction methods as delegates: the Seam C reuse options, the hook
37
- * option wrapper and the reuse counter. The method bodies stay the Runner's; the pass calls them as the run body did. */
38
- compactionSeats: {
39
- seamCCompactionOptions: (prepared: Prepared) => Pick<MaybeCompactOptions, "summaryProvider" | "onCompaction" | "maxConsecutiveProviderReuse" | "consecutiveProviderReuse"> | undefined;
40
- compactionHookOptions: (spec: TaskSpec, sessionId: string, trigger: "auto" | "manual" | "forced", identity?: HookInvocationIdentity, seatBound?: {
41
- timeoutMs: number;
42
- signal?: AbortSignal;
43
- }) => Pick<MaybeCompactOptions, "trigger" | "preCompact" | "postCompact">;
44
- recordCompactionReuse: (prepared: Prepared, comp: {
45
- compacted: boolean;
46
- reused?: boolean;
47
- }) => void;
48
- };
49
36
  }
50
37
  /** Nothing comes back: the lane's products are INSTALLED on the seats it borrowed — the harness's loop recovery
51
38
  * chain and the microCompact arm-B seat — and the shared pass is read by those two installations alone. */
52
- export interface RunRecoveryLanesResult {
39
+ export interface RunRecoveryLanesResult extends InstallingPhaseResult {
53
40
  }
54
41
  export declare function runRecoveryLanes(input: RunRecoveryLanesInput): RunRecoveryLanesResult;
@@ -7,8 +7,9 @@ import { rebaseCadenceWindows } from "./turn-attachments.js";
7
7
  import { buildWorkingFileAttachments, centerAdoptionOption, contextInstructionFilesOption, emitInputTruncated, forkContextOption } from "./compaction-call-options.js";
8
8
  import { gitRestateOption } from "./git-leg-delivery.js";
9
9
  import { COMPACTION_FREED_EPSILON, COMPACTION_REGROWTH_FACTOR, MAX_CONSECUTIVE_COMPACTION_FAILURES } from "./compaction-knobs.js";
10
+ import { compactionHookOptions, recordCompactionReuse, seamCCompactionOptions } from "./compaction-seams.js";
10
11
  export function runRecoveryLanes(input) {
11
- const { spec, prepared, queue, rs, ident, compactionBrain, compactionBreaker, windowSafetyOptions, runner, compactionSeats } = input;
12
+ const { spec, prepared, queue, rs, ident, compactionBrain, compactionBreaker, windowSafetyOptions, runner } = input;
12
13
  const runForcedCompactionPass = async (lane, turnSignal) => {
13
14
  if (!(spec.compaction?.enabled ?? true))
14
15
  return false;
@@ -37,14 +38,14 @@ export function runRecoveryLanes(input) {
37
38
  workingFileAttachments: buildWorkingFileAttachments(spec, prepared),
38
39
  ...contextInstructionFilesOption(prepared),
39
40
  ...(prepared.onCompactionApplied ? { onApplied: prepared.onCompactionApplied } : {}),
40
- ...compactionSeats.seamCCompactionOptions(prepared),
41
+ ...seamCCompactionOptions(runner, prepared),
41
42
  ...gitRestateOption(prepared),
42
43
  ...windowSafetyOptions(prepared.harness.getModel()),
43
- ...compactionSeats.compactionHookOptions(spec, prepared.sessionId, "forced", prepared.hookIdentity, { timeoutMs: prepared.hookTimeoutMs, signal: passSignal }),
44
+ ...compactionHookOptions(runner, spec, prepared.sessionId, "forced", prepared.hookIdentity, { timeoutMs: prepared.hookTimeoutMs, signal: passSignal }),
44
45
  });
45
46
  if (comp.compacted) {
46
47
  compactionBreaker.failures = 0;
47
- compactionSeats.recordCompactionReuse(prepared, comp);
48
+ recordCompactionReuse(runner, prepared, comp);
48
49
  if ((comp.freedTokens ?? 0) >= COMPACTION_FREED_EPSILON) {
49
50
  const postSize = comp.postTriggerTokens ?? Math.max(0, (comp.triggerTokens ?? comp.tokensBefore ?? 0) - (comp.freedTokens ?? 0));
50
51
  rs.counters.compactionFloor = Math.ceil(postSize * COMPACTION_REGROWTH_FACTOR);
@@ -0,0 +1,113 @@
1
+ /**
2
+ * design/393 S6 — the run body's SETTLE AND TEARDOWN (R15), verbatim from `Runner.runLocked`: the end-of-task
3
+ * compaction's frames and detector reset, the nested-stats fold, the prefix-cache observability and its loud
4
+ * mismatch / low-hit disclosures, the cross-slice cumulative spend fold, the human-review and mechanism counters,
5
+ * the result assembly (`assembleResult` — the one place the leg's facts become a TaskResult), the resume leg's
6
+ * unstarted-action reopen compensation, the read-state seal and the settle-time workspace-state write, the
7
+ * StopFailure observer, the delegation-lifecycle terminal, the reap-stash for a committed pause, the resumed-terminal
8
+ * unpin, the memory harvest, the `task.end` trace, `setResult`, the sub-agent's terminal tick, the mooted manual
9
+ * compaction, the forwarded-frame drain and the queue's `done` + close, the file-history boundary settle and the
10
+ * prompt-suggestion kickoff — then, in its finally, the four teardown legs in the order they were: the shell-lane
11
+ * children settle, the background-shell sweep, the registry clears / the background-agent abort / the retained
12
+ * child sessions, and the owned env's teardown. The suggestion pass (`suggestNextPrompts`, with its four bounds) and the
13
+ * owned-env teardown (`teardownOwnedEnv`) are the lane's own module-private functions since design/393 S7, verbatim from
14
+ * the Runner's private methods: each has this one caller, and a sibling file would be a lane-to-lane reach (the S6 legs' reading).
15
+ *
16
+ * Async (eleven first-level awaits, all of them the same awaits at the same positions). The `queue.push("done")` and
17
+ * the teardown legs' order are contract (the forwarded-frame drain lands before `done`; the env is torn down after
18
+ * every reader of it); nothing here reorders them. Products: the result is PUBLISHED through `setResult` and the
19
+ * effects are installed on the borrowed seats — nothing comes back to the driver (the same empty Result the seat
20
+ * lanes whose products are all installations carry).
21
+ */
22
+ import type { AssistantMessage } from "../../internal/llm.js";
23
+ import type { ResolvedReasoning } from "../../brain/reasoning.js";
24
+ import type { PushQueue } from "../push-queue.js";
25
+ import type { SessionStore } from "../session.js";
26
+ import { type CompactOutcome, type DelegationLifecycleEvent, type TaskEvent, type TaskResult, type TaskSpec } from "../types.js";
27
+ import { type Stats } from "./assemble-result.js";
28
+ import type { EndOfTaskCompaction, InstallingPhaseResult, ManualCompactRef, Prepared, ResumeRun, RunInternals, RunnerDepsSeat, RunState, SuspendReap, TaskIdRef } from "./contracts.js";
29
+ export interface RunSettleAndTeardownInput {
30
+ /** borrowed-readonly — the task spec: the hooks slot, the suggestion opt-in, the retain / forward flags, the task id and principal. */
31
+ spec: TaskSpec;
32
+ /** borrowed-mutable — the run's event queue: the compaction / human-input / task_progress / done frames, then CLOSED here. */
33
+ queue: PushQueue<TaskEvent>;
34
+ /** borrowed-mutable — the leg's prepared seat: the settle-time seal and workspace write, the refs the result assembly reads, the env the teardown reaps. */
35
+ prepared: Prepared;
36
+ /** borrowed-readonly — the resume plan when this leg resumed a checkpoint (the reopen compensation and the unpin read it). */
37
+ resume: ResumeRun | undefined;
38
+ /** borrowed-readonly — the trusted run-scoped channel: the delegation task type, cycle seq, parent task id and the display-sink forward. */
39
+ internals: RunInternals | undefined;
40
+ /** borrowed-readonly — the run's mutable state, read for the telemetry / degrade / limits / counters the result and the frames report. */
41
+ rs: RunState;
42
+ /** borrowed-mutable — this leg's usage counters: the nested / cumulative folds, the cache-hit rate, the mechanism counters are written here. */
43
+ stats: Stats;
44
+ /** borrowed-readonly — the run's event-identity mint. */
45
+ ident: () => {
46
+ eventId: string;
47
+ parentToolCallId?: string;
48
+ sourceTaskId?: string;
49
+ };
50
+ /** borrowed-readonly — the spawning tool call's id when this task runs AS A SUB-AGENT (gates the terminal tick). */
51
+ parentToolCallId: string | undefined;
52
+ /** borrowed-readonly — the sub-agent display name for the terminal tick. */
53
+ subagentName: string | undefined;
54
+ /** borrowed-readonly — the loop-liveness latch: `userHalted` signs the result's halt seat. */
55
+ loopLatch: {
56
+ readonly userHalted: boolean;
57
+ };
58
+ /** borrowed-readonly — the hard walltime timer: `fired` and `latenessMs` ride the result and the `task.end` frame. */
59
+ timeout: {
60
+ readonly fired: boolean;
61
+ readonly latenessMs?: number;
62
+ };
63
+ /** borrowed-readonly — the run's own committed tail (the read-state seal). */
64
+ ownCommittedTailRef: {
65
+ readonly current: string | undefined;
66
+ };
67
+ /** borrowed-readonly — the delegation-lifecycle emission closure (the terminal station is here). */
68
+ emitDelegationLifecycle: (event: DelegationLifecycleEvent) => void;
69
+ /** borrowed-mutable — the stream layer's backstop carrier: the owed delegation terminal is cleared here. */
70
+ taskIdRef: TaskIdRef | undefined;
71
+ /** borrowed-mutable — the manual /compact seat: the parked waiters are mooted and the channel closed before `done`. */
72
+ manualCompactRef: ManualCompactRef;
73
+ /** borrowed-readonly — the boundary lane's drain of the manual-compact waiters (with the outcome every waiter receives). */
74
+ drainManualCompact: (outcome: CompactOutcome) => void;
75
+ /** borrowed-readonly — the leg lane's final assistant message (undefined on every no-prompt arm). */
76
+ final: AssistantMessage | undefined;
77
+ /** borrowed-readonly — the adopted terminal cause (the leg's throw, or what the terminal-adoption lane lifted over it). */
78
+ threw: unknown;
79
+ /** borrowed-readonly — the live-abort flag captured before the leg's release-abort. */
80
+ abortedLive: boolean;
81
+ /** borrowed-readonly — the leg's snapshot of `loopLatch.userInterrupted`: names the origin of a stop that landed after the answer settled. */
82
+ userInterruptedLive: boolean;
83
+ /** borrowed-readonly — #677: the terminal-adoption lane's ONE evaluation of `answerSettled` (a clean `"stop"` final, no continuation
84
+ * lost). Read by the arbitration (`ResultFlags.answerSettled`), the teardown's stop-source attribution and the notice. */
85
+ answerSettled: boolean;
86
+ /** borrowed-readonly — design/174: the answered-but-never-collected deliveries the leg's finally settled. */
87
+ strandedHumanAnswers: ReadonlyArray<{
88
+ deliveryId: string;
89
+ toolCallId: string;
90
+ }>;
91
+ /** borrowed-readonly — the reasoning seat's resolution, as the read face on its Result (the result's `effectiveReasoning`). */
92
+ reasoningResolution: {
93
+ readonly current: ResolvedReasoning | undefined;
94
+ };
95
+ /** borrowed-readonly — the end-of-task compaction's outcome (the terminal-adoption lane's `finish` call). */
96
+ comp: EndOfTaskCompaction;
97
+ /** borrowed-readonly — the stream's result setter: the assembled TaskResult is published through it exactly once. */
98
+ setResult: (r: TaskResult) => void;
99
+ /** borrowed-readonly — the stream's suggestions seat: the fire-and-forget suggestion pass's promise is handed to it. */
100
+ onSuggestions: (p: Promise<string[]>) => void;
101
+ /** borrowed-readonly — the stream's reap-stash for a committed pause (what `destroy()` reaps when the run SUSPENDED). */
102
+ onSuspend: (reap: SuspendReap) => void;
103
+ /** borrowed-readonly — the Runner's deployment deps, read LIVE (`onError`, `hooks`, `checkpointStore`, `executionEnv`, `onNotice`; the
104
+ * suggestion pass reads `brain` / `pricing` / `roles` and the owned-env teardown `onError` through it too); the one home of why it
105
+ * is a seat and not a captured object is {@link RunnerDepsSeat}. */
106
+ runner: RunnerDepsSeat;
107
+ /** borrowed-readonly — the session store: the resumed-terminal leg unpins the checkpoint's session through it. */
108
+ sessions: SessionStore;
109
+ }
110
+ /** Nothing comes back: the result is published through `setResult`, the queue is closed, the teardown legs ran. */
111
+ export interface RunSettleAndTeardownResult extends InstallingPhaseResult {
112
+ }
113
+ export declare function runSettleAndTeardown(input: RunSettleAndTeardownInput): Promise<RunSettleAndTeardownResult>;