@sema-agent/core 5.56.0 → 5.58.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 (208) hide show
  1. package/CHANGELOG.md +122 -0
  2. package/dist/agents/cascade.d.ts +1 -1
  3. package/dist/agents/cumulative-stats.d.ts +1 -1
  4. package/dist/agents/observer.d.ts +2 -2
  5. package/dist/agents/peer-admission.d.ts +1 -1
  6. package/dist/agents/retain-ledger.d.ts +2 -2
  7. package/dist/agents/roster-store.d.ts +8 -8
  8. package/dist/agents/send-message-tool.d.ts +13 -2
  9. package/dist/agents/send-message-tool.js +34 -12
  10. package/dist/agents/subagent-steps.d.ts +1 -1
  11. package/dist/agents/subagent.d.ts +13 -13
  12. package/dist/agents/team.d.ts +15 -6
  13. package/dist/agents/team.js +1 -0
  14. package/dist/agents/tool-filter.d.ts +2 -2
  15. package/dist/agents/verify.d.ts +1 -1
  16. package/dist/bench/metrics.d.ts +35 -35
  17. package/dist/brain/anthropic.js +15 -5
  18. package/dist/brain/circuit-breaker.js +2 -1
  19. package/dist/brain/degrading.d.ts +1 -1
  20. package/dist/brain/degrading.js +4 -1
  21. package/dist/brain/errors.d.ts +3 -3
  22. package/dist/brain/failover.js +16 -1
  23. package/dist/brain/open-responses.js +15 -5
  24. package/dist/brain/openai.js +16 -5
  25. package/dist/brain/reasoning.d.ts +2 -2
  26. package/dist/brain/repetition.d.ts +1 -1
  27. package/dist/brain/request-params.d.ts +30 -27
  28. package/dist/brain/request-params.js +1 -7
  29. package/dist/brain/route-adjudicator.d.ts +190 -0
  30. package/dist/brain/route-adjudicator.js +189 -0
  31. package/dist/brain/route-conformance.d.ts +55 -0
  32. package/dist/brain/route-conformance.js +136 -0
  33. package/dist/brain/routing.js +8 -3
  34. package/dist/brain/status-sink.d.ts +2 -2
  35. package/dist/brain/stream-shared.d.ts +1 -1
  36. package/dist/config/catalog.d.ts +5 -5
  37. package/dist/core/arg-summary.d.ts +4 -4
  38. package/dist/core/ask-class.d.ts +2 -2
  39. package/dist/core/ask-question.d.ts +1 -1
  40. package/dist/core/auto-compaction.d.ts +15 -15
  41. package/dist/core/auto-mode.d.ts +5 -5
  42. package/dist/core/background-agent-store.d.ts +20 -20
  43. package/dist/core/background-shell.d.ts +4 -4
  44. package/dist/core/checkpoint-store.d.ts +35 -27
  45. package/dist/core/context-edit.d.ts +1 -1
  46. package/dist/core/context-guard.d.ts +1 -1
  47. package/dist/core/exec-output-tail.d.ts +6 -6
  48. package/dist/core/file-snapshot-store.d.ts +8 -8
  49. package/dist/core/git-worktree-env.d.ts +3 -3
  50. package/dist/core/governance-codes.js +2 -0
  51. package/dist/core/hooks.d.ts +73 -33
  52. package/dist/core/hooks.js +87 -25
  53. package/dist/core/image-downsample.d.ts +1 -1
  54. package/dist/core/locked-config.d.ts +1 -1
  55. package/dist/core/lsp.d.ts +1 -1
  56. package/dist/core/mailbox-store.d.ts +1 -1
  57. package/dist/core/mcp.d.ts +3 -3
  58. package/dist/core/mcp.js +4 -4
  59. package/dist/core/memory-engine/consolidation-driver.d.ts +207 -0
  60. package/dist/core/memory-engine/consolidation-driver.js +378 -0
  61. package/dist/core/memory-engine/consolidation.d.ts +46 -2
  62. package/dist/core/memory-engine/consolidation.js +1 -0
  63. package/dist/core/memory-engine/data-plane.d.ts +1 -1
  64. package/dist/core/memory-engine/distiller.d.ts +550 -0
  65. package/dist/core/memory-engine/distiller.js +598 -0
  66. package/dist/core/memory-engine/dual-root.d.ts +1 -1
  67. package/dist/core/memory-engine/engine.d.ts +62 -8
  68. package/dist/core/memory-engine/engine.js +40 -4
  69. package/dist/core/memory-engine/file-backend.d.ts +1 -1
  70. package/dist/core/memory-engine/index.d.ts +4 -2
  71. package/dist/core/memory-engine/index.js +4 -2
  72. package/dist/core/memory-engine/origin-clearance.d.ts +1 -1
  73. package/dist/core/memory-engine/scope-contract.d.ts +4 -4
  74. package/dist/core/memory-engine/sync-client.d.ts +16 -16
  75. package/dist/core/memory-engine/sync.d.ts +4 -4
  76. package/dist/core/memory-recall.d.ts +1 -1
  77. package/dist/core/memory.d.ts +2 -2
  78. package/dist/core/permission-rule-consent.d.ts +230 -36
  79. package/dist/core/permission-rule-consent.js +258 -54
  80. package/dist/core/permission-rule-model.d.ts +295 -97
  81. package/dist/core/permission-rule-model.js +132 -41
  82. package/dist/core/permission-rules.d.ts +9 -9
  83. package/dist/core/remote-env.d.ts +8 -8
  84. package/dist/core/roles.d.ts +3 -3
  85. package/dist/core/roles.js +1 -0
  86. package/dist/core/runner/assemble-result.d.ts +2 -2
  87. package/dist/core/runner/compaction-call-options.d.ts +3 -3
  88. package/dist/core/runner/memory-consolidation-driver.d.ts +49 -0
  89. package/dist/core/runner/memory-consolidation-driver.js +60 -0
  90. package/dist/core/runner/memory-consolidation.d.ts +1 -1
  91. package/dist/core/runner/prepare-config-doors.d.ts +3 -3
  92. package/dist/core/runner/prepare-task.d.ts +21 -21
  93. package/dist/core/runner/prepare-task.js +54 -18
  94. package/dist/core/runner/prepare-workspace-restore.d.ts +2 -2
  95. package/dist/core/runner/runtask.d.ts +15 -12
  96. package/dist/core/runner/runtask.js +48 -0
  97. package/dist/core/runner/session-rule-policy.d.ts +1 -1
  98. package/dist/core/runner/teardown-bounded.d.ts +1 -1
  99. package/dist/core/runner/tool-disclosure.d.ts +2 -2
  100. package/dist/core/runner/turn-attachments.d.ts +11 -11
  101. package/dist/core/scheduler.d.ts +10 -5
  102. package/dist/core/secret-env.d.ts +1 -1
  103. package/dist/core/sensitive-path-policy.d.ts +1 -1
  104. package/dist/core/session-policy-store.d.ts +2 -2
  105. package/dist/core/session-reconcile.d.ts +2 -2
  106. package/dist/core/session-store.d.ts +3 -3
  107. package/dist/core/session.d.ts +1 -1
  108. package/dist/core/shutdown-debug.d.ts +2 -2
  109. package/dist/core/side-query.d.ts +14 -7
  110. package/dist/core/spec-contract.d.ts +1 -1
  111. package/dist/core/store-contracts/contract-harness.d.ts +2 -2
  112. package/dist/core/store-contracts/contract-kit-version.d.ts +2 -2
  113. package/dist/core/store-contracts/mailbox-store-contract.d.ts +1 -1
  114. package/dist/core/store-contracts/mailbox-store-contract.js +1 -1
  115. package/dist/core/task-notification.d.ts +5 -5
  116. package/dist/core/task-registry-agent.d.ts +12 -12
  117. package/dist/core/task-registry-monitor.d.ts +1 -1
  118. package/dist/core/task-registry-shared.d.ts +41 -41
  119. package/dist/core/task-registry.d.ts +12 -12
  120. package/dist/core/tool-detach.d.ts +2 -2
  121. package/dist/core/tool-errors.d.ts +3 -3
  122. package/dist/core/tool-policy.d.ts +55 -28
  123. package/dist/core/tool-result-budget.d.ts +1 -1
  124. package/dist/core/tool-result-store.d.ts +2 -2
  125. package/dist/core/tools.d.ts +1 -1
  126. package/dist/core/trace.d.ts +26 -23
  127. package/dist/core/types.d.ts +155 -70
  128. package/dist/core/untrusted-egress.d.ts +1 -1
  129. package/dist/core/untrusted-text.d.ts +7 -7
  130. package/dist/core/wiring-manifest.d.ts +5 -5
  131. package/dist/core/workflow-journal-store.d.ts +14 -14
  132. package/dist/core/workflow-run-store-contract.d.ts +1 -1
  133. package/dist/core/workflow-run-store-contract.js +1 -1
  134. package/dist/core/workflow-run-store.d.ts +4 -4
  135. package/dist/engine/compaction/compaction.d.ts +3 -3
  136. package/dist/engine/compaction/utils.d.ts +2 -2
  137. package/dist/engine/execution-env/kill-tree.d.ts +1 -1
  138. package/dist/engine/execution-env/node-execution-env.d.ts +8 -8
  139. package/dist/engine/harness/agent-harness.d.ts +6 -6
  140. package/dist/engine/harness/agent-harness.js +26 -1
  141. package/dist/engine/harness/messages.d.ts +1 -1
  142. package/dist/engine/harness/types.d.ts +15 -11
  143. package/dist/engine/llm/types.d.ts +79 -14
  144. package/dist/engine/loop/agent-loop.d.ts +3 -3
  145. package/dist/engine/loop/types.d.ts +4 -4
  146. package/dist/engine/lsp/node-lsp-manager.d.ts +2 -2
  147. package/dist/engine/session/import-validate.d.ts +1 -1
  148. package/dist/engine/session/log-digest.d.ts +1 -1
  149. package/dist/engine/session/memory-repo.d.ts +2 -2
  150. package/dist/engine/session/session.d.ts +4 -4
  151. package/dist/fixtures/index.d.ts +4 -4
  152. package/dist/index.d.ts +8 -4
  153. package/dist/index.js +5 -2
  154. package/dist/internal/llm.d.ts +1 -1
  155. package/dist/orchestration/goal.d.ts +1 -1
  156. package/dist/orchestration/run-spec.d.ts +1 -1
  157. package/dist/orchestration/run-workflow-tool.d.ts +12 -12
  158. package/dist/orchestration/workflow-governance.d.ts +4 -4
  159. package/dist/orchestration/workflow-observe.d.ts +1 -1
  160. package/dist/orchestration/workflow-script-runner.d.ts +1 -1
  161. package/dist/orchestration/workflow-script-store.d.ts +9 -9
  162. package/dist/orchestration/workflow-size-guideline.d.ts +1 -1
  163. package/dist/orchestration/workflow-types.d.ts +5 -5
  164. package/dist/orchestration/workflow.d.ts +10 -10
  165. package/dist/prompt-assembly/artifact-store.d.ts +1 -1
  166. package/dist/prompt-assembly/artifact.d.ts +1 -1
  167. package/dist/prompt-assembly/assemble.d.ts +1 -1
  168. package/dist/prompt-assembly/composer.d.ts +2 -2
  169. package/dist/prompt-assembly/epoch.d.ts +2 -2
  170. package/dist/prompt-assembly/event-registry.d.ts +1 -1
  171. package/dist/prompt-assembly/explain.d.ts +3 -3
  172. package/dist/prompt-assembly/tool-catalog.d.ts +1 -1
  173. package/dist/prompt-assembly/turn-snapshot.d.ts +4 -4
  174. package/dist/prompt-assembly/types.d.ts +12 -12
  175. package/dist/prompts/coordinator.d.ts +1 -1
  176. package/dist/prompts/default.d.ts +10 -10
  177. package/dist/prompts/default.js +2 -0
  178. package/dist/prompts/simple-sections.d.ts +3 -3
  179. package/dist/prompts/supervisor.d.ts +2 -2
  180. package/dist/scenarios/full-body.d.ts +3 -3
  181. package/dist/scenarios/scenario-registry.d.ts +6 -2
  182. package/dist/scenarios/scenario-registry.js +4 -2
  183. package/dist/stores/cc/sidecar-transcript.d.ts +3 -3
  184. package/dist/stores/file/fs-atomic.d.ts +2 -2
  185. package/dist/stores/file/index.d.ts +1 -1
  186. package/dist/stores/file/session-store.d.ts +2 -2
  187. package/dist/stores/file/workflow-journal-store.d.ts +4 -4
  188. package/dist/tools/fs/bash-readonly-classifier.d.ts +1 -1
  189. package/dist/tools/fs/encoding.d.ts +4 -4
  190. package/dist/tools/fs/fs-bash.d.ts +3 -3
  191. package/dist/tools/fs/fs-pdf.d.ts +1 -1
  192. package/dist/tools/fs/fs-shared.d.ts +6 -6
  193. package/dist/tools/fs/index.d.ts +2 -2
  194. package/dist/tools/fs/index.js +8 -1
  195. package/dist/tools/fs/notebook.d.ts +1 -1
  196. package/dist/tools/fs/pdf.d.ts +1 -1
  197. package/dist/tools/fs/read-deny.d.ts +1 -1
  198. package/dist/tools/fs/safety.d.ts +9 -9
  199. package/dist/tools/fs/search.d.ts +2 -2
  200. package/dist/tools/monitor.d.ts +3 -3
  201. package/dist/tools/scheduler-tools.js +28 -6
  202. package/dist/tools/task-list.d.ts +2 -2
  203. package/dist/tools/web.d.ts +19 -4
  204. package/dist/tools/web.js +8 -2
  205. package/dist/tools/worktree.d.ts +5 -5
  206. package/dist/tools/worktree.js +2 -2
  207. package/package.json +1 -1
  208. package/test/export-surface.snapshot.json +74 -3
