@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
@@ -1,12 +1,13 @@
1
1
  import {} from "../internal/llm.js";
2
2
  import { BrainError } from "./errors.js";
3
3
  import { DEGENERATE_MESSAGE, trimDegenerateTail } from "./repetition.js";
4
- import { STREAM_TORN_WARNING, createRepetitionPoll, noteResponseModel, parseStreamedToolArgs, placeTurnNotes } from "./stream-shared.js";
4
+ import { STREAM_TORN_WARNING, createRepetitionPoll, modelOutputInvalidOf, noteResponseModel, nameMissingCause, parseStreamedToolArgs, placeTurnNotes } from "./stream-shared.js";
5
5
  import { admitToolCallId, providerResultIds, providerToolCallId, responseToolCallIds } from "./tool-call-id.js";
6
6
  import { emitBrainTelemetry } from "./status-sink.js";
7
7
  import { errorResultMediaNote, IMAGE_OMITTED_NO_VISION, imagesOmittedNoVisionNote, modelSupportsVision, sendableImages } from "./media-degrade.js";
8
8
  import { OUTPUT_CAP_KEYS, RESPONSES_RESERVED, applyExtraBody, effectiveOutputCap, lockHeader, mergeHeaders } from "./request-params.js";
9
- import { adjudicateModelRoute, applyRouteCredentialHeaders, assertServableRequestRoot, createBrainRouteJudge, joinRequestUrl, resolveRequestRoot, resolveRouteCredential, routeRefusalText } from "./route-adjudicator.js";
9
+ import { adjudicateModelRoute, applyRouteCredentialHeaders, assertServableRequestRoot, createBrainRouteJudge, joinRequestUrl, resolveRequestRootOf, resolveRouteCredential, routeRefusalText } from "./route-adjudicator.js";
10
+ import { requestRouteOf } from "./request-route.js";
10
11
  import { declaredOffSpelling, mintEffortWireValue, reasoningRequestCarried } from "./reasoning.js";
11
12
  import { runStreamingBrain } from "./stream-engine.js";
12
13
  import { refuseRetiredTimeoutKnobs } from "./timeout.js";
