zidane 7.2.4 → 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 -27242
  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-zVSyo6K1.js +0 -331
  342. package/dist/ipc-zVSyo6K1.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-h5czzllR.js +0 -1549
  363. package/dist/shell-path-h5czzllR.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,104 +1,14 @@
1
- import { F as unsupportedMediaError, S as resolvePromptCacheKey, b as sanitizeToolSpecs, k as lookupModel, v as createToolNameBoundary, w as fillEstimatedCost } from "./openai-compat-Dy56weK8.js";
2
- import { t as lazyAsync } from "./lazy-DLOurOC_.js";
3
1
  import { f as isRetryableHttpStatus, h as matchesToolPairingError, l as classifyErrorPrelude, m as matchesContextExceeded, u as errorMessage } from "./errors-DKiMrOKq.js";
2
+ import { A as lookupModel, C as createToolJsonEscaper, I as unsupportedMediaError, T as fillEstimatedCost, b as resolvePromptCacheKey, g as createToolNameBoundary, v as sanitizeToolSpecs } from "./openai-compat-CFrpH7uq.js";
4
3
  import { renderSystemForWire, splitSystemPrompt } from "./prompt.js";
5
- import { g as toAnthropic, u as fromAnthropic } from "./messages-2jcOA_5R.js";
6
- import { a as readOAuthCredentials, r as extractRuntimeCredentials, s as resolveOAuthApiKey } from "./oauth-DxHO17JE.js";
4
+ import { a as fromAnthropic, u as toAnthropic } from "./messages-BqiwcD2Q.js";
5
+ import { t as lazyAsync } from "./lazy-DLOurOC_.js";
6
+ import { a as readOAuthCredentials, r as extractRuntimeCredentials, s as resolveOAuthApiKey } from "./oauth-Px_pBB9W.js";
7
7
  import { Buffer } from "node:buffer";
8
8
  import { arch, homedir, hostname, platform, userInfo } from "node:os";
9
9
  import { createHash, randomUUID } from "node:crypto";
10
- //#region src/chat/anthropic-models.ts
11
- /**
12
- * Anthropic "fast mode" — `speed: "fast"` on the Messages API. ~2.5× output
13
- * tokens/sec at a per-model price multiplier. Supported on Opus 4.6 / 4.7 /
14
- * 4.8 / 5 / 5.5 only; the API errors if sent on any other model, so it's
15
- * attached just to those entries (see {@link FAST_MODE_OPTIONS}).
16
- *
17
- * The multiplier scales ALL rate components (input, output, and both cache
18
- * rates) uniformly: per Anthropic, "prompt caching multipliers apply on top of
19
- * fast mode pricing" across the full context window. Opus 5.5 ($4/$20 →
20
- * $8/$40), 5 and 4.8 ($5/$25 → $10/$50) are 2×; Opus 4.6 / 4.7 are a steeper
21
- * 6× ($5/$25 → $30/$150).
22
- * See https://platform.claude.com/docs/en/build-with-claude/fast-mode.
23
- */
24
- const FAST_MODE_OPTION = {
25
- id: "fast",
26
- label: "Fast mode",
27
- description: "~2.5× faster output at premium pricing",
28
- costMultiplier: {
29
- input: 2,
30
- output: 2,
31
- cacheRead: 2,
32
- cacheWrite: 2
33
- }
34
- };
35
- const FAST_MODE_OPTION_LEGACY = {
36
- ...FAST_MODE_OPTION,
37
- description: "~2.5× faster output at 6× pricing",
38
- costMultiplier: {
39
- input: 6,
40
- output: 6,
41
- cacheRead: 6,
42
- cacheWrite: 6
43
- }
44
- };
45
- /** Model ids that accept `speed: "fast"`, mapped to their fast-mode option. */
46
- const FAST_MODE_OPTIONS = {
47
- "claude-opus-5-5": FAST_MODE_OPTION,
48
- "claude-opus-5": FAST_MODE_OPTION,
49
- "claude-opus-4-8": FAST_MODE_OPTION,
50
- "claude-opus-4-7": FAST_MODE_OPTION_LEGACY,
51
- "claude-opus-4-6": FAST_MODE_OPTION_LEGACY
52
- };
53
- /**
54
- * The price multiplier to apply to a model's base rates when fast mode is
55
- * active, or `undefined` when the model has no fast-mode pricing (i.e. doesn't
56
- * support it). Mirrors {@link FAST_MODE_OPTIONS} — kept as a separate accessor
57
- * so the cost layer can stay decoupled from the picker-facing option objects.
58
- */
59
- function fastModeCostMultiplier(modelId) {
60
- return FAST_MODE_OPTIONS[modelId]?.costMultiplier;
61
- }
62
- /**
63
- * Currently empty: pi-ai 0.87.1 bundles every GA Anthropic model up to and
64
- * including Claude Opus 5.5 (2026-09-22) — Opus 4.8 / 5 / 5.5, Fable 5 / 5.1,
65
- * Sonnet 4.6 / 5, Haiku 4.5 — with published rates, 1M context and 128k output.
66
- *
67
- * When adding a stopgap entry, mirror pi-ai's `ModelInfo` shape and set
68
- * `provider: 'anthropic'`. Known caveats worth carrying over in the comment:
69
- * Fable 5 / 5.1 REJECT forced tool use (`tool_choice` of `any` or `tool`
70
- * returns 400), which breaks zidane's structured-output paths (`loop.ts`,
71
- * `generate-data.ts`, the eval judge) — Opus 5.5 rejects it too, handled
72
- * generically by the learned `MODELS_REJECTING_FORCED_TOOL_CHOICE` retry in
73
- * providers/anthropic.ts. Opus 5.5 also REJECTS non-adaptive thinking:
74
- * `thinking: {type:'enabled', budget_tokens}` and `{type:'disabled'}` both 400
75
- * with `"thinking.type.enabled/disabled" is not supported for this model`;
76
- * zidane's explicit-budget path (`behavior.thinkingBudget`, the Bedrock-only
77
- * shape) emits `enabled`, so the provider catches that 400 and retries as
78
- * adaptive (`MODELS_REJECTING_ENABLED_THINKING`). Claude Mythos 5 / 5.1 are
79
- * deliberately absent: invitation-only (Project Glasswing), so they would be
80
- * dead picker entries for virtually all users.
81
- *
82
- * See https://platform.claude.com/docs/en/about-claude/models/overview.
83
- */
84
- const ANTHROPIC_EXTRA_MODELS = [];
85
- //#endregion
86
10
  //#region src/providers/anthropic-claude-code.ts
