@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
@@ -8,6 +8,7 @@ import { errorResultMediaNote, IMAGE_OMITTED_NO_VISION, imagesOmittedNoVisionNot
8
8
  import { OUTPUT_CAP_KEYS, RESPONSES_RESERVED, applyExtraBody, effectiveOutputCap, headerBagOnce, lockHeader, mergeHeaders } from "./request-params.js";
9
9
  import { admitRouteRequest, applyRouteCredentialHeaders, assertServableRequestRoot, brainConfigSnapshot, createBrainRouteJudge, joinRequestUrl, resolveRequestRootOf, resolveRouteCredential } from "./route-adjudicator.js";
10
10
  import { requestRouteOf } from "./request-route.js";
11
+ import { NAMES_AS_WRITTEN, resolveProviderDialect, endpointToolNames } from "./provider-dialect.js";
11
12
  import { declaredOffSpelling, mintEffortWireValue, reasoningRequestCarried } from "./reasoning.js";
12
13
  import { runStreamingBrain } from "./stream-engine.js";
13
14
  import { refuseRetiredTimeoutKnobs } from "./timeout.js";
@@ -64,7 +65,7 @@ function toUserParts(content, supportsVision) {
64
65
  parts.push({ type: "input_text", text: imagesOmittedNoVisionNote(images.length) });
65
66
  return parts;
66
67
  }
67
- function toResponsesInput(ctx, model, replayReasoning) {
68
+ function toResponsesInput(ctx, model, replayReasoning, toolNames) {
68
69
  const supportsVision = modelSupportsVision(model);
69
70
  const out = [];
70
71
  let pendingImages = [];
@@ -116,7 +117,7 @@ function toResponsesInput(ctx, model, replayReasoning) {
116
117
  if (text !== "")
117
118
  out.push({ type: "message", role: "assistant", content: [{ type: "output_text", text }] });
118
119
  for (const tc of toolCalls) {
119
- out.push({ type: "function_call", call_id: providerToolCallId(tc), name: tc.name, arguments: JSON.stringify(tc.arguments ?? {}) });
120
+ out.push({ type: "function_call", call_id: providerToolCallId(tc), name: toolNames.sent(tc.name), arguments: JSON.stringify(tc.arguments ?? {}) });
120
121
  }
121
122
  }
122
123
  else if (m.role === "toolResult") {
@@ -145,12 +146,12 @@ function toResponsesInput(ctx, model, replayReasoning) {
145
146
  flushImages();
146
147
  return out;
147
148
  }
148
- function toResponsesTools(ctx) {
149
+ function toResponsesTools(ctx, toolNames) {
149
150
  if (!ctx.tools || ctx.tools.length === 0)
150
151
  return undefined;
151
152
  return ctx.tools.map((t) => ({
152
153
  type: "function",
153
- name: t.name,
154
+ name: toolNames.sent(t.name),
154
155
  description: t.description,
155
156
  parameters: t.parameters,
156
157
  strict: false,
@@ -231,6 +232,7 @@ export function createOpenResponsesBrain(given = {}) {
231
232
  let sentEffort;
232
233
  let builtMaxTokens;
233
234
  let builtMaxTokensLane = "unset";
235
+ let sentToolNames = NAMES_AS_WRITTEN;
234
236
  return runStreamingBrain({
235
237
  model,
236
238
  doFetch,
@@ -245,6 +247,8 @@ export function createOpenResponsesBrain(given = {}) {
245
247
  if (!root) {
246
248
  throw new Error("createOpenResponsesBrain: no baseUrl configured (set config.baseUrl or model.baseUrl)");
247
249
  }
250
+ const url = joinRequestUrl(root, "/responses");
251
+ const builtToolNames = endpointToolNames(resolveProviderDialect(url, model.api), model.api, (context.tools ?? []).map((t) => t.name));
248
252
  const modelHeaders = headerBagOnce(model.headers);
249
253
  const optionsHeaders = headerBagOnce(options?.headers);
250
254
  const routeCredential = resolveRouteCredential({
@@ -265,12 +269,12 @@ export function createOpenResponsesBrain(given = {}) {
265
269
  const effort = resolveWireEffort(model, options?.reasoning);
266
270
  const body = {
267
271
  model: model.id,
268
- input: toResponsesInput(context, model, config.replayReasoning !== false),
272
+ input: toResponsesInput(context, model, config.replayReasoning !== false, builtToolNames),
269
273
  stream: true,
270
274
  };
271
275
  if (context.systemPrompt)
272
276
  body.instructions = context.systemPrompt;
273
- const tools = toResponsesTools(context);
277
+ const tools = toResponsesTools(context, builtToolNames);
274
278
  if (tools)
275
279
  body.tools = tools;
276
280
  if (options?.temperature !== undefined)
@@ -293,9 +297,9 @@ export function createOpenResponsesBrain(given = {}) {
293
297
  lockHeader(headers, "content-type", "application/json");
294
298
  if (apiKey)
295
299
  lockHeader(headers, OPEN_RESPONSES_KEY_HEADER, `Bearer ${apiKey}`);
296
- const { body: wire, dropped: extraBodyDropped } = applyExtraBody(body, model.extraBody, RESPONSES_RESERVED);
300
+ const { body: wire, dropped: extraBodyDropped } = applyExtraBody(body, model, RESPONSES_RESERVED);
297
301
  return {
298
- url: joinRequestUrl(root, "/responses"),
302
+ url,
299
303
  headers,
300
304
  body: JSON.stringify(wire),
301
305
  extraBodyDropped,
@@ -307,6 +311,7 @@ export function createOpenResponsesBrain(given = {}) {
307
311
  sentMaxTokens = builtMaxTokens;
308
312
  sentMaxTokensLane = builtMaxTokensLane;
309
313
  sentEffort = effort;
314
+ sentToolNames = builtToolNames;
310
315
  },
311
316
  };
312
317
  },
@@ -457,7 +462,7 @@ export function createOpenResponsesBrain(given = {}) {
457
462
  else if (itemType === "function_call") {
458
463
  const acc = openItem(index, "function_call", itemId);
459
464
  acc.callId = frame.item?.call_id ?? "";
460
- acc.name = frame.item?.name ?? "";
465
+ acc.name = sentToolNames.called(frame.item?.name ?? "");
461
466
  if (frame.item?.arguments)
462
467
  acc.args += frame.item.arguments;
463
468
  }
@@ -546,7 +551,7 @@ export function createOpenResponsesBrain(given = {}) {
546
551
  if (!acc.callId && frame.item?.call_id)
547
552
  acc.callId = frame.item.call_id;
548
553
  if (!acc.name && frame.item?.name)
549
- acc.name = frame.item.name;
554
+ acc.name = sentToolNames.called(frame.item.name);
550
555
  if (acc.args === "" && frame.item?.arguments)
551
556
  acc.args = frame.item.arguments;
552
557
  }
@@ -7,7 +7,7 @@ import { emitBrainTelemetry } from "./status-sink.js";
7
7
  import { errorResultMediaNote, IMAGE_OMITTED_NO_VISION, imagesOmittedNoVisionNote, modelSupportsVision, sendableImages } from "./media-degrade.js";
8
8
  import { OPENAI_RESERVED, OUTPUT_CAP_KEYS, applyExtraBody, effectiveOutputCap, headerBagOnce, lockHeader, mergeHeaders } from "./request-params.js";
9
9
  import { BrainError, providerErrorWord } from "./errors.js";
10
- import { inBandProviderError } from "./provider-dialect.js";
10
+ import { NAMES_AS_WRITTEN, inBandProviderError, resolveProviderDialect, endpointToolNames } from "./provider-dialect.js";
11
11
  import { admitRouteRequest, applyRouteCredentialHeaders, assertServableRequestRoot, brainConfigSnapshot, createBrainRouteJudge, joinRequestUrl, resolveRequestRootOf, resolveRouteCredential } from "./route-adjudicator.js";
12
12
  import { requestRouteOf } from "./request-route.js";
13
13
  import { declaredOffSpelling, mintEffortWireValue, reasoningRequestCarried } from "./reasoning.js";
@@ -155,7 +155,7 @@ function applyThinking(body, model, reasoning) {
155
155
  }
156
156
  }
157
157
  }
158
- function toOpenAIMessages(ctx, replayThinking = true, model) {
158
+ function toOpenAIMessages(ctx, replayThinking = true, model, toolNames) {
159
159
  const supportsVision = modelSupportsVision(model);
160
160
  const out = [];
161
161
  const needsEmptyReasoningField = !!model?.reasoning && thinkingCompat(model).requiresReasoningContentOnAssistantMessages === true;
@@ -206,7 +206,7 @@ function toOpenAIMessages(ctx, replayThinking = true, model) {
206
206
  msg.tool_calls = toolCalls.map((tc) => ({
207
207
  id: providerToolCallId(tc),
208
208
  type: "function",
209
- function: { name: tc.name, arguments: JSON.stringify(tc.arguments ?? {}) },
209
+ function: { name: toolNames.sent(tc.name), arguments: JSON.stringify(tc.arguments ?? {}) },
210
210
  }));
211
211
  }
212
212
  out.push(msg);
@@ -244,13 +244,13 @@ function toolResultText(text, hasCarriedImages, original) {
244
244
  return "(image attached below)";
245
245
  return Array.isArray(original) && original.length > 0 ? "(non-text tool result omitted)" : "";
246
246
  }
247
- function toOpenAITools(ctx) {
247
+ function toOpenAITools(ctx, toolNames) {
248
248
  if (!ctx.tools || ctx.tools.length === 0) {
249
249
  return undefined;
250
250
  }
251
251
  return ctx.tools.map((t) => ({
252
252
  type: "function",
253
- function: { name: t.name, description: t.description, parameters: t.parameters },
253
+ function: { name: toolNames.sent(t.name), description: t.description, parameters: t.parameters },
254
254
  }));
255
255
  }
256
256
  const FINISH_REASON_READINGS = Object.freeze({
@@ -334,6 +334,7 @@ export function createOpenAIBrain(given = {}) {
334
334
  let sentMaxTokensLane = "unset";
335
335
  let builtMaxTokens;
336
336
  let builtMaxTokensLane = "unset";
337
+ let sentToolNames = NAMES_AS_WRITTEN;
337
338
  return runStreamingBrain({
338
339
  model,
339
340
  doFetch,
@@ -348,6 +349,8 @@ export function createOpenAIBrain(given = {}) {
348
349
  if (!root) {
349
350
  throw new Error("createOpenAIBrain: no baseUrl configured (set config.baseUrl or model.baseUrl)");
350
351
  }
352
+ const url = joinRequestUrl(root, "/chat/completions");
353
+ const builtToolNames = endpointToolNames(resolveProviderDialect(url, model.api), model.api, (context.tools ?? []).map((t) => t.name));
351
354
  const modelHeaders = headerBagOnce(model.headers);
352
355
  const optionsHeaders = headerBagOnce(options?.headers);
353
356
  const routeCredential = resolveRouteCredential({
@@ -362,11 +365,11 @@ export function createOpenAIBrain(given = {}) {
362
365
  const apiKey = routeCredential.apiKey;
363
366
  const body = {
364
367
  model: model.id,
365
- messages: toOpenAIMessages(context, config.replayThinking, model),
368
+ messages: toOpenAIMessages(context, config.replayThinking, model, builtToolNames),
366
369
  stream: true,
367
370
  stream_options: { include_usage: true },
368
371
  };
369
- const tools = toOpenAITools(context);
372
+ const tools = toOpenAITools(context, builtToolNames);
370
373
  if (tools)
371
374
  body.tools = tools;
372
375
  if (options?.temperature !== undefined)
@@ -393,9 +396,9 @@ export function createOpenAIBrain(given = {}) {
393
396
  lockHeader(headers, "content-type", "application/json");
394
397
  if (apiKey)
395
398
  lockHeader(headers, OPENAI_KEY_HEADER, `Bearer ${apiKey}`);
396
- const { body: wire, dropped: extraBodyDropped } = applyExtraBody(body, model.extraBody, OPENAI_RESERVED);
399
+ const { body: wire, dropped: extraBodyDropped } = applyExtraBody(body, model, OPENAI_RESERVED);
397
400
  return {
398
- url: joinRequestUrl(root, "/chat/completions"),
401
+ url,
399
402
  headers,
400
403
  body: JSON.stringify(wire),
401
404
  extraBodyDropped,
@@ -406,6 +409,7 @@ export function createOpenAIBrain(given = {}) {
406
409
  routeAdmission();
407
410
  sentMaxTokens = builtMaxTokens;
408
411
  sentMaxTokensLane = builtMaxTokensLane;
412
+ sentToolNames = builtToolNames;
409
413
  },
410
414
  };
411
415
  },
@@ -577,7 +581,7 @@ export function createOpenAIBrain(given = {}) {
577
581
  if (tc.id)
578
582
  acc.id = tc.id;
579
583
  if (tc.function?.name)
580
- acc.name = tc.function.name;
584
+ acc.name = sentToolNames.called(tc.function.name);
581
585
  if (tc.function?.arguments && !acc.closedTc)
582
586
  acc.args += tc.function.arguments;
583
587
  toolAccum.set(idx, acc);
@@ -619,7 +623,7 @@ export function createOpenAIBrain(given = {}) {
619
623
  }
620
624
  }
621
625
  if (config.repairTextToolCalls && toolCalls.length === 0 && textFace && context.tools && context.tools.length > 0) {
622
- const names = new Set(context.tools.flatMap((t) => [t.name, ...(t.aliases ?? [])]));
626
+ const names = new Set(context.tools.flatMap((t) => [t.name, sentToolNames.sent(t.name), ...(t.aliases ?? [])]));
623
627
  const repaired = repairTextToolCalls(textFace, names);
624
628
  if (repaired.toolCalls.length > 0) {
625
629
  finalContent.length = 0;
@@ -627,7 +631,8 @@ export function createOpenAIBrain(given = {}) {
627
631
  finalContent.push({ type: "thinking", thinking: accumReasoning });
628
632
  if (repaired.cleanedText)
629
633
  finalContent.push({ type: "text", text: repaired.cleanedText });
630
- for (const tc of repaired.toolCalls) {
634
+ for (const repairedCall of repaired.toolCalls) {
635
+ const tc = { ...repairedCall, name: sentToolNames.called(repairedCall.name) };
631
636
  finalContent.push(tc);
632
637
  toolCalls.push(tc);
633
638
  }
@@ -1,6 +1,7 @@
1
1
  /**
2
- * The provider dialect table — what each provider endpoint MEANS by the way it fails, declared once per
3
- * endpoint and read by every seat that reports a provider failure.
2
+ * The provider dialect table — what each provider endpoint MEANS by the way it fails and by the tool names it is
3
+ * sent, declared once per endpoint and read by every seat that reports a provider failure or names a tool on the
4
+ * wire.
4
5
  *
5
6
  * KEY. An endpoint is named by (wire family, host suffix + path): the same brand can serve two endpoints whose
6
7
  * failures read in opposite ways (Moonshot's open platform states an exhausted balance as a 429, its coding
@@ -14,7 +15,9 @@
14
15
  * column: rows that turn a status, the envelope's word (`error.code`, else `error.type` — the same word
15
16
  * `apiErrorCode` carries) and the envelope's sentence (`error.message`) into one {@link ProviderCondition}. The
16
17
  * context-limit refusal is a flag on the same rows (`inputTooLong`), so "this 400 is the input being too long"
17
- * and "this 400 is something else the provider named" are read off one row and cannot disagree.
18
+ * and "this 400 is something else the provider named" are read off one row and cannot disagree. `toolNames` is
19
+ * the tool-name column: names the endpoint gives a meaning of its own on one wire ({@link ToolNameRow}), read by
20
+ * {@link endpointToolNames} — the one projection every brain sends tool names through and reads call names back by.
18
21
  *
19
22
  * ONE VERDICT, TWO SEATS. {@link judgeHttpFailure} answers once per failed response; the retry decision, the
20
23
  * retry frame (`BrainStatus.providerCondition`) and the terminal (`BrainError` → `AssistantMessage` →
@@ -142,11 +145,24 @@ export interface DialectKey {
142
145
  /** A path prefix, matched at a segment boundary. Absent = every path on the host. */
143
146
  readonly path?: string;
144
147
  }
148
+ /**
149
+ * One row of the tool-name column. On `wire`, the endpoint treats a tool sent under `name` as a feature of its own
150
+ * rather than as the tool the request declares, so a tool by that name travels as `sentAs` instead, and a call the
151
+ * model makes to `sentAs` is a call to `name`. The name inside the engine, the prompts that mention it and the
152
+ * tool's parameters do not change; only the spelling on this wire does.
153
+ */
154
+ export interface ToolNameRow {
155
+ readonly wire: Model["api"];
156
+ readonly name: string;
157
+ readonly sentAs: string;
158
+ }
145
159
  /** One endpoint's declared dialect: its key and its columns. */
146
160
  export interface ProviderDialect {
147
161
  readonly name: string;
148
162
  readonly key: DialectKey;
149
163
  readonly failures: readonly FailureRow[];
164
+ /** Absent = the endpoint gives no tool name a meaning of its own: every name travels as written. */
165
+ readonly toolNames?: readonly ToolNameRow[];
150
166
  }
151
167
  /**
152
168
  * The declared dialects. Each row's source is the provider's own error documentation as collected in the
@@ -172,6 +188,26 @@ export declare const GENERIC_FAILURES: readonly FailureRow[];
172
188
  export declare function isTransientStatus(status: number): boolean;
173
189
  /** The endpoint a request went to, or `undefined` when no dialect declares it. */
174
190
  export declare function resolveProviderDialect(url: string, wire: Model["api"]): ProviderDialect | undefined;
191
+ /**
192
+ * How one request's tool names travel. Both halves read the one set the request declares: `sent` spells a declared
193
+ * tool's name, in the tool table and in every replayed call to it; `called` reads a call name the model sends back as
194
+ * the declared tool that travels under it. A name the request does not declare travels and comes back as written —
195
+ * a replayed call to a tool no longer mounted keeps its name, and a model that calls a tool by the name the prompts
196
+ * use still reaches it. A brain builds one with each request and keeps the one the engine commits; its parser reads
197
+ * call names through it.
198
+ */
199
+ export interface EndpointToolNames {
200
+ readonly sent: (name: string) => string;
201
+ readonly called: (sentName: string) => string;
202
+ }
203
+ /** Every name travels as written: the projection of an endpoint whose dialect has no tool-name row on the wire. */
204
+ export declare const NAMES_AS_WRITTEN: EndpointToolNames;
205
+ /**
206
+ * The tool-name projection of one request: the dialect's rows for this wire, applied to the tools the request
207
+ * declares. Two declared tools that would travel under one name are refused before anything is sent — the model
208
+ * could not tell them apart, and neither could the call that comes back.
209
+ */
210
+ export declare function endpointToolNames(dialect: ProviderDialect | undefined, wire: Model["api"], declared: readonly string[]): EndpointToolNames;
175
211
  /** One failure's reading off the table. */
176
212
  export interface ProviderVerdict {
177
213
  readonly condition: ProviderCondition;
@@ -87,6 +87,7 @@ export const PROVIDER_DIALECTS = Object.freeze([
87
87
  { status: [429], word: ["1311", "1313"], condition: "stop_other" },
88
88
  { status: [400], word: ["1261"], condition: "stop_other", inputTooLong: true },
89
89
  ],
90
+ toolNames: [{ wire: ANTHROPIC, name: "ToolSearch", sentAs: "ToolFinder" }],
90
91
  },
91
92
  {
92
93
  name: "openai",
@@ -120,6 +121,33 @@ export function resolveProviderDialect(url, wire) {
120
121
  d.key.hosts.some((h) => host === h || host.endsWith(`.${h}`)) &&
121
122
  (d.key.path === undefined || path === d.key.path || path.startsWith(`${d.key.path}/`)));
122
123
  }
124
+ export const NAMES_AS_WRITTEN = Object.freeze({ sent: (name) => name, called: (sentName) => sentName });
125
+ export function endpointToolNames(dialect, wire, declared) {
126
+ const rows = (dialect?.toolNames ?? []).filter((r) => r.wire === wire);
127
+ if (rows.length === 0)
128
+ return NAMES_AS_WRITTEN;
129
+ const sentAs = new Map(rows.map((r) => [r.name, r.sentAs]));
130
+ const holderOf = new Map();
131
+ const forward = new Map();
132
+ const back = new Map();
133
+ for (const name of new Set(declared)) {
134
+ const onWire = sentAs.get(name) ?? name;
135
+ const holder = holderOf.get(onWire);
136
+ if (holder !== undefined) {
137
+ const moved = rows.filter((r) => r.sentAs === onWire).map((r) => JSON.stringify(r.name)).join(" / ");
138
+ const asWritten = [holder, name].find((n) => n === onWire);
139
+ throw new BrainError("invalid_request", `the request was not sent: the tools ${JSON.stringify(holder)} and ${JSON.stringify(name)} would both travel as ${JSON.stringify(onWire)}. ` +
140
+ `This endpoint gives the tool name ${moved} a meaning of its own on this wire, so a tool by that name is sent as ${JSON.stringify(onWire)}, ` +
141
+ `and two tools cannot share one name on the wire — rename ${asWritten === undefined ? "one of them" : `the tool named ${JSON.stringify(asWritten)}`}.`);
142
+ }
143
+ holderOf.set(onWire, name);
144
+ if (onWire !== name) {
145
+ forward.set(name, onWire);
146
+ back.set(onWire, name);
147
+ }
148
+ }
149
+ return { sent: (name) => forward.get(name) ?? name, called: (sentName) => back.get(sentName) ?? sentName };
150
+ }
123
151
  function statementOf(err) {
124
152
  if (err === undefined)
125
153
  return undefined;
@@ -53,7 +53,7 @@ export declare const DEFAULT_EFFORT_LEVELS: readonly ThinkingLevel[];
53
53
  * here so {@link resolveReasoning} can report ONE endpoint discriminant across both brain families.
54
54
  */
55
55
  export type ReasoningFormat = "openai" | "openrouter" | "deepseek" | "together" | "zai" | "qwen" | "qwen-chat-template" | "budget"
56
- /** Anthropic `output_config.effort` (CC 2.1.198 / Fable-5 class, design/119): the tier is a named
56
+ /** Anthropic `output_config.effort` (Fable-5 class, design/119): the tier is a named
57
57
  * effort string, clamped to `compat.effortLevels` — the anthropic-side twin of the OpenAI
58
58
  * `reasoning_effort` path (thinking FORM is `thinkingMode`; effort carries the intensity). */
59
59
  | "effort"
@@ -1,3 +1,4 @@
1
+ import type { Model } from "../internal/llm.js";
1
2
  /** OpenAI request-body keys core owns; `extraBody` cannot override these. */
2
3
  export declare const OPENAI_RESERVED: ReadonlySet<string>;
3
4
  /** Anthropic request-body keys core owns; `extraBody` cannot override these. (Note the asymmetry vs
@@ -13,17 +14,66 @@ export declare const ANTHROPIC_RESERVED: ReadonlySet<string>;
13
14
  * wire and the drop announced, never a silently server-linked turn.
14
15
  */
15
16
  export declare const RESPONSES_RESERVED: ReadonlySet<string>;
17
+ /** What {@link judgeExtraBody} refuses: the code, the one sentence, and (on `config.invalid_argument`) the member it names.
18
+ * Not an engine notice (a refusal is thrown, never delivered), so it carries none of a notice's members. */
19
+ export interface ExtraBodyRefusal {
20
+ readonly code: "config.invalid_argument" | "config.extra_body_output_cap";
21
+ readonly sentence: string;
22
+ readonly field?: "Model.extraBody";
23
+ }
16
24
  /**
17
- * Merge `extraBody` into a brain's already-built request `body`, dropping any key the brain owns so core
25
+ * {@link judgeExtraBody}'s answer: the refusal, or — admitted — the model's keys as ONE copy (`undefined` when the model
26
+ * carries no `extraBody` at all). The copy is what was judged, and it is what the merge walks: nothing is read from the
27
+ * object a second time.
28
+ */
29
+ export type ExtraBodyVerdict = {
30
+ readonly refused: ExtraBodyRefusal;
31
+ readonly entries?: undefined;
32
+ } | {
33
+ readonly refused?: undefined;
34
+ readonly entries: ReadonlyArray<readonly [string, unknown]> | undefined;
35
+ };
36
+ /**
37
+ * THE admission law for a model's `extraBody`, asked at both seats that can hand a request a model spec: the prepare step
38
+ * (the task's own model, before the session is acquired — a refused request never touches the session) and the request
39
+ * build ({@link applyExtraBody} — a model spec a host brain swapped in for one request, the compaction model, any other
40
+ * call of the leg). One judge, one sentence per refusal, whichever seat asks. Absent is admitted; otherwise the value must
41
+ * be a plain object of request-body keys, and it must not carry `max_completion_tokens`.
42
+ *
43
+ * The keys are read ONCE (`Object.entries`, one walk of the object): the refusal is decided on that copy and an admitted
44
+ * verdict hands the same copy to the merge, so an object that answers differently the second time it is asked (a getter, a
45
+ * Proxy trap) cannot pass one answer and send another.
46
+ *
47
+ * - A value that is not a plain object is refused as `config.invalid_argument` (`detail.field` = `Model.extraBody`). It is
48
+ * never read as keys: a string or an array would spread into the body as numbered keys, a number or `false` would be
49
+ * ignored without a word.
50
+ * - `max_completion_tokens` is refused as `config.extra_body_output_cap` on every wire: it is a spelling of the output cap, and
51
+ * the engine owns the output cap (it writes the per-request cap itself), so a cap is never taken from `extraBody` and the key
52
+ * is refused rather than stripped-and-announced like the keys in a wire's reserved set. On the OpenAI wire the spelling is
53
+ * also one the endpoint reads and the overflow retry lowers (stripping it would silently un-cap a deployment that used it as
54
+ * its only bound; passing it on would let a constant fight the retry); the other two wires' endpoints do not read it, and the
55
+ * refusal was never wire-dependent at the task's own model, so it is not made so here. (The sibling spelling `max_tokens` IS
56
+ * reserved: the adapter always writes it, so a stray copy never survives.)
57
+ *
58
+ * The sentence names the kind of a refused value and reads none of its members: it never echoes the value (an `extraBody`
59
+ * can hold a credential-bearing template).
60
+ */
61
+ export declare function judgeExtraBody(extraBody: unknown, modelId: string): ExtraBodyVerdict;
62
+ /**
63
+ * Merge a model's `extraBody` into a brain's already-built request `body`, dropping any key the brain owns so core
18
64
  * always wins. `body` is a NEW object (passthrough keys first, then core keys) when `extraBody` is set; the
19
65
  * exact `body` reference (no allocation, byte-identical serialization) when it isn't — so an existing
20
66
  * deployment with no `extraBody` is unaffected.
21
67
  *
68
+ * The request seat of {@link judgeExtraBody}: an `extraBody` it refuses ends the build with a `BrainError`
69
+ * (`invalid_request`, the sentence led by the refusal's code — the shape a pre-flight route refusal has) before anything is
70
+ * merged or sent. The three wire adapters reach this function and nothing else; none of them judges the value itself.
71
+ *
22
72
  * `dropped` is the keys of `extraBody` that were stripped, in `extraBody`'s insertion order, names only (a
23
73
  * value never leaves this function except inside `body`). It is a property of the same walk that strips, so
24
74
  * what is said and what is dropped cannot disagree; empty when nothing was stripped.
25
75
  */
26
- export declare function applyExtraBody(body: Record<string, unknown>, extraBody: Record<string, unknown> | undefined, reserved: ReadonlySet<string>): {
76
+ export declare function applyExtraBody(body: Record<string, unknown>, model: Pick<Model, "id" | "extraBody">, reserved: ReadonlySet<string>): {
27
77
  body: Record<string, unknown>;
28
78
  dropped: readonly string[];
29
79
  };
@@ -94,8 +144,8 @@ export declare const OUTPUT_CAP_KEYS: Readonly<Record<"openai" | "anthropic" | "
94
144
  * of the lane's cap keys that is present and usable, or `undefined` when none is.
95
145
  *
96
146
  * Read off the merged body rather than off the knob the adapter set, because those are not the same
97
- * thing: `extraBody` can contribute a cap under a spelling the adapter did not choose, and a
98
- * consumer that treats the adapter's own number as "the cap on the wire" would be wrong about a
99
- * request that carries two. Smallest wins so a consumer reasoning about the bound stays conservative.
147
+ * thing: what is on the wire is the only cap the provider enforces, and the adapter's own number can differ
148
+ * from it (the Anthropic lane raises `max_tokens` to fit a thinking budget). Smallest wins so a consumer
149
+ * reasoning about the bound stays conservative.
100
150
  */
101
151
  export declare function effectiveOutputCap(body: Record<string, unknown>, keys: readonly string[]): number | undefined;
@@ -1,4 +1,6 @@
1
1
  import { isCredentialHeaderName } from "../core/secret-env.js";
2
+ import { isPlainRecord } from "../core/mods/kernel/receive.js";
3
+ import { BrainError } from "./errors.js";
2
4
  export const OPENAI_RESERVED = new Set([
3
5
  "model",
4
6
  "messages",
@@ -40,12 +42,42 @@ export const RESPONSES_RESERVED = new Set([
40
42
  "conversation",
41
43
  ]);
42
44
  const NO_KEYS = Object.freeze([]);
43
- export function applyExtraBody(body, extraBody, reserved) {
44
- if (!extraBody)
45
+ const extraBodyKind = (v) => (v === null ? "null" : Array.isArray(v) ? "an array" : typeof v === "object" ? "an object that is not plain (a class instance, a Map, …)" : `a ${typeof v}`);
46
+ export function judgeExtraBody(extraBody, modelId) {
47
+ if (extraBody === undefined)
48
+ return { entries: undefined };
49
+ const whose = `Model.extraBody of model ${JSON.stringify(modelId)}`;
50
+ if (!isPlainRecord(extraBody)) {
51
+ return {
52
+ refused: {
53
+ code: "config.invalid_argument",
54
+ field: "Model.extraBody",
55
+ sentence: `${whose} is ${extraBodyKind(extraBody)} — it must be a plain object of request-body keys, or absent; any other value is refused rather than spread into the request body as numbered keys or left out without a word. Write a plain object, or remove it.`,
56
+ },
57
+ };
58
+ }
59
+ const entries = Object.entries(extraBody);
60
+ if (entries.some(([k]) => k === "max_completion_tokens")) {
61
+ return {
62
+ refused: {
63
+ code: "config.extra_body_output_cap",
64
+ sentence: `${whose} supplies "max_completion_tokens" — an output-cap spelling the engine owns: it writes the per-request cap ` +
65
+ `itself, so a cap is never taken from extraBody. Set it via limits.maxOutputTokens (per request) or Model.maxTokens; ` +
66
+ `on the OpenAI wire Model.compat.maxTokensField picks the spelling.`,
67
+ },
68
+ };
69
+ }
70
+ return { entries };
71
+ }
72
+ export function applyExtraBody(body, model, reserved) {
73
+ const verdict = judgeExtraBody(model.extraBody, model.id);
74
+ if (verdict.refused !== undefined)
75
+ throw new BrainError("invalid_request", `${verdict.refused.code}: ${verdict.refused.sentence}`);
76
+ if (verdict.entries === undefined)
45
77
  return { body, dropped: NO_KEYS };
46
78
  const passthrough = {};
47
79
  const dropped = [];
48
- for (const [k, v] of Object.entries(extraBody)) {
80
+ for (const [k, v] of verdict.entries) {
49
81
  if (reserved.has(k))
50
82
  dropped.push(k);
51
83
  else
@@ -1,5 +1,5 @@
1
1
  /**
2
- * Transient-failure retry backoff (RB-420-b, CC 2.1.220 parity).
2
+ * Transient-failure retry backoff (RB-420-b).
3
3
  *
4
4
  * The shape is **increasing exponential + light additive jitter**, not full jitter:
5
5
  * `min(base * 2^attempt, 32s)` plus up to 25% of that. Full jitter (`random(0, exp)`) made the Nth
@@ -375,3 +375,18 @@ export declare function unroutableSeatNotice(args: {
375
375
  sessionId?: string;
376
376
  runId?: string;
377
377
  }): EngineNotice;
378
+ /**
379
+ * The third twin, for a seat with nothing to fall back TO and nothing worth keeping (the advisor tool: serving it with
380
+ * the primary model would advise the agent with itself, and keeping it would refuse every call the model makes): the
381
+ * pairing is broken, so the seat is DETACHED for this run — not mounted, no model swapped. Same `detail` keys as
382
+ * {@link unroutableSeatNotice}; `action: "detached"` is the discriminator.
383
+ */
384
+ export declare function seatDetachedNotice(args: {
385
+ seat: string;
386
+ from: string;
387
+ verdict: Extract<RouteAdjudication, {
388
+ ok: false;
389
+ }>;
390
+ sessionId?: string;
391
+ runId?: string;
392
+ }): EngineNotice;
@@ -531,3 +531,18 @@ export function unroutableSeatNotice(args) {
531
531
  },
532
532
  };
533
533
  }
534
+ export function seatDetachedNotice(args) {
535
+ return {
536
+ code: "route.seat_detached",
537
+ message: `derived model "${args.from}" (${args.seat}) is not routable (${args.verdict.code}) — the seat is detached for this run and nothing serves it in its place. ${args.verdict.detail.fixHint}`,
538
+ detail: {
539
+ seat: args.seat,
540
+ from: args.from,
541
+ cause: args.verdict.code,
542
+ fixHint: args.verdict.detail.fixHint,
543
+ action: "detached",
544
+ ...(args.sessionId !== undefined ? { sessionId: args.sessionId } : {}),
545
+ ...(args.runId !== undefined ? { runId: args.runId } : {}),
546
+ },
547
+ };
548
+ }
@@ -1,7 +1,7 @@
1
1
  import { createAssistantMessageEventStream, } from "../internal/llm.js";
2
2
  import { STREAM_TORN_WARNING } from "./stream-shared.js";
3
3
  import { FLOOR_OUTPUT_TOKENS, parseContextOverflow, planOutputCapAdjustment } from "./context-overflow.js";
4
- import { abortLikeName, BrainError, brainErrorCodeOf, classifyFetchThrow, classifyHttp, describeNetworkError, isProviderEchoShape, namesTheFailure, proxyTunnelRefusedSentence, readConnectFailure, readProviderErrorCode, readProviderRequestId, refusedTheRequest } from "./errors.js";
4
+ import { abortLikeName, BrainError, brainErrorCodeOf, classifyFetchThrow, classifyHttp, describeNetworkError, isProviderEchoShape, namesTheFailure, proxyTunnelRefusedSentence, readConnectFailure, readProviderErrorCode, readProviderRequestId, refusedTheRequest, thrownBrainFailure } from "./errors.js";
5
5
  import { stripUrlCredentials } from "./route-adjudicator.js";
6
6
  import { admittedRequestRoute } from "./request-route.js";
7
7
  import { isTransientStatus, isProviderCondition, isProviderConditionSource, judgeHttpFailure, PROVIDER_CONDITION_TRAITS, resolveProviderDialect, } from "./provider-dialect.js";
@@ -314,10 +314,11 @@ export function runStreamingBrain(args) {
314
314
  }
315
315
  errorMsg.stopReason = aborted ? "aborted" : "error";
316
316
  errorMsg.errorMessage = thrownText(err);
317
- if (!aborted && brainErrorCodeOf(err) !== undefined) {
318
- if (readMember(err, "inputTooLong") === true)
319
- errorMsg.errorKind = "input_too_long";
320
- else if (readMember(err, "inputTooLongRuledOut") === true)
317
+ const failure = aborted ? {} : thrownBrainFailure(err);
318
+ if (failure.code !== undefined) {
319
+ if (failure.errorKind !== undefined)
320
+ errorMsg.errorKind = failure.errorKind;
321
+ else if (failure.inputTooLongRuledOut === true)
321
322
  errorMsg.inputTooLongRuledOut = true;
322
323
  if (readMember(err, "errorBodyIncomplete") === true)
323
324
  errorMsg.errorBodyIncomplete = true;
@@ -14,7 +14,7 @@ import { type AssistantMessage, type ModelOutputInvalid, type StreamDropCause }
14
14
  *
15
15
  * Internal module: not re-exported from `src/index.ts`.
16
16
  */
17
- /** The warning (CC 2.1.220's words; gone from 2.1.245 on — 2.1.296 asks for a resume instead) stamped beside `partialFinalized` when a stream ended before its close — by the
17
+ /** The warning (the reference's former words; later replaced by a resume request) stamped beside `partialFinalized` when a stream ended before its close — by the
18
18
  * mid-stream promotion (the body threw) and by the parsers' own finalize (content arrived, no finish frame). */
19
19
  export declare const STREAM_TORN_WARNING = "Connection closed mid-response. The response above may be incomplete.";
20
20
  /** A provider word as a stream-end seat carries it: the word in the provider echo shape, else `?` — the fact that a