@@ -5,7 +5,7 @@ export declare function redactSecrets(s: string, report?: RedactionReport): stri
5
5
  export declare function redactHostLeaks(s: string, report?: RedactionReport): string;
6
6
  /** Secret-redact + size-bound (NO injection fence) — the SAME-PRINCIPAL tier: workflow outputs/results/errors
7
7
  * riding back to the launching model/script, run rows behind scope-gated observe. Paths/URLs survive
8
- * ([1295]② — the assertion pattern depends on them); secrets never do. */
8
+ * (the assertion pattern depends on them); secrets never do. */
9
9
  export declare function boundedRedactedSummary(value: unknown, max: number): string;
10
10
  /**
11
11
  * The FULL untrusted-egress transform (design/97 CORE-2): full host-leak redaction + size-bound + FENCE. Use
@@ -236,7 +236,7 @@ export declare function defuseExactMarkInSegments(segments: readonly string[], m
236
236
  */
237
237
  export declare function sanitizeUntrustedText(text: string, extraTags?: string[]): string;
238
238
  /**
239
- * [c209-C] codex 收口 C1/C2 (metadata-driven, replaces the shape-anchored
239
+ * [c209-C] 收口 C1/C2 (metadata-driven, replaces the shape-anchored
240
240
  * `stripLeadingSystemReminders`) — cut the engine-prepended prefix off a user-lane message using the
241
241
  * EXACT length recorded on the message at mint time (`UserMessage.enginePrefixChars`, stamped where
242
242
  * the engine concatenated first-frame listing reminders / a UserPromptSubmit additionalContext
@@ -246,7 +246,7 @@ export declare function sanitizeUntrustedText(text: string, extraTags?: string[]
246
246
  * summarizer input) must not let them (a) impersonate user authority or (b) evict the real
247
247
  * objective from a head-truncated excerpt.
248
248
  *
249
- * The old helper GUESSED by reminder shape, which mis-fired in both directions (codex 收口轮): a
249
+ * The old helper GUESSED by reminder shape, which mis-fired in both directions (收口轮): a
250
250
  * same-line engine mint (`<system-reminder>[deadline] …</system-reminder>`) was NOT recognized and
251
251
  * entered the window under `[user]` authority, while a user who legitimately opened their own
252
252
  * prompt with a byte-exact reminder block WAS stripped. Metadata removes the guess entirely:
@@ -270,7 +270,7 @@ export interface EngineSegment {
270
270
  end: number;
271
271
  }
272
272
  /**
273
- * [c209-C] R5 codex R4 复核 — the three-state result of {@link normalizeEngineSegments}. `absent`
273
+ * [c209-C] R5 — the three-state result of {@link normalizeEngineSegments}. `absent`
274
274
  * and `malformed` are DIFFERENT states on purpose (R4 #1): a message whose `engineSegments` field
275
275
  * is present-but-malformed must render WHOLLY verbatim — the metadata family is suspect, so a
276
276
  * co-present `enginePrefixChars` must NOT get a second chance to cut (absent metadata is the only
@@ -285,7 +285,7 @@ export type NormalizedEngineSegments = {
285
285
  readonly segments: ReadonlyArray<EngineSegment>;
286
286
  };
287
287
  /**
288
- * [c209-C] R4 codex 终判 (R5: three-state + exception-safe over `unknown`) — validate
288
+ * [c209-C] R4 终判 (R5: three-state + exception-safe over `unknown`) — validate
289
289
  * `UserMessage.engineSegments` against the text it indexes into.
290
290
  * - `absent`: the field is `undefined` (or an empty array — it claims no engine bytes), so the
291
291
  * `enginePrefixChars` sugar MAY still apply.
@@ -303,7 +303,7 @@ export type NormalizedEngineSegments = {
303
303
  */
