zidane 7.2.5 → 8.0.4

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 (376) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +34 -6
  3. package/dist/{acp-D-tVyUjw.js → acp-DQDhi2dj.js} +230 -77
  4. package/dist/acp-DQDhi2dj.js.map +1 -0
  5. package/dist/acp-cli.d.ts +1 -1
  6. package/dist/acp-cli.js +9 -66
  7. package/dist/acp-cli.js.map +1 -1
  8. package/dist/acp.d.ts +10 -590
  9. package/dist/acp.d.ts.map +1 -1
  10. package/dist/acp.js +3 -3
  11. package/dist/{agent-D0zZnGbt.js → agent-DSLNmBp0.js} +14401 -13214
  12. package/dist/agent-DSLNmBp0.js.map +1 -0
  13. package/dist/agent.d.ts +1 -1
  14. package/dist/agent.js +3 -2
  15. package/dist/aliasing-lVFbm81n.js +217 -0
  16. package/dist/aliasing-lVFbm81n.js.map +1 -0
  17. package/dist/{anthropic-C2aole0G.js → anthropic-CD00LhUP.js} +1442 -1264
  18. package/dist/anthropic-CD00LhUP.js.map +1 -0
  19. package/dist/artifacts-CV2hUKnL.js.map +1 -1
  20. package/dist/{atomic-write-B7zr1ddF.js → atomic-write-Ijgf2Mhc.js} +13 -3
  21. package/dist/atomic-write-Ijgf2Mhc.js.map +1 -0
  22. package/dist/call-tool-dHlbGOIY.js +70 -0
  23. package/dist/call-tool-dHlbGOIY.js.map +1 -0
  24. package/dist/chat/pure.d.ts +372 -6
  25. package/dist/chat/pure.d.ts.map +1 -1
  26. package/dist/chat/pure.js +35 -244
  27. package/dist/chat/pure.js.map +1 -1
  28. package/dist/{approvals-DKaJZYlm.js → chat-JPJJ8uu5.js} +15879 -14631
  29. package/dist/chat-JPJJ8uu5.js.map +1 -0
  30. package/dist/chat.d.ts +4 -6
  31. package/dist/chat.js +23 -12
  32. package/dist/cli-shared-C-YCaglL.js +159 -0
  33. package/dist/cli-shared-C-YCaglL.js.map +1 -0
  34. package/dist/client-core-BQSyDALT.d.ts +2115 -0
  35. package/dist/client-core-BQSyDALT.d.ts.map +1 -0
  36. package/dist/codemode-worker.d.ts +1 -0
  37. package/dist/codemode-worker.js +155 -0
  38. package/dist/codemode-worker.js.map +1 -0
  39. package/dist/codemode.d.ts +352 -0
  40. package/dist/codemode.d.ts.map +1 -0
  41. package/dist/codemode.js +5 -0
  42. package/dist/connection-Dr-Js4yZ.d.ts +28 -0
  43. package/dist/connection-Dr-Js4yZ.d.ts.map +1 -0
  44. package/dist/connection-loop-gdh22LTI.js +112 -0
  45. package/dist/connection-loop-gdh22LTI.js.map +1 -0
  46. package/dist/context-segments-BHKlagL6.js +1016 -0
  47. package/dist/context-segments-BHKlagL6.js.map +1 -0
  48. package/dist/{context-transport-T_6AYIvy.js → context-transport-DSMTUsK1.js} +3 -3
  49. package/dist/{context-transport-T_6AYIvy.js.map → context-transport-DSMTUsK1.js.map} +1 -1
  50. package/dist/contexts/daytona.d.ts +19 -8
  51. package/dist/contexts/daytona.d.ts.map +1 -1
  52. package/dist/contexts/daytona.js +1 -440
  53. package/dist/contexts/docker.d.ts +36 -7
  54. package/dist/contexts/docker.d.ts.map +1 -1
  55. package/dist/contexts/docker.js +1 -456
  56. package/dist/contexts/e2b.d.ts +68 -13
  57. package/dist/contexts/e2b.d.ts.map +1 -1
  58. package/dist/contexts/e2b.js +1 -382
  59. package/dist/contexts/sandbox.d.ts +1 -1
  60. package/dist/contexts/sandbox.js +5 -0
  61. package/dist/contexts/sandbox.js.map +1 -1
  62. package/dist/{contexts-CRE9pw07.js → contexts-d7UolYot.js} +1059 -524
  63. package/dist/contexts-d7UolYot.js.map +1 -0
  64. package/dist/contexts.d.ts +3 -3
  65. package/dist/contexts.js +1 -1
  66. package/dist/cred-keys-GpBg71cP.js +105 -0
  67. package/dist/cred-keys-GpBg71cP.js.map +1 -0
  68. package/dist/{auth-BG2rVKSt.js → credentials-JttEuRON.js} +55 -206
  69. package/dist/credentials-JttEuRON.js.map +1 -0
  70. package/dist/{cursor-iojRXHF9.js → cursor-CdjaQTBW.js} +3 -3
  71. package/dist/{cursor-iojRXHF9.js.map → cursor-CdjaQTBW.js.map} +1 -1
  72. package/dist/daemon-cli.d.ts +1 -1
  73. package/dist/daemon-cli.js +3 -2
  74. package/dist/daemon-cli.js.map +1 -1
  75. package/dist/daytona-DG3omipZ.js +513 -0
  76. package/dist/daytona-DG3omipZ.js.map +1 -0
  77. package/dist/defaults-Cx3zvDOV.js +23 -0
  78. package/dist/defaults-Cx3zvDOV.js.map +1 -0
  79. package/dist/dispatcher-BMlu2BmZ.js +4941 -0
  80. package/dist/dispatcher-BMlu2BmZ.js.map +1 -0
  81. package/dist/docker-BZhMMJUp.js +727 -0
  82. package/dist/docker-BZhMMJUp.js.map +1 -0
  83. package/dist/e2b-CEVOdRib.js +480 -0
  84. package/dist/e2b-CEVOdRib.js.map +1 -0
  85. package/dist/edit-utils-EGosADZq.js +234 -0
  86. package/dist/edit-utils-EGosADZq.js.map +1 -0
  87. package/dist/environment-8wsKE2Ln.js +214 -0
  88. package/dist/environment-8wsKE2Ln.js.map +1 -0
  89. package/dist/eval-BNcvle_J.js +1595 -0
  90. package/dist/eval-BNcvle_J.js.map +1 -0
  91. package/dist/eval.d.ts +2 -2
  92. package/dist/eval.js +1 -1489
  93. package/dist/executor-Cx5-8yqi.js +621 -0
  94. package/dist/executor-Cx5-8yqi.js.map +1 -0
  95. package/dist/extension-authoring-DyGGmq9V.js +385 -0
  96. package/dist/extension-authoring-DyGGmq9V.js.map +1 -0
  97. package/dist/extensions.d.ts +2 -2
  98. package/dist/extensions.js +3 -3
  99. package/dist/{fetch-url-DX75gpL0.js → fetch-url-Ct2TjDWt.js} +4 -4
  100. package/dist/{fetch-url-DX75gpL0.js.map → fetch-url-Ct2TjDWt.js.map} +1 -1
  101. package/dist/{format-BF745pLL.js → format-C2NQEVUH.js} +39 -2
  102. package/dist/format-C2NQEVUH.js.map +1 -0
  103. package/dist/format-bytes-C7tfc3Zm.js +55 -0
  104. package/dist/format-bytes-C7tfc3Zm.js.map +1 -0
  105. package/dist/headless-C_rNUuYC.js +960 -0
  106. package/dist/headless-C_rNUuYC.js.map +1 -0
  107. package/dist/headless.d.ts +1 -1
  108. package/dist/headless.js +1 -413
  109. package/dist/{history-search-C4bk1Wz_.js → history-search-CcYzF8-0.js} +7 -3
  110. package/dist/history-search-CcYzF8-0.js.map +1 -0
  111. package/dist/history-search-worker.d.ts +1 -1
  112. package/dist/history-search-worker.js +1 -1
  113. package/dist/host-D7NrI03V.js +378 -0
  114. package/dist/host-D7NrI03V.js.map +1 -0
  115. package/dist/host-signals-BcP5QKUD.js +118 -0
  116. package/dist/host-signals-BcP5QKUD.js.map +1 -0
  117. package/dist/identity-CwfO8K-t.js +26 -0
  118. package/dist/identity-CwfO8K-t.js.map +1 -0
  119. package/dist/{index-BgN1T3lk.d.ts → index-BGe1fQT7.d.ts} +10987 -9320
  120. package/dist/index-BGe1fQT7.d.ts.map +1 -0
  121. package/dist/index-BVQsIKGn.d.ts +448 -0
  122. package/dist/index-BVQsIKGn.d.ts.map +1 -0
  123. package/dist/{index-C6NEd5y_.d.ts → index-CHABJd-L.d.ts} +3386 -502
  124. package/dist/index-CHABJd-L.d.ts.map +1 -0
  125. package/dist/{index-C37_ppWv.d.ts → index-D6a7qXpg.d.ts} +2 -3
  126. package/dist/index-D6a7qXpg.d.ts.map +1 -0
  127. package/dist/index.d.ts +6 -6
  128. package/dist/index.js +27 -23
  129. package/dist/{completion-core-BRo86R_L.js → inline-ghost-BVRQeGoL.js} +50 -2
  130. package/dist/inline-ghost-BVRQeGoL.js.map +1 -0
  131. package/dist/ipc/remote.d.ts +313 -0
  132. package/dist/ipc/remote.d.ts.map +1 -0
  133. package/dist/ipc/remote.js +4 -0
  134. package/dist/ipc.d.ts +6 -964
  135. package/dist/ipc.js +403 -4
  136. package/dist/ipc.js.map +1 -0
  137. package/dist/{isolation-Kfoof0MM.d.ts → isolation-D9L650W5.d.ts} +100 -15
  138. package/dist/isolation-D9L650W5.d.ts.map +1 -0
  139. package/dist/json-rpc--HXQti1E.js +350 -0
  140. package/dist/json-rpc--HXQti1E.js.map +1 -0
  141. package/dist/links-j8rED1sR.js +603 -0
  142. package/dist/links-j8rED1sR.js.map +1 -0
  143. package/dist/local-terminal-D8QThwo_.js +252 -0
  144. package/dist/local-terminal-D8QThwo_.js.map +1 -0
  145. package/dist/{logger--C1VQjwJ.js → logger-Gtqlayx8.js} +199 -173
  146. package/dist/logger-Gtqlayx8.js.map +1 -0
  147. package/dist/logs-view-CWG8aUAG.js.map +1 -1
  148. package/dist/{mcp-CgNd-f3F.js → mcp-_wecH9Qe.js} +608 -562
  149. package/dist/mcp-_wecH9Qe.js.map +1 -0
  150. package/dist/mcp.d.ts +2 -2
  151. package/dist/mcp.js +2 -2
  152. package/dist/media-sniff-UKijEaiQ.js.map +1 -1
  153. package/dist/{messages-2jcOA_5R.js → messages-BqiwcD2Q.js} +1017 -1014
  154. package/dist/messages-BqiwcD2Q.js.map +1 -0
  155. package/dist/{oauth-DxHO17JE.js → oauth-Px_pBB9W.js} +5 -5
  156. package/dist/{oauth-DxHO17JE.js.map → oauth-Px_pBB9W.js.map} +1 -1
  157. package/dist/{openai-compat-Dy56weK8.js → openai-compat-CFrpH7uq.js} +432 -589
  158. package/dist/openai-compat-CFrpH7uq.js.map +1 -0
  159. package/dist/orchestration-BCGmB8Ps.js +511 -0
  160. package/dist/orchestration-BCGmB8Ps.js.map +1 -0
  161. package/dist/output/stream-json.d.ts +1 -2
  162. package/dist/output/stream-json.d.ts.map +1 -1
  163. package/dist/output/stream-json.js +1 -1
  164. package/dist/output/terminal.d.ts +1 -2
  165. package/dist/output/terminal.d.ts.map +1 -1
  166. package/dist/output/terminal.js +13 -7
  167. package/dist/output/terminal.js.map +1 -1
  168. package/dist/{plugins-gbI7SBA6.js → plugins-DS7mahzZ.js} +20 -101
  169. package/dist/plugins-DS7mahzZ.js.map +1 -0
  170. package/dist/plugins.d.ts +1 -1
  171. package/dist/plugins.js +1 -2
  172. package/dist/prelude-Cxo4t74B.js +517 -0
  173. package/dist/prelude-Cxo4t74B.js.map +1 -0
  174. package/dist/presets.d.ts +1 -1
  175. package/dist/presets.js +1 -2
  176. package/dist/project-root-B8zADr4o.js +167 -0
  177. package/dist/project-root-B8zADr4o.js.map +1 -0
  178. package/dist/project-user-paths-BSgtrRxl.js +58 -0
  179. package/dist/project-user-paths-BSgtrRxl.js.map +1 -0
  180. package/dist/{prompts-Pqc3JdW_.d.ts → prompts-DYcvqShf.d.ts} +14 -11
  181. package/dist/prompts-DYcvqShf.d.ts.map +1 -0
  182. package/dist/protocol-DnhqqSmE.js +13 -0
  183. package/dist/protocol-DnhqqSmE.js.map +1 -0
  184. package/dist/providers/anthropic.d.ts +2 -2
  185. package/dist/providers/anthropic.js +1 -2
  186. package/dist/providers/arcee.d.ts +1 -1
  187. package/dist/providers/arcee.js +1 -1
  188. package/dist/providers/baseten.d.ts +1 -1
  189. package/dist/providers/baseten.js +1 -1
  190. package/dist/providers/cerebras.d.ts +1 -1
  191. package/dist/providers/cerebras.js +3 -2
  192. package/dist/providers/cerebras.js.map +1 -1
  193. package/dist/providers/local.d.ts +1 -1
  194. package/dist/providers/local.js +1 -1
  195. package/dist/providers/openai-compat.d.ts +1 -1
  196. package/dist/providers/openai-compat.js +1 -2
  197. package/dist/providers/openai.d.ts +1 -1
  198. package/dist/providers/openai.js +15 -12
  199. package/dist/providers/openai.js.map +1 -1
  200. package/dist/providers/openrouter.d.ts +1 -1
  201. package/dist/providers/openrouter.js +3 -2
  202. package/dist/providers/openrouter.js.map +1 -1
  203. package/dist/providers/xai.d.ts +1 -1
  204. package/dist/providers/xai.js +3 -3
  205. package/dist/{providers-BVhnFyiY.js → providers-XUR7F4Hi.js} +4 -4
  206. package/dist/{providers-BVhnFyiY.js.map → providers-XUR7F4Hi.js.map} +1 -1
  207. package/dist/providers.d.ts +1 -1
  208. package/dist/providers.js +4 -4
  209. package/dist/registry-D6ShBWJU.js +5234 -0
  210. package/dist/registry-D6ShBWJU.js.map +1 -0
  211. package/dist/remote-hosts-BtA_9ZGp.js +97 -0
  212. package/dist/remote-hosts-BtA_9ZGp.js.map +1 -0
  213. package/dist/restate.d.ts +2 -3
  214. package/dist/restate.d.ts.map +1 -1
  215. package/dist/restate.js +631 -572
  216. package/dist/restate.js.map +1 -1
  217. package/dist/run-summary-CklLiZ4y.js +288 -0
  218. package/dist/run-summary-CklLiZ4y.js.map +1 -0
  219. package/dist/{sandbox-BH0WQkXn.d.ts → sandbox-C5dR5DwQ.d.ts} +6 -3
  220. package/dist/sandbox-C5dR5DwQ.d.ts.map +1 -0
  221. package/dist/session/sqlite.d.ts +1 -2
  222. package/dist/session/sqlite.d.ts.map +1 -1
  223. package/dist/session/sqlite.js +1 -616
  224. package/dist/session-factory-BUGY5P40.js +1576 -0
  225. package/dist/session-factory-BUGY5P40.js.map +1 -0
  226. package/dist/{session-BqRP1hS7.js → session-xh9JXu6i.js} +94 -52
  227. package/dist/session-xh9JXu6i.js.map +1 -0
  228. package/dist/session.d.ts +1 -1
  229. package/dist/session.js +2 -2
  230. package/dist/settings-keys-Ckf29NeM.js +677 -0
  231. package/dist/settings-keys-Ckf29NeM.js.map +1 -0
  232. package/dist/shell-path-Dqaoow2J.js +412 -0
  233. package/dist/shell-path-Dqaoow2J.js.map +1 -0
  234. package/dist/{skills-BC3dodWp.js → skills-DKqZJm4X.js} +430 -470
  235. package/dist/skills-DKqZJm4X.js.map +1 -0
  236. package/dist/skills.d.ts +2 -2
  237. package/dist/skills.js +1 -2
  238. package/dist/source-mPExaUm8.js +381 -0
  239. package/dist/source-mPExaUm8.js.map +1 -0
  240. package/dist/sqlite-DV1DQzN2.js +698 -0
  241. package/dist/sqlite-DV1DQzN2.js.map +1 -0
  242. package/dist/{src-CkNQKFKr.js → src-BRMYRJib.js} +903 -1121
  243. package/dist/src-BRMYRJib.js.map +1 -0
  244. package/dist/{stdio-DPpBDPx5.js → stdio-C6YyoW3I.js} +4 -4
  245. package/dist/{stdio-DPpBDPx5.js.map → stdio-C6YyoW3I.js.map} +1 -1
  246. package/dist/{stdio-loader-Bbx19dMZ.js → stdio-loader-C830Vg-Z.js} +4 -4
  247. package/dist/{stdio-loader-Bbx19dMZ.js.map → stdio-loader-C830Vg-Z.js.map} +1 -1
  248. package/dist/system-prompt-MNVHatSD.d.ts.map +1 -1
  249. package/dist/timeout-DEaqslLO.d.ts.map +1 -1
  250. package/dist/todo-edits-Dn251YUP.js +1790 -0
  251. package/dist/todo-edits-Dn251YUP.js.map +1 -0
  252. package/dist/{turn-operations-DrbJlpq9.js → tool-formatters-IQFDrdrs.js} +1456 -2120
  253. package/dist/tool-formatters-IQFDrdrs.js.map +1 -0
  254. package/dist/tool-state-Dku6YqAB.js +989 -0
  255. package/dist/tool-state-Dku6YqAB.js.map +1 -0
  256. package/dist/tools/fetch-url.d.ts +1 -2
  257. package/dist/tools/fetch-url.d.ts.map +1 -1
  258. package/dist/tools/fetch-url.js +1 -2
  259. package/dist/tools/prompts.d.ts +1 -1
  260. package/dist/tools/prompts.js +7 -7
  261. package/dist/tools/prompts.js.map +1 -1
  262. package/dist/tools/web-search.d.ts +1 -2
  263. package/dist/tools/web-search.d.ts.map +1 -1
  264. package/dist/tools/web-search.js +2 -2
  265. package/dist/tools/web-search.js.map +1 -1
  266. package/dist/tools-_DnT3AGM.js +578 -0
  267. package/dist/tools-_DnT3AGM.js.map +1 -0
  268. package/dist/tools.d.ts +3 -3
  269. package/dist/tools.js +4 -2
  270. package/dist/tui.d.ts +534 -517
  271. package/dist/tui.d.ts.map +1 -1
  272. package/dist/tui.js +34933 -27243
  273. package/dist/tui.js.map +1 -1
  274. package/dist/turn-operations-B8sokwi5.js +333 -0
  275. package/dist/turn-operations-B8sokwi5.js.map +1 -0
  276. package/dist/turn-operations-DQX5ZZni.d.ts +3089 -0
  277. package/dist/turn-operations-DQX5ZZni.d.ts.map +1 -0
  278. package/dist/types-C7ZFOztE.d.ts +132 -0
  279. package/dist/types-C7ZFOztE.d.ts.map +1 -0
  280. package/dist/types-CH5XpIHw.js +114 -0
  281. package/dist/types-CH5XpIHw.js.map +1 -0
  282. package/dist/{types-CWgENVLY.js → types-Cu0ZGDu9.js} +10 -6
  283. package/dist/types-Cu0ZGDu9.js.map +1 -0
  284. package/dist/types-IqegbJEE.d.ts +624 -0
  285. package/dist/types-IqegbJEE.d.ts.map +1 -0
  286. package/dist/types.d.ts +4 -4
  287. package/dist/types.js +1 -1
  288. package/dist/url-D8HCl65b.js +1259 -0
  289. package/dist/url-D8HCl65b.js.map +1 -0
  290. package/dist/wasm-BVT-j5cl.js +33 -0
  291. package/dist/wasm-BVT-j5cl.js.map +1 -0
  292. package/dist/workspace-exec-stream-SV2R9d5S.js +355 -0
  293. package/dist/workspace-exec-stream-SV2R9d5S.js.map +1 -0
  294. package/dist/ws-CIHMvlSh.js +952 -0
  295. package/dist/ws-CIHMvlSh.js.map +1 -0
  296. package/dist/ws-client-N7NxzvQp.js +230 -0
  297. package/dist/ws-client-N7NxzvQp.js.map +1 -0
  298. package/dist/{xai-CazjStOK.js → xai-CvJTeLrI.js} +165 -5
  299. package/dist/xai-CvJTeLrI.js.map +1 -0
  300. package/dist/xdg-zweed0-t.js +117 -0
  301. package/dist/xdg-zweed0-t.js.map +1 -0
  302. package/docs/ACP.md +52 -0
  303. package/docs/ARCHITECTURE.md +103 -6
  304. package/docs/ARTIFACTS.md +8 -4
  305. package/docs/CHAT.md +165 -14
  306. package/docs/EXECUTION_CONTEXT.md +8 -0
  307. package/docs/EXTENSIONS.md +123 -2
  308. package/docs/HEADLESS.md +2 -0
  309. package/docs/IPC.md +775 -64
  310. package/docs/MACHINES.md +456 -0
  311. package/docs/PANELS.md +3 -0
  312. package/docs/README.md +4 -0
  313. package/docs/RESTATE.md +3 -2
  314. package/docs/RUN_IN_BACKGROUND.md +10 -2
  315. package/docs/SERVER.md +1085 -0
  316. package/docs/SKILL.md +6 -1
  317. package/docs/TERMINAL.md +75 -0
  318. package/docs/TUI.md +65 -14
  319. package/package.json +58 -26
  320. package/scripts/eval.ts +4 -0
  321. package/dist/acp-D-tVyUjw.js.map +0 -1
  322. package/dist/agent-D0zZnGbt.js.map +0 -1
  323. package/dist/anthropic-C2aole0G.js.map +0 -1
  324. package/dist/approvals-DKaJZYlm.js.map +0 -1
  325. package/dist/atomic-write-B7zr1ddF.js.map +0 -1
  326. package/dist/auth-BG2rVKSt.js.map +0 -1
  327. package/dist/completion-core-BRo86R_L.js.map +0 -1
  328. package/dist/contexts/daytona.js.map +0 -1
  329. package/dist/contexts/docker.js.map +0 -1
  330. package/dist/contexts/e2b.js.map +0 -1
  331. package/dist/contexts-CRE9pw07.js.map +0 -1
  332. package/dist/eval.js.map +0 -1
  333. package/dist/format-BF745pLL.js.map +0 -1
  334. package/dist/glob-DluQFSw1.js +0 -270
  335. package/dist/glob-DluQFSw1.js.map +0 -1
  336. package/dist/headless.js.map +0 -1
  337. package/dist/history-search-C4bk1Wz_.js.map +0 -1
  338. package/dist/index-BgN1T3lk.d.ts.map +0 -1
  339. package/dist/index-C37_ppWv.d.ts.map +0 -1
  340. package/dist/index-C6NEd5y_.d.ts.map +0 -1
  341. package/dist/ipc-BKVIIOqH.js +0 -331
  342. package/dist/ipc-BKVIIOqH.js.map +0 -1
  343. package/dist/ipc.d.ts.map +0 -1
  344. package/dist/isolation-Kfoof0MM.d.ts.map +0 -1
  345. package/dist/json-rpc-rSWMUh9b.js +0 -192
  346. package/dist/json-rpc-rSWMUh9b.js.map +0 -1
  347. package/dist/logger--C1VQjwJ.js.map +0 -1
  348. package/dist/mcp-CgNd-f3F.js.map +0 -1
  349. package/dist/messages-2jcOA_5R.js.map +0 -1
  350. package/dist/openai-compat-Dy56weK8.js.map +0 -1
  351. package/dist/output-cap-C9zukcCj.js +0 -100
  352. package/dist/output-cap-C9zukcCj.js.map +0 -1
  353. package/dist/panels-B6gRk4bf.js +0 -789
  354. package/dist/panels-B6gRk4bf.js.map +0 -1
  355. package/dist/plugins-gbI7SBA6.js.map +0 -1
  356. package/dist/prompts-Pqc3JdW_.d.ts.map +0 -1
  357. package/dist/run-summary-BU_NgwUT.js +0 -269
  358. package/dist/run-summary-BU_NgwUT.js.map +0 -1
  359. package/dist/sandbox-BH0WQkXn.d.ts.map +0 -1
  360. package/dist/session/sqlite.js.map +0 -1
  361. package/dist/session-BqRP1hS7.js.map +0 -1
  362. package/dist/shell-path-DfdXrGg9.js +0 -1549
  363. package/dist/shell-path-DfdXrGg9.js.map +0 -1
  364. package/dist/skills-BC3dodWp.js.map +0 -1
  365. package/dist/src-CkNQKFKr.js.map +0 -1
  366. package/dist/todo-edits-UOwgxGKu.js +0 -528
  367. package/dist/todo-edits-UOwgxGKu.js.map +0 -1
  368. package/dist/tool-formatters-DoRLnfuD.d.ts +0 -759
  369. package/dist/tool-formatters-DoRLnfuD.d.ts.map +0 -1
  370. package/dist/transcript-anchors-BeudMbXx.d.ts +0 -1762
  371. package/dist/transcript-anchors-BeudMbXx.d.ts.map +0 -1
  372. package/dist/turn-operations-C8bMBDl_.d.ts +0 -1258
  373. package/dist/turn-operations-C8bMBDl_.d.ts.map +0 -1
  374. package/dist/turn-operations-DrbJlpq9.js.map +0 -1
  375. package/dist/types-CWgENVLY.js.map +0 -1
  376. package/dist/xai-CazjStOK.js.map +0 -1
