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