@@ -199,12 +200,12 @@ function responsesErrorCode(code) {
199
200
  const INCOMPLETE_MAX_OUTPUT_TOKENS = "max_output_tokens";
200
201
  const INCOMPLETE_CONTENT_FILTER = "content_filter";
201
202
  const RESPONSE_INCOMPLETE_WARNING = 'The response above may be incomplete: the endpoint reported status "incomplete" with no reason this client recognises.';
202
- function closeFunctionCall(acc, responseIds) {
203
+ function closeFunctionCall(acc, responseIds, closed) {
203
204
  if (acc.closedTc)
204
205
  return acc.closedTc;
205
206
  if (!acc.name)
206
207
  return undefined;
207
- const args = parseStreamedToolArgs(acc.args);
208
+ const args = parseStreamedToolArgs(acc.args, closed);
208
209
  if (args === undefined)
209
210
  return undefined;
210
211
  const { engineId, wireId } = admitToolCallId(acc.callId, "call_", responseIds);
@@ -237,7 +238,7 @@ export function createOpenResponsesBrain(config = {}) {
237
238
  maxRetries: options?.maxRetries,
238
239
  stallTimeouts: options?.stallTimeouts,
239
240
  buildRequest: (overrides) => {
240
- const root = resolveRequestRoot(model.baseUrl, config.baseUrl);
241
+ const { root, origin: rootOrigin } = resolveRequestRootOf(model.baseUrl, config.baseUrl);
241
242
  if (!root) {
242
243
  throw new Error("createOpenResponsesBrain: no baseUrl configured (set config.baseUrl or model.baseUrl)");
243
244
  }
@@ -288,11 +289,13 @@ export function createOpenResponsesBrain(config = {}) {
288
289
  lockHeader(headers, "content-type", "application/json");
289
290
  if (apiKey)
290
291
  headers["authorization"] = `Bearer ${apiKey}`;
291
- const wire = applyExtraBody(body, model.extraBody, RESPONSES_RESERVED);
292
+ const { body: wire, dropped: extraBodyDropped } = applyExtraBody(body, model.extraBody, RESPONSES_RESERVED);
292
293
  return {
293
294
  url: joinRequestUrl(root, "/responses"),
294
295
  headers,
295
296
  body: JSON.stringify(wire),
297
+ extraBodyDropped,
298
+ route: requestRouteOf(routeCredential, rootOrigin),
296
299
  outputCapTokens: effectiveOutputCap(wire, OUTPUT_CAP_KEYS.responses),
297
300
  capDerivedPaths: OUTPUT_CAP_KEYS.responses,
298
301
  onCommitted: () => {
@@ -343,7 +346,7 @@ export function createOpenResponsesBrain(config = {}) {
343
346
  }
344
347
  };
345
348
  const openItem = (index, kind, itemId) => {
346
- const acc = { kind, text: "", itemId, callId: "", name: "", args: "", closed: false };
349
+ const acc = { kind, text: "", itemId, callId: "", name: "", args: "", closed: false, itemDone: false };
347
350
  items.set(index, acc);
348
351
  return acc;
349
352
  };
@@ -413,7 +416,7 @@ export function createOpenResponsesBrain(config = {}) {
413
416
  out.push({ type: "text_end", contentIndex: index, content: messageFace(acc), partial: { ...partial } });
414
417
  }
415
418
  else {
416
- const tc = closeFunctionCall(acc, responseIds);
419
+ const tc = closeFunctionCall(acc, responseIds, true);
417
420
  if (tc)
418
421
  out.push({ type: "toolcall_end", contentIndex: index, toolCall: tc, partial: { ...partial } });
419
422
  }
@@ -544,6 +547,7 @@ export function createOpenResponsesBrain(config = {}) {
544
547
  }
545
548
  if (!acc.itemId && frame.item?.id)
546
549
  acc.itemId = frame.item.id;
550
+ acc.itemDone = true;
547
551
  closeItem(index, acc);
548
552
  return;
549
553
  }
@@ -631,6 +635,7 @@ export function createOpenResponsesBrain(config = {}) {
631
635
  const unnamed = [];
632
636
  let anyText = false;
633
637
  let reasoningSeen = false;
638
+ const endedCut = terminalStatus === undefined || terminalStatus === "incomplete";
634
639
  for (const [, acc] of [...items.entries()].sort((a, b) => a[0] - b[0])) {
635
640
  if (acc.kind === "reasoning") {
636
641
  if (acc.text.length === 0)
@@ -651,7 +656,8 @@ export function createOpenResponsesBrain(config = {}) {
651
656
  }
652
657
  }
653
658
  else {
654
- const tc = closeFunctionCall(acc, responseIds);
659
+ const closed = acc.itemDone || !endedCut;
660
+ const tc = closeFunctionCall(acc, responseIds, closed);
655
661
  if (tc) {
656
662
  toolCalls.push(tc);
657
663
  finalContent.push(tc);
@@ -660,7 +666,7 @@ export function createOpenResponsesBrain(config = {}) {
660
666
  malformed.push(`${acc.name}(${acc.args.slice(0, MALFORMED_ARGS_CHARS)})`);
661
667
  }
662
668
  else {
663
- unnamed.push(`call_id="${acc.callId || "?"}"(${acc.args.slice(0, MALFORMED_ARGS_CHARS)})`);
669
+ (nameMissingCause(closed) === "truncated" ? malformed : unnamed).push(`call_id="${acc.callId || "?"}"(${acc.args.slice(0, MALFORMED_ARGS_CHARS)})`);
664
670
  }
665
671
  }
666
672
  }
@@ -728,6 +734,8 @@ export function createOpenResponsesBrain(config = {}) {
728
734
  : !safetyCut && !refused && toolError === undefined && truncatedEmpty && !dynamicCut && !staticReasoningCut
729
735
  ? "length_empty"
730
736
  : undefined;
737
+ const capFacts = { capStop: truncated, outputTokens: usageRaw?.output_tokens, capTokens: sentMaxTokens };
738
+ const modelOutputInvalid = errored && toolError !== undefined && !degenerate && !safetyCut && !refused ? modelOutputInvalidOf({ truncated: malformed.length, unnamed: unnamed.length }, capFacts) : undefined;
731
739
  const diagnostics = capabilityNotes.length > 0
732
740
  ? [...(partial.diagnostics ?? []), { type: CAPABILITY_DIAGNOSTIC_TYPE, timestamp: Date.now(), details: { notes: [...capabilityNotes] } }]
733
741
  : [];
@@ -741,6 +749,7 @@ export function createOpenResponsesBrain(config = {}) {
741
749
  ...(responseId !== undefined ? { responseId } : {}),
742
750
  ...(errorMessageOut ? { errorMessage: errorMessageOut } : {}),
743
751
  ...(errorKind ? { errorKind } : {}),
752
+ ...(modelOutputInvalid !== undefined ? { modelOutputInvalid } : {}),
744
753
  ...(tornWithContent ? { partialFinalized: true } : {}),
745
754
  ...(rep.cut !== undefined || rep.spared.length > 0
746
755
  ? { repetition: { ...(rep.cut !== undefined ? { cut: rep.cut } : {}), ...(rep.spared.length > 0 ? { spared: rep.spared } : {}) } }
@@ -1,23 +1,25 @@
1
1
  import {} from "../internal/llm.js";
2
2
  import { repairTextToolCalls } from "./tool-call-repair.js";
3
3
  import { DEGENERATE_MESSAGE, trimDegenerateTail } from "./repetition.js";
4
- import { STREAM_TORN_WARNING, createRepetitionPoll, noteResponseModel, parseStreamedToolArgs, placeTurnNotes, truncationCauseClause } from "./stream-shared.js";
4
+ import { STREAM_TORN_WARNING, createRepetitionPoll, createStreamEndLedger, echoFoldedWord, modelOutputInvalidOf, noteResponseModel, nameMissingCause, parseStreamedToolArgs, placeTurnNotes, truncationCauseClause } from "./stream-shared.js";
5
5
  import { admitToolCallId, providerResultIds, providerToolCallId, responseToolCallIds } from "./tool-call-id.js";
6
6
  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, lockHeader, mergeHeaders } from "./request-params.js";
9
- import { BrainError } from "./errors.js";
10
- import { adjudicateModelRoute, applyRouteCredentialHeaders, assertServableRequestRoot, createBrainRouteJudge, joinRequestUrl, resolveRequestRoot, resolveRouteCredential, routeRefusalText } from "./route-adjudicator.js";
9
+ import { BrainError, providerErrorWord } from "./errors.js";
10
+ import { inBandProviderError } from "./provider-dialect.js";
11
+ import { adjudicateModelRoute, applyRouteCredentialHeaders, assertServableRequestRoot, createBrainRouteJudge, joinRequestUrl, resolveRequestRootOf, resolveRouteCredential, routeRefusalText } from "./route-adjudicator.js";
12
+ import { requestRouteOf } from "./request-route.js";
11
13
  import { declaredOffSpelling, mintEffortWireValue, reasoningRequestCarried } from "./reasoning.js";
12
14
  import { runStreamingBrain } from "./stream-engine.js";
13
15
  import { refuseRetiredTimeoutKnobs } from "./timeout.js";
14
16
  import { resolveFetch } from "./transport.js";
15
- function closeToolCallAccum(acc, responseIds) {
17
+ function closeToolCallAccum(acc, responseIds, closed) {
16
18
  if (acc.closedTc)
17
19
  return acc.closedTc;
18
20
  if (!acc.name)
19
21
  return undefined;
20
- const args = parseStreamedToolArgs(acc.args);
22
+ const args = parseStreamedToolArgs(acc.args, closed);
21
23
  if (args === undefined)
22
24
  return undefined;
23
25
  const { engineId, wireId } = admitToolCallId(acc.id, "call_", responseIds);
@@ -250,6 +252,45 @@ function toOpenAITools(ctx) {
250
252
  function: { name: t.name, description: t.description, parameters: t.parameters },
251
253
  }));
252
254
  }
255
+ const FINISH_REASON_READINGS = Object.freeze({
256
+ stop: { kind: "finished" },
257
+ length: { kind: "finished" },
258
+ tool_calls: { kind: "finished" },
259
+ function_call: { kind: "finished" },
260
+ content_filter: { kind: "refusal" },
261
+ sensitive: { kind: "refusal" },
262
+ model_context_window_exceeded: { kind: "input_too_long" },
263
+ insufficient_system_resource: { kind: "provider_cut", code: "server" },
264
+ aborted: { kind: "provider_cut", code: "server" },
265
+ network_error: { kind: "provider_cut", code: "network" },
266
+ });
267
+ function deltaOf(raw) {
268
+ return typeof raw === "object" && raw !== null && !Array.isArray(raw) ? raw : undefined;
269
+ }
270
+ function finishWordOf(raw) {
271
+ if (!raw)
272
+ return null;
273
+ return typeof raw === "string" ? raw : "?";
274
+ }
275
+ function lateContentKind(delta) {
276
+ if (delta === undefined)
277
+ return undefined;
278
+ const calls = delta.tool_calls;
279
+ if (calls !== undefined && calls !== null && !(Array.isArray(calls) && calls.length === 0))
280
+ return "tool_calls";
281
+ if (delta.refusal)
282
+ return "refusal";
283
+ if (delta.content)
284
+ return "text";
285
+ if (delta.reasoning || delta.reasoning_content)
286
+ return "reasoning";
287
+ return undefined;
288
+ }
289
+ function readFinishReason(reason) {
290
+ if (reason == null)
291
+ return undefined;
292
+ return Object.hasOwn(FINISH_REASON_READINGS, reason) ? FINISH_REASON_READINGS[reason] : { kind: "unrecognized" };
293
+ }
253
294
  function mapFinishReason(reason, hadToolCalls) {
254
295
  if (hadToolCalls) {
255
296
  return "toolUse";
@@ -300,7 +341,7 @@ export function createOpenAIBrain(config = {}) {
300
341
  maxRetries: options?.maxRetries,
301
342
  stallTimeouts: options?.stallTimeouts,
302
343
  buildRequest: (overrides) => {
303
- const root = resolveRequestRoot(model.baseUrl, config.baseUrl);
344
+ const { root, origin: rootOrigin } = resolveRequestRootOf(model.baseUrl, config.baseUrl);
304
345
  if (!root) {
305
346
  throw new Error("createOpenAIBrain: no baseUrl configured (set config.baseUrl or model.baseUrl)");
306
347
  }
@@ -348,11 +389,13 @@ export function createOpenAIBrain(config = {}) {
348
389
  lockHeader(headers, "content-type", "application/json");
349
390
  if (apiKey)
350
391
  headers["authorization"] = `Bearer ${apiKey}`;
351
- const wire = applyExtraBody(body, model.extraBody, OPENAI_RESERVED);
392
+ const { body: wire, dropped: extraBodyDropped } = applyExtraBody(body, model.extraBody, OPENAI_RESERVED);
352
393
  return {
353
394
  url: joinRequestUrl(root, "/chat/completions"),
354
395
  headers,
355
396
  body: JSON.stringify(wire),
397
+ extraBodyDropped,
398
+ route: requestRouteOf(routeCredential, rootOrigin),
356
399
  outputCapTokens: effectiveOutputCap(wire, OUTPUT_CAP_KEYS.openai),
357
400
  capDerivedPaths: [mtField],
358
401
  onCommitted: () => {
@@ -379,7 +422,9 @@ export function createOpenAIBrain(config = {}) {
379
422
  const toolAccum = new Map();
380
423
  const responseIds = responseToolCallIds();
381
424
  let finishReason = null;
382
- const terminalFrameSeen = () => finishReason != null;
425
+ let inBandError;
426
+ const afterEnd = createStreamEndLedger();
427
+ const terminalFrameSeen = () => finishReason != null || inBandError !== undefined;
383
428
  let usageRaw;
384
429
  let malformedFrames = 0;
385
430
  let malformedSample;
@@ -452,6 +497,8 @@ export function createOpenAIBrain(config = {}) {
452
497
  closeThinking();
453
498
  },
454
499
  onLine(rawLine) {
500
+ if (inBandError !== undefined)
501
+ return;
455
502
  const line = rawLine.trim();
456
503
  if (!line.startsWith("data:"))
457
504
  return;
@@ -467,15 +514,34 @@ export function createOpenAIBrain(config = {}) {
467
514
  malformedSample ??= data.slice(0, 160);
468
515
  return;
469
516
  }
517
+ const stated = chunk.error;
518
+ if (typeof stated === "object" && stated !== null && !Array.isArray(stated)) {
519
+ if (terminalFrameSeen()) {
520
+ afterEnd.note("error", providerErrorWord(stated) ?? "?");
521
+ return;
522
+ }
523
+ inBandError = inBandProviderError(ctrl.dialect, stated, "gateway");
524
+ ctrl.cancel();
525
+ return;
526
+ }
470
527
  if (chunk.usage)
471
528
  usageRaw = chunk.usage;
472
529
  noteResponseModel(partial, chunk.model, model.id);
473
530
  const choice = chunk.choices?.[0];
474
531
  if (!choice)
475
532
  return;
476
- if (choice.finish_reason)
477
- finishReason = choice.finish_reason;
478
- const delta = choice.delta;
533
+ const finishWord = finishWordOf(choice.finish_reason);
534
+ if (terminalFrameSeen()) {
535
+ const late = lateContentKind(deltaOf(choice.delta));
536
+ if (finishWord !== null && finishWord !== finishReason)
537
+ afterEnd.note("ending", finishWord);
538
+ else if (late !== undefined)
539
+ afterEnd.note("content", late);
540
+ return;
541
+ }
542
+ if (finishWord !== null)
543
+ finishReason = finishWord;
544
+ const delta = deltaOf(choice.delta);
479
545
  if (delta?.reasoning)
480
546
  pushReasoningDelta(delta.reasoning);
481
547
  else if (delta?.reasoning_content)
@@ -486,7 +552,7 @@ export function createOpenAIBrain(config = {}) {
486
552
  }
487
553
  if (delta?.content)
488
554
  pushTextDelta(delta.content);
489
- if (delta?.tool_calls) {
555
+ if (Array.isArray(delta?.tool_calls)) {
490
556
  ctrl.sawContentToken();
491
557
  for (const tc of delta.tool_calls) {
492
558
  const idx = tc.index ?? (tc.id ? toolAccum.size : Math.max(0, toolAccum.size - 1));
@@ -496,9 +562,9 @@ export function createOpenAIBrain(config = {}) {
496
562
  continue;
497
563
  if (prevAcc.args === "")
498
564
  continue;
499
- const closed = closeToolCallAccum(prevAcc, responseIds);
500
- if (closed) {
501
- out.push({ type: "toolcall_end", contentIndex: prevIdx, toolCall: closed, partial: { ...partial } });
565
+ const done = closeToolCallAccum(prevAcc, responseIds, false);
566
+ if (done) {
567
+ out.push({ type: "toolcall_end", contentIndex: prevIdx, toolCall: done, partial: { ...partial } });
502
568
  }
503
569
  }
504
570
  }
@@ -516,7 +582,7 @@ export function createOpenAIBrain(config = {}) {
516
582
  finalize(opts) {
517
583
  closeThinking();
518
584
  const textFace = degenerate && degenFace === "text" && rep.cut !== undefined ? trimDegenerateTail(accumText, rep.cut) : accumText;
519
- if (emittedTextStart && (opts?.truncated !== true || finishReason != null)) {
585
+ if (emittedTextStart && ((opts?.truncated !== true && inBandError === undefined) || finishReason != null)) {
520
586
  out.push({ type: "text_end", contentIndex: textIndex, content: textFace, partial: { ...partial } });
521
587
  }
522
588
  const finalContent = [];
@@ -528,16 +594,17 @@ export function createOpenAIBrain(config = {}) {
528
594
  const malformed = [];
529
595
  const unnamed = [];
530
596
  let emptyPlaceholders = 0;
597
+ const endedCut = finishReason === "length" || finishReason == null;
531
598
  for (const acc of [...toolAccum.entries()].sort((a, b) => a[0] - b[0]).map((e) => e[1])) {
532
599
  if (!acc.name) {
533
600
  if (!acc.id && acc.args === "") {
534
601
  emptyPlaceholders++;
535
602
  continue;
536
603
  }
537
- unnamed.push(`id="${acc.id || "?"}"(${acc.args.slice(0, 200)})`);
604
+ (nameMissingCause(!endedCut) === "truncated" ? malformed : unnamed).push(`id="${acc.id || "?"}"(${acc.args.slice(0, 200)})`);
538
605
  continue;
539
606
  }
540
- const tc = closeToolCallAccum(acc, responseIds);
607
+ const tc = closeToolCallAccum(acc, responseIds, !endedCut);
541
608
  if (tc) {
542
609
  toolCalls.push(tc);
543
610
  finalContent.push(tc);
@@ -570,8 +637,9 @@ export function createOpenAIBrain(config = {}) {
570
637
  unnamed.push(emptyPlaceholders > 0 ? emptySlots : "<no tool_call delta arrived on the stream>");
571
638
  }
572
639
  const toolErrorParts = [];
640
+ const capFacts = { capStop: finishReason === "length", outputTokens: usageRaw?.completion_tokens, capTokens: sentMaxTokens };
573
641
  if (malformed.length > 0) {
574
- toolErrorParts.push(`tool call argument(s) not valid JSON (likely truncated, finish_reason="${finishReason ?? "?"}"${truncationCauseClause({ capStop: finishReason === "length", outputTokens: usageRaw?.completion_tokens, capTokens: sentMaxTokens, terminalFrameSeen: terminalFrameSeen() })}): ${malformed.join("; ")}`);
642
+ toolErrorParts.push(`tool call argument(s) not valid JSON (likely truncated, finish_reason="${finishReason ?? "?"}"${truncationCauseClause({ ...capFacts, terminalFrameSeen: terminalFrameSeen() })}): ${malformed.join("; ")}`);
575
643
  }
576
644
  if (unnamed.length > 0) {
577
645
  toolErrorParts.push(`tool call(s) arrived with no tool name and cannot be executed (finish_reason="${finishReason ?? "?"}"): ${unnamed.join("; ")}`);
@@ -589,9 +657,18 @@ export function createOpenAIBrain(config = {}) {
589
657
  notes.push({ cause: "bad_frame", count: malformedFrames, text: `\n[note: ${malformedFrames} provider stream frame(s) were not valid JSON and were dropped — the streamed output may be missing content (first sample: ${JSON.stringify(malformedSample)})]` });
590
658
  }
591
659
  placeTurnNotes(partial, finalContent, notes);
660
+ if (inBandError !== undefined) {
661
+ ctrl.keepOutput({ content: finalContent, usage: computeUsage(model, usageRaw), ...(usageRaw === undefined ? { usageMissing: true } : {}) });
662
+ throw inBandError;
663
+ }
592
664
  const truncatedEmpty = finishReason === "length" && noUsableContent && !toolError;
593
665
  const dynamicCut = truncatedEmpty && options?.maxTokensDynamic === true;
594
- const safetyCut = finishReason === "content_filter";
666
+ const finishReading = readFinishReason(finishReason);
667
+ const safetyCut = finishReading?.kind === "refusal";
668
+ const contextWindowExceeded = finishReading?.kind === "input_too_long";
669
+ const providerCut = finishReading?.kind === "provider_cut" ? finishReading : undefined;
670
+ const finishReasonUnknown = finishReading?.kind === "unrecognized" ? echoFoldedWord(finishReason ?? "") : undefined;
671
+ const finishQuoted = JSON.stringify((finishReason ?? "").slice(0, 64));
595
672
  const refused = accumRefusal.trim().length > 0;
596
673
  const emptyNoFinish = noUsableContent && finishReason == null && !degenerate;
597
674
  const maxTokensNote = sentMaxTokens !== undefined
@@ -604,20 +681,26 @@ export function createOpenAIBrain(config = {}) {
604
681
  const errorMessage = degenerate
605
682
  ? DEGENERATE_MESSAGE
606
683
  : safetyCut
607
- ? `[refusal] response cut by the provider content filter (finish_reason="content_filter") — the output was censored/truncated for policy and is unreliable`
684
+ ? `[refusal] response cut by the provider content filter (finish_reason=${finishQuoted}) — the output was censored/truncated for policy and is unreliable`
608
685
  : refused
609
686
  ? `[refusal] response refused by the model for policy reasons: ${accumRefusal.trim()}`
610
- : (toolError ??
611
- (truncatedEmpty && !dynamicCut
612
- ? accumReasoning.trim()
613
- ? `[length_empty] response truncated at max_tokens (finish_reason="length", ${maxTokensNote}) with no answer text — the model spent the whole budget on reasoning (${accumReasoning.length} reasoning chars). Raise max_tokens, or disable thinking for this task.`
614
- : `[length_empty] response truncated at max_tokens (finish_reason="length", ${maxTokensNote}) with no answer text — raise max_tokens`
615
- : emptyNoFinish
616
- ? `[stream_torn] model stream ended with no content and no finish_reason — the response was lost (a torn stream or an in-band provider error frame)${malformedFrames > 0 ? ` — ${malformedFrames} unparseable data frame(s) were dropped on this stream (first sample: ${JSON.stringify(malformedSample)})` : ""}`
617
- : undefined));
687
+ : contextWindowExceeded
688
+ ? `[invalid_request] model context window exceeded (finish_reason=${finishQuoted}) — the conversation no longer fits the model's context window`
689
+ : providerCut !== undefined
690
+ ? `[${providerCut.code}] response cut short by the provider (finish_reason=${finishQuoted}) — the text above may be incomplete`
691
+ : (toolError ??
692
+ (truncatedEmpty && !dynamicCut
693
+ ? accumReasoning.trim()
694
+ ? `[length_empty] response truncated at max_tokens (finish_reason="length", ${maxTokensNote}) with no answer text — the model spent the whole budget on reasoning (${accumReasoning.length} reasoning chars). Raise max_tokens, or disable thinking for this task.`
695
+ : `[length_empty] response truncated at max_tokens (finish_reason="length", ${maxTokensNote}) with no answer text — raise max_tokens`
696
+ : emptyNoFinish
697
+ ? `[stream_torn] model stream ended with no content and no finish_reason — the response was lost (a torn stream or an in-band provider error frame)${malformedFrames > 0 ? ` — ${malformedFrames} unparseable data frame(s) were dropped on this stream (first sample: ${JSON.stringify(malformedSample)})` : ""}`
698
+ : undefined));
618
699
  const errored = degenerate ||
619
700
  safetyCut ||
620
701
  refused ||
702
+ contextWindowExceeded ||
703
+ providerCut !== undefined ||
621
704
  emptyNoFinish ||
622
705
  (toolError !== undefined && noUsableContent) ||
623
706
  (truncatedEmpty && !dynamicCut);
@@ -625,9 +708,14 @@ export function createOpenAIBrain(config = {}) {
625
708
  const errorMessageOut = tornWithContent ? (errorMessage ? `${errorMessage}\n${STREAM_TORN_WARNING}` : STREAM_TORN_WARNING) : errorMessage;
626
709
  const errorKind = degenerate
627
710
  ? "degenerate"
628
- : !safetyCut && !refused && toolError === undefined && truncatedEmpty && !dynamicCut
629
- ? "length_empty"
630
- : undefined;
711
+ : !safetyCut && !refused && contextWindowExceeded
712
+ ? "input_too_long"
713
+ : !safetyCut && !refused && toolError === undefined && truncatedEmpty && !dynamicCut
714
+ ? "length_empty"
715
+ : undefined;
716
+ const modelOutputInvalid = errored && toolError !== undefined && !degenerate && !safetyCut && !refused && !contextWindowExceeded && providerCut === undefined
717
+ ? modelOutputInvalidOf({ truncated: malformed.length, unnamed: unnamed.length }, capFacts)
718
+ : undefined;
631
719
  const finalMessage = {
632
720
  ...partial,
633
721
  content: finalContent.length > 0 ? finalContent : [{ type: "text", text: "" }],
@@ -637,7 +725,10 @@ export function createOpenAIBrain(config = {}) {
637
725
  timestamp: Date.now(),
638
726
  ...(errorMessageOut ? { errorMessage: errorMessageOut } : {}),
639
727
  ...(errorKind ? { errorKind } : {}),
728
+ ...(modelOutputInvalid !== undefined ? { modelOutputInvalid } : {}),
640
729
  ...(tornWithContent ? { partialFinalized: true } : {}),
730
+ ...(finishReasonUnknown !== undefined ? { finishReasonUnknown } : {}),
731
+ ...(afterEnd.ignored !== undefined ? { streamEndIgnored: afterEnd.ignored } : {}),
641
732
  ...(rep.cut !== undefined || rep.spared.length > 0
642
733
  ? { repetition: { ...(rep.cut !== undefined ? { cut: rep.cut } : {}), ...(rep.spared.length > 0 ? { spared: rep.spared } : {}) } }
643
734
  : {}),
@@ -0,0 +1,214 @@
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.
4
+ *
5
+ * KEY. An endpoint is named by (wire family, host suffix + path): the same brand can serve two endpoints whose
6
+ * failures read in opposite ways (Moonshot's open platform states an exhausted balance as a 429, its coding
7
+ * subscription states a spent usage window as a 403 and keeps 429 for momentary overload), and the same word
8
+ * can mean opposite things on two brands (`insufficient_quota` is a per-minute token limit on DashScope and an
9
+ * empty balance on OpenAI). So the table is keyed by where the request went, never by vendor name or by word.
10
+ * A request whose endpoint matches no key reads only the GENERIC rows: the statements whose meaning does not
11
+ * depend on who said them.
12
+ *
13
+ * COLUMNS. A dialect is a record of named columns about one endpoint. `failures` is the failure-classification
14
+ * column: rows that turn a status, the envelope's word (`error.code`, else `error.type` — the same word
15
+ * `apiErrorCode` carries) and the envelope's sentence (`error.message`) into one {@link ProviderCondition}. The
16
+ * 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
+ *
19
+ * ONE VERDICT, TWO SEATS. {@link judgeHttpFailure} answers once per failed response; the retry decision, the
20
+ * retry frame (`BrainStatus.providerCondition`) and the terminal (`BrainError` → `AssistantMessage` →
21
+ * `terminal.detail`) all read that answer. An in-band error frame (a provider error delivered inside a 200
22
+ * stream) is judged by {@link judgeInBandError} over the same rows.
23
+ *
24
+ * DEGRADATION DIRECTION. Every row whose evidence is prose is fragile (a provider rewords and the row stops
25
+ * matching). A row that stops matching falls to the endpoint's own status row, then to the generic rows, then
26
+ * to the status alone — which in every case is the retrying reading, never the stopping one: a missed quota
27
+ * costs a backoff ladder, a false quota costs the user a run.
28
+ */
29
+ import type { Model } from "../internal/llm.js";
30
+ import type { AssertAllKeysHandled } from "../core/ask-origin.js";
31
+ import { BrainError, type FailedBody } from "./errors.js";
32
+ /**
33
+ * What the provider said about the account or its own capacity when it failed a request — the one closed set
34
+ * both the retry frame and the terminal report:
35
+ * - `quota_exhausted` — the account cannot be served until someone acts or a window resets (an empty balance,
36
+ * an overdue bill, a spent usage window, a free tier used up). Not retried.
37
+ * - `throttled` — slow down: a request / token rate limit that clears on its own. Retried (backoff, the
38
+ * provider's `Retry-After` as the floor).
39
+ * - `overloaded` — the provider's own capacity, not the account's. Retried.
40
+ * - `stop_other` — a refusal that resending cannot change (credentials, model access, the request itself, its
41
+ * content, the plan's tier). Not retried. A context-limit refusal is one of these and is ALSO typed
42
+ * `input_too_long` on its own seat.
43
+ * - `unknown` — the endpoint said nothing this table can read. Retried exactly as the status alone would be.
44
+ */
45
+ export declare const PROVIDER_CONDITIONS: readonly ["quota_exhausted", "throttled", "overloaded", "stop_other", "unknown"];
46
+ export type ProviderCondition = (typeof PROVIDER_CONDITIONS)[number];
47
+ /**
48
+ * Which evidence the condition rests on:
49
+ * - `unified_header` — a subscription quota header (`anthropic-ratelimit-unified-representative-claim` /
50
+ * `-overage-status` / `-overage-disabled-reason`) on a 429.
51
+ * - `provider_code` — a row keyed on the envelope's word (`error.code`, else `error.type`) or its sentence
52
+ * (`error.message`) matched.
53
+ * - `status` — no row read the envelope (none arrived, it did not end, or no row names its word or sentence): the
54
+ * default for what arrived — the endpoint's row for the status, else the generic row, else the status alone; an
55
+ * in-band error frame, which states no status, defaults to `unknown`.
56
+ */
57
+ export declare const PROVIDER_CONDITION_SOURCES: readonly ["unified_header", "provider_code", "status"];
58
+ export type ProviderConditionSource = (typeof PROVIDER_CONDITION_SOURCES)[number];
59
+ /**
60
+ * What each condition means to this engine — the one place retryability lives:
61
+ * - `retryable` — the connect ladder re-sends a response judged so (the provider's explicit `x-should-retry`
62
+ * verdict still outranks it, in both directions);
63
+ * - `inBandCode` — the brain error code an in-band error frame carries (it has no status to classify by).
64
+ */
65
+ export declare const PROVIDER_CONDITION_TRAITS: {
66
+ readonly quota_exhausted: {
67
+ readonly retryable: false;
68
+ readonly inBandCode: "rate_limit";
69
+ };
70
+ readonly throttled: {
71
+ readonly retryable: true;
72
+ readonly inBandCode: "rate_limit";
73
+ };
74
+ readonly overloaded: {
75
+ readonly retryable: true;
76
+ readonly inBandCode: "server";
77
+ };
78
+ readonly stop_other: {
79
+ readonly retryable: false;
80
+ readonly inBandCode: "invalid_request";
81
+ };
82
+ readonly unknown: {
83
+ readonly retryable: true;
84
+ readonly inBandCode: "server";
85
+ };
86
+ };
87
+ /** Compile-time fence: every condition has a traits row. */
88
+ export type ConditionTraitsCoverEveryCondition = AssertAllKeysHandled<Exclude<ProviderCondition, keyof typeof PROVIDER_CONDITION_TRAITS>>;
89
+ /** Membership read for a value that crossed a seat (a brand-read error member, a host-minted message). */
90
+ export declare function isProviderCondition(v: unknown): v is ProviderCondition;
91
+ export declare function isProviderConditionSource(v: unknown): v is ProviderConditionSource;
92
+ /**
93
+ * The context-limit refusal FAMILY, anchored at the START of the provider's diagnostic (`error.message`). The
94
+ * two error directions cost asymmetrically, and the asymmetry is what sets the width: a FALSE POSITIVE (a bare
95
+ * "Input is too long" prefix that is really field-length validation) costs one bounded recovery attempt on a
96
+ * request that already failed — the retry fails identically and the original error surfaces, self-limiting. A
97
+ * FALSE NEGATIVE (an unlisted GENUINE refusal read as an authoritative negative) permanently suppresses
98
+ * recovery for that turn: the task dies where it would have recovered. So within a PARSED provider envelope the
99
+ * whole conservative family classifies when it matches AT POSITION 0 of the diagnostic — "a provider stating
100
+ * this error states it first"; a reflection arrives behind a preamble ("validation failed; offending prompt: …")
101
+ * and the position-0 anchor is what separates the two. A prefixed genuine refusal inside a parsed envelope
102
+ * therefore reads as ruled-out — the residual narrowing, accepted (prose-only bodies keep the historic prose
103
+ * reach through the "unknown" arm).
104
+ *
105
+ * Members, by provenance: the loop's historic prose patterns re-anchored at position 0; the llama.cpp openings
106
+ * ("the request exceeds the available context size", "request (N tokens) exceeds …"); Gemini / Vertex through
107
+ * an OpenAI-compatible gateway ("the input token count (N) exceeds the maximum number of tokens allowed (M)");
108
+ * llama.cpp-family /v1 servers ("requested tokens (N) exceed context window of M"); two conservative gateway
109
+ * paraphrases ("your input exceeds the context window …", "the number of tokens in the request exceeds …");
110
+ * DashScope ("Range of input length should be [1, N]"); Moonshot's open platform ("Input token length too
111
+ * long"); Moonshot's coding endpoint ("Invalid request: Your request exceeded model token limit: N …" and
112
+ * "total message size N exceeds limit M"); Z.AI ("Prompt too long"). An unlisted subject-first provider spelling
113
+ * is a member to ADD; the anchor stays. A provider that names this refusal with a STRUCTURAL code says so on its
114
+ * own row instead (`context_length_exceeded` below, GLM's `1261`), and a code row outranks every sentence.
115
+ */
116
+ export declare const INPUT_TOO_LONG_ANCHORED_RE: RegExp;
117
+ /** True when the (provider-authored) diagnostic OPENS with the context-limit refusal family. */
118
+ export declare function startsWithInputTooLongAnchor(diagnostic: string): boolean;
119
+ /**
120
+ * Three-state context-limit verdict: `"yes"` — the provider stated it, on a row that says so; `"no"` — the
121
+ * status cannot carry it, or the provider's envelope parsed and states something else; `"unknown"` — a status
122
+ * that can carry it whose body established no provenance (a text/plain gateway, or a body that did not end — the
123
+ * terminal marks the latter `errorBodyIncomplete`, so no seat reads its prose either).
124
+ */
125
+ export type InputTooLongVerdict = "yes" | "no" | "unknown";
126
+ /** One row of the failure column. A row with no `status` applies to every status. */
127
+ export interface FailureRow {
128
+ readonly status?: readonly number[];
129
+ /** The envelope's word (`error.code` when a string, else `error.type`), compared exactly. */
130
+ readonly word?: readonly string[];
131
+ /** Matched against the envelope's `error.message`. Anchored unless the row's evidence says otherwise. */
132
+ readonly sentence?: RegExp;
133
+ readonly condition: ProviderCondition;
134
+ /** This row's statement IS the context-limit refusal. */
135
+ readonly inputTooLong?: true;
136
+ }
137
+ /** Where a dialect applies: the wire families it was evidenced for, its host suffixes, an optional path prefix. */
138
+ export interface DialectKey {
139
+ readonly wires: readonly Model["api"][];
140
+ /** A request host equal to one of these, or ending in `.` + one. */
141
+ readonly hosts: readonly string[];
142
+ /** A path prefix, matched at a segment boundary. Absent = every path on the host. */
143
+ readonly path?: string;
144
+ }
145
+ /** One endpoint's declared dialect: its key and its columns. */
146
+ export interface ProviderDialect {
147
+ readonly name: string;
148
+ readonly key: DialectKey;
149
+ readonly failures: readonly FailureRow[];
150
+ }
151
+ /**
152
+ * The declared dialects. Each row's source is the provider's own error documentation as collected in the
153
+ * per-provider matrix (status, word, sentence → condition); a `sentence` row is the fragile kind and degrades
154
+ * as the module note says.
155
+ */
156
+ export declare const PROVIDER_DIALECTS: readonly ProviderDialect[];
157
+ /**
158
+ * The rows every endpoint answers to beneath its own, and the only rows an unrecognized endpoint has. Each
159
+ * states something whose meaning no provider in the table overloads: Payment Required, OpenAI's spend codes,
160
+ * the structural context-limit code and the context-limit sentences, the transport's 413. The cross-provider
161
+ * word `insufficient_quota` is pinned to `unknown` here on purpose — on an endpoint nobody declared, it is as
162
+ * likely a token-rate limit as an empty balance.
163
+ */
164
+ export declare const GENERIC_FAILURES: readonly FailureRow[];
165
+ /**
166
+ * The TRANSIENT statuses — the server family and the two transient 4xx (408 request timeout, 409 lock timeout;
167
+ * CC's own retry predicate treats them like 5xx). Two readers, one fact: unread, such a status defaults to
168
+ * `unknown` (retried), and no row turns one into a stop (pinned), so the connect ladder decides them without
169
+ * reading the body (a stalled error body must not cost each retry the body's read bound); the terminal still
170
+ * reads and judges it.
171
+ */
172
+ export declare function isTransientStatus(status: number): boolean;
173
+ /** The endpoint a request went to, or `undefined` when no dialect declares it. */
174
+ export declare function resolveProviderDialect(url: string, wire: Model["api"]): ProviderDialect | undefined;
175
+ /** One failure's reading off the table. */
176
+ export interface ProviderVerdict {
177
+ readonly condition: ProviderCondition;
178
+ readonly source: ProviderConditionSource;
179
+ /** When the condition is `quota_exhausted` and the provider stated when it lifts: wall-clock epoch ms. */
180
+ readonly resetAtMs?: number;
181
+ readonly inputTooLong: InputTooLongVerdict;
182
+ }
183
+ type HeaderBag = {
184
+ get?: (name: string) => string | null;
185
+ } | undefined | null;
186
+ /**
187
+ * Judge one failed HTTP response. `body` is the error body as read (`endedNormally` false = cut by a bound or
188
+ * torn): only a body that ENDED may steer, so a cut one is read as stating nothing — the endpoint's status row
189
+ * and the generic rows still apply. Absent `body` = not read (a status whose verdict no body can change).
190
+ */
191
+ export declare function judgeHttpFailure(args: {
192
+ dialect: ProviderDialect | undefined;
193
+ status: number;
194
+ headers?: HeaderBag;
195
+ body?: FailedBody;
196
+ }): ProviderVerdict;
197
+ /** Judge an in-band error frame's envelope object (a provider error delivered inside a 200 stream). */
198
+ export declare function judgeInBandError(dialect: ProviderDialect | undefined, envelope: {
199
+ message?: unknown;
200
+ code?: unknown;
201
+ type?: unknown;
202
+ }): ProviderVerdict;
203
+ /**
204
+ * The failure an in-band error frame states, as the brain error the stream's terminal carries: the code its
205
+ * condition reads as ({@link PROVIDER_CONDITION_TRAITS}), the provider's word and sentence in the message, the word
206
+ * on the echo seat, the verdict, and the context-limit reading of the same row. A frame the provider sent on its
207
+ * own stream is a provider failure by construction (`apiError`); it states no status.
208
+ */
209
+ export declare function inBandProviderError(dialect: ProviderDialect | undefined, envelope: {
210
+ message?: unknown;
211
+ code?: unknown;
212
+ type?: unknown;
213
+ }, label: string): BrainError;
214
+ export {};