@sema-agent/core 5.20.0 → 5.21.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 (312) hide show
  1. package/CHANGELOG.md +9 -0
  2. package/dist/agents/agent-definition.d.ts +7 -0
  3. package/dist/agents/agent-transcript-tool.d.ts +30 -0
  4. package/dist/agents/builtin-agents.d.ts +60 -0
  5. package/dist/agents/cascade.d.ts +107 -0
  6. package/dist/agents/cumulative-stats.d.ts +56 -0
  7. package/dist/agents/observer.d.ts +162 -0
  8. package/dist/agents/peer-admission.d.ts +95 -0
  9. package/dist/agents/repair-loop.d.ts +226 -0
  10. package/dist/agents/retain-ledger.d.ts +141 -0
  11. package/dist/agents/roster-store.d.ts +105 -0
  12. package/dist/agents/send-message-tool.d.ts +92 -0
  13. package/dist/agents/session-util.d.ts +5 -0
  14. package/dist/agents/subagent-steps.d.ts +66 -0
  15. package/dist/agents/subagent.d.ts +600 -0
  16. package/dist/agents/suspend-guard.d.ts +29 -0
  17. package/dist/agents/teacher.d.ts +75 -0
  18. package/dist/agents/team.d.ts +120 -1
  19. package/dist/agents/tool-filter.d.ts +34 -0
  20. package/dist/agents/verify.d.ts +198 -0
  21. package/dist/bench/metrics.d.ts +455 -0
  22. package/dist/brain/anthropic.d.ts +30 -0
  23. package/dist/brain/circuit-breaker.d.ts +33 -0
  24. package/dist/brain/context-overflow.d.ts +60 -3
  25. package/dist/brain/degrading.d.ts +67 -0
  26. package/dist/brain/errors.d.ts +42 -0
  27. package/dist/brain/failover.d.ts +15 -0
  28. package/dist/brain/media-degrade.d.ts +39 -0
  29. package/dist/brain/model-presets.d.ts +31 -0
  30. package/dist/brain/open-responses.d.ts +19 -0
  31. package/dist/brain/openai.d.ts +46 -0
  32. package/dist/brain/reasoning.d.ts +106 -1
  33. package/dist/brain/repetition.d.ts +83 -0
  34. package/dist/brain/request-params.d.ts +56 -0
  35. package/dist/brain/retry.d.ts +46 -0
  36. package/dist/brain/routing.d.ts +12 -0
  37. package/dist/brain/status-sink.d.ts +30 -1
  38. package/dist/brain/stream-engine.d.ts +147 -0
  39. package/dist/brain/stream-shared.d.ts +34 -0
  40. package/dist/brain/terminal-cause.d.ts +31 -0
  41. package/dist/brain/timeout.d.ts +107 -0
  42. package/dist/brain/tool-call-id.d.ts +20 -0
  43. package/dist/brain/tool-call-repair.d.ts +13 -0
  44. package/dist/config/catalog.d.ts +47 -0
  45. package/dist/config/defaults.d.ts +33 -0
  46. package/dist/core/a2a-task-state.d.ts +53 -0
  47. package/dist/core/a2a.d.ts +51 -0
  48. package/dist/core/arg-summary.d.ts +62 -0
  49. package/dist/core/ask-question.d.ts +272 -2
  50. package/dist/core/auto-compaction.d.ts +467 -0
  51. package/dist/core/auto-compaction.js +20 -6
  52. package/dist/core/auto-mode-prompt-assets.d.ts +8 -0
  53. package/dist/core/auto-mode-prompt.d.ts +27 -0
  54. package/dist/core/auto-mode.d.ts +54 -3
  55. package/dist/core/auto-promote.d.ts +100 -0
  56. package/dist/core/background-agent-store.d.ts +292 -0
  57. package/dist/core/background-shell.d.ts +110 -0
  58. package/dist/core/cache-break-detector.d.ts +34 -0
  59. package/dist/core/canonical-json.d.ts +57 -0
  60. package/dist/core/checkpoint-store.d.ts +1574 -16
  61. package/dist/core/compliance.d.ts +30 -0
  62. package/dist/core/consolidate-scope.d.ts +75 -0
  63. package/dist/core/context-edit.d.ts +99 -0
  64. package/dist/core/context-guard.d.ts +46 -0
  65. package/dist/core/exec-gate.d.ts +44 -0
  66. package/dist/core/exec-output-tail.d.ts +61 -0
  67. package/dist/core/file-snapshot-store.d.ts +104 -0
  68. package/dist/core/fs-write-gate-policy.d.ts +36 -0
  69. package/dist/core/git-worktree-env.d.ts +31 -0
  70. package/dist/core/governance-codes.d.ts +19 -0
  71. package/dist/core/hooks.d.ts +608 -1
  72. package/dist/core/human-input-projection.d.ts +37 -0
  73. package/dist/core/human-input-projection.js +13 -0
  74. package/dist/core/image-downsample.d.ts +74 -0
  75. package/dist/core/locked-config.d.ts +37 -0
  76. package/dist/core/lsp-diagnostics.d.ts +77 -0
  77. package/dist/core/lsp-protocol.d.ts +29 -0
  78. package/dist/core/lsp-session.d.ts +60 -1
  79. package/dist/core/lsp.d.ts +150 -1
  80. package/dist/core/mailbox-store.d.ts +57 -0
  81. package/dist/core/mcp.d.ts +381 -0
  82. package/dist/core/media-byte-cap.d.ts +21 -0
  83. package/dist/core/memory-admission.d.ts +71 -0
  84. package/dist/core/memory-engine/content-origin.d.ts +64 -0
  85. package/dist/core/memory-engine/data-plane.d.ts +43 -0
  86. package/dist/core/memory-engine/dual-root.d.ts +24 -0
  87. package/dist/core/memory-engine/engine.d.ts +230 -0
  88. package/dist/core/memory-engine/engine.js +103 -35
  89. package/dist/core/memory-engine/file-backend.d.ts +155 -0
  90. package/dist/core/memory-engine/frontmatter.d.ts +16 -0
  91. package/dist/core/memory-engine/layout.d.ts +217 -0
  92. package/dist/core/memory-engine/memory-backend-contract.d.ts +12 -0
  93. package/dist/core/memory-engine/migrate.d.ts +9 -0
  94. package/dist/core/memory-engine/scan.d.ts +12 -0
  95. package/dist/core/memory-engine/scope-contract.d.ts +61 -1
  96. package/dist/core/memory-engine/sync-client.d.ts +87 -0
  97. package/dist/core/memory-engine/sync.d.ts +60 -0
  98. package/dist/core/memory-engine/tools.d.ts +41 -0
  99. package/dist/core/memory-engine/types.d.ts +188 -0
  100. package/dist/core/memory-recall.d.ts +141 -0
  101. package/dist/core/memory-vector.d.ts +20 -0
  102. package/dist/core/memory.d.ts +458 -0
  103. package/dist/core/message-utils.d.ts +6 -0
  104. package/dist/core/oracle-isolation.d.ts +69 -0
  105. package/dist/core/permission-rule-consent.d.ts +138 -0
  106. package/dist/core/permission-rule-model.d.ts +122 -0
  107. package/dist/core/permission-rule-store.d.ts +119 -3
  108. package/dist/core/permission-rules.d.ts +87 -1
  109. package/dist/core/present-plan-tool.d.ts +20 -0
  110. package/dist/core/pricing.d.ts +26 -0
  111. package/dist/core/property-harness.d.ts +86 -0
  112. package/dist/core/protocol-naming.d.ts +38 -0
  113. package/dist/core/protocol-table.d.ts +61 -0
  114. package/dist/core/push-queue.d.ts +1 -0
  115. package/dist/core/remote-env.d.ts +383 -1
  116. package/dist/core/retention-policy.d.ts +33 -0
  117. package/dist/core/retention.d.ts +51 -0
  118. package/dist/core/roles.d.ts +59 -0
  119. package/dist/core/runner/active-skill-scope.d.ts +34 -0
  120. package/dist/core/runner/assemble-result.d.ts +134 -0
  121. package/dist/core/runner/compaction-call-options.d.ts +97 -1
  122. package/dist/core/runner/grounding-signal.d.ts +10 -0
  123. package/dist/core/runner/image.d.ts +17 -0
  124. package/dist/core/runner/image.js +29 -15
  125. package/dist/core/runner/memory-consolidation.d.ts +60 -0
  126. package/dist/core/runner/prepare-memory.d.ts +59 -0
  127. package/dist/core/runner/prepare-task.d.ts +1011 -2
  128. package/dist/core/runner/prepare-task.js +12 -11
  129. package/dist/core/runner/prompt-suggestions.d.ts +7 -0
  130. package/dist/core/runner/runtask.d.ts +304 -3
  131. package/dist/core/runner/session-file-state-replay.d.ts +49 -0
  132. package/dist/core/runner/session-rule-policy.d.ts +58 -0
  133. package/dist/core/runner/strict-output-schema.d.ts +18 -3
  134. package/dist/core/runner/synthetic-tools.d.ts +113 -0
  135. package/dist/core/runner/teardown-bounded.d.ts +34 -0
  136. package/dist/core/runner/tool-disclosure.d.ts +227 -0
  137. package/dist/core/runner/tool-output-projection.d.ts +6 -0
  138. package/dist/core/runner/turn-attachments.d.ts +634 -0
  139. package/dist/core/runner/usage-accounting.d.ts +32 -0
  140. package/dist/core/runtime.d.ts +9 -0
  141. package/dist/core/safe-notify.d.ts +64 -0
  142. package/dist/core/safety-axis-vocab.d.ts +23 -0
  143. package/dist/core/safety-merge-corpus.d.ts +37 -0
  144. package/dist/core/scheduler.d.ts +121 -0
  145. package/dist/core/secret-env.d.ts +32 -0
  146. package/dist/core/select-model.d.ts +15 -0
  147. package/dist/core/sensitive-path-policy.d.ts +42 -0
  148. package/dist/core/session-policy-store.d.ts +94 -0
  149. package/dist/core/session-reconcile.d.ts +80 -0
  150. package/dist/core/session-store.d.ts +85 -0
  151. package/dist/core/session.d.ts +153 -0
  152. package/dist/core/shared-memory/contract.d.ts +22 -0
  153. package/dist/core/shared-memory/normalize.d.ts +123 -2
  154. package/dist/core/shared-memory/tools.d.ts +14 -0
  155. package/dist/core/shared-memory/types.d.ts +105 -0
  156. package/dist/core/shutdown-debug.d.ts +6 -0
  157. package/dist/core/side-query.d.ts +38 -0
  158. package/dist/core/side-query.js +6 -1
  159. package/dist/core/skill-tool-specifier.d.ts +72 -0
  160. package/dist/core/skills-directory.d.ts +100 -1
  161. package/dist/core/spec-contract.d.ts +89 -0
  162. package/dist/core/store-contracts/background-agent-store-contract.d.ts +31 -0
  163. package/dist/core/store-contracts/checkpoint-store-contract.d.ts +26 -0
  164. package/dist/core/store-contracts/contract-harness.d.ts +20 -0
  165. package/dist/core/store-contracts/contract-kit-version.d.ts +27 -0
  166. package/dist/core/store-contracts/file-snapshot-store-contract.d.ts +8 -0
  167. package/dist/core/store-contracts/mailbox-store-contract.d.ts +42 -0
  168. package/dist/core/store-contracts/tool-result-store-contract.d.ts +13 -0
  169. package/dist/core/strategy-store.d.ts +37 -0
  170. package/dist/core/stub-env.d.ts +7 -0
  171. package/dist/core/surrogate-safe-slice.d.ts +35 -0
  172. package/dist/core/task-notification.d.ts +202 -0
  173. package/dist/core/task-outcome.d.ts +53 -0
  174. package/dist/core/task-registry-agent.d.ts +337 -1
  175. package/dist/core/task-registry-monitor.d.ts +12 -0
  176. package/dist/core/task-registry-shared.d.ts +540 -0
  177. package/dist/core/task-registry.d.ts +343 -0
  178. package/dist/core/task-registry.js +13 -2
  179. package/dist/core/task-tool-shape.d.ts +44 -0
  180. package/dist/core/tighten-task-spec.d.ts +21 -0
  181. package/dist/core/tool-detach.d.ts +21 -0
  182. package/dist/core/tool-errors.d.ts +131 -0
  183. package/dist/core/tool-errors.js +4 -0
  184. package/dist/core/tool-name-aliases.d.ts +27 -0
  185. package/dist/core/tool-policy.d.ts +555 -0
  186. package/dist/core/tool-result-budget.d.ts +32 -0
  187. package/dist/core/tool-result-store.d.ts +174 -1
  188. package/dist/core/tools.d.ts +45 -0
  189. package/dist/core/trace.d.ts +323 -0
  190. package/dist/core/types.d.ts +3859 -2
  191. package/dist/core/untrusted-egress.d.ts +8 -0
  192. package/dist/core/untrusted-text.d.ts +156 -0
  193. package/dist/core/usage-window-store.d.ts +95 -0
  194. package/dist/core/version.d.ts +1 -0
  195. package/dist/core/warm-resume.d.ts +17 -0
  196. package/dist/core/wiring-manifest.d.ts +169 -0
  197. package/dist/core/with-retry.d.ts +24 -0
  198. package/dist/core/workflow-journal-store.d.ts +160 -0
  199. package/dist/core/workflow-run-store-contract.d.ts +25 -0
  200. package/dist/core/workflow-run-store.d.ts +119 -0
  201. package/dist/engine/compaction/compaction.d.ts +256 -1
  202. package/dist/engine/compaction/utils.d.ts +94 -0
  203. package/dist/engine/execution-env/kill-tree.d.ts +29 -0
  204. package/dist/engine/execution-env/node-execution-env.d.ts +94 -0
  205. package/dist/engine/harness/agent-harness.d.ts +116 -0
  206. package/dist/engine/harness/agent-harness.js +3 -14
  207. package/dist/engine/harness/messages.d.ts +15 -0
  208. package/dist/engine/harness/types.d.ts +464 -2
  209. package/dist/engine/llm/diagnostics.d.ts +4 -0
  210. package/dist/engine/llm/event-stream.d.ts +3 -0
  211. package/dist/engine/llm/index.d.ts +7 -0
  212. package/dist/engine/llm/types.d.ts +500 -3
  213. package/dist/engine/llm/validation.d.ts +3 -0
  214. package/dist/engine/loop/agent-loop.d.ts +87 -2
  215. package/dist/engine/loop/runtime-deps.d.ts +7 -0
  216. package/dist/engine/loop/types.d.ts +424 -0
  217. package/dist/engine/lsp/frame-decoder.d.ts +13 -0
  218. package/dist/engine/lsp/node-lsp-manager.d.ts +107 -0
  219. package/dist/engine/lsp/stdio-lsp-transport.d.ts +7 -0
  220. package/dist/engine/session/import-validate.d.ts +27 -0
  221. package/dist/engine/session/log-digest.d.ts +93 -0
  222. package/dist/engine/session/memory-repo.d.ts +6 -0
  223. package/dist/engine/session/memory-storage.d.ts +2 -0
  224. package/dist/engine/session/session.d.ts +75 -0
  225. package/dist/engine/session/storage-base.d.ts +8 -0
  226. package/dist/fixtures/index.d.ts +36 -0
  227. package/dist/index.d.ts +16 -1
  228. package/dist/index.js +0 -1
  229. package/dist/internal/harness-types.d.ts +6 -0
  230. package/dist/internal/harness.d.ts +11 -0
  231. package/dist/internal/llm.d.ts +6 -0
  232. package/dist/orchestration/builtin-workflows.d.ts +53 -0
  233. package/dist/orchestration/dev-vm-script-runner.d.ts +19 -0
  234. package/dist/orchestration/goal.d.ts +57 -0
  235. package/dist/orchestration/goal.js +3 -0
  236. package/dist/orchestration/run-spec.d.ts +42 -0
  237. package/dist/orchestration/run-workflow-tool.d.ts +169 -0
  238. package/dist/orchestration/workflow-governance.d.ts +61 -0
  239. package/dist/orchestration/workflow-meta.d.ts +28 -0
  240. package/dist/orchestration/workflow-observe.d.ts +60 -0
  241. package/dist/orchestration/workflow-primitives.d.ts +23 -1
  242. package/dist/orchestration/workflow-sandbox-conformance.d.ts +38 -0
  243. package/dist/orchestration/workflow-script-runner.d.ts +88 -0
  244. package/dist/orchestration/workflow-script-store.d.ts +98 -0
  245. package/dist/orchestration/workflow-size-guideline.d.ts +67 -0
  246. package/dist/orchestration/workflow-types.d.ts +169 -2
  247. package/dist/orchestration/workflow.d.ts +358 -0
  248. package/dist/prompt-assembly/artifact-store.d.ts +33 -0
  249. package/dist/prompt-assembly/artifact.d.ts +25 -0
  250. package/dist/prompt-assembly/assemble.d.ts +20 -0
  251. package/dist/prompt-assembly/composer.d.ts +29 -0
  252. package/dist/prompt-assembly/epoch.d.ts +55 -1
  253. package/dist/prompt-assembly/event-registry.d.ts +35 -0
  254. package/dist/prompt-assembly/explain.d.ts +12 -0
  255. package/dist/prompt-assembly/tool-catalog.d.ts +38 -0
  256. package/dist/prompt-assembly/turn-snapshot.d.ts +40 -0
  257. package/dist/prompt-assembly/types.d.ts +115 -0
  258. package/dist/prompts/coordinator.d.ts +27 -0
  259. package/dist/prompts/default.d.ts +539 -0
  260. package/dist/prompts/simple-sections.d.ts +45 -0
  261. package/dist/prompts/supervisor.d.ts +66 -0
  262. package/dist/scenarios/env.d.ts +28 -0
  263. package/dist/scenarios/full-body.d.ts +50 -0
  264. package/dist/scenarios/scenario-registry.d.ts +60 -0
  265. package/dist/scenarios/teacher-quickstart.d.ts +27 -0
  266. package/dist/server/http.d.ts +17 -0
  267. package/dist/stores/cc/lockfile.d.ts +6 -0
  268. package/dist/stores/cc/mailbox-store.d.ts +8 -0
  269. package/dist/stores/cc/roster-adapter.d.ts +4 -0
  270. package/dist/stores/cc/sidecar-transcript.d.ts +66 -0
  271. package/dist/stores/file/background-agent-store.d.ts +24 -0
  272. package/dist/stores/file/checkpoint-store.d.ts +38 -0
  273. package/dist/stores/file/file-snapshot-store.d.ts +25 -0
  274. package/dist/stores/file/fs-atomic.d.ts +155 -0
  275. package/dist/stores/file/index.d.ts +89 -0
  276. package/dist/stores/file/mailbox-store.d.ts +36 -0
  277. package/dist/stores/file/memory-store.d.ts +82 -0
  278. package/dist/stores/file/permission-rule-store.d.ts +79 -0
  279. package/dist/stores/file/session-policy-store.d.ts +28 -0
  280. package/dist/stores/file/session-store.d.ts +40 -0
  281. package/dist/stores/file/shared-ledger.d.ts +83 -0
  282. package/dist/stores/file/tool-result-store.d.ts +11 -0
  283. package/dist/stores/file/usage-window-store.d.ts +18 -0
  284. package/dist/stores/file/workflow-journal-store.d.ts +100 -0
  285. package/dist/stores/file/workflow-run-store.d.ts +11 -0
  286. package/dist/tools/fs/bash-readonly-classifier.d.ts +282 -0
  287. package/dist/tools/fs/encoding.d.ts +60 -0
  288. package/dist/tools/fs/fs-bash.d.ts +133 -0
  289. package/dist/tools/fs/fs-pdf.d.ts +28 -0
  290. package/dist/tools/fs/fs-search-tools.d.ts +5 -0
  291. package/dist/tools/fs/fs-shared.d.ts +360 -0
  292. package/dist/tools/fs/fs-write.d.ts +16 -0
  293. package/dist/tools/fs/gh-rate-limit.d.ts +22 -0
  294. package/dist/tools/fs/index.d.ts +79 -0
  295. package/dist/tools/fs/notebook.d.ts +56 -0
  296. package/dist/tools/fs/pdf.d.ts +70 -0
  297. package/dist/tools/fs/pdf.js +8 -2
  298. package/dist/tools/fs/repo-map.d.ts +10 -0
  299. package/dist/tools/fs/safety.d.ts +376 -0
  300. package/dist/tools/fs/search.d.ts +131 -0
  301. package/dist/tools/loop-tick.d.ts +24 -0
  302. package/dist/tools/monitor.d.ts +55 -0
  303. package/dist/tools/scheduler-tools.d.ts +51 -0
  304. package/dist/tools/sql-adapters.d.ts +18 -0
  305. package/dist/tools/sql.d.ts +25 -0
  306. package/dist/tools/task-list.d.ts +77 -0
  307. package/dist/tools/todo.d.ts +8 -0
  308. package/dist/tools/web.d.ts +184 -0
  309. package/dist/tools/worktree.d.ts +81 -0
  310. package/package.json +2 -2
  311. package/dist/tools/gitea-issue.d.ts +0 -13
  312. package/dist/tools/gitea-issue.js +0 -75
