@sema-agent/core 7.54.1 → 7.55.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 (399) hide show
  1. package/CHANGELOG.md +437 -0
  2. package/dist/agents/agent-transcript-tool.js +2 -1
  3. package/dist/agents/builtin-agents.d.ts +12 -14
  4. package/dist/agents/cc-peer-directory.d.ts +36 -0
  5. package/dist/agents/cc-peer-directory.js +138 -0
  6. package/dist/agents/cc-peer-wire.d.ts +105 -0
  7. package/dist/agents/cc-peer-wire.js +98 -0
  8. package/dist/agents/cc-uds-peer-channel.d.ts +40 -0
  9. package/dist/agents/cc-uds-peer-channel.js +457 -0
  10. package/dist/agents/cross-session-envelope.d.ts +4 -1
  11. package/dist/agents/cross-session-envelope.js +8 -1
  12. package/dist/agents/cross-session-judge.d.ts +2 -2
  13. package/dist/agents/list-agents-tool.js +2 -1
  14. package/dist/agents/observer.d.ts +4 -5
  15. package/dist/agents/observer.js +2 -1
  16. package/dist/agents/peer-admission.d.ts +6 -0
  17. package/dist/agents/peer-admission.js +4 -1
  18. package/dist/agents/peer-directory.d.ts +43 -9
  19. package/dist/agents/peer-directory.js +66 -23
  20. package/dist/agents/peer-notices.d.ts +1 -1
  21. package/dist/agents/peer-session-drain.d.ts +3 -1
  22. package/dist/agents/peer-session-drain.js +1 -0
  23. package/dist/agents/read-inbox-tool.js +2 -1
  24. package/dist/agents/retain-ledger.d.ts +1 -1
  25. package/dist/agents/roster-store.d.ts +1 -1
  26. package/dist/agents/send-message-tool.d.ts +10 -0
  27. package/dist/agents/send-message-tool.js +34 -5
  28. package/dist/agents/subagent.d.ts +34 -79
  29. package/dist/agents/subagent.js +45 -46
  30. package/dist/agents/tool-filter.d.ts +29 -46
  31. package/dist/agents/tool-filter.js +8 -31
  32. package/dist/agents/verify.d.ts +3 -3
  33. package/dist/brain/anthropic.js +14 -9
  34. package/dist/brain/errors.d.ts +15 -0
  35. package/dist/brain/errors.js +10 -0
  36. package/dist/brain/model-presets.d.ts +4 -4
  37. package/dist/brain/open-responses.js +15 -10
  38. package/dist/brain/openai.js +17 -12
  39. package/dist/brain/provider-dialect.d.ts +39 -3
  40. package/dist/brain/provider-dialect.js +28 -0
  41. package/dist/brain/reasoning.d.ts +1 -1
  42. package/dist/brain/request-params.d.ts +55 -5
  43. package/dist/brain/request-params.js +35 -3
  44. package/dist/brain/retry.d.ts +1 -1
  45. package/dist/brain/route-adjudicator.d.ts +15 -0
  46. package/dist/brain/route-adjudicator.js +15 -0
  47. package/dist/brain/stream-engine.js +6 -5
  48. package/dist/brain/stream-shared.d.ts +1 -1
  49. package/dist/core/advisor-verdict.d.ts +120 -0
  50. package/dist/core/advisor-verdict.js +92 -0
  51. package/dist/core/agent-definition.d.ts +7 -8
  52. package/dist/core/allow-entry.d.ts +49 -23
  53. package/dist/core/allow-entry.js +57 -32
  54. package/dist/core/allow-rule-shadow.d.ts +7 -0
  55. package/dist/core/approval-object.d.ts +2 -1
  56. package/dist/core/approval-object.js +6 -6
  57. package/dist/core/ask-origin.d.ts +63 -11
  58. package/dist/core/ask-origin.js +27 -5
  59. package/dist/core/ask-question.js +10 -4
  60. package/dist/core/auto-compaction.d.ts +11 -8
  61. package/dist/core/auto-compaction.js +4 -2
  62. package/dist/core/auto-mode-arming.d.ts +2 -2
  63. package/dist/core/auto-mode-defaults.d.ts +8 -8
  64. package/dist/core/auto-mode-prompt-assets.d.ts +3 -3
  65. package/dist/core/auto-mode-prompt.d.ts +1 -1
  66. package/dist/core/auto-mode.d.ts +17 -9
  67. package/dist/core/auto-mode.js +9 -6
  68. package/dist/core/background-agent-store.d.ts +3 -3
  69. package/dist/core/canonical-json.d.ts +1 -1
  70. package/dist/core/canonical-json.js +2 -2
  71. package/dist/core/checkpoint-requirements.d.ts +6 -3
  72. package/dist/core/checkpoint-requirements.js +4 -14
  73. package/dist/core/checkpoint-store.d.ts +80 -51
  74. package/dist/core/checkpoint-store.js +56 -74
  75. package/dist/core/child-clamp-seats.d.ts +6 -0
  76. package/dist/core/child-clamp-seats.js +3 -16
  77. package/dist/core/compliance.d.ts +2 -2
  78. package/dist/core/context-edit.d.ts +6 -7
  79. package/dist/core/cross-boundary-taint.d.ts +9 -3
  80. package/dist/core/cross-boundary-taint.js +5 -3
  81. package/dist/core/decision-receipt.js +2 -2
  82. package/dist/core/effective-path-target.d.ts +1 -1
  83. package/dist/core/engine-notice.d.ts +19 -5
  84. package/dist/core/exec-output-tail.d.ts +1 -1
  85. package/dist/core/file-history-retention.d.ts +1 -1
  86. package/dist/core/file-history-store.d.ts +59 -9
  87. package/dist/core/file-history-store.js +35 -17
  88. package/dist/core/gate-fold.js +3 -2
  89. package/dist/core/gate-lanes.js +12 -8
  90. package/dist/core/gate-outcome.d.ts +17 -4
  91. package/dist/core/gate-outcome.js +30 -0
  92. package/dist/core/governance-codes.d.ts +13 -3
  93. package/dist/core/governance-codes.js +10 -0
  94. package/dist/core/hands-band.d.ts +1 -1
  95. package/dist/core/hooks.d.ts +4 -4
  96. package/dist/core/host-target.d.ts +49 -0
  97. package/dist/core/host-target.js +59 -0
  98. package/dist/core/image-downsample.d.ts +1 -1
  99. package/dist/core/lsp-diagnostics.d.ts +4 -4
  100. package/dist/core/lsp.d.ts +3 -3
  101. package/dist/core/mailbox-store.d.ts +4 -0
  102. package/dist/core/mcp-connection-pool.d.ts +18 -2
  103. package/dist/core/mcp-connection-pool.js +53 -6
  104. package/dist/core/mcp-failure.d.ts +23 -4
  105. package/dist/core/mcp-failure.js +26 -11
  106. package/dist/core/mcp-listing-drift.d.ts +10 -0
  107. package/dist/core/mcp-listing-drift.js +6 -0
  108. package/dist/core/mcp-server-link.d.ts +173 -0
  109. package/dist/core/mcp-server-link.js +127 -0
  110. package/dist/core/mcp-server-spec.d.ts +4 -2
  111. package/dist/core/mcp-session-end.d.ts +26 -0
  112. package/dist/core/mcp-session-end.js +29 -0
  113. package/dist/core/mcp-startup-request.d.ts +17 -0
  114. package/dist/core/mcp-startup-request.js +17 -0
  115. package/dist/core/mcp.d.ts +13 -13
  116. package/dist/core/mcp.js +187 -162
  117. package/dist/core/media-byte-cap.d.ts +1 -1
  118. package/dist/core/memory-engine/engine.d.ts +9 -9
  119. package/dist/core/memory-engine/provenance-wording.d.ts +1 -1
  120. package/dist/core/memory-engine/tools.js +4 -1
  121. package/dist/core/mode-policy.d.ts +1 -1
  122. package/dist/core/namespaced-rule-name.d.ts +33 -7
  123. package/dist/core/namespaced-rule-name.js +39 -25
  124. package/dist/core/output-style.d.ts +1 -1
  125. package/dist/core/param-rule-reach.d.ts +15 -0
  126. package/dist/core/param-rule-reach.js +30 -0
  127. package/dist/core/parent-spec-seat.d.ts +8 -1
  128. package/dist/core/parent-spec-seat.js +4 -0
  129. package/dist/core/pause-registry.d.ts +16 -5
  130. package/dist/core/pause-registry.js +6 -2
  131. package/dist/core/peer-channel.d.ts +70 -0
  132. package/dist/core/peer-channel.js +1 -0
  133. package/dist/core/permission-rule-consent.d.ts +11 -5
  134. package/dist/core/permission-rule-consent.js +37 -30
  135. package/dist/core/permission-rule-model.d.ts +233 -64
  136. package/dist/core/permission-rule-model.js +384 -85
  137. package/dist/core/permission-rule-provider.d.ts +2 -1
  138. package/dist/core/permission-rule-store.d.ts +20 -25
  139. package/dist/core/permission-rule-store.js +1 -4
  140. package/dist/core/permission-rule-sync.d.ts +11 -2
  141. package/dist/core/permission-rule-sync.js +8 -1
  142. package/dist/core/permission-rules.d.ts +49 -11
  143. package/dist/core/permission-rules.js +123 -89
  144. package/dist/core/persisted-rule-arms.d.ts +4 -2
  145. package/dist/core/present-plan-tool.js +3 -1
  146. package/dist/core/protocol-naming.d.ts +2 -2
  147. package/dist/core/read-only-shell-table.d.ts +1 -1
  148. package/dist/core/read-only-shell.d.ts +1 -1
  149. package/dist/core/roles.d.ts +6 -2
  150. package/dist/core/roles.js +45 -44
  151. package/dist/core/rule-offer-read.d.ts +53 -0
  152. package/dist/core/rule-offer-read.js +146 -0
  153. package/dist/core/rule-owner.d.ts +46 -0
  154. package/dist/core/rule-owner.js +28 -0
  155. package/dist/core/runner/advisor-instructions.d.ts +70 -0
  156. package/dist/core/runner/advisor-instructions.js +61 -0
  157. package/dist/core/runner/advisor-tool.d.ts +33 -0
  158. package/dist/core/runner/advisor-tool.js +112 -0
  159. package/dist/core/runner/announce-once-ledger.d.ts +4 -26
  160. package/dist/core/runner/announce-once-ledger.js +14 -46
  161. package/dist/core/runner/approval-feedback.js +6 -3
  162. package/dist/core/runner/assemble-result.d.ts +1 -1
  163. package/dist/core/runner/caller-roster.d.ts +7 -0
  164. package/dist/core/runner/caller-roster.js +11 -0
  165. package/dist/core/runner/classifier-ladder.d.ts +27 -5
  166. package/dist/core/runner/classifier-ladder.js +12 -11
  167. package/dist/core/runner/compaction-restate.d.ts +10 -6
  168. package/dist/core/runner/compaction-restate.js +9 -3
  169. package/dist/core/runner/contracts.d.ts +13 -9
  170. package/dist/core/runner/conversation-segment.d.ts +28 -0
  171. package/dist/core/runner/conversation-segment.js +42 -0
  172. package/dist/core/runner/cross-boundary-lane.d.ts +6 -5
  173. package/dist/core/runner/cross-boundary-lane.js +26 -15
  174. package/dist/core/runner/decide-continuation.d.ts +7 -4
  175. package/dist/core/runner/decide-continuation.js +2 -2
  176. package/dist/core/runner/denial-limit-arms.d.ts +2 -2
  177. package/dist/core/runner/derived-route-fallback.d.ts +24 -24
  178. package/dist/core/runner/derived-route-fallback.js +9 -7
  179. package/dist/core/runner/gate-exit.d.ts +6 -0
  180. package/dist/core/runner/gate-exit.js +7 -2
  181. package/dist/core/runner/initial-run-state.js +1 -1
  182. package/dist/core/runner/permission-rule-lanes.d.ts +2 -2
  183. package/dist/core/runner/permission-rule-lanes.js +14 -7
  184. package/dist/core/runner/person-path-rows.js +1 -1
  185. package/dist/core/runner/prepare-advisor.d.ts +63 -0
  186. package/dist/core/runner/prepare-advisor.js +77 -0
  187. package/dist/core/runner/prepare-caps-and-workflow.js +1 -1
  188. package/dist/core/runner/prepare-config-doors.d.ts +6 -4
  189. package/dist/core/runner/prepare-config-doors.js +18 -12
  190. package/dist/core/runner/prepare-delegation-surface.d.ts +2 -2
  191. package/dist/core/runner/prepare-delegation-surface.js +1 -1
  192. package/dist/core/runner/prepare-file-history.js +39 -39
  193. package/dist/core/runner/prepare-gate-stations.d.ts +1 -4
  194. package/dist/core/runner/prepare-gate-stations.js +2 -7
  195. package/dist/core/runner/prepare-inherited-gate.d.ts +5 -4
  196. package/dist/core/runner/prepare-inherited-gate.js +3 -3
  197. package/dist/core/runner/prepare-park-ask.js +7 -7
  198. package/dist/core/runner/prepare-policy-chain.d.ts +1 -1
  199. package/dist/core/runner/prepare-policy-chain.js +4 -10
  200. package/dist/core/runner/prepare-project-context.d.ts +5 -2
  201. package/dist/core/runner/prepare-project-context.js +6 -3
  202. package/dist/core/runner/prepare-prompt-inputs.js +1 -1
  203. package/dist/core/runner/prepare-protocol-tools.d.ts +2 -2
  204. package/dist/core/runner/prepare-protocol-tools.js +3 -2
  205. package/dist/core/runner/prepare-safety-scan.d.ts +9 -12
  206. package/dist/core/runner/prepare-safety-scan.js +8 -6
  207. package/dist/core/runner/prepare-task.js +15 -18
  208. package/dist/core/runner/prepare-tool-disclosure-mount.js +6 -4
  209. package/dist/core/runner/prepare-wiring-manifest.d.ts +6 -3
  210. package/dist/core/runner/prepare-wiring-manifest.js +2 -2
  211. package/dist/core/runner/resume-policy-outcome.js +1 -1
  212. package/dist/core/runner/retired-runner-deps.js +1 -1
  213. package/dist/core/runner/run-attachment-seats.js +0 -1
  214. package/dist/core/runner/run-compaction-machinery.d.ts +1 -1
  215. package/dist/core/runner/run-compaction-machinery.js +2 -12
  216. package/dist/core/runner/run-git-lane.d.ts +1 -0
  217. package/dist/core/runner/run-harness-handlers.js +2 -3
  218. package/dist/core/runner/run-leg.js +13 -0
  219. package/dist/core/runner/run-settle-and-teardown.js +1 -1
  220. package/dist/core/runner/run-telemetry-and-budget-seats.js +1 -1
  221. package/dist/core/runner/run-turn-boundary.d.ts +1 -0
  222. package/dist/core/runner/run-turn-boundary.js +14 -12
  223. package/dist/core/runner/session-rule-policy.d.ts +22 -21
  224. package/dist/core/runner/session-rule-policy.js +13 -28
  225. package/dist/core/runner/side-call-account.d.ts +32 -8
  226. package/dist/core/runner/side-call-account.js +23 -1
  227. package/dist/core/runner/strict-output-schema.d.ts +1 -1
  228. package/dist/core/runner/sub-agent-deny-lists.js +4 -3
  229. package/dist/core/runner/synthetic-tools.d.ts +10 -13
  230. package/dist/core/runner/synthetic-tools.js +4 -2
  231. package/dist/core/runner/tool-disclosure.js +2 -1
  232. package/dist/core/runner/tool-face-overlay.d.ts +2 -1
  233. package/dist/core/runner/tool-face-overlay.js +17 -1
  234. package/dist/core/runner/tool-progress-lane.d.ts +2 -2
  235. package/dist/core/runner/tool-turn-repair-seat.d.ts +3 -2
  236. package/dist/core/runner/turn-attachments.d.ts +60 -67
  237. package/dist/core/runner-deps.d.ts +37 -37
  238. package/dist/core/runtime-caps.d.ts +4 -4
  239. package/dist/core/safety-merge-corpus.js +17 -1
  240. package/dist/core/same-plain-value.d.ts +40 -0
  241. package/dist/core/same-plain-value.js +49 -0
  242. package/dist/core/scheduler.d.ts +1 -1
  243. package/dist/core/sensitive-path-policy.d.ts +1 -1
  244. package/dist/core/sensitive-path-policy.js +1 -1
  245. package/dist/core/session-policy-store.d.ts +77 -22
  246. package/dist/core/session-policy-store.js +56 -14
  247. package/dist/core/session-reconcile.d.ts +2 -2
  248. package/dist/core/session-store.d.ts +80 -30
  249. package/dist/core/session-store.js +118 -76
  250. package/dist/core/session.d.ts +24 -46
  251. package/dist/core/shared-memory/tools.js +3 -1
  252. package/dist/core/shared-memory/types.d.ts +1 -1
  253. package/dist/core/side-query.d.ts +10 -0
  254. package/dist/core/side-query.js +5 -0
  255. package/dist/core/store-contracts/checkpoint-store-contract.js +29 -2
  256. package/dist/core/store-contracts/file-history-store-contract.js +43 -3
  257. package/dist/core/store-contracts/session-policy-store-contract.d.ts +7 -0
  258. package/dist/core/store-contracts/session-policy-store-contract.js +130 -0
  259. package/dist/core/store-contracts/session-repo-contract.js +125 -0
  260. package/dist/core/store-contracts/session-store-contract.d.ts +4 -7
  261. package/dist/core/store-contracts/session-store-contract.js +215 -41
  262. package/dist/core/store-contracts/workflow-journal-store-contract.js +26 -1
  263. package/dist/core/surrogate-safe-slice.d.ts +3 -3
  264. package/dist/core/task-event.d.ts +10 -4
  265. package/dist/core/task-notification.d.ts +3 -3
  266. package/dist/core/task-registry-agent.d.ts +4 -4
  267. package/dist/core/task-registry-shared.d.ts +4 -4
  268. package/dist/core/task-registry-shared.js +1 -0
  269. package/dist/core/task-registry.d.ts +4 -4
  270. package/dist/core/task-registry.js +3 -1
  271. package/dist/core/task-result.d.ts +3 -3
  272. package/dist/core/task-spec.d.ts +52 -52
  273. package/dist/core/task-stream.d.ts +6 -6
  274. package/dist/core/task-tool-shape.d.ts +4 -4
  275. package/dist/core/tighten-task-spec.d.ts +1 -1
  276. package/dist/core/tool-catalog-entries.d.ts +19 -2
  277. package/dist/core/tool-catalog-entries.js +57 -42
  278. package/dist/core/tool-conformance.js +1 -0
  279. package/dist/core/tool-errors.d.ts +2 -2
  280. package/dist/core/tool-face-reader.js +5 -3
  281. package/dist/core/tool-face.d.ts +21 -2
  282. package/dist/core/tool-face.js +1 -1
  283. package/dist/core/tool-model-gate.d.ts +3 -3
  284. package/dist/core/tool-name-aliases.d.ts +29 -8
  285. package/dist/core/tool-name-aliases.js +27 -3
  286. package/dist/core/tool-name-readings.d.ts +5 -8
  287. package/dist/core/tool-name-readings.js +1 -2
  288. package/dist/core/tool-policy.d.ts +24 -5
  289. package/dist/core/tool-policy.js +34 -10
  290. package/dist/core/tool-registry.d.ts +14 -7
  291. package/dist/core/tool-registry.js +17 -7
  292. package/dist/core/tool-result-store.js +2 -1
  293. package/dist/core/tool-roster.d.ts +47 -18
  294. package/dist/core/tool-roster.js +53 -32
  295. package/dist/core/tool-spec-members.js +1 -1
  296. package/dist/core/tool-spec.d.ts +35 -21
  297. package/dist/core/tools.js +3 -2
  298. package/dist/core/trace.d.ts +4 -0
  299. package/dist/core/untrusted-egress.d.ts +1 -1
  300. package/dist/core/untrusted-text.d.ts +1 -1
  301. package/dist/core/warm-resume.d.ts +1 -1
  302. package/dist/core/wiring-manifest.d.ts +49 -0
  303. package/dist/core/wiring-manifest.js +13 -5
  304. package/dist/core/workflow-journal-store.d.ts +62 -0
  305. package/dist/core/workflow-journal-store.js +77 -1
  306. package/dist/core/workflow-run-store.d.ts +6 -0
  307. package/dist/core/workflow-run-store.js +2 -0
  308. package/dist/engine/compaction/compaction.d.ts +9 -9
  309. package/dist/engine/execution-env/node-execution-env.d.ts +19 -5
  310. package/dist/engine/execution-env/node-execution-env.js +43 -22
  311. package/dist/engine/harness/agent-harness.d.ts +14 -8
  312. package/dist/engine/harness/agent-harness.js +33 -26
  313. package/dist/engine/harness/types.d.ts +29 -7
  314. package/dist/engine/harness/types.js +12 -1
  315. package/dist/engine/llm/types.d.ts +9 -9
  316. package/dist/engine/llm/validation.d.ts +4 -1
  317. package/dist/engine/llm/validation.js +13 -1
  318. package/dist/engine/loop/agent-loop.d.ts +1 -1
  319. package/dist/engine/loop/agent-loop.js +10 -8
  320. package/dist/engine/loop/types.d.ts +15 -13
  321. package/dist/engine/lsp/node-lsp-manager.d.ts +2 -2
  322. package/dist/engine/session/memory-repo.d.ts +10 -11
  323. package/dist/engine/session/memory-repo.js +13 -8
  324. package/dist/engine/session/parent-chain-guard.d.ts +3 -2
  325. package/dist/engine/session/parent-chain-guard.js +1 -1
  326. package/dist/engine/session/repo-utils.d.ts +31 -3
  327. package/dist/engine/session/repo-utils.js +42 -5
  328. package/dist/index.d.ts +27 -15
  329. package/dist/index.js +21 -11
  330. package/dist/internal/harness-types.d.ts +1 -1
  331. package/dist/internal/harness.d.ts +3 -3
  332. package/dist/internal/harness.js +2 -2
  333. package/dist/internal/llm.d.ts +1 -1
  334. package/dist/internal/llm.js +1 -1
  335. package/dist/orchestration/goal.js +2 -2
  336. package/dist/orchestration/run-workflow-tool.d.ts +2 -2
  337. package/dist/orchestration/run-workflow-tool.js +5 -3
  338. package/dist/orchestration/workflow-size-guideline.d.ts +4 -4
  339. package/dist/orchestration/workflow-types.d.ts +18 -0
  340. package/dist/orchestration/workflow-types.js +6 -0
  341. package/dist/orchestration/workflow.d.ts +2 -13
  342. package/dist/orchestration/workflow.js +21 -31
  343. package/dist/prompt-assembly/event-registry.js +1 -0
  344. package/dist/prompt-assembly/tool-catalog.d.ts +3 -0
  345. package/dist/prompt-assembly/tool-catalog.js +3 -0
  346. package/dist/prompts/default.d.ts +14 -14
  347. package/dist/scenarios/full-body.d.ts +4 -4
  348. package/dist/stores/file/adoption/adopt.d.ts +4 -3
  349. package/dist/stores/file/adoption/adopt.js +24 -31
  350. package/dist/stores/file/adoption/marker.d.ts +6 -13
  351. package/dist/stores/file/adoption/marker.js +6 -15
  352. package/dist/stores/file/checkpoint-store.d.ts +3 -0
  353. package/dist/stores/file/checkpoint-store.js +9 -3
  354. package/dist/stores/file/file-history-store.d.ts +20 -19
  355. package/dist/stores/file/file-history-store.js +152 -135
  356. package/dist/stores/file/fs-atomic.d.ts +15 -0
  357. package/dist/stores/file/fs-atomic.js +89 -14
  358. package/dist/stores/file/index.d.ts +1 -1
  359. package/dist/stores/file/mailbox-store.d.ts +3 -0
  360. package/dist/stores/file/mailbox-store.js +3 -1
  361. package/dist/stores/file/permission-rule-adopt.d.ts +1 -1
  362. package/dist/stores/file/permission-rule-adopt.js +15 -16
  363. package/dist/stores/file/permission-rule-store.d.ts +18 -2
  364. package/dist/stores/file/permission-rule-store.js +21 -14
  365. package/dist/stores/file/session-policy-store.d.ts +3 -3
  366. package/dist/stores/file/session-store.d.ts +26 -11
  367. package/dist/stores/file/session-store.js +77 -40
  368. package/dist/stores/file/workflow-journal-store.d.ts +10 -4
  369. package/dist/stores/file/workflow-journal-store.js +28 -13
  370. package/dist/tools/artifact/artifact-text.d.ts +1 -1
  371. package/dist/tools/artifact/artifact-tool.js +2 -1
  372. package/dist/tools/fs/bash-readonly-classifier.d.ts +3 -3
  373. package/dist/tools/fs/fs-bash.d.ts +2 -2
  374. package/dist/tools/fs/fs-bash.js +3 -1
  375. package/dist/tools/fs/fs-shared.d.ts +8 -8
  376. package/dist/tools/fs/gh-rate-limit.d.ts +1 -1
  377. package/dist/tools/fs/notebook.d.ts +2 -2
  378. package/dist/tools/fs/read-deny.d.ts +29 -7
  379. package/dist/tools/fs/read-deny.js +63 -22
  380. package/dist/tools/fs/removal-targets.d.ts +1 -1
  381. package/dist/tools/fs/safety.d.ts +9 -9
  382. package/dist/tools/fs/search.d.ts +6 -6
  383. package/dist/tools/fs/shell-read-check.js +6 -1
  384. package/dist/tools/fs/shell-read-judge.d.ts +4 -0
  385. package/dist/tools/fs/shell-read-judge.js +5 -2
  386. package/dist/tools/loop-tick.d.ts +2 -2
  387. package/dist/tools/scheduler-tools.js +5 -1
  388. package/dist/tools/task-list.d.ts +7 -7
  389. package/dist/tools/task-list.js +5 -1
  390. package/dist/tools/todo.js +2 -1
  391. package/dist/tools/web.d.ts +1 -1
  392. package/dist/tools/web.js +40 -37
  393. package/dist/tools/worktree.d.ts +3 -3
  394. package/dist/tools/worktree.js +3 -1
  395. package/package.json +1 -1
  396. package/test/export-surface.snapshot.json +5756 -5638
  397. package/wire-changes/core@7.55.0.json +3318 -0
  398. package/dist/core/store-contracts/session-store-incarnation-contract.d.ts +0 -39
  399. package/dist/core/store-contracts/session-store-incarnation-contract.js +0 -95