@@ -1,224 +1,11 @@
1
- import { a as documentBlockMarker, r as assertResolvedMediaBlock } from "./types-CWgENVLY.js";
2
- import { n as estimateTokens } from "./utils-ngQzYzZD.js";
3
1
  import { f as isRetryableHttpStatus, h as matchesToolPairingError, l as classifyErrorPrelude, m as matchesContextExceeded } from "./errors-DKiMrOKq.js";
2
+ import { a as documentBlockMarker, r as assertResolvedMediaBlock } from "./types-Cu0ZGDu9.js";
4
3
  import { t as audioFormatFromMediaType } from "./media-sniff-UKijEaiQ.js";
4
+ import { a as rewriteMessagesToWire, n as buildAliasMaps, o as toCanonicalName, r as buildSanitizedWireAliases, s as toWireName } from "./aliasing-lVFbm81n.js";
5
+ import { n as estimateTokens } from "./utils-ngQzYzZD.js";
5
6
  import { renderSystemForWire, splitSystemPrompt } from "./prompt.js";
6
7
  import { Buffer } from "node:buffer";
7
8
  import { createHash } from "node:crypto";
8
- //#region src/hash.ts
9
- /**
10
- * FNV-1a (32-bit) rendered in base36 — a tiny, dependency-free, deterministic
11
- * hash.
12
- *
13
- * Used to disambiguate sanitized identifiers: distinct inputs that would
14
- * otherwise collapse to the same sanitized string (e.g. `a.b` and `a/b` both
15
- * → `a_b`, or two over-long names truncated to the same prefix) keep a stable,
16
- * unique suffix. Determinism matters because the suffix must be identical
17
- * across runs and across a `tool_use` / `tool_result` pair derived from the
18
- * same original value.
19
- */
20
- function fnv1aBase36(value) {
21
- let hash = 2166136261;
22
- for (let i = 0; i < value.length; i++) {
23
- hash ^= value.charCodeAt(i);
24
- hash = Math.imul(hash, 16777619);
25
- }
26
- return (hash >>> 0).toString(36);
27
- }
28
- //#endregion
29
- //#region src/aliasing.ts
30
- /**
31
- * Build alias lookup maps from a `toolAliases` record.
32
- *
33
- * Validates:
34
- * - No two canonical names map to the same alias (collision).
35
- * - No alias collides with another canonical tool name (would shadow).
36
- *
37
- * Silently ignores alias entries whose canonical name isn't in `canonicalNames` —
38
- * preset/agent authors can declare aliases for tools that may be added later via MCP.
39
- *
40
- * @param aliases - The `toolAliases` map from the agent options.
41
- * @param canonicalNames - All tool canonical names currently in scope (agent + MCP).
42
- */
43
- function buildAliasMaps(aliases, canonicalNames) {
44
- const aliasByCanonical = /* @__PURE__ */ new Map();
45
- const canonicalByAlias = /* @__PURE__ */ new Map();
46
- if (!aliases) return {
47
- aliasByCanonical,
48
- canonicalByAlias
49
- };
50
- const canonicalSet = new Set(canonicalNames);
51
- function isRemappedAway(canonical) {
52
- const mapped = aliases[canonical];
53
- return typeof mapped === "string" && mapped.length > 0 && mapped !== canonical;
54
- }
55
- for (const [canonical, alias] of Object.entries(aliases)) {
56
- if (typeof alias !== "string" || alias.length === 0) throw new Error(`Tool alias for "${canonical}" must be a non-empty string`);
57
- if (alias === canonical) continue;
58
- if (!canonicalSet.has(canonical)) continue;
59
- if (canonicalSet.has(alias) && !isRemappedAway(alias)) throw new Error(`Tool alias "${canonical}" -> "${alias}" collides with an existing canonical tool name`);
60
- const existingCanonical = canonicalByAlias.get(alias);
61
- if (existingCanonical && existingCanonical !== canonical) throw new Error(`Tool alias collision: both "${existingCanonical}" and "${canonical}" map to alias "${alias}"`);
62
- aliasByCanonical.set(canonical, alias);
63
- canonicalByAlias.set(alias, canonical);
64
- }
65
- return {
66
- aliasByCanonical,
67
- canonicalByAlias
68
- };
69
- }
70
- /** Return the alias for a canonical name, falling back to the canonical name itself. */
71
- function toWireName(canonical, maps) {
72
- return maps.aliasByCanonical.get(canonical) ?? canonical;
73
- }
74
- /** Return the canonical name for a wire name, falling back to the wire name itself. */
75
- function toCanonicalName(wire, maps) {
76
- return maps.canonicalByAlias.get(wire) ?? wire;
77
- }
78
- /**
79
- * Tool names must match `^[a-zA-Z0-9_-]{1,N}$`. The charset is universal; the
80
- * length cap is taken as the STRICTEST across providers (OpenAI/-compat: 64;
81
- * Anthropic allows 128) so a sanitized name is valid on EVERY provider — and so
82
- * a mid-session model switch can never make the provider-level drop guard
83
- * (`sanitizeToolSpecs`) discard a tool we could have kept.
84
- *
85
- * MCP tool names are minted verbatim as `mcp_<server>_<tool>` (see
86
- * `connectMcpServers`), so a server configured as `SSH Ipseity` yields
87
- * `mcp_SSH Ipseity_exec` — the space (and `.`/`:`/`/`, unicode, or a >64-char
88
- * join) 400s the request the instant that tool lands in the `tools` array:
89
- * `tools.N.custom.name: String should match pattern ...`.
90
- */
91
- const WIRE_NAME_MAX = 64;
92
- const WIRE_NAME_OK = /^[\w-]{1,64}$/;
93
- const WIRE_NAME_BAD_CHAR = /[^\w-]/g;
94
- /**
95
- * Build OUTBOUND wire aliases that coerce any tool name violating the provider
96
- * name constraint into a valid one. Only offenders get an entry; clean setups
97
- * return `undefined` (no alias map churn, prompt cache untouched).
98
- *
99
- * Returned as a `Record` so it merges into `effectiveToolAliases` upstream of
100
- * BOTH wire-name computations — the `tool_search` catalog and the `tools` array
101
- * — keeping them in lockstep. Canonical names (dispatch, hooks, persisted
102
- * turns) never change; only the bytes the model sees do.
103
- *
104
- * Scoped to MCP names (the only third-party-controlled, thus only realistically
105
- * invalid, source). The hash suffix keeps distinct originals distinct even when
106
- * they collapse to the same replacement; `taken` guards the residual collision.
107
- */
108
- function buildSanitizedWireAliases(names, existing) {
109
- const wireOf = (name) => {
110
- const alias = existing?.[name];
111
- return typeof alias === "string" && alias.length > 0 ? alias : name;
112
- };
113
- const taken = /* @__PURE__ */ new Set();
114
- const offenders = [];
115
- for (const name of names) {
116
- const wire = wireOf(name);
117
- if (WIRE_NAME_OK.test(wire)) taken.add(wire);
118
- else offenders.push(name);
119
- }
120
- if (offenders.length === 0) return void 0;
121
- const out = {};
122
- for (const name of offenders) {
123
- const sanitized = sanitizeWireName(wireOf(name), taken);
124
- out[name] = sanitized;
125
- taken.add(sanitized);
126
- }
127
- return out;
128
- }
129
- function sanitizeWireName(name, taken) {
130
- let base = name.replace(WIRE_NAME_BAD_CHAR, "_");
131
- if (base.length === 0) base = "tool";
132
- const hash = fnv1aBase36(name);
133
- const withSuffix = (suffix) => `${base.slice(0, Math.max(1, WIRE_NAME_MAX - suffix.length))}${suffix}`;
134
- let candidate = withSuffix(`_${hash}`);
135
- for (let n = 1; taken.has(candidate); n++) candidate = withSuffix(`_${hash}_${n}`);
136
- return candidate;
137
- }
138
- /**
139
- * Augment {@link AliasMaps} with INBOUND-ONLY aliases for the Claude Code
140
- * `mcp__server__tool` double-underscore naming convention. For every MCP
141
- * tool registered with the canonical `mcp_<server>_<tool>` form, add a
142
- * `canonicalByAlias` entry mapping the double-underscore variant to the
143
- * same canonical name. Outbound (`aliasByCanonical`) is left untouched —
144
- * the model still sees the single-underscore canonical on the wire, so
145
- * the tools-array byte count (and the provider prompt cache) is
146
- * unaffected.
147
- *
148
- * Why: SDK consumers and tool descriptions across the ecosystem
149
- * inconsistently reference one form or the other (Anthropic's docs use
150
- * double, zidane uses single). A Claude-Code-trained model emitting
151
- * `mcp__acme__apply_migration` against a server zidane registered as
152
- * `mcp_acme_apply_migration` would otherwise trip the `tool:unknown`
153
- * path and waste a turn on the correction.
154
- *
155
- * Idempotent: a canonical that already has a double-underscore alias
156
- * mapped (host's explicit `toolAliases` got there first) is left alone.
157
- * Tools whose canonical name DOESN'T start with `mcp_` (or that contain
158
- * no inner separator) are skipped — we don't want to invent aliases for
159
- * non-MCP tools or malformed names.
160
- *
161
- * Mutates `maps.canonicalByAlias` in place and returns the same object
162
- * for chaining.
163
- */
164
- function augmentMcpDoubleUnderscoreAliases(maps, canonicalNames) {
165
- for (const canonical of canonicalNames) {
166
- if (!canonical.startsWith("mcp_")) continue;
167
- const tail = canonical.slice(4);
168
- const sep = tail.indexOf("_");
169
- if (sep <= 0 || sep >= tail.length - 1) continue;
170
- const doubleForm = `mcp__${tail.slice(0, sep)}__${tail.slice(sep + 1)}`;
171
- if (doubleForm === canonical) continue;
172
- if (maps.canonicalByAlias.has(doubleForm)) continue;
173
- maps.canonicalByAlias.set(doubleForm, canonical);
174
- }
175
- return maps;
176
- }
177
- /**
178
- * Rewrite `tool_call` block names in a content array from canonical → wire for outbound
179
- * messages sent to the provider. Mutation is non-destructive (returns a new array).
180
- */
181
- function rewriteContentToWire(content, maps) {
182
- if (maps.aliasByCanonical.size === 0) return content;
183
- return content.map((block) => {
184
- if (block.type !== "tool_call") return block;
185
- const wire = maps.aliasByCanonical.get(block.name);
186
- if (!wire || wire === block.name) return block;
187
- return {
188
- ...block,
189
- name: wire
190
- };
191
- });
192
- }
193
- /**
194
- * Rewrite `tool_call` block names in a content array from wire → canonical for inbound
195
- * messages received from the provider. Non-destructive.
196
- */
197
- function rewriteContentToCanonical(content, maps) {
198
- if (maps.canonicalByAlias.size === 0) return content;
199
- return content.map((block) => {
200
- if (block.type !== "tool_call") return block;
201
- const canonical = maps.canonicalByAlias.get(block.name);
202
- if (!canonical || canonical === block.name) return block;
203
- return {
204
- ...block,
205
- name: canonical
206
- };
207
- });
208
- }
209
- /**
210
- * Rewrite every `SessionMessage.content` in an array from canonical → wire.
211
- * Returns a new array of new message objects — input messages are not mutated.
212
- * When the alias map is empty, returns the input by reference (no allocation).
213
- */
214
- function rewriteMessagesToWire(messages, maps) {
215
- if (maps.aliasByCanonical.size === 0) return messages;
216
- return messages.map((msg) => ({
217
- ...msg,
218
- content: rewriteContentToWire(msg.content, maps)
219
- }));
220
- }
221
- //#endregion
222
9
  //#region src/prompt.ts
