@sema-agent/core 7.48.0 → 7.49.1

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 (421) hide show
  1. package/CHANGELOG.md +457 -0
  2. package/README.md +2 -2
  3. package/dist/agents/cascade.d.ts +2 -5
  4. package/dist/agents/child-failure.d.ts +20 -0
  5. package/dist/agents/child-failure.js +28 -0
  6. package/dist/agents/cross-session-ref.d.ts +11 -3
  7. package/dist/agents/cross-session-ref.js +6 -0
  8. package/dist/agents/cumulative-stats.d.ts +12 -15
  9. package/dist/agents/cumulative-stats.js +1 -1
  10. package/dist/agents/extra-tool-names.js +1 -1
  11. package/dist/agents/inherited-tool-pool.d.ts +17 -13
  12. package/dist/agents/inherited-tool-pool.js +4 -3
  13. package/dist/agents/peer-session-drain.d.ts +3 -2
  14. package/dist/agents/peer-session-drain.js +5 -4
  15. package/dist/agents/send-message-tool.js +2 -9
  16. package/dist/agents/subagent.d.ts +10 -29
  17. package/dist/agents/subagent.js +65 -53
  18. package/dist/agents/suspend-guard.d.ts +1 -1
  19. package/dist/agents/tool-filter.d.ts +76 -65
  20. package/dist/agents/tool-filter.js +122 -92
  21. package/dist/agents/verify.d.ts +4 -7
  22. package/dist/agents/verify.js +6 -7
  23. package/dist/bench/metrics.d.ts +1 -2
  24. package/dist/brain/anthropic.js +133 -79
  25. package/dist/brain/errors.d.ts +53 -6
  26. package/dist/brain/errors.js +22 -2
  27. package/dist/brain/input-too-long.d.ts +40 -19
  28. package/dist/brain/input-too-long.js +3 -16
  29. package/dist/brain/open-responses.js +19 -10
  30. package/dist/brain/openai.js +123 -32
  31. package/dist/brain/provider-dialect.d.ts +214 -0
  32. package/dist/brain/provider-dialect.js +186 -0
  33. package/dist/brain/request-params.d.ts +27 -8
  34. package/dist/brain/request-params.js +7 -12
  35. package/dist/brain/request-route.d.ts +84 -0
  36. package/dist/brain/request-route.js +41 -0
  37. package/dist/brain/retry.d.ts +8 -0
  38. package/dist/brain/retry.js +10 -4
  39. package/dist/brain/route-adjudicator.d.ts +7 -0
  40. package/dist/brain/route-adjudicator.js +5 -1
  41. package/dist/brain/status-sink.d.ts +20 -0
  42. package/dist/brain/status-sink.js +11 -0
  43. package/dist/brain/stream-engine.d.ts +52 -1
  44. package/dist/brain/stream-engine.js +81 -24
  45. package/dist/brain/stream-shared.d.ts +57 -11
  46. package/dist/brain/stream-shared.js +28 -2
  47. package/dist/core/a2a.d.ts +1 -0
  48. package/dist/core/agent-config-dir.js +3 -2
  49. package/dist/core/allow-entry.d.ts +21 -12
  50. package/dist/core/allow-entry.js +38 -31
  51. package/dist/core/arg-summary.d.ts +21 -28
  52. package/dist/core/arg-summary.js +235 -88
  53. package/dist/core/ask-origin.d.ts +42 -24
  54. package/dist/core/ask-origin.js +18 -13
  55. package/dist/core/auto-mode-prompt-assets.d.ts +2 -2
  56. package/dist/core/auto-mode-prompt-assets.js +1 -1
  57. package/dist/core/auto-mode-prompt.d.ts +11 -1
  58. package/dist/core/auto-mode-prompt.js +13 -10
  59. package/dist/core/auto-mode-rebuild.d.ts +7 -0
  60. package/dist/core/auto-mode-rebuild.js +4 -1
  61. package/dist/core/canonical-json.d.ts +3 -0
  62. package/dist/core/canonical-json.js +2 -1
  63. package/dist/core/checkpoint-requirements.d.ts +892 -0
  64. package/dist/core/checkpoint-requirements.js +333 -0
  65. package/dist/core/checkpoint-store.d.ts +94 -65
  66. package/dist/core/checkpoint-store.js +14 -26
  67. package/dist/core/child-clamp-seats.d.ts +228 -69
  68. package/dist/core/child-clamp-seats.js +211 -17
  69. package/dist/core/classifier-unavailable-arm.d.ts +5 -1
  70. package/dist/core/classifier-unavailable-arm.js +3 -3
  71. package/dist/core/compliance.d.ts +3 -0
  72. package/dist/core/compliance.js +9 -4
  73. package/dist/core/credential-vocabulary.d.ts +140 -0
  74. package/dist/core/credential-vocabulary.js +131 -0
  75. package/dist/core/decision-receipt.js +1 -1
  76. package/dist/core/effective-path-target.d.ts +73 -16
  77. package/dist/core/effective-path-target.js +63 -33
  78. package/dist/core/engine-notice.d.ts +43 -11
  79. package/dist/core/file-history-store.js +2 -2
  80. package/dist/core/fs-write-gate-policy.d.ts +4 -0
  81. package/dist/core/fs-write-gate-policy.js +22 -5
  82. package/dist/core/gate-bounded-await.d.ts +28 -13
  83. package/dist/core/gate-bounded-await.js +41 -4
  84. package/dist/core/gate-fold.d.ts +1 -1
  85. package/dist/core/gate-fold.js +24 -25
  86. package/dist/core/gate-lanes.js +16 -15
  87. package/dist/core/gate-outcome.d.ts +20 -5
  88. package/dist/core/gate-outcome.js +5 -0
  89. package/dist/core/governance-codes.d.ts +11 -4
  90. package/dist/core/governance-codes.js +14 -3
  91. package/dist/core/hooks.d.ts +21 -0
  92. package/dist/core/locked-config.d.ts +8 -0
  93. package/dist/core/locked-config.js +14 -2
  94. package/dist/core/lsp.js +3 -5
  95. package/dist/core/mailbox-store.d.ts +3 -4
  96. package/dist/core/mcp-connection-pool.d.ts +75 -0
  97. package/dist/core/mcp-connection-pool.js +128 -0
  98. package/dist/core/mcp-failure.d.ts +2 -1
  99. package/dist/core/mcp-failure.js +13 -2
  100. package/dist/core/mcp.d.ts +4 -0
  101. package/dist/core/mcp.js +70 -43
  102. package/dist/core/memory-engine/content-origin.js +2 -14
  103. package/dist/core/memory-engine/engine.d.ts +32 -22
  104. package/dist/core/memory-engine/engine.js +103 -55
  105. package/dist/core/memory-engine/file-backend.d.ts +13 -30
  106. package/dist/core/memory-engine/file-backend.js +37 -252
  107. package/dist/core/memory-engine/index.d.ts +1 -1
  108. package/dist/core/memory-engine/index.js +1 -1
  109. package/dist/core/memory-engine/layout.d.ts +139 -9
  110. package/dist/core/memory-engine/layout.js +350 -7
  111. package/dist/core/memory-engine/scope-contract.d.ts +10 -0
  112. package/dist/core/memory-engine/scope-contract.js +8 -0
  113. package/dist/core/memory-engine/session-incarnation.d.ts +14 -4
  114. package/dist/core/memory-engine/session-incarnation.js +5 -2
  115. package/dist/core/memory-engine/types.d.ts +10 -1
  116. package/dist/core/memory.js +5 -17
  117. package/dist/core/model-seat.d.ts +4 -4
  118. package/dist/core/model-seat.js +1 -1
  119. package/dist/core/mounted-mcp.d.ts +57 -0
  120. package/dist/core/mounted-mcp.js +19 -0
  121. package/dist/core/namespaced-rule-name.d.ts +29 -0
  122. package/dist/core/namespaced-rule-name.js +52 -0
  123. package/dist/core/park-selfcheck.d.ts +1 -1
  124. package/dist/core/park-selfcheck.js +16 -6
  125. package/dist/core/path-guard-rows.d.ts +99 -0
  126. package/dist/core/path-guard-rows.js +45 -0
  127. package/dist/core/path-identity.d.ts +22 -16
  128. package/dist/core/path-identity.js +10 -10
  129. package/dist/core/path-rule-binding.d.ts +2 -1
  130. package/dist/core/path-rule-binding.js +3 -1
  131. package/dist/core/pause-registry.d.ts +16 -2
  132. package/dist/core/pause-registry.js +6 -0
  133. package/dist/core/permission-rule-consent.js +0 -7
  134. package/dist/core/permission-rule-model.d.ts +68 -24
  135. package/dist/core/permission-rule-model.js +105 -24
  136. package/dist/core/permission-rule-store.js +2 -2
  137. package/dist/core/permission-rules.d.ts +3 -30
  138. package/dist/core/permission-rules.js +4 -54
  139. package/dist/core/read-root-candidate.d.ts +1 -3
  140. package/dist/core/read-root-candidate.js +4 -15
  141. package/dist/core/real-approval.d.ts +4 -3
  142. package/dist/core/retired-keys.d.ts +13 -0
  143. package/dist/core/retired-keys.js +14 -0
  144. package/dist/core/roles.d.ts +2 -3
  145. package/dist/core/roles.js +15 -6
  146. package/dist/core/runner/assemble-result.d.ts +0 -7
  147. package/dist/core/runner/assemble-result.js +19 -31
  148. package/dist/core/runner/caller-roster.d.ts +78 -0
  149. package/dist/core/runner/caller-roster.js +219 -0
  150. package/dist/core/runner/checkpoint-scope.d.ts +16 -16
  151. package/dist/core/runner/checkpoint-scope.js +2 -2
  152. package/dist/core/runner/child-tree.js +2 -2
  153. package/dist/core/runner/contracts.d.ts +68 -35
  154. package/dist/core/runner/decide-continuation.d.ts +51 -3
  155. package/dist/core/runner/decide-continuation.js +76 -21
  156. package/dist/core/runner/denial-limit-arms.d.ts +17 -5
  157. package/dist/core/runner/denial-limit-arms.js +11 -9
  158. package/dist/core/runner/extra-body-dropped-seat.d.ts +8 -0
  159. package/dist/core/runner/extra-body-dropped-seat.js +22 -0
  160. package/dist/core/runner/finish-reason-seat.d.ts +9 -0
  161. package/dist/core/runner/finish-reason-seat.js +40 -0
  162. package/dist/core/runner/gate-exit.d.ts +44 -32
  163. package/dist/core/runner/gate-exit.js +112 -25
  164. package/dist/core/runner/inherited-ask-grants.js +6 -4
  165. package/dist/core/runner/mcp-redial.d.ts +3 -3
  166. package/dist/core/runner/mcp-redial.js +3 -4
  167. package/dist/core/runner/permission-rule-lanes.d.ts +1 -2
  168. package/dist/core/runner/permission-rule-lanes.js +5 -4
  169. package/dist/core/runner/prepare-artifact.d.ts +4 -0
  170. package/dist/core/runner/prepare-artifact.js +2 -1
  171. package/dist/core/runner/prepare-ask-lane.d.ts +2 -0
  172. package/dist/core/runner/prepare-ask-lane.js +12 -6
  173. package/dist/core/runner/prepare-boundary-parks.d.ts +5 -8
  174. package/dist/core/runner/prepare-boundary-parks.js +4 -7
  175. package/dist/core/runner/prepare-caps-and-workflow.d.ts +11 -15
  176. package/dist/core/runner/prepare-caps-and-workflow.js +19 -27
  177. package/dist/core/runner/prepare-config-doors.d.ts +9 -9
  178. package/dist/core/runner/prepare-config-doors.js +10 -5
  179. package/dist/core/runner/prepare-defer-classify.d.ts +2 -2
  180. package/dist/core/runner/prepare-defer-classify.js +5 -3
  181. package/dist/core/runner/prepare-delegation-surface.d.ts +1 -1
  182. package/dist/core/runner/prepare-delegation-surface.js +3 -3
  183. package/dist/core/runner/prepare-gate-stations.d.ts +4 -4
  184. package/dist/core/runner/prepare-gate-stations.js +9 -7
  185. package/dist/core/runner/prepare-hands-readface.d.ts +7 -7
  186. package/dist/core/runner/prepare-hands-readface.js +7 -7
  187. package/dist/core/runner/prepare-inherited-gate.d.ts +7 -6
  188. package/dist/core/runner/prepare-inherited-gate.js +14 -15
  189. package/dist/core/runner/prepare-listings.d.ts +7 -24
  190. package/dist/core/runner/prepare-listings.js +4 -5
  191. package/dist/core/runner/prepare-memory-engine-session.d.ts +2 -0
  192. package/dist/core/runner/prepare-memory-engine-session.js +4 -3
  193. package/dist/core/runner/prepare-memory.d.ts +6 -0
  194. package/dist/core/runner/prepare-memory.js +13 -13
  195. package/dist/core/runner/prepare-offload-wrappers.d.ts +5 -0
  196. package/dist/core/runner/prepare-offload-wrappers.js +3 -3
  197. package/dist/core/runner/prepare-park-ask.d.ts +7 -8
  198. package/dist/core/runner/prepare-park-ask.js +17 -10
  199. package/dist/core/runner/prepare-policy-chain.js +24 -44
  200. package/dist/core/runner/prepare-project-context.d.ts +1 -1
  201. package/dist/core/runner/prepare-project-context.js +3 -4
  202. package/dist/core/runner/prepare-protocol-tools.d.ts +9 -3
  203. package/dist/core/runner/prepare-protocol-tools.js +3 -4
  204. package/dist/core/runner/prepare-run-refs.d.ts +3 -0
  205. package/dist/core/runner/prepare-run-refs.js +2 -1
  206. package/dist/core/runner/prepare-safety-scan.d.ts +4 -8
  207. package/dist/core/runner/prepare-safety-scan.js +1 -2
  208. package/dist/core/runner/prepare-suspend-saga.d.ts +7 -1
  209. package/dist/core/runner/prepare-suspend-saga.js +28 -12
  210. package/dist/core/runner/prepare-task.d.ts +1 -1
  211. package/dist/core/runner/prepare-task.js +67 -56
  212. package/dist/core/runner/prepare-wiring-manifest.d.ts +11 -10
  213. package/dist/core/runner/prepare-wiring-manifest.js +5 -8
  214. package/dist/core/runner/resume-apply.js +7 -14
  215. package/dist/core/runner/resume-checkpoint-screen.js +11 -4
  216. package/dist/core/runner/resume-internals-and-config.js +2 -2
  217. package/dist/core/runner/resume-policy-outcome.js +5 -32
  218. package/dist/core/runner/resume-review-outcome.js +4 -1
  219. package/dist/core/runner/retired-runner-deps.d.ts +6 -0
  220. package/dist/core/runner/retired-runner-deps.js +10 -1
  221. package/dist/core/runner/run-brain-sinks.d.ts +4 -0
  222. package/dist/core/runner/run-brain-sinks.js +5 -2
  223. package/dist/core/runner/run-harness-handlers.js +29 -36
  224. package/dist/core/runner/run-leg.d.ts +0 -2
  225. package/dist/core/runner/run-leg.js +32 -33
  226. package/dist/core/runner/run-terminal-adoption.js +4 -3
  227. package/dist/core/runner/runtask.js +8 -8
  228. package/dist/core/runner/session-rule-policy.js +5 -5
  229. package/dist/core/runner/stream-settle-backstop.js +7 -4
  230. package/dist/core/runner/sub-agent-deny-lists.d.ts +51 -12
  231. package/dist/core/runner/sub-agent-deny-lists.js +111 -80
  232. package/dist/core/runner/terminal-account.d.ts +48 -0
  233. package/dist/core/runner/terminal-account.js +186 -0
  234. package/dist/core/runner/tool-end-body.d.ts +54 -17
  235. package/dist/core/runner/tool-end-body.js +27 -2
  236. package/dist/core/runner/tool-face-overlay.d.ts +3 -1
  237. package/dist/core/runner/tool-face-overlay.js +6 -4
  238. package/dist/core/runner/tool-occurrence.d.ts +106 -0
  239. package/dist/core/runner/tool-occurrence.js +123 -0
  240. package/dist/core/runner/tool-progress-lane.d.ts +16 -8
  241. package/dist/core/runner/tool-progress-lane.js +25 -34
  242. package/dist/core/runner/tool-turn-repair-seat.d.ts +28 -4
  243. package/dist/core/runner/tool-turn-repair-seat.js +36 -13
  244. package/dist/core/runner/turn-attachments.d.ts +1 -1
  245. package/dist/core/runner/write-protection-station.d.ts +21 -9
  246. package/dist/core/runner/write-protection-station.js +20 -17
  247. package/dist/core/runner-deps.d.ts +12 -22
  248. package/dist/core/secret-env.d.ts +16 -5
  249. package/dist/core/secret-env.js +23 -63
  250. package/dist/core/sensitive-path-policy.d.ts +19 -18
  251. package/dist/core/sensitive-path-policy.js +73 -49
  252. package/dist/core/session-reconcile.d.ts +3 -0
  253. package/dist/core/session-reconcile.js +5 -4
  254. package/dist/core/session-store.d.ts +5 -0
  255. package/dist/core/session-store.js +12 -0
  256. package/dist/core/session.d.ts +13 -0
  257. package/dist/core/shared-memory/normalize.d.ts +17 -4
  258. package/dist/core/shared-memory/normalize.js +7 -7
  259. package/dist/core/shell-lexer.js +5 -4
  260. package/dist/core/shell-wrapper-projection.js +1 -1
  261. package/dist/core/skill-grant.js +1 -1
  262. package/dist/core/store-contracts/checkpoint-store-contract.js +13 -0
  263. package/dist/core/store-contracts/mailbox-store-contract.d.ts +7 -14
  264. package/dist/core/store-contracts/session-store-incarnation-contract.d.ts +27 -0
  265. package/dist/core/store-contracts/session-store-incarnation-contract.js +92 -0
  266. package/dist/core/stub-env.d.ts +2 -0
  267. package/dist/core/stub-env.js +1 -0
  268. package/dist/core/synthetic-read-verdict.js +2 -2
  269. package/dist/core/task-event.d.ts +59 -5
  270. package/dist/core/task-result.d.ts +1 -1
  271. package/dist/core/task-spec.d.ts +42 -9
  272. package/dist/core/terminal-cause.d.ts +94 -11
  273. package/dist/core/tighten-task-spec.d.ts +5 -4
  274. package/dist/core/tighten-task-spec.js +20 -25
  275. package/dist/core/tool-catalog-entries.d.ts +5 -7
  276. package/dist/core/tool-catalog-entries.js +14 -15
  277. package/dist/core/tool-face.d.ts +47 -0
  278. package/dist/core/tool-face.js +5 -0
  279. package/dist/core/tool-model-gate.d.ts +5 -5
  280. package/dist/core/tool-name-aliases.d.ts +26 -2
  281. package/dist/core/tool-name-aliases.js +13 -0
  282. package/dist/core/tool-name-list.d.ts +30 -0
  283. package/dist/core/tool-name-list.js +55 -0
  284. package/dist/core/tool-name-readings.d.ts +1 -9
  285. package/dist/core/tool-name-readings.js +1 -3
  286. package/dist/core/tool-policy.d.ts +195 -85
  287. package/dist/core/tool-policy.js +165 -380
  288. package/dist/core/tool-registry.d.ts +44 -1
  289. package/dist/core/tool-registry.js +26 -0
  290. package/dist/core/tool-roster.d.ts +19 -1
  291. package/dist/core/tool-roster.js +21 -2
  292. package/dist/core/tool-spec-members.d.ts +45 -0
  293. package/dist/core/tool-spec-members.js +169 -0
  294. package/dist/core/tool-spec.d.ts +46 -8
  295. package/dist/core/tools.d.ts +6 -2
  296. package/dist/core/tools.js +8 -4
  297. package/dist/core/untrusted-egress.js +29 -26
  298. package/dist/core/untrusted-text.d.ts +13 -10
  299. package/dist/core/untrusted-text.js +6 -44
  300. package/dist/core/workflow-journal-store.d.ts +4 -1
  301. package/dist/core/write-protect.d.ts +65 -29
  302. package/dist/core/write-protect.js +235 -177
  303. package/dist/engine/compaction/compaction.d.ts +2 -2
  304. package/dist/engine/execution-env/node-execution-env.d.ts +5 -23
  305. package/dist/engine/execution-env/node-execution-env.js +16 -38
  306. package/dist/engine/execution-env/symlink-chain.d.ts +23 -0
  307. package/dist/engine/execution-env/symlink-chain.js +32 -0
  308. package/dist/engine/harness/types.d.ts +7 -0
  309. package/dist/engine/llm/tool-turns.d.ts +3 -0
  310. package/dist/engine/llm/tool-turns.js +1 -0
  311. package/dist/engine/llm/types.d.ts +59 -23
  312. package/dist/engine/loop/agent-loop.js +16 -2
  313. package/dist/engine/session/memory-repo.js +11 -3
  314. package/dist/engine/session/repo-utils.d.ts +8 -0
  315. package/dist/engine/session/repo-utils.js +13 -0
  316. package/dist/index.d.ts +20 -23
  317. package/dist/index.js +17 -20
  318. package/dist/internal/harness.d.ts +1 -1
  319. package/dist/internal/harness.js +1 -1
  320. package/dist/internal/llm.d.ts +2 -2
  321. package/dist/internal/llm.js +1 -1
  322. package/dist/orchestration/governance-baseline-validity.js +1 -1
  323. package/dist/orchestration/run-spec.js +3 -3
  324. package/dist/orchestration/run-workflow-tool.d.ts +16 -35
  325. package/dist/orchestration/run-workflow-tool.js +38 -78
  326. package/dist/orchestration/workflow-governance.d.ts +21 -25
  327. package/dist/orchestration/workflow-governance.js +38 -78
  328. package/dist/orchestration/workflow-primitives.d.ts +7 -22
  329. package/dist/orchestration/workflow-primitives.js +5 -12
  330. package/dist/orchestration/workflow-types.d.ts +1 -1
  331. package/dist/orchestration/workflow.d.ts +61 -11
  332. package/dist/orchestration/workflow.js +189 -117
  333. package/dist/scenarios/full-body.d.ts +1 -1
  334. package/dist/shell/lex.d.ts +0 -21
  335. package/dist/shell/lex.js +250 -68
  336. package/dist/shell/shell-words.d.ts +35 -0
  337. package/dist/shell/shell-words.js +65 -0
  338. package/dist/stores/file/checkpoint-store.d.ts +5 -5
  339. package/dist/stores/file/checkpoint-store.js +5 -2
  340. package/dist/stores/file/index.d.ts +0 -8
  341. package/dist/stores/file/index.js +0 -12
  342. package/dist/stores/file/session-store.d.ts +3 -0
  343. package/dist/stores/file/session-store.js +44 -19
  344. package/dist/tools/artifact/artifact-tool.js +2 -0
  345. package/dist/tools/fs/bash-program-position.d.ts +12 -4
  346. package/dist/tools/fs/bash-program-position.js +32 -9
  347. package/dist/tools/fs/bash-readonly-classifier.d.ts +1 -1
  348. package/dist/tools/fs/bash-readonly-classifier.js +8 -7
  349. package/dist/tools/fs/containment-face.d.ts +4 -0
  350. package/dist/tools/fs/containment-face.js +3 -0
  351. package/dist/tools/fs/fs-shared.d.ts +10 -0
  352. package/dist/tools/fs/fs-shared.js +18 -0
  353. package/dist/tools/fs/fs-write.js +4 -2
  354. package/dist/tools/fs/index.d.ts +1 -1
  355. package/dist/tools/fs/program-read-model.d.ts +46 -20
  356. package/dist/tools/fs/program-read-model.js +50 -20
  357. package/dist/tools/fs/program-read-model.rows.d.ts +0 -14
  358. package/dist/tools/fs/program-read-model.rows.js +16 -15
  359. package/dist/tools/fs/read-deny-home.d.ts +33 -47
  360. package/dist/tools/fs/read-deny-home.js +35 -49
  361. package/dist/tools/fs/read-deny.d.ts +23 -22
  362. package/dist/tools/fs/read-deny.js +114 -89
  363. package/dist/tools/fs/removal-targets.d.ts +56 -23
  364. package/dist/tools/fs/removal-targets.js +65 -87
  365. package/dist/tools/fs/safety.d.ts +29 -22
  366. package/dist/tools/fs/safety.js +17 -11
  367. package/dist/tools/fs/search.js +10 -8
  368. package/dist/tools/fs/shell-read-argv.js +1 -1
  369. package/dist/tools/fs/shell-read-bindings.d.ts +169 -37
  370. package/dist/tools/fs/shell-read-bindings.js +324 -86
  371. package/dist/tools/fs/shell-read-builtins.d.ts +35 -0
  372. package/dist/tools/fs/shell-read-builtins.js +43 -0
  373. package/dist/tools/fs/shell-read-check.d.ts +15 -1
  374. package/dist/tools/fs/shell-read-check.js +67 -43
  375. package/dist/tools/fs/shell-read-establish.js +6 -6
  376. package/dist/tools/fs/shell-read-functions.d.ts +22 -0
  377. package/dist/tools/fs/shell-read-functions.js +29 -0
  378. package/dist/tools/fs/shell-read-judge.d.ts +51 -18
  379. package/dist/tools/fs/shell-read-judge.js +40 -4
  380. package/dist/tools/fs/shell-read-plan.d.ts +12 -6
  381. package/dist/tools/fs/shell-read-plan.js +118 -113
  382. package/dist/tools/fs/shell-read-start.d.ts +29 -6
  383. package/dist/tools/fs/shell-read-start.js +16 -9
  384. package/dist/tools/fs/shell-read-word.js +4 -0
  385. package/dist/tools/fs/shell-read-workdir.d.ts +156 -0
  386. package/dist/tools/fs/shell-read-workdir.js +281 -0
  387. package/dist/tools/fs/shell-read-write-targets.d.ts +5 -2
  388. package/dist/tools/fs/shell-read-write-targets.js +14 -5
  389. package/dist/tools/fs/shell-reentry-text.d.ts +4 -6
  390. package/dist/tools/fs/shell-reentry-text.js +3 -11
  391. package/dist/tools/task-list.d.ts +1 -2
  392. package/dist/tools/web.js +1 -1
  393. package/package.json +4 -1
  394. package/test/export-surface.snapshot.json +107 -143
  395. package/wire-changes/core@7.49.0.json +4765 -0
  396. package/dist/agents/teacher.d.ts +0 -159
  397. package/dist/agents/teacher.js +0 -577
  398. package/dist/agents/team.d.ts +0 -226
  399. package/dist/agents/team.js +0 -257
  400. package/dist/core/strategy-store.d.ts +0 -238
  401. package/dist/core/strategy-store.js +0 -253
  402. package/dist/orchestration/builtin-workflows.d.ts +0 -133
  403. package/dist/orchestration/builtin-workflows.js +0 -159
  404. package/dist/scenarios/env.d.ts +0 -40
  405. package/dist/scenarios/env.js +0 -39
  406. package/dist/scenarios/scenario-registry.d.ts +0 -110
  407. package/dist/scenarios/scenario-registry.js +0 -140
  408. package/dist/scenarios/teacher-quickstart.d.ts +0 -40
  409. package/dist/scenarios/teacher-quickstart.js +0 -12
  410. package/dist/stores/cc/lockfile.d.ts +0 -10
  411. package/dist/stores/cc/lockfile.js +0 -98
  412. package/dist/stores/cc/mailbox-store.d.ts +0 -20
  413. package/dist/stores/cc/mailbox-store.js +0 -255
  414. package/dist/stores/cc/roster-adapter.d.ts +0 -12
  415. package/dist/stores/cc/roster-adapter.js +0 -117
  416. package/dist/stores/cc/sidecar-transcript.d.ts +0 -97
  417. package/dist/stores/cc/sidecar-transcript.js +0 -264
  418. package/dist/stores/cc/task-list-store.d.ts +0 -2
  419. package/dist/stores/cc/task-list-store.js +0 -125
  420. package/dist/stores/file/strategy-store.d.ts +0 -97
  421. package/dist/stores/file/strategy-store.js +0 -341
