cartethyia 2.7.9 → 2.8.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.env.example +6 -5
- package/dist/dashboard/assets/{BannedPage-BxoG1MrL.js → BannedPage-Dq530awD.js} +1 -1
- package/dist/dashboard/assets/BannedPage-Dq530awD.js.gz +0 -0
- package/dist/dashboard/assets/{CliToolDetailPage-ixwgKk53.js → CliToolDetailPage-DZzaS-7S.js} +1 -1
- package/dist/dashboard/assets/CliToolDetailPage-DZzaS-7S.js.gz +0 -0
- package/dist/dashboard/assets/{CliToolsPage-BmttNV3U.js → CliToolsPage-DaZZ3cqP.js} +1 -1
- package/dist/dashboard/assets/CliToolsPage-DaZZ3cqP.js.gz +0 -0
- package/dist/dashboard/assets/{CombosPage-BE3qwwfC.js → CombosPage-BlC_xdkX.js} +1 -1
- package/dist/dashboard/assets/CombosPage-BlC_xdkX.js.gz +0 -0
- package/dist/dashboard/assets/{ConsoleLogPage-CRZdmMIX.js → ConsoleLogPage-D-rqeVtG.js} +1 -1
- package/dist/dashboard/assets/ConsoleLogPage-D-rqeVtG.js.gz +0 -0
- package/dist/dashboard/assets/{CustomizationPage-Dv_FJ6Er.js → CustomizationPage-7xT5yg2E.js} +1 -1
- package/dist/dashboard/assets/CustomizationPage-7xT5yg2E.js.gz +0 -0
- package/dist/dashboard/assets/HealthEventsModal-Clq8E9cW.js +1 -0
- package/dist/dashboard/assets/HealthEventsModal-Clq8E9cW.js.gz +0 -0
- package/dist/dashboard/assets/{InjectSystemPromptPanel-BOoO8rpz.js → InjectSystemPromptPanel-6Teoq9Se.js} +2 -2
- package/dist/dashboard/assets/InjectSystemPromptPanel-6Teoq9Se.js.gz +0 -0
- package/dist/dashboard/assets/{LoginPage-ChJuNNVN.js → LoginPage-CZuI0MAR.js} +1 -1
- package/dist/dashboard/assets/LoginPage-CZuI0MAR.js.gz +0 -0
- package/dist/dashboard/assets/{ModelPicker-BZAJtPg1.js → ModelPicker-C1hNTlkr.js} +1 -1
- package/dist/dashboard/assets/ModelPicker-C1hNTlkr.js.gz +0 -0
- package/dist/dashboard/assets/{OverviewPage-BE40s3u5.js → OverviewPage-0yfhSI1C.js} +1 -1
- package/dist/dashboard/assets/OverviewPage-0yfhSI1C.js.gz +0 -0
- package/dist/dashboard/assets/ProviderDetailPage-xqTxdQ4c.js +8 -0
- package/dist/dashboard/assets/ProviderDetailPage-xqTxdQ4c.js.gz +0 -0
- package/dist/dashboard/assets/{ProviderIcon-CQ6bPUf_.js → ProviderIcon-Ddhm1InL.js} +1 -1
- package/dist/dashboard/assets/ProviderIcon-Ddhm1InL.js.gz +0 -0
- package/dist/dashboard/assets/ProvidersPage-C3fYuu6i.js +1 -0
- package/dist/dashboard/assets/ProvidersPage-C3fYuu6i.js.gz +0 -0
- package/dist/dashboard/assets/ProxyPage-CHtJtZ3u.js +9 -0
- package/dist/dashboard/assets/ProxyPage-CHtJtZ3u.js.gz +0 -0
- package/dist/dashboard/assets/QuotaPage-D1RV_2BX.js +1 -0
- package/dist/dashboard/assets/QuotaPage-D1RV_2BX.js.gz +0 -0
- package/dist/dashboard/assets/{SettingsPage-C5HPWqEv.js → SettingsPage-BzZAvYSX.js} +1 -1
- package/dist/dashboard/assets/SettingsPage-BzZAvYSX.js.gz +0 -0
- package/dist/dashboard/assets/{SetupPage-CFNcATJJ.js → SetupPage--s-EfEIL.js} +1 -1
- package/dist/dashboard/assets/SetupPage--s-EfEIL.js.gz +0 -0
- package/dist/dashboard/assets/{StudioPage-YoD4tY5l.js → StudioPage-BjXFGSK4.js} +1 -1
- package/dist/dashboard/assets/StudioPage-BjXFGSK4.js.gz +0 -0
- package/dist/dashboard/assets/{UsagePage-DxjaAhb_.js → UsagePage-CP8F8BN7.js} +1 -1
- package/dist/dashboard/assets/UsagePage-CP8F8BN7.js.gz +0 -0
- package/dist/dashboard/assets/{api-keys-BTlkq_Uk.js → api-keys-2hc12Uz2.js} +1 -1
- package/dist/dashboard/assets/api-keys-2hc12Uz2.js.gz +0 -0
- package/dist/dashboard/assets/app-DGXbNfAR.css +2 -0
- package/dist/dashboard/assets/app-DGXbNfAR.css.gz +0 -0
- package/dist/dashboard/assets/assert-BMcj1xZE.js +1 -0
- package/dist/dashboard/assets/assert-BMcj1xZE.js.gz +0 -0
- package/dist/dashboard/assets/{badge-DdbT_7Am.js → badge-DkRUuVfz.js} +1 -1
- package/dist/dashboard/assets/badge-DkRUuVfz.js.gz +0 -0
- package/dist/dashboard/assets/{banner-CsGN-nbm.js → banner-CDjW841Q.js} +1 -1
- package/dist/dashboard/assets/banner-CDjW841Q.js.gz +0 -0
- package/dist/dashboard/assets/{card-mgZ_TLLZ.js → card-Bto5UlL9.js} +1 -1
- package/dist/dashboard/assets/card-Bto5UlL9.js.gz +0 -0
- package/dist/dashboard/assets/{cli-tools-A1-v8-03.js → cli-tools-DaH6g9hL.js} +1 -1
- package/dist/dashboard/assets/cli-tools-DaH6g9hL.js.gz +0 -0
- package/dist/dashboard/assets/{clipboard-button-CJ4Zty89.js → clipboard-button-BYKBCzjk.js} +1 -1
- package/dist/dashboard/assets/clipboard-button-BYKBCzjk.js.gz +0 -0
- package/dist/dashboard/assets/{dialog-B5L2jPQ_.js → dialog-DL0Zftwv.js} +1 -1
- package/dist/dashboard/assets/dialog-DL0Zftwv.js.gz +0 -0
- package/dist/dashboard/assets/{drawer-DkjUouAj.js → drawer-Dpx_UXaS.js} +1 -1
- package/dist/dashboard/assets/drawer-Dpx_UXaS.js.gz +0 -0
- package/dist/dashboard/assets/{entry-B-LVLV6o.js → entry-BV7-1NoM.js} +1 -1
- package/dist/dashboard/assets/entry-BV7-1NoM.js.gz +0 -0
- package/dist/dashboard/assets/{entry-CAhdYl3B.js → entry-CGvdNU6r.js} +1 -1
- package/dist/dashboard/assets/entry-CGvdNU6r.js.gz +0 -0
- package/dist/dashboard/assets/entry-DScKYvZj.js +4 -0
- package/dist/dashboard/assets/entry-DScKYvZj.js.gz +0 -0
- package/dist/dashboard/assets/{formatters-CrsdLVsn.js → formatters-BS3DZlZj.js} +1 -1
- package/dist/dashboard/assets/formatters-BS3DZlZj.js.gz +0 -0
- package/dist/dashboard/assets/{index-BU64Lqvp.js → index-SQnvvTWX.js} +2 -2
- package/dist/dashboard/assets/index-SQnvvTWX.js.gz +0 -0
- package/dist/dashboard/assets/{inline-B2aDLyyg.js → inline-Dl-cuLK0.js} +1 -1
- package/dist/dashboard/assets/inline-Dl-cuLK0.js.gz +0 -0
- package/dist/dashboard/assets/{input-BCVkdR9d.js → input-Bfx0EzRc.js} +1 -1
- package/dist/dashboard/assets/input-Bfx0EzRc.js.gz +0 -0
- package/dist/dashboard/assets/{layout-DNcAdMK-.js → layout-BxhbQ_JS.js} +1 -1
- package/dist/dashboard/assets/layout-BxhbQ_JS.js.gz +0 -0
- package/dist/dashboard/assets/{list-row-DgrIH0hw.js → list-row-D49Y4ptn.js} +1 -1
- package/dist/dashboard/assets/list-row-D49Y4ptn.js.gz +0 -0
- package/dist/dashboard/assets/{live-Cae01iu8.js → live-CbVTdX9V.js} +1 -1
- package/dist/dashboard/assets/live-CbVTdX9V.js.gz +0 -0
- package/dist/dashboard/assets/{network-CRib7H_2.js → network-JGvDveof.js} +1 -1
- package/dist/dashboard/assets/network-JGvDveof.js.gz +0 -0
- package/dist/dashboard/assets/{numbers-BKQE8Xpz.js → numbers-Dw6kiew-.js} +1 -1
- package/dist/dashboard/assets/numbers-Dw6kiew-.js.gz +0 -0
- package/dist/dashboard/assets/{pagination-ecPvG_8g.js → pagination-iUoI8GeE.js} +1 -1
- package/dist/dashboard/assets/pagination-iUoI8GeE.js.gz +0 -0
- package/dist/dashboard/assets/providers/sensenova-intl.png +0 -0
- package/dist/dashboard/assets/providers/sensenova.png +0 -0
- package/dist/dashboard/assets/providers/zro.svg +3 -0
- package/dist/dashboard/assets/providers/zro.svg.gz +0 -0
- package/dist/dashboard/assets/quota-DiPD6UKH.js +1 -0
- package/dist/dashboard/assets/quota-DiPD6UKH.js.gz +0 -0
- package/dist/dashboard/assets/{routing-Ckm1UXuC.js → routing-8jZr-3WE.js} +1 -1
- package/dist/dashboard/assets/routing-8jZr-3WE.js.gz +0 -0
- package/dist/dashboard/assets/{select-ChoFWyKz.js → select-oO1FxMVb.js} +2 -2
- package/dist/dashboard/assets/select-oO1FxMVb.js.gz +0 -0
- package/dist/dashboard/assets/{settings-CKjFPlKW.js → settings-CLr3kdIx.js} +1 -1
- package/dist/dashboard/assets/settings-CLr3kdIx.js.gz +0 -0
- package/dist/dashboard/assets/{stack-DWCwU3fh.js → stack-Y3pDteZr.js} +1 -1
- package/dist/dashboard/assets/stack-Y3pDteZr.js.gz +0 -0
- package/dist/dashboard/assets/{state-Cg3VL5J_.js → state-CArX_Iak.js} +1 -1
- package/dist/dashboard/assets/state-CArX_Iak.js.gz +0 -0
- package/dist/dashboard/assets/{switch-Db70BMix.js → switch-DwlwmDO-.js} +1 -1
- package/dist/dashboard/assets/switch-DwlwmDO-.js.gz +0 -0
- package/dist/dashboard/assets/{useMutation-BqdE0LuM.js → useMutation-DJ9GYEgf.js} +1 -1
- package/dist/dashboard/assets/useMutation-DJ9GYEgf.js.gz +0 -0
- package/dist/dashboard/index.html +2 -2
- package/dist/dashboard/index.html.gz +0 -0
- package/dist/dashboard/precompressed-assets.json +54 -53
- package/migrations/full-postgres/0046_add_accounts_quota_plan_fetched_at.sql +7 -0
- package/migrations/full-postgres/0047_add_provider_device_flow_proxy.sql +17 -0
- package/migrations/lite-sqlite3/0046_add_accounts_quota_plan_fetched_at.sql +4 -0
- package/migrations/lite-sqlite3/0047_add_provider_device_flow_proxy.sql +19 -0
- package/package.json +1 -1
- package/src/boot/app.ts +11 -14
- package/src/boot/dependencies.ts +5 -7
- package/src/boot/flush.ts +20 -0
- package/src/boot/lifecycle.ts +7 -5
- package/src/config/providers.ts +6 -5
- package/src/config/routing.ts +26 -0
- package/src/config/spec-metadata.ts +72 -0
- package/src/config/spec.ts +28 -8
- package/src/console/api-keys/contracts.ts +12 -1
- package/src/console/api-keys/routes.ts +40 -28
- package/src/console/auth/account-reset.ts +7 -9
- package/src/console/backup/contracts.ts +4 -0
- package/src/console/backup/export-endpoint.ts +7 -5
- package/src/console/backup/nine-router.ts +71 -10
- package/src/console/backup/service.ts +8 -1
- package/src/console/cli-tools/service.ts +6 -12
- package/src/console/console-router-guards.ts +23 -16
- package/src/console/console-router.ts +1 -1
- package/src/console/domain-registration.ts +7 -4
- package/src/console/inferhub/client.ts +1 -1
- package/src/console/inferhub/normalize.ts +24 -28
- package/src/console/inferhub/types.ts +3 -0
- package/src/console/ip-bans/routes.ts +7 -13
- package/src/console/observability/live.ts +2 -2
- package/src/console/observability/store.ts +0 -53
- package/src/console/providers/catalog/contracts.ts +9 -3
- package/src/console/providers/catalog/model-operations.ts +2 -3
- package/src/console/providers/catalog/provider-operations.ts +1 -1
- package/src/console/providers/catalog/routes.ts +3 -2
- package/src/console/providers/catalog/store.ts +1914 -1902
- package/src/console/providers/detail/routes.ts +1 -0
- package/src/console/providers/detail/store.ts +4 -0
- package/src/console/providers/oauth/callback-listener.ts +30 -11
- package/src/console/providers/oauth/device-egress.ts +123 -0
- package/src/console/providers/oauth/routes.ts +123 -16
- package/src/console/quota/account-quota-global.ts +14 -24
- package/src/console/quota/account-quota-shared.ts +49 -0
- package/src/console/quota/account-quota-tenant.ts +11 -23
- package/src/console/quota/account-test-egress.ts +2 -2
- package/src/console/quota/daily-growth-job.ts +1 -1
- package/src/console/quota/quota-view.ts +19 -3
- package/src/console/routing/pools/contracts.ts +1 -1
- package/src/console/routing/pools/operations.ts +32 -47
- package/src/console/routing/pools/probe-verdict.ts +2 -2
- package/src/console/routing/pools/relay-deploy.ts +1 -1
- package/src/console/routing/pools/store.ts +4 -4
- package/src/console/shared/errors.ts +33 -6
- package/src/main.ts +2 -3
- package/src/network/client.ts +67 -0
- package/src/network/egress/bidi-session.ts +322 -0
- package/src/network/egress/dial.ts +201 -0
- package/src/network/egress/factory.ts +191 -0
- package/src/network/{outbound-fetch.ts → egress/fetch.ts} +195 -29
- package/src/network/egress/tls-profile.ts +123 -0
- package/src/network/egress/ws.ts +175 -0
- package/src/network/pool/{byte-accounting.ts → accounting.ts} +3 -2
- package/src/network/{types.ts → pool/agent-config.ts} +1 -1
- package/src/network/pool/agent.ts +2 -2
- package/src/network/{pool-cooldown-store.ts → pool/cooldown-store.ts} +95 -20
- package/src/network/{pool-health-machine.ts → pool/health.ts} +205 -6
- package/src/network/pool/resolver.ts +10 -849
- package/src/network/pool/selector.ts +184 -41
- package/src/network/ssrf.ts +7 -7
- package/src/network/{retry.ts → util/retry.ts} +1 -1
- package/src/network/{rate-limit-verdict.ts → verdict.ts} +1 -1
- package/src/observability/event-log.ts +7 -361
- package/src/observability/performance-metrics.ts +9 -0
- package/src/observability/runtime-metrics.ts +14 -9
- package/src/observability/telemetry-buffer.ts +16 -26
- package/src/observability/telemetry-reconciliation.ts +9 -37
- package/src/observability/telemetry-row.ts +125 -0
- package/src/persistence/db-mode.ts +4 -1
- package/src/persistence/dialect.ts +18 -0
- package/src/persistence/migrate.ts +6 -3
- package/src/persistence/schema.ts +17 -0
- package/src/persistence/ttl-cache.ts +21 -3
- package/src/protocol/codecs.ts +59 -2
- package/src/protocol/dsml.ts +34 -86
- package/src/protocol/markup-stream-parser.ts +195 -0
- package/src/protocol/reasoning-text.ts +19 -0
- package/src/protocol/request/chat.ts +10 -10
- package/src/protocol/request/gemini.ts +8 -2
- package/src/protocol/request/messages.ts +34 -22
- package/src/protocol/response/chat.ts +12 -20
- package/src/protocol/response/messages.ts +34 -7
- package/src/protocol/response/omp-tool-call-markup.ts +43 -86
- package/src/protocol/response/responses.ts +18 -2
- package/src/protocol/stop-reason.ts +23 -1
- package/src/protocol/think-split.ts +112 -0
- package/src/protocol/translation/dialect/qwen.ts +26 -58
- package/src/protocol/translation/quirks.ts +15 -0
- package/src/protocol/upstream/send-claude-messages.ts +2 -2
- package/src/providers/adapters/compatible-adapter.ts +76 -12
- package/src/providers/authentication/oauth-client.ts +40 -6
- package/src/providers/authentication/oauth-device-flow.ts +105 -11
- package/src/providers/authentication/oauth-flow-store.ts +82 -1
- package/src/providers/authentication/oauth-refresh-service.ts +766 -758
- package/src/providers/configured-provider.ts +148 -0
- package/src/providers/default-registry.ts +137 -36
- package/src/providers/discovery/discovery-types.ts +7 -0
- package/src/providers/discovery/probe-phases.ts +20 -6
- package/src/providers/discovery/probing-service.ts +22 -2
- package/src/providers/integrations/alibabacp/alibabacp-models.ts +1 -2
- package/src/providers/integrations/{dashscope-models.ts → alibabacp/dashscope-models.ts} +2 -2
- package/src/providers/integrations/antigravity/antigravity-protocol.ts +16 -1
- package/src/providers/integrations/buddy/account.ts +969 -0
- package/src/providers/integrations/buddy/capabilities.ts +12 -12
- package/src/providers/integrations/buddy/{buddy-catalog-shared.ts → catalog.ts} +198 -136
- package/src/providers/integrations/buddy/{buddy-chat-shared.ts → chat.ts} +176 -20
- package/src/providers/integrations/buddy/codebuddy/index.ts +429 -0
- package/src/providers/integrations/buddy/codebuddy/shared.ts +41 -26
- package/src/providers/integrations/buddy/headers.ts +311 -0
- package/src/providers/integrations/buddy/lifecycle.ts +1018 -0
- package/src/providers/integrations/buddy/{buddy-media.ts → media.ts} +1 -1
- package/src/providers/integrations/claude/claude-quota.ts +14 -17
- package/src/providers/integrations/cline/cline-oauth.ts +10 -5
- package/src/providers/integrations/cline/cline.ts +5 -6
- package/src/providers/integrations/clixad/clixad-oauth.ts +98 -0
- package/src/providers/integrations/clixad/clixad-quota.ts +132 -0
- package/src/providers/integrations/clixad/provider.ts +145 -0
- package/src/providers/integrations/codex/codex-oauth.ts +8 -5
- package/src/providers/integrations/commandcode/quota.ts +22 -28
- package/src/providers/integrations/cursor/cursor-auth.ts +1 -9
- package/src/providers/integrations/cursor/cursor-exec.ts +9 -2
- package/src/providers/integrations/cursor/cursor-hardening.ts +279 -0
- package/src/providers/integrations/cursor/cursor-http2.ts +605 -6
- package/src/providers/integrations/cursor/cursor-request.ts +26 -12
- package/src/providers/integrations/cursor/cursor-shared.ts +8 -5
- package/src/providers/integrations/cursor/cursor.ts +574 -110
- package/src/providers/integrations/cursor/protocol/messages.ts +22 -29
- package/src/providers/integrations/cursor/protocol/protobuf-schema.ts +37 -0
- package/src/providers/integrations/deepai/deepai-catalog.ts +149 -0
- package/src/providers/integrations/deepai/deepai-common.ts +145 -0
- package/src/providers/integrations/deepai/deepai-oauth.ts +129 -0
- package/src/providers/integrations/deepai/deepai-quota.ts +97 -0
- package/src/providers/integrations/deepai/provider.ts +42 -0
- package/src/providers/integrations/devin/devin-auth.ts +7 -0
- package/src/providers/integrations/devin/protocol/devin-proto.ts +1 -27
- package/src/providers/integrations/factory/factory-oauth.ts +33 -51
- package/src/providers/integrations/freebuff/assets/official-system-manager.txt +88 -0
- package/src/providers/integrations/freebuff/assets/official-system-worker.txt +57 -0
- package/src/providers/integrations/freebuff/assets/official-tools.json +1070 -0
- package/src/providers/integrations/freebuff/freebuff-catalog.ts +120 -0
- package/src/providers/integrations/freebuff/freebuff-constants.ts +1233 -0
- package/src/providers/integrations/freebuff/freebuff-discovery.ts +108 -0
- package/src/providers/integrations/freebuff/freebuff-oauth.ts +240 -0
- package/src/providers/integrations/freebuff/freebuff-quota.ts +260 -0
- package/src/providers/integrations/freebuff/freebuff-virtual.ts +89 -0
- package/src/providers/integrations/freebuff/freebuff.ts +682 -0
- package/src/providers/integrations/freepi/freepi-catalog.ts +5 -0
- package/src/providers/integrations/freepi/freepi-discovery.ts +2 -2
- package/src/providers/integrations/freepi/freepi-headers.ts +2 -2
- package/src/providers/integrations/freepi/freepi-protocol.ts +11 -2
- package/src/providers/integrations/freepi/freepi-realm.ts +0 -3
- package/src/providers/integrations/freepi/freepi-session.ts +158 -0
- package/src/providers/integrations/freepi/freepi.ts +80 -54
- package/src/providers/integrations/github/github-discovery.ts +30 -13
- package/src/providers/integrations/github/github-oauth.ts +217 -44
- package/src/providers/integrations/github/github-quota.ts +22 -5
- package/src/providers/integrations/github/github.ts +40 -32
- package/src/providers/integrations/grok/grok-oauth.ts +52 -49
- package/src/providers/integrations/grok/grok-ratelimit-store.ts +10 -17
- package/src/providers/integrations/grok/grok-turn-index.ts +11 -16
- package/src/providers/integrations/hermes/hermes-oauth.ts +3 -3
- package/src/providers/integrations/{hermes.ts → hermes/hermes.ts} +42 -13
- package/src/providers/integrations/hermes/index.ts +2 -0
- package/src/providers/integrations/kilo/kilo-oauth.ts +4 -4
- package/src/providers/integrations/kilo/kilo.ts +1 -1
- package/src/providers/integrations/kimi/kimi-oauth.ts +3 -3
- package/src/providers/integrations/kiro/kiro-catalog.ts +17 -1
- package/src/providers/integrations/kiro/kiro-discovery.ts +10 -12
- package/src/providers/integrations/kiro/kiro-oauth.ts +2 -2
- package/src/providers/integrations/kiro/kiro-quota.ts +8 -4
- package/src/providers/integrations/kiro/kiro.ts +15 -19
- package/src/providers/integrations/muse/muse-oauth.ts +5 -5
- package/src/providers/integrations/ollamacloud/index.ts +2 -0
- package/src/providers/integrations/{ollamacloud-models.ts → ollamacloud/models.ts} +2 -2
- package/src/providers/integrations/{ollamacloud-quota.ts → ollamacloud/quota.ts} +3 -3
- package/src/providers/integrations/opencode/fingerprint.ts +1 -1
- package/src/providers/integrations/opencode/opencode-go-quota.ts +2 -8
- package/src/providers/integrations/openrouter/provider.ts +1 -1
- package/src/providers/integrations/perch/perch-credential.ts +25 -0
- package/src/providers/integrations/perch/perch-protocol.ts +0 -6
- package/src/providers/integrations/perch/perch-quota.ts +2 -16
- package/src/providers/integrations/perch/perch.ts +6 -16
- package/src/providers/integrations/qoder/claim-qoder-credits.ts +19 -60
- package/src/providers/integrations/qoder/qoder-adapter.ts +20 -125
- package/src/providers/integrations/qoder/qoder-auth.ts +109 -30
- package/src/providers/integrations/qoder/qoder-catalog.ts +21 -6
- package/src/providers/integrations/qoder/qoder-chat.ts +32 -29
- package/src/providers/integrations/qoder/qoder-checkin.ts +5 -5
- package/src/providers/integrations/qoder/qoder-cosy.ts +37 -9
- package/src/providers/integrations/qoder/qoder-oauth.ts +9 -2
- package/src/providers/integrations/qoder/qoder-realm.ts +13 -36
- package/src/providers/integrations/qoder/qoder-sse.ts +447 -68
- package/src/providers/integrations/qoder/qoder-types.ts +9 -0
- package/src/providers/integrations/qoder/qoder.ts +3 -26
- package/src/providers/integrations/sensenova/provider.ts +144 -0
- package/src/providers/integrations/trae/trae-protocol.ts +9 -5
- package/src/providers/integrations/trae/trae-quota.ts +21 -29
- package/src/providers/integrations/trae/trae-realm.ts +38 -0
- package/src/providers/integrations/trae/trae.ts +7 -24
- package/src/providers/integrations/vercel/provider.ts +117 -0
- package/src/providers/integrations/vercel/vercel-quota.ts +96 -0
- package/src/providers/integrations/xai/xai-oauth.ts +5 -5
- package/src/providers/integrations/zcode-start-plan/gifts.ts +1 -1
- package/src/providers/integrations/zcode-start-plan/oauth.ts +3 -3
- package/src/providers/integrations/zcode-start-plan/provider.ts +226 -23
- package/src/providers/integrations/zcode-start-plan/quota.ts +19 -2
- package/src/providers/integrations/zro/zro.ts +205 -0
- package/src/providers/operations/account-error-classification.ts +199 -307
- package/src/providers/operations/account-health-service.ts +82 -1
- package/src/providers/operations/account-refresh-status.ts +36 -37
- package/src/providers/operations/account-tier.ts +15 -16
- package/src/providers/operations/client-version-resolver.ts +1 -1
- package/src/providers/operations/client-versions.ts +100 -81
- package/src/providers/operations/cooldown-rules.ts +11 -16
- package/src/providers/operations/oauth-refresh-lead.ts +46 -22
- package/src/providers/operations/{model-catalog-cache.ts → provider-caches.ts} +68 -16
- package/src/providers/operations/provider-catalog-service.ts +1 -1
- package/src/providers/operations/provider-credential-service.ts +118 -51
- package/src/providers/operations/provider-rules/github.ts +48 -0
- package/src/providers/operations/provider-rules/grok.ts +33 -0
- package/src/providers/operations/provider-rules/inception.ts +49 -0
- package/src/providers/operations/provider-rules/index.ts +32 -0
- package/src/providers/operations/provider-rules/perch.ts +37 -0
- package/src/providers/operations/provider-rules/qoder.ts +70 -0
- package/src/providers/operations/provider-rules/trae.ts +81 -0
- package/src/providers/operations/session-resolution.ts +17 -1
- package/src/providers/provider-contracts.ts +6 -4
- package/src/providers/{provider-credential-resolver.ts → provider-credentials.ts} +40 -3
- package/src/providers/provider-metadata.ts +70 -10
- package/src/providers/provider-probe.ts +15 -1
- package/src/providers/provider-registry.ts +42 -33
- package/src/providers/quota/quota-contracts.ts +2 -0
- package/src/providers/quota/quota-limit-windows.ts +16 -5
- package/src/providers/quota/quota-support.ts +1 -1
- package/src/providers/quota/quota-window-parser.ts +90 -18
- package/src/providers/quota/refresh.ts +100 -21
- package/src/security/api-key-auth-cache.ts +1 -1
- package/src/security/api-key-auth.ts +6 -2
- package/src/security/ip-boundary.ts +1 -1
- package/src/transport/dispatch/attempt-finalize.ts +15 -14
- package/src/transport/dispatch/attempt-loop.ts +73 -19
- package/src/transport/dispatch/generation.ts +2 -8
- package/src/transport/dispatch/handler-deps.ts +1 -1
- package/src/transport/dispatch/leases.ts +1 -1
- package/src/transport/dispatch/native-shared.ts +25 -0
- package/src/transport/dispatch/proxy-request.ts +8 -46
- package/src/transport/dispatch/responses-compact.ts +2 -8
- package/src/transport/dispatch/retry-policy.ts +1 -1
- package/src/transport/dispatch/streaming/finalize.ts +10 -7
- package/src/transport/dispatch/streaming/stream.ts +9 -37
- package/src/transport/dispatch/systemone.ts +2 -8
- package/src/transport/dispatch/token-count.ts +2 -6
- package/src/transport/dispatch/upstream.ts +63 -0
- package/src/transport/drain-endpoint.ts +31 -4
- package/src/transport/failure-policy.ts +16 -30
- package/src/transport/guards/body-policy.ts +7 -1
- package/src/transport/guards/error-lifecycle.ts +13 -1
- package/src/transport/guards/request-context.ts +22 -14
- package/src/transport/request/preparer.ts +81 -71
- package/src/transport/routing/bounded-lru.ts +14 -0
- package/src/transport/routing/drain-reserve.ts +129 -0
- package/src/transport/routing/plan-gate.ts +7 -1
- package/src/transport/routing/round-robin.ts +60 -0
- package/src/transport/routing/route-catalog.ts +123 -111
- package/src/transport/routing/route-model.ts +51 -9
- package/src/transport/routing/router.ts +393 -32
- package/src/transport/shutdown-notice.ts +1 -1
- package/src/transport/surface/adapters.ts +11 -2
- package/src/transport/surface/chat/adapter.ts +2 -2
- package/src/transport/surface/chat/encode.ts +47 -4
- package/src/transport/surface/chat/parse.ts +2 -12
- package/src/transport/surface/completion.ts +44 -33
- package/src/transport/surface/content-parts.ts +21 -0
- package/src/transport/surface/messages/adapter.ts +7 -1
- package/src/transport/surface/messages/encode.ts +11 -3
- package/src/transport/surface/messages/parse.ts +2 -1
- package/src/transport/surface/messages/stream.ts +33 -17
- package/src/transport/surface/responses/encode.ts +22 -5
- package/src/transport/surface/responses/parse.ts +3 -11
- package/src/workers/buddy-growth-tasks.ts +8 -8
- package/src/workers/daily-checkin.ts +4 -4
- package/src/workers/quota-refresh-sweep.ts +1 -1
- package/src/workers/zcode-gift-claim.ts +1 -1
- package/dist/dashboard/assets/BannedPage-BxoG1MrL.js.gz +0 -0
- package/dist/dashboard/assets/CliToolDetailPage-ixwgKk53.js.gz +0 -0
- package/dist/dashboard/assets/CliToolsPage-BmttNV3U.js.gz +0 -0
- package/dist/dashboard/assets/CombosPage-BE3qwwfC.js.gz +0 -0
- package/dist/dashboard/assets/ConsoleLogPage-CRZdmMIX.js.gz +0 -0
- package/dist/dashboard/assets/CustomizationPage-Dv_FJ6Er.js.gz +0 -0
- package/dist/dashboard/assets/HealthEventsModal-CoVrw2sM.js +0 -1
- package/dist/dashboard/assets/HealthEventsModal-CoVrw2sM.js.gz +0 -0
- package/dist/dashboard/assets/InjectSystemPromptPanel-BOoO8rpz.js.gz +0 -0
- package/dist/dashboard/assets/LoginPage-ChJuNNVN.js.gz +0 -0
- package/dist/dashboard/assets/ModelPicker-BZAJtPg1.js.gz +0 -0
- package/dist/dashboard/assets/OverviewPage-BE40s3u5.js.gz +0 -0
- package/dist/dashboard/assets/ProviderDetailPage-sfLoQtPV.js +0 -8
- package/dist/dashboard/assets/ProviderDetailPage-sfLoQtPV.js.gz +0 -0
- package/dist/dashboard/assets/ProviderIcon-CQ6bPUf_.js.gz +0 -0
- package/dist/dashboard/assets/ProvidersPage-DcepmPWo.js +0 -1
- package/dist/dashboard/assets/ProvidersPage-DcepmPWo.js.gz +0 -0
- package/dist/dashboard/assets/ProxyPage-BJ87Pp0U.js +0 -9
- package/dist/dashboard/assets/ProxyPage-BJ87Pp0U.js.gz +0 -0
- package/dist/dashboard/assets/QuotaPage-gkSyRAKa.js +0 -1
- package/dist/dashboard/assets/QuotaPage-gkSyRAKa.js.gz +0 -0
- package/dist/dashboard/assets/SettingsPage-C5HPWqEv.js.gz +0 -0
- package/dist/dashboard/assets/SetupPage-CFNcATJJ.js.gz +0 -0
- package/dist/dashboard/assets/StudioPage-YoD4tY5l.js.gz +0 -0
- package/dist/dashboard/assets/UsagePage-DxjaAhb_.js.gz +0 -0
- package/dist/dashboard/assets/api-keys-BTlkq_Uk.js.gz +0 -0
- package/dist/dashboard/assets/app-BX2nnKqs.css +0 -2
- package/dist/dashboard/assets/app-BX2nnKqs.css.gz +0 -0
- package/dist/dashboard/assets/assert-CndthXFQ.js +0 -1
- package/dist/dashboard/assets/assert-CndthXFQ.js.gz +0 -0
- package/dist/dashboard/assets/badge-DdbT_7Am.js.gz +0 -0
- package/dist/dashboard/assets/banner-CsGN-nbm.js.gz +0 -0
- package/dist/dashboard/assets/card-mgZ_TLLZ.js.gz +0 -0
- package/dist/dashboard/assets/cli-tools-A1-v8-03.js.gz +0 -0
- package/dist/dashboard/assets/clipboard-button-CJ4Zty89.js.gz +0 -0
- package/dist/dashboard/assets/dialog-B5L2jPQ_.js.gz +0 -0
- package/dist/dashboard/assets/drawer-DkjUouAj.js.gz +0 -0
- package/dist/dashboard/assets/entry-B-LVLV6o.js.gz +0 -0
- package/dist/dashboard/assets/entry-CAhdYl3B.js.gz +0 -0
- package/dist/dashboard/assets/entry-D2xD0Tmd.js +0 -4
- package/dist/dashboard/assets/entry-D2xD0Tmd.js.gz +0 -0
- package/dist/dashboard/assets/formatters-CrsdLVsn.js.gz +0 -0
- package/dist/dashboard/assets/index-BU64Lqvp.js.gz +0 -0
- package/dist/dashboard/assets/inline-B2aDLyyg.js.gz +0 -0
- package/dist/dashboard/assets/input-BCVkdR9d.js.gz +0 -0
- package/dist/dashboard/assets/layout-DNcAdMK-.js.gz +0 -0
- package/dist/dashboard/assets/list-row-DgrIH0hw.js.gz +0 -0
- package/dist/dashboard/assets/live-Cae01iu8.js.gz +0 -0
- package/dist/dashboard/assets/network-CRib7H_2.js.gz +0 -0
- package/dist/dashboard/assets/numbers-BKQE8Xpz.js.gz +0 -0
- package/dist/dashboard/assets/pagination-ecPvG_8g.js.gz +0 -0
- package/dist/dashboard/assets/quota-DJ1QlAOq.js +0 -1
- package/dist/dashboard/assets/quota-DJ1QlAOq.js.gz +0 -0
- package/dist/dashboard/assets/routing-Ckm1UXuC.js.gz +0 -0
- package/dist/dashboard/assets/select-ChoFWyKz.js.gz +0 -0
- package/dist/dashboard/assets/settings-CKjFPlKW.js.gz +0 -0
- package/dist/dashboard/assets/stack-DWCwU3fh.js.gz +0 -0
- package/dist/dashboard/assets/state-Cg3VL5J_.js.gz +0 -0
- package/dist/dashboard/assets/switch-Db70BMix.js.gz +0 -0
- package/dist/dashboard/assets/useMutation-BqdE0LuM.js.gz +0 -0
- package/src/network/pool-health.ts +0 -210
- package/src/providers/bundled-discovery-providers.ts +0 -98
- package/src/providers/configured-openai-providers.ts +0 -120
- package/src/providers/integrations/buddy/buddy-checkin.ts +0 -521
- package/src/providers/integrations/buddy/buddy-cli-headers.ts +0 -76
- package/src/providers/integrations/buddy/buddy-conversation-headers.ts +0 -130
- package/src/providers/integrations/buddy/buddy-discovery-shared.ts +0 -234
- package/src/providers/integrations/buddy/buddy-growth-shared.ts +0 -496
- package/src/providers/integrations/buddy/buddy-identity.ts +0 -300
- package/src/providers/integrations/buddy/buddy-oauth-shared.ts +0 -341
- package/src/providers/integrations/buddy/buddy-quota-shared.ts +0 -417
- package/src/providers/integrations/buddy/buddy-server-tools.ts +0 -240
- package/src/providers/integrations/buddy/buddy-usage-shared.ts +0 -221
- package/src/providers/integrations/buddy/buddy-usage-store.ts +0 -181
- package/src/providers/integrations/buddy/codebuddy/cn-catalog.ts +0 -37
- package/src/providers/integrations/buddy/codebuddy/cn-provider.ts +0 -185
- package/src/providers/integrations/buddy/codebuddy/oauth.ts +0 -47
- package/src/providers/integrations/buddy/codebuddy/provider.ts +0 -175
- package/src/providers/integrations/buddy/codebuddy/quota.ts +0 -154
- package/src/providers/integrations/qoder/chat-proto.ts +0 -328
- package/src/providers/integrations/qoder/qoder-grpc.ts +0 -871
- package/src/providers/integrations/qoder/qoder-ide.ts +0 -588
- package/src/providers/operations/model-discovery-cache.ts +0 -34
- package/src/providers/operations/probe-fetch.ts +0 -15
- package/src/providers/operations/provider-version-cache.ts +0 -30
- package/src/providers/provider-capabilities.ts +0 -33
- package/src/providers/provider-credential-envelope.ts +0 -43
- /package/dist/dashboard/assets/{app-B7kIWFm5.js → app-C0gTXEoN.js} +0 -0
- /package/dist/dashboard/assets/{app-B7kIWFm5.js.gz → app-C0gTXEoN.js.gz} +0 -0
- /package/src/network/{http2-bidi.ts → bidi.ts} +0 -0
- /package/src/network/pool/{pool-scripts.ts → scripts.ts} +0 -0
- /package/src/network/pool/{pool-state.ts → state.ts} +0 -0
- /package/src/network/{backoff.ts → util/backoff.ts} +0 -0
- /package/src/network/{deduplication.ts → util/dedupe.ts} +0 -0
- /package/src/network/{ip-utils.ts → util/ip.ts} +0 -0
|
@@ -0,0 +1,195 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Generic streaming prefix-buffer parser for in-band tool-call markup.
|
|
3
|
+
*
|
|
4
|
+
* Three grammars (DSML blocks, OMP `<tool_calls:8hex>` envelopes, Qwen
|
|
5
|
+
* `<tool_call>` JSON blocks) share one stateful loop: append chunks to a
|
|
6
|
+
* pending buffer, scan for the earliest opener, settle visible text up to a
|
|
7
|
+
* safe end that holds back a possible trailing opener fragment, parse a
|
|
8
|
+
* complete block when its closer appears, fail open past a block-size cap, and
|
|
9
|
+
* flush the tail. The grammar-specific parts are supplied as configuration:
|
|
10
|
+
* opener strings, an opener classifier (some grammars must validate beyond the
|
|
11
|
+
* bare prefix, e.g. OMP's hex marker), closer/parse functions, an unclosed
|
|
12
|
+
* block policy (hold vs fail-open pass-through), a flush policy (pass through
|
|
13
|
+
* vs discard an unterminated envelope), and a call-id factory. Each parser
|
|
14
|
+
* instance keeps its own buffer; nothing is shared.
|
|
15
|
+
*/
|
|
16
|
+
|
|
17
|
+
/** Result of one push/flush pass: text that settled plus recovered calls. */
|
|
18
|
+
export interface MarkupStreamParseResult<Call extends { readonly id: string }> {
|
|
19
|
+
readonly text: string;
|
|
20
|
+
readonly calls: readonly Call[];
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
/** Raw call shape produced by a grammar's block parser, without its id. */
|
|
24
|
+
export type MarkupRawCall<Call extends { readonly id: string }> = Omit<Call, "id">;
|
|
25
|
+
|
|
26
|
+
/** Builds a complete call (id included) from a parsed raw call. */
|
|
27
|
+
export type MarkupCallFactory<Call extends { readonly id: string }> = (
|
|
28
|
+
call: MarkupRawCall<Call>,
|
|
29
|
+
index: number,
|
|
30
|
+
seq: number,
|
|
31
|
+
) => Call;
|
|
32
|
+
|
|
33
|
+
/** Classification of one opener candidate occurrence. */
|
|
34
|
+
export type MarkupOpenerClassification<Call extends { readonly id: string }> =
|
|
35
|
+
| {
|
|
36
|
+
/**
|
|
37
|
+
* The candidate may be the start of a real opener (e.g. a partial hex
|
|
38
|
+
* marker): hold everything from the candidate until a later chunk
|
|
39
|
+
* completes or disproves it.
|
|
40
|
+
*/
|
|
41
|
+
readonly kind: "hold";
|
|
42
|
+
}
|
|
43
|
+
| {
|
|
44
|
+
/**
|
|
45
|
+
* The candidate is definitely not an opener: emit it as literal text
|
|
46
|
+
* (one character) and rescan after it.
|
|
47
|
+
*/
|
|
48
|
+
readonly kind: "literal";
|
|
49
|
+
}
|
|
50
|
+
| {
|
|
51
|
+
readonly kind: "found";
|
|
52
|
+
/** Tag that closes the block opened at this position. */
|
|
53
|
+
readonly closer: string;
|
|
54
|
+
/**
|
|
55
|
+
* Parses one complete block (opener through closer). `undefined` means
|
|
56
|
+
* the block is not valid markup and is passed through as text verbatim.
|
|
57
|
+
*/
|
|
58
|
+
readonly parse: (block: string) => readonly MarkupRawCall<Call>[] | undefined;
|
|
59
|
+
/**
|
|
60
|
+
* Call factory for the calls recovered from this block; defaults to the
|
|
61
|
+
* parser-level `callId`. Some grammars derive ids from block-local state
|
|
62
|
+
* (e.g. OMP embeds the envelope marker).
|
|
63
|
+
*/
|
|
64
|
+
readonly callId?: MarkupCallFactory<Call>;
|
|
65
|
+
};
|
|
66
|
+
|
|
67
|
+
export interface MarkupStreamParserOptions<Call extends { readonly id: string }> {
|
|
68
|
+
/**
|
|
69
|
+
* Opener frontier. The earliest occurrence wins; trailing fragments that
|
|
70
|
+
* could start one are held back from settled text.
|
|
71
|
+
*/
|
|
72
|
+
readonly openers: readonly string[];
|
|
73
|
+
/** Classifies an opener candidate found at a scan position. */
|
|
74
|
+
readonly classifyOpener: (
|
|
75
|
+
pending: string,
|
|
76
|
+
index: number,
|
|
77
|
+
opener: string,
|
|
78
|
+
) => MarkupOpenerClassification<Call>;
|
|
79
|
+
/**
|
|
80
|
+
* Policy when a block's closer has not arrived yet. Default `"hold"`: keep
|
|
81
|
+
* the whole pending buffer from the opener until a later chunk completes or
|
|
82
|
+
* disproves the block. Returning `{ kind: "passThrough" }` fails open:
|
|
83
|
+
* everything from the opener is emitted as text immediately (the DSML
|
|
84
|
+
* block-size cap).
|
|
85
|
+
*/
|
|
86
|
+
readonly onUnclosed?: (
|
|
87
|
+
pending: string,
|
|
88
|
+
openIndex: number,
|
|
89
|
+
) => "hold" | { readonly kind: "passThrough" };
|
|
90
|
+
/**
|
|
91
|
+
* Tail policy at flush. Returns the text to emit for whatever remains in the
|
|
92
|
+
* buffer (default: everything, i.e. pass through). A grammar that discards
|
|
93
|
+
* unterminated envelopes returns `""` when the tail looks like an opener.
|
|
94
|
+
*/
|
|
95
|
+
readonly flush?: (pending: string) => string;
|
|
96
|
+
/** Call factory for recovered calls, unless a block overrides it. */
|
|
97
|
+
readonly callId?: MarkupCallFactory<Call>;
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
export class MarkupStreamParser<Call extends { readonly id: string }> {
|
|
101
|
+
readonly #options: MarkupStreamParserOptions<Call>;
|
|
102
|
+
#pending = "";
|
|
103
|
+
#callSequence = 0;
|
|
104
|
+
|
|
105
|
+
constructor(options: MarkupStreamParserOptions<Call>) {
|
|
106
|
+
this.#options = options;
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
/** Feeds one chunk and returns only settled text and complete calls. */
|
|
110
|
+
push(chunk: string): MarkupStreamParseResult<Call> {
|
|
111
|
+
this.#pending += chunk;
|
|
112
|
+
let cursor = 0;
|
|
113
|
+
let visible = "";
|
|
114
|
+
const calls: Call[] = [];
|
|
115
|
+
for (;;) {
|
|
116
|
+
let openIndex = -1;
|
|
117
|
+
let opener = "";
|
|
118
|
+
for (const candidate of this.#options.openers) {
|
|
119
|
+
const index = this.#pending.indexOf(candidate, cursor);
|
|
120
|
+
if (index >= 0 && (openIndex < 0 || index < openIndex)) {
|
|
121
|
+
openIndex = index;
|
|
122
|
+
opener = candidate;
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
if (openIndex < 0) {
|
|
126
|
+
const safeEnd = this.#settledEnd(cursor);
|
|
127
|
+
visible += this.#pending.slice(cursor, safeEnd);
|
|
128
|
+
cursor = safeEnd;
|
|
129
|
+
break;
|
|
130
|
+
}
|
|
131
|
+
visible += this.#pending.slice(cursor, openIndex);
|
|
132
|
+
const classified = this.#options.classifyOpener(this.#pending, openIndex, opener);
|
|
133
|
+
if (classified.kind === "literal") {
|
|
134
|
+
visible += "<";
|
|
135
|
+
cursor = openIndex + 1;
|
|
136
|
+
continue;
|
|
137
|
+
}
|
|
138
|
+
if (classified.kind === "hold") {
|
|
139
|
+
cursor = openIndex;
|
|
140
|
+
break;
|
|
141
|
+
}
|
|
142
|
+
const closeIndex = this.#pending.indexOf(classified.closer, openIndex + opener.length);
|
|
143
|
+
if (closeIndex < 0) {
|
|
144
|
+
const decision = this.#options.onUnclosed?.(this.#pending, openIndex) ?? "hold";
|
|
145
|
+
if (decision === "hold") {
|
|
146
|
+
cursor = openIndex;
|
|
147
|
+
break;
|
|
148
|
+
}
|
|
149
|
+
visible += this.#pending.slice(openIndex);
|
|
150
|
+
cursor = this.#pending.length;
|
|
151
|
+
break;
|
|
152
|
+
}
|
|
153
|
+
const end = closeIndex + classified.closer.length;
|
|
154
|
+
const block = this.#pending.slice(openIndex, end);
|
|
155
|
+
const parsed = classified.parse(block);
|
|
156
|
+
if (parsed === undefined) {
|
|
157
|
+
visible += block;
|
|
158
|
+
} else {
|
|
159
|
+
const callFor = classified.callId ?? this.#options.callId;
|
|
160
|
+
if (callFor === undefined) {
|
|
161
|
+
throw new Error("MarkupStreamParser: no call factory configured");
|
|
162
|
+
}
|
|
163
|
+
parsed.forEach((call, index) => {
|
|
164
|
+
calls.push(callFor(call, index, this.#callSequence++));
|
|
165
|
+
});
|
|
166
|
+
}
|
|
167
|
+
cursor = end;
|
|
168
|
+
}
|
|
169
|
+
this.#pending = this.#pending.slice(cursor);
|
|
170
|
+
return { text: visible, calls };
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
/** Settles trailing text per the configured flush policy. */
|
|
174
|
+
flush(): MarkupStreamParseResult<Call> {
|
|
175
|
+
const text = this.#options.flush?.(this.#pending) ?? this.#pending;
|
|
176
|
+
this.#pending = "";
|
|
177
|
+
return { text, calls: [] };
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
/** Holds back a trailing fragment that could be the start of an opener. */
|
|
181
|
+
#settledEnd(start: number): number {
|
|
182
|
+
const remaining = this.#pending.slice(start);
|
|
183
|
+
const maxOpener = this.#options.openers.reduce(
|
|
184
|
+
(max, open) => Math.max(max, open.length - 1),
|
|
185
|
+
0,
|
|
186
|
+
);
|
|
187
|
+
for (let length = Math.min(maxOpener, remaining.length); length > 0; length -= 1) {
|
|
188
|
+
const suffix = remaining.slice(-length);
|
|
189
|
+
if (this.#options.openers.some((open) => open.startsWith(suffix))) {
|
|
190
|
+
return this.#pending.length - length;
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
return this.#pending.length;
|
|
194
|
+
}
|
|
195
|
+
}
|
|
@@ -28,3 +28,22 @@ export function reasoningTextOf(part: ReasoningTextSource): string | undefined {
|
|
|
28
28
|
if (typeof summary === "string" && summary.length > 0) return summary;
|
|
29
29
|
return undefined;
|
|
30
30
|
}
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* The one reader for reasoning text replayed to upstream providers.
|
|
34
|
+
*
|
|
35
|
+
* Request builders echo the previous turn's reasoning back to a provider, and
|
|
36
|
+
* they deliberately prefer `summary` (the digest) ahead of `payload` (the
|
|
37
|
+
* stream) — the opposite of `reasoningTextOf`, which is for display. Returning
|
|
38
|
+
* `undefined` when neither field is a string lets each call site keep its exact
|
|
39
|
+
* fallback ("" for the chat/messages/gemini builders, the raw payload for
|
|
40
|
+
* Qoder's echo), so upstream-visible bytes do not change. Opaque parts are not
|
|
41
|
+
* special-cased here: the replay readers never consulted `opaque` either.
|
|
42
|
+
*/
|
|
43
|
+
export function reasoningTextForReplay(part: ReasoningTextSource): string | undefined {
|
|
44
|
+
const summary = part.summary;
|
|
45
|
+
if (typeof summary === "string") return summary;
|
|
46
|
+
const payload = part.payload;
|
|
47
|
+
if (typeof payload === "string") return payload;
|
|
48
|
+
return undefined;
|
|
49
|
+
}
|
|
@@ -16,6 +16,7 @@ import { clampThinkingLevelForModel } from "../../protocol/translation/dialect/m
|
|
|
16
16
|
import { isClaudeBillingHeaderText, resolveImageSource } from "../codecs";
|
|
17
17
|
import { resolvePromptCacheKey } from "../../providers/operations/session-resolution";
|
|
18
18
|
import { reasoningEffortFromIntent } from "../../protocol/reasoning";
|
|
19
|
+
import { reasoningTextForReplay } from "../reasoning-text";
|
|
19
20
|
import { parseChatResponseToEvents, decodeChatSseStream } from "../response/chat";
|
|
20
21
|
|
|
21
22
|
/** Fallback when no resolved policy is supplied — today's exact behavior. */
|
|
@@ -220,6 +221,13 @@ export function canonicalToChatPayload(
|
|
|
220
221
|
}
|
|
221
222
|
}
|
|
222
223
|
for (const m of request.messages) {
|
|
224
|
+
// Reasoning parts and their presence are computed once per message and
|
|
225
|
+
// shared by every branch below; the presence gate is on the *existence* of
|
|
226
|
+
// a reasoning part, not on non-empty text (see the comment at the first use).
|
|
227
|
+
const reasoningParts = m.content.filter(
|
|
228
|
+
(c): c is Extract<typeof c, { kind: "reasoning" }> => c.kind === "reasoning",
|
|
229
|
+
);
|
|
230
|
+
const hasReasoning = reasoningParts.length > 0;
|
|
223
231
|
if (m.role === "assistant" && m.content.some((c) => c.kind === "toolCall")) {
|
|
224
232
|
const toolCalls = m.content
|
|
225
233
|
.filter((c): c is Extract<typeof c, { kind: "toolCall" }> => c.kind === "toolCall")
|
|
@@ -251,16 +259,12 @@ export function canonicalToChatPayload(
|
|
|
251
259
|
// thinking mode" (CodeBuddy 400). Chat Completions has no
|
|
252
260
|
// reasoning content part, so it travels in the provider-native
|
|
253
261
|
// `reasoning_content` side channel, same as the branches below.
|
|
254
|
-
const reasoningContent =
|
|
255
|
-
.filter((c): c is Extract<typeof c, { kind: "reasoning" }> => c.kind === "reasoning")
|
|
256
|
-
.map((c) => c.summary ?? (typeof c.payload === "string" ? c.payload : ""))
|
|
257
|
-
.join("\n");
|
|
262
|
+
const reasoningContent = reasoningParts.map((c) => reasoningTextForReplay(c) ?? "").join("\n");
|
|
258
263
|
// Gated on the *presence* of a reasoning part, not on non-empty text:
|
|
259
264
|
// with `display: "omitted"` the provider emits a thinking block whose
|
|
260
265
|
// text is empty but whose signature marks the turn as a thinking turn,
|
|
261
266
|
// and the upstream still demands the field back. Omitting it there
|
|
262
267
|
// reproduces the same 400, so an empty string is the correct value.
|
|
263
|
-
const hasReasoning = m.content.some((c) => c.kind === "reasoning");
|
|
264
268
|
messages.push({
|
|
265
269
|
role: "assistant",
|
|
266
270
|
content: effectiveContent,
|
|
@@ -295,13 +299,9 @@ export function canonicalToChatPayload(
|
|
|
295
299
|
content: p.is_error === true ? `[tool_error] ${resultContent}` : resultContent,
|
|
296
300
|
});
|
|
297
301
|
}
|
|
298
|
-
const reasoningContent =
|
|
299
|
-
.filter((c): c is Extract<typeof c, { kind: "reasoning" }> => c.kind === "reasoning")
|
|
300
|
-
.map((c) => c.summary ?? (typeof c.payload === "string" ? c.payload : ""))
|
|
301
|
-
.join("\n");
|
|
302
|
+
const reasoningContent = reasoningParts.map((c) => reasoningTextForReplay(c) ?? "").join("\n");
|
|
302
303
|
// Presence, not length: an `omitted`-display thinking block carries an
|
|
303
304
|
// empty text with a signature, and the field is still required back.
|
|
304
|
-
const hasReasoning = m.content.some((c) => c.kind === "reasoning");
|
|
305
305
|
const hasRichContent = m.content.some(
|
|
306
306
|
(c) => c.kind === "image" || c.kind === "file" || c.kind === "audio" || c.kind === "document",
|
|
307
307
|
);
|
|
@@ -15,6 +15,7 @@ import {
|
|
|
15
15
|
type RewriteWalk,
|
|
16
16
|
} from "../codecs";
|
|
17
17
|
import { geminiThinkingOutputFloor } from "../../protocol/reasoning";
|
|
18
|
+
import { reasoningTextForReplay } from "../reasoning-text";
|
|
18
19
|
import { base64DecodedByteLength, clampImage } from "../image-clamp";
|
|
19
20
|
|
|
20
21
|
export function geminiModelUrl(base: string, model: string, action: string): string {
|
|
@@ -151,8 +152,13 @@ function toGeminiPart(
|
|
|
151
152
|
): Record<string, unknown>[] {
|
|
152
153
|
if (part.kind === "text") return [{ text: part.text }];
|
|
153
154
|
if (part.kind === "reasoning") {
|
|
154
|
-
|
|
155
|
-
|
|
155
|
+
// A `thinking` part must carry a non-empty signature, or Gemini-family
|
|
156
|
+
// upstreams reject the whole request with `400 ... thinking.signature:
|
|
157
|
+
// Field required`. Drop unsigned reasoning blocks (missing *or* empty
|
|
158
|
+
// signature) so the conversation replays cleanly.
|
|
159
|
+
if (typeof part.signature !== "string" || part.signature.length === 0) return [];
|
|
160
|
+
const summary = reasoningTextForReplay(part) ?? "";
|
|
161
|
+
return [{ text: summary, thought: true, thoughtSignature: part.signature }];
|
|
156
162
|
}
|
|
157
163
|
if (part.kind === "image") {
|
|
158
164
|
// Resolution goes through the shared `resolveImageSource` primitive rather
|
|
@@ -17,16 +17,19 @@ import {
|
|
|
17
17
|
normalizeAnthropicToolCallId,
|
|
18
18
|
parseArguments,
|
|
19
19
|
prefixClaudeToolName,
|
|
20
|
+
recordToolAliases,
|
|
20
21
|
sanitizeSchemaForAnthropic,
|
|
21
22
|
stringValue,
|
|
22
23
|
toWellFormedDeep,
|
|
23
24
|
toWellFormedString,
|
|
24
25
|
type ClaudeWireObject,
|
|
26
|
+
type ToolNameAlias,
|
|
25
27
|
isRecord,
|
|
26
28
|
resolveImageSource,
|
|
27
29
|
splitDataUrl,
|
|
28
30
|
finiteNumber,
|
|
29
31
|
} from "../codecs";
|
|
32
|
+
import { reasoningTextForReplay } from "../reasoning-text";
|
|
30
33
|
import { log } from "../../observability/logger";
|
|
31
34
|
import { base64DecodedByteLength, clampImage } from "../image-clamp";
|
|
32
35
|
import { LEVEL_TO_BUDGET } from "../../protocol/translation/thinking";
|
|
@@ -286,6 +289,7 @@ function partToClaudeBlock(
|
|
|
286
289
|
idMap: Map<string, string>;
|
|
287
290
|
isOAuth: boolean;
|
|
288
291
|
imageCount: number;
|
|
292
|
+
toolAliases: ToolNameAlias[];
|
|
289
293
|
maxBytesOverride?: number;
|
|
290
294
|
},
|
|
291
295
|
): ClaudeWireObject | undefined {
|
|
@@ -335,10 +339,12 @@ function partToClaudeBlock(
|
|
|
335
339
|
// stamp every call with its array position, so copying it here leaked a
|
|
336
340
|
// stream-only field into a request. The position is not lost: the block
|
|
337
341
|
// order in `content[]` already expresses it.
|
|
342
|
+
const sentName = prefixClaudeToolName(part.name, ctx?.isOAuth ?? false);
|
|
343
|
+
if (sentName !== part.name) ctx?.toolAliases.push({ sent: sentName, original: part.name });
|
|
338
344
|
return {
|
|
339
345
|
type: "tool_use",
|
|
340
346
|
id: normalized,
|
|
341
|
-
name:
|
|
347
|
+
name: sentName,
|
|
342
348
|
input: toWellFormedDeep(parseArguments(part.arguments)),
|
|
343
349
|
...(part.namespace === undefined ? {} : { namespace: part.namespace }),
|
|
344
350
|
};
|
|
@@ -374,7 +380,7 @@ function partToClaudeBlock(
|
|
|
374
380
|
!part.opaque &&
|
|
375
381
|
(typeof part.signature !== "string" || part.signature.trim().length === 0)
|
|
376
382
|
) {
|
|
377
|
-
const text =
|
|
383
|
+
const text = reasoningTextForReplay(part) ?? "";
|
|
378
384
|
return text.length > 0 ? { type: "text", text: toWellFormedString(text) } : undefined;
|
|
379
385
|
}
|
|
380
386
|
if (part.opaque) {
|
|
@@ -384,9 +390,7 @@ function partToClaudeBlock(
|
|
|
384
390
|
}
|
|
385
391
|
return {
|
|
386
392
|
type: "thinking",
|
|
387
|
-
thinking: toWellFormedString(
|
|
388
|
-
part.summary ?? (stringValue(part.payload) ? part.payload : ""),
|
|
389
|
-
),
|
|
393
|
+
thinking: toWellFormedString(reasoningTextForReplay(part) ?? ""),
|
|
390
394
|
...(part.signature === undefined
|
|
391
395
|
? {}
|
|
392
396
|
: { signature: toWellFormedString(part.signature) }),
|
|
@@ -578,6 +582,7 @@ export function canonicalToClaudeMessagesPayload(
|
|
|
578
582
|
idMap,
|
|
579
583
|
isOAuth: options.isOAuth ?? false,
|
|
580
584
|
imageCount,
|
|
585
|
+
toolAliases: [] as ToolNameAlias[],
|
|
581
586
|
...(options.maxBytesOverride === undefined
|
|
582
587
|
? {}
|
|
583
588
|
: { maxBytesOverride: options.maxBytesOverride }),
|
|
@@ -756,27 +761,34 @@ export function canonicalToClaudeMessagesPayload(
|
|
|
756
761
|
});
|
|
757
762
|
}
|
|
758
763
|
if (request.tools?.length) {
|
|
759
|
-
payload.tools = request.tools.map((tool) =>
|
|
760
|
-
|
|
761
|
-
|
|
762
|
-
|
|
763
|
-
:
|
|
764
|
-
|
|
765
|
-
|
|
766
|
-
|
|
767
|
-
|
|
768
|
-
|
|
769
|
-
|
|
770
|
-
|
|
771
|
-
|
|
772
|
-
|
|
773
|
-
|
|
774
|
-
|
|
764
|
+
payload.tools = request.tools.map((tool) => {
|
|
765
|
+
const sentName = prefixClaudeToolName(tool.name, isOAuth);
|
|
766
|
+
if (sentName !== tool.name) ctx.toolAliases.push({ sent: sentName, original: tool.name });
|
|
767
|
+
return {
|
|
768
|
+
name: sentName,
|
|
769
|
+
...(tool.description === undefined
|
|
770
|
+
? {}
|
|
771
|
+
: { description: toWellFormedDeep(tool.description) }),
|
|
772
|
+
input_schema: sanitizeSchemaForAnthropic(tool.jsonSchema),
|
|
773
|
+
...(tool.strict === true ? { strict: true } : {}),
|
|
774
|
+
...(tool.eager_input_streaming === undefined
|
|
775
|
+
? {}
|
|
776
|
+
: { eager_input_streaming: tool.eager_input_streaming }),
|
|
777
|
+
...(tool.defer_loading === undefined
|
|
778
|
+
? {}
|
|
779
|
+
: { defer_loading: tool.defer_loading }),
|
|
780
|
+
...(tool.input_examples === undefined ? {} : { input_examples: tool.input_examples }),
|
|
781
|
+
...(tool.allowed_callers === undefined ? {} : { allowed_callers: tool.allowed_callers }),
|
|
782
|
+
};
|
|
783
|
+
});
|
|
775
784
|
}
|
|
776
785
|
const rawToolChoice = canonicalToolChoice(request.tool_choice);
|
|
777
786
|
if (isRecord(rawToolChoice) && rawToolChoice.type === "tool" && stringValue(rawToolChoice.name)) {
|
|
778
|
-
|
|
787
|
+
const sentName = prefixClaudeToolName(rawToolChoice.name, isOAuth);
|
|
788
|
+
if (sentName !== rawToolChoice.name) ctx.toolAliases.push({ sent: sentName, original: rawToolChoice.name });
|
|
789
|
+
rawToolChoice.name = sentName;
|
|
779
790
|
}
|
|
791
|
+
recordToolAliases(request, ctx.toolAliases);
|
|
780
792
|
const parallelToolCallsDisabled =
|
|
781
793
|
request.generation_controls.parallel_tool_calls === false;
|
|
782
794
|
const supportsToolChoice = options.dialectPolicy?.supportsToolChoice ?? true;
|
|
@@ -9,7 +9,7 @@ import { gatewayErrorFromStreamError } from "../stream-error-frames";
|
|
|
9
9
|
import { mergeResponsesUsage } from "./responses";
|
|
10
10
|
import { usageFromProvider, readReasoningText } from "../../providers/provider-usage";
|
|
11
11
|
import { createToolEmitLedger } from "../tool-identity";
|
|
12
|
-
import { ThinkSplitter, stripThinkingTags } from "../think-split";
|
|
12
|
+
import { ThinkingTagStripper, ThinkSplitter, stripThinkingTags } from "../think-split";
|
|
13
13
|
import { DsmlStreamParser, parseDsmlToolCalls } from "../dsml";
|
|
14
14
|
import {
|
|
15
15
|
OmpToolCallMarkupParser,
|
|
@@ -267,10 +267,13 @@ export async function* decodeChatSseStream(
|
|
|
267
267
|
// Single emission ledger: one entry per logical call.
|
|
268
268
|
const ledger = createToolEmitLedger();
|
|
269
269
|
const think = new ThinkSplitter();
|
|
270
|
-
// Separate
|
|
270
|
+
// Separate stripper for the reasoning channel: `reasoning_content` is its own
|
|
271
271
|
// stream, and interleaving it into the answer splitter would let a tag in one
|
|
272
|
-
// channel swallow the other's text.
|
|
273
|
-
|
|
272
|
+
// channel swallow the other's text. The reasoning channel is thought in its
|
|
273
|
+
// entirety — untagged prose included — so it strips paired tags statefully
|
|
274
|
+
// while preserving source order instead of splitting into text/reasoning
|
|
275
|
+
// buckets that a `${reasoning}${text}` join would reorder.
|
|
276
|
+
const reasoningThink = new ThinkingTagStripper();
|
|
274
277
|
const declaredToolNames = declaredToolNamesForRequest(request);
|
|
275
278
|
const callableToolNames = callableToolNamesForRequest(request);
|
|
276
279
|
const contentMarkup =
|
|
@@ -364,21 +367,13 @@ export async function* decodeChatSseStream(
|
|
|
364
367
|
typeof reasoningRaw === "string" ? reasoningMarkup?.push(reasoningRaw) : undefined;
|
|
365
368
|
// Strip stray `<think>` tags the upstream double-wrapped inside its own
|
|
366
369
|
// reasoning stream (buddy's hy4-preview-f leaks them per-delta). This
|
|
367
|
-
// is the
|
|
370
|
+
// is the stripper's job, not `stripThinkingTags`'s: a stateless strip
|
|
368
371
|
// cannot see a tag split across two deltas, so `"<thi"` was emitted
|
|
369
372
|
// verbatim and only the following `</think>` removed.
|
|
370
|
-
const
|
|
373
|
+
const reasoningText =
|
|
371
374
|
typeof reasoningRaw === "string"
|
|
372
375
|
? reasoningThink.push(reasoningMarkupResult?.text ?? reasoningRaw)
|
|
373
376
|
: undefined;
|
|
374
|
-
// Both sides are reasoning. The splitter routes text outside a
|
|
375
|
-
// `<think>` span to its `.text` side, but this field is the reasoning
|
|
376
|
-
// stream in its entirety: untagged prose here is still thought, not
|
|
377
|
-
// answer. Taking only `.reasoning` dropped every un-tagged delta.
|
|
378
|
-
const reasoningText =
|
|
379
|
-
reasoningSplit === undefined
|
|
380
|
-
? undefined
|
|
381
|
-
: `${reasoningSplit.reasoning}${reasoningSplit.text}`;
|
|
382
377
|
if (typeof reasoningText === "string" && reasoningText.length > 0) {
|
|
383
378
|
yield {
|
|
384
379
|
type: "content_delta",
|
|
@@ -538,9 +533,7 @@ export async function* decodeChatSseStream(
|
|
|
538
533
|
}
|
|
539
534
|
const reasoningMarkupTail = reasoningMarkup?.flush();
|
|
540
535
|
if (reasoningMarkupTail?.text) {
|
|
541
|
-
const
|
|
542
|
-
// Both sides are reasoning: see the per-delta branch above.
|
|
543
|
-
const reasoningText = `${split.reasoning}${split.text}`;
|
|
536
|
+
const reasoningText = reasoningThink.push(reasoningMarkupTail.text);
|
|
544
537
|
if (reasoningText.length > 0) {
|
|
545
538
|
yield {
|
|
546
539
|
type: "content_delta",
|
|
@@ -549,10 +542,9 @@ export async function* decodeChatSseStream(
|
|
|
549
542
|
} as CanonicalEvent;
|
|
550
543
|
}
|
|
551
544
|
}
|
|
552
|
-
// Release anything the reasoning
|
|
545
|
+
// Release anything the reasoning stripper held for a tag that never
|
|
553
546
|
// completed, before `think.flush()` and the terminal.
|
|
554
|
-
const
|
|
555
|
-
const reasoningTail = `${reasoningRest.reasoning}${reasoningRest.text}`;
|
|
547
|
+
const reasoningTail = reasoningThink.flush();
|
|
556
548
|
if (reasoningTail.length > 0) {
|
|
557
549
|
yield {
|
|
558
550
|
type: "content_delta",
|
|
@@ -12,12 +12,33 @@ import { usageFromProvider } from '../../providers/provider-usage';
|
|
|
12
12
|
import { mapClaudeStreamError } from '../messages-errors';
|
|
13
13
|
import {
|
|
14
14
|
finiteNumber,
|
|
15
|
+
restoreAliasedToolName,
|
|
15
16
|
stringValue,
|
|
17
|
+
toolAliasesFor,
|
|
16
18
|
unprefixClaudeToolName,
|
|
17
19
|
type ClaudeWireObject,
|
|
20
|
+
type ToolNameAlias,
|
|
18
21
|
isRecord,
|
|
19
22
|
} from '../codecs';
|
|
20
23
|
|
|
24
|
+
/**
|
|
25
|
+
* Restore a tool name from the wire to the caller's original, exactly.
|
|
26
|
+
*
|
|
27
|
+
* A name the builder renamed (recorded in `aliases`) is restored verbatim; any
|
|
28
|
+
* other name falls back to the OAuth underscore-unprefixing rule. This is the
|
|
29
|
+
* single restoration point for the Claude wire, so the two rules can never
|
|
30
|
+
* disagree between the stream and non-stream decoders.
|
|
31
|
+
*/
|
|
32
|
+
function restoreClaudeToolName(
|
|
33
|
+
sent: string,
|
|
34
|
+
isOAuth: boolean,
|
|
35
|
+
aliases: ReadonlyArray<ToolNameAlias>,
|
|
36
|
+
): string {
|
|
37
|
+
const restored = restoreAliasedToolName(sent, aliases);
|
|
38
|
+
if (restored !== sent) return restored;
|
|
39
|
+
return unprefixClaudeToolName(sent, isOAuth);
|
|
40
|
+
}
|
|
41
|
+
|
|
21
42
|
export function mapClaudeStopReason(raw: string): CanonicalStopReason {
|
|
22
43
|
switch (raw) {
|
|
23
44
|
case "end_turn":
|
|
@@ -38,7 +59,7 @@ export function mapClaudeStopReason(raw: string): CanonicalStopReason {
|
|
|
38
59
|
}
|
|
39
60
|
}
|
|
40
61
|
|
|
41
|
-
export function parseClaudeContent(value: unknown, isOAuth = false): ContentPart {
|
|
62
|
+
export function parseClaudeContent(value: unknown, isOAuth = false, aliases: ReadonlyArray<ToolNameAlias> = []): ContentPart {
|
|
42
63
|
if (stringValue(value)) return { kind: "text", text: value };
|
|
43
64
|
if (!isRecord(value))
|
|
44
65
|
return { kind: "extension", name: "messages:unknown", payload: value };
|
|
@@ -59,7 +80,7 @@ export function parseClaudeContent(value: unknown, isOAuth = false): ContentPart
|
|
|
59
80
|
return {
|
|
60
81
|
kind: "toolCall",
|
|
61
82
|
call_id: value.id,
|
|
62
|
-
name:
|
|
83
|
+
name: restoreClaudeToolName(value.name, isOAuth, aliases),
|
|
63
84
|
arguments: value.input ?? {},
|
|
64
85
|
...(finiteNumber(value.index) ? { index: value.index } : {}),
|
|
65
86
|
};
|
|
@@ -77,7 +98,7 @@ export function parseClaudeContent(value: unknown, isOAuth = false): ContentPart
|
|
|
77
98
|
const content = stringValue(value.content)
|
|
78
99
|
? value.content
|
|
79
100
|
: Array.isArray(value.content)
|
|
80
|
-
? value.content.map((content) => parseClaudeContent(content, isOAuth))
|
|
101
|
+
? value.content.map((content) => parseClaudeContent(content, isOAuth, aliases))
|
|
81
102
|
: value.content == null
|
|
82
103
|
? ""
|
|
83
104
|
: [{ kind: "text" as const, text: String(value.content) }];
|
|
@@ -239,8 +260,9 @@ export function claudeResponseToEvents(
|
|
|
239
260
|
model,
|
|
240
261
|
},
|
|
241
262
|
];
|
|
263
|
+
const aliases = toolAliasesFor(request);
|
|
242
264
|
const blocks = Array.isArray(json.content)
|
|
243
|
-
? json.content.map((content) => parseClaudeContent(content, isOAuth))
|
|
265
|
+
? json.content.map((content) => parseClaudeContent(content, isOAuth, aliases))
|
|
244
266
|
: [];
|
|
245
267
|
let sequence = 2;
|
|
246
268
|
for (const block of blocks) {
|
|
@@ -292,6 +314,8 @@ interface ClaudeStreamState {
|
|
|
292
314
|
rawUsage: Record<string, unknown> | undefined;
|
|
293
315
|
sawMessageStop: boolean;
|
|
294
316
|
isOAuth: boolean;
|
|
317
|
+
/** Tool renames recorded for this request, for exact restore. */
|
|
318
|
+
aliases: ReadonlyArray<ToolNameAlias>;
|
|
295
319
|
}
|
|
296
320
|
|
|
297
321
|
function streamEventToCanonical(
|
|
@@ -321,7 +345,7 @@ function streamEventToCanonical(
|
|
|
321
345
|
state.calls.set(index, {
|
|
322
346
|
call_id: block.id,
|
|
323
347
|
...(stringValue(block.name)
|
|
324
|
-
? { name:
|
|
348
|
+
? { name: restoreClaudeToolName(block.name, state.isOAuth, state.aliases) }
|
|
325
349
|
: {}),
|
|
326
350
|
});
|
|
327
351
|
// Anthropic sends `input: {}` as a *placeholder* on content_block_start,
|
|
@@ -332,13 +356,14 @@ function streamEventToCanonical(
|
|
|
332
356
|
// send complete arguments here still gets them through.
|
|
333
357
|
if (
|
|
334
358
|
isRecord(block.input) &&
|
|
335
|
-
Object.keys(block.input).length > 0
|
|
359
|
+
Object.keys(block.input).length > 0 &&
|
|
360
|
+
stringValue(block.name)
|
|
336
361
|
) {
|
|
337
362
|
events.push({
|
|
338
363
|
type: "tool_call_delta",
|
|
339
364
|
sequence_number: next++,
|
|
340
365
|
call_id: block.id,
|
|
341
|
-
|
|
366
|
+
name: restoreClaudeToolName(block.name, state.isOAuth, state.aliases),
|
|
342
367
|
arguments_delta: JSON.stringify(block.input),
|
|
343
368
|
});
|
|
344
369
|
}
|
|
@@ -446,6 +471,7 @@ export async function* parseClaudeSseStream(
|
|
|
446
471
|
body: ReadableStream<Uint8Array>,
|
|
447
472
|
signal?: AbortSignal,
|
|
448
473
|
isOAuth = false,
|
|
474
|
+
aliases: ReadonlyArray<ToolNameAlias> = [],
|
|
449
475
|
): AsyncIterable<CanonicalEvent> {
|
|
450
476
|
const state: ClaudeStreamState = {
|
|
451
477
|
calls: new Map(),
|
|
@@ -455,6 +481,7 @@ export async function* parseClaudeSseStream(
|
|
|
455
481
|
rawUsage: undefined,
|
|
456
482
|
sawMessageStop: false,
|
|
457
483
|
isOAuth,
|
|
484
|
+
aliases,
|
|
458
485
|
};
|
|
459
486
|
let sequence = 1;
|
|
460
487
|
for await (const sse of decodeSseEvents(body, { signal })) {
|