223
10
  /**
224
11
  * Coerce the run-level prompt into a `PromptPart[]`.
@@ -656,6 +443,388 @@ async function fillEstimatedCost(usage, provider, multiplier, catalog) {
656
443
  };
657
444
  }
658
445
  //#endregion
446
+ //#region src/providers/tool-args.ts
447
+ /**
448
+ * Parse a tool-call arguments payload, repairing truncation and trailing
449
+ * garbage when strict parsing fails. Returns `undefined` when no bounded
450
+ * repair produces valid JSON.
451
+ */
452
+ function parseToolCallArguments(raw) {
453
+ try {
454
+ const parsed = JSON.parse(raw);
455
+ if (typeof parsed === "object" && parsed !== null && !Array.isArray(parsed)) return {
456
+ input: parsed,
457
+ repaired: false
458
+ };
459
+ } catch {}
460
+ const escaped = createToolJsonEscaper()(0, raw);
461
+ for (const { candidate, fabricated } of repairCandidates(escaped)) try {
462
+ const parsed = JSON.parse(candidate);
463
+ if (typeof parsed === "object" && parsed !== null && !Array.isArray(parsed)) {
464
+ if (fabricated && Object.keys(parsed).length === 0) continue;
465
+ return {
466
+ input: parsed,
467
+ repaired: true
468
+ };
469
+ }
470
+ } catch {}
471
+ }
472
+ const NAMED_ESCAPES = {
473
+ "\n": "\\n",
474
+ "\r": "\\r",
475
+ " ": "\\t",
476
+ "\b": "\\b",
477
+ "\f": "\\f"
478
+ };
479
+ function escapeControl(char) {
480
+ return NAMED_ESCAPES[char] ?? `\\u${char.charCodeAt(0).toString(16).padStart(4, "0")}`;
481
+ }
482
+ /**
483
+ * Escapes control characters inside JSON string literals, one content block
484
+ * at a time. A block's string state (inside a string, after a backslash)
485
+ * carries over from one delta to the next.
486
+ */
487
+ function createToolJsonEscaper() {
488
+ const states = /* @__PURE__ */ new Map();
489
+ return (index, partial) => {
490
+ const state = states.get(index) ?? {
491
+ inString: false,
492
+ escaped: false
493
+ };
494
+ states.set(index, state);
495
+ let out = "";
496
+ for (const char of partial) {
497
+ if (!state.inString) {
498
+ if (char === "\"") state.inString = true;
499
+ out += char;
500
+ continue;
501
+ }
502
+ if (state.escaped) {
503
+ state.escaped = false;
504
+ out += char;
505
+ } else if (char === "\\") {
506
+ state.escaped = true;
507
+ out += char;
508
+ } else if (char === "\"") {
509
+ state.inString = false;
510
+ out += char;
511
+ } else out += char < " " ? escapeControl(char) : char;
512
+ }
513
+ return out;
514
+ };
515
+ }
516
+ /**
517
+ * Bounded, ordered repair candidates:
518
+ * 1. longest complete top-level object prefix (trailing-garbage case)
519
+ * 2. payload + structural closers (truncated mid-string / mid-object)
520
+ * 3. payload minus a dangling partial token, + closers (truncated mid-token)
521
+ *
522
+ * `fabricated` marks candidates whose closure was invented here (2 and 3) —
523
+ * the caller holds those to a stricter acceptance bar than a prefix that was
524
+ * complete in the payload itself.
525
+ */
526
+ function* repairCandidates(raw) {
527
+ const text = raw.trim();
528
+ if (!text.startsWith("{")) return;
529
+ const scan = scanJson(text);
530
+ if (scan.completeAt !== void 0) yield {
531
+ candidate: text.slice(0, scan.completeAt),
532
+ fabricated: false
533
+ };
534
+ yield {
535
+ candidate: close(text, scan),
536
+ fabricated: true
537
+ };
538
+ let trimmed = text;
539
+ for (let step = 0; step < 6; step++) {
540
+ const next = (scanJson(trimmed).inString ? trimmed.replace(/"(?:[^"\\]|\\.)*$/, "") : trimmed.replace(/(?:"(?:[^"\\]|\\.)*"|[^\s{}[\],:"]+|[,:])\s*$/, "")).trimEnd();
541
+ if (next === trimmed || !next.startsWith("{")) break;
542
+ trimmed = next;
543
+ yield {
544
+ candidate: close(trimmed, scanJson(trimmed)),
545
+ fabricated: true
546
+ };
547
+ }
548
+ }
549
+ function scanJson(text) {
550
+ const stack = [];
551
+ let inString = false;
552
+ let escaped = false;
553
+ let completeAt;
554
+ for (let i = 0; i < text.length; i++) {
555
+ const ch = text[i];
556
+ if (inString) {
557
+ if (escaped) escaped = false;
558
+ else if (ch === "\\") escaped = true;
559
+ else if (ch === "\"") inString = false;
560
+ continue;
561
+ }
562
+ if (ch === "\"") inString = true;
563
+ else if (ch === "{") stack.push("}");
564
+ else if (ch === "[") stack.push("]");
565
+ else if (ch === "}" || ch === "]") {
566
+ stack.pop();
567
+ if (stack.length === 0 && completeAt === void 0) completeAt = i + 1;
568
+ }
569
+ }
570
+ return {
571
+ stack,
572
+ inString,
573
+ completeAt
574
+ };
575
+ }
576
+ function close(text, scan) {
577
+ let out = text;
578
+ if (scan.inString) {
579
+ if (/(?:^|[^\\])(?:\\\\)*\\$/.test(out)) out = out.slice(0, -1);
580
+ out += "\"";
581
+ }
582
+ for (let i = scan.stack.length - 1; i >= 0; i--) out += scan.stack[i];
583
+ return out;
584
+ }
585
+ //#endregion
586
+ //#region src/providers/openai-compat-stream.ts
587
+ /**
588
+ * Ceiling on how many UTF-16 code units may accumulate between two newline
589
+ * boundaries when parsing an SSE stream. A broken or malicious server that
590
+ * emits an unbounded stream of non-newline bytes would otherwise grow `buffer`
591
+ * without end and eventually OOM the host. Measured in JS string length (UTF-16
592
+ * units, 8M units ≈ 8–24 MB of UTF-8 input) rather than bytes — close enough
593
+ * for a pathological-stream tripwire without paying `Buffer.byteLength` on
594
+ * every chunk. Safely above the largest tool-call arg JSON we reasonably
595
+ * expect.
596
+ */
597
+ const SSE_MAX_BUFFER_LENGTH = 8388608;
598
+ var OpenAICompatStreamError = class extends Error {
599
+ constructor(message) {
600
+ super(message);
601
+ this.name = "OpenAICompatStreamError";
602
+ }
603
+ };
604
+ /**
605
+ * Flatten a chunk-list `content` delta into ordered text runs tagged as
606
+ * reasoning or answer text. Mistral's shape is
607
+ * `[{ type: 'thinking', thinking: [{ type: 'text', text }] }]` for reasoning
608
+ * and `[{ type: 'text', text }]` for plain text; anything unrecognized is
609
+ * skipped rather than string-coerced into the output.
610
+ */
611
+ function flattenContentChunks(parts) {
612
+ const out = [];
613
+ for (const part of parts) {
614
+ if (typeof part === "string") {
615
+ if (part) out.push({
616
+ kind: "text",
617
+ text: part
618
+ });
619
+ continue;
620
+ }
621
+ if (!part || typeof part !== "object") continue;
622
+ const record = part;
623
+ if (record.type === "thinking") {
624
+ const inner = Array.isArray(record.thinking) ? record.thinking : [];
625
+ for (const run of flattenContentChunks(inner)) out.push({
626
+ kind: "thinking",
627
+ text: run.text
628
+ });
629
+ continue;
630
+ }
631
+ if (typeof record.text === "string" && record.text) out.push({
632
+ kind: "text",
633
+ text: record.text
634
+ });
635
+ }
636
+ return out;
637
+ }
638
+ /**
639
+ * Provider-reported USD for the request, or `undefined` when the gateway
640
+ * didn't price it. OpenRouter's field is `usage.cost` — the authoritative
641
+ * figure (it knows which upstream it routed to; a local rate table doesn't).
642
+ * On BYOK requests `cost` is only OpenRouter's fee and the upstream bill lands
643
+ * on the user's own provider account, so real spend is the sum with
644
+ * `cost_details.upstream_inference_cost`; on non-BYOK that detail merely
645
+ * mirrors `cost` and must NOT be added. `total_cost` is kept as a fallback
646
+ * for gateways that use that name.
647
+ */
648
+ function reportedCost(usage) {
649
+ const base = usage.cost ?? usage.total_cost;
650
+ if (typeof base !== "number") return void 0;
651
+ const upstream = usage.cost_details?.upstream_inference_cost;
652
+ return usage.is_byok && typeof upstream === "number" ? base + upstream : base;
653
+ }
654
+ function usageFromChunk(chunk) {
655
+ const chunkUsage = chunk.usage;
656
+ if (chunkUsage) {
657
+ const cachedRead = chunkUsage.prompt_tokens_details?.cached_tokens;
658
+ const detailsWrite = chunkUsage.prompt_tokens_details?.cache_creation_input_tokens ?? chunkUsage.prompt_tokens_details?.cache_write_tokens;
659
+ const cachedWrite = detailsWrite ?? chunkUsage.cache_creation_input_tokens;
660
+ const includedInPrompt = (cachedRead ?? 0) + (detailsWrite ?? 0);
661
+ return {
662
+ input: Math.max(0, (chunkUsage.prompt_tokens ?? 0) - includedInPrompt),
663
+ output: chunkUsage.completion_tokens ?? 0,
664
+ cost: reportedCost(chunkUsage),
665
+ ...typeof cachedRead === "number" && cachedRead > 0 ? { cacheRead: cachedRead } : {},
666
+ ...typeof cachedWrite === "number" && cachedWrite > 0 ? { cacheCreation: cachedWrite } : {}
667
+ };
668
+ }
669
+ const promptEvalCount = chunk.prompt_eval_count;
670
+ const evalCount = chunk.eval_count;
671
+ if (typeof promptEvalCount === "number" || typeof evalCount === "number") return {
672
+ input: typeof promptEvalCount === "number" ? promptEvalCount : 0,
673
+ output: typeof evalCount === "number" ? evalCount : 0
674
+ };
675
+ return null;
676
+ }
677
+ async function consumeSSE(response, callbacks, signal) {
678
+ if (!response.body) throw new OpenAICompatStreamError(`The stream came back empty (status ${response.status} ${response.statusText}).`);
679
+ const reader = response.body.getReader();
680
+ const decoder = new TextDecoder();
681
+ let buffer = "";
682
+ let text = "";
683
+ let thinking = "";
684
+ let finishReason = "stop";
685
+ let sawTerminator = false;
686
+ let usage = {
687
+ input: 0,
688
+ output: 0
689
+ };
690
+ const tcMap = /* @__PURE__ */ new Map();
691
+ const idNonce = Math.random().toString(36).slice(2, 10);
692
+ const reasoningMap = /* @__PURE__ */ new Map();
693
+ let sawReasoningDetails = false;
694
+ try {
695
+ while (true) {
696
+ if (signal?.aborted) throw new DOMException("The operation was aborted.", "AbortError");
697
+ const { done, value } = await reader.read();
698
+ if (done) break;
699
+ buffer += decoder.decode(value, { stream: true });
700
+ if (buffer.length > SSE_MAX_BUFFER_LENGTH) throw new OpenAICompatStreamError(`SSE buffer exceeded ${SSE_MAX_BUFFER_LENGTH} characters without a line break. The server may not be sending SSE.`);
701
+ const lines = buffer.split("\n");
702
+ buffer = lines.pop() || "";
703
+ for (const line of lines) {
704
+ if (!line.startsWith("data:")) continue;
705
+ const data = line.slice(5).trim();
706
+ if (data === "[DONE]") {
707
+ sawTerminator = true;
708
+ continue;
709
+ }
710
+ let chunk;
711
+ try {
712
+ chunk = JSON.parse(data);
713
+ } catch {
714
+ continue;
715
+ }
716
+ const parsedUsage = usageFromChunk(chunk);
717
+ if (parsedUsage) usage = parsedUsage;
718
+ const choice = chunk.choices?.[0];
719
+ if (!choice) continue;
720
+ const fr = choice.finish_reason;
721
+ if (fr) {
722
+ finishReason = fr;
723
+ sawTerminator = true;
724
+ }
725
+ const delta = choice.delta;
726
+ const reasoningDeltaArr = delta?.reasoning_details;
727
+ if (reasoningDeltaArr && reasoningDeltaArr.length > 0) {
728
+ sawReasoningDetails = true;
729
+ for (const item of reasoningDeltaArr) {
730
+ const idx = typeof item.index === "number" ? item.index : 0;
731
+ const existing = reasoningMap.get(idx) ?? {};
732
+ if (typeof item.text === "string") {
733
+ existing.text = (existing.text ?? "") + item.text;
734
+ thinking += item.text;
735
+ callbacks.onThinking?.(item.text);
736
+ }
737
+ if (typeof item.summary === "string") {
738
+ existing.summary = (existing.summary ?? "") + item.summary;
739
+ thinking += item.summary;
740
+ callbacks.onThinking?.(item.summary);
741
+ }
742
+ for (const key of [
743
+ "type",
744
+ "signature",
745
+ "data",
746
+ "format",
747
+ "id"
748
+ ]) {
749
+ const v = item[key];
750
+ if (typeof v === "string") existing[key] = v;
751
+ }
752
+ reasoningMap.set(idx, existing);
753
+ }
754
+ }
755
+ if (!sawReasoningDetails) {
756
+ const thinkingDelta = delta?.reasoning_content ?? delta?.reasoning;
757
+ if (thinkingDelta) {
758
+ thinking += thinkingDelta;
759
+ callbacks.onThinking?.(thinkingDelta);
760
+ }
761
+ }
762
+ const contentDelta = delta?.content;
763
+ if (typeof contentDelta === "string" && contentDelta) {
764
+ text += contentDelta;
765
+ callbacks.onText(contentDelta);
766
+ } else if (Array.isArray(contentDelta)) for (const part of flattenContentChunks(contentDelta)) if (part.kind === "thinking") {
767
+ thinking += part.text;
768
+ callbacks.onThinking?.(part.text);
769
+ } else {
770
+ text += part.text;
771
+ callbacks.onText(part.text);
772
+ }
773
+ const toolCallsDelta = delta?.tool_calls;
774
+ if (toolCallsDelta) {
775
+ if (toolCallsDelta.length > 0) callbacks.onToolCallDelta?.();
776
+ for (const tc of toolCallsDelta) {
777
+ const existing = tcMap.get(tc.index);
778
+ if (existing) {
779
+ if (tc.id) existing.id = tc.id;
780
+ existing.name ||= tc.function?.name ?? "";
781
+ if (tc.function?.arguments) existing.args += tc.function.arguments;
782
+ } else tcMap.set(tc.index, {
783
+ id: tc.id || `call_${tc.index}_${idNonce}`,
784
+ name: tc.function?.name || "",
785
+ args: tc.function?.arguments || ""
786
+ });
787
+ }
788
+ }
789
+ }
790
+ }
791
+ } catch (err) {
792
+ if (!(err instanceof Error && err.name === "AbortError")) await reader.cancel().catch(() => {});
793
+ throw err;
794
+ } finally {
795
+ reader.releaseLock();
796
+ }
797
+ const clipForError = (args) => args.length > 200 ? `${args.slice(0, 200)}… [${args.length} chars]` : args;
798
+ const toolCalls = [];
799
+ for (const tc of tcMap.values()) {
800
+ if (!tc.args) {
801
+ toolCalls.push({
802
+ id: tc.id,
803
+ name: tc.name,
804
+ input: {}
805
+ });
806
+ continue;
807
+ }
808
+ const parsed = parseToolCallArguments(tc.args);
809
+ if (!parsed) throw new OpenAICompatStreamError(`Tool call "${tc.name}" (${tc.id}) arguments were truncated or malformed beyond repair: ${clipForError(tc.args)}`);
810
+ if (parsed.repaired && !sawTerminator) throw new OpenAICompatStreamError(`Tool call "${tc.name}" (${tc.id}) arguments were cut off by a truncated stream: ${clipForError(tc.args)}`);
811
+ toolCalls.push({
812
+ id: tc.id,
813
+ name: tc.name,
814
+ input: parsed.input
815
+ });
816
+ }
817
+ const reasoningDetails = Array.from(reasoningMap.entries()).sort(([a], [b]) => a - b).map(([, item]) => item);
818
+ return {
819
+ text,
820
+ thinking,
821
+ toolCalls,
822
+ finishReason,
823
+ usage,
824
+ reasoningDetails
825
+ };
826
+ }
827
+ //#endregion
659
828
  //#region src/providers/prompt-cache-key.ts
