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
|
@@ -20,20 +20,26 @@
|
|
|
20
20
|
*/
|
|
21
21
|
import type { ImageGenerationOutcome, ProviderAdapter, ProviderDispatchTarget } from "../../providers/provider-contracts";
|
|
22
22
|
import { GatewayError } from "../../protocol/gateway-error";
|
|
23
|
-
import { resolveCredentialForAccount } from "../../providers/operations/provider-credential-service";
|
|
24
23
|
import type { ServiceKind } from "../../protocol/canonical-model";
|
|
25
24
|
import { metrics } from "../../observability/metrics";
|
|
26
25
|
import type { ProxyRequestState } from "../request/state";
|
|
27
26
|
import { completeAttempt, estimatedUsage, nativeCompletionBase } from "./attempt-finalize";
|
|
28
27
|
import { runAttemptLoop } from "./attempt-loop";
|
|
29
28
|
import { captureProviderRateLimit } from "./ratelimit-capture";
|
|
29
|
+
import {
|
|
30
|
+
hasScope,
|
|
31
|
+
jsonResponse,
|
|
32
|
+
networkFetchContext,
|
|
33
|
+
requireRecordBody,
|
|
34
|
+
resolveAttemptCredential,
|
|
35
|
+
} from "./native-shared";
|
|
30
36
|
|
|
31
37
|
import type { GatewayHandlerDeps } from "./handler-deps";
|
|
32
38
|
|
|
33
|
-
|
|
39
|
+
type GenerationHandlerDeps = GatewayHandlerDeps;
|
|
34
40
|
|
|
35
41
|
/** Which surface a handler serves. Drives candidate filtering and error copy. */
|
|
36
|
-
|
|
42
|
+
type GenerationKind = Extract<ServiceKind, "imageGeneration" | "videoGeneration">;
|
|
37
43
|
|
|
38
44
|
/**
|
|
39
45
|
* Surfaces the gateway routes but does not model.
|
|
@@ -44,7 +50,7 @@ export type GenerationKind = Extract<ServiceKind, "imageGeneration" | "videoGene
|
|
|
44
50
|
* is the whole feature: routing, admission, failover, and accounting still
|
|
45
51
|
* apply, and the upstream's own bytes come back untouched.
|
|
46
52
|
*/
|
|
47
|
-
|
|
53
|
+
type PassthroughKind = Extract<ServiceKind, "embedding" | "audioTranscription" | "audioSpeech">;
|
|
48
54
|
|
|
49
55
|
/** Error-copy noun per surface, so a refusal names what the caller asked for. */
|
|
50
56
|
const SURFACE_NOUNS: Record<GenerationKind | PassthroughKind, string> = {
|
|
@@ -74,13 +80,6 @@ function isMediaKind(kind: GenerationKind | PassthroughKind): kind is Generation
|
|
|
74
80
|
*/
|
|
75
81
|
const MAX_ITEMS_PER_REQUEST = 10;
|
|
76
82
|
|
|
77
|
-
function jsonResponse(payload: unknown, status: number, requestId: string): Response {
|
|
78
|
-
return new Response(JSON.stringify(payload), {
|
|
79
|
-
status,
|
|
80
|
-
headers: { "content-type": "application/json", "x-request-id": requestId },
|
|
81
|
-
});
|
|
82
|
-
}
|
|
83
|
-
|
|
84
83
|
/**
|
|
85
84
|
* Forwards a streaming upstream response to the client and accounts for it.
|
|
86
85
|
*
|
|
@@ -145,12 +144,12 @@ async function passThrough(
|
|
|
145
144
|
}
|
|
146
145
|
|
|
147
146
|
/** Builds the handler for one generation surface. */
|
|
148
|
-
|
|
147
|
+
function createGenerationHandler(kind: GenerationKind, deps: GenerationHandlerDeps) {
|
|
149
148
|
return createNativeSurfaceHandler(kind, deps);
|
|
150
149
|
}
|
|
151
150
|
|
|
152
151
|
/** Builds the handler for one routed surface, media or passthrough. */
|
|
153
|
-
|
|
152
|
+
function createNativeSurfaceHandler(
|
|
154
153
|
kind: GenerationKind | PassthroughKind,
|
|
155
154
|
deps: GenerationHandlerDeps,
|
|
156
155
|
) {
|
|
@@ -158,19 +157,14 @@ export function createNativeSurfaceHandler(
|
|
|
158
157
|
return async ({ request }: { request: Request }): Promise<Response> => {
|
|
159
158
|
const state = deps.stateStore.require(request);
|
|
160
159
|
const authorization = state.authorization;
|
|
161
|
-
const
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
400,
|
|
166
|
-
`The ${noun} body must be a JSON object (request {requestId}). Send one with at least a model and a prompt. Check the shape of what you sent — then resend 🪞`,
|
|
167
|
-
);
|
|
168
|
-
}
|
|
169
|
-
const generation = body as Record<string, unknown>;
|
|
160
|
+
const generation = requireRecordBody(
|
|
161
|
+
state,
|
|
162
|
+
`The ${noun} body must be a JSON object (request {requestId}). Send one with at least a model and a prompt. Check the shape of what you sent — then resend 🪞`,
|
|
163
|
+
);
|
|
170
164
|
if (typeof generation.model !== "string" || generation.model.trim().length === 0) {
|
|
171
165
|
throw new GatewayError("invalid_request", 400, `A model is required (request {requestId}): it names the ${noun} provider to use. Check the shape of what you sent — then resend 🪞`);
|
|
172
166
|
}
|
|
173
|
-
if (!authorization
|
|
167
|
+
if (!hasScope(authorization?.snapshot.scopes, "routing:invoke")) {
|
|
174
168
|
throw new GatewayError(
|
|
175
169
|
"policy_rejected",
|
|
176
170
|
403,
|
|
@@ -200,10 +194,15 @@ export function createNativeSurfaceHandler(
|
|
|
200
194
|
const prepared = await deps.proxyPreparer.prepareNativeService({
|
|
201
195
|
model: generation.model,
|
|
202
196
|
serviceKind: kind,
|
|
203
|
-
authorization
|
|
197
|
+
// `requireRecordBody` already refused a missing authorization; this guard
|
|
198
|
+
// exists only to narrow the type for the code below.
|
|
199
|
+
authorization: authorization!,
|
|
204
200
|
...(state.abortController.signal ? { signal: state.abortController.signal } : {}),
|
|
205
201
|
...(state.clientUserAgent === undefined ? {} : { clientUserAgent: state.clientUserAgent }),
|
|
206
202
|
});
|
|
203
|
+
if (!authorization) {
|
|
204
|
+
throw new GatewayError("invalid_request", 400, "authentication required (request {requestId})");
|
|
205
|
+
}
|
|
207
206
|
|
|
208
207
|
return runAttemptLoop<Response, ProviderAdapter>({
|
|
209
208
|
state,
|
|
@@ -221,19 +220,7 @@ export function createNativeSurfaceHandler(
|
|
|
221
220
|
strictPoolSelection: false,
|
|
222
221
|
exhaustedError: new GatewayError("route_unavailable", 503, `no eligible ${noun} generation route (request {requestId}). The bouncer stepped out — come back shortly 🚪`),
|
|
223
222
|
prepare: async (candidate) => {
|
|
224
|
-
const credential = candidate
|
|
225
|
-
? await resolveCredentialForAccount(
|
|
226
|
-
deps.db,
|
|
227
|
-
candidate.provider_id,
|
|
228
|
-
candidate.provider_account_id,
|
|
229
|
-
deps.oauthRefreshService && deps.resolveOAuthRefresher
|
|
230
|
-
? { refreshService: deps.oauthRefreshService, resolveRefresher: deps.resolveOAuthRefresher }
|
|
231
|
-
: undefined,
|
|
232
|
-
)
|
|
233
|
-
: {
|
|
234
|
-
provider_id: candidate.provider_id as ProviderAdapter["provider_id"],
|
|
235
|
-
credential_kind: "none" as const,
|
|
236
|
-
};
|
|
223
|
+
const credential = await resolveAttemptCredential(deps, candidate);
|
|
237
224
|
const adapter = await deps.resolveProviderAdapter?.(candidate.provider_id);
|
|
238
225
|
if (!adapter) {
|
|
239
226
|
throw new GatewayError(
|
|
@@ -309,14 +296,7 @@ export function createNativeSurfaceHandler(
|
|
|
309
296
|
abort_signal: state.abortController.signal,
|
|
310
297
|
request_headers: inboundHeaders,
|
|
311
298
|
...(candidate.user_agent === undefined ? {} : { user_agent: candidate.user_agent }),
|
|
312
|
-
...(deps.
|
|
313
|
-
? {
|
|
314
|
-
outbound_fetch: deps.networkBindingFactory.fetch(
|
|
315
|
-
leases.proxySlot?.poolId,
|
|
316
|
-
authorization.tenantId,
|
|
317
|
-
),
|
|
318
|
-
}
|
|
319
|
-
: {}),
|
|
299
|
+
...networkFetchContext(deps, leases.proxySlot?.poolId, authorization.tenantId),
|
|
320
300
|
};
|
|
321
301
|
// Prefer the provider's own method for this kind; otherwise post the
|
|
322
302
|
// body to the candidate's endpoint through the adapter, which owns the
|
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shared helpers for the native dispatch handlers (web search, token count,
|
|
3
|
+
* System One, responses-compact, generation). The handlers previously spelled
|
|
4
|
+
* the same credential-resolution, outbound-fetch, body-validation, thinking-
|
|
5
|
+
* suffix, response-serialization, and usage-clone blocks by hand, and the
|
|
6
|
+
* copies could drift (generation's `jsonResponse` lost the `cache-control`
|
|
7
|
+
* header). One home here keeps them in step.
|
|
8
|
+
*/
|
|
9
|
+
import { GatewayError } from "../../protocol/gateway-error";
|
|
10
|
+
import type { ProviderId, ResolvedCredential, ValidatedOutboundFetch } from "../../providers/provider-contracts";
|
|
11
|
+
import { resolveCredentialForAccount } from "../../providers/operations/provider-credential-service";
|
|
12
|
+
import { repriceUsage, usageFromProvider } from "../../providers/provider-usage";
|
|
13
|
+
import type { UsageRecord } from "../../protocol/canonical-model";
|
|
14
|
+
import { parseThinkingSuffix } from "../../protocol/translation/thinking";
|
|
15
|
+
import type { GatewayHandlerDeps } from "./handler-deps";
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* Whether a scope list contains the named scope. The native handlers used to
|
|
19
|
+
* force `scopes?.includes(name as never)` — a type-loop hole that bypassed
|
|
20
|
+
* the `AccessScope` union only to compare runtime strings. The check is the
|
|
21
|
+
* same, with a real `readonly string[]` receiver.
|
|
22
|
+
*/
|
|
23
|
+
export function hasScope(scopes: readonly string[] | undefined, name: string): boolean {
|
|
24
|
+
return scopes?.includes(name) === true;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* Resolves the credential for one candidate: a real account credential when
|
|
29
|
+
* the candidate carries an account, otherwise the credential-less `"none"`
|
|
30
|
+
* credential. Shared by every native handler's `prepare`.
|
|
31
|
+
*/
|
|
32
|
+
export async function resolveAttemptCredential(
|
|
33
|
+
deps: Pick<GatewayHandlerDeps, "db" | "oauthRefreshService" | "resolveOAuthRefresher">,
|
|
34
|
+
candidate: { readonly provider_id: string; readonly provider_account_id?: string },
|
|
35
|
+
): Promise<ResolvedCredential> {
|
|
36
|
+
if (!candidate.provider_account_id) {
|
|
37
|
+
return {
|
|
38
|
+
provider_id: candidate.provider_id as ProviderId,
|
|
39
|
+
credential_kind: "none" as const,
|
|
40
|
+
};
|
|
41
|
+
}
|
|
42
|
+
return resolveCredentialForAccount(
|
|
43
|
+
deps.db,
|
|
44
|
+
candidate.provider_id,
|
|
45
|
+
candidate.provider_account_id,
|
|
46
|
+
deps.oauthRefreshService && deps.resolveOAuthRefresher
|
|
47
|
+
? { refreshService: deps.oauthRefreshService, resolveRefresher: deps.resolveOAuthRefresher }
|
|
48
|
+
: undefined,
|
|
49
|
+
);
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
/** The outbound-fetch context fragment native handlers spread into the dispatch context. */
|
|
53
|
+
export function networkFetchContext(
|
|
54
|
+
deps: { readonly networkBindingFactory?: GatewayHandlerDeps["networkBindingFactory"] },
|
|
55
|
+
poolId: string | undefined,
|
|
56
|
+
tenantId: string | null,
|
|
57
|
+
): { outbound_fetch?: ValidatedOutboundFetch } {
|
|
58
|
+
if (!deps.networkBindingFactory) return {};
|
|
59
|
+
return { outbound_fetch: deps.networkBindingFactory.fetch(poolId, tenantId ?? undefined) };
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
/** Serializes a JSON payload with the shared native-response header set. */
|
|
63
|
+
export function jsonResponse(payload: unknown, status: number, requestId: string): Response {
|
|
64
|
+
return new Response(JSON.stringify(payload), {
|
|
65
|
+
status,
|
|
66
|
+
headers: {
|
|
67
|
+
"content-type": "application/json",
|
|
68
|
+
"cache-control": "no-store",
|
|
69
|
+
"x-request-id": requestId,
|
|
70
|
+
},
|
|
71
|
+
});
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
/**
|
|
75
|
+
* Strips a thinking suffix (`model(high)`) from the model name and rebuilds
|
|
76
|
+
* the body with the bare model when it changed. Returns the bare model and
|
|
77
|
+
* the body to forward upstream.
|
|
78
|
+
*/
|
|
79
|
+
export function stripThinkingSuffix(
|
|
80
|
+
model: string,
|
|
81
|
+
body: Record<string, unknown>,
|
|
82
|
+
): { bareModel: string; body: Record<string, unknown> } {
|
|
83
|
+
const { model: bareModel } = parseThinkingSuffix(model);
|
|
84
|
+
return { bareModel, body: bareModel === model ? body : { ...body, model: bareModel } };
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
/**
|
|
88
|
+
* Validates the ingress body is a non-null object and returns it as a record.
|
|
89
|
+
* Throws the standard `invalid_request` with the caller's message (kept
|
|
90
|
+
* per-route so the wire text is unchanged).
|
|
91
|
+
*/
|
|
92
|
+
export function requireRecordBody(
|
|
93
|
+
state: { readonly authorization?: unknown; readonly ingressBody?: unknown },
|
|
94
|
+
message: string,
|
|
95
|
+
): Record<string, unknown> {
|
|
96
|
+
const { authorization, ingressBody } = state;
|
|
97
|
+
if (!authorization || ingressBody === null || typeof ingressBody !== "object" || Array.isArray(ingressBody))
|
|
98
|
+
throw new GatewayError("invalid_request", 400, message);
|
|
99
|
+
return ingressBody as Record<string, unknown>;
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
/**
|
|
103
|
+
* Reads usage from an upstream response clone, repricing the reported value (or
|
|
104
|
+
* the caller's estimate) for the routed provider/model. Shared by the native
|
|
105
|
+
* handlers that proxy an upstream JSON body verbatim.
|
|
106
|
+
*/
|
|
107
|
+
export async function usageFromUpstreamClone(
|
|
108
|
+
response: Response,
|
|
109
|
+
estimate: UsageRecord,
|
|
110
|
+
providerId: string,
|
|
111
|
+
modelId: string,
|
|
112
|
+
): Promise<UsageRecord> {
|
|
113
|
+
let reportedUsage: ReturnType<typeof usageFromProvider>;
|
|
114
|
+
try {
|
|
115
|
+
const parsed: unknown = await response.clone().json();
|
|
116
|
+
reportedUsage = usageFromProvider(
|
|
117
|
+
typeof parsed === "object" && parsed !== null
|
|
118
|
+
? (parsed as Record<string, unknown>)["usage"]
|
|
119
|
+
: undefined,
|
|
120
|
+
);
|
|
121
|
+
} catch {
|
|
122
|
+
reportedUsage = undefined;
|
|
123
|
+
}
|
|
124
|
+
return repriceUsage(reportedUsage ?? estimate, providerId, modelId);
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
|
|
@@ -41,7 +41,7 @@ import type { PreparedProxyRequest } from "../request/preparer";
|
|
|
41
41
|
|
|
42
42
|
import type { GatewayHandlerDeps } from "./handler-deps";
|
|
43
43
|
|
|
44
|
-
|
|
44
|
+
type ProviderProxyHandlerDeps = GatewayHandlerDeps & {
|
|
45
45
|
/** Live lookup of a provider's SSRF-validated upstream host. */
|
|
46
46
|
readonly byokUpstreamHosts?: { readonly get: (providerId: string) => ByokUpstreamHost | undefined };
|
|
47
47
|
};
|
|
@@ -135,6 +135,7 @@ export async function handleProviderProxyRequest(
|
|
|
135
135
|
{
|
|
136
136
|
providerId: candidateForPrompt.provider_id,
|
|
137
137
|
modelId: candidateForPrompt.model_id,
|
|
138
|
+
requestedModel: prepared.plan?.requested_model ?? candidateForPrompt.model_id,
|
|
138
139
|
},
|
|
139
140
|
)?.text
|
|
140
141
|
: undefined;
|
|
@@ -239,6 +240,7 @@ export async function handleProviderProxyRequest(
|
|
|
239
240
|
...(candidate.output_limit == null ? {} : { output_limit: candidate.output_limit }),
|
|
240
241
|
capabilities: candidate.capability_profile,
|
|
241
242
|
user_agent: candidate.user_agent,
|
|
243
|
+
...(candidate.dialect === undefined ? {} : { dialect: candidate.dialect }),
|
|
242
244
|
};
|
|
243
245
|
const candidateRequest =
|
|
244
246
|
candidate.model_id === dispatchRequest.model
|
|
@@ -1,11 +1,15 @@
|
|
|
1
1
|
import { GatewayError } from "../../protocol/gateway-error";
|
|
2
|
-
import { resolveCredentialForAccount } from "../../providers/operations/provider-credential-service";
|
|
3
2
|
import { metrics } from "../../observability/metrics";
|
|
4
|
-
import { parseThinkingSuffix } from "../../protocol/translation/thinking";
|
|
5
3
|
import type { CodexCompactAdapter } from "../../providers/integrations/codex/codex";
|
|
6
4
|
import { completeAttempt, estimatedUsage, nativeCompletionBase } from "./attempt-finalize";
|
|
7
|
-
import { repriceUsage, usageFromProvider } from "../../providers/provider-usage";
|
|
8
5
|
import { runAttemptLoop } from "./attempt-loop";
|
|
6
|
+
import {
|
|
7
|
+
networkFetchContext,
|
|
8
|
+
requireRecordBody,
|
|
9
|
+
resolveAttemptCredential,
|
|
10
|
+
stripThinkingSuffix,
|
|
11
|
+
usageFromUpstreamClone,
|
|
12
|
+
} from "./native-shared";
|
|
9
13
|
|
|
10
14
|
/**
|
|
11
15
|
* The native Codex compaction route (`POST /v1/responses/compact`) and the
|
|
@@ -13,7 +17,7 @@ import { runAttemptLoop } from "./attempt-loop";
|
|
|
13
17
|
*/
|
|
14
18
|
import type { GatewayHandlerDeps } from "./handler-deps";
|
|
15
19
|
|
|
16
|
-
|
|
20
|
+
type ResponsesCompactHandlerDeps = GatewayHandlerDeps;
|
|
17
21
|
|
|
18
22
|
/**
|
|
19
23
|
* Handles `POST /v1/responses/compact`: the native Codex compaction proxy. The
|
|
@@ -25,10 +29,10 @@ export function createResponsesCompactHandler(deps: ResponsesCompactHandlerDeps)
|
|
|
25
29
|
return async ({ request }: { request: Request }): Promise<Response> => {
|
|
26
30
|
const state = deps.stateStore.require(request);
|
|
27
31
|
const authorization = state.authorization;
|
|
28
|
-
const
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
+
const compact = requireRecordBody(
|
|
33
|
+
state,
|
|
34
|
+
"compact request body must be a JSON object (request {requestId}). Check the shape of what you sent — then resend 🪞",
|
|
35
|
+
);
|
|
32
36
|
if (typeof compact.model !== "string" || compact.model.trim().length === 0)
|
|
33
37
|
throw new GatewayError("invalid_request", 400, "model is required (request {requestId}). Check the shape of what you sent — then resend 🪞");
|
|
34
38
|
// A thinking suffix (`model(high)`) is stripped here for the same reason the
|
|
@@ -39,9 +43,7 @@ export function createResponsesCompactHandler(deps: ResponsesCompactHandlerDeps)
|
|
|
39
43
|
// reasoning effort to shape, and the body is passed upstream verbatim.
|
|
40
44
|
// Stripping keeps a client that appends the suffix to every request working
|
|
41
45
|
// here instead of failing with a misleading model-not-found.
|
|
42
|
-
const {
|
|
43
|
-
const compactBody: Record<string, unknown> =
|
|
44
|
-
compactModel === compact.model ? compact : { ...compact, model: compactModel };
|
|
46
|
+
const { bareModel: compactModel, body: compactBody } = stripThinkingSuffix(compact.model, compact);
|
|
45
47
|
if (!(typeof compact.input === "string" || Array.isArray(compact.input)))
|
|
46
48
|
throw new GatewayError("invalid_request", 400, "input must be a string or array (request {requestId}). Check the shape of what you sent — then resend 🪞");
|
|
47
49
|
if ("instructions" in compact && typeof compact.instructions !== "string")
|
|
@@ -57,7 +59,7 @@ export function createResponsesCompactHandler(deps: ResponsesCompactHandlerDeps)
|
|
|
57
59
|
throw new GatewayError("admission_unavailable", 503, "Codex compact transport unavailable (request {requestId}). The bouncer stepped out — come back shortly 🚪");
|
|
58
60
|
const prepared = await deps.proxyPreparer.prepareNativeCompact({
|
|
59
61
|
model: compactModel,
|
|
60
|
-
authorization
|
|
62
|
+
authorization: authorization!,
|
|
61
63
|
signal: state.abortController.signal,
|
|
62
64
|
...(state.clientUserAgent === undefined ? {} : { clientUserAgent: state.clientUserAgent }),
|
|
63
65
|
});
|
|
@@ -88,14 +90,10 @@ export function createResponsesCompactHandler(deps: ResponsesCompactHandlerDeps)
|
|
|
88
90
|
503,
|
|
89
91
|
"Codex compact requires an OAuth account (request {requestId}). Wrong key, right door — check the credential 🔑",
|
|
90
92
|
);
|
|
91
|
-
const credential = await
|
|
92
|
-
|
|
93
|
-
"codex",
|
|
94
|
-
|
|
95
|
-
deps.oauthRefreshService && deps.resolveOAuthRefresher
|
|
96
|
-
? { refreshService: deps.oauthRefreshService, resolveRefresher: deps.resolveOAuthRefresher }
|
|
97
|
-
: undefined,
|
|
98
|
-
);
|
|
93
|
+
const credential = await resolveAttemptCredential(deps, {
|
|
94
|
+
...candidate,
|
|
95
|
+
provider_id: "codex",
|
|
96
|
+
});
|
|
99
97
|
if (credential.credential_kind !== "oauth")
|
|
100
98
|
throw new GatewayError(
|
|
101
99
|
"capability_unsupported",
|
|
@@ -110,36 +108,17 @@ export function createResponsesCompactHandler(deps: ResponsesCompactHandlerDeps)
|
|
|
110
108
|
credential,
|
|
111
109
|
deadline: state.deadlineMs,
|
|
112
110
|
abort_signal: state.abortController.signal,
|
|
113
|
-
...(deps.
|
|
114
|
-
? {
|
|
115
|
-
outbound_fetch: deps.networkBindingFactory.fetch(
|
|
116
|
-
leases.proxySlot?.poolId,
|
|
117
|
-
authorization.tenantId,
|
|
118
|
-
),
|
|
119
|
-
}
|
|
120
|
-
: {}),
|
|
111
|
+
...networkFetchContext(deps, leases.proxySlot?.poolId, authorization!.tenantId),
|
|
121
112
|
});
|
|
122
113
|
// Prefer the usage the compaction endpoint actually reported. The
|
|
123
114
|
// estimate is a fixed 1024+1024 reserve, and compaction is by
|
|
124
115
|
// construction a large-input operation, so charging it unconditionally
|
|
125
|
-
// let real spend run far past the counter. `
|
|
126
|
-
//
|
|
127
|
-
//
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
const parsed: unknown = await response.clone().json();
|
|
132
|
-
reportedUsage = usageFromProvider(
|
|
133
|
-
typeof parsed === "object" && parsed !== null
|
|
134
|
-
? (parsed as Record<string, unknown>)["usage"]
|
|
135
|
-
: undefined,
|
|
136
|
-
);
|
|
137
|
-
} catch {
|
|
138
|
-
reportedUsage = undefined;
|
|
139
|
-
}
|
|
140
|
-
const usage = repriceUsage(
|
|
141
|
-
reportedUsage ??
|
|
142
|
-
estimatedUsage(prepared.estimatedInputTokens, prepared.estimatedOutputTokens),
|
|
116
|
+
// let real spend run far past the counter. `usageFromUpstreamClone`
|
|
117
|
+
// falls back to the estimate when the body reported nothing, and
|
|
118
|
+
// `response.clone()` leaves the body readable for the client.
|
|
119
|
+
const usage = await usageFromUpstreamClone(
|
|
120
|
+
response,
|
|
121
|
+
estimatedUsage(prepared.estimatedInputTokens, prepared.estimatedOutputTokens),
|
|
143
122
|
candidate.provider_id,
|
|
144
123
|
candidate.model_id,
|
|
145
124
|
);
|
|
@@ -12,12 +12,12 @@
|
|
|
12
12
|
import type { CanonicalEvent, SourceSurface, UsageRecord } from "../../../protocol/canonical-model";
|
|
13
13
|
import { canonicalTerminal } from "../../../protocol/codecs";
|
|
14
14
|
import { reasoningTextOf } from "../../../protocol/reasoning-text";
|
|
15
|
-
import {
|
|
15
|
+
import { ThinkSplitter } from "../../../protocol/think-split";
|
|
16
16
|
import { createDispatchStreamEncoder, type DispatchStreamEncoder } from "../stream-bridge";
|
|
17
17
|
import { THINKING_LOOP_MARKER, ThinkingLoopDetector } from "./thinking-loop";
|
|
18
18
|
|
|
19
19
|
/** The terminal event shape every stream settles (or fails to settle) on. */
|
|
20
|
-
|
|
20
|
+
type StreamTerminalEvent = Extract<CanonicalEvent, { type: "terminal" }>;
|
|
21
21
|
|
|
22
22
|
/**
|
|
23
23
|
* SSE comment frame: valid framing on every streamed surface, ignored by
|
|
@@ -46,7 +46,7 @@ interface TruncatedEventTranscript {
|
|
|
46
46
|
}
|
|
47
47
|
|
|
48
48
|
/** Error-frame input in the shape the dispatch stream encoder accepts. */
|
|
49
|
-
|
|
49
|
+
type StreamErrorFrameInput = Parameters<DispatchStreamEncoder["encodeError"]>[0];
|
|
50
50
|
|
|
51
51
|
/**
|
|
52
52
|
* Per-event state and framing for one stream. Client framing and protocol
|
|
@@ -93,10 +93,11 @@ export class StreamEventPipeline {
|
|
|
93
93
|
*/
|
|
94
94
|
private readonly diagnosticsCaptureMode: "none" | "metadata" | "full";
|
|
95
95
|
private readonly streamEncoder: DispatchStreamEncoder;
|
|
96
|
-
// One splitter per stream
|
|
97
|
-
//
|
|
98
|
-
//
|
|
99
|
-
|
|
96
|
+
// One splitter per stream, kept purely as a feeder for the loop guard: it
|
|
97
|
+
// reports the content currently inside an open `<think>` span so a runaway
|
|
98
|
+
// chain-of-thought is caught even when the provider wrote it into the text
|
|
99
|
+
// stream. It never re-routes the emitted events — text is forwarded verbatim.
|
|
100
|
+
private readonly thinkSplitter = new ThinkSplitter();
|
|
100
101
|
/**
|
|
101
102
|
* Content-level loop guard. A model that degenerates into a repeated
|
|
102
103
|
* chain-of-thought keeps sending bytes, so the stall timeout — which fires
|
|
@@ -259,26 +260,17 @@ export class StreamEventPipeline {
|
|
|
259
260
|
// `loopDetected`, so this only matters for an event already in flight;
|
|
260
261
|
// dropping it is the alternative to throwing mid-stream.
|
|
261
262
|
if (this.loopDetector.detected) return false;
|
|
262
|
-
//
|
|
263
|
-
//
|
|
264
|
-
//
|
|
265
|
-
//
|
|
266
|
-
//
|
|
263
|
+
// Text is forwarded verbatim: inline thinking tags are a per-provider
|
|
264
|
+
// decoder concern, not a universal one. Splitting them here for every
|
|
265
|
+
// surface misclassified literal `<think>` in an answer as reasoning — the
|
|
266
|
+
// answer vanished into the thinking pane and the poisoned history stopped
|
|
267
|
+
// follow-up turns. The loop guard still watches reasoning a provider puts
|
|
268
|
+
// inside an open `<think>` span, without reclassifying the answer.
|
|
267
269
|
if (event.type === "content_delta" && event.content.kind === "text") {
|
|
270
|
+
const enqueued = this.enqueueOne(event, controller);
|
|
268
271
|
const split = this.thinkSplitter.push(event.content.text);
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
const reasoningEvent: CanonicalEvent = {
|
|
272
|
-
...event,
|
|
273
|
-
content: { kind: "reasoning", payload: null, summary: split.reasoning },
|
|
274
|
-
};
|
|
275
|
-
enqueued = this.enqueueOne(reasoningEvent, controller) || enqueued;
|
|
276
|
-
if (this.guardReasoning(split.reasoning, controller)) return enqueued;
|
|
277
|
-
}
|
|
278
|
-
if (split.text.length > 0) {
|
|
279
|
-
enqueued =
|
|
280
|
-
this.enqueueOne({ ...event, content: { kind: "text", text: split.text } }, controller) ||
|
|
281
|
-
enqueued;
|
|
272
|
+
if (split.pendingReasoning.length > 0) {
|
|
273
|
+
if (this.guardReasoning(split.pendingReasoning, controller)) return true;
|
|
282
274
|
}
|
|
283
275
|
return enqueued;
|
|
284
276
|
}
|
|
@@ -290,31 +282,8 @@ export class StreamEventPipeline {
|
|
|
290
282
|
this.guardReasoning(reasoningTextOf(event.content) ?? "", controller);
|
|
291
283
|
return enqueued;
|
|
292
284
|
}
|
|
293
|
-
// Text held back for a tag that never completed must be released *before*
|
|
294
|
-
// the terminal: a content event after it is rejected by the surface
|
|
295
|
-
// encoders, and the tail of the answer would be lost instead.
|
|
296
285
|
if (event.type === "terminal") {
|
|
297
|
-
|
|
298
|
-
if (rest.reasoning.length > 0) {
|
|
299
|
-
this.enqueueOne(
|
|
300
|
-
{
|
|
301
|
-
type: "content_delta",
|
|
302
|
-
sequence_number: event.sequence_number,
|
|
303
|
-
content: { kind: "reasoning", payload: null, summary: rest.reasoning },
|
|
304
|
-
},
|
|
305
|
-
controller,
|
|
306
|
-
);
|
|
307
|
-
}
|
|
308
|
-
if (rest.text.length > 0) {
|
|
309
|
-
this.enqueueOne(
|
|
310
|
-
{
|
|
311
|
-
type: "content_delta",
|
|
312
|
-
sequence_number: event.sequence_number,
|
|
313
|
-
content: { kind: "text", text: rest.text },
|
|
314
|
-
},
|
|
315
|
-
controller,
|
|
316
|
-
);
|
|
317
|
-
}
|
|
286
|
+
return this.enqueueOne(event, controller);
|
|
318
287
|
}
|
|
319
288
|
return this.enqueueOne(event, controller);
|
|
320
289
|
}
|
|
@@ -335,29 +304,6 @@ export class StreamEventPipeline {
|
|
|
335
304
|
): boolean {
|
|
336
305
|
const reason = text.length > 0 ? this.loopDetector.push(text) : undefined;
|
|
337
306
|
if (reason === undefined) return false;
|
|
338
|
-
// Flush before the terminal: content after it is rejected by the surface
|
|
339
|
-
// encoders, and the held-back text would be lost.
|
|
340
|
-
const rest = this.thinkSplitter.flush();
|
|
341
|
-
if (rest.reasoning.length > 0) {
|
|
342
|
-
this.enqueueOne(
|
|
343
|
-
{
|
|
344
|
-
type: "content_delta",
|
|
345
|
-
sequence_number: this.lastSequenceNumber + 1,
|
|
346
|
-
content: { kind: "reasoning", payload: null, summary: rest.reasoning },
|
|
347
|
-
},
|
|
348
|
-
controller,
|
|
349
|
-
);
|
|
350
|
-
}
|
|
351
|
-
if (rest.text.length > 0) {
|
|
352
|
-
this.enqueueOne(
|
|
353
|
-
{
|
|
354
|
-
type: "content_delta",
|
|
355
|
-
sequence_number: this.lastSequenceNumber + 1,
|
|
356
|
-
content: { kind: "text", text: rest.text },
|
|
357
|
-
},
|
|
358
|
-
controller,
|
|
359
|
-
);
|
|
360
|
-
}
|
|
361
307
|
this.enqueueOne(
|
|
362
308
|
canonicalTerminal({
|
|
363
309
|
sequenceNumber: this.lastSequenceNumber + 1,
|
|
@@ -39,7 +39,7 @@ import {
|
|
|
39
39
|
import { KEEPALIVE_COMMENT_BYTES, type StreamEventPipeline } from "./encoder";
|
|
40
40
|
|
|
41
41
|
/** Collaborators the stream tail reads from the dispatch handler. */
|
|
42
|
-
|
|
42
|
+
interface StreamFinalizeDeps {
|
|
43
43
|
readonly db: CartethyiaDatabase;
|
|
44
44
|
readonly poolSelector?: NetworkPoolSelector | undefined;
|
|
45
45
|
readonly telemetryBuffer?: TelemetryBatchBuffer | undefined;
|
|
@@ -56,7 +56,7 @@ export interface StreamCandidateIdentity {
|
|
|
56
56
|
}
|
|
57
57
|
|
|
58
58
|
/** What the stream tail needs from the attempt's input. */
|
|
59
|
-
|
|
59
|
+
interface StreamFinalizeInput {
|
|
60
60
|
readonly state: ProxyRequestState;
|
|
61
61
|
readonly deps: StreamFinalizeDeps;
|
|
62
62
|
readonly prepared: PreparedProxyRequest;
|
|
@@ -64,7 +64,7 @@ import { StreamEventPipeline } from "./encoder";
|
|
|
64
64
|
import { StreamFinalizer, type StreamCandidateIdentity } from "./finalize";
|
|
65
65
|
|
|
66
66
|
/** Collaborators the streaming branch reads from the dispatch handler. */
|
|
67
|
-
|
|
67
|
+
interface StreamingDispatchDeps {
|
|
68
68
|
readonly db: CartethyiaDatabase;
|
|
69
69
|
readonly networkBindingFactory?: ValidatedNetworkBindingFactory | undefined;
|
|
70
70
|
readonly poolSelector?: NetworkPoolSelector | undefined;
|
|
@@ -73,7 +73,7 @@ export interface StreamingDispatchDeps {
|
|
|
73
73
|
}
|
|
74
74
|
|
|
75
75
|
/** Everything one streamed attempt needs, all resolved by its caller. */
|
|
76
|
-
|
|
76
|
+
interface StreamingDispatchInput {
|
|
77
77
|
readonly state: ProxyRequestState;
|
|
78
78
|
readonly deps: StreamingDispatchDeps;
|
|
79
79
|
readonly prepared: PreparedProxyRequest;
|
|
@@ -228,7 +228,11 @@ export async function dispatchStreamingAttempt(input: StreamingDispatchInput): P
|
|
|
228
228
|
if (!isWrappedInjectionProvider(candidate.provider_id)) return {};
|
|
229
229
|
const text = resolveTenantSystemPrompt(
|
|
230
230
|
await readTenantSystemPromptsForDispatch(deps.db, prepared.authorization.snapshot.tenant_id),
|
|
231
|
-
{
|
|
231
|
+
{
|
|
232
|
+
providerId: candidate.provider_id,
|
|
233
|
+
modelId: candidate.model_id,
|
|
234
|
+
requestedModel: prepared.plan?.requested_model ?? candidate.model_id,
|
|
235
|
+
},
|
|
232
236
|
)?.text;
|
|
233
237
|
return text === undefined ? {} : { tenantSystemPrompt: text };
|
|
234
238
|
})()),
|
|
@@ -70,7 +70,7 @@ const SEGMENT_MIN_CLUSTER = 4;
|
|
|
70
70
|
* would hide every later prose paragraph from the heuristics. */
|
|
71
71
|
const CODE_LINE = /^(?:[ \t]*```.*|(?: {2,}|\t)(?![ \t]*(?:[-*+]|\d+[.)])[ \t]).*|.*[{}[\](;,>][ \t]*)$/gm;
|
|
72
72
|
|
|
73
|
-
|
|
73
|
+
interface ThinkingLoopConfig {
|
|
74
74
|
readonly enabled?: boolean;
|
|
75
75
|
}
|
|
76
76
|
|