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
|
@@ -27,6 +27,7 @@ import type {
|
|
|
27
27
|
} from "../../../protocol/canonical-model";
|
|
28
28
|
import { resolveImageSource, splitDataUrl } from "../../../protocol/codecs";
|
|
29
29
|
import { IMAGE_CLAMP_MAX_BYTES } from "../../../protocol/image-clamp";
|
|
30
|
+
import { applyCacheMode } from "../../provider-usage";
|
|
30
31
|
import type { ProviderAdapter, ProviderDispatchContext, ProviderDispatchTarget } from "../../provider-contracts";
|
|
31
32
|
import { readCredentialSecret } from "../../provider-contracts";
|
|
32
33
|
import type { Http2BidiEndReason, ValidatedHttp2BidiStream } from "../../../network/http2-bidi";
|
|
@@ -62,6 +63,7 @@ import { defaultParameterValues, fetchCursorModels } from "./cursor-catalog";
|
|
|
62
63
|
import type { CursorModelInfo } from "./cursor-catalog";
|
|
63
64
|
import { decodeValueToJson, decodeStructEntriesToJson } from "./protocol/struct";
|
|
64
65
|
import { cursorVariantForExecArgs } from "./protocol/tool-canonical";
|
|
66
|
+
import { fnv1a32 } from "../shared/hash";
|
|
65
67
|
|
|
66
68
|
/**
|
|
67
69
|
* Client-heartbeat cadence for every Cursor Run.
|
|
@@ -81,8 +83,38 @@ const CURSOR_HEARTBEAT_INTERVAL_MS = 5_000;
|
|
|
81
83
|
* every dispatch.
|
|
82
84
|
*/
|
|
83
85
|
const CURSOR_ROSTER_TTL_MS = 300_000;
|
|
84
|
-
/**
|
|
86
|
+
/**
|
|
87
|
+
* credential → { roster, fetchedAt } for the parameter lookup.
|
|
88
|
+
*
|
|
89
|
+
* Keyed by an FNV-1a digest of the credential rather than the raw token so a
|
|
90
|
+
* long-lived map does not hold live credentials as keys. Bounded by
|
|
91
|
+
* `ROSTER_CACHE_MAX` with oldest-first eviction: the TTL is only checked on
|
|
92
|
+
* read, so without a cap rotated tokens would grow the map without bound.
|
|
93
|
+
*/
|
|
94
|
+
const ROSTER_CACHE_MAX = 1024;
|
|
85
95
|
const rosterCache = new Map<string, { roster: readonly CursorModelInfo[]; fetchedAt: number }>();
|
|
96
|
+
|
|
97
|
+
function rosterCacheSet(credential: string, roster: readonly CursorModelInfo[]): void {
|
|
98
|
+
const key = String(fnv1a32(credential));
|
|
99
|
+
rosterCache.delete(key); // re-set moves the entry to newest position
|
|
100
|
+
rosterCache.set(key, { roster, fetchedAt: Date.now() });
|
|
101
|
+
while (rosterCache.size > ROSTER_CACHE_MAX) {
|
|
102
|
+
const oldest = rosterCache.keys().next().value;
|
|
103
|
+
if (oldest === undefined) break;
|
|
104
|
+
rosterCache.delete(oldest);
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
/**
|
|
109
|
+
* Test-only access to the roster cache (cap/eviction/TTL behavior is covered
|
|
110
|
+
* by `test/providers/cursor-roster-cache.test.ts` without a full dispatch).
|
|
111
|
+
*/
|
|
112
|
+
export const rosterCacheForTests = {
|
|
113
|
+
size: (): number => rosterCache.size,
|
|
114
|
+
set: rosterCacheSet,
|
|
115
|
+
get: (credential: string): { roster: readonly CursorModelInfo[]; fetchedAt: number } | undefined =>
|
|
116
|
+
rosterCache.get(String(fnv1a32(credential))),
|
|
117
|
+
};
|
|
86
118
|
/** Client-heartbeat cadence the Cursor edge expects (donor `heartbeatMs`). */
|
|
87
119
|
const CURSOR_HEARTBEAT_INTERVAL_OVERRIDE = (() => {
|
|
88
120
|
const raw = process.env.CARTETHYIA_CURSOR_HEARTBEAT_MS?.trim();
|
|
@@ -152,14 +184,14 @@ function finishImage(bytes: Uint8Array): CursorImageInput {
|
|
|
152
184
|
throw new GatewayError(
|
|
153
185
|
"invalid_request",
|
|
154
186
|
400,
|
|
155
|
-
"Cursor accepts PNG, JPEG, WebP and GIF image input only",
|
|
187
|
+
"Cursor accepts PNG, JPEG, WebP and GIF image input only (request {requestId}). Check the shape of what you sent — then resend 🪞",
|
|
156
188
|
);
|
|
157
189
|
}
|
|
158
190
|
if (bytes.byteLength > MAX_IMAGE_BYTES) {
|
|
159
191
|
throw new GatewayError(
|
|
160
192
|
"invalid_request",
|
|
161
193
|
400,
|
|
162
|
-
`Cursor image input exceeds the ${MAX_IMAGE_BYTES}-byte limit
|
|
194
|
+
`Cursor image input exceeds the ${MAX_IMAGE_BYTES}-byte limit (request {requestId}). We love long reads, but not that long 📚`,
|
|
163
195
|
);
|
|
164
196
|
}
|
|
165
197
|
return { data: bytes, mimeType };
|
|
@@ -183,7 +215,7 @@ async function resolveImageInput(
|
|
|
183
215
|
if (dataUrl !== undefined) {
|
|
184
216
|
const bytes = base64ToBytes(dataUrl.data);
|
|
185
217
|
if (bytes === undefined) {
|
|
186
|
-
throw new GatewayError("invalid_request", 400, "Cursor image attachment is not valid base64");
|
|
218
|
+
throw new GatewayError("invalid_request", 400, "Cursor image attachment is not valid base64 (request {requestId}). Check the shape of what you sent — then resend 🪞");
|
|
187
219
|
}
|
|
188
220
|
return finishImage(bytes);
|
|
189
221
|
}
|
|
@@ -192,7 +224,7 @@ async function resolveImageInput(
|
|
|
192
224
|
throw new GatewayError(
|
|
193
225
|
"invalid_request",
|
|
194
226
|
400,
|
|
195
|
-
"Cursor image URLs must be HTTPS; private and non-TLS sources are not fetched",
|
|
227
|
+
"Cursor image URLs must be HTTPS; private and non-TLS sources are not fetched (request {requestId}). Check the shape of what you sent — then resend 🪞",
|
|
196
228
|
);
|
|
197
229
|
}
|
|
198
230
|
const fetcher = context.outbound_attachment_fetch;
|
|
@@ -200,7 +232,7 @@ async function resolveImageInput(
|
|
|
200
232
|
throw new GatewayError(
|
|
201
233
|
"invalid_request",
|
|
202
234
|
400,
|
|
203
|
-
"Cursor has no validated egress to fetch this image URL",
|
|
235
|
+
"Cursor has no validated egress to fetch this image URL (request {requestId}). All roads blocked — time to find a new route 🗺️",
|
|
204
236
|
);
|
|
205
237
|
}
|
|
206
238
|
// Redirects are not followed: reject the response rather than letting a
|
|
@@ -222,7 +254,7 @@ async function resolveImageInput(
|
|
|
222
254
|
throw new GatewayError(
|
|
223
255
|
"invalid_request",
|
|
224
256
|
400,
|
|
225
|
-
`Cursor image input exceeds the ${MAX_IMAGE_BYTES}-byte limit
|
|
257
|
+
`Cursor image input exceeds the ${MAX_IMAGE_BYTES}-byte limit (request {requestId}). We love long reads, but not that long 📚`,
|
|
226
258
|
);
|
|
227
259
|
}
|
|
228
260
|
return finishImage(body);
|
|
@@ -249,7 +281,7 @@ function usageFromTurnEnded(turnEnded: Record<string, unknown>): UsageRecord {
|
|
|
249
281
|
const input = count(turnEnded["input_tokens"]);
|
|
250
282
|
const output = count(turnEnded["output_tokens"]);
|
|
251
283
|
const cacheRead = count(turnEnded["cache_read"]);
|
|
252
|
-
return {
|
|
284
|
+
return applyCacheMode({
|
|
253
285
|
input_tokens: input,
|
|
254
286
|
cached_input_tokens: cacheRead,
|
|
255
287
|
cache_write_tokens: count(turnEnded["cache_write"]),
|
|
@@ -258,7 +290,7 @@ function usageFromTurnEnded(turnEnded: Record<string, unknown>): UsageRecord {
|
|
|
258
290
|
reasoning_tokens: count(turnEnded["reasoning_tokens"]),
|
|
259
291
|
estimated_cost: null,
|
|
260
292
|
total_tokens: input + output,
|
|
261
|
-
};
|
|
293
|
+
});
|
|
262
294
|
}
|
|
263
295
|
|
|
264
296
|
function nonEmptyStringOf(value: unknown): string | undefined {
|
|
@@ -503,7 +535,7 @@ class CursorAdapter implements ProviderAdapter {
|
|
|
503
535
|
throw new GatewayError(
|
|
504
536
|
"invalid_request",
|
|
505
537
|
400,
|
|
506
|
-
"This tool result cannot be matched to a live Cursor Run; resend the complete conversation.",
|
|
538
|
+
"This tool result cannot be matched to a live Cursor Run (request {requestId}); resend the complete conversation. The session went cold — reconnect or resend 🔌",
|
|
507
539
|
);
|
|
508
540
|
}
|
|
509
541
|
const resolvedAll = pending.map((item) => cursorRunSessions.resolveCall(item.callId, scope));
|
|
@@ -530,7 +562,7 @@ class CursorAdapter implements ProviderAdapter {
|
|
|
530
562
|
throw new GatewayError(
|
|
531
563
|
"invalid_request",
|
|
532
564
|
400,
|
|
533
|
-
"This tool result refers to a Cursor tool call that is no longer pending. Resend the complete conversation.",
|
|
565
|
+
"This tool result refers to a Cursor tool call that is no longer pending (request {requestId}). Resend the complete conversation. The session went cold — reconnect or resend 🔌",
|
|
534
566
|
{ callIds: pending.map((item) => item.callId) },
|
|
535
567
|
);
|
|
536
568
|
}
|
|
@@ -538,12 +570,12 @@ class CursorAdapter implements ProviderAdapter {
|
|
|
538
570
|
throw new GatewayError(
|
|
539
571
|
"invalid_request",
|
|
540
572
|
400,
|
|
541
|
-
"These tool results belong to different Cursor Runs; resend them one Run at a time.",
|
|
573
|
+
"These tool results belong to different Cursor Runs (request {requestId}); resend them one Run at a time. The session went cold — reconnect or resend 🔌",
|
|
542
574
|
);
|
|
543
575
|
}
|
|
544
576
|
const session = cursorRunSessions.get(runId);
|
|
545
577
|
if (session === undefined) {
|
|
546
|
-
throw new GatewayError("invalid_request", 400, "Cursor Run is no longer live");
|
|
578
|
+
throw new GatewayError("invalid_request", 400, "Cursor Run is no longer live (request {requestId}). The session went cold — reconnect or resend 🔌");
|
|
547
579
|
}
|
|
548
580
|
const handle = this.#handles.get(runId);
|
|
549
581
|
if (handle === undefined) {
|
|
@@ -605,7 +637,7 @@ class CursorAdapter implements ProviderAdapter {
|
|
|
605
637
|
throw new GatewayError(
|
|
606
638
|
"admission_unavailable",
|
|
607
639
|
503,
|
|
608
|
-
"Cursor requires validated HTTP/2 egress; none is configured for this route",
|
|
640
|
+
"Cursor requires validated HTTP/2 egress (request {requestId}); none is configured for this route. No bridge to cross — configure a pool first 🏗️",
|
|
609
641
|
{ providerId: CURSOR_PROVIDER_ID },
|
|
610
642
|
);
|
|
611
643
|
}
|
|
@@ -784,7 +816,7 @@ class CursorAdapter implements ProviderAdapter {
|
|
|
784
816
|
: new GatewayError(
|
|
785
817
|
"platform_unavailable",
|
|
786
818
|
502,
|
|
787
|
-
`Cursor Run failed: ${error instanceof Error ? error.message : String(error)}
|
|
819
|
+
`Cursor Run failed (request {requestId}): ${error instanceof Error ? error.message : String(error)}. The upstream came back empty-handed — retry 🌙`,
|
|
788
820
|
{ providerId: CURSOR_PROVIDER_ID },
|
|
789
821
|
"upstream",
|
|
790
822
|
);
|
|
@@ -828,7 +860,7 @@ class CursorAdapter implements ProviderAdapter {
|
|
|
828
860
|
throw new GatewayError(
|
|
829
861
|
"platform_unavailable",
|
|
830
862
|
502,
|
|
831
|
-
`Cursor Run origin could not be resolved: ${error instanceof Error ? error.message : String(error)}
|
|
863
|
+
`Cursor Run origin could not be resolved (request {requestId}): ${error instanceof Error ? error.message : String(error)}. The connection ghosted us — come back in a moment 👻`,
|
|
832
864
|
{ providerId: CURSOR_PROVIDER_ID },
|
|
833
865
|
"upstream",
|
|
834
866
|
);
|
|
@@ -846,7 +878,8 @@ class CursorAdapter implements ProviderAdapter {
|
|
|
846
878
|
credential: string,
|
|
847
879
|
context: ProviderDispatchContext,
|
|
848
880
|
): Promise<readonly CursorModelInfo[]> {
|
|
849
|
-
const
|
|
881
|
+
const key = String(fnv1a32(credential));
|
|
882
|
+
const cached = rosterCache.get(key);
|
|
850
883
|
if (cached !== undefined && Date.now() - cached.fetchedAt < CURSOR_ROSTER_TTL_MS) {
|
|
851
884
|
return cached.roster;
|
|
852
885
|
}
|
|
@@ -858,7 +891,7 @@ class CursorAdapter implements ProviderAdapter {
|
|
|
858
891
|
: { fetcher: context.outbound_fetch as unknown as typeof fetch }),
|
|
859
892
|
signal: context.abort_signal,
|
|
860
893
|
});
|
|
861
|
-
|
|
894
|
+
rosterCacheSet(credential, roster);
|
|
862
895
|
return roster;
|
|
863
896
|
} catch {
|
|
864
897
|
return cached?.roster ?? [];
|
|
@@ -890,7 +923,7 @@ class CursorAdapter implements ProviderAdapter {
|
|
|
890
923
|
}
|
|
891
924
|
const message = item;
|
|
892
925
|
if (context.abort_signal.aborted) {
|
|
893
|
-
failure = new GatewayError("transport_closed", 499, "request was cancelled");
|
|
926
|
+
failure = new GatewayError("transport_closed", 499, "The request was cancelled (request {requestId}). Send it again whenever ready 🙃");
|
|
894
927
|
break;
|
|
895
928
|
}
|
|
896
929
|
const execServer = recordOf(message["exec_server_message"]);
|
|
@@ -994,7 +1027,7 @@ class CursorAdapter implements ProviderAdapter {
|
|
|
994
1027
|
: new GatewayError(
|
|
995
1028
|
"platform_unavailable",
|
|
996
1029
|
502,
|
|
997
|
-
`Cursor Run failed: ${error instanceof Error ? error.message : String(error)}
|
|
1030
|
+
`Cursor Run failed (request {requestId}): ${error instanceof Error ? error.message : String(error)}. The upstream came back empty-handed — retry 🌙`,
|
|
998
1031
|
{ providerId: CURSOR_PROVIDER_ID },
|
|
999
1032
|
"upstream",
|
|
1000
1033
|
);
|
|
@@ -71,59 +71,3 @@ export function* streamFrames(buffer: Uint8Array): Generator<Frame, void, void>
|
|
|
71
71
|
offset = start + len
|
|
72
72
|
}
|
|
73
73
|
}
|
|
74
|
-
|
|
75
|
-
export async function* asyncStreamFrames(
|
|
76
|
-
stream: ReadableStream<Uint8Array>,
|
|
77
|
-
): AsyncGenerator<Frame, void, void> {
|
|
78
|
-
const reader = stream.getReader()
|
|
79
|
-
const chunks: Uint8Array[] = []
|
|
80
|
-
let pendingLength = 0
|
|
81
|
-
|
|
82
|
-
try {
|
|
83
|
-
while (true) {
|
|
84
|
-
const { done, value } = await reader.read()
|
|
85
|
-
if (done && chunks.length === 0) return
|
|
86
|
-
if (value) {
|
|
87
|
-
chunks.push(value)
|
|
88
|
-
pendingLength += value.length
|
|
89
|
-
}
|
|
90
|
-
|
|
91
|
-
// Try to parse frames from accumulated data
|
|
92
|
-
const merged = mergeChunks(chunks)
|
|
93
|
-
const frames = Array.from(streamFrames(merged))
|
|
94
|
-
const consumed = frames.reduce((sum, f) => sum + 5 + f.payload.length, 0)
|
|
95
|
-
|
|
96
|
-
if (frames.length > 0) {
|
|
97
|
-
for (const frame of frames) {
|
|
98
|
-
yield frame
|
|
99
|
-
}
|
|
100
|
-
// Keep any trailing bytes for next iteration
|
|
101
|
-
const remaining = merged.subarray(consumed)
|
|
102
|
-
chunks.length = 0
|
|
103
|
-
if (remaining.length > 0) {
|
|
104
|
-
chunks.push(remaining)
|
|
105
|
-
pendingLength = remaining.length
|
|
106
|
-
} else {
|
|
107
|
-
pendingLength = 0
|
|
108
|
-
}
|
|
109
|
-
}
|
|
110
|
-
|
|
111
|
-
if (done) return
|
|
112
|
-
}
|
|
113
|
-
} finally {
|
|
114
|
-
reader.releaseLock()
|
|
115
|
-
}
|
|
116
|
-
}
|
|
117
|
-
|
|
118
|
-
function mergeChunks(chunks: Uint8Array[]): Uint8Array {
|
|
119
|
-
const first = chunks[0]
|
|
120
|
-
if (chunks.length === 1 && first !== undefined) return first
|
|
121
|
-
const total = chunks.reduce((s, c) => s + c.length, 0)
|
|
122
|
-
const merged = new Uint8Array(total)
|
|
123
|
-
let offset = 0
|
|
124
|
-
for (const c of chunks) {
|
|
125
|
-
merged.set(c, offset)
|
|
126
|
-
offset += c.length
|
|
127
|
-
}
|
|
128
|
-
return merged
|
|
129
|
-
}
|
|
@@ -2282,99 +2282,3 @@ export function decodeMessage<T = Record<string, unknown>>(
|
|
|
2282
2282
|
const decoded = type.decode(data)
|
|
2283
2283
|
return type.toObject(decoded, { defaults: true, json: true, longs: Number }) as T
|
|
2284
2284
|
}
|
|
2285
|
-
|
|
2286
|
-
/** Decode without inventing absent proto defaults (used for byte-stable snapshots). */
|
|
2287
|
-
export function decodeMessageSparse<T = Record<string, unknown>>(
|
|
2288
|
-
typeName: string,
|
|
2289
|
-
data: Uint8Array,
|
|
2290
|
-
): T {
|
|
2291
|
-
const root = getMessageTypes()
|
|
2292
|
-
const type = root.lookupType(typeName)
|
|
2293
|
-
const decoded = type.decode(data)
|
|
2294
|
-
return type.toObject(decoded, { json: true, longs: Number }) as T
|
|
2295
|
-
}
|
|
2296
|
-
|
|
2297
|
-
type RawField = {
|
|
2298
|
-
field: number
|
|
2299
|
-
wireType: number
|
|
2300
|
-
varint?: string
|
|
2301
|
-
fixed?: number | string
|
|
2302
|
-
bytes?: Uint8Array
|
|
2303
|
-
}
|
|
2304
|
-
|
|
2305
|
-
/** Schema-free walk of one message's top-level wire fields (no nested descent). */
|
|
2306
|
-
function readRawFields(buf: Uint8Array): RawField[] {
|
|
2307
|
-
const reader = protobuf.Reader.create(buf)
|
|
2308
|
-
const fields: RawField[] = []
|
|
2309
|
-
while (reader.pos < reader.len) {
|
|
2310
|
-
const tag = reader.uint32()
|
|
2311
|
-
const field = tag >>> 3
|
|
2312
|
-
const wireType = tag & 7
|
|
2313
|
-
switch (wireType) {
|
|
2314
|
-
case 0:
|
|
2315
|
-
fields.push({ field, wireType, varint: reader.uint64().toString() })
|
|
2316
|
-
break
|
|
2317
|
-
case 1:
|
|
2318
|
-
fields.push({ field, wireType, fixed: reader.fixed64().toString() })
|
|
2319
|
-
break
|
|
2320
|
-
case 2:
|
|
2321
|
-
fields.push({ field, wireType, bytes: reader.bytes() })
|
|
2322
|
-
break
|
|
2323
|
-
case 5:
|
|
2324
|
-
fields.push({ field, wireType, fixed: reader.fixed32() })
|
|
2325
|
-
break
|
|
2326
|
-
default:
|
|
2327
|
-
// Groups (3/4) aren't used on this wire; bail rather than desync the reader.
|
|
2328
|
-
return fields
|
|
2329
|
-
}
|
|
2330
|
-
}
|
|
2331
|
-
return fields
|
|
2332
|
-
}
|
|
2333
|
-
|
|
2334
|
-
/**
|
|
2335
|
-
* Diagnostic-only: walk AgentServerMessage.interaction_update(1).turn_ended(14)
|
|
2336
|
-
* without going through our hand-written TurnEnded schema, so a `cache_write`/
|
|
2337
|
-
* `reasoning_tokens` question can be checked against the raw wire instead of
|
|
2338
|
-
* guessed. Confirmed field ids 1-5 (input/output/cache_read/cache_write/
|
|
2339
|
-
* reasoning) decode correctly. Live captures routinely include `f4` explicitly
|
|
2340
|
-
* as `0` while `f3` (cache_read) and `f5` (reasoning) are non-zero — Cursor's
|
|
2341
|
-
* agent TurnEnded populates the field but does not report write counts here.
|
|
2342
|
-
*/
|
|
2343
|
-
export function debugWalkTurnEnded(payload: Uint8Array): string {
|
|
2344
|
-
try {
|
|
2345
|
-
const top = readRawFields(payload)
|
|
2346
|
-
const iuField = top.find((f) => f.field === 1 && f.wireType === 2)
|
|
2347
|
-
if (!iuField?.bytes) return "(no interaction_update field)"
|
|
2348
|
-
const iu = readRawFields(iuField.bytes)
|
|
2349
|
-
const teField = iu.find((f) => f.field === 14 && f.wireType === 2)
|
|
2350
|
-
if (!teField?.bytes) return "(no turn_ended field in interaction_update)"
|
|
2351
|
-
const te = readRawFields(teField.bytes)
|
|
2352
|
-
return te
|
|
2353
|
-
.map(
|
|
2354
|
-
(f) =>
|
|
2355
|
-
`f${f.field}:wt${f.wireType}=${f.varint ?? f.fixed ?? (f.bytes ? `bytes[${f.bytes.length}]` : "?")}`,
|
|
2356
|
-
)
|
|
2357
|
-
.join(" ")
|
|
2358
|
-
} catch (e) {
|
|
2359
|
-
return `(walk failed: ${(e as Error).message})`
|
|
2360
|
-
}
|
|
2361
|
-
}
|
|
2362
|
-
|
|
2363
|
-
/**
|
|
2364
|
-
* Decode a protobuf sub-message from a frame payload that wraps it in
|
|
2365
|
-
* a top-level field key + length varint. Skips the outer wrapper and
|
|
2366
|
-
* decodes the inner body as `typeName`.
|
|
2367
|
-
*/
|
|
2368
|
-
export function decodeWrappedMessage<T = Record<string, unknown>>(
|
|
2369
|
-
typeName: string,
|
|
2370
|
-
data: Uint8Array,
|
|
2371
|
-
): T {
|
|
2372
|
-
let offset = 1 // skip field key
|
|
2373
|
-
// skip varint length
|
|
2374
|
-
while (offset < data.length) {
|
|
2375
|
-
const b = data[offset] ?? 0
|
|
2376
|
-
offset++
|
|
2377
|
-
if (!(b & 0x80)) break
|
|
2378
|
-
}
|
|
2379
|
-
return decodeMessage<T>(typeName, data.subarray(offset))
|
|
2380
|
-
}
|
|
@@ -106,7 +106,7 @@ function factoryClientHeaders(orgId: string): Record<string, string> {
|
|
|
106
106
|
* (`packages/ai/src/providers/factory-droid.ts:271` — `"x-api-provider":
|
|
107
107
|
* input.upstream`), so a value outside it has no meaning on this wire.
|
|
108
108
|
*/
|
|
109
|
-
|
|
109
|
+
const FACTORY_DROID_UPSTREAMS = [
|
|
110
110
|
"fireworks",
|
|
111
111
|
"baseten",
|
|
112
112
|
"mistral",
|
|
@@ -123,7 +123,7 @@ export const FACTORY_DROID_UPSTREAMS = [
|
|
|
123
123
|
"databricks",
|
|
124
124
|
] as const;
|
|
125
125
|
|
|
126
|
-
|
|
126
|
+
type FactoryDroidUpstream = (typeof FACTORY_DROID_UPSTREAMS)[number];
|
|
127
127
|
|
|
128
128
|
const FACTORY_DROID_UPSTREAM_SET: ReadonlySet<string> = new Set(FACTORY_DROID_UPSTREAMS);
|
|
129
129
|
|
|
@@ -154,7 +154,7 @@ function logDroppedUpstream(reason: string, value: string): void {
|
|
|
154
154
|
* unmapped failure. Omitting falls back to Factory's default routing, which is
|
|
155
155
|
* the behavior a request that names no upstream already gets.
|
|
156
156
|
*/
|
|
157
|
-
|
|
157
|
+
function factoryApiProviderHeader(
|
|
158
158
|
options: Readonly<Record<string, unknown>> | undefined,
|
|
159
159
|
): Record<string, string> {
|
|
160
160
|
const value = options?.["factory_api_provider"];
|
|
@@ -179,7 +179,7 @@ export function factoryApiProviderHeader(
|
|
|
179
179
|
* `/api/cli/whoami` reported. An account with no recorded residency is the
|
|
180
180
|
* global host, which is Factory's default.
|
|
181
181
|
*/
|
|
182
|
-
|
|
182
|
+
function factoryBaseUrl(context: ProviderDispatchContext): string {
|
|
183
183
|
const region = context.credential.auth_state?.["region"];
|
|
184
184
|
return region === "eu" ? FACTORY_DROID_EU_BASE_URL : FACTORY_DROID_BASE_URL;
|
|
185
185
|
}
|
|
@@ -200,7 +200,7 @@ export function factoryBaseUrl(context: ProviderDispatchContext): string {
|
|
|
200
200
|
* operator wrote into `auth_state`. The two-axis read is kept because the donor
|
|
201
201
|
* needs it, not because we currently populate the second axis.
|
|
202
202
|
*/
|
|
203
|
-
|
|
203
|
+
function factoryInferenceRegion(
|
|
204
204
|
context: ProviderDispatchContext,
|
|
205
205
|
): "global" | "us" | "eu" {
|
|
206
206
|
const state = context.credential.auth_state;
|
|
@@ -266,11 +266,11 @@ const REGION_UPSTREAMS: Readonly<Record<"global" | "us" | "eu", readonly Factory
|
|
|
266
266
|
* is, which is a property of the route rather than of the request. The donor's
|
|
267
267
|
* own message text is preserved as the `reason` so the mapping is traceable.
|
|
268
268
|
*/
|
|
269
|
-
|
|
269
|
+
function factoryRegionUnavailable(modelId: string, region: string): GatewayError {
|
|
270
270
|
return new GatewayError(
|
|
271
271
|
"capability_unsupported",
|
|
272
272
|
400,
|
|
273
|
-
`factory: ${modelId} is unavailable in this account region (${region})
|
|
273
|
+
`factory: ${modelId} is unavailable in this account region (${region}) (request {requestId}). Know your tools — this one just isn't in the box 🧰`,
|
|
274
274
|
{ model: modelId, region, reason: "Factory Droid model is unavailable in this account region." },
|
|
275
275
|
);
|
|
276
276
|
}
|
|
@@ -294,7 +294,7 @@ export function factoryRegionUnavailable(modelId: string, region: string): Gatew
|
|
|
294
294
|
* Sending `configured_order` without that discovery would claim a rotation we
|
|
295
295
|
* never resolved.
|
|
296
296
|
*/
|
|
297
|
-
|
|
297
|
+
function factoryRoutingSourceHeader(request: CanonicalRequest): Record<string, string> {
|
|
298
298
|
const continuing = request.messages.some((message) => message.role === "assistant");
|
|
299
299
|
return { "x-provider-routing-source": continuing ? "session_lock" : "registry_default" };
|
|
300
300
|
}
|
|
@@ -313,7 +313,7 @@ export function factoryRoutingSourceHeader(request: CanonicalRequest): Record<st
|
|
|
313
313
|
* donor's own region-unavailable error rather than an upstream 4xx this layer
|
|
314
314
|
* cannot explain.
|
|
315
315
|
*/
|
|
316
|
-
|
|
316
|
+
function factoryRegionCheckedApiProviderHeader(
|
|
317
317
|
request: CanonicalRequest,
|
|
318
318
|
context: ProviderDispatchContext,
|
|
319
319
|
): Record<string, string> {
|
|
@@ -330,7 +330,7 @@ export function factoryRegionCheckedApiProviderHeader(
|
|
|
330
330
|
}
|
|
331
331
|
|
|
332
332
|
/** The two routing headers together, as every Factory wire sends them. */
|
|
333
|
-
|
|
333
|
+
function factoryRoutingHeaders(
|
|
334
334
|
request: CanonicalRequest,
|
|
335
335
|
context: ProviderDispatchContext,
|
|
336
336
|
): Record<string, string> {
|
|
@@ -351,7 +351,7 @@ export function factoryRoutingHeaders(
|
|
|
351
351
|
function factoryEnvelope(context: ProviderDispatchContext): { token: string; orgId: string } {
|
|
352
352
|
const secret = context.credential.secret;
|
|
353
353
|
if (secret === undefined || secret.length === 0) {
|
|
354
|
-
throw new GatewayError("invalid_request", 400, "factory: credential is missing a secret value");
|
|
354
|
+
throw new GatewayError("invalid_request", 400, "factory: credential is missing a secret value (request {requestId}). Wrong key, right door — check the credential 🔑");
|
|
355
355
|
}
|
|
356
356
|
try {
|
|
357
357
|
const envelope = decodeFactoryDroidCredential(secret);
|
|
@@ -360,7 +360,7 @@ function factoryEnvelope(context: ProviderDispatchContext): { token: string; org
|
|
|
360
360
|
throw new GatewayError(
|
|
361
361
|
"invalid_request",
|
|
362
362
|
400,
|
|
363
|
-
`factory: ${error instanceof Error ? error.message : "stored credential is not a Factory Droid envelope"}
|
|
363
|
+
`factory: ${error instanceof Error ? error.message : "stored credential is not a Factory Droid envelope"} (request {requestId}). Wrong key, right door — check the credential 🔑`,
|
|
364
364
|
);
|
|
365
365
|
}
|
|
366
366
|
}
|
|
@@ -523,7 +523,7 @@ class FactoryDroidAdapter implements ProviderAdapter {
|
|
|
523
523
|
throw new GatewayError(
|
|
524
524
|
"platform_unavailable",
|
|
525
525
|
502,
|
|
526
|
-
"factory gemini returned empty stream",
|
|
526
|
+
"factory gemini returned empty stream (request {requestId}). The upstream came back empty-handed — retry 🌙",
|
|
527
527
|
{},
|
|
528
528
|
"upstream",
|
|
529
529
|
);
|
|
@@ -6,7 +6,7 @@ import { mapUpstreamHttpError } from "../../transport/failure-policy";
|
|
|
6
6
|
import type { CanonicalEvent, CanonicalRequest, CanonicalStopReason } from "../../protocol/canonical-model";
|
|
7
7
|
import { decodeSseEvents } from "../../protocol/sse-decoder";
|
|
8
8
|
import { usageFromProvider } from "../provider-usage";
|
|
9
|
-
import { readCredentialSecret, type ImageGenerationOutcome, type ProviderDispatchTarget, type ProviderAdapter, type ProviderDispatchContext, type WebSearchOutcome, type WebSearchResult } from "../provider-contracts";
|
|
9
|
+
import { readCredentialSecret, assertWireFamily, type ImageGenerationOutcome, type ProviderDispatchTarget, type ProviderAdapter, type ProviderDispatchContext, type WebSearchOutcome, type WebSearchResult } from "../provider-contracts";
|
|
10
10
|
import type { ModelDefinition } from "../provider-model-definition";
|
|
11
11
|
import { fetchOpenAICompatibleModels } from "../discovery/openai-model-discovery";
|
|
12
12
|
import { isRecord } from "../../protocol/codecs";
|
|
@@ -181,7 +181,7 @@ class GeminiAdapter implements ProviderAdapter {
|
|
|
181
181
|
context: ProviderDispatchContext,
|
|
182
182
|
): AsyncIterable<CanonicalEvent> {
|
|
183
183
|
if (candidate.wire_family !== "chat" && candidate.wire_family !== "responses" && candidate.wire_family !== "messages") {
|
|
184
|
-
|
|
184
|
+
assertWireFamily(candidate, ["chat", "responses", "messages"], "gemini");
|
|
185
185
|
}
|
|
186
186
|
const apiKey = readCredentialSecret(context.credential, "Gemini API key is required");
|
|
187
187
|
|
|
@@ -262,7 +262,7 @@ class GeminiAdapter implements ProviderAdapter {
|
|
|
262
262
|
return;
|
|
263
263
|
}
|
|
264
264
|
|
|
265
|
-
if (!response.body) throw new GatewayError("platform_unavailable", 502, "Gemini returned empty stream", {}, "upstream");
|
|
265
|
+
if (!response.body) throw new GatewayError("platform_unavailable", 502, "Gemini returned empty stream (request {requestId}). The upstream came back empty-handed — retry 🌙", {}, "upstream");
|
|
266
266
|
let seq = 1;
|
|
267
267
|
yield { type: "response_start", sequence_number: seq++, model: request.model } as CanonicalEvent;
|
|
268
268
|
const state = { started: true, stopped: false, activeCalls: new Set<string>() };
|
|
@@ -339,7 +339,7 @@ class GeminiAdapter implements ProviderAdapter {
|
|
|
339
339
|
context: ProviderDispatchContext,
|
|
340
340
|
): Promise<WebSearchOutcome> {
|
|
341
341
|
const query = typeof body.query === "string" ? body.query.trim() : "";
|
|
342
|
-
if (!query) throw new GatewayError("invalid_request", 400, "search query is required");
|
|
342
|
+
if (!query) throw new GatewayError("invalid_request", 400, "search query is required (request {requestId}). Check the shape of what you sent — then resend 🪞");
|
|
343
343
|
const rawMax = body.max_results;
|
|
344
344
|
const maxResults =
|
|
345
345
|
typeof rawMax === "number" && Number.isFinite(rawMax)
|
|
@@ -368,7 +368,7 @@ class GeminiAdapter implements ProviderAdapter {
|
|
|
368
368
|
throw new GatewayError(
|
|
369
369
|
"platform_unavailable",
|
|
370
370
|
502,
|
|
371
|
-
`Gemini search unreachable: ${error instanceof Error ? error.message : String(error)}
|
|
371
|
+
`Gemini search unreachable (request {requestId}): ${error instanceof Error ? error.message : String(error)}. The connection ghosted us — come back in a moment 👻`,
|
|
372
372
|
);
|
|
373
373
|
}
|
|
374
374
|
if (!response.ok) throw await mapUpstreamHttpError(response, "gemini search");
|
|
@@ -376,11 +376,11 @@ class GeminiAdapter implements ProviderAdapter {
|
|
|
376
376
|
try {
|
|
377
377
|
data = await response.json();
|
|
378
378
|
} catch {
|
|
379
|
-
throw new GatewayError("platform_unavailable", 502, "Gemini search returned invalid JSON");
|
|
379
|
+
throw new GatewayError("platform_unavailable", 502, "Gemini search returned invalid JSON (request {requestId}). The upstream came back empty-handed — retry 🌙");
|
|
380
380
|
}
|
|
381
381
|
const results = normalizeGroundingResults(data, maxResults);
|
|
382
382
|
if (results.length === 0)
|
|
383
|
-
throw new GatewayError("platform_unavailable", 502, "Gemini search returned no grounded results");
|
|
383
|
+
throw new GatewayError("platform_unavailable", 502, "Gemini search returned no grounded results (request {requestId}). The upstream came back empty-handed — retry 🌙");
|
|
384
384
|
return { results, total_results: results.length };
|
|
385
385
|
}
|
|
386
386
|
|
|
@@ -391,7 +391,7 @@ class GeminiAdapter implements ProviderAdapter {
|
|
|
391
391
|
): Promise<ImageGenerationOutcome> {
|
|
392
392
|
const prompt = imagePrompt(body);
|
|
393
393
|
const model = candidate.model_id.length > 0 ? candidate.model_id : typeof body.model === "string" ? body.model : "";
|
|
394
|
-
if (model.length === 0) throw new GatewayError("invalid_request", 400, "model is required");
|
|
394
|
+
if (model.length === 0) throw new GatewayError("invalid_request", 400, "model is required (request {requestId}). Check the shape of what you sent — then resend 🪞");
|
|
395
395
|
const apiKey = readCredentialSecret(context.credential, "Gemini API key is required");
|
|
396
396
|
const outboundFetch = context.outbound_fetch ?? this.fetchFn;
|
|
397
397
|
const lifecycle = createUpstreamDeadlineLifecycle(context);
|
|
@@ -418,7 +418,7 @@ class GeminiAdapter implements ProviderAdapter {
|
|
|
418
418
|
throw new GatewayError(
|
|
419
419
|
"platform_unavailable",
|
|
420
420
|
502,
|
|
421
|
-
`Gemini image generation unreachable: ${error instanceof Error ? error.message : String(error)}
|
|
421
|
+
`Gemini image generation unreachable (request {requestId}): ${error instanceof Error ? error.message : String(error)}. The connection ghosted us — come back in a moment 👻`,
|
|
422
422
|
{},
|
|
423
423
|
"upstream",
|
|
424
424
|
);
|
|
@@ -430,11 +430,11 @@ class GeminiAdapter implements ProviderAdapter {
|
|
|
430
430
|
try {
|
|
431
431
|
data = await response.json();
|
|
432
432
|
} catch {
|
|
433
|
-
throw new GatewayError("platform_unavailable", 502, "Gemini image generation returned invalid JSON", {}, "upstream");
|
|
433
|
+
throw new GatewayError("platform_unavailable", 502, "Gemini image generation returned invalid JSON (request {requestId}). The upstream came back empty-handed — retry 🌙", {}, "upstream");
|
|
434
434
|
}
|
|
435
435
|
const images = geminiInlineImages(data);
|
|
436
436
|
if (images.length === 0) {
|
|
437
|
-
throw new GatewayError("platform_unavailable", 502, "Gemini image generation returned no image", {}, "upstream");
|
|
437
|
+
throw new GatewayError("platform_unavailable", 502, "Gemini image generation returned no image (request {requestId}). The upstream came back empty-handed — retry 🌙", {}, "upstream");
|
|
438
438
|
}
|
|
439
439
|
return { created: imageCreatedSeconds(), data: images };
|
|
440
440
|
}
|