304
304
  export declare function normalizeEngineSegments(text: string, segments: unknown): NormalizedEngineSegments;
305
305
  /**
306
- * [c209-C] R4 codex 终判 — the SEGMENT sibling of {@link cutEnginePrefix}: remove every
306
+ * [c209-C] R4 终判 — the SEGMENT sibling of {@link cutEnginePrefix}: remove every
307
307
  * engine-trusted `[start, end)` segment from a user-lane message, keeping the bytes OUTSIDE the
308
308
  * segments verbatim (the caller/operator-authored content that derived views may present under
309
309
  * `[user]`/`[User]:` authority). Unlike the prefix cut, segments can sit mid-message: the resume
@@ -311,7 +311,7 @@ export declare function normalizeEngineSegments(text: string, segments: unknown)
311
311
  * ResumeOutcome/ResumeRun contract), so a trusted engine frame may legally follow an untrusted
312
312
  * fenced one.
313
313
  *
314
- * [c209-C] R5 (codex R4 #1) — the result distinguishes WHY nothing was cut: `malformed:true`
314
+ * [c209-C] R5 — the result distinguishes WHY nothing was cut: `malformed:true`
315
315
  * means the field was PRESENT but bad (per {@link normalizeEngineSegments}) — the caller must
316
316
  * render the whole message verbatim and MUST NOT fall through to `enginePrefixChars` (segments
317
317
  * exist ⇒ they own the message; malformed ⇒ the metadata family is suspect wholesale). Only
@@ -323,7 +323,7 @@ export declare function cutEngineSegments(text: string, segments: unknown): {
323
323
  malformed: boolean;
324
324
  };
325
325
  /**
326
- * [c209-C] R5 (codex R4 #3) — the ONE flatten under which `engineSegments`/`enginePrefixChars`
326
+ * [c209-C] R5 — the ONE flatten under which `engineSegments`/`enginePrefixChars`
327
327
  * offsets are DEFINED: a user-lane message qualifies only when its content is a plain string or a
328
328
  * SINGLE text block (whose text is that same string). Multi-block / image-bearing content returns
329
329
  * `undefined` and consumers render the message VERBATIM with their own local flatten — the two
@@ -36,7 +36,7 @@ export type WiringLegKind = "root" | "child" | "resume";
36
36
  /** The shape of the resolved permission-ask seat (`spec.onAsk ?? deps.onAsk`): a live approver
37
37
  * callback, a blanket `"allow"`/`"deny"` policy setting, or nothing at all. `"deny"` (a deliberate
38
38
  * policy) and `"absent"` (a degrade to the headless auto-deny default) are DISTINCT on purpose —
39
- * design/173 codex 5. */
39
+ * design/173 */
40
40
  export type AskSeamForm = "callback" | "allow" | "deny" | "absent";
41
41
  /** What a policy `ask` actually reaches under this assembly. `"unresolved"` = not computable from
42
42
  * the facts at hand (the static half's park-dependent arm). */
@@ -106,7 +106,7 @@ export interface WiringManifest {
106
106
  serversOptedIn: number;
107
107
  };
108
108
  parkLane: {
109
- /** A checkpoint store is wired (capability — design/173 codex 13: capability and current policy
109
+ /** A checkpoint store is wired (capability — design/173: capability and current policy
110
110
  * are reported separately). */
111
111
  capable: boolean;
112
112
  /** capable ∧ (durableApproval opt-in ∨ forceDurableGate entitlement ∨ armed safety-tool
@@ -114,7 +114,7 @@ export interface WiringManifest {
114
114
  * vocabulary are prepare-time facts). */
115
115
  effective: boolean | "unresolved";
116
116
  /** Why `effective` is `false`/`"unresolved"` — empty when `true`. The derivation chain an
117
- * operator follows from `static unresolved` to `effective park unavailable` (codex 7). */
117
+ * operator follows from `static unresolved` to `effective park unavailable`. */
118
118
  reasons: readonly ParkLaneReason[];
119
119
  /** design/173 §8.4 (opus R7): the DECLARED durability of the resolved checkpoint store — an
120
120
  * armed park lane over a process-local store is the "armed but memory-backed" degrade shape
@@ -159,7 +159,7 @@ export interface WiringManifest {
159
159
  };
160
160
  /**
161
161
  * Governance surfaces (presence facts only). `audience: "operator"` is the MACHINE-READABLE
162
- * projection classification (design/173 codex 9): a serving layer forwarding this event to a
162
+ * projection classification (design/173): a serving layer forwarding this event to a
163
163
  * multi-tenant/shared stream MUST project this section for operators only — and when it does no
164
164
  * projection, the default is to NOT disclose the section, never to leak it.
165
165
  */
@@ -263,7 +263,7 @@ export declare function resolveSubagentTranscriptTier(agentStoreWired: boolean,
263
263
  };
264
264
  } | undefined): SubagentTranscriptTier;
265
265
  /**
266
- * The ONE `ask.effective` derivation (design/173 codex 5) — shared by the effective manifest AND
266
+ * The ONE `ask.effective` derivation (design/173) — shared by the effective manifest AND
267
267
  * the posture door (`config.interaction_posture`), so "what does the door require" and "what does
268
268
  * the manifest report" can never disagree:
269
269
  * - a live approver callback ⇒ `human_reachable` (regardless of the park lane);
@@ -29,13 +29,13 @@ export interface ResumeClaimArgs {
29
29
  * run's journal whose recorded scope equals the requested `scope` (a cross-scope `resumeFromRunId` resolves to an
30
30
  * EMPTY journal → the resume safely diverges to a live re-run, never disclosing another tenant's results).
31
31
  *
32
- * SESSION-axis RULING (clay 裁定 2026-07-22, B-2 会话轴扫描案; FINAL form settled in the γ batch):
32
+ * SESSION-axis RULING (ruled 2026-07-22):
33
33
  * `load` is deliberately SCOPE-only, PERMANENTLY — same-scope callers from a different session may
34
34
  * replay a run's journal. Rationale: (a) same-scope = same trust domain (the task-list store
35
35
  * records the same posture) and a runId is engine-minted, not enumerable; (b) cross-session resume
36
36
  * is `resumeFromRunId`'s CORE legitimate use — a fresh session picking up yesterday's run has a new
37
37
  * taskId AND a new sessionId by construction, so ANY engine-side session/owner clamp on this face
38
- * refuses exactly the contract the tool teaches (the [1455] prefix-replay pins are the regression
38
+ * refuses exactly the contract the tool teaches (the prefix-replay pins are the regression
39
39
  * proof; a γ-batch recheck attempt was reverted on them). Layering: the ENGINE owns the scope
40
40
  * hard-wall (this WHERE); the SESSION acceptance arm belongs to the SERVING layer, which has a
41
41
  * session-bound connection to adjudicate against (server 1.247's wire-face soft acceptance). This
@@ -48,13 +48,13 @@ export interface WorkflowJournalStore {
48
48
  /** Record one agent's result under `(runId, scope)`. MUST be idempotent per `(runId, ordinal)` — a resumed run
49
49
  * re-appends the cached results of its replayed prefix, so a second append for the same ordinal overwrites. */
