cartethyia 2.7.4 → 2.7.6
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 +5 -0
- package/README.md +18 -6
- package/dist/dashboard/assets/BannedPage-B1N603cM.js +1 -0
- package/dist/dashboard/assets/BannedPage-B1N603cM.js.gz +0 -0
- package/dist/dashboard/assets/CliToolDetailPage-9q4_4NoK.js +3 -0
- package/dist/dashboard/assets/CliToolDetailPage-9q4_4NoK.js.gz +0 -0
- package/dist/dashboard/assets/CliToolsPage-DwshGtK-.js +1 -0
- package/dist/dashboard/assets/CliToolsPage-DwshGtK-.js.gz +0 -0
- package/dist/dashboard/assets/CombosPage-D762MIkp.js +1 -0
- package/dist/dashboard/assets/CombosPage-D762MIkp.js.gz +0 -0
- package/dist/dashboard/assets/ConsoleLogPage-KRYjHZsX.js +1 -0
- package/dist/dashboard/assets/ConsoleLogPage-KRYjHZsX.js.gz +0 -0
- package/dist/dashboard/assets/CustomizationPage-DXsxk5uM.js +1 -0
- package/dist/dashboard/assets/CustomizationPage-DXsxk5uM.js.gz +0 -0
- package/dist/dashboard/assets/HealthEventsModal-BEjAjD4F.js +1 -0
- package/dist/dashboard/assets/HealthEventsModal-BEjAjD4F.js.gz +0 -0
- package/dist/dashboard/assets/InjectSystemPromptPanel-d5v3K_Yc.js +899 -0
- package/dist/dashboard/assets/InjectSystemPromptPanel-d5v3K_Yc.js.gz +0 -0
- package/dist/dashboard/assets/LoginPage-Ccv4tjNS.js +1 -0
- package/dist/dashboard/assets/LoginPage-Ccv4tjNS.js.gz +0 -0
- package/dist/dashboard/assets/{ModelPicker-BMS2t8BA.js → ModelPicker-C6WlpU5E.js} +1 -1
- package/dist/dashboard/assets/ModelPicker-C6WlpU5E.js.gz +0 -0
- package/dist/dashboard/assets/OverviewPage-DN9fYNWA.js +1 -0
- package/dist/dashboard/assets/OverviewPage-DN9fYNWA.js.gz +0 -0
- package/dist/dashboard/assets/ProviderDetailPage-BY0ieUgz.js +5 -0
- package/dist/dashboard/assets/ProviderDetailPage-BY0ieUgz.js.gz +0 -0
- package/dist/dashboard/assets/ProviderIcon-jjqXJDA3.js +1 -0
- package/dist/dashboard/assets/ProviderIcon-jjqXJDA3.js.gz +0 -0
- package/dist/dashboard/assets/ProvidersPage-DNsbfea2.js +1 -0
- package/dist/dashboard/assets/ProvidersPage-DNsbfea2.js.gz +0 -0
- package/dist/dashboard/assets/{ProxyPage-lsrx7NYg.js → ProxyPage-DxjvUzSD.js} +1 -1
- package/dist/dashboard/assets/ProxyPage-DxjvUzSD.js.gz +0 -0
- package/dist/dashboard/assets/QuotaPage-OaHScjpX.js +1 -0
- package/dist/dashboard/assets/QuotaPage-OaHScjpX.js.gz +0 -0
- package/dist/dashboard/assets/SettingsPage-BW4AKj2H.js +1 -0
- package/dist/dashboard/assets/SettingsPage-BW4AKj2H.js.gz +0 -0
- package/dist/dashboard/assets/SetupPage-44BZrxFC.js +1 -0
- package/dist/dashboard/assets/SetupPage-44BZrxFC.js.gz +0 -0
- package/dist/dashboard/assets/{StudioPage-Cq5tW7hW.js → StudioPage-DRPavCdU.js} +4 -4
- package/dist/dashboard/assets/StudioPage-DRPavCdU.js.gz +0 -0
- package/dist/dashboard/assets/ToolIcon-CfeLA-Z_.js +1 -0
- package/dist/dashboard/assets/ToolIcon-CfeLA-Z_.js.gz +0 -0
- package/dist/dashboard/assets/UsagePage-B7M7LvMM.js +56 -0
- package/dist/dashboard/assets/UsagePage-B7M7LvMM.js.gz +0 -0
- package/dist/dashboard/assets/api-keys-KvX83mRe.js +1 -0
- package/dist/dashboard/assets/api-keys-KvX83mRe.js.gz +0 -0
- package/dist/dashboard/assets/app-DRnQLhsc.js +9 -0
- package/dist/dashboard/assets/app-DRnQLhsc.js.gz +0 -0
- package/dist/dashboard/assets/app-mweRcsKp.css +2 -0
- package/dist/dashboard/assets/app-mweRcsKp.css.gz +0 -0
- package/dist/dashboard/assets/assert-CidQVoNo.js +1 -0
- package/dist/dashboard/assets/assert-CidQVoNo.js.gz +0 -0
- package/dist/dashboard/assets/{badge-D9CS6dZk.js → badge-BaX2GTrn.js} +1 -1
- package/dist/dashboard/assets/badge-BaX2GTrn.js.gz +0 -0
- package/dist/dashboard/assets/{banner-DympBNq4.js → banner-DFH4Bkte.js} +1 -1
- package/dist/dashboard/assets/banner-DFH4Bkte.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-CxDw0lK6.js} +1 -1
- package/dist/dashboard/assets/card-CxDw0lK6.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/circle-question-mark-Cz4un8sH.js +1 -0
- package/dist/dashboard/assets/circle-question-mark-Cz4un8sH.js.gz +0 -0
- package/dist/dashboard/assets/cli-tools-Bwv5-zGZ.js +1 -0
- package/dist/dashboard/assets/cli-tools-Bwv5-zGZ.js.gz +0 -0
- package/dist/dashboard/assets/{clipboard-button-DJm-9pz7.js → clipboard-button-DfS1ntiq.js} +1 -1
- package/dist/dashboard/assets/clipboard-button-DfS1ntiq.js.gz +0 -0
- package/dist/dashboard/assets/dialog-BK-NRr5u.js +1 -0
- package/dist/dashboard/assets/dialog-BK-NRr5u.js.gz +0 -0
- package/dist/dashboard/assets/{drawer-CqGYeOrd.js → drawer-QqPul6sC.js} +1 -1
- package/dist/dashboard/assets/drawer-QqPul6sC.js.gz +0 -0
- package/dist/dashboard/assets/entry-BMlYJVFj.js +1 -0
- package/dist/dashboard/assets/entry-BMlYJVFj.js.gz +0 -0
- package/dist/dashboard/assets/entry-D6WvojeD.js +4 -0
- package/dist/dashboard/assets/entry-D6WvojeD.js.gz +0 -0
- package/dist/dashboard/assets/entry-Dmx7gBiN.js +1 -0
- package/dist/dashboard/assets/entry-Dmx7gBiN.js.gz +0 -0
- package/dist/dashboard/assets/{formatters-D-MTJxMr.js → formatters-u7JPB5BX.js} +1 -1
- package/dist/dashboard/assets/formatters-u7JPB5BX.js.gz +0 -0
- package/dist/dashboard/assets/house-h9AZlJuT.js +1 -0
- package/dist/dashboard/assets/house-h9AZlJuT.js.gz +0 -0
- package/dist/dashboard/assets/{index-DBNPOfhV.js → index-Ko4dLRnV.js} +2 -2
- package/dist/dashboard/assets/index-Ko4dLRnV.js.gz +0 -0
- package/dist/dashboard/assets/{inline-BT0zntEr.js → inline-CHJQwxLa.js} +1 -1
- package/dist/dashboard/assets/inline-CHJQwxLa.js.gz +0 -0
- package/dist/dashboard/assets/{input-Da2ZViWg.js → input-BlmlizVV.js} +1 -1
- package/dist/dashboard/assets/input-BlmlizVV.js.gz +0 -0
- package/dist/dashboard/assets/{layout-BXNeLw6M.js → layout-Bz93I-yE.js} +1 -1
- package/dist/dashboard/assets/layout-Bz93I-yE.js.gz +0 -0
- package/dist/dashboard/assets/{list-row-BycOrrIV.js → list-row-Ml16KCfu.js} +1 -1
- package/dist/dashboard/assets/list-row-Ml16KCfu.js.gz +0 -0
- package/dist/dashboard/assets/live-7_QpnYGu.js +1 -0
- package/dist/dashboard/assets/live-7_QpnYGu.js.gz +0 -0
- package/dist/dashboard/assets/{mutation-Rr0TIvcj.js → mutation-GU7XdEjz.js} +1 -1
- package/dist/dashboard/assets/mutation-GU7XdEjz.js.gz +0 -0
- package/dist/dashboard/assets/network-CuMDaTzT.js +1 -0
- package/dist/dashboard/assets/network-CuMDaTzT.js.gz +0 -0
- package/dist/dashboard/assets/numbers-CoqpaDMx.js +2 -0
- package/dist/dashboard/assets/numbers-CoqpaDMx.js.gz +0 -0
- package/dist/dashboard/assets/pagination-B5aOoweZ.js +1 -0
- package/dist/dashboard/assets/pagination-B5aOoweZ.js.gz +0 -0
- package/dist/dashboard/assets/providers/zai.webp +0 -0
- package/dist/dashboard/assets/providers/zcode.webp +0 -0
- package/dist/dashboard/assets/{query-keys-BloKtaXJ.js → query-keys-YSoQOUh6.js} +1 -1
- package/dist/dashboard/assets/{query-keys-BloKtaXJ.js.gz → query-keys-YSoQOUh6.js.gz} +0 -0
- package/dist/dashboard/assets/quota-DJ1QlAOq.js +1 -0
- package/dist/dashboard/assets/quota-DJ1QlAOq.js.gz +0 -0
- package/dist/dashboard/assets/routing-fnCsxgNO.js +1 -0
- package/dist/dashboard/assets/routing-fnCsxgNO.js.gz +0 -0
- package/dist/dashboard/assets/{select-BIYIBkMU.js → select-BHqpd-bg.js} +2 -2
- package/dist/dashboard/assets/select-BHqpd-bg.js.gz +0 -0
- package/dist/dashboard/assets/settings-BxslsErn.js +1 -0
- package/dist/dashboard/assets/settings-BxslsErn.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-j7cXjgYX.js} +1 -1
- package/dist/dashboard/assets/stack-j7cXjgYX.js.gz +0 -0
- package/dist/dashboard/assets/{state-CkfdYWel.js → state-DHmEnLa2.js} +1 -1
- package/dist/dashboard/assets/state-DHmEnLa2.js.gz +0 -0
- package/dist/dashboard/assets/{switch-SYm237HG.js → switch-DmZcyTIC.js} +1 -1
- package/dist/dashboard/assets/switch-DmZcyTIC.js.gz +0 -0
- package/dist/dashboard/assets/{useMutation-BQqCRNIi.js → useMutation-CbCP4w1o.js} +1 -1
- package/dist/dashboard/assets/useMutation-CbCP4w1o.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 +60 -59
- 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/full-postgres/0042_add_telemetry_degenerate_stop.sql +14 -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/migrations/lite-sqlite3/0042_add_telemetry_degenerate_stop.sql +12 -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 +794 -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 +19 -14
- package/src/config/resources.ts +0 -5
- package/src/config/runtime.ts +2 -5
- package/src/config/spec.ts +33 -6
- package/src/config/usage.ts +27 -0
- 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 +56 -24
- 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 +43 -299
- package/src/console/cli-tools/fs-ops.ts +29 -0
- package/src/console/cli-tools/injectors/claude.ts +3 -3
- package/src/console/cli-tools/injectors/codex.ts +181 -181
- package/src/console/cli-tools/injectors/driver.ts +150 -247
- package/src/console/cli-tools/injectors/kilo.ts +146 -21
- package/src/console/cli-tools/injectors/opencode.ts +176 -153
- package/src/console/cli-tools/routes.ts +7 -1
- package/src/console/cli-tools/service.ts +8 -7
- 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 +7 -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 +23 -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 +11 -13
- 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 +9 -2
- package/src/observability/event-query.ts +61 -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 +19 -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 +121 -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 +29 -2
- 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 +8 -125
- 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 +71 -4
- 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 +35 -37
- 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 +88 -28
- package/src/providers/integrations/antigravity/antigravity-quota.ts +18 -6
- package/src/providers/integrations/antigravity/antigravity.ts +22 -13
- 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 +35 -3
- 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 +70 -12
- package/src/providers/integrations/github/github-oauth.ts +184 -14
- package/src/providers/integrations/github/github.ts +134 -26
- 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 +80 -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 +94 -11
- 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 +422 -71
- 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 +51 -8
- 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 +198 -133
- package/src/providers/operations/account-health-service.ts +31 -39
- package/src/providers/operations/account-reset-service.ts +58 -1
- package/src/providers/operations/byok-wire-profile.ts +19 -15
- 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 +50 -19
- 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 +13 -6
- package/src/security/admission/ttl.ts +61 -61
- package/src/security/api-key-auth.ts +17 -3
- 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 +70 -22
- package/src/transport/dispatch/attempt-loop.ts +22 -0
- 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 +21 -1
- package/src/transport/guards/auth-guard.ts +0 -6
- package/src/transport/guards/body-policy.ts +3 -3
- package/src/transport/guards/error-lifecycle.ts +4 -0
- 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 +7 -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 +159 -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/reasoning-summary.ts +9 -14
- 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 +431 -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 +0 -1
- package/dist/dashboard/assets/BannedPage-ChG5svFb.js.gz +0 -0
- package/dist/dashboard/assets/CliToolDetailPage-BIcWQun7.js +0 -1
- package/dist/dashboard/assets/CliToolDetailPage-BIcWQun7.js.gz +0 -0
- package/dist/dashboard/assets/CliToolsPage-Bf2VelDe.js +0 -1
- 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 +0 -1
- 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 +0 -1
- 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 +0 -1
- 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/ToolIcon-K1ckcDKg.js +0 -1
- package/dist/dashboard/assets/ToolIcon-K1ckcDKg.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-BayTTy01.js +0 -9
- package/dist/dashboard/assets/app-BayTTy01.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 +0 -1
- 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 +0 -1
- 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 +0 -1
- 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/mutation-Rr0TIvcj.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/providers/zai-coding-plan.svg +0 -6
- package/dist/dashboard/assets/providers/zai-coding-plan.svg.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/console/cli-tools/injectors/cline.ts +0 -110
- package/src/console/cli-tools/injectors/copilot.ts +0 -108
- package/src/console/cli-tools/injectors/cowork.ts +0 -64
- package/src/console/cli-tools/injectors/deepseek-tui.ts +0 -85
- package/src/console/cli-tools/injectors/droid.ts +0 -96
- package/src/console/cli-tools/injectors/grok-build.ts +0 -70
- package/src/console/cli-tools/injectors/hermes.ts +0 -101
- package/src/console/cli-tools/injectors/jcode.ts +0 -115
- package/src/console/cli-tools/injectors/openclaw.ts +0 -161
- 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/brand/{og_bansos.webp → og_bansos_initial.webp} +0 -0
- /package/dist/dashboard/assets/brand/{og_image.webp → og_image_initial.webp} +0 -0
|
@@ -32,7 +32,7 @@ export interface ParamQuirk {
|
|
|
32
32
|
}
|
|
33
33
|
|
|
34
34
|
/** Per-wire output-token policy, in one table instead of per-builder branches. */
|
|
35
|
-
|
|
35
|
+
interface WireTokenBound {
|
|
36
36
|
/** Default when the caller sent no limit (undefined = leave absent). */
|
|
37
37
|
readonly defaultMaxTokens?: number;
|
|
38
38
|
/** Floor applied to any positive caller value below it (wire minimum). */
|
|
@@ -66,6 +66,13 @@ const DEFAULT_OUTPUT_TOKENS = 32_000;
|
|
|
66
66
|
* Output-token bounds per wire family. Chat has no global ceiling: a model's
|
|
67
67
|
* catalog output limit is the ceiling, and an unknown model passes the
|
|
68
68
|
* caller's value through. Messages keeps its Anthropic floors and OAuth cap.
|
|
69
|
+
*
|
|
70
|
+
* The ceiling only ever comes from `options.maxOutputTokens` (the model's
|
|
71
|
+
* catalog output limit, supplied by the compatible adapter from
|
|
72
|
+
* `candidate.output_limit`). When it is omitted there is nothing to clamp to,
|
|
73
|
+
* which is intentional pass-through: a direct codec caller without a catalog
|
|
74
|
+
* limit is unbounded, and an unknown model passes the caller's value through by
|
|
75
|
+
* design — the bound table supplies floors/defaults, never an invented ceiling.
|
|
69
76
|
*/
|
|
70
77
|
export const WIRE_TOKEN_BOUNDS: Readonly<Record<string, WireTokenBound>> = {
|
|
71
78
|
chat: { minTokens: 16, defaultMaxTokens: DEFAULT_OUTPUT_TOKENS },
|
|
@@ -73,7 +80,14 @@ export const WIRE_TOKEN_BOUNDS: Readonly<Record<string, WireTokenBound>> = {
|
|
|
73
80
|
responses: { minTokens: 16, defaultMaxTokens: DEFAULT_OUTPUT_TOKENS },
|
|
74
81
|
};
|
|
75
82
|
|
|
76
|
-
/**
|
|
83
|
+
/**
|
|
84
|
+
* Resolves the output-token value for one wire from caller controls.
|
|
85
|
+
*
|
|
86
|
+
* Clamping to a ceiling happens only when `options.maxOutputTokens` (the
|
|
87
|
+
* model's catalog limit) is present. An omitted `maxOutputTokens` means
|
|
88
|
+
* pass-through by design: a direct codec caller without a catalog limit is
|
|
89
|
+
* unbounded, and this function never fabricates a ceiling on its own.
|
|
90
|
+
*/
|
|
77
91
|
export function resolveWireMaxTokens(
|
|
78
92
|
wire: string,
|
|
79
93
|
controls: { max_tokens?: number | undefined },
|
|
@@ -120,7 +134,7 @@ function modelGeneration(modelId: string): { family: string; major: number; mino
|
|
|
120
134
|
}
|
|
121
135
|
|
|
122
136
|
/** True when the model rejects `temperature`/`top_p`/`top_k` at any thinking setting. */
|
|
123
|
-
|
|
137
|
+
function rejectsSamplingParams(modelId: string): boolean {
|
|
124
138
|
const generation = modelGeneration(modelId);
|
|
125
139
|
if (generation === undefined) return false;
|
|
126
140
|
// Opus turns strict at 4.7; the other families at 5.0.
|
|
@@ -157,7 +171,7 @@ const PARAM_QUIRKS: readonly ParamQuirk[] = [
|
|
|
157
171
|
];
|
|
158
172
|
|
|
159
173
|
/** Finds the first quirk matching the provider/model pair, or undefined. */
|
|
160
|
-
|
|
174
|
+
function findParamQuirk(
|
|
161
175
|
providerId: string,
|
|
162
176
|
modelId: string,
|
|
163
177
|
): ParamQuirk | undefined {
|
|
@@ -5,7 +5,9 @@
|
|
|
5
5
|
// so the native config (`thinking_type` + `budget_tokens`) is dropped while the
|
|
6
6
|
// request-level effort intent (OpenAI `reasoning_effort`) survives — that field
|
|
7
7
|
// is a property of the request, not of the turn.
|
|
8
|
-
import type { CanonicalRequest, ReasoningIntent
|
|
8
|
+
import type { CanonicalRequest, ReasoningIntent } from "../canonical-model";
|
|
9
|
+
import type { ThinkingConfig } from "./dialect/thinking-ladder";
|
|
10
|
+
import { clampThinkingLevelForModel } from "./dialect/model-thinking";
|
|
9
11
|
|
|
10
12
|
/**
|
|
11
13
|
* Canonical reasoning effort ladder, ordered least to most intensive.
|
|
@@ -41,7 +43,7 @@ export type ThinkingSuffixIntent =
|
|
|
41
43
|
* A parsed model name: the bare id the router and upstream must see, plus the
|
|
42
44
|
* thinking level the caller asked for (or null when they asked for none).
|
|
43
45
|
*/
|
|
44
|
-
|
|
46
|
+
interface ParsedThinkingSuffix {
|
|
45
47
|
readonly model: string;
|
|
46
48
|
readonly intent: ThinkingSuffixIntent | null;
|
|
47
49
|
}
|
|
@@ -200,248 +202,11 @@ export function withThinkingSuffixIntent(
|
|
|
200
202
|
}
|
|
201
203
|
|
|
202
204
|
/** Standard OpenAI Responses wire supported efforts (OpenAI, OpenCode, Azure). Responses API has no 'max' tier. */
|
|
203
|
-
export const RESPONSES_WIRE_SUPPORTED_EFFORTS: readonly ReasoningEffortLevel[] = [
|
|
204
|
-
"minimal",
|
|
205
|
-
"low",
|
|
206
|
-
"medium",
|
|
207
|
-
"high",
|
|
208
|
-
"xhigh",
|
|
209
|
-
];
|
|
210
|
-
|
|
211
|
-
/** Full 6-tier effort scale for models that support 'max' (Claude, MiMo, Kimi, DeepSeek). */
|
|
212
|
-
export const EXTENDED_SUPPORTED_EFFORTS: readonly ReasoningEffortLevel[] = [
|
|
213
|
-
"minimal",
|
|
214
|
-
"low",
|
|
215
|
-
"medium",
|
|
216
|
-
"high",
|
|
217
|
-
"xhigh",
|
|
218
|
-
"max",
|
|
219
|
-
];
|
|
220
|
-
|
|
221
|
-
/** Standard 4-tier effort scale (Gemini, Qwen). */
|
|
222
|
-
export const BASE_SUPPORTED_EFFORTS: readonly ReasoningEffortLevel[] = [
|
|
223
|
-
"minimal",
|
|
224
|
-
"low",
|
|
225
|
-
"medium",
|
|
226
|
-
"high",
|
|
227
|
-
];
|
|
228
|
-
|
|
229
|
-
/**
|
|
230
|
-
* The `mimo-v2.6` family rejects every effort outside this set.
|
|
231
|
-
*
|
|
232
|
-
* Verified live against OpenCode's `/zen/v1` on 2026-09-22: `minimal`, `xhigh`,
|
|
233
|
-
* and `max` each answer `500 {"type":"error","error":{"message":"Internal server
|
|
234
|
-
* error"}}` — an opaque failure that names nothing, so the caller sees a dead
|
|
235
|
-
* request rather than a bad parameter — while `low`/`medium`/`high` and an
|
|
236
|
-
* omitted field answer `200`. Its siblings on the very same endpoint
|
|
237
|
-
* (`mimo-v2.5-free`, `nemotron-3-ultra-free`, `big-pickle`) accept the full
|
|
238
|
-
* ladder, so this is a property of the model rather than of the route.
|
|
239
|
-
*
|
|
240
|
-
* Narrowing is the safe direction: every level here is accepted by all hosts of
|
|
241
|
-
* the id, so the worst case for a host that would also take `xhigh` is that the
|
|
242
|
-
* request runs one tier below what the caller asked for instead of failing.
|
|
243
|
-
*/
|
|
244
|
-
const MIMO_V26_SUPPORTED_EFFORTS: readonly ReasoningEffortLevel[] = ["low", "medium", "high"];
|
|
245
|
-
|
|
246
|
-
/**
|
|
247
|
-
* Mercury (Inception Labs) — the chat ladder is `{instant, low, medium,
|
|
248
|
-
* high}`: `minimal`, `xhigh`, and `max` each answer a 400
|
|
249
|
-
* `reasoning_effort must be one of: 'instant', 'low', 'medium', 'high'`.
|
|
250
|
-
* `instant` is not on the canonical ladder, so it can only appear here; the
|
|
251
|
-
* clamp steps down to `high` for any higher request.
|
|
252
|
-
*/
|
|
253
|
-
const INCEPTION_SUPPORTED_EFFORTS: readonly ReasoningEffortLevel[] = [
|
|
254
|
-
"instant",
|
|
255
|
-
"low",
|
|
256
|
-
"medium",
|
|
257
|
-
"high",
|
|
258
|
-
];
|
|
259
205
|
|
|
260
|
-
/**
|
|
261
|
-
* `low..max`: the OpenAI 5.6/6/daybreak generation and the new-gen Claude
|
|
262
|
-
* adaptive models (`fable`/`mythos`/`opus-5`/`sonnet-5`/`opus-4-7`/`opus-4-8`)
|
|
263
|
-
* all serve `max`, and none of them advertises `minimal`.
|
|
264
|
-
*/
|
|
265
|
-
const LOW_TO_MAX_SUPPORTED_EFFORTS: readonly ReasoningEffortLevel[] = [
|
|
266
|
-
"low",
|
|
267
|
-
"medium",
|
|
268
|
-
"high",
|
|
269
|
-
"xhigh",
|
|
270
|
-
"max",
|
|
271
|
-
];
|
|
272
|
-
|
|
273
|
-
/** `gpt-5.5` rows: neither `minimal` nor `max`. */
|
|
274
|
-
const GPT55_SUPPORTED_EFFORTS: readonly ReasoningEffortLevel[] = [
|
|
275
|
-
"low",
|
|
276
|
-
"medium",
|
|
277
|
-
"high",
|
|
278
|
-
"xhigh",
|
|
279
|
-
];
|
|
280
|
-
|
|
281
|
-
/** Claude adaptive 4.6 pair: `low..high`, no `xhigh`/`max`. */
|
|
282
|
-
const CLAUDE_ADAPTIVE_46_SUPPORTED_EFFORTS: readonly ReasoningEffortLevel[] = [
|
|
283
|
-
"low",
|
|
284
|
-
"medium",
|
|
285
|
-
"high",
|
|
286
|
-
];
|
|
287
|
-
|
|
288
|
-
/**
|
|
289
|
-
* Resolves the valid reasoning effort levels for a given model and wire family.
|
|
290
|
-
*
|
|
291
|
-
* Priority order:
|
|
292
|
-
* 1. Explicit model-declared `reasoningEfforts` from the catalog.
|
|
293
|
-
* 2. Wire family constraint: the Responses wire API (`/v1/responses`) does not
|
|
294
|
-
* support 'max' (capped at 'xhigh') unless the model's published ladder
|
|
295
|
-
* includes it.
|
|
296
|
-
* 3. Model family heuristics, matching each family's published ladder:
|
|
297
|
-
* - Muse Spark (Meta on OpenCode / Fireworks): `["minimal", "low", "medium", "high", "xhigh"]`
|
|
298
|
-
* - Gemini: `["minimal", "low", "medium", "high"]`
|
|
299
|
-
* - Claude: per-generation — 4.6 adaptive stops at `high`, budget-era 4.5/4.1
|
|
300
|
-
* tops out at `xhigh`, new-gen adaptive is `low..max`.
|
|
301
|
-
* - DeepSeek, Kimi, MiMo: full extended ladder including 'max'
|
|
302
|
-
* - Default: extended ladder.
|
|
303
|
-
*/
|
|
304
|
-
export function resolveSupportedReasoningEfforts(
|
|
305
|
-
modelId?: string,
|
|
306
|
-
wireFamily?: WireFamily,
|
|
307
|
-
declaredEfforts?: readonly string[],
|
|
308
|
-
): readonly ReasoningEffortLevel[] {
|
|
309
|
-
if (declaredEfforts !== undefined && declaredEfforts.length > 0) {
|
|
310
|
-
const filtered = declaredEfforts.filter((e): e is ReasoningEffortLevel =>
|
|
311
|
-
REASONING_EFFORT_LADDER.includes(e as ReasoningEffortLevel),
|
|
312
|
-
);
|
|
313
|
-
if (filtered.length > 0) return filtered;
|
|
314
|
-
}
|
|
315
|
-
|
|
316
|
-
const id = (modelId ?? "").toLowerCase();
|
|
317
|
-
|
|
318
|
-
if (wireFamily === "responses") {
|
|
319
|
-
// Catalog ladders for the ChatGPT/OpenAI generations: `gpt-5.5`
|
|
320
|
-
// is the one row that stops at `xhigh`.
|
|
321
|
-
if (id.includes("gpt-5.5")) return GPT55_SUPPORTED_EFFORTS;
|
|
322
|
-
if (id.includes("gpt-5.6") || id.includes("gpt-6") || id.includes("daybreak")) {
|
|
323
|
-
return LOW_TO_MAX_SUPPORTED_EFFORTS;
|
|
324
|
-
}
|
|
325
|
-
return RESPONSES_WIRE_SUPPORTED_EFFORTS;
|
|
326
|
-
}
|
|
327
|
-
|
|
328
|
-
if (id.includes("muse")) {
|
|
329
|
-
return RESPONSES_WIRE_SUPPORTED_EFFORTS;
|
|
330
|
-
}
|
|
331
|
-
if (id.includes("gemini")) {
|
|
332
|
-
return BASE_SUPPORTED_EFFORTS;
|
|
333
|
-
}
|
|
334
|
-
// Checked before the generic default, which would hand this family `xhigh`
|
|
335
|
-
// and `max` — both of which it answers with an opaque 500.
|
|
336
|
-
if (id.includes("mimo-v2.6")) {
|
|
337
|
-
return MIMO_V26_SUPPORTED_EFFORTS;
|
|
338
|
-
}
|
|
339
|
-
// Checked before the generic default: Mercury's chat endpoint answers every
|
|
340
|
-
// effort outside {instant, low, medium, high} with a 400 that names the
|
|
341
|
-
// field (recorded live from request 40b60777).
|
|
342
|
-
if (id.includes("mercury") && wireFamily === "chat") {
|
|
343
|
-
return INCEPTION_SUPPORTED_EFFORTS;
|
|
344
|
-
}
|
|
345
|
-
// Claude catalog ladders: `output_config.effort` rides the
|
|
346
|
-
// Messages wire, so an out-of-ladder tier is an upstream rejection risk.
|
|
347
|
-
// Dot-tolerant (`cb/claude-opus-4.6`) because gateway-prefixed ids keep the
|
|
348
|
-
// upstream separator.
|
|
349
|
-
if (id.includes("claude")) {
|
|
350
|
-
const claudeId = id.replaceAll(".", "-");
|
|
351
|
-
if (claudeId.includes("opus-4-6") || claudeId.includes("sonnet-4-6")) {
|
|
352
|
-
return CLAUDE_ADAPTIVE_46_SUPPORTED_EFFORTS;
|
|
353
|
-
}
|
|
354
|
-
if (
|
|
355
|
-
claudeId.includes("fable") ||
|
|
356
|
-
claudeId.includes("mythos") ||
|
|
357
|
-
claudeId.includes("opus-5") ||
|
|
358
|
-
claudeId.includes("sonnet-5") ||
|
|
359
|
-
claudeId.includes("opus-4-7") ||
|
|
360
|
-
claudeId.includes("opus-4-8")
|
|
361
|
-
) {
|
|
362
|
-
return LOW_TO_MAX_SUPPORTED_EFFORTS;
|
|
363
|
-
}
|
|
364
|
-
if (
|
|
365
|
-
claudeId.includes("opus-4-5") ||
|
|
366
|
-
claudeId.includes("sonnet-4-5") ||
|
|
367
|
-
claudeId.includes("haiku-4-5") ||
|
|
368
|
-
claudeId.includes("opus-4-1") ||
|
|
369
|
-
claudeId.includes("opus-4-0") ||
|
|
370
|
-
claudeId.includes("sonnet-4-0")
|
|
371
|
-
) {
|
|
372
|
-
// Budget-mode rows: `minimal..xhigh`, no `max` — same shape as the
|
|
373
|
-
// responses-wire default.
|
|
374
|
-
return RESPONSES_WIRE_SUPPORTED_EFFORTS;
|
|
375
|
-
}
|
|
376
|
-
}
|
|
377
|
-
|
|
378
|
-
return EXTENDED_SUPPORTED_EFFORTS;
|
|
379
|
-
}
|
|
380
|
-
|
|
381
|
-
/**
|
|
382
|
-
* Whether a Claude model wants *adaptive* thinking (`thinking.type: "adaptive"`
|
|
383
|
-
* + `output_config.effort`) or *budget* thinking (`thinking.type: "enabled"` +
|
|
384
|
-
* `budget_tokens`).
|
|
385
|
-
*
|
|
386
|
-
* The two generations reject each other's shape: an adaptive-era model answers
|
|
387
|
-
* a budget block with `thinking.budget_tokens: Extra inputs are not permitted`,
|
|
388
|
-
* and a budget-era model answers an adaptive block with `adaptive thinking is
|
|
389
|
-
* not supported on this model` (verified live against the Anthropic OAuth
|
|
390
|
-
* route — opus-4-5/sonnet-4-5/haiku-4-5 400 on adaptive, while
|
|
391
|
-
* opus-4-6+/sonnet-4-6+/5-series accept it).
|
|
392
|
-
*
|
|
393
|
-
* Adaptive era, per the reference catalog: Opus 4.6+, Sonnet 4.6+, and the
|
|
394
|
-
* 5-series (fable/mythos/opus-5/sonnet-5). Everything older is budget era.
|
|
395
|
-
* The rule is stated once here so the Messages codec and the effort ladder
|
|
396
|
-
* cannot disagree about which generation a model belongs to.
|
|
397
|
-
*/
|
|
398
|
-
export function claudeUsesAdaptiveThinking(modelId: string): boolean {
|
|
399
|
-
const id = modelId.toLowerCase().replaceAll(".", "-");
|
|
400
|
-
if (id.includes("fable") || id.includes("mythos")) return true;
|
|
401
|
-
if (id.includes("opus-5") || id.includes("sonnet-5")) return true;
|
|
402
|
-
if (id.includes("opus-4-6") || id.includes("sonnet-4-6")) return true;
|
|
403
|
-
if (id.includes("opus-4-7") || id.includes("opus-4-8")) return true;
|
|
404
|
-
return false;
|
|
405
|
-
}
|
|
406
|
-
|
|
407
|
-
/**
|
|
408
|
-
* Clamps a requested reasoning effort against a target model/wire's supported ladder.
|
|
409
|
-
*
|
|
410
|
-
* If the requested effort is not in the supported list, it gracefully steps down to the
|
|
411
|
-
* highest supported level that is less than or equal to the requested index in the canonical ladder.
|
|
412
|
-
* Synonyms are normalized: 'ultra' -> 'max', 'off' -> 'none'.
|
|
413
|
-
* Returns undefined for 'none' / unrequested.
|
|
414
|
-
*/
|
|
415
|
-
export function clampReasoningEffort(
|
|
416
|
-
requested: string | undefined,
|
|
417
|
-
supported: readonly ReasoningEffortLevel[],
|
|
418
|
-
): ReasoningEffortLevel | undefined {
|
|
419
|
-
if (!requested || typeof requested !== "string") return undefined;
|
|
420
|
-
const raw = requested.toLowerCase().trim();
|
|
421
|
-
const normalized = raw === "ultra" ? "max" : raw === "off" ? "none" : raw;
|
|
422
|
-
if (normalized === "none") return undefined;
|
|
423
|
-
|
|
424
|
-
const reqLevel = normalized as ReasoningEffortLevel;
|
|
425
|
-
// Don't clamp if provider declares it supports the level but we haven't updated constants yet.
|
|
426
|
-
// Fall through to direct return for any ladder member the caller asked for.
|
|
427
|
-
if (supported.includes(reqLevel)) return reqLevel;
|
|
428
|
-
// Unknown string → drop, don't invent a fallback.
|
|
429
|
-
const requestedIndex = REASONING_EFFORT_LADDER.indexOf(reqLevel);
|
|
430
|
-
if (requestedIndex === -1) return undefined;
|
|
431
|
-
|
|
432
|
-
let clamped: ReasoningEffortLevel | undefined;
|
|
433
|
-
for (const level of supported) {
|
|
434
|
-
if (REASONING_EFFORT_LADDER.indexOf(level) > requestedIndex) break;
|
|
435
|
-
clamped = level;
|
|
436
|
-
}
|
|
437
|
-
// No smaller supported level exists (caller asked below floor): use floor rather than max.
|
|
438
|
-
return clamped ?? supported[0];
|
|
439
|
-
}
|
|
440
206
|
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
readonly
|
|
444
|
-
readonly supportedEfforts?: readonly string[];
|
|
207
|
+
interface ThinkingNormalizationOptions {
|
|
208
|
+
/** Resolved thinking config (from `resolveThinkingForModel`). Absent = no clamp. */
|
|
209
|
+
readonly thinking?: ThinkingConfig;
|
|
445
210
|
}
|
|
446
211
|
|
|
447
212
|
/**
|
|
@@ -459,7 +224,7 @@ function isLastMessageFromUser(request: CanonicalRequest): boolean {
|
|
|
459
224
|
* `thinking` config is also present, so a config drop must never leave them
|
|
460
225
|
* orphaned.
|
|
461
226
|
*/
|
|
462
|
-
|
|
227
|
+
function hasReplayedThinkingBlocks(request: CanonicalRequest): boolean {
|
|
463
228
|
for (const message of request.messages) {
|
|
464
229
|
for (const part of message.content) {
|
|
465
230
|
if (part.kind !== "reasoning") continue;
|
|
@@ -504,15 +269,10 @@ export function normalizeThinkingConfig(
|
|
|
504
269
|
}
|
|
505
270
|
}
|
|
506
271
|
|
|
507
|
-
// Only clamp when caller actually set an effort AND
|
|
508
|
-
//
|
|
509
|
-
if (reasoning?.effort !== undefined && options?.
|
|
510
|
-
const
|
|
511
|
-
options?.modelId ?? request.model,
|
|
512
|
-
options?.wireFamily,
|
|
513
|
-
options?.supportedEfforts,
|
|
514
|
-
);
|
|
515
|
-
const clamped = clampReasoningEffort(reasoning.effort, supported);
|
|
272
|
+
// Only clamp when caller actually set an effort AND a thinking config is
|
|
273
|
+
// resolved (ladder known). Without one, don't invent a clamp — pass through.
|
|
274
|
+
if (reasoning?.effort !== undefined && options?.thinking !== undefined) {
|
|
275
|
+
const clamped = clampThinkingLevelForModel(options.thinking, reasoning.effort);
|
|
516
276
|
if (clamped !== reasoning.effort) {
|
|
517
277
|
reasoning = { ...reasoning };
|
|
518
278
|
if (clamped === undefined) delete reasoning.effort;
|
|
@@ -9,7 +9,7 @@
|
|
|
9
9
|
import type { CanonicalRequest } from "../canonical-model";
|
|
10
10
|
|
|
11
11
|
/** Anthropic tool ID contract: alphanumerics, underscore, hyphen only. */
|
|
12
|
-
|
|
12
|
+
const TOOL_ID_PATTERN: RegExp = /^[a-zA-Z0-9_-]+$/;
|
|
13
13
|
|
|
14
14
|
const INVALID_TOOL_ID_CHARS = /[^a-zA-Z0-9_-]/g;
|
|
15
15
|
|
|
@@ -21,7 +21,7 @@ const INVALID_TOOL_ID_CHARS = /[^a-zA-Z0-9_-]/g;
|
|
|
21
21
|
* input is not a non-empty string or nothing valid remains, so callers can
|
|
22
22
|
* fall back to a deterministic generated ID.
|
|
23
23
|
*/
|
|
24
|
-
|
|
24
|
+
function sanitizeToolId(id: unknown): string | null {
|
|
25
25
|
if (typeof id !== "string" || id.length === 0) return null;
|
|
26
26
|
const base = id.includes("|") ? (id.split("|")[0] ?? id) : id;
|
|
27
27
|
const sanitized = base.replace(INVALID_TOOL_ID_CHARS, "");
|
|
@@ -33,7 +33,7 @@ export function sanitizeToolId(id: unknown): string | null {
|
|
|
33
33
|
* identical histories produce byte-identical requests — cache-friendly and
|
|
34
34
|
* directly testable.
|
|
35
35
|
*/
|
|
36
|
-
|
|
36
|
+
function generateToolCallId(msgIndex = 0, tcIndex = 0, toolName?: string): string {
|
|
37
37
|
const name = toolName ? `_${toolName.replace(INVALID_TOOL_ID_CHARS, "")}` : "";
|
|
38
38
|
return `call_msg${msgIndex}_tc${tcIndex}${name}`;
|
|
39
39
|
}
|
|
@@ -211,7 +211,7 @@ function toolCallIdsIn(message: CanonicalMessage): string[] {
|
|
|
211
211
|
* and is repaired by synthesizing a result (`repairMissingToolResponses`), not
|
|
212
212
|
* by deleting the call — the model should see that the tool was interrupted.
|
|
213
213
|
*/
|
|
214
|
-
|
|
214
|
+
function dropOrphanToolResults(
|
|
215
215
|
messages: readonly CanonicalMessage[],
|
|
216
216
|
): CanonicalMessage[] {
|
|
217
217
|
const callIds = new Set<string>();
|
|
@@ -1,6 +1,10 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Shared upstream JSON executor for [OpenAI]-compatible adapters: POSTs a payload
|
|
3
3
|
* with deadline/abort wiring and returns the response plus a release hook.
|
|
4
|
+
*
|
|
5
|
+
* `bodyEncoder` lets a provider send the same body with non-JSON encoding
|
|
6
|
+
* (e.g. zstd, which the Grok Build CLI does). When omitted, the JSON string is
|
|
7
|
+
* sent as-is.
|
|
4
8
|
*/
|
|
5
9
|
import type { ProviderDispatchContext, ValidatedOutboundFetch } from "../../providers/provider-contracts";
|
|
6
10
|
import { abortGatewayError, createUpstreamDeadlineLifecycle } from "../../providers/operations/upstream-deadline";
|
|
@@ -11,13 +15,14 @@ export async function postUpstreamJson(
|
|
|
11
15
|
payload: Record<string, unknown>,
|
|
12
16
|
context: ProviderDispatchContext,
|
|
13
17
|
outboundFetch: ValidatedOutboundFetch,
|
|
18
|
+
bodyEncoder?: (payload: Record<string, unknown>) => string | Uint8Array<ArrayBuffer>,
|
|
14
19
|
): Promise<{ res: Response; signal: AbortSignal; release: () => void }> {
|
|
15
20
|
const lifecycle = createUpstreamDeadlineLifecycle(context);
|
|
16
21
|
try {
|
|
17
22
|
const res = await outboundFetch(fetchUrl, {
|
|
18
23
|
method: "POST",
|
|
19
24
|
headers,
|
|
20
|
-
body: JSON.stringify(payload),
|
|
25
|
+
body: bodyEncoder ? bodyEncoder(payload) : JSON.stringify(payload),
|
|
21
26
|
signal: lifecycle.signal,
|
|
22
27
|
});
|
|
23
28
|
return {
|
|
@@ -13,6 +13,9 @@ import {
|
|
|
13
13
|
import { applyRouteUserAgent, type ProviderDispatchTarget, type ProviderId, type ProviderDispatchContext } from "../provider-contracts";
|
|
14
14
|
import { BaseProviderAdapter } from "./base-adapter";
|
|
15
15
|
import { encodeWireRequest, decodeWireResponse, decodeWireStream } from "../../protocol/registry";
|
|
16
|
+
import { resolveDialect } from "../../protocol/translation/dialect/resolver";
|
|
17
|
+
import { resolveThinkingForModel } from "../../protocol/translation/dialect/thinking-ladder";
|
|
18
|
+
import type { DialectPolicy } from "../../protocol/translation/dialect/types";
|
|
16
19
|
import { postUpstreamJson } from "../../protocol/upstream/post-json";
|
|
17
20
|
import { GATEWAY_USER_AGENT } from "../operations/gateway-user-agent";
|
|
18
21
|
import { resolvePromptCacheKey } from "../operations/session-resolution";
|
|
@@ -25,6 +28,19 @@ import {
|
|
|
25
28
|
} from "../../protocol/codecs";
|
|
26
29
|
const TEXT_DECODER = new TextDecoder("utf-8", { fatal: false });
|
|
27
30
|
|
|
31
|
+
/**
|
|
32
|
+
* Provider ids that understand the OpenAI-style `service_tier` control. Only
|
|
33
|
+
* these upstreams accept the field; every other OpenAI-compatible provider
|
|
34
|
+
* either ignores it or rejects the whole request with `unsupported_value`
|
|
35
|
+
* (measured: GitHub Copilot returns 400). `service_tier` is advisory on the
|
|
36
|
+
* providers that do support it, so dropping it elsewhere is lossless.
|
|
37
|
+
*/
|
|
38
|
+
const SERVICE_TIER_SUPPORTED_PROVIDERS: ReadonlySet<string> = new Set([
|
|
39
|
+
"openai",
|
|
40
|
+
"codex",
|
|
41
|
+
"anthropic",
|
|
42
|
+
]);
|
|
43
|
+
|
|
28
44
|
/**
|
|
29
45
|
* The subset of a canonical request a native-service header hook may read.
|
|
30
46
|
*
|
|
@@ -89,6 +105,14 @@ export interface OpenAICompatibleAdapterConfig {
|
|
|
89
105
|
* this is the enforcement boundary, not account-creation validation.
|
|
90
106
|
*/
|
|
91
107
|
readonly credential_forwarding?: "account" | "never";
|
|
108
|
+
/**
|
|
109
|
+
* Body encoding for the upstream POST. `"json"` (default) sends the plain
|
|
110
|
+
* JSON string. `"zstd"` compresses the JSON with `Bun.zstdCompressSync` and
|
|
111
|
+
* stamps `Content-Encoding: zstd` — the Grok Build CLI does this via its
|
|
112
|
+
* sampler (`request_compression.rs`), and the proxy accepts it (verified
|
|
113
|
+
* live 2026-11-02). Falls back to plain JSON if the runtime lacks zstd.
|
|
114
|
+
*/
|
|
115
|
+
readonly request_compression?: "json" | "zstd";
|
|
92
116
|
/**
|
|
93
117
|
* Stamps `user-agent: Cartethyia/<version>` on every dispatch. Explicit
|
|
94
118
|
* opt-in per provider spec — never a default — so first-party cloaking
|
|
@@ -188,6 +212,10 @@ export class OpenAICompatibleAdapter extends BaseProviderAdapter {
|
|
|
188
212
|
// serving the stale pinned fallback on the first dispatch.
|
|
189
213
|
Object.assign(headers, await this.config.buildExtraHeaders(context, request, candidate));
|
|
190
214
|
}
|
|
215
|
+
// The compression header must match the body actually sent. It is stamped
|
|
216
|
+
// here — alongside the other request headers — so auth/proxy layers see the
|
|
217
|
+
// final shape before the transport runs.
|
|
218
|
+
if (this.config.request_compression === "zstd") headers["content-encoding"] = "zstd";
|
|
191
219
|
Object.assign(headers, filterProviderCustomHeaders(context.credential.custom_headers));
|
|
192
220
|
applyRouteUserAgent(headers, context.credential, context.user_agent);
|
|
193
221
|
return headers;
|
|
@@ -201,6 +229,17 @@ export class OpenAICompatibleAdapter extends BaseProviderAdapter {
|
|
|
201
229
|
const wireFamily = candidate.wire_family;
|
|
202
230
|
const effectiveRequest = this.config.prepareRequest?.(request) ?? request;
|
|
203
231
|
const promptCacheKey = resolvePromptCacheKey(effectiveRequest, context);
|
|
232
|
+
const dialectPolicy: DialectPolicy = resolveDialect(
|
|
233
|
+
candidate.model_id,
|
|
234
|
+
candidate.provider_id,
|
|
235
|
+
wireFamily,
|
|
236
|
+
candidate.dialect,
|
|
237
|
+
);
|
|
238
|
+
const thinking = resolveThinkingForModel(
|
|
239
|
+
candidate.model_id,
|
|
240
|
+
candidate.provider_id,
|
|
241
|
+
wireFamily,
|
|
242
|
+
);
|
|
204
243
|
const payload = await encodeWireRequest(wireFamily, effectiveRequest, {
|
|
205
244
|
supportsPromptCaching: this.config.supports_prompt_caching !== false,
|
|
206
245
|
...(promptCacheKey === undefined ? {} : { promptCacheKey }),
|
|
@@ -211,6 +250,8 @@ export class OpenAICompatibleAdapter extends BaseProviderAdapter {
|
|
|
211
250
|
...(context.image_clamp_max_bytes === undefined
|
|
212
251
|
? {}
|
|
213
252
|
: { maxBytesOverride: context.image_clamp_max_bytes }),
|
|
253
|
+
dialectPolicy,
|
|
254
|
+
thinking,
|
|
214
255
|
});
|
|
215
256
|
if (
|
|
216
257
|
wireFamily !== "messages" &&
|
|
@@ -251,6 +292,18 @@ export class OpenAICompatibleAdapter extends BaseProviderAdapter {
|
|
|
251
292
|
}
|
|
252
293
|
}
|
|
253
294
|
this.config.prePayload?.(payload, effectiveRequest, candidate, context);
|
|
295
|
+
// `service_tier` is an OpenAI-style control that only a small set of
|
|
296
|
+
// upstreams understand. Every other OpenAI-compatible provider either
|
|
297
|
+
// ignores it silently or rejects the whole request with
|
|
298
|
+
// `unsupported_value` (measured: GitHub Copilot returns 400). Since the
|
|
299
|
+
// field is purely advisory on the providers that support it, dropping it
|
|
300
|
+
// everywhere else is safe and prevents avoidable upstream 400s.
|
|
301
|
+
if (
|
|
302
|
+
payload["service_tier"] !== undefined &&
|
|
303
|
+
!SERVICE_TIER_SUPPORTED_PROVIDERS.has(candidate.provider_id)
|
|
304
|
+
) {
|
|
305
|
+
delete payload["service_tier"];
|
|
306
|
+
}
|
|
254
307
|
return payload;
|
|
255
308
|
}
|
|
256
309
|
|
|
@@ -283,6 +336,11 @@ export class OpenAICompatibleAdapter extends BaseProviderAdapter {
|
|
|
283
336
|
payload as Record<string, unknown>,
|
|
284
337
|
context,
|
|
285
338
|
outboundFetch,
|
|
339
|
+
// zstd body encoding: matches the Grok Build CLI's
|
|
340
|
+
// `request_compression` (zstd with a JSON fallback when unavailable).
|
|
341
|
+
this.config.request_compression === "zstd" && typeof Bun?.zstdCompressSync === "function"
|
|
342
|
+
? (p) => Bun.zstdCompressSync(Buffer.from(JSON.stringify(p))) as Uint8Array<ArrayBuffer>
|
|
343
|
+
: undefined,
|
|
286
344
|
);
|
|
287
345
|
upstream.release();
|
|
288
346
|
return upstream.res;
|
|
@@ -300,8 +358,11 @@ export class OpenAICompatibleAdapter extends BaseProviderAdapter {
|
|
|
300
358
|
* the caller (the route handler validates only the trust boundary), so this
|
|
301
359
|
* method only stamps headers and posts.
|
|
302
360
|
*
|
|
303
|
-
* `systemone` is kept as a named alias because
|
|
304
|
-
*
|
|
361
|
+
* `systemone` is kept as a named alias because both names are live: the
|
|
362
|
+
* transport dispatch handler for `POST /v1/systemone`
|
|
363
|
+
* (transport/dispatch/systemone.ts) and the discovery probing service
|
|
364
|
+
* (discovery/probing-service.ts) read it directly; both names are the same
|
|
365
|
+
* behavior.
|
|
305
366
|
*/
|
|
306
367
|
async dispatchNativeService(
|
|
307
368
|
body: Record<string, unknown>,
|
|
@@ -356,7 +417,10 @@ export class OpenAICompatibleAdapter extends BaseProviderAdapter {
|
|
|
356
417
|
"upstream",
|
|
357
418
|
);
|
|
358
419
|
}
|
|
359
|
-
yield* decodeWireStream(wireFamily, res.body, request, {
|
|
420
|
+
yield* decodeWireStream(wireFamily, res.body, request, {
|
|
421
|
+
signal: context.abort_signal,
|
|
422
|
+
dialectPolicy: resolveDialect(candidate.model_id, candidate.provider_id, wireFamily, candidate.dialect),
|
|
423
|
+
});
|
|
360
424
|
} else {
|
|
361
425
|
// A streaming request answered with a non-SSE body is a provider
|
|
362
426
|
// protocol violation, and the body is often an error envelope or a
|
|
@@ -390,12 +454,15 @@ export class OpenAICompatibleAdapter extends BaseProviderAdapter {
|
|
|
390
454
|
// the absence of every completion shape so a provider that merely
|
|
391
455
|
// echoes an `error` field alongside real output is not misread.
|
|
392
456
|
const envelopeError = json["error"];
|
|
457
|
+
const startPlanError = this.provider_id === "zcode-start" &&
|
|
458
|
+
(json["success"] === false || (json["code"] !== undefined &&
|
|
459
|
+
![0, 200, "0", "200"].includes(json["code"] as string | number)));
|
|
393
460
|
const hasCompletionShape =
|
|
394
461
|
json["choices"] !== undefined ||
|
|
395
462
|
json["output"] !== undefined ||
|
|
396
463
|
json["content"] !== undefined ||
|
|
397
464
|
json["candidates"] !== undefined;
|
|
398
|
-
if (envelopeError !== undefined && envelopeError !== null && !hasCompletionShape) {
|
|
465
|
+
if (((envelopeError !== undefined && envelopeError !== null) || startPlanError) && !hasCompletionShape) {
|
|
399
466
|
const errorObject = isRecord(envelopeError) ? envelopeError : json;
|
|
400
467
|
const identifier = upstreamErrorIdentifier(json);
|
|
401
468
|
const providerStatus = [
|
|
@@ -340,11 +340,6 @@ export function jwksVerifierFor(
|
|
|
340
340
|
return verifier;
|
|
341
341
|
}
|
|
342
342
|
|
|
343
|
-
/** Test hook: forgets cached JWKS verifiers. */
|
|
344
|
-
export function resetJwksVerifiersForTests(): void {
|
|
345
|
-
jwksVerifiers.clear();
|
|
346
|
-
}
|
|
347
|
-
|
|
348
343
|
interface IssuedTokenValidation {
|
|
349
344
|
readonly jwksUrl?: string;
|
|
350
345
|
readonly issuer?: string | readonly string[];
|