660
829
  /**
661
830
  * A stable key for everything a session shares: the system prompt plus its
@@ -784,7 +953,7 @@ function decodeRefSegment(seg) {
784
953
  */
785
954
  function sanitizeNode(node, ctx, depth, path) {
786
955
  if (depth > MAX_DEPTH) {
787
- ctx.warnings.push(`${ctx.prefix}schema nested deeper than ${MAX_DEPTH} levels at ${path || "$"} — replaced with permissive {}`);
956
+ ctx.warnings.push(`${ctx.prefix}schema nested deeper than ${MAX_DEPTH} levels at ${path || "$"}, replaced with {}`);
788
957
  return {};
789
958
  }
790
959
  if (!isPlainObject(node)) return {};
@@ -909,16 +1078,17 @@ function enforceRoot(schema, ctx) {
909
1078
  }
910
1079
  };
911
1080
  const t = out.type;
912
- if (Array.isArray(t)) if (t.includes("object")) {
913
- dirtyOnce();
914
- out.type = "object";
915
- if (t.length > 1) ctx.warnings.push(`${ctx.prefix}collapsed root type:[${t.join(",")}] to 'object'`);
916
- } else {
917
- dirtyOnce();
918
- ctx.warnings.push(`${ctx.prefix}root type:[${t.join(",")}] does not include 'object' — coerced to 'object'`);
919
- out.type = "object";
920
- }
921
- else if (typeof t === "string" && t !== "object") {
1081
+ if (Array.isArray(t)) {
1082
+ if (t.includes("object")) {
1083
+ dirtyOnce();
1084
+ out.type = "object";
1085
+ if (t.length > 1) ctx.warnings.push(`${ctx.prefix}collapsed root type:[${t.join(",")}] to 'object'`);
1086
+ } else {
1087
+ dirtyOnce();
1088
+ ctx.warnings.push(`${ctx.prefix}root type:[${t.join(",")}] does not include 'object', set to 'object'`);
1089
+ out.type = "object";
1090
+ }
1091
+ } else if (typeof t === "string" && t !== "object") {
922
1092
  dirtyOnce();
923
1093
  ctx.warnings.push(`${ctx.prefix}coerced root type:'${t}' → 'object'`);
924
1094
  out.type = "object";
@@ -1021,7 +1191,7 @@ function sanitizeToolSpecs(tools, options = {}) {
1021
1191
  const out = [];
1022
1192
  for (const tool of tools) {
1023
1193
  if (!isValidToolName(tool.name, profile)) {
1024
- emitOnce(`dropped tool with invalid name "${clipToolName(tool.name)}" — must match ^[A-Za-z0-9_-]{1,${maxToolNameLen(profile)}}$ for the ${profile} provider`);
1194
+ emitOnce(`dropped tool with invalid name "${clipToolName(tool.name)}": must match ^[A-Za-z0-9_-]{1,${maxToolNameLen(profile)}}$ for the ${profile} provider`);
1025
1195
  continue;
1026
1196
  }
1027
1197
  const result = sanitizeToolSchema(tool.inputSchema, {
@@ -1032,116 +1202,21 @@ function sanitizeToolSpecs(tools, options = {}) {
1032
1202
  out.push(tool);
1033
1203
  continue;
1034
1204
  }
1035
- for (const line of result.warnings) emitOnce(line);
1036
- out.push({
1037
- ...tool,
1038
- inputSchema: result.schema
1039
- });
1040
- }
1041
- return out;
1042
- }
1043
- /** Clip an over-long / weird name so a warning line stays readable in logs. */
1044
- function clipToolName(name) {
1045
- return name.length > 80 ? `${name.slice(0, 80)}…` : name;
1046
- }
1047
- function defaultWarn(line) {
1048
- console.warn(`[zidane:schema] ${line}`);
1049
- }
1050
- //#endregion
1051
- //#region src/providers/tool-args.ts
1052
- /**
1053
- * Parse a tool-call arguments payload, repairing truncation and trailing
1054
- * garbage when strict parsing fails. Returns `undefined` when no bounded
1055
- * repair produces valid JSON.
1056
- */
1057
- function parseToolCallArguments(raw) {
1058
- try {
1059
- const parsed = JSON.parse(raw);
1060
- if (typeof parsed === "object" && parsed !== null && !Array.isArray(parsed)) return {
1061
- input: parsed,
1062
- repaired: false
1063
- };
1064
- } catch {}
1065
- for (const { candidate, fabricated } of repairCandidates(raw)) try {
1066
- const parsed = JSON.parse(candidate);
1067
- if (typeof parsed === "object" && parsed !== null && !Array.isArray(parsed)) {
1068
- if (fabricated && Object.keys(parsed).length === 0) continue;
1069
- return {
1070
- input: parsed,
1071
- repaired: true
1072
- };
1073
- }
1074
- } catch {}
1075
- }
1076
- /**
1077
- * Bounded, ordered repair candidates:
1078
- * 1. longest complete top-level object prefix (trailing-garbage case)
1079
- * 2. payload + structural closers (truncated mid-string / mid-object)
1080
- * 3. payload minus a dangling partial token, + closers (truncated mid-token)
1081
- *
1082
- * `fabricated` marks candidates whose closure was invented here (2 and 3) —
1083
- * the caller holds those to a stricter acceptance bar than a prefix that was
1084
- * complete in the payload itself.
1085
- */
1086
- function* repairCandidates(raw) {
1087
- const text = raw.trim();
1088
- if (!text.startsWith("{")) return;
1089
- const scan = scanJson(text);
1090
- if (scan.completeAt !== void 0) yield {
1091
- candidate: text.slice(0, scan.completeAt),
1092
- fabricated: false
1093
- };
1094
- yield {
1095
- candidate: close(text, scan),
1096
- fabricated: true
1097
- };
1098
- let trimmed = text;
1099
- for (let step = 0; step < 6; step++) {
1100
- const next = (scanJson(trimmed).inString ? trimmed.replace(/"(?:[^"\\]|\\.)*$/, "") : trimmed.replace(/(?:"(?:[^"\\]|\\.)*"|[^\s{}[\],:"]+|[,:])\s*$/, "")).trimEnd();
1101
- if (next === trimmed || !next.startsWith("{")) break;
1102
- trimmed = next;
1103
- yield {
1104
- candidate: close(trimmed, scanJson(trimmed)),
1105
- fabricated: true
1106
- };
1107
- }
1108
- }
1109
- function scanJson(text) {
1110
- const stack = [];
1111
- let inString = false;
1112
- let escaped = false;
1113
- let completeAt;
1114
- for (let i = 0; i < text.length; i++) {
1115
- const ch = text[i];
1116
- if (inString) {
1117
- if (escaped) escaped = false;
1118
- else if (ch === "\\") escaped = true;
1119
- else if (ch === "\"") inString = false;
1120
- continue;
1121
- }
1122
- if (ch === "\"") inString = true;
1123
- else if (ch === "{") stack.push("}");
1124
- else if (ch === "[") stack.push("]");
1125
- else if (ch === "}" || ch === "]") {
1126
- stack.pop();
1127
- if (stack.length === 0 && completeAt === void 0) completeAt = i + 1;
1128
- }
1129
- }
1130
- return {
1131
- stack,
1132
- inString,
1133
- completeAt
1134
- };
1135
- }
1136
- function close(text, scan) {
1137
- let out = text;
1138
- if (scan.inString) {
1139
- if (/(?:^|[^\\])(?:\\\\)*\\$/.test(out)) out = out.slice(0, -1);
1140
- out += "\"";
1205
+ for (const line of result.warnings) emitOnce(line);
1206
+ out.push({
1207
+ ...tool,
1208
+ inputSchema: result.schema
1209
+ });
1141
1210
  }
1142
- for (let i = scan.stack.length - 1; i >= 0; i--) out += scan.stack[i];
1143
1211
  return out;
1144
1212
  }