50
50
  append(runId: string, scope: string, entry: WorkflowJournalEntry): Promise<void>;
51
- /** [1409]③ (CC diagnostics parity, additive): a HUMAN/MODEL-readable coordinate for this run's journal —
51
+ /** (CC diagnostics parity, additive): a HUMAN/MODEL-readable coordinate for this run's journal —
52
52
  * the file store returns the on-disk jsonl path (CC "Read journal.jsonl" local form); a service store
53
53
  * returns its API route (cloud form). `undefined`/absent ⇒ the completion notification's diagnostics
54
54
  * line teaches only the TaskOutput route (which is always live). Engine-facing string, never parsed. */
55
55
  locator?(runId: string, scope: string): string | undefined;
56
56
  /**
57
- * RB-242 ([1980] server → [1981] core ruling, 2026-07-30) — ADMISSION for a resume, so two concurrent
57
+ * RB-242 (ruled 2026-07-30) — ADMISSION for a resume, so two concurrent
58
58
  * `resumeFromRunId` legs off ONE source run cannot fork its execution.
59
59
  *
60
60
  * Why a store seam at all: the engine's own mutex is in-process only (`startWorkflow` refuses a duplicate
@@ -65,7 +65,7 @@ export interface WorkflowJournalStore {
65
65
  * shared durable layer, i.e. here.
66
66
  *
67
67
  * OPTIONAL, and absence is a first-class state: a store that does NOT implement this has NO STORE-LEVEL lease
68
- * semantics. RB-367 ([2054] test AI dual-process probe): a store without the hook is no longer completely
68
+ * semantics. RB-367 (dual-process probe): a store without the hook is no longer completely
69
69
  * unguarded, though — `runWorkflow`'s engine falls back to a process-local admission table for exactly this
70
70
  * shape, so a same-process double `resumeFromRunId` off one source is still refused even against a store
71
71
  * that never implements this member. That fallback cannot see a SECOND process, which is the one thing a
@@ -83,13 +83,13 @@ export interface WorkflowJournalStore {
83
83
  * and is charset-clamped before it lands in a message.
84
84
  * - IDEMPOTENT for the same holder: a re-claim by the SAME `newRunId` on a claim it already holds MUST be
85
85
  * granted (a retry must not deadlock a run against itself).
86
- * - `scope` is the journal scope passed through VERBATIM ([1981]). A claim is keyed by `(sourceRunId, scope)`,
86
+ * - `scope` is the journal scope passed through VERBATIM. A claim is keyed by `(sourceRunId, scope)`,
87
87
  * NOT by `sourceRunId` alone: a cross-scope caller already resolves to an EMPTY journal (the CORE-9 wall
88
88
  * above) so it cannot fork anything, and letting it take a global claim would hand any tenant a
89
89
  * denial-of-resume lever over another's runs.
90
90
  * - THROWING is a store failure, not a refusal — it propagates and fails the resume. Return `{granted:false}`
91
91
  * to refuse.
92
- * - A GRANT MEANS POSSESSION (RB-356①, codex 异源复审 2026-07-29). `granted: true` may only be returned once
92
+ * - A GRANT MEANS POSSESSION (RB-356). `granted: true` may only be returned once
93
93
  * the claim is RECORDED where every other contender will see it; a store that cannot tell whether it holds
94
94
  * the claim must refuse, with `holder` omitted if it cannot attribute the winner. The asymmetry is the
95
95
  * reason: an unearned refusal fails one resume loudly and is recoverable, an unearned grant forks a run
@@ -101,7 +101,7 @@ export interface WorkflowJournalStore {
101
101
  * "an incomplete record is dead, take it over" is only safe if an in-flight acquisition can never look
102
102
  * incomplete.
103
103
  *
104
- * TWO INVALIDATION DOMAINS, each covering what the other cannot ([1981], settled with server):
104
+ * TWO INVALIDATION DOMAINS, each covering what the other cannot:
105
105
  * 1. ENGINE release — the normal path, prompt, covers every terminal outcome of a live engine.
106
106
  * 2. STORE TTL — the backstop for an engine that DIED holding a claim (crash/kill/replica loss): it never
107
107
  * reaches its `finally`, so only a store-side expiry can ever free that row. Server's SQL twins land this
@@ -113,7 +113,7 @@ export interface WorkflowJournalStore {
113
113
  holder?: string;
114
114
  }>;
115
115
  /**
116
- * RB-242 ([1981]) — release the claim {@link resumeClaim} granted to `newRunId` on `(sourceRunId, scope)`.
116
+ * RB-242 — release the claim {@link resumeClaim} granted to `newRunId` on `(sourceRunId, scope)`.
117
117
  * Called by the engine at the resuming run's TERMINAL boundary (in a `finally`, so abort/error/abandon are
118
118
  * covered), and ONLY when the matching claim was actually granted.
119
119
  *
@@ -124,7 +124,7 @@ export interface WorkflowJournalStore {
124
124
  * A throw here is swallowed by the engine — a release failure must never replace the run's real outcome, and
125
125
  * the store's TTL is the standing backstop for the row it left behind.
126
126
  *
127
- * RB-355 (codex 异源复审 2026-07-29): the engine's terminal boundary now BOUNDS this call (and its wait on
127
+ * RB-355: the engine's terminal boundary now BOUNDS this call (and its wait on
128
128
  * the {@link resumeClaim} verdict) by a timeout — a store that hangs would otherwise keep the run's `done`
129
129
  * promise pending forever, after the outcome is already decided. A release that outlives that bound is
130
130
  * treated exactly like one that throws: swallowed, with the TTL as the backstop. Implementations should not
@@ -139,18 +139,18 @@ export declare const MAX_JOURNAL_RESULT_BYTES: number;
139
139
  /** True when a serialized journal result is too large to store (UTF-8 byte length over {@link MAX_JOURNAL_RESULT_BYTES}). */
140
140
  export declare function oversizeJournalResult(serialized: string): boolean;
141
141
  export declare function callKeyOrdinal(callKey: string): number;
142
- /** RB-243 ([1937]): the errorCode a journal OVERSIZE TOMBSTONE carries — the resume path recognizes it to
142
+ /** RB-243: the errorCode a journal OVERSIZE TOMBSTONE carries — the resume path recognizes it to
143
143
  * say WHY an ordinal never replays. `failed` + this code lands on the T2A-4 no-replay arm, so replay
144
144
  * behavior is identical to the entry simply being absent (the pre-tombstone shape). */
145
145
  export declare const JOURNAL_OVERSIZE_ERROR_CODE = "workflow.journal_oversize";
146
- /** RB-243 ([1937]): mint the tiny FAILED entry the ENGINE journals in place of an oversize result. The
146
+ /** RB-243: mint the tiny FAILED entry the ENGINE journals in place of an oversize result. The
147
147
  * tombstone is minted in the engine, NOT in a store — the stores' skip semantics are unchanged (the
148
148
  * §4.1 backend-parity pin depends on that layering; a store-side tombstone would re-create the RB-168
149
149
  * dialect divergence). Never copies `result.result`/`structuredOutput` (the oversize payload); keeps
150
150
  * taskId/sessionId/stats so the journal read-face still shows the session handle and the paid spend. */
151
151
  export declare function journalOversizeTombstone(result: TaskResult, bytes: number): TaskResult;
