cartethyia 2.7.3 → 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-2TJD37Hb.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-xefJNRmJ.js → CliToolDetailPage-DZKmVuJN.js} +1 -1
- package/dist/dashboard/assets/CliToolDetailPage-DZKmVuJN.js.gz +0 -0
- package/dist/dashboard/assets/{CliToolsPage-Rj9iHQ3F.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-BKj_r0rp.js +1 -0
- 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-C4w7vea-.js → LoginPage-DkXb6dx-.js} +1 -1
- package/dist/dashboard/assets/LoginPage-DkXb6dx-.js.gz +0 -0
- package/dist/dashboard/assets/{ModelPicker-BtPcAfot.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-5SnUSy3j.js +9 -0
- 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-BQS0Rx_u.js → SetupPage-WTa0sktC.js} +1 -1
- package/dist/dashboard/assets/SetupPage-WTa0sktC.js.gz +0 -0
- package/dist/dashboard/assets/{StudioPage-TP7voAQ0.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-C0YYuZJ4.js → assert-C0K-c4eo.js} +1 -1
- package/dist/dashboard/assets/assert-C0K-c4eo.js.gz +0 -0
- package/dist/dashboard/assets/{badge-B_DMpMJN.js → badge-DfbhQU4k.js} +1 -1
- package/dist/dashboard/assets/badge-DfbhQU4k.js.gz +0 -0
- package/dist/dashboard/assets/{banner-DMrMPmth.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-Be5Uzamx.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-muFRphDu.js → cli-tools-CQXVMn4P.js} +1 -1
- package/dist/dashboard/assets/cli-tools-CQXVMn4P.js.gz +0 -0
- package/dist/dashboard/assets/{clipboard-button-DOfrVmsi.js → clipboard-button-BQqBQd2n.js} +1 -1
- package/dist/dashboard/assets/clipboard-button-BQqBQd2n.js.gz +0 -0
- package/dist/dashboard/assets/{dialog-C9omdjQt.js → dialog-BEK7KP0H.js} +1 -1
- package/dist/dashboard/assets/dialog-BEK7KP0H.js.gz +0 -0
- package/dist/dashboard/assets/{drawer-Bm8WKaGY.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-q5HwZ8nN.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-BTScrQpe.js → formatters-BAACA727.js} +1 -1
- package/dist/dashboard/assets/formatters-BAACA727.js.gz +0 -0
- package/dist/dashboard/assets/{github-badge-Orjuzemr.js → github-badge-YSCE4UC2.js} +1 -1
- package/dist/dashboard/assets/github-badge-YSCE4UC2.js.gz +0 -0
- package/dist/dashboard/assets/{index-cPrX5vn6.js → index-FQlj0HUT.js} +2 -2
- package/dist/dashboard/assets/index-FQlj0HUT.js.gz +0 -0
- package/dist/dashboard/assets/{inline-Dvux8w-0.js → inline-C4gU5iOL.js} +1 -1
- package/dist/dashboard/assets/inline-C4gU5iOL.js.gz +0 -0
- package/dist/dashboard/assets/{input-CU1Rgf3p.js → input-BHHX_Tmm.js} +1 -1
- package/dist/dashboard/assets/input-BHHX_Tmm.js.gz +0 -0
- package/dist/dashboard/assets/{layout-C_7A6H55.js → layout-CajrYUnD.js} +1 -1
- package/dist/dashboard/assets/{layout-C_7A6H55.js.gz → layout-CajrYUnD.js.gz} +0 -0
- package/dist/dashboard/assets/{list-row-CzFvogbj.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/minimize-2-BTmMTK4o.js +1 -0
- package/dist/dashboard/assets/minimize-2-BTmMTK4o.js.gz +0 -0
- package/dist/dashboard/assets/{mutation-JJGQm8TD.js → mutation-Rr0TIvcj.js} +1 -1
- package/dist/dashboard/assets/mutation-Rr0TIvcj.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/{query-keys-CLaNz8Xz.js → query-keys-BloKtaXJ.js} +1 -1
- package/dist/dashboard/assets/query-keys-BloKtaXJ.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-BEH32QOC.js → routing-in0f_IfK.js} +1 -1
- package/dist/dashboard/assets/routing-in0f_IfK.js.gz +0 -0
- package/dist/dashboard/assets/{select-B3iTetHN.js → select-BLULNqTp.js} +2 -2
- 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-KrOrm7JZ.js → stack-D2lIR0tg.js} +1 -1
- package/dist/dashboard/assets/stack-D2lIR0tg.js.gz +0 -0
- package/dist/dashboard/assets/{state-DLS7IDMy.js → state-DTARjfiW.js} +1 -1
- package/dist/dashboard/assets/state-DTARjfiW.js.gz +0 -0
- package/dist/dashboard/assets/{switch-42ItvbAs.js → switch-c0oPSnqW.js} +1 -1
- package/dist/dashboard/assets/switch-c0oPSnqW.js.gz +0 -0
- package/dist/dashboard/assets/{useMutation-Dmnfh1Ue.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 +59 -57
- package/migrations/full-postgres/0027_qoder_identity_genuine_seed.sql +9 -10
- package/migrations/full-postgres/0032_add_provider_pool_accounts.sql +53 -0
- package/migrations/full-postgres/0033_add_api_key_ban.sql +9 -0
- package/migrations/full-postgres/0034_add_api_key_ban_until.sql +7 -0
- package/migrations/full-postgres/0035_align_pool_account_status_enum.sql +21 -0
- 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/0027_qoder_identity_genuine_seed.sql +9 -10
- package/migrations/lite-sqlite3/0032_add_provider_pool_accounts.sql +44 -0
- package/migrations/lite-sqlite3/0033_add_api_key_ban.sql +8 -0
- package/migrations/lite-sqlite3/0034_add_api_key_ban_until.sql +5 -0
- package/migrations/lite-sqlite3/0035_align_pool_account_status_enum.sql +6 -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 -5
- package/scripts/cli/update.ts +15 -41
- package/src/boot/app.ts +67 -10
- 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 +8 -4
- 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 +92 -31
- package/src/console/api-keys/routes.ts +131 -6
- package/src/console/audit/routes.ts +3 -3
- package/src/console/auth/access.ts +4 -4
- package/src/console/auth/account-reset.ts +5 -5
- 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 +40 -34
- 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 +11 -9
- package/src/console/backup/export-endpoint.ts +11 -12
- package/src/console/backup/nine-router.ts +1 -7
- package/src/console/backup/routes.ts +32 -36
- 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 +4 -4
- package/src/console/cli-tools/service.ts +1 -1
- package/src/console/cli-tools/store.ts +2 -2
- package/src/console/console-router-guards.ts +2 -2
- package/src/console/console-router.ts +36 -4
- package/src/console/dashboard-assets.ts +9 -9
- package/src/console/data-management/routes.ts +3 -3
- package/src/console/domain-registration.ts +18 -4
- 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 +5 -1
- package/src/console/observability/live.ts +34 -21
- package/src/console/observability/logs.ts +4 -4
- package/src/console/observability/performance.ts +3 -3
- package/src/console/observability/routes.ts +3 -3
- package/src/console/observability/sse.ts +62 -8
- package/src/console/observability/store.ts +36 -20
- package/src/console/providers/catalog/catalog-projections.ts +1 -1
- package/src/console/providers/catalog/contracts.ts +82 -22
- package/src/console/providers/catalog/model-operations.ts +1 -1
- package/src/console/providers/catalog/provider-operations.ts +110 -17
- package/src/console/providers/catalog/public-model-store.ts +0 -0
- package/src/console/providers/catalog/routes.ts +30 -6
- package/src/console/providers/catalog/store-helpers.ts +349 -326
- package/src/console/providers/catalog/store.ts +1662 -1292
- package/src/console/providers/detail/routes.ts +4 -4
- package/src/console/providers/oauth/callback-listener.ts +100 -18
- package/src/console/providers/oauth/routes.ts +95 -16
- 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 +285 -67
- package/src/console/quota/account-test-egress.ts +4 -4
- 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/model/routes.ts +3 -3
- package/src/console/routing/pools/contracts.ts +13 -10
- package/src/console/routing/pools/import-parse.ts +3 -3
- package/src/console/routing/pools/operations.ts +14 -7
- package/src/console/routing/pools/probe-verdict.ts +8 -3
- package/src/console/routing/pools/relay-deploy.ts +12 -12
- package/src/console/routing/pools/routes.ts +3 -3
- package/src/console/routing/pools/store.ts +21 -1
- package/src/console/settings/contracts.ts +29 -2
- package/src/console/settings/routes.ts +3 -3
- package/src/console/settings/store.ts +20 -0
- package/src/console/share/share-router.ts +112 -44
- package/src/console/share/share-stats.ts +109 -39
- 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 +42 -6
- 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 +256 -98
- 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 +76 -5
- package/src/network/pool/agent.ts +7 -6
- package/src/network/pool/byte-accounting.ts +1 -1
- package/src/network/pool/resolver.ts +55 -51
- package/src/network/pool/selector.ts +150 -136
- package/src/network/pool-cooldown-store.ts +71 -16
- package/src/network/pool-health-machine.ts +22 -2
- package/src/network/rate-limit-verdict.ts +68 -0
- package/src/network/retry.ts +1 -1
- package/src/network/ssrf.ts +24 -75
- package/src/observability/event-log.ts +2 -2
- package/src/observability/event-query.ts +286 -214
- 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/telemetry-status.ts +1 -1
- 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 +10 -5
- package/src/persistence/dialect.ts +5 -1
- package/src/persistence/readiness.ts +19 -7
- package/src/persistence/redis.ts +1 -1
- package/src/persistence/schema.ts +177 -45
- package/src/persistence/shared-cache.ts +2 -2
- package/src/persistence/sort-order.ts +1 -1
- package/src/persistence/stores/api-key-store.ts +109 -4
- package/src/persistence/stores/share-store.ts +20 -8
- package/src/persistence/stores/telemetry-store.ts +1 -1
- 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 +12 -16
- package/src/protocol/dsml.ts +3 -49
- package/src/protocol/gateway-error.ts +6 -3
- package/src/protocol/image-clamp.ts +2 -2
- package/src/protocol/image-generation.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 +27 -12
- package/src/protocol/response/codex.ts +2 -2
- package/src/protocol/response/gemini.ts +1 -1
- package/src/protocol/response/messages.ts +6 -6
- package/src/protocol/response/omp-tool-call-markup.ts +1 -1
- package/src/protocol/response/responses.ts +3 -3
- package/src/protocol/sse-decoder.ts +64 -4
- 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 +8 -8
- 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/protocol/upstream/send-claude-messages.ts +3 -3
- package/src/providers/adapters/base-adapter.ts +1 -1
- package/src/providers/adapters/compatible-adapter.ts +44 -5
- 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/authentication/oauth-refresh-service.ts +2 -2
- package/src/providers/bundled-discovery-providers.ts +6 -30
- package/src/providers/configured-openai-providers.ts +82 -97
- package/src/providers/configured-provider.ts +1 -1
- 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 +50 -15
- package/src/providers/discovery/probing-service.ts +18 -20
- package/src/providers/integrations/agentrouter/agentrouter.ts +14 -5
- package/src/providers/integrations/alibabacp/alibabacp.ts +2 -2
- package/src/providers/integrations/anthropic.ts +4 -11
- 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 +15 -26
- package/src/providers/integrations/buddy/buddy-catalog-shared.ts +2 -2
- 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-discovery-shared.ts +37 -6
- package/src/providers/integrations/buddy/buddy-identity.ts +108 -1
- package/src/providers/integrations/buddy/buddy-media.ts +16 -16
- 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 +5 -16
- package/src/providers/integrations/buddy/codebuddy/shared.ts +30 -9
- package/src/providers/integrations/buddy/workbuddy/provider.ts +6 -10
- package/src/providers/integrations/buddy/workbuddy/shared.ts +21 -3
- package/src/providers/integrations/claude/claude-betas.ts +1 -1
- package/src/providers/integrations/claude/claude-cch.ts +148 -148
- package/src/providers/integrations/claude/claude-credentials.ts +1 -1
- package/src/providers/integrations/claude/claude-slow-lane-retry.ts +1 -1
- package/src/providers/integrations/claude/claude.ts +3 -10
- package/src/providers/integrations/claude/fallback-credit.ts +3 -7
- package/src/providers/integrations/cline/cline.ts +2 -2
- package/src/providers/integrations/cloudflareai/cloudflareai.ts +4 -7
- package/src/providers/integrations/codex/codex-device-code.ts +101 -101
- package/src/providers/integrations/codex/codex-errors.ts +1 -1
- package/src/providers/integrations/codex/codex-oauth.ts +0 -1
- package/src/providers/integrations/codex/codex.ts +14 -15
- package/src/providers/integrations/commandcode/commandcode.ts +76 -116
- package/src/providers/integrations/commandcode/quota.ts +132 -48
- package/src/providers/integrations/cursor/cursor-http2.ts +11 -14
- 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 +53 -20
- 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 +13 -13
- package/src/providers/integrations/gemini.ts +11 -11
- 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 +47 -20
- 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 +88 -42
- package/src/providers/integrations/inferhub.ts +4 -11
- package/src/providers/integrations/kilo/kilo-oauth.ts +1 -1
- package/src/providers/integrations/kimi/kimi.ts +4 -11
- 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 +91 -78
- package/src/providers/integrations/muse/muse-oauth.ts +0 -1
- package/src/providers/integrations/muse/muse-quota.ts +0 -4
- package/src/providers/integrations/muse/muse.ts +6 -9
- package/src/providers/integrations/opencode/fingerprint.ts +7 -5
- package/src/providers/integrations/opencode/provider.ts +17 -24
- package/src/providers/integrations/perplexity.ts +2 -2
- package/src/providers/integrations/qoder/qoder-catalog.ts +132 -17
- package/src/providers/integrations/qoder/qoder-checkin.ts +26 -8
- package/src/providers/integrations/qoder/qoder-native-identity-store.ts +9 -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 +22 -28
- package/src/providers/integrations/qoder/qoder-sse.ts +159 -0
- package/src/providers/integrations/qoder/qoder-umid.ts +33 -38
- package/src/providers/integrations/qoder/qoder-virtual.ts +14 -2
- package/src/providers/integrations/qoder/qoder.ts +521 -63
- 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/tokenharbor.ts +2 -2
- 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 +59 -19
- package/src/providers/integrations/xai/xai-oauth.ts +5 -5
- package/src/providers/integrations/zcode/oauth.ts +1 -1
- 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 +22 -6
- package/src/providers/operations/provider-credential-service.ts +35 -6
- package/src/providers/operations/upstream-deadline.ts +3 -3
- package/src/providers/provider-contracts.ts +65 -10
- package/src/providers/provider-credential-resolver.ts +1 -1
- 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-registry.ts +4 -4
- package/src/providers/provider-usage.ts +81 -16
- package/src/providers/quota/cache.ts +29 -0
- package/src/providers/quota/quota-contracts.ts +28 -10
- package/src/providers/quota/refresh.ts +29 -6
- package/src/providers/quota/snapshot.ts +94 -0
- package/src/providers/search/search-provider.ts +6 -8
- package/src/providers/search/search-providers.ts +2 -1
- package/src/security/abuse.ts +8 -8
- package/src/security/admission/reasons.ts +17 -17
- package/src/security/admission/service.ts +2 -2
- package/src/security/admission/ttl.ts +61 -61
- package/src/security/api-key-auth.ts +20 -8
- 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/coerce.ts +19 -0
- package/src/shared/invoke-guard.ts +47 -0
- package/src/transport/contracts.ts +13 -4
- package/src/transport/dispatch/attempt-finalize.ts +5 -4
- package/src/transport/dispatch/attempt-loop.ts +10 -7
- package/src/transport/dispatch/capture-policy.ts +34 -37
- package/src/transport/dispatch/empty-stream.ts +28 -25
- package/src/transport/dispatch/generation.ts +33 -53
- package/src/transport/dispatch/leases.ts +8 -8
- package/src/transport/dispatch/native-shared.ts +127 -0
- package/src/transport/dispatch/proxy-request.ts +10 -8
- package/src/transport/dispatch/responses-compact.ts +35 -56
- package/src/transport/dispatch/retry-policy.ts +4 -67
- package/src/transport/dispatch/stream-bridge.ts +1 -1
- package/src/transport/dispatch/streaming/encoder.ts +18 -72
- package/src/transport/dispatch/streaming/finalize.ts +11 -10
- 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 +27 -55
- package/src/transport/dispatch/token-count.ts +49 -46
- package/src/transport/dispatch/websearch.ts +24 -50
- package/src/transport/drain-endpoint.ts +3 -3
- package/src/transport/failure-policy.ts +19 -6
- package/src/transport/guards/auth-guard.ts +6 -11
- package/src/transport/guards/body-policy.ts +7 -7
- package/src/transport/guards/error-lifecycle.ts +18 -3
- package/src/transport/guards/guard-errors.ts +7 -3
- package/src/transport/guards/headroom-guard.ts +2 -2
- package/src/transport/guards/pipeline.ts +7 -7
- package/src/transport/guards/readiness-guard.ts +16 -2
- package/src/transport/guards/request-context.ts +15 -20
- package/src/transport/request/preparer.ts +306 -27
- 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 +5 -20
- 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 +113 -19
- package/src/transport/routing/route-model.ts +131 -38
- package/src/transport/routing/router.ts +154 -39
- package/src/transport/shutdown-notice.ts +21 -9
- 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 +3 -3
- package/src/transport/surface/content-parts.ts +1 -1
- package/src/transport/surface/dialects.ts +2 -2
- package/src/transport/surface/messages/encode.ts +1 -1
- 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-2TJD37Hb.js.gz +0 -0
- package/dist/dashboard/assets/CliToolDetailPage-xefJNRmJ.js.gz +0 -0
- package/dist/dashboard/assets/CliToolsPage-Rj9iHQ3F.js.gz +0 -0
- package/dist/dashboard/assets/CombosPage-JEbYJFxw.js +0 -1
- package/dist/dashboard/assets/CombosPage-JEbYJFxw.js.gz +0 -0
- package/dist/dashboard/assets/ConsoleLogPage-C3xx_inM.js +0 -1
- package/dist/dashboard/assets/ConsoleLogPage-C3xx_inM.js.gz +0 -0
- package/dist/dashboard/assets/CustomizationPage-Dw306gJU.js +0 -1
- package/dist/dashboard/assets/CustomizationPage-Dw306gJU.js.gz +0 -0
- package/dist/dashboard/assets/HealthEventsModal-jaBo1TWV.js +0 -1
- package/dist/dashboard/assets/HealthEventsModal-jaBo1TWV.js.gz +0 -0
- package/dist/dashboard/assets/LoginPage-C4w7vea-.js.gz +0 -0
- package/dist/dashboard/assets/ModelPicker-BtPcAfot.js.gz +0 -0
- package/dist/dashboard/assets/OverviewPage-CGC5gNs1.js +0 -1
- package/dist/dashboard/assets/OverviewPage-CGC5gNs1.js.gz +0 -0
- package/dist/dashboard/assets/ProviderDetailPage-DQcthNGt.js +0 -4
- package/dist/dashboard/assets/ProviderDetailPage-DQcthNGt.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-0OsXRGXe.js +0 -1
- package/dist/dashboard/assets/ProvidersPage-0OsXRGXe.js.gz +0 -0
- package/dist/dashboard/assets/ProxyPage-DdPc8slb.js +0 -9
- package/dist/dashboard/assets/ProxyPage-DdPc8slb.js.gz +0 -0
- package/dist/dashboard/assets/QuotaPage-Ci5O4BnH.js +0 -1
- package/dist/dashboard/assets/QuotaPage-Ci5O4BnH.js.gz +0 -0
- package/dist/dashboard/assets/SettingsPage-CDZjTt87.js +0 -1
- package/dist/dashboard/assets/SettingsPage-CDZjTt87.js.gz +0 -0
- package/dist/dashboard/assets/SetupPage-BQS0Rx_u.js.gz +0 -0
- package/dist/dashboard/assets/SortableList-BAL5npBC.js +0 -1
- package/dist/dashboard/assets/SortableList-BAL5npBC.js.gz +0 -0
- package/dist/dashboard/assets/StudioPage-TP7voAQ0.js.gz +0 -0
- package/dist/dashboard/assets/UsagePage-Cj_fEzhg.js +0 -56
- package/dist/dashboard/assets/UsagePage-Cj_fEzhg.js.gz +0 -0
- package/dist/dashboard/assets/api-keys-MbI7e7rt.js +0 -1
- package/dist/dashboard/assets/api-keys-MbI7e7rt.js.gz +0 -0
- package/dist/dashboard/assets/app-B2vyPoII.css +0 -2
- package/dist/dashboard/assets/app-B2vyPoII.css.gz +0 -0
- package/dist/dashboard/assets/assert-C0YYuZJ4.js.gz +0 -0
- package/dist/dashboard/assets/badge-B_DMpMJN.js.gz +0 -0
- package/dist/dashboard/assets/banner-DMrMPmth.js.gz +0 -0
- package/dist/dashboard/assets/card-Be5Uzamx.js.gz +0 -0
- package/dist/dashboard/assets/cli-tools-muFRphDu.js.gz +0 -0
- package/dist/dashboard/assets/clipboard-button-DOfrVmsi.js.gz +0 -0
- package/dist/dashboard/assets/dialog-C9omdjQt.js.gz +0 -0
- package/dist/dashboard/assets/drawer-Bm8WKaGY.js.gz +0 -0
- package/dist/dashboard/assets/entry-DS90gUks.js +0 -1
- package/dist/dashboard/assets/entry-DS90gUks.js.gz +0 -0
- package/dist/dashboard/assets/entry-j40LJotO.js +0 -4
- package/dist/dashboard/assets/entry-j40LJotO.js.gz +0 -0
- package/dist/dashboard/assets/entry-q5HwZ8nN.js.gz +0 -0
- package/dist/dashboard/assets/formatters-BTScrQpe.js.gz +0 -0
- package/dist/dashboard/assets/github-badge-Orjuzemr.js.gz +0 -0
- package/dist/dashboard/assets/index-cPrX5vn6.js.gz +0 -0
- package/dist/dashboard/assets/inline-Dvux8w-0.js.gz +0 -0
- package/dist/dashboard/assets/input-CU1Rgf3p.js.gz +0 -0
- package/dist/dashboard/assets/list-row-CzFvogbj.js.gz +0 -0
- package/dist/dashboard/assets/live-KaG15HLQ.js +0 -1
- package/dist/dashboard/assets/live-KaG15HLQ.js.gz +0 -0
- package/dist/dashboard/assets/minimize-2-D-MN8W8a.js +0 -1
- package/dist/dashboard/assets/minimize-2-D-MN8W8a.js.gz +0 -0
- package/dist/dashboard/assets/mutation-JJGQm8TD.js.gz +0 -0
- package/dist/dashboard/assets/numbers-BNDZnsUE.js +0 -2
- package/dist/dashboard/assets/numbers-BNDZnsUE.js.gz +0 -0
- package/dist/dashboard/assets/query-keys-CLaNz8Xz.js.gz +0 -0
- package/dist/dashboard/assets/quota-DZGyp0N5.js +0 -1
- package/dist/dashboard/assets/quota-DZGyp0N5.js.gz +0 -0
- package/dist/dashboard/assets/routing-BEH32QOC.js.gz +0 -0
- package/dist/dashboard/assets/select-B3iTetHN.js.gz +0 -0
- package/dist/dashboard/assets/settings-Dt3Eqbnq.js +0 -1
- package/dist/dashboard/assets/settings-Dt3Eqbnq.js.gz +0 -0
- package/dist/dashboard/assets/stack-KrOrm7JZ.js.gz +0 -0
- package/dist/dashboard/assets/state-DLS7IDMy.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-42ItvbAs.js.gz +0 -0
- package/dist/dashboard/assets/useMutation-Dmnfh1Ue.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-wvwCi4Eh.js → app-Bgd3zANQ.js} +0 -0
- /package/dist/dashboard/assets/{app-wvwCi4Eh.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
|
@@ -22,6 +22,7 @@ import type { CanonicalRequest } from "../../../protocol/canonical-model";
|
|
|
22
22
|
import { GatewayError } from "../../../protocol/gateway-error";
|
|
23
23
|
import { decodeMuseCredential } from "../../../security/credential-codec";
|
|
24
24
|
import { OpenAICompatibleAdapter, withBearerAuthentication } from "../../adapters/compatible-adapter";
|
|
25
|
+
import { assertCredentialKind } from "../../provider-contracts";
|
|
25
26
|
import type { ProviderDispatchTarget, ProviderDispatchContext, ResolvedCredential } from "../../provider-contracts";
|
|
26
27
|
import { providerBaseUrl } from "../../provider-metadata";
|
|
27
28
|
|
|
@@ -85,19 +86,19 @@ export function parseMuseCodeCredential(
|
|
|
85
86
|
// as before the extraction.
|
|
86
87
|
const message = error instanceof Error ? error.message : "";
|
|
87
88
|
if (message.endsWith("must be a JSON object")) {
|
|
88
|
-
throw new GatewayError("invalid_request", 400, "muse: credential must be a JSON object");
|
|
89
|
+
throw new GatewayError("invalid_request", 400, "muse: credential must be a JSON object (request {requestId}). Wrong key, right door — check the credential 🔑");
|
|
89
90
|
}
|
|
90
91
|
if (message.endsWith("is not a valid JSON blob")) {
|
|
91
92
|
throw new GatewayError(
|
|
92
93
|
"invalid_request",
|
|
93
94
|
400,
|
|
94
|
-
"muse: credential is not a valid JSON blob; sign in again",
|
|
95
|
+
"muse: credential is not a valid JSON blob (request {requestId}); sign in again. Wrong key, right door — check the credential 🔑",
|
|
95
96
|
);
|
|
96
97
|
}
|
|
97
98
|
throw new GatewayError(
|
|
98
99
|
"authentication_failed",
|
|
99
100
|
401,
|
|
100
|
-
"muse: credential is missing oauthAccessToken or apiKey; sign in again",
|
|
101
|
+
"muse: credential is missing oauthAccessToken or apiKey (request {requestId}); sign in again. Wrong key, right door — check the credential 🔑",
|
|
101
102
|
);
|
|
102
103
|
}
|
|
103
104
|
}
|
|
@@ -137,17 +138,13 @@ class MuseCodeAdapter extends OpenAICompatibleAdapter {
|
|
|
137
138
|
candidate: ProviderDispatchTarget,
|
|
138
139
|
): Promise<Record<string, string>> {
|
|
139
140
|
if (context.credential.credential_kind !== "oauth") {
|
|
140
|
-
|
|
141
|
-
"invalid_request",
|
|
142
|
-
400,
|
|
143
|
-
`muse: OAuth credential required (got credential_kind=${context.credential.credential_kind})`,
|
|
144
|
-
);
|
|
141
|
+
assertCredentialKind(context.credential, "oauth", "muse");
|
|
145
142
|
}
|
|
146
143
|
if (!context.credential.secret) {
|
|
147
144
|
throw new GatewayError(
|
|
148
145
|
"authentication_failed",
|
|
149
146
|
401,
|
|
150
|
-
"muse: OAuth credential secret is required",
|
|
147
|
+
"muse: OAuth credential secret is required (request {requestId}). Wrong key, right door — check the credential 🔑",
|
|
151
148
|
);
|
|
152
149
|
}
|
|
153
150
|
const { apiKey } = decodeMuseCredential(context.credential.secret);
|
|
@@ -2,12 +2,14 @@ import { getOpenCodeVersion } from "../../operations/client-versions";
|
|
|
2
2
|
import { createHash, randomBytes } from "node:crypto";
|
|
3
3
|
|
|
4
4
|
/**
|
|
5
|
-
* The
|
|
6
|
-
*
|
|
7
|
-
*
|
|
8
|
-
*
|
|
5
|
+
* The pinned reference client identity the parity suite asserts on.
|
|
6
|
+
*
|
|
7
|
+
* The runtime fallback lives in `VERSION_SOURCES.opencode.fallback`
|
|
8
|
+
* (`operations/client-versions.ts`); this mirror exists so the parity suite
|
|
9
|
+
* can pin the exact identity sent before discovery resolves. Keep both in
|
|
10
|
+
* lockstep when the CLI releases.
|
|
9
11
|
*/
|
|
10
|
-
export const OPENCODE_CLIENT_VERSION = "2.
|
|
12
|
+
export const OPENCODE_CLIENT_VERSION = "2.2.5";
|
|
11
13
|
|
|
12
14
|
let lastTimestamp = 0;
|
|
13
15
|
let sequenceCounter = 0;
|
|
@@ -150,17 +150,6 @@ export function isFreeTierZenModel(modelId: string): boolean {
|
|
|
150
150
|
return bare.endsWith("-free") || KNOWN_FREE_ZEN_IDS.includes(bare) || bare.toLowerCase().includes("free");
|
|
151
151
|
}
|
|
152
152
|
|
|
153
|
-
/**
|
|
154
|
-
* The anonymous credential the free tier accepts.
|
|
155
|
-
*
|
|
156
|
-
* Captured from a real client dispatch and confirmed live 2026-10-14: without
|
|
157
|
-
* it a free-model request is refused with 403 `FreeTierError` even when every
|
|
158
|
-
* other field is byte-exact, and with it the same request returns 200. It is a
|
|
159
|
-
* sentinel the upstream recognizes, not a secret — but it is a credential
|
|
160
|
-
* value, so it lives here rather than in the shared fingerprint.
|
|
161
|
-
*/
|
|
162
|
-
const ANONYMOUS_ZEN_BEARER = "public";
|
|
163
|
-
|
|
164
153
|
/**
|
|
165
154
|
* The `Accept` a free-tier dispatch advertises.
|
|
166
155
|
*
|
|
@@ -184,9 +173,10 @@ function opencodeDesktopHeaders(
|
|
|
184
173
|
context.request_headers?.["x-opencode-project"],
|
|
185
174
|
context.request_headers?.["x-opencode-session-id"],
|
|
186
175
|
),
|
|
187
|
-
// The gate
|
|
188
|
-
//
|
|
189
|
-
|
|
176
|
+
// The free-tier gate accepts dispatches with no `Authorization` at all
|
|
177
|
+
// (verified live 2026-11-02: the same captured flow answers 200 both with
|
|
178
|
+
// `Bearer public` and with no auth header, as long as the body/session
|
|
179
|
+
// fingerprint is valid). No anonymous sentinel is sent.
|
|
190
180
|
// The free-tier gate refuses non-streaming dispatches with 403
|
|
191
181
|
// FreeTierError, so free models always advertise SSE regardless of the
|
|
192
182
|
// client's own Accept; billed models keep the JSON default. The value is
|
|
@@ -211,27 +201,28 @@ function opencodeDesktopHeaders(
|
|
|
211
201
|
* `ToolDefinition`s — every wire codec serializes them, no per-wire patching.
|
|
212
202
|
*/
|
|
213
203
|
/**
|
|
214
|
-
* Every tool the free-tier gate recognises, in the order the
|
|
215
|
-
* them
|
|
204
|
+
* Every tool the free-tier gate recognises, in the order the real 2.2.0
|
|
205
|
+
* client declares them on the wire (mitm capture 2026-11-02, flow 4), with
|
|
206
|
+
* the client's own description and schema.
|
|
216
207
|
*
|
|
217
208
|
* The gate compares a recognised tool's definition, not just its name: a stub
|
|
218
209
|
* carrying the right name is refused. These are therefore verbatim captures —
|
|
219
|
-
* see `./tool-definitions` for provenance.
|
|
210
|
+
* see `./tool-definitions` for provenance. A real dispatch carries exactly
|
|
211
|
+
* these 11 tools (the binary's full `UPt` registry has 14, but the build
|
|
212
|
+
* agent sends only these).
|
|
220
213
|
*/
|
|
221
214
|
const FREE_AGENT_TOOL_NAMES_ORDERED: readonly string[] = [
|
|
222
|
-
"
|
|
215
|
+
"edit",
|
|
223
216
|
"glob",
|
|
224
|
-
"read",
|
|
225
217
|
"grep",
|
|
218
|
+
"read",
|
|
219
|
+
"shell",
|
|
220
|
+
"skill",
|
|
221
|
+
"subagent",
|
|
226
222
|
"webfetch",
|
|
227
223
|
"websearch",
|
|
228
224
|
"write",
|
|
229
|
-
"edit",
|
|
230
|
-
"subagent",
|
|
231
225
|
"execute",
|
|
232
|
-
"patch",
|
|
233
|
-
"question",
|
|
234
|
-
"skill",
|
|
235
226
|
];
|
|
236
227
|
|
|
237
228
|
/**
|
|
@@ -268,6 +259,8 @@ function ensureFreeAgentRequest(request: CanonicalRequest): CanonicalRequest {
|
|
|
268
259
|
name,
|
|
269
260
|
description: definition?.description ?? name,
|
|
270
261
|
jsonSchema: (definition?.parameters ?? FREE_AGENT_TOOL_SCHEMA) as ToolDefinition["jsonSchema"],
|
|
262
|
+
// The real client marks every declared tool strict:false on the wire.
|
|
263
|
+
strict: false,
|
|
271
264
|
};
|
|
272
265
|
});
|
|
273
266
|
if (missing.length === 0) return request;
|
|
@@ -69,11 +69,11 @@ export function createPerplexityAdapter(fetchImpl?: typeof fetch): ProviderAdapt
|
|
|
69
69
|
void _candidate;
|
|
70
70
|
const query = extractSearchQuery(request);
|
|
71
71
|
if (!query) {
|
|
72
|
-
throw new GatewayError("invalid_request", 400, "Search query is required.");
|
|
72
|
+
throw new GatewayError("invalid_request", 400, "Search query is required (request {requestId}). Check the shape of what you sent — then resend 🪞");
|
|
73
73
|
}
|
|
74
74
|
const token = tokenFromContext(context);
|
|
75
75
|
if (!token) {
|
|
76
|
-
throw new GatewayError("authentication_failed", 401, "Missing Perplexity API key");
|
|
76
|
+
throw new GatewayError("authentication_failed", 401, "Missing Perplexity API key (request {requestId}). Wrong key, right door — check the key 🔑");
|
|
77
77
|
}
|
|
78
78
|
|
|
79
79
|
const fetchFn = (context.outbound_fetch as unknown as typeof fetch | undefined) ?? fetchImpl ?? globalThis.fetch;
|
|
@@ -86,6 +86,14 @@ interface QoderModelConfig {
|
|
|
86
86
|
* `false` marks the model as billed.
|
|
87
87
|
*/
|
|
88
88
|
readonly is_free?: boolean;
|
|
89
|
+
/**
|
|
90
|
+
* The reasoning effort to send when the caller did not ask for one. The IDE
|
|
91
|
+
* surface follows the `reasoningEffort` field: a model marked `is_reasoning`
|
|
92
|
+
* may still stream no reasoning unless an effort is present (verified live:
|
|
93
|
+
* Sonus streams thinking only when effort is sent; DeepSeek thinks by
|
|
94
|
+
* default). Set only for models that need the push.
|
|
95
|
+
*/
|
|
96
|
+
readonly default_reasoning_effort?: string;
|
|
89
97
|
}
|
|
90
98
|
|
|
91
99
|
/**
|
|
@@ -112,7 +120,7 @@ export const QODER_CN_MODEL_CONFIGS: Readonly<Record<string, QoderModelConfig>>
|
|
|
112
120
|
};
|
|
113
121
|
|
|
114
122
|
/**
|
|
115
|
-
* Global/intl roster (
|
|
123
|
+
* Global/intl roster (18 keys), from the donor's `qoder_catalog_intl.json`.
|
|
116
124
|
*
|
|
117
125
|
* Note how the shared keys differ from CN — `auto` is non-reasoning here and
|
|
118
126
|
* `qmodel` carries a 1M window. That is why the rosters are not merged.
|
|
@@ -127,19 +135,27 @@ export const QODER_INTL_MODEL_CONFIGS: Readonly<Record<string, QoderModelConfig>
|
|
|
127
135
|
fast: { id: "fast", display_name: "Fast", max_input_tokens: 1000000, max_output_tokens: 64_000, is_vl: true, is_reasoning: false },
|
|
128
136
|
performance: { id: "performance", display_name: "Performance", max_input_tokens: 1000000, max_output_tokens: 64_000, is_vl: true, is_reasoning: false },
|
|
129
137
|
efficient: { id: "efficient", display_name: "Efficient", max_input_tokens: 200000, max_output_tokens: 64_000, is_vl: true, is_reasoning: false },
|
|
130
|
-
|
|
131
|
-
|
|
138
|
+
// Sonus/Cantus need an explicit effort on the IDE surface; without it the
|
|
139
|
+
// upstream streams text only, no reasoning (verified live). DeepSeek-family
|
|
140
|
+
// models think by default and are left untouched.
|
|
141
|
+
smodel: { id: "smodel", display_name: "Sonus", max_input_tokens: 1000000, max_output_tokens: 128_000, is_vl: true, is_free: false, is_reasoning: true, default_reasoning_effort: "high" },
|
|
142
|
+
cmodel: { id: "cmodel", display_name: "Cantus", max_input_tokens: 1000000, max_output_tokens: 128_000, is_vl: true, is_free: false, is_reasoning: true, default_reasoning_effort: "high" },
|
|
132
143
|
qmodel_38max: { id: "qmodel_38max", display_name: "Qwen3.8-Max", max_input_tokens: 1000000, max_output_tokens: 131_072, is_vl: true, is_reasoning: true },
|
|
133
144
|
qfmodel: { id: "qfmodel", display_name: "Qwen3.8-Flash", max_input_tokens: 1000000, max_output_tokens: 131_072, is_vl: true, is_free: true, is_reasoning: true },
|
|
134
145
|
qmodel_latest: { id: "qmodel_latest", display_name: "Qwen3.7-Max", max_input_tokens: 1000000, max_output_tokens: 131_072, is_vl: true, is_reasoning: false },
|
|
135
146
|
qmodel: { id: "qmodel", display_name: "Qwen3.7-Plus", max_input_tokens: 1000000, max_output_tokens: 131_072, is_vl: true, is_reasoning: false },
|
|
136
|
-
kmodel_latest: { id: "kmodel_latest", display_name: "Kimi-K3", max_input_tokens: 1000000, max_output_tokens: 131_072, is_vl: true, is_free: false, is_reasoning: false },
|
|
147
|
+
kmodel_latest: { id: "kmodel_latest", display_name: "Kimi-K3.1-Pro", max_input_tokens: 1000000, max_output_tokens: 131_072, is_vl: true, is_free: false, is_reasoning: false },
|
|
137
148
|
kmodel: { id: "kmodel", display_name: "Kimi-K2.8-Preview", max_input_tokens: 1000000, max_output_tokens: 65_536, is_vl: true, is_free: false, is_reasoning: false },
|
|
138
149
|
gmodel: { id: "gmodel", display_name: "GLM-5.3", max_input_tokens: 1000000, max_output_tokens: 131_072, is_vl: true, is_free: false, is_reasoning: true },
|
|
139
150
|
gfmodel: { id: "gfmodel", display_name: "GLM-5.3-Flash", max_input_tokens: 1000000, max_output_tokens: 131_072, is_vl: true, is_reasoning: true },
|
|
140
151
|
dmodel: { id: "dmodel", display_name: "DeepSeek-V4-Pro", max_input_tokens: 1000000, max_output_tokens: 384_000, is_vl: true, is_free: false, is_reasoning: true },
|
|
141
|
-
|
|
142
|
-
|
|
152
|
+
// Live roster (2026-11-01) reports dfmodel as billed (is_free false); it was
|
|
153
|
+
// previously marked free. Display names are corrected from the same capture.
|
|
154
|
+
dfmodel: { id: "dfmodel", display_name: "DeepSeek-Flash", max_input_tokens: 1000000, max_output_tokens: 384_000, is_vl: true, is_free: false, is_reasoning: true },
|
|
155
|
+
mmodel: { id: "mmodel", display_name: "MiniMax-M3.1-Flash", max_input_tokens: 1000000, max_output_tokens: 512_000, is_vl: true, is_free: false, is_reasoning: false },
|
|
156
|
+
// `lite` is the free-tier plan package: same 1M window and multimodal input
|
|
157
|
+
// as `qmodel` (Qwen3.7-Plus), capped at 64k output, free tier.
|
|
158
|
+
lite: { id: "lite", display_name: "Lite-Qwen-3.7-Plus", max_input_tokens: 1000000, max_output_tokens: 65_536, is_vl: true, is_free: true, is_reasoning: false },
|
|
143
159
|
};
|
|
144
160
|
|
|
145
161
|
/**
|
|
@@ -211,13 +227,24 @@ export function qoderVirtualModels(
|
|
|
211
227
|
// substitutes the shared unfiled fallback for null — the same marker a
|
|
212
228
|
// hand-added row gets.
|
|
213
229
|
ctx: target.contextLimit ?? null,
|
|
214
|
-
|
|
215
|
-
|
|
230
|
+
// A virtual override wins; otherwise inherit the target's ceiling.
|
|
231
|
+
...(virtual.outputLimit !== undefined
|
|
232
|
+
? { out: virtual.outputLimit }
|
|
233
|
+
: target.outputLimit === null
|
|
234
|
+
? {}
|
|
235
|
+
: { out: target.outputLimit }),
|
|
236
|
+
vision: virtual.vision ?? target.modalities.input.includes("image"),
|
|
216
237
|
reasoning: target.reasoning ?? false,
|
|
217
238
|
toolCall: target.toolCall ?? false,
|
|
218
239
|
// The same model under its caller-facing name belongs to the same tier,
|
|
219
|
-
// so the pill follows the roster row rather than being restated
|
|
220
|
-
|
|
240
|
+
// so the pill follows the roster row rather than being restated —
|
|
241
|
+
// unless the virtual card explicitly overrides it (`lite` is a free
|
|
242
|
+
// plan package over a billed slot).
|
|
243
|
+
...(virtual.free !== undefined
|
|
244
|
+
? { free: virtual.free, freeTier: virtual.free }
|
|
245
|
+
: target.freeTier === undefined
|
|
246
|
+
? {}
|
|
247
|
+
: { free: target.freeTier, freeTier: target.freeTier }),
|
|
221
248
|
}),
|
|
222
249
|
);
|
|
223
250
|
}
|
|
@@ -272,11 +299,27 @@ export function mapQoderCatalogResponse(raw: unknown): QoderCatalogEntry[] {
|
|
|
272
299
|
return entries;
|
|
273
300
|
}
|
|
274
301
|
|
|
302
|
+
/**
|
|
303
|
+
* The static roster's stated output ceiling for one slot, when the roster
|
|
304
|
+
* states one.
|
|
305
|
+
*
|
|
306
|
+
* Upstream's live `/model/list` rows report no output limit, so a discovered
|
|
307
|
+
* row cannot read one from the wire. Inheriting the roster's number keeps the
|
|
308
|
+
* discovered row's `outputLimit` honest — without it `defineModel` falls back
|
|
309
|
+
* to a base-catalog/majority vote that can sit below the roster's ceiling
|
|
310
|
+
* (e.g. `qwen3.7-plus` votes 64k while the roster says 131k).
|
|
311
|
+
*/
|
|
312
|
+
function qoderRosterMaxOutputFor(providerId: string, key: string): number | undefined {
|
|
313
|
+
const configs = providerId === "qodercn" ? QODER_CN_MODEL_CONFIGS : QODER_INTL_MODEL_CONFIGS;
|
|
314
|
+
return configs[key]?.max_output_tokens;
|
|
315
|
+
}
|
|
316
|
+
|
|
275
317
|
/** Projects one live catalog row onto a Cartethyia catalog row. */
|
|
276
318
|
export function qoderCatalogModel(
|
|
277
319
|
entry: QoderCatalogEntry,
|
|
278
320
|
providerId: string,
|
|
279
321
|
): ModelDefinition {
|
|
322
|
+
const rosterOutput = qoderRosterMaxOutputFor(providerId, entry.key);
|
|
280
323
|
return defineModel({
|
|
281
324
|
id: entry.key,
|
|
282
325
|
providerId,
|
|
@@ -293,6 +336,9 @@ export function qoderCatalogModel(
|
|
|
293
336
|
// a free row bills zero per token and belongs to the provider's free tier.
|
|
294
337
|
free: entry.isFree,
|
|
295
338
|
freeTier: entry.isFree,
|
|
339
|
+
// The live row carries no output ceiling, so inherit the static roster's
|
|
340
|
+
// stated one when it exists (see `qoderRosterMaxOutputFor`).
|
|
341
|
+
...(rosterOutput === undefined ? {} : { out: rosterOutput }),
|
|
296
342
|
});
|
|
297
343
|
}
|
|
298
344
|
|
|
@@ -353,6 +399,14 @@ interface CachedRoster {
|
|
|
353
399
|
/** Per-realm live-list cache; keyed by realm, not by account. */
|
|
354
400
|
const discoveryCache = new Map<QoderRealm, CachedRoster>();
|
|
355
401
|
|
|
402
|
+
/**
|
|
403
|
+
* Per-realm max-context window per roster key, taken from the live list's
|
|
404
|
+
* `context_config` (the widest selectable window). This is what dispatch reads
|
|
405
|
+
* to send `model_config.max_input_tokens`; without it the request would use the
|
|
406
|
+
* static roster's *currently active* window (often 180k) instead of the max.
|
|
407
|
+
*/
|
|
408
|
+
const discoveryMaxContextByKey = new Map<QoderRealm, Map<string, number>>();
|
|
409
|
+
|
|
356
410
|
/**
|
|
357
411
|
* Drops one realm's cached list.
|
|
358
412
|
*
|
|
@@ -361,8 +415,21 @@ const discoveryCache = new Map<QoderRealm, CachedRoster>();
|
|
|
361
415
|
* previous assertion left behind.
|
|
362
416
|
*/
|
|
363
417
|
export function resetQoderDiscoveryCache(realm?: QoderRealm): void {
|
|
364
|
-
if (realm === undefined)
|
|
365
|
-
|
|
418
|
+
if (realm === undefined) {
|
|
419
|
+
discoveryCache.clear();
|
|
420
|
+
discoveryMaxContextByKey.clear();
|
|
421
|
+
} else {
|
|
422
|
+
discoveryCache.delete(realm);
|
|
423
|
+
discoveryMaxContextByKey.delete(realm);
|
|
424
|
+
}
|
|
425
|
+
}
|
|
426
|
+
|
|
427
|
+
/**
|
|
428
|
+
* The widest selectable context window per roster key for one realm, from the
|
|
429
|
+
* live model list. Empty when discovery has not succeeded for that realm yet.
|
|
430
|
+
*/
|
|
431
|
+
export function qoderDiscoveredMaxContexts(realm: QoderRealm): ReadonlyMap<string, number> {
|
|
432
|
+
return discoveryMaxContextByKey.get(realm) ?? new Map();
|
|
366
433
|
}
|
|
367
434
|
|
|
368
435
|
export async function discoverQoderModels(input: {
|
|
@@ -389,7 +456,7 @@ export async function discoverQoderModels(input: {
|
|
|
389
456
|
throw new GatewayError(
|
|
390
457
|
"authentication_failed",
|
|
391
458
|
401,
|
|
392
|
-
"Qoder model discovery requires an account credential.",
|
|
459
|
+
"Qoder model discovery requires an account credential (request {requestId}). Wrong key, right door — check the credential 🔑",
|
|
393
460
|
{ providerId, realm: input.realm },
|
|
394
461
|
);
|
|
395
462
|
}
|
|
@@ -398,7 +465,7 @@ export async function discoverQoderModels(input: {
|
|
|
398
465
|
throw new GatewayError(
|
|
399
466
|
"invalid_request",
|
|
400
467
|
400,
|
|
401
|
-
"Qoder model discovery requires a validated outbound fetch",
|
|
468
|
+
"Qoder model discovery requires a validated outbound fetch (request {requestId}). No bridge to cross — configure a pool first 🏗️",
|
|
402
469
|
{ providerId, realm: input.realm },
|
|
403
470
|
);
|
|
404
471
|
}
|
|
@@ -409,6 +476,11 @@ export async function discoverQoderModels(input: {
|
|
|
409
476
|
const url = `${host}${QODER_MODELS_PATH}`;
|
|
410
477
|
try {
|
|
411
478
|
const headers = await input.headers(url, signedBody);
|
|
479
|
+
// GET, not POST: upstream refuses POST on the model-list surface (400
|
|
480
|
+
// "Request method 'POST' not supported"). The signature covers the body,
|
|
481
|
+
// so the body must accompany the GET. The gateway's validated egress
|
|
482
|
+
// dials GET+body through the Node http(s) client (the runtime fetch
|
|
483
|
+
// rejects GET bodies), which is exactly the shape the donor client sends.
|
|
412
484
|
const response = await fetcher(url, {
|
|
413
485
|
method: "GET",
|
|
414
486
|
headers: headers as unknown as HeadersInit,
|
|
@@ -429,10 +501,53 @@ export async function discoverQoderModels(input: {
|
|
|
429
501
|
lastError = new Error("Qoder model list returned no usable models");
|
|
430
502
|
continue;
|
|
431
503
|
}
|
|
432
|
-
const models = enabled.
|
|
504
|
+
const models = enabled.flatMap((entry) => {
|
|
505
|
+
// Publish caller-facing virtual ids (`sonus`, `lite-qwen-3.7-plus`, …)
|
|
506
|
+
// instead of the opaque roster keys (`smodel`, `qmodel`, …). A discovery
|
|
507
|
+
// row must look like what the UI offers and what a caller can type;
|
|
508
|
+
// keeping the raw key here made live-synced rows appear under names
|
|
509
|
+
// nobody can route to by display, and hid overridden cards like `lite`.
|
|
510
|
+
// More than one virtual may share a slot (`lite-qwen-3.7-plus` and
|
|
511
|
+
// `qwen3.7-plus` both dispatch to `qmodel`), so every match on the slot
|
|
512
|
+
// is published.
|
|
513
|
+
const virtuals = QODER_VIRTUAL_MODELS.filter((virtual) => virtual.target === entry.key);
|
|
514
|
+
if (virtuals.length === 0) return [qoderCatalogModel(entry, providerId)];
|
|
515
|
+
const rosterOutput = qoderRosterMaxOutputFor(providerId, entry.key);
|
|
516
|
+
return virtuals.map((virtual) =>
|
|
517
|
+
defineModel({
|
|
518
|
+
id: virtual.id,
|
|
519
|
+
providerId,
|
|
520
|
+
wireFamily: "chat",
|
|
521
|
+
endpoint: QODER_CHAT_PATH,
|
|
522
|
+
ctx: entry.maxInputTokens ?? null,
|
|
523
|
+
vision: virtual.vision ?? entry.isVl,
|
|
524
|
+
reasoning: entry.isReasoning,
|
|
525
|
+
// A virtual override wins; otherwise inherit the static roster's
|
|
526
|
+
// ceiling for the slot instead of a base-catalog/majority estimate
|
|
527
|
+
// (see `qoderRosterMaxOutputFor`).
|
|
528
|
+
...(virtual.outputLimit !== undefined
|
|
529
|
+
? { out: virtual.outputLimit }
|
|
530
|
+
: rosterOutput === undefined
|
|
531
|
+
? {}
|
|
532
|
+
: { out: rosterOutput }),
|
|
533
|
+
free: virtual.free ?? entry.isFree,
|
|
534
|
+
freeTier: virtual.free ?? entry.isFree,
|
|
535
|
+
}),
|
|
536
|
+
);
|
|
537
|
+
});
|
|
538
|
+
// Index the widest selectable window per key (from `context_config`,
|
|
539
|
+
// already computed into `maxInputTokens` by `mapQoderCatalogResponse`) so
|
|
540
|
+
// dispatch can send the maximum rather than the currently active one.
|
|
541
|
+
const maxCtx = new Map<string, number>();
|
|
542
|
+
for (const entry of enabled) {
|
|
543
|
+
if (entry.maxInputTokens !== undefined && entry.key.length > 0) {
|
|
544
|
+
maxCtx.set(entry.key, entry.maxInputTokens);
|
|
545
|
+
}
|
|
546
|
+
}
|
|
433
547
|
// Cached only after a host actually answered: a failure must stay
|
|
434
548
|
// retryable on the next call rather than being frozen for five minutes.
|
|
435
549
|
discoveryCache.set(input.realm, { at: Date.now(), models });
|
|
550
|
+
discoveryMaxContextByKey.set(input.realm, maxCtx);
|
|
436
551
|
return models;
|
|
437
552
|
} catch (error) {
|
|
438
553
|
lastError = error;
|
|
@@ -441,9 +556,9 @@ export async function discoverQoderModels(input: {
|
|
|
441
556
|
throw new GatewayError(
|
|
442
557
|
"transport_unavailable",
|
|
443
558
|
502,
|
|
444
|
-
`Qoder model discovery failed for ${input.realm}: ${
|
|
559
|
+
`Qoder model discovery failed for ${input.realm} (request {requestId}): ${
|
|
445
560
|
lastError instanceof Error ? lastError.message : "unknown error"
|
|
446
|
-
}
|
|
561
|
+
}. The connection ghosted us — come back in a moment 👻`,
|
|
447
562
|
{ providerId, realm: input.realm },
|
|
448
563
|
"upstream",
|
|
449
564
|
);
|
|
@@ -175,15 +175,18 @@ async function tryClaimDaily(
|
|
|
175
175
|
if (campaigns === null) {
|
|
176
176
|
return { state: "error", amount: 0, error: "Campaign list unavailable." };
|
|
177
177
|
}
|
|
178
|
-
|
|
178
|
+
// Claim a `CLAIMABLE` CREDITS-kind campaign. Promo rows (`VIEW_DETAILS`,
|
|
179
|
+
// no benefit) are not credit grants and must not be claimed — claiming one
|
|
180
|
+
// spends the account's daily slot for nothing and makes the sweep report a
|
|
181
|
+
// misleading `claimed` with 0 credits.
|
|
182
|
+
const claimable = campaigns.filter((c) => {
|
|
183
|
+
if (String(c["claim_status"] ?? "").toUpperCase() !== "CLAIMABLE") return false;
|
|
184
|
+
const kind = String(asRecord(c["benefit"])?.["kind"] ?? "").toUpperCase();
|
|
185
|
+
const action = String(c["action_type"] ?? "").toUpperCase();
|
|
186
|
+
return kind === "CREDITS" || action === "CLAIM_BENEFIT";
|
|
187
|
+
});
|
|
188
|
+
for (const campaign of claimable) {
|
|
179
189
|
const benefit = asRecord(campaign["benefit"]);
|
|
180
|
-
const kind = String(benefit?.["kind"] ?? "").toUpperCase();
|
|
181
|
-
if (kind !== "CREDITS" && kind !== "") continue;
|
|
182
|
-
const actionType = String(campaign["action_type"] ?? "");
|
|
183
|
-
if (actionType !== "" && actionType !== "CLAIM_BENEFIT") continue;
|
|
184
|
-
const claimStatus = String(campaign["claim_status"] ?? "").toUpperCase();
|
|
185
|
-
if (claimStatus === "CLAIMED") return { state: "already_claimed", amount: 0, error: null };
|
|
186
|
-
if (claimStatus !== "CLAIMABLE") continue;
|
|
187
190
|
const campaignId = String(campaign["campaign_id"] ?? "");
|
|
188
191
|
if (!campaignId) continue;
|
|
189
192
|
const claim = await claimWithHeaders(base, campaignId, headers, fetcher);
|
|
@@ -195,6 +198,18 @@ async function tryClaimDaily(
|
|
|
195
198
|
if (claim.state === "not_eligible") return { state: "not_eligible", amount: 0, error: null };
|
|
196
199
|
return { state: "error", amount: 0, error: "Campaign claim failed." };
|
|
197
200
|
}
|
|
201
|
+
// Nothing claimable. Only a CREDITS-kind campaign that is `CLAIMED` proves
|
|
202
|
+
// today's credit was already taken; a claimed promo (`VIEW_DETAILS`, no
|
|
203
|
+
// benefit) says nothing about the daily grant, so it must not be reported
|
|
204
|
+
// as already_claimed. When the CREDITS campaign is absent entirely, the
|
|
205
|
+
// daily grant is simply not present (or hidden) for this account.
|
|
206
|
+
const anyCreditsClaimed = campaigns.some((c) => {
|
|
207
|
+
if (String(c["claim_status"] ?? "").toUpperCase() !== "CLAIMED") return false;
|
|
208
|
+
const kind = String(asRecord(c["benefit"])?.["kind"] ?? "").toUpperCase();
|
|
209
|
+
const action = String(c["action_type"] ?? "").toUpperCase();
|
|
210
|
+
return kind === "CREDITS" || action === "CLAIM_BENEFIT";
|
|
211
|
+
});
|
|
212
|
+
if (anyCreditsClaimed) return { state: "already_claimed", amount: 0, error: null };
|
|
198
213
|
return { state: "unavailable", amount: 0, error: "No daily CREDITS campaign claimable." };
|
|
199
214
|
}
|
|
200
215
|
|
|
@@ -224,6 +239,9 @@ async function probeDailyClaim(
|
|
|
224
239
|
): Promise<{ result: { state: DailyCheckinState; amount: number; error: string | null }; identity: QoderNativeIdentity | null }> {
|
|
225
240
|
const basic = await tryClaimDaily(base, campaignHeaders(credential), fetcher);
|
|
226
241
|
if (basic.state === "claimed" || basic.state === "already_claimed") {
|
|
242
|
+
// `tryClaimDaily` only claims CREDITS-kind campaigns, so a `claimed` or
|
|
243
|
+
// `already_claimed` basic result is already about the daily credit grant —
|
|
244
|
+
// terminal, no identity probe needed.
|
|
227
245
|
return { result: basic, identity: null };
|
|
228
246
|
}
|
|
229
247
|
if (basic.state === "unavailable") {
|
|
@@ -2,15 +2,16 @@
|
|
|
2
2
|
* Persistence for the Qoder native machine identity (UMID) bound to an
|
|
3
3
|
* account.
|
|
4
4
|
*
|
|
5
|
-
*
|
|
6
|
-
*
|
|
7
|
-
*
|
|
8
|
-
*
|
|
9
|
-
*
|
|
5
|
+
* Same-account probes found that daily 100-credit grant visibility does not
|
|
6
|
+
* depend on machine headers. This store preserves native identities and seeds
|
|
7
|
+
* for deterministic replay and other surfaces that may use device identity.
|
|
8
|
+
* A native identity is a deterministic function of a seed file
|
|
9
|
+
* (`~/.config/.locale_cfg`). The bound record lives in
|
|
10
|
+
* `provider_accounts.native_identity` (plain JSON, not a secret).
|
|
10
11
|
*
|
|
11
12
|
* Uniqueness of the device is enforced by the partial unique index on the
|
|
12
|
-
* extracted `machineToken`; this store keeps the JS side of that
|
|
13
|
-
* and surfaces the DB constraint as the backstop.
|
|
13
|
+
* extracted `machineToken`; this store keeps the JS side of that internal
|
|
14
|
+
* identity-allocation invariant and surfaces the DB constraint as the backstop.
|
|
14
15
|
*/
|
|
15
16
|
import { and, eq, isNotNull, ne } from "drizzle-orm";
|
|
16
17
|
import type { CartethyiaDatabase } from "../../../persistence/db-handle";
|
|
@@ -30,7 +31,7 @@ export interface QoderNativeIdentityStore {
|
|
|
30
31
|
get(providerId: string, accountId: string): Promise<NativeIdentityRecord | undefined>;
|
|
31
32
|
/**
|
|
32
33
|
* Machine tokens already bound to **other** accounts, so a caller can mint
|
|
33
|
-
* a fresh
|
|
34
|
+
* a fresh identity without colliding. A bound token represents a device identity, and
|
|
34
35
|
* the unique index that backs this spans all `provider_accounts` rows. The
|
|
35
36
|
* account's own bound token is not "occupied" — reusing one's own device is
|
|
36
37
|
* the point.
|