@dexto/core 1.7.1 → 1.8.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (533) hide show
  1. package/dist/agent/DextoAgent.cjs +157 -62
  2. package/dist/agent/DextoAgent.d.ts +71 -17
  3. package/dist/agent/DextoAgent.d.ts.map +1 -1
  4. package/dist/agent/DextoAgent.js +161 -63
  5. package/dist/agent/agent-options.d.ts +6 -10
  6. package/dist/agent/agent-options.d.ts.map +1 -1
  7. package/dist/agent/agentCard.js +1 -1
  8. package/dist/agent/error-codes.js +1 -1
  9. package/dist/agent/errors.js +1 -1
  10. package/dist/agent/index.d.ts +1 -0
  11. package/dist/agent/index.d.ts.map +1 -1
  12. package/dist/agent/index.js +1 -1
  13. package/dist/agent/schemas.d.ts +2 -2
  14. package/dist/agent/schemas.js +1 -1
  15. package/dist/agent/state-manager.js +1 -1
  16. package/dist/approval/error-codes.cjs +1 -1
  17. package/dist/approval/error-codes.d.ts +1 -1
  18. package/dist/approval/error-codes.d.ts.map +1 -1
  19. package/dist/approval/error-codes.js +2 -2
  20. package/dist/approval/errors.cjs +2 -5
  21. package/dist/approval/errors.d.ts.map +1 -1
  22. package/dist/approval/errors.js +3 -6
  23. package/dist/approval/factory.cjs +19 -4
  24. package/dist/approval/factory.d.ts +4 -1
  25. package/dist/approval/factory.d.ts.map +1 -1
  26. package/dist/approval/factory.js +19 -5
  27. package/dist/approval/index.d.ts +1 -1
  28. package/dist/approval/index.d.ts.map +1 -1
  29. package/dist/approval/index.js +1 -1
  30. package/dist/approval/manager.cjs +168 -26
  31. package/dist/approval/manager.d.ts +46 -12
  32. package/dist/approval/manager.d.ts.map +1 -1
  33. package/dist/approval/manager.js +177 -29
  34. package/dist/approval/schemas.cjs +26 -26
  35. package/dist/approval/schemas.d.ts +29 -29
  36. package/dist/approval/schemas.d.ts.map +1 -1
  37. package/dist/approval/schemas.js +23 -23
  38. package/dist/approval/types.cjs +5 -5
  39. package/dist/approval/types.d.ts +18 -18
  40. package/dist/approval/types.d.ts.map +1 -1
  41. package/dist/approval/types.js +6 -6
  42. package/dist/{chunk-PTJYTZNU.js → chunk-C6A6W6XS.js} +1 -44
  43. package/dist/config/index.cjs +75 -0
  44. package/dist/config/index.d.ts +15 -0
  45. package/dist/config/index.d.ts.map +1 -0
  46. package/dist/config/index.js +50 -0
  47. package/dist/context/compaction/overflow.js +1 -1
  48. package/dist/context/compaction/strategies/noop.js +1 -1
  49. package/dist/context/compaction/strategies/reactive-overflow-compaction.js +1 -1
  50. package/dist/context/content-clone.cjs +131 -0
  51. package/dist/context/content-clone.d.ts +7 -0
  52. package/dist/context/content-clone.d.ts.map +1 -0
  53. package/dist/context/content-clone.js +104 -0
  54. package/dist/context/error-codes.js +1 -1
  55. package/dist/context/errors.js +1 -1
  56. package/dist/context/index.cjs +2 -0
  57. package/dist/context/index.d.ts +1 -0
  58. package/dist/context/index.d.ts.map +1 -1
  59. package/dist/context/index.js +2 -1
  60. package/dist/context/manager.cjs +47 -35
  61. package/dist/context/manager.d.ts +7 -7
  62. package/dist/context/manager.d.ts.map +1 -1
  63. package/dist/context/manager.js +48 -36
  64. package/dist/context/media-helpers.js +1 -1
  65. package/dist/context/schemas.cjs +77 -0
  66. package/dist/context/schemas.d.ts +5 -0
  67. package/dist/context/schemas.d.ts.map +1 -0
  68. package/dist/context/schemas.js +53 -0
  69. package/dist/context/types.js +1 -1
  70. package/dist/context/utils.cjs +70 -69
  71. package/dist/context/utils.d.ts +3 -3
  72. package/dist/context/utils.d.ts.map +1 -1
  73. package/dist/context/utils.js +71 -70
  74. package/dist/errors/DextoBaseError.js +1 -1
  75. package/dist/errors/DextoRuntimeError.js +1 -1
  76. package/dist/errors/DextoValidationError.js +1 -1
  77. package/dist/errors/index.js +1 -1
  78. package/dist/errors/result-bridge.js +1 -1
  79. package/dist/errors/types.js +1 -1
  80. package/dist/events/index.cjs +9 -1
  81. package/dist/events/index.d.ts +20 -8
  82. package/dist/events/index.d.ts.map +1 -1
  83. package/dist/events/index.js +10 -2
  84. package/dist/hooks/builtins/content-policy.js +1 -1
  85. package/dist/hooks/builtins/response-sanitizer.js +1 -1
  86. package/dist/hooks/error-codes.js +1 -1
  87. package/dist/hooks/index.js +1 -1
  88. package/dist/hooks/manager.cjs +1 -1
  89. package/dist/hooks/manager.d.ts +2 -2
  90. package/dist/hooks/manager.d.ts.map +1 -1
  91. package/dist/hooks/manager.js +2 -2
  92. package/dist/hooks/types.d.ts +2 -2
  93. package/dist/hooks/types.d.ts.map +1 -1
  94. package/dist/index.browser.js +1 -1
  95. package/dist/index.cjs +2 -0
  96. package/dist/index.d.ts +1 -0
  97. package/dist/index.d.ts.map +1 -1
  98. package/dist/index.js +2 -1
  99. package/dist/llm/curation-config.js +1 -1
  100. package/dist/llm/curation.js +1 -1
  101. package/dist/llm/error-codes.js +1 -1
  102. package/dist/llm/errors.js +1 -1
  103. package/dist/llm/executor/index.cjs +32 -0
  104. package/dist/llm/executor/index.d.ts +2 -0
  105. package/dist/llm/executor/index.d.ts.map +1 -0
  106. package/dist/llm/executor/index.js +11 -0
  107. package/dist/llm/executor/provider-options.js +1 -1
  108. package/dist/llm/executor/stream-processor.cjs +28 -139
  109. package/dist/llm/executor/stream-processor.d.ts +2 -13
  110. package/dist/llm/executor/stream-processor.d.ts.map +1 -1
  111. package/dist/llm/executor/stream-processor.js +29 -140
  112. package/dist/{session/history/memory.cjs → llm/executor/tool-definitions.cjs} +21 -33
  113. package/dist/llm/executor/tool-definitions.d.ts +4 -0
  114. package/dist/llm/executor/tool-definitions.d.ts.map +1 -0
  115. package/dist/llm/executor/tool-definitions.js +22 -0
  116. package/dist/llm/executor/tool-output-truncator.js +1 -1
  117. package/dist/llm/executor/turn-executor.cjs +1093 -458
  118. package/dist/llm/executor/turn-executor.d.ts +269 -43
  119. package/dist/llm/executor/turn-executor.d.ts.map +1 -1
  120. package/dist/llm/executor/turn-executor.js +1079 -405
  121. package/dist/llm/executor/types.d.ts +6 -0
  122. package/dist/llm/executor/types.d.ts.map +1 -1
  123. package/dist/llm/formatters/vercel.js +1 -1
  124. package/dist/llm/index.cjs +2 -0
  125. package/dist/llm/index.d.ts +1 -0
  126. package/dist/llm/index.d.ts.map +1 -1
  127. package/dist/llm/index.js +2 -1
  128. package/dist/llm/providers/codex-app-server.cjs +22 -2
  129. package/dist/llm/providers/codex-app-server.d.ts.map +1 -1
  130. package/dist/llm/providers/codex-app-server.js +23 -3
  131. package/dist/llm/providers/codex-base-url.js +1 -1
  132. package/dist/llm/providers/local/ai-sdk-adapter.js +1 -1
  133. package/dist/llm/providers/local/downloader.js +1 -1
  134. package/dist/llm/providers/local/error-codes.js +1 -1
  135. package/dist/llm/providers/local/errors.js +1 -1
  136. package/dist/llm/providers/local/gpu-detector.js +1 -1
  137. package/dist/llm/providers/local/index.js +1 -1
  138. package/dist/llm/providers/local/node-llama-provider.js +1 -1
  139. package/dist/llm/providers/local/ollama-provider.js +1 -1
  140. package/dist/llm/providers/local/registry.js +1 -1
  141. package/dist/llm/providers/local/schemas.js +1 -1
  142. package/dist/llm/providers/openrouter-model-registry.js +1 -1
  143. package/dist/llm/reasoning/anthropic-betas.js +1 -1
  144. package/dist/llm/reasoning/anthropic-thinking.js +1 -1
  145. package/dist/llm/reasoning/openai-reasoning-effort.js +1 -1
  146. package/dist/llm/reasoning/profile.js +1 -1
  147. package/dist/llm/reasoning/profiles/anthropic.js +1 -1
  148. package/dist/llm/reasoning/profiles/bedrock.js +1 -1
  149. package/dist/llm/reasoning/profiles/google.js +1 -1
  150. package/dist/llm/reasoning/profiles/openai-compatible.js +1 -1
  151. package/dist/llm/reasoning/profiles/openai.js +1 -1
  152. package/dist/llm/reasoning/profiles/openrouter.js +1 -1
  153. package/dist/llm/reasoning/profiles/shared.js +1 -1
  154. package/dist/llm/reasoning/profiles/vertex.js +1 -1
  155. package/dist/llm/registry/auto-update.js +1 -1
  156. package/dist/llm/registry/index.js +1 -1
  157. package/dist/llm/registry/models.generated.js +1 -1
  158. package/dist/llm/registry/models.manual.js +1 -1
  159. package/dist/llm/registry/sync.js +1 -1
  160. package/dist/llm/resolver.js +1 -1
  161. package/dist/llm/schemas.js +1 -1
  162. package/dist/llm/services/factory.cjs +5 -4
  163. package/dist/llm/services/factory.d.ts +3 -3
  164. package/dist/llm/services/factory.d.ts.map +1 -1
  165. package/dist/llm/services/factory.js +6 -5
  166. package/dist/llm/services/types.d.ts +10 -1
  167. package/dist/llm/services/types.d.ts.map +1 -1
  168. package/dist/llm/services/vercel.cjs +23 -8
  169. package/dist/llm/services/vercel.d.ts +11 -7
  170. package/dist/llm/services/vercel.d.ts.map +1 -1
  171. package/dist/llm/services/vercel.js +24 -9
  172. package/dist/llm/types.js +1 -1
  173. package/dist/llm/usage-metadata.cjs +20 -3
  174. package/dist/llm/usage-metadata.d.ts +1 -0
  175. package/dist/llm/usage-metadata.d.ts.map +1 -1
  176. package/dist/llm/usage-metadata.js +19 -3
  177. package/dist/llm/usage-scope.js +1 -1
  178. package/dist/llm/usage-summary.js +1 -1
  179. package/dist/llm/validation.js +1 -1
  180. package/dist/logger/browser.js +1 -1
  181. package/dist/logger/default-logger-factory.js +1 -1
  182. package/dist/logger/factory.js +1 -1
  183. package/dist/logger/index.js +1 -1
  184. package/dist/logger/logger.js +1 -1
  185. package/dist/logger/v2/dexto-logger.js +1 -1
  186. package/dist/logger/v2/error-codes.js +1 -1
  187. package/dist/logger/v2/errors.js +1 -1
  188. package/dist/logger/v2/schemas.js +1 -1
  189. package/dist/logger/v2/test-utils.js +1 -1
  190. package/dist/logger/v2/transport-factory.js +1 -1
  191. package/dist/logger/v2/transports/console-transport.js +1 -1
  192. package/dist/logger/v2/transports/file-transport.js +1 -1
  193. package/dist/logger/v2/transports/silent-transport.js +1 -1
  194. package/dist/logger/v2/types.js +1 -1
  195. package/dist/mcp/bundled-config.js +1 -1
  196. package/dist/mcp/error-codes.js +1 -1
  197. package/dist/mcp/errors.js +1 -1
  198. package/dist/mcp/index.js +1 -1
  199. package/dist/mcp/manager.js +1 -1
  200. package/dist/mcp/mcp-client.js +1 -1
  201. package/dist/mcp/resolver.js +1 -1
  202. package/dist/mcp/schemas.js +1 -1
  203. package/dist/memory/error-codes.js +1 -1
  204. package/dist/memory/errors.js +1 -1
  205. package/dist/memory/index.js +1 -1
  206. package/dist/memory/manager.cjs +7 -27
  207. package/dist/memory/manager.d.ts +4 -12
  208. package/dist/memory/manager.d.ts.map +1 -1
  209. package/dist/memory/manager.js +8 -28
  210. package/dist/memory/schemas.js +1 -1
  211. package/dist/prompts/error-codes.js +1 -1
  212. package/dist/prompts/errors.js +1 -1
  213. package/dist/prompts/index.js +1 -1
  214. package/dist/prompts/name-validation.js +1 -1
  215. package/dist/prompts/prompt-manager.cjs +9 -38
  216. package/dist/prompts/prompt-manager.d.ts +2 -10
  217. package/dist/prompts/prompt-manager.d.ts.map +1 -1
  218. package/dist/prompts/prompt-manager.js +10 -39
  219. package/dist/prompts/providers/config-prompt-provider.cjs +8 -87
  220. package/dist/prompts/providers/config-prompt-provider.d.ts.map +1 -1
  221. package/dist/prompts/providers/config-prompt-provider.js +9 -88
  222. package/dist/prompts/providers/custom-prompt-provider.cjs +21 -22
  223. package/dist/prompts/providers/custom-prompt-provider.d.ts +19 -4
  224. package/dist/prompts/providers/custom-prompt-provider.d.ts.map +1 -1
  225. package/dist/prompts/providers/custom-prompt-provider.js +22 -23
  226. package/dist/prompts/providers/mcp-prompt-provider.js +1 -1
  227. package/dist/prompts/schemas.cjs +2 -24
  228. package/dist/prompts/schemas.d.ts +0 -52
  229. package/dist/prompts/schemas.d.ts.map +1 -1
  230. package/dist/prompts/schemas.js +3 -25
  231. package/dist/prompts/types.d.ts +5 -32
  232. package/dist/prompts/types.d.ts.map +1 -1
  233. package/dist/prompts/utils.js +1 -1
  234. package/dist/resources/agent-resources-provider.js +1 -1
  235. package/dist/resources/error-codes.js +1 -1
  236. package/dist/resources/errors.js +1 -1
  237. package/dist/resources/handlers/blob-handler.cjs +14 -11
  238. package/dist/resources/handlers/blob-handler.d.ts +4 -4
  239. package/dist/resources/handlers/blob-handler.d.ts.map +1 -1
  240. package/dist/resources/handlers/blob-handler.js +15 -12
  241. package/dist/resources/handlers/factory.cjs +3 -3
  242. package/dist/resources/handlers/factory.js +4 -4
  243. package/dist/resources/handlers/filesystem-handler.js +1 -1
  244. package/dist/resources/handlers/types.d.ts +2 -2
  245. package/dist/resources/handlers/types.d.ts.map +1 -1
  246. package/dist/resources/index.js +1 -1
  247. package/dist/resources/manager.cjs +10 -7
  248. package/dist/resources/manager.d.ts +4 -4
  249. package/dist/resources/manager.d.ts.map +1 -1
  250. package/dist/resources/manager.js +11 -8
  251. package/dist/resources/reference-parser.js +1 -1
  252. package/dist/resources/schemas.cjs +1 -1
  253. package/dist/resources/schemas.d.ts +2 -2
  254. package/dist/resources/schemas.js +2 -2
  255. package/dist/runtime/host-runtime.js +1 -1
  256. package/dist/runtime/index.cjs +3 -0
  257. package/dist/runtime/index.d.ts +2 -0
  258. package/dist/runtime/index.d.ts.map +1 -1
  259. package/dist/runtime/index.js +3 -1
  260. package/dist/runtime/run-context.js +1 -1
  261. package/dist/search/index.js +1 -1
  262. package/dist/search/search-service.cjs +6 -13
  263. package/dist/search/search-service.d.ts +5 -3
  264. package/dist/search/search-service.d.ts.map +1 -1
  265. package/dist/search/search-service.js +7 -14
  266. package/dist/session/chat-session.cjs +264 -108
  267. package/dist/session/chat-session.d.ts +75 -21
  268. package/dist/session/chat-session.d.ts.map +1 -1
  269. package/dist/session/chat-session.js +268 -108
  270. package/dist/session/error-codes.js +1 -1
  271. package/dist/session/errors.js +1 -1
  272. package/dist/session/index.cjs +19 -2
  273. package/dist/session/index.d.ts +4 -3
  274. package/dist/session/index.d.ts.map +1 -1
  275. package/dist/session/index.js +19 -3
  276. package/dist/session/message-queue.cjs +82 -51
  277. package/dist/session/message-queue.d.ts +13 -8
  278. package/dist/session/message-queue.d.ts.map +1 -1
  279. package/dist/session/message-queue.js +83 -52
  280. package/dist/session/queue-clone.cjs +50 -0
  281. package/dist/session/queue-clone.d.ts +5 -0
  282. package/dist/session/queue-clone.d.ts.map +1 -0
  283. package/dist/session/queue-clone.js +25 -0
  284. package/dist/session/schemas.cjs +74 -2
  285. package/dist/session/schemas.d.ts +94 -0
  286. package/dist/session/schemas.d.ts.map +1 -1
  287. package/dist/session/schemas.js +69 -2
  288. package/dist/session/session-manager.cjs +107 -123
  289. package/dist/session/session-manager.d.ts +7 -6
  290. package/dist/session/session-manager.d.ts.map +1 -1
  291. package/dist/session/session-manager.js +108 -124
  292. package/dist/session/title-generator.cjs +14 -26
  293. package/dist/session/title-generator.d.ts +4 -6
  294. package/dist/session/title-generator.d.ts.map +1 -1
  295. package/dist/session/title-generator.js +16 -28
  296. package/dist/session/types.cjs +28 -0
  297. package/dist/session/types.d.ts +5 -1
  298. package/dist/session/types.d.ts.map +1 -1
  299. package/dist/session/types.js +19 -0
  300. package/dist/{session/history/factory.cjs → skills/index.cjs} +9 -9
  301. package/dist/skills/index.d.ts +4 -0
  302. package/dist/skills/index.d.ts.map +1 -0
  303. package/dist/skills/index.js +7 -0
  304. package/dist/skills/skill-manager.cjs +76 -0
  305. package/dist/skills/skill-manager.d.ts +13 -0
  306. package/dist/skills/skill-manager.d.ts.map +1 -0
  307. package/dist/skills/skill-manager.js +53 -0
  308. package/dist/skills/types.d.ts +24 -0
  309. package/dist/skills/types.d.ts.map +1 -0
  310. package/dist/skills/workspace-skill-source.cjs +120 -0
  311. package/dist/skills/workspace-skill-source.d.ts +16 -0
  312. package/dist/skills/workspace-skill-source.d.ts.map +1 -0
  313. package/dist/skills/workspace-skill-source.js +97 -0
  314. package/dist/storage/approvals/types.cjs +38 -0
  315. package/dist/storage/approvals/types.d.ts +54 -0
  316. package/dist/storage/approvals/types.d.ts.map +1 -0
  317. package/dist/storage/approvals/types.js +14 -0
  318. package/dist/storage/artifacts/types.d.ts +73 -0
  319. package/dist/storage/artifacts/types.d.ts.map +1 -0
  320. package/dist/storage/conversation/database.cjs +233 -0
  321. package/dist/storage/conversation/database.d.ts +38 -0
  322. package/dist/storage/conversation/database.d.ts.map +1 -0
  323. package/dist/storage/conversation/database.js +210 -0
  324. package/dist/storage/conversation/types.cjs +16 -0
  325. package/dist/storage/conversation/types.d.ts +21 -0
  326. package/dist/storage/conversation/types.d.ts.map +1 -0
  327. package/dist/storage/conversation/types.js +0 -0
  328. package/dist/storage/database/types.d.ts +4 -0
  329. package/dist/storage/database/types.d.ts.map +1 -1
  330. package/dist/storage/error-codes.js +1 -1
  331. package/dist/storage/errors.cjs +6 -6
  332. package/dist/storage/errors.d.ts +2 -2
  333. package/dist/storage/errors.js +7 -7
  334. package/dist/storage/index.cjs +42 -5
  335. package/dist/storage/index.d.ts +19 -8
  336. package/dist/storage/index.d.ts.map +1 -1
  337. package/dist/storage/index.js +39 -4
  338. package/dist/storage/memories/types.cjs +16 -0
  339. package/dist/storage/memories/types.d.ts +17 -0
  340. package/dist/storage/memories/types.d.ts.map +1 -0
  341. package/dist/storage/memories/types.js +0 -0
  342. package/dist/storage/message-queue/types.cjs +16 -0
  343. package/dist/storage/message-queue/types.d.ts +15 -0
  344. package/dist/storage/message-queue/types.d.ts.map +1 -0
  345. package/dist/storage/message-queue/types.js +0 -0
  346. package/dist/storage/prompts/types.cjs +16 -0
  347. package/dist/storage/prompts/types.d.ts +14 -0
  348. package/dist/storage/prompts/types.d.ts.map +1 -0
  349. package/dist/storage/prompts/types.js +0 -0
  350. package/dist/storage/runtime-events/types.cjs +16 -0
  351. package/dist/storage/runtime-events/types.d.ts +19 -0
  352. package/dist/storage/runtime-events/types.d.ts.map +1 -0
  353. package/dist/storage/runtime-events/types.js +0 -0
  354. package/dist/storage/sessions/types.cjs +16 -0
  355. package/dist/storage/sessions/types.d.ts +19 -0
  356. package/dist/storage/sessions/types.d.ts.map +1 -0
  357. package/dist/storage/sessions/types.js +0 -0
  358. package/dist/storage/stores/backend.cjs +702 -0
  359. package/dist/storage/stores/backend.d.ts +303 -0
  360. package/dist/storage/stores/backend.d.ts.map +1 -0
  361. package/dist/storage/stores/backend.js +677 -0
  362. package/dist/storage/stores/in-memory.cjs +510 -0
  363. package/dist/storage/stores/in-memory.d.ts +11 -0
  364. package/dist/storage/stores/in-memory.d.ts.map +1 -0
  365. package/dist/storage/stores/in-memory.js +487 -0
  366. package/dist/storage/stores/types.cjs +16 -0
  367. package/dist/storage/stores/types.d.ts +36 -0
  368. package/dist/storage/stores/types.d.ts.map +1 -0
  369. package/dist/storage/stores/types.js +0 -0
  370. package/dist/storage/tool-executions/types.cjs +127 -0
  371. package/dist/storage/tool-executions/types.d.ts +193 -0
  372. package/dist/storage/tool-executions/types.d.ts.map +1 -0
  373. package/dist/storage/tool-executions/types.js +96 -0
  374. package/dist/storage/tool-preferences/types.cjs +16 -0
  375. package/dist/storage/tool-preferences/types.d.ts +29 -0
  376. package/dist/storage/tool-preferences/types.d.ts.map +1 -0
  377. package/dist/storage/tool-preferences/types.js +0 -0
  378. package/dist/storage/tool-state/types.cjs +16 -0
  379. package/dist/storage/tool-state/types.d.ts +20 -0
  380. package/dist/storage/tool-state/types.d.ts.map +1 -0
  381. package/dist/storage/tool-state/types.js +0 -0
  382. package/dist/storage/workspaces/types.cjs +16 -0
  383. package/dist/storage/workspaces/types.d.ts +19 -0
  384. package/dist/storage/workspaces/types.d.ts.map +1 -0
  385. package/dist/storage/workspaces/types.js +0 -0
  386. package/dist/systemPrompt/contributors.cjs +10 -14
  387. package/dist/systemPrompt/contributors.d.ts +3 -3
  388. package/dist/systemPrompt/contributors.d.ts.map +1 -1
  389. package/dist/systemPrompt/contributors.js +11 -15
  390. package/dist/systemPrompt/error-codes.js +1 -1
  391. package/dist/systemPrompt/errors.js +1 -1
  392. package/dist/systemPrompt/in-built-prompts.js +1 -1
  393. package/dist/systemPrompt/index.js +1 -1
  394. package/dist/systemPrompt/manager.js +1 -1
  395. package/dist/systemPrompt/registry.js +1 -1
  396. package/dist/systemPrompt/schemas.js +1 -1
  397. package/dist/telemetry/decorators.js +1 -1
  398. package/dist/telemetry/error-codes.js +1 -1
  399. package/dist/telemetry/errors.js +1 -1
  400. package/dist/telemetry/exporters.js +1 -1
  401. package/dist/telemetry/index.js +1 -1
  402. package/dist/telemetry/schemas.js +1 -1
  403. package/dist/telemetry/telemetry.js +1 -1
  404. package/dist/telemetry/utils.js +1 -1
  405. package/dist/test-utils/in-memory-storage.cjs +9 -17
  406. package/dist/test-utils/in-memory-storage.js +9 -16
  407. package/dist/test-utils/session-state-stores.cjs +21 -24
  408. package/dist/test-utils/session-state-stores.js +22 -24
  409. package/dist/tools/{confirmation → approval}/allowed-tools-provider/factory.cjs +1 -1
  410. package/dist/tools/{confirmation → approval}/allowed-tools-provider/factory.d.ts +2 -2
  411. package/dist/tools/approval/allowed-tools-provider/factory.d.ts.map +1 -0
  412. package/dist/tools/{confirmation → approval}/allowed-tools-provider/factory.js +2 -2
  413. package/dist/tools/approval/allowed-tools-provider/in-memory.d.ts.map +1 -0
  414. package/dist/tools/{confirmation → approval}/allowed-tools-provider/in-memory.js +1 -1
  415. package/dist/tools/approval/allowed-tools-provider/storage.cjs +66 -0
  416. package/dist/tools/{confirmation → approval}/allowed-tools-provider/storage.d.ts +4 -10
  417. package/dist/tools/approval/allowed-tools-provider/storage.d.ts.map +1 -0
  418. package/dist/tools/approval/allowed-tools-provider/storage.js +43 -0
  419. package/dist/tools/approval/allowed-tools-provider/types.cjs +16 -0
  420. package/dist/tools/approval/allowed-tools-provider/types.d.ts.map +1 -0
  421. package/dist/tools/approval/allowed-tools-provider/types.js +0 -0
  422. package/dist/tools/approval/session-tool-policy.cjs +269 -0
  423. package/dist/tools/approval/session-tool-policy.d.ts +43 -0
  424. package/dist/tools/approval/session-tool-policy.d.ts.map +1 -0
  425. package/dist/tools/approval/session-tool-policy.js +245 -0
  426. package/dist/tools/define-tool.js +1 -1
  427. package/dist/tools/display-types.js +1 -1
  428. package/dist/tools/error-codes.cjs +3 -3
  429. package/dist/tools/error-codes.d.ts +4 -4
  430. package/dist/tools/error-codes.d.ts.map +1 -1
  431. package/dist/tools/error-codes.js +4 -4
  432. package/dist/tools/errors.cjs +12 -12
  433. package/dist/tools/errors.d.ts +6 -6
  434. package/dist/tools/errors.d.ts.map +1 -1
  435. package/dist/tools/errors.js +13 -13
  436. package/dist/tools/index.cjs +3 -0
  437. package/dist/tools/index.d.ts +3 -0
  438. package/dist/tools/index.d.ts.map +1 -1
  439. package/dist/tools/index.js +3 -1
  440. package/dist/tools/pattern-utils.js +1 -1
  441. package/dist/tools/presentation/tool-presentation.cjs +182 -0
  442. package/dist/tools/presentation/tool-presentation.d.ts +51 -0
  443. package/dist/tools/presentation/tool-presentation.d.ts.map +1 -0
  444. package/dist/tools/presentation/tool-presentation.js +159 -0
  445. package/dist/tools/presentation.js +1 -1
  446. package/dist/tools/schemas.cjs +5 -10
  447. package/dist/tools/schemas.d.ts +1 -4
  448. package/dist/tools/schemas.d.ts.map +1 -1
  449. package/dist/tools/schemas.js +6 -11
  450. package/dist/tools/session-tool-preferences-store.cjs +12 -28
  451. package/dist/tools/session-tool-preferences-store.d.ts +4 -7
  452. package/dist/tools/session-tool-preferences-store.d.ts.map +1 -1
  453. package/dist/tools/session-tool-preferences-store.js +12 -29
  454. package/dist/tools/tool-call-metadata.js +1 -1
  455. package/dist/tools/tool-manager.cjs +871 -834
  456. package/dist/tools/tool-manager.d.ts +94 -96
  457. package/dist/tools/tool-manager.d.ts.map +1 -1
  458. package/dist/tools/tool-manager.js +876 -833
  459. package/dist/tools/types.d.ts +10 -14
  460. package/dist/tools/types.d.ts.map +1 -1
  461. package/dist/utils/api-key-resolver.js +1 -1
  462. package/dist/utils/async-context.js +1 -1
  463. package/dist/utils/debug.js +1 -1
  464. package/dist/utils/defer.js +1 -1
  465. package/dist/utils/env.js +1 -1
  466. package/dist/utils/error-conversion.js +1 -1
  467. package/dist/utils/execution-context.js +1 -1
  468. package/dist/utils/fs-walk.js +1 -1
  469. package/dist/utils/path.js +1 -1
  470. package/dist/utils/redactor.js +1 -1
  471. package/dist/utils/result.js +1 -1
  472. package/dist/utils/safe-stringify.js +1 -1
  473. package/dist/utils/schema.js +1 -1
  474. package/dist/utils/service-initializer.cjs +37 -33
  475. package/dist/utils/service-initializer.d.ts +9 -5
  476. package/dist/utils/service-initializer.d.ts.map +1 -1
  477. package/dist/utils/service-initializer.js +38 -34
  478. package/dist/utils/zod-schema-converter.js +1 -1
  479. package/dist/workspace/error-codes.cjs +5 -1
  480. package/dist/workspace/error-codes.d.ts +4 -0
  481. package/dist/workspace/error-codes.d.ts.map +1 -1
  482. package/dist/workspace/error-codes.js +6 -2
  483. package/dist/workspace/errors.cjs +43 -0
  484. package/dist/workspace/errors.d.ts +9 -0
  485. package/dist/workspace/errors.d.ts.map +1 -1
  486. package/dist/workspace/errors.js +44 -1
  487. package/dist/workspace/index.d.ts +1 -1
  488. package/dist/workspace/index.d.ts.map +1 -1
  489. package/dist/workspace/index.js +1 -1
  490. package/dist/workspace/manager.cjs +21 -29
  491. package/dist/workspace/manager.d.ts +6 -6
  492. package/dist/workspace/manager.d.ts.map +1 -1
  493. package/dist/workspace/manager.js +22 -30
  494. package/dist/workspace/types.d.ts +47 -0
  495. package/dist/workspace/types.d.ts.map +1 -1
  496. package/package.json +114 -2
  497. package/dist/approval/session-approval-store.cjs +0 -91
  498. package/dist/approval/session-approval-store.d.ts +0 -37
  499. package/dist/approval/session-approval-store.d.ts.map +0 -1
  500. package/dist/approval/session-approval-store.js +0 -68
  501. package/dist/session/history/database.cjs +0 -232
  502. package/dist/session/history/database.d.ts +0 -41
  503. package/dist/session/history/database.d.ts.map +0 -1
  504. package/dist/session/history/database.js +0 -209
  505. package/dist/session/history/factory.d.ts +0 -11
  506. package/dist/session/history/factory.d.ts.map +0 -1
  507. package/dist/session/history/factory.js +0 -8
  508. package/dist/session/history/memory.d.ts +0 -22
  509. package/dist/session/history/memory.d.ts.map +0 -1
  510. package/dist/session/history/memory.js +0 -34
  511. package/dist/session/history/types.d.ts +0 -26
  512. package/dist/session/history/types.d.ts.map +0 -1
  513. package/dist/session/message-queue-store.cjs +0 -75
  514. package/dist/session/message-queue-store.d.ts +0 -16
  515. package/dist/session/message-queue-store.d.ts.map +0 -1
  516. package/dist/session/message-queue-store.js +0 -52
  517. package/dist/storage/storage-manager.cjs +0 -209
  518. package/dist/storage/storage-manager.d.ts +0 -77
  519. package/dist/storage/storage-manager.d.ts.map +0 -1
  520. package/dist/storage/storage-manager.js +0 -186
  521. package/dist/tools/confirmation/allowed-tools-provider/factory.d.ts.map +0 -1
  522. package/dist/tools/confirmation/allowed-tools-provider/in-memory.d.ts.map +0 -1
  523. package/dist/tools/confirmation/allowed-tools-provider/storage.cjs +0 -69
  524. package/dist/tools/confirmation/allowed-tools-provider/storage.d.ts.map +0 -1
  525. package/dist/tools/confirmation/allowed-tools-provider/storage.js +0 -46
  526. package/dist/tools/confirmation/allowed-tools-provider/types.d.ts.map +0 -1
  527. /package/dist/{session/history → skills}/types.cjs +0 -0
  528. /package/dist/{session/history → skills}/types.js +0 -0
  529. /package/dist/{tools/confirmation/allowed-tools-provider → storage/artifacts}/types.cjs +0 -0
  530. /package/dist/{tools/confirmation/allowed-tools-provider → storage/artifacts}/types.js +0 -0
  531. /package/dist/tools/{confirmation → approval}/allowed-tools-provider/in-memory.cjs +0 -0
  532. /package/dist/tools/{confirmation → approval}/allowed-tools-provider/in-memory.d.ts +0 -0
  533. /package/dist/tools/{confirmation → approval}/allowed-tools-provider/types.d.ts +0 -0