152
152
  /**
153
- * RB-367 ([2054] test AI dual-process probe, core-side judgment) — the TTL a resume claim {@link
153
+ * RB-367 (dual-process probe, core-side judgment) — the TTL a resume claim {@link
154
154
  * InMemoryWorkflowJournalStore} grants survives WITHOUT an engine release: the backstop for an engine that
155
155
  * abandoned a granted claim without ever reaching the terminal `finally` that releases it (a bug, not the
156
156
  * normal path — the normal path releases promptly). Same VALUE as the file store's `RESUME_CLAIM_TTL_MS`
@@ -169,7 +169,7 @@ export declare const IN_MEMORY_RESUME_CLAIM_TTL_MS: number;
169
169
  * store WITHOUT the seam — its own header said so). Left unimplemented, the DEFAULT deployment (no
170
170
  * `journalStore` supplied, or this store supplied explicitly) had NO protection against two same-process
171
171
  * `resumeFromRunId` calls off one source forking its execution — the class of bug RB-242 exists to close, and
172
- * a test AI's dual-process probe found it wide open on the default path while the file store's half already
172
+ * a dual-process probe found it wide open on the default path while the file store's half already
173
173
  * worked. A single-process store's promise is necessarily single-process: this implementation gives no
174
174
  * cross-process guarantee (there is no shared medium to publish a claim on), so a multi-process deployment
175
175
  * still needs a store that IS durable/shared (the file or SQL stores) for the seam to mean anything beyond
@@ -21,7 +21,7 @@ export declare function createWorkflowRun(over?: Partial<WorkflowRun>): Workflow
21
21
  * runner). The DEFAULT runs the cases inline and sequentially (so `service` can call
22
22
  * `await workflowRunStoreContract(make)` with no harness at all).
23
23
  *
24
- * ⚠️ Binding note (service [390]): the cases are REGISTERED eagerly and awaited via `Promise.all` — an async
24
+ * ⚠️ Binding note: the cases are REGISTERED eagerly and awaited via `Promise.all` — an async
25
25
  * `runAssertion` that schedules work concurrently will interleave cases. Bindings whose stores share state
26
26
  * (e.g. SQL twins on one table) must CHAIN the assertions themselves (serialize inside `runAssertion`).
27
27
  */
@@ -56,7 +56,7 @@ export async function workflowRunStoreContract(make, runAssertion = defaultSeque
56
56
  assert.equal((await store.get(r.id)).status, "completed");
57
57
  assert.equal(await store.update("ghost", r.scope, createWorkflowRun({ id: "ghost" })), false);
58
58
  });
