cartethyia 2.7.5 → 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 +4 -1
- package/README.md +1 -1
- 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-D5rol2j2.js → ConsoleLogPage-KRYjHZsX.js} +1 -1
- 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-B5nZvmf0.js → InjectSystemPromptPanel-d5v3K_Yc.js} +245 -2
- 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-DnQPSIA8.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-5SnUSy3j.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-BJtRZ4qD.js → SettingsPage-BW4AKj2H.js} +1 -1
- 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-BfAb5-o_.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-BNzeZ2Vk.js → UsagePage-B7M7LvMM.js} +13 -13
- 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-C0K-c4eo.js → assert-CidQVoNo.js} +1 -1
- package/dist/dashboard/assets/assert-CidQVoNo.js.gz +0 -0
- package/dist/dashboard/assets/{badge-DfbhQU4k.js → badge-BaX2GTrn.js} +1 -1
- package/dist/dashboard/assets/badge-BaX2GTrn.js.gz +0 -0
- package/dist/dashboard/assets/{banner-BllT4LcF.js → banner-DFH4Bkte.js} +1 -1
- package/dist/dashboard/assets/banner-DFH4Bkte.js.gz +0 -0
- package/dist/dashboard/assets/{card-CtkX66Wd.js → card-CxDw0lK6.js} +1 -1
- package/dist/dashboard/assets/card-CxDw0lK6.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-CQXVMn4P.js → cli-tools-Bwv5-zGZ.js} +1 -1
- package/dist/dashboard/assets/cli-tools-Bwv5-zGZ.js.gz +0 -0
- package/dist/dashboard/assets/{clipboard-button-BQqBQd2n.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-BrTEZ8zu.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-BAACA727.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-FQlj0HUT.js → index-Ko4dLRnV.js} +2 -2
- package/dist/dashboard/assets/index-Ko4dLRnV.js.gz +0 -0
- package/dist/dashboard/assets/{inline-C4gU5iOL.js → inline-CHJQwxLa.js} +1 -1
- package/dist/dashboard/assets/inline-CHJQwxLa.js.gz +0 -0
- package/dist/dashboard/assets/{input-BHHX_Tmm.js → input-BlmlizVV.js} +1 -1
- package/dist/dashboard/assets/input-BlmlizVV.js.gz +0 -0
- package/dist/dashboard/assets/{layout-CajrYUnD.js → layout-Bz93I-yE.js} +1 -1
- package/dist/dashboard/assets/layout-Bz93I-yE.js.gz +0 -0
- package/dist/dashboard/assets/{list-row-Bx2I7XUe.js → list-row-Ml16KCfu.js} +1 -1
- package/dist/dashboard/assets/list-row-Ml16KCfu.js.gz +0 -0
- package/dist/dashboard/assets/{live-DNNqRbj2.js → live-7_QpnYGu.js} +1 -1
- 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-C5UBACrJ.js → network-CuMDaTzT.js} +1 -1
- 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-Xsi9Qx04.js → pagination-B5aOoweZ.js} +1 -1
- 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-in0f_IfK.js → routing-fnCsxgNO.js} +1 -1
- package/dist/dashboard/assets/routing-fnCsxgNO.js.gz +0 -0
- package/dist/dashboard/assets/{select-BLULNqTp.js → select-BHqpd-bg.js} +2 -2
- package/dist/dashboard/assets/select-BHqpd-bg.js.gz +0 -0
- package/dist/dashboard/assets/{settings-CcGczj6I.js → settings-BxslsErn.js} +1 -1
- package/dist/dashboard/assets/settings-BxslsErn.js.gz +0 -0
- package/dist/dashboard/assets/{stack-D2lIR0tg.js → stack-j7cXjgYX.js} +1 -1
- package/dist/dashboard/assets/stack-j7cXjgYX.js.gz +0 -0
- package/dist/dashboard/assets/{state-DTARjfiW.js → state-DHmEnLa2.js} +1 -1
- package/dist/dashboard/assets/state-DHmEnLa2.js.gz +0 -0
- package/dist/dashboard/assets/{switch-c0oPSnqW.js → switch-DmZcyTIC.js} +1 -1
- package/dist/dashboard/assets/switch-DmZcyTIC.js.gz +0 -0
- package/dist/dashboard/assets/{useMutation-m8WGNPrz.js → useMutation-CbCP4w1o.js} +1 -1
- package/dist/dashboard/assets/useMutation-CbCP4w1o.js.gz +0 -0
- package/dist/dashboard/index.html +2 -2
- package/dist/dashboard/index.html.gz +0 -0
- package/dist/dashboard/precompressed-assets.json +57 -57
- package/migrations/full-postgres/0042_add_telemetry_degenerate_stop.sql +14 -0
- package/migrations/lite-sqlite3/0042_add_telemetry_degenerate_stop.sql +12 -0
- package/package.json +1 -1
- package/src/boot/dependencies.ts +10 -2
- package/src/config/providers.ts +13 -7
- package/src/config/spec.ts +18 -11
- package/src/config/usage.ts +27 -0
- package/src/console/api-keys/routes.ts +19 -23
- package/src/console/cli-tools/contracts.ts +39 -295
- 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 +6 -6
- package/src/console/cli-tools/injectors/driver.ts +8 -105
- package/src/console/cli-tools/injectors/kilo.ts +146 -21
- package/src/console/cli-tools/injectors/opencode.ts +28 -5
- package/src/console/cli-tools/routes.ts +6 -0
- package/src/console/cli-tools/service.ts +7 -6
- package/src/console/observability/contracts.ts +6 -0
- package/src/console/observability/store.ts +3 -0
- package/src/console/share/share-stats.ts +7 -9
- package/src/observability/event-log.ts +7 -0
- package/src/observability/event-query.ts +2 -0
- package/src/observability/telemetry-buffer.ts +7 -0
- package/src/persistence/schema.ts +8 -0
- package/src/persistence/stores/api-key-store.ts +19 -1
- package/src/protocol/dsml.ts +5 -76
- package/src/providers/adapters/compatible-adapter.ts +29 -1
- package/src/providers/default-registry.ts +12 -2
- package/src/providers/integrations/antigravity/antigravity-protocol.ts +88 -14
- package/src/providers/integrations/antigravity/antigravity-quota.ts +18 -6
- package/src/providers/integrations/antigravity/antigravity.ts +20 -11
- package/src/providers/integrations/cursor/cursor.ts +2 -3
- package/src/providers/integrations/github/github-discovery.ts +15 -2
- package/src/providers/integrations/github/github-oauth.ts +178 -9
- package/src/providers/integrations/github/github.ts +95 -14
- package/src/providers/integrations/kiro/kiro.ts +1 -2
- package/src/providers/integrations/qoder/qoder-catalog.ts +9 -3
- package/src/providers/integrations/qoder/qoder.ts +147 -88
- package/src/providers/integrations/trae/trae.ts +2 -2
- package/src/providers/operations/account-error-classification.ts +67 -17
- package/src/providers/operations/byok-wire-profile.ts +19 -15
- package/src/providers/provider-usage.ts +15 -49
- package/src/security/admission/service.ts +11 -4
- package/src/security/api-key-auth.ts +5 -3
- package/src/transport/dispatch/attempt-finalize.ts +69 -21
- package/src/transport/dispatch/attempt-loop.ts +22 -0
- package/src/transport/failure-policy.ts +15 -1
- package/src/transport/guards/error-lifecycle.ts +4 -0
- package/src/transport/request/state.ts +6 -0
- package/src/transport/routing/router.ts +7 -0
- package/src/transport/surface/reasoning-summary.ts +9 -14
- package/src/transport/vision-handoff.ts +83 -28
- package/dist/dashboard/assets/BannedPage-Cj15GsMp.js +0 -1
- package/dist/dashboard/assets/BannedPage-Cj15GsMp.js.gz +0 -0
- package/dist/dashboard/assets/ClaimGiftsButton-D83pBJ6J.js +0 -1
- package/dist/dashboard/assets/ClaimGiftsButton-D83pBJ6J.js.gz +0 -0
- package/dist/dashboard/assets/CliToolDetailPage-DZKmVuJN.js +0 -1
- package/dist/dashboard/assets/CliToolDetailPage-DZKmVuJN.js.gz +0 -0
- package/dist/dashboard/assets/CliToolsPage-BIccZmeL.js +0 -1
- package/dist/dashboard/assets/CliToolsPage-BIccZmeL.js.gz +0 -0
- package/dist/dashboard/assets/CombosPage-DEEKkYD-.js +0 -1
- package/dist/dashboard/assets/CombosPage-DEEKkYD-.js.gz +0 -0
- package/dist/dashboard/assets/ConsoleLogPage-D5rol2j2.js.gz +0 -0
- package/dist/dashboard/assets/CustomizationPage-BKj_r0rp.js +0 -1
- package/dist/dashboard/assets/CustomizationPage-BKj_r0rp.js.gz +0 -0
- package/dist/dashboard/assets/InjectSystemPromptPanel-B5nZvmf0.js.gz +0 -0
- package/dist/dashboard/assets/LoginPage-DkXb6dx-.js +0 -1
- package/dist/dashboard/assets/LoginPage-DkXb6dx-.js.gz +0 -0
- package/dist/dashboard/assets/ModelPicker-DnQPSIA8.js.gz +0 -0
- package/dist/dashboard/assets/OverviewPage-Ci2wQKUz.js +0 -1
- package/dist/dashboard/assets/OverviewPage-Ci2wQKUz.js.gz +0 -0
- package/dist/dashboard/assets/ProviderDetailPage-odlgYrOg.js +0 -5
- package/dist/dashboard/assets/ProviderDetailPage-odlgYrOg.js.gz +0 -0
- package/dist/dashboard/assets/ProviderIcon-EfeloBn4.js +0 -1
- package/dist/dashboard/assets/ProviderIcon-EfeloBn4.js.gz +0 -0
- package/dist/dashboard/assets/ProvidersPage-CqFBQEB8.js +0 -1
- package/dist/dashboard/assets/ProvidersPage-CqFBQEB8.js.gz +0 -0
- package/dist/dashboard/assets/ProxyPage-5SnUSy3j.js.gz +0 -0
- package/dist/dashboard/assets/QuotaPage-CmnMDzhP.js +0 -1
- package/dist/dashboard/assets/QuotaPage-CmnMDzhP.js.gz +0 -0
- package/dist/dashboard/assets/SettingsPage-BJtRZ4qD.js.gz +0 -0
- package/dist/dashboard/assets/SetupPage-WTa0sktC.js +0 -1
- package/dist/dashboard/assets/SetupPage-WTa0sktC.js.gz +0 -0
- package/dist/dashboard/assets/StudioPage-BfAb5-o_.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-BNzeZ2Vk.js.gz +0 -0
- package/dist/dashboard/assets/api-keys-l29JROPv.js +0 -1
- package/dist/dashboard/assets/api-keys-l29JROPv.js.gz +0 -0
- package/dist/dashboard/assets/app--PJWq8_C.css +0 -2
- package/dist/dashboard/assets/app--PJWq8_C.css.gz +0 -0
- package/dist/dashboard/assets/app-Bgd3zANQ.js +0 -9
- package/dist/dashboard/assets/app-Bgd3zANQ.js.gz +0 -0
- package/dist/dashboard/assets/assert-C0K-c4eo.js.gz +0 -0
- package/dist/dashboard/assets/badge-DfbhQU4k.js.gz +0 -0
- package/dist/dashboard/assets/banner-BllT4LcF.js.gz +0 -0
- package/dist/dashboard/assets/card-CtkX66Wd.js.gz +0 -0
- package/dist/dashboard/assets/cli-tools-CQXVMn4P.js.gz +0 -0
- package/dist/dashboard/assets/clipboard-button-BQqBQd2n.js.gz +0 -0
- package/dist/dashboard/assets/dialog-BEK7KP0H.js +0 -1
- package/dist/dashboard/assets/dialog-BEK7KP0H.js.gz +0 -0
- package/dist/dashboard/assets/drawer-BrTEZ8zu.js.gz +0 -0
- package/dist/dashboard/assets/entry-CHWxbS56.js +0 -1
- package/dist/dashboard/assets/entry-CHWxbS56.js.gz +0 -0
- package/dist/dashboard/assets/entry-EBHJ3DrE.js +0 -1
- package/dist/dashboard/assets/entry-EBHJ3DrE.js.gz +0 -0
- package/dist/dashboard/assets/entry-LCS85hiq.js +0 -4
- package/dist/dashboard/assets/entry-LCS85hiq.js.gz +0 -0
- package/dist/dashboard/assets/formatters-BAACA727.js.gz +0 -0
- package/dist/dashboard/assets/github-badge-YSCE4UC2.js +0 -1
- package/dist/dashboard/assets/github-badge-YSCE4UC2.js.gz +0 -0
- package/dist/dashboard/assets/index-FQlj0HUT.js.gz +0 -0
- package/dist/dashboard/assets/inline-C4gU5iOL.js.gz +0 -0
- package/dist/dashboard/assets/input-BHHX_Tmm.js.gz +0 -0
- package/dist/dashboard/assets/layout-CajrYUnD.js.gz +0 -0
- package/dist/dashboard/assets/list-row-Bx2I7XUe.js.gz +0 -0
- package/dist/dashboard/assets/live-DNNqRbj2.js.gz +0 -0
- package/dist/dashboard/assets/mutation-Rr0TIvcj.js.gz +0 -0
- package/dist/dashboard/assets/network-C5UBACrJ.js.gz +0 -0
- package/dist/dashboard/assets/numbers-CUWAZK4J.js +0 -2
- package/dist/dashboard/assets/numbers-CUWAZK4J.js.gz +0 -0
- package/dist/dashboard/assets/pagination-Xsi9Qx04.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-DvQbD_sr.js +0 -1
- package/dist/dashboard/assets/quota-DvQbD_sr.js.gz +0 -0
- package/dist/dashboard/assets/routing-in0f_IfK.js.gz +0 -0
- package/dist/dashboard/assets/select-BLULNqTp.js.gz +0 -0
- package/dist/dashboard/assets/settings-CcGczj6I.js.gz +0 -0
- package/dist/dashboard/assets/stack-D2lIR0tg.js.gz +0 -0
- package/dist/dashboard/assets/state-DTARjfiW.js.gz +0 -0
- package/dist/dashboard/assets/switch-c0oPSnqW.js.gz +0 -0
- package/dist/dashboard/assets/useMutation-m8WGNPrz.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
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
// Persisted API-key store: the console API-key domain and gateway authentication both consume this boundary.
|
|
2
2
|
|
|
3
|
-
import { and, asc, count, desc, eq, inArray, isNotNull, isNull, lte, or, sql, type SQL } from "drizzle-orm";
|
|
3
|
+
import { and, asc, count, desc, eq, gt, inArray, isNotNull, isNull, lte, or, sql, type SQL } from "drizzle-orm";
|
|
4
4
|
import { nextSortIndex, reorderSortIndex, type SortOrderDb } from "../sort-order";
|
|
5
5
|
import { getDbHandle } from "../boot";
|
|
6
6
|
import type { CartethyiaDatabase } from "../db-handle";
|
|
@@ -253,6 +253,8 @@ async function writeSharePopup(
|
|
|
253
253
|
/** Explicit persistence boundary. Production must provide this; there is no fallback store. */
|
|
254
254
|
export interface ApiKeyStore {
|
|
255
255
|
list(tenantId: string): Promise<readonly ApiKeyRecord[]>;
|
|
256
|
+
/** Active, non-revoked bans for one tenant, including share children. */
|
|
257
|
+
listActiveBanned(tenantId: string): Promise<readonly ApiKeyRecord[]>;
|
|
256
258
|
get(tenantId: string, keyId: string): Promise<ApiKeyRecord | undefined>;
|
|
257
259
|
listChildren(tenantId: string, parentKeyId: string): Promise<readonly ApiKeyRecord[]>;
|
|
258
260
|
revokeChildrenByScope(
|
|
@@ -382,6 +384,22 @@ export class DrizzleApiKeyStore implements ApiKeyStore {
|
|
|
382
384
|
.limit(1000);
|
|
383
385
|
return this.withPopups(this.db, rows);
|
|
384
386
|
}
|
|
387
|
+
async listActiveBanned(tenantId: string): Promise<readonly ApiKeyRecord[]> {
|
|
388
|
+
const now = new Date();
|
|
389
|
+
const rows = await this.db
|
|
390
|
+
.select()
|
|
391
|
+
.from(apiKeys)
|
|
392
|
+
.where(
|
|
393
|
+
and(
|
|
394
|
+
eq(apiKeys.tenantId, tenantId),
|
|
395
|
+
isNotNull(apiKeys.bannedAt),
|
|
396
|
+
isNull(apiKeys.revokedAt),
|
|
397
|
+
or(isNull(apiKeys.bannedUntil), gt(apiKeys.bannedUntil, now)),
|
|
398
|
+
),
|
|
399
|
+
)
|
|
400
|
+
.orderBy(desc(apiKeys.bannedAt), apiKeys.id);
|
|
401
|
+
return rows.map((row) => this.map(row));
|
|
402
|
+
}
|
|
385
403
|
|
|
386
404
|
/** Rewrites the list order for one tenant; `keyIds` is the full order. */
|
|
387
405
|
async reorder(tenantId: string, keyIds: readonly string[]): Promise<void> {
|
package/src/protocol/dsml.ts
CHANGED
|
@@ -3,21 +3,11 @@
|
|
|
3
3
|
*
|
|
4
4
|
* DeepSeek-family models occasionally write their tool calls as XML-like DSML
|
|
5
5
|
* markup inside the plain-text content stream instead of the structured
|
|
6
|
-
* `tool_calls` field.
|
|
6
|
+
* `tool_calls` field. The gateway sees it from one upstream family:
|
|
7
7
|
*
|
|
8
8
|
* - CodeBuddy/WorkBuddy emit strict blocks (`<|DSML| calls>…</|DSML| calls>`)
|
|
9
9
|
* that must be parsed exactly, with declared-tool allowlisting.
|
|
10
|
-
* - Qoder emits looser blocks (`<[^>]*DSML[^>]*calls>…`) that tolerate any
|
|
11
|
-
* intermediate characters in the tag, and its parameter values are plain
|
|
12
|
-
* strings.
|
|
13
|
-
*
|
|
14
|
-
* The two share the same recovery idea, so the mechanics live here once and
|
|
15
|
-
* each caller picks its dialect through options. The defaults reproduce the
|
|
16
|
-
* CodeBuddy dialect exactly (`app/dsml.py` in codebuddy2api); Qoder passes
|
|
17
|
-
* `fuzzy: true` and its id factory, mirroring `qoder_proxy.py`.
|
|
18
10
|
*/
|
|
19
|
-
import { randomUUID } from "node:crypto";
|
|
20
|
-
|
|
21
11
|
export interface DsmlToolCall {
|
|
22
12
|
readonly id: string;
|
|
23
13
|
readonly name: string;
|
|
@@ -34,19 +24,15 @@ export interface DsmlParseOptions {
|
|
|
34
24
|
readonly separators?: readonly string[];
|
|
35
25
|
/** Block names a strict opener may name. */
|
|
36
26
|
readonly blockNames?: readonly string[];
|
|
37
|
-
/**
|
|
38
|
-
readonly fuzzy?: boolean;
|
|
39
|
-
/** How parameter values decode: `json` (CodeBuddy) or `string` (Qoder). */
|
|
27
|
+
/** How parameter values decode: `json` (CodeBuddy) or `string`. */
|
|
40
28
|
readonly params?: "json" | "string";
|
|
41
|
-
/** Call id factory. Defaults to sequential
|
|
29
|
+
/** Call id factory. Defaults to sequential. */
|
|
42
30
|
readonly id?: (call: { readonly name: string }, index: number, seq: number) => string;
|
|
43
31
|
/** Non-empty allowlist makes the strict dialect reject undeclared names. */
|
|
44
32
|
readonly allowedNames?: ReadonlySet<string>;
|
|
45
33
|
/**
|
|
46
34
|
* When true, JSON stringifies argument objects with recursively sorted keys,
|
|
47
|
-
* matching the reference bridge (`json.dumps(..., sort_keys=True)`).
|
|
48
|
-
* strict dialect defaults to true; the fuzzy dialect never sorts, matching
|
|
49
|
-
* its reference's `json.dumps(params)`.
|
|
35
|
+
* matching the reference bridge (`json.dumps(..., sort_keys=True)`).
|
|
50
36
|
*/
|
|
51
37
|
readonly sortKeys?: boolean;
|
|
52
38
|
/**
|
|
@@ -75,10 +61,6 @@ function sequentialId(_call: { readonly name: string }, _index: number, seq: num
|
|
|
75
61
|
return `call_dsml_${seq}_${_call.name}`;
|
|
76
62
|
}
|
|
77
63
|
|
|
78
|
-
function uuidId(_call: { readonly name: string }, _index: number, _seq: number): string {
|
|
79
|
-
return `call_${randomUUID().replace(/-/g, "").slice(0, 16)}`;
|
|
80
|
-
}
|
|
81
|
-
|
|
82
64
|
interface DsmlParseResult {
|
|
83
65
|
readonly text: string;
|
|
84
66
|
readonly calls: readonly DsmlToolCall[];
|
|
@@ -257,63 +239,11 @@ function normalizeForSort(value: unknown): unknown {
|
|
|
257
239
|
return out;
|
|
258
240
|
}
|
|
259
241
|
|
|
260
|
-
/** The Qoder fuzzy block scanner, mirroring the reference bridge's regexes. */
|
|
261
|
-
const FUZZY_CALLS_RE = /<[^>]*DSML[^>]*calls>([\s\S]*?)<\/[^>]*DSML[^>]*calls>/;
|
|
262
|
-
const FUZZY_INVOKE_RE = /<[^>]*DSML[^>]*invoke\s+name=["']([^"']+)["']>([\s\S]*?)<\/[^>]*invoke>/g;
|
|
263
|
-
const FUZZY_PARAM_RE = /<[^>]*DSML[^>]*parameter\s+name=["']([^"']+)["'][^>]*>([\s\S]*?)<\/[^>]*parameter>/g;
|
|
264
|
-
|
|
265
|
-
function parseFuzzyDsml(text: string, options: DsmlParseOptions): DsmlRecovery {
|
|
266
|
-
const id = options.id ?? uuidId;
|
|
267
|
-
if (text.length === 0 || !text.includes("DSML")) return { calls: [], clean: text };
|
|
268
|
-
|
|
269
|
-
const callsMatch = FUZZY_CALLS_RE.exec(text);
|
|
270
|
-
let block: string;
|
|
271
|
-
let clean: string;
|
|
272
|
-
|
|
273
|
-
if (callsMatch) {
|
|
274
|
-
block = callsMatch[1] ?? "";
|
|
275
|
-
const before = text.slice(0, callsMatch.index).trimEnd();
|
|
276
|
-
const after = text.slice(callsMatch.index + callsMatch[0].length).trimStart();
|
|
277
|
-
clean = (before + " " + after).trim();
|
|
278
|
-
} else {
|
|
279
|
-
// No <calls> wrapper (issue #51): find bare <invoke> blocks in the whole
|
|
280
|
-
// text, then cut the prose off at the last `<` before the first invoke —
|
|
281
|
-
// exclusive of the invoke's own tag start, exactly like the reference's
|
|
282
|
-
// `text.rfind("<", 0, first_index)`.
|
|
283
|
-
FUZZY_INVOKE_RE.lastIndex = 0;
|
|
284
|
-
const first = FUZZY_INVOKE_RE.exec(text);
|
|
285
|
-
if (!first) return { calls: [], clean: text };
|
|
286
|
-
block = text;
|
|
287
|
-
const cut = text.lastIndexOf("<", first.index - 1);
|
|
288
|
-
clean = text.slice(0, cut >= 0 ? cut : first.index).trim();
|
|
289
|
-
}
|
|
290
|
-
|
|
291
|
-
const calls: DsmlToolCall[] = [];
|
|
292
|
-
FUZZY_INVOKE_RE.lastIndex = 0;
|
|
293
|
-
let inv: RegExpExecArray | null;
|
|
294
|
-
let seq = 0;
|
|
295
|
-
while ((inv = FUZZY_INVOKE_RE.exec(block)) !== null) {
|
|
296
|
-
const params: Record<string, string> = {};
|
|
297
|
-
FUZZY_PARAM_RE.lastIndex = 0;
|
|
298
|
-
let par: RegExpExecArray | null;
|
|
299
|
-
while ((par = FUZZY_PARAM_RE.exec(inv[2] ?? "")) !== null) {
|
|
300
|
-
params[par[1] ?? ""] = (par[2] ?? "").trim();
|
|
301
|
-
}
|
|
302
|
-
const call = { name: inv[1] ?? "", arguments: JSON.stringify(params) };
|
|
303
|
-
calls.push({ ...call, id: id(call, calls.length, seq++) });
|
|
304
|
-
}
|
|
305
|
-
|
|
306
|
-
return { calls, clean };
|
|
307
|
-
}
|
|
308
|
-
|
|
309
242
|
/**
|
|
310
|
-
* Recovers DSML tool calls from one plain-text string.
|
|
311
|
-
* by `options.fuzzy`; each dialect keeps its exact public shape:
|
|
243
|
+
* Recovers DSML tool calls from one plain-text string.
|
|
312
244
|
*
|
|
313
245
|
* - strict (CodeBuddy): returns `{ text, calls }`, with `text` the clean
|
|
314
246
|
* prose; `undefined` when nothing was recovered.
|
|
315
|
-
* - fuzzy (Qoder): returns `{ clean, calls }`, with no-DSML input returning
|
|
316
|
-
* `{ calls: [], clean: text }`.
|
|
317
247
|
*
|
|
318
248
|
* Callers that need the streaming strict parser use {@link DsmlStreamParser}.
|
|
319
249
|
*/
|
|
@@ -321,7 +251,6 @@ export function parseDsmlToolCalls(
|
|
|
321
251
|
text: string,
|
|
322
252
|
options: DsmlParseOptions = {},
|
|
323
253
|
): DsmlRecovery | DsmlParseResult | undefined {
|
|
324
|
-
if (options.fuzzy === true) return parseFuzzyDsml(text, options);
|
|
325
254
|
if (!text.includes("DSML")) return undefined;
|
|
326
255
|
const parser = new DsmlStreamParser(options);
|
|
327
256
|
const first = parser.push(text);
|
|
@@ -28,6 +28,19 @@ import {
|
|
|
28
28
|
} from "../../protocol/codecs";
|
|
29
29
|
const TEXT_DECODER = new TextDecoder("utf-8", { fatal: false });
|
|
30
30
|
|
|
31
|
+
/**
|
|
32
|
+
* Provider ids that understand the OpenAI-style `service_tier` control. Only
|
|
33
|
+
* these upstreams accept the field; every other OpenAI-compatible provider
|
|
34
|
+
* either ignores it or rejects the whole request with `unsupported_value`
|
|
35
|
+
* (measured: GitHub Copilot returns 400). `service_tier` is advisory on the
|
|
36
|
+
* providers that do support it, so dropping it elsewhere is lossless.
|
|
37
|
+
*/
|
|
38
|
+
const SERVICE_TIER_SUPPORTED_PROVIDERS: ReadonlySet<string> = new Set([
|
|
39
|
+
"openai",
|
|
40
|
+
"codex",
|
|
41
|
+
"anthropic",
|
|
42
|
+
]);
|
|
43
|
+
|
|
31
44
|
/**
|
|
32
45
|
* The subset of a canonical request a native-service header hook may read.
|
|
33
46
|
*
|
|
@@ -279,6 +292,18 @@ export class OpenAICompatibleAdapter extends BaseProviderAdapter {
|
|
|
279
292
|
}
|
|
280
293
|
}
|
|
281
294
|
this.config.prePayload?.(payload, effectiveRequest, candidate, context);
|
|
295
|
+
// `service_tier` is an OpenAI-style control that only a small set of
|
|
296
|
+
// upstreams understand. Every other OpenAI-compatible provider either
|
|
297
|
+
// ignores it silently or rejects the whole request with
|
|
298
|
+
// `unsupported_value` (measured: GitHub Copilot returns 400). Since the
|
|
299
|
+
// field is purely advisory on the providers that support it, dropping it
|
|
300
|
+
// everywhere else is safe and prevents avoidable upstream 400s.
|
|
301
|
+
if (
|
|
302
|
+
payload["service_tier"] !== undefined &&
|
|
303
|
+
!SERVICE_TIER_SUPPORTED_PROVIDERS.has(candidate.provider_id)
|
|
304
|
+
) {
|
|
305
|
+
delete payload["service_tier"];
|
|
306
|
+
}
|
|
282
307
|
return payload;
|
|
283
308
|
}
|
|
284
309
|
|
|
@@ -429,12 +454,15 @@ export class OpenAICompatibleAdapter extends BaseProviderAdapter {
|
|
|
429
454
|
// the absence of every completion shape so a provider that merely
|
|
430
455
|
// echoes an `error` field alongside real output is not misread.
|
|
431
456
|
const envelopeError = json["error"];
|
|
457
|
+
const startPlanError = this.provider_id === "zcode-start" &&
|
|
458
|
+
(json["success"] === false || (json["code"] !== undefined &&
|
|
459
|
+
![0, 200, "0", "200"].includes(json["code"] as string | number)));
|
|
432
460
|
const hasCompletionShape =
|
|
433
461
|
json["choices"] !== undefined ||
|
|
434
462
|
json["output"] !== undefined ||
|
|
435
463
|
json["content"] !== undefined ||
|
|
436
464
|
json["candidates"] !== undefined;
|
|
437
|
-
if (envelopeError !== undefined && envelopeError !== null && !hasCompletionShape) {
|
|
465
|
+
if (((envelopeError !== undefined && envelopeError !== null) || startPlanError) && !hasCompletionShape) {
|
|
438
466
|
const errorObject = isRecord(envelopeError) ? envelopeError : json;
|
|
439
467
|
const identifier = upstreamErrorIdentifier(json);
|
|
440
468
|
const providerStatus = [
|
|
@@ -239,8 +239,18 @@ export const PROVIDER_CAPABILITIES = {
|
|
|
239
239
|
loadAuthentication: oauthCapability(() => import("./integrations/antigravity/antigravity-oauth"), "antigravityOAuthClient", { withRefresher: true }),
|
|
240
240
|
loadQuotaCollector: quotaCapability(() => import("./integrations/antigravity/antigravity-quota"), "fetchAntigravityQuota"),
|
|
241
241
|
loadModelDiscovery: async () => async ({ baseUrl, credential, fetcher }) => {
|
|
242
|
-
const { discoverAntigravityModels } = await import("./integrations/antigravity/antigravity-protocol");
|
|
243
|
-
|
|
242
|
+
const { discoverAntigravityModels, loadAntigravityProject } = await import("./integrations/antigravity/antigravity-protocol");
|
|
243
|
+
// The reference client resolves the project before catalog calls; the
|
|
244
|
+
// live backend accepts both, but sending it matches the captured wire.
|
|
245
|
+
const projectId = await loadAntigravityProject(credential, {
|
|
246
|
+
...(baseUrl === undefined ? {} : { baseUrl }),
|
|
247
|
+
...(fetcher ? { fetcher } : {}),
|
|
248
|
+
}).catch(() => undefined);
|
|
249
|
+
return discoverAntigravityModels(credential, {
|
|
250
|
+
baseUrl,
|
|
251
|
+
...(fetcher ? { fetcher } : {}),
|
|
252
|
+
...(projectId === undefined ? {} : { projectId }),
|
|
253
|
+
});
|
|
244
254
|
},
|
|
245
255
|
},
|
|
246
256
|
muse: {
|
|
@@ -96,7 +96,8 @@ interface AntigravityModelWireProfile {
|
|
|
96
96
|
|
|
97
97
|
/**
|
|
98
98
|
* `maxOutputTokens` the backend enforces per wire id (captured from the real
|
|
99
|
-
* `antigravity/hub` client
|
|
99
|
+
* `antigravity/hub` client and verified live against `fetchAvailableModels`
|
|
100
|
+
* on 2026-11-03). Claude on `daily-cloudcode-pa` rejects
|
|
100
101
|
* `maxOutputTokens > 64000` with a `400 Request contains an invalid argument`
|
|
101
102
|
* regardless of the thinking budget; Gemini SKUs accept their discovered
|
|
102
103
|
* output ceiling. Keyed by the routed upstream wire id (post effort-routing),
|
|
@@ -106,22 +107,75 @@ interface AntigravityModelWireProfile {
|
|
|
106
107
|
const ANTIGRAVITY_MODEL_WIRE_PROFILES: Readonly<
|
|
107
108
|
Record<string, AntigravityModelWireProfile>
|
|
108
109
|
> = Object.freeze({
|
|
109
|
-
// Anthropic on Antigravity caps at 64000 output tokens.
|
|
110
|
-
"claude-opus-4-6-thinking": {
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
110
|
+
// Anthropic on Antigravity caps at 64000 output tokens (verified live).
|
|
111
|
+
"claude-opus-4-6-thinking": {
|
|
112
|
+
modelEnum: "MODEL_PLACEHOLDER_M26",
|
|
113
|
+
maxOutputTokens: 64000,
|
|
114
|
+
},
|
|
115
|
+
"claude-sonnet-4-6": {
|
|
116
|
+
modelEnum: "MODEL_PLACEHOLDER_M35",
|
|
117
|
+
maxOutputTokens: 64000,
|
|
118
|
+
},
|
|
119
|
+
// Gemini SKUs, as the live roster publishes them (2026-11-03).
|
|
120
|
+
"gemini-2.5-flash": {
|
|
121
|
+
modelEnum: "MODEL_GOOGLE_GEMINI_2_5_FLASH",
|
|
122
|
+
maxOutputTokens: 65535,
|
|
123
|
+
},
|
|
124
|
+
"gemini-2.5-flash-thinking": {
|
|
125
|
+
modelEnum: "MODEL_GOOGLE_GEMINI_2_5_FLASH_THINKING",
|
|
126
|
+
maxOutputTokens: 65535,
|
|
127
|
+
},
|
|
128
|
+
"gemini-2.5-flash-lite": {
|
|
129
|
+
modelEnum: "MODEL_GOOGLE_GEMINI_2_5_FLASH_LITE",
|
|
130
|
+
maxOutputTokens: 65535,
|
|
131
|
+
},
|
|
132
|
+
"gemini-2.5-pro": {
|
|
133
|
+
modelEnum: "MODEL_GOOGLE_GEMINI_2_5_PRO",
|
|
134
|
+
maxOutputTokens: 65535,
|
|
135
|
+
},
|
|
136
|
+
"gemini-3-flash": {
|
|
137
|
+
modelEnum: "MODEL_PLACEHOLDER_M18",
|
|
115
138
|
maxOutputTokens: 65536,
|
|
116
139
|
},
|
|
117
|
-
"gemini-3.1-
|
|
118
|
-
modelEnum: "
|
|
140
|
+
"gemini-3.1-flash-lite": {
|
|
141
|
+
modelEnum: "MODEL_PLACEHOLDER_M50",
|
|
119
142
|
maxOutputTokens: 65535,
|
|
120
143
|
},
|
|
121
|
-
"gemini-
|
|
122
|
-
modelEnum: "
|
|
144
|
+
"gemini-3.1-flash-image": {
|
|
145
|
+
modelEnum: "MODEL_PLACEHOLDER_M21",
|
|
146
|
+
maxOutputTokens: 65536,
|
|
147
|
+
},
|
|
148
|
+
"gemini-3.5-flash-lite": {
|
|
149
|
+
modelEnum: "MODEL_PLACEHOLDER_M198",
|
|
123
150
|
maxOutputTokens: 65535,
|
|
124
151
|
},
|
|
152
|
+
// Gemini 3.8 Flash effort tiers (real deployment names).
|
|
153
|
+
"gemini-3.8-flash-low": {
|
|
154
|
+
modelEnum: "MODEL_PLACEHOLDER_M320",
|
|
155
|
+
maxOutputTokens: 65536,
|
|
156
|
+
},
|
|
157
|
+
"gemini-3.8-flash-medium": {
|
|
158
|
+
modelEnum: "MODEL_PLACEHOLDER_M319",
|
|
159
|
+
maxOutputTokens: 65536,
|
|
160
|
+
},
|
|
161
|
+
"gemini-3.8-flash-high": {
|
|
162
|
+
modelEnum: "MODEL_PLACEHOLDER_M318",
|
|
163
|
+
maxOutputTokens: 65536,
|
|
164
|
+
},
|
|
165
|
+
"gemini-3.8-flash-tiered": {
|
|
166
|
+
modelEnum: "MODEL_PLACEHOLDER_M322",
|
|
167
|
+
maxOutputTokens: 65536,
|
|
168
|
+
},
|
|
169
|
+
// GPT-OSS via Antigravity (verified live).
|
|
170
|
+
"gpt-oss-120b-medium": {
|
|
171
|
+
modelEnum: "MODEL_OPENAI_GPT_OSS_120B_MEDIUM",
|
|
172
|
+
maxOutputTokens: 32768,
|
|
173
|
+
},
|
|
174
|
+
// Tab (laptop-class) preview SKU.
|
|
175
|
+
"tab_flash_lite_preview": {
|
|
176
|
+
modelEnum: "MODEL_PLACEHOLDER_M19",
|
|
177
|
+
maxOutputTokens: 4096,
|
|
178
|
+
},
|
|
125
179
|
});
|
|
126
180
|
|
|
127
181
|
export function getAntigravityModelWireProfile(
|
|
@@ -398,6 +452,7 @@ export async function discoverAntigravityModels(
|
|
|
398
452
|
readonly baseUrl?: string;
|
|
399
453
|
readonly fetcher?: typeof fetch;
|
|
400
454
|
readonly signal?: AbortSignal;
|
|
455
|
+
readonly projectId?: string;
|
|
401
456
|
} = {},
|
|
402
457
|
): Promise<readonly ModelDefinition[] | null> {
|
|
403
458
|
const fetcher = options.fetcher ?? fetch;
|
|
@@ -419,7 +474,10 @@ export async function discoverAntigravityModels(
|
|
|
419
474
|
"content-type": "application/json",
|
|
420
475
|
"user-agent": getAntigravityUserAgent(),
|
|
421
476
|
},
|
|
422
|
-
|
|
477
|
+
// The reference client always sends the resolved project
|
|
478
|
+
// (`cloudCodeMainService.js`); the live backend accepts both, but the
|
|
479
|
+
// project is required for billing-gated endpoints.
|
|
480
|
+
body: JSON.stringify(options.projectId === undefined ? {} : { project: options.projectId }),
|
|
423
481
|
signal,
|
|
424
482
|
});
|
|
425
483
|
if (!response.ok) continue;
|
|
@@ -489,9 +547,16 @@ export function applySkipThoughtSignatureBypass(
|
|
|
489
547
|
* Sending the Gemini shape makes the backend treat the call as a different
|
|
490
548
|
* client and refuse to enroll the account, which the operator sees as
|
|
491
549
|
* "You do not have a valid license of this product".
|
|
550
|
+
*
|
|
551
|
+
* The reference client (`cloudCodeMainService.js`) sends the full product
|
|
552
|
+
* identity: `ideName`, `ideType`, and `ideVersion`. `ideType` alone was
|
|
553
|
+
* accepted live, but the full shape is the captured wire and avoids any
|
|
554
|
+
* client-class gating on the control plane.
|
|
492
555
|
*/
|
|
493
556
|
export const ANTIGRAVITY_LOAD_CODE_ASSIST_METADATA = Object.freeze({
|
|
557
|
+
ideName: "antigravity",
|
|
494
558
|
ideType: "ANTIGRAVITY",
|
|
559
|
+
ideVersion: getAntigravityVersion(),
|
|
495
560
|
});
|
|
496
561
|
|
|
497
562
|
const projectIdCache = new Map<string, string>();
|
|
@@ -570,7 +635,9 @@ const FREE_TIER_ID = "free-tier";
|
|
|
570
635
|
const ONBOARD_USER_PATH = "/v1internal:onboardUser";
|
|
571
636
|
const ONBOARD_OPERATIONS_PATH = "/v1internal";
|
|
572
637
|
const ONBOARD_TIMEOUT_MS = 30_000;
|
|
573
|
-
|
|
638
|
+
// Reference client (`cloudCodeMainService.js`) polls the operation every
|
|
639
|
+
// 500ms (`gXa = 500`).
|
|
640
|
+
const ONBOARD_POLL_INTERVAL_MS = 500;
|
|
574
641
|
|
|
575
642
|
/** Thrown when an account cannot be enrolled in the Antigravity free tier. */
|
|
576
643
|
export class AntigravityProvisioningError extends Error {
|
|
@@ -699,6 +766,9 @@ async function onboardUser(
|
|
|
699
766
|
if (left <= 0) throw new AntigravityProvisioningError("onboardUser timed out");
|
|
700
767
|
return left;
|
|
701
768
|
};
|
|
769
|
+
const projectId = extractProjectId(
|
|
770
|
+
await loadCodeAssist(fetcher, base, accessToken, signal),
|
|
771
|
+
);
|
|
702
772
|
let operation = await cloudCodeAssistCall(
|
|
703
773
|
fetcher,
|
|
704
774
|
base,
|
|
@@ -706,7 +776,11 @@ async function onboardUser(
|
|
|
706
776
|
ONBOARD_USER_PATH,
|
|
707
777
|
{
|
|
708
778
|
method: "POST",
|
|
709
|
-
body: {
|
|
779
|
+
body: {
|
|
780
|
+
tierId: FREE_TIER_ID,
|
|
781
|
+
...(projectId === undefined ? {} : { cloudaicompanionProject: projectId }),
|
|
782
|
+
metadata: ANTIGRAVITY_LOAD_CODE_ASSIST_METADATA,
|
|
783
|
+
},
|
|
710
784
|
},
|
|
711
785
|
signal,
|
|
712
786
|
);
|
|
@@ -118,9 +118,6 @@ function keepWorse(
|
|
|
118
118
|
return candidateRemaining < currentRemaining ? candidate : current;
|
|
119
119
|
}
|
|
120
120
|
|
|
121
|
-
/** Total the upstream's fractional allowance is normalized against. */
|
|
122
|
-
const QUOTA_TOTAL = 1000;
|
|
123
|
-
|
|
124
121
|
/** Builds a window from a `remainingFraction` + `resetTime` pair. */
|
|
125
122
|
function fractionWindow(
|
|
126
123
|
kind: string,
|
|
@@ -129,9 +126,8 @@ function fractionWindow(
|
|
|
129
126
|
resetsAt: string | null,
|
|
130
127
|
): ProviderQuotaWindow {
|
|
131
128
|
const fraction = Math.min(1, Math.max(0, remainingFraction));
|
|
132
|
-
const used = QUOTA_TOTAL - Math.round(QUOTA_TOTAL * fraction);
|
|
133
129
|
return {
|
|
134
|
-
...percentWindow(kind, label, (1 - fraction) * 100, resetsAt,
|
|
130
|
+
...percentWindow(kind, label, (1 - fraction) * 100, resetsAt, null, null, "independent"),
|
|
135
131
|
recurring: true,
|
|
136
132
|
};
|
|
137
133
|
}
|
|
@@ -316,7 +312,23 @@ export async function fetchAntigravityQuota(
|
|
|
316
312
|
...(project === undefined ? {} : { project }),
|
|
317
313
|
}),
|
|
318
314
|
);
|
|
319
|
-
|
|
315
|
+
// The summary endpoint already covers a family with a weekly window; the
|
|
316
|
+
// per-model windows are a subset of that same allowance, so rendering
|
|
317
|
+
// both doubles every row the operator sees. Per-model windows stay as a
|
|
318
|
+
// fallback when the summary was unavailable, so a family still reports
|
|
319
|
+
// something.
|
|
320
|
+
const summaryLabels = windows.map((window) => window.label.toLowerCase());
|
|
321
|
+
// Model family key → the summary family label it falls under.
|
|
322
|
+
const summaryLabelForModel = (key: string): string =>
|
|
323
|
+
key === "google" ? "gemini" : "claude";
|
|
324
|
+
const modelWindows = parseModelQuotas(models);
|
|
325
|
+
windows.push(
|
|
326
|
+
...modelWindows.filter((window) => {
|
|
327
|
+
const familyKey = window.kind.split(":")[0] ?? "";
|
|
328
|
+
const summaryLabel = summaryLabelForModel(familyKey);
|
|
329
|
+
return !summaryLabels.some((label) => label.includes(summaryLabel));
|
|
330
|
+
}),
|
|
331
|
+
);
|
|
320
332
|
plan = plan ?? text(models.tier) ?? text(models.plan);
|
|
321
333
|
break;
|
|
322
334
|
} catch {
|
|
@@ -94,22 +94,26 @@ export const ANTIGRAVITY_MODELS: readonly ModelDefinition[] = [
|
|
|
94
94
|
antigravityModel("claude-opus-4-6", 250_000, 64_000, true),
|
|
95
95
|
antigravityModel("claude-sonnet-5-5", 1_000_000, 128_000, true),
|
|
96
96
|
antigravityModel("claude-opus-5-5", 1_000_000, 128_000, true),
|
|
97
|
-
// Gemini text SKUs, as the Antigravity roster publishes them
|
|
98
|
-
|
|
99
|
-
antigravityModel("gemini-2.5-flash
|
|
100
|
-
antigravityModel("gemini-
|
|
101
|
-
antigravityModel("gemini-
|
|
102
|
-
antigravityModel("gemini-2.5-
|
|
103
|
-
antigravityModel("gemini-3
|
|
104
|
-
antigravityModel("gemini-3.
|
|
97
|
+
// Gemini text SKUs, as the Antigravity roster publishes them (verified live
|
|
98
|
+
// 2026-11-03): Gemini SKUs ceiling at 65535/65536 output tokens.
|
|
99
|
+
antigravityModel("gemini-2.5-flash", 1_000_000, 65_535, true),
|
|
100
|
+
antigravityModel("gemini-2.5-flash-thinking", 1_000_000, 65_535, true),
|
|
101
|
+
antigravityModel("gemini-2.5-flash-lite", 1_000_000, 65_535, true),
|
|
102
|
+
antigravityModel("gemini-2.5-pro", 1_000_000, 65_535, true),
|
|
103
|
+
antigravityModel("gemini-3-flash", 1_000_000, 65_536, true),
|
|
104
|
+
antigravityModel("gemini-3.1-flash-lite", 1_000_000, 65_535, true),
|
|
105
|
+
antigravityModel("gemini-3.5-flash-lite", 1_000_000, 65_535, true),
|
|
106
|
+
antigravityModel("gemini-3.8-flash", 1_000_000, 65_536, true),
|
|
105
107
|
antigravityModel("gemini-4-argon", 1_000_000, 65_536, true),
|
|
106
108
|
antigravityModel("gemini-4-carbon", 1_000_000, 65_536, true),
|
|
107
109
|
// Tab (laptop-class) preview SKU.
|
|
108
110
|
antigravityModel("tab_flash_lite_preview", 16_000, 4_000, true),
|
|
109
111
|
// Gemini image generation. `gemini-3-pro-image` uses the same catalog
|
|
110
112
|
// limits/capabilities as the existing `gemini-3.1-flash-image` row.
|
|
111
|
-
antigravityModel("gemini-3.1-flash-image",
|
|
112
|
-
antigravityModel("gemini-3-pro-image",
|
|
113
|
+
antigravityModel("gemini-3.1-flash-image", 65_536, 65_536, false, true),
|
|
114
|
+
antigravityModel("gemini-3-pro-image", 65_536, 65_536, false, true),
|
|
115
|
+
// GPT-OSS via Antigravity (verified live 2026-11-03).
|
|
116
|
+
antigravityModel("gpt-oss-120b", 131_072, 32_768, true),
|
|
113
117
|
];
|
|
114
118
|
|
|
115
119
|
function normalizeAntigravityGrounding(data: unknown, maxResults: number): readonly WebSearchResult[] {
|
|
@@ -777,8 +781,13 @@ function antigravityThinkingBudget(modelId: string): number | undefined {
|
|
|
777
781
|
return modelId.includes("3.1-pro") ? 10_001 : 10_000;
|
|
778
782
|
}
|
|
779
783
|
|
|
784
|
+
// Original reference instruction (captured from the Antigravity client):
|
|
785
|
+
// "You are Antigravity, a powerful agentic AI coding assistant designed by the Google Deepmind team working on Advanced Agentic Coding.You are pair programming with a USER to solve their coding task. The task may require creating a new codebase, modifying or debugging an existing codebase, or simply answering a question.**Absolute paths only****Proactiveness**"
|
|
786
|
+
// Generalized to a neutral identity so the gateway does not impersonate the
|
|
787
|
+
// vendor's branded assistant. The brand-specific wording is kept above for
|
|
788
|
+
// reference; re-enable it if an upstream behavior ever depends on it.
|
|
780
789
|
const ANTIGRAVITY_SYSTEM_INSTRUCTION =
|
|
781
|
-
"You are
|
|
790
|
+
"You are a helpful assistant.";
|
|
782
791
|
|
|
783
792
|
/**
|
|
784
793
|
* Restatement appended as a trailing user turn when a Gemini route carries a
|
|
@@ -27,7 +27,6 @@ import type {
|
|
|
27
27
|
} from "../../../protocol/canonical-model";
|
|
28
28
|
import { resolveImageSource, splitDataUrl } from "../../../protocol/codecs";
|
|
29
29
|
import { IMAGE_CLAMP_MAX_BYTES } from "../../../protocol/image-clamp";
|
|
30
|
-
import { applyCacheMode } from "../../provider-usage";
|
|
31
30
|
import type { ProviderAdapter, ProviderDispatchContext, ProviderDispatchTarget } from "../../provider-contracts";
|
|
32
31
|
import { readCredentialSecret } from "../../provider-contracts";
|
|
33
32
|
import type { Http2BidiEndReason, ValidatedHttp2BidiStream } from "../../../network/http2-bidi";
|
|
@@ -281,7 +280,7 @@ function usageFromTurnEnded(turnEnded: Record<string, unknown>): UsageRecord {
|
|
|
281
280
|
const input = count(turnEnded["input_tokens"]);
|
|
282
281
|
const output = count(turnEnded["output_tokens"]);
|
|
283
282
|
const cacheRead = count(turnEnded["cache_read"]);
|
|
284
|
-
return
|
|
283
|
+
return {
|
|
285
284
|
input_tokens: input,
|
|
286
285
|
cached_input_tokens: cacheRead,
|
|
287
286
|
cache_write_tokens: count(turnEnded["cache_write"]),
|
|
@@ -290,7 +289,7 @@ function usageFromTurnEnded(turnEnded: Record<string, unknown>): UsageRecord {
|
|
|
290
289
|
reasoning_tokens: count(turnEnded["reasoning_tokens"]),
|
|
291
290
|
estimated_cost: null,
|
|
292
291
|
total_tokens: input + output,
|
|
293
|
-
}
|
|
292
|
+
};
|
|
294
293
|
}
|
|
295
294
|
|
|
296
295
|
function nonEmptyStringOf(value: unknown): string | undefined {
|
|
@@ -33,7 +33,8 @@ import {
|
|
|
33
33
|
GITHUB_AUTO_MODELS,
|
|
34
34
|
recordGithubModelRoutes,
|
|
35
35
|
} from "./github";
|
|
36
|
-
import { GITHUB_REQUEST_HEADERS, parseGithubCredential } from "./github-oauth";
|
|
36
|
+
import { GITHUB_REQUEST_HEADERS, githubCopilotClientIds, parseGithubCredential } from "./github-oauth";
|
|
37
|
+
import { createHash } from "node:crypto";
|
|
37
38
|
|
|
38
39
|
/** A context window above this is unsatisfiable headroom, not a real limit. */
|
|
39
40
|
const MAX_CONTEXT = 1_000_000_000;
|
|
@@ -170,8 +171,20 @@ export async function discoverGithubModels(
|
|
|
170
171
|
const signal =
|
|
171
172
|
input.signal === undefined ? timeoutSignal : AbortSignal.any([input.signal, timeoutSignal]);
|
|
172
173
|
try {
|
|
174
|
+
// The reference client stamps its Copilot identity on `/models` too
|
|
175
|
+
// (`_mixinHeaders` covers the Models request type): session + machine ids.
|
|
176
|
+
// Machine id is per-account — see `githubCopilotClientIds`.
|
|
177
|
+
const accountKey = createHash("sha256").update(`${apiHost}:${access}`).digest("hex");
|
|
178
|
+
const { sessionId, machineId } = await githubCopilotClientIds(accountKey);
|
|
173
179
|
const response = await fetcher(`https://${apiHost}/models`, {
|
|
174
|
-
headers: {
|
|
180
|
+
headers: {
|
|
181
|
+
accept: "application/json",
|
|
182
|
+
authorization: `Bearer ${access}`,
|
|
183
|
+
...GITHUB_REQUEST_HEADERS,
|
|
184
|
+
"VScode-SessionId": sessionId,
|
|
185
|
+
"VScode-MachineId": machineId,
|
|
186
|
+
"editor-device-id": machineId,
|
|
187
|
+
},
|
|
175
188
|
signal,
|
|
176
189
|
});
|
|
177
190
|
if (!response.ok) return null;
|