87
11
  /**
88
- * Claude Code client alignment for Anthropic subscription OAuth.
89
- *
90
- * Anthropic's subscription endpoint serves the Claude Code CLI. Requests that
91
- * do not look like that client are, at best, treated as a different product; at
92
- * worst they miss features the CLI relies on. This module holds every surface
93
- * that has to match, in one file, so a client bump is one edit rather than a
94
- * scavenger hunt through the provider.
95
- *
96
- * Modelled on `@pi-plugins/claude-oauth`, which maintains the same alignment
97
- * for pi and verifies its pins against a live client trace. Everything here is
98
- * scoped to the OAuth path — API-key, gateway-bearer and Bedrock requests never
99
- * reach it.
100
- */
101
- /**
102
12
  * Pinned Claude Code client versions.
103
13
  *
104
14
  * These travel together: the billing fingerprint below hashes
@@ -169,6 +79,42 @@ function claudeCodeToolAliases(names) {
169
79
  return aliases;
170
80
  }
171
81
  /**
82
+ * The wire `system` block and `messages` for one request.
83
+ *
84
+ * Claude Code OAuth requires the system block to be the canonical Claude Code
85
+ * prompt, so the real system prompt is folded into a leading user/assistant
86
+ * pair ahead of the conversation. Every other auth shape sends the rendered
87
+ * system prompt as the system block. Shared by `stream()` and `countTokens()`
88
+ * so the count measures what is actually sent.
89
+ */
90
+ function foldSystemForWire(system, messages, claudeCode) {
91
+ const wireSystem = renderSystemForWire(system);
92
+ if (!claudeCode) return {
93
+ system: wireSystem,
94
+ messages: [...messages]
95
+ };
96
+ return {
97
+ system: `You are Claude Code, Anthropic's official CLI for Claude.`,
98
+ messages: system ? [
99
+ {
100
+ role: "user",
101
+ content: [{
102
+ type: "text",
103
+ text: wireSystem
104
+ }]
105
+ },
106
+ {
107
+ role: "assistant",
108
+ content: [{
109
+ type: "text",
110
+ text: "Understood. I will proceed with these instructions above the rest of my system prompt."
111
+ }]
112
+ },
113
+ ...messages
114
+ ] : [...messages]
115
+ };
116
+ }
117
+ /**
172
118
  * Beta set the Claude Code agent sends, in client order.
173
119
  *
174
120
  * Sent as one unit: the endpoint is configured for this combination, and
@@ -486,133 +432,7 @@ function wrapFetchForAnthropicRateLimit(fetch) {
486
432
  }, fetch);
487
433
  }
488
434
  //#endregion
489
- //#region src/providers/diagnostic.ts
490
- const NETWORK_CODES = /* @__PURE__ */ new Set([
491
- "ECONNREFUSED",
492
- "ECONNRESET",
493
- "ETIMEDOUT",
494
- "ENOTFOUND",
495
- "EAI_AGAIN",
496
- "ENETUNREACH",
497
- "EHOSTUNREACH",
498
- "EPIPE",
499
- "UND_ERR_CONNECT_TIMEOUT",
500
- "UND_ERR_HEADERS_TIMEOUT",
501
- "UND_ERR_SOCKET",
502
- "CERT_HAS_EXPIRED",
503
- "DEPTH_ZERO_SELF_SIGNED_CERT",
504
- "UNABLE_TO_VERIFY_LEAF_SIGNATURE",
505
- "ERR_TLS_CERT_ALTNAME_INVALID",
506
- "AbortError",
507
- "TimeoutError"
508
- ]);
509
- function sanitizeProviderDiagnosticMetadata(metadata) {
510
- const safe = {};
511
- if (typeof metadata.transportAttempt === "number" && Number.isSafeInteger(metadata.transportAttempt) && metadata.transportAttempt > 0) safe.transportAttempt = metadata.transportAttempt;
512
- if (typeof metadata.networkCode === "string" && NETWORK_CODES.has(metadata.networkCode)) safe.networkCode = metadata.networkCode;
513
- if (typeof metadata.httpStatus === "number" && Number.isInteger(metadata.httpStatus) && metadata.httpStatus >= 100 && metadata.httpStatus <= 599) safe.httpStatus = metadata.httpStatus;
514
- if (typeof metadata.upstreamRequestId === "string" && metadata.upstreamRequestId.length <= 128 && /^req_[\w-]+$/.test(metadata.upstreamRequestId)) safe.upstreamRequestId = metadata.upstreamRequestId;
515
- const retryAfter = metadata.retryAfter;
516
- if (typeof retryAfter === "string" && retryAfter.length <= 32 && (/^\d+(?:\.\d+)?$/.test(retryAfter) || retryAfter.length === 29 && new Date(retryAfter).toUTCString() === retryAfter)) safe.retryAfter = retryAfter;
517
- return safe;
518
- }
519
- /** No request or error objects cross this boundary. Diagnostics cannot fail a request. */
520
- function createProviderDiagnosticTracker(emit, signal) {
521
- const requestId = crypto.randomUUID();
522
- const started = performance.now();
523
- let stageStarted = started;
524
- let current;
525
- let attempt = 0;
526
- let transportAttempt = 0;
527
- let finished = false;
528
- let timer;
529
- let abort = () => {};
530
- function send(event, metadata = {}) {
531
- if (!current) return;
532
- const now = performance.now();
533
- try {
534
- emit?.({
535
- requestId,
536
- stage: current,
537
- event,
538
- elapsedMs: Math.round(now - started),
539
- stageElapsedMs: Math.round(now - stageStarted),
540
- attempt,
541
- ...sanitizeProviderDiagnosticMetadata(metadata)
542
- });
543
- } catch {}
544
- }
545
- const tracker = {
546
- wrapFetch(fetch) {
547
- if (!emit) return fetch;
548
- return Object.assign(async (...args) => {
549
- const number = ++transportAttempt;
550
- const began = performance.now();
551
- const report = (event, metadata = {}) => {
552
- try {
553
- emit({
554
- requestId,
555
- stage: "transport",
556
- event,
557
- elapsedMs: Math.round(performance.now() - started),
558
- stageElapsedMs: Math.round(performance.now() - began),
559
- attempt,
560
- ...sanitizeProviderDiagnosticMetadata({
561
- ...metadata,
562
- transportAttempt: number
563
- })
564
- });
565
- } catch {}
566
- };
567
- report("start");
568
- try {
569
- const response = await fetch(...args);
570
- report("end", {
571
- httpStatus: response.status,
572
- upstreamRequestId: response.headers.get("request-id"),
573
- retryAfter: response.headers.get("retry-after")
574
- });
575
- return response;
576
- } catch (error) {
577
- const err = error;
578
- report("failure", { networkCode: [
579
- err?.cause?.code,
580
- err?.code,
581
- err?.name
582
- ].find((value) => typeof value === "string" && NETWORK_CODES.has(value)) });
583
- throw error;
584
- }
585
- }, fetch);
586
- },
587
- stage(stage, metadata = {}) {
588
- if (!emit || finished) return;
589
- if (current) send("end");
590
- current = stage;
591
- stageStarted = performance.now();
592
- if (stage === "dispatch") attempt++;
593
- send("start", metadata);
594
- if (timer) clearInterval(timer);
595
- timer = setInterval(send, 3e4, "waiting");
596
- timer.unref?.();
597
- if (signal?.aborted) abort();
598
- },
599
- finish(event, metadata = {}) {
600
- if (!emit || finished) return;
601
- finished = true;
602
- clearInterval(timer);
603
- signal?.removeEventListener("abort", abort);
604
- if (current) {
605
- send("end");
606
- send(event, metadata);
607
- }
608
- }
609
- };
610
- abort = () => tracker.finish("abort");
611
- if (emit) signal?.addEventListener("abort", abort, { once: true });
612
- return tracker;
613
- }
614
- //#endregion
615
- //#region src/providers/anthropic.ts
435
+ //#region src/providers/anthropic-client.ts
616
436
  const loadAnthropicSdk = lazyAsync(async () => {
617
437
  try {
618
438
  return (await import("@anthropic-ai/sdk")).default;
@@ -664,76 +484,33 @@ const OAUTH_DEFAULT_BETAS = CLAUDE_CODE_BETAS;
664
484
  * See: https://platform.claude.com/docs/en/build-with-claude/fast-mode
665
485
  */
666
486
  const FAST_MODE_BETA = "fast-mode-2026-02-01";
667
- /** Gates `thinking.block_binding` and the `input_transformations` response field. */
668
- const THINKING_BINDING_BETA = "thinking-binding-controls-2026-08-01";
669
- const THINKING_BINDING_BEHAVIORS = /* @__PURE__ */ new Set([
670
- "drop_block",
671
- "error",
672
- "off"
487
+ const API_KEY_RESERVED_EXTRA_HEADER_NAMES = /* @__PURE__ */ new Set(["anthropic-beta"]);
488
+ const OAUTH_RESERVED_EXTRA_HEADER_NAMES = /* @__PURE__ */ new Set([
489
+ "accept",
490
+ "anthropic-beta",
491
+ "anthropic-client-platform",
492
+ "anthropic-client-version",
493
+ "x-stainless-arch",
494
+ "x-stainless-lang",
495
+ "x-stainless-os",
496
+ "x-stainless-package-version",
497
+ "x-stainless-retry-count",
498
+ "x-stainless-runtime",
499
+ "x-stainless-runtime-version",
500
+ "x-stainless-timeout",
501
+ "anthropic-dangerous-direct-browser-access",
502
+ "user-agent",
503
+ "x-app"
673
504
  ]);
505
+ function filterReservedExtraHeaders(extraHeaders, reservedNames) {
506
+ const out = {};
507
+ for (const [name, value] of Object.entries(extraHeaders ?? {})) if (!reservedNames.has(name.toLowerCase())) out[name] = value;
508
+ return out;
509
+ }
674
510
  /**
675
- * Env channel the chat host writes the user's `thinkingBinding` SETTING to.
676
- * Distinct from `ZIDANE_THINKING_BINDING` (the shell override) so the two
677
- * never read each other back: a host recreated in-process must not mistake
678
- * an earlier host's setting write for a shell value.
679
- */
680
- const THINKING_BINDING_SETTING_ENV = "ZIDANE_THINKING_BINDING_SETTING";
681
- /**
682
- * Effective {@link AnthropicParams.thinkingBinding}: the explicit param wins,
683
- * then the shell's `ZIDANE_THINKING_BINDING`, then the chat host's setting
684
- * channel ({@link THINKING_BINDING_SETTING_ENV}), then `'drop_block'`. Read
685
- * per request so a flip lands on the next call without rebuilding the
686
- * provider (the factory is no-arg in the chat host). Unrecognized values are
687
- * ignored at each level.
688
- */
689
- function resolveThinkingBinding(param, env = process.env) {
690
- if (param !== void 0) return param;
691
- for (const key of ["ZIDANE_THINKING_BINDING", THINKING_BINDING_SETTING_ENV]) {
692
- const value = env[key]?.trim();
693
- if (value && THINKING_BINDING_BEHAVIORS.has(value)) return value;
694
- }
695
- return "drop_block";
696
- }
697
- /**
698
- * The 400 the API returns under `prefix_mismatch_behavior: "error"` for a
699
- * replayed block whose prefix changed. Distinct from a corrupt/tampered
700
- * signature: this one names the binding and the remedy.
701
- */
702
- function isPrefixMismatchError(err) {
703
- return /bound to a different conversation|prefix_mismatch_behavior/i.test(errorText(err));
704
- }
705
- function isInputTransformation(value) {
706
- if (typeof value !== "object" || value === null) return false;
707
- const v = value;
708
- return typeof v.type === "string" && typeof v.path === "string" && typeof v.reason === "string";
709
- }
710
- const API_KEY_RESERVED_EXTRA_HEADER_NAMES = /* @__PURE__ */ new Set(["anthropic-beta"]);
711
- const OAUTH_RESERVED_EXTRA_HEADER_NAMES = /* @__PURE__ */ new Set([
712
- "accept",
713
- "anthropic-beta",
714
- "anthropic-client-platform",
715
- "anthropic-client-version",
716
- "x-stainless-arch",
717
- "x-stainless-lang",
718
- "x-stainless-os",
719
- "x-stainless-package-version",
720
- "x-stainless-retry-count",
721
- "x-stainless-runtime",
722
- "x-stainless-runtime-version",
723
- "x-stainless-timeout",
724
- "anthropic-dangerous-direct-browser-access",
725
- "user-agent",
726
- "x-app"
727
- ]);
728
- function filterReservedExtraHeaders(extraHeaders, reservedNames) {
729
- const out = {};
730
- for (const [name, value] of Object.entries(extraHeaders ?? {})) if (!reservedNames.has(name.toLowerCase())) out[name] = value;
731
- return out;
732
- }
733
- /**
734
- * Build the `anthropic-beta` header value — OAuth defaults plus caller-supplied
735
- * extras, de-duped while preserving order. Returns `undefined` when no betas
736
- * apply (non-OAuth, no extras).
511
+ * Build the `anthropic-beta` header value — OAuth defaults plus caller-supplied
512
+ * extras, de-duped while preserving order. Returns `undefined` when no betas
513
+ * apply (non-OAuth, no extras).
737
514
  */
738
515
  function resolveAnthropicBetas(isOAuth, extraBetas) {
739
516
  const seen = /* @__PURE__ */ new Set();
@@ -863,424 +640,84 @@ function createClient(SDK, apiKey, auth, baseURL, extraBetas, extraHeaders, wrap
863
640
  if (wrapFetch) options.fetch = wrapFetch(options.fetch ?? globalThis.fetch);
864
641
  return new SDK(options);
865
642
  }
643
+ //#endregion
644
+ //#region src/providers/anthropic-errors.ts
866
645
  /**
867
- * Map `ThinkingLevel` budgeted tiers to Anthropic's `output_config.effort`
868
- * enum. `minimal` collapses to `low` (the closest equivalent — Anthropic does
869
- * not have a sub-`low` tier).
870
- */
871
- /**
872
- * Explicit thinking budgets for Bedrock, per effort tier. Bedrock's
873
- * anthropic-native path only accepts the legacy
874
- * `thinking: { type: 'enabled', budget_tokens }` shape (the 4.6 surface —
875
- * `output_config.effort`, adaptive, `display` — is rejected by its
876
- * translation layer), so effort tiers degrade to token budgets. Floor is
877
- * Anthropic's 1024 minimum; ceilings stay well under haiku/sonnet output
878
- * caps — the request builder clamps against the model ceiling regardless.
879
- */
880
- /**
881
- * Output tokens reserved for the visible response when an explicit thinking
882
- * budget must be shrunk to fit under the model's `max_tokens` ceiling — see
883
- * the budget clamp in `stream()`.
884
- */
885
- const THINKING_RESPONSE_RESERVE_TOKENS = 1024;
886
- const BEDROCK_THINKING_BUDGETS = {
887
- low: 4096,
888
- medium: 12288,
889
- high: 24576,
890
- xhigh: 32768,
891
- max: 32768
892
- };
893
- const EFFORT_FOR_LEVEL = {
894
- minimal: "low",
895
- low: "low",
896
- medium: "medium",
897
- high: "high",
898
- xhigh: "xhigh",
899
- max: "max"
900
- };
901
- /**
902
- * Decide how to translate a `ThinkingLevel` into Anthropic's request shape.
903
- * Pure / synchronous — exported so tests can assert routing without standing
904
- * up the SDK.
646
+ * Duck-type check for an Anthropic SDK `APIError` — avoids a runtime dependency
647
+ * on `@anthropic-ai/sdk` so `classifyError` stays usable even when the optional
648
+ * peer dep isn't loaded (e.g. host code calling it on an unrelated provider's
649
+ * error).
905
650
  *
906
- * Routing rules:
907
- * - `'off'` → `null` (no thinking field, no effort hint).
908
- * - `'adaptive'` → adaptive thinking with no effort hint (model decides
909
- * everything). When `taskBudget` is set, it is carried as
910
- * `taskBudgetTokens` and emitted as `output_config.task_budget` — the
911
- * native whole-task thinking cap. LEGACY: when `customBudget` is set, it
912
- * is carried as `maxTokensCap` so the request builder caps `max_tokens`
913
- * accordingly — this clamps the whole response envelope (text and
914
- * tool-call JSON included), which is the wrong knob for bounding thinking
915
- * now that `taskBudget` exists; kept only for callers who already depend
916
- * on it. Prefer `taskBudget`.
917
- * - Budgeted levels → adaptive thinking with an `effort` hint (plus
918
- * `taskBudgetTokens` when `taskBudget` is set), unless `customBudget` is
919
- * provided.
920
- * - Any level + `customBudget` → explicit-budget `enabled` path, carrying
921
- * the level's `effort` hint alongside the budget. The caller has opted
922
- * into precise budget control and accepts the Anthropic deprecation
923
- * warning that comes with it on opus 4.6+. `'adaptive'` is the sole
924
- * exception: it never falls back to enabled, since adaptive is the
925
- * current Anthropic API surface for self-budgeted thinking. `taskBudget`
926
- * is adaptive-only and ignored on this path.
927
- * - `effortHint: false` (default `true`) strips the `effort` hint from
928
- * every shape — budgeted levels plan plain adaptive and the
929
- * `customBudget` path plans `enabled` with no `output_config.effort` —
930
- * for Anthropic models that reject the effort field.
651
+ * Anthropic's APIError shape: `.status: number` + `.error` (parsed body, object
652
+ * or null). Plain `Error`s don't have `.status` + `.error`.
931
653
  */
932
- function planAnthropicThinking(level, customBudget, taskBudget, effortHint = true) {
933
- if (level === "off") return null;
934
- const taskBudgetTokens = typeof taskBudget === "number" && taskBudget > 0 ? taskBudget : void 0;
935
- if (level === "adaptive") return {
936
- kind: "adaptive",
937
- ...typeof customBudget === "number" && customBudget > 0 ? { maxTokensCap: customBudget } : {},
938
- ...taskBudgetTokens !== void 0 ? { taskBudgetTokens } : {}
939
- };
940
- if (customBudget !== void 0) return {
941
- kind: "enabled",
942
- budgetTokens: customBudget,
943
- maxTokensBump: customBudget,
944
- ...effortHint ? { effort: EFFORT_FOR_LEVEL[level] } : {}
945
- };
946
- return {
947
- kind: "adaptive",
948
- ...effortHint ? { effort: EFFORT_FOR_LEVEL[level] } : {},
949
- ...taskBudgetTokens !== void 0 ? { taskBudgetTokens } : {}
950
- };
654
+ function looksLikeAnthropicApiError(err) {
655
+ if (!err || typeof err !== "object") return false;
656
+ const e = err;
657
+ return typeof e.status === "number" && "error" in e;
951
658
  }
952
659
  /**
953
- * Map Anthropic's native `stop_reason` to the zidane `TurnFinishReason` union.
660
+ * Anthropic SSE `error` event types that warrant a retry. `overloaded_error`
661
+ * is the headline case (capacity event mid-stream); `api_error` and
662
+ * `timeout_error` are both server-side transient failures. `invalid_request_error`,
663
+ * `authentication_error`, `permission_error`, `not_found_error`, `billing_error`
664
+ * are terminal — retrying them would just hammer a bad request.
954
665
  *
955
- * `pause_turn` and `model_context_window_exceeded` are 4.6+ stop reasons that
956
- * pre-Z21 collapsed to `'other'` and silently terminated the run. They now
957
- * map to `'pause'` and `'length'` respectively, and the surrounding caller
958
- * adjusts the `done` flag so the loop can recover.
959
- */
960
- function mapStopReason(stopReason) {
961
- if (!stopReason) return void 0;
962
- switch (stopReason) {
963
- case "end_turn":
964
- case "stop_sequence": return "stop";
965
- case "tool_use": return "tool-calls";
966
- case "max_tokens":
967
- case "model_context_window_exceeded": return "length";
968
- case "refusal": return "content-filter";
969
- case "pause_turn": return "pause";
970
- default: return "other";
971
- }
972
- }
973
- /**
974
- * Conservative per-family output ceiling, used ONLY as a fallback when pi-ai's
975
- * model registry doesn't know the model (or pi-ai is externalized) — see
976
- * {@link resolveAnthropicMaxOutput}, which is the primary path. These are
977
- * non-beta floors we can always send without a 400; the registry reports the
978
- * real (often much higher, e.g. Opus 4.x = 128K native) max when available.
666
+ * `rate_limit_error` here would be redundant: the SDK's pre-stream retry
667
+ * handles 429, and a mid-stream `rate_limit_error` is exceedingly rare. We
668
+ * include it anyway for symmetry with the HTTP-level retry policy.
979
669
  */
980
- function defaultAnthropicMaxTokens(modelId) {
981
- const id = modelId.toLowerCase();
982
- if (id.includes("haiku")) return 8192;
983
- if (id.includes("sonnet")) return 64e3;
984
- return 32e3;
985
- }
670
+ const SSE_RETRYABLE_ERROR_TYPES = /* @__PURE__ */ new Set([
671
+ "overloaded_error",
672
+ "api_error",
673
+ "timeout_error",
674
+ "rate_limit_error"
675
+ ]);
986
676
  /**
987
- * Lazily-loaded pi-ai model-registry getter (cached; keeps the multi-MB
988
- * registry out of the static bundle, mirroring `cost.ts`). Returns `null` when
989
- * pi-ai is externalized, in which case callers fall back to the family map.
677
+ * Try to parse an Anthropic SSE `error` event payload out of a thrown error's
678
+ * message. The SDK's `MessageStream` surfaces mid-stream error events by
679
+ * throwing an `AnthropicError` whose `.message` contains the raw JSON shape:
680
+ *
681
+ * {"type":"error","error":{"type":"overloaded_error","message":"Overloaded"},"request_id":"req_..."}
682
+ *
683
+ * Returns the inner `{ type, message }` or `null` when the message isn't
684
+ * the canonical SSE error shape. Tolerant: silently returns `null` for
685
+ * non-string input, non-JSON content, or any shape mismatch.
990
686
  */
991
- const loadPiModelGetter = lazyAsync(async () => {
687
+ function matchSseErrorEvent(message) {
688
+ if (typeof message !== "string" || message.length === 0) return null;
689
+ if (!message.includes("\"type\":\"error\"") && !message.includes("\"type\": \"error\"")) return null;
690
+ const start = message.indexOf("{");
691
+ if (start < 0) return null;
992
692
  try {
993
- return (await import("@earendil-works/pi-ai/providers/all")).getBuiltinModel;
693
+ const parsed = JSON.parse(message.slice(start));
694
+ if (!parsed || typeof parsed !== "object") return null;
695
+ const outer = parsed;
696
+ if (outer.type !== "error" || !outer.error || typeof outer.error !== "object") return null;
697
+ const inner = outer.error;
698
+ if (typeof inner.type !== "string") return null;
699
+ return {
700
+ type: inner.type,
701
+ message: typeof inner.message === "string" ? inner.message : inner.type
702
+ };
994
703
  } catch {
995
704
  return null;
996
705
  }
997
- });
706
+ }
998
707
  /**
999
- * Resolve a model's max output tokens. Prefers pi-ai's bundled registry — the
1000
- * authoritative source the SDK itself uses to build requests, so e.g. Opus 4.x
1001
- * reports its full native 128K (no extended-output beta required) — and falls
1002
- * back to {@link defaultAnthropicMaxTokens} only when the registry lacks the
1003
- * model. Used as BOTH the default (when the caller leaves `maxTokens` unset)
1004
- * and a hard clamp, since a `max_tokens` above the model's max would 400.
708
+ * Classify an Anthropic SDK / HTTP error for typed-error wrapping.
1005
709
  *
1006
- * The clamp is only as good as the ceiling's provenance, so an explicit caller
1007
- * `maxTokens` can RAISE the fallback: models the registry doesn't know are
1008
- * mostly ids that never appear in pi-ai's anthropic registry — Bedrock ids
1009
- * (`global.anthropic.claude-*`) and non-Anthropic models served over the
1010
- * Anthropic wire (`openai.gpt-*` on Bedrock, gateway aliases). For the
1011
- * latter the fallback degrades to the 32000 catch-all; for the former the
1012
- * family match yields a deliberately conservative non-beta floor. Clamping a
1013
- * caller who knows the real ceiling down to either silently truncates long
1014
- * generations mid-write (observed as turns pinned at exactly 32000 tokens).
1015
- *
1016
- * It can only raise, never lower: the caller's `maxTokens` is a cap on the
1017
- * VISIBLE response, already enforced as `max_tokens` itself, whereas this
1018
- * value is the model's physical ceiling. Letting it lower the ceiling would
1019
- * break the `enabled` thinking path's invariant that the budget sits ON TOP
1020
- * of the response cap — the budget would be shrunk to share the caller's cap,
1021
- * or dropped entirely once no satisfiable budget fits.
1022
- *
1023
- * A registry-backed max always wins over the caller — above it the provider
1024
- * 400s. A CATALOG entry (`behavior.modelCatalog` / `setModelCatalog`) outranks
1025
- * even that: it's an explicit claim about a model whose registry entry may be
1026
- * absent, stale, or an alias for something else entirely.
1027
- */
1028
- async function resolveAnthropicMaxOutput(modelId, explicitMaxTokens, catalog) {
1029
- const override = lookupModel("anthropic", modelId, catalog)?.maxTokens;
1030
- if (typeof override === "number" && override > 0) return override;
1031
- const registryMax = (await loadPiModelGetter())?.("anthropic", modelId)?.maxTokens;
1032
- if (typeof registryMax === "number" && registryMax > 0) return registryMax;
1033
- const fallback = defaultAnthropicMaxTokens(modelId);
1034
- return typeof explicitMaxTokens === "number" && explicitMaxTokens > 0 ? Math.max(fallback, explicitMaxTokens) : fallback;
1035
- }
1036
- /**
1037
- * Anthropic bills a 1h-TTL cache write at 2× base input against 1.25× for the
1038
- * default 5m TTL, but `cache_creation_input_tokens` (what `TurnUsage.
1039
- * cacheCreation` carries) is the SUM of both buckets. Registry `cacheWrite`
1040
- * rates are the 5m rate, so a turn that wrote under `ttl: '1h'` needs its
1041
- * write component scaled by `(5m·1.25 + 1h·2) / (total·1.25)`. `1` when the
1042
- * response carries no split (Bedrock, older API versions) or no 1h writes.
1043
- */
1044
- const CACHE_WRITE_1H_OVER_5M = 2 / 1.25;
1045
- function cacheWriteTtlMultiplier(usage) {
1046
- const split = usage.cache_creation;
1047
- const oneHour = split?.ephemeral_1h_input_tokens ?? 0;
1048
- if (oneHour <= 0) return 1;
1049
- const fiveMin = split?.ephemeral_5m_input_tokens ?? 0;
1050
- const total = usage.cache_creation_input_tokens ?? fiveMin + oneHour;
1051
- if (total <= 0) return 1;
1052
- return (fiveMin + oneHour * CACHE_WRITE_1H_OVER_5M) / total;
1053
- }
1054
- /** Per-rate product of two multipliers; a missing key on either side is `1`. */
1055
- function composeCostMultipliers(a, b) {
1056
- if (!a) return b;
1057
- if (!b) return a;
1058
- return {
1059
- input: (a.input ?? 1) * (b.input ?? 1),
1060
- output: (a.output ?? 1) * (b.output ?? 1),
1061
- cacheRead: (a.cacheRead ?? 1) * (b.cacheRead ?? 1),
1062
- cacheWrite: (a.cacheWrite ?? 1) * (b.cacheWrite ?? 1)
1063
- };
1064
- }
1065
- /**
1066
- * Price an API-key (non-OAuth) turn.
1067
- *
1068
- * - Bedrock traffic is looked up under pi-ai's `amazon-bedrock` registry: the
1069
- * echoed ids (`global.anthropic.claude-…`, `eu.anthropic.…`) never appear
1070
- * under `anthropic`, and Bedrock's regional uplifts only exist there.
1071
- * - The API may echo a dated snapshot for an alias request (`claude-haiku-4-5`
1072
- * → `claude-haiku-4-5-20251001`). Rates and the fast-mode multiplier are
1073
- * resolved by the echoed id first, then by the REQUESTED id, so a snapshot
1074
- * the registry doesn't list yet is still priced (and a fast-mode Opus turn
1075
- * keeps its 2× instead of silently billing at base). The echoed id stays on
1076
- * the record — only the price falls back.
1077
- * - 1h cache writes are scaled to their real rate (see
1078
- * {@link cacheWriteTtlMultiplier}); fast mode composes on top.
1079
- */
1080
- async function priceAnthropicUsage(raw, response, requestedModelId, fastRequested, bedrock, catalog) {
1081
- const providerKey = bedrock ? "amazon-bedrock" : "anthropic";
1082
- const echoedModelId = raw.modelId ?? requestedModelId;
1083
- const fast = fastRequested ? fastModeCostMultiplier(echoedModelId) ?? fastModeCostMultiplier(requestedModelId) : void 0;
1084
- const ttl = cacheWriteTtlMultiplier(response.usage);
1085
- const multiplier = composeCostMultipliers(fast, ttl === 1 ? void 0 : { cacheWrite: ttl });
1086
- const priced = await fillEstimatedCost(raw, providerKey, multiplier, catalog);
1087
- if (priced.cost !== void 0 || echoedModelId === requestedModelId) return priced;
1088
- const byRequested = await fillEstimatedCost({
1089
- ...raw,
1090
- modelId: requestedModelId
1091
- }, providerKey, multiplier, catalog);
1092
- return byRequested.cost !== void 0 ? {
1093
- ...raw,
1094
- cost: byRequested.cost
1095
- } : raw;
1096
- }
1097
- const EPHEMERAL = { type: "ephemeral" };
1098
- /**
1099
- * `cache_control` for the requested TTL. `'5m'` stays the bare ephemeral shape
1100
- * (no `ttl` field) so default-TTL requests are byte-identical to what every
1101
- * zidane version has ever sent — adding `ttl: '5m'` would be semantically
1102
- * equal but is gratuitous churn against proxies that pattern-match the body.
1103
- * `'1h'` also requires the `extended-cache-ttl-2025-04-11` beta header, which
1104
- * the request path adds — see {@link EXTENDED_CACHE_TTL_BETA}.
1105
- */
1106
- function cacheControlFor(ttl) {
1107
- return ttl === "1h" ? {
1108
- type: "ephemeral",
1109
- ttl: "1h"
1110
- } : EPHEMERAL;
1111
- }
1112
- /** Beta flag Anthropic requires before it honors `ttl: '1h'` on `cache_control`. */
1113
- const EXTENDED_CACHE_TTL_BETA = "extended-cache-ttl-2025-04-11";
1114
- /**
1115
- * Mutate an Anthropic request in place to add cache breakpoints on the three
1116
- * stable prefixes:
1117
- * 1. System prompt — `cache_control` on the static prefix only (see below).
1118
- * 2. Tool definitions — last tool.
1119
- * 3. Conversation — last content block of the last message.
1120
- *
1121
- * Each breakpoint tells Anthropic to cache the prefix ending at that block;
1122
- * subsequent turns reuse the cached prefix and pay only for the delta. Safe
1123
- * no-op when any prefix is empty (no tools, empty system, etc.).
1124
- *
1125
- * System-prompt boundary handling (`SYSTEM_PROMPT_BOUNDARY`):
1126
- *
1127
- * - When `originalSystem` is provided AND carries the marker, the system
1128
- * block is rewritten as a 2-block array: static (cached) then dynamic
1129
- * (uncached). The caller is expected to have already stripped the marker
1130
- * from `params.system` via {@link renderSystemForWire} — this helper
1131
- * only re-splits to apply `cache_control` cleanly.
1132
- * - When `originalSystem` is omitted or marker-free, the existing single-
1133
- * block treatment applies: `cache_control` on the whole system string.
1134
- * - Array system prompts: existing semantics — `cache_control` lands on the
1135
- * last block. Callers building their own multi-block layout own the
1136
- * breakpoint placement.
1137
- */
1138
- function applyAnthropicCacheBreakpoints(params, originalSystem, ttl) {
1139
- const cacheControl = cacheControlFor(ttl);
1140
- if (typeof params.system === "string") {
1141
- if (params.system.length > 0) {
1142
- const parts = splitSystemPrompt(originalSystem && originalSystem.length > 0 ? originalSystem : params.system);
1143
- if (parts.dynamic.length > 0) {
1144
- const blocks = [];
1145
- if (parts.static.length > 0) blocks.push({
1146
- type: "text",
1147
- text: parts.static,
1148
- cache_control: cacheControl
1149
- });
1150
- blocks.push({
1151
- type: "text",
1152
- text: parts.dynamic
1153
- });
1154
- params.system = blocks;
1155
- } else params.system = [{
1156
- type: "text",
1157
- text: parts.static,
1158
- cache_control: cacheControl
1159
- }];
1160
- }
1161
- } else if (Array.isArray(params.system) && params.system.length > 0) {
1162
- const lastIdx = params.system.length - 1;
1163
- params.system = params.system.map((block, i) => i === lastIdx ? {
1164
- ...block,
1165
- cache_control: cacheControl
1166
- } : block);
1167
- }
1168
- if (params.tools && params.tools.length > 0) {
1169
- const lastIdx = params.tools.length - 1;
1170
- params.tools = params.tools.map((tool, i) => i === lastIdx ? {
1171
- ...tool,
1172
- cache_control: cacheControl
1173
- } : tool);
1174
- }
1175
- if (params.messages.length === 0) return;
1176
- const lastMsgIdx = params.messages.length - 1;
1177
- const lastMsg = params.messages[lastMsgIdx];
1178
- if (typeof lastMsg.content === "string") {
1179
- if (lastMsg.content.length === 0) return;
1180
- params.messages[lastMsgIdx] = {
1181
- ...lastMsg,
1182
- content: [{
1183
- type: "text",
1184
- text: lastMsg.content,
1185
- cache_control: cacheControl
1186
- }]
1187
- };
1188
- return;
1189
- }
1190
- if (!Array.isArray(lastMsg.content) || lastMsg.content.length === 0) return;
1191
- const blocks = lastMsg.content;
1192
- let targetIdx = blocks.length - 1;
1193
- while (targetIdx >= 0 && isThinkingBlock(blocks[targetIdx])) targetIdx -= 1;
1194
- if (targetIdx < 0) return;
1195
- const nextBlocks = blocks.slice();
1196
- nextBlocks[targetIdx] = {
1197
- ...nextBlocks[targetIdx],
1198
- cache_control: cacheControl
1199
- };
1200
- params.messages[lastMsgIdx] = {
1201
- ...lastMsg,
1202
- content: nextBlocks
1203
- };
1204
- }
1205
- function isThinkingBlock(block) {
1206
- return block.type === "thinking" || block.type === "redacted_thinking";
1207
- }
1208
- /**
1209
- * Duck-type check for an Anthropic SDK `APIError` — avoids a runtime dependency
1210
- * on `@anthropic-ai/sdk` so `classifyError` stays usable even when the optional
1211
- * peer dep isn't loaded (e.g. host code calling it on an unrelated provider's
1212
- * error).
1213
- *
1214
- * Anthropic's APIError shape: `.status: number` + `.error` (parsed body, object
1215
- * or null). Plain `Error`s don't have `.status` + `.error`.
1216
- */
1217
- function looksLikeAnthropicApiError(err) {
1218
- if (!err || typeof err !== "object") return false;
1219
- const e = err;
1220
- return typeof e.status === "number" && "error" in e;
1221
- }
1222
- /**
1223
- * Anthropic SSE `error` event types that warrant a retry. `overloaded_error`
1224
- * is the headline case (capacity event mid-stream); `api_error` and
1225
- * `timeout_error` are both server-side transient failures. `invalid_request_error`,
1226
- * `authentication_error`, `permission_error`, `not_found_error`, `billing_error`
1227
- * are terminal — retrying them would just hammer a bad request.
1228
- *
1229
- * `rate_limit_error` here would be redundant: the SDK's pre-stream retry
1230
- * handles 429, and a mid-stream `rate_limit_error` is exceedingly rare. We
1231
- * include it anyway for symmetry with the HTTP-level retry policy.
1232
- */
1233
- const SSE_RETRYABLE_ERROR_TYPES = /* @__PURE__ */ new Set([
1234
- "overloaded_error",
1235
- "api_error",
1236
- "timeout_error",
1237
- "rate_limit_error"
1238
- ]);
1239
- /**
1240
- * Try to parse an Anthropic SSE `error` event payload out of a thrown error's
1241
- * message. The SDK's `MessageStream` surfaces mid-stream error events by
1242
- * throwing an `AnthropicError` whose `.message` contains the raw JSON shape:
1243
- *
1244
- * {"type":"error","error":{"type":"overloaded_error","message":"Overloaded"},"request_id":"req_..."}
1245
- *
1246
- * Returns the inner `{ type, message }` or `null` when the message isn't
1247
- * the canonical SSE error shape. Tolerant: silently returns `null` for
1248
- * non-string input, non-JSON content, or any shape mismatch.
1249
- */
1250
- function matchSseErrorEvent(message) {
1251
- if (typeof message !== "string" || message.length === 0) return null;
1252
- if (!message.includes("\"type\":\"error\"") && !message.includes("\"type\": \"error\"")) return null;
1253
- const start = message.indexOf("{");
1254
- if (start < 0) return null;
1255
- try {
1256
- const parsed = JSON.parse(message.slice(start));
1257
- if (!parsed || typeof parsed !== "object") return null;
1258
- const outer = parsed;
1259
- if (outer.type !== "error" || !outer.error || typeof outer.error !== "object") return null;
1260
- const inner = outer.error;
1261
- if (typeof inner.type !== "string") return null;
1262
- return {
1263
- type: inner.type,
1264
- message: typeof inner.message === "string" ? inner.message : inner.type
1265
- };
1266
- } catch {
1267
- return null;
1268
- }
1269
- }
1270
- /**
1271
- * Classify an Anthropic SDK / HTTP error for typed-error wrapping.
1272
- *
1273
- * - `prompt is too long` (400 invalid_request_error) → `context_exceeded`.
1274
- * - `'tool_use' ids were found without 'tool_result' blocks` /
1275
- * `'tool_result must be preceded by a tool_call'` (400) →
1276
- * `tool_pairing_corruption`. The local repair pass should have caught
1277
- * this — the typed error tells consumers their pre-send pipeline is
1278
- * shipping orphaned blocks somehow (custom `context:transform` hook,
1279
- * bypassed loop, mid-stream session edit) so they can patch the root
1280
- * cause instead of chasing 400s.
1281
- * - Any other Anthropic `APIError`-shaped value → `provider_error` with the
1282
- * native status/type code.
1283
- * - Unknown errors → `null` (loop wraps in `AgentProviderError` generically).
710
+ * - `prompt is too long` (400 invalid_request_error) → `context_exceeded`.
711
+ * - `'tool_use' ids were found without 'tool_result' blocks` /
712
+ * `'tool_result must be preceded by a tool_call'` (400) →
713
+ * `tool_pairing_corruption`. The local repair pass should have caught
714
+ * this — the typed error tells consumers their pre-send pipeline is
715
+ * shipping orphaned blocks somehow (custom `context:transform` hook,
716
+ * bypassed loop, mid-stream session edit) so they can patch the root
717
+ * cause instead of chasing 400s.
718
+ * - Any other Anthropic `APIError`-shaped value → `provider_error` with the
719
+ * native status/type code.
720
+ * - Unknown errors → `null` (loop wraps in `AgentProviderError` generically).
1284
721
  *
1285
722
  * Anthropic's wire error shape is `{ type: 'error', error: { type, message } }` — the
1286
723
  * SDK stores the parsed body on `err.error`. We walk both levels so callers see the
@@ -1344,7 +781,15 @@ function shouldFallbackFromFastMode(err) {
1344
781
  return /\b(?:fast|speed)\b/i.test(message) && /capacity|overload|rate|unavailable|unsupported|not supported|not permitted|extra inputs|invalid/i.test(message);
1345
782
  }
1346
783
  /**
1347
- * Anthropic signs thinking blocks so they can be echoed through tool-use
784
+ * The 400 the API returns under `prefix_mismatch_behavior: "error"` for a
785
+ * replayed block whose prefix changed. Distinct from a corrupt/tampered
786
+ * signature: this one names the binding and the remedy.
787
+ */
788
+ function isPrefixMismatchError(err) {
789
+ return /bound to a different conversation|prefix_mismatch_behavior/i.test(errorText(err));
790
+ }
791
+ /**
792
+ * Anthropic signs thinking blocks so they can be echoed through tool-use
1348
793
  * chains without exposing raw reasoning. A signature can become
1349
794
  * unverifiable after a model/route/account switch, a legacy session edit,
1350
795
  * or a provider-side signing-key rotation. We cannot validate the opaque
@@ -1442,24 +887,6 @@ function parseFailingMessageIndex(err) {
1442
887
  return Number.isSafeInteger(index) ? index : void 0;
1443
888
  }
1444
889
  /**
1445
- * Hard cap on signature-400 scrub retries within one `stream()` call. Two
1446
- * passes resolve every real-world shape (bounded pass, then the
1447
- * everything-but-active-chain pass); the third is margin. Beyond that the
1448
- * error is not signature poisoning and must surface.
1449
- */
1450
- const MAX_THINKING_SCRUB_PASSES = 3;
1451
- /**
1452
- * Models observed rejecting forced tool use, so later calls skip straight to
1453
- * the downgraded shape instead of paying the failing round-trip every time.
1454
- *
1455
- * Learned, not declared: Claude Fable 5.1 is the first model where
1456
- * `tool_choice` of `tool` / `any` returns 400, and a catalog flag would need
1457
- * upkeep for every successor that follows suit. Process-wide and keyed by
1458
- * model id only — whether a model accepts forcing is a property of the model,
1459
- * not of the endpoint or credential serving it.
1460
- */
1461
- const MODELS_REJECTING_FORCED_TOOL_CHOICE = /* @__PURE__ */ new Set();
1462
- /**
1463
890
  * True for the 400 Anthropic returns when a model does not support forcing a
1464
891
  * tool: `tool_choice: type "tool" and "any" are not supported for this model.`
1465
892
  * Anchored on the status/type gate plus the field name and the "not supported
@@ -1493,174 +920,1313 @@ function isThinkingBindingRejectedError(err) {
1493
920
  const text = errorText(err);
1494
921
  return /block_binding|prefix_mismatch_behavior|thinking-binding-controls/i.test(text) && !/invalid\s+`?signature`?|bound to a different conversation/i.test(text);
1495
922
  }
1496
- /** The same request with `thinking.block_binding` removed. */
1497
- function withoutThinkingBinding(params) {
1498
- if (!params.thinking) return params;
1499
- const { block_binding: _dropped, ...thinking } = params.thinking;
1500
- return {
1501
- ...params,
1502
- thinking
923
+ /**
924
+ * True for the 400 Anthropic returns when a model does not support the manual
925
+ * extended-thinking shape: `"thinking.type.enabled" is not supported for this
926
+ * model. Use "thinking.type.adaptive" and "output_config.effort" ...`. Anchored
927
+ * on the validation-400 gate plus the dotted field name and the "not supported
928
+ * for this model" tail, so a reworded middle still matches while an unrelated
929
+ * `thinking` validation error (bad budget, wrong type) does not. Only the
930
+ * `enabled` variant is matched: zidane omits the field for the `'off'` level
931
+ * (adaptive on these models) and never emits `thinking.type.disabled`.
932
+ */
933
+ function isEnabledThinkingUnsupportedError(err) {
934
+ return isRequestValidationError(err) && /\bthinking\.type\.enabled\b[^.]+not supported for this model\b/i.test(errorText(err));
935
+ }
936
+ //#endregion
937
+ //#region src/providers/anthropic-cache.ts
938
+ const EPHEMERAL = { type: "ephemeral" };
939
+ /**
940
+ * `cache_control` for the requested TTL. `'5m'` stays the bare ephemeral shape
941
+ * (no `ttl` field) so default-TTL requests are byte-identical to what every
942
+ * zidane version has ever sent — adding `ttl: '5m'` would be semantically
943
+ * equal but is gratuitous churn against proxies that pattern-match the body.
944
+ * `'1h'` also requires the `extended-cache-ttl-2025-04-11` beta header, which
945
+ * the request path adds — see {@link EXTENDED_CACHE_TTL_BETA}.
946
+ */
947
+ function cacheControlFor(ttl) {
948
+ return ttl === "1h" ? {
949
+ type: "ephemeral",
950
+ ttl: "1h"
951
+ } : EPHEMERAL;
952
+ }
953
+ /** Beta flag Anthropic requires before it honors `ttl: '1h'` on `cache_control`. */
954
+ const EXTENDED_CACHE_TTL_BETA = "extended-cache-ttl-2025-04-11";
955
+ /** Anthropic's per-request limit on `cache_control` markers. */
956
+ const MAX_CACHE_BREAKPOINTS = 4;
957
+ /**
958
+ * Mutate an Anthropic request in place to add cache breakpoints on the three
959
+ * stable prefixes:
960
+ * 1. System prompt — `cache_control` on the static prefix only (see below).
961
+ * 2. Tool definitions — last tool.
962
+ * 3. Conversation — last content block of the last message.
963
+ *
964
+ * Each breakpoint tells Anthropic to cache the prefix ending at that block;
965
+ * subsequent turns reuse the cached prefix and pay only for the delta. Safe
966
+ * no-op when any prefix is empty (no tools, empty system, etc.).
967
+ *
968
+ * System-prompt boundary handling (`SYSTEM_PROMPT_BOUNDARY`):
969
+ *
970
+ * - When `originalSystem` is provided AND carries the marker, the system
971
+ * block is rewritten as a 2-block array: static (cached) then dynamic
972
+ * (uncached). The caller is expected to have already stripped the marker
973
+ * from `params.system` via {@link renderSystemForWire} — this helper
974
+ * only re-splits to apply `cache_control` cleanly.
975
+ * - When `originalSystem` is omitted or marker-free, the existing single-
976
+ * block treatment applies: `cache_control` on the whole system string.
977
+ * - Array system prompts: existing semantics — `cache_control` lands on the
978
+ * last block. Callers building their own multi-block layout own the
979
+ * breakpoint placement.
980
+ */
981
+ function applyAnthropicCacheBreakpoints(params, originalSystem, ttl) {
982
+ const cacheControl = cacheControlFor(ttl);
983
+ if (typeof params.system === "string") {
984
+ if (params.system.length > 0) {
985
+ const splitSource = originalSystem && originalSystem.length > 0 ? originalSystem : params.system;
986
+ const parts = splitSystemPrompt(splitSource);
987
+ if (parts.dynamic.length > 0) {
988
+ const blocks = [];
989
+ if (parts.static.length > 0) blocks.push({
990
+ type: "text",
991
+ text: parts.static,
992
+ cache_control: cacheControl
993
+ });
994
+ blocks.push({
995
+ type: "text",
996
+ text: parts.dynamic
997
+ });
998
+ params.system = blocks;
999
+ } else params.system = [{
1000
+ type: "text",
1001
+ text: parts.static,
1002
+ cache_control: cacheControl
1003
+ }];
1004
+ }
1005
+ } else if (Array.isArray(params.system) && params.system.length > 0) {
1006
+ const lastIdx = params.system.length - 1;
1007
+ params.system = params.system.map((block, i) => i === lastIdx ? {
1008
+ ...block,
1009
+ cache_control: cacheControl
1010
+ } : block);
1011
+ }
1012
+ if (params.tools && params.tools.length > 0) {
1013
+ const lastIdx = params.tools.length - 1;
1014
+ params.tools = params.tools.map((tool, i) => i === lastIdx ? {
1015
+ ...tool,
1016
+ cache_control: cacheControl
1017
+ } : tool);
1018
+ }
1019
+ if (params.messages.length === 0) return;
1020
+ const lastMsgIdx = params.messages.length - 1;
1021
+ markMessageBreakpoint(params.messages, lastMsgIdx, cacheControl);
1022
+ if (countCacheBreakpoints(params) >= MAX_CACHE_BREAKPOINTS) return;
1023
+ for (let i = lastMsgIdx - 1; i >= 0; i--) {
1024
+ if (params.messages[i].role !== "user") continue;
1025
+ if (i < lastMsgIdx - 1) markMessageBreakpoint(params.messages, i, cacheControl);
1026
+ break;
1027
+ }
1028
+ }
1029
+ /** Put `cache_control` on the last cache-eligible block of `messages[idx]`. */
1030
+ function markMessageBreakpoint(messages, idx, cacheControl) {
1031
+ const msg = messages[idx];
1032
+ if (typeof msg.content === "string") {
1033
+ if (msg.content.length === 0) return;
1034
+ messages[idx] = {
1035
+ ...msg,
1036
+ content: [{
1037
+ type: "text",
1038
+ text: msg.content,
1039
+ cache_control: cacheControl
1040
+ }]
1041
+ };
1042
+ return;
1043
+ }
1044
+ if (!Array.isArray(msg.content) || msg.content.length === 0) return;
1045
+ const blocks = msg.content;
1046
+ let targetIdx = blocks.length - 1;
1047
+ while (targetIdx >= 0 && isThinkingBlock(blocks[targetIdx])) targetIdx -= 1;
1048
+ if (targetIdx < 0) return;
1049
+ const nextBlocks = blocks.slice();
1050
+ nextBlocks[targetIdx] = {
1051
+ ...nextBlocks[targetIdx],
1052
+ cache_control: cacheControl
1053
+ };
1054
+ messages[idx] = {
1055
+ ...msg,
1056
+ content: nextBlocks
1057
+ };
1058
+ }
1059
+ function hasCacheControl(value) {
1060
+ return typeof value === "object" && value !== null && value.cache_control != null;
1061
+ }
1062
+ function countCacheBreakpoints(params) {
1063
+ let count = 0;
1064
+ if (Array.isArray(params.system)) {
1065
+ for (const block of params.system) if (hasCacheControl(block)) count++;
1066
+ }
1067
+ for (const tool of params.tools ?? []) if (hasCacheControl(tool)) count++;
1068
+ for (const msg of params.messages) {
1069
+ if (!Array.isArray(msg.content)) continue;
1070
+ for (const block of msg.content) if (hasCacheControl(block)) count++;
1071
+ else if (block.type === "tool_result" && Array.isArray(block.content)) {
1072
+ for (const part of block.content) if (hasCacheControl(part)) count++;
1073
+ }
1074
+ }
1075
+ return count;
1076
+ }
1077
+ function isThinkingBlock(block) {
1078
+ return block.type === "thinking" || block.type === "redacted_thinking";
1079
+ }
1080
+ //#endregion
1081
+ //#region src/providers/anthropic-thinking.ts
1082
+ /** Gates `thinking.block_binding` and the `input_transformations` response field. */
1083
+ const THINKING_BINDING_BETA = "thinking-binding-controls-2026-08-01";
1084
+ const THINKING_BINDING_BEHAVIORS = /* @__PURE__ */ new Set([
1085
+ "drop_block",
1086
+ "error",
1087
+ "off"
1088
+ ]);
1089
+ /**
1090
+ * Env channel the chat host writes the user's `thinkingBinding` SETTING to.
1091
+ * Distinct from `ZIDANE_THINKING_BINDING` (the shell override) so the two
1092
+ * never read each other back: a host recreated in-process must not mistake
1093
+ * an earlier host's setting write for a shell value.
1094
+ */
1095
+ const THINKING_BINDING_SETTING_ENV = "ZIDANE_THINKING_BINDING_SETTING";
1096
+ /**
1097
+ * Effective {@link AnthropicParams.thinkingBinding}: the explicit param wins,
1098
+ * then the shell's `ZIDANE_THINKING_BINDING`, then the chat host's setting
1099
+ * channel ({@link THINKING_BINDING_SETTING_ENV}), then `'drop_block'`. Read
1100
+ * per request so a flip lands on the next call without rebuilding the
1101
+ * provider (the factory is no-arg in the chat host). Unrecognized values are
1102
+ * ignored at each level.
1103
+ */
1104
+ function resolveThinkingBinding(param, env = process.env) {
1105
+ if (param !== void 0) return param;
1106
+ for (const key of ["ZIDANE_THINKING_BINDING", THINKING_BINDING_SETTING_ENV]) {
1107
+ const value = env[key]?.trim();
1108
+ if (value && THINKING_BINDING_BEHAVIORS.has(value)) return value;
1109
+ }
1110
+ return "drop_block";
1111
+ }
1112
+ /**
1113
+ * Output tokens reserved for the visible response when an explicit thinking
1114
+ * budget must be shrunk to fit under the model's `max_tokens` ceiling — see
1115
+ * the budget clamp in `buildAnthropicStreamRequest` (`./anthropic-request`).
1116
+ */
1117
+ const THINKING_RESPONSE_RESERVE_TOKENS = 1024;
1118
+ /**
1119
+ * Explicit thinking budgets for Bedrock, per effort tier. Bedrock's
1120
+ * anthropic-native path only accepts the legacy
1121
+ * `thinking: { type: 'enabled', budget_tokens }` shape (the 4.6 surface —
1122
+ * `output_config.effort`, adaptive, `display` — is rejected by its
1123
+ * translation layer), so effort tiers degrade to token budgets. Floor is
1124
+ * Anthropic's 1024 minimum; ceilings stay well under haiku/sonnet output
1125
+ * caps — the request builder clamps against the model ceiling regardless.
1126
+ */
1127
+ const BEDROCK_THINKING_BUDGETS = {
1128
+ low: 4096,
1129
+ medium: 12288,
1130
+ high: 24576,
1131
+ xhigh: 32768,
1132
+ max: 32768
1133
+ };
1134
+ /**
1135
+ * Map `ThinkingLevel` budgeted tiers to Anthropic's `output_config.effort`
1136
+ * enum. `minimal` collapses to `low` (the closest equivalent — Anthropic does
1137
+ * not have a sub-`low` tier).
1138
+ */
1139
+ const EFFORT_FOR_LEVEL = {
1140
+ minimal: "low",
1141
+ low: "low",
1142
+ medium: "medium",
1143
+ high: "high",
1144
+ xhigh: "xhigh",
1145
+ max: "max"
1146
+ };
1147
+ /**
1148
+ * Decide how to translate a `ThinkingLevel` into Anthropic's request shape.
1149
+ * Pure / synchronous — exported so tests can assert routing without standing
1150
+ * up the SDK.
1151
+ *
1152
+ * Routing rules:
1153
+ * - `'off'` → `null` (no thinking field, no effort hint).
1154
+ * - `'adaptive'` → adaptive thinking with no effort hint (model decides
1155
+ * everything). When `taskBudget` is set, it is carried as
1156
+ * `taskBudgetTokens` and emitted as `output_config.task_budget` — the
1157
+ * native whole-task thinking cap. LEGACY: when `customBudget` is set, it
1158
+ * is carried as `maxTokensCap` so the request builder caps `max_tokens`
1159
+ * accordingly — this clamps the whole response envelope (text and
1160
+ * tool-call JSON included), which is the wrong knob for bounding thinking
1161
+ * now that `taskBudget` exists; kept only for callers who already depend
1162
+ * on it. Prefer `taskBudget`.
1163
+ * - Budgeted levels → adaptive thinking with an `effort` hint (plus
1164
+ * `taskBudgetTokens` when `taskBudget` is set), unless `customBudget` is
1165
+ * provided.
1166
+ * - Any level + `customBudget` → explicit-budget `enabled` path, carrying
1167
+ * the level's `effort` hint alongside the budget. The caller has opted
1168
+ * into precise budget control and accepts the Anthropic deprecation
1169
+ * warning that comes with it on opus 4.6+. `'adaptive'` is the sole
1170
+ * exception: it never falls back to enabled, since adaptive is the
1171
+ * current Anthropic API surface for self-budgeted thinking. `taskBudget`
1172
+ * is adaptive-only and ignored on this path.
1173
+ * - `effortHint: false` (default `true`) strips the `effort` hint from
1174
+ * every shape — budgeted levels plan plain adaptive and the
1175
+ * `customBudget` path plans `enabled` with no `output_config.effort` —
1176
+ * for Anthropic models that reject the effort field.
1177
+ */
1178
+ function planAnthropicThinking(level, customBudget, taskBudget, effortHint = true) {
1179
+ if (level === "off") return null;
1180
+ const taskBudgetTokens = typeof taskBudget === "number" && taskBudget > 0 ? taskBudget : void 0;
1181
+ if (level === "adaptive") return {
1182
+ kind: "adaptive",
1183
+ ...typeof customBudget === "number" && customBudget > 0 ? { maxTokensCap: customBudget } : {},
1184
+ ...taskBudgetTokens !== void 0 ? { taskBudgetTokens } : {}
1185
+ };
1186
+ if (customBudget !== void 0) return {
1187
+ kind: "enabled",
1188
+ budgetTokens: customBudget,
1189
+ maxTokensBump: customBudget,
1190
+ ...effortHint ? { effort: EFFORT_FOR_LEVEL[level] } : {}
1191
+ };
1192
+ return {
1193
+ kind: "adaptive",
1194
+ ...effortHint ? { effort: EFFORT_FOR_LEVEL[level] } : {},
1195
+ ...taskBudgetTokens !== void 0 ? { taskBudgetTokens } : {}
1196
+ };
1197
+ }
1198
+ //#endregion
1199
+ //#region src/providers/anthropic-request.ts
1200
+ /**
1201
+ * Conservative per-family output ceiling, used ONLY as a fallback when pi-ai's
1202
+ * model registry doesn't know the model (or pi-ai is externalized) — see
1203
+ * {@link resolveAnthropicMaxOutput}, which is the primary path. These are
1204
+ * non-beta floors we can always send without a 400; the registry reports the
1205
+ * real (often much higher, e.g. Opus 4.x = 128K native) max when available.
1206
+ */
1207
+ function defaultAnthropicMaxTokens(modelId) {
1208
+ const id = modelId.toLowerCase();
1209
+ if (id.includes("haiku")) return 8192;
1210
+ if (id.includes("sonnet")) return 64e3;
1211
+ return 32e3;
1212
+ }
1213
+ /**
1214
+ * Lazily-loaded pi-ai model-registry getter (cached; keeps the multi-MB
1215
+ * registry out of the static bundle, mirroring `cost.ts`). Returns `null` when
1216
+ * pi-ai is externalized, in which case callers fall back to the family map.
1217
+ */
1218
+ const loadPiModelGetter = lazyAsync(async () => {
1219
+ try {
1220
+ return (await import("@earendil-works/pi-ai/providers/all")).getBuiltinModel;
1221
+ } catch {
1222
+ return null;
1223
+ }
1224
+ });
1225
+ /**
1226
+ * Resolve a model's max output tokens. Prefers pi-ai's bundled registry — the
1227
+ * authoritative source the SDK itself uses to build requests, so e.g. Opus 4.x
1228
+ * reports its full native 128K (no extended-output beta required) — and falls
1229
+ * back to {@link defaultAnthropicMaxTokens} only when the registry lacks the
1230
+ * model. Used as BOTH the default (when the caller leaves `maxTokens` unset)
1231
+ * and a hard clamp, since a `max_tokens` above the model's max would 400.
1232
+ *
1233
+ * The clamp is only as good as the ceiling's provenance, so an explicit caller
1234
+ * `maxTokens` can RAISE the fallback: models the registry doesn't know are
1235
+ * mostly ids that never appear in pi-ai's anthropic registry — Bedrock ids
1236
+ * (`global.anthropic.claude-*`) and non-Anthropic models served over the
1237
+ * Anthropic wire (`openai.gpt-*` on Bedrock, gateway aliases). For the
1238
+ * latter the fallback degrades to the 32000 catch-all; for the former the
1239
+ * family match yields a deliberately conservative non-beta floor. Clamping a
1240
+ * caller who knows the real ceiling down to either silently truncates long
1241
+ * generations mid-write (observed as turns pinned at exactly 32000 tokens).
1242
+ *
1243
+ * It can only raise, never lower: the caller's `maxTokens` is a cap on the
1244
+ * VISIBLE response, already enforced as `max_tokens` itself, whereas this
1245
+ * value is the model's physical ceiling. Letting it lower the ceiling would
1246
+ * break the `enabled` thinking path's invariant that the budget sits ON TOP
1247
+ * of the response cap — the budget would be shrunk to share the caller's cap,
1248
+ * or dropped entirely once no satisfiable budget fits.
1249
+ *
1250
+ * A registry-backed max always wins over the caller — above it the provider
1251
+ * 400s. A CATALOG entry (`behavior.modelCatalog` / `setModelCatalog`) outranks
1252
+ * even that: it's an explicit claim about a model whose registry entry may be
1253
+ * absent, stale, or an alias for something else entirely.
1254
+ */
1255
+ async function resolveAnthropicMaxOutput(modelId, explicitMaxTokens, catalog) {
1256
+ const override = lookupModel("anthropic", modelId, catalog)?.maxTokens;
1257
+ if (typeof override === "number" && override > 0) return override;
1258
+ const registryMax = (await loadPiModelGetter())?.("anthropic", modelId)?.maxTokens;
1259
+ if (typeof registryMax === "number" && registryMax > 0) return registryMax;
1260
+ const fallback = defaultAnthropicMaxTokens(modelId);
1261
+ return typeof explicitMaxTokens === "number" && explicitMaxTokens > 0 ? Math.max(fallback, explicitMaxTokens) : fallback;
1262
+ }
1263
+ /**
1264
+ * Build the Messages request body for one `stream()` call: system block (and
1265
+ * the OAuth persona fold), tool-name boundary, max-output resolution, cache
1266
+ * breakpoints, thinking shape, Claude Code alignment, fast mode, tool choice,
1267
+ * and the prompt-cache affinity key/header.
1268
+ */
1269
+ async function buildAnthropicStreamRequest(input) {
1270
+ const { anthropicParams, bedrockConfig, options, callIsOAuth, effectiveCacheTtl, extendedTtl, plan, thinkingBinding, bindingActive, resolvedExtraHeaders } = input;
1271
+ const { system, messages } = foldSystemForWire(options.system, options.messages, callIsOAuth);
1272
+ const inputTools = options.tools ?? [];
1273
+ const nameBoundary = createToolNameBoundary(messages, inputTools.map((t) => t.name), callIsOAuth ? claudeCodeToolAliases : void 0);
1274
+ const wireTools = nameBoundary.changed ? inputTools.map((t) => t.name === nameBoundary.toWire(t.name) ? t : {
1275
+ ...t,
1276
+ name: nameBoundary.toWire(t.name)
1277
+ }) : inputTools;
1278
+ const modelId = options.model;
1279
+ const modelMaxOutput = await resolveAnthropicMaxOutput(modelId, options.maxTokens, options.modelCatalog);
1280
+ const params = {
1281
+ ...anthropicParams?.extraBodyParams ?? {},
1282
+ model: modelId,
1283
+ max_tokens: options.maxTokens ?? modelMaxOutput,
1284
+ system,
1285
+ tools: wireTools,
1286
+ messages: nameBoundary.messages.map((m) => toAnthropic(m)),
1287
+ stream: true
1288
+ };
1289
+ if (anthropicParams?.contextManagement && !bedrockConfig) params.context_management = anthropicParams.contextManagement;
1290
+ if (options.cache !== false) applyAnthropicCacheBreakpoints(params, callIsOAuth ? void 0 : options.system, extendedTtl ? effectiveCacheTtl : void 0);
1291
+ applyAnthropicThinkingPlan(params, plan, bedrockConfig, bindingActive, thinkingBinding);
1292
+ params.max_tokens = Math.min(params.max_tokens, modelMaxOutput);
1293
+ if (callIsOAuth) alignClaudeCodePayload(params);
1294
+ fitThinkingBudgetUnderEnvelope(params);
1295
+ if (options.modelOptions?.fast && !callIsOAuth) params.speed = "fast";
1296
+ if (options.toolChoice) {
1297
+ if (options.toolChoice.type === "tool" && options.toolChoice.name) params.tool_choice = {
1298
+ type: "tool",
1299
+ name: nameBoundary.toWire(options.toolChoice.name)
1300
+ };
1301
+ else if (options.toolChoice.type === "required") params.tool_choice = { type: "any" };
1302
+ else params.tool_choice = { type: "auto" };
1303
+ }
1304
+ const promptCacheKey = resolvePromptCacheKey(anthropicParams?.promptCacheKey, {
1305
+ model: modelId,
1306
+ system: options.system,
1307
+ messages: options.messages
1308
+ });
1309
+ if (promptCacheKey !== void 0 && params.metadata?.user_id === void 0) params.metadata = {
1310
+ ...params.metadata,
1311
+ user_id: promptCacheKey
1312
+ };
1313
+ const affinityHeaderName = anthropicParams?.promptCacheKeyHeader?.toLowerCase();
1314
+ return {
1315
+ params,
1316
+ nameBoundary,
1317
+ modelId,
1318
+ affinityHeader: anthropicParams?.promptCacheKeyHeader !== void 0 && promptCacheKey !== void 0 && !Object.keys(resolvedExtraHeaders ?? {}).some((k) => k.toLowerCase() === affinityHeaderName) ? { [anthropicParams.promptCacheKeyHeader]: promptCacheKey } : void 0
1319
+ };
1320
+ }
1321
+ /** Set the thinking fields (and the max-tokens/temperature they imply) from the plan. */
1322
+ function applyAnthropicThinkingPlan(params, plan, bedrockConfig, bindingActive, thinkingBinding) {
1323
+ if (plan && bedrockConfig) {
1324
+ const budget = plan.kind === "enabled" ? plan.budgetTokens : BEDROCK_THINKING_BUDGETS[plan.effort ?? "medium"];
1325
+ params.thinking = {
1326
+ type: "enabled",
1327
+ budget_tokens: budget
1328
+ };
1329
+ params.max_tokens = budget + params.max_tokens;
1330
+ params.temperature = 1;
1331
+ } else if (plan) {
1332
+ if (plan.kind === "enabled") {
1333
+ params.thinking = {
1334
+ type: "enabled",
1335
+ budget_tokens: plan.budgetTokens,
1336
+ display: "summarized"
1337
+ };
1338
+ params.max_tokens = plan.maxTokensBump + params.max_tokens;
1339
+ if (plan.effort) params.output_config = {
1340
+ ...params.output_config,
1341
+ effort: plan.effort
1342
+ };
1343
+ } else {
1344
+ params.thinking = {
1345
+ type: "adaptive",
1346
+ display: "summarized"
1347
+ };
1348
+ const outputConfig = {};
1349
+ if (plan.effort) outputConfig.effort = plan.effort;
1350
+ if (typeof plan.taskBudgetTokens === "number" && plan.taskBudgetTokens > 0) outputConfig.task_budget = {
1351
+ type: "tokens",
1352
+ total: plan.taskBudgetTokens
1353
+ };
1354
+ if (Object.keys(outputConfig).length > 0) params.output_config = {
1355
+ ...params.output_config,
1356
+ ...outputConfig
1357
+ };
1358
+ if (typeof plan.maxTokensCap === "number" && plan.maxTokensCap > 0) params.max_tokens = Math.min(params.max_tokens, plan.maxTokensCap);
1359
+ }
1360
+ params.temperature = 1;
1361
+ if (bindingActive) params.thinking.block_binding = { prefix_mismatch_behavior: thinkingBinding };
1362
+ }
1363
+ }
1364
+ /** Claude Code payload alignment for the OAuth persona (output cap, billing block, `user_id`). */
1365
+ function alignClaudeCodePayload(params) {
1366
+ params.max_tokens = Math.min(params.max_tokens, CLAUDE_CODE_MAX_OUTPUT_TOKENS);
1367
+ if (Array.isArray(params.system)) params.system = [{
1368
+ type: "text",
1369
+ text: claudeCodeBillingText(firstUserMessageText(params.messages))
1370
+ }, ...params.system];
1371
+ if (typeof params.metadata?.user_id !== "string") params.metadata = {
1372
+ ...params.metadata,
1373
+ user_id: claudeCodeUserId()
1374
+ };
1375
+ }
1376
+ function fitThinkingBudgetUnderEnvelope(params) {
1377
+ if (params.thinking?.type === "enabled" && params.thinking.budget_tokens >= params.max_tokens) {
1378
+ const fitted = params.max_tokens - THINKING_RESPONSE_RESERVE_TOKENS;
1379
+ if (fitted >= 1024) params.thinking.budget_tokens = fitted;
1380
+ else {
1381
+ delete params.thinking;
1382
+ delete params.temperature;
1383
+ }
1384
+ }
1385
+ }
1386
+ //#endregion
1387
+ //#region src/providers/anthropic-retry.ts
1388
+ /**
1389
+ * Models observed rejecting forced tool use, so later calls skip straight to
1390
+ * the downgraded shape instead of paying the failing round-trip every time.
1391
+ *
1392
+ * Learned, not declared: Claude Fable 5.1 is the first model where
1393
+ * `tool_choice` of `tool` / `any` returns 400, and a catalog flag would need
1394
+ * upkeep for every successor that follows suit. Process-wide and keyed by
1395
+ * model id only — whether a model accepts forcing is a property of the model,
1396
+ * not of the endpoint or credential serving it.
1397
+ */
1398
+ const MODELS_REJECTING_FORCED_TOOL_CHOICE = /* @__PURE__ */ new Set();
1399
+ /** The same request with `thinking.block_binding` removed. */
1400
+ function withoutThinkingBinding(params) {
1401
+ if (!params.thinking) return params;
1402
+ const { block_binding: _dropped, ...thinking } = params.thinking;
1403
+ return {
1404
+ ...params,
1405
+ thinking
1406
+ };
1407
+ }
1408
+ function isForcedToolChoice(choice) {
1409
+ return choice?.type === "tool" || choice?.type === "any";
1410
+ }
1411
+ /**
1412
+ * Models observed rejecting the explicit-budget thinking shape
1413
+ * (`thinking: { type: 'enabled', budget_tokens }`), so later calls skip the
1414
+ * failing round-trip and downgrade to adaptive up front.
1415
+ *
1416
+ * Learned, not declared — same rationale as
1417
+ * {@link MODELS_REJECTING_FORCED_TOOL_CHOICE}. Claude Opus 5.5 is the first
1418
+ * model where the `enabled` shape 400s (adaptive-only, thinking always on);
1419
+ * successors that follow suit are caught without a catalog edit.
1420
+ */
1421
+ const MODELS_REJECTING_ENABLED_THINKING = /* @__PURE__ */ new Set();
1422
+ function isEnabledThinking(thinking) {
1423
+ return thinking?.type === "enabled";
1424
+ }
1425
+ /**
1426
+ * The same request with the explicit budget dropped: `thinking.type` flipped to
1427
+ * `adaptive`, `budget_tokens` removed, every other thinking field
1428
+ * (`display`, `block_binding`) kept. `temperature` stays pinned to 1 (adaptive
1429
+ * requires it, same as the enabled shape) and the budget-inflated `max_tokens`
1430
+ * is left as-is — it is already clamped to the model ceiling and an oversized
1431
+ * envelope is harmless for adaptive, which thinks and replies inside it. Any
1432
+ * `output_config.effort` the enabled path set survives on `params.output_config`.
1433
+ */
1434
+ function withoutEnabledThinking(params) {
1435
+ const thinking = params.thinking;
1436
+ if (!thinking || thinking.type !== "enabled") return params;
1437
+ const { budget_tokens: _dropped, type: _type, ...rest } = thinking;
1438
+ return {
1439
+ ...params,
1440
+ thinking: {
1441
+ ...rest,
1442
+ type: "adaptive"
1443
+ }
1444
+ };
1445
+ }
1446
+ /**
1447
+ * The same request with forcing removed: `tool_choice: auto` plus one trailing
1448
+ * system sentence naming what the model was being forced into.
1449
+ *
1450
+ * The sentence is load-bearing, not decoration. `enforceSchemaOutput` sends the
1451
+ * agent's own system prompt, which says nothing about `__output__` — forcing
1452
+ * was the whole instruction — so without it a model on `auto` can legitimately
1453
+ * answer in prose and the caller's "no structured payload" guard fires. It is
1454
+ * appended as a final uncached block: everything before it keeps its cache
1455
+ * prefix, and the downgrade adds no new breakpoint.
1456
+ */
1457
+ function withoutForcedToolChoice(params) {
1458
+ const choice = params.tool_choice;
1459
+ const nudge = choice?.type === "tool" ? `Respond only by calling the \`${choice.name}\` tool. Do not reply with prose.` : "Respond only by calling one of the provided tools. Do not reply with prose.";
1460
+ const system = typeof params.system === "string" ? params.system.length > 0 ? `${params.system}\n\n${nudge}` : nudge : [...params.system ?? [], {
1461
+ type: "text",
1462
+ text: nudge
1463
+ }];
1464
+ return {
1465
+ ...params,
1466
+ system,
1467
+ tool_choice: { type: "auto" }
1468
+ };
1469
+ }
1470
+ /**
1471
+ * Wire index where the ACTIVE chain begins: the last user message that
1472
+ * carries real user content (string content, or any non-tool_result
1473
+ * block). Everything from there onward is the current prompt plus the
1474
+ * in-flight assistant/tool exchange — its thinking blocks were minted by
1475
+ * this very call chain and Anthropic requires them to be echoed back, so
1476
+ * escalated scrubs must never cross this boundary. `undefined` when no
1477
+ * such message exists (degenerate resume shapes) — callers treat that as
1478
+ * "no protected region".
1479
+ */
1480
+ function activeChainScrubBoundary(messages) {
1481
+ for (let i = messages.length - 1; i >= 0; i--) {
1482
+ const message = messages[i];
1483
+ if (message?.role !== "user") continue;
1484
+ if (typeof message.content === "string") return i;
1485
+ if (message.content.some((block) => block.type !== "tool_result")) return i;
1486
+ }
1487
+ }
1488
+ /**
1489
+ * Decide what a scrub pass may touch. The bound NEVER crosses into the
1490
+ * active chain wholesale — not even on pass 0 with no parseable locator
1491
+ * (an unbounded first pass would strip the in-flight chain's thinking and
1492
+ * trade a recoverable 400 for an "expected thinking block" one). When the
1493
+ * API-reported failing index lies INSIDE the chain, only that single
1494
+ * message is scrubbed on top of the pre-chain region: the block the API
1495
+ * itself rejected fails whether or not it is echoed, but sibling chain
1496
+ * messages below it may hold still-valid thinking the exchange requires.
1497
+ *
1498
+ * - pass 0 with a pre-chain locator → bounded at the locator (preserves
1499
+ * later, still-valid historical thinking).
1500
+ * - pass 0 without a locator, and every escalated pass → the full
1501
+ * pre-chain history.
1502
+ * - no active chain at all (degenerate resume shapes) → locator bound on
1503
+ * pass 0, full history afterwards.
1504
+ */
1505
+ function planThinkingScrub(scrubPass, failingIndex, messages) {
1506
+ const chainStart = activeChainScrubBoundary(messages);
1507
+ if (chainStart === void 0) return scrubPass === 0 && failingIndex !== void 0 ? { upToIndex: failingIndex } : {};
1508
+ const beforeChain = chainStart - 1;
1509
+ const inChain = failingIndex !== void 0 && failingIndex >= chainStart;
1510
+ const upToIndex = scrubPass === 0 && failingIndex !== void 0 && !inChain ? failingIndex : beforeChain;
1511
+ return inChain ? {
1512
+ upToIndex,
1513
+ alsoMessageIndex: failingIndex
1514
+ } : { upToIndex };
1515
+ }
1516
+ /**
1517
+ * Remove opaque historical Anthropic reasoning from a retry payload. Text,
1518
+ * tool calls/results, images, and every other block are preserved exactly.
1519
+ * If a message consisted only of reasoning, leave a neutral text marker so
1520
+ * the wire never receives an empty content array and conversation role
1521
+ * boundaries stay intact.
1522
+ *
1523
+ * `upToIndex` bounds the scrub to messages at/before the API-reported
1524
+ * failing index (see {@link parseFailingMessageIndex}); `undefined` strips
1525
+ * everywhere. `alsoMessageIndex` additionally scrubs that single message
1526
+ * beyond the bound (see {@link planThinkingScrub}). A later stale block
1527
+ * simply triggers the same recovery again — each pass removes at least
1528
+ * one block, so the recursion is bounded.
1529
+ */
1530
+ function withoutHistoricalThinking(messages, upToIndex, alsoMessageIndex) {
1531
+ let removed = 0;
1532
+ return {
1533
+ messages: messages.map((message, index) => {
1534
+ if (upToIndex !== void 0 && index > upToIndex && index !== alsoMessageIndex) return message;
1535
+ if (!Array.isArray(message.content)) return message;
1536
+ const content = message.content.filter((block) => {
1537
+ if (block.type === "thinking" || block.type === "redacted_thinking") {
1538
+ removed += 1;
1539
+ return false;
1540
+ }
1541
+ return true;
1542
+ });
1543
+ return {
1544
+ ...message,
1545
+ content: content.length > 0 ? content : [{
1546
+ type: "text",
1547
+ text: "[historical reasoning omitted]"
1548
+ }]
1549
+ };
1550
+ }),
1551
+ removed
1552
+ };
1553
+ }
1554
+ //#endregion
1555
+ //#region src/providers/anthropic-tool-json.ts
1556
+ /**
1557
+ * Raw control characters in streamed tool input.
1558
+ *
1559
+ * With fine-grained tool streaming (one of the Claude Code subscription
1560
+ * betas) the API streams a tool call's input JSON without validating it, so a
1561
+ * string value can carry a literal newline or tab. The SDK re-parses the
1562
+ * accumulated input on every `input_json_delta` with a strict `JSON.parse`,
1563
+ * which throws "Bad control character in string literal" and fails the whole
1564
+ * turn. Escaping those characters inside strings before the SDK sees the delta
1565
+ * yields the value the model meant.
1566
+ */
1567
+ /** The stream with every `input_json_delta` escaped; same object, so the SDK keeps its controller. */
1568
+ function escapingStream(stream) {
1569
+ const escape = createToolJsonEscaper();
1570
+ const events = stream[Symbol.asyncIterator].bind(stream);
1571
+ Object.defineProperty(stream, Symbol.asyncIterator, {
1572
+ configurable: true,
1573
+ async *value() {
1574
+ for await (const event of { [Symbol.asyncIterator]: events }) {
1575
+ const e = event;
1576
+ if (e.type === "content_block_delta" && e.delta?.type === "input_json_delta" && typeof e.delta.partial_json === "string") yield {
1577
+ ...e,
1578
+ delta: {
1579
+ ...e.delta,
1580
+ partial_json: escape(e.index ?? 0, e.delta.partial_json)
1581
+ }
1582
+ };
1583
+ else yield event;
1584
+ }
1585
+ }
1586
+ });
1587
+ return stream;
1588
+ }
1589
+ /**
1590
+ * `messages` whose `stream()` escapes tool-input control characters. The
1591
+ * SDK's `stream()` builds its `MessageStream` from `this.create(...)
1592
+ * .withResponse()`, so only `create` is replaced; everything else (client,
1593
+ * logger, headers, abort, `connect`) is the real one, through the prototype.
1594
+ * Pinned by a test against the real SDK, which fails if that changes.
1595
+ */
1596
+ function withToolJsonEscaping(messages) {
1597
+ const create = (...args) => {
1598
+ const pending = messages.create(...args);
1599
+ if (!args[0]?.stream) return pending;
1600
+ return {
1601
+ ...pending,
1602
+ withResponse: async () => {
1603
+ const result = await pending.withResponse();
1604
+ return {
1605
+ ...result,
1606
+ data: escapingStream(result.data)
1607
+ };
1608
+ }
1609
+ };
1610
+ };
1611
+ return Object.create(messages, { create: { value: create } });
1612
+ }
1613
+ //#endregion
1614
+ //#region src/chat/anthropic-models.ts
1615
+ /**
1616
+ * Anthropic "fast mode" — `speed: "fast"` on the Messages API. ~2.5× output
1617
+ * tokens/sec at a per-model price multiplier. Supported on Opus 4.6 / 4.7 /
1618
+ * 4.8 / 5 / 5.5 only; the API errors if sent on any other model, so it's
1619
+ * attached just to those entries (see {@link FAST_MODE_OPTIONS}).
1620
+ *
1621
+ * The multiplier scales ALL rate components (input, output, and both cache
1622
+ * rates) uniformly: per Anthropic, "prompt caching multipliers apply on top of
1623
+ * fast mode pricing" across the full context window. Opus 5.5 ($4/$20 →
1624
+ * $8/$40), 5 and 4.8 ($5/$25 → $10/$50) are 2×; Opus 4.6 / 4.7 are a steeper
1625
+ * 6× ($5/$25 → $30/$150).
1626
+ * See https://platform.claude.com/docs/en/build-with-claude/fast-mode.
1627
+ */
1628
+ const FAST_MODE_OPTION = {
1629
+ id: "fast",
1630
+ label: "Fast mode",
1631
+ description: "~2.5× faster output at premium pricing",
1632
+ costMultiplier: {
1633
+ input: 2,
1634
+ output: 2,
1635
+ cacheRead: 2,
1636
+ cacheWrite: 2
1637
+ }
1638
+ };
1639
+ const FAST_MODE_OPTION_LEGACY = {
1640
+ ...FAST_MODE_OPTION,
1641
+ description: "~2.5× faster output at 6× pricing",
1642
+ costMultiplier: {
1643
+ input: 6,
1644
+ output: 6,
1645
+ cacheRead: 6,
1646
+ cacheWrite: 6
1647
+ }
1648
+ };
1649
+ /** Model ids that accept `speed: "fast"`, mapped to their fast-mode option. */
1650
+ const FAST_MODE_OPTIONS = {
1651
+ "claude-opus-5-5": FAST_MODE_OPTION,
1652
+ "claude-opus-5": FAST_MODE_OPTION,
1653
+ "claude-opus-4-8": FAST_MODE_OPTION,
1654
+ "claude-opus-4-7": FAST_MODE_OPTION_LEGACY,
1655
+ "claude-opus-4-6": FAST_MODE_OPTION_LEGACY
1656
+ };
1657
+ /**
1658
+ * The price multiplier to apply to a model's base rates when fast mode is
1659
+ * active, or `undefined` when the model has no fast-mode pricing (i.e. doesn't
1660
+ * support it). Mirrors {@link FAST_MODE_OPTIONS} — kept as a separate accessor
1661
+ * so the cost layer can stay decoupled from the picker-facing option objects.
1662
+ */
1663
+ function fastModeCostMultiplier(modelId) {
1664
+ return FAST_MODE_OPTIONS[modelId]?.costMultiplier;
1665
+ }
1666
+ /**
1667
+ * Currently empty: pi-ai 1.0.4 bundles every GA Anthropic model up to and
1668
+ * including Claude Sonnet 5.5 — Opus 4.8 / 5 / 5.5, Fable 5 / 5.1,
1669
+ * Sonnet 4.6 / 5 / 5.5, Haiku 4.5 — with published rates, 1M context and 128k output.
1670
+ *
1671
+ * When adding a stopgap entry, mirror pi-ai's `ModelInfo` shape and set
1672
+ * `provider: 'anthropic'`. Known caveats worth carrying over in the comment:
1673
+ * Fable 5 / 5.1 REJECT forced tool use (`tool_choice` of `any` or `tool`
1674
+ * returns 400), which breaks zidane's structured-output paths (`loop.ts`,
1675
+ * `generate-data.ts`, the eval judge) — Opus 5.5 rejects it too, handled
1676
+ * generically by the learned `MODELS_REJECTING_FORCED_TOOL_CHOICE` retry in
1677
+ * providers/anthropic.ts. Opus 5.5 also REJECTS non-adaptive thinking:
1678
+ * `thinking: {type:'enabled', budget_tokens}` and `{type:'disabled'}` both 400
1679
+ * with `"thinking.type.enabled/disabled" is not supported for this model`;
1680
+ * zidane's explicit-budget path (`behavior.thinkingBudget`, the Bedrock-only
1681
+ * shape) emits `enabled`, so the provider catches that 400 and retries as
1682
+ * adaptive (`MODELS_REJECTING_ENABLED_THINKING`). Claude Mythos 5 / 5.1 are
1683
+ * deliberately absent: invitation-only (Project Glasswing), so they would be
1684
+ * dead picker entries for virtually all users.
1685
+ *
1686
+ * See https://platform.claude.com/docs/en/about-claude/models/overview.
1687
+ */
1688
+ const ANTHROPIC_EXTRA_MODELS = [];
1689
+ //#endregion
1690
+ //#region src/providers/anthropic-usage.ts
1691
+ /**
1692
+ * Map Anthropic's native `stop_reason` to the zidane `TurnFinishReason` union.
1693
+ *
1694
+ * `pause_turn` and `model_context_window_exceeded` are 4.6+ stop reasons that
1695
+ * pre-Z21 collapsed to `'other'` and silently terminated the run. They now
1696
+ * map to `'pause'` and `'length'` respectively, and the surrounding caller
1697
+ * adjusts the `done` flag so the loop can recover.
1698
+ */
1699
+ function mapStopReason(stopReason) {
1700
+ if (!stopReason) return void 0;
1701
+ switch (stopReason) {
1702
+ case "end_turn":
1703
+ case "stop_sequence": return "stop";
1704
+ case "tool_use": return "tool-calls";
1705
+ case "max_tokens":
1706
+ case "model_context_window_exceeded": return "length";
1707
+ case "refusal": return "content-filter";
1708
+ case "pause_turn": return "pause";
1709
+ default: return "other";
1710
+ }
1711
+ }
1712
+ /**
1713
+ * Anthropic bills a 1h-TTL cache write at 2× base input against 1.25× for the
1714
+ * default 5m TTL, but `cache_creation_input_tokens` (what `TurnUsage.
1715
+ * cacheCreation` carries) is the SUM of both buckets. Registry `cacheWrite`
1716
+ * rates are the 5m rate, so a turn that wrote under `ttl: '1h'` needs its
1717
+ * write component scaled by `(5m·1.25 + 1h·2) / (total·1.25)`. `1` when the
1718
+ * response carries no split (Bedrock, older API versions) or no 1h writes.
1719
+ */
1720
+ const CACHE_WRITE_1H_OVER_5M = 2 / 1.25;
1721
+ function cacheWriteTtlMultiplier(usage) {
1722
+ const split = usage.cache_creation;
1723
+ const oneHour = split?.ephemeral_1h_input_tokens ?? 0;
1724
+ if (oneHour <= 0) return 1;
1725
+ const fiveMin = split?.ephemeral_5m_input_tokens ?? 0;
1726
+ const total = usage.cache_creation_input_tokens ?? fiveMin + oneHour;
1727
+ if (total <= 0) return 1;
1728
+ return (fiveMin + oneHour * CACHE_WRITE_1H_OVER_5M) / total;
1729
+ }
1730
+ /** Per-rate product of two multipliers; a missing key on either side is `1`. */
1731
+ function composeCostMultipliers(a, b) {
1732
+ if (!a) return b;
1733
+ if (!b) return a;
1734
+ return {
1735
+ input: (a.input ?? 1) * (b.input ?? 1),
1736
+ output: (a.output ?? 1) * (b.output ?? 1),
1737
+ cacheRead: (a.cacheRead ?? 1) * (b.cacheRead ?? 1),
1738
+ cacheWrite: (a.cacheWrite ?? 1) * (b.cacheWrite ?? 1)
1739
+ };
1740
+ }
1741
+ /**
1742
+ * Price an API-key (non-OAuth) turn.
1743
+ *
1744
+ * - Bedrock traffic is looked up under pi-ai's `amazon-bedrock` registry: the
1745
+ * echoed ids (`global.anthropic.claude-…`, `eu.anthropic.…`) never appear
1746
+ * under `anthropic`, and Bedrock's regional uplifts only exist there.
1747
+ * - The API may echo a dated snapshot for an alias request (`claude-haiku-4-5`
1748
+ * → `claude-haiku-4-5-20251001`). Rates and the fast-mode multiplier are
1749
+ * resolved by the echoed id first, then by the REQUESTED id, so a snapshot
1750
+ * the registry doesn't list yet is still priced (and a fast-mode Opus turn
1751
+ * keeps its 2× instead of silently billing at base). The echoed id stays on
1752
+ * the record — only the price falls back.
1753
+ * - 1h cache writes are scaled to their real rate (see
1754
+ * {@link cacheWriteTtlMultiplier}); fast mode composes on top.
1755
+ */
1756
+ async function priceAnthropicUsage(raw, response, requestedModelId, fastRequested, bedrock, catalog) {
1757
+ const providerKey = bedrock ? "amazon-bedrock" : "anthropic";
1758
+ const echoedModelId = raw.modelId ?? requestedModelId;
1759
+ const fast = fastRequested ? fastModeCostMultiplier(echoedModelId) ?? fastModeCostMultiplier(requestedModelId) : void 0;
1760
+ const ttl = cacheWriteTtlMultiplier(response.usage);
1761
+ const multiplier = composeCostMultipliers(fast, ttl === 1 ? void 0 : { cacheWrite: ttl });
1762
+ const priced = await fillEstimatedCost(raw, providerKey, multiplier, catalog);
1763
+ if (priced.cost !== void 0 || echoedModelId === requestedModelId) return priced;
1764
+ const byRequested = await fillEstimatedCost({
1765
+ ...raw,
1766
+ modelId: requestedModelId
1767
+ }, providerKey, multiplier, catalog);
1768
+ return byRequested.cost !== void 0 ? {
1769
+ ...raw,
1770
+ cost: byRequested.cost
1771
+ } : raw;
1772
+ }
1773
+ //#endregion
1774
+ //#region src/providers/diagnostic.ts
1775
+ const NETWORK_CODES = /* @__PURE__ */ new Set([
1776
+ "ECONNREFUSED",
1777
+ "ECONNRESET",
1778
+ "ETIMEDOUT",
1779
+ "ENOTFOUND",
1780
+ "EAI_AGAIN",
1781
+ "ENETUNREACH",
1782
+ "EHOSTUNREACH",
1783
+ "EPIPE",
1784
+ "UND_ERR_CONNECT_TIMEOUT",
1785
+ "UND_ERR_HEADERS_TIMEOUT",
1786
+ "UND_ERR_SOCKET",
1787
+ "CERT_HAS_EXPIRED",
1788
+ "DEPTH_ZERO_SELF_SIGNED_CERT",
1789
+ "UNABLE_TO_VERIFY_LEAF_SIGNATURE",
1790
+ "ERR_TLS_CERT_ALTNAME_INVALID",
1791
+ "AbortError",
1792
+ "TimeoutError"
1793
+ ]);
1794
+ function sanitizeProviderDiagnosticMetadata(metadata) {
1795
+ const safe = {};
1796
+ if (typeof metadata.transportAttempt === "number" && Number.isSafeInteger(metadata.transportAttempt) && metadata.transportAttempt > 0) safe.transportAttempt = metadata.transportAttempt;
1797
+ if (typeof metadata.networkCode === "string" && NETWORK_CODES.has(metadata.networkCode)) safe.networkCode = metadata.networkCode;
1798
+ if (typeof metadata.httpStatus === "number" && Number.isInteger(metadata.httpStatus) && metadata.httpStatus >= 100 && metadata.httpStatus <= 599) safe.httpStatus = metadata.httpStatus;
1799
+ if (typeof metadata.upstreamRequestId === "string" && metadata.upstreamRequestId.length <= 128 && /^req_[\w-]+$/.test(metadata.upstreamRequestId)) safe.upstreamRequestId = metadata.upstreamRequestId;
1800
+ const retryAfter = metadata.retryAfter;
1801
+ if (typeof retryAfter === "string" && retryAfter.length <= 32 && (/^\d+(?:\.\d+)?$/.test(retryAfter) || retryAfter.length === 29 && new Date(retryAfter).toUTCString() === retryAfter)) safe.retryAfter = retryAfter;
1802
+ return safe;
1803
+ }
1804
+ /** No request or error objects cross this boundary. Diagnostics cannot fail a request. */
1805
+ function createProviderDiagnosticTracker(emit, signal) {
1806
+ const requestId = crypto.randomUUID();
1807
+ const started = performance.now();
1808
+ let stageStarted = started;
1809
+ let current;
1810
+ let attempt = 0;
1811
+ let transportAttempt = 0;
1812
+ let finished = false;
1813
+ let timer;
1814
+ let abort = () => {};
1815
+ function send(event, metadata = {}) {
1816
+ if (!current) return;
1817
+ const now = performance.now();
1818
+ try {
1819
+ emit?.({
1820
+ requestId,
1821
+ stage: current,
1822
+ event,
1823
+ elapsedMs: Math.round(now - started),
1824
+ stageElapsedMs: Math.round(now - stageStarted),
1825
+ attempt,
1826
+ ...sanitizeProviderDiagnosticMetadata(metadata)
1827
+ });
1828
+ } catch {}
1829
+ }
1830
+ const tracker = {
1831
+ wrapFetch(fetch) {
1832
+ if (!emit) return fetch;
1833
+ return Object.assign(async (...args) => {
1834
+ const number = ++transportAttempt;
1835
+ const began = performance.now();
1836
+ const report = (event, metadata = {}) => {
1837
+ try {
1838
+ emit({
1839
+ requestId,
1840
+ stage: "transport",
1841
+ event,
1842
+ elapsedMs: Math.round(performance.now() - started),
1843
+ stageElapsedMs: Math.round(performance.now() - began),
1844
+ attempt,
1845
+ ...sanitizeProviderDiagnosticMetadata({
1846
+ ...metadata,
1847
+ transportAttempt: number
1848
+ })
1849
+ });
1850
+ } catch {}
1851
+ };
1852
+ report("start");
1853
+ try {
1854
+ const response = await fetch(...args);
1855
+ report("end", {
1856
+ httpStatus: response.status,
1857
+ upstreamRequestId: response.headers.get("request-id"),
1858
+ retryAfter: response.headers.get("retry-after")
1859
+ });
1860
+ return response;
1861
+ } catch (error) {
1862
+ const err = error;
1863
+ report("failure", { networkCode: [
1864
+ err?.cause?.code,
1865
+ err?.code,
1866
+ err?.name
1867
+ ].find((value) => typeof value === "string" && NETWORK_CODES.has(value)) });
1868
+ throw error;
1869
+ }
1870
+ }, fetch);
1871
+ },
1872
+ stage(stage, metadata = {}) {
1873
+ if (!emit || finished) return;
1874
+ if (current) send("end");
1875
+ current = stage;
1876
+ stageStarted = performance.now();
1877
+ if (stage === "dispatch") attempt++;
1878
+ send("start", metadata);
1879
+ if (timer) clearInterval(timer);
1880
+ timer = setInterval(send, 3e4, "waiting");
1881
+ timer.unref?.();
1882
+ if (signal?.aborted) abort();
1883
+ },
1884
+ finish(event, metadata = {}) {
1885
+ if (!emit || finished) return;
1886
+ finished = true;
1887
+ clearInterval(timer);
1888
+ signal?.removeEventListener("abort", abort);
1889
+ if (current) {
1890
+ send("end");
1891
+ send(event, metadata);
1892
+ }
1893
+ }
1503
1894
  };
1895
+ abort = () => tracker.finish("abort");
1896
+ if (emit) signal?.addEventListener("abort", abort, { once: true });
1897
+ return tracker;
1504
1898
  }
1505
- function isForcedToolChoice(choice) {
1506
- return choice?.type === "tool" || choice?.type === "any";
1899
+ //#endregion
1900
+ //#region src/providers/anthropic-stream.ts
1901
+ function isInputTransformation(value) {
1902
+ if (typeof value !== "object" || value === null) return false;
1903
+ const v = value;
1904
+ return typeof v.type === "string" && typeof v.path === "string" && typeof v.reason === "string";
1507
1905
  }
1508
- /**
1509
- * Models observed rejecting the explicit-budget thinking shape
1510
- * (`thinking: { type: 'enabled', budget_tokens }`), so later calls skip the
1511
- * failing round-trip and downgrade to adaptive up front.
1512
- *
1513
- * Learned, not declared — same rationale as
1514
- * {@link MODELS_REJECTING_FORCED_TOOL_CHOICE}. Claude Opus 5.5 is the first
1515
- * model where the `enabled` shape 400s (adaptive-only, thinking always on);
1516
- * successors that follow suit are caught without a catalog edit.
1517
- */
1518
- const MODELS_REJECTING_ENABLED_THINKING = /* @__PURE__ */ new Set();
1519
- /**
1520
- * True for the 400 Anthropic returns when a model does not support the manual
1521
- * extended-thinking shape: `"thinking.type.enabled" is not supported for this
1522
- * model. Use "thinking.type.adaptive" and "output_config.effort" ...`. Anchored
1523
- * on the validation-400 gate plus the dotted field name and the "not supported
1524
- * for this model" tail, so a reworded middle still matches while an unrelated
1525
- * `thinking` validation error (bad budget, wrong type) does not. Only the
1526
- * `enabled` variant is matched: zidane omits the field for the `'off'` level
1527
- * (adaptive on these models) and never emits `thinking.type.disabled`.
1528
- */
1529
- function isEnabledThinkingUnsupportedError(err) {
1530
- return isRequestValidationError(err) && /\bthinking\.type\.enabled\b[^.]+not supported for this model\b/i.test(errorText(err));
1906
+ function betasFor(anthropicParams, conditional) {
1907
+ return conditional.length > 0 ? [...anthropicParams?.extraBetas ?? [], ...conditional] : anthropicParams?.extraBetas;
1531
1908
  }
1532
- function isEnabledThinking(thinking) {
1533
- return thinking?.type === "enabled";
1909
+ /** The `anthropic()` provider's `stream()`: prepare auth + client, build the request, run it. */
1910
+ async function streamAnthropic(provider, options, callbacks) {
1911
+ const diagnostic = createProviderDiagnosticTracker(callbacks.onDiagnostic, options.signal);
1912
+ const live = {
1913
+ diagnosticActive: false,
1914
+ apiKey: ""
1915
+ };
1916
+ try {
1917
+ const prepared = await prepareAnthropicCall(provider, options, callbacks, diagnostic, live);
1918
+ const { params, nameBoundary, modelId, affinityHeader } = await buildAnthropicStreamRequest(prepared);
1919
+ const call = {
1920
+ ...prepared,
1921
+ nameBoundary,
1922
+ modelId,
1923
+ affinityHeader
1924
+ };
1925
+ const { callIsOAuth } = call;
1926
+ let initialParams = isForcedToolChoice(params.tool_choice) && MODELS_REJECTING_FORCED_TOOL_CHOICE.has(modelId) ? withoutForcedToolChoice(params) : params;
1927
+ if (isEnabledThinking(initialParams.thinking) && MODELS_REJECTING_ENABLED_THINKING.has(modelId)) initialParams = withoutEnabledThinking(initialParams);
1928
+ const result = await runAnthropicStream(call, initialParams, options.modelOptions?.fast === true && !callIsOAuth);
1929
+ diagnostic.finish("success");
1930
+ return result;
1931
+ } catch (err) {
1932
+ diagnostic.finish(options.signal?.aborted ? "abort" : "failure", { httpStatus: err && typeof err === "object" && "status" in err ? err.status : void 0 });
1933
+ throw err;
1934
+ } finally {
1935
+ diagnostic.finish("failure");
1936
+ }
1534
1937
  }
1535
- /**
1536
- * The same request with the explicit budget dropped: `thinking.type` flipped to
1537
- * `adaptive`, `budget_tokens` removed, every other thinking field
1538
- * (`display`, `block_binding`) kept. `temperature` stays pinned to 1 (adaptive
1539
- * requires it, same as the enabled shape) and the budget-inflated `max_tokens`
1540
- * is left as-is — it is already clamped to the model ceiling and an oversized
1541
- * envelope is harmless for adaptive, which thinks and replies inside it. Any
1542
- * `output_config.effort` the enabled path set survives on `params.output_config`.
1543
- */
1544
- function withoutEnabledThinking(params) {
1545
- const thinking = params.thinking;
1546
- if (!thinking || thinking.type !== "enabled") return params;
1547
- const { budget_tokens: _dropped, type: _type, ...rest } = thinking;
1548
- return {
1549
- ...params,
1550
- thinking: {
1551
- ...rest,
1552
- type: "adaptive"
1938
+ /** Resolve (or force-refresh) this call's credential through the shared OAuth machinery. */
1939
+ async function resolveAnthropicCallApiKey(call, forceRefresh = false, rejectedAccess) {
1940
+ const identity = credentialIdentity(call.provider.anthropicParams);
1941
+ return await resolveOAuthApiKey({
1942
+ provider: identity.providerId,
1943
+ providerId: identity.providerId,
1944
+ params: call.provider.runtimeCredentials ? {
1945
+ ...call.provider.anthropicParams,
1946
+ ...call.provider.runtimeCredentials
1947
+ } : call.provider.anthropicParams,
1948
+ envKey: identity.envKey,
1949
+ missingError: identity.missingError,
1950
+ refreshError: identity.refreshError,
1951
+ forceRefresh,
1952
+ rejectedAccess
1953
+ }, {
1954
+ ...call.callbacks,
1955
+ onOAuthStage(stage) {
1956
+ if (!call.callbacks.onDiagnostic || call.provider.anthropicParams?.authMode === "api-key" || call.provider.anthropicParams?.authMode === "bearer") return;
1957
+ call.live.diagnosticActive = true;
1958
+ call.diagnostic.stage(stage);
1959
+ },
1960
+ async onOAuthRefresh(ctx) {
1961
+ if (ctx.source === "params") call.provider.runtimeCredentials = {
1962
+ access: ctx.credentials.access,
1963
+ refresh: ctx.credentials.refresh,
1964
+ expires: ctx.credentials.expires
1965
+ };
1966
+ await call.callbacks.onOAuthRefresh?.(ctx);
1553
1967
  }
1554
- };
1968
+ });
1555
1969
  }
1556
1970
  /**
1557
- * The same request with forcing removed: `tool_choice: auto` plus one trailing
1558
- * system sentence naming what the model was being forced into.
1559
- *
1560
- * The sentence is load-bearing, not decoration. `enforceSchemaOutput` sends the
1561
- * agent's own system prompt, which says nothing about `__output__` — forcing
1562
- * was the whole instruction — so without it a model on `auto` can legitimately
1563
- * answer in prose and the caller's "no structured payload" guard fires. It is
1564
- * appended as a final uncached block: everything before it keeps its cache
1565
- * prefix, and the downgrade adds no new breakpoint.
1971
+ * Auth, betas, extra headers, and client for one call — everything decided
1972
+ * before the request body.
1566
1973
  */
1567
- function withoutForcedToolChoice(params) {
1568
- const choice = params.tool_choice;
1569
- const nudge = choice?.type === "tool" ? `Respond only by calling the \`${choice.name}\` tool. Do not reply with prose.` : "Respond only by calling one of the provided tools. Do not reply with prose.";
1570
- const system = typeof params.system === "string" ? params.system.length > 0 ? `${params.system}\n\n${nudge}` : nudge : [...params.system ?? [], {
1571
- type: "text",
1572
- text: nudge
1573
- }];
1974
+ async function prepareAnthropicCall(provider, options, callbacks, diagnostic, live) {
1975
+ const { anthropicParams, bedrockConfig } = provider;
1976
+ if (!bedrockConfig) live.apiKey = await resolveAnthropicCallApiKey({
1977
+ provider,
1978
+ callbacks,
1979
+ diagnostic,
1980
+ live
1981
+ });
1982
+ const callAuth = resolveAnthropicAuthShape(live.apiKey, bedrockConfig ? "api-key" : anthropicParams?.authMode);
1983
+ const callIsOAuth = callAuth.claudeCode;
1984
+ if (callIsOAuth && callbacks.onDiagnostic) {
1985
+ live.diagnosticActive = true;
1986
+ diagnostic.stage("prepare");
1987
+ }
1988
+ /**
1989
+ * Whether a provider auth rejection on this call is worth ATTEMPTING one
1990
+ * forced credential rotation. A bearer-authenticated call MAY resolve its
1991
+ * token through the refreshable OAuth store — subscription OAuth and
1992
+ * `authMode: 'bearer'` gateways (`extensions/bolt`) both do — so a 401
1993
+ * arriving before the local expiry is recoverable for them. Deliberately
1994
+ * WIDER than {@link callIsOAuth}, which additionally means "wear the
1995
+ * Claude Code persona"; a gateway is not Claude Code but its token still
1996
+ * rotates.
1997
+ *
1998
+ * The ones that cannot rotate stop at the identical-credential guard in
1999
+ * the recovery below rather than being excluded here: a static bearer
2000
+ * token supplied as `apiKey` short-circuits `resolveOAuthApiKey` and never
2001
+ * reaches the store, so the re-resolve returns the same value and costs
2002
+ * nothing but a function call. API-key and Bedrock calls never get that
2003
+ * far — `callAuth.bearer` is false for both.
2004
+ */
2005
+ const callCanRotateAuth = callAuth.bearer;
2006
+ const effectiveCacheTtl = options.cacheTtl ?? (callIsOAuth ? "1h" : void 0);
2007
+ const extendedTtl = options.cache !== false && effectiveCacheTtl === "1h" && !bedrockConfig;
2008
+ const plan = planAnthropicThinking(options.thinking ?? "off", options.thinkingBudget, options.taskBudget, options.effortHint !== false);
2009
+ const thinkingBinding = resolveThinkingBinding(anthropicParams?.thinkingBinding);
2010
+ const bindingActive = plan !== null && !bedrockConfig && thinkingBinding !== "off" && !provider.thinkingBindingRejected;
2011
+ const baseConditionalBetas = [...options.modelOptions?.fast && !callIsOAuth ? [FAST_MODE_BETA] : [], ...extendedTtl ? [EXTENDED_CACHE_TTL_BETA] : []];
2012
+ const requestBetas = betasFor(anthropicParams, [...baseConditionalBetas, ...bindingActive ? [THINKING_BINDING_BETA] : []]);
2013
+ const resolvedExtraHeaders = await resolveExtraHeaders(anthropicParams?.extraHeaders);
1574
2014
  return {
1575
- ...params,
1576
- system,
1577
- tool_choice: { type: "auto" }
2015
+ provider,
2016
+ callbacks,
2017
+ diagnostic,
2018
+ live,
2019
+ anthropicParams,
2020
+ bedrockConfig,
2021
+ options,
2022
+ callIsOAuth,
2023
+ effectiveCacheTtl,
2024
+ extendedTtl,
2025
+ plan,
2026
+ thinkingBinding,
2027
+ bindingActive,
2028
+ resolvedExtraHeaders,
2029
+ client: bedrockConfig ? await createBedrockClient(bedrockConfig, anthropicParams, resolvedExtraHeaders) : createClient(await loadAnthropicSdk(), live.apiKey, callAuth, anthropicParams?.baseURL, requestBetas, resolvedExtraHeaders, callIsOAuth ? diagnostic.wrapFetch : void 0),
2030
+ callAuth,
2031
+ callCanRotateAuth,
2032
+ baseConditionalBetas,
2033
+ requestBetas
1578
2034
  };
1579
2035
  }
1580
- /**
1581
- * Wire index where the ACTIVE chain begins: the last user message that
1582
- * carries real user content (string content, or any non-tool_result
1583
- * block). Everything from there onward is the current prompt plus the
1584
- * in-flight assistant/tool exchange — its thinking blocks were minted by
1585
- * this very call chain and Anthropic requires them to be echoed back, so
1586
- * escalated scrubs must never cross this boundary. `undefined` when no
1587
- * such message exists (degenerate resume shapes) — callers treat that as
1588
- * "no protected region".
1589
- */
1590
- function activeChainScrubBoundary(messages) {
1591
- for (let i = messages.length - 1; i >= 0; i--) {
1592
- const message = messages[i];
1593
- if (message?.role !== "user") continue;
1594
- if (typeof message.content === "string") return i;
1595
- if (message.content.some((block) => block.type !== "tool_result")) return i;
2036
+ /** Dispatch one request and settle it, recovering through the retry ladder on failure. */
2037
+ async function runAnthropicStream(call, requestParams, fastRequested, scrubPass = 0, authPass = 0) {
2038
+ if (call.live.diagnosticActive) call.diagnostic.stage("dispatch");
2039
+ const s = withToolJsonEscaping(call.client.messages).stream(requestParams, {
2040
+ signal: call.options.signal,
2041
+ ...call.affinityHeader ? { headers: call.affinityHeader } : {}
2042
+ });
2043
+ const turn = attachAnthropicStreamListeners(call, s);
2044
+ let response;
2045
+ try {
2046
+ response = await s.finalMessage();
2047
+ } catch (err) {
2048
+ return recoverAnthropicStreamFailure(call, turn, err, requestParams, fastRequested, scrubPass, authPass);
1596
2049
  }
2050
+ return settleAnthropicStream(call, turn, response, fastRequested);
2051
+ }
2052
+ /** Wire diagnostics, output deltas, live usage, input transformations, and server-tool callbacks. */
2053
+ function attachAnthropicStreamListeners(call, s) {
2054
+ if (call.live.diagnosticActive) {
2055
+ s.on("connect", () => call.diagnostic.stage("response-headers", {
2056
+ httpStatus: s.response?.status,
2057
+ upstreamRequestId: s.request_id
2058
+ }));
2059
+ let firstActivity = true;
2060
+ s.on("streamEvent", () => {
2061
+ if (!firstActivity) return;
2062
+ firstActivity = false;
2063
+ call.diagnostic.stage("first-activity");
2064
+ call.diagnostic.stage("stream");
2065
+ });
2066
+ }
2067
+ const turn = {
2068
+ text: "",
2069
+ observedOutput: false,
2070
+ inputTransformations: void 0
2071
+ };
2072
+ s.on("text", (delta) => {
2073
+ turn.observedOutput = true;
2074
+ turn.text += delta;
2075
+ call.callbacks.onText(delta);
2076
+ });
2077
+ if (call.callbacks.onThinking) s.on("thinking", (delta) => {
2078
+ turn.observedOutput = true;
2079
+ call.callbacks.onThinking(delta);
2080
+ });
2081
+ if (call.callbacks.onUsage) {
2082
+ let live;
2083
+ s.on("streamEvent", (event) => {
2084
+ if (event.type === "message_start") {
2085
+ const u = event.message.usage;
2086
+ live = {
2087
+ inputTokens: u.input_tokens ?? 0,
2088
+ ...u.cache_read_input_tokens != null ? { cacheRead: u.cache_read_input_tokens } : {},
2089
+ ...u.cache_creation_input_tokens != null ? { cacheCreation: u.cache_creation_input_tokens } : {},
2090
+ ...call.callIsOAuth ? { billable: false } : {}
2091
+ };
2092
+ } else if (event.type === "message_delta") live = {
2093
+ ...live ?? {
2094
+ inputTokens: 0,
2095
+ ...call.callIsOAuth ? { billable: false } : {}
2096
+ },
2097
+ outputTokens: event.usage.output_tokens
2098
+ };
2099
+ else return;
2100
+ call.callbacks.onUsage(live);
2101
+ });
2102
+ }
2103
+ if (call.callbacks.onInputTransformations) s.on("streamEvent", (event) => {
2104
+ const list = (event.type === "message_start" ? event.message : event.type === "message_delta" ? event : void 0)?.input_transformations;
2105
+ if (Array.isArray(list) && list.length > 0) turn.inputTransformations = list.filter(isInputTransformation);
2106
+ });
2107
+ if (call.callbacks.onToolCallDelta) s.on("inputJson", () => {
2108
+ turn.observedOutput = true;
2109
+ call.callbacks.onToolCallDelta();
2110
+ });
2111
+ if (call.callbacks.onServerToolUse || call.callbacks.onServerToolResult) s.on("contentBlock", (block) => {
2112
+ turn.observedOutput = true;
2113
+ if (block.type === "server_tool_use") call.callbacks.onServerToolUse?.({
2114
+ id: block.id,
2115
+ name: block.name,
2116
+ input: block.input ?? {}
2117
+ });
2118
+ else if (block.type === "web_search_tool_result") call.callbacks.onServerToolResult?.({
2119
+ toolUseId: block.tool_use_id,
2120
+ toolName: "web_search",
2121
+ content: block.content
2122
+ });
2123
+ });
2124
+ return turn;
1597
2125
  }
1598
2126
  /**
1599
- * Decide what a scrub pass may touch. The bound NEVER crosses into the
1600
- * active chain wholesale — not even on pass 0 with no parseable locator
1601
- * (an unbounded first pass would strip the in-flight chain's thinking and
1602
- * trade a recoverable 400 for an "expected thinking block" one). When the
1603
- * API-reported failing index lies INSIDE the chain, only that single
1604
- * message is scrubbed on top of the pre-chain region: the block the API
1605
- * itself rejected fails whether or not it is echoed, but sibling chain
1606
- * messages below it may hold still-valid thinking the exchange requires.
1607
- *
1608
- * - pass 0 with a pre-chain locator → bounded at the locator (preserves
1609
- * later, still-valid historical thinking).
1610
- * - pass 0 without a locator, and every escalated pass → the full
1611
- * pre-chain history.
1612
- * - no active chain at all (degenerate resume shapes) → locator bound on
1613
- * pass 0, full history afterwards.
1614
- */
1615
- function planThinkingScrub(scrubPass, failingIndex, messages) {
1616
- const chainStart = activeChainScrubBoundary(messages);
1617
- if (chainStart === void 0) return scrubPass === 0 && failingIndex !== void 0 ? { upToIndex: failingIndex } : {};
1618
- const beforeChain = chainStart - 1;
1619
- const inChain = failingIndex !== void 0 && failingIndex >= chainStart;
1620
- const upToIndex = scrubPass === 0 && failingIndex !== void 0 && !inChain ? failingIndex : beforeChain;
1621
- return inChain ? {
1622
- upToIndex,
1623
- alsoMessageIndex: failingIndex
1624
- } : { upToIndex };
1625
- }
1626
- /**
1627
- * Remove opaque historical Anthropic reasoning from a retry payload. Text,
1628
- * tool calls/results, images, and every other block are preserved exactly.
1629
- * If a message consisted only of reasoning, leave a neutral text marker so
1630
- * the wire never receives an empty content array and conversation role
1631
- * boundaries stay intact.
1632
- *
1633
- * `upToIndex` bounds the scrub to messages at/before the API-reported
1634
- * failing index (see {@link parseFailingMessageIndex}); `undefined` strips
1635
- * everywhere. `alsoMessageIndex` additionally scrubs that single message
1636
- * beyond the bound (see {@link planThinkingScrub}). A later stale block
1637
- * simply triggers the same recovery again — each pass removes at least
1638
- * one block, so the recursion is bounded.
2127
+ * The retry ladder for a failed dispatch: thinking-signature scrub, forced
2128
+ * OAuth rotation, fast-mode fallback, binding downgrade, forced-tool-choice
2129
+ * and enabled-thinking downgrades. Rethrows when nothing applies.
1639
2130
  */
1640
- function withoutHistoricalThinking(messages, upToIndex, alsoMessageIndex) {
1641
- let removed = 0;
2131
+ async function recoverAnthropicStreamFailure(call, turn, err, requestParams, fastRequested, scrubPass, authPass) {
2132
+ if (!(call.bindingActive && call.thinkingBinding === "error" && isPrefixMismatchError(err)) && !turn.observedOutput && scrubPass < 3 && isRecoverableThinkingBlockError(err, requestParams.messages)) {
2133
+ const failingIndex = parseFailingMessageIndex(err);
2134
+ const plan = planThinkingScrub(scrubPass, failingIndex, requestParams.messages);
2135
+ const scrubbed = withoutHistoricalThinking(requestParams.messages, plan.upToIndex, plan.alsoMessageIndex);
2136
+ if (scrubbed.removed > 0) {
2137
+ try {
2138
+ await call.callbacks.onHistoryRepair?.({
2139
+ type: "invalid-anthropic-thinking-signature",
2140
+ ...failingIndex !== void 0 ? { wireMessageIndex: failingIndex } : {}
2141
+ });
2142
+ } catch (repairErr) {
2143
+ if (process.env.ZIDANE_DEBUG) process.stderr.write(`[zidane/anthropic] history repair callback failed: ${errorMessage(repairErr)}\n`);
2144
+ }
2145
+ return await runAnthropicStream(call, {
2146
+ ...requestParams,
2147
+ messages: scrubbed.messages
2148
+ }, fastRequested, scrubPass + 1, authPass);
2149
+ }
2150
+ }
2151
+ if (call.callCanRotateAuth && authPass === 0 && !turn.observedOutput && isAnthropicAuthenticationError(err)) {
2152
+ const rejectedAccess = call.live.apiKey;
2153
+ let refreshedApiKey;
2154
+ try {
2155
+ refreshedApiKey = await resolveAnthropicCallApiKey(call, true, rejectedAccess);
2156
+ } catch (refreshErr) {
2157
+ if (err !== null && typeof err === "object" && err.cause === void 0) try {
2158
+ err.cause = refreshErr;
2159
+ } catch {}
2160
+ if (process.env.ZIDANE_DEBUG) process.stderr.write(`[zidane/anthropic] forced OAuth refresh after 401 failed: ${errorMessage(refreshErr)}\n`);
2161
+ throw err;
2162
+ }
2163
+ if (refreshedApiKey === rejectedAccess) throw err;
2164
+ call.live.apiKey = refreshedApiKey;
2165
+ call.client = createClient(await loadAnthropicSdk(), call.live.apiKey, call.callAuth, call.anthropicParams?.baseURL, call.requestBetas, call.resolvedExtraHeaders, call.callIsOAuth ? call.diagnostic.wrapFetch : void 0);
2166
+ return await runAnthropicStream(call, requestParams, fastRequested, scrubPass, authPass + 1);
2167
+ }
2168
+ if (fastRequested && !turn.observedOutput && shouldFallbackFromFastMode(err)) {
2169
+ const standardParams = { ...requestParams };
2170
+ delete standardParams.speed;
2171
+ return await runAnthropicStream(call, standardParams, false, scrubPass, authPass);
2172
+ }
2173
+ if (call.bindingActive && !call.provider.thinkingBindingRejected && !turn.observedOutput && isThinkingBindingRejectedError(err)) {
2174
+ call.provider.thinkingBindingRejected = true;
2175
+ if (process.env.ZIDANE_DEBUG) process.stderr.write(`[zidane/anthropic] endpoint rejected thinking.block_binding; retrying without it: ${errorMessage(err)}\n`);
2176
+ call.client = createClient(await loadAnthropicSdk(), call.live.apiKey, call.callAuth, call.anthropicParams?.baseURL, betasFor(call.anthropicParams, call.baseConditionalBetas), call.resolvedExtraHeaders, call.callIsOAuth ? call.diagnostic.wrapFetch : void 0);
2177
+ return await runAnthropicStream(call, withoutThinkingBinding(requestParams), fastRequested, scrubPass, authPass);
2178
+ }
2179
+ if (!turn.observedOutput && isForcedToolChoice(requestParams.tool_choice) && isForcedToolChoiceUnsupportedError(err)) {
2180
+ MODELS_REJECTING_FORCED_TOOL_CHOICE.add(call.modelId);
2181
+ return await runAnthropicStream(call, withoutForcedToolChoice(requestParams), fastRequested, scrubPass, authPass);
2182
+ }
2183
+ if (!turn.observedOutput && isEnabledThinking(requestParams.thinking) && isEnabledThinkingUnsupportedError(err)) {
2184
+ MODELS_REJECTING_ENABLED_THINKING.add(call.modelId);
2185
+ return await runAnthropicStream(call, withoutEnabledThinking(requestParams), fastRequested, scrubPass, authPass);
2186
+ }
2187
+ throw err;
2188
+ }
2189
+ /** Fire the settled-stream hooks and map the final message to a `TurnResult`. */
2190
+ async function settleAnthropicStream(call, turn, response, fastRequested) {
2191
+ if (turn.inputTransformations && turn.inputTransformations.length > 0) try {
2192
+ call.callbacks.onInputTransformations?.(turn.inputTransformations);
2193
+ } catch (hookErr) {
2194
+ if (process.env.ZIDANE_DEBUG) process.stderr.write(`[zidane/anthropic] onInputTransformations threw: ${errorMessage(hookErr)}\n`);
2195
+ }
2196
+ const toolCalls = response.content.filter((b) => b.type === "tool_use").map((b) => ({
2197
+ id: b.id,
2198
+ name: call.nameBoundary.fromWire(b.name),
2199
+ input: b.input
2200
+ }));
2201
+ const finishReason = mapStopReason(response.stop_reason);
2202
+ const isPause = response.stop_reason === "pause_turn";
2203
+ const rawUsage = {
2204
+ input: response.usage.input_tokens,
2205
+ output: response.usage.output_tokens,
2206
+ cacheCreation: response.usage.cache_creation_input_tokens ?? void 0,
2207
+ cacheRead: response.usage.cache_read_input_tokens ?? void 0,
2208
+ ...finishReason ? { finishReason } : {},
2209
+ modelId: response.model ?? call.options.model
2210
+ };
2211
+ const usage = call.callIsOAuth ? rawUsage : await priceAnthropicUsage(rawUsage, response, call.modelId, fastRequested, Boolean(call.bedrockConfig), call.options.modelCatalog);
2212
+ const assistantMessage = fromAnthropic({
2213
+ role: "assistant",
2214
+ content: response.content
2215
+ });
2216
+ if (call.nameBoundary.changed) assistantMessage.content = assistantMessage.content.map((block) => block.type === "tool_call" ? {
2217
+ ...block,
2218
+ name: call.nameBoundary.fromWire(block.name)
2219
+ } : block);
1642
2220
  return {
1643
- messages: messages.map((message, index) => {
1644
- if (upToIndex !== void 0 && index > upToIndex && index !== alsoMessageIndex) return message;
1645
- if (!Array.isArray(message.content)) return message;
1646
- const content = message.content.filter((block) => {
1647
- if (block.type === "thinking" || block.type === "redacted_thinking") {
1648
- removed += 1;
1649
- return false;
1650
- }
1651
- return true;
1652
- });
1653
- return {
1654
- ...message,
1655
- content: content.length > 0 ? content : [{
1656
- type: "text",
1657
- text: "[historical reasoning omitted]"
1658
- }]
1659
- };
1660
- }),
1661
- removed
2221
+ assistantMessage,
2222
+ text: turn.text,
2223
+ toolCalls,
2224
+ done: !isPause && (response.stop_reason === "end_turn" || toolCalls.length === 0),
2225
+ usage
1662
2226
  };
1663
2227
  }
2228
+ //#endregion
2229
+ //#region src/providers/anthropic.ts
1664
2230
  /**
1665
2231
  * Build a user `SessionMessage` from multimodal prompt parts.
1666
2232
  *
@@ -1711,15 +2277,12 @@ function anthropic(anthropicParams) {
1711
2277
  const bedrockConfig = normalizeBedrock(anthropicParams?.bedrock);
1712
2278
  const isOAuth = resolveAnthropicAuthShape(bedrockConfig ? "" : getConfiguredApiKey(anthropicParams), anthropicParams?.authMode).bearer;
1713
2279
  const defaultModel = anthropicParams?.defaultModel || "claude-fable-5-1";
1714
- let runtimeCredentials = extractRuntimeCredentials(anthropicParams);
1715
- /**
1716
- * Set once this provider instance sees the endpoint reject the
1717
- * preserved-thinking binding beta or field; every later request on the
1718
- * instance skips both up front instead of paying the failing round-trip.
1719
- * Per instance, not process-wide: acceptance is a property of the
1720
- * endpoint + credential, and one process may hold several.
1721
- */
1722
- let thinkingBindingRejected = false;
2280
+ const state = {
2281
+ anthropicParams,
2282
+ bedrockConfig,
2283
+ runtimeCredentials: extractRuntimeCredentials(anthropicParams),
2284
+ thinkingBindingRejected: false
2285
+ };
1723
2286
  return {
1724
2287
  name: "anthropic",
1725
2288
  meta: {
@@ -1733,6 +2296,7 @@ function anthropic(anthropicParams) {
1733
2296
  audio: false,
1734
2297
  video: false,
1735
2298
  ...bedrockConfig ? {} : { nativeWebSearch: { maxUses: 5 } },
2299
+ ...bedrockConfig ? { maxMediaPerRequest: 20 } : {},
1736
2300
  adaptiveBudgetIsEnvelope: true,
1737
2301
  ...anthropicParams?.capabilities
1738
2302
  }
@@ -1740,7 +2304,8 @@ function anthropic(anthropicParams) {
1740
2304
  formatTools(tools) {
1741
2305
  const nativeWebSearch = this.meta.capabilities?.nativeWebSearch;
1742
2306
  const hasWebSearch = !!nativeWebSearch && tools.some((t) => t.name === "web_search");
1743
- const out = sanitizeToolSpecs(hasWebSearch ? tools.filter((t) => t.name !== "web_search") : tools, { profile: "anthropic" }).map((t) => ({
2307
+ const fnTools = hasWebSearch ? tools.filter((t) => t.name !== "web_search") : tools;
2308
+ const out = sanitizeToolSpecs(fnTools, { profile: "anthropic" }).map((t) => ({
1744
2309
  name: t.name,
1745
2310
  description: t.description ?? "",
1746
2311
  input_schema: t.inputSchema
@@ -1795,9 +2360,9 @@ function anthropic(anthropicParams) {
1795
2360
  const apiKey = await resolveOAuthApiKey({
1796
2361
  provider: identity.providerId,
1797
2362
  providerId: identity.providerId,
1798
- params: runtimeCredentials ? {
2363
+ params: state.runtimeCredentials ? {
1799
2364
  ...anthropicParams,
1800
- ...runtimeCredentials
2365
+ ...state.runtimeCredentials
1801
2366
  } : anthropicParams,
1802
2367
  envKey: identity.envKey,
1803
2368
  missingError: identity.missingError,
@@ -1806,25 +2371,7 @@ function anthropic(anthropicParams) {
1806
2371
  const callAuth = resolveAnthropicAuthShape(apiKey, anthropicParams?.authMode);
1807
2372
  const callIsOAuth = callAuth.claudeCode;
1808
2373
  const client = createClient(SDK, apiKey, callAuth, anthropicParams?.baseURL, anthropicParams?.extraBetas, await resolveExtraHeaders(anthropicParams?.extraHeaders));
1809
- const wireSystem = renderSystemForWire(payload.system);
1810
- const system = callIsOAuth ? `You are Claude Code, Anthropic's official CLI for Claude.` : wireSystem;
1811
- const messages = callIsOAuth && payload.system ? [
1812
- {
1813
- role: "user",
1814
- content: [{
1815
- type: "text",
1816
- text: wireSystem
1817
- }]
1818
- },
1819
- {
1820
- role: "assistant",
1821
- content: [{
1822
- type: "text",
1823
- text: "Understood. I will proceed with these instructions above the rest of my system prompt."
1824
- }]
1825
- },
1826
- ...payload.messages
1827
- ] : [...payload.messages];
2374
+ const { system, messages } = foldSystemForWire(payload.system, payload.messages, callIsOAuth);
1828
2375
  const countTools = payload.tools;
1829
2376
  const countBoundary = createToolNameBoundary(messages, countTools.map((t) => t.name), callIsOAuth ? claudeCodeToolAliases : void 0);
1830
2377
  return (await client.messages.countTokens({
@@ -1841,381 +2388,12 @@ function anthropic(anthropicParams) {
1841
2388
  return null;
1842
2389
  }
1843
2390
  },
1844
- async stream(options, callbacks) {
1845
- const diagnostic = createProviderDiagnosticTracker(callbacks.onDiagnostic, options.signal);
1846
- let diagnosticActive = false;
1847
- try {
1848
- let apiKey = "";
1849
- const resolveCallApiKey = async (forceRefresh = false, rejectedAccess) => {
1850
- const identity = credentialIdentity(anthropicParams);
1851
- return await resolveOAuthApiKey({
1852
- provider: identity.providerId,
1853
- providerId: identity.providerId,
1854
- params: runtimeCredentials ? {
1855
- ...anthropicParams,
1856
- ...runtimeCredentials
1857
- } : anthropicParams,
1858
- envKey: identity.envKey,
1859
- missingError: identity.missingError,
1860
- refreshError: identity.refreshError,
1861
- forceRefresh,
1862
- rejectedAccess
1863
- }, {
1864
- ...callbacks,
1865
- onOAuthStage(stage) {
1866
- if (!callbacks.onDiagnostic || anthropicParams?.authMode === "api-key" || anthropicParams?.authMode === "bearer") return;
1867
- diagnosticActive = true;
1868
- diagnostic.stage(stage);
1869
- },
1870
- async onOAuthRefresh(ctx) {
1871
- if (ctx.source === "params") runtimeCredentials = {
1872
- access: ctx.credentials.access,
1873
- refresh: ctx.credentials.refresh,
1874
- expires: ctx.credentials.expires
1875
- };
1876
- await callbacks.onOAuthRefresh?.(ctx);
1877
- }
1878
- });
1879
- };
1880
- if (!bedrockConfig) apiKey = await resolveCallApiKey();
1881
- const callAuth = resolveAnthropicAuthShape(apiKey, bedrockConfig ? "api-key" : anthropicParams?.authMode);
1882
- const callIsOAuth = callAuth.claudeCode;
1883
- if (callIsOAuth && callbacks.onDiagnostic) {
1884
- diagnosticActive = true;
1885
- diagnostic.stage("prepare");
1886
- }
1887
- /**
1888
- * Whether a provider auth rejection on this call is worth ATTEMPTING one
1889
- * forced credential rotation. A bearer-authenticated call MAY resolve its
1890
- * token through the refreshable OAuth store — subscription OAuth and
1891
- * `authMode: 'bearer'` gateways (`extensions/bolt`) both do — so a 401
1892
- * arriving before the local expiry is recoverable for them. Deliberately
1893
- * WIDER than {@link callIsOAuth}, which additionally means "wear the
1894
- * Claude Code persona"; a gateway is not Claude Code but its token still
1895
- * rotates.
1896
- *
1897
- * The ones that cannot rotate stop at the identical-credential guard in
1898
- * the recovery below rather than being excluded here: a static bearer
1899
- * token supplied as `apiKey` short-circuits `resolveOAuthApiKey` and never
1900
- * reaches the store, so the re-resolve returns the same value and costs
1901
- * nothing but a function call. API-key and Bedrock calls never get that
1902
- * far — `callAuth.bearer` is false for both.
1903
- */
1904
- const callCanRotateAuth = callAuth.bearer;
1905
- const effectiveCacheTtl = options.cacheTtl ?? (callIsOAuth ? "1h" : void 0);
1906
- const extendedTtl = options.cache !== false && effectiveCacheTtl === "1h" && !bedrockConfig;
1907
- const plan = planAnthropicThinking(options.thinking ?? "off", options.thinkingBudget, options.taskBudget, options.effortHint !== false);
1908
- const thinkingBinding = resolveThinkingBinding(anthropicParams?.thinkingBinding);
1909
- const bindingActive = plan !== null && !bedrockConfig && thinkingBinding !== "off" && !thinkingBindingRejected;
1910
- const baseConditionalBetas = [...options.modelOptions?.fast && !callIsOAuth ? [FAST_MODE_BETA] : [], ...extendedTtl ? [EXTENDED_CACHE_TTL_BETA] : []];
1911
- const conditionalBetas = [...baseConditionalBetas, ...bindingActive ? [THINKING_BINDING_BETA] : []];
1912
- const betasFor = (conditional) => conditional.length > 0 ? [...anthropicParams?.extraBetas ?? [], ...conditional] : anthropicParams?.extraBetas;
1913
- const requestBetas = betasFor(conditionalBetas);
1914
- const resolvedExtraHeaders = await resolveExtraHeaders(anthropicParams?.extraHeaders);
1915
- let client = bedrockConfig ? await createBedrockClient(bedrockConfig, anthropicParams, resolvedExtraHeaders) : createClient(await loadAnthropicSdk(), apiKey, callAuth, anthropicParams?.baseURL, requestBetas, resolvedExtraHeaders, callIsOAuth ? diagnostic.wrapFetch : void 0);
1916
- const wireSystem = renderSystemForWire(options.system);
1917
- const system = callIsOAuth ? `You are Claude Code, Anthropic's official CLI for Claude.` : wireSystem;
1918
- const messages = callIsOAuth && options.system ? [
1919
- {
1920
- role: "user",
1921
- content: [{
1922
- type: "text",
1923
- text: wireSystem
1924
- }]
1925
- },
1926
- {
1927
- role: "assistant",
1928
- content: [{
1929
- type: "text",
1930
- text: "Understood. I will proceed with these instructions above the rest of my system prompt."
1931
- }]
1932
- },
1933
- ...options.messages
1934
- ] : [...options.messages];
1935
- const inputTools = options.tools ?? [];
1936
- const nameBoundary = createToolNameBoundary(messages, inputTools.map((t) => t.name), callIsOAuth ? claudeCodeToolAliases : void 0);
1937
- const wireTools = nameBoundary.changed ? inputTools.map((t) => t.name === nameBoundary.toWire(t.name) ? t : {
1938
- ...t,
1939
- name: nameBoundary.toWire(t.name)
1940
- }) : inputTools;
1941
- const modelId = options.model;
1942
- const modelMaxOutput = await resolveAnthropicMaxOutput(modelId, options.maxTokens, options.modelCatalog);
1943
- const params = {
1944
- ...anthropicParams?.extraBodyParams ?? {},
1945
- model: modelId,
1946
- max_tokens: options.maxTokens ?? modelMaxOutput,
1947
- system,
1948
- tools: wireTools,
1949
- messages: nameBoundary.messages.map((m) => toAnthropic(m)),
1950
- stream: true
1951
- };
1952
- if (anthropicParams?.contextManagement && !bedrockConfig) params.context_management = anthropicParams.contextManagement;
1953
- if (options.cache !== false) applyAnthropicCacheBreakpoints(params, callIsOAuth ? void 0 : options.system, extendedTtl ? effectiveCacheTtl : void 0);
1954
- if (plan && bedrockConfig) {
1955
- const budget = plan.kind === "enabled" ? plan.budgetTokens : BEDROCK_THINKING_BUDGETS[plan.effort ?? "medium"];
1956
- params.thinking = {
1957
- type: "enabled",
1958
- budget_tokens: budget
1959
- };
1960
- params.max_tokens = budget + params.max_tokens;
1961
- params.temperature = 1;
1962
- } else if (plan) {
1963
- if (plan.kind === "enabled") {
1964
- params.thinking = {
1965
- type: "enabled",
1966
- budget_tokens: plan.budgetTokens,
1967
- display: "summarized"
1968
- };
1969
- params.max_tokens = plan.maxTokensBump + params.max_tokens;
1970
- if (plan.effort) params.output_config = {
1971
- ...params.output_config,
1972
- effort: plan.effort
1973
- };
1974
- } else {
1975
- params.thinking = {
1976
- type: "adaptive",
1977
- display: "summarized"
1978
- };
1979
- const outputConfig = {};
1980
- if (plan.effort) outputConfig.effort = plan.effort;
1981
- if (typeof plan.taskBudgetTokens === "number" && plan.taskBudgetTokens > 0) outputConfig.task_budget = {
1982
- type: "tokens",
1983
- total: plan.taskBudgetTokens
1984
- };
1985
- if (Object.keys(outputConfig).length > 0) params.output_config = {
1986
- ...params.output_config,
1987
- ...outputConfig
1988
- };
1989
- if (typeof plan.maxTokensCap === "number" && plan.maxTokensCap > 0) params.max_tokens = Math.min(params.max_tokens, plan.maxTokensCap);
1990
- }
1991
- params.temperature = 1;
1992
- if (bindingActive) params.thinking.block_binding = { prefix_mismatch_behavior: thinkingBinding };
1993
- }
1994
- params.max_tokens = Math.min(params.max_tokens, modelMaxOutput);
1995
- if (callIsOAuth) {
1996
- params.max_tokens = Math.min(params.max_tokens, CLAUDE_CODE_MAX_OUTPUT_TOKENS);
1997
- if (Array.isArray(params.system)) params.system = [{
1998
- type: "text",
1999
- text: claudeCodeBillingText(firstUserMessageText(params.messages))
2000
- }, ...params.system];
2001
- if (typeof params.metadata?.user_id !== "string") params.metadata = {
2002
- ...params.metadata,
2003
- user_id: claudeCodeUserId()
2004
- };
2005
- }
2006
- if (params.thinking?.type === "enabled" && params.thinking.budget_tokens >= params.max_tokens) {
2007
- const fitted = params.max_tokens - THINKING_RESPONSE_RESERVE_TOKENS;
2008
- if (fitted >= 1024) params.thinking.budget_tokens = fitted;
2009
- else {
2010
- delete params.thinking;
2011
- delete params.temperature;
2012
- }
2013
- }
2014
- if (options.modelOptions?.fast && !callIsOAuth) params.speed = "fast";
2015
- if (options.toolChoice) if (options.toolChoice.type === "tool" && options.toolChoice.name) params.tool_choice = {
2016
- type: "tool",
2017
- name: nameBoundary.toWire(options.toolChoice.name)
2018
- };
2019
- else if (options.toolChoice.type === "required") params.tool_choice = { type: "any" };
2020
- else params.tool_choice = { type: "auto" };
2021
- const promptCacheKey = resolvePromptCacheKey(anthropicParams?.promptCacheKey, {
2022
- model: modelId,
2023
- system: options.system,
2024
- messages: options.messages
2025
- });
2026
- if (promptCacheKey !== void 0 && params.metadata?.user_id === void 0) params.metadata = {
2027
- ...params.metadata,
2028
- user_id: promptCacheKey
2029
- };
2030
- const affinityHeaderName = anthropicParams?.promptCacheKeyHeader?.toLowerCase();
2031
- const affinityHeader = anthropicParams?.promptCacheKeyHeader !== void 0 && promptCacheKey !== void 0 && !Object.keys(resolvedExtraHeaders ?? {}).some((k) => k.toLowerCase() === affinityHeaderName) ? { [anthropicParams.promptCacheKeyHeader]: promptCacheKey } : void 0;
2032
- const runStream = async (requestParams, fastRequested, scrubPass = 0, authPass = 0) => {
2033
- if (diagnosticActive) diagnostic.stage("dispatch");
2034
- const s = client.messages.stream(requestParams, {
2035
- signal: options.signal,
2036
- ...affinityHeader ? { headers: affinityHeader } : {}
2037
- });
2038
- if (diagnosticActive) {
2039
- s.on("connect", () => diagnostic.stage("response-headers", {
2040
- httpStatus: s.response?.status,
2041
- upstreamRequestId: s.request_id
2042
- }));
2043
- let firstActivity = true;
2044
- s.on("streamEvent", () => {
2045
- if (!firstActivity) return;
2046
- firstActivity = false;
2047
- diagnostic.stage("first-activity");
2048
- diagnostic.stage("stream");
2049
- });
2050
- }
2051
- let text = "";
2052
- let observedOutput = false;
2053
- s.on("text", (delta) => {
2054
- observedOutput = true;
2055
- text += delta;
2056
- callbacks.onText(delta);
2057
- });
2058
- if (callbacks.onThinking) s.on("thinking", (delta) => {
2059
- observedOutput = true;
2060
- callbacks.onThinking(delta);
2061
- });
2062
- if (callbacks.onUsage) {
2063
- let live;
2064
- s.on("streamEvent", (event) => {
2065
- if (event.type === "message_start") {
2066
- const u = event.message.usage;
2067
- live = {
2068
- inputTokens: u.input_tokens ?? 0,
2069
- ...u.cache_read_input_tokens != null ? { cacheRead: u.cache_read_input_tokens } : {},
2070
- ...u.cache_creation_input_tokens != null ? { cacheCreation: u.cache_creation_input_tokens } : {},
2071
- ...callIsOAuth ? { billable: false } : {}
2072
- };
2073
- } else if (event.type === "message_delta") live = {
2074
- ...live ?? {
2075
- inputTokens: 0,
2076
- ...callIsOAuth ? { billable: false } : {}
2077
- },
2078
- outputTokens: event.usage.output_tokens
2079
- };
2080
- else return;
2081
- callbacks.onUsage(live);
2082
- });
2083
- }
2084
- let inputTransformations;
2085
- if (callbacks.onInputTransformations) s.on("streamEvent", (event) => {
2086
- const list = (event.type === "message_start" ? event.message : event.type === "message_delta" ? event : void 0)?.input_transformations;
2087
- if (Array.isArray(list) && list.length > 0) inputTransformations = list.filter(isInputTransformation);
2088
- });
2089
- if (callbacks.onToolCallDelta) s.on("inputJson", () => {
2090
- observedOutput = true;
2091
- callbacks.onToolCallDelta();
2092
- });
2093
- if (callbacks.onServerToolUse || callbacks.onServerToolResult) s.on("contentBlock", (block) => {
2094
- observedOutput = true;
2095
- if (block.type === "server_tool_use") callbacks.onServerToolUse?.({
2096
- id: block.id,
2097
- name: block.name,
2098
- input: block.input ?? {}
2099
- });
2100
- else if (block.type === "web_search_tool_result") callbacks.onServerToolResult?.({
2101
- toolUseId: block.tool_use_id,
2102
- toolName: "web_search",
2103
- content: block.content
2104
- });
2105
- });
2106
- let response;
2107
- try {
2108
- response = await s.finalMessage();
2109
- } catch (err) {
2110
- if (!(bindingActive && thinkingBinding === "error" && isPrefixMismatchError(err)) && !observedOutput && scrubPass < MAX_THINKING_SCRUB_PASSES && isRecoverableThinkingBlockError(err, requestParams.messages)) {
2111
- const failingIndex = parseFailingMessageIndex(err);
2112
- const plan = planThinkingScrub(scrubPass, failingIndex, requestParams.messages);
2113
- const scrubbed = withoutHistoricalThinking(requestParams.messages, plan.upToIndex, plan.alsoMessageIndex);
2114
- if (scrubbed.removed > 0) {
2115
- try {
2116
- await callbacks.onHistoryRepair?.({
2117
- type: "invalid-anthropic-thinking-signature",
2118
- ...failingIndex !== void 0 ? { wireMessageIndex: failingIndex } : {}
2119
- });
2120
- } catch (repairErr) {
2121
- if (process.env.ZIDANE_DEBUG) process.stderr.write(`[zidane/anthropic] history repair callback failed: ${errorMessage(repairErr)}\n`);
2122
- }
2123
- return await runStream({
2124
- ...requestParams,
2125
- messages: scrubbed.messages
2126
- }, fastRequested, scrubPass + 1, authPass);
2127
- }
2128
- }
2129
- if (callCanRotateAuth && authPass === 0 && !observedOutput && isAnthropicAuthenticationError(err)) {
2130
- const rejectedAccess = apiKey;
2131
- let refreshedApiKey;
2132
- try {
2133
- refreshedApiKey = await resolveCallApiKey(true, rejectedAccess);
2134
- } catch (refreshErr) {
2135
- if (err !== null && typeof err === "object" && err.cause === void 0) try {
2136
- err.cause = refreshErr;
2137
- } catch {}
2138
- if (process.env.ZIDANE_DEBUG) process.stderr.write(`[zidane/anthropic] forced OAuth refresh after 401 failed: ${errorMessage(refreshErr)}\n`);
2139
- throw err;
2140
- }
2141
- if (refreshedApiKey === rejectedAccess) throw err;
2142
- apiKey = refreshedApiKey;
2143
- client = createClient(await loadAnthropicSdk(), apiKey, callAuth, anthropicParams?.baseURL, requestBetas, resolvedExtraHeaders, callIsOAuth ? diagnostic.wrapFetch : void 0);
2144
- return await runStream(requestParams, fastRequested, scrubPass, authPass + 1);
2145
- }
2146
- if (fastRequested && !observedOutput && shouldFallbackFromFastMode(err)) {
2147
- const standardParams = { ...requestParams };
2148
- delete standardParams.speed;
2149
- return await runStream(standardParams, false, scrubPass, authPass);
2150
- }
2151
- if (bindingActive && !thinkingBindingRejected && !observedOutput && isThinkingBindingRejectedError(err)) {
2152
- thinkingBindingRejected = true;
2153
- if (process.env.ZIDANE_DEBUG) process.stderr.write(`[zidane/anthropic] endpoint rejected thinking.block_binding; retrying without it: ${errorMessage(err)}\n`);
2154
- client = createClient(await loadAnthropicSdk(), apiKey, callAuth, anthropicParams?.baseURL, betasFor(baseConditionalBetas), resolvedExtraHeaders, callIsOAuth ? diagnostic.wrapFetch : void 0);
2155
- return await runStream(withoutThinkingBinding(requestParams), fastRequested, scrubPass, authPass);
2156
- }
2157
- if (!observedOutput && isForcedToolChoice(requestParams.tool_choice) && isForcedToolChoiceUnsupportedError(err)) {
2158
- MODELS_REJECTING_FORCED_TOOL_CHOICE.add(modelId);
2159
- return await runStream(withoutForcedToolChoice(requestParams), fastRequested, scrubPass, authPass);
2160
- }
2161
- if (!observedOutput && isEnabledThinking(requestParams.thinking) && isEnabledThinkingUnsupportedError(err)) {
2162
- MODELS_REJECTING_ENABLED_THINKING.add(modelId);
2163
- return await runStream(withoutEnabledThinking(requestParams), fastRequested, scrubPass, authPass);
2164
- }
2165
- throw err;
2166
- }
2167
- if (inputTransformations && inputTransformations.length > 0) try {
2168
- callbacks.onInputTransformations?.(inputTransformations);
2169
- } catch (hookErr) {
2170
- if (process.env.ZIDANE_DEBUG) process.stderr.write(`[zidane/anthropic] onInputTransformations threw: ${errorMessage(hookErr)}\n`);
2171
- }
2172
- const toolCalls = response.content.filter((b) => b.type === "tool_use").map((b) => ({
2173
- id: b.id,
2174
- name: nameBoundary.fromWire(b.name),
2175
- input: b.input
2176
- }));
2177
- const finishReason = mapStopReason(response.stop_reason);
2178
- const isPause = response.stop_reason === "pause_turn";
2179
- const rawUsage = {
2180
- input: response.usage.input_tokens,
2181
- output: response.usage.output_tokens,
2182
- cacheCreation: response.usage.cache_creation_input_tokens ?? void 0,
2183
- cacheRead: response.usage.cache_read_input_tokens ?? void 0,
2184
- ...finishReason ? { finishReason } : {},
2185
- modelId: response.model ?? options.model
2186
- };
2187
- const usage = callIsOAuth ? rawUsage : await priceAnthropicUsage(rawUsage, response, modelId, fastRequested, Boolean(bedrockConfig), options.modelCatalog);
2188
- const assistantMessage = fromAnthropic({
2189
- role: "assistant",
2190
- content: response.content
2191
- });
2192
- if (nameBoundary.changed) assistantMessage.content = assistantMessage.content.map((block) => block.type === "tool_call" ? {
2193
- ...block,
2194
- name: nameBoundary.fromWire(block.name)
2195
- } : block);
2196
- return {
2197
- assistantMessage,
2198
- text,
2199
- toolCalls,
2200
- done: !isPause && (response.stop_reason === "end_turn" || toolCalls.length === 0),
2201
- usage
2202
- };
2203
- };
2204
- let initialParams = isForcedToolChoice(params.tool_choice) && MODELS_REJECTING_FORCED_TOOL_CHOICE.has(modelId) ? withoutForcedToolChoice(params) : params;
2205
- if (isEnabledThinking(initialParams.thinking) && MODELS_REJECTING_ENABLED_THINKING.has(modelId)) initialParams = withoutEnabledThinking(initialParams);
2206
- const result = await runStream(initialParams, options.modelOptions?.fast === true && !callIsOAuth);
2207
- diagnostic.finish("success");
2208
- return result;
2209
- } catch (err) {
2210
- diagnostic.finish(options.signal?.aborted ? "abort" : "failure", { httpStatus: err && typeof err === "object" && "status" in err ? err.status : void 0 });
2211
- throw err;
2212
- } finally {
2213
- diagnostic.finish("failure");
2214
- }
2391
+ stream(options, callbacks) {
2392
+ return streamAnthropic(state, options, callbacks);
2215
2393
  }
2216
2394
  };
2217
2395
  }
2218
2396
  //#endregion
2219
- export { FAST_MODE_OPTIONS as _, buildAnthropicClientOptions as a, credentialIdentity as c, resolveAnthropicAuthShape as d, resolveAnthropicBetas as f, ANTHROPIC_EXTRA_MODELS as g, sanitizeProviderDiagnosticMetadata as h, applyAnthropicCacheBreakpoints as i, defaultAnthropicMaxTokens as l, resolveThinkingBinding as m, THINKING_BINDING_SETTING_ENV as n, cacheWriteTtlMultiplier as o, resolveAnthropicMaxOutput as p, anthropic as r, classifyAnthropicError as s, EXTENDED_CACHE_TTL_BETA as t, planAnthropicThinking as u };
2397
+ export { resolveAnthropicBetas as _, FAST_MODE_OPTIONS as a, THINKING_BINDING_SETTING_ENV as c, EXTENDED_CACHE_TTL_BETA as d, applyAnthropicCacheBreakpoints as f, resolveAnthropicAuthShape as g, credentialIdentity as h, ANTHROPIC_EXTRA_MODELS as i, planAnthropicThinking as l, buildAnthropicClientOptions as m, sanitizeProviderDiagnosticMetadata as n, defaultAnthropicMaxTokens as o, classifyAnthropicError as p, cacheWriteTtlMultiplier as r, resolveAnthropicMaxOutput as s, anthropic as t, resolveThinkingBinding as u };
2220
2398
 
2221
- //# sourceMappingURL=anthropic-C2aole0G.js.map
2399
+ //# sourceMappingURL=anthropic-CD00LhUP.js.map