@sema-ai/core 1.275.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 (962) hide show
  1. package/CHANGELOG.md +5433 -0
  2. package/LICENSE +27 -0
  3. package/NOTICE.md +30 -0
  4. package/README.md +1040 -0
  5. package/dist/agents/agent-definition.d.ts +10 -0
  6. package/dist/agents/agent-definition.d.ts.map +1 -0
  7. package/dist/agents/agent-definition.js +18 -0
  8. package/dist/agents/agent-definition.js.map +1 -0
  9. package/dist/agents/builtin-agents.d.ts +69 -0
  10. package/dist/agents/builtin-agents.d.ts.map +1 -0
  11. package/dist/agents/builtin-agents.js +177 -0
  12. package/dist/agents/builtin-agents.js.map +1 -0
  13. package/dist/agents/cascade.d.ts +101 -0
  14. package/dist/agents/cascade.d.ts.map +1 -0
  15. package/dist/agents/cascade.js +189 -0
  16. package/dist/agents/cascade.js.map +1 -0
  17. package/dist/agents/observer.d.ts +209 -0
  18. package/dist/agents/observer.d.ts.map +1 -0
  19. package/dist/agents/observer.js +495 -0
  20. package/dist/agents/observer.js.map +1 -0
  21. package/dist/agents/repair-loop.d.ts +236 -0
  22. package/dist/agents/repair-loop.d.ts.map +1 -0
  23. package/dist/agents/repair-loop.js +293 -0
  24. package/dist/agents/repair-loop.js.map +1 -0
  25. package/dist/agents/session-util.d.ts +8 -0
  26. package/dist/agents/session-util.d.ts.map +1 -0
  27. package/dist/agents/session-util.js +9 -0
  28. package/dist/agents/session-util.js.map +1 -0
  29. package/dist/agents/subagent-steps.d.ts +93 -0
  30. package/dist/agents/subagent-steps.d.ts.map +1 -0
  31. package/dist/agents/subagent-steps.js +206 -0
  32. package/dist/agents/subagent-steps.js.map +1 -0
  33. package/dist/agents/subagent.d.ts +441 -0
  34. package/dist/agents/subagent.d.ts.map +1 -0
  35. package/dist/agents/subagent.js +2492 -0
  36. package/dist/agents/subagent.js.map +1 -0
  37. package/dist/agents/suspend-guard.d.ts +35 -0
  38. package/dist/agents/suspend-guard.d.ts.map +1 -0
  39. package/dist/agents/suspend-guard.js +48 -0
  40. package/dist/agents/suspend-guard.js.map +1 -0
  41. package/dist/agents/teacher.d.ts +137 -0
  42. package/dist/agents/teacher.d.ts.map +1 -0
  43. package/dist/agents/teacher.js +575 -0
  44. package/dist/agents/teacher.js.map +1 -0
  45. package/dist/agents/team.d.ts +211 -0
  46. package/dist/agents/team.d.ts.map +1 -0
  47. package/dist/agents/team.js +293 -0
  48. package/dist/agents/team.js.map +1 -0
  49. package/dist/agents/tool-filter.d.ts +29 -0
  50. package/dist/agents/tool-filter.d.ts.map +1 -0
  51. package/dist/agents/tool-filter.js +50 -0
  52. package/dist/agents/tool-filter.js.map +1 -0
  53. package/dist/agents/verify.d.ts +177 -0
  54. package/dist/agents/verify.d.ts.map +1 -0
  55. package/dist/agents/verify.js +305 -0
  56. package/dist/agents/verify.js.map +1 -0
  57. package/dist/bench/metrics.d.ts +714 -0
  58. package/dist/bench/metrics.d.ts.map +1 -0
  59. package/dist/bench/metrics.js +618 -0
  60. package/dist/bench/metrics.js.map +1 -0
  61. package/dist/bin/sema-tb.d.ts +3 -0
  62. package/dist/bin/sema-tb.d.ts.map +1 -0
  63. package/dist/bin/sema-tb.js +516 -0
  64. package/dist/bin/sema-tb.js.map +1 -0
  65. package/dist/bin/tb-env.d.ts +13 -0
  66. package/dist/bin/tb-env.d.ts.map +1 -0
  67. package/dist/bin/tb-env.js +26 -0
  68. package/dist/bin/tb-env.js.map +1 -0
  69. package/dist/brain/anthropic.d.ts +46 -0
  70. package/dist/brain/anthropic.d.ts.map +1 -0
  71. package/dist/brain/anthropic.js +830 -0
  72. package/dist/brain/anthropic.js.map +1 -0
  73. package/dist/brain/circuit-breaker.d.ts +46 -0
  74. package/dist/brain/circuit-breaker.d.ts.map +1 -0
  75. package/dist/brain/circuit-breaker.js +173 -0
  76. package/dist/brain/circuit-breaker.js.map +1 -0
  77. package/dist/brain/degrading.d.ts +98 -0
  78. package/dist/brain/degrading.d.ts.map +1 -0
  79. package/dist/brain/degrading.js +249 -0
  80. package/dist/brain/degrading.js.map +1 -0
  81. package/dist/brain/errors.d.ts +31 -0
  82. package/dist/brain/errors.d.ts.map +1 -0
  83. package/dist/brain/errors.js +58 -0
  84. package/dist/brain/errors.js.map +1 -0
  85. package/dist/brain/failover.d.ts +18 -0
  86. package/dist/brain/failover.d.ts.map +1 -0
  87. package/dist/brain/failover.js +118 -0
  88. package/dist/brain/failover.js.map +1 -0
  89. package/dist/brain/model-presets.d.ts +36 -0
  90. package/dist/brain/model-presets.d.ts.map +1 -0
  91. package/dist/brain/model-presets.js +54 -0
  92. package/dist/brain/model-presets.js.map +1 -0
  93. package/dist/brain/openai.d.ts +43 -0
  94. package/dist/brain/openai.d.ts.map +1 -0
  95. package/dist/brain/openai.js +784 -0
  96. package/dist/brain/openai.js.map +1 -0
  97. package/dist/brain/reasoning.d.ts +138 -0
  98. package/dist/brain/reasoning.d.ts.map +1 -0
  99. package/dist/brain/reasoning.js +146 -0
  100. package/dist/brain/reasoning.js.map +1 -0
  101. package/dist/brain/repetition.d.ts +60 -0
  102. package/dist/brain/repetition.d.ts.map +1 -0
  103. package/dist/brain/repetition.js +121 -0
  104. package/dist/brain/repetition.js.map +1 -0
  105. package/dist/brain/request-params.d.ts +29 -0
  106. package/dist/brain/request-params.d.ts.map +1 -0
  107. package/dist/brain/request-params.js +78 -0
  108. package/dist/brain/request-params.js.map +1 -0
  109. package/dist/brain/retry.d.ts +18 -0
  110. package/dist/brain/retry.d.ts.map +1 -0
  111. package/dist/brain/retry.js +42 -0
  112. package/dist/brain/retry.js.map +1 -0
  113. package/dist/brain/routing.d.ts +19 -0
  114. package/dist/brain/routing.d.ts.map +1 -0
  115. package/dist/brain/routing.js +44 -0
  116. package/dist/brain/routing.js.map +1 -0
  117. package/dist/brain/status-sink.d.ts +46 -0
  118. package/dist/brain/status-sink.d.ts.map +1 -0
  119. package/dist/brain/status-sink.js +36 -0
  120. package/dist/brain/status-sink.js.map +1 -0
  121. package/dist/brain/stream-engine.d.ts +85 -0
  122. package/dist/brain/stream-engine.d.ts.map +1 -0
  123. package/dist/brain/stream-engine.js +391 -0
  124. package/dist/brain/stream-engine.js.map +1 -0
  125. package/dist/brain/timeout.d.ts +44 -0
  126. package/dist/brain/timeout.d.ts.map +1 -0
  127. package/dist/brain/timeout.js +41 -0
  128. package/dist/brain/timeout.js.map +1 -0
  129. package/dist/brain/tool-call-repair.d.ts +15 -0
  130. package/dist/brain/tool-call-repair.d.ts.map +1 -0
  131. package/dist/brain/tool-call-repair.js +67 -0
  132. package/dist/brain/tool-call-repair.js.map +1 -0
  133. package/dist/brain/walltime.d.ts +14 -0
  134. package/dist/brain/walltime.d.ts.map +1 -0
  135. package/dist/brain/walltime.js +14 -0
  136. package/dist/brain/walltime.js.map +1 -0
  137. package/dist/core/arg-summary.d.ts +19 -0
  138. package/dist/core/arg-summary.d.ts.map +1 -0
  139. package/dist/core/arg-summary.js +96 -0
  140. package/dist/core/arg-summary.js.map +1 -0
  141. package/dist/core/ask-question.d.ts +113 -0
  142. package/dist/core/ask-question.d.ts.map +1 -0
  143. package/dist/core/ask-question.js +246 -0
  144. package/dist/core/ask-question.js.map +1 -0
  145. package/dist/core/auto-compaction.d.ts +341 -0
  146. package/dist/core/auto-compaction.d.ts.map +1 -0
  147. package/dist/core/auto-compaction.js +495 -0
  148. package/dist/core/auto-compaction.js.map +1 -0
  149. package/dist/core/auto-promote.d.ts +126 -0
  150. package/dist/core/auto-promote.d.ts.map +1 -0
  151. package/dist/core/auto-promote.js +171 -0
  152. package/dist/core/auto-promote.js.map +1 -0
  153. package/dist/core/background-shell.d.ts +128 -0
  154. package/dist/core/background-shell.d.ts.map +1 -0
  155. package/dist/core/background-shell.js +42 -0
  156. package/dist/core/background-shell.js.map +1 -0
  157. package/dist/core/cache-break-detector.d.ts +63 -0
  158. package/dist/core/cache-break-detector.d.ts.map +1 -0
  159. package/dist/core/cache-break-detector.js +0 -0
  160. package/dist/core/cache-break-detector.js.map +1 -0
  161. package/dist/core/canonical-json.d.ts +45 -0
  162. package/dist/core/canonical-json.d.ts.map +1 -0
  163. package/dist/core/canonical-json.js +132 -0
  164. package/dist/core/canonical-json.js.map +1 -0
  165. package/dist/core/checkpoint-store.d.ts +1101 -0
  166. package/dist/core/checkpoint-store.d.ts.map +1 -0
  167. package/dist/core/checkpoint-store.js +514 -0
  168. package/dist/core/checkpoint-store.js.map +1 -0
  169. package/dist/core/consolidate-scope.d.ts +94 -0
  170. package/dist/core/consolidate-scope.d.ts.map +1 -0
  171. package/dist/core/consolidate-scope.js +158 -0
  172. package/dist/core/consolidate-scope.js.map +1 -0
  173. package/dist/core/context-edit.d.ts +82 -0
  174. package/dist/core/context-edit.d.ts.map +1 -0
  175. package/dist/core/context-edit.js +149 -0
  176. package/dist/core/context-edit.js.map +1 -0
  177. package/dist/core/context-guard.d.ts +43 -0
  178. package/dist/core/context-guard.d.ts.map +1 -0
  179. package/dist/core/context-guard.js +171 -0
  180. package/dist/core/context-guard.js.map +1 -0
  181. package/dist/core/dynamic-recall.d.ts +100 -0
  182. package/dist/core/dynamic-recall.d.ts.map +1 -0
  183. package/dist/core/dynamic-recall.js +108 -0
  184. package/dist/core/dynamic-recall.js.map +1 -0
  185. package/dist/core/exec-gate.d.ts +74 -0
  186. package/dist/core/exec-gate.d.ts.map +1 -0
  187. package/dist/core/exec-gate.js +143 -0
  188. package/dist/core/exec-gate.js.map +1 -0
  189. package/dist/core/exec-output-tail.d.ts +37 -0
  190. package/dist/core/exec-output-tail.d.ts.map +1 -0
  191. package/dist/core/exec-output-tail.js +63 -0
  192. package/dist/core/exec-output-tail.js.map +1 -0
  193. package/dist/core/file-snapshot-store.d.ts +137 -0
  194. package/dist/core/file-snapshot-store.d.ts.map +1 -0
  195. package/dist/core/file-snapshot-store.js +319 -0
  196. package/dist/core/file-snapshot-store.js.map +1 -0
  197. package/dist/core/git-worktree-env.d.ts +41 -0
  198. package/dist/core/git-worktree-env.d.ts.map +1 -0
  199. package/dist/core/git-worktree-env.js +64 -0
  200. package/dist/core/git-worktree-env.js.map +1 -0
  201. package/dist/core/hooks.d.ts +372 -0
  202. package/dist/core/hooks.d.ts.map +1 -0
  203. package/dist/core/hooks.js +269 -0
  204. package/dist/core/hooks.js.map +1 -0
  205. package/dist/core/lsp-diagnostics.d.ts +74 -0
  206. package/dist/core/lsp-diagnostics.d.ts.map +1 -0
  207. package/dist/core/lsp-diagnostics.js +125 -0
  208. package/dist/core/lsp-diagnostics.js.map +1 -0
  209. package/dist/core/lsp-protocol.d.ts +28 -0
  210. package/dist/core/lsp-protocol.d.ts.map +1 -0
  211. package/dist/core/lsp-protocol.js +179 -0
  212. package/dist/core/lsp-protocol.js.map +1 -0
  213. package/dist/core/lsp-session.d.ts +56 -0
  214. package/dist/core/lsp-session.d.ts.map +1 -0
  215. package/dist/core/lsp-session.js +185 -0
  216. package/dist/core/lsp-session.js.map +1 -0
  217. package/dist/core/lsp.d.ts +132 -0
  218. package/dist/core/lsp.d.ts.map +1 -0
  219. package/dist/core/lsp.js +147 -0
  220. package/dist/core/lsp.js.map +1 -0
  221. package/dist/core/mcp.d.ts +294 -0
  222. package/dist/core/mcp.d.ts.map +1 -0
  223. package/dist/core/mcp.js +992 -0
  224. package/dist/core/mcp.js.map +1 -0
  225. package/dist/core/media-byte-cap.d.ts +34 -0
  226. package/dist/core/media-byte-cap.d.ts.map +1 -0
  227. package/dist/core/media-byte-cap.js +76 -0
  228. package/dist/core/media-byte-cap.js.map +1 -0
  229. package/dist/core/memory-engine/data-plane.d.ts +103 -0
  230. package/dist/core/memory-engine/data-plane.d.ts.map +1 -0
  231. package/dist/core/memory-engine/data-plane.js +272 -0
  232. package/dist/core/memory-engine/data-plane.js.map +1 -0
  233. package/dist/core/memory-engine/dual-root.d.ts +40 -0
  234. package/dist/core/memory-engine/dual-root.d.ts.map +1 -0
  235. package/dist/core/memory-engine/dual-root.js +95 -0
  236. package/dist/core/memory-engine/dual-root.js.map +1 -0
  237. package/dist/core/memory-engine/engine.d.ts +161 -0
  238. package/dist/core/memory-engine/engine.d.ts.map +1 -0
  239. package/dist/core/memory-engine/engine.js +1110 -0
  240. package/dist/core/memory-engine/engine.js.map +1 -0
  241. package/dist/core/memory-engine/file-backend.d.ts +162 -0
  242. package/dist/core/memory-engine/file-backend.d.ts.map +1 -0
  243. package/dist/core/memory-engine/file-backend.js +948 -0
  244. package/dist/core/memory-engine/file-backend.js.map +1 -0
  245. package/dist/core/memory-engine/frontmatter.d.ts +24 -0
  246. package/dist/core/memory-engine/frontmatter.d.ts.map +1 -0
  247. package/dist/core/memory-engine/frontmatter.js +135 -0
  248. package/dist/core/memory-engine/frontmatter.js.map +1 -0
  249. package/dist/core/memory-engine/index.d.ts +13 -0
  250. package/dist/core/memory-engine/index.d.ts.map +1 -0
  251. package/dist/core/memory-engine/index.js +28 -0
  252. package/dist/core/memory-engine/index.js.map +1 -0
  253. package/dist/core/memory-engine/layout.d.ts +123 -0
  254. package/dist/core/memory-engine/layout.d.ts.map +1 -0
  255. package/dist/core/memory-engine/layout.js +643 -0
  256. package/dist/core/memory-engine/layout.js.map +1 -0
  257. package/dist/core/memory-engine/memory-backend-contract.d.ts +22 -0
  258. package/dist/core/memory-engine/memory-backend-contract.d.ts.map +1 -0
  259. package/dist/core/memory-engine/memory-backend-contract.js +271 -0
  260. package/dist/core/memory-engine/memory-backend-contract.js.map +1 -0
  261. package/dist/core/memory-engine/migrate.d.ts +17 -0
  262. package/dist/core/memory-engine/migrate.d.ts.map +1 -0
  263. package/dist/core/memory-engine/migrate.js +35 -0
  264. package/dist/core/memory-engine/migrate.js.map +1 -0
  265. package/dist/core/memory-engine/scan.d.ts +20 -0
  266. package/dist/core/memory-engine/scan.d.ts.map +1 -0
  267. package/dist/core/memory-engine/scan.js +84 -0
  268. package/dist/core/memory-engine/scan.js.map +1 -0
  269. package/dist/core/memory-engine/scope-contract.d.ts +104 -0
  270. package/dist/core/memory-engine/scope-contract.d.ts.map +1 -0
  271. package/dist/core/memory-engine/scope-contract.js +288 -0
  272. package/dist/core/memory-engine/scope-contract.js.map +1 -0
  273. package/dist/core/memory-engine/sync-client.d.ts +100 -0
  274. package/dist/core/memory-engine/sync-client.d.ts.map +1 -0
  275. package/dist/core/memory-engine/sync-client.js +328 -0
  276. package/dist/core/memory-engine/sync-client.js.map +1 -0
  277. package/dist/core/memory-engine/sync.d.ts +97 -0
  278. package/dist/core/memory-engine/sync.d.ts.map +1 -0
  279. package/dist/core/memory-engine/sync.js +91 -0
  280. package/dist/core/memory-engine/sync.js.map +1 -0
  281. package/dist/core/memory-engine/types.d.ts +279 -0
  282. package/dist/core/memory-engine/types.d.ts.map +1 -0
  283. package/dist/core/memory-engine/types.js +9 -0
  284. package/dist/core/memory-engine/types.js.map +1 -0
  285. package/dist/core/memory-recall.d.ts +261 -0
  286. package/dist/core/memory-recall.d.ts.map +1 -0
  287. package/dist/core/memory-recall.js +600 -0
  288. package/dist/core/memory-recall.js.map +1 -0
  289. package/dist/core/memory-vector.d.ts +24 -0
  290. package/dist/core/memory-vector.d.ts.map +1 -0
  291. package/dist/core/memory-vector.js +51 -0
  292. package/dist/core/memory-vector.js.map +1 -0
  293. package/dist/core/memory.d.ts +502 -0
  294. package/dist/core/memory.d.ts.map +1 -0
  295. package/dist/core/memory.js +881 -0
  296. package/dist/core/memory.js.map +1 -0
  297. package/dist/core/message-utils.d.ts +7 -0
  298. package/dist/core/message-utils.d.ts.map +1 -0
  299. package/dist/core/message-utils.js +10 -0
  300. package/dist/core/message-utils.js.map +1 -0
  301. package/dist/core/oracle-isolation.d.ts +85 -0
  302. package/dist/core/oracle-isolation.d.ts.map +1 -0
  303. package/dist/core/oracle-isolation.js +121 -0
  304. package/dist/core/oracle-isolation.js.map +1 -0
  305. package/dist/core/permission-rules.d.ts +102 -0
  306. package/dist/core/permission-rules.d.ts.map +1 -0
  307. package/dist/core/permission-rules.js +357 -0
  308. package/dist/core/permission-rules.js.map +1 -0
  309. package/dist/core/present-plan-tool.d.ts +28 -0
  310. package/dist/core/present-plan-tool.d.ts.map +1 -0
  311. package/dist/core/present-plan-tool.js +119 -0
  312. package/dist/core/present-plan-tool.js.map +1 -0
  313. package/dist/core/pricing.d.ts +48 -0
  314. package/dist/core/pricing.d.ts.map +1 -0
  315. package/dist/core/pricing.js +46 -0
  316. package/dist/core/pricing.js.map +1 -0
  317. package/dist/core/property-harness.d.ts +126 -0
  318. package/dist/core/property-harness.d.ts.map +1 -0
  319. package/dist/core/property-harness.js +192 -0
  320. package/dist/core/property-harness.js.map +1 -0
  321. package/dist/core/push-queue.d.ts +10 -0
  322. package/dist/core/push-queue.d.ts.map +1 -0
  323. package/dist/core/push-queue.js +42 -0
  324. package/dist/core/push-queue.js.map +1 -0
  325. package/dist/core/remote-env.d.ts +432 -0
  326. package/dist/core/remote-env.d.ts.map +1 -0
  327. package/dist/core/remote-env.js +77 -0
  328. package/dist/core/remote-env.js.map +1 -0
  329. package/dist/core/roles.d.ts +74 -0
  330. package/dist/core/roles.d.ts.map +1 -0
  331. package/dist/core/roles.js +272 -0
  332. package/dist/core/roles.js.map +1 -0
  333. package/dist/core/runner/active-skill-scope.d.ts +64 -0
  334. package/dist/core/runner/active-skill-scope.d.ts.map +1 -0
  335. package/dist/core/runner/active-skill-scope.js +197 -0
  336. package/dist/core/runner/active-skill-scope.js.map +1 -0
  337. package/dist/core/runner/assemble-result.d.ts +191 -0
  338. package/dist/core/runner/assemble-result.d.ts.map +1 -0
  339. package/dist/core/runner/assemble-result.js +250 -0
  340. package/dist/core/runner/assemble-result.js.map +1 -0
  341. package/dist/core/runner/call-cap.d.ts +130 -0
  342. package/dist/core/runner/call-cap.d.ts.map +1 -0
  343. package/dist/core/runner/call-cap.js +151 -0
  344. package/dist/core/runner/call-cap.js.map +1 -0
  345. package/dist/core/runner/grounding-signal.d.ts +12 -0
  346. package/dist/core/runner/grounding-signal.d.ts.map +1 -0
  347. package/dist/core/runner/grounding-signal.js +94 -0
  348. package/dist/core/runner/grounding-signal.js.map +1 -0
  349. package/dist/core/runner/image.d.ts +23 -0
  350. package/dist/core/runner/image.d.ts.map +1 -0
  351. package/dist/core/runner/image.js +151 -0
  352. package/dist/core/runner/image.js.map +1 -0
  353. package/dist/core/runner/memory-consolidation.d.ts +112 -0
  354. package/dist/core/runner/memory-consolidation.d.ts.map +1 -0
  355. package/dist/core/runner/memory-consolidation.js +372 -0
  356. package/dist/core/runner/memory-consolidation.js.map +1 -0
  357. package/dist/core/runner/prepare-task.d.ts +583 -0
  358. package/dist/core/runner/prepare-task.d.ts.map +1 -0
  359. package/dist/core/runner/prepare-task.js +3612 -0
  360. package/dist/core/runner/prepare-task.js.map +1 -0
  361. package/dist/core/runner/prompt-suggestions.d.ts +33 -0
  362. package/dist/core/runner/prompt-suggestions.d.ts.map +1 -0
  363. package/dist/core/runner/prompt-suggestions.js +116 -0
  364. package/dist/core/runner/prompt-suggestions.js.map +1 -0
  365. package/dist/core/runner/runtask.d.ts +274 -0
  366. package/dist/core/runner/runtask.d.ts.map +1 -0
  367. package/dist/core/runner/runtask.js +4606 -0
  368. package/dist/core/runner/runtask.js.map +1 -0
  369. package/dist/core/runner/session-rule-policy.d.ts +28 -0
  370. package/dist/core/runner/session-rule-policy.d.ts.map +1 -0
  371. package/dist/core/runner/session-rule-policy.js +110 -0
  372. package/dist/core/runner/session-rule-policy.js.map +1 -0
  373. package/dist/core/runner/strict-output-schema.d.ts +36 -0
  374. package/dist/core/runner/strict-output-schema.d.ts.map +1 -0
  375. package/dist/core/runner/strict-output-schema.js +365 -0
  376. package/dist/core/runner/strict-output-schema.js.map +1 -0
  377. package/dist/core/runner/synthetic-tools.d.ts +72 -0
  378. package/dist/core/runner/synthetic-tools.d.ts.map +1 -0
  379. package/dist/core/runner/synthetic-tools.js +203 -0
  380. package/dist/core/runner/synthetic-tools.js.map +1 -0
  381. package/dist/core/runner/tool-disclosure.d.ts +117 -0
  382. package/dist/core/runner/tool-disclosure.d.ts.map +1 -0
  383. package/dist/core/runner/tool-disclosure.js +0 -0
  384. package/dist/core/runner/tool-disclosure.js.map +1 -0
  385. package/dist/core/runner/turn-attachments.d.ts +381 -0
  386. package/dist/core/runner/turn-attachments.d.ts.map +1 -0
  387. package/dist/core/runner/turn-attachments.js +596 -0
  388. package/dist/core/runner/turn-attachments.js.map +1 -0
  389. package/dist/core/runner/usage-accounting.d.ts +35 -0
  390. package/dist/core/runner/usage-accounting.d.ts.map +1 -0
  391. package/dist/core/runner/usage-accounting.js +45 -0
  392. package/dist/core/runner/usage-accounting.js.map +1 -0
  393. package/dist/core/runtime.d.ts +9 -0
  394. package/dist/core/runtime.d.ts.map +1 -0
  395. package/dist/core/runtime.js +17 -0
  396. package/dist/core/runtime.js.map +1 -0
  397. package/dist/core/safety-axis-vocab.d.ts +33 -0
  398. package/dist/core/safety-axis-vocab.d.ts.map +1 -0
  399. package/dist/core/safety-axis-vocab.js +35 -0
  400. package/dist/core/safety-axis-vocab.js.map +1 -0
  401. package/dist/core/safety-merge-corpus.d.ts +48 -0
  402. package/dist/core/safety-merge-corpus.d.ts.map +1 -0
  403. package/dist/core/safety-merge-corpus.js +203 -0
  404. package/dist/core/safety-merge-corpus.js.map +1 -0
  405. package/dist/core/scheduler.d.ts +126 -0
  406. package/dist/core/scheduler.d.ts.map +1 -0
  407. package/dist/core/scheduler.js +54 -0
  408. package/dist/core/scheduler.js.map +1 -0
  409. package/dist/core/secret-env.d.ts +23 -0
  410. package/dist/core/secret-env.d.ts.map +1 -0
  411. package/dist/core/secret-env.js +35 -0
  412. package/dist/core/secret-env.js.map +1 -0
  413. package/dist/core/select-model.d.ts +26 -0
  414. package/dist/core/select-model.d.ts.map +1 -0
  415. package/dist/core/select-model.js +58 -0
  416. package/dist/core/select-model.js.map +1 -0
  417. package/dist/core/sensitive-path-policy.d.ts +24 -0
  418. package/dist/core/sensitive-path-policy.d.ts.map +1 -0
  419. package/dist/core/sensitive-path-policy.js +96 -0
  420. package/dist/core/sensitive-path-policy.js.map +1 -0
  421. package/dist/core/session-policy-store.d.ts +102 -0
  422. package/dist/core/session-policy-store.d.ts.map +1 -0
  423. package/dist/core/session-policy-store.js +177 -0
  424. package/dist/core/session-policy-store.js.map +1 -0
  425. package/dist/core/session-reconcile.d.ts +63 -0
  426. package/dist/core/session-reconcile.d.ts.map +1 -0
  427. package/dist/core/session-reconcile.js +71 -0
  428. package/dist/core/session-reconcile.js.map +1 -0
  429. package/dist/core/session-store.d.ts +99 -0
  430. package/dist/core/session-store.d.ts.map +1 -0
  431. package/dist/core/session-store.js +298 -0
  432. package/dist/core/session-store.js.map +1 -0
  433. package/dist/core/session.d.ts +144 -0
  434. package/dist/core/session.d.ts.map +1 -0
  435. package/dist/core/session.js +56 -0
  436. package/dist/core/session.js.map +1 -0
  437. package/dist/core/spec-contract.d.ts +147 -0
  438. package/dist/core/spec-contract.d.ts.map +1 -0
  439. package/dist/core/spec-contract.js +340 -0
  440. package/dist/core/spec-contract.js.map +1 -0
  441. package/dist/core/strategy-store.d.ts +50 -0
  442. package/dist/core/strategy-store.d.ts.map +1 -0
  443. package/dist/core/strategy-store.js +100 -0
  444. package/dist/core/strategy-store.js.map +1 -0
  445. package/dist/core/stub-env.d.ts +35 -0
  446. package/dist/core/stub-env.d.ts.map +1 -0
  447. package/dist/core/stub-env.js +69 -0
  448. package/dist/core/stub-env.js.map +1 -0
  449. package/dist/core/task-notification.d.ts +115 -0
  450. package/dist/core/task-notification.d.ts.map +1 -0
  451. package/dist/core/task-notification.js +247 -0
  452. package/dist/core/task-notification.js.map +1 -0
  453. package/dist/core/task-outcome.d.ts +80 -0
  454. package/dist/core/task-outcome.d.ts.map +1 -0
  455. package/dist/core/task-outcome.js +40 -0
  456. package/dist/core/task-outcome.js.map +1 -0
  457. package/dist/core/task-registry.d.ts +349 -0
  458. package/dist/core/task-registry.d.ts.map +1 -0
  459. package/dist/core/task-registry.js +1751 -0
  460. package/dist/core/task-registry.js.map +1 -0
  461. package/dist/core/tighten-task-spec.d.ts +27 -0
  462. package/dist/core/tighten-task-spec.d.ts.map +1 -0
  463. package/dist/core/tighten-task-spec.js +95 -0
  464. package/dist/core/tighten-task-spec.js.map +1 -0
  465. package/dist/core/tool-detach.d.ts +31 -0
  466. package/dist/core/tool-detach.d.ts.map +1 -0
  467. package/dist/core/tool-detach.js +62 -0
  468. package/dist/core/tool-detach.js.map +1 -0
  469. package/dist/core/tool-errors.d.ts +72 -0
  470. package/dist/core/tool-errors.d.ts.map +1 -0
  471. package/dist/core/tool-errors.js +194 -0
  472. package/dist/core/tool-errors.js.map +1 -0
  473. package/dist/core/tool-name-aliases.d.ts +5 -0
  474. package/dist/core/tool-name-aliases.d.ts.map +1 -0
  475. package/dist/core/tool-name-aliases.js +130 -0
  476. package/dist/core/tool-name-aliases.js.map +1 -0
  477. package/dist/core/tool-policy.d.ts +295 -0
  478. package/dist/core/tool-policy.d.ts.map +1 -0
  479. package/dist/core/tool-policy.js +567 -0
  480. package/dist/core/tool-policy.js.map +1 -0
  481. package/dist/core/tool-result-budget.d.ts +44 -0
  482. package/dist/core/tool-result-budget.d.ts.map +1 -0
  483. package/dist/core/tool-result-budget.js +140 -0
  484. package/dist/core/tool-result-budget.js.map +1 -0
  485. package/dist/core/tool-result-store.d.ts +136 -0
  486. package/dist/core/tool-result-store.d.ts.map +1 -0
  487. package/dist/core/tool-result-store.js +219 -0
  488. package/dist/core/tool-result-store.js.map +1 -0
  489. package/dist/core/tools.d.ts +14 -0
  490. package/dist/core/tools.d.ts.map +1 -0
  491. package/dist/core/tools.js +98 -0
  492. package/dist/core/tools.js.map +1 -0
  493. package/dist/core/trace.d.ts +340 -0
  494. package/dist/core/trace.d.ts.map +1 -0
  495. package/dist/core/trace.js +12 -0
  496. package/dist/core/trace.js.map +1 -0
  497. package/dist/core/types.d.ts +2828 -0
  498. package/dist/core/types.d.ts.map +1 -0
  499. package/dist/core/types.js +2 -0
  500. package/dist/core/types.js.map +1 -0
  501. package/dist/core/untrusted-egress.d.ts +32 -0
  502. package/dist/core/untrusted-egress.d.ts.map +1 -0
  503. package/dist/core/untrusted-egress.js +49 -0
  504. package/dist/core/untrusted-egress.js.map +1 -0
  505. package/dist/core/untrusted-text.d.ts +64 -0
  506. package/dist/core/untrusted-text.d.ts.map +1 -0
  507. package/dist/core/untrusted-text.js +119 -0
  508. package/dist/core/untrusted-text.js.map +1 -0
  509. package/dist/core/warm-resume.d.ts +23 -0
  510. package/dist/core/warm-resume.d.ts.map +1 -0
  511. package/dist/core/warm-resume.js +28 -0
  512. package/dist/core/warm-resume.js.map +1 -0
  513. package/dist/core/with-retry.d.ts +43 -0
  514. package/dist/core/with-retry.d.ts.map +1 -0
  515. package/dist/core/with-retry.js +59 -0
  516. package/dist/core/with-retry.js.map +1 -0
  517. package/dist/core/workflow-journal-store.d.ts +44 -0
  518. package/dist/core/workflow-journal-store.d.ts.map +1 -0
  519. package/dist/core/workflow-journal-store.js +47 -0
  520. package/dist/core/workflow-journal-store.js.map +1 -0
  521. package/dist/core/workflow-run-store-contract.d.ts +31 -0
  522. package/dist/core/workflow-run-store-contract.d.ts.map +1 -0
  523. package/dist/core/workflow-run-store-contract.js +191 -0
  524. package/dist/core/workflow-run-store-contract.js.map +1 -0
  525. package/dist/core/workflow-run-store.d.ts +149 -0
  526. package/dist/core/workflow-run-store.d.ts.map +1 -0
  527. package/dist/core/workflow-run-store.js +110 -0
  528. package/dist/core/workflow-run-store.js.map +1 -0
  529. package/dist/engine/compaction/compaction.d.ts +139 -0
  530. package/dist/engine/compaction/compaction.d.ts.map +1 -0
  531. package/dist/engine/compaction/compaction.js +1030 -0
  532. package/dist/engine/compaction/compaction.js.map +1 -0
  533. package/dist/engine/compaction/utils.d.ts +45 -0
  534. package/dist/engine/compaction/utils.d.ts.map +1 -0
  535. package/dist/engine/compaction/utils.js +203 -0
  536. package/dist/engine/compaction/utils.js.map +1 -0
  537. package/dist/engine/execution-env/kill-tree.d.ts +20 -0
  538. package/dist/engine/execution-env/kill-tree.d.ts.map +1 -0
  539. package/dist/engine/execution-env/kill-tree.js +183 -0
  540. package/dist/engine/execution-env/kill-tree.js.map +1 -0
  541. package/dist/engine/execution-env/node-execution-env.d.ts +133 -0
  542. package/dist/engine/execution-env/node-execution-env.d.ts.map +1 -0
  543. package/dist/engine/execution-env/node-execution-env.js +1031 -0
  544. package/dist/engine/execution-env/node-execution-env.js.map +1 -0
  545. package/dist/engine/harness/agent-harness.d.ts +174 -0
  546. package/dist/engine/harness/agent-harness.d.ts.map +1 -0
  547. package/dist/engine/harness/agent-harness.js +1053 -0
  548. package/dist/engine/harness/agent-harness.js.map +1 -0
  549. package/dist/engine/harness/messages.d.ts +17 -0
  550. package/dist/engine/harness/messages.d.ts.map +1 -0
  551. package/dist/engine/harness/messages.js +122 -0
  552. package/dist/engine/harness/messages.js.map +1 -0
  553. package/dist/engine/harness/types.d.ts +713 -0
  554. package/dist/engine/harness/types.d.ts.map +1 -0
  555. package/dist/engine/harness/types.js +100 -0
  556. package/dist/engine/harness/types.js.map +1 -0
  557. package/dist/engine/llm/diagnostics.d.ts +23 -0
  558. package/dist/engine/llm/diagnostics.d.ts.map +1 -0
  559. package/dist/engine/llm/diagnostics.js +32 -0
  560. package/dist/engine/llm/diagnostics.js.map +1 -0
  561. package/dist/engine/llm/event-stream.d.ts +25 -0
  562. package/dist/engine/llm/event-stream.d.ts.map +1 -0
  563. package/dist/engine/llm/event-stream.js +103 -0
  564. package/dist/engine/llm/event-stream.js.map +1 -0
  565. package/dist/engine/llm/index.d.ts +12 -0
  566. package/dist/engine/llm/index.d.ts.map +1 -0
  567. package/dist/engine/llm/index.js +12 -0
  568. package/dist/engine/llm/index.js.map +1 -0
  569. package/dist/engine/llm/types.d.ts +753 -0
  570. package/dist/engine/llm/types.d.ts.map +1 -0
  571. package/dist/engine/llm/types.js +2 -0
  572. package/dist/engine/llm/types.js.map +1 -0
  573. package/dist/engine/llm/validation.d.ts +8 -0
  574. package/dist/engine/llm/validation.d.ts.map +1 -0
  575. package/dist/engine/llm/validation.js +318 -0
  576. package/dist/engine/llm/validation.js.map +1 -0
  577. package/dist/engine/loop/agent-loop.d.ts +74 -0
  578. package/dist/engine/loop/agent-loop.d.ts.map +1 -0
  579. package/dist/engine/loop/agent-loop.js +1490 -0
  580. package/dist/engine/loop/agent-loop.js.map +1 -0
  581. package/dist/engine/loop/runtime-deps.d.ts +17 -0
  582. package/dist/engine/loop/runtime-deps.d.ts.map +1 -0
  583. package/dist/engine/loop/runtime-deps.js +21 -0
  584. package/dist/engine/loop/runtime-deps.js.map +1 -0
  585. package/dist/engine/loop/types.d.ts +609 -0
  586. package/dist/engine/loop/types.d.ts.map +1 -0
  587. package/dist/engine/loop/types.js +2 -0
  588. package/dist/engine/loop/types.js.map +1 -0
  589. package/dist/engine/lsp/frame-decoder.d.ts +16 -0
  590. package/dist/engine/lsp/frame-decoder.d.ts.map +1 -0
  591. package/dist/engine/lsp/frame-decoder.js +53 -0
  592. package/dist/engine/lsp/frame-decoder.js.map +1 -0
  593. package/dist/engine/lsp/node-lsp-manager.d.ts +105 -0
  594. package/dist/engine/lsp/node-lsp-manager.d.ts.map +1 -0
  595. package/dist/engine/lsp/node-lsp-manager.js +343 -0
  596. package/dist/engine/lsp/node-lsp-manager.js.map +1 -0
  597. package/dist/engine/lsp/stdio-lsp-transport.d.ts +37 -0
  598. package/dist/engine/lsp/stdio-lsp-transport.d.ts.map +1 -0
  599. package/dist/engine/lsp/stdio-lsp-transport.js +185 -0
  600. package/dist/engine/lsp/stdio-lsp-transport.js.map +1 -0
  601. package/dist/engine/session/import-validate.d.ts +44 -0
  602. package/dist/engine/session/import-validate.d.ts.map +1 -0
  603. package/dist/engine/session/import-validate.js +92 -0
  604. package/dist/engine/session/import-validate.js.map +1 -0
  605. package/dist/engine/session/memory-repo.d.ts +25 -0
  606. package/dist/engine/session/memory-repo.d.ts.map +1 -0
  607. package/dist/engine/session/memory-repo.js +59 -0
  608. package/dist/engine/session/memory-repo.js.map +1 -0
  609. package/dist/engine/session/memory-storage.d.ts +14 -0
  610. package/dist/engine/session/memory-storage.d.ts.map +1 -0
  611. package/dist/engine/session/memory-storage.js +17 -0
  612. package/dist/engine/session/memory-storage.js.map +1 -0
  613. package/dist/engine/session/repo-utils.d.ts +11 -0
  614. package/dist/engine/session/repo-utils.d.ts.map +1 -0
  615. package/dist/engine/session/repo-utils.js +40 -0
  616. package/dist/engine/session/repo-utils.js.map +1 -0
  617. package/dist/engine/session/session.d.ts +34 -0
  618. package/dist/engine/session/session.d.ts.map +1 -0
  619. package/dist/engine/session/session.js +227 -0
  620. package/dist/engine/session/session.js.map +1 -0
  621. package/dist/engine/session/storage-base.d.ts +38 -0
  622. package/dist/engine/session/storage-base.d.ts.map +1 -0
  623. package/dist/engine/session/storage-base.js +157 -0
  624. package/dist/engine/session/storage-base.js.map +1 -0
  625. package/dist/engine/session/timestamps.d.ts +3 -0
  626. package/dist/engine/session/timestamps.d.ts.map +1 -0
  627. package/dist/engine/session/timestamps.js +15 -0
  628. package/dist/engine/session/timestamps.js.map +1 -0
  629. package/dist/engine/session/uuid.d.ts +2 -0
  630. package/dist/engine/session/uuid.d.ts.map +1 -0
  631. package/dist/engine/session/uuid.js +50 -0
  632. package/dist/engine/session/uuid.js.map +1 -0
  633. package/dist/index.d.ts +160 -0
  634. package/dist/index.d.ts.map +1 -0
  635. package/dist/index.js +374 -0
  636. package/dist/index.js.map +1 -0
  637. package/dist/internal/harness.d.ts +26 -0
  638. package/dist/internal/harness.d.ts.map +1 -0
  639. package/dist/internal/harness.js +24 -0
  640. package/dist/internal/harness.js.map +1 -0
  641. package/dist/internal/llm.d.ts +9 -0
  642. package/dist/internal/llm.d.ts.map +1 -0
  643. package/dist/internal/llm.js +8 -0
  644. package/dist/internal/llm.js.map +1 -0
  645. package/dist/orchestration/builtin-workflows.d.ts +44 -0
  646. package/dist/orchestration/builtin-workflows.d.ts.map +1 -0
  647. package/dist/orchestration/builtin-workflows.js +165 -0
  648. package/dist/orchestration/builtin-workflows.js.map +1 -0
  649. package/dist/orchestration/dev-vm-script-runner.d.ts +24 -0
  650. package/dist/orchestration/dev-vm-script-runner.d.ts.map +1 -0
  651. package/dist/orchestration/dev-vm-script-runner.js +106 -0
  652. package/dist/orchestration/dev-vm-script-runner.js.map +1 -0
  653. package/dist/orchestration/goal.d.ts +97 -0
  654. package/dist/orchestration/goal.d.ts.map +1 -0
  655. package/dist/orchestration/goal.js +248 -0
  656. package/dist/orchestration/goal.js.map +1 -0
  657. package/dist/orchestration/run-spec.d.ts +63 -0
  658. package/dist/orchestration/run-spec.d.ts.map +1 -0
  659. package/dist/orchestration/run-spec.js +274 -0
  660. package/dist/orchestration/run-spec.js.map +1 -0
  661. package/dist/orchestration/run-workflow-tool.d.ts +187 -0
  662. package/dist/orchestration/run-workflow-tool.d.ts.map +1 -0
  663. package/dist/orchestration/run-workflow-tool.js +612 -0
  664. package/dist/orchestration/run-workflow-tool.js.map +1 -0
  665. package/dist/orchestration/workflow-governance.d.ts +70 -0
  666. package/dist/orchestration/workflow-governance.d.ts.map +1 -0
  667. package/dist/orchestration/workflow-governance.js +176 -0
  668. package/dist/orchestration/workflow-governance.js.map +1 -0
  669. package/dist/orchestration/workflow-meta.d.ts +41 -0
  670. package/dist/orchestration/workflow-meta.d.ts.map +1 -0
  671. package/dist/orchestration/workflow-meta.js +426 -0
  672. package/dist/orchestration/workflow-meta.js.map +1 -0
  673. package/dist/orchestration/workflow-observe.d.ts +77 -0
  674. package/dist/orchestration/workflow-observe.d.ts.map +1 -0
  675. package/dist/orchestration/workflow-observe.js +177 -0
  676. package/dist/orchestration/workflow-observe.js.map +1 -0
  677. package/dist/orchestration/workflow-primitives.d.ts +31 -0
  678. package/dist/orchestration/workflow-primitives.d.ts.map +1 -0
  679. package/dist/orchestration/workflow-primitives.js +104 -0
  680. package/dist/orchestration/workflow-primitives.js.map +1 -0
  681. package/dist/orchestration/workflow-sandbox-conformance.d.ts +34 -0
  682. package/dist/orchestration/workflow-sandbox-conformance.d.ts.map +1 -0
  683. package/dist/orchestration/workflow-sandbox-conformance.js +301 -0
  684. package/dist/orchestration/workflow-sandbox-conformance.js.map +1 -0
  685. package/dist/orchestration/workflow-script-runner.d.ts +127 -0
  686. package/dist/orchestration/workflow-script-runner.d.ts.map +1 -0
  687. package/dist/orchestration/workflow-script-runner.js +48 -0
  688. package/dist/orchestration/workflow-script-runner.js.map +1 -0
  689. package/dist/orchestration/workflow-script-store.d.ts +99 -0
  690. package/dist/orchestration/workflow-script-store.d.ts.map +1 -0
  691. package/dist/orchestration/workflow-script-store.js +133 -0
  692. package/dist/orchestration/workflow-script-store.js.map +1 -0
  693. package/dist/orchestration/workflow-size-guideline.d.ts +50 -0
  694. package/dist/orchestration/workflow-size-guideline.d.ts.map +1 -0
  695. package/dist/orchestration/workflow-size-guideline.js +78 -0
  696. package/dist/orchestration/workflow-size-guideline.js.map +1 -0
  697. package/dist/orchestration/workflow.d.ts +624 -0
  698. package/dist/orchestration/workflow.d.ts.map +1 -0
  699. package/dist/orchestration/workflow.js +1596 -0
  700. package/dist/orchestration/workflow.js.map +1 -0
  701. package/dist/prompts/default.d.ts +474 -0
  702. package/dist/prompts/default.d.ts.map +1 -0
  703. package/dist/prompts/default.js +676 -0
  704. package/dist/prompts/default.js.map +1 -0
  705. package/dist/prompts/supervisor.d.ts +60 -0
  706. package/dist/prompts/supervisor.d.ts.map +1 -0
  707. package/dist/prompts/supervisor.js +162 -0
  708. package/dist/prompts/supervisor.js.map +1 -0
  709. package/dist/scenarios/env.d.ts +41 -0
  710. package/dist/scenarios/env.d.ts.map +1 -0
  711. package/dist/scenarios/env.js +65 -0
  712. package/dist/scenarios/env.js.map +1 -0
  713. package/dist/scenarios/full-body.d.ts +47 -0
  714. package/dist/scenarios/full-body.d.ts.map +1 -0
  715. package/dist/scenarios/full-body.js +36 -0
  716. package/dist/scenarios/full-body.js.map +1 -0
  717. package/dist/scenarios/scenario-registry.d.ts +107 -0
  718. package/dist/scenarios/scenario-registry.d.ts.map +1 -0
  719. package/dist/scenarios/scenario-registry.js +192 -0
  720. package/dist/scenarios/scenario-registry.js.map +1 -0
  721. package/dist/scenarios/teacher-quickstart.d.ts +41 -0
  722. package/dist/scenarios/teacher-quickstart.d.ts.map +1 -0
  723. package/dist/scenarios/teacher-quickstart.js +32 -0
  724. package/dist/scenarios/teacher-quickstart.js.map +1 -0
  725. package/dist/server/http.d.ts +36 -0
  726. package/dist/server/http.d.ts.map +1 -0
  727. package/dist/server/http.js +144 -0
  728. package/dist/server/http.js.map +1 -0
  729. package/dist/stores/file/checkpoint-store.d.ts +62 -0
  730. package/dist/stores/file/checkpoint-store.d.ts.map +1 -0
  731. package/dist/stores/file/checkpoint-store.js +250 -0
  732. package/dist/stores/file/checkpoint-store.js.map +1 -0
  733. package/dist/stores/file/file-snapshot-store.d.ts +43 -0
  734. package/dist/stores/file/file-snapshot-store.d.ts.map +1 -0
  735. package/dist/stores/file/file-snapshot-store.js +374 -0
  736. package/dist/stores/file/file-snapshot-store.js.map +1 -0
  737. package/dist/stores/file/fs-atomic.d.ts +95 -0
  738. package/dist/stores/file/fs-atomic.d.ts.map +1 -0
  739. package/dist/stores/file/fs-atomic.js +415 -0
  740. package/dist/stores/file/fs-atomic.js.map +1 -0
  741. package/dist/stores/file/index.d.ts +98 -0
  742. package/dist/stores/file/index.d.ts.map +1 -0
  743. package/dist/stores/file/index.js +109 -0
  744. package/dist/stores/file/index.js.map +1 -0
  745. package/dist/stores/file/memory-store.d.ts +95 -0
  746. package/dist/stores/file/memory-store.d.ts.map +1 -0
  747. package/dist/stores/file/memory-store.js +393 -0
  748. package/dist/stores/file/memory-store.js.map +1 -0
  749. package/dist/stores/file/session-policy-store.d.ts +24 -0
  750. package/dist/stores/file/session-policy-store.d.ts.map +1 -0
  751. package/dist/stores/file/session-policy-store.js +123 -0
  752. package/dist/stores/file/session-policy-store.js.map +1 -0
  753. package/dist/stores/file/session-store.d.ts +34 -0
  754. package/dist/stores/file/session-store.d.ts.map +1 -0
  755. package/dist/stores/file/session-store.js +175 -0
  756. package/dist/stores/file/session-store.js.map +1 -0
  757. package/dist/stores/file/tool-result-store.d.ts +23 -0
  758. package/dist/stores/file/tool-result-store.d.ts.map +1 -0
  759. package/dist/stores/file/tool-result-store.js +61 -0
  760. package/dist/stores/file/tool-result-store.js.map +1 -0
  761. package/dist/stores/file/workflow-journal-store.d.ts +36 -0
  762. package/dist/stores/file/workflow-journal-store.d.ts.map +1 -0
  763. package/dist/stores/file/workflow-journal-store.js +157 -0
  764. package/dist/stores/file/workflow-journal-store.js.map +1 -0
  765. package/dist/stores/file/workflow-run-store.d.ts +58 -0
  766. package/dist/stores/file/workflow-run-store.d.ts.map +1 -0
  767. package/dist/stores/file/workflow-run-store.js +178 -0
  768. package/dist/stores/file/workflow-run-store.js.map +1 -0
  769. package/dist/stores/pg.d.ts +210 -0
  770. package/dist/stores/pg.d.ts.map +1 -0
  771. package/dist/stores/pg.js +652 -0
  772. package/dist/stores/pg.js.map +1 -0
  773. package/dist/tools/fs/encoding.d.ts +51 -0
  774. package/dist/tools/fs/encoding.d.ts.map +1 -0
  775. package/dist/tools/fs/encoding.js +74 -0
  776. package/dist/tools/fs/encoding.js.map +1 -0
  777. package/dist/tools/fs/gh-rate-limit.d.ts +19 -0
  778. package/dist/tools/fs/gh-rate-limit.d.ts.map +1 -0
  779. package/dist/tools/fs/gh-rate-limit.js +35 -0
  780. package/dist/tools/fs/gh-rate-limit.js.map +1 -0
  781. package/dist/tools/fs/index.d.ts +246 -0
  782. package/dist/tools/fs/index.d.ts.map +1 -0
  783. package/dist/tools/fs/index.js +2130 -0
  784. package/dist/tools/fs/index.js.map +1 -0
  785. package/dist/tools/fs/pdf.d.ts +106 -0
  786. package/dist/tools/fs/pdf.d.ts.map +1 -0
  787. package/dist/tools/fs/pdf.js +178 -0
  788. package/dist/tools/fs/pdf.js.map +1 -0
  789. package/dist/tools/fs/repo-map.d.ts +15 -0
  790. package/dist/tools/fs/repo-map.d.ts.map +1 -0
  791. package/dist/tools/fs/repo-map.js +251 -0
  792. package/dist/tools/fs/repo-map.js.map +1 -0
  793. package/dist/tools/fs/safety.d.ts +168 -0
  794. package/dist/tools/fs/safety.d.ts.map +1 -0
  795. package/dist/tools/fs/safety.js +479 -0
  796. package/dist/tools/fs/safety.js.map +1 -0
  797. package/dist/tools/fs/search.d.ts +118 -0
  798. package/dist/tools/fs/search.d.ts.map +1 -0
  799. package/dist/tools/fs/search.js +650 -0
  800. package/dist/tools/fs/search.js.map +1 -0
  801. package/dist/tools/gitea-issue.d.ts +39 -0
  802. package/dist/tools/gitea-issue.d.ts.map +1 -0
  803. package/dist/tools/gitea-issue.js +91 -0
  804. package/dist/tools/gitea-issue.js.map +1 -0
  805. package/dist/tools/monitor.d.ts +64 -0
  806. package/dist/tools/monitor.d.ts.map +1 -0
  807. package/dist/tools/monitor.js +135 -0
  808. package/dist/tools/monitor.js.map +1 -0
  809. package/dist/tools/scheduler-tools.d.ts +48 -0
  810. package/dist/tools/scheduler-tools.d.ts.map +1 -0
  811. package/dist/tools/scheduler-tools.js +449 -0
  812. package/dist/tools/scheduler-tools.js.map +1 -0
  813. package/dist/tools/sql-adapters.d.ts +32 -0
  814. package/dist/tools/sql-adapters.d.ts.map +1 -0
  815. package/dist/tools/sql-adapters.js +31 -0
  816. package/dist/tools/sql-adapters.js.map +1 -0
  817. package/dist/tools/sql.d.ts +36 -0
  818. package/dist/tools/sql.d.ts.map +1 -0
  819. package/dist/tools/sql.js +131 -0
  820. package/dist/tools/sql.js.map +1 -0
  821. package/dist/tools/task-list.d.ts +26 -0
  822. package/dist/tools/task-list.d.ts.map +1 -0
  823. package/dist/tools/task-list.js +352 -0
  824. package/dist/tools/task-list.js.map +1 -0
  825. package/dist/tools/todo.d.ts +11 -0
  826. package/dist/tools/todo.d.ts.map +1 -0
  827. package/dist/tools/todo.js +126 -0
  828. package/dist/tools/todo.js.map +1 -0
  829. package/dist/tools/web.d.ts +59 -0
  830. package/dist/tools/web.d.ts.map +1 -0
  831. package/dist/tools/web.js +607 -0
  832. package/dist/tools/web.js.map +1 -0
  833. package/dist/tools/worktree.d.ts +88 -0
  834. package/dist/tools/worktree.d.ts.map +1 -0
  835. package/dist/tools/worktree.js +434 -0
  836. package/dist/tools/worktree.js.map +1 -0
  837. package/docs/A1-ATTRIBUTION-ROUND1-2026-07-09.md +181 -0
  838. package/docs/AB-ORACLE-GATE-VERDICT-2026-07-10.md +100 -0
  839. package/docs/ANCHOR-GAP-INVENTORY-2026-07-09.md +143 -0
  840. package/docs/ARCHITECTURE.md +125 -0
  841. package/docs/BUGHUNT-2026-07-05-NIGHT.md +98 -0
  842. package/docs/BUILD.md +63 -0
  843. package/docs/CANCEL-ASYNC-ATTRIBUTION-2026-07-09.md +98 -0
  844. package/docs/CC-198-VS-201-DRIFT-2026-07-09.md +70 -0
  845. package/docs/CC-BASELINE-FAKE-ZERO-AUDIT-2026-07-09.md +51 -0
  846. package/docs/CC-DRIFT-198-206-AGENT-TYPES-2026-07-10.md +82 -0
  847. package/docs/CC-DRIFT-198-206-CHANGELOG-2026-07-10.md +82 -0
  848. package/docs/CC-DRIFT-198-206-REMINDERS-2026-07-10.md +96 -0
  849. package/docs/CC-DRIFT-198-206-ROADMAP-2026-07-10.md +110 -0
  850. package/docs/CC-DRIFT-198-206-TOOL-INVENTORY-2026-07-10.md +53 -0
  851. package/docs/CC-DRIFT-198-206-USAGE-CONSTANTS-2026-07-10.md +64 -0
  852. package/docs/CC-DRIFT-198-206-WORKFLOW-2026-07-10.md +83 -0
  853. package/docs/CC-PARITY-CHECKLIST.md +220 -0
  854. package/docs/CC-PARITY-DEEP-SWEEP-2026-07-07.md +149 -0
  855. package/docs/CC-SUBAGENT-PROMPT-STUDY-2026-07-09.md +219 -0
  856. package/docs/CC-TASK-REMINDER-CADENCE-STUDY-2026-07-09.md +396 -0
  857. package/docs/CC-TOOL-PARITY-SWEEP-2026-07.md +56 -0
  858. package/docs/CC-TOOL-PROMPT-DEEP-DIFF-2026-07-08.md +274 -0
  859. package/docs/CC-TOOLSURFACE-DEEP-DIVE-2026-07-07.md +197 -0
  860. package/docs/CC206-OBSERVER-ANCHORS-2026-07-11.md +463 -0
  861. package/docs/CC207-CORE-SWEEP-BACKLOG-2026-07-12.md +155 -0
  862. package/docs/CENTER-CONTROL-PLANE-SEAM.md +86 -0
  863. package/docs/CLEANUP-CONTRACT-ANCHOR-2026-07-09.md +83 -0
  864. package/docs/COLD-START-RSI-2026-07-09.md +72 -0
  865. package/docs/COMPACTION-LIVE-AUDIT-2026-07-09.md +114 -0
  866. package/docs/CONTEXT-lifecycle-extension-points-and-stop-attribution.md +71 -0
  867. package/docs/COREWARS-POLYGLOT-TRIAGE-2026-07-09.md +85 -0
  868. package/docs/DEADTARGET-OVERFULL-HBOX-2026-07-10.md +92 -0
  869. package/docs/DEADTARGET-PATH-TRACING-REVERSE-2026-07-10.md +87 -0
  870. package/docs/DEADTARGET-WINNING-AVG-COREWARS-2026-07-10.md +96 -0
  871. package/docs/DEEPSEEK-API-LIMITS-PROBE-2026-07-09.md +118 -0
  872. package/docs/DESIGN-140-MOCK-VERIFY-2026-07-11.md +79 -0
  873. package/docs/DESIGN-140-VERIFICATION-2026-07-11.md +43 -0
  874. package/docs/DESIGN-DRAFT-workflow-collab-2026-07-11.md +56 -0
  875. package/docs/DESIGN-ORACLE-GROUNDING-GATE-2026-07-10.md +167 -0
  876. package/docs/DESIGN-TFRAG-RECONCILE-SCAFFOLD-2026-07-09.md +102 -0
  877. package/docs/EXP-PA2-PE-DESIGN-2026-07-11.md +220 -0
  878. package/docs/EXT-DOGFOOD-2026-07-12.md +50 -0
  879. package/docs/FINAL-VERIFY-SURFACE-AUDIT-2026-07-09.md +44 -0
  880. package/docs/FRAG-RECON-INVESTIGATION-2026-07-09.md +183 -0
  881. package/docs/HANDOFF.md +121 -0
  882. package/docs/KNOWN-ISSUES.md +96 -0
  883. package/docs/LEGW-WINDOW-TAX-2026-07-10.md +82 -0
  884. package/docs/LIVE-PROBE-BATCH-2026-07-11.md +207 -0
  885. package/docs/M2-CERT-ATTRIBUTION-2026-07-10.md +61 -0
  886. package/docs/M25-LEG-VARIANCE-ATTRIBUTION-2026-07-10.md +81 -0
  887. package/docs/MAILMAN-TIMEOUT-ATTRIBUTION-2026-07-10.md +88 -0
  888. package/docs/MEMORY-BACKEND-DIALECT-NOTES.md +69 -0
  889. package/docs/MTEB-ESCAPE-HATCH-ATTRIBUTION-2026-07-09.md +57 -0
  890. package/docs/MTEB-LEADERBOARD-ATTRIBUTION-2026-07-10.md +134 -0
  891. package/docs/ORACLE-GATE-NEGATIVE-SAMPLE-2026-07-11.md +28 -0
  892. package/docs/PARITY-CONTEXT-TRANSACTIONS-2026-07-10.md +67 -0
  893. package/docs/PARITY-PROGRESS-MATRIX-2026-07-10.md +37 -0
  894. package/docs/PARITY-SPOT-AGENT-TYPES-2026-07-10.md +70 -0
  895. package/docs/PARITY-SPOT-REMINDERS-2026-07-10.md +144 -0
  896. package/docs/PARITY-SPOT-TOOL-INVENTORY-2026-07-10.md +61 -0
  897. package/docs/PARITY-SPOT-USAGE-CONSTANTS-2026-07-10.md +95 -0
  898. package/docs/PARITY-SPOT-WORKFLOW-2026-07-10.md +93 -0
  899. package/docs/PASSWORD-RECOVERY-PANEL-VERDICT-2026-07-10.md +62 -0
  900. package/docs/R8-R9-FINALIZE-COORDINATION-2026-07-09.md +124 -0
  901. package/docs/REPL-CODE-MODE-EVALUATION-2026-07-10.md +187 -0
  902. package/docs/REPORT-1249-TARGETED.md +48 -0
  903. package/docs/RESEARCH-3P-MEMORY-SWAP-2026-07-12.md +273 -0
  904. package/docs/ROADMAP.md +111 -0
  905. package/docs/RSI-CLOUD-DEPLOY-2026-07-06.md +289 -0
  906. package/docs/RSI-PROCESS-AI-COLDSTART-2026-07-11.md +68 -0
  907. package/docs/S18-THOROUGHNESS-AUDIT-2026-07-09.md +113 -0
  908. package/docs/SERVICE-INTEGRATION-GUIDE.md +298 -0
  909. package/docs/SUBAGENT-STREAM-RESILIENCE-PARITY-2026-07-10.md +118 -0
  910. package/docs/SWEBENCH-PRO-RECON-2026-07-11.md +31 -0
  911. package/docs/TB-EFFICIENCY-TELEMETRY-2026-07-08.md +114 -0
  912. package/docs/TB-FAILURE-AUTOPSY-2026-07-05-RERUN.md +67 -0
  913. package/docs/TB-FAIRNESS-AUDIT-2026-07-08.md +141 -0
  914. package/docs/TB-FULL-1257-2026-07-08.md +77 -0
  915. package/docs/TB-LEG-GAP-ATTRIBUTION-1261-1263-2026-07-11.md +154 -0
  916. package/docs/TB-REGRESSION-DAEMON-KILL-2026-07-08.md +58 -0
  917. package/docs/TB-RSI-CROSSCHECK-2026-07-06.md +68 -0
  918. package/docs/TB-RSI-LEDGER.md +30 -0
  919. package/docs/TB-STABLE-SET-2026-07-08.md +127 -0
  920. package/docs/TB21-RECON-2026-07-11.md +28 -0
  921. package/docs/TEST-DESIGN-BATCH-1-2-3.md +97 -0
  922. package/docs/THIRD-PARTY-INTEGRATION.md +45 -0
  923. package/docs/TOKEN-ESTIMATE-CALIBRATION-LIVE-2026-07-09.md +102 -0
  924. package/docs/audit-2026-06-10-/347/254/254/344/272/214/350/275/256-/347/251/272/347/231/275/345/214/272/344/270/216/345/277/230/346/216/245/347/272/277.md +147 -0
  925. package/docs/audit-2026-06-10-/350/256/241/347/256/227bug/346/211/253/346/217/217.md +163 -0
  926. package/docs/audit-2026-06-11-/344/277/256/345/244/215/345/244/215/345/256/241/344/270/216/345/233/236/345/275/222/344/270/223/346/211/253.md +95 -0
  927. package/docs/audit-2026-06-12-design71-P1/346/275/234/344/274/217/351/235/242/350/243/201/345/206/263/344/270/216/345/220/236/351/224/231/345/256/241/350/256/241.md +45 -0
  928. package/docs/audit-2026-06-12-/345/205/254/345/274/200/346/227/213/351/222/256/346/264/273/346/200/247/344/270/216vendored/346/255/273/350/267/257.md +63 -0
  929. package/docs/audit-2026-06-15/ADDENDUM-second-pass.md +88 -0
  930. package/docs/audit-2026-06-15/ARCHITECTURE-AND-ROADMAP.md +187 -0
  931. package/docs/audit-2026-06-15/DOC-CORRECTIONS.md +105 -0
  932. package/docs/audit-2026-06-15/INDEX.md +49 -0
  933. package/docs/audit-2026-06-15/ORCHESTRATION-STATUS.md +98 -0
  934. package/docs/audit-2026-06-15/PRODUCTION-ISSUES.md +189 -0
  935. package/docs/audit-2026-06-15/REFERENCES-literature.md +139 -0
  936. package/docs/audit-2026-06-15/VENDOR-REFACTOR-PLAN.md +96 -0
  937. package/docs/cc-probe-198/README.md +72 -0
  938. package/docs/cc-probe-198/STABILITY-AUDIT.md +118 -0
  939. package/docs/cc-probe-198/live-schema-monitor-worktree-2026-07-09.json +56 -0
  940. package/docs/cc-probe-198/mount-variants.json +536 -0
  941. package/docs/cc-probe-198/plan-mode-run.json +1 -0
  942. package/docs/cc-probe-198/probe-bash-bg.json +224 -0
  943. package/docs/cc-probe-198/probe-edit-mismatch.json +120 -0
  944. package/docs/cc-probe-198/probe-read-missing.json +62 -0
  945. package/docs/cc-probe-198/probe-search-empty.json +127 -0
  946. package/docs/cc-probe-198/probe-task-family.json +227 -0
  947. package/docs/cc-probe-198/probes.status +6 -0
  948. package/docs/cc-probe-198/raw-capture-interactive.json +948 -0
  949. package/docs/cc-probe-198/raw-capture-print.json +787 -0
  950. package/docs/cc-probe-198/raw-capture2-interactive.json +948 -0
  951. package/docs/cc-probe-198/raw-capture2-print.json +787 -0
  952. package/docs/cc-probe-198/system-prompt.txt +135 -0
  953. package/docs/cc-probe-198/tools-array.json +962 -0
  954. package/docs/durability-boundary.md +63 -0
  955. package/docs/fix-2026-06-10-/350/256/241/347/256/227bug/344/277/256/345/244/215-search/346/211/271.md +75 -0
  956. package/docs/fix-2026-06-11-/347/254/254/344/272/214/350/275/256-/344/277/256/345/244/215-search/346/211/271.md +62 -0
  957. package/docs/parity-sweep/REPORT-DYNAMIC.md +97 -0
  958. package/docs/parity-sweep/REPORT-STATIC-GGB.md +127 -0
  959. package/docs/parity-sweep/REPORT-STATIC-RWE.md +133 -0
  960. package/docs/vendor-history.md +385 -0
  961. package/docs/vendored-upstream-diff-2026-07.md +83 -0
  962. package/package.json +70 -0