@@ -1,7 +1,4 @@
1
- import {
2
- __callDispose,
3
- __using
4
- } from "../../chunk-PTJYTZNU.js";
1
+ import "../../chunk-C6A6W6XS.js";
5
2
  import {
6
3
  streamText,
7
4
  generateText,
@@ -9,20 +6,155 @@ import {
9
6
  jsonSchema,
10
7
  APICallError
11
8
  } from "ai";
9
+ import { z } from "zod";
12
10
  import { trace } from "@opentelemetry/api";
11
+ import { sanitizeToolResult } from "../../context/utils.js";
13
12
  import { StreamProcessor } from "./stream-processor.js";
13
+ import { truncateToolResult } from "./tool-output-truncator.js";
14
14
  import { buildProviderOptions, getEffectiveReasoningBudgetTokens } from "./provider-options.js";
15
15
  import { DextoLogComponent } from "../../logger/v2/types.js";
16
- import { defer } from "../../utils/defer.js";
17
16
  import { DextoRuntimeError } from "../../errors/DextoRuntimeError.js";
18
17
  import { ErrorScope, ErrorType } from "../../errors/types.js";
19
18
  import { LLMErrorCode } from "../error-codes.js";
20
19
  import { toError } from "../../utils/error-conversion.js";
21
20
  import { isCodexBaseURL } from "../providers/codex-base-url.js";
21
+ import { createModelToolDefinitions } from "./tool-definitions.js";
22
+ import { ApprovalStatus } from "../../approval/types.js";
23
+ const MCP_TOOL_PREFIX = "mcp--";
24
+ const MODEL_REQUEST_MAX_RETRIES = 2;
25
+ const LLMFinishReasonStateSchema = z.enum([
26
+ "stop",
27
+ "tool-calls",
28
+ "length",
29
+ "content-filter",
30
+ "error",
31
+ "other",
32
+ "unknown",
33
+ "cancelled",
34
+ "max-steps"
35
+ ]);
36
+ const TokenUsageStateSchema = z.object({
37
+ inputTokens: z.number().optional(),
38
+ outputTokens: z.number().optional(),
39
+ reasoningTokens: z.number().optional(),
40
+ totalTokens: z.number().optional(),
41
+ cacheReadTokens: z.number().optional(),
42
+ cacheWriteTokens: z.number().optional()
43
+ }).strict().transform((parsed) => {
44
+ const usage = {};
45
+ if (parsed.inputTokens !== void 0) usage.inputTokens = parsed.inputTokens;
46
+ if (parsed.outputTokens !== void 0) usage.outputTokens = parsed.outputTokens;
47
+ if (parsed.reasoningTokens !== void 0) usage.reasoningTokens = parsed.reasoningTokens;
48
+ if (parsed.totalTokens !== void 0) usage.totalTokens = parsed.totalTokens;
49
+ if (parsed.cacheReadTokens !== void 0) usage.cacheReadTokens = parsed.cacheReadTokens;
50
+ if (parsed.cacheWriteTokens !== void 0) usage.cacheWriteTokens = parsed.cacheWriteTokens;
51
+ return usage;
52
+ });
53
+ const ModelToolCallStateSchema = z.object({
54
+ toolCallId: z.string(),
55
+ toolName: z.string(),
56
+ input: z.unknown()
57
+ }).strict();
58
+ const ModelStepResultStateSchema = z.object({
59
+ text: z.string(),
60
+ finishReason: LLMFinishReasonStateSchema,
61
+ usage: TokenUsageStateSchema,
62
+ toolCalls: z.array(ModelToolCallStateSchema)
63
+ }).strict();
64
+ const JsonValueSchema = z.json();
65
+ const ProviderOptionsStateSchema = z.record(
66
+ z.string(),
67
+ z.record(z.string(), JsonValueSchema)
68
+ );
69
+ const JsonSchemaStateSchema = z.custom(
70
+ (value) => typeof value === "object" && value !== null && !Array.isArray(value)
71
+ );
72
+ const ToolSetEntryStateSchema = z.object({
73
+ name: z.string().optional(),
74
+ description: z.string().optional(),
75
+ parameters: JsonSchemaStateSchema,
76
+ _meta: z.record(z.string(), JsonValueSchema).optional()
77
+ }).strict().transform((parsed) => {
78
+ const tool = { parameters: parsed.parameters };
79
+ if (parsed.name !== void 0) tool.name = parsed.name;
80
+ if (parsed.description !== void 0) tool.description = parsed.description;
81
+ if (parsed._meta !== void 0) tool._meta = parsed._meta;
82
+ return tool;
83
+ });
84
+ const ToolSetStateSchema = z.record(z.string(), ToolSetEntryStateSchema);
85
+ const ModelStepRequestStateSchema = z.object({
86
+ messages: z.array(
87
+ z.custom(
88
+ (value) => typeof value === "object" && value !== null && !Array.isArray(value)
89
+ )
90
+ ),
91
+ estimatedInputTokens: z.number().int().nonnegative(),
92
+ toolDefinitions: ToolSetStateSchema,
93
+ reasoning: z.object({
94
+ reasoningVariant: z.string().optional(),
95
+ reasoningBudgetTokens: z.number().int().positive().optional()
96
+ }).strict().optional(),
97
+ providerOptions: ProviderOptionsStateSchema.optional(),
98
+ streaming: z.boolean()
99
+ }).strict();
100
+ const TurnDriverStateSchema = z.discriminatedUnion("phase", [
101
+ z.object({
102
+ phase: z.literal("ready-for-model"),
103
+ stepCount: z.number().int().nonnegative(),
104
+ startedAtMs: z.number().int().nonnegative(),
105
+ supportsTools: z.boolean(),
106
+ lastText: z.string(),
107
+ lastUsage: TokenUsageStateSchema.nullable(),
108
+ lastFinishReason: LLMFinishReasonStateSchema
109
+ }).strict(),
110
+ z.object({
111
+ phase: z.literal("model-step-prepared"),
112
+ stepCount: z.number().int().nonnegative(),
113
+ startedAtMs: z.number().int().nonnegative(),
114
+ supportsTools: z.boolean(),
115
+ modelStepId: z.string(),
116
+ request: ModelStepRequestStateSchema,
117
+ lastText: z.string(),
118
+ lastUsage: TokenUsageStateSchema.nullable(),
119
+ lastFinishReason: LLMFinishReasonStateSchema
120
+ }).strict(),
121
+ z.object({
122
+ phase: z.literal("model-step-complete"),
123
+ stepCount: z.number().int().nonnegative(),
124
+ startedAtMs: z.number().int().nonnegative(),
125
+ supportsTools: z.boolean(),
126
+ modelStepId: z.string(),
127
+ result: ModelStepResultStateSchema,
128
+ toolCallsExecuted: z.boolean()
129
+ }).strict(),
130
+ z.object({
131
+ phase: z.literal("stopped"),
132
+ stepCount: z.number().int().nonnegative(),
133
+ startedAtMs: z.number().int().nonnegative(),
134
+ supportsTools: z.boolean(),
135
+ lastText: z.string(),
136
+ lastUsage: TokenUsageStateSchema.nullable(),
137
+ lastFinishReason: LLMFinishReasonStateSchema,
138
+ finished: z.boolean()
139
+ }).strict()
140
+ ]);
141
+ function parseTurnDriverState(input) {
142
+ return TurnDriverStateSchema.parse(input);
143
+ }
144
+ function toModelStepRequestState(request) {
145
+ return {
146
+ messages: structuredClone(request.messages),
147
+ estimatedInputTokens: request.estimatedInputTokens,
148
+ toolDefinitions: structuredClone(request.toolDefinitions),
149
+ ...request.reasoning === void 0 ? {} : { reasoning: structuredClone(request.reasoning) },
150
+ ...request.providerOptions === void 0 ? {} : { providerOptions: structuredClone(request.providerOptions) },
151
+ streaming: request.streaming
152
+ };
153
+ }
22
154
  const toolSupportCache = /* @__PURE__ */ new Map();
23
155
  const LOCAL_PROVIDERS = ["ollama", "local"];
24
156
  class TurnExecutor {
25
- constructor(model, toolManager, contextManager, eventBus, resourceManager, sessionId, config, llmContext, logger, messageQueue, modelLimits, externalSignal, compactionStrategy = null, runContext) {
157
+ constructor(model, toolManager, contextManager, eventBus, resourceManager, sessionId, config, llmContext, logger, steerQueue, followUpQueue, modelLimits, externalSignal, compactionStrategy = null, runContext) {
26
158
  this.model = model;
27
159
  this.toolManager = toolManager;
28
160
  this.contextManager = contextManager;
@@ -31,7 +163,8 @@ class TurnExecutor {
31
163
  this.sessionId = sessionId;
32
164
  this.config = config;
33
165
  this.llmContext = llmContext;
34
- this.messageQueue = messageQueue;
166
+ this.steerQueue = steerQueue;
167
+ this.followUpQueue = followUpQueue;
35
168
  this.modelLimits = modelLimits;
36
169
  this.externalSignal = externalSignal;
37
170
  this.runContext = runContext;
@@ -46,11 +179,7 @@ class TurnExecutor {
46
179
  */
47
180
  stepAbortController;
48
181
  compactionStrategy = null;
49
- /**
50
- * Map to track tool-call metadata by toolCallId.
51
- * Used to pass execution-time info (approval + presentation snapshot) to result persistence.
52
- */
53
- toolCallMetadata = /* @__PURE__ */ new Map();
182
+ currentModelStepId = "in-memory-model-step-0";
54
183
  /**
55
184
  * Get StreamProcessor config from TurnExecutor state.
56
185
  * @param estimatedInputTokens Optional estimated input tokens for analytics
@@ -79,238 +208,300 @@ class TurnExecutor {
79
208
  * @param streaming If true, emits llm:chunk events during streaming. Default true.
80
209
  */
81
210
  async execute(contributorContext, streaming = true) {
82
- var _stack = [];
211
+ const driver = await this.createDriver(contributorContext, { streaming });
83
212
  try {
84
- const _ = __using(_stack, defer(() => this.cleanup()));
85
- const startTime = Date.now();
86
- let stepCount = 0;
87
- let lastStepTokens = null;
88
- let lastFinishReason = "unknown";
89
- let lastText = "";
90
- this.eventBus.emit("llm:thinking", {});
91
- const supportsTools = await this.validateToolSupport();
92
- if (!supportsTools) {
93
- const modelKey = `${this.llmContext.provider}:${this.llmContext.model}`;
94
- this.eventBus.emit("llm:unsupported-input", {
95
- errors: [
96
- `Model '${modelKey}' does not support tool calling.`,
97
- "You can still chat, but the model will not be able to use tools or execute commands."
98
- ],
99
- provider: this.llmContext.provider,
100
- model: this.llmContext.model,
101
- details: {
102
- feature: "tool-calling",
103
- supported: false
104
- }
105
- });
106
- this.logger.warn(
107
- `Model ${modelKey} does not support tools - continuing without tool calling`
108
- );
109
- }
110
- let currentAbortHandler = null;
213
+ let stopped = false;
111
214
  try {
112
- while (true) {
113
- if (currentAbortHandler && this.externalSignal) {
114
- this.externalSignal.removeEventListener("abort", currentAbortHandler);
115
- }
116
- this.stepAbortController = new AbortController();
117
- currentAbortHandler = () => this.stepAbortController.abort();
118
- if (this.externalSignal && !this.externalSignal.aborted) {
119
- this.externalSignal.addEventListener("abort", currentAbortHandler, {
120
- once: true
121
- });
215
+ while (!stopped) {
216
+ const modelStep = await driver.runNextModelStep();
217
+ if (modelStep.result.finishReason === "tool-calls") {
218
+ await driver.executeToolCalls();
122
219
  }
123
- const coalesced = await this.messageQueue.dequeueAll();
124
- if (coalesced) {
125
- await this.injectQueuedMessages(coalesced);
220
+ const nextStep = await driver.decideNextStep();
221
+ if (nextStep.kind === "stop") {
222
+ stopped = true;
126
223
  }
127
- await this.pruneOldToolOutputs();
128
- let prepared = await this.contextManager.getFormattedMessagesForLLM(
224
+ }
225
+ } catch (error) {
226
+ return await driver.fail(error);
227
+ }
228
+ return await driver.finish();
229
+ } finally {
230
+ driver.dispose();
231
+ }
232
+ }
233
+ async createDriver(contributorContext, options = { streaming: true }) {
234
+ const now = Date.now();
235
+ const state = options.state ?? {
236
+ phase: "ready-for-model",
237
+ stepCount: 0,
238
+ startedAtMs: now,
239
+ supportsTools: await this.validateInitialToolSupport(),
240
+ lastText: "",
241
+ lastUsage: null,
242
+ lastFinishReason: "unknown"
243
+ };
244
+ const startTime = state.startedAtMs;
245
+ let stepCount = state.stepCount;
246
+ let lastStepTokens = state.phase === "model-step-complete" ? structuredClone(state.result.usage) : structuredClone(state.lastUsage);
247
+ let lastFinishReason = state.phase === "model-step-complete" ? state.result.finishReason : state.lastFinishReason;
248
+ let lastText = state.phase === "model-step-complete" ? state.result.text : state.lastText;
249
+ let currentStepScope = null;
250
+ let currentResult = state.phase === "model-step-complete" ? structuredClone(state.result) : null;
251
+ let preparedModelRequest = state.phase === "model-step-prepared" ? await this.restorePreparedModelRequest(state.request, state.supportsTools) : null;
252
+ let currentToolCallsExecuted = state.phase === "model-step-complete" ? state.toolCallsExecuted : false;
253
+ let modelStepPreparing = false;
254
+ let modelStepRunning = false;
255
+ let toolCallsRunning = false;
256
+ let stopped = state.phase === "stopped";
257
+ let finished = state.phase === "stopped" ? state.finished : false;
258
+ let disposed = false;
259
+ const turn = { supportsTools: state.supportsTools };
260
+ if (state.phase === "model-step-prepared" || state.phase === "model-step-complete") {
261
+ this.currentModelStepId = state.modelStepId;
262
+ currentStepScope = this.startModelStepScope();
263
+ }
264
+ const closeCurrentStepScope = () => {
265
+ currentStepScope?.[Symbol.dispose]();
266
+ currentStepScope = null;
267
+ };
268
+ const getState = () => {
269
+ if (modelStepPreparing) {
270
+ throw new Error("Turn driver cannot checkpoint during model preparation");
271
+ }
272
+ if (modelStepRunning) {
273
+ throw new Error("Turn driver cannot checkpoint during a model step");
274
+ }
275
+ if (toolCallsRunning) {
276
+ throw new Error("Turn driver cannot checkpoint during tool execution");
277
+ }
278
+ if (stopped) {
279
+ return {
280
+ phase: "stopped",
281
+ stepCount,
282
+ startedAtMs: startTime,
283
+ supportsTools: turn.supportsTools,
284
+ lastText,
285
+ lastUsage: structuredClone(lastStepTokens),
286
+ lastFinishReason,
287
+ finished
288
+ };
289
+ }
290
+ if (preparedModelRequest !== null) {
291
+ return {
292
+ phase: "model-step-prepared",
293
+ stepCount,
294
+ startedAtMs: startTime,
295
+ supportsTools: turn.supportsTools,
296
+ modelStepId: this.currentModelStepId,
297
+ request: toModelStepRequestState(preparedModelRequest),
298
+ lastText,
299
+ lastUsage: structuredClone(lastStepTokens),
300
+ lastFinishReason
301
+ };
302
+ }
303
+ if (currentResult !== null) {
304
+ return {
305
+ phase: "model-step-complete",
306
+ stepCount,
307
+ startedAtMs: startTime,
308
+ supportsTools: turn.supportsTools,
309
+ modelStepId: this.currentModelStepId,
310
+ result: {
311
+ text: currentResult.text,
312
+ finishReason: currentResult.finishReason,
313
+ usage: structuredClone(currentResult.usage),
314
+ toolCalls: structuredClone(currentResult.toolCalls)
315
+ },
316
+ toolCallsExecuted: currentToolCallsExecuted
317
+ };
318
+ }
319
+ return {
320
+ phase: "ready-for-model",
321
+ stepCount,
322
+ startedAtMs: startTime,
323
+ supportsTools: turn.supportsTools,
324
+ lastText,
325
+ lastUsage: structuredClone(lastStepTokens),
326
+ lastFinishReason
327
+ };
328
+ };
329
+ const assertCanUseDriver = () => {
330
+ if (disposed) {
331
+ throw new Error("Turn driver has already been disposed");
332
+ }
333
+ if (finished) {
334
+ throw new Error("Turn driver has already finished");
335
+ }
336
+ };
337
+ return {
338
+ prepareNextModelStep: async () => {
339
+ assertCanUseDriver();
340
+ if (stopped) {
341
+ throw new Error("Turn driver has already reached a stop decision");
342
+ }
343
+ if (preparedModelRequest !== null) {
344
+ return { stepCount };
345
+ }
346
+ if (currentStepScope !== null) {
347
+ throw new Error("Previous model step has not been decided yet");
348
+ }
349
+ currentStepScope = this.startModelStepScope();
350
+ this.currentModelStepId = `in-memory-model-step-${stepCount}`;
351
+ modelStepPreparing = true;
352
+ try {
353
+ preparedModelRequest = await this.prepareNextModelRequest({
129
354
  contributorContext,
130
- this.llmContext
131
- );
132
- const toolDefinitions = supportsTools ? this.toolManager.filterToolsForSession(
133
- await this.toolManager.getAllTools(),
134
- this.sessionId
135
- ) : {};
136
- let estimatedTokens = await this.contextManager.getEstimatedNextInputTokens(
137
- prepared.systemPrompt,
138
- prepared.preparedHistory,
139
- toolDefinitions
140
- );
141
- if (this.shouldCompact(estimatedTokens)) {
142
- this.logger.debug(
143
- `Pre-check: estimated ${estimatedTokens} tokens exceeds threshold, compacting`
144
- );
145
- const didCompact = await this.compactContext(
146
- estimatedTokens,
147
- contributorContext,
148
- toolDefinitions
149
- );
150
- if (didCompact) {
151
- prepared = await this.contextManager.getFormattedMessagesForLLM(
152
- contributorContext,
153
- this.llmContext
154
- );
155
- estimatedTokens = await this.contextManager.getEstimatedNextInputTokens(
156
- prepared.systemPrompt,
157
- prepared.preparedHistory,
158
- toolDefinitions
159
- );
160
- this.logger.debug(
161
- `Post-compaction: recomputed estimate is ${estimatedTokens} tokens`
162
- );
355
+ supportsTools: turn.supportsTools,
356
+ streaming: options.streaming
357
+ });
358
+ } catch (error) {
359
+ currentStepScope[Symbol.dispose]();
360
+ currentStepScope = null;
361
+ throw error;
362
+ } finally {
363
+ modelStepPreparing = false;
364
+ }
365
+ return { stepCount };
366
+ },
367
+ runNextModelStep: async () => {
368
+ assertCanUseDriver();
369
+ if (stopped) {
370
+ throw new Error("Turn driver has already reached a stop decision");
371
+ }
372
+ if (currentResult !== null) {
373
+ throw new Error("Previous model step has not been decided yet");
374
+ }
375
+ modelStepRunning = true;
376
+ try {
377
+ if (preparedModelRequest === null) {
378
+ if (currentStepScope !== null) {
379
+ throw new Error("Previous model step has not been decided yet");
163
380
  }
381
+ currentStepScope = this.startModelStepScope();
382
+ this.currentModelStepId = `in-memory-model-step-${stepCount}`;
383
+ preparedModelRequest = await this.prepareNextModelRequest({
384
+ contributorContext,
385
+ supportsTools: turn.supportsTools,
386
+ streaming: options.streaming
387
+ });
388
+ }
389
+ const modelStepRequest = preparedModelRequest;
390
+ if (currentStepScope === null || modelStepRequest === null) {
391
+ throw new Error("Model step request was not prepared");
164
392
  }
165
393
  this.logger.debug(`Step ${stepCount}: Starting`);
166
- const tools = supportsTools ? await this.createTools() : {};
167
- const providerOptions = buildProviderOptions({
168
- provider: this.llmContext.provider,
169
- model: this.llmContext.model,
170
- reasoning: this.config.reasoning
171
- });
172
- this.logger.debug("LLM request options", {
173
- provider: this.llmContext.provider,
174
- model: this.llmContext.model,
175
- requestedReasoning: {
176
- variant: this.config.reasoning?.variant,
177
- budgetTokens: this.config.reasoning?.budgetTokens
178
- },
179
- providerOptions
180
- });
181
- const reasoningVariant = this.config.reasoning?.variant;
182
- const reasoningBudgetTokens = getEffectiveReasoningBudgetTokens(providerOptions);
183
- const reasoningForStream = reasoningVariant !== void 0 || reasoningBudgetTokens !== void 0 ? {
184
- ...reasoningVariant !== void 0 && { reasoningVariant },
185
- ...reasoningBudgetTokens !== void 0 && { reasoningBudgetTokens }
186
- } : void 0;
187
- const streamProcessor = new StreamProcessor(
188
- this.contextManager,
189
- this.eventBus,
190
- this.resourceManager,
191
- this.stepAbortController.signal,
192
- this.getStreamProcessorConfig(estimatedTokens, reasoningForStream),
193
- this.logger,
194
- streaming,
195
- this.toolCallMetadata
196
- );
197
- const result = await streamProcessor.process(
198
- () => streamText({
199
- model: this.model,
200
- stopWhen: stepCountIs(1),
201
- tools,
202
- abortSignal: this.stepAbortController.signal,
203
- messages: prepared.formattedMessages,
204
- ...this.config.maxOutputTokens !== void 0 && {
205
- maxOutputTokens: this.config.maxOutputTokens
206
- },
207
- ...this.config.temperature !== void 0 && {
208
- temperature: this.config.temperature
209
- },
210
- // Provider-specific options (caching, reasoning, etc.)
211
- ...providerOptions !== void 0 && {
212
- providerOptions
213
- },
214
- // Log stream-level errors (tool errors, API errors during streaming)
215
- onError: (error) => {
216
- this.logger.error("Stream error", { error });
217
- }
218
- })
219
- );
394
+ const result = await this.runModelStepWithRetry(modelStepRequest);
395
+ currentResult = result;
396
+ currentToolCallsExecuted = result.finishReason !== "tool-calls";
397
+ preparedModelRequest = null;
220
398
  lastStepTokens = result.usage;
221
399
  lastFinishReason = result.finishReason;
222
400
  lastText = result.text;
223
401
  this.logger.debug(
224
402
  `Step ${stepCount}: Finished with reason="${result.finishReason}", tokens=${JSON.stringify(result.usage)}`
225
403
  );
226
- if (result.finishReason === "cancelled") {
227
- this.logger.info(
228
- `Context estimation (cancelled): keeping last known actuals, partial response (${result.text.length} chars) will be estimated`
229
- );
230
- } else if (result.usage?.inputTokens !== void 0) {
231
- const contextInputTokens2 = this.getContextInputTokens(result.usage);
232
- const actualInputTokens = contextInputTokens2 ?? result.usage.inputTokens;
233
- const diff = estimatedTokens - actualInputTokens;
234
- const diffPercent = actualInputTokens > 0 ? (diff / actualInputTokens * 100).toFixed(1) : "0.0";
235
- this.logger.info(
236
- `Context estimation accuracy: estimated=${estimatedTokens}, actual=${actualInputTokens}, error=${diff} (${diffPercent}%)`
237
- );
238
- this.contextManager.setLastActualInputTokens(actualInputTokens);
239
- if (result.usage?.outputTokens !== void 0) {
240
- this.contextManager.setLastActualOutputTokens(result.usage.outputTokens);
241
- }
242
- await this.contextManager.recordLastCallMessageCount();
243
- }
244
- const contextInputTokens = result.usage ? this.getContextInputTokens(result.usage) : null;
245
- if (contextInputTokens && this.shouldCompactFromActual(contextInputTokens)) {
246
- this.logger.debug(
247
- `Post-response: actual ${contextInputTokens} tokens exceeds threshold, compacting`
248
- );
249
- await this.compactContext(
250
- contextInputTokens,
251
- contributorContext,
252
- toolDefinitions
253
- );
254
- }
255
- if (result.finishReason !== "tool-calls") {
256
- const queuedOnTerminate = await this.messageQueue.dequeueAll();
257
- if (queuedOnTerminate) {
258
- this.logger.debug(
259
- `Continuing: ${queuedOnTerminate.messages.length} queued message(s) to process`
260
- );
261
- await this.injectQueuedMessages(queuedOnTerminate);
262
- continue;
263
- }
264
- this.logger.debug(`Terminating: finishReason is "${result.finishReason}"`);
265
- break;
266
- }
267
- if (this.externalSignal?.aborted && !this.messageQueue.hasPending()) {
268
- this.logger.debug("Terminating: hard cancel - external abort signal received");
269
- lastFinishReason = "cancelled";
270
- break;
271
- }
272
- stepCount++;
273
- if (this.config.maxSteps !== void 0 && stepCount >= this.config.maxSteps) {
274
- this.logger.debug(`Terminating: reached maxSteps (${this.config.maxSteps})`);
275
- lastFinishReason = "max-steps";
276
- break;
404
+ await this.applyModelStepResult({
405
+ result,
406
+ request: modelStepRequest,
407
+ contributorContext
408
+ });
409
+ return {
410
+ result,
411
+ stepCount
412
+ };
413
+ } finally {
414
+ modelStepRunning = false;
415
+ }
416
+ },
417
+ executeToolCalls: async () => {
418
+ assertCanUseDriver();
419
+ if (currentStepScope === null) {
420
+ throw new Error("No active model step is available for tool execution");
421
+ }
422
+ const result = currentResult;
423
+ if (result === null) {
424
+ throw new Error("No model step result is available for tool execution");
425
+ }
426
+ if (currentToolCallsExecuted) {
427
+ throw new Error("Tool calls for the current model step have already run");
428
+ }
429
+ if (result.finishReason === "tool-calls") {
430
+ toolCallsRunning = true;
431
+ currentToolCallsExecuted = true;
432
+ try {
433
+ await this.executeModelToolCalls(result.toolCalls);
434
+ } catch (error) {
435
+ currentToolCallsExecuted = false;
436
+ throw error;
437
+ } finally {
438
+ toolCallsRunning = false;
277
439
  }
278
440
  }
279
- } catch (error) {
280
- const mappedError = this.mapProviderError(error);
281
- this.logger.error("TurnExecutor failed", { error: mappedError });
282
- this.eventBus.emit("llm:error", {
283
- error: mappedError,
284
- context: "TurnExecutor",
285
- recoverable: false
286
- });
287
- await this.contextManager.flush();
288
- this.eventBus.emit("run:complete", {
289
- finishReason: "error",
441
+ },
442
+ decideNextStep: async () => {
443
+ assertCanUseDriver();
444
+ if (currentStepScope === null) {
445
+ throw new Error("No active model step is available to decide");
446
+ }
447
+ const result = currentResult;
448
+ if (result === null) {
449
+ throw new Error("No model step result is available to decide");
450
+ }
451
+ if (result.finishReason === "tool-calls" && !currentToolCallsExecuted) {
452
+ throw new Error("Tool calls must finish before deciding the next model step");
453
+ }
454
+ const nextStep = await this.decideNextStep(result, stepCount);
455
+ stepCount = nextStep.stepCount;
456
+ currentResult = null;
457
+ currentToolCallsExecuted = false;
458
+ closeCurrentStepScope();
459
+ if (nextStep.kind === "stop") {
460
+ lastFinishReason = nextStep.finishReason;
461
+ stopped = true;
462
+ return {
463
+ kind: "stop",
464
+ stepCount,
465
+ finishReason: lastFinishReason
466
+ };
467
+ }
468
+ return {
469
+ kind: "continue",
470
+ stepCount
471
+ };
472
+ },
473
+ finish: async () => {
474
+ assertCanUseDriver();
475
+ if (!stopped) {
476
+ throw new Error("Turn driver cannot finish before a stop decision");
477
+ }
478
+ const result = await this.finishTurn({
479
+ startTime,
290
480
  stepCount,
291
- durationMs: Date.now() - startTime,
292
- error: mappedError
481
+ text: lastText,
482
+ usage: lastStepTokens,
483
+ finishReason: lastFinishReason
293
484
  });
294
- throw mappedError;
485
+ finished = true;
486
+ return result;
487
+ },
488
+ fail: async (error) => {
489
+ closeCurrentStepScope();
490
+ return this.failTurn(error, stepCount, startTime);
491
+ },
492
+ getState,
493
+ checkpoint: () => {
494
+ const state2 = getState();
495
+ disposed = true;
496
+ closeCurrentStepScope();
497
+ return state2;
498
+ },
499
+ dispose: () => {
500
+ disposed = true;
501
+ closeCurrentStepScope();
502
+ this.cleanup();
295
503
  }
296
- await this.contextManager.flush();
297
- this.setTelemetryAttributes(lastStepTokens);
298
- this.eventBus.emit("run:complete", {
299
- finishReason: lastFinishReason,
300
- stepCount,
301
- durationMs: Date.now() - startTime
302
- });
303
- return {
304
- text: lastText,
305
- stepCount,
306
- usage: lastStepTokens,
307
- finishReason: lastFinishReason
308
- };
309
- } catch (_2) {
310
- var _error = _2, _hasError = true;
311
- } finally {
312
- __callDispose(_stack, _error, _hasError);
313
- }
504
+ };
314
505
  }
315
506
  /**
316
507
  * Abort the current step execution.
@@ -319,6 +510,170 @@ class TurnExecutor {
319
510
  abort() {
320
511
  this.stepAbortController.abort();
321
512
  }
513
+ async validateInitialToolSupport() {
514
+ try {
515
+ return (await this.startTurn()).supportsTools;
516
+ } catch (error) {
517
+ this.cleanup();
518
+ throw error;
519
+ }
520
+ }
521
+ async startTurn() {
522
+ this.eventBus.emit("llm:thinking", {});
523
+ const supportsTools = await this.validateToolSupport();
524
+ if (!supportsTools) {
525
+ const modelKey = `${this.llmContext.provider}:${this.llmContext.model}`;
526
+ this.eventBus.emit("llm:unsupported-input", {
527
+ errors: [
528
+ `Model '${modelKey}' does not support tool calling.`,
529
+ "You can still chat, but the model will not be able to use tools or execute commands."
530
+ ],
531
+ provider: this.llmContext.provider,
532
+ model: this.llmContext.model,
533
+ details: {
534
+ feature: "tool-calling",
535
+ supported: false
536
+ }
537
+ });
538
+ this.logger.warn(
539
+ `Model ${modelKey} does not support tools - continuing without tool calling`
540
+ );
541
+ }
542
+ return { supportsTools };
543
+ }
544
+ startModelStepScope() {
545
+ this.stepAbortController = new AbortController();
546
+ const abortHandler = () => this.stepAbortController.abort();
547
+ if (this.externalSignal?.aborted) {
548
+ this.stepAbortController.abort();
549
+ } else if (this.externalSignal) {
550
+ this.externalSignal.addEventListener("abort", abortHandler, { once: true });
551
+ }
552
+ return {
553
+ [Symbol.dispose]: () => {
554
+ this.externalSignal?.removeEventListener("abort", abortHandler);
555
+ }
556
+ };
557
+ }
558
+ async finishTurn(input) {
559
+ await this.contextManager.flush();
560
+ this.setTelemetryAttributes(input.usage);
561
+ this.eventBus.emit("run:complete", {
562
+ finishReason: input.finishReason,
563
+ stepCount: input.stepCount,
564
+ durationMs: Date.now() - input.startTime
565
+ });
566
+ return {
567
+ text: input.text,
568
+ stepCount: input.stepCount,
569
+ usage: input.usage,
570
+ finishReason: input.finishReason
571
+ };
572
+ }
573
+ async failTurn(error, stepCount, startTime) {
574
+ const mappedError = this.mapProviderError(error);
575
+ this.logger.error("TurnExecutor failed", { error: mappedError });
576
+ this.eventBus.emit("llm:error", {
577
+ error: mappedError,
578
+ context: "TurnExecutor",
579
+ recoverable: false
580
+ });
581
+ await this.contextManager.flush();
582
+ this.eventBus.emit("run:complete", {
583
+ finishReason: "error",
584
+ stepCount,
585
+ durationMs: Date.now() - startTime,
586
+ error: mappedError
587
+ });
588
+ throw mappedError;
589
+ }
590
+ advanceStep(stepCount) {
591
+ const nextStepCount = stepCount + 1;
592
+ if (this.config.maxSteps !== void 0 && nextStepCount >= this.config.maxSteps) {
593
+ return {
594
+ kind: "stop",
595
+ stepCount: nextStepCount,
596
+ finishReason: "max-steps"
597
+ };
598
+ }
599
+ return {
600
+ kind: "continue",
601
+ stepCount: nextStepCount
602
+ };
603
+ }
604
+ async continueWithQueuedInput(kind, queue, stepCount, finishReason) {
605
+ const label = kind === "late-steer" ? "late steer" : "follow-up";
606
+ if (this.externalSignal?.aborted || finishReason === "cancelled") {
607
+ this.logger.debug(`Terminating: cancel received before ${label}`);
608
+ return {
609
+ kind: "stop",
610
+ stepCount,
611
+ finishReason: "cancelled"
612
+ };
613
+ }
614
+ const stepAdvance = this.advanceStep(stepCount);
615
+ if (stepAdvance.kind === "stop") {
616
+ this.logger.debug(`Terminating: reached maxSteps (${this.config.maxSteps})`);
617
+ return stepAdvance;
618
+ }
619
+ const queued = await queue.dequeueAll();
620
+ if (!queued) {
621
+ this.logger.debug(`Terminating: finishReason is "${finishReason}"`);
622
+ return {
623
+ kind: "stop",
624
+ stepCount: stepAdvance.stepCount,
625
+ finishReason
626
+ };
627
+ }
628
+ const messageName = kind === "late-steer" ? "steer" : "follow-up";
629
+ const suffix = kind === "late-steer" ? " at end of turn" : "";
630
+ this.logger.debug(
631
+ `Continuing: ${queued.messages.length} ${messageName} message(s) to process${suffix}`
632
+ );
633
+ await this.injectQueuedMessages(queued);
634
+ return {
635
+ kind: "continue",
636
+ stepCount: stepAdvance.stepCount
637
+ };
638
+ }
639
+ async decideNextStep(result, stepCount) {
640
+ if (result.finishReason === "tool-calls") {
641
+ await this.steerQueue.refresh();
642
+ if (this.externalSignal?.aborted && !this.steerQueue.hasPending()) {
643
+ this.logger.debug("Terminating: hard cancel - external abort signal received");
644
+ return {
645
+ kind: "stop",
646
+ stepCount,
647
+ finishReason: "cancelled"
648
+ };
649
+ }
650
+ return this.advanceStep(stepCount);
651
+ }
652
+ await this.steerQueue.refresh();
653
+ if (this.steerQueue.hasPending()) {
654
+ return this.continueWithQueuedInput(
655
+ "late-steer",
656
+ this.steerQueue,
657
+ stepCount,
658
+ result.finishReason
659
+ );
660
+ }
661
+ await this.followUpQueue.refresh();
662
+ if (this.followUpQueue.hasPending()) {
663
+ return this.continueWithQueuedInput(
664
+ "follow-up",
665
+ this.followUpQueue,
666
+ stepCount,
667
+ result.finishReason
668
+ );
669
+ }
670
+ this.logger.debug(`Terminating: finishReason is "${result.finishReason}"`);
671
+ return {
672
+ kind: "stop",
673
+ stepCount,
674
+ finishReason: result.finishReason
675
+ };
676
+ }
322
677
  /**
323
678
  * Inject coalesced queued messages into the context as a single user message.
324
679
  * This enables mid-task user guidance.
@@ -412,210 +767,526 @@ class TurnExecutor {
412
767
  return true;
413
768
  }
414
769
  }
415
- /**
416
- * Creates tools with execute callbacks and toModelOutput.
417
- *
418
- * Key design decisions:
419
- * - execute() returns raw result with inline images (async)
420
- * - toModelOutput() formats for LLM consumption (sync)
421
- * - StreamProcessor handles persistence via tool-result events
422
- */
423
- async createTools() {
424
- const tools = this.toolManager.filterToolsForSession(
770
+ async prepareNextModelRequest(input) {
771
+ const coalesced = await this.steerQueue.dequeueAll();
772
+ if (coalesced) {
773
+ await this.injectQueuedMessages(coalesced);
774
+ }
775
+ await this.pruneOldToolOutputs();
776
+ let prepared = await this.contextManager.getFormattedMessagesForLLM(
777
+ input.contributorContext,
778
+ this.llmContext
779
+ );
780
+ const toolDefinitions = input.supportsTools ? this.toolManager.filterToolsForSession(
425
781
  await this.toolManager.getAllTools(),
426
782
  this.sessionId
783
+ ) : {};
784
+ let estimatedInputTokens = await this.contextManager.getEstimatedNextInputTokens(
785
+ prepared.systemPrompt,
786
+ prepared.preparedHistory,
787
+ toolDefinitions
427
788
  );
428
- return Object.fromEntries(
429
- Object.entries(tools).map(([name, tool]) => [
430
- name,
431
- {
432
- inputSchema: jsonSchema(tool.parameters),
433
- ...tool.description && { description: tool.description },
434
- /**
435
- * Execute callback - runs the tool and returns raw result.
436
- * Does NOT persist - StreamProcessor handles that on tool-result event.
437
- *
438
- * Uses Promise.race to ensure we return quickly on abort, even if the
439
- * underlying tool (especially MCP tools we don't control) keeps running.
440
- */
441
- execute: async (args, options) => {
442
- this.logger.debug(
443
- `Executing tool: ${name} (toolCallId: ${options.toolCallId})`
444
- );
445
- const abortSignal = this.stepAbortController.signal;
446
- if (abortSignal.aborted) {
447
- this.logger.debug(`Tool ${name} cancelled before execution`);
448
- return { error: "Cancelled by user", cancelled: true };
449
- }
450
- let abortHandler = null;
451
- const abortPromise = new Promise(
452
- (resolve) => {
453
- abortHandler = () => {
454
- this.logger.debug(`Tool ${name} cancelled during execution`);
455
- resolve({ error: "Cancelled by user", cancelled: true });
456
- };
457
- abortSignal.addEventListener("abort", abortHandler, { once: true });
458
- }
459
- );
460
- try {
461
- const result = await Promise.race([
462
- (async () => {
463
- const executionResult = await this.toolManager.executeTool(
464
- name,
465
- args,
466
- options.toolCallId,
467
- {
468
- sessionId: this.sessionId,
469
- abortSignal,
470
- ...this.runContext !== void 0 ? { runContext: this.runContext } : {}
471
- }
472
- );
473
- const metadata = (() => {
474
- const meta = {};
475
- if (executionResult.presentationSnapshot !== void 0) {
476
- meta.presentationSnapshot = executionResult.presentationSnapshot;
477
- }
478
- if (executionResult.meta !== void 0) {
479
- meta.meta = executionResult.meta;
480
- }
481
- if (executionResult.requireApproval !== void 0) {
482
- meta.requireApproval = executionResult.requireApproval;
483
- if (executionResult.approvalStatus !== void 0) {
484
- meta.approvalStatus = executionResult.approvalStatus;
485
- }
486
- }
487
- return Object.keys(meta).length > 0 ? meta : void 0;
488
- })();
489
- if (metadata) {
490
- this.toolCallMetadata.set(options.toolCallId, metadata);
491
- }
492
- return executionResult.result;
493
- })(),
494
- abortPromise
495
- ]);
496
- return result;
497
- } finally {
498
- if (abortHandler) {
499
- abortSignal.removeEventListener("abort", abortHandler);
500
- }
501
- }
502
- },
503
- /**
504
- * toModelOutput - formats raw result for LLM consumption.
505
- * Called by Vercel SDK when preparing messages for next LLM call.
506
- * SYNC - images are already inline in the raw result.
507
- */
508
- toModelOutput: (result) => {
509
- return this.formatToolResultForLLM(result, name);
510
- }
789
+ if (this.shouldCompact(estimatedInputTokens)) {
790
+ this.logger.debug(
791
+ `Pre-check: estimated ${estimatedInputTokens} tokens exceeds threshold, compacting`
792
+ );
793
+ const didCompact = await this.compactContext(
794
+ estimatedInputTokens,
795
+ input.contributorContext,
796
+ toolDefinitions
797
+ );
798
+ if (didCompact) {
799
+ prepared = await this.contextManager.getFormattedMessagesForLLM(
800
+ input.contributorContext,
801
+ this.llmContext
802
+ );
803
+ estimatedInputTokens = await this.contextManager.getEstimatedNextInputTokens(
804
+ prepared.systemPrompt,
805
+ prepared.preparedHistory,
806
+ toolDefinitions
807
+ );
808
+ this.logger.debug(
809
+ `Post-compaction: recomputed estimate is ${estimatedInputTokens} tokens`
810
+ );
811
+ }
812
+ }
813
+ const providerOptions = buildProviderOptions({
814
+ provider: this.llmContext.provider,
815
+ model: this.llmContext.model,
816
+ reasoning: this.config.reasoning
817
+ });
818
+ this.logger.debug("LLM request options", {
819
+ provider: this.llmContext.provider,
820
+ model: this.llmContext.model,
821
+ requestedReasoning: {
822
+ variant: this.config.reasoning?.variant,
823
+ budgetTokens: this.config.reasoning?.budgetTokens
824
+ },
825
+ providerOptions
826
+ });
827
+ const reasoningVariant = this.config.reasoning?.variant;
828
+ const reasoningBudgetTokens = getEffectiveReasoningBudgetTokens(providerOptions);
829
+ const reasoning = reasoningVariant !== void 0 || reasoningBudgetTokens !== void 0 ? {
830
+ ...reasoningVariant !== void 0 && { reasoningVariant },
831
+ ...reasoningBudgetTokens !== void 0 && { reasoningBudgetTokens }
832
+ } : void 0;
833
+ return {
834
+ messages: prepared.formattedMessages,
835
+ tools: input.supportsTools ? createModelToolDefinitions(toolDefinitions) : {},
836
+ toolDefinitions,
837
+ estimatedInputTokens,
838
+ reasoning,
839
+ providerOptions,
840
+ streaming: input.streaming
841
+ };
842
+ }
843
+ async restorePreparedModelRequest(state, supportsTools) {
844
+ const toolDefinitions = supportsTools ? structuredClone(state.toolDefinitions) : {};
845
+ return {
846
+ messages: structuredClone(state.messages),
847
+ tools: supportsTools ? createModelToolDefinitions(toolDefinitions) : {},
848
+ toolDefinitions,
849
+ estimatedInputTokens: state.estimatedInputTokens,
850
+ reasoning: state.reasoning === void 0 ? void 0 : {
851
+ ...state.reasoning.reasoningVariant === void 0 ? {} : { reasoningVariant: state.reasoning.reasoningVariant },
852
+ ...state.reasoning.reasoningBudgetTokens === void 0 ? {} : { reasoningBudgetTokens: state.reasoning.reasoningBudgetTokens }
853
+ },
854
+ providerOptions: state.providerOptions,
855
+ streaming: state.streaming
856
+ };
857
+ }
858
+ async runModelStep(request) {
859
+ const streamProcessor = new StreamProcessor(
860
+ this.contextManager,
861
+ this.eventBus,
862
+ this.stepAbortController.signal,
863
+ this.getStreamProcessorConfig(request.estimatedInputTokens, request.reasoning),
864
+ this.logger,
865
+ request.streaming
866
+ );
867
+ return streamProcessor.process(
868
+ () => streamText({
869
+ model: this.model,
870
+ stopWhen: stepCountIs(1),
871
+ maxRetries: 0,
872
+ tools: request.tools,
873
+ abortSignal: this.stepAbortController.signal,
874
+ messages: request.messages,
875
+ ...this.config.maxOutputTokens !== void 0 && {
876
+ maxOutputTokens: this.config.maxOutputTokens
877
+ },
878
+ ...this.config.temperature !== void 0 && {
879
+ temperature: this.config.temperature
880
+ },
881
+ // Provider-specific options (caching, reasoning, etc.)
882
+ ...request.providerOptions !== void 0 && {
883
+ providerOptions: request.providerOptions
884
+ },
885
+ // Log stream-level errors (tool errors, API errors during streaming)
886
+ onError: (error) => {
887
+ this.logger.error("Stream error", { error });
511
888
  }
512
- ])
889
+ })
513
890
  );
514
891
  }
515
- /**
516
- * Format tool result for LLM consumption.
517
- * Handles multimodal content (text + images).
518
- *
519
- * This handles RAW tool results - the structure may vary.
520
- */
521
- formatToolResultForLLM(result, toolName) {
522
- if (result && typeof result === "object" && "error" in result) {
523
- const errorResult = result;
524
- let errorFlags = "";
525
- if (errorResult.denied) errorFlags += " (denied)";
526
- if (errorResult.timeout) errorFlags += " (timeout)";
892
+ async runModelStepWithRetry(request) {
893
+ for (let failedAttempts = 0; ; failedAttempts += 1) {
894
+ const historyLengthBefore = (await this.contextManager.getHistory()).length;
895
+ try {
896
+ return await this.runModelStep(request);
897
+ } catch (error) {
898
+ const historyLengthAfter = (await this.contextManager.getHistory()).length;
899
+ const historyLengthChanged = historyLengthAfter !== historyLengthBefore;
900
+ if (!this.canRetryModelRequest(error, historyLengthChanged) || failedAttempts >= MODEL_REQUEST_MAX_RETRIES) {
901
+ throw error;
902
+ }
903
+ const mappedError = this.mapProviderError(error);
904
+ this.eventBus.emit("llm:retrying", {
905
+ error: mappedError,
906
+ context: "TurnExecutor.runModelStep",
907
+ attempt: failedAttempts + 1,
908
+ maxRetries: MODEL_REQUEST_MAX_RETRIES,
909
+ provider: this.llmContext.provider,
910
+ model: this.llmContext.model
911
+ });
912
+ this.logger.warn("Retrying model request after transient failure", {
913
+ attempt: failedAttempts + 1,
914
+ maxRetries: MODEL_REQUEST_MAX_RETRIES,
915
+ error: mappedError
916
+ });
917
+ }
918
+ }
919
+ }
920
+ canRetryModelRequest(error, historyLengthChanged) {
921
+ if (historyLengthChanged) return false;
922
+ if (this.stepAbortController.signal.aborted) return false;
923
+ if (!APICallError.isInstance?.(error)) return false;
924
+ return error.isRetryable;
925
+ }
926
+ async applyModelStepResult(input) {
927
+ const { result, request, contributorContext } = input;
928
+ if (result.finishReason === "cancelled") {
929
+ this.logger.info(
930
+ `Context estimation (cancelled): keeping last known actuals, partial response (${result.text.length} chars) will be estimated`
931
+ );
932
+ return;
933
+ }
934
+ const contextInputTokens = this.getContextInputTokens(result.usage);
935
+ if (result.usage.inputTokens !== void 0) {
936
+ const actualInputTokens = contextInputTokens ?? result.usage.inputTokens;
937
+ const diff = request.estimatedInputTokens - actualInputTokens;
938
+ const diffPercent = actualInputTokens > 0 ? (diff / actualInputTokens * 100).toFixed(1) : "0.0";
939
+ this.logger.info(
940
+ `Context estimation accuracy: estimated=${request.estimatedInputTokens}, actual=${actualInputTokens}, error=${diff} (${diffPercent}%)`
941
+ );
942
+ this.contextManager.setLastActualInputTokens(actualInputTokens);
943
+ if (result.usage.outputTokens !== void 0) {
944
+ this.contextManager.setLastActualOutputTokens(result.usage.outputTokens);
945
+ }
946
+ await this.contextManager.recordLastCallMessageCount();
947
+ }
948
+ if (result.finishReason !== "tool-calls" && contextInputTokens && this.shouldCompactFromActual(contextInputTokens)) {
949
+ this.logger.debug(
950
+ `Post-response: actual ${contextInputTokens} tokens exceeds threshold, compacting`
951
+ );
952
+ await this.compactContext(
953
+ contextInputTokens,
954
+ contributorContext,
955
+ request.toolDefinitions
956
+ );
957
+ }
958
+ }
959
+ async executeModelToolCalls(toolCalls) {
960
+ const preparedCalls = [];
961
+ for (const toolCall of toolCalls) {
962
+ preparedCalls.push(await this.prepareModelToolCall(toolCall));
963
+ }
964
+ const executionResults = await Promise.all(
965
+ preparedCalls.map((prepared) => this.executePreparedModelToolCall(prepared))
966
+ );
967
+ for (let index = 0; index < toolCalls.length; index += 1) {
968
+ const toolCall = toolCalls[index];
969
+ const executionResult = executionResults[index];
970
+ if (toolCall === void 0 || executionResult === void 0) {
971
+ throw new Error("Tool call result count must match emitted tool call count");
972
+ }
973
+ await this.persistModelToolResult(toolCall, executionResult);
974
+ }
975
+ }
976
+ async prepareModelToolCall(toolCall) {
977
+ if (this.stepAbortController.signal.aborted) {
527
978
  return {
528
- type: "text",
529
- value: `Tool ${toolName} failed${errorFlags}: ${errorResult.error}`
979
+ kind: "terminal",
980
+ toolCall,
981
+ modelVisibleResult: this.cancelledToolResult(
982
+ this.buildToolCallFallbackSnapshot(toolCall.toolName)
983
+ )
530
984
  };
531
985
  }
532
- if (this.hasMultimodalContent(result)) {
533
- const contentArray = result.content;
534
- const contentValue = [];
535
- for (const part of contentArray) {
536
- if (part.type === "text" && typeof part.text === "string") {
537
- contentValue.push({ type: "text", text: part.text });
538
- } else if (part.type === "image") {
539
- const imageData = this.extractImageData(part);
540
- if (imageData) {
541
- contentValue.push({
542
- type: "media",
543
- data: imageData,
544
- mediaType: part.mimeType || "image/jpeg"
545
- });
546
- }
547
- } else if (part.type === "file") {
548
- const fileData = this.extractFileData(part);
549
- if (fileData) {
550
- contentValue.push({
551
- type: "media",
552
- data: fileData,
553
- mediaType: part.mimeType || "application/octet-stream"
554
- });
555
- }
556
- }
986
+ let prepared;
987
+ try {
988
+ prepared = await this.toolManager.prepareToolCall({
989
+ toolName: toolCall.toolName,
990
+ input: toolCall.input,
991
+ toolCallId: toolCall.toolCallId,
992
+ sessionId: this.sessionId,
993
+ ...this.runContext !== void 0 ? { runContext: this.runContext } : {}
994
+ });
995
+ } catch (error) {
996
+ const modelVisibleResult = this.failedToolResult(
997
+ toolCall.toolName,
998
+ error,
999
+ this.buildToolCallFallbackSnapshot(toolCall.toolName)
1000
+ );
1001
+ this.emitFallbackToolCall(toolCall, modelVisibleResult);
1002
+ return {
1003
+ kind: "terminal",
1004
+ toolCall,
1005
+ modelVisibleResult
1006
+ };
1007
+ }
1008
+ if (prepared.kind === "terminal") {
1009
+ if ("call" in prepared) {
1010
+ this.emitToolCall(toolCall, prepared.call);
1011
+ } else {
1012
+ this.emitFallbackToolCall(toolCall, prepared.modelVisibleResult);
1013
+ }
1014
+ } else {
1015
+ this.emitToolCall(toolCall, prepared.call);
1016
+ }
1017
+ return { kind: "prepared", toolCall, prepared };
1018
+ }
1019
+ async executePreparedModelToolCall(preparedCall) {
1020
+ try {
1021
+ if (preparedCall.kind === "terminal") {
1022
+ return preparedCall.modelVisibleResult;
1023
+ }
1024
+ const { prepared } = preparedCall;
1025
+ if (prepared.kind === "terminal") {
1026
+ return prepared.modelVisibleResult;
1027
+ }
1028
+ if (prepared.kind === "ready") {
1029
+ return this.executePreparedToolCallWithAbort(
1030
+ prepared.call,
1031
+ this.resolveModelToolExecutionIdentity(preparedCall.toolCall.toolCallId)
1032
+ );
1033
+ }
1034
+ const identity = this.resolveToolApprovalIdentity();
1035
+ const recorded = await this.toolManager.recordApprovalRequest(prepared, identity);
1036
+ const approval = await this.requestApprovalDecisionWithAbort(recorded);
1037
+ if (approval.kind === "terminal") {
1038
+ return approval.modelVisibleResult;
557
1039
  }
558
- if (contentValue.length > 0 && contentValue.some((v) => v.type === "media")) {
559
- return { type: "content", value: contentValue };
1040
+ const decision = this.toApprovalDecisionInput(approval.response);
1041
+ const applied = await this.toolManager.applyApprovalDecision(
1042
+ recorded,
1043
+ decision,
1044
+ this.runContext
1045
+ );
1046
+ if (applied.kind === "terminal") {
1047
+ return applied.modelVisibleResult;
1048
+ }
1049
+ return this.executePreparedToolCallWithAbort(
1050
+ applied.call,
1051
+ this.resolveModelToolExecutionIdentity(preparedCall.toolCall.toolCallId)
1052
+ );
1053
+ } catch (error) {
1054
+ return this.failedToolResult(
1055
+ preparedCall.toolCall.toolName,
1056
+ error,
1057
+ this.getPreparedToolCallSnapshot(preparedCall)
1058
+ );
1059
+ }
1060
+ }
1061
+ emitFallbackToolCall(toolCall, executionResult) {
1062
+ this.emitToolCall(toolCall, {
1063
+ input: this.getToolCallInputForEvent(toolCall.input),
1064
+ presentationSnapshot: executionResult.presentationSnapshot ?? this.buildToolCallFallbackSnapshot(toolCall.toolName),
1065
+ toolName: toolCall.toolName
1066
+ });
1067
+ }
1068
+ async executePreparedToolCallWithAbort(call, executionIdentity) {
1069
+ const abortSignal = this.stepAbortController.signal;
1070
+ let abortHandler = null;
1071
+ const abortPromise = new Promise((resolve) => {
1072
+ abortHandler = () => {
1073
+ this.logger.debug(`Tool ${call.toolName} cancelled during execution`);
1074
+ resolve(this.cancelledToolResult(call.presentationSnapshot, call));
1075
+ };
1076
+ abortSignal.addEventListener("abort", abortHandler, { once: true });
1077
+ });
1078
+ try {
1079
+ return await Promise.race([
1080
+ this.toolManager.executePreparedToolCall(call, {
1081
+ sessionId: this.sessionId,
1082
+ abortSignal,
1083
+ executionIdentity,
1084
+ ...this.runContext !== void 0 ? { runContext: this.runContext } : {}
1085
+ }),
1086
+ abortPromise
1087
+ ]);
1088
+ } finally {
1089
+ if (abortHandler) {
1090
+ abortSignal.removeEventListener("abort", abortHandler);
560
1091
  }
561
- const textParts = contentArray.filter((p) => p.type === "text" && typeof p.text === "string").map((p) => p.text);
1092
+ }
1093
+ }
1094
+ async requestApprovalDecisionWithAbort(recorded) {
1095
+ const abortSignal = this.stepAbortController.signal;
1096
+ if (abortSignal.aborted) {
562
1097
  return {
563
- type: "text",
564
- value: textParts.join("\n") || "[empty result]"
1098
+ kind: "terminal",
1099
+ modelVisibleResult: this.cancelledToolResult(
1100
+ recorded.prepared.call.presentationSnapshot,
1101
+ recorded.prepared.call
1102
+ )
565
1103
  };
566
1104
  }
567
- if (typeof result === "string") {
568
- return { type: "text", value: result };
1105
+ let abortHandler = null;
1106
+ const abortPromise = new Promise((resolve) => {
1107
+ abortHandler = () => {
1108
+ this.logger.debug(
1109
+ `Tool ${recorded.prepared.call.toolName} approval cancelled before execution`
1110
+ );
1111
+ resolve({
1112
+ kind: "terminal",
1113
+ modelVisibleResult: this.cancelledToolResult(
1114
+ recorded.prepared.call.presentationSnapshot,
1115
+ recorded.prepared.call
1116
+ )
1117
+ });
1118
+ };
1119
+ abortSignal.addEventListener("abort", abortHandler, { once: true });
1120
+ });
1121
+ try {
1122
+ return await Promise.race([
1123
+ this.toolManager.requestApprovalDecision(recorded).then((response) => ({ kind: "response", response })),
1124
+ abortPromise
1125
+ ]);
1126
+ } finally {
1127
+ if (abortHandler) {
1128
+ abortSignal.removeEventListener("abort", abortHandler);
1129
+ }
569
1130
  }
1131
+ }
1132
+ cancelledToolResult(presentationSnapshot, call) {
570
1133
  return {
571
- type: "text",
572
- value: typeof result === "object" && result !== null ? JSON.stringify(result) : String(result)
1134
+ result: { error: "Cancelled by user", cancelled: true },
1135
+ presentationSnapshot,
1136
+ ...call?.meta !== void 0 ? { meta: call.meta } : {},
1137
+ ...call?.approval !== void 0 ? call.approval : {}
573
1138
  };
574
1139
  }
575
- /**
576
- * Extract image data from a part, handling various formats.
577
- */
578
- extractImageData(part) {
579
- if (typeof part.image === "string") {
580
- return part.image;
581
- }
582
- if (typeof part.data === "string") {
583
- return part.data;
1140
+ failedToolResult(toolName, error, presentationSnapshot) {
1141
+ const message = toError(error, this.logger).message;
1142
+ this.logger.error(`Tool ${toolName} failed before execution result was produced`, {
1143
+ error: message
1144
+ });
1145
+ return {
1146
+ result: { error: message },
1147
+ presentationSnapshot
1148
+ };
1149
+ }
1150
+ getPreparedToolCallSnapshot(preparedCall) {
1151
+ if (preparedCall.kind === "terminal") {
1152
+ return preparedCall.modelVisibleResult.presentationSnapshot ?? this.buildToolCallFallbackSnapshot(preparedCall.toolCall.toolName);
584
1153
  }
585
- if (part.image instanceof Buffer) {
586
- return part.image.toString("base64");
1154
+ if ("call" in preparedCall.prepared) {
1155
+ return preparedCall.prepared.call.presentationSnapshot;
587
1156
  }
588
- if (part.data instanceof Buffer) {
589
- return part.data.toString("base64");
1157
+ return preparedCall.prepared.modelVisibleResult.presentationSnapshot ?? this.buildToolCallFallbackSnapshot(preparedCall.toolCall.toolName);
1158
+ }
1159
+ async persistModelToolResult(toolCall, executionResult) {
1160
+ const success = this.isToolExecutionSuccessful(executionResult);
1161
+ const sanitized = await sanitizeToolResult(
1162
+ executionResult.result,
1163
+ {
1164
+ artifactStore: this.resourceManager.getArtifactStore(),
1165
+ toolName: toolCall.toolName,
1166
+ toolCallId: toolCall.toolCallId,
1167
+ success
1168
+ },
1169
+ this.logger
1170
+ );
1171
+ const truncated = truncateToolResult(sanitized);
1172
+ const metadata = this.getToolExecutionMetadata(executionResult);
1173
+ const errorMessage = this.getToolExecutionErrorMessage(executionResult.result);
1174
+ await this.contextManager.addToolResult(
1175
+ toolCall.toolCallId,
1176
+ toolCall.toolName,
1177
+ truncated,
1178
+ metadata
1179
+ );
1180
+ this.eventBus.emit("llm:tool-result", {
1181
+ toolName: toolCall.toolName,
1182
+ ...metadata?.presentationSnapshot !== void 0 && {
1183
+ presentationSnapshot: metadata.presentationSnapshot
1184
+ },
1185
+ ...metadata?.meta !== void 0 && {
1186
+ meta: metadata.meta
1187
+ },
1188
+ callId: toolCall.toolCallId,
1189
+ success,
1190
+ sanitized: truncated,
1191
+ rawResult: executionResult.result,
1192
+ ...!success && errorMessage !== null ? { error: errorMessage } : {},
1193
+ ...metadata?.requireApproval !== void 0 && {
1194
+ requireApproval: metadata.requireApproval
1195
+ },
1196
+ ...metadata?.approvalStatus !== void 0 && {
1197
+ approvalStatus: metadata.approvalStatus
1198
+ }
1199
+ });
1200
+ }
1201
+ emitToolCall(toolCall, call) {
1202
+ this.eventBus.emit("llm:tool-call", {
1203
+ toolName: toolCall.toolName,
1204
+ ...call.presentationSnapshot !== void 0 && {
1205
+ presentationSnapshot: call.presentationSnapshot
1206
+ },
1207
+ args: call.input,
1208
+ ...call.meta !== void 0 ? { meta: call.meta } : {},
1209
+ ...call.callDescription !== void 0 && { callDescription: call.callDescription },
1210
+ callId: toolCall.toolCallId,
1211
+ ...this.runContext?.hostRuntime !== void 0 && {
1212
+ hostRuntime: this.runContext.hostRuntime
1213
+ }
1214
+ });
1215
+ }
1216
+ resolveToolApprovalIdentity() {
1217
+ const ids = this.runContext?.hostRuntime?.ids;
1218
+ return {
1219
+ runId: ids?.runId ?? this.sessionId,
1220
+ turnId: ids?.turnId ?? "in-memory-turn",
1221
+ modelStepId: ids?.modelStepId ?? this.currentModelStepId
1222
+ };
1223
+ }
1224
+ resolveModelToolExecutionIdentity(toolCallId) {
1225
+ const ids = this.runContext?.hostRuntime?.ids;
1226
+ return {
1227
+ runId: ids?.runId ?? this.sessionId,
1228
+ turnId: ids?.turnId ?? "in-memory-turn",
1229
+ modelStepId: ids?.modelStepId ?? this.currentModelStepId,
1230
+ toolCallId
1231
+ };
1232
+ }
1233
+ toApprovalDecisionInput(response) {
1234
+ if (response.status === ApprovalStatus.APPROVED) {
1235
+ return {
1236
+ approvalId: response.approvalId,
1237
+ status: ApprovalStatus.APPROVED,
1238
+ ...response.data !== void 0 ? { data: response.data } : {}
1239
+ };
590
1240
  }
591
- if (part.image instanceof ArrayBuffer) {
592
- return Buffer.from(new Uint8Array(part.image)).toString("base64");
1241
+ const status = response.status === ApprovalStatus.DENIED ? ApprovalStatus.DENIED : ApprovalStatus.CANCELLED;
1242
+ return {
1243
+ approvalId: response.approvalId,
1244
+ status,
1245
+ ...response.reason !== void 0 ? { reason: response.reason } : {},
1246
+ ...response.message !== void 0 ? { message: response.message } : {},
1247
+ ...response.timeoutMs !== void 0 ? { timeoutMs: response.timeoutMs } : {},
1248
+ ...response.data !== void 0 ? { data: response.data } : {}
1249
+ };
1250
+ }
1251
+ getToolExecutionMetadata(executionResult) {
1252
+ const metadata = {};
1253
+ if (executionResult.presentationSnapshot !== void 0) {
1254
+ metadata.presentationSnapshot = executionResult.presentationSnapshot;
593
1255
  }
594
- if (part.data instanceof ArrayBuffer) {
595
- return Buffer.from(new Uint8Array(part.data)).toString("base64");
1256
+ if (executionResult.meta !== void 0) {
1257
+ metadata.meta = executionResult.meta;
596
1258
  }
597
- return null;
598
- }
599
- /**
600
- * Extract file data from a part.
601
- */
602
- extractFileData(part) {
603
- if (typeof part.data === "string") {
604
- return part.data;
1259
+ if (executionResult.requireApproval !== void 0) {
1260
+ metadata.requireApproval = executionResult.requireApproval;
605
1261
  }
606
- if (part.data instanceof Buffer) {
607
- return part.data.toString("base64");
1262
+ if (executionResult.approvalStatus !== void 0) {
1263
+ metadata.approvalStatus = executionResult.approvalStatus;
608
1264
  }
609
- if (part.data instanceof ArrayBuffer) {
610
- return Buffer.from(new Uint8Array(part.data)).toString("base64");
1265
+ return Object.keys(metadata).length > 0 ? metadata : void 0;
1266
+ }
1267
+ isToolExecutionSuccessful(executionResult) {
1268
+ return !this.getToolExecutionErrorMessage(executionResult.result);
1269
+ }
1270
+ getToolExecutionErrorMessage(result) {
1271
+ if (result && typeof result === "object" && "error" in result) {
1272
+ const error = result.error;
1273
+ return typeof error === "string" ? error : String(error);
611
1274
  }
612
1275
  return null;
613
1276
  }
614
- /**
615
- * Check if result has multimodal content array
616
- */
617
- hasMultimodalContent(result) {
618
- return result !== null && typeof result === "object" && "content" in result && Array.isArray(result.content);
1277
+ getToolCallInputForEvent(input) {
1278
+ return input !== null && typeof input === "object" && !Array.isArray(input) ? input : {};
1279
+ }
1280
+ buildToolCallFallbackSnapshot(toolName) {
1281
+ return {
1282
+ version: 1,
1283
+ source: {
1284
+ type: toolName.startsWith(MCP_TOOL_PREFIX) ? "mcp" : "local"
1285
+ },
1286
+ header: {
1287
+ title: toolName.replace(/[_-]+/g, " ")
1288
+ }
1289
+ };
619
1290
  }
620
1291
  /**
621
1292
  * Constants for pruning thresholds
@@ -686,16 +1357,16 @@ class TurnExecutor {
686
1357
  }
687
1358
  /**
688
1359
  * Cleanup resources when execution scope exits.
689
- * Called automatically via defer() on normal exit, throw, or abort.
1360
+ * Called automatically by the turn driver on normal exit, throw, or abort.
690
1361
  */
691
1362
  cleanup() {
692
1363
  this.logger.debug("TurnExecutor cleanup triggered");
693
1364
  if (!this.stepAbortController.signal.aborted) {
694
1365
  this.stepAbortController.abort();
695
1366
  }
696
- void this.messageQueue.clear().catch((error) => {
1367
+ void this.steerQueue.clear().catch((error) => {
697
1368
  this.logger.warn(
698
- `Failed to clear queued follow-up messages during cleanup: ${error instanceof Error ? error.message : String(error)}`
1369
+ `Failed to clear queued steer messages during cleanup: ${error instanceof Error ? error.message : String(error)}`
699
1370
  );
700
1371
  });
701
1372
  }
@@ -909,5 +1580,8 @@ class TurnExecutor {
909
1580
  }
910
1581
  }
911
1582
  export {
912
- TurnExecutor
1583
+ ModelStepResultStateSchema,
1584
+ TurnDriverStateSchema,
1585
+ TurnExecutor,
1586
+ parseTurnDriverState
913
1587
  };