@@ -0,0 +1,186 @@
1
+ import { BrainError, carriedProviderWord, providerErrorWord, statedEnvelope } from "./errors.js";
2
+ import { readUnifiedResetEpochMs } from "./retry.js";
3
+ export const PROVIDER_CONDITIONS = Object.freeze(["quota_exhausted", "throttled", "overloaded", "stop_other", "unknown"]);
4
+ export const PROVIDER_CONDITION_SOURCES = Object.freeze(["unified_header", "provider_code", "status"]);
5
+ export const PROVIDER_CONDITION_TRAITS = {
6
+ quota_exhausted: { retryable: false, inBandCode: "rate_limit" },
7
+ throttled: { retryable: true, inBandCode: "rate_limit" },
8
+ overloaded: { retryable: true, inBandCode: "server" },
9
+ stop_other: { retryable: false, inBandCode: "invalid_request" },
10
+ unknown: { retryable: true, inBandCode: "server" },
11
+ };
12
+ Object.freeze(PROVIDER_CONDITION_TRAITS);
13
+ export function isProviderCondition(v) {
14
+ return typeof v === "string" && PROVIDER_CONDITIONS.includes(v);
15
+ }
16
+ export function isProviderConditionSource(v) {
17
+ return typeof v === "string" && PROVIDER_CONDITION_SOURCES.includes(v);
18
+ }
19
+ export const INPUT_TOO_LONG_ANCHORED_RE = /^(?:prompt is too long|prompt too long|input is too long|this model's maximum context length is |context.{0,3}length|context window (?:limit|exceeded)|reached its context window|too many tokens|maximum context|input length and `max_tokens` exceed context limit|(?:the )?request(?: \([^)]{0,40}\))? exceeds|(?:the )?input token count(?: \([^)]{0,40}\))? exceeds|requested tokens(?: \([^)]{0,40}\))? exceed|your input exceeds|(?:the )?number of tokens in the request exceeds|range of input length should be|input token length too long|invalid request: your request exceeded model token limit|total message size)/i;
20
+ export function startsWithInputTooLongAnchor(diagnostic) {
21
+ return INPUT_TOO_LONG_ANCHORED_RE.test(diagnostic.trimStart());
22
+ }
23
+ const INPUT_TOO_LONG_STATUSES = new Set([400, 413, 422]);
24
+ const OPENAI_CHAT = "openai-completions";
25
+ const OPENAI_RESPONSES = "openai-responses";
26
+ const ANTHROPIC = "anthropic-messages";
27
+ const OPENAI_SPEND_CODES = ["credit_balance_exhausted", "organization_spend_limit_exceeded", "project_spend_limit_exceeded", "organization_usage_limit_exceeded"];
28
+ export const PROVIDER_DIALECTS = Object.freeze([
29
+ {
30
+ name: "deepseek",
31
+ key: { wires: [OPENAI_CHAT, ANTHROPIC], hosts: ["api.deepseek.com"] },
32
+ failures: [
33
+ { status: [429], condition: "throttled" },
34
+ { status: [503], condition: "overloaded" },
35
+ ],
36
+ },
37
+ {
38
+ name: "dashscope",
39
+ key: { wires: [OPENAI_CHAT], hosts: ["dashscope.aliyuncs.com", "dashscope-intl.aliyuncs.com"] },
40
+ failures: [
41
+ { status: [429], word: ["limit_requests", "limit_burst_rate", "Throttling.Concurrency", "Throttling"], condition: "throttled" },
42
+ { status: [429], word: ["insufficient_quota", "Throttling.AllocationQuota"], sentence: /^free allocated quota exceeded/i, condition: "quota_exhausted" },
43
+ { status: [429], word: ["insufficient_quota", "Throttling.AllocationQuota"], condition: "throttled" },
44
+ { status: [429], word: ["Throttling.ServiceOverloaded", "ResourceExhausted"], condition: "overloaded" },
45
+ { status: [429], word: ["PrepaidBillOverdue", "PostpaidBillOverdue", "BudgetLimitExceeded", "CommodityNotPurchased"], condition: "quota_exhausted" },
46
+ { status: [429], condition: "throttled" },
47
+ { status: [400], word: ["Arrearage"], condition: "quota_exhausted" },
48
+ { status: [403], word: ["AllocationQuota.FreeTierOnly"], condition: "quota_exhausted" },
49
+ { status: [400], word: ["DataInspectionFailed"], condition: "stop_other" },
50
+ { status: [500, 503], word: ["InternalError", "RequestTimeOut", "ModelUnavailable"], condition: "overloaded" },
51
+ ],
52
+ },
53
+ {
54
+ name: "moonshot",
55
+ key: { wires: [OPENAI_CHAT], hosts: ["api.moonshot.cn", "api.moonshot.ai"] },
56
+ failures: [
57
+ { status: [429], word: ["exceeded_current_quota_error"], condition: "quota_exhausted" },
58
+ { status: [429], word: ["rate_limit_reached_error"], sentence: /\bTPD\b|每日/i, condition: "quota_exhausted" },
59
+ { status: [429], word: ["rate_limit_reached_error"], condition: "throttled" },
60
+ { status: [429], word: ["engine_overloaded_error"], condition: "overloaded" },
61
+ { status: [429], condition: "throttled" },
62
+ { status: [503], word: ["server_unavailable"], condition: "overloaded" },
63
+ { status: [403], word: ["permission_denied_error"], condition: "stop_other" },
64
+ { status: [400], word: ["content_filter"], condition: "stop_other" },
65
+ ],
66
+ },
67
+ {
68
+ name: "kimi-code",
69
+ key: { wires: [ANTHROPIC, OPENAI_CHAT], hosts: ["api.kimi.com"], path: "/coding" },
70
+ failures: [
71
+ { status: [429], sentence: /^the engine is currently overloaded/i, condition: "overloaded" },
72
+ { status: [429], condition: "throttled" },
73
+ { status: [403], sentence: /^you(?:'|’)ve reached your\b.*\busage limit/i, condition: "quota_exhausted" },
74
+ ],
75
+ },
76
+ {
77
+ name: "glm",
78
+ key: { wires: [OPENAI_CHAT, ANTHROPIC], hosts: ["open.bigmodel.cn", "api.z.ai"] },
79
+ failures: [
80
+ { status: [429], word: ["1302"], condition: "throttled" },
81
+ { status: [429], word: ["1305"], condition: "overloaded" },
82
+ {
83
+ status: [429],
84
+ word: ["1113", "1308", "1309", "1310", "1314", "1315", "1316", "1317", "1318", "1319", "1320", "1321"],
85
+ condition: "quota_exhausted",
86
+ },
87
+ { status: [429], word: ["1311", "1313"], condition: "stop_other" },
88
+ { status: [400], word: ["1261"], condition: "stop_other", inputTooLong: true },
89
+ ],
90
+ },
91
+ {
92
+ name: "openai",
93
+ key: { wires: [OPENAI_CHAT, OPENAI_RESPONSES], hosts: ["api.openai.com"] },
94
+ failures: [
95
+ { status: [429], word: [...OPENAI_SPEND_CODES, "insufficient_quota"], condition: "quota_exhausted" },
96
+ { status: [429], word: ["slow_down", "rate_limit_exceeded", "rate_limit_error"], condition: "throttled" },
97
+ { status: [429], condition: "throttled" },
98
+ { status: [503], word: ["server_is_overloaded"], condition: "overloaded" },
99
+ ],
100
+ },
101
+ ]);
102
+ export const GENERIC_FAILURES = Object.freeze([
103
+ { status: [402], condition: "quota_exhausted" },
104
+ { status: [429], word: [...OPENAI_SPEND_CODES], condition: "quota_exhausted" },
105
+ { status: [429], word: ["insufficient_quota"], condition: "unknown" },
106
+ { status: [400, 422], word: ["context_length_exceeded"], condition: "stop_other", inputTooLong: true },
107
+ { status: [400, 422], sentence: INPUT_TOO_LONG_ANCHORED_RE, condition: "stop_other", inputTooLong: true },
108
+ { status: [413], condition: "stop_other", inputTooLong: true },
109
+ ]);
110
+ export function isTransientStatus(status) {
111
+ return status >= 500 || status === 408 || status === 409;
112
+ }
113
+ export function resolveProviderDialect(url, wire) {
114
+ if (!URL.canParse(url))
115
+ return undefined;
116
+ const u = new URL(url);
117
+ const host = u.hostname.toLowerCase().replace(/\.$/, "");
118
+ const path = u.pathname;
119
+ return PROVIDER_DIALECTS.find((d) => d.key.wires.includes(wire) &&
120
+ d.key.hosts.some((h) => host === h || host.endsWith(`.${h}`)) &&
121
+ (d.key.path === undefined || path === d.key.path || path.startsWith(`${d.key.path}/`)));
122
+ }
123
+ function statementOf(err) {
124
+ if (err === undefined)
125
+ return undefined;
126
+ const word = providerErrorWord(err);
127
+ const sentence = typeof err.message === "string" ? err.message.trimStart() : undefined;
128
+ return { ...(word !== undefined ? { word } : {}), ...(sentence !== undefined ? { sentence } : {}) };
129
+ }
130
+ function bestRow(rows, status, stated) {
131
+ let best;
132
+ let bestRank = -1;
133
+ for (const row of rows) {
134
+ if (status === undefined ? row.word === undefined && row.sentence === undefined : row.status !== undefined && !row.status.includes(status))
135
+ continue;
136
+ if (row.word !== undefined && (stated?.word === undefined || !row.word.includes(stated.word)))
137
+ continue;
138
+ if (row.sentence !== undefined && (stated?.sentence === undefined || !row.sentence.test(stated.sentence)))
139
+ continue;
140
+ const rank = (row.word !== undefined ? 2 : 0) + (row.sentence !== undefined ? 1 : 0);
141
+ if (rank > bestRank) {
142
+ best = row;
143
+ bestRank = rank;
144
+ }
145
+ }
146
+ return best;
147
+ }
148
+ function verdictOf(dialect, status, stated, enveloped) {
149
+ const row = bestRow(dialect?.failures ?? [], status, stated) ?? bestRow(GENERIC_FAILURES, status, stated);
150
+ const condition = row?.condition ?? (status === undefined || status === 429 || isTransientStatus(status) ? "unknown" : "stop_other");
151
+ const source = row !== undefined && (row.word !== undefined || row.sentence !== undefined) ? "provider_code" : "status";
152
+ const inputTooLong = status !== undefined && !INPUT_TOO_LONG_STATUSES.has(status) ? "no" : row?.inputTooLong === true ? "yes" : enveloped ? "no" : "unknown";
153
+ return { condition, source, inputTooLong };
154
+ }
155
+ const UNIFIED_QUOTA_HEADERS = [
156
+ "anthropic-ratelimit-unified-representative-claim",
157
+ "anthropic-ratelimit-unified-overage-status",
158
+ "anthropic-ratelimit-unified-overage-disabled-reason",
159
+ ];
160
+ function headerPresent(headers, name) {
161
+ const v = headers?.get?.(name);
162
+ return typeof v === "string" && v.length > 0;
163
+ }
164
+ export function judgeHttpFailure(args) {
165
+ const { dialect, status, headers, body } = args;
166
+ if (status === 429 && UNIFIED_QUOTA_HEADERS.some((h) => headerPresent(headers, h))) {
167
+ const resetAtMs = readUnifiedResetEpochMs(headers);
168
+ return { condition: "quota_exhausted", source: "unified_header", ...(resetAtMs !== undefined ? { resetAtMs } : {}), inputTooLong: "no" };
169
+ }
170
+ const envelope = statedEnvelope(body);
171
+ return verdictOf(dialect, status, statementOf(envelope), envelope !== undefined);
172
+ }
173
+ export function judgeInBandError(dialect, envelope) {
174
+ return verdictOf(dialect, undefined, statementOf(envelope), true);
175
+ }
176
+ export function inBandProviderError(dialect, envelope, label) {
177
+ const v = judgeInBandError(dialect, envelope);
178
+ const word = carriedProviderWord(envelope);
179
+ const sentence = typeof envelope.message === "string" ? envelope.message : "";
180
+ return new BrainError(PROVIDER_CONDITION_TRAITS[v.condition].inBandCode, `${label} stream error (${word ?? "unknown"}): ${sentence}`, undefined, {
181
+ apiError: true,
182
+ ...(v.inputTooLong === "yes" ? { inputTooLong: true } : v.inputTooLong === "no" ? { inputTooLongRuledOut: true } : {}),
183
+ ...(word !== undefined ? { providerCode: word } : {}),
184
+ verdict: { condition: v.condition, source: v.source },
185
+ });
186
+ }
@@ -1,3 +1,19 @@
1
+ /**
2
+ * Request-parameter passthrough (design/40). A deployment can set official provider params it wants but
3
+ * core doesn't model as first-class fields (OpenAI `frequency_penalty`/`presence_penalty`/`top_p`/`seed`/
4
+ * `logit_bias`; Anthropic `top_k`/`top_p`/`stop_sequences`; …) via `Model.extraBody`, and core merges them
5
+ * into the brain's request body. Anchored at the **Model** level (not per-turn) so the serialized body
6
+ * stays byte-stable across turns → the prefix cache holds (design/9/31).
7
+ *
8
+ * Symmetric: each brain owns its structural + tuning keys (`reserved`) and ALWAYS wins — `extraBody` can
9
+ * only supply the long tail, never clobber `messages`/`tools`/`temperature`/etc. Stripping is the safety
10
+ * enforcement (the brains are standalone-usable), and a strip is never silent: {@link applyExtraBody}
11
+ * RETURNS the keys it stripped, the brain reports them on the request it built
12
+ * (`SSERequest.extraBodyDropped`), the stream engine reports them to the run's sink when it commits that
13
+ * request (`reportExtraBodyDropped`), and the Runner announces them (`route.extra_body_reserved_dropped`).
14
+ * One reading, at the one place the strip happens — so an `extraBody` a host brain swapped in for a single
15
+ * request, or one on the compaction model, is said the same way the task's own model spec is.
16
+ */
1
17
  /** OpenAI request-body keys core owns; `extraBody` cannot override these. */
2
18
  export declare const OPENAI_RESERVED: ReadonlySet<string>;
3
19
  /** Anthropic request-body keys core owns; `extraBody` cannot override these. (Note the asymmetry vs
@@ -9,19 +25,24 @@ export declare const ANTHROPIC_RESERVED: ReadonlySet<string>;
9
25
  * The last three are NOT keys the adapter sets — they are keys it must be IMPOSSIBLE to set. The
10
26
  * Open Responses lane is stateless by contract (this engine is the transcript authority), and
11
27
  * `extraBody` is the only other path to the request body, so `store` / `previous_response_id` /
12
- * `conversation` are reserved purely to close it. A deployment that sets one gets the design/40
13
- * collision warning at load and a stripped key on the wire, never a silently server-linked turn.
28
+ * `conversation` are reserved purely to close it. A deployment that sets one gets a stripped key on the
29
+ * wire and the drop announced, never a silently server-linked turn.
14
30
  */
15
31
  export declare const RESPONSES_RESERVED: ReadonlySet<string>;
16
- /** Reserved set for a model's API. */
17
- export declare function reservedFor(api: string): ReadonlySet<string>;
18
32
  /**
19
33
  * Merge `extraBody` into a brain's already-built request `body`, dropping any key the brain owns so core
20
- * always wins. Returns a NEW object (passthrough keys first, then core keys) when `extraBody` is set; the
34
+ * always wins. `body` is a NEW object (passthrough keys first, then core keys) when `extraBody` is set; the
21
35
  * exact `body` reference (no allocation, byte-identical serialization) when it isn't — so an existing
22
36
  * deployment with no `extraBody` is unaffected.
37
+ *
38
+ * `dropped` is the keys of `extraBody` that were stripped, in `extraBody`'s insertion order, names only (a
39
+ * value never leaves this function except inside `body`). It is a property of the same walk that strips, so
40
+ * what is said and what is dropped cannot disagree; empty when nothing was stripped.
23
41
  */
24
- export declare function applyExtraBody(body: Record<string, unknown>, extraBody: Record<string, unknown> | undefined, reserved: ReadonlySet<string>): Record<string, unknown>;
42
+ export declare function applyExtraBody(body: Record<string, unknown>, extraBody: Record<string, unknown> | undefined, reserved: ReadonlySet<string>): {
43
+ body: Record<string, unknown>;
44
+ dropped: readonly string[];
45
+ };
25
46
  /** The auth-bearing header names (case-fold), single-sourced for the credential enforcement
26
47
  * (`applyRouteCredentialHeaders`, route-adjudicator.ts — the ONE authority over auth spelling: a
27
48
  * per-model winner strips every carrier, any case, and re-asserts the winning bag's own),
@@ -99,5 +120,3 @@ export declare const OUTPUT_CAP_KEYS: Readonly<Record<"openai" | "anthropic" | "
99
120
  * request that carries two. Smallest wins so a consumer reasoning about the bound stays conservative.
100
121
  */
101
122
  export declare function effectiveOutputCap(body: Record<string, unknown>, keys: readonly string[]): number | undefined;
102
- /** Names in `extraBody` that collide with a reserved (core-owned) key — for a load-time warning. */
103
- export declare function reservedCollisions(extraBody: Record<string, unknown> | undefined, reserved: ReadonlySet<string>): string[];
@@ -1,4 +1,3 @@
1
- import { RESPONSES_APIS } from "./reasoning.js";
2
1
  export const OPENAI_RESERVED = new Set([
3
2
  "model",
4
3
  "messages",
@@ -39,20 +38,19 @@ export const RESPONSES_RESERVED = new Set([
39
38
  "previous_response_id",
40
39
  "conversation",
41
40
  ]);
42
- export function reservedFor(api) {
43
- if (RESPONSES_APIS.has(api))
44
- return RESPONSES_RESERVED;
45
- return api === "anthropic-messages" ? ANTHROPIC_RESERVED : OPENAI_RESERVED;
46
- }
41
+ const NO_KEYS = Object.freeze([]);
47
42
  export function applyExtraBody(body, extraBody, reserved) {
48
43
  if (!extraBody)
49
- return body;
44
+ return { body, dropped: NO_KEYS };
50
45
  const passthrough = {};
46
+ const dropped = [];
51
47
  for (const [k, v] of Object.entries(extraBody)) {
52
- if (!reserved.has(k))
48
+ if (reserved.has(k))
49
+ dropped.push(k);
50
+ else
53
51
  passthrough[k] = v;
54
52
  }
55
- return { ...passthrough, ...body };
53
+ return { body: { ...passthrough, ...body }, dropped: dropped.length === 0 ? NO_KEYS : dropped };
56
54
  }
57
55
  export const AUTH_CARRIER_NAMES = new Set(["authorization", "x-api-key"]);
58
56
  export function lockHeader(headers, lowerName, value) {
@@ -109,6 +107,3 @@ export function effectiveOutputCap(body, keys) {
109
107
  }
110
108
  return smallest;
111
109
  }
112
- export function reservedCollisions(extraBody, reserved) {
113
- return extraBody ? Object.keys(extraBody).filter((k) => reserved.has(k)) : [];
114
- }
@@ -0,0 +1,84 @@
1
+ /**
2
+ * The route a provider request took, as the brain that built it states it: where the credential it carried came
3
+ * from, how that credential rode, and which knob named the request's root. One projection of the two resolutions a
4
+ * request build already runs ({@link import("./route-adjudicator.js").resolveRouteCredential} and
5
+ * {@link import("./route-adjudicator.js").resolveRequestRootOf}) — never a key value, never a URL.
6
+ *
7
+ * Who reads it: the engine's terminal-shell mint lifts the committed request's route onto
8
+ * `AssistantMessage.apiErrorRoute` (only beside `isApiErrorMessage`), and a run whose terminal is a provider refusal
9
+ * carries it on `terminal.detail.route`. {@link ROUTE_CREDENTIAL_PAIRING} is the same vocabulary as a table: one row
10
+ * per declaration shape a request can carry, naming the knob(s) the credential is read from and the root knob it is
11
+ * paired with — the machine-readable half of the pairing law whose verdicts the conformance corpus pins.
12
+ */
13
+ import type { RouteCredential } from "../internal/llm.js";
14
+ /** Where the credential a request would carry came from.
15
+ * - `"per-model"` — resolved FOR this model: a per-call key/headers from the per-model auth hook
16
+ * (`getApiKeyAndHeaders`), or an auth-bearing header declared on `Model.headers`. Paired by
17
+ * construction (the resolver was asked about THIS entry), so the adjudicator never refuses it.
18
+ * - `"deployment-config"` — the brain construction-time fallback (`config.apiKey` / an auth header
19
+ * in `config.headers`). Paired only with the deployment's own declared root (`config.baseUrl`).
20
+ * - `"absent"` — no credential anywhere. Legal for keyless gateways; refused only where an entry
21
+ * declares its OWN URL away from a declared deployment root (a distinct endpoint with no
22
+ * credential route is a configuration hole, not a keyless deployment). */
23
+ export declare const ROUTE_CREDENTIAL_SOURCES: readonly ["per-model", "deployment-config", "absent"];
24
+ export type RouteCredentialSource = (typeof ROUTE_CREDENTIAL_SOURCES)[number];
25
+ /** How a credential rode: the brain's apiKey knob (written as the lane's own auth header), or an auth-bearing header
26
+ * from one of the header bags. */
27
+ export declare const ROUTE_CARRIERS: readonly ["apiKey", "header"];
28
+ export type RouteCarrier = (typeof ROUTE_CARRIERS)[number];
29
+ /** The header bag an auth-bearing header came from: the per-call options (the per-model auth hook's headers), the
30
+ * model entry (`Model.headers`), or the brain's construction config (`config.headers`). */
31
+ export declare const ROUTE_CARRIER_BAGS: readonly ["options", "model", "config"];
32
+ export type RouteCarrierBag = (typeof ROUTE_CARRIER_BAGS)[number];
33
+ /** Which knob named the request's root: the model entry (`Model.baseUrl`), the brain's construction config
34
+ * (`config.baseUrl`), or the lane's own default endpoint (neither was declared). */
35
+ export declare const REQUEST_ROOT_ORIGINS: readonly ["model", "deployment", "lane-default"];
36
+ export type RequestRootOrigin = (typeof REQUEST_ROOT_ORIGINS)[number];
37
+ /**
38
+ * The route a request took ({@link requestRouteOf}). Never a key value and never a URL — the words name knobs, so the
39
+ * value may travel wherever the failure it describes travels.
40
+ * - `credentialSource` — {@link RouteCredentialSource}.
41
+ * - `carrier` — how the credential rode ({@link RouteCarrier}); absent exactly when `credentialSource` is `"absent"`.
42
+ * - `carrierBag` — the header bag whose auth header rode ({@link RouteCarrierBag}); present exactly when one did:
43
+ * with carrier `"header"`, and beside carrier `"apiKey"` in the deployment shape that sets both `config.apiKey`
44
+ * and an auth header in `config.headers` (both ride).
45
+ * - `root` — which knob named the request's root ({@link RequestRootOrigin}).
46
+ * The legal shapes are exactly the rows of {@link ROUTE_CREDENTIAL_PAIRING}.
47
+ */
48
+ export interface RequestRoute {
49
+ credentialSource: RouteCredentialSource;
50
+ carrier?: RouteCarrier;
51
+ carrierBag?: RouteCarrierBag;
52
+ root: RequestRootOrigin;
53
+ }
54
+ /** The route of a request carrying `credential`, rooted at the knob `root` names — the one mint of a
55
+ * {@link RequestRoute}. Reads the credential's SHAPE only; its key value never leaves this function. */
56
+ export declare function requestRouteOf(credential: RouteCredential, root: RequestRootOrigin): RequestRoute;
57
+ /** One row of {@link ROUTE_CREDENTIAL_PAIRING}. */
58
+ export interface RouteCredentialPairingRow {
59
+ readonly credentialSource: RouteCredentialSource;
60
+ readonly carrier?: RouteCarrier;
61
+ readonly carrierBag?: RouteCarrierBag;
62
+ /** The knob(s) the credential is read from, in this engine's own spelling (`getApiKeyAndHeaders` is the per-model
63
+ * auth hook, whose answer reaches the brain as the per-call options). Empty for `"absent"`. */
64
+ readonly credentialKnobs: readonly string[];
65
+ /** The root knob the credential is paired with: `"Model.baseUrl"` for a per-model credential (paired by
66
+ * construction — it was resolved for this entry), `"config.baseUrl"` for the deployment credential (paired only
67
+ * when that root is declared and the request targets it; undeclared = the unpinned posture). Absent for
68
+ * `"absent"`. */
69
+ readonly pairsWith?: "Model.baseUrl" | "config.baseUrl";
70
+ }
71
+ /**
72
+ * The pairing law as a table — one row per route shape a request can carry, in resolution precedence (an earlier
73
+ * row's source wins when several are configured; the three deployment rows are one rank, the deployment credential
74
+ * judged as one). A consumer naming "which key was that" reads the row a {@link RequestRoute} lands on (same
75
+ * `credentialSource` / `carrier` / `carrierBag`), never a sentence. The verdicts the law gives these shapes are the
76
+ * conformance corpus's (`ROUTE_ADJUDICATION_CONFORMANCE_CORPUS`).
77
+ */
78
+ export declare const ROUTE_CREDENTIAL_PAIRING: readonly RouteCredentialPairingRow[];
79
+ /** The pairing row a route lands on, `undefined` for a shape no request carries. */
80
+ export declare function routePairingRowOf(route: Pick<RequestRoute, "credentialSource" | "carrier" | "carrierBag">): RouteCredentialPairingRow | undefined;
81
+ /** A route as a value this engine did not build carries it (a host Brain's message, an adapter's request): each member
82
+ * read once, and the whole value admitted only as a shape some request carries — a {@link ROUTE_CREDENTIAL_PAIRING}
83
+ * row plus a closed-set root. Anything else is no route (absent), never a partial one. */
84
+ export declare function admittedRequestRoute(value: unknown): RequestRoute | undefined;
@@ -0,0 +1,41 @@
1
+ import { readMember } from "../core/thrown-value.js";
2
+ export const ROUTE_CREDENTIAL_SOURCES = Object.freeze(["per-model", "deployment-config", "absent"]);
3
+ export const ROUTE_CARRIERS = Object.freeze(["apiKey", "header"]);
4
+ export const ROUTE_CARRIER_BAGS = Object.freeze(["options", "model", "config"]);
5
+ export const REQUEST_ROOT_ORIGINS = Object.freeze(["model", "deployment", "lane-default"]);
6
+ export function requestRouteOf(credential, root) {
7
+ const carrier = credential.apiKey !== undefined ? "apiKey" : credential.headersBorne === true ? "header" : undefined;
8
+ return {
9
+ credentialSource: credential.source,
10
+ ...(carrier !== undefined ? { carrier } : {}),
11
+ ...(credential.headersBorne === true && credential.carrierBag !== undefined ? { carrierBag: credential.carrierBag } : {}),
12
+ root,
13
+ };
14
+ }
15
+ export const ROUTE_CREDENTIAL_PAIRING = Object.freeze([
16
+ { credentialSource: "per-model", carrier: "apiKey", credentialKnobs: ["getApiKeyAndHeaders().apiKey"], pairsWith: "Model.baseUrl" },
17
+ { credentialSource: "per-model", carrier: "header", carrierBag: "options", credentialKnobs: ["getApiKeyAndHeaders().headers"], pairsWith: "Model.baseUrl" },
18
+ { credentialSource: "per-model", carrier: "header", carrierBag: "model", credentialKnobs: ["Model.headers"], pairsWith: "Model.baseUrl" },
19
+ { credentialSource: "deployment-config", carrier: "apiKey", credentialKnobs: ["config.apiKey"], pairsWith: "config.baseUrl" },
20
+ { credentialSource: "deployment-config", carrier: "apiKey", carrierBag: "config", credentialKnobs: ["config.apiKey", "config.headers"], pairsWith: "config.baseUrl" },
21
+ { credentialSource: "deployment-config", carrier: "header", carrierBag: "config", credentialKnobs: ["config.headers"], pairsWith: "config.baseUrl" },
22
+ { credentialSource: "absent", credentialKnobs: [] },
23
+ ].map((row) => Object.freeze({ ...row, credentialKnobs: Object.freeze([...row.credentialKnobs]) })));
24
+ export function routePairingRowOf(route) {
25
+ return ROUTE_CREDENTIAL_PAIRING.find((row) => row.credentialSource === route.credentialSource && row.carrier === route.carrier && row.carrierBag === route.carrierBag);
26
+ }
27
+ const ROOT_ORIGIN_SET = new Set(REQUEST_ROOT_ORIGINS);
28
+ export function admittedRequestRoute(value) {
29
+ if (value === null || typeof value !== "object")
30
+ return undefined;
31
+ const credentialSource = readMember(value, "credentialSource");
32
+ const carrier = readMember(value, "carrier");
33
+ const carrierBag = readMember(value, "carrierBag");
34
+ const root = readMember(value, "root");
35
+ if (!ROOT_ORIGIN_SET.has(root))
36
+ return undefined;
37
+ const row = ROUTE_CREDENTIAL_PAIRING.find((r) => r.credentialSource === credentialSource && r.carrier === carrier && r.carrierBag === carrierBag);
38
+ if (row === undefined)
39
+ return undefined;
40
+ return { credentialSource: row.credentialSource, ...(row.carrier !== undefined ? { carrier: row.carrier } : {}), ...(row.carrierBag !== undefined ? { carrierBag: row.carrierBag } : {}), root: root };
41
+ }
@@ -24,6 +24,14 @@ export declare function parseRetryAfter(res: Response | undefined): number | und
24
24
  * (a stale stamp carries no wait, so the caller falls back to its computed backoff).
25
25
  */
26
26
  export declare function parseRateLimitReset(res: Response | undefined): number | undefined;
27
+ /**
28
+ * The one read of `anthropic-ratelimit-unified-reset`: the absolute instant (epoch ms, wall clock) the window
29
+ * reopens, or undefined when absent, unparseable or not a positive stamp. The backoff floor above reads it
30
+ * relative to now; a quota verdict carries it as the instant itself (`provider-dialect.ts`).
31
+ */
32
+ export declare function readUnifiedResetEpochMs(headers: {
33
+ get?: (name: string) => string | null;
34
+ } | undefined | null): number | undefined;
27
35
  /**
28
36
  * A single provider wait hint after clamping, carrying enough of its own history to disclose a
29
37
  * truncation: `rawMs` is only set when the response actually asked for more than {@link
@@ -15,14 +15,20 @@ export function parseRetryAfter(res) {
15
15
  return undefined;
16
16
  }
17
17
  export function parseRateLimitReset(res) {
18
- const h = res?.headers?.get?.("anthropic-ratelimit-unified-reset");
18
+ const at = readUnifiedResetEpochMs(res?.headers);
19
+ if (at === undefined)
20
+ return undefined;
21
+ const ms = at - Date.now();
22
+ return ms > 0 ? ms : undefined;
23
+ }
24
+ export function readUnifiedResetEpochMs(headers) {
25
+ const h = headers?.get?.("anthropic-ratelimit-unified-reset");
19
26
  if (!h)
20
27
  return undefined;
21
28
  const epochSecs = Number(h);
22
- if (!Number.isFinite(epochSecs))
29
+ if (!Number.isFinite(epochSecs) || epochSecs <= 0)
23
30
  return undefined;
24
- const ms = Math.round(epochSecs * 1000 - Date.now());
25
- return ms > 0 ? ms : undefined;
31
+ return Math.round(epochSecs * 1000);
26
32
  }
27
33
  function clampHint(rawMs) {
28
34
  return rawMs > MAX_HEADER_WAIT_MS ? { ms: MAX_HEADER_WAIT_MS, rawMs } : { ms: rawMs };
@@ -40,6 +40,7 @@
40
40
  import type { Model } from "../internal/llm.js";
41
41
  import type { RouteAdjudication, RouteCredential, RoutePairingConfig, RoutePairingPosture } from "../internal/llm.js";
42
42
  import type { Brain, EngineNotice } from "../core/types.js";
43
+ import type { RequestRootOrigin } from "./request-route.js";
43
44
  /** A base URL's ROUTE KEY — the value the pairing law COMPARES, folded to WIRE equivalence: the
44
45
  * halves the wire itself treats as case-insensitive (scheme and host, RFC 9110) fold, the scheme's
45
46
  * default port elides, and PATH and QUERY ride byte-preserved apart from the trailing slashes the
@@ -113,6 +114,12 @@ export declare function stripUrlCredentials(text: string): string;
113
114
  * three homes; now it has one. Answers `""` when nothing is declared and the lane has no default —
114
115
  * whether that is a refusal is the caller's. */
115
116
  export declare function resolveRequestRoot(modelBaseUrl: string | undefined, configBaseUrl: string | undefined, laneDefault?: string): string;
117
+ /** {@link resolveRequestRoot} with the knob that named the root beside it (`RequestRootOrigin`) — the one
118
+ * resolution; the root a request build sends to and the root its route states cannot come from two readings. */
119
+ export declare function resolveRequestRootOf(modelBaseUrl: string | undefined, configBaseUrl: string | undefined, laneDefault?: string): {
120
+ root: string;
121
+ origin: RequestRootOrigin;
122
+ };
116
123
  /** Whether a header bag carries an auth-bearing header (any case). */
117
124
  export declare function hasAuthCarrier(headers: Record<string, string> | undefined): boolean;
118
125
  /**
@@ -178,10 +178,14 @@ export function stripUrlCredentials(text) {
178
178
  return text.replace(/([A-Za-z][A-Za-z0-9+.\-]*:\/\/)[^/\s"'@]*@/g, `$1${REDACTED_CREDENTIALS}@`);
179
179
  }
180
180
  export function resolveRequestRoot(modelBaseUrl, configBaseUrl, laneDefault = "") {
181
+ return resolveRequestRootOf(modelBaseUrl, configBaseUrl, laneDefault).root;
182
+ }
183
+ export function resolveRequestRootOf(modelBaseUrl, configBaseUrl, laneDefault = "") {
181
184
  const entry = judgeRequestRoot(modelBaseUrl, "Model.baseUrl");
182
185
  const declared = judgeRequestRoot(configBaseUrl, "config.baseUrl");
186
+ const origin = entry !== undefined ? "model" : declared !== undefined ? "deployment" : "lane-default";
183
187
  const chosen = (entry ?? declared)?.parsed ?? servableParse(laneDefault.trim());
184
- return chosen === undefined ? laneDefault : canonicalRootSpelling(chosen);
188
+ return { root: chosen === undefined ? laneDefault : canonicalRootSpelling(chosen), origin };
185
189
  }
186
190
  export function hasAuthCarrier(headers) {
187
191
  if (!headers)
@@ -130,3 +130,23 @@ export declare function runWithReasoningWireFacts<T>(observe: (f: ReasoningWireF
130
130
  * {@link runWithReasoningWireFacts}).
131
131
  */
132
132
  export declare function reportReasoningWireFacts(facts: ReasoningWireFacts): void;
133
+ /** What a request that is about to be sent had stripped from its model's `extraBody`: the wire adapter's `api`, the catalog id
134
+ * the request was sent as, and the stripped key NAMES (never a value), in `extraBody`'s order. */
135
+ export interface ExtraBodyDroppedReport {
136
+ api: string;
137
+ modelId: string;
138
+ keys: readonly string[];
139
+ }
140
+ /**
141
+ * Run `fn` with a per-run extraBody-strip sink in scope — the FOURTH brain→runner ALS channel, same decoupling contract as
142
+ * its siblings (no brain-interface field, no per-call option, no-op outside the scope, a report never changes a call's
143
+ * outcome). Unlike them it spans the WHOLE leg (the Runner scopes it around everything the leg does, the end-of-task
144
+ * compaction included), is NOT shielded around the leg's internal calls (the compaction summary, a side query fired from a
145
+ * tool, the classifier: their model specs strip keys too), and is NOT revoked on settlement: it writes to no returned value
146
+ * (the report is an out-of-band notice, attributed to its run by id), and the lanes that run after the result — the
147
+ * next-prompt suggestions, a call the guardrail abandoned — strip keys the operator should hear about all the same.
148
+ */
149
+ export declare function runWithExtraBodyDropped<T>(observe: (r: ExtraBodyDroppedReport) => void, fn: () => Promise<T>): Promise<T>;
150
+ /** Report the strip of the request the engine has SELECTED to send, to the active per-run sink, if any (called at the
151
+ * engine's commit points, never from `buildRequest`, which is also built speculatively). */
152
+ export declare function reportExtraBodyDropped(report: ExtraBodyDroppedReport): void;
@@ -57,3 +57,14 @@ export function reportReasoningWireFacts(facts) {
57
57
  catch {
58
58
  }
59
59
  }
60
+ const extraBodyDroppedSinkStore = new AsyncLocalStorage();
61
+ export function runWithExtraBodyDropped(observe, fn) {
62
+ return extraBodyDroppedSinkStore.run({ observe }, fn);
63
+ }
64
+ export function reportExtraBodyDropped(report) {
65
+ try {
66
+ extraBodyDroppedSinkStore.getStore()?.observe(report);
67
+ }
68
+ catch {
69
+ }
70
+ }
@@ -1,4 +1,8 @@
1
- import { type AssistantMessage, type Model, createAssistantMessageEventStream } from "../internal/llm.js";
1
+ import { type AssistantMessage, type Model, type Usage, createAssistantMessageEventStream } from "../internal/llm.js";
2
+ import type { BrainRetryErrClass } from "../core/types.js";
3
+ import type { AssertAllKeysHandled } from "../core/ask-origin.js";
4
+ import { type RequestRoute } from "./request-route.js";
5
+ import { type ProviderDialect } from "./provider-dialect.js";
2
6
  import { type BrainTimeoutConfig } from "./timeout.js";
3
7
  /**
4
8
  * Shared streaming engine for the OpenAI- and Anthropic-shaped brains (design/32, consolidation).
@@ -130,6 +134,21 @@ export interface SSERequest {
130
134
  * come back identical; an adapter that declares nothing therefore permits no body change at all.
131
135
  */
132
136
  capDerivedPaths?: readonly string[];
137
+ /**
138
+ * The keys `Model.extraBody` carried that this adapter owns and therefore stripped from the body
139
+ * ({@link import("./request-params.js").applyExtraBody}'s `dropped`), names only; empty or absent when
140
+ * nothing was stripped. The engine reports them to the run's sink ({@link reportExtraBodyDropped}) when this
141
+ * request is committed to be sent, which is where the Runner announces them.
142
+ */
143
+ extraBodyDropped?: readonly string[];
144
+ /**
145
+ * The route this request takes, as the adapter that built it states it ({@link RequestRoute}, minted by
146
+ * `requestRouteOf` from the same credential and root resolutions the build used). The engine lifts the committed
147
+ * request's route onto the terminal shell of a provider failure (`AssistantMessage.apiErrorRoute`, beside
148
+ * `isApiErrorMessage`) — every failure of the request states the same route, so it is declared once here rather
149
+ * than on each failure. Absent = the adapter states none.
150
+ */
151
+ route?: RequestRoute;
133
152
  /**
134
153
  * Called by the engine once, if and only if THIS request becomes the one that is sent.
135
154
  *
@@ -168,6 +187,20 @@ export interface StreamControls {
168
187
  sawContentToken(): void;
169
188
  /** Cancel the underlying stream (e.g. degenerate-repetition cutoff). The read loop then ends. */
170
189
  cancel(): void;
190
+ /** The endpoint this call goes to, as the provider dialect table names it (`undefined` = none declares it):
191
+ * what an in-band error frame is judged by. */
192
+ dialect: ProviderDialect | undefined;
193
+ /** Hand the engine what this attempt produced — its final content and the provider-reported usage — before
194
+ * raising the provider's own in-band failure from `finalize`: the terminal message the engine mints for that
195
+ * failure keeps it (the text the provider streamed, the usage it reported), rather than an empty shell. */
196
+ keepOutput(output: KeptOutput): void;
197
+ }
198
+ /** The output a parser hands over with {@link StreamControls.keepOutput}. */
199
+ export interface KeptOutput {
200
+ content: AssistantMessage["content"];
201
+ usage: Usage;
202
+ /** The provider reported no usage frame (the zeros are not a measurement). */
203
+ usageMissing?: true;
171
204
  }
172
205
  export interface StreamParser {
173
206
  /** Handle one raw SSE line (`data: {...}`); parse, emit events, call `ctrl.sawContentToken()` on content. */
@@ -215,6 +248,23 @@ export interface StreamParser {
215
248
  */
216
249
  sealForRetry(): void;
217
250
  }
251
+ /**
252
+ * The phase a retry-wait frame of each {@link BrainRetryErrClass} carries — ONE table, so a frame's two
253
+ * classifications are never mapped separately: the phase is what the brain is doing about the wait (waiting
254
+ * out a rate limit, re-connecting, re-sending), read off why it waits. Every retry-wait frame this engine
255
+ * emits — the connect ladder, the first-byte lane, the output-cap re-send, the mid-stream tiers — reads it.
256
+ */
257
+ declare const RETRY_PHASE_OF_ERR_CLASS: {
258
+ readonly connect_refused: "reconnecting";
259
+ readonly transport: "reconnecting";
260
+ readonly stall: "reconnecting";
261
+ readonly rate_limit: "rate_limited";
262
+ readonly server: "retrying";
263
+ readonly http: "retrying";
264
+ readonly output_cap: "retrying";
265
+ };
266
+ /** Compile-time fence: every retry class has a phase row. */
267
+ export type RetryPhaseTableCoversEveryErrClass = AssertAllKeysHandled<Exclude<BrainRetryErrClass, keyof typeof RETRY_PHASE_OF_ERR_CLASS>>;
218
268
  /**
219
269
  * Run one streaming request end-to-end and drive the provider `parser`. Returns a fresh event stream;
220
270
  * never throws (errors are pushed as `error` events, mirroring the Brain contract).
@@ -249,3 +299,4 @@ export declare function runStreamingBrain(args: {
249
299
  * and never more than the brain's own budget ({@link resolveMaxRetries}); a non-finite or negative value caps nothing. */
250
300
  maxRetries?: number;
251
301
  }): ReturnType<typeof createAssistantMessageEventStream>;
302
+ export {};