cartethyia 2.7.4 → 2.7.5
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 +2 -0
- package/README.md +17 -5
- package/dist/dashboard/assets/{BannedPage-ChG5svFb.js → BannedPage-Cj15GsMp.js} +1 -1
- package/dist/dashboard/assets/BannedPage-Cj15GsMp.js.gz +0 -0
- package/dist/dashboard/assets/ClaimGiftsButton-D83pBJ6J.js +1 -0
- package/dist/dashboard/assets/ClaimGiftsButton-D83pBJ6J.js.gz +0 -0
- package/dist/dashboard/assets/{CliToolDetailPage-BIcWQun7.js → CliToolDetailPage-DZKmVuJN.js} +1 -1
- package/dist/dashboard/assets/CliToolDetailPage-DZKmVuJN.js.gz +0 -0
- package/dist/dashboard/assets/{CliToolsPage-Bf2VelDe.js → CliToolsPage-BIccZmeL.js} +1 -1
- package/dist/dashboard/assets/CliToolsPage-BIccZmeL.js.gz +0 -0
- package/dist/dashboard/assets/CombosPage-DEEKkYD-.js +1 -0
- package/dist/dashboard/assets/CombosPage-DEEKkYD-.js.gz +0 -0
- package/dist/dashboard/assets/ConsoleLogPage-D5rol2j2.js +1 -0
- package/dist/dashboard/assets/ConsoleLogPage-D5rol2j2.js.gz +0 -0
- package/dist/dashboard/assets/{CustomizationPage-ggeMSjte.js → CustomizationPage-BKj_r0rp.js} +1 -1
- package/dist/dashboard/assets/CustomizationPage-BKj_r0rp.js.gz +0 -0
- package/dist/dashboard/assets/InjectSystemPromptPanel-B5nZvmf0.js +656 -0
- package/dist/dashboard/assets/InjectSystemPromptPanel-B5nZvmf0.js.gz +0 -0
- package/dist/dashboard/assets/{LoginPage-U6AKaJcF.js → LoginPage-DkXb6dx-.js} +1 -1
- package/dist/dashboard/assets/LoginPage-DkXb6dx-.js.gz +0 -0
- package/dist/dashboard/assets/{ModelPicker-BMS2t8BA.js → ModelPicker-DnQPSIA8.js} +1 -1
- package/dist/dashboard/assets/ModelPicker-DnQPSIA8.js.gz +0 -0
- package/dist/dashboard/assets/OverviewPage-Ci2wQKUz.js +1 -0
- package/dist/dashboard/assets/OverviewPage-Ci2wQKUz.js.gz +0 -0
- package/dist/dashboard/assets/ProviderDetailPage-odlgYrOg.js +5 -0
- package/dist/dashboard/assets/ProviderDetailPage-odlgYrOg.js.gz +0 -0
- package/dist/dashboard/assets/ProviderIcon-EfeloBn4.js +1 -0
- package/dist/dashboard/assets/ProviderIcon-EfeloBn4.js.gz +0 -0
- package/dist/dashboard/assets/ProvidersPage-CqFBQEB8.js +1 -0
- package/dist/dashboard/assets/ProvidersPage-CqFBQEB8.js.gz +0 -0
- package/dist/dashboard/assets/{ProxyPage-lsrx7NYg.js → ProxyPage-5SnUSy3j.js} +1 -1
- package/dist/dashboard/assets/ProxyPage-5SnUSy3j.js.gz +0 -0
- package/dist/dashboard/assets/QuotaPage-CmnMDzhP.js +1 -0
- package/dist/dashboard/assets/QuotaPage-CmnMDzhP.js.gz +0 -0
- package/dist/dashboard/assets/SettingsPage-BJtRZ4qD.js +1 -0
- package/dist/dashboard/assets/SettingsPage-BJtRZ4qD.js.gz +0 -0
- package/dist/dashboard/assets/{SetupPage-f0DE1h0-.js → SetupPage-WTa0sktC.js} +1 -1
- package/dist/dashboard/assets/SetupPage-WTa0sktC.js.gz +0 -0
- package/dist/dashboard/assets/{StudioPage-Cq5tW7hW.js → StudioPage-BfAb5-o_.js} +3 -3
- package/dist/dashboard/assets/StudioPage-BfAb5-o_.js.gz +0 -0
- package/dist/dashboard/assets/UsagePage-BNzeZ2Vk.js +56 -0
- package/dist/dashboard/assets/UsagePage-BNzeZ2Vk.js.gz +0 -0
- package/dist/dashboard/assets/api-keys-l29JROPv.js +1 -0
- package/dist/dashboard/assets/api-keys-l29JROPv.js.gz +0 -0
- package/dist/dashboard/assets/app--PJWq8_C.css +2 -0
- package/dist/dashboard/assets/app--PJWq8_C.css.gz +0 -0
- package/dist/dashboard/assets/assert-C0K-c4eo.js +1 -0
- package/dist/dashboard/assets/assert-C0K-c4eo.js.gz +0 -0
- package/dist/dashboard/assets/{badge-D9CS6dZk.js → badge-DfbhQU4k.js} +1 -1
- package/dist/dashboard/assets/badge-DfbhQU4k.js.gz +0 -0
- package/dist/dashboard/assets/{banner-DympBNq4.js → banner-BllT4LcF.js} +1 -1
- package/dist/dashboard/assets/banner-BllT4LcF.js.gz +0 -0
- package/dist/dashboard/assets/brand/login_register.jpg +0 -0
- package/dist/dashboard/assets/brand/login_register_initial.jpg +0 -0
- package/dist/dashboard/assets/brand/og_bansos.jpg +0 -0
- package/dist/dashboard/assets/brand/og_image.jpg +0 -0
- package/dist/dashboard/assets/{card-ibRWU_uT.js → card-CtkX66Wd.js} +1 -1
- package/dist/dashboard/assets/card-CtkX66Wd.js.gz +0 -0
- package/dist/dashboard/assets/chevron-left-Bf6CaTSJ.js +1 -0
- package/dist/dashboard/assets/chevron-left-Bf6CaTSJ.js.gz +0 -0
- package/dist/dashboard/assets/cli-tools-CQXVMn4P.js +1 -0
- package/dist/dashboard/assets/cli-tools-CQXVMn4P.js.gz +0 -0
- package/dist/dashboard/assets/{clipboard-button-DJm-9pz7.js → clipboard-button-BQqBQd2n.js} +1 -1
- package/dist/dashboard/assets/clipboard-button-BQqBQd2n.js.gz +0 -0
- package/dist/dashboard/assets/{dialog-8fiE6tec.js → dialog-BEK7KP0H.js} +1 -1
- package/dist/dashboard/assets/dialog-BEK7KP0H.js.gz +0 -0
- package/dist/dashboard/assets/{drawer-CqGYeOrd.js → drawer-BrTEZ8zu.js} +1 -1
- package/dist/dashboard/assets/drawer-BrTEZ8zu.js.gz +0 -0
- package/dist/dashboard/assets/entry-CHWxbS56.js +1 -0
- package/dist/dashboard/assets/entry-CHWxbS56.js.gz +0 -0
- package/dist/dashboard/assets/{entry-BSAsYsmV.js → entry-EBHJ3DrE.js} +1 -1
- package/dist/dashboard/assets/entry-EBHJ3DrE.js.gz +0 -0
- package/dist/dashboard/assets/entry-LCS85hiq.js +4 -0
- package/dist/dashboard/assets/entry-LCS85hiq.js.gz +0 -0
- package/dist/dashboard/assets/{formatters-D-MTJxMr.js → formatters-BAACA727.js} +1 -1
- package/dist/dashboard/assets/formatters-BAACA727.js.gz +0 -0
- package/dist/dashboard/assets/{github-badge-CPK47xQx.js → github-badge-YSCE4UC2.js} +1 -1
- package/dist/dashboard/assets/github-badge-YSCE4UC2.js.gz +0 -0
- package/dist/dashboard/assets/{index-DBNPOfhV.js → index-FQlj0HUT.js} +2 -2
- package/dist/dashboard/assets/index-FQlj0HUT.js.gz +0 -0
- package/dist/dashboard/assets/{inline-BT0zntEr.js → inline-C4gU5iOL.js} +1 -1
- package/dist/dashboard/assets/inline-C4gU5iOL.js.gz +0 -0
- package/dist/dashboard/assets/{input-Da2ZViWg.js → input-BHHX_Tmm.js} +1 -1
- package/dist/dashboard/assets/input-BHHX_Tmm.js.gz +0 -0
- package/dist/dashboard/assets/{layout-BXNeLw6M.js → layout-CajrYUnD.js} +1 -1
- package/dist/dashboard/assets/layout-CajrYUnD.js.gz +0 -0
- package/dist/dashboard/assets/{list-row-BycOrrIV.js → list-row-Bx2I7XUe.js} +1 -1
- package/dist/dashboard/assets/list-row-Bx2I7XUe.js.gz +0 -0
- package/dist/dashboard/assets/live-DNNqRbj2.js +1 -0
- package/dist/dashboard/assets/live-DNNqRbj2.js.gz +0 -0
- package/dist/dashboard/assets/network-C5UBACrJ.js +1 -0
- package/dist/dashboard/assets/network-C5UBACrJ.js.gz +0 -0
- package/dist/dashboard/assets/numbers-CUWAZK4J.js +2 -0
- package/dist/dashboard/assets/numbers-CUWAZK4J.js.gz +0 -0
- package/dist/dashboard/assets/pagination-Xsi9Qx04.js +1 -0
- package/dist/dashboard/assets/pagination-Xsi9Qx04.js.gz +0 -0
- package/dist/dashboard/assets/quota-DvQbD_sr.js +1 -0
- package/dist/dashboard/assets/quota-DvQbD_sr.js.gz +0 -0
- package/dist/dashboard/assets/routing-in0f_IfK.js +1 -0
- package/dist/dashboard/assets/routing-in0f_IfK.js.gz +0 -0
- package/dist/dashboard/assets/{select-BIYIBkMU.js → select-BLULNqTp.js} +1 -1
- package/dist/dashboard/assets/select-BLULNqTp.js.gz +0 -0
- package/dist/dashboard/assets/settings-CcGczj6I.js +1 -0
- package/dist/dashboard/assets/settings-CcGczj6I.js.gz +0 -0
- package/dist/dashboard/assets/shield-BMQNxORh.js +1 -0
- package/dist/dashboard/assets/shield-BMQNxORh.js.gz +0 -0
- package/dist/dashboard/assets/{stack-DfgnFDWY.js → stack-D2lIR0tg.js} +1 -1
- package/dist/dashboard/assets/stack-D2lIR0tg.js.gz +0 -0
- package/dist/dashboard/assets/{state-CkfdYWel.js → state-DTARjfiW.js} +1 -1
- package/dist/dashboard/assets/state-DTARjfiW.js.gz +0 -0
- package/dist/dashboard/assets/{switch-SYm237HG.js → switch-c0oPSnqW.js} +1 -1
- package/dist/dashboard/assets/switch-c0oPSnqW.js.gz +0 -0
- package/dist/dashboard/assets/{useMutation-BQqCRNIi.js → useMutation-m8WGNPrz.js} +1 -1
- package/dist/dashboard/assets/useMutation-m8WGNPrz.js.gz +0 -0
- package/dist/dashboard/console-backgrounds.jpg +0 -0
- package/dist/dashboard/console-backgrounds_initial.jpg +0 -0
- package/dist/dashboard/index.html +2 -2
- package/dist/dashboard/index.html.gz +0 -0
- package/dist/dashboard/precompressed-assets.json +56 -55
- package/migrations/full-postgres/0036_system_prompt_presets_refs.sql +10 -0
- package/migrations/full-postgres/0037_share_concurrency_scope.sql +3 -0
- package/migrations/full-postgres/0038_add_accounts_quota_snapshot.sql +7 -0
- package/migrations/full-postgres/0039_add_telemetry_provider_model_indexes.sql +13 -0
- package/migrations/full-postgres/0040_add_models_dialect.sql +3 -0
- package/migrations/full-postgres/0041_add_daily_checkin_ledger_account_fk.sql +7 -0
- package/migrations/lite-sqlite3/0036_system_prompt_presets_refs.sql +14 -0
- package/migrations/lite-sqlite3/0037_share_concurrency_scope.sql +3 -0
- package/migrations/lite-sqlite3/0038_add_accounts_quota_snapshot.sql +4 -0
- package/migrations/lite-sqlite3/0039_add_telemetry_provider_model_indexes.sql +6 -0
- package/migrations/lite-sqlite3/0040_add_models_dialect.sql +3 -0
- package/migrations/lite-sqlite3/0041_add_daily_checkin_ledger_account_fk.sql +26 -0
- package/package.json +4 -6
- package/scripts/cli/update.ts +15 -41
- package/src/boot/app.ts +58 -2
- package/src/boot/dependencies.ts +786 -732
- package/src/boot/lifecycle.ts +11 -12
- package/src/config/cooldowns.ts +34 -55
- package/src/config/network.ts +1 -1
- package/src/config/package-paths.ts +1 -1
- package/src/config/providers.ts +13 -14
- package/src/config/resources.ts +0 -5
- package/src/config/runtime.ts +2 -5
- package/src/config/spec.ts +26 -6
- package/src/console/api-keys/ban-constants.ts +38 -0
- package/src/console/api-keys/contracts.ts +71 -62
- package/src/console/api-keys/routes.ts +48 -12
- package/src/console/auth/access.ts +4 -4
- package/src/console/auth/account-reset.ts +1 -1
- package/src/console/auth/audit-recorder.ts +1 -1
- package/src/console/auth/lockout.ts +7 -3
- package/src/console/auth/row-coercion.ts +57 -12
- package/src/console/auth/session-resolver.ts +1 -1
- package/src/console/auth/session-service.ts +8 -2
- package/src/console/auth/session.ts +37 -31
- package/src/console/auth/setup-service.ts +4 -3
- package/src/console/auth/user-store.ts +1 -1
- package/src/console/backup/9router-map.ts +0 -3
- package/src/console/backup/contracts.ts +9 -9
- package/src/console/backup/export-endpoint.ts +5 -6
- package/src/console/backup/nine-router.ts +1 -7
- package/src/console/backup/routes.ts +29 -33
- package/src/console/backup/service.ts +468 -468
- package/src/console/backup/store.ts +47 -29
- package/src/console/backup/validate.ts +11 -1
- package/src/console/cli-tools/contracts.ts +7 -7
- package/src/console/cli-tools/injectors/cline.ts +110 -110
- package/src/console/cli-tools/injectors/codex.ts +181 -181
- package/src/console/cli-tools/injectors/copilot.ts +108 -108
- package/src/console/cli-tools/injectors/driver.ts +247 -247
- package/src/console/cli-tools/injectors/jcode.ts +115 -115
- package/src/console/cli-tools/injectors/openclaw.ts +161 -161
- package/src/console/cli-tools/injectors/opencode.ts +153 -153
- package/src/console/cli-tools/routes.ts +1 -1
- package/src/console/cli-tools/service.ts +1 -1
- package/src/console/cli-tools/store.ts +2 -2
- package/src/console/console-router.ts +32 -0
- package/src/console/dashboard-assets.ts +9 -9
- package/src/console/domain-registration.ts +16 -2
- package/src/console/inferhub/client.ts +0 -7
- package/src/console/inferhub/key-store.ts +1 -1
- package/src/console/inferhub/normalize.ts +2 -2
- package/src/console/inferhub/routes.ts +1 -1
- package/src/console/inferhub/types.ts +1 -1
- package/src/console/observability/contracts.ts +1 -1
- package/src/console/observability/live.ts +31 -18
- package/src/console/observability/logs.ts +1 -1
- package/src/console/observability/sse.ts +62 -8
- package/src/console/observability/store.ts +20 -4
- package/src/console/providers/catalog/catalog-projections.ts +1 -1
- package/src/console/providers/catalog/contracts.ts +39 -0
- package/src/console/providers/catalog/model-operations.ts +1 -1
- package/src/console/providers/catalog/provider-operations.ts +95 -17
- package/src/console/providers/catalog/public-model-store.ts +0 -0
- package/src/console/providers/catalog/routes.ts +27 -3
- package/src/console/providers/catalog/store.ts +147 -8
- package/src/console/providers/detail/routes.ts +1 -1
- package/src/console/providers/oauth/callback-listener.ts +100 -18
- package/src/console/providers/oauth/routes.ts +92 -13
- package/src/console/quota/account-quota-global.ts +41 -3
- package/src/console/quota/account-quota-shared.ts +10 -3
- package/src/console/quota/account-quota-tenant.ts +259 -66
- package/src/console/quota/daily-growth-job.ts +308 -0
- package/src/console/quota/native-identity.ts +2 -2
- package/src/console/quota/quota-view.ts +1 -1
- package/src/console/remote-support/routes.ts +1 -1
- package/src/console/remote-support/service.ts +2 -2
- package/src/console/routing/model/contracts.ts +1 -1
- package/src/console/routing/pools/contracts.ts +2 -2
- package/src/console/routing/pools/import-parse.ts +3 -3
- package/src/console/routing/pools/relay-deploy.ts +3 -3
- package/src/console/settings/contracts.ts +29 -2
- package/src/console/settings/store.ts +20 -0
- package/src/console/share/share-router.ts +100 -32
- package/src/console/share/share-stats.ts +4 -4
- package/src/console/share/share-usage.ts +1 -1
- package/src/console/shared/errors.ts +2 -2
- package/src/console/shared/object.ts +18 -0
- package/src/console/shared/read-through-cache.ts +4 -4
- package/src/console/shared/transaction.ts +14 -0
- package/src/console/system-prompt/contracts.ts +89 -12
- package/src/console/system-prompt/routes.ts +98 -45
- package/src/console/updates/apply-update.ts +244 -0
- package/src/console/updates/routes.ts +252 -97
- package/src/main.ts +11 -5
- package/src/network/http2-bidi.ts +1 -1
- package/src/network/ip-utils.ts +298 -0
- package/src/network/outbound-fetch.ts +1 -1
- package/src/network/pool/agent.ts +7 -6
- package/src/network/pool/byte-accounting.ts +1 -1
- package/src/network/pool/resolver.ts +16 -12
- package/src/network/pool/selector.ts +150 -136
- package/src/network/pool-health-machine.ts +1 -1
- package/src/network/rate-limit-verdict.ts +1 -1
- package/src/network/retry.ts +1 -1
- package/src/network/ssrf.ts +20 -71
- package/src/observability/event-log.ts +2 -2
- package/src/observability/event-query.ts +59 -291
- package/src/observability/log-sanitize.ts +1 -1
- package/src/observability/metrics.ts +4 -4
- package/src/observability/payload-capture.ts +6 -5
- package/src/observability/payload-store.ts +1 -1
- package/src/observability/runtime-metrics.ts +1 -1
- package/src/observability/telemetry-buffer.ts +12 -3
- package/src/observability/telemetry-reconciliation.ts +3 -3
- package/src/observability/token-speed.ts +1 -1
- package/src/persistence/connection-url.ts +1 -1
- package/src/persistence/db-handle.ts +1 -1
- package/src/persistence/db-pg.ts +2 -2
- package/src/persistence/db-sqlite.ts +3 -3
- package/src/persistence/dialect.ts +5 -1
- package/src/persistence/readiness.ts +1 -1
- package/src/persistence/redis.ts +1 -1
- package/src/persistence/schema.ts +113 -40
- package/src/persistence/shared-cache.ts +2 -2
- package/src/persistence/sort-order.ts +1 -1
- package/src/persistence/stores/api-key-store.ts +10 -1
- package/src/persistence/stores/share-store.ts +20 -8
- package/src/persistence/system-prompt-store.ts +63 -18
- package/src/persistence/tenant-preferences.ts +1 -1
- package/src/persistence/ttl-cache.ts +3 -3
- package/src/persistence/usage-flush.ts +7 -2
- package/src/protocol/canonical-model.ts +1 -1
- package/src/protocol/codecs.ts +6 -10
- package/src/protocol/dsml.ts +3 -49
- package/src/protocol/image-clamp.ts +2 -2
- package/src/protocol/reasoning-text.ts +1 -1
- package/src/protocol/reasoning.ts +7 -52
- package/src/protocol/registry.ts +50 -15
- package/src/protocol/request/chat.ts +46 -19
- package/src/protocol/request/codex.ts +1 -1
- package/src/protocol/request/messages.ts +46 -14
- package/src/protocol/request/responses.ts +19 -10
- package/src/protocol/response/chat.ts +25 -10
- package/src/protocol/response/codex.ts +1 -1
- package/src/protocol/response/messages.ts +1 -1
- package/src/protocol/response/omp-tool-call-markup.ts +1 -1
- package/src/protocol/response/responses.ts +1 -1
- package/src/protocol/sse-decoder.ts +50 -1
- package/src/protocol/stop-reason.ts +2 -2
- package/src/protocol/think-split.ts +347 -0
- package/src/protocol/translation/attachment-integrity.ts +3 -3
- package/src/protocol/translation/cache-controls.ts +8 -20
- package/src/protocol/translation/capabilities.ts +6 -6
- package/src/protocol/translation/dialect/deepseek.ts +10 -0
- package/src/protocol/translation/dialect/inband.ts +39 -0
- package/src/protocol/translation/dialect/model-thinking.ts +89 -0
- package/src/protocol/translation/dialect/qwen.ts +114 -0
- package/src/protocol/translation/dialect/resolver.ts +83 -0
- package/src/protocol/translation/dialect/rules.ts +93 -0
- package/src/protocol/translation/dialect/thinking-ladder.ts +245 -0
- package/src/protocol/translation/dialect/types.ts +58 -0
- package/src/protocol/translation/quirks.ts +18 -4
- package/src/protocol/translation/thinking.ts +12 -252
- package/src/protocol/translation/tool-id.ts +3 -3
- package/src/protocol/translation/tool-repair.ts +1 -1
- package/src/protocol/upstream/post-json.ts +6 -1
- package/src/providers/adapters/compatible-adapter.ts +42 -3
- package/src/providers/authentication/jwt-validator.ts +0 -5
- package/src/providers/authentication/oauth-client.ts +254 -253
- package/src/providers/authentication/oauth-flow-store.ts +42 -7
- package/src/providers/bundled-discovery-providers.ts +6 -30
- package/src/providers/configured-openai-providers.ts +82 -97
- package/src/providers/default-registry.ts +23 -35
- package/src/providers/discovery/catalog/catalog-format.ts +13 -2
- package/src/providers/discovery/discovery-types.ts +0 -1
- package/src/providers/discovery/openai-model-discovery.ts +2 -2
- package/src/providers/discovery/probe-phases.ts +48 -13
- package/src/providers/discovery/probing-service.ts +6 -8
- package/src/providers/integrations/agentrouter/agentrouter.ts +12 -2
- package/src/providers/integrations/antigravity/antigravity-oauth.ts +0 -1
- package/src/providers/integrations/antigravity/antigravity-protocol.ts +0 -14
- package/src/providers/integrations/antigravity/antigravity.ts +2 -2
- package/src/providers/integrations/buddy/buddy-catalog-shared.ts +1 -1
- package/src/providers/integrations/buddy/buddy-chat-shared.ts +20 -4
- package/src/providers/integrations/buddy/buddy-cli-headers.ts +19 -52
- package/src/providers/integrations/buddy/buddy-identity.ts +86 -0
- package/src/providers/integrations/buddy/buddy-oauth-shared.ts +1 -1
- package/src/providers/integrations/buddy/codebuddy/cn-provider.ts +1 -2
- package/src/providers/integrations/buddy/codebuddy/provider.ts +4 -15
- package/src/providers/integrations/buddy/codebuddy/shared.ts +30 -9
- package/src/providers/integrations/buddy/workbuddy/provider.ts +5 -9
- package/src/providers/integrations/buddy/workbuddy/shared.ts +21 -3
- package/src/providers/integrations/claude/claude-cch.ts +148 -148
- package/src/providers/integrations/claude/fallback-credit.ts +3 -7
- package/src/providers/integrations/cline/cline.ts +1 -1
- package/src/providers/integrations/codex/codex-device-code.ts +101 -101
- package/src/providers/integrations/codex/codex-oauth.ts +0 -1
- package/src/providers/integrations/commandcode/commandcode.ts +75 -115
- package/src/providers/integrations/commandcode/quota.ts +131 -51
- package/src/providers/integrations/cursor/cursor-http2.ts +0 -3
- package/src/providers/integrations/cursor/cursor-quota.ts +2 -6
- package/src/providers/integrations/cursor/cursor-request.ts +0 -87
- package/src/providers/integrations/cursor/cursor-shared.ts +0 -4
- package/src/providers/integrations/cursor/cursor.ts +38 -5
- package/src/providers/integrations/cursor/protocol/framing.ts +0 -56
- package/src/providers/integrations/cursor/protocol/messages.ts +0 -96
- package/src/providers/integrations/factory/factory.ts +9 -9
- package/src/providers/integrations/github/github-discovery.ts +55 -10
- package/src/providers/integrations/github/github-oauth.ts +6 -5
- package/src/providers/integrations/github/github.ts +41 -14
- package/src/providers/integrations/grok/grok-oauth.ts +261 -261
- package/src/providers/integrations/grok/grok-quota-frame.ts +1 -1
- package/src/providers/integrations/grok/grok-quota.ts +16 -7
- package/src/providers/integrations/grok/grok-ratelimit-store.ts +0 -5
- package/src/providers/integrations/grok/grok-ratelimit.ts +3 -0
- package/src/providers/integrations/grok/grok.ts +86 -36
- package/src/providers/integrations/kilo/kilo-oauth.ts +1 -1
- package/src/providers/integrations/kiro/kiro-cache.ts +31 -0
- package/src/providers/integrations/kiro/kiro-catalog.ts +31 -5
- package/src/providers/integrations/kiro/kiro-discovery.ts +47 -43
- package/src/providers/integrations/kiro/kiro-machine-id.ts +6 -3
- package/src/providers/integrations/kiro/kiro-oauth.ts +523 -255
- package/src/providers/integrations/kiro/kiro-quota.ts +35 -47
- package/src/providers/integrations/kiro/kiro-request.ts +8 -11
- package/src/providers/integrations/kiro/kiro-stream.ts +13 -0
- package/src/providers/integrations/kiro/kiro.ts +81 -68
- package/src/providers/integrations/muse/muse-oauth.ts +0 -1
- package/src/providers/integrations/muse/muse-quota.ts +0 -4
- package/src/providers/integrations/opencode/fingerprint.ts +7 -5
- package/src/providers/integrations/opencode/provider.ts +17 -24
- package/src/providers/integrations/qoder/qoder-catalog.ts +85 -8
- package/src/providers/integrations/qoder/qoder-oauth.ts +165 -25
- package/src/providers/integrations/qoder/qoder-quota.ts +48 -6
- package/src/providers/integrations/qoder/qoder-realm.ts +10 -31
- package/src/providers/integrations/qoder/qoder-sse.ts +159 -0
- package/src/providers/integrations/qoder/qoder-umid.ts +21 -25
- package/src/providers/integrations/qoder/qoder-virtual.ts +12 -0
- package/src/providers/integrations/qoder/qoder.ts +354 -62
- package/src/providers/integrations/shared/connect.ts +0 -54
- package/src/providers/integrations/shared/hash.ts +15 -0
- package/src/providers/integrations/shared/session-cache.ts +136 -0
- package/src/providers/integrations/trae/trae-cache.ts +7 -87
- package/src/providers/integrations/trae/trae-catalog.ts +1 -6
- package/src/providers/integrations/trae/trae-protocol.ts +17 -8
- package/src/providers/integrations/trae/trae-realm.ts +0 -7
- package/src/providers/integrations/trae/trae.ts +53 -10
- package/src/providers/integrations/xai/xai-oauth.ts +5 -5
- package/src/providers/integrations/zcode-start-plan/gifts.ts +265 -0
- package/src/providers/integrations/zcode-start-plan/oauth.ts +154 -0
- package/src/providers/integrations/zcode-start-plan/provider.ts +131 -0
- package/src/providers/integrations/zcode-start-plan/quota.ts +152 -0
- package/src/providers/integrations/zcode-start-plan/zcode_prompt.json +10 -0
- package/src/providers/operations/account-error-classification.ts +131 -116
- package/src/providers/operations/account-health-service.ts +31 -39
- package/src/providers/operations/account-reset-service.ts +58 -1
- package/src/providers/operations/cli-platform.ts +31 -5
- package/src/providers/operations/client-version-resolver.ts +4 -6
- package/src/providers/operations/client-versions.ts +10 -7
- package/src/providers/operations/provider-catalog-seeder.ts +2 -0
- package/src/providers/operations/provider-catalog-service.ts +18 -2
- package/src/providers/operations/provider-credential-service.ts +19 -2
- package/src/providers/provider-contracts.ts +18 -7
- package/src/providers/provider-metadata.ts +17 -2
- package/src/providers/provider-model-definition.ts +22 -1
- package/src/providers/provider-probe.ts +4 -2
- package/src/providers/provider-usage.ts +81 -16
- package/src/providers/quota/cache.ts +29 -0
- package/src/providers/quota/quota-contracts.ts +4 -0
- package/src/providers/quota/refresh.ts +27 -4
- package/src/providers/quota/snapshot.ts +94 -0
- package/src/providers/search/search-provider.ts +1 -3
- package/src/providers/search/search-providers.ts +2 -1
- package/src/security/abuse.ts +4 -4
- package/src/security/admission/service.ts +2 -2
- package/src/security/admission/ttl.ts +61 -61
- package/src/security/api-key-auth.ts +16 -4
- package/src/security/client-router-fingerprint.ts +4 -4
- package/src/security/credential-codec.ts +3 -3
- package/src/security/csrf.ts +2 -2
- package/src/security/ip-boundary.ts +16 -189
- package/src/security/model-access-rule.ts +1 -1
- package/src/security/outbound-headers.ts +18 -0
- package/src/shared/invoke-guard.ts +47 -0
- package/src/transport/contracts.ts +13 -4
- package/src/transport/dispatch/attempt-finalize.ts +1 -1
- package/src/transport/dispatch/capture-policy.ts +34 -37
- package/src/transport/dispatch/empty-stream.ts +23 -20
- package/src/transport/dispatch/generation.ts +25 -45
- package/src/transport/dispatch/native-shared.ts +127 -0
- package/src/transport/dispatch/proxy-request.ts +3 -1
- package/src/transport/dispatch/responses-compact.ts +25 -46
- package/src/transport/dispatch/streaming/encoder.ts +18 -72
- package/src/transport/dispatch/streaming/finalize.ts +2 -2
- package/src/transport/dispatch/streaming/stream.ts +7 -3
- package/src/transport/dispatch/streaming/thinking-loop.ts +1 -1
- package/src/transport/dispatch/systemone.ts +20 -48
- package/src/transport/dispatch/token-count.ts +41 -38
- package/src/transport/dispatch/websearch.ts +19 -45
- package/src/transport/drain-endpoint.ts +1 -1
- package/src/transport/failure-policy.ts +6 -0
- package/src/transport/guards/auth-guard.ts +0 -6
- package/src/transport/guards/body-policy.ts +3 -3
- package/src/transport/guards/headroom-guard.ts +1 -1
- package/src/transport/guards/pipeline.ts +1 -1
- package/src/transport/guards/request-context.ts +12 -17
- package/src/transport/request/preparer.ts +286 -7
- package/src/transport/request/rtk/compress-request.ts +3 -3
- package/src/transport/request/rtk/rtk-constants.ts +2 -2
- package/src/transport/request/rtk/rtk-filters.ts +8 -8
- package/src/transport/request/state.ts +1 -13
- package/src/transport/request/system-prompt-injection.ts +74 -11
- package/src/transport/request/tenant-preferences.ts +22 -0
- package/src/transport/routing/candidate-index.ts +2 -2
- package/src/transport/routing/round-robin.ts +1 -1
- package/src/transport/routing/route-catalog.ts +17 -18
- package/src/transport/routing/route-model.ts +126 -33
- package/src/transport/routing/router.ts +152 -37
- package/src/transport/shutdown-notice.ts +2 -2
- package/src/transport/surface/adapters.ts +3 -3
- package/src/transport/surface/chat/encode.ts +7 -7
- package/src/transport/surface/chat/parse.ts +7 -7
- package/src/transport/surface/completion.ts +2 -2
- package/src/transport/surface/content-parts.ts +1 -1
- package/src/transport/surface/dialects.ts +2 -2
- package/src/transport/surface/messages/parse.ts +3 -3
- package/src/transport/surface/responses/adapter.ts +1 -1
- package/src/transport/surface/responses/errors.ts +0 -9
- package/src/transport/vision-handoff-cache.ts +58 -0
- package/src/transport/vision-handoff.ts +376 -0
- package/src/workers/account-identity-sweep.ts +2 -2
- package/src/workers/buddy-growth-tasks.ts +392 -346
- package/src/workers/daily-checkin.ts +102 -49
- package/src/workers/maintenance-lease.ts +2 -35
- package/src/workers/oauth-refresh-sweep.ts +8 -1
- package/src/workers/quota-refresh-sweep.ts +120 -82
- package/src/workers/scheduler.ts +67 -4
- package/src/workers/sweep-runner.ts +24 -5
- package/src/workers/zcode-gift-claim.ts +108 -0
- package/dist/dashboard/assets/AccountCooldown-Bjo92Qat.js +0 -1
- package/dist/dashboard/assets/AccountCooldown-Bjo92Qat.js.gz +0 -0
- package/dist/dashboard/assets/BannedPage-ChG5svFb.js.gz +0 -0
- package/dist/dashboard/assets/CliToolDetailPage-BIcWQun7.js.gz +0 -0
- package/dist/dashboard/assets/CliToolsPage-Bf2VelDe.js.gz +0 -0
- package/dist/dashboard/assets/CombosPage-DCgm5g6g.js +0 -1
- package/dist/dashboard/assets/CombosPage-DCgm5g6g.js.gz +0 -0
- package/dist/dashboard/assets/ConsoleLogPage-a8mD0QF1.js +0 -1
- package/dist/dashboard/assets/ConsoleLogPage-a8mD0QF1.js.gz +0 -0
- package/dist/dashboard/assets/CustomizationPage-ggeMSjte.js.gz +0 -0
- package/dist/dashboard/assets/HealthEventsModal-DzSWzE_j.js +0 -1
- package/dist/dashboard/assets/HealthEventsModal-DzSWzE_j.js.gz +0 -0
- package/dist/dashboard/assets/LoginPage-U6AKaJcF.js.gz +0 -0
- package/dist/dashboard/assets/ModelPicker-BMS2t8BA.js.gz +0 -0
- package/dist/dashboard/assets/OverviewPage-D2D4IiHl.js +0 -1
- package/dist/dashboard/assets/OverviewPage-D2D4IiHl.js.gz +0 -0
- package/dist/dashboard/assets/ProviderDetailPage-CrNf7j_X.js +0 -5
- package/dist/dashboard/assets/ProviderDetailPage-CrNf7j_X.js.gz +0 -0
- package/dist/dashboard/assets/ProviderIcon-FB6yS4v1.js +0 -1
- package/dist/dashboard/assets/ProviderIcon-FB6yS4v1.js.gz +0 -0
- package/dist/dashboard/assets/ProvidersPage-BSDbquc1.js +0 -1
- package/dist/dashboard/assets/ProvidersPage-BSDbquc1.js.gz +0 -0
- package/dist/dashboard/assets/ProxyPage-lsrx7NYg.js.gz +0 -0
- package/dist/dashboard/assets/QuotaPage-L0skzML8.js +0 -1
- package/dist/dashboard/assets/QuotaPage-L0skzML8.js.gz +0 -0
- package/dist/dashboard/assets/SettingsPage-CmAbjRHW.js +0 -1
- package/dist/dashboard/assets/SettingsPage-CmAbjRHW.js.gz +0 -0
- package/dist/dashboard/assets/SetupPage-f0DE1h0-.js.gz +0 -0
- package/dist/dashboard/assets/SortableList-ClzpwyET.js +0 -1
- package/dist/dashboard/assets/SortableList-ClzpwyET.js.gz +0 -0
- package/dist/dashboard/assets/StudioPage-Cq5tW7hW.js.gz +0 -0
- package/dist/dashboard/assets/UsagePage-Dfc9rWQn.js +0 -56
- package/dist/dashboard/assets/UsagePage-Dfc9rWQn.js.gz +0 -0
- package/dist/dashboard/assets/api-keys-C38iXoO4.js +0 -1
- package/dist/dashboard/assets/api-keys-C38iXoO4.js.gz +0 -0
- package/dist/dashboard/assets/app-a159k0ub.css +0 -2
- package/dist/dashboard/assets/app-a159k0ub.css.gz +0 -0
- package/dist/dashboard/assets/assert-DbRA8EG2.js +0 -15
- package/dist/dashboard/assets/assert-DbRA8EG2.js.gz +0 -0
- package/dist/dashboard/assets/badge-D9CS6dZk.js.gz +0 -0
- package/dist/dashboard/assets/banner-DympBNq4.js.gz +0 -0
- package/dist/dashboard/assets/card-ibRWU_uT.js.gz +0 -0
- package/dist/dashboard/assets/cli-tools-63qBGaRw.js +0 -1
- package/dist/dashboard/assets/cli-tools-63qBGaRw.js.gz +0 -0
- package/dist/dashboard/assets/clipboard-button-DJm-9pz7.js.gz +0 -0
- package/dist/dashboard/assets/dialog-8fiE6tec.js.gz +0 -0
- package/dist/dashboard/assets/drawer-CqGYeOrd.js.gz +0 -0
- package/dist/dashboard/assets/entry-BSAsYsmV.js.gz +0 -0
- package/dist/dashboard/assets/entry-CiIQULZD.js +0 -4
- package/dist/dashboard/assets/entry-CiIQULZD.js.gz +0 -0
- package/dist/dashboard/assets/entry-Daz0lJ-W.js +0 -1
- package/dist/dashboard/assets/entry-Daz0lJ-W.js.gz +0 -0
- package/dist/dashboard/assets/formatters-D-MTJxMr.js.gz +0 -0
- package/dist/dashboard/assets/github-badge-CPK47xQx.js.gz +0 -0
- package/dist/dashboard/assets/index-DBNPOfhV.js.gz +0 -0
- package/dist/dashboard/assets/inline-BT0zntEr.js.gz +0 -0
- package/dist/dashboard/assets/input-Da2ZViWg.js.gz +0 -0
- package/dist/dashboard/assets/layout-BXNeLw6M.js.gz +0 -0
- package/dist/dashboard/assets/list-row-BycOrrIV.js.gz +0 -0
- package/dist/dashboard/assets/live-DCQNZpF7.js +0 -1
- package/dist/dashboard/assets/live-DCQNZpF7.js.gz +0 -0
- package/dist/dashboard/assets/network-9Yj2ZyLo.js +0 -1
- package/dist/dashboard/assets/network-9Yj2ZyLo.js.gz +0 -0
- package/dist/dashboard/assets/numbers-CEagj6ZZ.js +0 -2
- package/dist/dashboard/assets/numbers-CEagj6ZZ.js.gz +0 -0
- package/dist/dashboard/assets/quota-Caw7wqci.js +0 -1
- package/dist/dashboard/assets/quota-Caw7wqci.js.gz +0 -0
- package/dist/dashboard/assets/routing-CO9zCUus.js +0 -1
- package/dist/dashboard/assets/routing-CO9zCUus.js.gz +0 -0
- package/dist/dashboard/assets/select-BIYIBkMU.js.gz +0 -0
- package/dist/dashboard/assets/settings-jS3-PNSA.js +0 -1
- package/dist/dashboard/assets/settings-jS3-PNSA.js.gz +0 -0
- package/dist/dashboard/assets/stack-DfgnFDWY.js.gz +0 -0
- package/dist/dashboard/assets/state-CkfdYWel.js.gz +0 -0
- package/dist/dashboard/assets/stream-retry-5QnVuSSo.js +0 -1
- package/dist/dashboard/assets/stream-retry-5QnVuSSo.js.gz +0 -0
- package/dist/dashboard/assets/switch-SYm237HG.js.gz +0 -0
- package/dist/dashboard/assets/useMutation-BQqCRNIi.js.gz +0 -0
- package/src/network/response-headers.ts +0 -39
- package/src/protocol/response/dsml.ts +0 -38
- package/src/providers/integrations/xiaomi-mimo/think-stream.ts +0 -229
- /package/dist/dashboard/assets/{app-BayTTy01.js → app-Bgd3zANQ.js} +0 -0
- /package/dist/dashboard/assets/{app-BayTTy01.js.gz → app-Bgd3zANQ.js.gz} +0 -0
- /package/dist/dashboard/assets/brand/{og_bansos.webp → og_bansos_initial.webp} +0 -0
- /package/dist/dashboard/assets/brand/{og_image.webp → og_image_initial.webp} +0 -0
|
@@ -31,7 +31,7 @@ export interface SseEvent {
|
|
|
31
31
|
readonly data: string;
|
|
32
32
|
}
|
|
33
33
|
|
|
34
|
-
|
|
34
|
+
interface SseDecodeOptions {
|
|
35
35
|
/**
|
|
36
36
|
* Max UTF-16 length of a single line; default equals `maxEventBytes`.
|
|
37
37
|
*
|
|
@@ -51,6 +51,43 @@ export interface SseDecodeOptions {
|
|
|
51
51
|
|
|
52
52
|
const DEFAULT_MAX_EVENT_BYTES = 4 * 1024 * 1024;
|
|
53
53
|
|
|
54
|
+
/**
|
|
55
|
+
* True when the accumulated data is a complete JSON value.
|
|
56
|
+
*
|
|
57
|
+
* Uses a bracket-depth scan that skips string contents (including escapes), so
|
|
58
|
+
* an inline `\n` or `\n\n` inside a string does not count as a structural
|
|
59
|
+
* terminator. A non-JSON payload (`[DONE]`, plain text) has depth 0 and reads
|
|
60
|
+
* as complete, so blank-line boundaries stay working for ordinary streams.
|
|
61
|
+
*/
|
|
62
|
+
function isCompleteJsonValue(data: string): boolean {
|
|
63
|
+
if (data.length === 0) return true;
|
|
64
|
+
let depth = 0;
|
|
65
|
+
let inString = false;
|
|
66
|
+
let escaped = false;
|
|
67
|
+
for (let i = 0; i < data.length; i += 1) {
|
|
68
|
+
const ch = data[i]!;
|
|
69
|
+
if (inString) {
|
|
70
|
+
if (escaped) {
|
|
71
|
+
escaped = false;
|
|
72
|
+
} else if (ch === "\\") {
|
|
73
|
+
escaped = true;
|
|
74
|
+
} else if (ch === '"') {
|
|
75
|
+
inString = false;
|
|
76
|
+
}
|
|
77
|
+
continue;
|
|
78
|
+
}
|
|
79
|
+
if (ch === '"') {
|
|
80
|
+
inString = true;
|
|
81
|
+
} else if (ch === "{" || ch === "[") {
|
|
82
|
+
depth += 1;
|
|
83
|
+
} else if (ch === "}" || ch === "]") {
|
|
84
|
+
depth -= 1;
|
|
85
|
+
if (depth < 0) return true; // trailing close: not a partial JSON prefix
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
return depth <= 0;
|
|
89
|
+
}
|
|
90
|
+
|
|
54
91
|
// A corrupt SSE stream is an upstream protocol failure, not a client mistake:
|
|
55
92
|
// labelling it `invalid_request` told the client its request was wrong and
|
|
56
93
|
// invited a retry of the identical request against a broken upstream. The
|
|
@@ -156,6 +193,18 @@ export async function* decodeSseEvents(
|
|
|
156
193
|
}
|
|
157
194
|
if (line.startsWith("id:") || line.startsWith("retry:")) return;
|
|
158
195
|
if (line.trim() === "") {
|
|
196
|
+
// A blank line is an SSE event boundary — but only when the payload
|
|
197
|
+
// accumulated so far is already a complete value. Some upstreams
|
|
198
|
+
// (Qoder IDE /model/v1) emit JSON that contains literal blank lines
|
|
199
|
+
// inside a string (`raw_usage` carries keys like
|
|
200
|
+
// `"data_policy_preferre\n\nnd_count"`). Treating that blank line as a
|
|
201
|
+
// boundary splits the JSON, leaves a dangling continuation, and throws
|
|
202
|
+
// "Malformed SSE line". When the open data is not yet a complete JSON
|
|
203
|
+
// value, append the blank line as a continuation instead.
|
|
204
|
+
if (dataLines.length > 0 && !isCompleteJsonValue(dataLines.join("\n"))) {
|
|
205
|
+
dataLines.push("");
|
|
206
|
+
return;
|
|
207
|
+
}
|
|
159
208
|
yield* dispatchEvent();
|
|
160
209
|
return;
|
|
161
210
|
}
|
|
@@ -35,14 +35,14 @@ const WIRE_STOP_REASONS = {
|
|
|
35
35
|
},
|
|
36
36
|
} satisfies Record<string, Record<CanonicalStopReason, string>>;
|
|
37
37
|
|
|
38
|
-
|
|
38
|
+
type StopReasonWireFamily = keyof typeof WIRE_STOP_REASONS;
|
|
39
39
|
|
|
40
40
|
/**
|
|
41
41
|
* Maps a canonical stop reason onto `wire`'s vocabulary, falling back when the
|
|
42
42
|
* terminal carried none: Chat has no null finish_reason and defaults to `stop`,
|
|
43
43
|
* while Messages omits `stop_reason` entirely.
|
|
44
44
|
*/
|
|
45
|
-
|
|
45
|
+
function canonicalStopReasonToWire(
|
|
46
46
|
wire: StopReasonWireFamily,
|
|
47
47
|
reason: CanonicalStopReason | undefined,
|
|
48
48
|
fallback: string,
|
|
@@ -0,0 +1,347 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Canonical inline-thinking split.
|
|
3
|
+
*
|
|
4
|
+
* Some upstream models write their reasoning into the *text* stream wrapped in
|
|
5
|
+
* `<think>…</think>` (or `<thinking>…</thinking>`) instead of a dedicated
|
|
6
|
+
* reasoning field. This module recovers that reasoning — statefully, so a tag
|
|
7
|
+
* split across two chunks is still recognized — and lives in the canonical
|
|
8
|
+
* protocol layer because it serves every wire: the chat decoder, provider
|
|
9
|
+
* decoders (CommandCode, Xiaomi MiMo Studio), and nothing else is per-provider
|
|
10
|
+
* about it.
|
|
11
|
+
*
|
|
12
|
+
* Two safety rules keep the classification honest (mirroring the DSML parser's
|
|
13
|
+
* fail-open behavior):
|
|
14
|
+
*
|
|
15
|
+
* - Only a *paired* span — an opening tag followed by its matching closing tag,
|
|
16
|
+
* outside a code span — is treated as reasoning. An opening tag that never
|
|
17
|
+
* closes at end-of-stream is almost certainly literal output (docs, a code
|
|
18
|
+
* sample, a model reciting the syntax), so it is released as plain text
|
|
19
|
+
* rather than swallowing the tail of the answer into the thinking pane.
|
|
20
|
+
* - A stray closing tag with no opener is likewise preserved verbatim.
|
|
21
|
+
*
|
|
22
|
+
* The splitter is stateful because a tag can straddle two SSE frames: the
|
|
23
|
+
* `<thi` of one chunk and the `nk>` of the next are one opening tag, and a
|
|
24
|
+
* stateless regex would emit the fragment as text. It therefore holds back a
|
|
25
|
+
* trailing run that could still become a tag until the next chunk settles it.
|
|
26
|
+
*
|
|
27
|
+
* Two further quirks are handled here rather than at each call site:
|
|
28
|
+
* - NUL bytes (`\u0000`) are injected by the MiMo Studio upstream between
|
|
29
|
+
* thought tokens; forwarded verbatim they break JSON encoders and terminal
|
|
30
|
+
* renderers.
|
|
31
|
+
* - Text before an opening tag is the answer (some models answer first and
|
|
32
|
+
* reason afterwards), so it stays content; only the enclosed span becomes
|
|
33
|
+
* reasoning.
|
|
34
|
+
*/
|
|
35
|
+
|
|
36
|
+
/** Tags whose enclosed span is reasoning, longest-first so `</thinking>` is never split as `<t`. */
|
|
37
|
+
const OPEN_TAGS = ["<thinking>", "<think>"] as const;
|
|
38
|
+
const CLOSE_TAGS = ["</thinking>", "</think>"] as const;
|
|
39
|
+
|
|
40
|
+
/** An opening tag, with optional attributes between the name and the `>`. */
|
|
41
|
+
const THINK_OPEN_RE = /^<think(?:ing)?\b[^>]*>/;
|
|
42
|
+
|
|
43
|
+
/**
|
|
44
|
+
* Fail-open cap for an unclosed thinking span. Past it the span is treated as
|
|
45
|
+
* plain text instead of being buffered indefinitely — same rule as DSML's
|
|
46
|
+
* `maxBlockBytes` reference guard.
|
|
47
|
+
*/
|
|
48
|
+
const MAX_THINK_BLOCK_BYTES = 64 * 1024;
|
|
49
|
+
|
|
50
|
+
/**
|
|
51
|
+
* Removes visible thinking tags, leaving any that sit inside a code span or
|
|
52
|
+
* fence alone — and leaving any tag that is not part of a complete pair alone
|
|
53
|
+
* too, since an unpaired tag is the subject of the answer rather than markup
|
|
54
|
+
* the upstream leaked.
|
|
55
|
+
*
|
|
56
|
+
* A tag inside backticks is the *subject* of the answer — documentation or a
|
|
57
|
+
* code sample showing the tag — not markup the upstream leaked, so stripping it
|
|
58
|
+
* would silently rewrite the answer. The same goes for an opening tag whose
|
|
59
|
+
* closing tag never arrived or a closing tag with no opener.
|
|
60
|
+
*/
|
|
61
|
+
export function stripThinkingTags(value: string): string {
|
|
62
|
+
if (!value.includes("<")) return value;
|
|
63
|
+
let out = "";
|
|
64
|
+
let i = 0;
|
|
65
|
+
let ticks = 0;
|
|
66
|
+
let fenced = false;
|
|
67
|
+
while (i < value.length) {
|
|
68
|
+
const char = value[i];
|
|
69
|
+
if (char === "`") {
|
|
70
|
+
let run = 1;
|
|
71
|
+
while (value[i + run] === "`") run++;
|
|
72
|
+
if (ticks === 0) {
|
|
73
|
+
ticks = run;
|
|
74
|
+
fenced = run >= 3;
|
|
75
|
+
} else if (run === ticks) {
|
|
76
|
+
ticks = 0;
|
|
77
|
+
fenced = false;
|
|
78
|
+
}
|
|
79
|
+
out += value.slice(i, i + run);
|
|
80
|
+
i += run;
|
|
81
|
+
continue;
|
|
82
|
+
}
|
|
83
|
+
// A newline closes an inline span that never closed on its own line; a
|
|
84
|
+
// fence runs to a closing line instead.
|
|
85
|
+
if (char === "\n" && ticks > 0 && !fenced) ticks = 0;
|
|
86
|
+
if (char !== "<" || ticks > 0) {
|
|
87
|
+
out += char;
|
|
88
|
+
i += 1;
|
|
89
|
+
continue;
|
|
90
|
+
}
|
|
91
|
+
const opened = THINK_OPEN_RE.exec(value.slice(i))?.[0];
|
|
92
|
+
if (opened === undefined) {
|
|
93
|
+
out += char;
|
|
94
|
+
i += 1;
|
|
95
|
+
continue;
|
|
96
|
+
}
|
|
97
|
+
const innerStart = i + opened.length;
|
|
98
|
+
const closed = pairedClose(value, innerStart, ticks, fenced);
|
|
99
|
+
if (closed === undefined) {
|
|
100
|
+
// No matching close: the opening tag is literal output, keep it.
|
|
101
|
+
out += char;
|
|
102
|
+
i += 1;
|
|
103
|
+
continue;
|
|
104
|
+
}
|
|
105
|
+
// A complete paired span is reasoning markup: keep the inner text, drop
|
|
106
|
+
// the tag bytes.
|
|
107
|
+
out += value.slice(innerStart, closed.index);
|
|
108
|
+
i = closed.index + closed.length;
|
|
109
|
+
}
|
|
110
|
+
return out;
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
interface PairedClose {
|
|
114
|
+
readonly index: number;
|
|
115
|
+
readonly length: number;
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
/** The first closing tag at or after `from`, outside any code span/fence. */
|
|
119
|
+
function pairedClose(
|
|
120
|
+
value: string,
|
|
121
|
+
from: number,
|
|
122
|
+
ticksIn: number,
|
|
123
|
+
fencedIn: boolean,
|
|
124
|
+
): PairedClose | undefined {
|
|
125
|
+
let ticks = ticksIn;
|
|
126
|
+
let fenced = fencedIn;
|
|
127
|
+
for (let i = from; i < value.length; i++) {
|
|
128
|
+
const char = value[i];
|
|
129
|
+
if (char === "`") {
|
|
130
|
+
let run = 1;
|
|
131
|
+
while (value[i + run] === "`") run++;
|
|
132
|
+
if (ticks === 0) {
|
|
133
|
+
ticks = run;
|
|
134
|
+
fenced = run >= 3;
|
|
135
|
+
} else if (run === ticks) {
|
|
136
|
+
ticks = 0;
|
|
137
|
+
fenced = false;
|
|
138
|
+
}
|
|
139
|
+
i += run - 1;
|
|
140
|
+
continue;
|
|
141
|
+
}
|
|
142
|
+
if (char === "\n" && ticks > 0 && !fenced) ticks = 0;
|
|
143
|
+
if (char !== "<" || ticks > 0) continue;
|
|
144
|
+
for (const tag of CLOSE_TAGS) {
|
|
145
|
+
if (value.startsWith(tag, i)) return { index: i, length: tag.length };
|
|
146
|
+
}
|
|
147
|
+
// `</think >` / `</thinking >`: whitespace before the closing `>` is
|
|
148
|
+
// accepted, same as the historical regex-backed strip.
|
|
149
|
+
const relaxed = /^<\/(?:think|thinking)\s*>/.exec(value.slice(i));
|
|
150
|
+
if (relaxed !== null) return { index: i, length: relaxed[0].length };
|
|
151
|
+
}
|
|
152
|
+
return undefined;
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
/** The longest suffix of `text` that is a proper prefix of any tag. */
|
|
156
|
+
function danglingTagPrefix(text: string): string {
|
|
157
|
+
const tags = [...OPEN_TAGS, ...CLOSE_TAGS];
|
|
158
|
+
const maxLength = Math.max(...tags.map((tag) => tag.length)) - 1;
|
|
159
|
+
const limit = Math.min(maxLength, text.length);
|
|
160
|
+
for (let length = limit; length > 0; length -= 1) {
|
|
161
|
+
const suffix = text.slice(-length);
|
|
162
|
+
if (tags.some((tag) => tag.startsWith(suffix))) return suffix;
|
|
163
|
+
}
|
|
164
|
+
return "";
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
/** Strips the NUL padding MiMo Studio injects into thought streams. */
|
|
168
|
+
function stripNul(text: string): string {
|
|
169
|
+
return text.includes("\u0000") ? text.replace(/\u0000/g, "") : text;
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
export interface ThinkSplit {
|
|
173
|
+
/** Answer text, with all reasoning spans removed. */
|
|
174
|
+
readonly text: string;
|
|
175
|
+
/** Reasoning text, tag-free. Empty when the chunk carried no thought. */
|
|
176
|
+
readonly reasoning: string;
|
|
177
|
+
/**
|
|
178
|
+
* Content that landed inside a span that is still open at the end of this
|
|
179
|
+
* chunk. It is not yet classified — the span has not closed — so callers
|
|
180
|
+
* that render must not emit it; a loop guard may still watch it.
|
|
181
|
+
*/
|
|
182
|
+
readonly pendingReasoning: string;
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
/** A tag match plus the code state at the match, so the caller commits it. */
|
|
186
|
+
interface TagMatch {
|
|
187
|
+
readonly index: number;
|
|
188
|
+
readonly length: number;
|
|
189
|
+
readonly codeTicks: number;
|
|
190
|
+
readonly codeFenced: boolean;
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
/**
|
|
194
|
+
* Splits one upstream text chunk into answer text and reasoning text.
|
|
195
|
+
*
|
|
196
|
+
* Only a pair of matching tags resolves to reasoning: the text inside stays
|
|
197
|
+
* buffered until the closing tag arrives, so the split is never decided before
|
|
198
|
+
* the span is known to be complete. If the stream ends (or the buffer exceeds
|
|
199
|
+
* `MAX_THINK_BLOCK_BYTES`) with the span still open, the whole thing is
|
|
200
|
+
* released as plain text.
|
|
201
|
+
*
|
|
202
|
+
* Call `flush()` once the upstream stream ends to release any text the splitter
|
|
203
|
+
* held back while it waited for a possible tag to complete.
|
|
204
|
+
*/
|
|
205
|
+
export class ThinkSplitter {
|
|
206
|
+
#buffer = "";
|
|
207
|
+
#inReasoning = false;
|
|
208
|
+
/** The opening tag of the span currently being scanned; restored on fail-open. */
|
|
209
|
+
#openMarker = "";
|
|
210
|
+
/** Backtick run that opened the code span/fence we are inside; 0 when not in
|
|
211
|
+
* code. A tag inside a code span is the *subject* of the answer — a doc or a
|
|
212
|
+
* code sample mentioning `<think>` — not a delimiter, so it must survive
|
|
213
|
+
* verbatim instead of splitting the stream. */
|
|
214
|
+
#codeTicks = 0;
|
|
215
|
+
/** Whether `#codeTicks` opened a fenced block (closes on its own line) rather
|
|
216
|
+
* than an inline span. */
|
|
217
|
+
#codeFenced = false;
|
|
218
|
+
/** Span characters already reported as `pendingReasoning`; only the fresh
|
|
219
|
+
* tail of the open span is reported per chunk. */
|
|
220
|
+
#reportedSpanLen = 0;
|
|
221
|
+
|
|
222
|
+
/** Feeds a chunk; returns the text/reasoning split for everything settled. */
|
|
223
|
+
push(chunk: string): ThinkSplit {
|
|
224
|
+
this.#buffer += stripNul(chunk);
|
|
225
|
+
let text = "";
|
|
226
|
+
let reasoning = "";
|
|
227
|
+
|
|
228
|
+
for (;;) {
|
|
229
|
+
if (!this.#inReasoning) {
|
|
230
|
+
const opened = this.#findOpen();
|
|
231
|
+
if (opened === undefined) break;
|
|
232
|
+
text += this.#consumeUpTo(opened);
|
|
233
|
+
const openTag = this.#buffer.slice(opened.index, opened.index + opened.length);
|
|
234
|
+
this.#buffer = this.#buffer.slice(opened.index + opened.length);
|
|
235
|
+
this.#inReasoning = true;
|
|
236
|
+
this.#openMarker = openTag;
|
|
237
|
+
continue;
|
|
238
|
+
}
|
|
239
|
+
const closed = this.#findClose();
|
|
240
|
+
if (closed === undefined) break;
|
|
241
|
+
reasoning += this.#consumeUpTo(closed);
|
|
242
|
+
this.#buffer = this.#buffer.slice(closed.index + closed.length);
|
|
243
|
+
this.#inReasoning = false;
|
|
244
|
+
this.#openMarker = "";
|
|
245
|
+
this.#reportedSpanLen = 0;
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
// Hold back a suffix that could still grow into a tag; the rest is settled.
|
|
249
|
+
const held = danglingTagPrefix(this.#buffer);
|
|
250
|
+
const settled = held.length > 0 ? this.#buffer.slice(0, -held.length) : this.#buffer;
|
|
251
|
+
let pendingReasoning = "";
|
|
252
|
+
if (this.#inReasoning) {
|
|
253
|
+
// The closing tag has not arrived: do not classify any of this as
|
|
254
|
+
// reasoning yet. Keep it buffered so a later close can resolve it, but
|
|
255
|
+
// fail open past the cap so a runaway cannot buffer forever.
|
|
256
|
+
if (settled.length > MAX_THINK_BLOCK_BYTES) {
|
|
257
|
+
text += this.#openMarker + settled;
|
|
258
|
+
this.#buffer = held;
|
|
259
|
+
this.#inReasoning = false;
|
|
260
|
+
this.#openMarker = "";
|
|
261
|
+
this.#reportedSpanLen = 0;
|
|
262
|
+
} else {
|
|
263
|
+
this.#buffer = settled + held;
|
|
264
|
+
// Fresh span content this chunk added — visible to a loop guard, never
|
|
265
|
+
// to a renderer (the span has not closed).
|
|
266
|
+
pendingReasoning = this.#buffer.slice(this.#reportedSpanLen);
|
|
267
|
+
this.#reportedSpanLen = this.#buffer.length;
|
|
268
|
+
return { text, reasoning, pendingReasoning };
|
|
269
|
+
}
|
|
270
|
+
} else {
|
|
271
|
+
text += stripThinkingTags(settled);
|
|
272
|
+
this.#buffer = held;
|
|
273
|
+
}
|
|
274
|
+
return { text, reasoning, pendingReasoning };
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
/** Releases text held back for a tag that never completed. */
|
|
278
|
+
flush(): ThinkSplit {
|
|
279
|
+
const rest = this.#buffer;
|
|
280
|
+
this.#buffer = "";
|
|
281
|
+
this.#codeTicks = 0;
|
|
282
|
+
this.#codeFenced = false;
|
|
283
|
+
this.#reportedSpanLen = 0;
|
|
284
|
+
if (this.#inReasoning) {
|
|
285
|
+
// An open tag that never closed is not evidence of reasoning — restore it
|
|
286
|
+
// byte-for-byte and release the whole tail as text.
|
|
287
|
+
this.#inReasoning = false;
|
|
288
|
+
const marker = this.#openMarker;
|
|
289
|
+
this.#openMarker = "";
|
|
290
|
+
return { text: marker + stripThinkingTags(rest), reasoning: "", pendingReasoning: "" };
|
|
291
|
+
}
|
|
292
|
+
return { text: stripThinkingTags(rest), reasoning: "", pendingReasoning: "" };
|
|
293
|
+
}
|
|
294
|
+
|
|
295
|
+
/** Returns the text before a tag and commits the code state at it. */
|
|
296
|
+
#consumeUpTo(match: TagMatch): string {
|
|
297
|
+
this.#codeTicks = match.codeTicks;
|
|
298
|
+
this.#codeFenced = match.codeFenced;
|
|
299
|
+
return this.#buffer.slice(0, match.index);
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
#findOpen(): TagMatch | undefined {
|
|
303
|
+
return this.#findTag(OPEN_TAGS);
|
|
304
|
+
}
|
|
305
|
+
|
|
306
|
+
#findClose(): TagMatch | undefined {
|
|
307
|
+
return this.#findTag(CLOSE_TAGS);
|
|
308
|
+
}
|
|
309
|
+
|
|
310
|
+
/**
|
|
311
|
+
* The earliest occurrence of any of `tags` that is *not* inside a code span
|
|
312
|
+
* or fence, scanning left to right so code state is tracked exactly once per
|
|
313
|
+
* position. Returns the match and the code state at it, so `push` can commit
|
|
314
|
+
* that state when it consumes the tag.
|
|
315
|
+
*/
|
|
316
|
+
#findTag(tags: readonly string[]): TagMatch | undefined {
|
|
317
|
+
const buffer = this.#buffer;
|
|
318
|
+
let ticks = this.#codeTicks;
|
|
319
|
+
let fenced = this.#codeFenced;
|
|
320
|
+
for (let i = 0; i < buffer.length; i++) {
|
|
321
|
+
const char = buffer[i];
|
|
322
|
+
if (char === "`") {
|
|
323
|
+
let run = 1;
|
|
324
|
+
while (buffer[i + run] === "`") run++;
|
|
325
|
+
if (ticks === 0) {
|
|
326
|
+
ticks = run;
|
|
327
|
+
// Three or more backticks open a fence rather than an inline span.
|
|
328
|
+
fenced = run >= 3;
|
|
329
|
+
} else if (run === ticks) {
|
|
330
|
+
ticks = 0;
|
|
331
|
+
fenced = false;
|
|
332
|
+
}
|
|
333
|
+
i += run - 1;
|
|
334
|
+
continue;
|
|
335
|
+
}
|
|
336
|
+
// A newline closes an inline span that never closed on its own line; a
|
|
337
|
+
// fence runs to a closing line instead.
|
|
338
|
+
if (char === "\n" && ticks > 0 && !fenced) ticks = 0;
|
|
339
|
+
if (char !== "<" || ticks > 0) continue;
|
|
340
|
+
for (const tag of tags) {
|
|
341
|
+
if (!buffer.startsWith(tag, i)) continue;
|
|
342
|
+
return { index: i, length: tag.length, codeTicks: ticks, codeFenced: fenced };
|
|
343
|
+
}
|
|
344
|
+
}
|
|
345
|
+
return undefined;
|
|
346
|
+
}
|
|
347
|
+
}
|
|
@@ -9,7 +9,7 @@ import { log } from "../../observability/logger";
|
|
|
9
9
|
* and in the placeholder text the model sees, so each one has to be readable
|
|
10
10
|
* on its own.
|
|
11
11
|
*/
|
|
12
|
-
|
|
12
|
+
type AttachmentDefect =
|
|
13
13
|
/** The base64 payload is not a whole number of 4-char groups. */
|
|
14
14
|
| "truncated_base64"
|
|
15
15
|
/** Base64 is well-formed but the bytes behind it are not a decodable image. */
|
|
@@ -26,13 +26,13 @@ export type AttachmentDefect =
|
|
|
26
26
|
| "unrecognized_signature";
|
|
27
27
|
|
|
28
28
|
/** One attachment dropped from a request, and why. */
|
|
29
|
-
|
|
29
|
+
interface DroppedAttachment {
|
|
30
30
|
readonly defect: AttachmentDefect;
|
|
31
31
|
/** Index of the message the part lived in, for the log line. */
|
|
32
32
|
readonly messageIndex: number;
|
|
33
33
|
}
|
|
34
34
|
|
|
35
|
-
|
|
35
|
+
interface AttachmentIntegrityResult {
|
|
36
36
|
/** The request with every defective inline attachment replaced by a note. */
|
|
37
37
|
readonly request: CanonicalRequest;
|
|
38
38
|
/** Non-empty only when something was actually dropped. */
|
|
@@ -74,13 +74,13 @@ export function markLatestBreakpoint(
|
|
|
74
74
|
// Anthropic Cache Control (Messages API)
|
|
75
75
|
// ============================================================================
|
|
76
76
|
|
|
77
|
-
|
|
77
|
+
interface AnthropicCacheControl {
|
|
78
78
|
type: "ephemeral";
|
|
79
79
|
/** Real Anthropic Messages wire field — NOT `budget_tokens` (that belongs only to `thinking`). */
|
|
80
80
|
ttl?: AnthropicCacheTtl;
|
|
81
81
|
}
|
|
82
82
|
|
|
83
|
-
|
|
83
|
+
type AnthropicCacheTtl = "5m" | "1h";
|
|
84
84
|
|
|
85
85
|
interface AnthropicCacheControlOptions {
|
|
86
86
|
ttl?: AnthropicCacheTtl;
|
|
@@ -93,27 +93,15 @@ interface AnthropicCacheControlOptions {
|
|
|
93
93
|
* No invented minimum prefix length.
|
|
94
94
|
*/
|
|
95
95
|
export function anthropicCacheControl(
|
|
96
|
-
|
|
96
|
+
_hint: CacheHint | undefined,
|
|
97
97
|
options: AnthropicCacheControlOptions = {},
|
|
98
|
-
):
|
|
98
|
+
): { cache_control: AnthropicCacheControl } {
|
|
99
99
|
const control: AnthropicCacheControl = { type: "ephemeral" };
|
|
100
100
|
if (options.ttl) control.ttl = options.ttl;
|
|
101
101
|
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
if (hint.kind === "breakpoint") {
|
|
108
|
-
// Per-content-block cache control for explicitly marked breakpoints
|
|
109
|
-
// The breakpoint list indicates positions where cache boundaries should be
|
|
110
|
-
// applied (in top-level request builder when flattening to Messages format)
|
|
111
|
-
return {
|
|
112
|
-
// Caller-marked breakpoints handled by surface adapter
|
|
113
|
-
// per_block_cache: hint.list, // not exposed to API, managed by adapter
|
|
114
|
-
cache_control: control,
|
|
115
|
-
};
|
|
116
|
-
}
|
|
117
|
-
|
|
102
|
+
// Every hint shape maps to the same top-level control: stable_prefix emits
|
|
103
|
+
// it at the last cacheable block, breakpoint hints are handled per-block by
|
|
104
|
+
// the surface adapter, and no hint still gets Anthropic's automatic cache
|
|
105
|
+
// control. The (unused) hint parameter is kept so call sites document intent.
|
|
118
106
|
return { cache_control: control };
|
|
119
107
|
}
|
|
@@ -9,7 +9,7 @@ import {
|
|
|
9
9
|
} from "../canonical-model";
|
|
10
10
|
|
|
11
11
|
/** Capabilities declared by one resolved provider/model/route candidate. */
|
|
12
|
-
|
|
12
|
+
interface RouteCapabilities {
|
|
13
13
|
readonly text: true;
|
|
14
14
|
readonly image: boolean;
|
|
15
15
|
/** Accepts non-image document payloads (PDF, plain files). */
|
|
@@ -45,7 +45,7 @@ export interface RouteCapabilities {
|
|
|
45
45
|
* A bespoke adapter is not in this matrix at all — see
|
|
46
46
|
* `BESPOKE_GENERATION_CONTROLS` for why it receives every control.
|
|
47
47
|
*/
|
|
48
|
-
|
|
48
|
+
const GENERATION_CONTROL_MATRIX: Readonly<
|
|
49
49
|
Record<WireFamily, ReadonlySet<keyof GenerationControls>>
|
|
50
50
|
> = {
|
|
51
51
|
chat: new Set([
|
|
@@ -98,7 +98,7 @@ const BESPOKE_GENERATION_CONTROLS: ReadonlySet<keyof GenerationControls> = new S
|
|
|
98
98
|
* and `web_search_tool_result` are Anthropic Messages blocks, so only the
|
|
99
99
|
* Messages wire re-encodes them (`protocol/request/messages.ts`).
|
|
100
100
|
*/
|
|
101
|
-
|
|
101
|
+
const EXTENSION_MATRIX: Readonly<Record<WireFamily, ReadonlySet<string>>> = {
|
|
102
102
|
chat: new Set(),
|
|
103
103
|
responses: new Set(),
|
|
104
104
|
messages: new Set(["server_tool_use", "search_result", "web_search_tool_result"]),
|
|
@@ -155,7 +155,7 @@ export function pickWireSupportedControls(
|
|
|
155
155
|
* both the router (`routing/router.ts`) and the planner share one predicate
|
|
156
156
|
* without a layering cycle.
|
|
157
157
|
*/
|
|
158
|
-
|
|
158
|
+
interface CapabilityProfileHolder {
|
|
159
159
|
readonly capability_profile: Readonly<Record<string, boolean>>;
|
|
160
160
|
readonly wire_family: WireFamily;
|
|
161
161
|
}
|
|
@@ -288,7 +288,7 @@ export type RequiredCapability =
|
|
|
288
288
|
* No field is silently removed: every unsupported semantic requirement has
|
|
289
289
|
* already produced a typed rejection before this result exists.
|
|
290
290
|
*/
|
|
291
|
-
|
|
291
|
+
interface ProjectedRequest extends CanonicalRequest {
|
|
292
292
|
readonly requiredCapabilities: readonly RequiredCapability[];
|
|
293
293
|
}
|
|
294
294
|
|
|
@@ -347,7 +347,7 @@ export function deriveRequiredCapabilities(
|
|
|
347
347
|
}
|
|
348
348
|
|
|
349
349
|
/** Anthropic and OpenAI 5.6+ both cap explicit cache breakpoints per request. */
|
|
350
|
-
|
|
350
|
+
const MAX_CACHE_BREAKPOINTS = 4;
|
|
351
351
|
|
|
352
352
|
/**
|
|
353
353
|
* Validates the cache-breakpoint count at the preflight boundary — before
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* DeepSeek wire dialect: DSML in-band tool calls.
|
|
3
|
+
*
|
|
4
|
+
* The engine (`DsmlStreamParser`) lives in `src/protocol/dsml.ts` and is shared
|
|
5
|
+
* with the CodeBuddy/Qoder families. This module owns the DeepSeek dialect
|
|
6
|
+
* facade used by the in-band scanner factory.
|
|
7
|
+
*/
|
|
8
|
+
import { DsmlStreamParser } from "../../dsml";
|
|
9
|
+
|
|
10
|
+
export { DsmlStreamParser };
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* In-band tool-call scanner interface + factory.
|
|
3
|
+
*
|
|
4
|
+
* Some model families emit tool calls as markup inside the text stream instead
|
|
5
|
+
* of structured `tool_calls`: DeepSeek DSML, Qwen `<tool_call>` JSON, OMP
|
|
6
|
+
* `<tool_calls:8hex>`. Each is a pluggable codec; the codecs select one by
|
|
7
|
+
* dialect id.
|
|
8
|
+
*/
|
|
9
|
+
import { DsmlStreamParser } from "./deepseek";
|
|
10
|
+
import { QwenToolCallScanner } from "./qwen";
|
|
11
|
+
import type { DialectId } from "./types";
|
|
12
|
+
|
|
13
|
+
interface InbandToolCall {
|
|
14
|
+
readonly id: string;
|
|
15
|
+
readonly name: string;
|
|
16
|
+
readonly arguments: string;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
export interface InbandScanResult {
|
|
20
|
+
readonly text: string;
|
|
21
|
+
readonly calls: readonly InbandToolCall[];
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
export interface InbandScanner {
|
|
25
|
+
push(chunk: string): InbandScanResult;
|
|
26
|
+
flush(): InbandScanResult;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
/** Creates the scanner for a dialect, or undefined for structured-only dialects. */
|
|
30
|
+
export function createInbandScanner(
|
|
31
|
+
dialect: DialectId | null | undefined,
|
|
32
|
+
allowedNames: ReadonlySet<string>,
|
|
33
|
+
): InbandScanner | undefined {
|
|
34
|
+
if (dialect === "qwen") return new QwenToolCallScanner(allowedNames);
|
|
35
|
+
if (dialect === "deepseek") return new DsmlStreamParser({ allowedNames });
|
|
36
|
+
return undefined;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
export type { DsmlToolCall } from "../../dsml";
|