cartethyia 2.7.4 → 2.7.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.env.example +5 -0
- package/README.md +18 -6
- package/dist/dashboard/assets/BannedPage-B1N603cM.js +1 -0
- package/dist/dashboard/assets/BannedPage-B1N603cM.js.gz +0 -0
- package/dist/dashboard/assets/CliToolDetailPage-9q4_4NoK.js +3 -0
- package/dist/dashboard/assets/CliToolDetailPage-9q4_4NoK.js.gz +0 -0
- package/dist/dashboard/assets/CliToolsPage-DwshGtK-.js +1 -0
- package/dist/dashboard/assets/CliToolsPage-DwshGtK-.js.gz +0 -0
- package/dist/dashboard/assets/CombosPage-D762MIkp.js +1 -0
- package/dist/dashboard/assets/CombosPage-D762MIkp.js.gz +0 -0
- package/dist/dashboard/assets/ConsoleLogPage-KRYjHZsX.js +1 -0
- package/dist/dashboard/assets/ConsoleLogPage-KRYjHZsX.js.gz +0 -0
- package/dist/dashboard/assets/CustomizationPage-DXsxk5uM.js +1 -0
- package/dist/dashboard/assets/CustomizationPage-DXsxk5uM.js.gz +0 -0
- package/dist/dashboard/assets/HealthEventsModal-BEjAjD4F.js +1 -0
- package/dist/dashboard/assets/HealthEventsModal-BEjAjD4F.js.gz +0 -0
- package/dist/dashboard/assets/InjectSystemPromptPanel-d5v3K_Yc.js +899 -0
- package/dist/dashboard/assets/InjectSystemPromptPanel-d5v3K_Yc.js.gz +0 -0
- package/dist/dashboard/assets/LoginPage-Ccv4tjNS.js +1 -0
- package/dist/dashboard/assets/LoginPage-Ccv4tjNS.js.gz +0 -0
- package/dist/dashboard/assets/{ModelPicker-BMS2t8BA.js → ModelPicker-C6WlpU5E.js} +1 -1
- package/dist/dashboard/assets/ModelPicker-C6WlpU5E.js.gz +0 -0
- package/dist/dashboard/assets/OverviewPage-DN9fYNWA.js +1 -0
- package/dist/dashboard/assets/OverviewPage-DN9fYNWA.js.gz +0 -0
- package/dist/dashboard/assets/ProviderDetailPage-BY0ieUgz.js +5 -0
- package/dist/dashboard/assets/ProviderDetailPage-BY0ieUgz.js.gz +0 -0
- package/dist/dashboard/assets/ProviderIcon-jjqXJDA3.js +1 -0
- package/dist/dashboard/assets/ProviderIcon-jjqXJDA3.js.gz +0 -0
- package/dist/dashboard/assets/ProvidersPage-DNsbfea2.js +1 -0
- package/dist/dashboard/assets/ProvidersPage-DNsbfea2.js.gz +0 -0
- package/dist/dashboard/assets/{ProxyPage-lsrx7NYg.js → ProxyPage-DxjvUzSD.js} +1 -1
- package/dist/dashboard/assets/ProxyPage-DxjvUzSD.js.gz +0 -0
- package/dist/dashboard/assets/QuotaPage-OaHScjpX.js +1 -0
- package/dist/dashboard/assets/QuotaPage-OaHScjpX.js.gz +0 -0
- package/dist/dashboard/assets/SettingsPage-BW4AKj2H.js +1 -0
- package/dist/dashboard/assets/SettingsPage-BW4AKj2H.js.gz +0 -0
- package/dist/dashboard/assets/SetupPage-44BZrxFC.js +1 -0
- package/dist/dashboard/assets/SetupPage-44BZrxFC.js.gz +0 -0
- package/dist/dashboard/assets/{StudioPage-Cq5tW7hW.js → StudioPage-DRPavCdU.js} +4 -4
- package/dist/dashboard/assets/StudioPage-DRPavCdU.js.gz +0 -0
- package/dist/dashboard/assets/ToolIcon-CfeLA-Z_.js +1 -0
- package/dist/dashboard/assets/ToolIcon-CfeLA-Z_.js.gz +0 -0
- package/dist/dashboard/assets/UsagePage-B7M7LvMM.js +56 -0
- package/dist/dashboard/assets/UsagePage-B7M7LvMM.js.gz +0 -0
- package/dist/dashboard/assets/api-keys-KvX83mRe.js +1 -0
- package/dist/dashboard/assets/api-keys-KvX83mRe.js.gz +0 -0
- package/dist/dashboard/assets/app-DRnQLhsc.js +9 -0
- package/dist/dashboard/assets/app-DRnQLhsc.js.gz +0 -0
- package/dist/dashboard/assets/app-mweRcsKp.css +2 -0
- package/dist/dashboard/assets/app-mweRcsKp.css.gz +0 -0
- package/dist/dashboard/assets/assert-CidQVoNo.js +1 -0
- package/dist/dashboard/assets/assert-CidQVoNo.js.gz +0 -0
- package/dist/dashboard/assets/{badge-D9CS6dZk.js → badge-BaX2GTrn.js} +1 -1
- package/dist/dashboard/assets/badge-BaX2GTrn.js.gz +0 -0
- package/dist/dashboard/assets/{banner-DympBNq4.js → banner-DFH4Bkte.js} +1 -1
- package/dist/dashboard/assets/banner-DFH4Bkte.js.gz +0 -0
- package/dist/dashboard/assets/brand/login_register.jpg +0 -0
- package/dist/dashboard/assets/brand/login_register_initial.jpg +0 -0
- package/dist/dashboard/assets/brand/og_bansos.jpg +0 -0
- package/dist/dashboard/assets/brand/og_image.jpg +0 -0
- package/dist/dashboard/assets/{card-ibRWU_uT.js → card-CxDw0lK6.js} +1 -1
- package/dist/dashboard/assets/card-CxDw0lK6.js.gz +0 -0
- package/dist/dashboard/assets/chevron-left-Bf6CaTSJ.js +1 -0
- package/dist/dashboard/assets/chevron-left-Bf6CaTSJ.js.gz +0 -0
- package/dist/dashboard/assets/circle-question-mark-Cz4un8sH.js +1 -0
- package/dist/dashboard/assets/circle-question-mark-Cz4un8sH.js.gz +0 -0
- package/dist/dashboard/assets/cli-tools-Bwv5-zGZ.js +1 -0
- package/dist/dashboard/assets/cli-tools-Bwv5-zGZ.js.gz +0 -0
- package/dist/dashboard/assets/{clipboard-button-DJm-9pz7.js → clipboard-button-DfS1ntiq.js} +1 -1
- package/dist/dashboard/assets/clipboard-button-DfS1ntiq.js.gz +0 -0
- package/dist/dashboard/assets/dialog-BK-NRr5u.js +1 -0
- package/dist/dashboard/assets/dialog-BK-NRr5u.js.gz +0 -0
- package/dist/dashboard/assets/{drawer-CqGYeOrd.js → drawer-QqPul6sC.js} +1 -1
- package/dist/dashboard/assets/drawer-QqPul6sC.js.gz +0 -0
- package/dist/dashboard/assets/entry-BMlYJVFj.js +1 -0
- package/dist/dashboard/assets/entry-BMlYJVFj.js.gz +0 -0
- package/dist/dashboard/assets/entry-D6WvojeD.js +4 -0
- package/dist/dashboard/assets/entry-D6WvojeD.js.gz +0 -0
- package/dist/dashboard/assets/entry-Dmx7gBiN.js +1 -0
- package/dist/dashboard/assets/entry-Dmx7gBiN.js.gz +0 -0
- package/dist/dashboard/assets/{formatters-D-MTJxMr.js → formatters-u7JPB5BX.js} +1 -1
- package/dist/dashboard/assets/formatters-u7JPB5BX.js.gz +0 -0
- package/dist/dashboard/assets/house-h9AZlJuT.js +1 -0
- package/dist/dashboard/assets/house-h9AZlJuT.js.gz +0 -0
- package/dist/dashboard/assets/{index-DBNPOfhV.js → index-Ko4dLRnV.js} +2 -2
- package/dist/dashboard/assets/index-Ko4dLRnV.js.gz +0 -0
- package/dist/dashboard/assets/{inline-BT0zntEr.js → inline-CHJQwxLa.js} +1 -1
- package/dist/dashboard/assets/inline-CHJQwxLa.js.gz +0 -0
- package/dist/dashboard/assets/{input-Da2ZViWg.js → input-BlmlizVV.js} +1 -1
- package/dist/dashboard/assets/input-BlmlizVV.js.gz +0 -0
- package/dist/dashboard/assets/{layout-BXNeLw6M.js → layout-Bz93I-yE.js} +1 -1
- package/dist/dashboard/assets/layout-Bz93I-yE.js.gz +0 -0
- package/dist/dashboard/assets/{list-row-BycOrrIV.js → list-row-Ml16KCfu.js} +1 -1
- package/dist/dashboard/assets/list-row-Ml16KCfu.js.gz +0 -0
- package/dist/dashboard/assets/live-7_QpnYGu.js +1 -0
- package/dist/dashboard/assets/live-7_QpnYGu.js.gz +0 -0
- package/dist/dashboard/assets/{mutation-Rr0TIvcj.js → mutation-GU7XdEjz.js} +1 -1
- package/dist/dashboard/assets/mutation-GU7XdEjz.js.gz +0 -0
- package/dist/dashboard/assets/network-CuMDaTzT.js +1 -0
- package/dist/dashboard/assets/network-CuMDaTzT.js.gz +0 -0
- package/dist/dashboard/assets/numbers-CoqpaDMx.js +2 -0
- package/dist/dashboard/assets/numbers-CoqpaDMx.js.gz +0 -0
- package/dist/dashboard/assets/pagination-B5aOoweZ.js +1 -0
- package/dist/dashboard/assets/pagination-B5aOoweZ.js.gz +0 -0
- package/dist/dashboard/assets/providers/zai.webp +0 -0
- package/dist/dashboard/assets/providers/zcode.webp +0 -0
- package/dist/dashboard/assets/{query-keys-BloKtaXJ.js → query-keys-YSoQOUh6.js} +1 -1
- package/dist/dashboard/assets/{query-keys-BloKtaXJ.js.gz → query-keys-YSoQOUh6.js.gz} +0 -0
- package/dist/dashboard/assets/quota-DJ1QlAOq.js +1 -0
- package/dist/dashboard/assets/quota-DJ1QlAOq.js.gz +0 -0
- package/dist/dashboard/assets/routing-fnCsxgNO.js +1 -0
- package/dist/dashboard/assets/routing-fnCsxgNO.js.gz +0 -0
- package/dist/dashboard/assets/{select-BIYIBkMU.js → select-BHqpd-bg.js} +2 -2
- package/dist/dashboard/assets/select-BHqpd-bg.js.gz +0 -0
- package/dist/dashboard/assets/settings-BxslsErn.js +1 -0
- package/dist/dashboard/assets/settings-BxslsErn.js.gz +0 -0
- package/dist/dashboard/assets/shield-BMQNxORh.js +1 -0
- package/dist/dashboard/assets/shield-BMQNxORh.js.gz +0 -0
- package/dist/dashboard/assets/{stack-DfgnFDWY.js → stack-j7cXjgYX.js} +1 -1
- package/dist/dashboard/assets/stack-j7cXjgYX.js.gz +0 -0
- package/dist/dashboard/assets/{state-CkfdYWel.js → state-DHmEnLa2.js} +1 -1
- package/dist/dashboard/assets/state-DHmEnLa2.js.gz +0 -0
- package/dist/dashboard/assets/{switch-SYm237HG.js → switch-DmZcyTIC.js} +1 -1
- package/dist/dashboard/assets/switch-DmZcyTIC.js.gz +0 -0
- package/dist/dashboard/assets/{useMutation-BQqCRNIi.js → useMutation-CbCP4w1o.js} +1 -1
- package/dist/dashboard/assets/useMutation-CbCP4w1o.js.gz +0 -0
- package/dist/dashboard/console-backgrounds.jpg +0 -0
- package/dist/dashboard/console-backgrounds_initial.jpg +0 -0
- package/dist/dashboard/index.html +2 -2
- package/dist/dashboard/index.html.gz +0 -0
- package/dist/dashboard/precompressed-assets.json +60 -59
- package/migrations/full-postgres/0036_system_prompt_presets_refs.sql +10 -0
- package/migrations/full-postgres/0037_share_concurrency_scope.sql +3 -0
- package/migrations/full-postgres/0038_add_accounts_quota_snapshot.sql +7 -0
- package/migrations/full-postgres/0039_add_telemetry_provider_model_indexes.sql +13 -0
- package/migrations/full-postgres/0040_add_models_dialect.sql +3 -0
- package/migrations/full-postgres/0041_add_daily_checkin_ledger_account_fk.sql +7 -0
- package/migrations/full-postgres/0042_add_telemetry_degenerate_stop.sql +14 -0
- package/migrations/lite-sqlite3/0036_system_prompt_presets_refs.sql +14 -0
- package/migrations/lite-sqlite3/0037_share_concurrency_scope.sql +3 -0
- package/migrations/lite-sqlite3/0038_add_accounts_quota_snapshot.sql +4 -0
- package/migrations/lite-sqlite3/0039_add_telemetry_provider_model_indexes.sql +6 -0
- package/migrations/lite-sqlite3/0040_add_models_dialect.sql +3 -0
- package/migrations/lite-sqlite3/0041_add_daily_checkin_ledger_account_fk.sql +26 -0
- package/migrations/lite-sqlite3/0042_add_telemetry_degenerate_stop.sql +12 -0
- package/package.json +4 -6
- package/scripts/cli/update.ts +15 -41
- package/src/boot/app.ts +58 -2
- package/src/boot/dependencies.ts +794 -732
- package/src/boot/lifecycle.ts +11 -12
- package/src/config/cooldowns.ts +34 -55
- package/src/config/network.ts +1 -1
- package/src/config/package-paths.ts +1 -1
- package/src/config/providers.ts +19 -14
- package/src/config/resources.ts +0 -5
- package/src/config/runtime.ts +2 -5
- package/src/config/spec.ts +33 -6
- package/src/config/usage.ts +27 -0
- package/src/console/api-keys/ban-constants.ts +38 -0
- package/src/console/api-keys/contracts.ts +71 -62
- package/src/console/api-keys/routes.ts +56 -24
- package/src/console/auth/access.ts +4 -4
- package/src/console/auth/account-reset.ts +1 -1
- package/src/console/auth/audit-recorder.ts +1 -1
- package/src/console/auth/lockout.ts +7 -3
- package/src/console/auth/row-coercion.ts +57 -12
- package/src/console/auth/session-resolver.ts +1 -1
- package/src/console/auth/session-service.ts +8 -2
- package/src/console/auth/session.ts +37 -31
- package/src/console/auth/setup-service.ts +4 -3
- package/src/console/auth/user-store.ts +1 -1
- package/src/console/backup/9router-map.ts +0 -3
- package/src/console/backup/contracts.ts +9 -9
- package/src/console/backup/export-endpoint.ts +5 -6
- package/src/console/backup/nine-router.ts +1 -7
- package/src/console/backup/routes.ts +29 -33
- package/src/console/backup/service.ts +468 -468
- package/src/console/backup/store.ts +47 -29
- package/src/console/backup/validate.ts +11 -1
- package/src/console/cli-tools/contracts.ts +43 -299
- package/src/console/cli-tools/fs-ops.ts +29 -0
- package/src/console/cli-tools/injectors/claude.ts +3 -3
- package/src/console/cli-tools/injectors/codex.ts +181 -181
- package/src/console/cli-tools/injectors/driver.ts +150 -247
- package/src/console/cli-tools/injectors/kilo.ts +146 -21
- package/src/console/cli-tools/injectors/opencode.ts +176 -153
- package/src/console/cli-tools/routes.ts +7 -1
- package/src/console/cli-tools/service.ts +8 -7
- package/src/console/cli-tools/store.ts +2 -2
- package/src/console/console-router.ts +32 -0
- package/src/console/dashboard-assets.ts +9 -9
- package/src/console/domain-registration.ts +16 -2
- package/src/console/inferhub/client.ts +0 -7
- package/src/console/inferhub/key-store.ts +1 -1
- package/src/console/inferhub/normalize.ts +2 -2
- package/src/console/inferhub/routes.ts +1 -1
- package/src/console/inferhub/types.ts +1 -1
- package/src/console/observability/contracts.ts +7 -1
- package/src/console/observability/live.ts +31 -18
- package/src/console/observability/logs.ts +1 -1
- package/src/console/observability/sse.ts +62 -8
- package/src/console/observability/store.ts +23 -4
- package/src/console/providers/catalog/catalog-projections.ts +1 -1
- package/src/console/providers/catalog/contracts.ts +39 -0
- package/src/console/providers/catalog/model-operations.ts +1 -1
- package/src/console/providers/catalog/provider-operations.ts +95 -17
- package/src/console/providers/catalog/public-model-store.ts +0 -0
- package/src/console/providers/catalog/routes.ts +27 -3
- package/src/console/providers/catalog/store.ts +147 -8
- package/src/console/providers/detail/routes.ts +1 -1
- package/src/console/providers/oauth/callback-listener.ts +100 -18
- package/src/console/providers/oauth/routes.ts +92 -13
- package/src/console/quota/account-quota-global.ts +41 -3
- package/src/console/quota/account-quota-shared.ts +10 -3
- package/src/console/quota/account-quota-tenant.ts +259 -66
- package/src/console/quota/daily-growth-job.ts +308 -0
- package/src/console/quota/native-identity.ts +2 -2
- package/src/console/quota/quota-view.ts +1 -1
- package/src/console/remote-support/routes.ts +1 -1
- package/src/console/remote-support/service.ts +2 -2
- package/src/console/routing/model/contracts.ts +1 -1
- package/src/console/routing/pools/contracts.ts +2 -2
- package/src/console/routing/pools/import-parse.ts +3 -3
- package/src/console/routing/pools/relay-deploy.ts +3 -3
- package/src/console/settings/contracts.ts +29 -2
- package/src/console/settings/store.ts +20 -0
- package/src/console/share/share-router.ts +100 -32
- package/src/console/share/share-stats.ts +11 -13
- package/src/console/share/share-usage.ts +1 -1
- package/src/console/shared/errors.ts +2 -2
- package/src/console/shared/object.ts +18 -0
- package/src/console/shared/read-through-cache.ts +4 -4
- package/src/console/shared/transaction.ts +14 -0
- package/src/console/system-prompt/contracts.ts +89 -12
- package/src/console/system-prompt/routes.ts +98 -45
- package/src/console/updates/apply-update.ts +244 -0
- package/src/console/updates/routes.ts +252 -97
- package/src/main.ts +11 -5
- package/src/network/http2-bidi.ts +1 -1
- package/src/network/ip-utils.ts +298 -0
- package/src/network/outbound-fetch.ts +1 -1
- package/src/network/pool/agent.ts +7 -6
- package/src/network/pool/byte-accounting.ts +1 -1
- package/src/network/pool/resolver.ts +16 -12
- package/src/network/pool/selector.ts +150 -136
- package/src/network/pool-health-machine.ts +1 -1
- package/src/network/rate-limit-verdict.ts +1 -1
- package/src/network/retry.ts +1 -1
- package/src/network/ssrf.ts +20 -71
- package/src/observability/event-log.ts +9 -2
- package/src/observability/event-query.ts +61 -291
- package/src/observability/log-sanitize.ts +1 -1
- package/src/observability/metrics.ts +4 -4
- package/src/observability/payload-capture.ts +6 -5
- package/src/observability/payload-store.ts +1 -1
- package/src/observability/runtime-metrics.ts +1 -1
- package/src/observability/telemetry-buffer.ts +19 -3
- package/src/observability/telemetry-reconciliation.ts +3 -3
- package/src/observability/token-speed.ts +1 -1
- package/src/persistence/connection-url.ts +1 -1
- package/src/persistence/db-handle.ts +1 -1
- package/src/persistence/db-pg.ts +2 -2
- package/src/persistence/db-sqlite.ts +3 -3
- package/src/persistence/dialect.ts +5 -1
- package/src/persistence/readiness.ts +1 -1
- package/src/persistence/redis.ts +1 -1
- package/src/persistence/schema.ts +121 -40
- package/src/persistence/shared-cache.ts +2 -2
- package/src/persistence/sort-order.ts +1 -1
- package/src/persistence/stores/api-key-store.ts +29 -2
- package/src/persistence/stores/share-store.ts +20 -8
- package/src/persistence/system-prompt-store.ts +63 -18
- package/src/persistence/tenant-preferences.ts +1 -1
- package/src/persistence/ttl-cache.ts +3 -3
- package/src/persistence/usage-flush.ts +7 -2
- package/src/protocol/canonical-model.ts +1 -1
- package/src/protocol/codecs.ts +6 -10
- package/src/protocol/dsml.ts +8 -125
- package/src/protocol/image-clamp.ts +2 -2
- package/src/protocol/reasoning-text.ts +1 -1
- package/src/protocol/reasoning.ts +7 -52
- package/src/protocol/registry.ts +50 -15
- package/src/protocol/request/chat.ts +46 -19
- package/src/protocol/request/codex.ts +1 -1
- package/src/protocol/request/messages.ts +46 -14
- package/src/protocol/request/responses.ts +19 -10
- package/src/protocol/response/chat.ts +25 -10
- package/src/protocol/response/codex.ts +1 -1
- package/src/protocol/response/messages.ts +1 -1
- package/src/protocol/response/omp-tool-call-markup.ts +1 -1
- package/src/protocol/response/responses.ts +1 -1
- package/src/protocol/sse-decoder.ts +50 -1
- package/src/protocol/stop-reason.ts +2 -2
- package/src/protocol/think-split.ts +347 -0
- package/src/protocol/translation/attachment-integrity.ts +3 -3
- package/src/protocol/translation/cache-controls.ts +8 -20
- package/src/protocol/translation/capabilities.ts +6 -6
- package/src/protocol/translation/dialect/deepseek.ts +10 -0
- package/src/protocol/translation/dialect/inband.ts +39 -0
- package/src/protocol/translation/dialect/model-thinking.ts +89 -0
- package/src/protocol/translation/dialect/qwen.ts +114 -0
- package/src/protocol/translation/dialect/resolver.ts +83 -0
- package/src/protocol/translation/dialect/rules.ts +93 -0
- package/src/protocol/translation/dialect/thinking-ladder.ts +245 -0
- package/src/protocol/translation/dialect/types.ts +58 -0
- package/src/protocol/translation/quirks.ts +18 -4
- package/src/protocol/translation/thinking.ts +12 -252
- package/src/protocol/translation/tool-id.ts +3 -3
- package/src/protocol/translation/tool-repair.ts +1 -1
- package/src/protocol/upstream/post-json.ts +6 -1
- package/src/providers/adapters/compatible-adapter.ts +71 -4
- package/src/providers/authentication/jwt-validator.ts +0 -5
- package/src/providers/authentication/oauth-client.ts +254 -253
- package/src/providers/authentication/oauth-flow-store.ts +42 -7
- package/src/providers/bundled-discovery-providers.ts +6 -30
- package/src/providers/configured-openai-providers.ts +82 -97
- package/src/providers/default-registry.ts +35 -37
- package/src/providers/discovery/catalog/catalog-format.ts +13 -2
- package/src/providers/discovery/discovery-types.ts +0 -1
- package/src/providers/discovery/openai-model-discovery.ts +2 -2
- package/src/providers/discovery/probe-phases.ts +48 -13
- package/src/providers/discovery/probing-service.ts +6 -8
- package/src/providers/integrations/agentrouter/agentrouter.ts +12 -2
- package/src/providers/integrations/antigravity/antigravity-oauth.ts +0 -1
- package/src/providers/integrations/antigravity/antigravity-protocol.ts +88 -28
- package/src/providers/integrations/antigravity/antigravity-quota.ts +18 -6
- package/src/providers/integrations/antigravity/antigravity.ts +22 -13
- package/src/providers/integrations/buddy/buddy-catalog-shared.ts +1 -1
- package/src/providers/integrations/buddy/buddy-chat-shared.ts +20 -4
- package/src/providers/integrations/buddy/buddy-cli-headers.ts +19 -52
- package/src/providers/integrations/buddy/buddy-identity.ts +86 -0
- package/src/providers/integrations/buddy/buddy-oauth-shared.ts +1 -1
- package/src/providers/integrations/buddy/codebuddy/cn-provider.ts +1 -2
- package/src/providers/integrations/buddy/codebuddy/provider.ts +4 -15
- package/src/providers/integrations/buddy/codebuddy/shared.ts +30 -9
- package/src/providers/integrations/buddy/workbuddy/provider.ts +5 -9
- package/src/providers/integrations/buddy/workbuddy/shared.ts +21 -3
- package/src/providers/integrations/claude/claude-cch.ts +148 -148
- package/src/providers/integrations/claude/fallback-credit.ts +3 -7
- package/src/providers/integrations/cline/cline.ts +1 -1
- package/src/providers/integrations/codex/codex-device-code.ts +101 -101
- package/src/providers/integrations/codex/codex-oauth.ts +0 -1
- package/src/providers/integrations/commandcode/commandcode.ts +75 -115
- package/src/providers/integrations/commandcode/quota.ts +131 -51
- package/src/providers/integrations/cursor/cursor-http2.ts +0 -3
- package/src/providers/integrations/cursor/cursor-quota.ts +2 -6
- package/src/providers/integrations/cursor/cursor-request.ts +0 -87
- package/src/providers/integrations/cursor/cursor-shared.ts +0 -4
- package/src/providers/integrations/cursor/cursor.ts +35 -3
- package/src/providers/integrations/cursor/protocol/framing.ts +0 -56
- package/src/providers/integrations/cursor/protocol/messages.ts +0 -96
- package/src/providers/integrations/factory/factory.ts +9 -9
- package/src/providers/integrations/github/github-discovery.ts +70 -12
- package/src/providers/integrations/github/github-oauth.ts +184 -14
- package/src/providers/integrations/github/github.ts +134 -26
- package/src/providers/integrations/grok/grok-oauth.ts +261 -261
- package/src/providers/integrations/grok/grok-quota-frame.ts +1 -1
- package/src/providers/integrations/grok/grok-quota.ts +16 -7
- package/src/providers/integrations/grok/grok-ratelimit-store.ts +0 -5
- package/src/providers/integrations/grok/grok-ratelimit.ts +3 -0
- package/src/providers/integrations/grok/grok.ts +86 -36
- package/src/providers/integrations/kilo/kilo-oauth.ts +1 -1
- package/src/providers/integrations/kiro/kiro-cache.ts +31 -0
- package/src/providers/integrations/kiro/kiro-catalog.ts +31 -5
- package/src/providers/integrations/kiro/kiro-discovery.ts +47 -43
- package/src/providers/integrations/kiro/kiro-machine-id.ts +6 -3
- package/src/providers/integrations/kiro/kiro-oauth.ts +523 -255
- package/src/providers/integrations/kiro/kiro-quota.ts +35 -47
- package/src/providers/integrations/kiro/kiro-request.ts +8 -11
- package/src/providers/integrations/kiro/kiro-stream.ts +13 -0
- package/src/providers/integrations/kiro/kiro.ts +80 -68
- package/src/providers/integrations/muse/muse-oauth.ts +0 -1
- package/src/providers/integrations/muse/muse-quota.ts +0 -4
- package/src/providers/integrations/opencode/fingerprint.ts +7 -5
- package/src/providers/integrations/opencode/provider.ts +17 -24
- package/src/providers/integrations/qoder/qoder-catalog.ts +94 -11
- package/src/providers/integrations/qoder/qoder-oauth.ts +165 -25
- package/src/providers/integrations/qoder/qoder-quota.ts +48 -6
- package/src/providers/integrations/qoder/qoder-realm.ts +10 -31
- package/src/providers/integrations/qoder/qoder-sse.ts +159 -0
- package/src/providers/integrations/qoder/qoder-umid.ts +21 -25
- package/src/providers/integrations/qoder/qoder-virtual.ts +12 -0
- package/src/providers/integrations/qoder/qoder.ts +422 -71
- package/src/providers/integrations/shared/connect.ts +0 -54
- package/src/providers/integrations/shared/hash.ts +15 -0
- package/src/providers/integrations/shared/session-cache.ts +136 -0
- package/src/providers/integrations/trae/trae-cache.ts +7 -87
- package/src/providers/integrations/trae/trae-catalog.ts +1 -6
- package/src/providers/integrations/trae/trae-protocol.ts +17 -8
- package/src/providers/integrations/trae/trae-realm.ts +0 -7
- package/src/providers/integrations/trae/trae.ts +51 -8
- package/src/providers/integrations/xai/xai-oauth.ts +5 -5
- package/src/providers/integrations/zcode-start-plan/gifts.ts +265 -0
- package/src/providers/integrations/zcode-start-plan/oauth.ts +154 -0
- package/src/providers/integrations/zcode-start-plan/provider.ts +131 -0
- package/src/providers/integrations/zcode-start-plan/quota.ts +152 -0
- package/src/providers/integrations/zcode-start-plan/zcode_prompt.json +10 -0
- package/src/providers/operations/account-error-classification.ts +198 -133
- package/src/providers/operations/account-health-service.ts +31 -39
- package/src/providers/operations/account-reset-service.ts +58 -1
- package/src/providers/operations/byok-wire-profile.ts +19 -15
- package/src/providers/operations/cli-platform.ts +31 -5
- package/src/providers/operations/client-version-resolver.ts +4 -6
- package/src/providers/operations/client-versions.ts +10 -7
- package/src/providers/operations/provider-catalog-seeder.ts +2 -0
- package/src/providers/operations/provider-catalog-service.ts +18 -2
- package/src/providers/operations/provider-credential-service.ts +19 -2
- package/src/providers/provider-contracts.ts +18 -7
- package/src/providers/provider-metadata.ts +17 -2
- package/src/providers/provider-model-definition.ts +22 -1
- package/src/providers/provider-probe.ts +4 -2
- package/src/providers/provider-usage.ts +50 -19
- package/src/providers/quota/cache.ts +29 -0
- package/src/providers/quota/quota-contracts.ts +4 -0
- package/src/providers/quota/refresh.ts +27 -4
- package/src/providers/quota/snapshot.ts +94 -0
- package/src/providers/search/search-provider.ts +1 -3
- package/src/providers/search/search-providers.ts +2 -1
- package/src/security/abuse.ts +4 -4
- package/src/security/admission/service.ts +13 -6
- package/src/security/admission/ttl.ts +61 -61
- package/src/security/api-key-auth.ts +17 -3
- package/src/security/client-router-fingerprint.ts +4 -4
- package/src/security/credential-codec.ts +3 -3
- package/src/security/csrf.ts +2 -2
- package/src/security/ip-boundary.ts +16 -189
- package/src/security/model-access-rule.ts +1 -1
- package/src/security/outbound-headers.ts +18 -0
- package/src/shared/invoke-guard.ts +47 -0
- package/src/transport/contracts.ts +13 -4
- package/src/transport/dispatch/attempt-finalize.ts +70 -22
- package/src/transport/dispatch/attempt-loop.ts +22 -0
- package/src/transport/dispatch/capture-policy.ts +34 -37
- package/src/transport/dispatch/empty-stream.ts +23 -20
- package/src/transport/dispatch/generation.ts +25 -45
- package/src/transport/dispatch/native-shared.ts +127 -0
- package/src/transport/dispatch/proxy-request.ts +3 -1
- package/src/transport/dispatch/responses-compact.ts +25 -46
- package/src/transport/dispatch/streaming/encoder.ts +18 -72
- package/src/transport/dispatch/streaming/finalize.ts +2 -2
- package/src/transport/dispatch/streaming/stream.ts +7 -3
- package/src/transport/dispatch/streaming/thinking-loop.ts +1 -1
- package/src/transport/dispatch/systemone.ts +20 -48
- package/src/transport/dispatch/token-count.ts +41 -38
- package/src/transport/dispatch/websearch.ts +19 -45
- package/src/transport/drain-endpoint.ts +1 -1
- package/src/transport/failure-policy.ts +21 -1
- package/src/transport/guards/auth-guard.ts +0 -6
- package/src/transport/guards/body-policy.ts +3 -3
- package/src/transport/guards/error-lifecycle.ts +4 -0
- package/src/transport/guards/headroom-guard.ts +1 -1
- package/src/transport/guards/pipeline.ts +1 -1
- package/src/transport/guards/request-context.ts +12 -17
- package/src/transport/request/preparer.ts +286 -7
- package/src/transport/request/rtk/compress-request.ts +3 -3
- package/src/transport/request/rtk/rtk-constants.ts +2 -2
- package/src/transport/request/rtk/rtk-filters.ts +8 -8
- package/src/transport/request/state.ts +7 -13
- package/src/transport/request/system-prompt-injection.ts +74 -11
- package/src/transport/request/tenant-preferences.ts +22 -0
- package/src/transport/routing/candidate-index.ts +2 -2
- package/src/transport/routing/round-robin.ts +1 -1
- package/src/transport/routing/route-catalog.ts +17 -18
- package/src/transport/routing/route-model.ts +126 -33
- package/src/transport/routing/router.ts +159 -37
- package/src/transport/shutdown-notice.ts +2 -2
- package/src/transport/surface/adapters.ts +3 -3
- package/src/transport/surface/chat/encode.ts +7 -7
- package/src/transport/surface/chat/parse.ts +7 -7
- package/src/transport/surface/completion.ts +2 -2
- package/src/transport/surface/content-parts.ts +1 -1
- package/src/transport/surface/dialects.ts +2 -2
- package/src/transport/surface/messages/parse.ts +3 -3
- package/src/transport/surface/reasoning-summary.ts +9 -14
- package/src/transport/surface/responses/adapter.ts +1 -1
- package/src/transport/surface/responses/errors.ts +0 -9
- package/src/transport/vision-handoff-cache.ts +58 -0
- package/src/transport/vision-handoff.ts +431 -0
- package/src/workers/account-identity-sweep.ts +2 -2
- package/src/workers/buddy-growth-tasks.ts +392 -346
- package/src/workers/daily-checkin.ts +102 -49
- package/src/workers/maintenance-lease.ts +2 -35
- package/src/workers/oauth-refresh-sweep.ts +8 -1
- package/src/workers/quota-refresh-sweep.ts +120 -82
- package/src/workers/scheduler.ts +67 -4
- package/src/workers/sweep-runner.ts +24 -5
- package/src/workers/zcode-gift-claim.ts +108 -0
- package/dist/dashboard/assets/AccountCooldown-Bjo92Qat.js +0 -1
- package/dist/dashboard/assets/AccountCooldown-Bjo92Qat.js.gz +0 -0
- package/dist/dashboard/assets/BannedPage-ChG5svFb.js +0 -1
- package/dist/dashboard/assets/BannedPage-ChG5svFb.js.gz +0 -0
- package/dist/dashboard/assets/CliToolDetailPage-BIcWQun7.js +0 -1
- package/dist/dashboard/assets/CliToolDetailPage-BIcWQun7.js.gz +0 -0
- package/dist/dashboard/assets/CliToolsPage-Bf2VelDe.js +0 -1
- package/dist/dashboard/assets/CliToolsPage-Bf2VelDe.js.gz +0 -0
- package/dist/dashboard/assets/CombosPage-DCgm5g6g.js +0 -1
- package/dist/dashboard/assets/CombosPage-DCgm5g6g.js.gz +0 -0
- package/dist/dashboard/assets/ConsoleLogPage-a8mD0QF1.js +0 -1
- package/dist/dashboard/assets/ConsoleLogPage-a8mD0QF1.js.gz +0 -0
- package/dist/dashboard/assets/CustomizationPage-ggeMSjte.js +0 -1
- package/dist/dashboard/assets/CustomizationPage-ggeMSjte.js.gz +0 -0
- package/dist/dashboard/assets/HealthEventsModal-DzSWzE_j.js +0 -1
- package/dist/dashboard/assets/HealthEventsModal-DzSWzE_j.js.gz +0 -0
- package/dist/dashboard/assets/LoginPage-U6AKaJcF.js +0 -1
- package/dist/dashboard/assets/LoginPage-U6AKaJcF.js.gz +0 -0
- package/dist/dashboard/assets/ModelPicker-BMS2t8BA.js.gz +0 -0
- package/dist/dashboard/assets/OverviewPage-D2D4IiHl.js +0 -1
- package/dist/dashboard/assets/OverviewPage-D2D4IiHl.js.gz +0 -0
- package/dist/dashboard/assets/ProviderDetailPage-CrNf7j_X.js +0 -5
- package/dist/dashboard/assets/ProviderDetailPage-CrNf7j_X.js.gz +0 -0
- package/dist/dashboard/assets/ProviderIcon-FB6yS4v1.js +0 -1
- package/dist/dashboard/assets/ProviderIcon-FB6yS4v1.js.gz +0 -0
- package/dist/dashboard/assets/ProvidersPage-BSDbquc1.js +0 -1
- package/dist/dashboard/assets/ProvidersPage-BSDbquc1.js.gz +0 -0
- package/dist/dashboard/assets/ProxyPage-lsrx7NYg.js.gz +0 -0
- package/dist/dashboard/assets/QuotaPage-L0skzML8.js +0 -1
- package/dist/dashboard/assets/QuotaPage-L0skzML8.js.gz +0 -0
- package/dist/dashboard/assets/SettingsPage-CmAbjRHW.js +0 -1
- package/dist/dashboard/assets/SettingsPage-CmAbjRHW.js.gz +0 -0
- package/dist/dashboard/assets/SetupPage-f0DE1h0-.js +0 -1
- package/dist/dashboard/assets/SetupPage-f0DE1h0-.js.gz +0 -0
- package/dist/dashboard/assets/SortableList-ClzpwyET.js +0 -1
- package/dist/dashboard/assets/SortableList-ClzpwyET.js.gz +0 -0
- package/dist/dashboard/assets/StudioPage-Cq5tW7hW.js.gz +0 -0
- package/dist/dashboard/assets/ToolIcon-K1ckcDKg.js +0 -1
- package/dist/dashboard/assets/ToolIcon-K1ckcDKg.js.gz +0 -0
- package/dist/dashboard/assets/UsagePage-Dfc9rWQn.js +0 -56
- package/dist/dashboard/assets/UsagePage-Dfc9rWQn.js.gz +0 -0
- package/dist/dashboard/assets/api-keys-C38iXoO4.js +0 -1
- package/dist/dashboard/assets/api-keys-C38iXoO4.js.gz +0 -0
- package/dist/dashboard/assets/app-BayTTy01.js +0 -9
- package/dist/dashboard/assets/app-BayTTy01.js.gz +0 -0
- package/dist/dashboard/assets/app-a159k0ub.css +0 -2
- package/dist/dashboard/assets/app-a159k0ub.css.gz +0 -0
- package/dist/dashboard/assets/assert-DbRA8EG2.js +0 -15
- package/dist/dashboard/assets/assert-DbRA8EG2.js.gz +0 -0
- package/dist/dashboard/assets/badge-D9CS6dZk.js.gz +0 -0
- package/dist/dashboard/assets/banner-DympBNq4.js.gz +0 -0
- package/dist/dashboard/assets/card-ibRWU_uT.js.gz +0 -0
- package/dist/dashboard/assets/cli-tools-63qBGaRw.js +0 -1
- package/dist/dashboard/assets/cli-tools-63qBGaRw.js.gz +0 -0
- package/dist/dashboard/assets/clipboard-button-DJm-9pz7.js.gz +0 -0
- package/dist/dashboard/assets/dialog-8fiE6tec.js +0 -1
- package/dist/dashboard/assets/dialog-8fiE6tec.js.gz +0 -0
- package/dist/dashboard/assets/drawer-CqGYeOrd.js.gz +0 -0
- package/dist/dashboard/assets/entry-BSAsYsmV.js +0 -1
- package/dist/dashboard/assets/entry-BSAsYsmV.js.gz +0 -0
- package/dist/dashboard/assets/entry-CiIQULZD.js +0 -4
- package/dist/dashboard/assets/entry-CiIQULZD.js.gz +0 -0
- package/dist/dashboard/assets/entry-Daz0lJ-W.js +0 -1
- package/dist/dashboard/assets/entry-Daz0lJ-W.js.gz +0 -0
- package/dist/dashboard/assets/formatters-D-MTJxMr.js.gz +0 -0
- package/dist/dashboard/assets/github-badge-CPK47xQx.js +0 -1
- package/dist/dashboard/assets/github-badge-CPK47xQx.js.gz +0 -0
- package/dist/dashboard/assets/index-DBNPOfhV.js.gz +0 -0
- package/dist/dashboard/assets/inline-BT0zntEr.js.gz +0 -0
- package/dist/dashboard/assets/input-Da2ZViWg.js.gz +0 -0
- package/dist/dashboard/assets/layout-BXNeLw6M.js.gz +0 -0
- package/dist/dashboard/assets/list-row-BycOrrIV.js.gz +0 -0
- package/dist/dashboard/assets/live-DCQNZpF7.js +0 -1
- package/dist/dashboard/assets/live-DCQNZpF7.js.gz +0 -0
- package/dist/dashboard/assets/mutation-Rr0TIvcj.js.gz +0 -0
- package/dist/dashboard/assets/network-9Yj2ZyLo.js +0 -1
- package/dist/dashboard/assets/network-9Yj2ZyLo.js.gz +0 -0
- package/dist/dashboard/assets/numbers-CEagj6ZZ.js +0 -2
- package/dist/dashboard/assets/numbers-CEagj6ZZ.js.gz +0 -0
- package/dist/dashboard/assets/providers/zai-coding-plan.svg +0 -6
- package/dist/dashboard/assets/providers/zai-coding-plan.svg.gz +0 -0
- package/dist/dashboard/assets/quota-Caw7wqci.js +0 -1
- package/dist/dashboard/assets/quota-Caw7wqci.js.gz +0 -0
- package/dist/dashboard/assets/routing-CO9zCUus.js +0 -1
- package/dist/dashboard/assets/routing-CO9zCUus.js.gz +0 -0
- package/dist/dashboard/assets/select-BIYIBkMU.js.gz +0 -0
- package/dist/dashboard/assets/settings-jS3-PNSA.js +0 -1
- package/dist/dashboard/assets/settings-jS3-PNSA.js.gz +0 -0
- package/dist/dashboard/assets/stack-DfgnFDWY.js.gz +0 -0
- package/dist/dashboard/assets/state-CkfdYWel.js.gz +0 -0
- package/dist/dashboard/assets/stream-retry-5QnVuSSo.js +0 -1
- package/dist/dashboard/assets/stream-retry-5QnVuSSo.js.gz +0 -0
- package/dist/dashboard/assets/switch-SYm237HG.js.gz +0 -0
- package/dist/dashboard/assets/useMutation-BQqCRNIi.js.gz +0 -0
- package/src/console/cli-tools/injectors/cline.ts +0 -110
- package/src/console/cli-tools/injectors/copilot.ts +0 -108
- package/src/console/cli-tools/injectors/cowork.ts +0 -64
- package/src/console/cli-tools/injectors/deepseek-tui.ts +0 -85
- package/src/console/cli-tools/injectors/droid.ts +0 -96
- package/src/console/cli-tools/injectors/grok-build.ts +0 -70
- package/src/console/cli-tools/injectors/hermes.ts +0 -101
- package/src/console/cli-tools/injectors/jcode.ts +0 -115
- package/src/console/cli-tools/injectors/openclaw.ts +0 -161
- package/src/network/response-headers.ts +0 -39
- package/src/protocol/response/dsml.ts +0 -38
- package/src/providers/integrations/xiaomi-mimo/think-stream.ts +0 -229
- /package/dist/dashboard/assets/brand/{og_bansos.webp → og_bansos_initial.webp} +0 -0
- /package/dist/dashboard/assets/brand/{og_image.webp → og_image_initial.webp} +0 -0
|
@@ -0,0 +1,152 @@
|
|
|
1
|
+
import { asCoercedNumber, asRecord, asTrimmedString } from "../../../shared/coerce";
|
|
2
|
+
import type { FetchLike, ProviderQuotaResult, ProviderQuotaWindow } from "../../quota/quota-contracts";
|
|
3
|
+
|
|
4
|
+
const BALANCE_URL = "https://zcode.z.ai/api/v1/zcode-plan/billing/balance?app_version=3.16.3";
|
|
5
|
+
const DEVICE_MID = "9f1b0d4e-3c2a-4e7b-9f1d-6a2c8b5e0d31";
|
|
6
|
+
const APP_VERSION = "3.16.3";
|
|
7
|
+
|
|
8
|
+
function instant(value: unknown): string | null {
|
|
9
|
+
const seconds = asCoercedNumber(value);
|
|
10
|
+
if (seconds === undefined || seconds <= 0) return null;
|
|
11
|
+
const date = new Date(seconds * 1000);
|
|
12
|
+
return Number.isFinite(date.getTime()) ? date.toISOString() : null;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
function boundary(values: readonly unknown[], latest: boolean): string | null {
|
|
16
|
+
const instants = values.map(instant).filter((value): value is string => value !== null);
|
|
17
|
+
if (instants.length === 0) return null;
|
|
18
|
+
return instants.reduce((a, b) => (latest ? a > b : a < b) ? a : b);
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
// The upstream capabilities, not the display name, declare which models a grant serves.
|
|
22
|
+
function modelIds(value: unknown): readonly string[] {
|
|
23
|
+
if (!Array.isArray(value)) return [];
|
|
24
|
+
return [...new Set(value.flatMap((entry: unknown) => {
|
|
25
|
+
const capability = asTrimmedString(entry);
|
|
26
|
+
if (capability === undefined || (capability.includes(":") && !capability.startsWith("model:"))) return [];
|
|
27
|
+
const model = capability.replace(/^model:/, "").trim().toLowerCase();
|
|
28
|
+
return model ? [model] : [];
|
|
29
|
+
}))];
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
function periodLabel(period: string | undefined): string {
|
|
33
|
+
if (period === "daily_night") return "nightly";
|
|
34
|
+
if (period === "one_time") return "one-time";
|
|
35
|
+
return period ?? "grant";
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
function grantLabel(name: string): string {
|
|
39
|
+
return /^(?:zcode\s+)?start plan$/i.test(name) ? "Start" : name;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
function percent(value: number | null, limit: number | null): number | null {
|
|
43
|
+
return value !== null && limit !== null && limit > 0
|
|
44
|
+
? Math.min(100, Math.max(0, value / limit * 100))
|
|
45
|
+
: null;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
function samePlan(bucket: Record<string, unknown>, plan: Record<string, unknown>): boolean {
|
|
49
|
+
const userPlan = asTrimmedString(bucket["user_plan_id"]);
|
|
50
|
+
const owner = asTrimmedString(plan["user_plan_id"]);
|
|
51
|
+
if (userPlan !== undefined && owner !== undefined) return userPlan === owner;
|
|
52
|
+
const id = asTrimmedString(bucket["plan_id"]);
|
|
53
|
+
return id !== undefined && id === asTrimmedString(plan["plan_id"]);
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
/** Billing shape verified against opencode-zcode-auth 0.1.42; see the provider guide. */
|
|
57
|
+
export async function fetchZcodeStartPlanQuota(
|
|
58
|
+
credential: string,
|
|
59
|
+
fetcher: FetchLike,
|
|
60
|
+
): Promise<ProviderQuotaResult> {
|
|
61
|
+
const source = "zcode-start";
|
|
62
|
+
try {
|
|
63
|
+
const response = await fetcher(BALANCE_URL, {
|
|
64
|
+
headers: {
|
|
65
|
+
authorization: `Bearer ${credential}`,
|
|
66
|
+
accept: "application/json",
|
|
67
|
+
"x-device-mid": DEVICE_MID,
|
|
68
|
+
"x-zcode-app-version": APP_VERSION,
|
|
69
|
+
"x-client-language": "en-US",
|
|
70
|
+
},
|
|
71
|
+
signal: AbortSignal.timeout(15_000),
|
|
72
|
+
});
|
|
73
|
+
if (!response.ok) return { source, plan: null, windows: [], error: `plan billing answered ${response.status}` };
|
|
74
|
+
const payload = asRecord(await response.json());
|
|
75
|
+
const code = payload?.["code"];
|
|
76
|
+
if (!payload || payload["success"] === false ||
|
|
77
|
+
(code !== undefined && ![0, 200, "0", "200"].includes(code as string | number))) {
|
|
78
|
+
return { source, plan: null, windows: [], error: "plan billing rejected request" };
|
|
79
|
+
}
|
|
80
|
+
const data = asRecord(payload["data"]);
|
|
81
|
+
if (!data || !Array.isArray(data["balances"]) || !Array.isArray(data["plans"])) {
|
|
82
|
+
return { source, plan: null, windows: [], error: "plan billing returned an unreadable balance" };
|
|
83
|
+
}
|
|
84
|
+
const plans = data["plans"].flatMap((value: unknown) => {
|
|
85
|
+
const plan = asRecord(value);
|
|
86
|
+
return plan ? [plan] : [];
|
|
87
|
+
});
|
|
88
|
+
const windows: ProviderQuotaWindow[] = [];
|
|
89
|
+
const names = new Set<string>();
|
|
90
|
+
const represented = new Set<Record<string, unknown>>();
|
|
91
|
+
for (const raw of data["balances"]) {
|
|
92
|
+
const bucket = asRecord(raw);
|
|
93
|
+
if (!bucket) continue;
|
|
94
|
+
const owner = plans.find((plan) => samePlan(bucket, plan));
|
|
95
|
+
if (owner) represented.add(owner);
|
|
96
|
+
const name = asTrimmedString(owner?.["name"]) ?? "Start Plan";
|
|
97
|
+
names.add(name);
|
|
98
|
+
const entitlement = (Array.isArray(owner?.["entitlements"]) ? owner["entitlements"] : [])
|
|
99
|
+
.map(asRecord).find((entry) => entry?.["entitlement_id"] === bucket["entitlement_id"]);
|
|
100
|
+
const period = asTrimmedString(entitlement?.["period"]);
|
|
101
|
+
const limit = asCoercedNumber(bucket["total_units"]) ?? null;
|
|
102
|
+
const reportedUsed = asCoercedNumber(bucket["used_units"]);
|
|
103
|
+
const reportedRemaining = asCoercedNumber(bucket["remaining_units"]);
|
|
104
|
+
const used = reportedUsed ?? (limit !== null && reportedRemaining !== undefined ? Math.max(0, limit - reportedRemaining) : null);
|
|
105
|
+
const remaining = reportedRemaining ?? (limit !== null && used !== null ? Math.max(0, limit - used) : null);
|
|
106
|
+
const models = modelIds(bucket["capabilities"] ?? entitlement?.["capabilities"]);
|
|
107
|
+
const expired = asTrimmedString(owner?.["status"])?.toLowerCase() === "expired";
|
|
108
|
+
windows.push({
|
|
109
|
+
kind: period ?? "grant",
|
|
110
|
+
label: `${asTrimmedString(bucket["show_name"]) ?? (models.join(", ") || "GLM")} · ${grantLabel(name)} · ${periodLabel(period)}`,
|
|
111
|
+
accounting: "independent",
|
|
112
|
+
modelIds: models,
|
|
113
|
+
startsAt: boundary([owner?.["starts_at"], bucket["period_start"]], true),
|
|
114
|
+
resetsAt: boundary([bucket["expires_at"], bucket["period_end"], owner?.["ends_at"]], false),
|
|
115
|
+
usedPercent: expired ? 100 : percent(used, limit),
|
|
116
|
+
remainingPercent: expired ? 0 : percent(remaining, limit),
|
|
117
|
+
used,
|
|
118
|
+
limit,
|
|
119
|
+
remaining,
|
|
120
|
+
recurring: !expired && (period === "daily" || period === "daily_night"),
|
|
121
|
+
});
|
|
122
|
+
}
|
|
123
|
+
// The balance may list a future plan before it has materialized any buckets.
|
|
124
|
+
for (const plan of plans) {
|
|
125
|
+
const startsAt = instant(plan["starts_at"]);
|
|
126
|
+
if (represented.has(plan) || !startsAt || Date.parse(startsAt) <= Date.now() || plan["status"] === "expired") continue;
|
|
127
|
+
const name = asTrimmedString(plan["name"]) ?? "Start Plan";
|
|
128
|
+
names.add(name);
|
|
129
|
+
const entitlements = Array.isArray(plan["entitlements"]) ? plan["entitlements"] : [];
|
|
130
|
+
const pending = entitlements.length > 0 ? entitlements : [{}];
|
|
131
|
+
for (const raw of pending) {
|
|
132
|
+
const entitlement = asRecord(raw);
|
|
133
|
+
windows.push({
|
|
134
|
+
kind: "grant", label: `${grantLabel(name)} · ${asTrimmedString(entitlement?.["show_name"]) ?? "not started yet"}`,
|
|
135
|
+
accounting: "independent", modelIds: modelIds(entitlement?.["capabilities"]), startsAt,
|
|
136
|
+
resetsAt: instant(plan["ends_at"]), usedPercent: null, remainingPercent: null,
|
|
137
|
+
remaining: null, used: null, limit: asCoercedNumber(entitlement?.["grant_units"]) ?? null,
|
|
138
|
+
recurring: false,
|
|
139
|
+
});
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
return { source, plan: [...names].join(", ") || null, windows, error: null };
|
|
143
|
+
} catch (error) {
|
|
144
|
+
const name = error instanceof Error ? error.name : "";
|
|
145
|
+
const message = name === "TimeoutError" || name === "AbortError"
|
|
146
|
+
? "plan billing operation timed out or was aborted"
|
|
147
|
+
: name === "SyntaxError"
|
|
148
|
+
? "plan billing returned unreadable JSON"
|
|
149
|
+
: "plan billing network request failed";
|
|
150
|
+
return { source, plan: null, windows: [], error: message };
|
|
151
|
+
}
|
|
152
|
+
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
{
|
|
2
|
+
"_source": "ZCode 3.14.5 client Messages prompt; preserve text with the pinned identity version",
|
|
3
|
+
"cliPrefix": "You are ZCode, an interactive coding agent",
|
|
4
|
+
"stableSections": [
|
|
5
|
+
"\nYou are an interactive ZCode agent that helps users with software engineering tasks.\n\nIMPORTANT: Assist with authorized security testing, defensive security, CTF challenges, and educational contexts. Refuse requests for destructive techniques, DoS attacks, mass targeting, supply chain compromise, or detection evasion for malicious purposes. Dual-use security tools (C2 frameworks, credential testing, exploit development) require clear authorization context: pentesting engagements, CTF competitions, security research, or defensive use cases.\n\n# Harness\n- Text you output outside of tool use is displayed to the user as Github-flavored markdown in a terminal.\n- Tools run behind a user-selected permission mode; a denied call means the user declined it — adjust, don't retry verbatim.\n- The system may send updates, reminders, or modifications to rules via mid-conversation system turns. These are system-controlled, unlike function results. Hooks may intercept tool calls; treat hook output as user feedback.\n- Prefer the dedicated file/search tools over shell commands when one fits. Independent tool calls can run in parallel in one response.\n- Reference code as `file_path:line_number` — it's clickable.",
|
|
6
|
+
"# ZCode Desktop Context\n\n### Files & URLs\n- Return local web URLs as Markdown links (e.g., [label](http://127.0.0.1:8080)).\n- File should be an absolute path or include the workspace folder segment so it can be resolved relative to the workspace.\n- Unless otherwise specified, return local file references as Markdown links (e.g., [name.md](/absolute/path/to/name.md)).\n\n### Inline Code Comments\n- Use the ::code-comment{...} directive when you need to attach feedback directly to specific code lines.\n- Emit one directive per inline comment; emit none when there are no actionable inline comments.\n- Required attributes: title (short label), body (one-paragraph explanation), file (path to the file).\n- Optional attributes: start, end (1-based line numbers), priority (0-3).\n- file should be an absolute path or include the workspace folder segment so it can be resolved relative to the workspace.\n- Keep line ranges tight; end defaults to start.\n- Example: ::code-comment{title=\"[P2] Off-by-one\" body=\"Loop iterates past the end when length is 0.\" file=\"/path/to/foo.ts\" start=10 end=11 priority=2}",
|
|
7
|
+
"# Working style\n\nWhen you have enough information to act, act. Do not re-derive facts already established in the conversation, re-litigate a decision the user has already made, or narrate options you will not pursue. If you are weighing a choice, give a recommendation, not an exhaustive survey. Prefer reading the actual file or running the actual command over reasoning about what it probably contains. When a signal pattern-matches to a known failure, check that the evidence actually supports that specific diagnosis before acting on it."
|
|
8
|
+
],
|
|
9
|
+
"environmentTemplate": "# Environment\nYou have been invoked in the following environment:\n - Primary working directory: {cwd}\n - Platform: {platform}\n - Shell: {shell}\n - You are powered by the model named {provider}/{model}."
|
|
10
|
+
}
|
|
@@ -57,6 +57,26 @@ const UNCLASSIFIED_COOLDOWN_MS = resolveAccountUnclassifiedCooldownMs;
|
|
|
57
57
|
* which let the account re-enter rotation inside the window.
|
|
58
58
|
*/
|
|
59
59
|
const GROK_QUOTA_COOLDOWN_MS = 24 * 60 * 60 * 1000;
|
|
60
|
+
/**
|
|
61
|
+
* Trae answers `4013 "AI service is not available in the current region now."`
|
|
62
|
+
* when the upstream does not serve the account's region. A day because the
|
|
63
|
+
* verdict is durable: it reproduces on every request until the region opens,
|
|
64
|
+
* and the account must not be re-dialled every thirty seconds for the whole
|
|
65
|
+
* window.
|
|
66
|
+
*/
|
|
67
|
+
const TRAE_REGION_COOLDOWN_MS = 24 * 60 * 60 * 1000;
|
|
68
|
+
/**
|
|
69
|
+
* Trae's free-tier quota (`4008` / "exceeded the quota") resets daily, so its
|
|
70
|
+
* exhaustion is a full-day model backoff — never the generic 1h fallback,
|
|
71
|
+
* which let the account re-enter rotation inside the window.
|
|
72
|
+
*/
|
|
73
|
+
const TRAE_QUOTA_COOLDOWN_MS = 24 * 60 * 60 * 1000;
|
|
74
|
+
/**
|
|
75
|
+
* Qoder's quota verdicts (`110` billing-daily-count, the upstream-499 close)
|
|
76
|
+
* are per-model: one model's spend cap does not drain another. A day matches
|
|
77
|
+
* the daily billing window the provider names.
|
|
78
|
+
*/
|
|
79
|
+
const QODER_QUOTA_COOLDOWN_MS = 24 * 60 * 60 * 1000;
|
|
60
80
|
/**
|
|
61
81
|
* The buddy family's policy/channel block (`11140`, `11128`) is a *base* backoff,
|
|
62
82
|
* not a flat penalty — see {@link resolveAccountPolicyBlockCooldownMs}. It used
|
|
@@ -438,6 +458,26 @@ function banWording(lower: string): boolean {
|
|
|
438
458
|
);
|
|
439
459
|
}
|
|
440
460
|
|
|
461
|
+
/**
|
|
462
|
+
* Whether GitHub Copilot stated the account lacks a license — a ban-shaped
|
|
463
|
+
* verdict on the account, not a refreshable auth rejection.
|
|
464
|
+
*
|
|
465
|
+
* Observed live (2026-11-03): the health log showed
|
|
466
|
+
* `unauthorized: not licensed to use Copilot` and `forbidden` on
|
|
467
|
+
* `gpt-6-luna`. Copilot answers 401 for a bad credential and 403 for a
|
|
468
|
+
* license/entitlement refusal, so `forbidden`/`unauthorized` on this surface
|
|
469
|
+
* is the same verdict. No amount of waiting or refreshing changes it — the
|
|
470
|
+
* subscription cannot serve this credential.
|
|
471
|
+
*/
|
|
472
|
+
function copilotNotLicensed(lower: string): boolean {
|
|
473
|
+
return (
|
|
474
|
+
lower.includes("not licensed") ||
|
|
475
|
+
lower.includes("forbidden") ||
|
|
476
|
+
lower.includes("unauthorized") ||
|
|
477
|
+
lower.includes("license")
|
|
478
|
+
);
|
|
479
|
+
}
|
|
480
|
+
|
|
441
481
|
/**
|
|
442
482
|
* Bounded to a day, matching `MAX_COOLDOWN_MS` in the failure policy: a stated
|
|
443
483
|
* window longer than that is a monthly or plan-level limit, and parking an
|
|
@@ -586,20 +626,10 @@ interface AccountErrorSignals {
|
|
|
586
626
|
readonly staticToken: boolean;
|
|
587
627
|
readonly credentialKind: string | undefined;
|
|
588
628
|
/** Buddy-family provider: the only family with provider-specific codes below. */
|
|
589
|
-
readonly buddy: boolean;
|
|
590
|
-
/**
|
|
591
|
-
* The upstream named a restriction on this account, not a refusal of the
|
|
592
|
-
* request. Only the `11140` shape carries `displayMsg` about the account
|
|
593
|
-
* being restricted, so the policy arm can tell a ban from a bad request
|
|
594
|
-
* instead of treating both as one cooldown.
|
|
595
|
-
*/
|
|
596
629
|
readonly buddyBanned: boolean;
|
|
597
630
|
readonly priceRefusal: boolean;
|
|
598
|
-
readonly deploymentInfraError: boolean;
|
|
599
631
|
readonly quotaSignal: boolean;
|
|
600
632
|
readonly policyRejection: boolean;
|
|
601
|
-
readonly requestScoped: boolean;
|
|
602
|
-
readonly channelRejection: boolean;
|
|
603
633
|
readonly hostedToolFailure: boolean;
|
|
604
634
|
readonly modelEntitlementFailure: boolean;
|
|
605
635
|
readonly queuedUpstream: boolean;
|
|
@@ -793,7 +823,20 @@ export function classifyAccountError(
|
|
|
793
823
|
const modelBlockHits = Math.max(1, Math.floor(options?.modelBlockHits ?? 1));
|
|
794
824
|
const staticToken = options?.staticToken === true;
|
|
795
825
|
const credentialKind = options?.credentialKind;
|
|
796
|
-
|
|
826
|
+
|
|
827
|
+
// Start Plan is a separate provider: its named trial refusal rests only that model.
|
|
828
|
+
const providerId = options?.providerId ?? (error instanceof GatewayError ? error.details.providerId : undefined);
|
|
829
|
+
const refusedModel = statusCode === 400
|
|
830
|
+
? /no active limited quota for ([\w.-]+)/i.exec(message)?.[1]
|
|
831
|
+
: statusCode === 429
|
|
832
|
+
? /limited quota(?: for)? ([\w.-]+)(?: is)? exhausted/i.exec(message)?.[1]
|
|
833
|
+
: undefined;
|
|
834
|
+
if (providerId === "zcode-start" && modelId !== undefined && refusedModel !== undefined &&
|
|
835
|
+
refusedModel.toLowerCase().replace(/-trial$/, "") === modelId.toLowerCase().replace(/-trial$/, "")) {
|
|
836
|
+
const cooldownMs = statedCooldownMs ?? DEFAULT_QUOTA_COOLDOWN_MS();
|
|
837
|
+
return result("model_unreachable", "cooldown", cooldownMs, new Date(Date.now() + cooldownMs),
|
|
838
|
+
reason("Start Plan trial unavailable for this model"), origin === "upstream");
|
|
839
|
+
}
|
|
797
840
|
|
|
798
841
|
// A price refusal is a verdict on the *request*, not on the account. inferhub
|
|
799
842
|
// answers 402 with `no provider's ask matches your max-per-mtok bid`: the
|
|
@@ -869,6 +912,7 @@ export function classifyAccountError(
|
|
|
869
912
|
// keeps serving its other models.
|
|
870
913
|
providerCode === "112" ||
|
|
871
914
|
providerCode === "110" ||
|
|
915
|
+
providerCode === "116" ||
|
|
872
916
|
providerCode === "insufficient_quota" ||
|
|
873
917
|
providerCode === "quota_exceeded" ||
|
|
874
918
|
providerCode === "subscription:free-usage-exhausted" ||
|
|
@@ -1067,7 +1111,8 @@ export function classifyAccountError(
|
|
|
1067
1111
|
// for all other models. Disabling the whole account breaks healthy models.
|
|
1068
1112
|
const modelEntitlementFailure =
|
|
1069
1113
|
statusCode === 403 &&
|
|
1070
|
-
(
|
|
1114
|
+
((providerId === "commandcode" && lower.includes("model_not_in_plan")) ||
|
|
1115
|
+
lower.includes("not have a valid license") ||
|
|
1071
1116
|
lower.includes("valid license of this product") ||
|
|
1072
1117
|
lower.includes("model not supported") ||
|
|
1073
1118
|
lower.includes("not entitled to") ||
|
|
@@ -1131,14 +1176,10 @@ export function classifyAccountError(
|
|
|
1131
1176
|
modelBlockHits,
|
|
1132
1177
|
staticToken,
|
|
1133
1178
|
credentialKind,
|
|
1134
|
-
buddy,
|
|
1135
1179
|
buddyBanned,
|
|
1136
1180
|
priceRefusal,
|
|
1137
|
-
deploymentInfraError,
|
|
1138
1181
|
quotaSignal,
|
|
1139
1182
|
policyRejection,
|
|
1140
|
-
requestScoped,
|
|
1141
|
-
channelRejection,
|
|
1142
1183
|
hostedToolFailure,
|
|
1143
1184
|
modelEntitlementFailure,
|
|
1144
1185
|
queuedUpstream,
|
|
@@ -1225,101 +1266,6 @@ const ACCOUNT_ERROR_RULES: readonly AccountErrorRule[] = [
|
|
|
1225
1266
|
false,
|
|
1226
1267
|
),
|
|
1227
1268
|
},
|
|
1228
|
-
{
|
|
1229
|
-
name: "deployment-infrastructure",
|
|
1230
|
-
match: (s) => s.deploymentInfraError,
|
|
1231
|
-
decide: (s) =>
|
|
1232
|
-
s.result(
|
|
1233
|
-
"server_error",
|
|
1234
|
-
"cooldown",
|
|
1235
|
-
60_000,
|
|
1236
|
-
null,
|
|
1237
|
-
`Proxy deployment error: ${s.message.slice(0, 160)}`,
|
|
1238
|
-
false,
|
|
1239
|
-
),
|
|
1240
|
-
},
|
|
1241
|
-
{
|
|
1242
|
-
name: "model-frequency-window",
|
|
1243
|
-
match: (s) => s.lower.includes("frequency limit") && s.lower.includes("switch to the other models"),
|
|
1244
|
-
decide: (s) => {
|
|
1245
|
-
const cooldownMs = s.statedCooldownMs ?? DEFAULT_QUOTA_COOLDOWN_MS();
|
|
1246
|
-
return s.result(
|
|
1247
|
-
"rate_limit_transient",
|
|
1248
|
-
"cooldown",
|
|
1249
|
-
cooldownMs,
|
|
1250
|
-
new Date(Date.now() + cooldownMs),
|
|
1251
|
-
s.reason("Provider frequency limit for this model"),
|
|
1252
|
-
// Provider-scoped evidence still has to reach the writer: a stream frame
|
|
1253
|
-
// carries no credential detail, so `canMutate` is false and without this
|
|
1254
|
-
// the pair would be retried for the whole window it was closed for.
|
|
1255
|
-
s.origin === "upstream" && s.scope === "provider",
|
|
1256
|
-
);
|
|
1257
|
-
},
|
|
1258
|
-
},
|
|
1259
|
-
{
|
|
1260
|
-
name: "content-policy-block",
|
|
1261
|
-
match: (s) => s.policyRejection && s.buddy,
|
|
1262
|
-
decide: (s) => {
|
|
1263
|
-
// A ban is a verdict on the credential, and cooldown cannot answer it:
|
|
1264
|
-
// the account is refused, not throttled. Disabling is the fix, and
|
|
1265
|
-
// disabling *immediately* is a feature — a client's retry budget is spent
|
|
1266
|
-
// in seconds, so a banned account that merely cooled stayed in the plan
|
|
1267
|
-
// and burned sibling accounts that were still healthy before the window
|
|
1268
|
-
// expired.
|
|
1269
|
-
//
|
|
1270
|
-
// The two shapes are told apart by the body, not the code alone: `11140`
|
|
1271
|
-
// names a restriction on the account, `11-128` refuses the request.
|
|
1272
|
-
if (s.buddyBanned) {
|
|
1273
|
-
return s.result(
|
|
1274
|
-
"policy_blocked_banned",
|
|
1275
|
-
"disabled",
|
|
1276
|
-
0,
|
|
1277
|
-
null,
|
|
1278
|
-
s.reason("Account banned by upstream"),
|
|
1279
|
-
// A ban is evidence about the credential even at provider scope, for
|
|
1280
|
-
// the same reason a named revocation is: the message is the evidence.
|
|
1281
|
-
// Without this a stream frame's missing credential detail would leave
|
|
1282
|
-
// a banned account serving.
|
|
1283
|
-
true,
|
|
1284
|
-
);
|
|
1285
|
-
}
|
|
1286
|
-
// Not a ban: the upstream refused this request. The account is fine, so
|
|
1287
|
-
// the only correct move is to stop retrying it verbatim. Cooling the
|
|
1288
|
-
// account here was the bug that made one malformed request look like a
|
|
1289
|
-
// dead credential.
|
|
1290
|
-
return s.result(
|
|
1291
|
-
"policy_blocked_invalid_request",
|
|
1292
|
-
"cooldown",
|
|
1293
|
-
0,
|
|
1294
|
-
null,
|
|
1295
|
-
s.reason("Upstream refused this request"),
|
|
1296
|
-
// Never mutates: a malformed body fails identically on every account,
|
|
1297
|
-
// so cooling would burn a healthy credential on the gateway's own fault.
|
|
1298
|
-
false,
|
|
1299
|
-
);
|
|
1300
|
-
},
|
|
1301
|
-
},
|
|
1302
|
-
{
|
|
1303
|
-
name: "request-scoped-rejection",
|
|
1304
|
-
match: (s) => s.requestScoped && s.buddy,
|
|
1305
|
-
decide: (s) =>
|
|
1306
|
-
s.result("unknown", "cooldown", 0, null, s.reason("Request-scoped upstream rejection"), false),
|
|
1307
|
-
},
|
|
1308
|
-
{
|
|
1309
|
-
name: "channel-rejection",
|
|
1310
|
-
match: (s) => s.channelRejection && s.buddy,
|
|
1311
|
-
decide: (s) => {
|
|
1312
|
-
const channelBlockMs = resolveAccountPolicyBlockCooldownMs();
|
|
1313
|
-
return s.result(
|
|
1314
|
-
"policy_blocked",
|
|
1315
|
-
"cooldown",
|
|
1316
|
-
channelBlockMs,
|
|
1317
|
-
new Date(Date.now() + channelBlockMs),
|
|
1318
|
-
s.reason("Provider channel rejection"),
|
|
1319
|
-
s.origin === "upstream",
|
|
1320
|
-
);
|
|
1321
|
-
},
|
|
1322
|
-
},
|
|
1323
1269
|
{
|
|
1324
1270
|
name: "validation-required",
|
|
1325
1271
|
match: (s) => s.validationRequired,
|
|
@@ -1337,6 +1283,33 @@ const ACCOUNT_ERROR_RULES: readonly AccountErrorRule[] = [
|
|
|
1337
1283
|
true,
|
|
1338
1284
|
),
|
|
1339
1285
|
},
|
|
1286
|
+
{
|
|
1287
|
+
// GitHub Copilot answers a license/entitlement refusal with 403 and
|
|
1288
|
+
// "not licensed to use Copilot" / "forbidden" / "unauthorized". That is a
|
|
1289
|
+
// verdict on the account: the subscription cannot serve this credential,
|
|
1290
|
+
// and no amount of waiting or refreshing changes it. Cooldown cycling
|
|
1291
|
+
// (auth_invalidated + 5m backoff) kept a dead account in rotation where a
|
|
1292
|
+
// client's retry budget burned sibling accounts — the same failure the
|
|
1293
|
+
// buddy ban exists to prevent. Disable immediately. Must run before
|
|
1294
|
+
// `credential-rejected`, which would claim the bare 403 as a refreshable
|
|
1295
|
+
// auth rejection.
|
|
1296
|
+
name: "github-copilot-not-licensed",
|
|
1297
|
+
match: (s) =>
|
|
1298
|
+
s.origin === "upstream" &&
|
|
1299
|
+
s.providerId === "github" &&
|
|
1300
|
+
copilotNotLicensed(s.lower),
|
|
1301
|
+
decide: (s) =>
|
|
1302
|
+
s.result(
|
|
1303
|
+
"policy_blocked_banned",
|
|
1304
|
+
"disabled",
|
|
1305
|
+
0,
|
|
1306
|
+
null,
|
|
1307
|
+
s.reason("GitHub Copilot account not licensed"),
|
|
1308
|
+
// A license refusal is evidence about the account even at provider
|
|
1309
|
+
// scope, for the same reason a named revocation or a buddy ban is.
|
|
1310
|
+
true,
|
|
1311
|
+
),
|
|
1312
|
+
},
|
|
1340
1313
|
{
|
|
1341
1314
|
name: "credential-rejected",
|
|
1342
1315
|
match: (s) =>
|
|
@@ -1468,9 +1441,84 @@ const ACCOUNT_ERROR_RULES: readonly AccountErrorRule[] = [
|
|
|
1468
1441
|
);
|
|
1469
1442
|
},
|
|
1470
1443
|
},
|
|
1444
|
+
{
|
|
1445
|
+
// Trae answers `4013 "AI service is not available in the current region
|
|
1446
|
+
// now."` when the upstream does not serve the account's region. That is a
|
|
1447
|
+
// durable verdict on the account, not a transient transport fault: it
|
|
1448
|
+
// reproduces on every request until the region opens, so it must cool hard
|
|
1449
|
+
// for a day rather than be re-dialled every thirty seconds. Must run
|
|
1450
|
+
// before `transport-fault`, which would read the 502 as a short
|
|
1451
|
+
// `server_error`.
|
|
1452
|
+
name: "trae-region-unavailable",
|
|
1453
|
+
match: (s) =>
|
|
1454
|
+
(s.providerId === "trae" || s.providerId === "traecn") &&
|
|
1455
|
+
(s.providerCode === "4013" || s.lower.includes("not available in the current region")),
|
|
1456
|
+
decide: (s) => {
|
|
1457
|
+
const cooldownMs = TRAE_REGION_COOLDOWN_MS;
|
|
1458
|
+
return s.result(
|
|
1459
|
+
"quota_exhausted",
|
|
1460
|
+
"cooldown",
|
|
1461
|
+
cooldownMs,
|
|
1462
|
+
new Date(Date.now() + cooldownMs),
|
|
1463
|
+
s.reason("Trae service unavailable in the current region"),
|
|
1464
|
+
// Account-scoped provider evidence still has to reach the writer: a
|
|
1465
|
+
// stream frame carries no credential detail, so `canMutate` is false
|
|
1466
|
+
// and without this the account stays in rotation to reproduce the
|
|
1467
|
+
// refusal for the whole window the region is closed for.
|
|
1468
|
+
true,
|
|
1469
|
+
);
|
|
1470
|
+
},
|
|
1471
|
+
},
|
|
1472
|
+
{
|
|
1473
|
+
// Trae's free-tier quota (`4008` / "exceeded the quota") resets daily.
|
|
1474
|
+
// Treating it like the generic quota cooldown (1h account-wide fallback)
|
|
1475
|
+
// let the account re-enter rotation inside the window and reproduce the
|
|
1476
|
+
// refusal every few minutes — the "cooldown not holding" report. The
|
|
1477
|
+
// verdict is a full-day backoff on *any* model (the account's quota is
|
|
1478
|
+
// spent, so every model on it shares the wall). Scoped to the model so
|
|
1479
|
+
// the account is not disabled wholesale; the 1-day window means a model
|
|
1480
|
+
// stays parked for the day instead of flapping. Must run before
|
|
1481
|
+
// `quota-exhausted`, which would apply the generic shorter fallback.
|
|
1482
|
+
name: "trae-quota-exhausted",
|
|
1483
|
+
match: (s) =>
|
|
1484
|
+
(s.providerId === "trae" || s.providerId === "traecn") &&
|
|
1485
|
+
(s.providerCode === "4008" || s.lower.includes("have exceeded the quota")),
|
|
1486
|
+
decide: (s) => {
|
|
1487
|
+
const cooldownMs = s.statedCooldownMs ?? TRAE_QUOTA_COOLDOWN_MS;
|
|
1488
|
+
return s.result(
|
|
1489
|
+
"model_unreachable",
|
|
1490
|
+
"cooldown",
|
|
1491
|
+
cooldownMs,
|
|
1492
|
+
new Date(Date.now() + cooldownMs),
|
|
1493
|
+
s.reason("Trae quota exhausted for this model"),
|
|
1494
|
+
s.origin === "upstream" && s.modelId !== undefined,
|
|
1495
|
+
);
|
|
1496
|
+
},
|
|
1497
|
+
},
|
|
1498
|
+
{
|
|
1499
|
+
// Qoder's quota verdicts — `110` "Billing daily count exceeded" and the
|
|
1500
|
+
// upstream-499 exhausted-quota close — are per-model: one model's spend
|
|
1501
|
+
// cap does not drain another. Scoping them to the model keeps the account
|
|
1502
|
+
// serving its other models. Must run before `quota-exhausted`, which
|
|
1503
|
+
// parks the whole account.
|
|
1504
|
+
name: "qoder-model-quota",
|
|
1505
|
+
match: (s) =>
|
|
1506
|
+
(s.providerId === "qoder" || s.providerId === "qodercn") && s.quotaSignal,
|
|
1507
|
+
decide: (s) => {
|
|
1508
|
+
const cooldownMs = s.statedCooldownMs ?? QODER_QUOTA_COOLDOWN_MS;
|
|
1509
|
+
return s.result(
|
|
1510
|
+
"model_unreachable",
|
|
1511
|
+
"cooldown",
|
|
1512
|
+
cooldownMs,
|
|
1513
|
+
new Date(Date.now() + cooldownMs),
|
|
1514
|
+
s.reason("Qoder quota exhausted for this model"),
|
|
1515
|
+
s.origin === "upstream" && s.modelId !== undefined,
|
|
1516
|
+
);
|
|
1517
|
+
},
|
|
1518
|
+
},
|
|
1471
1519
|
{
|
|
1472
1520
|
name: "quota-exhausted",
|
|
1473
|
-
match: (s) => s.quotaSignal,
|
|
1521
|
+
match: (s) => s.origin === "upstream" && s.quotaSignal,
|
|
1474
1522
|
decide: (s) => {
|
|
1475
1523
|
// xAI Grok Build's free tier resets on a rolling window. Use a duration
|
|
1476
1524
|
// stated by the provider when present; otherwise park for the conservative
|
|
@@ -1478,11 +1526,21 @@ const ACCOUNT_ERROR_RULES: readonly AccountErrorRule[] = [
|
|
|
1478
1526
|
const grokFreeTier =
|
|
1479
1527
|
s.providerCode === "subscription:free-usage-exhausted" ||
|
|
1480
1528
|
s.providerCode.startsWith("subscription:") ||
|
|
1529
|
+
// A 402 spend/entitlement wall (`personal-team-blocked:spending-limit`,
|
|
1530
|
+
// "out of credits") is the same verdict: the account cannot serve until
|
|
1531
|
+
// the operator tops up or upgrades. The default 1h fallback re-dialled
|
|
1532
|
+
// it every hour inside a window that will not clear on its own.
|
|
1533
|
+
s.providerCode.includes("spending") ||
|
|
1534
|
+
s.providerCode.includes("credits") ||
|
|
1481
1535
|
s.lower.includes("free-usage") ||
|
|
1482
1536
|
s.lower.includes("free usage") ||
|
|
1483
1537
|
s.lower.includes("included free usage") ||
|
|
1484
1538
|
s.lower.includes("rolling 24-hour") ||
|
|
1485
|
-
s.lower.includes("rolling 24 hour")
|
|
1539
|
+
s.lower.includes("rolling 24 hour") ||
|
|
1540
|
+
s.lower.includes("spending limit") ||
|
|
1541
|
+
s.lower.includes("out of credits") ||
|
|
1542
|
+
s.lower.includes("run out of credits") ||
|
|
1543
|
+
s.lower.includes("need a grok subscription");
|
|
1486
1544
|
const buddyCreditsExhausted =
|
|
1487
1545
|
s.providerCode === "14018" || s.lower.includes("credits exhausted");
|
|
1488
1546
|
const cooldownMs = grokFreeTier
|
|
@@ -1514,6 +1572,7 @@ const ACCOUNT_ERROR_RULES: readonly AccountErrorRule[] = [
|
|
|
1514
1572
|
// moves to the next account and the flagged one returns almost at once.
|
|
1515
1573
|
name: "inception-per-minute-limit",
|
|
1516
1574
|
match: (s) =>
|
|
1575
|
+
s.origin === "upstream" &&
|
|
1517
1576
|
s.providerId === "inception" &&
|
|
1518
1577
|
(s.statusCode === 429 ||
|
|
1519
1578
|
s.providerCode === "rate_limit_reached" ||
|
|
@@ -1538,15 +1597,16 @@ const ACCOUNT_ERROR_RULES: readonly AccountErrorRule[] = [
|
|
|
1538
1597
|
{
|
|
1539
1598
|
name: "rate-limit",
|
|
1540
1599
|
match: (s) =>
|
|
1541
|
-
s.
|
|
1542
|
-
s.
|
|
1543
|
-
|
|
1544
|
-
|
|
1545
|
-
|
|
1546
|
-
|
|
1547
|
-
|
|
1548
|
-
|
|
1549
|
-
|
|
1600
|
+
s.origin === "upstream" &&
|
|
1601
|
+
(s.statusCode === 429 ||
|
|
1602
|
+
s.providerCode === "rate_limit_exceeded" ||
|
|
1603
|
+
s.lower.includes("rate_limit") ||
|
|
1604
|
+
s.lower.includes("rate limit") ||
|
|
1605
|
+
s.lower.includes("too many requests") ||
|
|
1606
|
+
s.lower.includes("requests per minute") ||
|
|
1607
|
+
s.lower.includes("tokens per minute") ||
|
|
1608
|
+
s.lower.includes("tpm limit") ||
|
|
1609
|
+
s.lower.includes("rpm limit")),
|
|
1550
1610
|
decide: (s) => {
|
|
1551
1611
|
const cooldownMs = s.statedCooldownMs ?? DEFAULT_RATE_LIMIT_COOLDOWN_MS();
|
|
1552
1612
|
// Same per-account reasoning as quota above: the failing account (or
|
|
@@ -1565,13 +1625,14 @@ const ACCOUNT_ERROR_RULES: readonly AccountErrorRule[] = [
|
|
|
1565
1625
|
{
|
|
1566
1626
|
name: "model-capacity",
|
|
1567
1627
|
match: (s) =>
|
|
1568
|
-
s.
|
|
1569
|
-
s.statusCode ===
|
|
1570
|
-
|
|
1571
|
-
|
|
1572
|
-
|
|
1573
|
-
|
|
1574
|
-
|
|
1628
|
+
s.origin === "upstream" &&
|
|
1629
|
+
(s.statusCode === 503 ||
|
|
1630
|
+
s.statusCode === 529 ||
|
|
1631
|
+
s.providerCode === "model_capacity" ||
|
|
1632
|
+
s.queuedUpstream ||
|
|
1633
|
+
s.lower.includes("model overloaded") ||
|
|
1634
|
+
s.lower.includes("capacity exceeded") ||
|
|
1635
|
+
s.lower.includes("temporarily unavailable")),
|
|
1575
1636
|
decide: (s) => {
|
|
1576
1637
|
const cooldownMs = s.statedCooldownMs ?? MODEL_CAPACITY_COOLDOWN_MS();
|
|
1577
1638
|
const modelScopedMutation = s.origin === "upstream" && s.modelId !== undefined;
|
|
@@ -1631,20 +1692,24 @@ const ACCOUNT_ERROR_RULES: readonly AccountErrorRule[] = [
|
|
|
1631
1692
|
// verdict, not a transport fault. It must run before `transport-fault`,
|
|
1632
1693
|
// which otherwise reads the status as a 5xx-class outage and cools the
|
|
1633
1694
|
// account for the shorter transient window — or leaves it unmutated.
|
|
1695
|
+
//
|
|
1696
|
+
// The verdict is per-model, like Qoder's other quota signs: one model's
|
|
1697
|
+
// spend cap does not drain another, so it cools the pair, never the whole
|
|
1698
|
+
// account.
|
|
1634
1699
|
name: "qoder-499-quota",
|
|
1635
1700
|
match: (s) =>
|
|
1636
1701
|
(s.providerId === "qoder" || s.providerId === "qodercn") &&
|
|
1637
1702
|
s.statusCode === 499 &&
|
|
1638
1703
|
s.origin === "upstream",
|
|
1639
1704
|
decide: (s) => {
|
|
1640
|
-
const cooldownMs = s.statedCooldownMs ??
|
|
1705
|
+
const cooldownMs = s.statedCooldownMs ?? QODER_QUOTA_COOLDOWN_MS;
|
|
1641
1706
|
return s.result(
|
|
1642
|
-
"
|
|
1707
|
+
"model_unreachable",
|
|
1643
1708
|
"cooldown",
|
|
1644
1709
|
cooldownMs,
|
|
1645
1710
|
new Date(Date.now() + cooldownMs),
|
|
1646
|
-
s.reason("Qoder quota exhausted (upstream 499)"),
|
|
1647
|
-
s.origin === "upstream",
|
|
1711
|
+
s.reason("Qoder quota exhausted for this model (upstream 499)"),
|
|
1712
|
+
s.origin === "upstream" && s.modelId !== undefined,
|
|
1648
1713
|
);
|
|
1649
1714
|
},
|
|
1650
1715
|
},
|