@@ -0,0 +1,1490 @@
1
+ /**
2
+ * First-party agent loop (design/118 ④a — de-vendoring 4/6).
3
+ *
4
+ * Rewritten from the vendored openclaw distillation with the loop's control flow made EXPLICIT as a
5
+ * state machine (the CC query.ts State/transition shape, sema deps injected): every "go around again"
6
+ * is a named {@link LoopContinue} and every exit is a named {@link LoopTerminal}, so tests can assert
7
+ * WHICH path ran (test/loop-transitions.test.ts) instead of inferring it from event order. ④a is
8
+ * behavior-1:1 with the vendored loop — no new recovery chains; those land in ④b as new Continue
9
+ * reasons on this skeleton.
10
+ *
11
+ * Load-bearing invariants carried over verbatim (the VENDORED EDIT provenance comments are kept at
12
+ * their sites as history):
13
+ * - A-1 layer ② abort-before-stream guard (a mid-batch abort must never reach the next provider
14
+ * request) — {@link runSingleTurn} entry guard, Terminal `aborted_before_stream`.
15
+ * - Durable double-execution gate (a deferred parallel tool closure must never run its side effect
16
+ * after a mid-batch suspend/abort) — {@link executePreparedToolCall} entry guard.
17
+ * - D4 post-hook posture (afterToolCall throw must not rewrite a committed side effect into a flat
18
+ * failure) — {@link finalizeExecutedToolCall}.
19
+ * - The TWO queue drain points (1.204 priority wiring基石): steer drains at every turn end
20
+ * (Continue `steer_injected` / mid-work boundary), followUp drains only when the agent would
21
+ * otherwise stop (Continue `follow_up_injected`). Never merge these into one queue.
22
+ * - text_delta.partial reconstruction (upstream cherry-pick 6fcc945702).
23
+ */
24
+ import { EventStream as LlmEventStream } from "../llm/index.js";
25
+ import { findToolByName, validateToolArguments } from "../llm/index.js";
26
+ // VENDORED EDIT (design/136 §2.4, same class as the design/115 P0 findToolByName edit): the retired-tool
27
+ // tombstone table lives with OLD_TO_NEW in core (single "historical names" archive point); the roster-miss
28
+ // branch consults it AFTER findToolByName so a deployment's own same-named tool always wins.
29
+ import { TOMBSTONED_TOOLS } from "../../core/tool-name-aliases.js";
30
+ import { resolveAgentCoreStreamFn } from "./runtime-deps.js";
31
+ const EMPTY_USAGE = {
32
+ input: 0,
33
+ output: 0,
34
+ cacheRead: 0,
35
+ cacheWrite: 0,
36
+ totalTokens: 0,
37
+ cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0, total: 0 },
38
+ };
39
+ const EventStreamConstructor = LlmEventStream;
40
+ function appendTextDeltaToAssistantMessage(message, contentIndex, delta) {
41
+ const content = [...message.content];
42
+ const currentContent = content[contentIndex];
43
+ content[contentIndex] =
44
+ currentContent?.type === "text"
45
+ ? { ...currentContent, text: currentContent.text + delta }
46
+ : { type: "text", text: delta };
47
+ return { ...message, content };
48
+ }
49
+ function resolveAssistantMessageUpdate(event, currentMessage) {
50
+ if ("partial" in event && event.partial) {
51
+ return event.partial;
52
+ }
53
+ if (event.type === "text_delta") {
54
+ return appendTextDeltaToAssistantMessage(currentMessage, event.contentIndex, event.delta);
55
+ }
56
+ return currentMessage;
57
+ }
58
+ /**
59
+ * Start an agent loop with a new prompt message.
60
+ * The prompt is added to the context and events are emitted for it.
61
+ */
62
+ export function agentLoop(prompts, context, config, signal, streamFn, runtime) {
63
+ const stream = createAgentStream();
64
+ void runAgentLoop(prompts, context, config, async (event) => {
65
+ stream.push(event);
66
+ }, signal, streamFn, runtime)
67
+ .then((messages) => {
68
+ stream.end(messages);
69
+ })
70
+ .catch((error) => {
71
+ pushLoopFailure(stream, config, error, signal?.aborted === true);
72
+ });
73
+ return stream;
74
+ }
75
+ /**
76
+ * Continue an agent loop from the current context without adding a new message.
77
+ * Used for retries - context already has user message or tool results.
78
+ *
79
+ * **Important:** The last message in context must convert to a `user` or `toolResult` message
80
+ * via `convertToLlm`. If it doesn't, the LLM provider will reject the request.
81
+ * This cannot be validated here since `convertToLlm` is only called once per turn.
82
+ */
83
+ export function agentLoopContinue(context, config, signal, streamFn, runtime) {
84
+ if (context.messages.length === 0) {
85
+ throw new Error("Cannot continue: no messages in context");
86
+ }
87
+ if (context.messages[context.messages.length - 1].role === "assistant") {
88
+ throw new Error("Cannot continue from message role: assistant");
89
+ }
90
+ const stream = createAgentStream();
91
+ void runAgentLoopContinue(context, config, async (event) => {
92
+ stream.push(event);
93
+ }, signal, streamFn, runtime)
94
+ .then((messages) => {
95
+ stream.end(messages);
96
+ })
97
+ .catch((error) => {
98
+ pushLoopFailure(stream, config, error, signal?.aborted === true);
99
+ });
100
+ return stream;
101
+ }
102
+ /** Run a prompt-started loop and emit events through a caller-owned sink. */
103
+ export async function runAgentLoop(prompts, context, config, emit, signal, streamFn, runtime, trace) {
104
+ const newMessages = [...prompts];
105
+ const currentContext = {
106
+ ...context,
107
+ messages: [...context.messages, ...prompts],
108
+ };
109
+ await emit({ type: "agent_start" });
110
+ await emit({ type: "turn_start" });
111
+ for (const prompt of prompts) {
112
+ await emit({ type: "message_start", message: prompt });
113
+ await emit({ type: "message_end", message: prompt });
114
+ }
115
+ await runLoop(currentContext, newMessages, config, signal, emit, streamFn, runtime, trace);
116
+ return newMessages;
117
+ }
118
+ /** Continue an existing loop context and emit only newly produced messages. */
119
+ export async function runAgentLoopContinue(context, config, emit, signal, streamFn, runtime, trace) {
120
+ if (context.messages.length === 0) {
121
+ throw new Error("Cannot continue: no messages in context");
122
+ }
123
+ if (context.messages[context.messages.length - 1].role === "assistant") {
124
+ throw new Error("Cannot continue from message role: assistant");
125
+ }
126
+ const newMessages = [];
127
+ const currentContext = { ...context };
128
+ await emit({ type: "agent_start" });
129
+ await emit({ type: "turn_start" });
130
+ await runLoop(currentContext, newMessages, config, signal, emit, streamFn, runtime, trace);
131
+ return newMessages;
132
+ }
133
+ function createAgentStream() {
134
+ return new EventStreamConstructor((event) => event.type === "agent_end", (event) => (event.type === "agent_end" ? event.messages : []));
135
+ }
136
+ function createLoopFailureMessage(config, error, aborted) {
137
+ return {
138
+ role: "assistant",
139
+ content: [{ type: "text", text: "" }],
140
+ api: config.model.api,
141
+ provider: config.model.provider,
142
+ model: config.model.id,
143
+ usage: EMPTY_USAGE,
144
+ stopReason: aborted ? "aborted" : "error",
145
+ errorMessage: error instanceof Error ? error.message : String(error),
146
+ timestamp: Date.now(),
147
+ };
148
+ }
149
+ function pushLoopFailure(stream, config, error, aborted) {
150
+ const failureMessage = createLoopFailureMessage(config, error, aborted);
151
+ stream.push({ type: "message_start", message: failureMessage });
152
+ stream.push({ type: "message_end", message: failureMessage });
153
+ stream.push({ type: "turn_end", message: failureMessage, toolResults: [] });
154
+ stream.push({ type: "agent_end", messages: [failureMessage] });
155
+ }
156
+ // ④b default prompt-too-long classifier: conservative provider-message patterns (an integrator with a
157
+ // typed error channel overrides via `recovery.promptTooLong.detect`). Only consulted when a recovery
158
+ // hook is configured. Honest cost note: a false positive triggers one bounded recover() call — at the
159
+ // harness wiring that PERSISTS a forced compaction to the session (visible, not free), so patterns
160
+ // stay word-bounded and error-scoped; recovery-less runs are untouched either way.
161
+ const PROMPT_TOO_LONG_RE = /context.{0,3}length|context_length|context window (?:limit|exceeded)|reached its context window|prompt is too long|too many tokens|maximum context|exceeds? .{0,30}(?:context|token)|input is too long|\b413\b/i;
162
+ /** No non-blank text/thinking and no tool calls — mirrors the harness's empty-failure-persistence skip. */
163
+ function isBlankFailureContent(message) {
164
+ return message.content.every((c) => c.type === "text" ? c.text.trim() === "" : c.type === "thinking" ? c.thinking.trim() === "" : false);
165
+ }
166
+ function defaultDetectPromptTooLong(message) {
167
+ return message.stopReason === "error" && PROMPT_TOO_LONG_RE.test(message.errorMessage ?? "");
168
+ }
169
+ /**
170
+ * M1 (docs/PARITY-CONTEXT-TRANSACTIONS-2026-07-10 §4, CC 2.1.198 withhold parity): hold back the
171
+ * message_start/message_end of a stream-final that LOOKS like a recoverable prompt-too-long failure
172
+ * (error stop + classifier match + blank content — the same predicate the recovery gate uses), so
173
+ * the loop can decide the recovery outcome BEFORE consumers see any error. CC 198 does this inside
174
+ * its stream decoder (`claude-cli-2.1.198.pretty.js:473371-473374`, `if (!$s) yield`); ours is a
175
+ * hold-buffer at the loop's emit seam (degrading.ts heldStart pattern, adapted to the final).
176
+ *
177
+ * Safety shape: a real PTL rejection fails BEFORE the provider streams anything, so its
178
+ * message_start is the terminal-path one (emitted together with message_end, carrying the final
179
+ * error message) — both get held as a unit. A LIVE partial start (stopReason "stop" placeholder,
180
+ * stream-engine emptyAssistant) is never a candidate and passes through untouched, and once a live
181
+ * start went out we never hold the end (no dangling message_start on a later discard). All other
182
+ * events pass through verbatim — non-PTL error ordering is untouched by construction.
183
+ */
184
+ function createPtlWithholdBuffer(emit, detect) {
185
+ const held = [];
186
+ let liveStartEmitted = false;
187
+ const isCandidate = (message) => message.role === "assistant" &&
188
+ message.stopReason === "error" &&
189
+ detect(message) &&
190
+ isBlankFailureContent(message);
191
+ return {
192
+ sink: async (event) => {
193
+ if (event.type === "message_start" && isCandidate(event.message)) {
194
+ held.push(event); // terminal-path start of a candidate failure (paired with its end below)
195
+ return;
196
+ }
197
+ if (event.type === "message_end" && !liveStartEmitted && isCandidate(event.message)) {
198
+ held.push(event);
199
+ return;
200
+ }
201
+ if (event.type === "message_start")
202
+ liveStartEmitted = true;
203
+ await emit(event);
204
+ },
205
+ async flush() {
206
+ for (const event of held.splice(0))
207
+ await emit(event);
208
+ },
209
+ discard() {
210
+ held.length = 0;
211
+ },
212
+ };
213
+ }
214
+ /** S2 (design/119): retry nudge for a `toolUse` stop that carried zero parseable tool calls. */
215
+ function createMalformedToolUseNudge() {
216
+ return {
217
+ role: "custom",
218
+ customType: "loop:malformed-tool-use-retry",
219
+ content: "Your previous response indicated tool use but contained no valid tool call. Re-issue the tool call(s) now, with complete and valid JSON arguments — provide exactly one JSON value per parameter, and do not truncate.",
220
+ display: false,
221
+ timestamp: Date.now(),
222
+ };
223
+ }
224
+ /** S2 (design/119): retry nudge for a turn that produced only internal reasoning, no visible output. */
225
+ function createThinkingOnlyNudge() {
226
+ return {
227
+ role: "custom",
228
+ customType: "loop:thinking-only-retry",
229
+ content: "Your previous response had no visible output — it contained only internal reasoning. Respond now with your answer as visible text (or make the required tool calls); do not end the turn with reasoning alone.",
230
+ display: false,
231
+ timestamp: Date.now(),
232
+ };
233
+ }
234
+ /** design/124 tier A: continue nudge after a partially-finalized (mid-stream cut, promoted) "stop" turn.
235
+ * Separate message + counter from the truncated-output nudge — the cause differs (connection loss, not a
236
+ * token budget) and the model already sees the brain's "may be incomplete" warning in the transcript. */
237
+ function createMidstreamPartialContinueNudge() {
238
+ return {
239
+ role: "custom",
240
+ customType: "loop:midstream-partial-continue",
241
+ content: "Your previous response was cut off mid-stream by a connection failure — the content above may be incomplete. Continue EXACTLY where you left off; do not repeat any content you already produced, do not re-introduce or summarize.",
242
+ display: false,
243
+ timestamp: Date.now(),
244
+ };
245
+ }
246
+ /** The ④b synthetic continue nudge — a non-displayed custom message (convertToLlm renders it as user). */
247
+ /** T1-4: the different-approach nudge after a degenerate-repetition cutoff (same custom-message shape as
248
+ * the truncated-output continue — event ordering flows through the normal pending-message path). */
249
+ function createDegenerateRecoveryNudge() {
250
+ return {
251
+ role: "custom",
252
+ customType: "loop:degenerate-output-recovery",
253
+ content: "Your previous reply degenerated into repetition and was cut off. Do NOT repeat or continue that text. " +
254
+ "Take a DIFFERENT approach: state your next concrete step or conclusion in one short sentence, then proceed normally.",
255
+ display: false,
256
+ timestamp: Date.now(),
257
+ };
258
+ }
259
+ /** design/130 P2b: the write-out nudge after a walltime cutoff — the salvaged prefix stays in the
260
+ * transcript; the model gets ONE short final turn inside the reserved cushion. */
261
+ function createWalltimeCutoffRecoveryNudge() {
262
+ return {
263
+ role: "custom",
264
+ customType: "loop:walltime-cutoff-recovery",
265
+ content: "Your previous response crossed the task's wall-clock deadline and was cut off (the partial text above is preserved). " +
266
+ "This is the FINAL turn: write your best current answer / deliverables NOW in one short response — no new work, no long commands.",
267
+ display: false,
268
+ timestamp: Date.now(),
269
+ };
270
+ }
271
+ /** service [405] codex delta-b: the length-stop variant for a turn whose whole budget went to
272
+ * (non-replayed) reasoning — "continue where you left off" would point at nothing the provider
273
+ * can see. Ask for the answer directly. */
274
+ function createReasoningCutContinueNudge() {
275
+ return {
276
+ role: "custom",
277
+ customType: "loop:truncated-output-continue",
278
+ content: "Your previous response hit the output-token limit before producing any visible text (the budget went to internal reasoning). " +
279
+ "Do NOT restart the long reasoning: state your current best answer or next concrete action directly as visible text (or make the required tool call) now.",
280
+ display: false,
281
+ timestamp: Date.now(),
282
+ };
283
+ }
284
+ function createContinueNudge() {
285
+ return {
286
+ role: "custom",
287
+ customType: "loop:truncated-output-continue",
288
+ content: "Your previous response was cut off because it hit the output-token limit. Continue EXACTLY where you left off — do not repeat any content you already produced, do not re-introduce or summarize.",
289
+ display: false,
290
+ timestamp: Date.now(),
291
+ };
292
+ }
293
+ /**
294
+ * Main loop logic shared by agentLoop and agentLoopContinue.
295
+ *
296
+ * Drive rule (identical to the vendored nested while-loops, made explicit):
297
+ * - While work remains (`hasMoreToolCalls || pendingMessages`), run turns; after each turn drain
298
+ * the STEERING queue (drain point A — mid-work boundary).
299
+ * - When work runs out, drain the FOLLOW-UP queue (drain point B — the agent was about to stop);
300
+ * a non-empty drain re-enters the turn loop, an empty one is the natural `completed` Terminal.
301
+ * Every Terminal path emits `agent_end` exactly once.
302
+ */
303
+ async function runLoop(initialContext, newMessages, initialConfig, signal, emit, streamFn, runtime, trace) {
304
+ const state = {
305
+ context: initialContext,
306
+ config: initialConfig,
307
+ newMessages,
308
+ firstTurn: true,
309
+ // Check for steering messages at start (user may have typed while waiting)
310
+ pendingMessages: (await initialConfig.getSteeringMessages?.()) || [],
311
+ hasMoreToolCalls: true,
312
+ truncatedOutputContinues: 0,
313
+ // [477] 1.253 双轨终审 MED: seed from HISTORY, not 0 — the `staticReasoningCut` tag is persisted
314
+ // on each downgraded assistant message, so a resumed run (suspend/resume rebuilds LoopState)
315
+ // counts prior downgrades instead of re-granting a fresh 2-recovery budget every runLoop.
316
+ staticReasoningCutRecoveries: initialContext.messages.filter((m) => m.role === "assistant" && m.staticReasoningCut === true).length,
317
+ degenerateContinues: 0,
318
+ walltimeCutoffContinues: 0,
319
+ malformedToolUseRetries: 0,
320
+ thinkingOnlyRetries: 0,
321
+ midstreamPartialContinues: 0,
322
+ };
323
+ while (true) {
324
+ if (!state.hasMoreToolCalls && state.pendingMessages.length === 0) {
325
+ // Drain point B: the agent would otherwise stop. Follow-up messages route through the same
326
+ // pending-message path so event ordering matches steering messages.
327
+ const followUpMessages = (await state.config.getFollowUpMessages?.()) || [];
328
+ if (followUpMessages.length === 0) {
329
+ trace?.({ kind: "terminal", reason: "completed" });
330
+ break;
331
+ }
332
+ state.pendingMessages = followUpMessages;
333
+ trace?.({ kind: "continue", reason: "follow_up_injected" });
334
+ }
335
+ const outcome = await runSingleTurn(state, signal, emit, streamFn, runtime, trace);
336
+ if (outcome.kind === "terminal") {
337
+ trace?.({ kind: "terminal", reason: outcome.reason });
338
+ // Terminal turns have already emitted `agent_end`.
339
+ return;
340
+ }
341
+ // Only a turn with actual further work is a Continue; a turn that ran dry falls through to the
342
+ // top-of-loop decision (drain point B → follow_up_injected, or the natural `completed` Terminal).
343
+ if (outcome.recovered) {
344
+ trace?.({ kind: "continue", reason: outcome.recovered });
345
+ }
346
+ else if (state.pendingMessages.length > 0) {
347
+ trace?.({ kind: "continue", reason: "steer_injected" });
348
+ }
349
+ else if (state.hasMoreToolCalls) {
350
+ trace?.({ kind: "continue", reason: "next_turn" });
351
+ }
352
+ }
353
+ await emit({ type: "agent_end", messages: state.newMessages });
354
+ }
355
+ /** [477]: per-run stop-loss for static reasoning-cut downgrades — the 3rd reasoning-only static
356
+ * max_tokens hit fails loud again (no infinite truncate/continue token burn on a budget-ignoring
357
+ * thinking model). */
358
+ const MAX_STATIC_REASONING_CUT_RECOVERIES = 2;
359
+ /** One turn: A-1 guard → inject pending → stream assistant → tool batch → boundary hooks → drain steer. */
360
+ async function runSingleTurn(state, signal, emit, streamFn, runtime, trace) {
361
+ // VENDORED EDIT provenance (audit A-1 layer ②, design/64 §28.3): an abort that fired during the
362
+ // previous turn's tool batch used to reach the next streamAssistantResponse anyway, which fails
363
+ // fast on the aborted signal and synthesizes an EMPTY stopReason:"aborted" assistant message —
364
+ // persisted into the session BETWEEN the interrupted batch and its later reconcile tool_results,
365
+ // leaving the session a permanently invalid sequence for strict providers (assistant tool_calls
366
+ // not all answered before the next assistant). Exit cleanly instead: no doomed request, no junk
367
+ // message; the caller's interrupt reconcile then appends its synthetic tool_results directly
368
+ // after the real batch — a legal transcript. (Durable invariant — see design/45.)
369
+ if (signal?.aborted) {
370
+ await emit({ type: "agent_end", messages: state.newMessages });
371
+ return { kind: "terminal", reason: "aborted_before_stream" };
372
+ }
373
+ if (!state.firstTurn) {
374
+ await emit({ type: "turn_start" });
375
+ }
376
+ else {
377
+ state.firstTurn = false;
378
+ }
379
+ // Process pending messages (inject before next assistant response)
380
+ if (state.pendingMessages.length > 0) {
381
+ for (const message of state.pendingMessages) {
382
+ await emit({ type: "message_start", message });
383
+ await emit({ type: "message_end", message });
384
+ state.context.messages.push(message);
385
+ state.newMessages.push(message);
386
+ }
387
+ }
388
+ // Stream assistant response. design/120 P2: the in-stream executor is PER-STREAM (a PTL retry
389
+ // below gets a fresh one); it is created unconditionally — with streamingToolExecution unset it
390
+ // admits nothing and every path below sees an empty executor (exactly the pre-P2 behavior).
391
+ let executor = new StreamToolExecutor(state.context, state.config, signal, emit);
392
+ // design/120 §5.2 settle barrier: after ANY stream final, await every in-flight in-stream call
393
+ // before any later step — recovery, terminal reconciliation and the batch pipeline must all start
394
+ // with zero in-stream work in flight. try/finally (codex impl-review BLOCKER-2): a THROW out of
395
+ // the stream (an emit/hook throw is the reachable case — brains report errors as events, not
396
+ // throws) must still settle, or admitted side effects would outlive the loop-failure terminal
397
+ // with nobody awaiting them. settle() never rejects (runOne's belt catch). Results still held at
398
+ // a throw are unrecoverable by design (no final assistant exists to own them in the transcript) —
399
+ // documented limitation, same shape as the pre-P2 loop-failure path.
400
+ // [477]: grant the brain the static reasoning-cut → recoverable-length downgrade only while the
401
+ // loop can actually recover it (truncated-output recovery configured — without the continue chain
402
+ // a downgraded `length` would just end the run as a silent empty stop, strictly worse than the
403
+ // fail-loud error) and the per-run stop-loss budget lasts.
404
+ const staticReasoningCutDowngrade = state.config.recovery?.truncatedOutput !== undefined &&
405
+ state.staticReasoningCutRecoveries < MAX_STATIC_REASONING_CUT_RECOVERIES;
406
+ // M1 (PARITY-CONTEXT-TRANSACTIONS §4): while a PTL recovery could still be attempted, withhold a
407
+ // candidate failure's message_start/message_end from consumers — CC 198 holds these errors inside
408
+ // its stream decoder (`:473371-473374`) and only leaks them once recovery's outcome is known.
409
+ // Recovery succeeded ⇒ the failed assistant is never seen (matches the existing pop-from-context);
410
+ // failed/declined/gate-unmet ⇒ flush() leaks the events at that point. The terminal truth is
411
+ // unchanged — only the interim "error → continued anyway" sequence disappears. Live visibility of
412
+ // the retry is deliberately given up (by-design trade, `withholdErrorEvents: false` restores it).
413
+ const ptl = state.config.recovery?.promptTooLong;
414
+ const ptlDetect = ptl?.detect ?? defaultDetectPromptTooLong;
415
+ const withholdEnabled = ptl !== undefined && (ptl.withholdErrorEvents ?? true);
416
+ let withhold = withholdEnabled ? createPtlWithholdBuffer(emit, ptlDetect) : undefined;
417
+ let message;
418
+ try {
419
+ message = await streamAssistantResponse(state.context, state.config, signal, withhold?.sink ?? emit, streamFn, runtime, executor, staticReasoningCutDowngrade);
420
+ }
421
+ finally {
422
+ await executor.settle();
423
+ }
424
+ // ④b recovery chain — prompt-too-long: retry INSIDE the turn (no extra `turn_start`). The failed
425
+ // assistant is dropped from the retry context and never enters the run's returned messages; its
426
+ // stream events are WITHHELD above (M1) until the recovery outcome is known. The recover() hook
427
+ // owns the policy (compact/trim); the loop owns the bounded transition (CC reactive-compact adapted).
428
+ {
429
+ if (ptl) {
430
+ const detect = ptlDetect;
431
+ const maxRetries = ptl.maxRetries ?? 2;
432
+ let attempt = 0;
433
+ while (message.stopReason === "error" &&
434
+ !signal?.aborted &&
435
+ detect(message) &&
436
+ // Recovery is gated on an EMPTY failure (no non-blank text/thinking, no tool calls) — the
437
+ // same predicate the harness uses to SKIP persisting failure assistants. A partial-content
438
+ // failure was already persisted by message_end, so popping it here would fork the in-memory
439
+ // context from the session (and a retry would leave adjacent assistants in the transcript);
440
+ // surface it as the terminal error instead, exactly like the pre-④b loop.
441
+ isBlankFailureContent(message) &&
442
+ // design/120 P2 guard: an in-stream side effect already happened ⇒ never pop-and-retry
443
+ // (the retried model would re-issue the call = double execution). A REAL prompt-too-long
444
+ // failure produces no output, so its executor is always empty — zero loss. This also covers
445
+ // the content-loss tear path isBlankFailureContent alone can't see (empty content, work
446
+ // done); note the merge-back in streamAssistantResponse already de-blanks that message, so
447
+ // this clause is belt-and-suspenders.
448
+ executor.admittedCount === 0 &&
449
+ attempt < maxRetries) {
450
+ attempt++;
451
+ // Drop the failed assistant from the context tail before handing the transcript to recover().
452
+ if (state.context.messages[state.context.messages.length - 1] === message) {
453
+ state.context.messages.pop();
454
+ }
455
+ // Contract says recover() must not throw; treat a throw as "recovery declined" (belt), never
456
+ // as a new failure that would swallow the original prompt-too-long error.
457
+ let replaced;
458
+ try {
459
+ replaced = await ptl.recover(state.context.messages, attempt);
460
+ }
461
+ catch {
462
+ replaced = undefined;
463
+ }
464
+ if (!replaced) {
465
+ // Recovery declined — restore the failed assistant so downstream sees the true transcript.
466
+ // (Its withheld events leak via the flush below — the decline IS the known outcome.)
467
+ state.context.messages.push(message);
468
+ break;
469
+ }
470
+ // M1: recovery replaced the transcript — the failed assistant's withheld events are
471
+ // discarded (consumers never see the recovered error), and the retry stream gets a fresh
472
+ // buffer (the retry itself may hit prompt-too-long again).
473
+ withhold?.discard();
474
+ withhold = withholdEnabled ? createPtlWithholdBuffer(emit, ptlDetect) : undefined;
475
+ state.context.messages = replaced;
476
+ trace?.({ kind: "continue", reason: "reactive_compact_retry" });
477
+ executor = new StreamToolExecutor(state.context, state.config, signal, emit); // per-stream
478
+ try {
479
+ message = await streamAssistantResponse(state.context, state.config, signal, withhold?.sink ?? emit, streamFn, runtime, executor, staticReasoningCutDowngrade);
480
+ }
481
+ finally {
482
+ await executor.settle(); // same throw-safety as the first stream (BLOCKER-2)
483
+ }
484
+ }
485
+ }
486
+ }
487
+ // M1: whatever is still held now has a KNOWN outcome — retries exhausted, recovery declined, or
488
+ // the gate never fired (aborted / maxRetries 0). Leak it here so the consumer's terminal truth is
489
+ // exactly the pre-M1 one (message_start+message_end of the surviving failure, original order).
490
+ await withhold?.flush();
491
+ state.newMessages.push(message);
492
+ // [477]: count each downgraded reasoning-cut turn against the per-run stop-loss (the brain tags
493
+ // them; once the budget is spent the grant above goes false and the next hit fails loud).
494
+ if (message.staticReasoningCut === true)
495
+ state.staticReasoningCutRecoveries++;
496
+ // T1-4 recovery — degenerate-repetition cutoff: the brain already cancelled the stream and salvaged the
497
+ // prefix into this errored turn. Ending the run here voids all prior work over one bad sampling run; nudge
498
+ // a DIFFERENT-approach continue instead, bounded to consecutive maxContinues (default 2). The cut-off turn
499
+ // stays in the transcript (its salvaged text is real context; the model sees what it repeated). On the
500
+ // cap, fall through to the normal error terminal (assemble → output.degenerate + salvagedOutput).
501
+ {
502
+ const degen = state.config.recovery?.degenerateOutput;
503
+ if (degen &&
504
+ message.stopReason === "error" &&
505
+ !signal?.aborted &&
506
+ degen.detect(message) &&
507
+ // codex 1.238 F2 (BLOCKER, r2 补角): a tool_call anywhere on this errored assistant — an admitted
508
+ // in-stream call OR a completed-but-unexecuted call in the final content (non-streaming path) —
509
+ // means recovering past it hands the provider a tool_call with no tool_result (4xx on strict
510
+ // providers). Gate BOTH faces; the rare degenerate+tool-call combo falls through to the error
511
+ // terminal, whose harvest writes the results correctly.
512
+ executor.admittedCount === 0 &&
513
+ message.content.every((b) => b.type !== "toolCall") &&
514
+ state.degenerateContinues < (degen.maxContinues ?? 2)) {
515
+ state.degenerateContinues++;
516
+ // codex F1: this turn still ENDED — emit its turn_end (the zero-shell usage rides the message with
517
+ // the brain's usageMissing flag) so turn accounting and save-points hold across the recovery.
518
+ await emit({ type: "turn_end", message, toolResults: [] });
519
+ // codex F5 (steer wins): drain the boundary steer first — a user redirect drives the next turn and
520
+ // suppresses the nudge; the continue is counted either way (bounded).
521
+ const drained = (await state.config.getSteeringMessages?.()) || [];
522
+ state.pendingMessages = drained.length > 0 ? drained : [createDegenerateRecoveryNudge()];
523
+ return { kind: "ran", recovered: "degenerate_output_recovery" };
524
+ }
525
+ if (message.stopReason !== "error")
526
+ state.degenerateContinues = 0;
527
+ }
528
+ // design/130 P2b — walltime-cutoff write-out recovery: the brain cut this turn at the soft
529
+ // per-call deadline (deliberate, salvaged prefix in the transcript). Ending the run here would
530
+ // void the reserved write-out cushion; nudge ONE bounded final turn instead. Same shape and
531
+ // gates as the degenerate recovery above (codex 1.238 F2: any tool_call face — admitted
532
+ // in-stream OR completed-but-unexecuted in content — forces the error terminal, whose harvest
533
+ // writes the results correctly). The counter is NOT reset on success: the deadline only gets
534
+ // nearer, so the cap bounds the whole run (no cutoff/recover ping-pong; the error terminal then
535
+ // assembles as timeout + salvagedOutput).
536
+ {
537
+ const wc = state.config.recovery?.walltimeCutoff;
538
+ if (wc &&
539
+ message.stopReason === "error" &&
540
+ !signal?.aborted &&
541
+ wc.detect(message) &&
542
+ executor.admittedCount === 0 &&
543
+ message.content.every((b) => b.type !== "toolCall") &&
544
+ state.walltimeCutoffContinues < (wc.maxContinues ?? 1)) {
545
+ state.walltimeCutoffContinues++;
546
+ // codex F1 (same as degenerate): this turn still ENDED — emit its turn_end so turn
547
+ // accounting and save-points hold across the recovery.
548
+ await emit({ type: "turn_end", message, toolResults: [] });
549
+ // codex F5 (steer wins): a boundary steer (e.g. the runner's finalize instruction, if it
550
+ // already fired) drives the write-out turn and suppresses the generic nudge.
551
+ const drained = (await state.config.getSteeringMessages?.()) || [];
552
+ state.pendingMessages = drained.length > 0 ? drained : [createWalltimeCutoffRecoveryNudge()];
553
+ return { kind: "ran", recovered: "walltime_cutoff_recovery" };
554
+ }
555
+ }
556
+ if (message.stopReason === "error" || message.stopReason === "aborted") {
557
+ // design/120 §5.4: in-stream side effects already happened — commit their REAL results before
558
+ // the terminal (a real result beats the wake-reconcile [INTERRUPTED] synthesis); unstarted
559
+ // calls stay for wake A-1. With an empty executor this is exactly the pre-P2 path.
560
+ const errorFinalResults = await harvestExecutorOnErrorFinal(executor, state, message, signal, emit);
561
+ // design/130 P2b (codex HIGH): a WALLTIME-CUT final may carry tool calls that CLOSED before the
562
+ // cut but were never admitted for execution — the harvest above only covers executor-admitted
563
+ // entries, so those calls would persist unanswered (a strict provider 4xxes the next request on
564
+ // this session forever). Synthesize an error toolResult for each uncovered call, scoped to the
565
+ // walltime cutoff ONLY (the pre-existing degenerate/error terminals keep their long-standing
566
+ // behavior — widening this is a separate decision).
567
+ if (state.config.recovery?.walltimeCutoff?.detect(message)) {
568
+ const covered = new Set(errorFinalResults.map((r) => r.toolCallId));
569
+ for (const tc of message.content.filter((c) => c.type === "toolCall")) {
570
+ if (covered.has(tc.id))
571
+ continue;
572
+ const synthetic = {
573
+ role: "toolResult",
574
+ toolCallId: tc.id,
575
+ toolName: tc.name,
576
+ content: [{ type: "text", text: "[call aborted by walltime cutoff — never executed]" }],
577
+ isError: true,
578
+ timestamp: Date.now(),
579
+ };
580
+ await emitToolResultMessage(synthetic, emit);
581
+ state.context.messages.push(synthetic);
582
+ state.newMessages.push(synthetic);
583
+ errorFinalResults.push(synthetic);
584
+ }
585
+ }
586
+ await emit({ type: "turn_end", message, toolResults: errorFinalResults });
587
+ await emit({ type: "agent_end", messages: state.newMessages });
588
+ return { kind: "terminal", reason: "assistant_error" };
589
+ }
590
+ // Check for tool calls
591
+ const toolCalls = message.content.filter((c) => c.type === "toolCall");
592
+ const toolResults = [];
593
+ state.hasMoreToolCalls = false;
594
+ if (toolCalls.length > 0) {
595
+ const executedToolBatch = await executeToolCalls(state.context, message, state.config, signal, emit, executor);
596
+ toolResults.push(...executedToolBatch.messages);
597
+ state.hasMoreToolCalls = !executedToolBatch.terminate;
598
+ for (const result of toolResults) {
599
+ state.context.messages.push(result);
600
+ state.newMessages.push(result);
601
+ }
602
+ }
603
+ else {
604
+ // Extreme contract breach: a done final with ZERO toolCall content while the executor admitted
605
+ // work (the batch pipeline never runs, so its orphan drain can't). Close the pairs here (F-3).
606
+ for (const orphan of executor.remaining()) {
607
+ executor.take(orphan.toolCall.id);
608
+ await closeOrphanedStreamEntry(orphan, emit);
609
+ }
610
+ }
611
+ await emit({ type: "turn_end", message, toolResults });
612
+ const nextTurnContext = {
613
+ message,
614
+ toolResults,
615
+ context: state.context,
616
+ newMessages: state.newMessages,
617
+ };
618
+ const nextTurnSnapshot = await state.config.prepareNextTurn?.(nextTurnContext);
619
+ if (nextTurnSnapshot) {
620
+ state.context = nextTurnSnapshot.context ?? state.context;
621
+ state.config = Object.assign({}, state.config, {
622
+ model: nextTurnSnapshot.model ?? state.config.model,
623
+ reasoning: nextTurnSnapshot.thinkingLevel === undefined
624
+ ? state.config.reasoning
625
+ : nextTurnSnapshot.thinkingLevel === "off"
626
+ ? undefined
627
+ : nextTurnSnapshot.thinkingLevel,
628
+ });
629
+ }
630
+ if (await state.config.shouldStopAfterTurn?.({
631
+ message,
632
+ toolResults,
633
+ context: state.context,
634
+ newMessages: state.newMessages,
635
+ })) {
636
+ await emit({ type: "agent_end", messages: state.newMessages });
637
+ return { kind: "terminal", reason: "stop_requested" };
638
+ }
639
+ // Drain point A (mid-work boundary): steering messages inject before the next provider request.
640
+ state.pendingMessages = (await state.config.getSteeringMessages?.()) || [];
641
+ // ④b recovery chain — truncated output: a `length`-stopped answer with NO tool calls would end
642
+ // the run mid-sentence. When enabled, inject a synthetic continue nudge (through the normal
643
+ // pending-message path so event ordering matches every other injected message) and run another
644
+ // turn — bounded to `maxContinues` CONSECUTIVE times; any non-length turn resets the counter.
645
+ // A length-stop WITH tool calls needs no nudge (the tool results drive the next turn anyway).
646
+ const truncated = state.config.recovery?.truncatedOutput;
647
+ if (message.stopReason === "length") {
648
+ if (truncated &&
649
+ toolCalls.length === 0 &&
650
+ // A steer drained at this same boundary means the USER redirected — their message drives the
651
+ // next turn; appending a "continue exactly where you left off" nudge after it would fight the
652
+ // redirect from the recency position. The continue counter is untouched (no nudge happened).
653
+ state.pendingMessages.length === 0 &&
654
+ state.truncatedOutputContinues < (truncated.maxContinues ?? 3)) {
655
+ state.truncatedOutputContinues++;
656
+ // codex 实现审 #2: this early return would skip the midstream-partial reset below, so a
657
+ // partial→length-recovery→partial alternation would be miscounted as CONSECUTIVE partials and
658
+ // burn the 3-nudge budget early. A length turn is never a partial-finalized stop — reset here too.
659
+ state.midstreamPartialContinues = 0;
660
+ // service [405] codex delta-b: a length stop with NO visible text (reasoning consumed the
661
+ // budget — the dynamicCut shape) must NOT say "continue where you left off": reasoning is not
662
+ // replayed to OpenAI-family providers, so the model would see an empty assistant + a request
663
+ // to seamlessly continue nothing. Ask for a fresh visible answer instead.
664
+ const noVisibleText = !message.content.some((c) => c.type === "text" && c.text.trim() !== "");
665
+ state.pendingMessages = [...state.pendingMessages, noVisibleText ? createReasoningCutContinueNudge() : createContinueNudge()];
666
+ return { kind: "ran", recovered: "max_output_tokens_recovery" };
667
+ }
668
+ }
669
+ else {
670
+ state.truncatedOutputContinues = 0;
671
+ }
672
+ // design/124 tier A downstream: a partially-finalized "stop" turn (mid-stream cut whose substantive
673
+ // prefix was promoted to content by the brain) must not end an autonomous run as an incomplete
674
+ // success — there is no user to notice the "may be incomplete" warning and re-prompt. Bounded
675
+ // continue nudge, truncatedOutput 范式: steer wins (a drained redirect suppresses the nudge), own
676
+ // counter + own message (never mixed with the length-stop budget), consecutive-reset. Always on
677
+ // (no config gate): the flag only ever appears when the brain recovered a mid-stream failure, and
678
+ // ending silently there is strictly worse for every integrator. A `partialFinalized` toolUse turn
679
+ // takes the normal tool path above — its results drive the next turn anyway.
680
+ if (message.stopReason === "stop" && message.partialFinalized === true) {
681
+ if (toolCalls.length === 0 &&
682
+ state.pendingMessages.length === 0 &&
683
+ state.midstreamPartialContinues < 3) {
684
+ state.midstreamPartialContinues++;
685
+ state.pendingMessages = [createMidstreamPartialContinueNudge()];
686
+ return { kind: "ran", recovered: "midstream_partial_recovery" };
687
+ }
688
+ }
689
+ else {
690
+ state.midstreamPartialContinues = 0;
691
+ }
692
+ // S2 recovery (design/119, CC 198 :473745-): a `toolUse` stop whose every tool call was dropped as
693
+ // malformed (the brain already appended a visible note) used to end the run silently mid-task —
694
+ // the model believes it acted, nothing ran. Nudge a retry, bounded per run. Steer wins (same
695
+ // reasoning as the truncated-output guard above).
696
+ const malformed = state.config.recovery?.malformedToolUse;
697
+ if (malformed &&
698
+ message.stopReason === "toolUse" &&
699
+ toolCalls.length === 0 &&
700
+ state.pendingMessages.length === 0 &&
701
+ state.malformedToolUseRetries < (malformed.maxRetries ?? 1)) {
702
+ state.malformedToolUseRetries++;
703
+ state.pendingMessages = [createMalformedToolUseNudge()];
704
+ return { kind: "ran", recovered: "malformed_tool_use_retry" };
705
+ }
706
+ // S2 recovery (design/119, CC 198 :473786- — the adaptive-thinking companion): a normal stop whose
707
+ // content is ONLY thinking (no non-blank text, no tool calls) is a silent empty success. Nudge the
708
+ // model to answer visibly, bounded per run. Steer wins.
709
+ const thinkingOnly = state.config.recovery?.thinkingOnly;
710
+ if (thinkingOnly &&
711
+ message.stopReason === "stop" &&
712
+ toolCalls.length === 0 &&
713
+ state.pendingMessages.length === 0 &&
714
+ state.thinkingOnlyRetries < (thinkingOnly.maxRetries ?? 1) &&
715
+ message.content.some((c) => c.type === "thinking") &&
716
+ !message.content.some((c) => c.type === "text" && c.text.trim() !== "")) {
717
+ state.thinkingOnlyRetries++;
718
+ state.pendingMessages = [createThinkingOnlyNudge()];
719
+ return { kind: "ran", recovered: "thinking_only_retry" };
720
+ }
721
+ return { kind: "ran" };
722
+ }
723
+ /**
724
+ * Stream an assistant response from the LLM.
725
+ * This is where AgentMessage[] gets transformed to Message[] for the LLM.
726
+ */
727
+ async function streamAssistantResponse(context, config, signal, emit, streamFn, runtime, executor, staticReasoningCutDowngrade) {
728
+ // Apply context transform if configured (AgentMessage[] → AgentMessage[])
729
+ let messages = context.messages;
730
+ if (config.transformContext) {
731
+ messages = await config.transformContext(messages, signal);
732
+ }
733
+ // Convert to LLM-compatible messages (AgentMessage[] → Message[])
734
+ const llmMessages = await config.convertToLlm(messages);
735
+ // Build LLM context
736
+ const llmContext = {
737
+ systemPrompt: context.systemPrompt,
738
+ messages: llmMessages,
739
+ tools: context.tools,
740
+ };
741
+ const streamFunction = resolveAgentCoreStreamFn(runtime, streamFn);
742
+ // Resolve API key (important for expiring tokens)
743
+ const resolvedApiKey = (config.getApiKey ? await config.getApiKey(config.model.provider) : undefined) || config.apiKey;
744
+ // design/130 P1: a wall-clock-aware host may shrink THIS call's output cap; evaluated per call
745
+ // (the spread below would otherwise carry the run-static maxTokens snapshot).
746
+ const perCallMaxTokens = config.maxTokensPerCall?.();
747
+ // design/130 P2b: soft per-call wall-clock deadline — a brain that observes the wall clock
748
+ // crossing it cuts the stream (salvaging the prefix) instead of riding into the hard abort.
749
+ const perCallDeadlineMs = config.callDeadlineMsPerCall?.();
750
+ const response = await streamFunction(config.model, llmContext, {
751
+ ...config,
752
+ // service [405]: `maxTokensDynamic` marks the cap as ENGINE-shrunk — a reasoning-only
753
+ // max_tokens hit then degrades to a recoverable `length` stop instead of the fail-loud error.
754
+ ...(perCallMaxTokens !== undefined ? { maxTokens: perCallMaxTokens, maxTokensDynamic: true } : {}),
755
+ ...(perCallDeadlineMs !== undefined ? { callDeadlineMs: perCallDeadlineMs } : {}),
756
+ // [477]: the loop's per-run stop-loss grant for the STATIC reasoning-cut downgrade (the static
757
+ // sibling of maxTokensDynamic above) — a reasoning-only static max_tokens hit then degrades to
758
+ // a recoverable `length` the truncated-output continue picks up.
759
+ ...(staticReasoningCutDowngrade === true ? { staticReasoningCutDowngrade: true } : {}),
760
+ apiKey: resolvedApiKey,
761
+ signal,
762
+ });
763
+ let partialMessage = null;
764
+ let addedPartial = false;
765
+ for await (const event of response) {
766
+ switch (event.type) {
767
+ case "start": {
768
+ const message = event.partial;
769
+ partialMessage = message;
770
+ context.messages.push(message);
771
+ addedPartial = true;
772
+ await emit({ type: "message_start", message: { ...message } });
773
+ break;
774
+ }
775
+ case "text_start":
776
+ case "text_delta":
777
+ case "text_end":
778
+ case "thinking_start":
779
+ case "thinking_delta":
780
+ case "thinking_end":
781
+ case "toolcall_start":
782
+ case "toolcall_delta":
783
+ case "toolcall_end":
784
+ if (partialMessage) {
785
+ const message = resolveAssistantMessageUpdate(event, partialMessage);
786
+ partialMessage = message;
787
+ context.messages[context.messages.length - 1] = message;
788
+ await emit({
789
+ type: "message_update",
790
+ assistantMessageEvent: event,
791
+ message: { ...message },
792
+ });
793
+ }
794
+ // design/120 P2: a completed-arguments call may start executing while the stream is live.
795
+ // Admission (opt-in flag + safe tool + source-order barrier + cap) lives in the executor;
796
+ // when it declines, the call simply waits for the post-stream batch pipeline as before.
797
+ // `partialMessage` may be null on a protocol-violating stream (toolcall_end before start) —
798
+ // that DECLINE must still go through the executor so the source-order barrier rises
799
+ // (impl-review F-1: skipping maybeAdmit entirely let a LATER safe call execute in-stream
800
+ // before this earlier bounced one, breaking the admitted-is-a-prefix invariant).
801
+ if (event.type === "toolcall_end" && executor) {
802
+ executor.maybeAdmit(event.toolCall, partialMessage);
803
+ }
804
+ break;
805
+ case "done":
806
+ case "error": {
807
+ const finalMessage = await response.result();
808
+ // design/120 §5.4 content-loss defense: an error/aborted final must not drop a toolCall
809
+ // block whose call ALREADY executed in-stream (persistence point is message_end below).
810
+ if (executor && (finalMessage.stopReason === "error" || finalMessage.stopReason === "aborted")) {
811
+ mergeBackAdmittedCalls(finalMessage, executor);
812
+ }
813
+ if (addedPartial) {
814
+ context.messages[context.messages.length - 1] = finalMessage;
815
+ }
816
+ else {
817
+ context.messages.push(finalMessage);
818
+ }
819
+ if (!addedPartial) {
820
+ await emit({ type: "message_start", message: { ...finalMessage } });
821
+ }
822
+ await emit({ type: "message_end", message: finalMessage });
823
+ return finalMessage;
824
+ }
825
+ }
826
+ }
827
+ const finalMessage = await response.result();
828
+ if (executor && (finalMessage.stopReason === "error" || finalMessage.stopReason === "aborted")) {
829
+ mergeBackAdmittedCalls(finalMessage, executor); // same defense for the no-terminal-event path
830
+ }
831
+ if (addedPartial) {
832
+ context.messages[context.messages.length - 1] = finalMessage;
833
+ }
834
+ else {
835
+ context.messages.push(finalMessage);
836
+ await emit({ type: "message_start", message: { ...finalMessage } });
837
+ }
838
+ await emit({ type: "message_end", message: finalMessage });
839
+ return finalMessage;
840
+ }
841
+ /**
842
+ * Execute tool calls from an assistant message.
843
+ */
844
+ async function executeToolCalls(currentContext, assistantMessage, config, signal, emit, executor) {
845
+ const toolCalls = assistantMessage.content.filter((c) => c.type === "toolCall");
846
+ if (config.toolExecution === "sequential") {
847
+ // Explicit whole-batch serial override — semantics preserved (design/120 §1.2). The in-stream
848
+ // executor never admits under this mode (its very first admission check), so there is nothing
849
+ // to harvest here.
850
+ return executeToolCallsSequential(currentContext, assistantMessage, toolCalls, config, signal, emit);
851
+ }
852
+ // design/120 P1: partitioned execution replaces the old any-sequential→whole-batch-serial pre-scan
853
+ // (which kept mixed read/write batches — the main beneficiary — fully serial forever). Consecutive
854
+ // concurrency-safe calls run as one capped parallel batch; unsafe calls run as singleton batches;
855
+ // batches execute strictly in assistant source order. Safe = explicit `executionMode:"parallel"`
856
+ // or a true-returning input hook — fail-closed for undeclared tools (CC 2.1.206 TOOL_DEFAULTS
857
+ // parity; see isCallConcurrencySafe below). The defineTool effect derivation maps read → parallel
858
+ // and write/idempotent/undeclared → sequential.
859
+ return executeToolCallsPartitioned(currentContext, assistantMessage, toolCalls, config, signal, emit, executor);
860
+ }
861
+ async function executeToolCallsSequential(currentContext, assistantMessage, toolCalls, config, signal, emit) {
862
+ const finalizedCalls = [];
863
+ const messages = [];
864
+ for (const toolCall of toolCalls) {
865
+ await emit({
866
+ type: "tool_execution_start",
867
+ toolCallId: toolCall.id,
868
+ toolName: toolCall.name,
869
+ args: toolCall.arguments,
870
+ });
871
+ const preparation = await prepareToolCall(currentContext, assistantMessage, toolCall, config, signal);
872
+ let finalized;
873
+ if (preparation.kind === "immediate") {
874
+ finalized = {
875
+ toolCall,
876
+ result: preparation.result,
877
+ isError: preparation.isError,
878
+ };
879
+ }
880
+ else {
881
+ const executed = await executePreparedToolCall(preparation, signal, emit);
882
+ finalized = await finalizeExecutedToolCall(currentContext, assistantMessage, preparation, executed, config, signal);
883
+ }
884
+ await emitToolExecutionEnd(finalized, emit);
885
+ const toolResultMessage = createToolResultMessage(finalized);
886
+ await emitToolResultMessage(toolResultMessage, emit);
887
+ finalizedCalls.push(finalized);
888
+ messages.push(toolResultMessage);
889
+ if (signal?.aborted) {
890
+ break;
891
+ }
892
+ }
893
+ return {
894
+ messages,
895
+ terminate: shouldTerminateToolBatch(finalizedCalls),
896
+ };
897
+ }
898
+ /**
899
+ * design/120 P1.5 (CC `isConcurrencySafe(parsedInput)` parity): per-CALL concurrency safety.
900
+ * FAIL-CLOSED direction (CC 2.1.206 `TOOL_DEFAULTS.isConcurrencySafe → false`, pretty.js:280839):
901
+ * only an explicit `executionMode:"parallel"` (static opt-in — CC's statically-true read tools) or a
902
+ * true-returning input-level `isConcurrencySafe` hook (Bash read-only commands — the one real CC
903
+ * consumer) makes a call batch-safe. An UNDECLARED tool, an unknown tool name (CC partitioner
904
+ * `o?.isConcurrencySafe(...)` → false, pretty.js:520091), and a throwing hook are all unsafe.
905
+ */
906
+ function isCallConcurrencySafe(tool, args) {
907
+ if (!tool)
908
+ return false;
909
+ if (tool.executionMode === "parallel")
910
+ return true;
911
+ if (!tool.isConcurrencySafe)
912
+ return false;
913
+ try {
914
+ return tool.isConcurrencySafe(args) === true;
915
+ }
916
+ catch {
917
+ return false;
918
+ }
919
+ }
920
+ /**
921
+ * CC 2.1.206 partition parity (pretty.js:520087-520096): a call is batch-safe ONLY if its arguments
922
+ * VALIDATE against the tool's schema (CC `safeParse` — a malformed call never rides a parallel batch;
923
+ * it stays a singleton and surfaces its validation error at execution) AND the tool/hook opts in.
924
+ * The hook sees the validated+coerced args — same as CC handing `parsed.data` to `isConcurrencySafe`.
925
+ */
926
+ function isBatchSafeToolCall(tool, toolCall) {
927
+ if (!tool)
928
+ return false;
929
+ let args;
930
+ try {
931
+ args = validateToolArguments(tool, prepareToolCallArguments(tool, toolCall));
932
+ }
933
+ catch {
934
+ return false;
935
+ }
936
+ return isCallConcurrencySafe(tool, args);
937
+ }
938
+ /** design/120 P1: consecutive-safe partitioning (CC 198 partitionToolCalls semantics). */
939
+ function partitionToolCalls(toolCalls, tools) {
940
+ const batches = [];
941
+ for (const tc of toolCalls) {
942
+ // VENDORED EDIT provenance (design/115 P0): alias-aware lookup, same as the old pre-scan.
943
+ const safe = isBatchSafeToolCall(findToolByName(tools, tc.name), tc);
944
+ const last = batches[batches.length - 1];
945
+ if (safe && last?.safe) {
946
+ last.calls.push(tc);
947
+ }
948
+ else {
949
+ batches.push({ safe, calls: [tc] });
950
+ }
951
+ }
952
+ return batches;
953
+ }
954
+ /** Minimal semaphore for the per-batch concurrency cap (design/120 §1.3; CC default 10). */
955
+ async function runCapped(thunks, limit) {
956
+ const results = new Array(thunks.length);
957
+ let next = 0;
958
+ const workers = Array.from({ length: Math.max(1, Math.min(limit, thunks.length)) }, async () => {
959
+ while (next < thunks.length) {
960
+ const i = next++;
961
+ results[i] = await thunks[i]();
962
+ }
963
+ });
964
+ await Promise.all(workers);
965
+ return results;
966
+ }
967
+ /**
968
+ * design/120 P1 — partitioned batch execution. Per partition: SERIAL preflight in source order
969
+ * (tool_execution_start + prepare + the design/37 gate — a suspending gate can therefore never fire
970
+ * before an earlier-source-order batch has executed: deliberate divergence from CC, whose per-call
971
+ * chains run concurrently but which has no durable suspend), then capped-concurrent execution, then
972
+ * the batch's tool-result message artifacts in source order (so each batch's results are committed
973
+ * before the next batch's gates run — design/120 §1.2 premise). The durable double-execution gate
974
+ * inside executePreparedToolCall and the mid-batch abort semantics are unchanged: an abort leaves
975
+ * the current batch's unstarted closures and ALL later batches unexecuted (the dangling set the
976
+ * interrupt reconcile / suspendedBatch machinery already handles — sub-batch boundaries are NOT
977
+ * persisted, checkpoint batchToolCallIds stays the whole assistant batch).
978
+ */
979
+ async function executeToolCallsPartitioned(currentContext, assistantMessage, toolCalls, config, signal, emit, executor) {
980
+ const cap = config.maxToolConcurrency ?? 10;
981
+ const allFinalized = [];
982
+ const messages = [];
983
+ // design/120 P2 harvest: commit the in-stream executor's held outcomes FIRST (finalize with the
984
+ // FINAL assistant message + tool_execution_end + tool-result message), before any batch
985
+ // preflight/gate runs — a later gate's durable checkpoint (batchContextAt scans committed
986
+ // toolResults) then counts every already-executed call in completedCallIds, so the resume-side
987
+ // [DEFERRED] ("it was NOT executed") can never lie about an executed call. The source-order
988
+ // barrier makes admitted calls a leading prefix of the batch, so this commit order IS the P1
989
+ // source order. Harvest iterates ALL calls (not prefix-break) as a hardening: even if a provider
990
+ // violated the ordering contract, an executed call is never re-run by the batch pipeline below.
991
+ const remainingCalls = [];
992
+ for (const toolCall of toolCalls) {
993
+ const held = executor?.take(toolCall.id);
994
+ if (!held) {
995
+ remainingCalls.push(toolCall);
996
+ continue;
997
+ }
998
+ const finalized = await finalizeStreamEntry(currentContext, assistantMessage, held, config, signal);
999
+ await emitToolExecutionEnd(finalized, emit);
1000
+ const toolResultMessage = createToolResultMessage(finalized);
1001
+ await emitToolResultMessage(toolResultMessage, emit);
1002
+ allFinalized.push(finalized);
1003
+ messages.push(toolResultMessage);
1004
+ }
1005
+ // A done-final content is a superset of admitted calls (the P2.0 provider contract), so the
1006
+ // executor is fully drained above; anything left is a contract breach — drop the outcome but
1007
+ // close its in-stream start with a synthetic end so id-pairing consumers never hang (F-3).
1008
+ if (executor) {
1009
+ for (const orphan of executor.remaining()) {
1010
+ executor.take(orphan.toolCall.id);
1011
+ await closeOrphanedStreamEntry(orphan, emit);
1012
+ }
1013
+ }
1014
+ const batches = partitionToolCalls(remainingCalls, currentContext.tools);
1015
+ outer: for (const batch of batches) {
1016
+ if (signal?.aborted)
1017
+ break;
1018
+ // Serial preflight (source order): start events + prepare + gate. Immediate outcomes (blocked /
1019
+ // not-found / validation failures) finalize here, exactly like both pre-P1 paths.
1020
+ const entries = [];
1021
+ for (const toolCall of batch.calls) {
1022
+ await emit({
1023
+ type: "tool_execution_start",
1024
+ toolCallId: toolCall.id,
1025
+ toolName: toolCall.name,
1026
+ args: toolCall.arguments,
1027
+ });
1028
+ const preparation = await prepareToolCall(currentContext, assistantMessage, toolCall, config, signal);
1029
+ if (preparation.kind === "immediate") {
1030
+ const finalized = { toolCall, result: preparation.result, isError: preparation.isError };
1031
+ await emitToolExecutionEnd(finalized, emit);
1032
+ entries.push({ finalized, toolCall });
1033
+ }
1034
+ else {
1035
+ entries.push({ prepared: preparation, toolCall });
1036
+ }
1037
+ if (signal?.aborted) {
1038
+ // Mid-preflight abort: later calls in this batch and all later batches stay unstarted —
1039
+ // same dangling-set shape as the pre-P1 paths.
1040
+ await settleBatch(entries, true);
1041
+ break outer;
1042
+ }
1043
+ }
1044
+ await settleBatch(entries, batch.safe);
1045
+ }
1046
+ return { messages, terminate: shouldTerminateToolBatch(allFinalized) };
1047
+ /** Execute the batch's prepared calls (capped-concurrent when safe, serial otherwise), then emit
1048
+ * this batch's tool-result messages in source order. */
1049
+ async function settleBatch(entries, concurrent) {
1050
+ const runOne = (prepared) => async () => {
1051
+ const executed = await executePreparedToolCall(prepared, signal, emit);
1052
+ const finalized = await finalizeExecutedToolCall(currentContext, assistantMessage, prepared, executed, config, signal);
1053
+ await emitToolExecutionEnd(finalized, emit);
1054
+ return finalized;
1055
+ };
1056
+ const preparedEntries = entries.filter((e) => e.prepared);
1057
+ let executedResults;
1058
+ if (concurrent && preparedEntries.length > 1) {
1059
+ executedResults = await runCapped(preparedEntries.map((e) => runOne(e.prepared)), cap);
1060
+ }
1061
+ else {
1062
+ executedResults = [];
1063
+ for (const e of preparedEntries) {
1064
+ executedResults.push(await runOne(e.prepared)());
1065
+ }
1066
+ }
1067
+ let idx = 0;
1068
+ for (const e of entries) {
1069
+ const finalized = e.finalized ?? executedResults[idx++];
1070
+ if (!finalized)
1071
+ continue;
1072
+ allFinalized.push(finalized);
1073
+ const toolResultMessage = createToolResultMessage(finalized);
1074
+ await emitToolResultMessage(toolResultMessage, emit);
1075
+ messages.push(toolResultMessage);
1076
+ }
1077
+ }
1078
+ }
1079
+ /**
1080
+ * design/120 P2: executes concurrency-safe tool calls WHILE the model is still streaming.
1081
+ *
1082
+ * Lifecycle is per-stream (one instance per streamAssistantResponse call — the PTL-retry re-stream
1083
+ * gets a fresh one). Admission (see {@link AgentLoopConfig.streamingToolExecution}) is deliberately
1084
+ * narrower than CC's: opt-in flag + non-sequential dispatch + safe tool + source-order barrier + cap.
1085
+ * The barrier is the CC processQueue FIFO-break equivalent, hardened: once ANY call bounces to the
1086
+ * post-stream batch pipeline, every later call bounces too, so an admitted set is always a leading
1087
+ * prefix of the assistant batch — a source-order-later call can never execute before a bounced
1088
+ * source-order-earlier one, and the harvest's commit order stays identical to the P1 source order.
1089
+ *
1090
+ * In-stream we emit ONLY `tool_execution_start` (at launch) and `tool_execution_update` (the tool's
1091
+ * own onUpdate). Finalization (afterToolCall), `tool_execution_end` and the tool-result message
1092
+ * artifacts are all deferred to the post-stream harvest, where the FINAL assistant message exists —
1093
+ * a mid-stream partial must never reach the tool_result hook or the session (message artifacts
1094
+ * committed mid-stream would interleave illegally with the still-open assistant message).
1095
+ */
1096
+ class StreamToolExecutor {
1097
+ context;
1098
+ config;
1099
+ signal;
1100
+ emit;
1101
+ entries = new Map();
1102
+ admittedOrder = [];
1103
+ barrier = false;
1104
+ inFlight = 0;
1105
+ constructor(context, config, signal, emit) {
1106
+ this.context = context;
1107
+ this.config = config;
1108
+ this.signal = signal;
1109
+ this.emit = emit;
1110
+ }
1111
+ /** Number of calls this executor admitted (0 ⇒ the stream behaved exactly as pre-P2). */
1112
+ get admittedCount() {
1113
+ return this.admittedOrder.length;
1114
+ }
1115
+ /** All admitted calls in admission order (read-only; used by the error-final content merge-back). */
1116
+ admittedToolCalls() {
1117
+ return this.admittedOrder.map((id) => this.entries.get(id)?.toolCall).filter((tc) => tc !== undefined);
1118
+ }
1119
+ /**
1120
+ * Admission check + launch for a call whose arguments just completed mid-stream (`toolcall_end`).
1121
+ * Every rejection raises the source-order barrier — from then on this executor admits nothing.
1122
+ */
1123
+ maybeAdmit(toolCall, partialAssistant) {
1124
+ if (this.barrier)
1125
+ return;
1126
+ if (this.config.streamingToolExecution !== true ||
1127
+ this.config.toolExecution === "sequential" ||
1128
+ this.signal?.aborted ||
1129
+ partialAssistant === null || // protocol violation (no start yet) — bounce AND raise the barrier
1130
+ !isBatchSafeToolCall(findToolByName(this.context.tools, toolCall.name), toolCall) || // P1.5: same per-call judgment as the batch partitioner (schema-invalid ⇒ unsafe, CC 206 parity)
1131
+ this.inFlight >= (this.config.maxToolConcurrency ?? 10) ||
1132
+ this.entries.has(toolCall.id) // defensive: at-most-once per id (provider contract)
1133
+ ) {
1134
+ this.barrier = true;
1135
+ return;
1136
+ }
1137
+ const entry = { toolCall, promise: Promise.resolve() };
1138
+ this.entries.set(toolCall.id, entry);
1139
+ this.admittedOrder.push(toolCall.id);
1140
+ entry.promise = this.runOne(entry, partialAssistant);
1141
+ }
1142
+ async runOne(entry, partialAssistant) {
1143
+ this.inFlight++;
1144
+ try {
1145
+ await this.emit({
1146
+ type: "tool_execution_start",
1147
+ toolCallId: entry.toolCall.id,
1148
+ toolName: entry.toolCall.name,
1149
+ args: entry.toolCall.arguments,
1150
+ });
1151
+ // Full prepare chain — defense in depth: beforeToolCall (block / updatedInput) works exactly
1152
+ // as on the batch path. The host's streamingToolExecution opt-in promises it cannot durably
1153
+ // suspend here. `partialAssistant` is the documented hook-payload snapshot (design/120 §5).
1154
+ const preparation = await prepareToolCall(this.context, partialAssistant, entry.toolCall, this.config, this.signal);
1155
+ if (preparation.kind === "immediate") {
1156
+ entry.immediate = preparation;
1157
+ return;
1158
+ }
1159
+ entry.prepared = preparation;
1160
+ entry.executed = await executePreparedToolCall(preparation, this.signal, this.emit);
1161
+ }
1162
+ catch (error) {
1163
+ // prepare/execute return error results by contract; this belt catches an emit() throw so
1164
+ // settle() never rejects and the held outcome is still a well-formed error result.
1165
+ entry.immediate = {
1166
+ kind: "immediate",
1167
+ result: createErrorToolResult(error instanceof Error ? error.message : String(error)),
1168
+ isError: true,
1169
+ };
1170
+ }
1171
+ finally {
1172
+ this.inFlight--;
1173
+ }
1174
+ }
1175
+ /**
1176
+ * The stream-final barrier (design/120 §5.2): await every in-flight call. MUST run after ANY
1177
+ * stream final (done/error/aborted) and before any later step — the batch pipeline therefore
1178
+ * starts with zero in-stream calls in flight (sequential exclusivity + the concurrency cap hold
1179
+ * structurally), and nothing can emit after the turn exits.
1180
+ */
1181
+ async settle() {
1182
+ this.barrier = true;
1183
+ await Promise.all([...this.entries.values()].map((e) => e.promise));
1184
+ }
1185
+ /** After settle: remove and return the held outcome for a call id (undefined = not admitted). */
1186
+ take(id) {
1187
+ const entry = this.entries.get(id);
1188
+ if (entry)
1189
+ this.entries.delete(id);
1190
+ return entry;
1191
+ }
1192
+ /** After settle: entries not yet taken, in admission order (the error-final harvest). */
1193
+ remaining() {
1194
+ return this.admittedOrder
1195
+ .map((id) => this.entries.get(id))
1196
+ .filter((e) => e !== undefined);
1197
+ }
1198
+ }
1199
+ /** Finalize one held executor entry into the standard outcome shape (afterToolCall runs HERE, with
1200
+ * the final assistant message — never a mid-stream partial). */
1201
+ async function finalizeStreamEntry(currentContext, assistantMessage, entry, config, signal) {
1202
+ if (entry.prepared && entry.executed) {
1203
+ return finalizeExecutedToolCall(currentContext, assistantMessage, entry.prepared, entry.executed, config, signal);
1204
+ }
1205
+ const immediate = entry.immediate ?? {
1206
+ kind: "immediate",
1207
+ // Unreachable after settle() (runOne always sets one of the outcome fields) — fail honest.
1208
+ result: createErrorToolResult("in-stream execution produced no outcome"),
1209
+ isError: true,
1210
+ };
1211
+ return { toolCall: entry.toolCall, result: immediate.result, isError: immediate.isError };
1212
+ }
1213
+ /**
1214
+ * design/120 impl-review F-3: an executor entry whose call cannot be attached to the transcript
1215
+ * (missing from the final content — a provider-contract breach) already emitted
1216
+ * `tool_execution_start` in-stream; close the start/end pair with a synthetic error end so
1217
+ * activity/spinner consumers that pair by toolCallId never hold a permanently-open call. The
1218
+ * outcome itself is dropped (an ownerless toolResult would be an illegal transcript).
1219
+ */
1220
+ async function closeOrphanedStreamEntry(entry, emit) {
1221
+ await emit({
1222
+ type: "tool_execution_end",
1223
+ toolCallId: entry.toolCall.id,
1224
+ toolName: entry.toolCall.name,
1225
+ result: createErrorToolResult("in-stream result dropped: the call is missing from the final assistant content (provider contract breach)"),
1226
+ isError: true,
1227
+ });
1228
+ }
1229
+ /**
1230
+ * design/120 §5.4 error/aborted-final harvest: commit every held outcome (the side effects already
1231
+ * happened — a real result beats a wake-reconcile [INTERRUPTED] synthesis), in admission order,
1232
+ * BEFORE the terminal turn_end/agent_end. Unstarted calls stay untouched — the existing wake A-1
1233
+ * reconcile closes them honestly.
1234
+ */
1235
+ async function harvestExecutorOnErrorFinal(executor, state, finalMessage, signal, emit) {
1236
+ const held = executor.remaining();
1237
+ if (held.length === 0)
1238
+ return [];
1239
+ const results = [];
1240
+ const persistedCallIds = new Set(finalMessage.content.filter((c) => c.type === "toolCall").map((c) => c.id));
1241
+ for (const entry of held) {
1242
+ executor.take(entry.toolCall.id);
1243
+ // A result may only enter the transcript when its toolCall exists on the persisted assistant —
1244
+ // the merge-back in streamAssistantResponse makes this the norm; a missing id here means the
1245
+ // merge-back path was bypassed (defensive), and an ownerless toolResult would be an illegal
1246
+ // transcript, so the outcome is dropped — with a synthetic end closing its in-stream start (F-3).
1247
+ if (!persistedCallIds.has(entry.toolCall.id)) {
1248
+ await closeOrphanedStreamEntry(entry, emit);
1249
+ continue;
1250
+ }
1251
+ const finalized = await finalizeStreamEntry(state.context, finalMessage, entry, state.config, signal);
1252
+ await emitToolExecutionEnd(finalized, emit);
1253
+ const toolResultMessage = createToolResultMessage(finalized);
1254
+ await emitToolResultMessage(toolResultMessage, emit);
1255
+ state.context.messages.push(toolResultMessage);
1256
+ state.newMessages.push(toolResultMessage);
1257
+ results.push(toolResultMessage);
1258
+ }
1259
+ return results;
1260
+ }
1261
+ /**
1262
+ * design/120 §5.4 content-loss defense: an error/aborted final whose message dropped mid-stream
1263
+ * blocks (the stream-engine tear path synthesizes an EMPTY-content error assistant) would leave an
1264
+ * already-executed in-stream call with zero transcript trace — no toolCall on the assistant, so its
1265
+ * result could never be attached and even wake reconcile couldn't see an orphan. Merge the
1266
+ * executor-held calls back into the final content BEFORE message_end (the persistence point).
1267
+ * The message also stops qualifying as an empty-failure skip, so it persists.
1268
+ */
1269
+ function mergeBackAdmittedCalls(finalMessage, executor) {
1270
+ const admitted = executor.admittedToolCalls();
1271
+ if (admitted.length === 0)
1272
+ return;
1273
+ const present = new Set(finalMessage.content.filter((c) => c.type === "toolCall").map((c) => c.id));
1274
+ const missing = admitted.filter((tc) => !present.has(tc.id));
1275
+ if (missing.length === 0)
1276
+ return;
1277
+ finalMessage.content = [...finalMessage.content, ...missing];
1278
+ }
1279
+ function shouldTerminateToolBatch(finalizedCalls) {
1280
+ return (finalizedCalls.length > 0 &&
1281
+ finalizedCalls.every((finalized) => finalized.result.terminate === true));
1282
+ }
1283
+ function prepareToolCallArguments(tool, toolCall) {
1284
+ if (!tool.prepareArguments) {
1285
+ return toolCall;
1286
+ }
1287
+ const preparedArguments = tool.prepareArguments(toolCall.arguments);
1288
+ if (preparedArguments === toolCall.arguments) {
1289
+ return toolCall;
1290
+ }
1291
+ return {
1292
+ ...toolCall,
1293
+ arguments: preparedArguments,
1294
+ };
1295
+ }
1296
+ async function prepareToolCall(currentContext, assistantMessage, toolCall, config, signal) {
1297
+ const tool = findToolByName(currentContext.tools, toolCall.name);
1298
+ if (!tool) {
1299
+ // design/136 §2.4 — TOMBSTONED tool names get an explicit migration message (immediate error result,
1300
+ // model can self-correct) instead of the generic not-found. Checked ONLY on a roster miss, so a
1301
+ // deployment-defined custom tool of the same name wins (the tombstone yields).
1302
+ const tombstone = TOMBSTONED_TOOLS[toolCall.name];
1303
+ if (tombstone !== undefined) {
1304
+ return {
1305
+ kind: "immediate",
1306
+ result: createErrorToolResult(tombstone),
1307
+ isError: true,
1308
+ };
1309
+ }
1310
+ // make-real field finding (design/120 验证): a weaker model that guesses a wrong tool name
1311
+ // (bash/cat/exec/read_file…) got a bare "not found" and kept guessing until the run died.
1312
+ // List the real roster so the very next attempt can self-correct — the highest-leverage
1313
+ // recovery text in the loop (bounded: names only).
1314
+ const available = (currentContext.tools ?? []).map((t) => t.name).join(", ");
1315
+ return {
1316
+ kind: "immediate",
1317
+ result: createErrorToolResult(`Tool ${toolCall.name} not found.${available ? ` Available tools: ${available}` : ""}`),
1318
+ isError: true,
1319
+ };
1320
+ }
1321
+ try {
1322
+ const preparedToolCall = prepareToolCallArguments(tool, toolCall);
1323
+ let finalArgs = validateToolArguments(tool, preparedToolCall);
1324
+ if (config.beforeToolCall) {
1325
+ const beforeResult = await config.beforeToolCall({
1326
+ assistantMessage,
1327
+ toolCall,
1328
+ args: finalArgs,
1329
+ context: currentContext,
1330
+ }, signal);
1331
+ if (signal?.aborted) {
1332
+ return {
1333
+ kind: "immediate",
1334
+ result: createErrorToolResult("Operation aborted"),
1335
+ isError: true,
1336
+ };
1337
+ }
1338
+ if (beforeResult?.block) {
1339
+ return {
1340
+ kind: "immediate",
1341
+ result: createErrorToolResult(beforeResult.reason || "Tool execution was blocked"),
1342
+ isError: true,
1343
+ };
1344
+ }
1345
+ // A non-blocking hook may rewrite the args (design/37 `updatedInput`). Re-validate the rewrite
1346
+ // against the tool schema before it can reach `tool.execute()` — a hook must never be able to
1347
+ // smuggle schema-invalid args past validation. Throws propagate to the catch below as an error
1348
+ // tool result, exactly like an invalid model-supplied call.
1349
+ if (beforeResult?.updatedInput !== undefined) {
1350
+ finalArgs = validateToolArguments(tool, {
1351
+ ...preparedToolCall,
1352
+ arguments: beforeResult.updatedInput,
1353
+ });
1354
+ }
1355
+ }
1356
+ if (signal?.aborted) {
1357
+ return {
1358
+ kind: "immediate",
1359
+ result: createErrorToolResult("Operation aborted"),
1360
+ isError: true,
1361
+ };
1362
+ }
1363
+ return {
1364
+ kind: "prepared",
1365
+ toolCall,
1366
+ tool,
1367
+ args: finalArgs,
1368
+ };
1369
+ }
1370
+ catch (error) {
1371
+ return {
1372
+ kind: "immediate",
1373
+ result: createErrorToolResult(error instanceof Error ? error.message : String(error)),
1374
+ isError: true,
1375
+ };
1376
+ }
1377
+ }
1378
+ async function executePreparedToolCall(prepared, signal, emit) {
1379
+ const updateEvents = [];
1380
+ // Upstream-parity gate (2026-07 diff, openclaw 5ea80c8d80 class): a misbehaving tool that keeps
1381
+ // calling onUpdate AFTER its execute() promise settled would otherwise emit
1382
+ // `tool_execution_update` events after `tool_execution_end`/result persistence — an event-order
1383
+ // contract violation. Once the outcome is settled, late updates are silently dropped.
1384
+ let acceptingUpdates = true;
1385
+ // VENDORED EDIT provenance (sema durable-checkpoint hardening): a deferred PARALLEL tool closure
1386
+ // (preflight-gated, then run together in Promise.all) can reach here AFTER a mid-batch durable
1387
+ // suspend/abort fired `signal.abort()`. Without this guard, a tool whose own `execute` ignores
1388
+ // `signal.aborted` would run its side effect on the off-branch turn, yet the durable resume tells
1389
+ // the model that sibling "was NOT executed" → DOUBLE-execution. Short-circuit BEFORE `tool.execute`
1390
+ // so the "not executed" assertion holds unconditionally — even for a non-abort-cooperative tool —
1391
+ // keeping the once-only/exactly-once continuation invariant (design/45 §4.ter).
1392
+ if (signal?.aborted) {
1393
+ return { result: createErrorToolResult("operation aborted before execution"), isError: true };
1394
+ }
1395
+ try {
1396
+ const result = await prepared.tool.execute(prepared.toolCall.id, prepared.args, signal, (partialResult) => {
1397
+ if (!acceptingUpdates) {
1398
+ return;
1399
+ }
1400
+ updateEvents.push(Promise.resolve(emit({
1401
+ type: "tool_execution_update",
1402
+ toolCallId: prepared.toolCall.id,
1403
+ toolName: prepared.toolCall.name,
1404
+ args: prepared.toolCall.arguments,
1405
+ partialResult,
1406
+ })));
1407
+ });
1408
+ acceptingUpdates = false;
1409
+ await Promise.all(updateEvents);
1410
+ return { result, isError: false };
1411
+ }
1412
+ catch (error) {
1413
+ acceptingUpdates = false;
1414
+ await Promise.all(updateEvents);
1415
+ return {
1416
+ result: createErrorToolResult(error instanceof Error ? error.message : String(error)),
1417
+ isError: true,
1418
+ };
1419
+ }
1420
+ }
1421
+ async function finalizeExecutedToolCall(currentContext, assistantMessage, prepared, executed, config, signal) {
1422
+ let result = executed.result;
1423
+ let isError = executed.isError;
1424
+ if (config.afterToolCall) {
1425
+ try {
1426
+ const afterResult = await config.afterToolCall({
1427
+ assistantMessage,
1428
+ toolCall: prepared.toolCall,
1429
+ args: prepared.args,
1430
+ result,
1431
+ isError,
1432
+ context: currentContext,
1433
+ }, signal);
1434
+ if (afterResult) {
1435
+ result = {
1436
+ content: afterResult.content ?? result.content,
1437
+ details: afterResult.details ?? result.details,
1438
+ terminate: afterResult.terminate ?? result.terminate,
1439
+ };
1440
+ isError = afterResult.isError ?? isError;
1441
+ }
1442
+ }
1443
+ catch (error) {
1444
+ // VENDORED EDIT provenance (sema vendored bug-hunt D4): the tool ALREADY executed (its side
1445
+ // effect committed in executePreparedToolCall) BEFORE afterToolCall runs. A throw in the
1446
+ // post-tool hook (sema design/37 tool_result policy) must NOT rewrite a SUCCEEDED
1447
+ // side-effecting tool into a FLAT failure — in our autonomous loop the model "recovers" by
1448
+ // RE-issuing it (duplicate open_pr / double write_file). Keep the real outcome (result/isError
1449
+ // unchanged) and APPEND a note that POST-processing failed; never force isError.
1450
+ const note = `[post-tool processing failed (the tool already executed): ${error instanceof Error ? error.message : String(error)}]`;
1451
+ result = { ...result, content: [...result.content, { type: "text", text: note }] };
1452
+ }
1453
+ }
1454
+ return {
1455
+ toolCall: prepared.toolCall,
1456
+ result,
1457
+ isError,
1458
+ };
1459
+ }
1460
+ function createErrorToolResult(message) {
1461
+ return {
1462
+ content: [{ type: "text", text: message }],
1463
+ details: {},
1464
+ };
1465
+ }
1466
+ async function emitToolExecutionEnd(finalized, emit) {
1467
+ await emit({
1468
+ type: "tool_execution_end",
1469
+ toolCallId: finalized.toolCall.id,
1470
+ toolName: finalized.toolCall.name,
1471
+ result: finalized.result,
1472
+ isError: finalized.isError,
1473
+ });
1474
+ }
1475
+ function createToolResultMessage(finalized) {
1476
+ return {
1477
+ role: "toolResult",
1478
+ toolCallId: finalized.toolCall.id,
1479
+ toolName: finalized.toolCall.name,
1480
+ content: finalized.result.content,
1481
+ details: finalized.result.details,
1482
+ isError: finalized.isError,
1483
+ timestamp: Date.now(),
1484
+ };
1485
+ }
1486
+ async function emitToolResultMessage(toolResultMessage, emit) {
1487
+ await emit({ type: "message_start", message: toolResultMessage });
1488
+ await emit({ type: "message_end", message: toolResultMessage });
1489
+ }
1490
+ //# sourceMappingURL=agent-loop.js.map