59
- run("the key id is authoritative — a payload with a mismatched id never poisons the projection (codex BUG4)", async () => {
59
+ run("the key id is authoritative — a payload with a mismatched id never poisons the projection", async () => {
60
60
  const store = make();
61
61
  const r = createWorkflowRun({ id: "real", status: "running" });
62
62
  await store.put("real", { ...r, id: "spoofed" });
@@ -7,7 +7,7 @@ import type { WorkflowRun, WorkflowRunStatus } from "../orchestration/workflow.j
7
7
  *
8
8
  * **Distinct from the four load-bearing durable seams** (session / checkpoint / memory / tool-result): those
9
9
  * are the engine's suspend/resume命脉, so core ships PG adapters for them. A WorkflowRunStore is an
10
- * **observation layer — opt-in, non-engine-critical** — so per design/97 §D.8 (clay 2026-06-22 拍) core
10
+ * **observation layer — opt-in, non-engine-critical** — so per design/97 §D.8 (2026-06-22 拍) core
11
11
  * ships ONLY: this interface + {@link InMemoryWorkflowRunStore} (process-local / default / tests) +
12
12
  * `FileWorkflowRunStore` (zero-dependency, TOC-local persistence — `src/stores/file/workflow-run-store.ts`).
13
13
  * **The PG backend lives in service (TOB), implementing THIS interface** when it needs cross-replica
@@ -34,7 +34,7 @@ export interface WorkflowRunSummary {
34
34
  id: string;
35
35
  /** The tenant / grouping key this run lives in ({@link WorkflowRun.scope}). */
36
36
  scope: string;
37
- /** γ 批 ([1510] server request): the ORIGINATING session id ({@link WorkflowRun.originatingSessionId}),
37
+ /** The ORIGINATING session id ({@link WorkflowRun.originatingSessionId}),
38
38
  * projected so a serving layer's LIST face can apply its session acceptance/filter arm without an
39
39
  * N+1 `get` of the full run. Absent for a direct `runWorkflow` call / sessionless deployment. */
40
40
  originatingSessionId?: string;
@@ -117,10 +117,10 @@ export interface WorkflowRunStore {
117
117
  * core query. Newest first (`createdAt` DESC). `opts.status` filters to one lifecycle state; `opts.limit`
118
118
  * caps the result count (applied AFTER the sort, so it keeps the newest N). An empty scope returns `[]`.
119
119
  */
120
- /** `opts.session` ([1513] server ask, δ 尾件): STORE-side push-down filter on
120
+ /** `opts.session`: STORE-side push-down filter on
121
121
  * `originatingSessionId` — strict equality, rows WITHOUT the field excluded (filter semantics,
122
122
  * deliberately unlike the per-id acceptance arm's absent-pass). Applied BEFORE limit, so the
123
- * serving layer's "this session's workflows" is FULL-history, not page-window ([1513] cli note). */
123
+ * serving layer's "this session's workflows" is FULL-history, not page-window (cli note). */
124
124
  listByScope(scope: string, opts?: WorkflowRunListByScopeOptions): Promise<WorkflowRunSummary[]>;
125
125
  /**
126
126
  * Retention sweep: delete OLD **terminal** runs in `scope` (a `running` run is NEVER deleted — design/97
@@ -26,7 +26,7 @@ export interface CompactionDetails {
26
26
  */
27
27
  invokedSkills?: InvokedSkillRetention[];
28
28
  /**
29
- * RB-398-b ([2105]): CUMULATIVE count of transcript messages this compaction's summary stands in
29
+ * RB-398-b①: CUMULATIVE count of transcript messages this compaction's summary stands in
30
30
  * for (this range's folded messages + the previous compaction's carried count). WRITE-side
31
31
  * accounting on purpose: deriving the count at render time from the branch walk broke the F3
32
32
  * "bounded wake equals full wake" invariant (a floored storage cannot see below the floor, so the
@@ -52,7 +52,7 @@ export interface CompactionDetails {
52
52
  */
53
53
  unsummarizedMessages?: number;
54
54
  /**
55
- * RB-398-c (blackboard [2105]): `<persisted-output ref="…">` handles found in the COMPACTED range
55
+ * RB-398-c: `<persisted-output ref="…">` handles found in the COMPACTED range
56
56
  * (merged over the previous compaction's retained set, oldest-first, capped at
57
57
  * {@link PERSISTED_OUTPUT_REFS_MAX_ENTRIES} newest). The offloaded blobs outlive the preview that
58
58
  * carried their only address — without this channel the handle survived only if the summarizer
@@ -62,7 +62,7 @@ export interface CompactionDetails {
62
62
  */
63
63
  persistedOutputRefs?: string[];
64
64
  /**
65
- * RB-402 (blackboard [2132]③c/[2133]): the activated deferred-tool names LIVE at the
65
+ * RB-402: the activated deferred-tool names LIVE at the
66
66
  * moment this compaction landed — the design/36 activation state whose transcript carriers
67
67
  * (the ToolSearch toolCall parts, and since RB-431 the successful direct calls, that
68
68
  * `extractDiscoveredToolNames` replays at every task boundary)
@@ -98,8 +98,8 @@ export declare function readElidedMessages(details: unknown): number | undefined
98
98
  * {@link readElidedMessages} — a non-negative safe integer, else absent (pre-field sessions /
99
99
  * foreign shapes ⇒ no uncovered-scale clause, byte-identical wrapper). */
100
100
  export declare function readUnsummarizedMessages(details: unknown): number | undefined;
101
- /** Defensive reader for persisted `CompactionDetails.activeTools` (RB-402, blackboard [2132]③c/
102
- * [2133]): the ToolSearch activation snapshot each landed compaction restates. details is
101
+ /** Defensive reader for persisted `CompactionDetails.activeTools` (RB-402):
102
+ * the ToolSearch activation snapshot each landed compaction restates. details is
103
103
  * `unknown` on the wire — pre-field sessions and foreign shapes yield an empty list; non-string/
104
104
  * empty members are dropped (the consumer additionally intersects with the current leg's deferred
105
105
  * registry, so an unknown name is inert either way). */
@@ -14,7 +14,7 @@ export type KillProcessTreeOptions = {
14
14
  * handle with `exitCode === null && signalCode === null`); the pid probe remains only an
15
15
  * auxiliary check. Absent ⇒ the pre-existing pid-only behavior (callers without a process handle).
16
16
  *
17
- * codex R2 (1.296.1) — `false` cancels the DIRECT-pid escalation (that is where pid-reuse risk
17
+ * (1.296.1) — `false` cancels the DIRECT-pid escalation (that is where pid-reuse risk
18
18
  * lives), but on the group-kill lane it no longer cancels the GROUP leg: the anchor only knows
19
19
  * the LEADER — a detached shell that honors SIGTERM and exits while its TERM-ignoring descendants
20
20
  * (run89's build workers) keep the group alive. While ANY original member lives, POSIX reserves
@@ -6,12 +6,12 @@ import type { SchedulerCapability, ScheduledIntent, SchedulerContext, ScheduledT
6
6
  import { SchedulerError } from "../../core/scheduler.js";
7
7
  /** Convert user-facing timeout seconds into a positive, timer-safe millisecond delay. */
8
8
  export declare function resolveExecTimeoutMs(timeoutSeconds: unknown): number | undefined;
9
- /** service [377] review finding (win32): `where bash.exe` can resolve to `System32\bash.exe` — the
9
+ /** review finding (win32): `where bash.exe` can resolve to `System32\bash.exe` — the
10
10
  * WSL LAUNCHER, not a native shell. Running it drops into a Linux subsystem where Windows cwd/paths
11
11
  * do not exist; silently adopting it is exactly the "wrong shell, false green" failure D1 forbids.
12
12
  * Filter it (and the WindowsApps alias) out of PATH discovery; Git-Bash candidates are tried first. */
13
13
  export declare function isWslBashLauncher(p: string): boolean;
14
- /** Shell discovery for the platform (service [377] ask ①: exported as the single SDK source so a host
14
+ /** Shell discovery for the platform (ask ①: exported as the single SDK source so a host
15
15
  * adapter does not mirror the platform logic). Explicit `customShellPath` wins (missing → err);
16
16
  * win32 = Git-Bash discovery (ProgramFiles → PATH, WSL launcher filtered) with fail-loud
17
17
  * `shell_unavailable` (never a silent cmd.exe fallback); POSIX = /bin/bash → PATH bash → sh. */
@@ -21,7 +21,7 @@ export declare function getShellConfig(customShellPath?: string): Promise<Result
21
21
  }, ExecutionError>>;
22
22
  /** test seam (mirrors the notice-seat announce reset): the once-per-process fallback latches. */
23
23
  export declare function __resetSecretScrubAnnouncement(): void;
24
- /** RB-235 ([1937] BB2): the spool-reclaim decision, extracted PURE so every rule is unit-pinnable.
24
+ /** RB-235: the spool-reclaim decision, extracted PURE so every rule is unit-pinnable.
25
25
  * Both reclaim sites (foreground `reclaimSpool`, background `syncSpool`) route through this one
26
26
  * function so they cannot drift apart.
27
27
  *
@@ -65,7 +65,7 @@ export declare function decideSpoolReclaim(args: {
65
65
  reclaim: true;
66
66
  skippedBytes: number;
67
67
  };
68
- /** design/128 T1-1 / codex 1.236 复审 R2: open the spool file pair ALL-OR-NOTHING — a failure opening the
68
+ /** design/128 T1-1: open the spool file pair ALL-OR-NOTHING — a failure opening the
69
69
  * second file must close the first fd before rethrowing (the caller's catch only clears its references, so
70
70
  * a half-open pair would leak fdOut for the env's lifetime). `wx` + 0600 (never follow / never reuse an
71
71
  * existing path). Exported for direct fault-injection tests (pre-create a path → EEXIST). `a` (not
@@ -132,14 +132,14 @@ export declare class NodeExecutionEnv implements ExecutionEnv, BackgroundShellCa
132
132
  abortSignal?: AbortSignal;
133
133
  }): Promise<Result<string[], FileError>>;
134
134
  readBinaryFile(path: string, abortSignal?: AbortSignal): Promise<Result<Uint8Array, FileError>>;
135
- /** RB-221 ([1937]): whole-file replace via same-directory staging + fsync + rename (CC 2.1.220 `Q5`,
135
+ /** RB-221: whole-file replace via same-directory staging + fsync + rename (CC 2.1.220 `Q5`,
136
136
  * pretty220.js:60808). The former single-step `writeFile` was an in-place O_TRUNC: an abort mid-write
137
137
  * (Esc during a large Write — ctx.signal reaches here directly), ENOSPC, or a crash left the target as
138
138
  * a torn prefix of the NEW content with the original unrecoverable. Post-fix contract: the target is
139
139
  * either fully old or fully new; `aborted` means it was never touched. Known semantic change (same as
140
140
  * CC): rename breaks a hard link — the other link keeps the old content. */
141
141
  writeFile(path: string, content: string | Uint8Array, abortSignal?: AbortSignal): Promise<Result<void, FileError>>;
142
- /** RB-221 ([1937]): the historical single-step in-place overwrite — kept for targets where
142
+ /** RB-221: the historical single-step in-place overwrite — kept for targets where
143
143
  * staging+rename would change node identity (symlink chains, non-regular files) and as the
144
144
  * CC-parity fallback for filesystems where the rename cannot work. NOT atomic by design. */
145
145
  private writeFileInPlace;
@@ -180,11 +180,11 @@ export declare class NodeExecutionEnv implements ExecutionEnv, BackgroundShellCa
180
180
  /** design/128 T1-1: incrementally read a retained shell's spool files into the in-memory tails, so
181
181
  * pollBackground serves the same cursor semantics whether stdio came over pipes or spool files.
182
182
  * Bounded single read per stream per poll (the tail keeps only its rolling window anyway).
183
- * codex R3 F-C: reads are positioned by spool.fileCursor (the FILE offset — rotation truncates
183
+ * reads are positioned by spool.fileCursor (the FILE offset — rotation truncates
184
184
  * the file), while poll slicing keeps using the logical stream totalBytes; the two advance in
185
185
  * lockstep here but are NOT interchangeable after a rotation. */
186
186
  private syncSpool;
187
- /** codex R3 F-D + [1105]: reclaim an EPHEMERAL spool (detach-adopted, or any non-retain bg
187
+ /** +: reclaim an EPHEMERAL spool (detach-adopted, or any non-retain bg
188
188
  * spawn — the whole unix bg lane is spool-backed now) — fold the final residue into the tails,
189
189
  * unlink both files, and drop the spool reference (later syncs become no-ops). Idempotent;
190
190
  * never touches design/128 retain-lane spools (no `ephemeral` flag). A still-writing detached
@@ -2,7 +2,7 @@ import type { ActorAssertion, AssistantMessage, ImageContent, Model } from "../l
2
2
  import type { AgentMessage, AgentTool, LoopMalformedToolUseRecovery, LoopThinkingOnlyRecovery, LoopTruncatedOutputRecovery, QueueMode, ThinkingLevel } from "../loop/types.js";
3
3
  import { type EngineSegment } from "../../core/untrusted-text.js";
4
4
  import type { AbortResult, AgentHarnessEvent, AgentHarnessEventResultMap, AgentHarnessOptions, AgentHarnessOwnEvent, AgentHarnessResources, AgentHarnessStreamOptions, ExecutionEnv, PromptTemplate, Skill } from "./types.js";
5
- /** [c209-C] codex 收口 C1/C2 — engine-provenance metadata a caller can stamp on the user message it
5
+ /** [c209-C] 收口 C1/C2 — engine-provenance metadata a caller can stamp on the user message it
6
6
  * mints (see the field docs on {@link UserMessage}). Threaded from `prompt`/`steer`/`followUp`/
7
7
  * `nextTurn` options into the persisted message so derived views (auto-mode window, compaction
8
8
  * serializer) work from METADATA, never from reminder-shape guessing. */
@@ -93,7 +93,7 @@ export declare class AgentHarness<TSkill extends Skill = Skill, TPromptTemplate
93
93
  * hand a queued frame to the model once the run is unwinding, and — crucially — none may SPLICE one
94
94
  * out of the queue either (that would delete the terminal undrained account the abort path owes it). */
95
95
  private aborting;
96
- /** backlog #389 (codex adversarial r1, HIGH-1) — frames a boundary has REMOVED from a queue but that
96
+ /** backlog #389 (HIGH-1) — frames a boundary has REMOVED from a queue but that
97
97
  * have not yet entered the model's context.
98
98
  *
99
99
  * The abort latch alone leaves a real window: `drainQueuedMessages` splices first and then awaits
@@ -147,7 +147,7 @@ export declare class AgentHarness<TSkill extends Skill = Skill, TPromptTemplate
147
147
  * gated: its splice opens a NEW run (idle-park redelivery), and a halt belongs to the run that
148
148
  * minted it. */
149
149
  engineInjectionsHeld?: () => boolean;
150
- /** RB-30 codex F1/F2: shared recovery sweep — collects engine-note payloads from the given queues
150
+ /** RB-30: shared recovery sweep — collects engine-note payloads from the given queues
151
151
  * in DELIVERY order (steer before followUp, each queue forward — the live loop serves steering
152
152
  * first, so the recovered redelivery must not present "later" frames ahead of "now/next"),
153
153
  * removes those entries, and hands the payloads to the runner sink. Called from BOTH terminal
@@ -243,16 +243,16 @@ export declare class AgentHarness<TSkill extends Skill = Skill, TPromptTemplate
243
243
  prompt(text: string, options?: {
244
244
  images?: ImageContent[];
245
245
  } & UserMessageProvenance): Promise<AssistantMessage>;
246
- /** [920] R2-③: an empty/whitespace-only injection with no images carries ZERO information — it
246
+ /** R2-③: an empty/whitespace-only injection with no images carries ZERO information — it
247
247
  * must not mint a user frame (strict endpoints reject empty user content, and an empty follow-up would
248
248
  * pointlessly extend the run by one turn). No-op, not a throw: injection callers are fire-and-
249
249
  * forget lanes (wakeups, reminders) and a shell bug upstream must not crash the run. */
250
250
  private static emptyInjection;
251
- /** REF-B6 — the ONE injection enqueue behind steer()/followUp()/nextTurn(): the [920] R2-③ empty-injection
251
+ /** REF-B6 — the ONE injection enqueue behind steer/followUp/nextTurn: the R2-③ empty-injection
252
252
  * short circuit, the user frame, the RB-30 engine-payload SIDECAR (a WeakMap entry, never a message field —
253
253
  * pre-prompt exits recover these too), the queue push, and the broadcast. All three lanes ship in ONE
254
254
  * `queue_update` event (see emitQueueUpdate), so they are one protocol contract and must stay one
255
- * implementation: [920] R2-③ and RB-30 each had to be patched in three places.
255
+ * implementation: R2-③ and RB-30 each had to be patched in three places.
256
256
  *
257
257
  * The idle check is deliberately NOT here: its message differs per lane, and nextTurn() legitimately has
258
258
  * none (queueing the NEXT prompt while idle is exactly what it is for). */
@@ -2,6 +2,7 @@ import { snapshotActorAssertion, stripEngineMetadata } from "../llm/index.js";
2
2
  import { runAgentLoop } from "../loop/agent-loop.js";
3
3
  import { resolveAgentCoreStreamFn } from "../loop/runtime-deps.js";
4
4
  import { normalizeEngineSegments } from "../../core/untrusted-text.js";
5
+ import { AUTH_CARRIER_NAMES } from "../../brain/request-params.js";
5
6
  import { convertToLlm } from "./messages.js";
6
7
  import { AgentHarnessError, CompactionError, SessionError, toError, } from "./types.js";
7
8
  function createUserMessage(text, images, provenance) {
@@ -84,6 +85,28 @@ function mergeHeaders(...headers) {
84
85
  }
85
86
  return hasHeaders ? merged : undefined;
86
87
  }
88
+ function dropAuthCarriers(bag) {
89
+ if (!bag)
90
+ return bag;
91
+ const out = {};
92
+ for (const [k, v] of Object.entries(bag)) {
93
+ if (!AUTH_CARRIER_NAMES.has(k.toLowerCase()))
94
+ out[k] = v;
95
+ }
96
+ return out;
97
+ }
98
+ function refuseAuthCarriersInStreamOptions(bag) {
99
+ if (!bag)
100
+ return;
101
+ for (const k of Object.keys(bag)) {
102
+ if (AUTH_CARRIER_NAMES.has(k.toLowerCase())) {
103
+ throw new Error(`streamOptions.headers must not carry an auth header ("${k}") — the run-static bag is not an auth channel ` +
104
+ `(the route pairing law reads options-borne carriers as per-model credentials, which a run-wide bag is not). ` +
105
+ `Put a deployment credential on the brain config (apiKey / headers, where its URL half is judged), or serve ` +
106
+ `per-model credentials through getApiKeyAndHeaders.`);
107
+ }
108
+ }
109
+ }
87
110
  function applyStreamOptionsPatch(base, patch) {
88
111
  const result = cloneStreamOptions(base);
89
112
  if (!patch) {
@@ -239,6 +262,7 @@ export class AgentHarness {
239
262
  this.env = options.env;
240
263
  this.session = options.session;
241
264
  this.resources = options.resources ?? {};
265
+ refuseAuthCarriersInStreamOptions(options.streamOptions?.headers);
242
266
  this.streamOptions = cloneStreamOptions(options.streamOptions);
243
267
  this.systemPrompt = options.systemPrompt;
244
268
  this.systemBlocks = options.systemBlocks;
@@ -426,7 +450,7 @@ export class AgentHarness {
426
450
  const auth = await this.getApiKeyAndHeaders?.(model);
427
451
  const snapshotOptions = {
428
452
  ...turnState.streamOptions,
429
- headers: mergeHeaders(turnState.streamOptions.headers, auth?.headers),
453
+ headers: mergeHeaders(dropAuthCarriers(turnState.streamOptions.headers), auth?.headers),
430
454
  };
431
455
  const requestOptions = await this.emitBeforeProviderRequest(model, turnState.sessionId, snapshotOptions);
432
456
  return resolveAgentCoreStreamFn(this.runtime)(model, context, {
@@ -951,6 +975,7 @@ export class AgentHarness {
951
975
  return cloneStreamOptions(this.streamOptions);
952
976
  }
953
977
  async setStreamOptions(streamOptions) {
978
+ refuseAuthCarriersInStreamOptions(streamOptions?.headers);
954
979
  this.streamOptions = cloneStreamOptions(streamOptions);
955
980
  }
956
981
  setSystemPrompt(prompt, blocks) {
@@ -20,7 +20,7 @@ export declare function createCustomMessage(customType: string, content: string
20
20
  * product, not authored content. */
21
21
  export declare const NORMALIZED_CONTENT_PREFIX = "[invalid content block normalized to text]";
22
22
  /**
23
- * Fail-soft salvage for a possibly-contaminated LLM message ([868] 件b): any structurally-invalid
23
+ * Fail-soft salvage for a possibly-contaminated LLM message (件b): any structurally-invalid
24
24
  * `content` shape (bare object as the whole field, or a typeless/unknown-type block in the array) is
25
25
  * normalized to a prefixed text block. Legal messages are returned BY REFERENCE, untouched. Shared by
26
26
  * `convertToLlm` (provider leg) and `serializeConversation` (compaction leg) — one helper, two mouths.
@@ -62,7 +62,11 @@ export interface AgentHarnessStreamOptions {
62
62
  maxRetries?: number;
63
63
  /** Optional cap for provider-requested retry delays. */
64
64
  maxRetryDelayMs?: number;
65
- /** Additional request headers merged with auth and lifecycle headers. */
65
+ /** Additional request headers merged with auth and lifecycle headers. NOT an auth channel: a bag
66
+ * carrying an auth header (`authorization` / `x-api-key`, any case) is refused loudly at the
67
+ * construction and `setStreamOptions` seats — the route pairing law reads options-borne
68
+ * carriers as per-model credentials, which a run-wide bag is not. Deployment credentials go on
69
+ * the brain config; per-model credentials ride `getApiKeyAndHeaders`. */
66
70
  headers?: Record<string, string>;
67
71
  /** Provider metadata forwarded with requests. */
68
72
  metadata?: SimpleStreamOptions["metadata"];
@@ -222,7 +226,7 @@ export interface ExecutionEnvExecOptions {
222
226
  /** Called with stderr chunks as they are produced. */
223
227
  onStderr?: (chunk: string) => void;
224
228
  /**
225
- * VENDORED EDIT (design/116 detach, 飞轮 [C]): when fired mid-run, an env that supports detach ADOPTS the
229
+ * VENDORED EDIT (design/116 detach, [C]): when fired mid-run, an env that supports detach ADOPTS the
226
230
  * running child as a background process (its handle never leaves the env) and settles the exec with a
227
231
  * `detached` marker instead of killing it. Envs without detach support ignore this (the exec runs on).
228
232
  */
@@ -265,7 +269,7 @@ export interface FileSystem {
265
269
  /** Read a binary file. */
266
270
  readBinaryFile(path: string, abortSignal?: AbortSignal): Promise<Result<Uint8Array, FileError>>;
267
271
  /** Create or overwrite a file, creating parent directories when supported. Implementation note
268
- * (RB-221 [1937]): the Node env replaces the file as a WHOLE (same-directory staging + fsync +
272
+ * (RB-221): the Node env replaces the file as a WHOLE (same-directory staging + fsync +
269
273
  * rename; `aborted` ⇒ target untouched), falling back to an in-place rewrite where rename cannot
270
274
  * apply (cross-device, symlink chains, non-regular targets, read-only parent dir). Atomicity is an
271
275
  * implementation quality, NOT an interface-level contract — a remote/transport env may only have a
@@ -451,7 +455,7 @@ export interface LeafEntry extends SessionTreeEntryBase {
451
455
  targetId: string | null;
452
456
  }
453
457
  /**
454
- * Prompt-epoch pin (campaign S3, prompt-assembly protocol §9.2) — a FIRST-CLASS typed entry (not a
458
+ * Prompt-epoch pin (stage S3, prompt-assembly protocol §9.2) — a FIRST-CLASS typed entry (not a
455
459
  * forgeable generic `custom` entry): which prompt-pack artifact this session is pinned to. Written
456
460
  * at session start (before the first conversation entry) and on legacy migration; every compaction
457
461
  * RESTATES the then-current descriptor inside its own `details.promptEpoch` (same-CAS atomicity,
@@ -478,7 +482,7 @@ export interface AnnouncedListingEntry extends SessionTreeEntryBase {
478
482
  models?: string[];
479
483
  }
480
484
  /**
481
- * REF-D3/D4 merge target: the active EnterWorktree session (M22 live-CC anchor, codex 终审 1.255 F2
485
+ * REF-D3/D4 merge target: the active EnterWorktree session (M22 live-CC anchor —
482
486
  * plain strings only, no closures, so it survives a durable suspend into `CheckpointState.activeWorktree`
483
487
  * verbatim). Canonical definition — `tools/worktree.ts` (the tool pair that owns this durably) re-exports
484
488
  * this type rather than declaring its own copy: the harness layer must never import FROM `tools/`
@@ -508,7 +512,7 @@ export interface WorkspaceState {
508
512
  activeWorktree?: ActiveWorktreeSession;
509
513
  }
510
514
  /**
511
- * design/155 (cli [1580]): the session's WORKSPACE STATE at a task settle — the tracked logical cwd
515
+ * design/155: the session's WORKSPACE STATE at a task settle — the tracked logical cwd
512
516
  * and the active EnterWorktree session. Ordinary continuation turns (a new task on the same
513
517
  * `spec.sessionId`) have NO checkpoint seed, so without this entry both refs silently reset to the
514
518
  * task root every turn (cd doesn't stick, ExitWorktree no-ops, the worktree leaks). Restore ladder
@@ -707,7 +711,7 @@ export interface SessionStorage<TMetadata extends SessionMetadata = SessionMetad
707
711
  getPathToRoot(leafId: string | null): Promise<SessionTreeEntry[]>;
708
712
  getEntries(): Promise<SessionTreeEntry[]>;
709
713
  /**
710
- * Campaign S3 / RB-14 seam (blackboard [975] joint verdict): OPTIONAL epoch anchor for
714
+ * S3 / RB-14 seam (joint verdict): OPTIONAL epoch anchor for
711
715
  * bounded-tail backends. A durable backend that loads only `firstKeptEntryId..leaf` cannot show
712
716
  * the branch walk an epoch carrier when a rewind cuts BEFORE the latest compaction's restatement
713
717
  * (window: firstKept ≤ cut < compactionEntry) — `Session.getPromptEpoch()` falls back to this
@@ -844,7 +848,7 @@ export interface SessionRepo<TMetadata extends SessionMetadata = SessionMetadata
844
848
  delete(metadata: TMetadata): Promise<void>;
845
849
  fork(source: TMetadata, options: SessionForkOptions & TCreateOptions): Promise<Session<TMetadata>>;
846
850
  /**
847
- * 2c session-sync (service [266]②): the FULL durable entry log for `sessionId`, oldest-first, with
851
+ * 2c session-sync: the FULL durable entry log for `sessionId`, oldest-first, with
848
852
  * `id`/`parentId` VERBATIM and BYPASSING any compaction floor — NOT `getEntries()`, which on a durable
849
853
  * backend that woke with a bounded F3 window returns only the tail (silently truncating pre-floor history).
850
854
  * Optional — a backend that supports cross-backend session export/migration implements it.
@@ -1110,7 +1114,7 @@ export interface AgentHarnessOptions<TSkill extends Skill = Skill, TPromptTempla
1110
1114
  resources: AgentHarnessResources<TSkill, TPromptTemplate>;
1111
1115
  }) => string | Promise<string>);
1112
1116
  /**
1113
- * Campaign S4 (ADDITIVE): physical system blocks for block-aware Brains. Static per leg (same
1117
+ * S4 (ADDITIVE): physical system blocks for block-aware Brains. Static per leg (same
1114
1118
  * freeze semantics as a string `systemPrompt`). When present it MUST correspond to the same
1115
1119
  * bytes as `systemPrompt` (the M13 projection duty is on the producer — prepare-task). Brains
1116
1120
  * that ignore it read `systemPrompt` and lose nothing.
@@ -1154,13 +1158,13 @@ export interface AgentHarnessOptions<TSkill extends Skill = Skill, TPromptTempla
1154
1158
  */
1155
1159
  abortResultDetails?: () => Record<string, unknown> | undefined;
1156
1160
  /**
1157
- * service [398] C2: the loop's recovery/terminal trace sink, forwarded to `runAgentLoop`'s trace
1161
+ * C2: the loop's recovery/terminal trace sink, forwarded to `runAgentLoop`'s trace
1158
1162
  * parameter (previously test-only — never passed in production, so the loop's six self-heal
1159
1163
  * recoveries were invisible outside display:false nudge messages). Must not throw; hot path.
1160
1164
  */
1161
1165
  loopTrace?: (step: import("../loop/agent-loop.js").LoopStep) => void;
1162
1166
  /**
1163
- * design/131 (service [404] 拍): per-task resilience intent flags, forwarded to every provider
1167
+ * design/131 (拍): per-task resilience intent flags, forwarded to every provider
1164
1168
  * call (`StreamOptions.resilience`) so the deployment's decorator stack (degrading / failover /
1165
1169
  * breaker) can stand aside for this task. Absent ⇒ today's behavior.
1166
1170
  */