1213
+ /** Clip an over-long / weird name so a warning line stays readable in logs. */
1214
+ function clipToolName(name) {
1215
+ return name.length > 80 ? `${name.slice(0, 80)}…` : name;
1216
+ }
1217
+ function defaultWarn(line) {
1218
+ console.warn(`[zidane:schema] ${line}`);
1219
+ }
1145
1220
  //#endregion
1146
1221
  //#region src/providers/tool-name-boundary.ts
1147
1222
  function createToolNameBoundary(messages, currentToolNames = [], resolveRequestAliases) {
@@ -1149,10 +1224,11 @@ function createToolNameBoundary(messages, currentToolNames = [], resolveRequestA
1149
1224
  for (const message of messages) for (const block of message.content) if (block.type === "tool_call") names.add(block.name);
1150
1225
  const requestAliases = resolveRequestAliases?.(names);
1151
1226
  const sanitizedAliases = buildSanitizedWireAliases(names, requestAliases);
1152
- const maps = buildAliasMaps(requestAliases || sanitizedAliases ? {
1227
+ const aliases = requestAliases || sanitizedAliases ? {
1153
1228
  ...requestAliases,
1154
1229
  ...sanitizedAliases
1155
- } : void 0, names);
1230
+ } : void 0;
1231
+ const maps = buildAliasMaps(aliases, names);
1156
1232
  return {
1157
1233
  messages: rewriteMessagesToWire([...messages], maps),
1158
1234
  toWire: (name) => toWireName(name, maps),
@@ -1165,246 +1241,6 @@ function createToolNameBoundary(messages, currentToolNames = [], resolveRequestA
1165
1241
  const TOOL_RESULTS_TAG = "__zidane_tool_results__";
1166
1242
  const ASSISTANT_TOOL_CALLS_TAG = "__zidane_assistant_tc__";
1167
1243
  /**
1168
- * Ceiling on how many UTF-16 code units may accumulate between two newline
1169
- * boundaries when parsing an SSE stream. A broken or malicious server that
1170
- * emits an unbounded stream of non-newline bytes would otherwise grow `buffer`
1171
- * without end and eventually OOM the host. Measured in JS string length (UTF-16
1172
- * units, 8M units ≈ 8–24 MB of UTF-8 input) rather than bytes — close enough
1173
- * for a pathological-stream tripwire without paying `Buffer.byteLength` on
1174
- * every chunk. Safely above the largest tool-call arg JSON we reasonably
1175
- * expect.
1176
- */
1177
- const SSE_MAX_BUFFER_LENGTH = 8 * 1024 * 1024;
1178
- var OpenAICompatStreamError = class extends Error {
1179
- constructor(message) {
1180
- super(message);
1181
- this.name = "OpenAICompatStreamError";
1182
- }
1183
- };
1184
- /**
1185
- * Flatten a chunk-list `content` delta into ordered text runs tagged as
1186
- * reasoning or answer text. Mistral's shape is
1187
- * `[{ type: 'thinking', thinking: [{ type: 'text', text }] }]` for reasoning
1188
- * and `[{ type: 'text', text }]` for plain text; anything unrecognized is
1189
- * skipped rather than string-coerced into the output.
1190
- */
1191
- function flattenContentChunks(parts) {
1192
- const out = [];
1193
- for (const part of parts) {
1194
- if (typeof part === "string") {
1195
- if (part) out.push({
1196
- kind: "text",
1197
- text: part
1198
- });
1199
- continue;
1200
- }
1201
- if (!part || typeof part !== "object") continue;
1202
- const record = part;
1203
- if (record.type === "thinking") {
1204
- const inner = Array.isArray(record.thinking) ? record.thinking : [];
1205
- for (const run of flattenContentChunks(inner)) out.push({
1206
- kind: "thinking",
1207
- text: run.text
1208
- });
1209
- continue;
1210
- }
1211
- if (typeof record.text === "string" && record.text) out.push({
1212
- kind: "text",
1213
- text: record.text
1214
- });
1215
- }
1216
- return out;
1217
- }
1218
- /**
1219
- * Provider-reported USD for the request, or `undefined` when the gateway
1220
- * didn't price it. OpenRouter's field is `usage.cost` — the authoritative
1221
- * figure (it knows which upstream it routed to; a local rate table doesn't).
1222
- * On BYOK requests `cost` is only OpenRouter's fee and the upstream bill lands
1223
- * on the user's own provider account, so real spend is the sum with
1224
- * `cost_details.upstream_inference_cost`; on non-BYOK that detail merely
1225
- * mirrors `cost` and must NOT be added. `total_cost` is kept as a fallback
1226
- * for gateways that use that name.
1227
- */
1228
- function reportedCost(usage) {
1229
- const base = usage.cost ?? usage.total_cost;
1230
- if (typeof base !== "number") return void 0;
1231
- const upstream = usage.cost_details?.upstream_inference_cost;
1232
- return usage.is_byok && typeof upstream === "number" ? base + upstream : base;
1233
- }
1234
- function usageFromChunk(chunk) {
1235
- const chunkUsage = chunk.usage;
1236
- if (chunkUsage) {
1237
- const cachedRead = chunkUsage.prompt_tokens_details?.cached_tokens;
1238
- const detailsWrite = chunkUsage.prompt_tokens_details?.cache_creation_input_tokens ?? chunkUsage.prompt_tokens_details?.cache_write_tokens;
1239
- const cachedWrite = detailsWrite ?? chunkUsage.cache_creation_input_tokens;
1240
- const includedInPrompt = (cachedRead ?? 0) + (detailsWrite ?? 0);
1241
- return {
1242
- input: Math.max(0, (chunkUsage.prompt_tokens ?? 0) - includedInPrompt),
1243
- output: chunkUsage.completion_tokens ?? 0,
1244
- cost: reportedCost(chunkUsage),
1245
- ...typeof cachedRead === "number" && cachedRead > 0 ? { cacheRead: cachedRead } : {},
1246
- ...typeof cachedWrite === "number" && cachedWrite > 0 ? { cacheCreation: cachedWrite } : {}
1247
- };
1248
- }
1249
- const promptEvalCount = chunk.prompt_eval_count;
1250
- const evalCount = chunk.eval_count;
1251
- if (typeof promptEvalCount === "number" || typeof evalCount === "number") return {
1252
- input: typeof promptEvalCount === "number" ? promptEvalCount : 0,
1253
- output: typeof evalCount === "number" ? evalCount : 0
1254
- };
1255
- return null;
1256
- }
1257
- async function consumeSSE(response, callbacks, signal) {
1258
- if (!response.body) throw new OpenAICompatStreamError(`Streaming response had no body — upstream returned an empty stream (status ${response.status} ${response.statusText}).`);
1259
- const reader = response.body.getReader();
1260
- const decoder = new TextDecoder();
1261
- let buffer = "";
1262
- let text = "";
1263
- let thinking = "";
1264
- let finishReason = "stop";
1265
- let sawTerminator = false;
1266
- let usage = {
1267
- input: 0,
1268
- output: 0
1269
- };
1270
- const tcMap = /* @__PURE__ */ new Map();
1271
- const idNonce = Math.random().toString(36).slice(2, 10);
1272
- const reasoningMap = /* @__PURE__ */ new Map();
1273
- let sawReasoningDetails = false;
1274
- try {
1275
- while (true) {
1276
- if (signal?.aborted) throw new DOMException("The operation was aborted.", "AbortError");
1277
- const { done, value } = await reader.read();
1278
- if (done) break;
1279
- buffer += decoder.decode(value, { stream: true });
1280
- if (buffer.length > SSE_MAX_BUFFER_LENGTH) throw new OpenAICompatStreamError(`SSE buffer exceeded ${SSE_MAX_BUFFER_LENGTH} characters without a line boundary — upstream may be streaming non-SSE data.`);
1281
- const lines = buffer.split("\n");
1282
- buffer = lines.pop() || "";
1283
- for (const line of lines) {
1284
- if (!line.startsWith("data:")) continue;
1285
- const data = line.slice(5).trim();
1286
- if (data === "[DONE]") {
1287
- sawTerminator = true;
1288
- continue;
1289
- }
1290
- let chunk;
1291
- try {
1292
- chunk = JSON.parse(data);
1293
- } catch {
1294
- continue;
1295
- }
1296
- const parsedUsage = usageFromChunk(chunk);
1297
- if (parsedUsage) usage = parsedUsage;
1298
- const choice = chunk.choices?.[0];
1299
- if (!choice) continue;
1300
- const fr = choice.finish_reason;
1301
- if (fr) {
1302
- finishReason = fr;
1303
- sawTerminator = true;
1304
- }
1305
- const delta = choice.delta;
1306
- const reasoningDeltaArr = delta?.reasoning_details;
1307
- if (reasoningDeltaArr && reasoningDeltaArr.length > 0) {
1308
- sawReasoningDetails = true;
1309
- for (const item of reasoningDeltaArr) {
1310
- const idx = typeof item.index === "number" ? item.index : 0;
1311
- const existing = reasoningMap.get(idx) ?? {};
1312
- if (typeof item.text === "string") {
1313
- existing.text = (existing.text ?? "") + item.text;
1314
- thinking += item.text;
1315
- callbacks.onThinking?.(item.text);
1316
- }
1317
- if (typeof item.summary === "string") {
1318
- existing.summary = (existing.summary ?? "") + item.summary;
1319
- thinking += item.summary;
1320
- callbacks.onThinking?.(item.summary);
1321
- }
1322
- for (const key of [
1323
- "type",
1324
- "signature",
1325
- "data",
1326
- "format",
1327
- "id"
1328
- ]) {
1329
- const v = item[key];
1330
- if (typeof v === "string") existing[key] = v;
1331
- }
1332
- reasoningMap.set(idx, existing);
1333
- }
1334
- }
1335
- if (!sawReasoningDetails) {
1336
- const thinkingDelta = delta?.reasoning_content ?? delta?.reasoning;
1337
- if (thinkingDelta) {
1338
- thinking += thinkingDelta;
1339
- callbacks.onThinking?.(thinkingDelta);
1340
- }
1341
- }
1342
- const contentDelta = delta?.content;
1343
- if (typeof contentDelta === "string" && contentDelta) {
1344
- text += contentDelta;
1345
- callbacks.onText(contentDelta);
1346
- } else if (Array.isArray(contentDelta)) for (const part of flattenContentChunks(contentDelta)) if (part.kind === "thinking") {
1347
- thinking += part.text;
1348
- callbacks.onThinking?.(part.text);
1349
- } else {
1350
- text += part.text;
1351
- callbacks.onText(part.text);
1352
- }
1353
- const toolCallsDelta = delta?.tool_calls;
1354
- if (toolCallsDelta) {
1355
- if (toolCallsDelta.length > 0) callbacks.onToolCallDelta?.();
1356
- for (const tc of toolCallsDelta) {
1357
- const existing = tcMap.get(tc.index);
1358
- if (existing) {
1359
- if (tc.id) existing.id = tc.id;
1360
- existing.name ||= tc.function?.name ?? "";
1361
- if (tc.function?.arguments) existing.args += tc.function.arguments;
1362
- } else tcMap.set(tc.index, {
1363
- id: tc.id || `call_${tc.index}_${idNonce}`,
1364
- name: tc.function?.name || "",
1365
- args: tc.function?.arguments || ""
1366
- });
1367
- }
1368
- }
1369
- }
1370
- }
1371
- } catch (err) {
1372
- if (!(err instanceof Error && err.name === "AbortError")) await reader.cancel().catch(() => {});
1373
- throw err;
1374
- } finally {
1375
- reader.releaseLock();
1376
- }
1377
- const clipForError = (args) => args.length > 200 ? `${args.slice(0, 200)}… [${args.length} chars]` : args;
1378
- const toolCalls = [];
1379
- for (const tc of tcMap.values()) {
1380
- if (!tc.args) {
1381
- toolCalls.push({
1382
- id: tc.id,
1383
- name: tc.name,
1384
- input: {}
1385
- });
1386
- continue;
1387
- }
1388
- const parsed = parseToolCallArguments(tc.args);
1389
- if (!parsed) throw new OpenAICompatStreamError(`Tool call "${tc.name}" (${tc.id}) arguments were truncated or malformed beyond repair: ${clipForError(tc.args)}`);
1390
- if (parsed.repaired && !sawTerminator) throw new OpenAICompatStreamError(`Tool call "${tc.name}" (${tc.id}) arguments were cut off by a truncated stream: ${clipForError(tc.args)}`);
1391
- toolCalls.push({
1392
- id: tc.id,
1393
- name: tc.name,
1394
- input: parsed.input
1395
- });
1396
- }
1397
- const reasoningDetails = Array.from(reasoningMap.entries()).sort(([a], [b]) => a - b).map(([, item]) => item);
1398
- return {
1399
- text,
1400
- thinking,
1401
- toolCalls,
1402
- finishReason,
1403
- usage,
1404
- reasoningDetails
1405
- };
1406
- }
1407
- /**
1408
1244
  * Encode a single image block as an OpenAI `image_url` multi-part entry.
1409
1245
  */
1410
1246
  function toImageUrlPart(img) {
@@ -1570,9 +1406,7 @@ function toOAIMessages(system, messages, options = {}) {
1570
1406
  case "document":
1571
1407
  documentBlocks.push(b);
1572
1408
  break;
1573
- case "provider_reasoning":
1574
- if (reasoningEnabled && b.producer === reasoningProducer && !(b.model && activeModel && b.model !== activeModel)) reasoningBlocks.push(b);
1575
- break;
1409
+ case "provider_reasoning": if (reasoningEnabled && b.producer === reasoningProducer && !(b.model && activeModel && b.model !== activeModel)) reasoningBlocks.push(b);
1576
1410
  }
1577
1411
  const reasoningDetails = reasoningBlocks.flatMap((b) => b.producer === "openrouter" ? b.details : []);
1578
1412
  const reasoningText = reasoningMode === "reasoning_content" ? reasoningBlocks.map((b) => b.producer === "vllm" ? b.reasoningText : "").filter(Boolean).join("") : "";
@@ -1772,6 +1606,12 @@ function applyOAICacheBreakpoints(messages, originalSystem, ttl) {
1772
1606
  if (first.role === "system") markSystemMessage(first, cacheControl, originalSystem);
1773
1607
  const lastIdx = messages.length - 1;
1774
1608
  if (lastIdx > 0) markLastContentPart(messages[lastIdx], cacheControl);
1609
+ for (let i = lastIdx - 1; i > 0; i--) {
1610
+ if (messages[i].role !== "assistant") continue;
1611
+ const prevTail = i - 1;
1612
+ if (prevTail > 0 && messages[prevTail].role !== "system" && messages[prevTail].role !== "assistant") markLastContentPart(messages[prevTail], cacheControl);
1613
+ break;
1614
+ }
1775
1615
  }
1776
1616
  /**
1777
1617
  * Place the cache marker on the static prefix of the system message. When
@@ -1790,7 +1630,8 @@ function markSystemMessage(msg, cacheControl, originalSystem) {
1790
1630
  markLastContentPart(msg, cacheControl);
1791
1631
  return;
1792
1632
  }
1793
- const parts = splitSystemPrompt(originalSystem && originalSystem.length > 0 ? originalSystem : msg.content);
1633
+ const splitSource = originalSystem && originalSystem.length > 0 ? originalSystem : msg.content;
1634
+ const parts = splitSystemPrompt(splitSource);
1794
1635
  if (parts.dynamic.length === 0) {
1795
1636
  msg.content = [{
1796
1637
  type: "text",
@@ -2220,12 +2061,14 @@ function openaiCompat(params) {
2220
2061
  }));
2221
2062
  body.tools = shouldCache ? applyOAIToolCacheBreakpoint(tools, options.cacheTtl) : tools;
2222
2063
  }
2223
- if (options.toolChoice) if (options.toolChoice.type === "tool" && options.toolChoice.name) body.tool_choice = {
2224
- type: "function",
2225
- function: { name: nameBoundary.toWire(options.toolChoice.name) }
2226
- };
2227
- else if (options.toolChoice.type === "required") body.tool_choice = "required";
2228
- else body.tool_choice = "auto";
2064
+ if (options.toolChoice) {
2065
+ if (options.toolChoice.type === "tool" && options.toolChoice.name) body.tool_choice = {
2066
+ type: "function",
2067
+ function: { name: nameBoundary.toWire(options.toolChoice.name) }
2068
+ };
2069
+ else if (options.toolChoice.type === "required") body.tool_choice = "required";
2070
+ else body.tool_choice = "auto";
2071
+ }
2229
2072
  const promptCacheKey = resolvePromptCacheKey(params.promptCacheKey, {
2230
2073
  model: modelId,
2231
2074
  system: options.system,
@@ -2296,6 +2139,6 @@ function openaiCompat(params) {
2296
2139
  };
2297
2140
  }
2298
2141
  //#endregion
2299
- export { mergeCatalogEntry as A, rewriteMessagesToWire as B, estimateRebilledCostUsd as C, listModelOverlay as D, getModelCatalog as E, unsupportedMediaError as F, toWireName as H, augmentMcpDoubleUnderscoreAliases as I, buildAliasMaps as L, buildPromptMessage as M, canonicalizePrompt as N, listModels as O, defaultPromptMessage as P, buildSanitizedWireAliases as R, resolvePromptCacheKey as S, aliasCatalogProviders as T, fnv1aBase36 as U, toCanonicalName as V, userMessage as _, applyOAICacheBreakpoints as a, sanitizeToolSpecs as b, buildAssistantContent as c, formatTools as d, mapOAIFinishReason as f, toolResultsMessage as g, toOAIMessages as h, TOOL_RESULTS_TAG as i, setModelCatalog as j, lookupModel as k, classifyOpenAICompatError as l, openaiCompat as m, OpenAICompatHttpError as n, applyOAIToolCacheBreakpoint as o, openAICompatPromptMessage as p, OpenAICompatStreamError as r, assistantMessage as s, ASSISTANT_TOOL_CALLS_TAG as t, consumeSSE as u, createToolNameBoundary as v, fillEstimatedCost as w, derivePromptCacheKey as x, sanitizeToolSchema as y, rewriteContentToCanonical as z };
2142
+ export { lookupModel as A, createToolJsonEscaper as C, getModelCatalog as D, aliasCatalogProviders as E, defaultPromptMessage as F, unsupportedMediaError as I, setModelCatalog as M, buildPromptMessage as N, listModelOverlay as O, canonicalizePrompt as P, consumeSSE as S, fillEstimatedCost as T, sanitizeToolSchema as _, applyOAIToolCacheBreakpoint as a, resolvePromptCacheKey as b, classifyOpenAICompatError as c, openAICompatPromptMessage as d, openaiCompat as f, createToolNameBoundary as g, userMessage as h, applyOAICacheBreakpoints as i, mergeCatalogEntry as j, listModels as k, formatTools as l, toolResultsMessage as m, OpenAICompatHttpError as n, assistantMessage as o, toOAIMessages as p, TOOL_RESULTS_TAG as r, buildAssistantContent as s, ASSISTANT_TOOL_CALLS_TAG as t, mapOAIFinishReason as u, sanitizeToolSpecs as v, estimateRebilledCostUsd as w, OpenAICompatStreamError as x, derivePromptCacheKey as y };
2300
2143
 
2301
- //# sourceMappingURL=openai-compat-Dy56weK8.js.map
2144
+ //# sourceMappingURL=openai-compat-CFrpH7uq.js.map