@@ -88,17 +88,18 @@ import { countElicitOptIns, deriveAskEffective, deriveWiringManifest, resolveAsk
88
88
  import { GLOBAL_USAGE_KEY, resolveUsageWindows, usageRetryAfterMs } from "../usage-window-store.js";
89
89
  const RECONCILE_MAX_RETRIES = 3;
90
90
  const DEFAULT_MAX_SUSPENDS = 5;
91
- const TASK_LIMIT_KEYS = [
92
- "maxTokens",
93
- "maxCostUsd",
94
- "maxTurns",
95
- "maxWalltimeMs",
96
- "maxOutputTokens",
97
- "approachNotice",
98
- "budgetStreamCancel",
99
- "degrade",
100
- "brainCallGuardrailMs",
101
- ];
91
+ const TASK_LIMIT_KEY_DICT = {
92
+ maxTokens: true,
93
+ maxCostUsd: true,
94
+ maxTurns: true,
95
+ maxWalltimeMs: true,
96
+ maxOutputTokens: true,
97
+ approachNotice: true,
98
+ budgetStreamCancel: true,
99
+ degrade: true,
100
+ brainCallGuardrailMs: true,
101
+ };
102
+ const TASK_LIMIT_KEYS = Object.keys(TASK_LIMIT_KEY_DICT);
102
103
  const NUMERIC_TASK_LIMIT_KEYS = ["maxTokens", "maxCostUsd", "maxTurns", "maxWalltimeMs", "maxOutputTokens"];
103
104
  const RETIRED_TASK_LIMIT_KEYS = {
104
105
  timeoutSec: "maxWalltimeMs (milliseconds, not seconds)",
@@ -2,6 +2,7 @@ import type { Model } from "../../internal/llm.js";
2
2
  import type { AgentMessage, ThinkingLevel } from "../../internal/harness-types.js";
3
3
  import type { Brain } from "../types.js";
4
4
  import type { ModelPricing } from "../pricing.js";
5
+ /** The LLM handle for the suggestion pass (mirrors `ConsolidationLLM`). */
5
6
  export interface SuggestionLLM {
6
7
  brain: Brain;
7
8
  model: Model;
@@ -21,5 +22,11 @@ export interface SuggestionResult {
21
22
  tokens: number;
22
23
  costMicroUsd: number;
23
24
  }
25
+ /** Parse the model's reply into ≤count clean suggestion strings. Returns [] on anything non-conforming. */
24
26
  export declare function parseSuggestions(text: string, count: number): string[];
27
+ /**
28
+ * Run ONE suggestion inference pass. May throw on a hard LLM/transport error — the caller
29
+ * (`Runner.suggestNextPrompts`) is fire-and-forget and swallows, so a failure just yields no suggestions.
30
+ * Returns `{ suggestions: [], tokens: 0, costMicroUsd: 0 }` when the transcript is empty.
31
+ */
25
32
  export declare function generatePromptSuggestions(llm: SuggestionLLM, transcript: AgentMessage[], count: number): Promise<SuggestionResult>;
@@ -7,18 +7,80 @@ import type { SessionStore } from "../session.js";
7
7
  import { type RecoveredOrphan } from "../session-reconcile.js";
8
8
  import { type ApprovalSettledBy } from "../tool-policy.js";
9
9
  import type { AgentDefinition, RunnerDeps, TaskEvent, TaskResult, TaskSpec, TaskStream } from "../types.js";
10
+ /**
11
+ * Config re-supplied to {@link Runner.resume} (design/45). A suspended task's tools / model / policy /
12
+ * hooks cannot be reconstructed from a checkpoint token (the session stores neither tool implementations
13
+ * nor the hand band), so the caller's trusted control plane re-supplies the same {@link TaskSpec} it ran
14
+ * with — minus the conversation bits: `sessionId` comes from the checkpoint and `objective` is replaced by
15
+ * an internally-generated continuation, so both are omitted.
16
+ */
10
17
  export type ResumeTaskConfig = Omit<TaskSpec, "objective" | "sessionId">;
18
+ /** design/45 resume plan threaded from {@link Runner.resume} into the shared run loop. */
11
19
  interface ResumeRun {
12
20
  cp: Checkpoint;
21
+ /**
22
+ * RB-152 (2026-07-25, 按面收口): did the APPROVED ACTION actually begin executing?
23
+ *
24
+ * The reopen compensation used to key on an error-code whitelist (`resume.env_failed` /
25
+ * `resume.session_not_found` / `resume.tool_unavailable`). That is a proxy for the thing that actually
26
+ * matters, and every time a NEW way to exit without running the action appeared, the whitelist did not
27
+ * know about it: a caller's abort landing anywhere between the CAS and `tool.execute` — across
28
+ * `SessionStore.acquire` (pluggable, cross-network on a durable backend), the MCP reconnect, the env
29
+ * rebuild, `resumeVM`, tool materialization — produced a `failed` result with NO errorCode, no reopen,
30
+ * and a human approval consumed for work that never happened. Two rounds of fixes (RB-77, RB-109) each
31
+ * moved that window rather than closing it, because both extended the whitelist.
32
+ *
33
+ * This binds the compensation to the FACT instead: set the instant before `tool.execute` for the gated
34
+ * call (the same `onExecuteStart` signal the orphan-reconcile split already trusts). Every terminal —
35
+ * throw OR returned result — asks one question: was the checkpoint consumed while this stayed false?
36
+ */
13
37
  pendingActionStarted?: boolean;
38
+ /** Validated against `cp.gate.kind` at the resume entry: human/irreversible_ask→`policy_ask`,
39
+ * resource_limit→`resource_limit` (design/74), needs_review→`dry_run_review` (design/76 §2.5),
40
+ * plan_review→`plan_review` (design/80 D-B). The gate-match guard in `resumeStream` enforces the
41
+ * correlation. design/144 §3: `wake` is the NON-GATE arm — only a checkpoint awaiting NO gate
42
+ * decision passes the resume entry with it (gate purity, `wake.gate_pending`); the run loop skips
43
+ * `applyResumeDecision` for it (no pending action to resolve) and re-enters via the continuation +
44
+ * pendingSteer tail alone. */
14
45
  outcome: Extract<ResumeOutcome, {
15
46
  gate: "policy_ask" | "resource_limit" | "dry_run_review" | "plan_review" | "wake";
16
47
  }>;
48
+ /** design/144 §3 (X5) — the wake's own operator message, validated (`validatePendingSteer`) at the
49
+ * resume entry and carried SEPARATELY from the checkpoint's parked `pendingSteer`: a message-bearing
50
+ * wake of a checkpoint that ALSO holds a parked steer must deliver BOTH (park order: parked first,
51
+ * wake message second), each under its own trusted framing — the old merge-into-the-slot shape
52
+ * silently DISPLACED the parked (undelivered) supervisor steer. Wake outcomes only. */
17
53
  wakeMessage?: Omit<PendingSteerEntry, "seq">;
54
+ /** Compensation hook (design/45/49): called iff the resumed run fails with `resume.env_failed` (post-CAS
55
+ * workspace `resumeVM` failed) OR `resume.tool_unavailable` (P-7: the approved tool vanished) — in both
56
+ * the CAS already consumed the checkpoint but the pending action never ran. `resumeStream` supplies a
57
+ * closure that reopens the checkpoint (`resolved → pending`) so a retry re-resumes the SAME suspended work
58
+ * instead of losing it to a forced "re-initiate". design/80 D-1 (reopen-by-reason): the `reason` is
59
+ * recorded on the reopened row so the next re-resume validates per reason — an `env_failed` reopen must
60
+ * replay the persisted winner (a system retry of the approved action), while a `tool_unavailable` reopen
61
+ * lets a human re-decide with the tool present (a fresh decision is allowed — preserves P-7). */
18
62
  onEnvRestoreFailed?: (reason: ReopenReason) => Promise<void>;
63
+ /** RB-471/FR-C1 — set in the run body right after `applyResumeDecision` completes: the negative-
64
+ * decision twin of `pendingActionStarted`. A reject/deny consumes its gate BY BEING DELIVERED, and
65
+ * this bit is the delivery fact — every throw-arm cause (prepare failure, `session_not_found`, a
66
+ * pre-delivery abort) and the walltime-exhausted settle fire BEFORE it is set, so an undelivered
67
+ * negative decision still reopens as `env_failed` (the retry replays the persisted decision; it
68
+ * never re-asks — design/80 D-1), closing the RB-152/RB-70 loss class the first RB-471 cut reopened. */
19
69
  decisionDelivered?: boolean;
20
70
  }
21
- declare function toolEndBodyFrom(result: unknown, isError: boolean, settledBy?: ApprovalSettledBy): {
71
+ /** The `tool_end` body fields projected from a harness tool result — output/truncated/totalChars via
72
+ * {@link toolOutputFrom} and the CC card via {@link structuredFrom}. Single construction point for BOTH
73
+ * the live loop's frames and the resumed batch's frames (`resolvePendingCall` + the deferred-sibling
74
+ * close): the resumed frames used to carry only `isError`, so a client rendering tool output from frames
75
+ * showed an empty body for every durable-approved call. Same projection = same source as the transcript.
76
+ * Also the one place `settledBy` reaches a frame — see the parameter. */
77
+ declare function toolEndBodyFrom(result: unknown, isError: boolean,
78
+ /** What ended the approval this call was waiting on, supplied by the CALLER of this projection — the
79
+ * live loop reads it off the gate's per-call sideband, the resumed leg off the decide. Deliberately
80
+ * a parameter and never derived from `result`: a tool's own `details` (which post-tool hooks may
81
+ * also replace) is writable by layers that adjudicate nothing, so reading provenance out of it would
82
+ * let a failing tool claim a person approved it. Omitted ⇒ this call settled no approval. */
83
+ settledBy?: ApprovalSettledBy): {
22
84
  output?: unknown;
23
85
  truncated?: boolean;
24
86
  totalChars?: number;
@@ -26,45 +88,284 @@ declare function toolEndBodyFrom(result: unknown, isError: boolean, settledBy?:
26
88
  errorCode?: string;
27
89
  settledBy?: ApprovalSettledBy;
28
90
  };
91
+ /**
92
+ * scan-1/A1 — the BODY of the synthetic `tool_end` that closes a reconcile-recovered orphan. ONE
93
+ * construction point for BOTH minting legs (the live-abort loop at the end of a run, and the wake/crash
94
+ * leg's replay at run open), so the two can never disagree about the shape of the same event.
95
+ *
96
+ * Both frames used to carry `isError:true` and NOTHING else: a consumer rendering tool output from the
97
+ * event stream showed an EMPTY body for every interrupted call, even though the persisted transcript
98
+ * (which the model reads) carried the full `[INTERRUPTED]` explanation — the two faces of one call
99
+ * disagreed. The projection goes through the same {@link toolEndBodyFrom} every live tool result uses, so
100
+ * `output` = the persisted model-facing text and `errorCode` = the persisted `details.errorKind`
101
+ * (`interrupted_never_started` / `interrupted_outcome_unknown`) — a consumer discriminates on the code
102
+ * instead of prose-matching. No `structured`: the reconcile mints no CC card (no `details.type`), which
103
+ * `structuredFrom`'s allowlist already enforces.
104
+ */
29
105
  export declare function reconciledToolEndBody(orphan: Pick<RecoveredOrphan, "text" | "errorKind">): ReturnType<typeof toolEndBodyFrom>;
30
106
  export declare const GOVERNANCE_READ_STALLED: unique symbol;
107
+ /** Await a ledger charge, firing `onSlow` ONCE if it has not settled after
108
+ * {@link CHARGE_SETTLE_DISCLOSE_MS}. The charge itself is always awaited to completion. */
31
109
  export declare function awaitChargeWithSlowDisclosure<T>(charge: Promise<T>, onSlow: () => void, discloseAfterMs?: number): Promise<T>;
110
+ /**
111
+ * Await `p` until the absolute epoch `deadline`, then give up with {@link GOVERNANCE_READ_STALLED}.
112
+ *
113
+ * Chunked, and deliberately so: the deadline is derived from a caller-declared environment lifetime, so
114
+ * the distance to it can exceed {@link MAX_TIMER_DELAY_MS} — a single timer armed for that distance
115
+ * would fire at once and abandon a perfectly healthy read. Each chunk re-reads the wall clock, so the
116
+ * decision is always made against the deadline itself rather than against an allowance computed once.
117
+ *
118
+ * Exported for its own unit pin (the same posture as the brain-call guardrail primitive): the
119
+ * behaviors below are clock behaviors, and only a virtual clock can assert them without spending the
120
+ * wall-clock time they describe. Not re-exported from the package index.
121
+ *
122
+ * An already-overdue deadline still gets ONE zero-delay pass: a promise that is settled (or settles in a
123
+ * microtask, which is every in-process store) must be allowed to win, because giving up on an answer we
124
+ * already hold would be a fabricated stall. The second pass is what makes the loop terminate.
125
+ */
32
126
  export declare function raceUntilDeadline<T>(p: Promise<T>, deadline: number): Promise<T | typeof GOVERNANCE_READ_STALLED>;
33
127
  export declare class Runner {
34
128
  private deps;
35
129
  readonly sessions: SessionStore;
130
+ /** Per-sessionId serialization so two tasks never mutate one session concurrently. */
36
131
  private sessionLocks;
132
+ /** service [403](a) — roots whose rewind-files snapshot hit `too_large`, with the refusal time.
133
+ * A 20G workspace otherwise pays a full bounded tree-walk (stat tens of thousands of files) EVERY
134
+ * task just to re-discover the same refusal; once too_large, skip further snapshots for that root
135
+ * (announced once via onError). E19 semantics unchanged — rewind for that root was already
136
+ * impossible. codex 131 审 C: TTL'd (30min), not permanent — a long-lived Runner over a tree the
137
+ * user later SHRINKS re-probes instead of being locked out until restart.
138
+ * RB-430-b: `skipAnnounced` makes the SKIP itself observable — one announcement per cooldown window,
139
+ * so an operator can tell "this turn produced no snapshot" from "snapshots are working", without the
140
+ * per-turn log spam the latch exists to prevent. Cleared with the entry when the window elapses. */
37
141
  private snapshotTooLargeRoots;
142
+ /** 飞轮 [492]② — task notifications born BETWEEN turns (run torn down / harness already idle), parked
143
+ * per session and drained into the session's next run at its first boundary. Runner-lived (outlives any
144
+ * single run, like the registry handles that produce into it); bounded + drop-disclosing, see
145
+ * {@link PendingSessionNotifications}. Not checkpointed — the producing handles are process-local. */
38
146
  private readonly pendingSessionNotifications;
147
+ /** Parent effective-policy inheritance (same-process resume convenience): checkpoint token → the OPAQUE
148
+ * `parentConstraints` the suspended leg ran under. Registered by `runTaskStream`'s result hook whenever a
149
+ * run spawned WITH `internals.inheritedGate.parentConstraints` ends `suspended` (process-local closures
150
+ * parked while the park is live — the same lifecycle posture as the subagent retain ledger's
151
+ * `internalsSnapshot`). `resumeStream` consults it when the caller supplied no constraints, so a
152
+ * same-process `runner.resume()` on a delegated child's checkpoint auto re-supplies the chain; a
153
+ * CROSS-process resume (registry miss — a different Runner/process) still requires an explicit
154
+ * `resumeStream(..., internals)` and fail-louds otherwise (`resume.parent_constraint_missing`).
155
+ * Retention: entries are kept across an `env_failed` reopen (the same token is retried), evicted on an
156
+ * observed `already_resolved` and by the FIFO cap — an evicted entry only ever degrades to the explicit
157
+ * re-supply requirement (fail-loud), never fail-open. */
39
158
  private readonly parentConstraintRegistry;
40
159
  private static readonly PARENT_CONSTRAINT_REGISTRY_CAP;
41
160
  constructor(deps: RunnerDeps);
161
+ /** design/73 §1 v1 — fire `RunnerDeps.onTaskOutcome` through the single swallow-guarded chokepoint
162
+ * ({@link emitTaskOutcome}: mechanical-tier only, throwing sink never breaks the caller). Public so
163
+ * thin compositions OVER the Runner (`runGoal`) can emit at their terminal state without reaching
164
+ * into private deps. */
42
165
  emitTaskOutcome(outcome: TaskOutcome): void;
166
+ /** design/141 件A — the deployment agent catalog (RunnerDeps.agents/builtinAgents), exposed READ-ONLY
167
+ * so the Agent-tool lane (`createSubagentTool`) defaults to the SAME registry the workflow lane
168
+ * consumes (single source; the types.ts "pass the same array" follow-on made structural). The array
169
+ * is a fresh copy — a caller mutating it never rewrites this Runner's own deps; the definitions
170
+ * themselves are the shared objects (frozen by convention, same as gateBaseline's posture). */
43
171
  get agentCatalog(): {
44
172
  agents?: AgentDefinition[];
45
173
  builtinAgents?: boolean;
46
174
  models?: Record<string, Model>;
47
175
  };
176
+ /** design/125 (codex 实现审 B1) — the deployment-level gating baseline, exposed READ-ONLY so thin
177
+ * assemblers over the Runner (`runSpec`) can COMPOSE with it. The task-level engine semantic is a
178
+ * WHOLE-SLOT override (`spec.toolPolicy ?? deps.toolPolicy`, same for hooks — prepare-task), so any
179
+ * assembler that sets `spec.toolPolicy`/`spec.hooks` without folding these in silently shadows the
180
+ * deployment baseline. Getter only — nothing here is writable from outside. */
48
181
  get gateBaseline(): {
49
182
  toolPolicy?: RunnerDeps["toolPolicy"];
50
183
  hooks?: RunnerDeps["hooks"];
51
184
  };
185
+ /** Acquire the lock for a sessionId; returns a release fn. New (undefined) sessions need no lock. */
52
186
  private acquireSessionLock;
187
+ /** [1463]① — one-shot brain-routed utility query (see {@link runSideQuery} for the full contract):
188
+ * preserves system/multi-turn messages/tool DEFINITIONS, routes through the deployment's brain with
189
+ * the same model resolution as tasks, returns real usage/model. No session, no tool execution, no
190
+ * policy gate, no accounting — caller-trusted. */
53
191
  sideQuery(spec: SideQuerySpec): Promise<SideQueryResult>;
192
+ /** Run a task and stream live events; await `.result()` for the final TaskResult. `resume` (internal)
193
+ * drives a design/45 durable resume through the same loop instead of a fresh objective prompt.
194
+ * `internals` (internal, design/78 Slice-1) is a TRUSTED run-scoped channel for live per-task state the
195
+ * Runner cannot see from `spec` (today: a `runRepairLoop` attempt's live `repairBundle`) — NOT a
196
+ * `TaskSpec` field; undefined on the public path.
197
+ * **Eager:** the task starts executing the moment this stream is constructed (fire-and-forget), NOT lazily
198
+ * on first iteration — you do NOT need to pull events for the run (and its `finish()`/env teardown) to
199
+ * happen. Iterating just observes events (the buffer is backpressure-free); `.result()` awaits completion. */
54
200
  runTaskStream(spec: TaskSpec, resume?: ResumeRun, internals?: RunInternals): TaskStream;
55
201
  private runLocked;
202
+ /**
203
+ * design/100 §E12 — the post-completion prompt-suggestion pass. Never throws (failures route to
204
+ * `onError(phase:"suggestions")` and resolve to `[]`), so it is fire-and-forget safe and `suggestions()`
205
+ * never rejects. Also fills the budget-excluded `stats.suggestions` line.
206
+ */
56
207
  private suggestNextPrompts;
208
+ /**
209
+ * design/101 §E19 — capture a working-tree snapshot of the just-finished turn, keyed by the leaf
210
+ * `SessionTreeEntry.id`. Best-effort + never throws (errors route to `onError(phase:"rewind")`). Runs against
211
+ * ANY ExecutionEnv (local or remote) when a `fileSnapshotStore` is wired (GATE-SPLIT, service [263]) — the
212
+ * snapshot is portable (env FileSystem ops). A deployment wanting VM-snapshot instead wires a VM-backed store.
213
+ */
57
214
  private snapshotTurn;
215
+ /** Run a task to completion and return a machine-readable result. */
58
216
  runTask(spec: TaskSpec, internals?: RunInternals): Promise<TaskResult>;
59
- resume(token: CheckpointToken, outcome: ResumeOutcome, taskConfig: ResumeTaskConfig, internals?: RunInternals): Promise<TaskResult>;
60
- resumeStream(token: CheckpointToken, outcome: ResumeOutcome, taskConfig: ResumeTaskConfig, internals?: RunInternals): Promise<TaskStream>;
217
+ /**
218
+ * Resume a task suspended at a durable approval gate (design/45 F4). The token came back as
219
+ * `TaskResult.checkpointToken` from a `status:"suspended"` run; `outcome` carries the human/external
220
+ * decision (`allow`/`deny`, with an optional `updatedInput` arg rewrite or `reason`); `taskConfig`
221
+ * **re-supplies** the same tools / model / policy the task ran with (a token cannot reconstruct tool
222
+ * implementations or the hand band — the session stores neither).
223
+ *
224
+ * Flow (§2.1): `get` the checkpoint → validate the outcome arm matches the gate (council #3) → **atomic
225
+ * CAS `resolve`**. *Winning the CAS is the sole trigger to execute the pending action* — so a double /
226
+ * concurrent resume of the same token loses the CAS and is rejected (`checkpoint.already_resolved`),
227
+ * never re-running the side-effecting tool. The winner rewinds the session to the suspension point,
228
+ * resolves the gated call (execute on `allow`, inject a denial on `deny`), closes the rest of the
229
+ * suspended batch as deferred, and re-enters the run loop with a continuation — returning a normal
230
+ * {@link TaskResult} (which may itself be `suspended` again with a fresh token).
231
+ *
232
+ * v1 serves only the `human`/`policy_ask` gate (F4). A `task_done` checkpoint (1C Path A) is not
233
+ * resumable here — the caller orchestrates that one and reads its handle directly.
234
+ *
235
+ * **🔒 Authorization boundary (design/80 D-2 / [122] invariant #1) — token-as-auth, scope is store-level
236
+ * isolation, NOT caller authorization.** `resume` is TOKEN-AS-AUTH: whoever presents a valid, still-`pending`
237
+ * checkpoint token resolves it. The scope passed to the store CAS is the checkpoint's OWN `cp.scope` (read
238
+ * off the row), so the store's scope-WHERE is store-level multi-tenant DATA isolation (one tenant's reaper /
239
+ * mis-scoped resolve can't touch another's row) — it does **not** verify that THIS CALLER is authorized for
240
+ * that scope. Authorizing the operator's principal against the checkpoint (the "tenant-B holding tenant-A's
241
+ * token must not resolve it" property) is the **caller's** responsibility: the BFF / supervisor service mints
242
+ * the principal, scopes the approval inbox to it, and only calls `resume` for a checkpoint that principal
243
+ * owns. The token's secrecy + single-use HMAC binding (D-G) is what keeps it from reaching the wrong tenant.
244
+ * A direct (non-BFF) client is BLOCKED until D-G's cryptographic principal binding — never trust a
245
+ * client-supplied principal/scope here.
246
+ *
247
+ * @throws {@link CheckpointError} `not_found` (no store / unknown token), `gate_mismatch` (outcome arm
248
+ * ≠ gate, or an unsupported gate), `invalid_outcome` (decision-action binding failed — boundCallId/
249
+ * boundInputHash mismatch, or a deny reason with a `</system-reminder>` tag), `reopen_revote` (an
250
+ * env_failed re-resume supplied a decision ≠ the persisted winner), `reopened_concurrently` (the
251
+ * optimistic-concurrency `rev` changed under a concurrent resolve/reopen — re-resume against current
252
+ * state), `unsupported_version` (checkpoint newer than this worker / remote handle with no factory),
253
+ * `already_resolved` (lost the CAS — idempotent no-op).
254
+ */
255
+ resume(token: CheckpointToken, outcome: ResumeOutcome, taskConfig: ResumeTaskConfig,
256
+ /** RB-48② (1.404): same TRUSTED run-internals seam as {@link resumeStream} — the convenience wrapper
257
+ * FORWARDS it (it used to silently drop a 4th arg, so a cross-process re-supply through resume()
258
+ * looked wired but always failed `resume.parent_constraint_missing`). */
259
+ internals?: RunInternals): Promise<TaskResult>;
260
+ /**
261
+ * Streaming form of {@link resume}: runs the identical pre-CAS guards + atomic CAS, then returns the live
262
+ * {@link TaskStream} of the resumed run (its events + `result()`) instead of draining it to a final
263
+ * {@link TaskResult}. Use this when the resumed segment's tool/turn events must reach an event sink for
264
+ * observability parity with the original `runInBackground` stream (service [15]); `resume()` is the
265
+ * convenience wrapper that drains it. The guards + CAS run FIRST, so this rejects with the same
266
+ * {@link CheckpointError}s as `resume` *before* any stream is returned (winning the CAS is still the sole
267
+ * trigger to execute the pending action — a lost CAS rejects, never returns a re-running stream).
268
+ *
269
+ * **Eager (like {@link runTaskStream}):** once this resolves, the resumed run is already executing — the
270
+ * pending action runs exactly once and the run-loop tail's `teardownOwnedEnv` (service [325]) tears down the
271
+ * rebuilt remote env even if you never iterate the stream. So abandoning the returned stream is safe (no leak,
272
+ * no hang); it only means you
273
+ * don't observe the resumed segment's events.
274
+ */
275
+ resumeStream(token: CheckpointToken, outcome: ResumeOutcome, taskConfig: ResumeTaskConfig,
276
+ /** service [371]①: the TRUSTED run-internals seam, symmetric with {@link runTaskStream} — a resume leg
277
+ * otherwise has no `onForwardEvent`席位, so a subagent's task_progress ticks (child-isolated stream,
278
+ * only exit = the forward sink) were unreachable on resume. Deployment-owned, never a TaskSpec field.
279
+ * Parent effective-policy inheritance CONTRACT: a checkpoint whose `state.inheritedGate.
280
+ * requiresParentConstraint` is true was suspended under inherited OPAQUE parent-policy constraints
281
+ * (live ToolPolicy/onAsk closures — non-serializable); this is the ONLY seam that re-supplies them
282
+ * (`internals.inheritedGate.parentConstraints`). Omitting them for such a checkpoint rejects pre-CAS
283
+ * with `resume.parent_constraint_missing` (fail-loud; the checkpoint stays pending) — never a silent
284
+ * resume with the ancestors' gate dropped — unless this SAME Runner spawned the leg (the spawn-time
285
+ * registry auto re-supplies them; see `parentConstraintRegistry`). The re-supplied chain's LENGTH must
286
+ * match the checkpoint's recorded `parentConstraintCount` (`resume.parent_constraint_mismatch`
287
+ * otherwise). Most entries are policies the deployment authored and can hand straight back; a
288
+ * hook-wired ancestor also contributes a PreToolUse SCREENING entry (issue #33) whose policy the
289
+ * engine mints — rebuild that one with the exported `createPreToolUseConstraintPolicy(hook, env)`. The DATA half (ancestorRules/shellGate) rides the checkpoint itself and needs no
290
+ * re-supply; on the resumed leg the CHECKPOINT snapshot is the trust floor — live internals may only
291
+ * TIGHTEN it (per-entry rev-monotonic ancestorRules replacement, max-rank shellGate fold), never
292
+ * displace it wholesale. TRUST BOUNDARY: `internals` is the DEPLOYMENT trust channel (the same tier as
293
+ * `inheritedManifestScope` and every other RunInternals field) — the library caller is trusted to
294
+ * re-supply the genuine chain; a caller able to invoke resumeStream already holds full Runner
295
+ * authority, so constraint substitution here is outside the enforced threat model (the count check
296
+ * catches shape MISTAKES, not a malicious trusted caller). */
297
+ internals?: RunInternals): Promise<TaskStream>;
298
+ /**
299
+ * design/45 resume step: with the harness idle and the branch rewound to the suspension leaf, resolve
300
+ * the gated tool call and close the rest of the suspended batch, all by appending `toolResult`s to the
301
+ * session (the next `harness.prompt(continuation)` replays them as context).
302
+ * - `allow` → execute the pending tool ONCE (re-validating `updatedInput`/captured post-hook args),
303
+ * append its real result. This deliberately bypasses the tool gate (the human already adjudicated)
304
+ * and the PostToolUse hook (documented v1 gap — rare, acceptable).
305
+ * - `deny` → append a model-readable denial result instead.
306
+ * - the remaining batch siblings (#k+1..N) → deferred-reissue results (v1 doesn't blind-run them).
307
+ */
61
308
  private applyResumeDecision;
309
+ /** Resolve the single gated call of a resumed batch (design/45): execute it once on `allow`, or inject
310
+ * a model-readable denial on `deny`. Appends exactly one `toolResult` for `pendingAction.toolCallId`.
311
+ * `emit` streams `tool_start`/`tool_end` for the resolved call so a `resumeStream` observer sees the
312
+ * approved tool actually execute (API#2 observability parity — service [15]/[37]; the gated call never
313
+ * emitted execution events in the original run, it suspended at the gate before running).
314
+ *
315
+ * RB-22 RULING (2026-07-18, deliberate — the $ counterpart of RB-21's walltime question): a HUMAN-
316
+ * APPROVED call executes even when the $ budget is already exhausted (`maxCostMicroUsd` ≤ spent).
317
+ * The tool execution itself consumes no model spend — the budget's coordinate is LLM cost, and the
318
+ * very next turn boundary's budget gate stops the run — so the overrun is ≈0 while refusing would
319
+ * WASTE the human approval (the review effort is already sunk). This deliberately differs from the
320
+ * walltime ruling (RB-21: NOT exempt) on principle: wall-clock exhaustion endangers the write-out
321
+ * window (time cannot be clawed back), $ exhaustion after an approved no-spend action endangers
322
+ * nothing. Pinned in resume tests; do not "fix" this into a pre-execution budget check. */
62
323
  private resolvePendingCall;
324
+ /**
325
+ * design/84 Seam C — the cost-optimization compaction options threaded into BOTH `maybeCompact` call
326
+ * sites (within-task turn boundary + `finish()`). All three fields come from `RunnerDeps` (a trusted
327
+ * FUNCTION seam — never `TaskSpec`, which is serializable/durable-resumable/untrusted-caller). The
328
+ * Runner OWNS the consecutive-reuse counter (`prepared.compactionReuseRef`) so the
329
+ * `maxConsecutiveProviderReuse` drift guard spans the whole task across both sites: it FEEDS the current
330
+ * count in as `consecutiveProviderReuse`, and {@link recordCompactionReuse} updates it from the result.
331
+ * Returns `undefined` when no provider is wired (so the call site spreads nothing → byte-identical to
332
+ * the pre-design/84 behavior).
333
+ */
63
334
  private seamCCompactionOptions;
335
+ /** design/134 §3.2 — resolve the pre/postCompact lifecycle callbacks (whole-slot `spec.hooks ??
336
+ * deps.hooks`, same resolution as the stop hook) and wrap each in a SWALLOW+TRACE shell before
337
+ * threading them into maybeCompact. The wrapper owns the observability half of the R3 MED contract
338
+ * (maybeCompact swallows defensively too, but has no sink): a throwing callback is reported via
339
+ * `onError(phase:"hook")` and treated as absent; a `block` returned under a "forced" trigger is
340
+ * reported as ignored (maybeCompact enforces the ignore — blocking a compaction the provider/trim
341
+ * layer already demanded would kill the run). */
64
342
  private compactionHookOptions;
343
+ /** design/84 Seam C — fold a finished compaction's `reused` flag into the run-scoped consecutive-reuse
344
+ * counter: a reused (provider) summary increments it, a real (LLM) summary resets it to 0. A no-op
345
+ * compaction (`compacted:false`) leaves the counter untouched. No-op when no provider is wired. */
65
346
  private recordCompactionReuse;
66
347
  private finish;
348
+ /**
349
+ * design/48 remote seam + service [325]: tear down a per-task env minted by `executionEnvFactory` (e.g. a
350
+ * remote container, or a `withWorktreeIsolation` worktree) — this task owned its lifetime. Best-effort, like
351
+ * `mcp.dispose`: a `destroy()` failure must not break the run. Only `ownedEnv` (factory-produced) is destroyed;
352
+ * a caller-owned static `deps.executionEnv` outlives the task and is left untouched. The service control plane's
353
+ * reaper is the backstop for an env orphaned by a rare pre-teardown throw (same posture as `mcp`).
354
+ *
355
+ * Runs from the run-loop tail AFTER every env-reader (finish()'s compaction `attachWorkingFiles` +
356
+ * `snapshotTurn`'s rewind-files capture), so the working tree is still readable when they run. This ORDER is the
357
+ * fix for service [325]: the old in-`finish()` destroy ran BEFORE `snapshotTurn`, so a factory-minted
358
+ * remote/worktree lane snapshotted an already-destroyed env (plain host/static lanes were false-green).
359
+ *
360
+ * design/49 v1.5 / design/76 §2.5: a SUSPENDED (`suspendRef.token`) or `needs_review` (`reviewRef.token`) pause
361
+ * `suspendVM`-paused the env and persisted its `workspaceHandle` into the checkpoint — destroying it would
362
+ * discard the paused VM and make resume fail to restore. Skip teardown; `resume()` rebuilds + `resumeVM`s it. A
363
+ * cancelled pause is reaped via `TaskStream.destroy()` (design/51); an abandoned one is the service container
364
+ * reaper's backstop. The gate here MIRRORS the tail's reap-stash (same durable fact
365
+ * `suspendRef.token===undefined && reviewRef.token===undefined`), so exactly one path owns the env's fate.
366
+ */
67
367
  private teardownOwnedEnv;
68
368
  }
369
+ /** Convenience: one-shot run with explicit deps (creates a throwaway Runner). */
69
370
  export declare function runTask(spec: TaskSpec, deps: RunnerDeps): Promise<TaskResult>;
70
371
  export type { TaskEvent, TaskStream };
@@ -1,7 +1,56 @@
1
+ /**
2
+ * Rebuild the hands' read-before-write state from a session's own transcript (ruled 2026-08-05).
3
+ *
4
+ * `readFileState` is minted per TASK and, until this module existed, was only ever re-seeded from a
5
+ * durable-resume checkpoint. An ordinary session CONTINUATION — a new `runTask` carrying the previous
6
+ * `sessionId` — therefore started blind: turn 1 Read the file, turn 2 was told "File has not been
7
+ * read yet", and every file cost a re-read round-trip on every turn of a long conversation.
8
+ *
9
+ * The transcript already records what is needed, so no new persisted surface is minted here: the
10
+ * tool results carry the file's whole text in their `details` card. This module walks those records
11
+ * and reports, per file, the LAST content the transcript can prove — the caller turns each into a
12
+ * read-state entry whose staleness hash is computed from THAT text.
13
+ *
14
+ * Two rules make the reconstruction safe rather than merely convenient:
15
+ *
16
+ * 1. **The content never comes from disk.** Every hash the caller derives from these records is a
17
+ * hash of what the transcript recorded. A file changed between the turns (by the user, a linter,
18
+ * a `git checkout`, a bash command — anything this transcript does not record) therefore fails
19
+ * the staleness comparison and the edit is refused, exactly as it is inside a single task. A
20
+ * reconstruction that re-read the file to build its hash would instead wave the dirty edit
21
+ * through; that is the one thing this module must never do.
22
+ * 2. **Only WHOLE-file records qualify.** A partial read, a notebook projection or an `Edit` result
23
+ * does not carry the file's full post-condition text, so there is nothing to hash honestly.
24
+ * Those files are simply not reported: the gate then behaves exactly as it does today (the model
25
+ * re-reads), which is the pre-existing cost, not a new failure.
26
+ */
1
27
  import type { AgentMessage } from "../../internal/harness.js";
28
+ /** The whole text of one file at the moment the transcript recorded it. */
2
29
  export interface TranscriptFileRecord {
30
+ /** The path as the tool recorded it — absolute (see {@link wholeFileRecordsFromTranscript}). */
3
31
  path: string;
32
+ /** The file's ENTIRE text at that moment, in the decoded coordinate the fs tools hash. */
4
33
  content: string;
34
+ /** The recording tool result's own timestamp — the most honest "last read at" available. */
5
35
  at: number;
6
36
  }
37
+ /**
38
+ * Per-file, the last whole-file content the transcript proves — in transcript order, last record wins.
39
+ *
40
+ * Records are read only from SUCCESSFUL results (an `isError` result changed nothing and proves
41
+ * nothing). A `Write` proves the post-condition it just persisted; a whole-file `Read` proves what it
42
+ * just served. An `Edit` result proves that the file CHANGED without recording its new text, so it
43
+ * retracts whatever an earlier record said — leaving a stale entry behind would blame the user for
44
+ * the agent's own edit ("modified since read") the next turn. Anything else (partial reads, dedup
45
+ * stubs, notebook projections, image/document reads, foreign tools) is inert: it neither proves nor
46
+ * retracts, because reading a file does not change it.
47
+ *
48
+ * The parameter is the session's own message lane (`AgentMessage`, custom lanes included) rather than
49
+ * the narrowed model-facing union: this reads the branch as the session stores it, and every lane that
50
+ * is not a tool result falls out on the first line of the loop.
51
+ *
52
+ * Paths are reported only when the tool recorded an ABSOLUTE one. A relative spelling was resolved
53
+ * against the tracked working directory of that moment, which this task cannot reconstruct; re-
54
+ * resolving it here could key the entry to a different file.
55
+ */
7
56
  export declare function wholeFileRecordsFromTranscript(messages: readonly AgentMessage[]): TranscriptFileRecord[];
@@ -2,9 +2,67 @@ import type { ExecutionEnv } from "../../internal/harness-types.js";
2
2
  import type { ToolEffect } from "../types.js";
3
3
  import { type NamedToolPolicy } from "../tool-policy.js";
4
4
  import type { SessionPermissionRules } from "../session-policy-store.js";
5
+ /** Tool names whose write target is the `file_path`/`path` arg ({@link fileArgPath}).
6
+ *
7
+ * REF-B3 — the ONE definition of that narrower set. Production consumer today:
8
+ * `createActiveSkillScopePolicy` (runner/active-skill-scope.ts, manifest `allowPaths`). The
9
+ * `allowDirs`/fs-write faces consume the superset {@link PATH_CONFINABLE_WRITE_TOOLS} instead.
10
+ *
11
+ * BOUNDARY: this set stays `file_path`-keyed — its members' write target is read by {@link fileArgPath}.
12
+ * `NotebookEdit` (whose target is `notebook_path`) lives in the superset
13
+ * {@link PATH_CONFINABLE_WRITE_TOOLS} below, NOT here: `createActiveSkillScopePolicy` reads THIS set and
14
+ * deliberately keeps fail-closed-denying notebooks under a manifest `allowPaths` fence (widening the
15
+ * skill face is a separate capability decision with its own review). */
5
16
  export declare const PATH_WRITE_TOOLS: ReadonlySet<string>;
17
+ /** The FULL path-confinable write-tool set: {@link PATH_WRITE_TOOLS} plus `NotebookEdit`, whose write
18
+ * target is `notebook_path` and is extracted by the shared tool-aware {@link writeTargetPath} ([886]①b —
19
+ * notebook_path outranks a decoy `file_path` for that tool).
20
+ *
21
+ * REF-B3 — the ONE spelling of "tools this codebase can confine by path". Consumers:
22
+ * {@link createSessionRulePolicy} (below, `allowDirs`) and `createFsWriteGatePolicy`
23
+ * (core/fs-write-gate-policy.ts), which used to rebuild `[...PATH_WRITE_TOOLS, "NotebookEdit"]` inline.
24
+ * A fourth spelling survives as a LITERAL in core/tool-policy.ts (the transcript-dir gate) because THIS
25
+ * module imports tool-policy.ts — that one is a documented coordinate held in sync by a source-scan pin
26
+ * (SW-10), not a silent copy.
27
+ *
28
+ * SW-10 relax (ruled 2026-08-04): `NotebookEdit` was previously absent from the session-rule face's
29
+ * covered set, so an `allowDirs` confinement denied it OUTRIGHT via the "mutating but not path-confinable"
30
+ * arm — a capability GAP relative to the fs-write gate, which has always proven the tool confinable.
31
+ * Both faces now share this set and the same target extractor, so the session face confines notebooks by
32
+ * path instead of refusing them. The fail-closed deny for every OTHER non-confinable mutating tool
33
+ * (bash, deployment-authored write tools, unknown effects) is unchanged. */
6
34
  export declare const PATH_CONFINABLE_WRITE_TOOLS: ReadonlySet<string>;
35
+ /** Path-segment-aware containment, FAMILY-AWARE ([K-PLATFORM-SWEEP] MAJOR#2: canonical keys are
36
+ * backslash-form on a win32 env — the "/"-hardcoded suffix rejected every legitimate write there).
37
+ * Compare in "/" form with drive-letter case folded; never keyed on process.platform (the env may be
38
+ * remote and of the OTHER family than the host).
39
+ *
40
+ * REF-B3 — exported as the single source for the policy modules that fence WRITES by an allowlist of
41
+ * directories: active-skill-scope.ts (manifest `allowPaths`) and fs-write-gate-policy.ts (`acceptDirs`
42
+ * /`exemptDirs`), plus the K-PLATFORM sweep tests. The line here used to read "exported ONLY for the
43
+ * K-PLATFORM sweep tests", which was already false when written (fs-write-gate-policy.ts imports it in
44
+ * production), and active-skill-scope.ts carried a byte-identical private twin — comment included — so
45
+ * a platform-family fix had to be remembered at two coordinates.
46
+ *
47
+ * The sibling implementation is `within()` in tools/fs/safety.ts (the fs-tool root fence). Those stay
48
+ * separate functions on purpose — that one is private to the fence and keyed on canonical roots — but
49
+ * they must never disagree on a verdict; the empty-root arm below is that alignment. */
7
50
  export declare function isWithin(root: string, p: string): boolean;
51
+ /**
52
+ * Build the per-session deny-narrowing policy. For each tool call:
53
+ * - `toolDeny` → deny the listed tools.
54
+ * - `toolAllow` (if set) → deny any tool NOT listed (a narrowing allowlist).
55
+ * - `commandAllow`/`commandDeny` → delegate to {@link createCoarseCommandNamePolicy} (argv[0] names; only
56
+ * speaks about shell tools). allowlist mode denies the un-listed/un-parseable; blocklist mode asks on the
57
+ * un-parseable bypass surface (the gate decides).
58
+ * - `allowDirs` (if set) → a WRITE tool must land inside one of the dirs (resolved via `canonicalizeTarget`,
59
+ * so a symlink can't smuggle a write out); a write-capable tool that cannot be path-confined (e.g. `bash`)
60
+ * is DENIED while `allowDirs` is set (fail-closed, mirrors active-skill-scope MAJOR-2).
61
+ * Returns `allow` when nothing constrains the call. `env`/`rootPath` are the task's real exec env + root, so
62
+ * matching sees the actual filesystem (a remote/E2B task resolves in its container). RB-108: a relative
63
+ * TARGET prefers the call's live tracked cwd ({@link ToolCallRequest.cwd}) when the engine stamps one;
64
+ * `allowDirs` entries always resolve against `rootPath`.
65
+ */
8
66
  export declare function createSessionRulePolicy(rules: SessionPermissionRules, opts: {
9
67
  env: ExecutionEnv;
10
68
  rootPath?: string;
@@ -1,4 +1,5 @@
1
1
  import type { TSchema } from "typebox";
2
+ /** Port of 204 `Lqn` — derive the strict form of a whole schema (root must be `type:"object"`). */
2
3
  export declare function deriveStrictSchema(schema: unknown): {
3
4
  ok: true;
4
5
  schema: Record<string, unknown>;
@@ -6,15 +7,29 @@ export declare function deriveStrictSchema(schema: unknown): {
6
7
  ok: false;
7
8
  reason: string;
8
9
  };
10
+ /** Exposed for callers that only need validity (no derivation). Runs the size guard first. */
9
11
  export declare function validateJsonSchemaShape(schema: unknown): string | null;
10
- export type CompiledOutputSchema = {
12
+ export type CompiledOutputSchema =
13
+ /** The schema is not a valid JSON Schema (or too large) — callers must FAIL FAST, never run silently. */
14
+ {
11
15
  error: string;
12
- } | {
16
+ }
17
+ /** Strict derivation succeeded: `modelSchema` is the tightened form to hand the model. */
18
+ | {
13
19
  modelSchema: TSchema;
14
20
  strict: true;
15
- } | {
21
+ }
22
+ /** Valid but outside the strict subset: serve the schema as-is; `fallbackReason` is the observable why. */
23
+ | {
16
24
  modelSchema: TSchema;
17
25
  strict: false;
18
26
  fallbackReason: string;
19
27
  };
28
+ /**
29
+ * Validate + strict-derive a structured-output schema (CC 2.1.205 semantics):
30
+ * invalid / oversized schema → `{error}` (the caller throws — no silent acceptance);
31
+ * in-subset schema → `{modelSchema: strictForm, strict:true}` (`additionalProperties:false` stamped);
32
+ * valid-but-unsupported schema → `{modelSchema: original, strict:false, fallbackReason}` (observable).
33
+ * A derivation CRASH also falls back non-strict (CC's inner try/catch), never fails the task.
34
+ */
20
35
  export declare function compileOutputSchema(schema: TSchema): CompiledOutputSchema;