cartethyia 2.7.8 → 2.7.9
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 +0 -1
- package/README.md +29 -59
- package/dist/dashboard/assets/BannedPage-BxoG1MrL.js +1 -0
- package/dist/dashboard/assets/BannedPage-BxoG1MrL.js.gz +0 -0
- package/dist/dashboard/assets/{CliToolDetailPage-BRWKPQPf.js → CliToolDetailPage-ixwgKk53.js} +1 -1
- package/dist/dashboard/assets/CliToolDetailPage-ixwgKk53.js.gz +0 -0
- package/dist/dashboard/assets/{CliToolsPage-BP-Y5iHN.js → CliToolsPage-BmttNV3U.js} +1 -1
- package/dist/dashboard/assets/CliToolsPage-BmttNV3U.js.gz +0 -0
- package/dist/dashboard/assets/CombosPage-BE3qwwfC.js +1 -0
- package/dist/dashboard/assets/CombosPage-BE3qwwfC.js.gz +0 -0
- package/dist/dashboard/assets/ConsoleLogPage-CRZdmMIX.js +1 -0
- package/dist/dashboard/assets/ConsoleLogPage-CRZdmMIX.js.gz +0 -0
- package/dist/dashboard/assets/CustomizationPage-Dv_FJ6Er.js +1 -0
- package/dist/dashboard/assets/CustomizationPage-Dv_FJ6Er.js.gz +0 -0
- package/dist/dashboard/assets/HealthEventsModal-CoVrw2sM.js +1 -0
- package/dist/dashboard/assets/HealthEventsModal-CoVrw2sM.js.gz +0 -0
- package/dist/dashboard/assets/{InjectSystemPromptPanel-Cv-2Ol_K.js → InjectSystemPromptPanel-BOoO8rpz.js} +2 -2
- package/dist/dashboard/assets/InjectSystemPromptPanel-BOoO8rpz.js.gz +0 -0
- package/dist/dashboard/assets/{LoginPage-bKfz_b1K.js → LoginPage-ChJuNNVN.js} +1 -1
- package/dist/dashboard/assets/LoginPage-ChJuNNVN.js.gz +0 -0
- package/dist/dashboard/assets/{ModelPicker-B-WQxx_H.js → ModelPicker-BZAJtPg1.js} +1 -1
- package/dist/dashboard/assets/ModelPicker-BZAJtPg1.js.gz +0 -0
- package/dist/dashboard/assets/OverviewPage-BE40s3u5.js +1 -0
- package/dist/dashboard/assets/OverviewPage-BE40s3u5.js.gz +0 -0
- package/dist/dashboard/assets/ProviderDetailPage-sfLoQtPV.js +8 -0
- package/dist/dashboard/assets/ProviderDetailPage-sfLoQtPV.js.gz +0 -0
- package/dist/dashboard/assets/ProviderIcon-CQ6bPUf_.js +1 -0
- package/dist/dashboard/assets/ProviderIcon-CQ6bPUf_.js.gz +0 -0
- package/dist/dashboard/assets/ProvidersPage-DcepmPWo.js +1 -0
- package/dist/dashboard/assets/ProvidersPage-DcepmPWo.js.gz +0 -0
- package/dist/dashboard/assets/{ProxyPage-emlTuxz6.js → ProxyPage-BJ87Pp0U.js} +1 -1
- package/dist/dashboard/assets/ProxyPage-BJ87Pp0U.js.gz +0 -0
- package/dist/dashboard/assets/{QuotaPage-CMJKNYWb.js → QuotaPage-gkSyRAKa.js} +1 -1
- package/dist/dashboard/assets/QuotaPage-gkSyRAKa.js.gz +0 -0
- package/dist/dashboard/assets/SettingsPage-C5HPWqEv.js +1 -0
- package/dist/dashboard/assets/SettingsPage-C5HPWqEv.js.gz +0 -0
- package/dist/dashboard/assets/{SetupPage-CUZrKs9r.js → SetupPage-CFNcATJJ.js} +1 -1
- package/dist/dashboard/assets/SetupPage-CFNcATJJ.js.gz +0 -0
- package/dist/dashboard/assets/{StudioPage-jWmUdDpy.js → StudioPage-YoD4tY5l.js} +1 -1
- package/dist/dashboard/assets/StudioPage-YoD4tY5l.js.gz +0 -0
- package/dist/dashboard/assets/UsagePage-DxjaAhb_.js +56 -0
- package/dist/dashboard/assets/UsagePage-DxjaAhb_.js.gz +0 -0
- package/dist/dashboard/assets/api-keys-BTlkq_Uk.js +1 -0
- package/dist/dashboard/assets/api-keys-BTlkq_Uk.js.gz +0 -0
- package/dist/dashboard/assets/app-BX2nnKqs.css +2 -0
- package/dist/dashboard/assets/app-BX2nnKqs.css.gz +0 -0
- package/dist/dashboard/assets/assert-CndthXFQ.js +1 -0
- package/dist/dashboard/assets/assert-CndthXFQ.js.gz +0 -0
- package/dist/dashboard/assets/{badge-DyI_mJfi.js → badge-DdbT_7Am.js} +1 -1
- package/dist/dashboard/assets/badge-DdbT_7Am.js.gz +0 -0
- package/dist/dashboard/assets/ban-durations-B58FyRxC.js +1 -0
- package/dist/dashboard/assets/ban-durations-B58FyRxC.js.gz +0 -0
- package/dist/dashboard/assets/{banner-B-yXtCqb.js → banner-CsGN-nbm.js} +1 -1
- package/dist/dashboard/assets/banner-CsGN-nbm.js.gz +0 -0
- package/dist/dashboard/assets/brand/bansos_page.webp +0 -0
- package/dist/dashboard/assets/brand/denia_bansos.webp +0 -0
- package/dist/dashboard/assets/brand/favicon.webp +0 -0
- package/dist/dashboard/assets/brand/login_register.webp +0 -0
- package/dist/dashboard/assets/brand/login_register_initial.webp +0 -0
- package/dist/dashboard/assets/brand/og_bansos.webp +0 -0
- package/dist/dashboard/assets/brand/og_image.webp +0 -0
- package/dist/dashboard/assets/brand/sidebar_ico.webp +0 -0
- package/dist/dashboard/assets/{card-_HwAEqFF.js → card-mgZ_TLLZ.js} +1 -1
- package/dist/dashboard/assets/card-mgZ_TLLZ.js.gz +0 -0
- package/dist/dashboard/assets/cli-tools-A1-v8-03.js +1 -0
- package/dist/dashboard/assets/cli-tools-A1-v8-03.js.gz +0 -0
- package/dist/dashboard/assets/{clipboard-button-ByjCk0o9.js → clipboard-button-CJ4Zty89.js} +1 -1
- package/dist/dashboard/assets/clipboard-button-CJ4Zty89.js.gz +0 -0
- package/dist/dashboard/assets/{dialog-BZhOlfz-.js → dialog-B5L2jPQ_.js} +1 -1
- package/dist/dashboard/assets/dialog-B5L2jPQ_.js.gz +0 -0
- package/dist/dashboard/assets/{drawer-BADqIRYP.js → drawer-DkjUouAj.js} +1 -1
- package/dist/dashboard/assets/drawer-DkjUouAj.js.gz +0 -0
- package/dist/dashboard/assets/{entry-COaC-irN.js → entry-B-LVLV6o.js} +1 -1
- package/dist/dashboard/assets/entry-B-LVLV6o.js.gz +0 -0
- package/dist/dashboard/assets/entry-CAhdYl3B.js +1 -0
- package/dist/dashboard/assets/entry-CAhdYl3B.js.gz +0 -0
- package/dist/dashboard/assets/entry-D2xD0Tmd.js +4 -0
- package/dist/dashboard/assets/entry-D2xD0Tmd.js.gz +0 -0
- package/dist/dashboard/assets/{formatters-DcHJyRiu.js → formatters-CrsdLVsn.js} +1 -1
- package/dist/dashboard/assets/formatters-CrsdLVsn.js.gz +0 -0
- package/dist/dashboard/assets/{index-CgKmFngv.js → index-BU64Lqvp.js} +2 -2
- package/dist/dashboard/assets/index-BU64Lqvp.js.gz +0 -0
- package/dist/dashboard/assets/{inline-B2BirKry.js → inline-B2aDLyyg.js} +1 -1
- package/dist/dashboard/assets/inline-B2aDLyyg.js.gz +0 -0
- package/dist/dashboard/assets/{input-D-qV9dKY.js → input-BCVkdR9d.js} +1 -1
- package/dist/dashboard/assets/input-BCVkdR9d.js.gz +0 -0
- package/dist/dashboard/assets/{layout-B7tVWhtV.js → layout-DNcAdMK-.js} +1 -1
- package/dist/dashboard/assets/layout-DNcAdMK-.js.gz +0 -0
- package/dist/dashboard/assets/{list-row-CtkGE3bF.js → list-row-DgrIH0hw.js} +1 -1
- package/dist/dashboard/assets/list-row-DgrIH0hw.js.gz +0 -0
- package/dist/dashboard/assets/{live-DGizF06-.js → live-Cae01iu8.js} +1 -1
- package/dist/dashboard/assets/live-Cae01iu8.js.gz +0 -0
- package/dist/dashboard/assets/{mutation-GU7XdEjz.js → mutation-BQ0ccH_A.js} +1 -1
- package/dist/dashboard/assets/mutation-BQ0ccH_A.js.gz +0 -0
- package/dist/dashboard/assets/{network-C9UE-bOr.js → network-CRib7H_2.js} +1 -1
- package/dist/dashboard/assets/network-CRib7H_2.js.gz +0 -0
- package/dist/dashboard/assets/{numbers-BnAd22a_.js → numbers-BKQE8Xpz.js} +1 -1
- package/dist/dashboard/assets/numbers-BKQE8Xpz.js.gz +0 -0
- package/dist/dashboard/assets/{pagination-BAywyMzS.js → pagination-ecPvG_8g.js} +1 -1
- package/dist/dashboard/assets/pagination-ecPvG_8g.js.gz +0 -0
- package/dist/dashboard/assets/providers/devin.svg +9 -0
- package/dist/dashboard/assets/providers/devin.svg.gz +0 -0
- package/dist/dashboard/assets/providers/windsurf.svg +10 -0
- package/dist/dashboard/assets/providers/windsurf.svg.gz +0 -0
- package/dist/dashboard/assets/{query-keys-YSoQOUh6.js → query-keys-IKLh0YFd.js} +1 -1
- package/dist/dashboard/assets/query-keys-IKLh0YFd.js.gz +0 -0
- package/dist/dashboard/assets/routing-Ckm1UXuC.js +1 -0
- package/dist/dashboard/assets/routing-Ckm1UXuC.js.gz +0 -0
- package/dist/dashboard/assets/{select-BCOcv8WK.js → select-ChoFWyKz.js} +1 -1
- package/dist/dashboard/assets/select-ChoFWyKz.js.gz +0 -0
- package/dist/dashboard/assets/settings-CKjFPlKW.js +1 -0
- package/dist/dashboard/assets/settings-CKjFPlKW.js.gz +0 -0
- package/dist/dashboard/assets/{stack-ByKt3Q1g.js → stack-DWCwU3fh.js} +1 -1
- package/dist/dashboard/assets/stack-DWCwU3fh.js.gz +0 -0
- package/dist/dashboard/assets/{state-DXbGTx7N.js → state-Cg3VL5J_.js} +1 -1
- package/dist/dashboard/assets/state-Cg3VL5J_.js.gz +0 -0
- package/dist/dashboard/assets/story/25817331.webp +0 -0
- package/dist/dashboard/assets/story/Shorekeeper.webp +0 -0
- package/dist/dashboard/assets/story/cartethyia-god.webp +0 -0
- package/dist/dashboard/assets/story/fleurdelys_plus.webp +0 -0
- package/dist/dashboard/assets/story/jinhsi-blossom.webp +0 -0
- package/dist/dashboard/assets/story/phrolova-a.webp +0 -0
- package/dist/dashboard/assets/story/requestdeniawokkjpg.webp +0 -0
- package/dist/dashboard/assets/story/wuthering-waves-hiyuki-aemeath-hiyuki-rover.webp +0 -0
- package/dist/dashboard/assets/{switch-ZeTsW623.js → switch-Db70BMix.js} +1 -1
- package/dist/dashboard/assets/switch-Db70BMix.js.gz +0 -0
- package/dist/dashboard/assets/{useMutation-CbCP4w1o.js → useMutation-BqdE0LuM.js} +1 -1
- package/dist/dashboard/assets/useMutation-BqdE0LuM.js.gz +0 -0
- package/dist/dashboard/console-backgrounds.webp +0 -0
- package/dist/dashboard/console-backgrounds_initial.webp +0 -0
- package/dist/dashboard/donation/qris-risun-marke.webp +0 -0
- package/dist/dashboard/index.html +3 -3
- package/dist/dashboard/index.html.gz +0 -0
- package/dist/dashboard/precompressed-assets.json +57 -55
- package/migrations/full-postgres/0044_add_models_warning_metadata.sql +10 -0
- package/migrations/full-postgres/0045_migrate_workbuddy_to_codebuddy.sql +156 -0
- package/migrations/lite-sqlite3/0044_add_models_warning_metadata.sql +11 -0
- package/migrations/lite-sqlite3/0045_migrate_workbuddy_to_codebuddy.sql +156 -0
- package/package.json +1 -1
- package/src/boot/dependencies.ts +11 -3
- package/src/config/cooldowns.ts +1 -1
- package/src/config/spec.ts +0 -6
- package/src/console/api-keys/routes.ts +11 -4
- package/src/console/console-router.ts +7 -0
- package/src/console/dashboard-assets.ts +5 -5
- package/src/console/domain-registration.ts +27 -0
- package/src/console/ip-bans/routes.ts +99 -0
- package/src/console/providers/catalog/catalog-projections.ts +5 -2
- package/src/console/providers/catalog/contracts.ts +123 -0
- package/src/console/providers/catalog/model-operations.ts +122 -10
- package/src/console/providers/catalog/provider-operations.ts +116 -8
- package/src/console/providers/catalog/public-model-store.ts +0 -0
- package/src/console/providers/catalog/routes.ts +64 -4
- package/src/console/providers/catalog/store-helpers.ts +30 -1
- package/src/console/providers/catalog/store.ts +243 -3
- package/src/console/quota/account-quota-global.ts +89 -1
- package/src/console/quota/native-identity.ts +2 -0
- package/src/console/settings/contracts.ts +18 -0
- package/src/console/settings/store.ts +32 -0
- package/src/console/system-prompt/contracts.ts +0 -1
- package/src/main.ts +1 -0
- package/src/observability/event-query.ts +18 -4
- package/src/persistence/dialect.ts +12 -0
- package/src/persistence/schema.ts +20 -2
- package/src/protocol/dsml.ts +1 -1
- package/src/protocol/gateway-error.ts +1 -0
- package/src/protocol/reasoning.ts +1 -1
- package/src/protocol/request/chat.ts +4 -4
- package/src/protocol/request/messages.ts +1 -1
- package/src/protocol/response/gemini.ts +6 -1
- package/src/protocol/sse-decoder.ts +25 -8
- package/src/protocol/stream-error-frames.ts +13 -3
- package/src/protocol/translation/quirks.ts +1 -1
- package/src/protocol/translation/tool-repair.ts +2 -2
- package/src/protocol/upstream/send-claude-messages.ts +15 -4
- package/src/protocol/upstream-parsing.ts +1 -1
- package/src/providers/adapters/compatible-adapter.ts +7 -5
- package/src/providers/authentication/oauth-refresh-service.ts +149 -36
- package/src/providers/default-registry.ts +68 -3
- package/src/providers/discovery/discovery-types.ts +12 -0
- package/src/providers/discovery/probe-phases.ts +61 -30
- package/src/providers/discovery/probing-service.ts +279 -164
- package/src/providers/integrations/antigravity/antigravity-protocol.ts +117 -2
- package/src/providers/integrations/antigravity/antigravity.ts +13 -2
- package/src/providers/integrations/buddy/buddy-catalog-shared.ts +72 -34
- package/src/providers/integrations/buddy/buddy-chat-shared.ts +18 -18
- package/src/providers/integrations/buddy/buddy-checkin.ts +17 -39
- package/src/providers/integrations/buddy/buddy-conversation-headers.ts +2 -2
- package/src/providers/integrations/buddy/buddy-discovery-shared.ts +5 -5
- package/src/providers/integrations/buddy/buddy-identity.ts +70 -0
- package/src/providers/integrations/buddy/buddy-media.ts +4 -5
- package/src/providers/integrations/buddy/buddy-oauth-shared.ts +2 -2
- package/src/providers/integrations/buddy/buddy-quota-shared.ts +1 -1
- package/src/providers/integrations/buddy/buddy-usage-shared.ts +1 -3
- package/src/providers/integrations/buddy/capabilities.ts +4 -41
- package/src/providers/integrations/buddy/codebuddy/cn-catalog.ts +2 -1
- package/src/providers/integrations/buddy/codebuddy/cn-provider.ts +20 -1
- package/src/providers/integrations/buddy/codebuddy/provider.ts +2 -2
- package/src/providers/integrations/buddy/codebuddy/shared.ts +6 -10
- package/src/providers/integrations/cursor/cursor-catalog.ts +2 -0
- package/src/providers/integrations/cursor/cursor-exec.ts +738 -0
- package/src/providers/integrations/cursor/cursor-http2.ts +2 -0
- package/src/providers/integrations/cursor/cursor-request.ts +9 -8
- package/src/providers/integrations/cursor/cursor-shared.ts +19 -1
- package/src/providers/integrations/cursor/cursor.ts +50 -30
- package/src/providers/integrations/cursor/protocol/tool-canonical.ts +26 -100
- package/src/providers/integrations/devin/devin-auth.ts +353 -0
- package/src/providers/integrations/devin/devin-catalog.ts +207 -0
- package/src/providers/integrations/devin/devin-http.ts +91 -0
- package/src/providers/integrations/devin/devin-quota.ts +214 -0
- package/src/providers/integrations/devin/devin-shared.ts +111 -0
- package/src/providers/integrations/devin/devin.ts +539 -0
- package/src/providers/integrations/devin/protocol/devin-proto.ts +584 -0
- package/src/providers/integrations/devin/protocol/framing.ts +124 -0
- package/src/providers/integrations/factory/factory.ts +2 -2
- package/src/providers/integrations/freepi/freepi-catalog.ts +60 -0
- package/src/providers/integrations/freepi/freepi-discovery.ts +82 -0
- package/src/providers/integrations/freepi/freepi-headers.ts +21 -0
- package/src/providers/integrations/freepi/freepi-oauth.ts +142 -0
- package/src/providers/integrations/freepi/freepi-protocol.ts +242 -0
- package/src/providers/integrations/freepi/freepi-quota.ts +126 -0
- package/src/providers/integrations/freepi/freepi-realm.ts +35 -0
- package/src/providers/integrations/freepi/freepi.ts +292 -0
- package/src/providers/integrations/gemini.ts +2 -2
- package/src/providers/integrations/hermes/hermes-oauth.ts +94 -0
- package/src/providers/integrations/hermes.ts +4 -12
- package/src/providers/integrations/opencode/fingerprint.ts +1 -1
- package/src/providers/integrations/perch/perch-catalog.ts +105 -0
- package/src/providers/integrations/perch/perch-oauth.ts +170 -0
- package/src/providers/integrations/perch/perch-protocol.ts +211 -0
- package/src/providers/integrations/perch/perch-quota.ts +137 -0
- package/src/providers/integrations/perch/perch-realm.ts +82 -0
- package/src/providers/integrations/perch/perch-system-prompt.ts +13 -0
- package/src/providers/integrations/perch/perch.ts +315 -0
- package/src/providers/integrations/perch/saffron-system-prompt.txt +8 -0
- package/src/providers/integrations/qoder/chat-proto.ts +328 -328
- package/src/providers/integrations/qoder/claim-qoder-credits.ts +1 -1
- package/src/providers/integrations/qoder/qoder-adapter.ts +89 -28
- package/src/providers/integrations/qoder/qoder-cache.ts +32 -0
- package/src/providers/integrations/qoder/qoder-catalog.ts +6 -1
- package/src/providers/integrations/qoder/qoder-checkin.ts +2 -2
- package/src/providers/integrations/qoder/qoder-grpc.ts +210 -6
- package/src/providers/integrations/qoder/qoder-ide.ts +5 -1
- package/src/providers/integrations/qoder/qoder-identity-cache.ts +184 -0
- package/src/providers/integrations/qoder/qoder-native-identity-store.ts +83 -18
- package/src/providers/integrations/qoder/qoder-realm.ts +9 -6
- package/src/providers/integrations/qoder/qoder-umid.ts +109 -342
- package/src/providers/integrations/qoder/qoder-virtual.ts +33 -1
- package/src/providers/integrations/qoder/qoder.ts +3 -6
- package/src/providers/integrations/trae/trae-catalog.ts +9 -14
- package/src/providers/integrations/trae/trae-headers.ts +36 -11
- package/src/providers/integrations/trae/trae-oauth.ts +14 -17
- package/src/providers/integrations/trae/trae-protocol.ts +3 -6
- package/src/providers/integrations/trae/trae-quota.ts +103 -21
- package/src/providers/integrations/trae/trae-realm.ts +36 -15
- package/src/providers/integrations/trae/trae.ts +97 -7
- package/src/providers/operations/account-error-classification.ts +66 -1
- package/src/providers/operations/account-health-service.ts +192 -26
- package/src/providers/operations/account-refresh-status.ts +284 -0
- package/src/providers/operations/account-tier.ts +67 -0
- package/src/providers/operations/client-versions.ts +37 -99
- package/src/providers/operations/cooldown-rules.ts +61 -0
- package/src/providers/operations/provider-catalog-seeder.ts +4 -0
- package/src/providers/provider-contracts.ts +29 -0
- package/src/providers/provider-metadata.ts +59 -4
- package/src/providers/provider-model-definition.ts +36 -0
- package/src/providers/quota/refresh.ts +21 -0
- package/src/security/abuse.ts +71 -0
- package/src/transport/dispatch/proxy-request.ts +1 -0
- package/src/transport/dispatch/streaming/stream.ts +1 -0
- package/src/transport/dispatch/upstream.ts +4 -1
- package/src/transport/failure-policy.ts +113 -7
- package/src/transport/routing/router.ts +25 -1
- package/src/transport/surface/messages/adapter.ts +2 -1
- package/src/transport/surface/responses/encode.ts +12 -1
- package/src/workers/daily-checkin.ts +1 -1
- package/src/workers/quota-refresh-sweep.ts +1 -1
- package/src/workers/scheduler.ts +22 -4
- package/dist/dashboard/assets/BannedPage-DeIbIiBU.js +0 -1
- package/dist/dashboard/assets/BannedPage-DeIbIiBU.js.gz +0 -0
- package/dist/dashboard/assets/CliToolDetailPage-BRWKPQPf.js.gz +0 -0
- package/dist/dashboard/assets/CliToolsPage-BP-Y5iHN.js.gz +0 -0
- package/dist/dashboard/assets/CombosPage-B7JHozVa.js +0 -1
- package/dist/dashboard/assets/CombosPage-B7JHozVa.js.gz +0 -0
- package/dist/dashboard/assets/ConsoleLogPage-GX7iGGcu.js +0 -1
- package/dist/dashboard/assets/ConsoleLogPage-GX7iGGcu.js.gz +0 -0
- package/dist/dashboard/assets/CustomizationPage-HVonbGEa.js +0 -1
- package/dist/dashboard/assets/CustomizationPage-HVonbGEa.js.gz +0 -0
- package/dist/dashboard/assets/HealthEventsModal-xaut4OJ9.js +0 -1
- package/dist/dashboard/assets/HealthEventsModal-xaut4OJ9.js.gz +0 -0
- package/dist/dashboard/assets/InjectSystemPromptPanel-Cv-2Ol_K.js.gz +0 -0
- package/dist/dashboard/assets/LoginPage-bKfz_b1K.js.gz +0 -0
- package/dist/dashboard/assets/ModelPicker-B-WQxx_H.js.gz +0 -0
- package/dist/dashboard/assets/OverviewPage-Z9pJZFo8.js +0 -1
- package/dist/dashboard/assets/OverviewPage-Z9pJZFo8.js.gz +0 -0
- package/dist/dashboard/assets/ProviderDetailPage-CMeDBxR1.js +0 -7
- package/dist/dashboard/assets/ProviderDetailPage-CMeDBxR1.js.gz +0 -0
- package/dist/dashboard/assets/ProviderIcon-jjqXJDA3.js +0 -1
- package/dist/dashboard/assets/ProviderIcon-jjqXJDA3.js.gz +0 -0
- package/dist/dashboard/assets/ProvidersPage-BXPdOpG4.js +0 -1
- package/dist/dashboard/assets/ProvidersPage-BXPdOpG4.js.gz +0 -0
- package/dist/dashboard/assets/ProxyPage-emlTuxz6.js.gz +0 -0
- package/dist/dashboard/assets/QuotaPage-CMJKNYWb.js.gz +0 -0
- package/dist/dashboard/assets/SettingsPage-BSy7EwGo.js +0 -1
- package/dist/dashboard/assets/SettingsPage-BSy7EwGo.js.gz +0 -0
- package/dist/dashboard/assets/SetupPage-CUZrKs9r.js.gz +0 -0
- package/dist/dashboard/assets/StudioPage-jWmUdDpy.js.gz +0 -0
- package/dist/dashboard/assets/UsagePage-5F9tGVGG.js +0 -56
- package/dist/dashboard/assets/UsagePage-5F9tGVGG.js.gz +0 -0
- package/dist/dashboard/assets/api-keys-KvX83mRe.js +0 -1
- package/dist/dashboard/assets/api-keys-KvX83mRe.js.gz +0 -0
- package/dist/dashboard/assets/app-BEsU8hKs.css +0 -2
- package/dist/dashboard/assets/app-BEsU8hKs.css.gz +0 -0
- package/dist/dashboard/assets/assert-CidQVoNo.js +0 -1
- package/dist/dashboard/assets/assert-CidQVoNo.js.gz +0 -0
- package/dist/dashboard/assets/badge-DyI_mJfi.js.gz +0 -0
- package/dist/dashboard/assets/banner-B-yXtCqb.js.gz +0 -0
- package/dist/dashboard/assets/brand/bansos_page.png +0 -0
- package/dist/dashboard/assets/brand/denia_bansos.jpg +0 -0
- package/dist/dashboard/assets/brand/favicon.jpg +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/brand/sidebar_ico.jpg +0 -0
- package/dist/dashboard/assets/card-_HwAEqFF.js.gz +0 -0
- package/dist/dashboard/assets/cli-tools-Bwv5-zGZ.js +0 -1
- package/dist/dashboard/assets/cli-tools-Bwv5-zGZ.js.gz +0 -0
- package/dist/dashboard/assets/clipboard-button-ByjCk0o9.js.gz +0 -0
- package/dist/dashboard/assets/dialog-BZhOlfz-.js.gz +0 -0
- package/dist/dashboard/assets/drawer-BADqIRYP.js.gz +0 -0
- package/dist/dashboard/assets/entry-COaC-irN.js.gz +0 -0
- package/dist/dashboard/assets/entry-Ca7LSCet.js +0 -4
- package/dist/dashboard/assets/entry-Ca7LSCet.js.gz +0 -0
- package/dist/dashboard/assets/entry-PDd27uCd.js +0 -1
- package/dist/dashboard/assets/entry-PDd27uCd.js.gz +0 -0
- package/dist/dashboard/assets/formatters-DcHJyRiu.js.gz +0 -0
- package/dist/dashboard/assets/index-CgKmFngv.js.gz +0 -0
- package/dist/dashboard/assets/inline-B2BirKry.js.gz +0 -0
- package/dist/dashboard/assets/input-D-qV9dKY.js.gz +0 -0
- package/dist/dashboard/assets/layout-B7tVWhtV.js.gz +0 -0
- package/dist/dashboard/assets/list-row-CtkGE3bF.js.gz +0 -0
- package/dist/dashboard/assets/live-DGizF06-.js.gz +0 -0
- package/dist/dashboard/assets/minimize-2-BTmMTK4o.js +0 -1
- package/dist/dashboard/assets/minimize-2-BTmMTK4o.js.gz +0 -0
- package/dist/dashboard/assets/mutation-GU7XdEjz.js.gz +0 -0
- package/dist/dashboard/assets/network-C9UE-bOr.js.gz +0 -0
- package/dist/dashboard/assets/numbers-BnAd22a_.js.gz +0 -0
- package/dist/dashboard/assets/pagination-BAywyMzS.js.gz +0 -0
- package/dist/dashboard/assets/query-keys-YSoQOUh6.js.gz +0 -0
- package/dist/dashboard/assets/routing-fnCsxgNO.js +0 -1
- package/dist/dashboard/assets/routing-fnCsxgNO.js.gz +0 -0
- package/dist/dashboard/assets/select-BCOcv8WK.js.gz +0 -0
- package/dist/dashboard/assets/settings-BxslsErn.js +0 -1
- package/dist/dashboard/assets/settings-BxslsErn.js.gz +0 -0
- package/dist/dashboard/assets/stack-ByKt3Q1g.js.gz +0 -0
- package/dist/dashboard/assets/state-DXbGTx7N.js.gz +0 -0
- package/dist/dashboard/assets/switch-ZeTsW623.js.gz +0 -0
- 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/donation/qris-risun-marke.png +0 -0
- package/src/providers/integrations/buddy/turing-device-token.ts +0 -262
- package/src/providers/integrations/buddy/workbuddy/cn-oauth.ts +0 -30
- package/src/providers/integrations/buddy/workbuddy/cn-provider.ts +0 -58
- package/src/providers/integrations/buddy/workbuddy/oauth.ts +0 -31
- package/src/providers/integrations/buddy/workbuddy/provider.ts +0 -209
- package/src/providers/integrations/buddy/workbuddy/quota.ts +0 -161
- package/src/providers/integrations/buddy/workbuddy/shared.ts +0 -285
- /package/dist/dashboard/assets/{app-CTxoqyYB.js → app-B7kIWFm5.js} +0 -0
- /package/dist/dashboard/assets/{app-CTxoqyYB.js.gz → app-B7kIWFm5.js.gz} +0 -0
|
@@ -0,0 +1,539 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Devin (Codeium Cascade) chat adapter.
|
|
3
|
+
*
|
|
4
|
+
* Speaks Connect-RPC over protobuf: unary `GetUserJwt` (auth), unary
|
|
5
|
+
* `GetCliModelConfigs` (discovery, in `devin-catalog.ts`), and server-
|
|
6
|
+
* streaming `GetChatMessage` (chat). The chat path frames the request as a
|
|
7
|
+
* Connect frame and reads a stream of frames with gzip + trailer handling.
|
|
8
|
+
*
|
|
9
|
+
* Ported from oh-my-pi (`providers/devin.ts`, MIT) with Cartethyia's
|
|
10
|
+
* `ProviderAdapter` contract.
|
|
11
|
+
*/
|
|
12
|
+
|
|
13
|
+
import { randomUUID } from "node:crypto";
|
|
14
|
+
import { gunzipSync } from "node:zlib";
|
|
15
|
+
import type {
|
|
16
|
+
CanonicalEvent,
|
|
17
|
+
CanonicalRequest,
|
|
18
|
+
CanonicalStopReason,
|
|
19
|
+
UsageRecord,
|
|
20
|
+
} from "../../../protocol/canonical-model";
|
|
21
|
+
import { joinTextParts, toolCallParts, toolResultParts } from "../../../protocol/canonical-model";
|
|
22
|
+
import type {
|
|
23
|
+
ProviderAdapter,
|
|
24
|
+
ProviderDispatchContext,
|
|
25
|
+
ProviderDispatchTarget,
|
|
26
|
+
} from "../../provider-contracts";
|
|
27
|
+
import { readCredentialSecret } from "../../provider-contracts";
|
|
28
|
+
import {
|
|
29
|
+
CONNECT_END_STREAM_FLAG,
|
|
30
|
+
ConnectFrameDecoder,
|
|
31
|
+
encodeFrame,
|
|
32
|
+
newExecutionId,
|
|
33
|
+
parseTrailer,
|
|
34
|
+
} from "./protocol/framing";
|
|
35
|
+
import { DevinEnums, DevinMessageTypes, fromEnum } from "./protocol/devin-proto";
|
|
36
|
+
import { callDevinUnary } from "./devin-http";
|
|
37
|
+
import {
|
|
38
|
+
DEVIN_ASSIGN_MODEL_PATH,
|
|
39
|
+
DEVIN_CHAT_MESSAGE_PATH,
|
|
40
|
+
DEVIN_DEFAULT_BASE_URL,
|
|
41
|
+
DEVIN_DEFAULT_STOP_PATTERNS,
|
|
42
|
+
DEVIN_GET_USER_JWT_PATH,
|
|
43
|
+
devinCliMetadata,
|
|
44
|
+
} from "./devin-shared";
|
|
45
|
+
|
|
46
|
+
const PROVIDER_ID = "devin";
|
|
47
|
+
|
|
48
|
+
/** Cap on tool-call ids (OpenAI-routed models reject >40 chars). */
|
|
49
|
+
const DEVIN_TOOL_CALL_ID_MAX_LENGTH = 40;
|
|
50
|
+
|
|
51
|
+
interface DevinAuthResult {
|
|
52
|
+
userJwt?: string;
|
|
53
|
+
baseUrl: string;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
async function fetchDevinAuthMetadata(
|
|
57
|
+
apiKey: string,
|
|
58
|
+
fetcher: typeof fetch,
|
|
59
|
+
signal: AbortSignal,
|
|
60
|
+
): Promise<DevinAuthResult> {
|
|
61
|
+
const response = await callDevinUnary<{ userJwt?: string; customApiServerUrl?: string }>(
|
|
62
|
+
DEVIN_GET_USER_JWT_PATH,
|
|
63
|
+
DevinMessageTypes.GetUserJwtRequest,
|
|
64
|
+
DevinMessageTypes.GetUserJwtResponse,
|
|
65
|
+
{ metadata: devinCliMetadata(apiKey) },
|
|
66
|
+
{ baseUrl: DEVIN_DEFAULT_BASE_URL, fetchImpl: fetcher, signal },
|
|
67
|
+
);
|
|
68
|
+
const result: DevinAuthResult = { baseUrl: response.customApiServerUrl?.trim() || DEVIN_DEFAULT_BASE_URL };
|
|
69
|
+
if (response.userJwt) result.userJwt = response.userJwt;
|
|
70
|
+
return result;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
interface DevinAssignment {
|
|
74
|
+
assignmentJwt?: string;
|
|
75
|
+
modelUid?: string;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
async function assignDevinModel(
|
|
79
|
+
apiKey: string,
|
|
80
|
+
userJwt: string | undefined,
|
|
81
|
+
modelRouterUid: string,
|
|
82
|
+
cascadeId: string,
|
|
83
|
+
baseUrl: string,
|
|
84
|
+
fetcher: typeof fetch,
|
|
85
|
+
signal: AbortSignal,
|
|
86
|
+
): Promise<DevinAssignment> {
|
|
87
|
+
const response = await callDevinUnary<{ assignment?: DevinAssignment }>(
|
|
88
|
+
DEVIN_ASSIGN_MODEL_PATH,
|
|
89
|
+
DevinMessageTypes.AssignModelRequest,
|
|
90
|
+
DevinMessageTypes.AssignModelResponse,
|
|
91
|
+
{
|
|
92
|
+
metadata: devinCliMetadata(apiKey, userJwt),
|
|
93
|
+
modelRouterUid,
|
|
94
|
+
cascadeId,
|
|
95
|
+
},
|
|
96
|
+
{ baseUrl, fetchImpl: fetcher, signal },
|
|
97
|
+
);
|
|
98
|
+
return response.assignment ?? {};
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
function normalizeToolCallId(id: string): string {
|
|
102
|
+
return id.replace(/[^a-zA-Z0-9_-]/g, "_").slice(0, DEVIN_TOOL_CALL_ID_MAX_LENGTH);
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
function systemPromptFrom(request: CanonicalRequest): string {
|
|
106
|
+
const parts: string[] = [];
|
|
107
|
+
for (const part of request.system ?? []) {
|
|
108
|
+
if (part.kind === "text") parts.push(part.text);
|
|
109
|
+
}
|
|
110
|
+
for (const part of request.instructions ?? []) {
|
|
111
|
+
if (part.kind === "text") parts.push(part.text);
|
|
112
|
+
}
|
|
113
|
+
return parts.join("\n\n");
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
function chatMessagePrompts(request: CanonicalRequest, cascadeId: string): object[] {
|
|
117
|
+
const out: object[] = [];
|
|
118
|
+
let index = 0;
|
|
119
|
+
const seedFor = (role: string, toolCallId?: string): string =>
|
|
120
|
+
toolCallId ? `${cascadeId}\0${index}\0${role}\0${toolCallId}` : `${cascadeId}\0${index}\0${role}`;
|
|
121
|
+
|
|
122
|
+
for (const message of request.messages) {
|
|
123
|
+
index += 1;
|
|
124
|
+
if (message.role === "system" || message.role === "developer") {
|
|
125
|
+
const text = joinTextParts(message.content);
|
|
126
|
+
if (text) {
|
|
127
|
+
out.push({
|
|
128
|
+
messageId: seedFor("user"),
|
|
129
|
+
source: DevinEnums.ChatMessageSource.USER,
|
|
130
|
+
prompt: text,
|
|
131
|
+
});
|
|
132
|
+
}
|
|
133
|
+
continue;
|
|
134
|
+
}
|
|
135
|
+
if (message.role === "user") {
|
|
136
|
+
// No inline images on this wire: a paired live control (2026-11-07)
|
|
137
|
+
// showed `swe-1-6-slow` answers the same "cannot see" with and without
|
|
138
|
+
// an ImageData payload, and `swe-2-flash-medium` rejects it with
|
|
139
|
+
// invalid_argument. Forwarding bytes would only cost tokens.
|
|
140
|
+
const text = joinTextParts(message.content);
|
|
141
|
+
const toolResults = toolResultParts(message);
|
|
142
|
+
const prompt: Record<string, unknown> = {
|
|
143
|
+
messageId: seedFor("user"),
|
|
144
|
+
source: DevinEnums.ChatMessageSource.USER,
|
|
145
|
+
prompt: text,
|
|
146
|
+
};
|
|
147
|
+
if (toolResults.length > 0) {
|
|
148
|
+
prompt.toolCallId = toolResults[0]!.call_id;
|
|
149
|
+
prompt.toolResultIsError = toolResults[0]!.is_error === true;
|
|
150
|
+
}
|
|
151
|
+
out.push(prompt);
|
|
152
|
+
continue;
|
|
153
|
+
}
|
|
154
|
+
if (message.role === "assistant") {
|
|
155
|
+
const text = joinTextParts(message.content);
|
|
156
|
+
const calls = toolCallParts(message);
|
|
157
|
+
const reasoning = message.content.filter((p) => p.kind === "reasoning");
|
|
158
|
+
const prompt: Record<string, unknown> = {
|
|
159
|
+
messageId: seedFor("assistant"),
|
|
160
|
+
source: DevinEnums.ChatMessageSource.SYSTEM,
|
|
161
|
+
prompt: text,
|
|
162
|
+
};
|
|
163
|
+
if (calls.length > 0) {
|
|
164
|
+
prompt.toolCalls = calls.map((call, i) => ({
|
|
165
|
+
id: normalizeToolCallId(call.call_id || `call_${i}`),
|
|
166
|
+
name: call.name,
|
|
167
|
+
argumentsJson: typeof call.arguments === "string" ? call.arguments : JSON.stringify(call.arguments ?? {}),
|
|
168
|
+
}));
|
|
169
|
+
}
|
|
170
|
+
if (reasoning.length > 0) {
|
|
171
|
+
const r = reasoning[0]!;
|
|
172
|
+
if (r.kind === "reasoning") {
|
|
173
|
+
if (typeof r.payload === "string") prompt.thinking = r.payload;
|
|
174
|
+
if (r.signature) prompt.signature = r.signature;
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
out.push(prompt);
|
|
178
|
+
continue;
|
|
179
|
+
}
|
|
180
|
+
if (message.role === "tool") {
|
|
181
|
+
const results = toolResultParts(message);
|
|
182
|
+
for (const result of results) {
|
|
183
|
+
const text = Array.isArray(result.content) ? joinTextParts(result.content) : String(result.content ?? "");
|
|
184
|
+
out.push({
|
|
185
|
+
messageId: seedFor("tool", result.call_id),
|
|
186
|
+
source: DevinEnums.ChatMessageSource.TOOL,
|
|
187
|
+
prompt: text,
|
|
188
|
+
toolCallId: result.call_id,
|
|
189
|
+
toolResultIsError: result.is_error === true,
|
|
190
|
+
});
|
|
191
|
+
}
|
|
192
|
+
continue;
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
return out;
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
function buildDevinChatRequest(
|
|
199
|
+
request: CanonicalRequest,
|
|
200
|
+
apiKey: string,
|
|
201
|
+
userJwt: string | undefined,
|
|
202
|
+
assignment: DevinAssignment,
|
|
203
|
+
cascadeId: string,
|
|
204
|
+
executionId: string,
|
|
205
|
+
): object {
|
|
206
|
+
const model = request.model;
|
|
207
|
+
const chatModelUid = assignment.modelUid?.trim() || model;
|
|
208
|
+
const controls = request.generation_controls;
|
|
209
|
+
const maxTokens = controls.max_tokens ?? controls.max_completion_tokens ?? controls.max_output_tokens ?? 64_000;
|
|
210
|
+
const stopPatterns = [
|
|
211
|
+
...DEVIN_DEFAULT_STOP_PATTERNS,
|
|
212
|
+
...(typeof controls.stop === "string" ? [controls.stop] : Array.isArray(controls.stop) ? controls.stop : []),
|
|
213
|
+
];
|
|
214
|
+
const tools = (request.tools ?? []).map((tool) => ({
|
|
215
|
+
name: tool.name,
|
|
216
|
+
description: tool.description ?? "",
|
|
217
|
+
jsonSchemaString: JSON.stringify(tool.jsonSchema ?? {}),
|
|
218
|
+
...(tool.strict ? { strict: true } : {}),
|
|
219
|
+
}));
|
|
220
|
+
|
|
221
|
+
return {
|
|
222
|
+
metadata: devinCliMetadata(apiKey, userJwt),
|
|
223
|
+
prompt: systemPromptFrom(request),
|
|
224
|
+
chatMessagePrompts: chatMessagePrompts(request, cascadeId),
|
|
225
|
+
requestType: DevinEnums.ChatMessageRequestType.CASCADE,
|
|
226
|
+
plannerMode: DevinEnums.ConversationalPlannerMode.DEFAULT,
|
|
227
|
+
systemPromptCacheOptions: { type: DevinEnums.CacheControlType.EPHEMERAL },
|
|
228
|
+
configuration: {
|
|
229
|
+
numCompletions: 1,
|
|
230
|
+
// uint64 fields must be plain numbers: protobufjs encodes a BigInt on
|
|
231
|
+
// the wire differently here and the upstream answers invalid_argument
|
|
232
|
+
// ("try a different model") on the stream trailer.
|
|
233
|
+
maxTokens,
|
|
234
|
+
maxNewlines: 400,
|
|
235
|
+
temperature: controls.temperature ?? 1,
|
|
236
|
+
topK: 40,
|
|
237
|
+
topP: Math.fround(controls.top_p ?? 0.95),
|
|
238
|
+
stopPatterns,
|
|
239
|
+
},
|
|
240
|
+
...(tools.length > 0 ? { tools } : {}),
|
|
241
|
+
...(request.tool_choice === "none" ? {} : { toolChoice: { optionName: "auto" } }),
|
|
242
|
+
...(request.tool_choice === "none" ? { disableParallelToolCalls: true } : {}),
|
|
243
|
+
cascadeId,
|
|
244
|
+
executionId,
|
|
245
|
+
chatModelUid,
|
|
246
|
+
...(assignment.assignmentJwt ? { modelAssignmentJwt: assignment.assignmentJwt } : {}),
|
|
247
|
+
};
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
interface DecodedChatResponse {
|
|
251
|
+
deltaText?: string;
|
|
252
|
+
deltaThinking?: string;
|
|
253
|
+
deltaSignature?: string;
|
|
254
|
+
stopReason?: number;
|
|
255
|
+
deltaToolCalls?: { id?: string; name?: string; argumentsJson?: string }[];
|
|
256
|
+
usage?: { inputTokens?: string | number; outputTokens?: string | number; cacheReadTokens?: string | number; cacheWriteTokens?: string | number };
|
|
257
|
+
creditCost?: number;
|
|
258
|
+
committedCreditCost?: number;
|
|
259
|
+
committedAcuCost?: number;
|
|
260
|
+
actualModelUid?: string;
|
|
261
|
+
messageId?: string;
|
|
262
|
+
outputId?: string;
|
|
263
|
+
phase?: number;
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
function decodeChatResponse(payload: Uint8Array): DecodedChatResponse {
|
|
267
|
+
const decoded = DevinMessageTypes.GetChatMessageResponse.decode(payload) as unknown as Record<string, unknown>;
|
|
268
|
+
return decoded as DecodedChatResponse;
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
function usageFromChat(decoded: DecodedChatResponse): UsageRecord | undefined {
|
|
272
|
+
const u = decoded.usage;
|
|
273
|
+
if (!u) return undefined;
|
|
274
|
+
const toNum = (v: string | number | undefined): number => (v === undefined ? 0 : typeof v === "number" ? v : Number(v));
|
|
275
|
+
const input = toNum(u.inputTokens);
|
|
276
|
+
const output = toNum(u.outputTokens);
|
|
277
|
+
const cacheRead = toNum(u.cacheReadTokens);
|
|
278
|
+
const cacheWrite = toNum(u.cacheWriteTokens);
|
|
279
|
+
const creditCost = decoded.creditCost ?? 0;
|
|
280
|
+
return {
|
|
281
|
+
input_tokens: input,
|
|
282
|
+
cached_input_tokens: cacheRead,
|
|
283
|
+
cache_write_tokens: cacheWrite,
|
|
284
|
+
uncached_input_tokens: Math.max(0, input - cacheRead),
|
|
285
|
+
output_tokens: output,
|
|
286
|
+
reasoning_tokens: "unavailable",
|
|
287
|
+
estimated_cost: null,
|
|
288
|
+
...(creditCost > 0 ? { credit_used: creditCost } : {}),
|
|
289
|
+
total_tokens: input + output,
|
|
290
|
+
};
|
|
291
|
+
}
|
|
292
|
+
|
|
293
|
+
function mapStopReason(raw: number | undefined, hasToolCalls: boolean): CanonicalStopReason {
|
|
294
|
+
if (hasToolCalls) return "tool_use";
|
|
295
|
+
if (raw === DevinEnums.StopReason.MAX_TOKENS || raw === DevinEnums.StopReason.MAX_NEWLINES || raw === DevinEnums.StopReason.INCOMPLETE || raw === DevinEnums.StopReason.PARTIAL) {
|
|
296
|
+
return "length";
|
|
297
|
+
}
|
|
298
|
+
if (raw === DevinEnums.StopReason.CONTENT_FILTER) return "content_filter";
|
|
299
|
+
return "stop";
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
export const devinAdapter: ProviderAdapter = {
|
|
303
|
+
provider_id: PROVIDER_ID,
|
|
304
|
+
|
|
305
|
+
async *dispatch(
|
|
306
|
+
request: CanonicalRequest,
|
|
307
|
+
candidate: ProviderDispatchTarget,
|
|
308
|
+
context: ProviderDispatchContext,
|
|
309
|
+
): AsyncIterable<CanonicalEvent> {
|
|
310
|
+
const apiKey = readCredentialSecret(context.credential, "Devin credential is missing");
|
|
311
|
+
const fetcher = (context.outbound_fetch ?? fetch) as typeof fetch;
|
|
312
|
+
const signal = context.abort_signal;
|
|
313
|
+
let seq = 0;
|
|
314
|
+
const nextSeq = (): number => ++seq;
|
|
315
|
+
|
|
316
|
+
// 1. Auth: mint user JWT (and possibly a custom API server URL).
|
|
317
|
+
let auth: DevinAuthResult;
|
|
318
|
+
try {
|
|
319
|
+
auth = await fetchDevinAuthMetadata(apiKey, fetcher, signal);
|
|
320
|
+
} catch (error) {
|
|
321
|
+
yield { type: "error", sequence_number: nextSeq(), category: "auth", message: error instanceof Error ? error.message : String(error), retryable: false };
|
|
322
|
+
return;
|
|
323
|
+
}
|
|
324
|
+
|
|
325
|
+
// 2. Optional router assignment.
|
|
326
|
+
const cascadeId = request.conversation?.conversation_id ?? randomUUID();
|
|
327
|
+
let assignment: DevinAssignment = {};
|
|
328
|
+
if (candidate.capabilities["modelRouter"]) {
|
|
329
|
+
try {
|
|
330
|
+
assignment = await assignDevinModel(apiKey, auth.userJwt, request.model, cascadeId, auth.baseUrl, fetcher, signal);
|
|
331
|
+
} catch (error) {
|
|
332
|
+
yield { type: "error", sequence_number: nextSeq(), category: "router", message: error instanceof Error ? error.message : String(error), retryable: false };
|
|
333
|
+
return;
|
|
334
|
+
}
|
|
335
|
+
}
|
|
336
|
+
|
|
337
|
+
const executionId = newExecutionId();
|
|
338
|
+
const chatRequest = buildDevinChatRequest(request, apiKey, auth.userJwt, assignment, cascadeId, executionId);
|
|
339
|
+
const body = DevinMessageTypes.GetChatMessageRequest.encode(chatRequest as object).finish();
|
|
340
|
+
const frame = encodeFrame(Buffer.from(body), true);
|
|
341
|
+
|
|
342
|
+
let response: Response;
|
|
343
|
+
try {
|
|
344
|
+
response = await fetcher(`${auth.baseUrl}${DEVIN_CHAT_MESSAGE_PATH}`, {
|
|
345
|
+
method: "POST",
|
|
346
|
+
headers: {
|
|
347
|
+
"content-type": "application/connect+proto",
|
|
348
|
+
"connect-protocol-version": "1",
|
|
349
|
+
"connect-content-encoding": frame[0] === 1 ? "gzip" : "identity",
|
|
350
|
+
"accept-encoding": "identity",
|
|
351
|
+
"connect-accept-encoding": "gzip",
|
|
352
|
+
"user-agent": "connect-go/1.18.1 (go1.26.3)",
|
|
353
|
+
},
|
|
354
|
+
body: new Uint8Array(frame),
|
|
355
|
+
signal,
|
|
356
|
+
});
|
|
357
|
+
} catch (error) {
|
|
358
|
+
yield { type: "error", sequence_number: nextSeq(), category: "transport", message: error instanceof Error ? error.message : String(error), retryable: true };
|
|
359
|
+
return;
|
|
360
|
+
}
|
|
361
|
+
|
|
362
|
+
if (!response.ok) {
|
|
363
|
+
const text = await response.text().catch(() => "");
|
|
364
|
+
yield {
|
|
365
|
+
type: "error",
|
|
366
|
+
sequence_number: nextSeq(),
|
|
367
|
+
category: "upstream",
|
|
368
|
+
message: `Devin HTTP ${response.status}: ${text.slice(0, 1024)}`,
|
|
369
|
+
retryable: response.status >= 500 || response.status === 429,
|
|
370
|
+
};
|
|
371
|
+
return;
|
|
372
|
+
}
|
|
373
|
+
|
|
374
|
+
yield { type: "response_start", sequence_number: nextSeq(), model: request.model, response_id: randomUUID() };
|
|
375
|
+
|
|
376
|
+
// 3. Stream decoder.
|
|
377
|
+
const decoder = new ConnectFrameDecoder();
|
|
378
|
+
let latestStopReason: number | undefined;
|
|
379
|
+
let hasToolCalls = false;
|
|
380
|
+
let sawContent = false;
|
|
381
|
+
const toolBlocks = new Map<string, { name: string; args: string }>();
|
|
382
|
+
// Some SWE lanes (live-verified: swe-2-flash-medium) emit tool invocation
|
|
383
|
+
// as inline markup in `deltaText` instead of `deltaToolCalls`. Buffer the
|
|
384
|
+
// text so a markup token split across frames still parses.
|
|
385
|
+
let rawText = "";
|
|
386
|
+
const reader = response.body?.getReader();
|
|
387
|
+
if (!reader) {
|
|
388
|
+
yield { type: "error", sequence_number: nextSeq(), category: "upstream", message: "Devin returned no body", retryable: false };
|
|
389
|
+
return;
|
|
390
|
+
}
|
|
391
|
+
|
|
392
|
+
for (;;) {
|
|
393
|
+
const { done, value } = await reader.read();
|
|
394
|
+
if (done) break;
|
|
395
|
+
let frames;
|
|
396
|
+
try {
|
|
397
|
+
frames = decoder.push(value);
|
|
398
|
+
} catch (error) {
|
|
399
|
+
yield { type: "error", sequence_number: nextSeq(), category: "upstream", message: error instanceof Error ? error.message : String(error), retryable: false };
|
|
400
|
+
return;
|
|
401
|
+
}
|
|
402
|
+
for (const frame of frames) {
|
|
403
|
+
if ((frame.flags & CONNECT_END_STREAM_FLAG) !== 0) {
|
|
404
|
+
// Connect end-stream trailers may also carry the compressed flag.
|
|
405
|
+
const trailerPayload = frame.compressed ? gunzipSync(frame.payload) : frame.payload;
|
|
406
|
+
const trailer = parseTrailer(trailerPayload);
|
|
407
|
+
if (trailer.error) {
|
|
408
|
+
const code = trailer.error.code ?? "unknown";
|
|
409
|
+
const message = trailer.error.message ?? "unknown error";
|
|
410
|
+
yield {
|
|
411
|
+
type: "error",
|
|
412
|
+
sequence_number: nextSeq(),
|
|
413
|
+
category: "upstream",
|
|
414
|
+
message: `Devin stream error ${code}: ${message}`,
|
|
415
|
+
retryable: code === "unavailable" || code === "resource_exhausted",
|
|
416
|
+
};
|
|
417
|
+
return;
|
|
418
|
+
}
|
|
419
|
+
continue;
|
|
420
|
+
}
|
|
421
|
+
let decoded: DecodedChatResponse;
|
|
422
|
+
try {
|
|
423
|
+
const payload = frame.compressed ? gunzipSync(frame.payload) : frame.payload;
|
|
424
|
+
decoded = decodeChatResponse(payload);
|
|
425
|
+
} catch (error) {
|
|
426
|
+
yield { type: "error", sequence_number: nextSeq(), category: "upstream", message: error instanceof Error ? error.message : String(error), retryable: false };
|
|
427
|
+
return;
|
|
428
|
+
}
|
|
429
|
+
|
|
430
|
+
if (decoded.deltaThinking) {
|
|
431
|
+
sawContent = true;
|
|
432
|
+
yield {
|
|
433
|
+
type: "content_delta",
|
|
434
|
+
sequence_number: nextSeq(),
|
|
435
|
+
content: { kind: "reasoning", payload: decoded.deltaThinking },
|
|
436
|
+
};
|
|
437
|
+
}
|
|
438
|
+
if (decoded.deltaText) {
|
|
439
|
+
rawText += decoded.deltaText;
|
|
440
|
+
// Inline tool-invocation markup: <|message_model|>NAME<|content_invoke_tool_json|>{...}<|end_message|>
|
|
441
|
+
const MARKUP = /<\|message_model\|>([^<]*)<\|content_invoke_tool_json\|>([\s\S]*?)<\|end_message\|>/g;
|
|
442
|
+
let cursor = 0;
|
|
443
|
+
let match: RegExpExecArray | null;
|
|
444
|
+
let plain = "";
|
|
445
|
+
while ((match = MARKUP.exec(rawText)) !== null) {
|
|
446
|
+
plain += rawText.slice(cursor, match.index);
|
|
447
|
+
cursor = match.index + match[0]!.length;
|
|
448
|
+
const toolName = match[1]!.trim() || "unknown_tool";
|
|
449
|
+
let args = match[2]!.trim();
|
|
450
|
+
try {
|
|
451
|
+
const parsed = JSON.parse(args) as { name?: string; args?: unknown };
|
|
452
|
+
if (parsed.args !== undefined) args = JSON.stringify(parsed.args);
|
|
453
|
+
} catch { /* keep raw */ }
|
|
454
|
+
const id = normalizeToolCallId(`call_${toolBlocks.size}`);
|
|
455
|
+
toolBlocks.set(id, { name: toolName, args });
|
|
456
|
+
hasToolCalls = true;
|
|
457
|
+
yield {
|
|
458
|
+
type: "tool_call_delta",
|
|
459
|
+
sequence_number: nextSeq(),
|
|
460
|
+
call_id: id,
|
|
461
|
+
name: toolName,
|
|
462
|
+
arguments_delta: args,
|
|
463
|
+
};
|
|
464
|
+
}
|
|
465
|
+
plain += rawText.slice(cursor);
|
|
466
|
+
// Hold back an incomplete markup prefix until the next frame.
|
|
467
|
+
const partialAt = plain.indexOf("<|message_model|>");
|
|
468
|
+
const emit = partialAt < 0 ? plain : plain.slice(0, partialAt);
|
|
469
|
+
rawText = partialAt < 0 ? "" : plain.slice(partialAt);
|
|
470
|
+
if (emit) {
|
|
471
|
+
sawContent = true;
|
|
472
|
+
yield {
|
|
473
|
+
type: "content_delta",
|
|
474
|
+
sequence_number: nextSeq(),
|
|
475
|
+
content: { kind: "text", text: emit },
|
|
476
|
+
};
|
|
477
|
+
}
|
|
478
|
+
}
|
|
479
|
+
if (decoded.deltaToolCalls?.length) {
|
|
480
|
+
hasToolCalls = true;
|
|
481
|
+
for (const tc of decoded.deltaToolCalls) {
|
|
482
|
+
const id = tc.id ?? `call_${toolBlocks.size}`;
|
|
483
|
+
const existing = toolBlocks.get(id);
|
|
484
|
+
if (existing) {
|
|
485
|
+
existing.args += tc.argumentsJson ?? "";
|
|
486
|
+
} else {
|
|
487
|
+
toolBlocks.set(id, { name: tc.name ?? "", args: tc.argumentsJson ?? "" });
|
|
488
|
+
}
|
|
489
|
+
yield {
|
|
490
|
+
type: "tool_call_delta",
|
|
491
|
+
sequence_number: nextSeq(),
|
|
492
|
+
call_id: id,
|
|
493
|
+
...(tc.name !== undefined ? { name: tc.name } : {}),
|
|
494
|
+
...(tc.argumentsJson !== undefined ? { arguments_delta: tc.argumentsJson } : {}),
|
|
495
|
+
};
|
|
496
|
+
}
|
|
497
|
+
}
|
|
498
|
+
if (decoded.usage) {
|
|
499
|
+
const usage = usageFromChat(decoded);
|
|
500
|
+
if (usage) yield { type: "usage", sequence_number: nextSeq(), usage };
|
|
501
|
+
}
|
|
502
|
+
if (decoded.stopReason !== undefined) latestStopReason = decoded.stopReason;
|
|
503
|
+
}
|
|
504
|
+
}
|
|
505
|
+
|
|
506
|
+
if (decoder.hasPartial) {
|
|
507
|
+
yield { type: "error", sequence_number: nextSeq(), category: "upstream", message: "Devin stream ended mid-frame (truncated)", retryable: true };
|
|
508
|
+
return;
|
|
509
|
+
}
|
|
510
|
+
|
|
511
|
+
// Flush a leftover text prefix that never completed a markup token.
|
|
512
|
+
if (rawText && !rawText.startsWith("<|message_model|>")) {
|
|
513
|
+
sawContent = true;
|
|
514
|
+
yield {
|
|
515
|
+
type: "content_delta",
|
|
516
|
+
sequence_number: nextSeq(),
|
|
517
|
+
content: { kind: "text", text: rawText },
|
|
518
|
+
};
|
|
519
|
+
rawText = "";
|
|
520
|
+
}
|
|
521
|
+
|
|
522
|
+
if (!sawContent && !hasToolCalls) {
|
|
523
|
+
yield { type: "error", sequence_number: nextSeq(), category: "upstream", message: "Devin stream ended without content", retryable: true };
|
|
524
|
+
return;
|
|
525
|
+
}
|
|
526
|
+
|
|
527
|
+
// Tool-call arguments are fully delivered through `tool_call_delta` events
|
|
528
|
+
// above; no `tool_result` is emitted (that event belongs to a client's tool
|
|
529
|
+
// output, not to the model's call). `toolBlocks` only tracks accumulation.
|
|
530
|
+
const stopReason = mapStopReason(latestStopReason, hasToolCalls);
|
|
531
|
+
yield {
|
|
532
|
+
type: "terminal",
|
|
533
|
+
sequence_number: nextSeq(),
|
|
534
|
+
state: "complete",
|
|
535
|
+
stop_reason: stopReason,
|
|
536
|
+
provider_stop_reason: fromEnum(DevinEnums.StopReason, latestStopReason),
|
|
537
|
+
};
|
|
538
|
+
},
|
|
539
|
+
};
|