cartethyia 2.5.2 → 2.5.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/dashboard/assets/{BannedPage-MsQaeQTs.js → BannedPage-C2orBsI2.js} +1 -1
- package/dist/dashboard/assets/BannedPage-C2orBsI2.js.gz +0 -0
- package/dist/dashboard/assets/CliToolDetailPage-DUcZ6pMB.js +1 -0
- package/dist/dashboard/assets/CliToolDetailPage-DUcZ6pMB.js.gz +0 -0
- package/dist/dashboard/assets/{CliToolsPage-DfWHTJ7v.js → CliToolsPage-BV6pxVQo.js} +1 -1
- package/dist/dashboard/assets/CliToolsPage-BV6pxVQo.js.gz +0 -0
- package/dist/dashboard/assets/{CombosPage-BrCBQDAc.js → CombosPage-Bsan4679.js} +1 -1
- package/dist/dashboard/assets/CombosPage-Bsan4679.js.gz +0 -0
- package/dist/dashboard/assets/{ConsoleLogPage-C6Uh33er.js → ConsoleLogPage-CW-wPmJ6.js} +1 -1
- package/dist/dashboard/assets/ConsoleLogPage-CW-wPmJ6.js.gz +0 -0
- package/dist/dashboard/assets/{CustomizationPage-8aS9hyJu.js → CustomizationPage-0p8uX7vB.js} +1 -1
- package/dist/dashboard/assets/CustomizationPage-0p8uX7vB.js.gz +0 -0
- package/dist/dashboard/assets/HealthEventsModal-BjqSMfko.js +1 -0
- package/dist/dashboard/assets/HealthEventsModal-BjqSMfko.js.gz +0 -0
- package/dist/dashboard/assets/{LoginPage-C8hKyXBe.js → LoginPage-BvzCx8Kr.js} +1 -1
- package/dist/dashboard/assets/LoginPage-BvzCx8Kr.js.gz +0 -0
- package/dist/dashboard/assets/{ModelPicker-CWkTUtpX.js → ModelPicker-BY1aKEkP.js} +1 -1
- package/dist/dashboard/assets/ModelPicker-BY1aKEkP.js.gz +0 -0
- package/dist/dashboard/assets/OverviewPage-DOQpy1y0.js +1 -0
- package/dist/dashboard/assets/OverviewPage-DOQpy1y0.js.gz +0 -0
- package/dist/dashboard/assets/ProviderDetailPage-ecxyUMzt.js +3 -0
- package/dist/dashboard/assets/ProviderDetailPage-ecxyUMzt.js.gz +0 -0
- package/dist/dashboard/assets/ProvidersPage-Js9jUPSb.js +1 -0
- package/dist/dashboard/assets/ProvidersPage-Js9jUPSb.js.gz +0 -0
- package/dist/dashboard/assets/ProxyPage-J3TBi3Kx.js +7 -0
- package/dist/dashboard/assets/ProxyPage-J3TBi3Kx.js.gz +0 -0
- package/dist/dashboard/assets/QuotaPage-C1gZS6xr.js +1 -0
- package/dist/dashboard/assets/QuotaPage-C1gZS6xr.js.gz +0 -0
- package/dist/dashboard/assets/SettingsPage-CS86ho5X.js +1 -0
- package/dist/dashboard/assets/SettingsPage-CS86ho5X.js.gz +0 -0
- package/dist/dashboard/assets/{SetupPage-CXjUlfqr.js → SetupPage-DDbMQsoo.js} +1 -1
- package/dist/dashboard/assets/SetupPage-DDbMQsoo.js.gz +0 -0
- package/dist/dashboard/assets/{SortableList-C-_oD3F2.js → SortableList-CB3Z7VTf.js} +1 -1
- package/dist/dashboard/assets/SortableList-CB3Z7VTf.js.gz +0 -0
- package/dist/dashboard/assets/{StudioPage-u9IxmYOI.js → StudioPage-D95UCPHI.js} +3 -3
- package/dist/dashboard/assets/StudioPage-D95UCPHI.js.gz +0 -0
- package/dist/dashboard/assets/{UsagePage-BEVLVrwP.js → UsagePage-Cnae9SWA.js} +13 -13
- package/dist/dashboard/assets/UsagePage-Cnae9SWA.js.gz +0 -0
- package/dist/dashboard/assets/{api-keys-uNywYlfv.js → api-keys-VY68Mhd1.js} +1 -1
- package/dist/dashboard/assets/api-keys-VY68Mhd1.js.gz +0 -0
- package/dist/dashboard/assets/app-COlK95oi.css +2 -0
- package/dist/dashboard/assets/app-COlK95oi.css.gz +0 -0
- package/dist/dashboard/assets/{assert-NHwYq95t.js → assert-Chi7pCnt.js} +1 -1
- package/dist/dashboard/assets/assert-Chi7pCnt.js.gz +0 -0
- package/dist/dashboard/assets/{badge-6uzDDvqs.js → badge-D4pQapKj.js} +1 -1
- package/dist/dashboard/assets/badge-D4pQapKj.js.gz +0 -0
- package/dist/dashboard/assets/{banner-4_WNg2WZ.js → banner-DH6cg-_B.js} +1 -1
- package/dist/dashboard/assets/banner-DH6cg-_B.js.gz +0 -0
- package/dist/dashboard/assets/{card--AtFedAq.js → card-BKqlUOe4.js} +1 -1
- package/dist/dashboard/assets/card-BKqlUOe4.js.gz +0 -0
- package/dist/dashboard/assets/{cli-tools-B3e7dx3N.js → cli-tools-fTgljTGA.js} +1 -1
- package/dist/dashboard/assets/cli-tools-fTgljTGA.js.gz +0 -0
- package/dist/dashboard/assets/{clipboard-button-NreUx6c8.js → clipboard-button-D5Ys_sM0.js} +1 -1
- package/dist/dashboard/assets/clipboard-button-D5Ys_sM0.js.gz +0 -0
- package/dist/dashboard/assets/database-Dz9N3zGd.js +1 -0
- package/dist/dashboard/assets/database-Dz9N3zGd.js.gz +0 -0
- package/dist/dashboard/assets/{dialog-BtpsJU98.js → dialog-BYj-8WuK.js} +1 -1
- package/dist/dashboard/assets/dialog-BYj-8WuK.js.gz +0 -0
- package/dist/dashboard/assets/{drawer-WwwtzihF.js → drawer-CmXIZ6H1.js} +1 -1
- package/dist/dashboard/assets/drawer-CmXIZ6H1.js.gz +0 -0
- package/dist/dashboard/assets/entry-CBg5zeu8.js +1 -0
- package/dist/dashboard/assets/entry-CBg5zeu8.js.gz +0 -0
- package/dist/dashboard/assets/entry-CQBr6U9c.js +1 -0
- package/dist/dashboard/assets/entry-CQBr6U9c.js.gz +0 -0
- package/dist/dashboard/assets/entry-CgdSAzEV.js +4 -0
- package/dist/dashboard/assets/entry-CgdSAzEV.js.gz +0 -0
- package/dist/dashboard/assets/{github-badge-D_eM3IgG.js → github-badge-BlptL8Uf.js} +1 -1
- package/dist/dashboard/assets/github-badge-BlptL8Uf.js.gz +0 -0
- package/dist/dashboard/assets/{index-DCBtROoK.js → index-js6TJvdr.js} +2 -2
- package/dist/dashboard/assets/index-js6TJvdr.js.gz +0 -0
- package/dist/dashboard/assets/{inline-BcNGF8Gr.js → inline-DUWDSmDV.js} +1 -1
- package/dist/dashboard/assets/inline-DUWDSmDV.js.gz +0 -0
- package/dist/dashboard/assets/{input-BG41et9G.js → input-LVjgZq4f.js} +1 -1
- package/dist/dashboard/assets/input-LVjgZq4f.js.gz +0 -0
- package/dist/dashboard/assets/{layout-C8mer_Ak.js → layout-CPfxpsfy.js} +1 -1
- package/dist/dashboard/assets/layout-CPfxpsfy.js.gz +0 -0
- package/dist/dashboard/assets/{list-row-Gh_W4OR_.js → list-row-DupvLfDx.js} +1 -1
- package/dist/dashboard/assets/list-row-DupvLfDx.js.gz +0 -0
- package/dist/dashboard/assets/{live-BJGYRBnR.js → live-C4pEJUqI.js} +1 -1
- package/dist/dashboard/assets/live-C4pEJUqI.js.gz +0 -0
- package/dist/dashboard/assets/model-bans-BRiuufkB.js +1 -0
- package/dist/dashboard/assets/model-bans-BRiuufkB.js.gz +0 -0
- package/dist/dashboard/assets/{mutation-BkoLM5Ba.js → mutation-B4ROwk8L.js} +1 -1
- package/dist/dashboard/assets/mutation-B4ROwk8L.js.gz +0 -0
- package/dist/dashboard/assets/numbers-YNcHvRY7.js +2 -0
- package/dist/dashboard/assets/numbers-YNcHvRY7.js.gz +0 -0
- package/dist/dashboard/assets/{query-keys-D7wX2vM5.js → query-keys-gmjzC3RS.js} +1 -1
- package/dist/dashboard/assets/{query-keys-D7wX2vM5.js.gz → query-keys-gmjzC3RS.js.gz} +0 -0
- package/dist/dashboard/assets/{routing-CcusqXA7.js → routing-C7tBT5o-.js} +1 -1
- package/dist/dashboard/assets/routing-C7tBT5o-.js.gz +0 -0
- package/dist/dashboard/assets/{select-DsX5QT8K.js → select-WUCXorXw.js} +2 -2
- package/dist/dashboard/assets/select-WUCXorXw.js.gz +0 -0
- package/dist/dashboard/assets/{settings-mpmXTgUa.js → settings-C_zKl1GS.js} +1 -1
- package/dist/dashboard/assets/settings-C_zKl1GS.js.gz +0 -0
- package/dist/dashboard/assets/{stack-DwLmjUFK.js → stack-_3O0F8Xn.js} +1 -1
- package/dist/dashboard/assets/stack-_3O0F8Xn.js.gz +0 -0
- package/dist/dashboard/assets/{state-DYdQmdAl.js → state-BgTxHcJS.js} +1 -1
- package/dist/dashboard/assets/state-BgTxHcJS.js.gz +0 -0
- package/dist/dashboard/assets/switch-DEjTtOWf.js +1 -0
- package/dist/dashboard/assets/switch-DEjTtOWf.js.gz +0 -0
- package/dist/dashboard/assets/terminal-0_IjPWTk.js +1 -0
- package/dist/dashboard/assets/terminal-0_IjPWTk.js.gz +0 -0
- package/dist/dashboard/assets/{useMutation-w4u4CVue.js → useMutation-BWSC0UAS.js} +1 -1
- package/dist/dashboard/assets/useMutation-BWSC0UAS.js.gz +0 -0
- package/dist/dashboard/assets/zap-C4EeVW4q.js +1 -0
- package/dist/dashboard/assets/zap-C4EeVW4q.js.gz +0 -0
- package/dist/dashboard/donation/qris-risun-marke.png +0 -0
- package/dist/dashboard/index.html +1 -1
- package/dist/dashboard/index.html.gz +0 -0
- package/dist/dashboard/precompressed-assets.json +54 -54
- package/package.json +1 -1
- package/scripts/cli/autostart.ts +237 -0
- package/scripts/cli/command/console-menu.ts +244 -246
- package/scripts/cli/command/tray.ts +208 -204
- package/scripts/cli/command/update.ts +27 -10
- package/scripts/cli/main.ts +28 -1
- package/src/boot/app.ts +693 -693
- package/src/boot/dependencies.ts +646 -616
- package/src/config/spec.ts +81 -2
- package/src/config/telemetry.ts +46 -0
- package/src/console/api-keys/bucket-spend.ts +15 -4
- package/src/console/backup/contracts.ts +15 -2
- package/src/console/backup/routes.ts +52 -1
- package/src/console/backup/service.ts +60 -4
- package/src/console/console-router.ts +8 -0
- package/src/console/data-management/contracts.ts +93 -0
- package/src/console/data-management/operations.ts +229 -0
- package/src/console/data-management/routes.ts +104 -0
- package/src/console/domain-registration.ts +39 -0
- package/src/console/observability/contracts.ts +524 -485
- package/src/console/observability/store.ts +1115 -1018
- package/src/console/providers/catalog/contracts.ts +6 -0
- package/src/console/providers/catalog/provider-operations.ts +20 -0
- package/src/console/providers/catalog/routes.ts +7 -0
- package/src/console/providers/catalog/store.ts +22 -1
- package/src/console/quota/account-quota-shared.ts +52 -39
- package/src/console/quota/refresh.ts +441 -429
- package/src/console/routing/pools/import-parse.ts +206 -0
- package/src/console/routing/pools/operations.ts +543 -501
- package/src/console/routing/pools/routes.ts +181 -164
- package/src/console/settings/contracts.ts +37 -0
- package/src/console/settings/store.ts +51 -0
- package/src/console/share/share-router.ts +6 -9
- package/src/console/updates/routes.ts +16 -0
- package/src/main.ts +10 -0
- package/src/observability/event-compaction.ts +315 -0
- package/src/observability/event-day-index.ts +442 -0
- package/src/observability/event-log.ts +152 -3
- package/src/observability/payload-capture.ts +373 -344
- package/src/observability/payload-store.ts +440 -366
- package/src/observability/telemetry-status.ts +28 -16
- package/src/persistence/health-event-flush.ts +36 -0
- package/src/persistence/schema.ts +1402 -1360
- package/src/persistence/stores/api-key-store.ts +6 -0
- package/src/persistence/stores/share-store.ts +583 -556
- package/src/persistence/stores/telemetry-store.ts +237 -214
- package/src/protocol/codecs.ts +1 -2
- package/src/protocol/image-clamp.ts +19 -1
- package/src/protocol/registry.ts +8 -0
- package/src/protocol/request/gemini.ts +9 -2
- package/src/protocol/request/messages.ts +14 -2
- package/src/protocol/response/gemini.ts +18 -4
- package/src/providers/adapters/compatible-adapter.ts +3 -0
- package/src/providers/bundled-discovery-providers.ts +122 -119
- package/src/providers/configured-openai-providers.ts +136 -134
- package/src/providers/default-registry.ts +5 -4
- package/src/providers/discovery/openai-model-discovery.ts +5 -0
- package/src/providers/discovery/openrouter-free-roster.ts +15 -17
- package/src/providers/integrations/antigravity/antigravity-quota.ts +11 -3
- package/src/providers/integrations/buddy/buddy-catalog-shared.ts +4 -4
- package/src/providers/integrations/buddy/workbuddy/shared.ts +201 -200
- package/src/providers/integrations/cline/cline-quota.ts +132 -128
- package/src/providers/integrations/codex/codex-headers.ts +25 -39
- package/src/providers/integrations/codex/codex.ts +2 -29
- package/src/providers/integrations/cursor/cursor-quota.ts +310 -0
- package/src/providers/integrations/cursor/cursor-request.ts +616 -471
- package/src/providers/integrations/cursor/cursor-session-manager.ts +319 -281
- package/src/providers/integrations/cursor/cursor.ts +1485 -960
- package/src/providers/integrations/cursor/protocol/messages.ts +25 -0
- package/src/providers/integrations/factory/factory.ts +8 -1
- package/src/providers/integrations/gemini.ts +6 -1
- package/src/providers/integrations/grok/grok-quota.ts +279 -177
- package/src/providers/integrations/grok/grok-ratelimit-store.ts +73 -0
- package/src/providers/integrations/grok/grok-ratelimit.ts +218 -0
- package/src/providers/integrations/opencode/provider.ts +531 -532
- package/src/providers/integrations/qoder/qoder-quota.ts +192 -0
- package/src/providers/integrations/tokenharbor.ts +2 -2
- package/src/providers/integrations/trae/trae-catalog.ts +5 -3
- package/src/providers/integrations/trae/trae-quota.ts +384 -0
- package/src/providers/operations/account-health-service.ts +1523 -1457
- package/src/providers/operations/client-versions.ts +9 -2
- package/src/providers/provider-contracts.ts +7 -0
- package/src/providers/provider-metadata.ts +13 -1
- package/src/providers/quota/quota-support.ts +8 -0
- package/src/security/api-key-auth.ts +504 -494
- package/src/transport/dispatch/attempt-finalize.ts +46 -5
- package/src/transport/dispatch/generation.ts +6 -0
- package/src/transport/dispatch/proxy-request.ts +33 -1
- package/src/transport/dispatch/ratelimit-capture.ts +37 -0
- package/src/transport/dispatch/streaming/stream.ts +30 -2
- package/src/transport/dispatch/upstream.ts +9 -0
- package/src/transport/request/preparer.ts +7 -6
- package/src/transport/request/state.ts +9 -0
- package/src/transport/request/tenant-preferences.ts +60 -0
- package/src/transport/routing/route-catalog.ts +854 -799
- package/dist/dashboard/assets/BannedPage-MsQaeQTs.js.gz +0 -0
- package/dist/dashboard/assets/CliToolDetailPage-BO9nKg9w.js +0 -1
- package/dist/dashboard/assets/CliToolDetailPage-BO9nKg9w.js.gz +0 -0
- package/dist/dashboard/assets/CliToolsPage-DfWHTJ7v.js.gz +0 -0
- package/dist/dashboard/assets/CombosPage-BrCBQDAc.js.gz +0 -0
- package/dist/dashboard/assets/ConsoleLogPage-C6Uh33er.js.gz +0 -0
- package/dist/dashboard/assets/CustomizationPage-8aS9hyJu.js.gz +0 -0
- package/dist/dashboard/assets/HealthEventsModal-qomXThxX.js +0 -1
- package/dist/dashboard/assets/HealthEventsModal-qomXThxX.js.gz +0 -0
- package/dist/dashboard/assets/LoginPage-C8hKyXBe.js.gz +0 -0
- package/dist/dashboard/assets/ModelPicker-CWkTUtpX.js.gz +0 -0
- package/dist/dashboard/assets/OverviewPage-C-ExCy1V.js +0 -1
- package/dist/dashboard/assets/OverviewPage-C-ExCy1V.js.gz +0 -0
- package/dist/dashboard/assets/ProviderDetailPage-tr811uaF.js +0 -3
- package/dist/dashboard/assets/ProviderDetailPage-tr811uaF.js.gz +0 -0
- package/dist/dashboard/assets/ProvidersPage-BS9IEpvv.js +0 -1
- package/dist/dashboard/assets/ProvidersPage-BS9IEpvv.js.gz +0 -0
- package/dist/dashboard/assets/ProxyPage-Rn_qXScb.js +0 -7
- package/dist/dashboard/assets/ProxyPage-Rn_qXScb.js.gz +0 -0
- package/dist/dashboard/assets/QuotaPage-BihkgQSq.js +0 -1
- package/dist/dashboard/assets/QuotaPage-BihkgQSq.js.gz +0 -0
- package/dist/dashboard/assets/SettingsPage-DhiEjm6T.js +0 -1
- package/dist/dashboard/assets/SettingsPage-DhiEjm6T.js.gz +0 -0
- package/dist/dashboard/assets/SetupPage-CXjUlfqr.js.gz +0 -0
- package/dist/dashboard/assets/SortableList-C-_oD3F2.js.gz +0 -0
- package/dist/dashboard/assets/StudioPage-u9IxmYOI.js.gz +0 -0
- package/dist/dashboard/assets/UsagePage-BEVLVrwP.js.gz +0 -0
- package/dist/dashboard/assets/api-keys-uNywYlfv.js.gz +0 -0
- package/dist/dashboard/assets/app-DxivpfYG.css +0 -2
- package/dist/dashboard/assets/app-DxivpfYG.css.gz +0 -0
- package/dist/dashboard/assets/assert-NHwYq95t.js.gz +0 -0
- package/dist/dashboard/assets/badge-6uzDDvqs.js.gz +0 -0
- package/dist/dashboard/assets/banner-4_WNg2WZ.js.gz +0 -0
- package/dist/dashboard/assets/card--AtFedAq.js.gz +0 -0
- package/dist/dashboard/assets/cli-tools-B3e7dx3N.js.gz +0 -0
- package/dist/dashboard/assets/clipboard-button-NreUx6c8.js.gz +0 -0
- package/dist/dashboard/assets/dialog-BtpsJU98.js.gz +0 -0
- package/dist/dashboard/assets/download-A0SW9OCW.js +0 -1
- package/dist/dashboard/assets/download-A0SW9OCW.js.gz +0 -0
- package/dist/dashboard/assets/drawer-WwwtzihF.js.gz +0 -0
- package/dist/dashboard/assets/entry-Dj9AR0gY.js +0 -4
- package/dist/dashboard/assets/entry-Dj9AR0gY.js.gz +0 -0
- package/dist/dashboard/assets/entry-TJIye_jT.js +0 -1
- package/dist/dashboard/assets/entry-TJIye_jT.js.gz +0 -0
- package/dist/dashboard/assets/entry-jy9_4-Ke.js +0 -1
- package/dist/dashboard/assets/entry-jy9_4-Ke.js.gz +0 -0
- package/dist/dashboard/assets/github-badge-D_eM3IgG.js.gz +0 -0
- package/dist/dashboard/assets/index-DCBtROoK.js.gz +0 -0
- package/dist/dashboard/assets/inline-BcNGF8Gr.js.gz +0 -0
- package/dist/dashboard/assets/input-BG41et9G.js.gz +0 -0
- package/dist/dashboard/assets/layout-C8mer_Ak.js.gz +0 -0
- package/dist/dashboard/assets/list-row-Gh_W4OR_.js.gz +0 -0
- package/dist/dashboard/assets/live-BJGYRBnR.js.gz +0 -0
- package/dist/dashboard/assets/model-bans-DeVLDA7I.js +0 -1
- package/dist/dashboard/assets/model-bans-DeVLDA7I.js.gz +0 -0
- package/dist/dashboard/assets/mutation-BkoLM5Ba.js.gz +0 -0
- package/dist/dashboard/assets/numbers-Bs4LOOuf.js +0 -2
- package/dist/dashboard/assets/numbers-Bs4LOOuf.js.gz +0 -0
- package/dist/dashboard/assets/routing-CcusqXA7.js.gz +0 -0
- package/dist/dashboard/assets/select-DsX5QT8K.js.gz +0 -0
- package/dist/dashboard/assets/settings-mpmXTgUa.js.gz +0 -0
- package/dist/dashboard/assets/sparkles-BRaRUxAU.js +0 -1
- package/dist/dashboard/assets/sparkles-BRaRUxAU.js.gz +0 -0
- package/dist/dashboard/assets/stack-DwLmjUFK.js.gz +0 -0
- package/dist/dashboard/assets/state-DYdQmdAl.js.gz +0 -0
- package/dist/dashboard/assets/switch-CidSfbG7.js +0 -1
- package/dist/dashboard/assets/switch-CidSfbG7.js.gz +0 -0
- package/dist/dashboard/assets/terminal-Bd4ee8TA.js +0 -1
- package/dist/dashboard/assets/terminal-Bd4ee8TA.js.gz +0 -0
- package/dist/dashboard/assets/useMutation-w4u4CVue.js.gz +0 -0
- /package/dist/dashboard/assets/{app-CafWtVXA.js → app-DCQZRmHY.js} +0 -0
- /package/dist/dashboard/assets/{app-CafWtVXA.js.gz → app-DCQZRmHY.js.gz} +0 -0
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* The free tier shared by the OpenRouter-backed providers.
|
|
3
3
|
*
|
|
4
|
-
* Cline, Kilo Code and OpenRouter serve one model catalog
|
|
5
|
-
*
|
|
6
|
-
*
|
|
7
|
-
*
|
|
8
|
-
*
|
|
4
|
+
* Cline, Kilo Code and OpenRouter serve one model catalog, and every id below
|
|
5
|
+
* was verified to exist under `openrouter`, `kilo` and `cline` — so this
|
|
6
|
+
* roster is a catalog fact, not a per-provider guess, and it lives in one
|
|
7
|
+
* place rather than being restated three times. Dropping a row here unlists
|
|
8
|
+
* it from all three providers' seeded catalog at the next boot; live
|
|
9
|
+
* discovery will still find it, which is the intended prune.
|
|
9
10
|
*
|
|
10
11
|
* The limits, modalities and capability flags are read from OpenRouter's own
|
|
11
12
|
* `/api/v1/models`, which states `context_length`,
|
|
@@ -13,6 +14,10 @@
|
|
|
13
14
|
* `supported_parameters`. That is the serving catalog's declaration, so these
|
|
14
15
|
* are measurements rather than defaults.
|
|
15
16
|
*
|
|
17
|
+
* The set is curated: a 2.6B toy (`liquid/lfm-2.5-2.6b:free`) and the
|
|
18
|
+
* upstream content-safety classifier (`nvidia/nemotron-3.5-content-safety:free`)
|
|
19
|
+
* are deliberately not seeded — a prefill classifier is not a chat model.
|
|
20
|
+
*
|
|
16
21
|
* This is a floor, not the authority: each provider also discovers live, and a
|
|
17
22
|
* row the listing carries that this roster does not is still found there. The
|
|
18
23
|
* roster exists so a fresh install has a usable free tier before any fetch, and
|
|
@@ -32,15 +37,16 @@ interface FreeRow {
|
|
|
32
37
|
readonly ctx: number;
|
|
33
38
|
readonly out: number;
|
|
34
39
|
readonly vision?: boolean;
|
|
35
|
-
/** `supported_parameters` omits `tools
|
|
40
|
+
/** `false` only when `supported_parameters` omits `tools`. */
|
|
36
41
|
readonly toolCall?: boolean;
|
|
37
42
|
}
|
|
38
43
|
|
|
39
44
|
/**
|
|
40
|
-
* The
|
|
45
|
+
* The shared `:free` ids still worth seeding, with the limits the catalog
|
|
46
|
+
* states for each.
|
|
41
47
|
*
|
|
42
|
-
* Every row declares `reasoning`: `supported_parameters` lists it on
|
|
43
|
-
*
|
|
48
|
+
* Every row declares `reasoning`: `supported_parameters` lists it on every
|
|
49
|
+
* entry. `toolCall` is `true` unless stated otherwise, because a row that
|
|
44
50
|
* advertises tools must keep them — a false `toolCall` makes the preflight
|
|
45
51
|
* strip `tools` from the request, which is a wrong capability rather than a
|
|
46
52
|
* conservative one.
|
|
@@ -48,7 +54,6 @@ interface FreeRow {
|
|
|
48
54
|
const FREE_ROWS: readonly FreeRow[] = [
|
|
49
55
|
{ id: "cohere/north-mini-code:free", ctx: 256_000, out: 64_000 },
|
|
50
56
|
{ id: "dots-studio/dots-3-note-preview:free", ctx: 512_000, out: 460_800, vision: true },
|
|
51
|
-
{ id: "liquid/lfm-2.5-2.6b:free", ctx: 65_536, out: 8_192 },
|
|
52
57
|
{ id: "minimax/minimax-m3.1-flash:free", ctx: 1_000_000, out: 524_288, vision: true },
|
|
53
58
|
{
|
|
54
59
|
id: "nvidia/nemotron-3-nano-omni-30b-a3b-reasoning:free",
|
|
@@ -57,13 +62,6 @@ const FREE_ROWS: readonly FreeRow[] = [
|
|
|
57
62
|
vision: true,
|
|
58
63
|
},
|
|
59
64
|
{ id: "nvidia/nemotron-3-ultra-550b-a55b:free", ctx: 1_000_000, out: 65_536 },
|
|
60
|
-
{
|
|
61
|
-
id: "nvidia/nemotron-3.5-content-safety:free",
|
|
62
|
-
ctx: 128_000,
|
|
63
|
-
out: 8_192,
|
|
64
|
-
vision: true,
|
|
65
|
-
toolCall: false,
|
|
66
|
-
},
|
|
67
65
|
{ id: "nvidia/nemotron-3.5-lightning:free", ctx: 1_000_000, out: 65_536 },
|
|
68
66
|
{ id: "nvidia/nemotron-3.5-super-vl:free", ctx: 1_000_000, out: 131_072, vision: true },
|
|
69
67
|
];
|
|
@@ -189,12 +189,20 @@ function parseModelQuotas(payload: Record<string, unknown>): ProviderQuotaWindow
|
|
|
189
189
|
const family = modelFamily(collapseAntigravityVariant(modelId));
|
|
190
190
|
const familyLabel = FAMILY_LABELS[family.key] ?? family.label;
|
|
191
191
|
for (const entry of modelQuotaEntries(model)) {
|
|
192
|
-
|
|
193
|
-
|
|
192
|
+
// A bucket with no fraction but a reset time is exhausted, not unknown:
|
|
193
|
+
// the upstream omits the field when there is nothing left to report, so
|
|
194
|
+
// dropping it let a healthy sibling window mask a lane that is blocked
|
|
195
|
+
// until reset. Only a bucket with neither signal is genuinely unknown.
|
|
196
|
+
// This matches what the summary path already does for a disabled bucket.
|
|
197
|
+
const reported = number(entry.info.remainingFraction);
|
|
198
|
+
const resetAt = isoDate(entry.info.resetTime);
|
|
199
|
+
const exhausted = reported === null && resetAt !== null;
|
|
200
|
+
if (reported === null && !exhausted) continue;
|
|
201
|
+
const fraction = reported ?? 0;
|
|
194
202
|
const kind = entry.kind ?? summaryWindowKind(entry.info);
|
|
195
203
|
const label = kind === undefined ? familyLabel : `${familyLabel} (${SUMMARY_WINDOW_LABELS[kind]})`;
|
|
196
204
|
const key = `${family.key}:${kind ?? "model"}`;
|
|
197
|
-
const window = fractionWindow(key, label, fraction,
|
|
205
|
+
const window = fractionWindow(key, label, fraction, resetAt);
|
|
198
206
|
grouped.set(key, keepWorse(grouped.get(key), window));
|
|
199
207
|
}
|
|
200
208
|
}
|
|
@@ -257,8 +257,8 @@ export const BUDDY_SHARED_RAW: readonly BuddyRawEntry[] = [
|
|
|
257
257
|
["claude-opus-4.6", "Claude Opus 4.6", true, true, 200_000, 64_000],
|
|
258
258
|
["claude-opus-4.7-1m", "Claude Opus 4.7 1M", true, true, 1_000_000, 64_000],
|
|
259
259
|
["claude-sonnet-4.6", "Claude Sonnet 4.6", true, true, 200_000, 32_000],
|
|
260
|
-
["deepseek-v4.1-flash", "DeepSeek V4.1 Flash", true,
|
|
261
|
-
["deepseek-v4.1-flash-sg", "DeepSeek V4.1 Flash SG", true,
|
|
260
|
+
["deepseek-v4.1-flash", "DeepSeek V4.1 Flash", true, true, 1_000_000, 384_000],
|
|
261
|
+
["deepseek-v4.1-flash-sg", "DeepSeek V4.1 Flash SG", true, true, 1_000_000, 128_000],
|
|
262
262
|
["deepseek-v4.1-pro", "DeepSeek V4.1 Pro", true, false, 1_000_000, 384_000],
|
|
263
263
|
["gemini-2.5-flash-image", "Gemini 2.5 Flash Image", true, true, 1_000_000, 64_000],
|
|
264
264
|
["gemini-3.0-pro-image", "Gemini 3.0 Pro Image", true, true, 1_000_000, 64_000],
|
|
@@ -286,8 +286,8 @@ export const BUDDY_SHARED_RAW: readonly BuddyRawEntry[] = [
|
|
|
286
286
|
["grok-4.7", "Grok 4.7", true, true, 500_000, 500_000],
|
|
287
287
|
["hy3", "Hy3", true, false, 192_000, 64_000, true],
|
|
288
288
|
["hy3-preview", "Hy3 Preview", true, false, 262_144, 64_000],
|
|
289
|
-
["hy4-preview", "Hy4 Preview", true,
|
|
290
|
-
["hy4-preview-f", "Hy4 Preview F", true,
|
|
289
|
+
["hy4-preview", "Hy4 Preview", true, true, 1_000_000, 64_000, true],
|
|
290
|
+
["hy4-preview-f", "Hy4 Preview F", true, true, 1_000_000, 64_000, true],
|
|
291
291
|
["kimi-k2.5", "Kimi K2.5", true, false, 164_000, 262_144],
|
|
292
292
|
["kimi-k2.6", "Kimi K2.6", true, false, 256_000, 262_144],
|
|
293
293
|
["kimi-k2.7", "Kimi K2.7", true, false, 256_000, 65_536],
|
|
@@ -1,200 +1,201 @@
|
|
|
1
|
-
import { createHash } from "node:crypto";
|
|
2
|
-
import { readFileSync } from "node:fs";
|
|
3
|
-
|
|
4
|
-
import type { OpenAICompatibleAdapterConfig } from "../../../adapters/compatible-adapter";
|
|
5
|
-
import { withBearerAuthentication } from "../../../adapters/compatible-adapter";
|
|
6
|
-
import type { CanonicalRequest } from "../../../../protocol/canonical-model";
|
|
7
|
-
import type { ProviderDispatchContext, ProviderDispatchTarget, ProviderId } from "../../../provider-contracts";
|
|
8
|
-
import { resolveInboundSessionId } from "../../../operations/session-resolution";
|
|
9
|
-
import { buddyConversationHeaders } from "../buddy-conversation-headers";
|
|
10
|
-
import { buddyCliHeaders, buddyCliTraceHeaders } from "../buddy-cli-headers";
|
|
11
|
-
import { buddyUserId, resolveBuddyIdentity } from "../buddy-identity";
|
|
12
|
-
import {
|
|
13
|
-
buildWorkBuddyUserAgent,
|
|
14
|
-
getWorkBuddyClientVersion,
|
|
15
|
-
getWorkBuddyCliVersion,
|
|
16
|
-
} from "../../../operations/client-versions";
|
|
17
|
-
|
|
18
|
-
/**
|
|
19
|
-
* WorkBuddy serves chat from a versioned path on a base URL that carries no
|
|
20
|
-
* version segment (billing uses the unversioned `/billing/…` path), so both the
|
|
21
|
-
* adapter config and the static catalog rows must state it. The generic
|
|
22
|
-
* `/chat/completions` default would join into
|
|
23
|
-
* `https://www.workbuddy.ai/chat/completions`, which that upstream answers with
|
|
24
|
-
* a 405 HTML error page.
|
|
25
|
-
*/
|
|
26
|
-
export const WORKBUDDY_CHAT_PATH = "/v2/chat/completions" as const;
|
|
27
|
-
|
|
28
|
-
export {
|
|
29
|
-
buildWorkBuddyUserAgent,
|
|
30
|
-
getWorkBuddyClientVersion,
|
|
31
|
-
getWorkBuddyCliVersion,
|
|
32
|
-
};
|
|
33
|
-
|
|
34
|
-
/** WorkBuddy international gateway domain (Origin/Referer/X-Domain). */
|
|
35
|
-
export const WORKBUDDY_DOMAIN = "www.workbuddy.ai";
|
|
36
|
-
|
|
37
|
-
/**
|
|
38
|
-
* Stable per-account device identifiers.
|
|
39
|
-
*
|
|
40
|
-
* WorkBuddy's desktop client presents one fixed virtual device per account.
|
|
41
|
-
* Deriving `X-Machine-ID` / `X-Session-ID` from the account id (sha256, 36 hex)
|
|
42
|
-
* keeps them constant across restarts while staying distinct per account, so
|
|
43
|
-
* multiple pooled accounts are not correlated by a missing or drifting device
|
|
44
|
-
* fingerprint. Mirrors the reference gateway's `wb2a:<purpose>:<uid>` scheme.
|
|
45
|
-
*/
|
|
46
|
-
function deriveAccountStableId(accountId: string, purpose: string): string {
|
|
47
|
-
const sum = createHash("sha256").update(`wb2a:${purpose}:${accountId}`).digest("hex");
|
|
48
|
-
return sum.slice(0, 36);
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
/**
|
|
52
|
-
* Per-request WorkBuddy chat headers — the exact desktop-client contract.
|
|
53
|
-
*
|
|
54
|
-
* The international gateway gates chat on the desktop `User-Agent` (platform
|
|
55
|
-
* brand `WorkBuddy AI
|
|
56
|
-
* `X-CodeBuddy-Request` risk
|
|
57
|
-
*
|
|
58
|
-
*
|
|
59
|
-
*
|
|
60
|
-
*
|
|
61
|
-
*
|
|
62
|
-
*
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
//
|
|
80
|
-
//
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
"
|
|
84
|
-
"
|
|
85
|
-
"x-
|
|
86
|
-
"x-
|
|
87
|
-
"x-ide-
|
|
88
|
-
"x-ide-
|
|
89
|
-
"x-
|
|
90
|
-
"x-
|
|
91
|
-
|
|
92
|
-
...
|
|
93
|
-
...
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
"
|
|
103
|
-
"x-
|
|
104
|
-
"x-
|
|
105
|
-
"x-
|
|
106
|
-
"x-
|
|
107
|
-
"x-ide-
|
|
108
|
-
"x-ide-
|
|
109
|
-
|
|
110
|
-
//
|
|
111
|
-
//
|
|
112
|
-
//
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
//
|
|
116
|
-
//
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
//
|
|
121
|
-
//
|
|
122
|
-
//
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
headers["x-
|
|
127
|
-
headers["x-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
*
|
|
137
|
-
*
|
|
138
|
-
*
|
|
139
|
-
*
|
|
140
|
-
*
|
|
141
|
-
*
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
const
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
const
|
|
150
|
-
|
|
151
|
-
return
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
*
|
|
177
|
-
*
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
}
|
|
1
|
+
import { createHash } from "node:crypto";
|
|
2
|
+
import { readFileSync } from "node:fs";
|
|
3
|
+
|
|
4
|
+
import type { OpenAICompatibleAdapterConfig } from "../../../adapters/compatible-adapter";
|
|
5
|
+
import { withBearerAuthentication } from "../../../adapters/compatible-adapter";
|
|
6
|
+
import type { CanonicalRequest } from "../../../../protocol/canonical-model";
|
|
7
|
+
import type { ProviderDispatchContext, ProviderDispatchTarget, ProviderId } from "../../../provider-contracts";
|
|
8
|
+
import { resolveInboundSessionId } from "../../../operations/session-resolution";
|
|
9
|
+
import { buddyConversationHeaders } from "../buddy-conversation-headers";
|
|
10
|
+
import { buddyCliHeaders, buddyCliTraceHeaders } from "../buddy-cli-headers";
|
|
11
|
+
import { buddyUserId, resolveBuddyIdentity } from "../buddy-identity";
|
|
12
|
+
import {
|
|
13
|
+
buildWorkBuddyUserAgent,
|
|
14
|
+
getWorkBuddyClientVersion,
|
|
15
|
+
getWorkBuddyCliVersion,
|
|
16
|
+
} from "../../../operations/client-versions";
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* WorkBuddy serves chat from a versioned path on a base URL that carries no
|
|
20
|
+
* version segment (billing uses the unversioned `/billing/…` path), so both the
|
|
21
|
+
* adapter config and the static catalog rows must state it. The generic
|
|
22
|
+
* `/chat/completions` default would join into
|
|
23
|
+
* `https://www.workbuddy.ai/chat/completions`, which that upstream answers with
|
|
24
|
+
* a 405 HTML error page.
|
|
25
|
+
*/
|
|
26
|
+
export const WORKBUDDY_CHAT_PATH = "/v2/chat/completions" as const;
|
|
27
|
+
|
|
28
|
+
export {
|
|
29
|
+
buildWorkBuddyUserAgent,
|
|
30
|
+
getWorkBuddyClientVersion,
|
|
31
|
+
getWorkBuddyCliVersion,
|
|
32
|
+
};
|
|
33
|
+
|
|
34
|
+
/** WorkBuddy international gateway domain (Origin/Referer/X-Domain). */
|
|
35
|
+
export const WORKBUDDY_DOMAIN = "www.workbuddy.ai";
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* Stable per-account device identifiers.
|
|
39
|
+
*
|
|
40
|
+
* WorkBuddy's desktop client presents one fixed virtual device per account.
|
|
41
|
+
* Deriving `X-Machine-ID` / `X-Session-ID` from the account id (sha256, 36 hex)
|
|
42
|
+
* keeps them constant across restarts while staying distinct per account, so
|
|
43
|
+
* multiple pooled accounts are not correlated by a missing or drifting device
|
|
44
|
+
* fingerprint. Mirrors the reference gateway's `wb2a:<purpose>:<uid>` scheme.
|
|
45
|
+
*/
|
|
46
|
+
function deriveAccountStableId(accountId: string, purpose: string): string {
|
|
47
|
+
const sum = createHash("sha256").update(`wb2a:${purpose}:${accountId}`).digest("hex");
|
|
48
|
+
return sum.slice(0, 36);
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
/**
|
|
52
|
+
* Per-request WorkBuddy chat headers — the exact desktop-client contract.
|
|
53
|
+
*
|
|
54
|
+
* The international gateway gates chat on the desktop `User-Agent` (platform
|
|
55
|
+
* brand `WorkBuddy AI`, carried on the wire as the token `workbuddy-ai`;
|
|
56
|
+
* the wrong token trips 403 code 11140), plus the `X-CodeBuddy-Request` risk
|
|
57
|
+
* gate and the account-scoped device headers.
|
|
58
|
+
* The background client-version monitor keeps this value fresh; dispatch only
|
|
59
|
+
* reads the cached value and never waits on a version endpoint.
|
|
60
|
+
*
|
|
61
|
+
* `cliIdentity` selects the reference CLI contract instead. The two are not
|
|
62
|
+
* variations of one set: the CLI drops every browser header and the device
|
|
63
|
+
* token, and adds the agent envelope. Left unset, nothing changes.
|
|
64
|
+
*/
|
|
65
|
+
export async function workbuddyHeaders(
|
|
66
|
+
context?: ProviderDispatchContext,
|
|
67
|
+
request?: CanonicalRequest,
|
|
68
|
+
domain = WORKBUDDY_DOMAIN,
|
|
69
|
+
clientVersion = getWorkBuddyClientVersion(),
|
|
70
|
+
cliIdentity?: boolean,
|
|
71
|
+
): Promise<Record<string, string>> {
|
|
72
|
+
const conversation = buddyConversationHeaders({
|
|
73
|
+
...(resolveInboundSessionId(context, request) === undefined
|
|
74
|
+
? {}
|
|
75
|
+
: { conversationId: resolveInboundSessionId(context, request) }),
|
|
76
|
+
});
|
|
77
|
+
const accountId = context?.credential.account_id;
|
|
78
|
+
if (resolveBuddyIdentity(context, cliIdentity) === "cli") {
|
|
79
|
+
// The reference CLI: issued by the OpenAI Node SDK, so no browser header
|
|
80
|
+
// and no device token, and the machine/session device pair does not
|
|
81
|
+
// exist — only `X-User-Id`, which is `anonymous` without a uid.
|
|
82
|
+
return {
|
|
83
|
+
accept: "application/json",
|
|
84
|
+
"user-agent": `CLI/${getWorkBuddyCliVersion()} CodeBuddy/${getWorkBuddyCliVersion()}`,
|
|
85
|
+
"x-domain": domain,
|
|
86
|
+
"x-agent-purpose": "conversation",
|
|
87
|
+
"x-ide-name": "CLI",
|
|
88
|
+
"x-ide-type": "CLI",
|
|
89
|
+
"x-ide-version": getWorkBuddyCliVersion(),
|
|
90
|
+
"x-product": "SaaS",
|
|
91
|
+
"x-no-enterprise-id": "1",
|
|
92
|
+
...conversation,
|
|
93
|
+
...buddyCliTraceHeaders(conversation),
|
|
94
|
+
...buddyCliHeaders({ userId: buddyUserId(context) }),
|
|
95
|
+
};
|
|
96
|
+
}
|
|
97
|
+
const headers: Record<string, string> = {
|
|
98
|
+
accept: "application/json, text/event-stream",
|
|
99
|
+
"user-agent": buildWorkBuddyUserAgent(clientVersion, getWorkBuddyCliVersion()),
|
|
100
|
+
origin: `https://${domain}`,
|
|
101
|
+
referer: `https://${domain}/`,
|
|
102
|
+
"accept-language": "en-US",
|
|
103
|
+
"x-requested-with": "XMLHttpRequest",
|
|
104
|
+
"x-codebuddy-request": "1",
|
|
105
|
+
"x-domain": domain,
|
|
106
|
+
"x-agent-purpose": "conversation",
|
|
107
|
+
"x-ide-name": "WorkBuddy",
|
|
108
|
+
"x-ide-type": "WorkBuddy",
|
|
109
|
+
"x-ide-version": clientVersion,
|
|
110
|
+
// Both references send the literal `SaaS` here. `WorkBuddy` was a value
|
|
111
|
+
// this repo invented; the desktop product name belongs in `x-ide-name`,
|
|
112
|
+
// and the CN test below compares the two realms against each other rather
|
|
113
|
+
// than to a hard-coded string.
|
|
114
|
+
"x-product": "SaaS",
|
|
115
|
+
// Personal international accounts carry no enterprise id: declare it
|
|
116
|
+
// explicitly so upstream risk control does not treat the omission as
|
|
117
|
+
// suspicious.
|
|
118
|
+
"x-no-enterprise-id": "1",
|
|
119
|
+
};
|
|
120
|
+
// The conversation/tracing family the upstream's channel check looks for. A
|
|
121
|
+
// live request carrying only `x-session-id` was refused for a missing
|
|
122
|
+
// conversation id; the aggregation key below is the one the reference marks
|
|
123
|
+
// mandatory.
|
|
124
|
+
Object.assign(headers, conversation);
|
|
125
|
+
if (accountId) {
|
|
126
|
+
headers["x-user-id"] = accountId;
|
|
127
|
+
headers["x-machine-id"] = deriveAccountStableId(accountId, "machine");
|
|
128
|
+
headers["x-session-id"] = deriveAccountStableId(accountId, "session");
|
|
129
|
+
}
|
|
130
|
+
const deviceToken = readBuddyDeviceToken(context);
|
|
131
|
+
if (deviceToken !== undefined) headers["x-device-token"] = deviceToken;
|
|
132
|
+
return headers;
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
/**
|
|
136
|
+
* Desktop risk token, sent only when the account actually has one.
|
|
137
|
+
*
|
|
138
|
+
* The account's own `auth_state` wins. When it carries none, a file the
|
|
139
|
+
* desktop client writes (`CARTETHYIA_DEVICE_TOKEN_FILE`, default
|
|
140
|
+
* `/app/data/device_token`) is read instead — cached for five minutes, and
|
|
141
|
+
* ignored when it is larger than 1 KB, because a token file that size is not
|
|
142
|
+
* a token. A missing file is the normal case and reads as "no token".
|
|
143
|
+
*/
|
|
144
|
+
const DEVICE_TOKEN_FILE_MAX_BYTES = 1024;
|
|
145
|
+
const DEVICE_TOKEN_FILE_TTL_MS = 5 * 60_000;
|
|
146
|
+
let deviceTokenFileCache: { readonly value: string | undefined; readonly readAt: number } | undefined;
|
|
147
|
+
|
|
148
|
+
export function readBuddyDeviceToken(context?: ProviderDispatchContext): string | undefined {
|
|
149
|
+
const state = context?.credential.auth_state;
|
|
150
|
+
const value = state?.["deviceToken"] ?? state?.["device_token"];
|
|
151
|
+
if (typeof value === "string" && value.trim().length > 0) return value.trim();
|
|
152
|
+
return readDeviceTokenFile();
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
function readDeviceTokenFile(): string | undefined {
|
|
156
|
+
const now = Date.now();
|
|
157
|
+
if (deviceTokenFileCache !== undefined && now - deviceTokenFileCache.readAt < DEVICE_TOKEN_FILE_TTL_MS) {
|
|
158
|
+
return deviceTokenFileCache.value;
|
|
159
|
+
}
|
|
160
|
+
const path = process.env["CARTETHYIA_DEVICE_TOKEN_FILE"] ?? "/app/data/device_token";
|
|
161
|
+
let value: string | undefined;
|
|
162
|
+
try {
|
|
163
|
+
const raw = readFileSync(path);
|
|
164
|
+
if (raw.byteLength > 0 && raw.byteLength <= DEVICE_TOKEN_FILE_MAX_BYTES) {
|
|
165
|
+
const text = raw.toString("utf8").trim();
|
|
166
|
+
if (text.length > 0) value = text;
|
|
167
|
+
}
|
|
168
|
+
} catch {
|
|
169
|
+
value = undefined;
|
|
170
|
+
}
|
|
171
|
+
deviceTokenFileCache = { value, readAt: now };
|
|
172
|
+
return value;
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
/**
|
|
176
|
+
* Shared OpenAI-compatible chat-adapter config for WorkBuddy: bearer auth
|
|
177
|
+
* (api_key and oauth both use `Authorization: Bearer`), `/v2/chat/completions`
|
|
178
|
+
* endpoint, per-request desktop-client headers, and the payload hook.
|
|
179
|
+
*/
|
|
180
|
+
export function workbuddyAdapterConfig(args: {
|
|
181
|
+
providerId: ProviderId;
|
|
182
|
+
baseUrl: string;
|
|
183
|
+
domain?: string;
|
|
184
|
+
prePayload: (
|
|
185
|
+
payload: Record<string, unknown>,
|
|
186
|
+
request: CanonicalRequest,
|
|
187
|
+
candidate: ProviderDispatchTarget,
|
|
188
|
+
) => void;
|
|
189
|
+
fetchImpl?: typeof fetch;
|
|
190
|
+
cliIdentity?: boolean;
|
|
191
|
+
}): OpenAICompatibleAdapterConfig {
|
|
192
|
+
return withBearerAuthentication({
|
|
193
|
+
provider_id: args.providerId,
|
|
194
|
+
base_url: args.baseUrl,
|
|
195
|
+
endpoint_paths_by_wire_family: { chat: WORKBUDDY_CHAT_PATH },
|
|
196
|
+
buildExtraHeaders: (context, request) =>
|
|
197
|
+
workbuddyHeaders(context, request, args.domain ?? WORKBUDDY_DOMAIN, undefined, args.cliIdentity),
|
|
198
|
+
prePayload: args.prePayload,
|
|
199
|
+
...(args.fetchImpl ? { fetchImpl: args.fetchImpl } : {}),
|
|
200
|
+
});
|
|
201
|
+
}
|