@@ -40,7 +40,7 @@ export function runTelemetryAndBudgetSeats(input) {
40
40
  rs.telemetry.pricingConfigured = isModelPriced(prepared.model, runner.deps.pricing);
41
41
  if (spec.limits?.degrade) {
42
42
  try {
43
- rs.degrade.degradeToModel = resolveModel(spec.limits.degrade.to, modelCatalog);
43
+ rs.degrade.degradeToModel = resolveModel(spec.limits.degrade.to, modelCatalog, "TaskSpec.limits.degrade.to");
44
44
  }
45
45
  catch (e) {
46
46
  runner.deps.onError?.(e, { phase: "degraded", sessionId: prepared.sessionId });
@@ -29,6 +29,7 @@ export interface RunTurnBoundaryInput {
29
29
  export interface RunTurnBoundaryResult {
30
30
  (event: {
31
31
  model: Model;
32
+ continues: boolean;
32
33
  }): Promise<undefined>;
33
34
  }
34
35
  export declare function createTurnBoundary(input: RunTurnBoundaryInput): RunTurnBoundaryResult;
@@ -13,7 +13,7 @@ import { droppedToolDigest, withAnnounceDigests } from "./announce-once-ledger.j
13
13
  import { formatDiagnosticsBlock, withholdListedDiagnostics } from "../lsp-diagnostics.js";
14
14
  import { workflowSizeGuidelineChangeNotice } from "../../orchestration/workflow-size-guideline.js";
15
15
  import { awaitChargeWithSlowDisclosure, discloseUnevaluableWindow, ENV_DUE_GOVERNANCE_READ_BUDGET_MS, GOVERNANCE_READ_STALLED, LIMIT_APPROACH_DEFAULT_THRESHOLDS, limitApproachFrames, platformLimitTerminal, raceUntilDeadline } from "./clock-and-limits.js";
16
- import { appendBoundaryFrames, compactionRestateOptions } from "./compaction-restate.js";
16
+ import { appendBoundaryFrames, compactionRestateOptions, frameCarried } from "./compaction-restate.js";
17
17
  import { COMPACTION_FREED_EPSILON, COMPACTION_REGROWTH_FACTOR, MAX_CONSECUTIVE_COMPACTION_FAILURES } from "./compaction-knobs.js";
18
18
  import { compactionHookOptions, recordCompactionReuse, seamCCompactionOptions } from "./compaction-seams.js";
19
19
  import { contextUsageSections } from "../../prompt-assembly/section-usage.js";
@@ -27,6 +27,7 @@ export function createTurnBoundary(input) {
27
27
  let finalVerifySeenAtLastBoundary = 0;
28
28
  let legContinues = true;
29
29
  const boundaryPass = async (event) => {
30
+ const turnOwesRequest = event.continues;
30
31
  let boundarySteered = false;
31
32
  const noNextRequest = () => prepared.stopRequestedRef.current || deps.loopLatch.userHalted;
32
33
  const walltimeHit = walltimeMonotonicDeadline !== undefined && performance.now() >= walltimeMonotonicDeadline;
@@ -149,7 +150,7 @@ export function createTurnBoundary(input) {
149
150
  if (approachCfg !== false &&
150
151
  rs.counters.approachNoticesSent < LIMIT_APPROACH_DEFAULT_THRESHOLDS.length &&
151
152
  prepared.suspendForResource === undefined &&
152
- rs.turn.lastTurnHadToolCalls &&
153
+ turnOwesRequest &&
153
154
  prepared.batchHaltRef.current === undefined &&
154
155
  !boundarySteered &&
155
156
  !prepared.abortController.signal.aborted) {
@@ -199,9 +200,10 @@ export function createTurnBoundary(input) {
199
200
  emitTrace(rs.telemetry.tracer, () => ({ kind: "review.dropped", version: 1, taskId: rs.telemetry.taskId, ts: Date.now() }));
200
201
  }
201
202
  if (!noNextRequest() && !prepared.abortController.signal.aborted)
202
- await appendBoundaryFrames(prepared, rs.turn.lastTurnHadToolCalls);
203
+ await appendBoundaryFrames(prepared, turnOwesRequest);
203
204
  if (prepared.lspDiagnostics &&
204
205
  !prepared.lspDiagnostics.registry.isEmpty() &&
206
+ turnOwesRequest &&
205
207
  !prepared.abortController.signal.aborted &&
206
208
  prepared.batchHaltRef.current === undefined) {
207
209
  const files = await withholdListedDiagnostics(prepared.lspDiagnostics.registry.drain(prepared.lspDiagnostics.runIdent), prepared.lspDiagnostics.withheldOf);
@@ -219,6 +221,7 @@ export function createTurnBoundary(input) {
219
221
  rs.attach.instrState !== undefined ||
220
222
  rs.attach.sizeGuidelineState !== undefined ||
221
223
  rs.attach.attachState !== undefined) &&
224
+ turnOwesRequest &&
222
225
  !boundarySteered &&
223
226
  prepared.batchHaltRef.current === undefined &&
224
227
  !noNextRequest() &&
@@ -265,21 +268,20 @@ export function createTurnBoundary(input) {
265
268
  const mcpAdds = mcpInstructionsOn && mcpDelta.pendingAdds.length > 0 ? [...mcpDelta.pendingAdds] : undefined;
266
269
  const mcpRemovals = mcpInstructionsOn && mcpDelta.pendingRemovals.length > 0 ? [...mcpDelta.pendingRemovals] : undefined;
267
270
  const mcpDropped = mcpInstructionsOn && prepared.mcp.droppedTools.length > 0 ? selectMcpDroppedBatch(prepared.mcp.droppedTools) : undefined;
268
- const budgetUsdOn = rs.attach.attachmentsCfg?.budgetUsd === true && rs.budget.maxCostMicroUsd !== undefined && rs.turn.lastTurnHadToolCalls;
271
+ const budgetUsdOn = rs.attach.attachmentsCfg?.budgetUsd === true && rs.budget.maxCostMicroUsd !== undefined;
269
272
  const totalTokensDeclared = rs.attach.attachmentsCfg?.totalTokensReminder;
270
273
  const totalTokensMode = rs.attach.attachmentsCfg?.totalTokensReminderMode ?? TOTAL_TOKENS_REMINDER_DEFAULT_MODE;
271
274
  const totalTokensArmedByDefault = totalTokensDeclared === undefined &&
272
275
  eventDefaultOn("total_tokens_reminder") &&
273
276
  totalTokensMode !== "fixed" &&
274
277
  totalTokensMode !== "infinite";
275
- const totalTokensOn = (totalTokensDeclared === true || totalTokensArmedByDefault) && rs.turn.lastTurnHadToolCalls;
278
+ const totalTokensOn = totalTokensDeclared === true || totalTokensArmedByDefault;
276
279
  const toolSearchReminderOn = rs.attach.attachmentsCfg?.toolSearchReminder === true && prepared.deferredToolNames !== undefined;
277
280
  const undiscoveredTools = toolSearchReminderOn
278
281
  ? [...prepared.deferredToolNames].filter((n) => !prepared.activeTools.has(n)).sort()
279
282
  : undefined;
280
- const receiptPending = (source) => prepared.frameReceipts.pending.some((r) => r.source === source);
281
- const agentListingDue = rs.attach.agentListingOn && prepared.agentListing !== undefined && !receiptPending("agent_listing");
282
- const skillsListingDue = rs.attach.skillsListingOn && prepared.skillsListing !== undefined && !receiptPending("skills_listing");
283
+ const agentListingDue = rs.attach.agentListingOn && prepared.agentListing !== undefined && !frameCarried(prepared.frameReceipts, "agent_listing");
284
+ const skillsListingDue = rs.attach.skillsListingOn && prepared.skillsListing !== undefined && !frameCarried(prepared.frameReceipts, "skills_listing");
283
285
  const listingBudget = prepared.skillsListing?.budget ?? prepared.agentListing?.budget;
284
286
  due.push(...collectDueAttachments(rs.attach.attachState, {
285
287
  turn: stats.turns,
@@ -302,7 +304,7 @@ export function createTurnBoundary(input) {
302
304
  skillsListing: rs.attach.skillsListingOn,
303
305
  mcpInstructions: mcpInstructionsOn,
304
306
  },
305
- ...(prepared.outputStyleFrame !== undefined && rs.turn.lastTurnHadToolCalls ? { outputStyle: prepared.outputStyleFrame } : {}),
307
+ ...(prepared.outputStyleFrame !== undefined && !frameCarried(prepared.frameReceipts, "output_style") ? { outputStyle: prepared.outputStyleFrame } : {}),
306
308
  ...(undiscoveredTools !== undefined && undiscoveredTools.length > 0
307
309
  ? { undiscoveredTools, deferDirectCall: prepared.deferDirectCall }
308
310
  : {}),
@@ -412,7 +414,7 @@ export function createTurnBoundary(input) {
412
414
  if (announcedOnceDirty)
413
415
  prepared.frameReceipts.listingSnapshotOwed = true;
414
416
  }
415
- if (rs.attach.dateState !== undefined && rs.turn.lastTurnHadToolCalls && !prepared.frameReceipts.pending.some((r) => r.source === "date_change")) {
417
+ if (rs.attach.dateState !== undefined && !frameCarried(prepared.frameReceipts, "date_change")) {
416
418
  const today = prepared.dateChange.today();
417
419
  const cand = collectDateChange(rs.attach.dateState, today);
418
420
  if (cand !== undefined) {
@@ -420,7 +422,7 @@ export function createTurnBoundary(input) {
420
422
  receiptCommits.push({ source: "date_change", commit: () => void (rs.attach.dateState.announcedDate = today) });
421
423
  }
422
424
  }
423
- if (rs.attach.sizeGuidelineState !== undefined && rs.turn.lastTurnHadToolCalls) {
425
+ if (rs.attach.sizeGuidelineState !== undefined) {
424
426
  const guideline = rs.attach.sizeGuidelineState.current();
425
427
  if (guideline !== rs.attach.sizeGuidelineState.announcedGuideline) {
426
428
  due.splice(due.length > 0 && due[0].source === "date_change" ? 1 : 0, 0, {
@@ -430,7 +432,7 @@ export function createTurnBoundary(input) {
430
432
  rs.attach.sizeGuidelineState.announcedGuideline = guideline;
431
433
  }
432
434
  }
433
- if (rs.attach.instrState !== undefined && rs.attach.instrProbe !== undefined && rs.turn.lastTurnHadToolCalls) {
435
+ if (rs.attach.instrState !== undefined && rs.attach.instrProbe !== undefined) {
434
436
  let probed = null;
435
437
  try {
436
438
  const PROBE_CEILING_MS = 2_000;
@@ -52,18 +52,27 @@ export declare function isWithin(root: string, p: string): boolean;
52
52
  export interface SessionRuleSource {
53
53
  /** The prepare-time snapshot: the audit's view, and the floor no live read may loosen. */
54
54
  seed: SessionPermissionRules;
55
- /** The per-call read, keyed on the call being adjudicated, and bounded by the gate's own signal. Absent
56
- * ⇒ the seed is the whole source. */
55
+ /** The live read, asked at every judgment and bounded by the gate's own signal; `toolCallId` names the call being
56
+ * judged. Absent ⇒ the seed is the whole source. */
57
57
  read?: (toolCallId: string, signal?: AbortSignal) => Promise<SessionPermissionRules>;
58
58
  }
59
+ /** May `row` follow `floor` by rev at all (the one reading of the live reader below and of the checkpoint/live merge): a floor
60
+ * at rev 0 has enforced no row and has no lineage to defend; above it only the floor's own lineage ({@link continuesLineage}). */
61
+ export declare function rowFollowsFloor(row: {
62
+ gen?: number;
63
+ }, floor: {
64
+ rev: number;
65
+ gen?: number;
66
+ }): boolean;
59
67
  /**
60
68
  * The LIVE half of {@link SessionRuleSource}: re-read `(sessionId, principal)` from the store on each
61
- * adjudicated call, floored by `seed`.
69
+ * adjudicated call, floored by `seed`. An ABSENT store is a source that cannot answer — a delegated leg on a
70
+ * runner wired without the store its ancestors' rules live in — and takes the arm a throwing store takes.
62
71
  *
63
72
  * ONE law, two consumers (this task's own session rules and each inherited ancestor's), where the policy
64
73
  * chain used to carry a hand-written live-preferring read for ancestors only and a frozen snapshot for the
65
- * task's own rules. Direction, unchanged from that read and stated once here: a whole-row replacement
66
- * includes RELAXATION — an operator's authorized post-prepare rule change propagates in BOTH directions;
74
+ * task's own rules. Direction, unchanged from that read and stated once here: a whole-row replacement includes RELAXATION
75
+ * — any post-prepare write the store's judge accepted propagates in BOTH directions (the replace is the delete port);
67
76
  * what the floor forbids is an UNAUTHORIZED loosening (a lagging replica, a deleted row, an unreachable
68
77
  * store), and nothing task-side can edit the rules row itself.
69
78
  *
@@ -80,30 +89,22 @@ export interface SessionRuleSource {
80
89
  * recreated row is another generation and is never compared to the enforced one, whatever its rev, and
81
90
  * a backend without lineages (gen 0 throughout) keeps the `>` protection above.
82
91
  *
83
- * The per-call handoff mirrors the permission-rule lanes': the first reader of a `toolCallId` takes the read
84
- * and hands it on, a second reader of the SAME call claims that one snapshot, and an unclaimed entry is
85
- * evicted first-in-first-out past a bound. It is a cost device, never a semantic one — a reader that cannot
86
- * claim simply reads again. Its firing path here is the fold itself: `policyLayers` re-appends the narrowing
87
- * layers AFTER a rewrite-capable caller layer, so one adjudication asks this layer twice under one id, and
88
- * the leading (original args) and trailing (rewritten args) passes must judge ONE set of rules.
89
- *
90
- * Two bounds keep a handed entry from ever being a STALE one, because `toolCallId` is not always unique —
91
- * the turn-boundary read-visibility query reuses one synthetic id for every path it screens and for every
92
- * turn of the run. The entry is taken ONCE, and a claimed snapshot is served only while its `rev` still
93
- * stands at the enforced floor; a claim from a later adjudication, whose floor has moved on, falls through
94
- * to a fresh read. A real call's id is the provider's: unique within one assistant response only (`brain/tool-call-id.ts`).
92
+ * Every ask is a store read, and nothing is kept between asks. Not by call id: a provider's id is unique within one
93
+ * assistant response only (`brain/tool-call-id.ts`) and the visibility probes share one synthetic id, so a read kept
94
+ * under it served a later call an earlier call's snapshot. Nor between the two passes of one judgment: the fold's
95
+ * trailing narrowing pass runs after a caller policy that may have waited on a person, and judges the rules as they
96
+ * stand then.
95
97
  */
96
- export declare function createLiveSessionRules(store: SessionPolicyStore, floor: {
98
+ export declare function createLiveSessionRules(store: SessionPolicyStore | undefined, floor: {
97
99
  sessionId: string;
98
100
  principal?: string;
99
101
  seed: StoredSessionRules;
100
102
  }, hooks?: {
101
103
  /** A rule source this layer could not read, once per distinct reason. */
102
104
  onUnreadable?: (reason: string) => void;
103
- /** The store row this layer now enforces, each time the floor ADVANCES. Never called for the synthetic
104
- * empty seed: it reports rows the store actually served, which is what a child may inherit. */
105
+ /** The store row this layer now enforces, each time the floor ADVANCES — never for the seed (its holder has it). */
105
106
  onEnforced?: (row: StoredSessionRules) => void;
106
- }): (toolCallId: string, signal?: AbortSignal) => Promise<SessionPermissionRules>;
107
+ }): NonNullable<SessionRuleSource["read"]>;
107
108
  /**
108
109
  * Build the per-session deny-narrowing policy. For each tool call:
109
110
  * - `toolDeny` → deny the calls its entries reach — the one list matcher's deny reading (`judgeAllowEntries`): a tool name
@@ -32,8 +32,10 @@ const deny = (tool, detail) => ({
32
32
  message: ruleDenialSentence({ source: "session", tool, ...(detail !== undefined ? { detail } : {}) }),
33
33
  decisionReason: "rule",
34
34
  });
35
- const HANDOFF_BOUND = 256;
36
35
  const ANNOUNCED_REASONS_BOUND = 8;
36
+ export function rowFollowsFloor(row, floor) {
37
+ return floor.rev === 0 || continuesLineage(row, floor);
38
+ }
37
39
  export function createLiveSessionRules(store, floor, hooks) {
38
40
  const announced = new Set();
39
41
  const announce = (reason) => {
@@ -46,6 +48,8 @@ export function createLiveSessionRules(store, floor, hooks) {
46
48
  let servedRow = false;
47
49
  let vanished = false;
48
50
  const read = async (signal) => {
51
+ if (store === undefined)
52
+ return (announce(`this leg's runner has no session-policy store to re-read the rules of session ${JSON.stringify(floor.sessionId)} from`), enforced);
49
53
  let live;
50
54
  try {
51
55
  live = await withGateTimeout(store.getRules(floor.sessionId, floor.principal), DEFAULT_GATE_AWAIT_TIMEOUT_MS, signal, "sessionRulesRead");
@@ -64,15 +68,13 @@ export function createLiveSessionRules(store, floor, hooks) {
64
68
  }
65
69
  return enforced;
66
70
  }
67
- if (enforced.rev > 0) {
68
- if (!continuesLineage(live, enforced)) {
69
- announce(`session ${JSON.stringify(floor.sessionId)} has a rules row of a new lineage (generation ${live.gen}, rev ${live.rev}), which does not continue the row this leg enforces (generation ${enforced.gen})`);
70
- return enforced;
71
- }
72
- if (vanished && live.gen === undefined) {
73
- announce(`session ${JSON.stringify(floor.sessionId)} has a new rules row at rev ${live.rev} after the row this leg enforced was deleted, and its backend carries no lineage to continue it by`);
74
- return enforced;
75
- }
71
+ if (!rowFollowsFloor(live, enforced)) {
72
+ announce(`session ${JSON.stringify(floor.sessionId)} has a rules row of a new lineage (generation ${live.gen}, rev ${live.rev}), which does not continue the row this leg enforces (generation ${enforced.gen})`);
73
+ return enforced;
74
+ }
75
+ if (vanished && live.gen === undefined) {
76
+ announce(`session ${JSON.stringify(floor.sessionId)} has a new rules row at rev ${live.rev} after the row this leg enforced was deleted, and its backend carries no lineage to continue it by`);
77
+ return enforced;
76
78
  }
77
79
  if (live.rev <= enforced.rev) {
78
80
  if (live.rev < enforced.rev) {
@@ -85,24 +87,7 @@ export function createLiveSessionRules(store, floor, hooks) {
85
87
  hooks?.onEnforced?.(live);
86
88
  return live;
87
89
  };
88
- const handed = new Map();
89
- return async (toolCallId, signal) => {
90
- const handedRead = handed.get(toolCallId);
91
- if (handedRead !== undefined) {
92
- handed.delete(toolCallId);
93
- const claimed = await handedRead;
94
- if (continuesLineage(claimed, enforced) && claimed.rev >= enforced.rev)
95
- return claimed;
96
- }
97
- const p = read(signal);
98
- handed.set(toolCallId, p);
99
- if (handed.size > HANDOFF_BOUND) {
100
- const oldest = handed.keys().next().value;
101
- if (oldest !== undefined)
102
- handed.delete(oldest);
103
- }
104
- return p;
105
- };
90
+ return (_toolCallId, signal) => read(signal);
106
91
  }
107
92
  function compileSessionRules(rules) {
108
93
  const shaped = readSessionRulesShape(rules);
@@ -1,22 +1,26 @@
1
1
  /**
2
2
  * The run's usage account for the model calls made BESIDE the main loop — the compaction summarizer, the permission
3
- * classifier, a mod's `$.model.complete`: the lanes, what a reply tells the account, the one door a lane books through, and the
4
- * ONE function behind it. The lane table says which `Stats` line keeps a lane's cost besides `costMicroUsd` (every lane folds
5
- * into the total — it is the budget coordinate and the reported figure); it is total over the lanes by its fence, so a fourth
6
- * lane is a row here, not a second accounting function.
3
+ * classifier, a mod's `$.model.complete`, the advisor tool: the lanes, what a reply tells the account, the one door a lane books
4
+ * through, and the ONE function behind it. The lane table says which `Stats` line keeps a lane's cost besides `costMicroUsd`
5
+ * (every lane folds into the total — it is the budget coordinate and the reported figure); it is total over the lanes by its
6
+ * fence, so another lane is a row here, not a second accounting function.
7
7
  */
8
8
  import type { AssistantMessageDiagnostic, Model, Usage } from "../../internal/llm.js";
9
9
  import { type ModelPricing } from "../pricing.js";
10
10
  import type { AssertAllKeysHandled } from "../ask-origin.js";
11
- import type { RunnerDeps, TaskSpec } from "../types.js";
11
+ import type { Brain, RunnerDeps, TaskSpec } from "../types.js";
12
12
  import type { Stats } from "./assemble-result.js";
13
- /** Whose model call it is: the compaction summarizer, the permission classifier, a mod's `$.model.complete`. */
14
- export type SideCallLane = "compaction" | "classifier" | "mod";
15
- /** The `Stats` line a lane's cost is also kept in: compaction is its own partition line; the classifier and the mods share the side-call line. */
13
+ /** Whose model call it is: the compaction summarizer, the permission classifier, a mod's `$.model.complete`, the advisor
14
+ * tool's consultation of its advisor model. The word rides every side-call trace row (`brain.call.lane`). */
15
+ export type SideCallLane = "compaction" | "classifier" | "mod" | "advisor";
16
+ /** The `Stats` line a lane's cost is also kept in: compaction is its own partition line (the engine's upkeep); the
17
+ * classifier, the mods and the advisor share the side-call line (calls the run's own agent caused, so they stay inside the
18
+ * root agent's cost). */
16
19
  export declare const SIDE_CALL_LANE_TOTAL: {
17
20
  readonly compaction: "compactionMicroUsd";
18
21
  readonly classifier: "sideCallMicroUsd";
19
22
  readonly mod: "sideCallMicroUsd";
23
+ readonly advisor: "sideCallMicroUsd";
20
24
  };
21
25
  export type LaneTotalCoversEverySideCallLane = AssertAllKeysHandled<Exclude<SideCallLane, keyof typeof SIDE_CALL_LANE_TOTAL>>;
22
26
  /** A side call's reply as the account reads it: the provider's usage (absent ⇒ none reported), the marks of what is unknown,
@@ -64,5 +68,25 @@ export interface SideCallCall {
64
68
  * unknown is not free). A reply the brain itself marked `usageMissing` does the same for its zero-filled usage.
65
69
  */
66
70
  export declare function recordSideCallUsage(stats: Stats, usage: Usage | undefined, lane: SideCallLane, call: SideCallCall): void;
71
+ /**
72
+ * The accounted brain of a DERIVED LEG — a model call made beside the main loop on the leg's behalf (the compaction summary,
73
+ * the advisor consultation): every reply is booked through `book` exactly once, under `lane`, and the call runs behind
74
+ * NO-OP status and reasoning-wire-facts sinks. Both arms obey the same law, whichever one the caller uses.
75
+ *
76
+ * The shields: a derived call fires inside the leg's `runWithStatusSink` scope (the compaction hook from `turn_boundary`
77
+ * within `harness.prompt`, the advisor from a tool call), so a 429/retry on it must not surface as a `status` event on the
78
+ * user's turn (status-sink.ts / TaskEvent.status), and its model, tier and output cap must not restate the leg's reasoning
79
+ * posture from a request the leg's caller never made — a no-op inner scope swallows the facts rather than consuming the
80
+ * leg's one correction.
81
+ *
82
+ * `complete` is ALWAYS provided (brainToRuntime prefers it), so the booking is awaited INLINE on both the native-complete and
83
+ * derived-from-stream paths, and the message is returned UNCHANGED (its `errorKind` is what the summary path's
84
+ * budget-escalation recovery reads). `stream` opens the inner stream inside the same scopes (the provider work it starts runs
85
+ * in them) and books the stream's final message when it settles: the inner `result()` settles once, whether the caller awaits
86
+ * it or only iterates, and the returned stream's `result()` is that booked settlement — a booking that throws rejects it rather
87
+ * than vanishing. A stream that ends without a final message books nothing; its caller owes the lower-bound mark. `brainOf`
88
+ * is read per call (a swapped deployment brain reaches legs already running).
89
+ */
90
+ export declare function derivedLegBrain(brainOf: () => Brain, lane: SideCallLane, book: SideCallBook): Brain;
67
91
  /** The leg's door: `recordSideCallUsage` bound to the leg's `stats` and account, reading what the reply itself says (its marks, and who served it). */
68
92
  export declare function sideCallBookOf(stats: Stats, account: SideCallAccount): SideCallBook;
@@ -1,4 +1,5 @@
1
1
  import { readDegradation } from "../../brain/degrading.js";
2
+ import { runWithReasoningWireFacts, runWithStatusSink } from "../../brain/status-sink.js";
2
3
  import { isModelPriced, modelCostToPricing } from "../pricing.js";
3
4
  import { emitTrace } from "../trace.js";
4
5
  import { cacheFamilyOf, usageCostMicroUsd } from "./usage-accounting.js";
@@ -6,6 +7,7 @@ export const SIDE_CALL_LANE_TOTAL = {
6
7
  compaction: "compactionMicroUsd",
7
8
  classifier: "sideCallMicroUsd",
8
9
  mod: "sideCallMicroUsd",
10
+ advisor: "sideCallMicroUsd",
9
11
  };
10
12
  function catalogModel(id, catalog) {
11
13
  if (catalog === undefined)
@@ -41,12 +43,32 @@ export function recordSideCallUsage(stats, usage, lane, call) {
41
43
  const total = SIDE_CALL_LANE_TOTAL[lane];
42
44
  stats[total] = (stats[total] ?? 0) + costMicroUsd;
43
45
  emitTrace(account.telemetry.tracer, () => ({
44
- kind: "brain.call", version: 1, taskId: account.telemetry.taskId, model: modelId, ...(served !== undefined ? { provider: served.provider } : {}),
46
+ kind: "brain.call", version: 1, taskId: account.telemetry.taskId, model: modelId, lane, ...(served !== undefined ? { provider: served.provider } : {}),
45
47
  promptTokens: uncachedInputTokens, totalInputTokens, completionTokens: usage.output || 0,
46
48
  cacheRead: usage.cacheRead || 0, cacheWrite: usage.cacheWrite || 0,
47
49
  latencyMs: 0, ...(priced ? { costMicroUsd } : {}), ...(call.stopReason !== undefined ? { stopReason: call.stopReason } : {}), ts: Date.now(),
48
50
  }));
49
51
  }
52
+ export function derivedLegBrain(brainOf, lane, book) {
53
+ const shielded = (fn) => runWithStatusSink(() => { }, async () => await runWithReasoningWireFacts(() => { }, fn));
54
+ return {
55
+ stream: (m, c, o) => shielded(async () => {
56
+ const inner = await Promise.resolve(brainOf().stream(m, c, o));
57
+ const booked = inner.result().then((msg) => {
58
+ book(lane, m, msg);
59
+ return msg;
60
+ });
61
+ booked.catch(() => { });
62
+ return { [Symbol.asyncIterator]: () => inner[Symbol.asyncIterator](), result: () => booked };
63
+ }),
64
+ complete: async (m, c, o) => {
65
+ const brain = brainOf();
66
+ const msg = await shielded(async () => (brain.complete ? await brain.complete(m, c, o) : await (await Promise.resolve(brain.stream(m, c, o))).result()));
67
+ book(lane, m, msg);
68
+ return msg;
69
+ },
70
+ };
71
+ }
50
72
  export function sideCallBookOf(stats, account) {
51
73
  return (lane, model, reply) => {
52
74
  const degradedTo = readDegradation(reply)?.to;
@@ -26,7 +26,7 @@ export type CompiledOutputSchema =
26
26
  fallbackReason: string;
27
27
  };
28
28
  /**
29
- * Validate + strict-derive a structured-output schema (CC 2.1.205 semantics):
29
+ * Validate + strict-derive a structured-output schema:
30
30
  * invalid / oversized schema → `{error}` (the caller throws — no silent acceptance);
31
31
  * in-subset schema → `{modelSchema: strictForm, strict:true}` (`additionalProperties:false` stamped);
32
32
  * valid-but-unsupported schema → `{modelSchema: original, strict:false, fallbackReason}` (observable).
@@ -6,7 +6,7 @@ import { ENGINE_TOOLS } from "../tool-catalog-entries.js";
6
6
  import { callerToolNameProblem } from "../caller-tool-name.js";
7
7
  import { mintNamespacePrefix } from "../protocol-naming.js";
8
8
  import { PROTOCOL_TABLE, protocolOf } from "../protocol-table.js";
9
- import { mountedToolNames, splitNamespacedName } from "../tool-name-aliases.js";
9
+ import { mountedToolNames, splitNamespacedName, wholeProtocolOf } from "../tool-name-aliases.js";
10
10
  import { projectionToolNames } from "../tool-policy.js";
11
11
  import { declaredDelegationNameOf } from "../delegation-name.js";
12
12
  export function renamedDelegationMountSentence(...rosters) {
@@ -117,10 +117,11 @@ function judgeToolNameList(where, side, value, universe, advise, code) {
117
117
  const content = side === "denied" && written;
118
118
  const reach = side === "denied" ? readDeniedToolList([entry]) : (readAllowedToolList([entry]) ?? readDeniedToolList([]));
119
119
  const split = splitNamespacedName(name);
120
- if (split !== undefined && split.peer === "*" && split.tool === undefined) {
120
+ const whole = wholeProtocolOf(name);
121
+ if (whole !== undefined) {
121
122
  if (side === "denied")
122
123
  continue;
123
- throw refused(`${where} declares ${renderListEntry(entry)} in its ${LIST_WORD[side]}: an allowed list has no protocol-wide form — name a peer (\`${split.ns.prefix}<peer>\`) or its tools.`, code, "unsupported_pattern");
124
+ throw refused(`${where} declares ${renderListEntry(entry)} in its ${LIST_WORD[side]}: an allowed list has no protocol-wide form — name a peer (\`${whole.prefix}<peer>\`) or one of its tools (\`${whole.prefix}<peer>__<tool>\`).`, code, "unsupported_pattern");
124
125
  }
125
126
  const { inert } = compileAllowList([toolName], "deny", universe.known);
126
127
  const flaw = inert[0] === undefined ? undefined : { ...inert[0], entry, ...(inert[0].reason === "near_miss" && inert[0].currentName !== undefined ? { carriedBy: universe.carrierOf(inert[0].currentName) } : {}) };
@@ -3,12 +3,9 @@ import type { AgentTool } from "../../internal/harness-types.js";
3
3
  import type { TerminalBlockedDetail } from "../terminal-cause.js";
4
4
  import { type ResolvedSkillListingBudget } from "../skill-listing-budget.js";
5
5
  import { type SkillGrantTable } from "../skill-grant.js";
6
- /** Reserved name of the injected structured-output tool (CC 2.1.187 `StructuredOutput`; batch-A rename — old
7
- * "submit_output" is canonicalized for pre-rename durable state). */
8
- export declare const OUTPUT_TOOL_NAME = "StructuredOutput";
9
6
  /** Reserved name of the injected blocked-report signal tool (PascalCase: `report_blocked`→`ReportBlocked`). */
10
7
  export declare const REPORT_BLOCKED_TOOL_NAME = "ReportBlocked";
11
- /** Name of the injected code-review findings echo tool (CC 2.1.207 parity — 锚 pretty.js:361412 `BCe`). */
8
+ /** Name of the injected code-review findings echo tool. */
12
9
  export declare const REPORT_FINDINGS_TOOL_NAME = "ReportFindings";
13
10
  /** Default `submit_output` retries (council OS3); total attempts = retries + 1. Overridable via `TaskSpec.outputRetries`. */
14
11
  export declare const OUTPUT_DEFAULT_RETRIES = 2;
@@ -32,7 +29,7 @@ export interface OutputRef {
32
29
  set?: boolean;
33
30
  }
34
31
  /**
35
- * @param strictSchema CC 2.1.205 parity (strict-output-schema.ts): the STRICT derivation of `schema` when
32
+ * @param strictSchema (strict-output-schema.ts): the STRICT derivation of `schema` when
36
33
  * it converted (`additionalProperties:false` stamped, subset-validated). It becomes the tool's
37
34
  * `parameters` — both the model-visible wire schema (CC sends it as `strictInputJSONSchema`) and the
38
35
  * validation schema (the strict form only TIGHTENS the caller's schema, so anything it accepts is valid
@@ -41,7 +38,7 @@ export interface OutputRef {
41
38
  */
42
39
  export declare function createOutputTool(ref: OutputRef, schema: TSchema, strictSchema?: TSchema): AgentTool;
43
40
  export declare function createReportBlockedTool(ref: BlockedRef): AgentTool;
44
- /** One reported finding (the CC 207 wire shape — see {@link createReportFindingsTool}). */
41
+ /** One reported finding (the wire shape — see {@link createReportFindingsTool}). */
45
42
  export interface ReportedFinding {
46
43
  file: string;
47
44
  line?: number;
@@ -51,12 +48,12 @@ export interface ReportedFinding {
51
48
  verdict?: "CONFIRMED" | "PLAUSIBLE";
52
49
  outcome?: "fixed" | "skipped" | "no_change_needed";
53
50
  }
54
- /** Build the injected `ReportFindings` echo tool (CC 2.1.207 parity — description verbatim from 锚
55
- * pretty.js:361413; `effect: "read"` mirrors CC `isReadOnly()`/`isConcurrencySafe()` → parallel-safe). */
51
+ /** Build the injected `ReportFindings` echo tool (
52
+ * `effect: "read"` mirrors CC `isReadOnly()`/`isConcurrencySafe()` → parallel-safe). */
56
53
  export declare function createReportFindingsTool(): AgentTool;
57
54
  /** Reserved name of the injected skill-loading tool (present only when `spec.skills` is non-empty). */
58
55
  export declare const SKILL_TOOL_NAME = "Skill";
59
- /** Per-skill LOAD gate on `SkillSpec.content` (CC 2.1.207 parity: CC's only invoke-time size door is a 1MB file-load gate — an over-limit skill is REJECTED
56
+ /** Per-skill LOAD gate on `SkillSpec.content` (the reference's only invoke-time size door is a 1MB file-load gate — an over-limit skill is REJECTED
60
57
  * WHOLE, never truncated, and the invoked body enters context untruncated). Sema skills are spec-supplied, so the equivalent gate sits at spec assembly:
61
58
  * an oversized skill is excluded from the disclosure block and the tool, with an operator-visible config error. The compaction-time retention caps are a
62
59
  * different door, deliberately. */
@@ -97,8 +94,8 @@ export interface SkillListingEntry {
97
94
  * their descriptions when the block overflows its byte budget ({@link buildSkillsBlock} tier B); the
98
95
  * DISPLAY order stays name-sorted, so adding this never moves a line.
99
96
  *
100
- * Why declaration order: CC 220's `sbs` (@317547) takes a priority function and is called with
101
- * `uNt(name)` (@608552 → @402383) = usage count decayed by recency of last use, and additionally
97
+ * Why declaration order: the reference takes a priority function and is called with
98
+ * a usage count decayed by recency of last use, and additionally
102
99
  * pins every `bundled` skill's description unconditionally. Core has NEITHER axis — no cross-session
103
100
  * skill-usage store, and no bundled/user distinction (every skill arrives through the same
104
101
  * caller-supplied `TaskSpec.skills`). Declaration order is the one priority statement the deployment
@@ -140,7 +137,7 @@ export declare function buildSkillsBlock(skills: ReadonlyArray<SkillListingEntry
140
137
  /** Render the `<skills>` disclosure block (metadata only — bodies stay behind the tool).
141
138
  * [c209-C] REVERSAL: no longer composed into the stable system prompt — this is now the RENDERER for
142
139
  * the `skills_listing` initial frame (first-user-turn reminder / boundary re-announce), so the
143
- * cached prefix carries zero skill bytes (design/C §2.3; CC 209 classic ships the same listing as a
140
+ * cached prefix carries zero skill bytes (design/C §2.3; the reference ships the same listing as a
144
141
  * first-turn reminder). `budget` absent ⇒ the seat reader's no-knob answer ({@link SKILL_LISTING_DEFAULT_BUDGET}).
145
142
  *
146
143
  * The fence and its four header lines are this lane's frame; the budget arithmetic and the three
@@ -157,7 +154,7 @@ export declare function renderSkillsBlock(skills: ReadonlyArray<SkillListingEntr
157
154
  * reader resolved (`@contract skills.listing_budget_enforced_as_declared`), which is the frame's whole
158
155
  * bound: the listing is an intact-class attachment, so no delivery lane measures it a second time.
159
156
  *
160
- * Tier B follows CC 220 `sbs` @317547-317586 (reserve the marker + every name-only line, then spend
157
+ * Tier B follows the reference (reserve the marker + every name-only line, then spend
161
158
  * the slack on descriptions in {@link SkillListingEntry.declaredRank} order); tier C closes with an
162
159
  * honest `(… +N more skills …)` count line — the tool still serves all of them.
163
160
  */
@@ -3,11 +3,10 @@ import { defineTool } from "../tools.js";
3
3
  import { sanitizeUntrustedText, SHELLED_BODY_ENVELOPE_TAGS } from "../untrusted-text.js";
4
4
  import { SKILL_LISTING_DEFAULT_BUDGET, SKILL_LISTING_DESC_MAX_CHARS_DEFAULT } from "../skill-listing-budget.js";
5
5
  import { readSkillTable, skillNamedBy } from "../skill-grant.js";
6
- import { toolFace } from "../tool-catalog-entries.js";
6
+ import { OUTPUT_TOOL_NAME, mountRuleFace, toolFace } from "../tool-catalog-entries.js";
7
7
  import { substituteSkillRoot, substituteSkillRootBounded } from "./skill-base-dir.js";
8
8
  import { readSkillsSeat } from "./skills-seat.js";
9
9
  import { foldListingWithin } from "./listing-fold.js";
10
- export const OUTPUT_TOOL_NAME = "StructuredOutput";
11
10
  export const REPORT_BLOCKED_TOOL_NAME = "ReportBlocked";
12
11
  export const REPORT_FINDINGS_TOOL_NAME = "ReportFindings";
13
12
  export const OUTPUT_DEFAULT_RETRIES = 2;
@@ -36,6 +35,7 @@ export function createReportBlockedTool(ref) {
36
35
  return defineTool({
37
36
  name: REPORT_BLOCKED_TOOL_NAME,
38
37
  ...toolFace("report-blocked"),
38
+ ruleFace: mountRuleFace("report-blocked"),
39
39
  description: "Call this ONLY when you cannot complete the task — missing information, missing permission/credentials, or an ambiguous request you cannot resolve. Provide a concise reason that an external system or operator can act on. Calling this ends the task.",
40
40
  parameters: Type.Object({ reason: Type.String() }),
41
41
  execute: (args) => {
@@ -64,6 +64,7 @@ export function createReportFindingsTool() {
64
64
  return defineTool({
65
65
  name: REPORT_FINDINGS_TOOL_NAME,
66
66
  ...toolFace("report-findings"),
67
+ ruleFace: mountRuleFace("report-findings"),
67
68
  description: "Report code-review findings as a typed list so the host UI can render them. Use this only when the " +
68
69
  "active code-review instructions tell you to report findings with this tool; otherwise follow whatever " +
69
70
  "output format those instructions specify. When reporting a review's results, call it once with the " +
@@ -155,6 +156,7 @@ export function createSkillTool(skills, grants) {
155
156
  return defineTool({
156
157
  name: SKILL_TOOL_NAME,
157
158
  ...toolFace("skill"),
159
+ ruleFace: mountRuleFace("skill"),
158
160
  executionMode: "sequential",
159
161
  description: `Invoke a skill.\n\n` +
160
162
  `A skill is a packaged set of instructions the user or project has set up for a particular kind of task (deploy steps, a review checklist, a repo-specific workflow). ` +
@@ -2,7 +2,7 @@ import { Type } from "typebox";
2
2
  import { Value } from "typebox/value";
3
3
  import { defineTool, errorResult } from "../tools.js";
4
4
  import { formatZodValidationError, truncateError } from "../tool-errors.js";
5
- import { toolFace } from "../tool-catalog-entries.js";
5
+ import { mountRuleFace, toolFace } from "../tool-catalog-entries.js";
6
6
  export const TOOL_SEARCH_NAME = "ToolSearch";
7
7
  export const TOOL_SEARCH_DEFAULT_MAX_RESULTS = 5;
8
8
  const MAX_QUERY_RESULTS = 25;
@@ -262,6 +262,7 @@ export function createToolSearchTool(opts) {
262
262
  return defineTool({
263
263
  name: TOOL_SEARCH_NAME,
264
264
  ...toolFace("tool-search"),
265
+ ruleFace: mountRuleFace("tool-search"),
265
266
  description: "Discover and activate deferred tools. " +
266
267
  activationPosture +
267
268
  "Query forms: " +
@@ -2,7 +2,8 @@
2
2
  * The MCP `toolFaces` OVERLAY: a deployment's per-tool face declaration for a
3
3
  * protocol tool that has no `ToolSpec` of its own (`McpServerSpec.toolFaces`, keyed by the server's RAW
4
4
  * tool name like `allowTools` / `toolAxes`). Validated against the MATERIALIZED schema at every listing
5
- * (the first mount and every RefreshMcpTools): `pathTarget.param` must be a top-level property; an
5
+ * (the first mount and every RefreshMcpTools): `pathTarget.param` / `hostTarget.param` must be a top-level property (and a
6
+ * face declares at most one of the two); an
6
7
  * `approvalCard` must find the keys the card needs; a `ruleFace` may only name scalar keys; `family`
7
8
  * must be a member of the closed set; every `resultCards` entry must live under the tool's own card namespace.
8
9
  * A failing overlay does NOT mount — the tool mounts BARE (no
@@ -2,7 +2,7 @@ import { MCP_NAMESPACE } from "../protocol-table.js";
2
2
  import { mintNamespacePrefix } from "../protocol-naming.js";
3
3
  import { RESERVED_APPROVAL_CARDS, TOOL_APPROVAL_CARDS, TOOL_FAMILIES, TOOL_PATH_ABSENCES, TOOL_PATH_ACCESSES, TOOL_PATH_BASES, RENDER_HINT_ACTIVITY_MAX_CHARS, RENDER_HINT_MAX_CHARS, RENDER_HINT_MAX_LIST, TOOL_KEY_MAX_CHARS, } from "../tool-face.js";
4
4
  import { engineCardOf, inputKeysOf, offendingResultCard, protocolToolOf, rosterCardId } from "../tool-roster.js";
5
- import { engineCardTypes } from "../tool-registry.js";
5
+ import { engineCardTypes, hostTargetingToolNames } from "../tool-registry.js";
6
6
  import { deliverEngineNotice } from "../engine-notice.js";
7
7
  export const APPROVAL_CARD_REQUIRED_KEYS = Object.freeze({
8
8
  "file-edit": ["file_path"],
@@ -10,6 +10,8 @@ export const APPROVAL_CARD_REQUIRED_KEYS = Object.freeze({
10
10
  "notebook-edit": ["notebook_path"],
11
11
  shell: ["command"],
12
12
  fetch: ["url"],
13
+ skill: ["skill"],
14
+ workflow: [],
13
15
  plan: [],
14
16
  question: [],
15
17
  generic: [],
@@ -58,6 +60,19 @@ export function faceProblem(face, schema, tool) {
58
60
  for (const a of face.pathTarget.aliases ?? [])
59
61
  vocabulary.add(a);
60
62
  }
63
+ if (face.hostTarget !== undefined) {
64
+ const hostNames = hostTargetingToolNames();
65
+ if (tool === undefined || !hostNames.has(tool.toolName)) {
66
+ return `hostTarget is declared on a tool whose name host rules are not written for (they are written for ${[...hostNames].join(", ")}) — a host rule's grammar belongs to the rule's tool name, so the slot would never be read; declare it only on a tool of that name`;
67
+ }
68
+ if (face.pathTarget !== undefined)
69
+ return `hostTarget and pathTarget are both declared — a face names one protected target, the URL a call reaches or the path it touches`;
70
+ if (top !== undefined && (typeof face.hostTarget.param !== "string" || !top.has(face.hostTarget.param)))
71
+ return `hostTarget.param ${JSON.stringify(face.hostTarget.param)} is not a top-level property of the tool's schema`;
72
+ const long = overlong("hostTarget.param", [face.hostTarget.param]);
73
+ if (long !== undefined)
74
+ return long;
75
+ }
61
76
  const hints = face.renderHints;
62
77
  if (hints !== undefined) {
63
78
  const card = hints.approvalCard;
@@ -148,6 +163,7 @@ export function applyMcpToolFaces(input) {
148
163
  ...t,
149
164
  ...(f.family !== undefined ? { family: f.family } : {}),
150
165
  ...(f.pathTarget !== undefined ? { pathTarget: f.pathTarget } : {}),
166
+ ...(f.hostTarget !== undefined ? { hostTarget: f.hostTarget } : {}),
151
167
  ...(f.renderHints !== undefined ? { renderHints: f.renderHints } : {}),
152
168
  ...(f.ruleFace !== undefined ? { ruleFace: f.ruleFace } : {}),
153
169
  };
@@ -37,8 +37,8 @@
37
37
  import type { TaskEvent, TaskEventIdentity } from "../types.js";
38
38
  import type { ToolProgressLane } from "./contracts.js";
39
39
  import { type ToolOccurrenceTable } from "./tool-occurrence.js";
40
- /** How long a tool call may stay silent before this lane beats for it, in ms. ONE SOURCE, and CC
41
- * 2.1.259's own per-tool heartbeat interval (`Cct`) — this engine keeps the cadence and folds the beat
40
+ /** How long a tool call may stay silent before this lane beats for it, in ms. ONE SOURCE, and the reference's
41
+ * own per-tool heartbeat interval — this engine keeps the cadence and folds the beat
42
42
  * into the one progress frame instead of minting a second shape (registered divergence). */
43
43
  export declare const TOOL_HEARTBEAT_MS = 30000;
44
44
  /** The floor between two frames of ONE call — the `tool_progress.cadence` contract, enforced here and