cartethyia 2.7.3 → 2.7.4
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/dist/dashboard/assets/{BannedPage-2TJD37Hb.js → BannedPage-ChG5svFb.js} +1 -1
- package/dist/dashboard/assets/BannedPage-ChG5svFb.js.gz +0 -0
- package/dist/dashboard/assets/{CliToolDetailPage-xefJNRmJ.js → CliToolDetailPage-BIcWQun7.js} +1 -1
- package/dist/dashboard/assets/CliToolDetailPage-BIcWQun7.js.gz +0 -0
- package/dist/dashboard/assets/{CliToolsPage-Rj9iHQ3F.js → CliToolsPage-Bf2VelDe.js} +1 -1
- package/dist/dashboard/assets/CliToolsPage-Bf2VelDe.js.gz +0 -0
- package/dist/dashboard/assets/{CombosPage-JEbYJFxw.js → CombosPage-DCgm5g6g.js} +1 -1
- package/dist/dashboard/assets/CombosPage-DCgm5g6g.js.gz +0 -0
- package/dist/dashboard/assets/ConsoleLogPage-a8mD0QF1.js +1 -0
- package/dist/dashboard/assets/ConsoleLogPage-a8mD0QF1.js.gz +0 -0
- package/dist/dashboard/assets/CustomizationPage-ggeMSjte.js +1 -0
- package/dist/dashboard/assets/CustomizationPage-ggeMSjte.js.gz +0 -0
- package/dist/dashboard/assets/HealthEventsModal-DzSWzE_j.js +1 -0
- package/dist/dashboard/assets/HealthEventsModal-DzSWzE_j.js.gz +0 -0
- package/dist/dashboard/assets/{LoginPage-C4w7vea-.js → LoginPage-U6AKaJcF.js} +1 -1
- package/dist/dashboard/assets/LoginPage-U6AKaJcF.js.gz +0 -0
- package/dist/dashboard/assets/{ModelPicker-BtPcAfot.js → ModelPicker-BMS2t8BA.js} +1 -1
- package/dist/dashboard/assets/ModelPicker-BMS2t8BA.js.gz +0 -0
- package/dist/dashboard/assets/OverviewPage-D2D4IiHl.js +1 -0
- package/dist/dashboard/assets/OverviewPage-D2D4IiHl.js.gz +0 -0
- package/dist/dashboard/assets/ProviderDetailPage-CrNf7j_X.js +5 -0
- package/dist/dashboard/assets/ProviderDetailPage-CrNf7j_X.js.gz +0 -0
- package/dist/dashboard/assets/ProvidersPage-BSDbquc1.js +1 -0
- package/dist/dashboard/assets/ProvidersPage-BSDbquc1.js.gz +0 -0
- package/dist/dashboard/assets/ProxyPage-lsrx7NYg.js +9 -0
- package/dist/dashboard/assets/ProxyPage-lsrx7NYg.js.gz +0 -0
- package/dist/dashboard/assets/QuotaPage-L0skzML8.js +1 -0
- package/dist/dashboard/assets/QuotaPage-L0skzML8.js.gz +0 -0
- package/dist/dashboard/assets/SettingsPage-CmAbjRHW.js +1 -0
- package/dist/dashboard/assets/SettingsPage-CmAbjRHW.js.gz +0 -0
- package/dist/dashboard/assets/{SetupPage-BQS0Rx_u.js → SetupPage-f0DE1h0-.js} +1 -1
- package/dist/dashboard/assets/SetupPage-f0DE1h0-.js.gz +0 -0
- package/dist/dashboard/assets/{SortableList-BAL5npBC.js → SortableList-ClzpwyET.js} +1 -1
- package/dist/dashboard/assets/SortableList-ClzpwyET.js.gz +0 -0
- package/dist/dashboard/assets/{StudioPage-TP7voAQ0.js → StudioPage-Cq5tW7hW.js} +3 -3
- package/dist/dashboard/assets/StudioPage-Cq5tW7hW.js.gz +0 -0
- package/dist/dashboard/assets/UsagePage-Dfc9rWQn.js +56 -0
- package/dist/dashboard/assets/UsagePage-Dfc9rWQn.js.gz +0 -0
- package/dist/dashboard/assets/api-keys-C38iXoO4.js +1 -0
- package/dist/dashboard/assets/api-keys-C38iXoO4.js.gz +0 -0
- package/dist/dashboard/assets/app-a159k0ub.css +2 -0
- package/dist/dashboard/assets/app-a159k0ub.css.gz +0 -0
- package/dist/dashboard/assets/assert-DbRA8EG2.js +15 -0
- package/dist/dashboard/assets/assert-DbRA8EG2.js.gz +0 -0
- package/dist/dashboard/assets/{badge-B_DMpMJN.js → badge-D9CS6dZk.js} +1 -1
- package/dist/dashboard/assets/badge-D9CS6dZk.js.gz +0 -0
- package/dist/dashboard/assets/{banner-DMrMPmth.js → banner-DympBNq4.js} +1 -1
- package/dist/dashboard/assets/banner-DympBNq4.js.gz +0 -0
- package/dist/dashboard/assets/{card-Be5Uzamx.js → card-ibRWU_uT.js} +1 -1
- package/dist/dashboard/assets/card-ibRWU_uT.js.gz +0 -0
- package/dist/dashboard/assets/cli-tools-63qBGaRw.js +1 -0
- package/dist/dashboard/assets/cli-tools-63qBGaRw.js.gz +0 -0
- package/dist/dashboard/assets/{clipboard-button-DOfrVmsi.js → clipboard-button-DJm-9pz7.js} +1 -1
- package/dist/dashboard/assets/clipboard-button-DJm-9pz7.js.gz +0 -0
- package/dist/dashboard/assets/{dialog-C9omdjQt.js → dialog-8fiE6tec.js} +1 -1
- package/dist/dashboard/assets/dialog-8fiE6tec.js.gz +0 -0
- package/dist/dashboard/assets/{drawer-Bm8WKaGY.js → drawer-CqGYeOrd.js} +1 -1
- package/dist/dashboard/assets/drawer-CqGYeOrd.js.gz +0 -0
- package/dist/dashboard/assets/{entry-q5HwZ8nN.js → entry-BSAsYsmV.js} +1 -1
- package/dist/dashboard/assets/entry-BSAsYsmV.js.gz +0 -0
- package/dist/dashboard/assets/entry-CiIQULZD.js +4 -0
- package/dist/dashboard/assets/entry-CiIQULZD.js.gz +0 -0
- package/dist/dashboard/assets/entry-Daz0lJ-W.js +1 -0
- package/dist/dashboard/assets/entry-Daz0lJ-W.js.gz +0 -0
- package/dist/dashboard/assets/{formatters-BTScrQpe.js → formatters-D-MTJxMr.js} +1 -1
- package/dist/dashboard/assets/formatters-D-MTJxMr.js.gz +0 -0
- package/dist/dashboard/assets/{github-badge-Orjuzemr.js → github-badge-CPK47xQx.js} +1 -1
- package/dist/dashboard/assets/github-badge-CPK47xQx.js.gz +0 -0
- package/dist/dashboard/assets/{index-cPrX5vn6.js → index-DBNPOfhV.js} +2 -2
- package/dist/dashboard/assets/index-DBNPOfhV.js.gz +0 -0
- package/dist/dashboard/assets/{inline-Dvux8w-0.js → inline-BT0zntEr.js} +1 -1
- package/dist/dashboard/assets/inline-BT0zntEr.js.gz +0 -0
- package/dist/dashboard/assets/{input-CU1Rgf3p.js → input-Da2ZViWg.js} +1 -1
- package/dist/dashboard/assets/input-Da2ZViWg.js.gz +0 -0
- package/dist/dashboard/assets/{layout-C_7A6H55.js → layout-BXNeLw6M.js} +1 -1
- package/dist/dashboard/assets/layout-BXNeLw6M.js.gz +0 -0
- package/dist/dashboard/assets/{list-row-CzFvogbj.js → list-row-BycOrrIV.js} +1 -1
- package/dist/dashboard/assets/list-row-BycOrrIV.js.gz +0 -0
- package/dist/dashboard/assets/live-DCQNZpF7.js +1 -0
- package/dist/dashboard/assets/live-DCQNZpF7.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-9Yj2ZyLo.js +1 -0
- package/dist/dashboard/assets/network-9Yj2ZyLo.js.gz +0 -0
- package/dist/dashboard/assets/{numbers-BNDZnsUE.js → numbers-CEagj6ZZ.js} +2 -2
- package/dist/dashboard/assets/numbers-CEagj6ZZ.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-Caw7wqci.js +1 -0
- package/dist/dashboard/assets/quota-Caw7wqci.js.gz +0 -0
- package/dist/dashboard/assets/routing-CO9zCUus.js +1 -0
- package/dist/dashboard/assets/routing-CO9zCUus.js.gz +0 -0
- package/dist/dashboard/assets/{select-B3iTetHN.js → select-BIYIBkMU.js} +2 -2
- package/dist/dashboard/assets/select-BIYIBkMU.js.gz +0 -0
- package/dist/dashboard/assets/settings-jS3-PNSA.js +1 -0
- package/dist/dashboard/assets/settings-jS3-PNSA.js.gz +0 -0
- package/dist/dashboard/assets/{stack-KrOrm7JZ.js → stack-DfgnFDWY.js} +1 -1
- package/dist/dashboard/assets/stack-DfgnFDWY.js.gz +0 -0
- package/dist/dashboard/assets/{state-DLS7IDMy.js → state-CkfdYWel.js} +1 -1
- package/dist/dashboard/assets/state-CkfdYWel.js.gz +0 -0
- package/dist/dashboard/assets/{switch-42ItvbAs.js → switch-SYm237HG.js} +1 -1
- package/dist/dashboard/assets/switch-SYm237HG.js.gz +0 -0
- package/dist/dashboard/assets/{useMutation-Dmnfh1Ue.js → useMutation-BQqCRNIi.js} +1 -1
- package/dist/dashboard/assets/useMutation-BQqCRNIi.js.gz +0 -0
- package/dist/dashboard/index.html +2 -2
- package/dist/dashboard/index.html.gz +0 -0
- package/dist/dashboard/precompressed-assets.json +55 -54
- 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/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/package.json +2 -1
- package/src/boot/app.ts +9 -8
- package/src/config/network.ts +7 -3
- package/src/console/api-keys/contracts.ts +52 -0
- package/src/console/api-keys/routes.ts +93 -4
- package/src/console/audit/routes.ts +3 -3
- package/src/console/auth/account-reset.ts +4 -4
- package/src/console/auth/session.ts +3 -3
- package/src/console/backup/contracts.ts +2 -0
- package/src/console/backup/export-endpoint.ts +6 -6
- package/src/console/backup/routes.ts +3 -3
- package/src/console/cli-tools/routes.ts +3 -3
- package/src/console/console-router-guards.ts +2 -2
- package/src/console/console-router.ts +4 -4
- package/src/console/data-management/routes.ts +3 -3
- package/src/console/domain-registration.ts +2 -2
- package/src/console/observability/contracts.ts +4 -0
- package/src/console/observability/live.ts +3 -3
- package/src/console/observability/logs.ts +3 -3
- package/src/console/observability/performance.ts +3 -3
- package/src/console/observability/routes.ts +3 -3
- package/src/console/observability/store.ts +16 -16
- package/src/console/providers/catalog/contracts.ts +43 -22
- package/src/console/providers/catalog/provider-operations.ts +17 -2
- package/src/console/providers/catalog/routes.ts +3 -3
- package/src/console/providers/catalog/store-helpers.ts +349 -326
- package/src/console/providers/catalog/store.ts +1523 -1292
- package/src/console/providers/detail/routes.ts +3 -3
- package/src/console/providers/oauth/routes.ts +3 -3
- package/src/console/quota/account-quota-tenant.ts +26 -1
- package/src/console/quota/account-test-egress.ts +4 -4
- package/src/console/routing/model/routes.ts +3 -3
- package/src/console/routing/pools/contracts.ts +11 -8
- 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 +9 -9
- package/src/console/routing/pools/routes.ts +3 -3
- package/src/console/routing/pools/store.ts +21 -1
- package/src/console/settings/routes.ts +3 -3
- package/src/console/share/share-router.ts +12 -12
- package/src/console/share/share-stats.ts +105 -35
- package/src/console/shared/read-through-cache.ts +38 -2
- package/src/console/updates/routes.ts +7 -4
- package/src/network/outbound-fetch.ts +75 -4
- package/src/network/pool/resolver.ts +39 -39
- package/src/network/pool-cooldown-store.ts +71 -16
- package/src/network/pool-health-machine.ts +21 -1
- package/src/network/rate-limit-verdict.ts +68 -0
- package/src/network/ssrf.ts +4 -4
- package/src/observability/event-query.ts +320 -16
- package/src/observability/telemetry-status.ts +1 -1
- package/src/persistence/db-sqlite.ts +7 -2
- package/src/persistence/readiness.ts +18 -6
- package/src/persistence/schema.ts +66 -7
- package/src/persistence/stores/api-key-store.ts +99 -3
- package/src/persistence/stores/telemetry-store.ts +1 -1
- package/src/protocol/codecs.ts +6 -6
- package/src/protocol/gateway-error.ts +6 -3
- package/src/protocol/image-generation.ts +2 -2
- package/src/protocol/response/chat.ts +2 -2
- package/src/protocol/response/codex.ts +1 -1
- package/src/protocol/response/gemini.ts +1 -1
- package/src/protocol/response/messages.ts +5 -5
- package/src/protocol/response/responses.ts +2 -2
- package/src/protocol/sse-decoder.ts +14 -3
- package/src/protocol/translation/capabilities.ts +2 -2
- 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 +2 -2
- package/src/providers/authentication/oauth-refresh-service.ts +2 -2
- package/src/providers/configured-provider.ts +1 -1
- package/src/providers/discovery/probe-phases.ts +2 -2
- package/src/providers/discovery/probing-service.ts +12 -12
- package/src/providers/integrations/agentrouter/agentrouter.ts +2 -3
- package/src/providers/integrations/alibabacp/alibabacp.ts +2 -2
- package/src/providers/integrations/anthropic.ts +4 -11
- package/src/providers/integrations/antigravity/antigravity.ts +13 -24
- package/src/providers/integrations/buddy/buddy-catalog-shared.ts +1 -1
- package/src/providers/integrations/buddy/buddy-discovery-shared.ts +37 -6
- package/src/providers/integrations/buddy/buddy-identity.ts +22 -1
- package/src/providers/integrations/buddy/buddy-media.ts +16 -16
- package/src/providers/integrations/buddy/codebuddy/provider.ts +1 -1
- package/src/providers/integrations/buddy/workbuddy/provider.ts +1 -1
- package/src/providers/integrations/claude/claude-betas.ts +1 -1
- 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/cline/cline.ts +1 -1
- package/src/providers/integrations/cloudflareai/cloudflareai.ts +4 -7
- package/src/providers/integrations/codex/codex-errors.ts +1 -1
- package/src/providers/integrations/codex/codex.ts +14 -15
- package/src/providers/integrations/commandcode/commandcode.ts +4 -4
- package/src/providers/integrations/commandcode/quota.ts +5 -1
- package/src/providers/integrations/cursor/cursor-http2.ts +11 -11
- package/src/providers/integrations/cursor/cursor.ts +15 -15
- package/src/providers/integrations/factory/factory.ts +4 -4
- package/src/providers/integrations/gemini.ts +11 -11
- package/src/providers/integrations/github/github.ts +6 -6
- package/src/providers/integrations/grok/grok.ts +2 -6
- package/src/providers/integrations/inferhub.ts +4 -11
- package/src/providers/integrations/kimi/kimi.ts +4 -11
- package/src/providers/integrations/kiro/kiro.ts +10 -10
- package/src/providers/integrations/muse/muse.ts +6 -9
- package/src/providers/integrations/perplexity.ts +2 -2
- package/src/providers/integrations/qoder/qoder-catalog.ts +47 -9
- 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-realm.ts +15 -0
- package/src/providers/integrations/qoder/qoder-umid.ts +12 -13
- package/src/providers/integrations/qoder/qoder-virtual.ts +2 -2
- package/src/providers/integrations/qoder/qoder.ts +188 -22
- package/src/providers/integrations/tokenharbor.ts +2 -2
- package/src/providers/integrations/trae/trae.ts +6 -9
- package/src/providers/integrations/zcode/oauth.ts +1 -1
- package/src/providers/operations/provider-catalog-service.ts +4 -4
- package/src/providers/operations/provider-credential-service.ts +16 -4
- package/src/providers/operations/upstream-deadline.ts +3 -3
- package/src/providers/provider-contracts.ts +47 -3
- package/src/providers/provider-credential-resolver.ts +1 -1
- package/src/providers/provider-registry.ts +4 -4
- package/src/providers/quota/quota-contracts.ts +24 -10
- package/src/providers/quota/refresh.ts +2 -2
- package/src/providers/search/search-provider.ts +5 -5
- package/src/security/abuse.ts +4 -4
- package/src/security/admission/reasons.ts +17 -17
- package/src/security/api-key-auth.ts +4 -4
- package/src/shared/coerce.ts +19 -0
- package/src/transport/dispatch/attempt-finalize.ts +4 -3
- package/src/transport/dispatch/attempt-loop.ts +10 -7
- package/src/transport/dispatch/empty-stream.ts +6 -6
- package/src/transport/dispatch/generation.ts +9 -9
- package/src/transport/dispatch/leases.ts +8 -8
- package/src/transport/dispatch/proxy-request.ts +7 -7
- package/src/transport/dispatch/responses-compact.ts +11 -11
- package/src/transport/dispatch/retry-policy.ts +4 -67
- package/src/transport/dispatch/stream-bridge.ts +1 -1
- package/src/transport/dispatch/streaming/finalize.ts +9 -8
- package/src/transport/dispatch/systemone.ts +8 -8
- package/src/transport/dispatch/token-count.ts +9 -9
- package/src/transport/dispatch/websearch.ts +6 -6
- package/src/transport/drain-endpoint.ts +2 -2
- package/src/transport/failure-policy.ts +13 -6
- package/src/transport/guards/auth-guard.ts +6 -5
- package/src/transport/guards/body-policy.ts +4 -4
- 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 +1 -1
- package/src/transport/guards/pipeline.ts +6 -6
- package/src/transport/guards/readiness-guard.ts +16 -2
- package/src/transport/guards/request-context.ts +3 -3
- package/src/transport/request/preparer.ts +20 -20
- package/src/transport/request/state.ts +4 -7
- package/src/transport/routing/route-catalog.ts +97 -2
- package/src/transport/routing/route-model.ts +7 -7
- package/src/transport/routing/router.ts +2 -2
- package/src/transport/shutdown-notice.ts +19 -7
- package/src/transport/surface/completion.ts +1 -1
- package/src/transport/surface/messages/encode.ts +1 -1
- 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.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/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.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 +0 -1
- 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 +0 -1
- 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/layout-C_7A6H55.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.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 +0 -1
- 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/switch-42ItvbAs.js.gz +0 -0
- package/dist/dashboard/assets/useMutation-Dmnfh1Ue.js.gz +0 -0
- /package/dist/dashboard/assets/{app-wvwCi4Eh.js → app-BayTTy01.js} +0 -0
- /package/dist/dashboard/assets/{app-wvwCi4Eh.js.gz → app-BayTTy01.js.gz} +0 -0
|
@@ -16,6 +16,7 @@
|
|
|
16
16
|
* protocol at the `/anthropic` path suffix, including `thinking_delta`
|
|
17
17
|
* blocks, so the Messages leg is built directly.
|
|
18
18
|
*/
|
|
19
|
+
import { assertWireFamily } from "../../provider-contracts";
|
|
19
20
|
import type {
|
|
20
21
|
ProviderAdapter,
|
|
21
22
|
ProviderDispatchContext,
|
|
@@ -57,7 +58,7 @@ function cloudflareEnvelope(context: ProviderDispatchContext): {
|
|
|
57
58
|
} {
|
|
58
59
|
const secret = context.credential.secret;
|
|
59
60
|
if (secret === undefined || secret.length === 0) {
|
|
60
|
-
throw new GatewayError("invalid_request", 400, "cloudflareai: credential is missing a secret value");
|
|
61
|
+
throw new GatewayError("invalid_request", 400, "cloudflareai: credential is missing a secret value (request {requestId}). Wrong key, right door — check the credential 🔑");
|
|
61
62
|
}
|
|
62
63
|
let envelope: ReturnType<typeof decodeCloudflareAiGatewayCredential>;
|
|
63
64
|
try {
|
|
@@ -66,7 +67,7 @@ function cloudflareEnvelope(context: ProviderDispatchContext): {
|
|
|
66
67
|
throw new GatewayError(
|
|
67
68
|
"invalid_request",
|
|
68
69
|
400,
|
|
69
|
-
`cloudflareai: ${error instanceof Error ? error.message : "stored credential is not a Cloudflare envelope"}
|
|
70
|
+
`cloudflareai: ${error instanceof Error ? error.message : "stored credential is not a Cloudflare envelope"} (request {requestId}). Wrong key, right door — check the credential 🔑`,
|
|
70
71
|
);
|
|
71
72
|
}
|
|
72
73
|
return { token: envelope.token, baseUrl: cloudflareBaseUrl(envelope.accountId, envelope.gatewayId) };
|
|
@@ -93,11 +94,7 @@ class CloudflareAiGatewayAdapter implements ProviderAdapter {
|
|
|
93
94
|
context: ProviderDispatchContext,
|
|
94
95
|
): AsyncIterable<CanonicalEvent> {
|
|
95
96
|
if (candidate.wire_family !== "messages") {
|
|
96
|
-
|
|
97
|
-
"capability_unsupported",
|
|
98
|
-
400,
|
|
99
|
-
`cloudflareai supports messages only, got ${candidate.wire_family}`,
|
|
100
|
-
);
|
|
97
|
+
assertWireFamily(candidate, "messages", "cloudflareai");
|
|
101
98
|
}
|
|
102
99
|
const { token, baseUrl } = cloudflareEnvelope(context);
|
|
103
100
|
const outbound = buildClaudeMessagesRequest({
|
|
@@ -167,7 +167,7 @@ export async function mapCodexErrorResponse(res: Response): Promise<never> {
|
|
|
167
167
|
throw new GatewayError(
|
|
168
168
|
classification.code,
|
|
169
169
|
classification.status,
|
|
170
|
-
friendlyMessage ?? sanitized
|
|
170
|
+
`${friendlyMessage ?? sanitized} (request {requestId}). The upstream came back empty-handed — retry 🌙`,
|
|
171
171
|
details,
|
|
172
172
|
classification.origin,
|
|
173
173
|
);
|
|
@@ -22,7 +22,7 @@
|
|
|
22
22
|
* OpenAI-compatible factory's reach — stays bespoke, never re-audit.
|
|
23
23
|
*/
|
|
24
24
|
import type { CanonicalEvent, CanonicalRequest } from "../../../protocol/canonical-model";
|
|
25
|
-
import { GatewayError
|
|
25
|
+
import { GatewayError } from "../../../protocol/gateway-error";
|
|
26
26
|
import { getCodexVersion } from "../../operations/client-versions";
|
|
27
27
|
import { buildCodexUserAgent } from "../../operations/cli-platform";
|
|
28
28
|
import { randomUUID } from "node:crypto";
|
|
@@ -54,6 +54,7 @@ export function _setCodexRateLimitSleepForTesting(
|
|
|
54
54
|
function sleep(ms: number, signal: AbortSignal): Promise<void> {
|
|
55
55
|
return rateLimitSleep(ms, signal);
|
|
56
56
|
}
|
|
57
|
+
import { assertWireFamily } from "../../provider-contracts";
|
|
57
58
|
import type { ImageGenerationOutcome, ProviderDispatchTarget, ProviderAdapter, ProviderDispatchContext, ResolvedCredential, WebSearchOutcome, WebSearchResult } from "../../provider-contracts";
|
|
58
59
|
import type { FetchLike } from "../../quota/quota-contracts";
|
|
59
60
|
import { boundedUpstreamArray, boundedUpstreamNumber, sanitizeUpstreamLabel } from "../../provider-sanitize";
|
|
@@ -199,7 +200,7 @@ export function assertCodexOAuthCredential(
|
|
|
199
200
|
throw new GatewayError(
|
|
200
201
|
"invalid_request",
|
|
201
202
|
400,
|
|
202
|
-
`codex: ChatGPT OAuth credential required (got credential_kind=${credential.credential_kind})
|
|
203
|
+
`codex: ChatGPT OAuth credential required (got credential_kind=${credential.credential_kind}) (request {requestId}). Wrong key, right door — check the credential 🔑`,
|
|
203
204
|
);
|
|
204
205
|
}
|
|
205
206
|
}
|
|
@@ -361,7 +362,7 @@ function authHeadersForCodex(
|
|
|
361
362
|
throw new GatewayError(
|
|
362
363
|
"invalid_request",
|
|
363
364
|
400,
|
|
364
|
-
"codex: OAuth credential is missing a bearer token",
|
|
365
|
+
"codex: OAuth credential is missing a bearer token (request {requestId}). Wrong key, right door — check the credential 🔑",
|
|
365
366
|
);
|
|
366
367
|
}
|
|
367
368
|
const token = new TextDecoder().decode(credential.secret);
|
|
@@ -748,7 +749,7 @@ export function createCodexAdapter(
|
|
|
748
749
|
context: ProviderDispatchContext,
|
|
749
750
|
): Promise<WebSearchOutcome> {
|
|
750
751
|
const query = typeof body.query === "string" ? body.query.trim() : "";
|
|
751
|
-
if (!query) throw new GatewayError("invalid_request", 400, "search query is required");
|
|
752
|
+
if (!query) throw new GatewayError("invalid_request", 400, "search query is required (request {requestId}). Check the shape of what you sent — then resend 🪞");
|
|
752
753
|
const requested = typeof body.model === "string" ? body.model.trim() : "";
|
|
753
754
|
const model = requested.length > 0 && requested !== "codex" ? requested : CODEX_SEARCH_DEFAULT_MODEL;
|
|
754
755
|
const request: CanonicalRequest = {
|
|
@@ -779,7 +780,7 @@ export function createCodexAdapter(
|
|
|
779
780
|
}
|
|
780
781
|
const results = normalizeCodexSearchCitations(citations, answerText);
|
|
781
782
|
if (results.length === 0)
|
|
782
|
-
throw new GatewayError("platform_unavailable", 502, "Codex search returned no citations");
|
|
783
|
+
throw new GatewayError("platform_unavailable", 502, "Codex search returned no citations (request {requestId}). The upstream came back empty-handed — retry 🌙");
|
|
783
784
|
const rawMax = body.max_results;
|
|
784
785
|
const maxResults =
|
|
785
786
|
typeof rawMax === "number" && Number.isFinite(rawMax)
|
|
@@ -796,7 +797,7 @@ export function createCodexAdapter(
|
|
|
796
797
|
const prompt = imagePrompt(body);
|
|
797
798
|
const requested =
|
|
798
799
|
candidate.model_id.length > 0 ? candidate.model_id : typeof body.model === "string" ? body.model : "";
|
|
799
|
-
if (requested.length === 0) throw new GatewayError("invalid_request", 400, "model is required");
|
|
800
|
+
if (requested.length === 0) throw new GatewayError("invalid_request", 400, "model is required (request {requestId}). Check the shape of what you sent — then resend 🪞");
|
|
800
801
|
// A `-image` id is the chat model with the suffix removed. Dedicated
|
|
801
802
|
// image tools still need a chat carrier, and the account's visible 5.6
|
|
802
803
|
// models are the current ones.
|
|
@@ -868,7 +869,7 @@ export function createCodexAdapter(
|
|
|
868
869
|
try {
|
|
869
870
|
parsed = JSON.parse(data);
|
|
870
871
|
} catch {
|
|
871
|
-
throw new GatewayError("platform_unavailable", 502, "Codex image stream returned malformed JSON", {}, "upstream");
|
|
872
|
+
throw new GatewayError("platform_unavailable", 502, "Codex image stream returned malformed JSON (request {requestId}). The upstream came back empty-handed — retry 🌙", {}, "upstream");
|
|
872
873
|
}
|
|
873
874
|
if (isRecord(parsed) && (parsed.type === "error" || parsed.type === "response.failed")) {
|
|
874
875
|
const message = isRecord(parsed.error) && typeof parsed.error.message === "string"
|
|
@@ -876,7 +877,7 @@ export function createCodexAdapter(
|
|
|
876
877
|
: isRecord(parsed.response) && isRecord(parsed.response.error) && typeof parsed.response.error.message === "string"
|
|
877
878
|
? parsed.response.error.message
|
|
878
879
|
: "Codex image generation failed";
|
|
879
|
-
throw new GatewayError("platform_unavailable", 502, message
|
|
880
|
+
throw new GatewayError("platform_unavailable", 502, `${message} (request {requestId}). The upstream came back empty-handed — retry 🌙`, {}, "upstream");
|
|
880
881
|
}
|
|
881
882
|
image = responsesImageResult(parsed) ?? image;
|
|
882
883
|
}
|
|
@@ -903,19 +904,17 @@ export function createCodexAdapter(
|
|
|
903
904
|
throw new GatewayError(
|
|
904
905
|
"invalid_request",
|
|
905
906
|
400,
|
|
906
|
-
"codex adapter received non-codex candidate",
|
|
907
|
+
"codex adapter received non-codex candidate (request {requestId}). Even we have bad days — check the registry wiring 🐻",
|
|
907
908
|
);
|
|
908
909
|
}
|
|
909
910
|
if (candidate.wire_family !== "responses") {
|
|
910
|
-
|
|
911
|
-
wire_family: candidate.wire_family,
|
|
912
|
-
});
|
|
911
|
+
assertWireFamily(candidate, "responses", "codex");
|
|
913
912
|
}
|
|
914
913
|
if (request.model.includes("?")) {
|
|
915
914
|
throw new GatewayError(
|
|
916
915
|
"invalid_request",
|
|
917
916
|
400,
|
|
918
|
-
"model must not contain query string",
|
|
917
|
+
"model must not contain query string (request {requestId}). Check the shape of what you sent — then resend 🪞",
|
|
919
918
|
);
|
|
920
919
|
}
|
|
921
920
|
|
|
@@ -1181,8 +1180,8 @@ export function createCodexAdapter(
|
|
|
1181
1180
|
"platform_unavailable",
|
|
1182
1181
|
502,
|
|
1183
1182
|
error instanceof Error
|
|
1184
|
-
? `Malformed SSE event: ${error.message}
|
|
1185
|
-
:
|
|
1183
|
+
? `Malformed SSE event: ${error.message} (request {requestId}). The upstream sent something we can't read — retry 🌙`
|
|
1184
|
+
: `Malformed SSE event (request {requestId}). The upstream sent something we can't read — retry 🌙`,
|
|
1186
1185
|
{},
|
|
1187
1186
|
"upstream",
|
|
1188
1187
|
);
|
|
@@ -527,7 +527,7 @@ export function transformLine(line: string, state: StreamState, seqBase: number)
|
|
|
527
527
|
const message =
|
|
528
528
|
extractUpstreamMessage(raw) ||
|
|
529
529
|
extractUpstreamMessage(event) ||
|
|
530
|
-
"Command Code stream error";
|
|
530
|
+
"Command Code stream error (request {requestId}). The upstream came back empty-handed — retry 🌙";
|
|
531
531
|
throw new GatewayError(
|
|
532
532
|
classification.code,
|
|
533
533
|
classification.status,
|
|
@@ -558,11 +558,11 @@ export async function* transformNdjson(body: ReadableStream<Uint8Array>, signal:
|
|
|
558
558
|
yield { type: "response_start", sequence_number: seq++, model: "commandcode" } as CanonicalEvent;
|
|
559
559
|
|
|
560
560
|
const readWithAbort = (): Promise<{ done: boolean; value?: Uint8Array }> => {
|
|
561
|
-
if (signal.aborted) throw new GatewayError("transport_closed", 499, "Command Code stream aborted");
|
|
561
|
+
if (signal.aborted) throw new GatewayError("transport_closed", 499, "Command Code stream aborted (request {requestId}). Send it again whenever ready 🙃");
|
|
562
562
|
const { promise, resolve, reject } = Promise.withResolvers<{ done: boolean; value?: Uint8Array }>() as unknown as { promise: Promise<{ done: boolean; value?: Uint8Array }>; resolve: (v: unknown) => void; reject: (e: unknown) => void };
|
|
563
563
|
const onAbort = (): void => {
|
|
564
|
-
if (signal.aborted) reject(new GatewayError("transport_closed", 499, "Command Code stream aborted"));
|
|
565
|
-
else reject(new GatewayError("platform_unavailable", 502, "Command Code stream error", {}, "upstream"));
|
|
564
|
+
if (signal.aborted) reject(new GatewayError("transport_closed", 499, "Command Code stream aborted (request {requestId}). Send it again whenever ready 🙃"));
|
|
565
|
+
else reject(new GatewayError("platform_unavailable", 502, "Command Code stream error (request {requestId}). The upstream came back empty-handed — retry 🌙", {}, "upstream"));
|
|
566
566
|
};
|
|
567
567
|
signal.addEventListener("abort", onAbort, { once: true });
|
|
568
568
|
void reader.read().then(resolve, reject).finally(() => signal.removeEventListener("abort", onAbort));
|
|
@@ -72,7 +72,11 @@ function creditWindow(credits: Record<string, unknown>): ProviderQuotaWindow | n
|
|
|
72
72
|
return {
|
|
73
73
|
kind: "credits",
|
|
74
74
|
label: "Credits",
|
|
75
|
-
|
|
75
|
+
// These are credits in one unit that can be spent interchangeably, so
|
|
76
|
+
// they are pooled like Qoder's plan/granted balances — not independent
|
|
77
|
+
// rate-limit lanes. The account-row pill and the Quota page both sum
|
|
78
|
+
// pooled windows, so this must be `pooled` or the balance never renders.
|
|
79
|
+
accounting: "pooled",
|
|
76
80
|
usedPercent: null,
|
|
77
81
|
remainingPercent: null,
|
|
78
82
|
resetsAt: null,
|
|
@@ -46,7 +46,7 @@ function connectErrorEnvelope(payload: Uint8Array): GatewayError | undefined {
|
|
|
46
46
|
return new GatewayError(
|
|
47
47
|
"quota_exceeded",
|
|
48
48
|
429,
|
|
49
|
-
`Cursor refused the Run: ${detail}
|
|
49
|
+
`Cursor refused the Run: ${detail} (request {requestId}). You've maxed this window — pace yourself ⏳`,
|
|
50
50
|
{ providerId: "cursor", upstreamCode: code },
|
|
51
51
|
"upstream",
|
|
52
52
|
);
|
|
@@ -54,7 +54,7 @@ function connectErrorEnvelope(payload: Uint8Array): GatewayError | undefined {
|
|
|
54
54
|
return new GatewayError(
|
|
55
55
|
"platform_unavailable",
|
|
56
56
|
502,
|
|
57
|
-
`Cursor refused the Run: ${detail}
|
|
57
|
+
`Cursor refused the Run: ${detail} (request {requestId}). The upstream came back empty-handed — retry 🌙`,
|
|
58
58
|
{ providerId: "cursor", upstreamCode: code },
|
|
59
59
|
"upstream",
|
|
60
60
|
);
|
|
@@ -126,7 +126,7 @@ export async function openCursorRun(input: {
|
|
|
126
126
|
throw new GatewayError(
|
|
127
127
|
"invalid_request",
|
|
128
128
|
400,
|
|
129
|
-
"Cursor Run requires an allowlisted Cursor agent origin",
|
|
129
|
+
"Cursor Run requires an allowlisted Cursor agent origin (request {requestId}). All roads blocked — time to find a new route 🗺️",
|
|
130
130
|
{ origin: input.origin },
|
|
131
131
|
);
|
|
132
132
|
}
|
|
@@ -153,7 +153,7 @@ function grpcError(status: string, message: string | undefined): GatewayError {
|
|
|
153
153
|
return new GatewayError(
|
|
154
154
|
"authentication_failed",
|
|
155
155
|
401,
|
|
156
|
-
`Cursor refused the credential${detail}
|
|
156
|
+
`Cursor refused the credential${detail} (request {requestId}). Wrong key, right door — check the credential 🔑`,
|
|
157
157
|
{ grpcStatus: status },
|
|
158
158
|
"upstream",
|
|
159
159
|
);
|
|
@@ -162,7 +162,7 @@ function grpcError(status: string, message: string | undefined): GatewayError {
|
|
|
162
162
|
return new GatewayError(
|
|
163
163
|
"quota_exceeded",
|
|
164
164
|
429,
|
|
165
|
-
`Cursor refused the Run${detail}
|
|
165
|
+
`Cursor refused the Run${detail} (request {requestId}). You've maxed this window — pace yourself ⏳`,
|
|
166
166
|
{ grpcStatus: status },
|
|
167
167
|
"upstream",
|
|
168
168
|
);
|
|
@@ -171,7 +171,7 @@ function grpcError(status: string, message: string | undefined): GatewayError {
|
|
|
171
171
|
return new GatewayError(
|
|
172
172
|
"deadline_exceeded",
|
|
173
173
|
504,
|
|
174
|
-
`Cursor Run ended before it finished${detail}
|
|
174
|
+
`Cursor Run ended before it finished${detail} (request {requestId}). Some things just take longer 🐢`,
|
|
175
175
|
{ grpcStatus: status },
|
|
176
176
|
"upstream",
|
|
177
177
|
);
|
|
@@ -179,7 +179,7 @@ function grpcError(status: string, message: string | undefined): GatewayError {
|
|
|
179
179
|
return new GatewayError(
|
|
180
180
|
"platform_unavailable",
|
|
181
181
|
502,
|
|
182
|
-
`Cursor Run failed (gRPC ${status})${detail}
|
|
182
|
+
`Cursor Run failed (gRPC ${status})${detail} (request {requestId}). The upstream came back empty-handed — retry 🌙`,
|
|
183
183
|
{ grpcStatus: status },
|
|
184
184
|
"upstream",
|
|
185
185
|
);
|
|
@@ -205,7 +205,7 @@ export function cursorRunTerminationError(input: {
|
|
|
205
205
|
: new GatewayError(
|
|
206
206
|
"transport_unavailable",
|
|
207
207
|
502,
|
|
208
|
-
`Cursor Run transport interrupted: ${input.reason.error.message}
|
|
208
|
+
`Cursor Run transport interrupted: ${input.reason.error.message} (request {requestId}). The connection ghosted us — come back in a moment 👻`,
|
|
209
209
|
{},
|
|
210
210
|
"network",
|
|
211
211
|
);
|
|
@@ -216,7 +216,7 @@ export function cursorRunTerminationError(input: {
|
|
|
216
216
|
return new GatewayError(
|
|
217
217
|
status === 401 || status === 403 ? "authentication_failed" : "platform_unavailable",
|
|
218
218
|
status === 401 || status === 403 ? 401 : 502,
|
|
219
|
-
`Cursor Run failed by remote: ${status}
|
|
219
|
+
`Cursor Run failed by remote: ${status} (request {requestId}). The upstream came back empty-handed — retry 🌙`,
|
|
220
220
|
{ httpStatus: status, ...(message === undefined ? {} : { upstreamMessage: message }) },
|
|
221
221
|
"upstream",
|
|
222
222
|
);
|
|
@@ -229,7 +229,7 @@ export function cursorRunTerminationError(input: {
|
|
|
229
229
|
return new GatewayError(
|
|
230
230
|
"platform_unavailable",
|
|
231
231
|
502,
|
|
232
|
-
"Cursor Run ended before turn_ended",
|
|
232
|
+
"Cursor Run ended before turn_ended (request {requestId}). The upstream came back empty-handed — retry 🌙",
|
|
233
233
|
{},
|
|
234
234
|
"upstream",
|
|
235
235
|
);
|
|
@@ -253,7 +253,7 @@ export async function* decodeServerMessages(
|
|
|
253
253
|
throw new GatewayError(
|
|
254
254
|
"platform_unavailable",
|
|
255
255
|
502,
|
|
256
|
-
"Cursor Run exceeded the frame buffer bound",
|
|
256
|
+
"Cursor Run exceeded the frame buffer bound (request {requestId}). The upstream sent more than we can hold — retry 🌙",
|
|
257
257
|
{},
|
|
258
258
|
"upstream",
|
|
259
259
|
);
|
|
@@ -152,14 +152,14 @@ function finishImage(bytes: Uint8Array): CursorImageInput {
|
|
|
152
152
|
throw new GatewayError(
|
|
153
153
|
"invalid_request",
|
|
154
154
|
400,
|
|
155
|
-
"Cursor accepts PNG, JPEG, WebP and GIF image input only",
|
|
155
|
+
"Cursor accepts PNG, JPEG, WebP and GIF image input only (request {requestId}). Check the shape of what you sent — then resend 🪞",
|
|
156
156
|
);
|
|
157
157
|
}
|
|
158
158
|
if (bytes.byteLength > MAX_IMAGE_BYTES) {
|
|
159
159
|
throw new GatewayError(
|
|
160
160
|
"invalid_request",
|
|
161
161
|
400,
|
|
162
|
-
`Cursor image input exceeds the ${MAX_IMAGE_BYTES}-byte limit
|
|
162
|
+
`Cursor image input exceeds the ${MAX_IMAGE_BYTES}-byte limit (request {requestId}). We love long reads, but not that long 📚`,
|
|
163
163
|
);
|
|
164
164
|
}
|
|
165
165
|
return { data: bytes, mimeType };
|
|
@@ -183,7 +183,7 @@ async function resolveImageInput(
|
|
|
183
183
|
if (dataUrl !== undefined) {
|
|
184
184
|
const bytes = base64ToBytes(dataUrl.data);
|
|
185
185
|
if (bytes === undefined) {
|
|
186
|
-
throw new GatewayError("invalid_request", 400, "Cursor image attachment is not valid base64");
|
|
186
|
+
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
187
|
}
|
|
188
188
|
return finishImage(bytes);
|
|
189
189
|
}
|
|
@@ -192,7 +192,7 @@ async function resolveImageInput(
|
|
|
192
192
|
throw new GatewayError(
|
|
193
193
|
"invalid_request",
|
|
194
194
|
400,
|
|
195
|
-
"Cursor image URLs must be HTTPS; private and non-TLS sources are not fetched",
|
|
195
|
+
"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
196
|
);
|
|
197
197
|
}
|
|
198
198
|
const fetcher = context.outbound_attachment_fetch;
|
|
@@ -200,7 +200,7 @@ async function resolveImageInput(
|
|
|
200
200
|
throw new GatewayError(
|
|
201
201
|
"invalid_request",
|
|
202
202
|
400,
|
|
203
|
-
"Cursor has no validated egress to fetch this image URL",
|
|
203
|
+
"Cursor has no validated egress to fetch this image URL (request {requestId}). All roads blocked — time to find a new route 🗺️",
|
|
204
204
|
);
|
|
205
205
|
}
|
|
206
206
|
// Redirects are not followed: reject the response rather than letting a
|
|
@@ -222,7 +222,7 @@ async function resolveImageInput(
|
|
|
222
222
|
throw new GatewayError(
|
|
223
223
|
"invalid_request",
|
|
224
224
|
400,
|
|
225
|
-
`Cursor image input exceeds the ${MAX_IMAGE_BYTES}-byte limit
|
|
225
|
+
`Cursor image input exceeds the ${MAX_IMAGE_BYTES}-byte limit (request {requestId}). We love long reads, but not that long 📚`,
|
|
226
226
|
);
|
|
227
227
|
}
|
|
228
228
|
return finishImage(body);
|
|
@@ -503,7 +503,7 @@ class CursorAdapter implements ProviderAdapter {
|
|
|
503
503
|
throw new GatewayError(
|
|
504
504
|
"invalid_request",
|
|
505
505
|
400,
|
|
506
|
-
"This tool result cannot be matched to a live Cursor Run; resend the complete conversation.",
|
|
506
|
+
"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
507
|
);
|
|
508
508
|
}
|
|
509
509
|
const resolvedAll = pending.map((item) => cursorRunSessions.resolveCall(item.callId, scope));
|
|
@@ -530,7 +530,7 @@ class CursorAdapter implements ProviderAdapter {
|
|
|
530
530
|
throw new GatewayError(
|
|
531
531
|
"invalid_request",
|
|
532
532
|
400,
|
|
533
|
-
"This tool result refers to a Cursor tool call that is no longer pending. Resend the complete conversation.",
|
|
533
|
+
"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
534
|
{ callIds: pending.map((item) => item.callId) },
|
|
535
535
|
);
|
|
536
536
|
}
|
|
@@ -538,12 +538,12 @@ class CursorAdapter implements ProviderAdapter {
|
|
|
538
538
|
throw new GatewayError(
|
|
539
539
|
"invalid_request",
|
|
540
540
|
400,
|
|
541
|
-
"These tool results belong to different Cursor Runs; resend them one Run at a time.",
|
|
541
|
+
"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
542
|
);
|
|
543
543
|
}
|
|
544
544
|
const session = cursorRunSessions.get(runId);
|
|
545
545
|
if (session === undefined) {
|
|
546
|
-
throw new GatewayError("invalid_request", 400, "Cursor Run is no longer live");
|
|
546
|
+
throw new GatewayError("invalid_request", 400, "Cursor Run is no longer live (request {requestId}). The session went cold — reconnect or resend 🔌");
|
|
547
547
|
}
|
|
548
548
|
const handle = this.#handles.get(runId);
|
|
549
549
|
if (handle === undefined) {
|
|
@@ -605,7 +605,7 @@ class CursorAdapter implements ProviderAdapter {
|
|
|
605
605
|
throw new GatewayError(
|
|
606
606
|
"admission_unavailable",
|
|
607
607
|
503,
|
|
608
|
-
"Cursor requires validated HTTP/2 egress; none is configured for this route",
|
|
608
|
+
"Cursor requires validated HTTP/2 egress (request {requestId}); none is configured for this route. No bridge to cross — configure a pool first 🏗️",
|
|
609
609
|
{ providerId: CURSOR_PROVIDER_ID },
|
|
610
610
|
);
|
|
611
611
|
}
|
|
@@ -784,7 +784,7 @@ class CursorAdapter implements ProviderAdapter {
|
|
|
784
784
|
: new GatewayError(
|
|
785
785
|
"platform_unavailable",
|
|
786
786
|
502,
|
|
787
|
-
`Cursor Run failed: ${error instanceof Error ? error.message : String(error)}
|
|
787
|
+
`Cursor Run failed (request {requestId}): ${error instanceof Error ? error.message : String(error)}. The upstream came back empty-handed — retry 🌙`,
|
|
788
788
|
{ providerId: CURSOR_PROVIDER_ID },
|
|
789
789
|
"upstream",
|
|
790
790
|
);
|
|
@@ -828,7 +828,7 @@ class CursorAdapter implements ProviderAdapter {
|
|
|
828
828
|
throw new GatewayError(
|
|
829
829
|
"platform_unavailable",
|
|
830
830
|
502,
|
|
831
|
-
`Cursor Run origin could not be resolved: ${error instanceof Error ? error.message : String(error)}
|
|
831
|
+
`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
832
|
{ providerId: CURSOR_PROVIDER_ID },
|
|
833
833
|
"upstream",
|
|
834
834
|
);
|
|
@@ -890,7 +890,7 @@ class CursorAdapter implements ProviderAdapter {
|
|
|
890
890
|
}
|
|
891
891
|
const message = item;
|
|
892
892
|
if (context.abort_signal.aborted) {
|
|
893
|
-
failure = new GatewayError("transport_closed", 499, "request was cancelled");
|
|
893
|
+
failure = new GatewayError("transport_closed", 499, "The request was cancelled (request {requestId}). Send it again whenever ready 🙃");
|
|
894
894
|
break;
|
|
895
895
|
}
|
|
896
896
|
const execServer = recordOf(message["exec_server_message"]);
|
|
@@ -994,7 +994,7 @@ class CursorAdapter implements ProviderAdapter {
|
|
|
994
994
|
: new GatewayError(
|
|
995
995
|
"platform_unavailable",
|
|
996
996
|
502,
|
|
997
|
-
`Cursor Run failed: ${error instanceof Error ? error.message : String(error)}
|
|
997
|
+
`Cursor Run failed (request {requestId}): ${error instanceof Error ? error.message : String(error)}. The upstream came back empty-handed — retry 🌙`,
|
|
998
998
|
{ providerId: CURSOR_PROVIDER_ID },
|
|
999
999
|
"upstream",
|
|
1000
1000
|
);
|
|
@@ -270,7 +270,7 @@ export function factoryRegionUnavailable(modelId: string, region: string): Gatew
|
|
|
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
|
}
|
|
@@ -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
|
}
|
|
@@ -411,7 +411,7 @@ class GithubAdapter extends OpenAICompatibleAdapter {
|
|
|
411
411
|
|
|
412
412
|
const secret = context.credential.secret;
|
|
413
413
|
if (secret === undefined || secret.length === 0) {
|
|
414
|
-
throw new GatewayError("authentication_failed", 401, "GitHub Copilot credential is missing");
|
|
414
|
+
throw new GatewayError("authentication_failed", 401, "GitHub Copilot credential is missing (request {requestId}). Wrong key, right door — check the credential 🔑");
|
|
415
415
|
}
|
|
416
416
|
const credential = new TextDecoder().decode(secret);
|
|
417
417
|
const autoInput = autoPrompt(request);
|
|
@@ -424,7 +424,7 @@ class GithubAdapter extends OpenAICompatibleAdapter {
|
|
|
424
424
|
: this.#getCachedAutoDecision(cacheKey, autoInput.hasImage);
|
|
425
425
|
if (autoDecision === undefined) {
|
|
426
426
|
if (autoInput.prompt.length === 0) {
|
|
427
|
-
throw new GatewayError("invalid_request", 400, "Copilot Auto requires a text prompt");
|
|
427
|
+
throw new GatewayError("invalid_request", 400, "Copilot Auto requires a text prompt (request {requestId}). Check the shape of what you sent — then resend 🪞");
|
|
428
428
|
}
|
|
429
429
|
autoDecision = await this.#selectAutoModel(
|
|
430
430
|
autoInput.prompt,
|
|
@@ -462,7 +462,7 @@ class GithubAdapter extends OpenAICompatibleAdapter {
|
|
|
462
462
|
throw new GatewayError(
|
|
463
463
|
"upstream_unprocessable",
|
|
464
464
|
502,
|
|
465
|
-
"Copilot Auto selected a model without a discovered inference endpoint",
|
|
465
|
+
"Copilot Auto selected a model without a discovered inference endpoint (request {requestId}). The upstream came back empty-handed — retry 🌙",
|
|
466
466
|
{ selected_model: selectedModelId },
|
|
467
467
|
"upstream",
|
|
468
468
|
);
|
|
@@ -498,7 +498,7 @@ class GithubAdapter extends OpenAICompatibleAdapter {
|
|
|
498
498
|
? undefined
|
|
499
499
|
: parseGithubCredential(new TextDecoder().decode(context.credential.secret));
|
|
500
500
|
if (credential === undefined) {
|
|
501
|
-
throw new GatewayError("authentication_failed", 401, "GitHub Copilot credential is missing");
|
|
501
|
+
throw new GatewayError("authentication_failed", 401, "GitHub Copilot credential is missing (request {requestId}). Wrong key, right door — check the credential 🔑");
|
|
502
502
|
}
|
|
503
503
|
const payload: Record<string, unknown> = { prompt, tier };
|
|
504
504
|
if (hasImage) payload.has_image = true;
|
|
@@ -522,7 +522,7 @@ class GithubAdapter extends OpenAICompatibleAdapter {
|
|
|
522
522
|
throw new GatewayError(
|
|
523
523
|
"upstream_unprocessable",
|
|
524
524
|
502,
|
|
525
|
-
"Copilot Auto returned an invalid routing response",
|
|
525
|
+
"Copilot Auto returned an invalid routing response (request {requestId}). The upstream came back empty-handed — retry 🌙",
|
|
526
526
|
{},
|
|
527
527
|
"upstream",
|
|
528
528
|
);
|
|
@@ -545,7 +545,7 @@ class GithubAdapter extends OpenAICompatibleAdapter {
|
|
|
545
545
|
throw new GatewayError(
|
|
546
546
|
"upstream_unprocessable",
|
|
547
547
|
502,
|
|
548
|
-
"Copilot Auto did not return a selected model",
|
|
548
|
+
"Copilot Auto did not return a selected model (request {requestId}). The upstream came back empty-handed — retry 🌙",
|
|
549
549
|
{},
|
|
550
550
|
"upstream",
|
|
551
551
|
);
|
|
@@ -9,12 +9,12 @@
|
|
|
9
9
|
* OpenAI-compatible adapter.
|
|
10
10
|
*/
|
|
11
11
|
import { randomBytes, randomUUID } from "node:crypto";
|
|
12
|
-
import { GatewayError } from "../../../protocol/gateway-error";
|
|
13
12
|
import type { CanonicalEvent, CanonicalRequest } from "../../../protocol/canonical-model";
|
|
14
13
|
import {
|
|
15
14
|
OpenAICompatibleAdapter,
|
|
16
15
|
withBearerAuthentication,
|
|
17
16
|
} from "../../adapters/compatible-adapter";
|
|
17
|
+
import { assertCredentialKind } from "../../provider-contracts";
|
|
18
18
|
import type { ProviderAdapter, ProviderDispatchTarget, ProviderDispatchContext } from "../../provider-contracts";
|
|
19
19
|
import { providerBaseUrl } from "../../provider-metadata";
|
|
20
20
|
import { boundedUpstreamArray, boundedUpstreamNumber, sanitizeUpstreamLabel } from "../../provider-sanitize";
|
|
@@ -526,11 +526,7 @@ class GrokAdapter extends OpenAICompatibleAdapter {
|
|
|
526
526
|
context: ProviderDispatchContext,
|
|
527
527
|
): AsyncIterable<CanonicalEvent> {
|
|
528
528
|
if (context.credential.credential_kind !== "oauth") {
|
|
529
|
-
|
|
530
|
-
"invalid_request",
|
|
531
|
-
400,
|
|
532
|
-
"grok requires an xAI OAuth device credential",
|
|
533
|
-
);
|
|
529
|
+
assertCredentialKind(context.credential, "oauth", "grok");
|
|
534
530
|
}
|
|
535
531
|
yield* super.dispatch(request, candidate, context);
|
|
536
532
|
}
|