agent-usage-all-in-one 0.5.0 → 0.6.1
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/README.md +12 -11
- package/README.zh-CN.md +12 -11
- package/dist/cli.js +1674 -234
- package/dist/cli.js.map +1 -1
- package/dist/web/_app/immutable/assets/2.RN1Pn-E8.css +1 -0
- package/dist/web/_app/immutable/chunks/CkDl_J6h.js +3 -0
- package/dist/web/_app/immutable/chunks/YtE49JQT.js +1 -0
- package/dist/web/_app/immutable/chunks/{Kc2LV0tw.js → tIH2kMzb.js} +1 -1
- package/dist/web/_app/immutable/entry/app.CtTSjPvR.js +2 -0
- package/dist/web/_app/immutable/entry/start.EiWwYI1w.js +1 -0
- package/dist/web/_app/immutable/nodes/0.Bc_BSNVt.js +1 -0
- package/dist/web/_app/immutable/nodes/1.Bmpb2sVB.js +1 -0
- package/dist/web/_app/immutable/nodes/2.B4_wlGNX.js +28 -0
- package/dist/web/_app/version.json +1 -1
- package/dist/web/brand/agent-usage-showcase.jpg +0 -0
- package/dist/web/brands/antigravity.svg +3 -0
- package/dist/web/index.html +9 -9
- package/package.json +1 -1
- package/static/brand/agent-usage-showcase.jpg +0 -0
- package/static/brands/antigravity.svg +3 -0
- package/dist/web/_app/immutable/assets/2.CHCuk4nb.css +0 -1
- package/dist/web/_app/immutable/chunks/3vuWay1s.js +0 -3
- package/dist/web/_app/immutable/chunks/CIxAYfti.js +0 -1
- package/dist/web/_app/immutable/entry/app.BKd02i81.js +0 -2
- package/dist/web/_app/immutable/entry/start.DrTKmCEQ.js +0 -1
- package/dist/web/_app/immutable/nodes/0.f03zL-fK.js +0 -1
- package/dist/web/_app/immutable/nodes/1.HxUixbgc.js +0 -1
- package/dist/web/_app/immutable/nodes/2.D3Z9fN6k.js +0 -27
package/dist/cli.js
CHANGED
|
@@ -159,7 +159,7 @@ function buildUsageExport(overview, request, accountIdentifiers = {}) {
|
|
|
159
159
|
calculatedAt: null
|
|
160
160
|
};
|
|
161
161
|
const modelObservations = history.models.flatMap(
|
|
162
|
-
(model) => model.observations.map((observation) => ({
|
|
162
|
+
(model) => (model.observations ?? []).map((observation) => ({
|
|
163
163
|
model: model.model,
|
|
164
164
|
observation
|
|
165
165
|
}))
|
|
@@ -210,14 +210,14 @@ function buildUsageExport(overview, request, accountIdentifiers = {}) {
|
|
|
210
210
|
});
|
|
211
211
|
const observationsById = new Map([
|
|
212
212
|
...history.models.flatMap(
|
|
213
|
-
(model) => model.observations.map((observation) => [observation.id, observation])
|
|
213
|
+
(model) => (model.observations ?? []).map((observation) => [observation.id, observation])
|
|
214
214
|
),
|
|
215
215
|
...(history.unclassified.observations ?? []).map(
|
|
216
216
|
(observation) => [observation.id, observation]
|
|
217
217
|
)
|
|
218
218
|
]);
|
|
219
219
|
const costRows = history.costs.map((cost) => {
|
|
220
|
-
const authorities = domain.costs.filter(
|
|
220
|
+
const authorities = (domain.costs ?? []).filter(
|
|
221
221
|
(candidate) => candidate.kind === cost.kind && candidate.currency.toUpperCase() === cost.currency.toUpperCase() && candidate.observedAt >= history.start && candidate.observedAt < history.end
|
|
222
222
|
).map((candidate) => candidate.authority);
|
|
223
223
|
return {
|
|
@@ -268,7 +268,7 @@ function buildUsageExport(overview, request, accountIdentifiers = {}) {
|
|
|
268
268
|
calculatedAt: null
|
|
269
269
|
};
|
|
270
270
|
});
|
|
271
|
-
const costObservationRows = domain.costs.filter((cost) => cost.observedAt >= history.start && cost.observedAt < history.end).map((cost) => {
|
|
271
|
+
const costObservationRows = (domain.costs ?? []).filter((cost) => cost.observedAt >= history.start && cost.observedAt < history.end).map((cost) => {
|
|
272
272
|
const snapshot2 = cost.priceSnapshot ?? null;
|
|
273
273
|
const observation = cost.usageObservationId ? observationsById.get(cost.usageObservationId) : null;
|
|
274
274
|
return {
|
|
@@ -557,10 +557,34 @@ function anthropicEntry(options) {
|
|
|
557
557
|
source: {
|
|
558
558
|
title: "Anthropic Claude API pricing",
|
|
559
559
|
url: options.sourceUrl,
|
|
560
|
-
retrievedAt: "2026-08-28"
|
|
560
|
+
retrievedAt: options.retrievedAt ?? "2026-08-28"
|
|
561
561
|
}
|
|
562
562
|
};
|
|
563
563
|
}
|
|
564
|
+
function antigravityEntry(options) {
|
|
565
|
+
const versionDate = "2026-09-02";
|
|
566
|
+
return {
|
|
567
|
+
id: options.id,
|
|
568
|
+
priceVersion: `antigravity-${versionDate}`,
|
|
569
|
+
providerId: "antigravity",
|
|
570
|
+
billingDomainId: "code-assist-subscription",
|
|
571
|
+
canonicalModel: options.model,
|
|
572
|
+
aliases: options.aliases,
|
|
573
|
+
currency: "USD",
|
|
574
|
+
effectiveFrom: GOOGLE_ANTIGRAVITY_EFFECTIVE_FROM,
|
|
575
|
+
effectiveUntil: null,
|
|
576
|
+
contextTier: "standard-api",
|
|
577
|
+
contextRule: { kind: "fixed" },
|
|
578
|
+
ratesPerMillion: {
|
|
579
|
+
input: options.input,
|
|
580
|
+
output: options.output,
|
|
581
|
+
reasoning: options.output,
|
|
582
|
+
"cache-read": options.cacheRead ?? null,
|
|
583
|
+
"cache-write": null
|
|
584
|
+
},
|
|
585
|
+
source: options.source ?? GOOGLE_ANTIGRAVITY_SOURCE
|
|
586
|
+
};
|
|
587
|
+
}
|
|
564
588
|
function openAiGpt56Entries(model, periods) {
|
|
565
589
|
return periods.flatMap(([effectiveFrom, effectiveUntil, input, output]) => {
|
|
566
590
|
const versionDate = effectiveFrom.slice(0, 10);
|
|
@@ -705,8 +729,48 @@ function openCodeLocalModelPrefix(entry) {
|
|
|
705
729
|
if (entry.providerId === "opencode-go" && entry.billingDomainId === "go-subscription") {
|
|
706
730
|
return "opencode-go";
|
|
707
731
|
}
|
|
732
|
+
if (entry.providerId === "antigravity" && entry.billingDomainId === "code-assist-subscription") {
|
|
733
|
+
return "google";
|
|
734
|
+
}
|
|
708
735
|
return null;
|
|
709
736
|
}
|
|
737
|
+
function customModelRateToCatalogEntry(rate) {
|
|
738
|
+
const versionDate = rate.updatedAt.slice(0, 10);
|
|
739
|
+
return {
|
|
740
|
+
id: `custom-rate-${rate.id}`,
|
|
741
|
+
priceVersion: `custom-${rate.id}-${rate.updatedAt}`,
|
|
742
|
+
providerId: rate.providerId,
|
|
743
|
+
billingDomainId: rate.billingDomainId ?? "*",
|
|
744
|
+
canonicalModel: rate.model,
|
|
745
|
+
aliases: [],
|
|
746
|
+
currency: "USD",
|
|
747
|
+
effectiveFrom: "2020-01-01T00:00:00.000Z",
|
|
748
|
+
effectiveUntil: null,
|
|
749
|
+
contextTier: "custom-rate",
|
|
750
|
+
contextRule: { kind: "fixed" },
|
|
751
|
+
ratesPerMillion: {
|
|
752
|
+
input: rate.ratesPerMillion.input,
|
|
753
|
+
output: rate.ratesPerMillion.output,
|
|
754
|
+
reasoning: rate.ratesPerMillion.output,
|
|
755
|
+
"cache-read": rate.ratesPerMillion.cacheRead,
|
|
756
|
+
"cache-write": null
|
|
757
|
+
},
|
|
758
|
+
source: {
|
|
759
|
+
title: "User-configured custom model rate",
|
|
760
|
+
url: "local://settings/rates",
|
|
761
|
+
retrievedAt: versionDate
|
|
762
|
+
}
|
|
763
|
+
};
|
|
764
|
+
}
|
|
765
|
+
function mergeCatalogWithCustomRates(catalog, customRates) {
|
|
766
|
+
if (!customRates || customRates.length === 0) return catalog;
|
|
767
|
+
const customEntries = customRates.map(customModelRateToCatalogEntry);
|
|
768
|
+
const rateFingerprints = customRates.map((r) => `${r.id}:${r.updatedAt}`).sort().join(";");
|
|
769
|
+
return {
|
|
770
|
+
version: `${catalog.version}+custom:${rateFingerprints}`,
|
|
771
|
+
entries: [...customEntries, ...catalog.entries]
|
|
772
|
+
};
|
|
773
|
+
}
|
|
710
774
|
function deriveRetailEquivalentCosts(snapshot2, catalog = ANTHROPIC_PRICING_CATALOG, calculatedAt = snapshot2.observedAt) {
|
|
711
775
|
const costs = [];
|
|
712
776
|
const decisions = [];
|
|
@@ -732,13 +796,31 @@ function priceObservation(providerId, observation, catalog, calculatedAt) {
|
|
|
732
796
|
return unavailable("model-unclassified");
|
|
733
797
|
}
|
|
734
798
|
const normalizedModel = normalized.model.trim().toLowerCase();
|
|
735
|
-
const
|
|
736
|
-
(entry2) => entry2.providerId === providerId && entry2.billingDomainId === observation.billingDomainId && [entry2.canonicalModel, ...entry2.aliases].some(
|
|
799
|
+
const matchingCandidates = catalog.entries.filter(
|
|
800
|
+
(entry2) => entry2.providerId === providerId && (entry2.billingDomainId === observation.billingDomainId || entry2.billingDomainId === "*") && [entry2.canonicalModel, ...entry2.aliases].some(
|
|
737
801
|
(model) => model.trim().toLowerCase() === normalizedModel
|
|
738
802
|
)
|
|
739
803
|
);
|
|
740
|
-
|
|
741
|
-
const
|
|
804
|
+
let selectedEntries;
|
|
805
|
+
const customExact = matchingCandidates.filter(
|
|
806
|
+
(e) => e.contextTier === "custom-rate" && e.billingDomainId === observation.billingDomainId
|
|
807
|
+
);
|
|
808
|
+
if (customExact.length > 0) {
|
|
809
|
+
selectedEntries = customExact;
|
|
810
|
+
} else {
|
|
811
|
+
const customWildcard = matchingCandidates.filter(
|
|
812
|
+
(e) => e.contextTier === "custom-rate" && e.billingDomainId === "*"
|
|
813
|
+
);
|
|
814
|
+
if (customWildcard.length > 0) {
|
|
815
|
+
selectedEntries = customWildcard;
|
|
816
|
+
} else {
|
|
817
|
+
selectedEntries = matchingCandidates.filter(
|
|
818
|
+
(e) => e.contextTier !== "custom-rate" && e.billingDomainId === observation.billingDomainId
|
|
819
|
+
);
|
|
820
|
+
}
|
|
821
|
+
}
|
|
822
|
+
if (selectedEntries.length === 0) return unavailable("model-unrecognized");
|
|
823
|
+
const timeActiveEntries = selectedEntries.filter(
|
|
742
824
|
(entry2) => observation.observedAt >= entry2.effectiveFrom && (!entry2.effectiveUntil || observation.observedAt < entry2.effectiveUntil)
|
|
743
825
|
);
|
|
744
826
|
if (timeActiveEntries.length === 0) return unavailable("price-not-effective");
|
|
@@ -877,7 +959,7 @@ function matchContext(rule, observation) {
|
|
|
877
959
|
function preciseMoney(value) {
|
|
878
960
|
return Number(value.toFixed(12));
|
|
879
961
|
}
|
|
880
|
-
var ANTHROPIC_PRICING_CATALOG, OPENCODE_GO_SOURCE, XAI_PRICING_SOURCE, OPENAI_GPT_56_SOURCE, OPEN_CODE_GO_SOURCE_PATH, openCodeHistory, OPEN_CODE_BASE_HISTORY, OPEN_CODE_PRICE_HISTORY, OPEN_CODE_FLAT_MODELS, OPEN_CODE_CONTEXT_MODELS, DEEPSEEK_GO_MODELS, WEEKDAY_PEAK_RANGES, DEEPSEEK_OFFICIAL_SOURCE, DEEPSEEK_OFFICIAL_MODELS, DEEPSEEK_OFFICIAL_EFFECTIVE_FROM, DIRECT_OFFICIAL_PRICING_CATALOG, OFFICIAL_PRICING_CATALOG;
|
|
962
|
+
var ANTHROPIC_PRICING_CATALOG, OPENCODE_GO_SOURCE, XAI_PRICING_SOURCE, OPENAI_GPT_56_SOURCE, OPEN_CODE_GO_SOURCE_PATH, openCodeHistory, OPEN_CODE_BASE_HISTORY, OPEN_CODE_PRICE_HISTORY, OPEN_CODE_FLAT_MODELS, OPEN_CODE_CONTEXT_MODELS, DEEPSEEK_GO_MODELS, WEEKDAY_PEAK_RANGES, DEEPSEEK_OFFICIAL_SOURCE, DEEPSEEK_OFFICIAL_MODELS, DEEPSEEK_OFFICIAL_EFFECTIVE_FROM, GOOGLE_ANTIGRAVITY_SOURCE, GOOGLE_ANTIGRAVITY_EFFECTIVE_FROM, DIRECT_OFFICIAL_PRICING_CATALOG, OFFICIAL_PRICING_CATALOG;
|
|
881
963
|
var init_retail_pricing = __esm({
|
|
882
964
|
"src/core/retail-pricing.ts"() {
|
|
883
965
|
"use strict";
|
|
@@ -885,6 +967,25 @@ var init_retail_pricing = __esm({
|
|
|
885
967
|
ANTHROPIC_PRICING_CATALOG = {
|
|
886
968
|
version: "2026-08-28",
|
|
887
969
|
entries: [
|
|
970
|
+
anthropicEntry({
|
|
971
|
+
id: "anthropic-fable-5-1-2026-09-01",
|
|
972
|
+
priceVersion: "anthropic-2026-09-01",
|
|
973
|
+
model: "claude-fable-5-1",
|
|
974
|
+
aliases: [
|
|
975
|
+
"Claude Fable 5.1",
|
|
976
|
+
"claude-fable-5.1",
|
|
977
|
+
"claude-fable-5-1-20260901",
|
|
978
|
+
"claude-fable-5.1-20260901",
|
|
979
|
+
"fable-5.1",
|
|
980
|
+
"fable-5-1"
|
|
981
|
+
],
|
|
982
|
+
effectiveFrom: "2026-09-01T00:00:00.000Z",
|
|
983
|
+
input: 10,
|
|
984
|
+
output: 50,
|
|
985
|
+
cacheRead: 0.25,
|
|
986
|
+
sourceUrl: "https://platform.claude.com/docs/en/about-claude/pricing",
|
|
987
|
+
retrievedAt: "2026-09-03"
|
|
988
|
+
}),
|
|
888
989
|
{
|
|
889
990
|
id: "anthropic-fable-5-2026-06-09",
|
|
890
991
|
priceVersion: "anthropic-2026-06-09",
|
|
@@ -1086,6 +1187,12 @@ var init_retail_pricing = __esm({
|
|
|
1086
1187
|
["deepseek-v4-flash-vision-exp", 0.22, 0.66, 7e-3]
|
|
1087
1188
|
];
|
|
1088
1189
|
DEEPSEEK_OFFICIAL_EFFECTIVE_FROM = "2026-08-17T00:00:00.000Z";
|
|
1190
|
+
GOOGLE_ANTIGRAVITY_SOURCE = {
|
|
1191
|
+
title: "Google Gemini API pricing",
|
|
1192
|
+
url: "https://ai.google.dev/pricing",
|
|
1193
|
+
retrievedAt: "2026-09-02"
|
|
1194
|
+
};
|
|
1195
|
+
GOOGLE_ANTIGRAVITY_EFFECTIVE_FROM = "2026-01-01T00:00:00.000Z";
|
|
1089
1196
|
DIRECT_OFFICIAL_PRICING_CATALOG = {
|
|
1090
1197
|
version: "2026-08-28-grok-4.6-build",
|
|
1091
1198
|
entries: [
|
|
@@ -1222,11 +1329,91 @@ var init_retail_pricing = __esm({
|
|
|
1222
1329
|
output: 12,
|
|
1223
1330
|
cacheRead: 1,
|
|
1224
1331
|
contextRule: { kind: "prompt-tokens", minimumExclusive: 2e5 }
|
|
1332
|
+
}),
|
|
1333
|
+
antigravityEntry({
|
|
1334
|
+
id: "antigravity-gemini-3.7-flash-2026-09-02",
|
|
1335
|
+
model: "gemini-3.7-flash",
|
|
1336
|
+
aliases: [
|
|
1337
|
+
"gemini-3.7-flash-high",
|
|
1338
|
+
"gemini-3.7-flash-medium",
|
|
1339
|
+
"gemini-3.7-flash-low",
|
|
1340
|
+
"gemini-3p7-flash-exp-d",
|
|
1341
|
+
"gemini-3.7-flash-exp",
|
|
1342
|
+
"Gemini 3.7 Flash (High)",
|
|
1343
|
+
"Gemini 3.7 Flash (Medium)",
|
|
1344
|
+
"Gemini 3.7 Flash (Low)"
|
|
1345
|
+
],
|
|
1346
|
+
input: 0.1,
|
|
1347
|
+
output: 0.4,
|
|
1348
|
+
cacheRead: 0.025
|
|
1349
|
+
}),
|
|
1350
|
+
antigravityEntry({
|
|
1351
|
+
id: "antigravity-gemini-3.6-flash-2026-09-02",
|
|
1352
|
+
model: "gemini-3.6-flash",
|
|
1353
|
+
aliases: [
|
|
1354
|
+
"gemini-3.6-flash-high",
|
|
1355
|
+
"gemini-3.6-flash-medium",
|
|
1356
|
+
"gemini-3.6-flash-low",
|
|
1357
|
+
"Gemini 3.6 Flash (High)",
|
|
1358
|
+
"Gemini 3.6 Flash (Medium)",
|
|
1359
|
+
"Gemini 3.6 Flash (Low)"
|
|
1360
|
+
],
|
|
1361
|
+
input: 0.1,
|
|
1362
|
+
output: 0.4,
|
|
1363
|
+
cacheRead: 0.025
|
|
1364
|
+
}),
|
|
1365
|
+
antigravityEntry({
|
|
1366
|
+
id: "antigravity-gemini-3.1-pro-2026-09-02",
|
|
1367
|
+
model: "gemini-3.1-pro",
|
|
1368
|
+
aliases: [
|
|
1369
|
+
"gemini-3.1-pro-high",
|
|
1370
|
+
"gemini-3.1-pro-low",
|
|
1371
|
+
"gemini-3p1-pro-exp",
|
|
1372
|
+
"Gemini 3.1 Pro (High)",
|
|
1373
|
+
"Gemini 3.1 Pro (Low)"
|
|
1374
|
+
],
|
|
1375
|
+
input: 1.25,
|
|
1376
|
+
output: 5,
|
|
1377
|
+
cacheRead: 0.3125
|
|
1378
|
+
}),
|
|
1379
|
+
antigravityEntry({
|
|
1380
|
+
id: "antigravity-claude-sonnet-4-6-2026-09-02",
|
|
1381
|
+
model: "claude-sonnet-4-6",
|
|
1382
|
+
aliases: ["claude-sonnet-4-6-thinking", "Claude Sonnet 4.6 (Thinking)"],
|
|
1383
|
+
input: 3,
|
|
1384
|
+
output: 15,
|
|
1385
|
+
cacheRead: 0.3,
|
|
1386
|
+
source: {
|
|
1387
|
+
title: "Anthropic Claude API pricing",
|
|
1388
|
+
url: "https://platform.claude.com/docs/en/about-claude/pricing",
|
|
1389
|
+
retrievedAt: "2026-09-02"
|
|
1390
|
+
}
|
|
1391
|
+
}),
|
|
1392
|
+
antigravityEntry({
|
|
1393
|
+
id: "antigravity-claude-opus-4-6-2026-09-02",
|
|
1394
|
+
model: "claude-opus-4-6-thinking",
|
|
1395
|
+
aliases: ["claude-opus-4-6", "Claude Opus 4.6 (Thinking)"],
|
|
1396
|
+
input: 15,
|
|
1397
|
+
output: 75,
|
|
1398
|
+
cacheRead: 1.5,
|
|
1399
|
+
source: {
|
|
1400
|
+
title: "Anthropic Claude API pricing",
|
|
1401
|
+
url: "https://platform.claude.com/docs/en/about-claude/pricing",
|
|
1402
|
+
retrievedAt: "2026-09-02"
|
|
1403
|
+
}
|
|
1404
|
+
}),
|
|
1405
|
+
antigravityEntry({
|
|
1406
|
+
id: "antigravity-gpt-oss-120b-2026-09-02",
|
|
1407
|
+
model: "gpt-oss-120b-medium",
|
|
1408
|
+
aliases: ["gpt-oss-120b", "GPT-OSS 120B (Medium)"],
|
|
1409
|
+
input: 0.15,
|
|
1410
|
+
output: 0.6,
|
|
1411
|
+
cacheRead: 0.05
|
|
1225
1412
|
})
|
|
1226
1413
|
]
|
|
1227
1414
|
};
|
|
1228
1415
|
OFFICIAL_PRICING_CATALOG = {
|
|
1229
|
-
version: "2026-09-
|
|
1416
|
+
version: "2026-09-03-fable-5.1",
|
|
1230
1417
|
entries: [
|
|
1231
1418
|
...DIRECT_OFFICIAL_PRICING_CATALOG.entries,
|
|
1232
1419
|
...openCodeLocalHistoryEntries(DIRECT_OFFICIAL_PRICING_CATALOG.entries)
|
|
@@ -1612,6 +1799,7 @@ var init_plan_pricing = __esm({
|
|
|
1612
1799
|
});
|
|
1613
1800
|
|
|
1614
1801
|
// src/core/usage-application.ts
|
|
1802
|
+
import { randomUUID } from "crypto";
|
|
1615
1803
|
function safeConnectorFailure(error) {
|
|
1616
1804
|
if (error instanceof Error && "code" in error && typeof error.code === "string" && "recovery" in error && typeof error.recovery === "string") {
|
|
1617
1805
|
return { code: error.code, message: error.message, recovery: error.recovery };
|
|
@@ -1719,7 +1907,7 @@ function notificationLevel(value) {
|
|
|
1719
1907
|
function pickAgentProviderIndex(overview) {
|
|
1720
1908
|
return {
|
|
1721
1909
|
generatedAt: overview.generatedAt,
|
|
1722
|
-
providers: overview.providers.filter((provider) => provider.id !== "opencode").map(({ id, displayName }) => ({ id, displayName }))
|
|
1910
|
+
providers: overview.providers.filter((provider) => provider.id !== "opencode" && provider.id !== "dsh").map(({ id, displayName }) => ({ id, displayName }))
|
|
1723
1911
|
};
|
|
1724
1912
|
}
|
|
1725
1913
|
var UsageApplication;
|
|
@@ -1743,6 +1931,7 @@ var init_usage_application = __esm({
|
|
|
1743
1931
|
#connectorPolicies;
|
|
1744
1932
|
#notifier;
|
|
1745
1933
|
#startAtLoginManager;
|
|
1934
|
+
#basePriceCatalog;
|
|
1746
1935
|
#priceCatalog;
|
|
1747
1936
|
#planCatalog;
|
|
1748
1937
|
#refreshPromise = null;
|
|
@@ -1765,10 +1954,16 @@ var init_usage_application = __esm({
|
|
|
1765
1954
|
this.#connectorPolicies = options.connectorPolicies ?? {};
|
|
1766
1955
|
this.#notifier = options.notifier;
|
|
1767
1956
|
this.#startAtLoginManager = options.startAtLoginManager;
|
|
1768
|
-
this.#
|
|
1957
|
+
this.#basePriceCatalog = options.priceCatalog === void 0 ? OFFICIAL_PRICING_CATALOG : options.priceCatalog;
|
|
1958
|
+
this.#priceCatalog = this.#resolvePriceCatalog();
|
|
1769
1959
|
this.#planCatalog = options.planCatalog ?? SUBSCRIPTION_PLAN_CATALOG;
|
|
1770
1960
|
this.#processingStatus = createProcessingStatus(this.#clock().toISOString(), false);
|
|
1771
1961
|
}
|
|
1962
|
+
#resolvePriceCatalog() {
|
|
1963
|
+
if (!this.#basePriceCatalog) return null;
|
|
1964
|
+
const customRates = this.#repository.getCustomModelRates?.() ?? [];
|
|
1965
|
+
return mergeCatalogWithCustomRates(this.#basePriceCatalog, customRates);
|
|
1966
|
+
}
|
|
1772
1967
|
async #backfillRetailCosts(mode) {
|
|
1773
1968
|
if (!this.#priceCatalog || !this.#repository.getRetailPricingBackfillPage && !this.#repository.getRetailPricingBackfillSnapshots || !this.#repository.saveDerivedCosts) {
|
|
1774
1969
|
return;
|
|
@@ -2115,6 +2310,57 @@ var init_usage_application = __esm({
|
|
|
2115
2310
|
});
|
|
2116
2311
|
return this.getPlanSettings();
|
|
2117
2312
|
}
|
|
2313
|
+
async getCustomModelRates() {
|
|
2314
|
+
return this.#repository.getCustomModelRates?.() ?? [];
|
|
2315
|
+
}
|
|
2316
|
+
async getCustomModelRate(id) {
|
|
2317
|
+
return this.#repository.getCustomModelRate?.(id) ?? null;
|
|
2318
|
+
}
|
|
2319
|
+
async setCustomModelRate(input) {
|
|
2320
|
+
const providerId = input.providerId?.trim();
|
|
2321
|
+
if (!providerId) throw new Error("Provider ID is required");
|
|
2322
|
+
const model = input.model?.trim();
|
|
2323
|
+
if (!model) throw new Error("Model name is required");
|
|
2324
|
+
if (!Number.isFinite(input.inputRate) || input.inputRate < 0) {
|
|
2325
|
+
throw new Error("Input rate must be a non-negative number");
|
|
2326
|
+
}
|
|
2327
|
+
if (!Number.isFinite(input.outputRate) || input.outputRate < 0) {
|
|
2328
|
+
throw new Error("Output rate must be a non-negative number");
|
|
2329
|
+
}
|
|
2330
|
+
const cacheReadRate = input.cacheReadRate ?? 0;
|
|
2331
|
+
if (!Number.isFinite(cacheReadRate) || cacheReadRate < 0) {
|
|
2332
|
+
throw new Error("Cache read rate must be a non-negative number");
|
|
2333
|
+
}
|
|
2334
|
+
const rate = {
|
|
2335
|
+
id: input.id || `rate-${randomUUID()}`,
|
|
2336
|
+
providerId,
|
|
2337
|
+
billingDomainId: input.billingDomainId?.trim() || null,
|
|
2338
|
+
model,
|
|
2339
|
+
ratesPerMillion: {
|
|
2340
|
+
input: input.inputRate,
|
|
2341
|
+
output: input.outputRate,
|
|
2342
|
+
cacheRead: cacheReadRate
|
|
2343
|
+
},
|
|
2344
|
+
updatedAt: this.#clock().toISOString()
|
|
2345
|
+
};
|
|
2346
|
+
await this.#queueDatabaseWrite(() => {
|
|
2347
|
+
this.#repository.saveCustomModelRate?.(rate);
|
|
2348
|
+
});
|
|
2349
|
+
this.#priceCatalog = this.#resolvePriceCatalog();
|
|
2350
|
+
await this.#backfillRetailCosts("hard-rebuild");
|
|
2351
|
+
return rate;
|
|
2352
|
+
}
|
|
2353
|
+
async deleteCustomModelRate(id) {
|
|
2354
|
+
let deleted = false;
|
|
2355
|
+
await this.#queueDatabaseWrite(() => {
|
|
2356
|
+
deleted = this.#repository.deleteCustomModelRate?.(id) ?? false;
|
|
2357
|
+
});
|
|
2358
|
+
if (deleted) {
|
|
2359
|
+
this.#priceCatalog = this.#resolvePriceCatalog();
|
|
2360
|
+
await this.#backfillRetailCosts("hard-rebuild");
|
|
2361
|
+
}
|
|
2362
|
+
return deleted;
|
|
2363
|
+
}
|
|
2118
2364
|
/**
|
|
2119
2365
|
* A billing domain can carry a plan price when its connector does not report
|
|
2120
2366
|
* an actual metered charge. Metered domains keep their own billed amounts and
|
|
@@ -2301,7 +2547,10 @@ var init_usage_application = __esm({
|
|
|
2301
2547
|
return this.#repository.getProviderOverview?.(now, providerId, query) ?? this.#repository.getOverview(now, query).providers.find((provider) => provider.id === providerId) ?? null;
|
|
2302
2548
|
}
|
|
2303
2549
|
async exportUsage(request) {
|
|
2304
|
-
const overview = this.#repository.getOverview(this.#clock(),
|
|
2550
|
+
const overview = this.#repository.getOverview(this.#clock(), {
|
|
2551
|
+
...request,
|
|
2552
|
+
auditEvidence: true
|
|
2553
|
+
});
|
|
2305
2554
|
const accountIdentifiers = request.includeAccountIdentifiers ? this.#repository.getProviderAccountIdentifiers() : {};
|
|
2306
2555
|
return buildUsageExport(overview, request, accountIdentifiers);
|
|
2307
2556
|
}
|
|
@@ -2560,6 +2809,20 @@ var init_catalog = __esm({
|
|
|
2560
2809
|
billingDomain: { id: "deepseek-official", displayName: "DeepSeek API" }
|
|
2561
2810
|
},
|
|
2562
2811
|
officialCredentialPaths: [".dsh"]
|
|
2812
|
+
},
|
|
2813
|
+
{
|
|
2814
|
+
id: "antigravity",
|
|
2815
|
+
displayName: "Antigravity",
|
|
2816
|
+
command: "agy",
|
|
2817
|
+
permissionDescription: "Read local Antigravity conversation session databases for token history. No credential file is opened.",
|
|
2818
|
+
credentialOwner: "official-client",
|
|
2819
|
+
experimental: true,
|
|
2820
|
+
expectedCoverage: ["quota", "tokens", "history"],
|
|
2821
|
+
target: {
|
|
2822
|
+
provider: { id: "antigravity", displayName: "Antigravity" },
|
|
2823
|
+
billingDomain: { id: "code-assist-subscription", displayName: "Gemini Code Assist" }
|
|
2824
|
+
},
|
|
2825
|
+
officialCredentialPaths: [".gemini/antigravity-cli", ".gemini/antigravity"]
|
|
2563
2826
|
}
|
|
2564
2827
|
];
|
|
2565
2828
|
}
|
|
@@ -4127,6 +4390,186 @@ var init_opencode_go_connector = __esm({
|
|
|
4127
4390
|
}
|
|
4128
4391
|
});
|
|
4129
4392
|
|
|
4393
|
+
// src/connectors/grok-build/grok-build-connector.ts
|
|
4394
|
+
import { z as z6 } from "zod";
|
|
4395
|
+
function incompleteTranscriptFailure3() {
|
|
4396
|
+
return {
|
|
4397
|
+
code: "local-transcript-scan-incomplete",
|
|
4398
|
+
message: "Some local Grok history could not be read.",
|
|
4399
|
+
recovery: "Agent Usage will retry automatically without removing stored history."
|
|
4400
|
+
};
|
|
4401
|
+
}
|
|
4402
|
+
function grokBuildBillingDomain() {
|
|
4403
|
+
return {
|
|
4404
|
+
id: "grok-build-subscription",
|
|
4405
|
+
displayName: "Grok Build / SuperGrok shared pool"
|
|
4406
|
+
};
|
|
4407
|
+
}
|
|
4408
|
+
function isGrokOfficialModel(model) {
|
|
4409
|
+
if (!model) return false;
|
|
4410
|
+
const normalized = model.trim().toLowerCase();
|
|
4411
|
+
if (normalized === "grok") return true;
|
|
4412
|
+
if (normalized.startsWith("grok-") || normalized.startsWith("grok/")) {
|
|
4413
|
+
return true;
|
|
4414
|
+
}
|
|
4415
|
+
return false;
|
|
4416
|
+
}
|
|
4417
|
+
function resolveGrokBillingDomain(model, customEndpoints) {
|
|
4418
|
+
if (!model) return "grok-build-subscription";
|
|
4419
|
+
const normalized = model.trim().toLowerCase();
|
|
4420
|
+
if (customEndpoints?.has(normalized)) {
|
|
4421
|
+
return customEndpoints.get(normalized);
|
|
4422
|
+
}
|
|
4423
|
+
if (isGrokOfficialModel(model)) {
|
|
4424
|
+
return "grok-build-subscription";
|
|
4425
|
+
}
|
|
4426
|
+
return "custom";
|
|
4427
|
+
}
|
|
4428
|
+
function grokBuildBillingDomains(usage = []) {
|
|
4429
|
+
const primary = grokBuildBillingDomain();
|
|
4430
|
+
const observed = [...new Set(usage.map((o) => o.billingDomainId))].filter((id) => id !== primary.id).sort();
|
|
4431
|
+
return [
|
|
4432
|
+
primary,
|
|
4433
|
+
...observed.map((id) => ({
|
|
4434
|
+
id,
|
|
4435
|
+
displayName: id === "custom" ? "Custom endpoints" : id
|
|
4436
|
+
}))
|
|
4437
|
+
];
|
|
4438
|
+
}
|
|
4439
|
+
function mapBillingQuota(billing) {
|
|
4440
|
+
const config = billing.config;
|
|
4441
|
+
if (!config) return [];
|
|
4442
|
+
const usedPercent = config.creditUsagePercent ?? derivePercent(config.used?.val, config.monthlyLimit?.val);
|
|
4443
|
+
if (usedPercent === null) return [];
|
|
4444
|
+
const periodType = config.currentPeriod?.type;
|
|
4445
|
+
const period = nativePeriod(periodType, config.currentPeriod ? void 0 : "monthly");
|
|
4446
|
+
const resetsAt = config.currentPeriod?.end ?? config.billingPeriodEnd ?? null;
|
|
4447
|
+
return [
|
|
4448
|
+
{
|
|
4449
|
+
id: `grok-build:${period.id}`,
|
|
4450
|
+
billingDomainId: "grok-build-subscription",
|
|
4451
|
+
label: period.label,
|
|
4452
|
+
usedPercent,
|
|
4453
|
+
windowDurationMinutes: nativeWindowDurationMinutes(
|
|
4454
|
+
config.currentPeriod?.start ?? config.billingPeriodStart,
|
|
4455
|
+
resetsAt,
|
|
4456
|
+
period.id
|
|
4457
|
+
),
|
|
4458
|
+
resetsAt,
|
|
4459
|
+
authority: "official-client",
|
|
4460
|
+
scope: "account-wide",
|
|
4461
|
+
status: billing.subscriptionTier ?? null
|
|
4462
|
+
}
|
|
4463
|
+
];
|
|
4464
|
+
}
|
|
4465
|
+
function nativeWindowDurationMinutes(startsAt, resetsAt, period) {
|
|
4466
|
+
const start = startsAt ? Date.parse(startsAt) : Number.NaN;
|
|
4467
|
+
const end = resetsAt ? Date.parse(resetsAt) : Number.NaN;
|
|
4468
|
+
if (Number.isFinite(start) && Number.isFinite(end) && end > start) {
|
|
4469
|
+
return Math.round((end - start) / 6e4);
|
|
4470
|
+
}
|
|
4471
|
+
if (period === "weekly") return 10080;
|
|
4472
|
+
if (period === "monthly") return 43200;
|
|
4473
|
+
return null;
|
|
4474
|
+
}
|
|
4475
|
+
function nativePeriod(type, fallback) {
|
|
4476
|
+
if (type === "USAGE_PERIOD_TYPE_WEEKLY") return { id: "weekly", label: "Weekly limit" };
|
|
4477
|
+
if (type === "USAGE_PERIOD_TYPE_MONTHLY" || fallback === "monthly") {
|
|
4478
|
+
return { id: "monthly", label: "Monthly limit" };
|
|
4479
|
+
}
|
|
4480
|
+
return { id: "usage", label: "Usage" };
|
|
4481
|
+
}
|
|
4482
|
+
function derivePercent(used, limit) {
|
|
4483
|
+
if (used === void 0 || limit === void 0 || limit <= 0) return null;
|
|
4484
|
+
return Math.min(100, Math.max(0, used / limit * 100));
|
|
4485
|
+
}
|
|
4486
|
+
function safeFailure5(error) {
|
|
4487
|
+
if (error instanceof Error && "code" in error && typeof error.code === "string" && "recovery" in error && typeof error.recovery === "string") {
|
|
4488
|
+
return { code: error.code, message: error.message, recovery: error.recovery };
|
|
4489
|
+
}
|
|
4490
|
+
return {
|
|
4491
|
+
code: "grok-billing-adapter-failed",
|
|
4492
|
+
message: "Grok Build subscription quota is unavailable.",
|
|
4493
|
+
recovery: "Open Grok Build and run /usage, then update Grok Build before retrying."
|
|
4494
|
+
};
|
|
4495
|
+
}
|
|
4496
|
+
var centSchema, usagePeriodSchema, billingConfigSchema, grokBillingResponseSchema, GrokBuildConnector;
|
|
4497
|
+
var init_grok_build_connector = __esm({
|
|
4498
|
+
"src/connectors/grok-build/grok-build-connector.ts"() {
|
|
4499
|
+
"use strict";
|
|
4500
|
+
centSchema = z6.object({ val: z6.number().default(0) }).passthrough();
|
|
4501
|
+
usagePeriodSchema = z6.object({
|
|
4502
|
+
type: z6.string().optional(),
|
|
4503
|
+
start: z6.string().optional(),
|
|
4504
|
+
end: z6.string().optional()
|
|
4505
|
+
}).passthrough();
|
|
4506
|
+
billingConfigSchema = z6.object({
|
|
4507
|
+
creditUsagePercent: z6.number().min(0).max(100).optional(),
|
|
4508
|
+
currentPeriod: usagePeriodSchema.optional(),
|
|
4509
|
+
monthlyLimit: centSchema.optional(),
|
|
4510
|
+
used: centSchema.optional(),
|
|
4511
|
+
billingPeriodStart: z6.string().optional(),
|
|
4512
|
+
billingPeriodEnd: z6.string().optional(),
|
|
4513
|
+
isUnifiedBillingUser: z6.boolean().optional()
|
|
4514
|
+
}).passthrough();
|
|
4515
|
+
grokBillingResponseSchema = z6.object({
|
|
4516
|
+
config: billingConfigSchema.nullable(),
|
|
4517
|
+
onDemandEnabled: z6.boolean().nullable().optional(),
|
|
4518
|
+
subscriptionTier: z6.string().optional(),
|
|
4519
|
+
sourceObservedAt: z6.string().datetime({ offset: true }).optional()
|
|
4520
|
+
}).passthrough();
|
|
4521
|
+
GrokBuildConnector = class {
|
|
4522
|
+
id = "grok";
|
|
4523
|
+
displayName = "Grok";
|
|
4524
|
+
consentId = "grok";
|
|
4525
|
+
#billingClient;
|
|
4526
|
+
#historyClient;
|
|
4527
|
+
#clock;
|
|
4528
|
+
constructor(options) {
|
|
4529
|
+
this.#billingClient = options.billingClient;
|
|
4530
|
+
this.#historyClient = options.historyClient;
|
|
4531
|
+
this.#clock = options.clock ?? (() => /* @__PURE__ */ new Date());
|
|
4532
|
+
}
|
|
4533
|
+
async collect(options = { mode: "incremental" }) {
|
|
4534
|
+
const warnings = [];
|
|
4535
|
+
let quotaBuckets = [];
|
|
4536
|
+
let observedAt = this.#clock().toISOString();
|
|
4537
|
+
try {
|
|
4538
|
+
const billing = await this.#billingClient.readBilling();
|
|
4539
|
+
observedAt = billing.sourceObservedAt ?? observedAt;
|
|
4540
|
+
quotaBuckets = mapBillingQuota(billing);
|
|
4541
|
+
if (quotaBuckets.length === 0) {
|
|
4542
|
+
warnings.push({
|
|
4543
|
+
code: "grok-subscription-quota-unavailable",
|
|
4544
|
+
message: "Grok Build subscription quota is unavailable.",
|
|
4545
|
+
recovery: "Open Grok Build and run /usage, then retry refresh."
|
|
4546
|
+
});
|
|
4547
|
+
}
|
|
4548
|
+
} catch (error) {
|
|
4549
|
+
warnings.push(safeFailure5(error));
|
|
4550
|
+
}
|
|
4551
|
+
const history = this.#historyClient ? await this.#historyClient.readUsage(options) : { usage: [], costs: [], complete: true };
|
|
4552
|
+
if (!history.complete) warnings.push(incompleteTranscriptFailure3());
|
|
4553
|
+
return {
|
|
4554
|
+
provider: { id: this.id, displayName: this.displayName },
|
|
4555
|
+
billingDomains: grokBuildBillingDomains(history.usage),
|
|
4556
|
+
quotaBuckets,
|
|
4557
|
+
usage: history.usage,
|
|
4558
|
+
...history.usage.length > 0 && history.complete ? {
|
|
4559
|
+
usageReconciliation: {
|
|
4560
|
+
authoritativeIdPrefixes: ["grok-transcript:"],
|
|
4561
|
+
retiredIdPrefixes: ["grok-otel:", "grok-headless:"]
|
|
4562
|
+
}
|
|
4563
|
+
} : {},
|
|
4564
|
+
costs: history.costs,
|
|
4565
|
+
warnings,
|
|
4566
|
+
observedAt
|
|
4567
|
+
};
|
|
4568
|
+
}
|
|
4569
|
+
};
|
|
4570
|
+
}
|
|
4571
|
+
});
|
|
4572
|
+
|
|
4130
4573
|
// src/server/zstd-frames.ts
|
|
4131
4574
|
import { zstdDecompressSync } from "zlib";
|
|
4132
4575
|
async function readZstdFramedText(source) {
|
|
@@ -4220,6 +4663,34 @@ import { createReadStream } from "fs";
|
|
|
4220
4663
|
import { mkdir as mkdir2, opendir, readFile as readFile3, rename as rename2, stat, writeFile as writeFile2 } from "fs/promises";
|
|
4221
4664
|
import { dirname, join as join3 } from "path";
|
|
4222
4665
|
import { createInterface } from "readline";
|
|
4666
|
+
function loadGrokConfigCustomModels(configContent) {
|
|
4667
|
+
const customModels = /* @__PURE__ */ new Map();
|
|
4668
|
+
const modelSections = [
|
|
4669
|
+
...configContent.matchAll(/\[model\.(?:"([^"]+)"|([a-zA-Z0-9_-]+))\]([\s\S]*?)(?=\n\[|$)/g)
|
|
4670
|
+
];
|
|
4671
|
+
for (const m of modelSections) {
|
|
4672
|
+
const key = m[1] || m[2];
|
|
4673
|
+
const body = m[3];
|
|
4674
|
+
const modelMatch = body.match(/model\s*=\s*"([^"]+)"/);
|
|
4675
|
+
const baseUrlMatch = body.match(/base_url\s*=\s*"([^"]+)"/);
|
|
4676
|
+
const providerMatch = body.match(/model_provider\s*=\s*"([^"]+)"/);
|
|
4677
|
+
if (baseUrlMatch || providerMatch) {
|
|
4678
|
+
const domain = providerMatch ? providerMatch[1].trim() : "custom";
|
|
4679
|
+
if (key) {
|
|
4680
|
+
customModels.set(key.trim().toLowerCase(), domain);
|
|
4681
|
+
const stripped = key.trim().toLowerCase().replace(/-(high|medium|low)$/, "");
|
|
4682
|
+
if (stripped) customModels.set(stripped, domain);
|
|
4683
|
+
}
|
|
4684
|
+
if (modelMatch) {
|
|
4685
|
+
const mName = modelMatch[1].trim().toLowerCase();
|
|
4686
|
+
customModels.set(mName, domain);
|
|
4687
|
+
const stripped = mName.replace(/-(high|medium|low)$/, "");
|
|
4688
|
+
if (stripped) customModels.set(stripped, domain);
|
|
4689
|
+
}
|
|
4690
|
+
}
|
|
4691
|
+
}
|
|
4692
|
+
return customModels;
|
|
4693
|
+
}
|
|
4223
4694
|
function isCachedTranscriptFile(value) {
|
|
4224
4695
|
const record = asObject(value);
|
|
4225
4696
|
if (!record || !Array.isArray(record.records)) return false;
|
|
@@ -4261,7 +4732,7 @@ function isParsedTranscriptRecord(value) {
|
|
|
4261
4732
|
function nonNegativeSafeInteger(value) {
|
|
4262
4733
|
return typeof value === "number" && Number.isSafeInteger(value) && value >= 0;
|
|
4263
4734
|
}
|
|
4264
|
-
function parseGrokTranscriptLine(line) {
|
|
4735
|
+
function parseGrokTranscriptLine(line, grokCustomModels) {
|
|
4265
4736
|
const record = parseObject(line);
|
|
4266
4737
|
const params = asObject(record?.params);
|
|
4267
4738
|
const update = asObject(params?.update);
|
|
@@ -4305,11 +4776,12 @@ function parseGrokTranscriptLine(line) {
|
|
|
4305
4776
|
const dedupeKey = `${sessionId}:${promptId ?? stableId(line)}:${model}`;
|
|
4306
4777
|
const directCost = grokCostUsd(totals.costUsdTicks);
|
|
4307
4778
|
const reportedCostUsd = directCost ?? (remainingCost !== null && untickedTokens > 0 ? remainingCost * (grokRecordedTokens(totals) / untickedTokens) : null);
|
|
4779
|
+
const billingDomainId = resolveGrokBillingDomain(model, grokCustomModels);
|
|
4308
4780
|
return {
|
|
4309
4781
|
dedupeKey,
|
|
4310
4782
|
observation: {
|
|
4311
4783
|
id: `grok-transcript:${stableId(dedupeKey)}`,
|
|
4312
|
-
billingDomainId
|
|
4784
|
+
billingDomainId,
|
|
4313
4785
|
model,
|
|
4314
4786
|
sessionId,
|
|
4315
4787
|
observedAt,
|
|
@@ -4634,6 +5106,7 @@ var init_local_transcript_usage_client = __esm({
|
|
|
4634
5106
|
"src/server/local-transcript-usage-client.ts"() {
|
|
4635
5107
|
"use strict";
|
|
4636
5108
|
init_token_normalization();
|
|
5109
|
+
init_grok_build_connector();
|
|
4637
5110
|
init_zstd_frames();
|
|
4638
5111
|
DSH_PRIMARY_BILLING_DOMAIN_ID = "deepseek-official";
|
|
4639
5112
|
DSH_SESSION_FORMAT_VERSION = 0;
|
|
@@ -4647,6 +5120,8 @@ var init_local_transcript_usage_client = __esm({
|
|
|
4647
5120
|
#cachePath;
|
|
4648
5121
|
#fileCache = /* @__PURE__ */ new Map();
|
|
4649
5122
|
#cacheLoaded = false;
|
|
5123
|
+
#grokCustomModels = /* @__PURE__ */ new Map();
|
|
5124
|
+
#grokCustomModelsLoaded = false;
|
|
4650
5125
|
constructor(options) {
|
|
4651
5126
|
this.#provider = options.provider;
|
|
4652
5127
|
this.#roots = options.roots;
|
|
@@ -4655,6 +5130,19 @@ var init_local_transcript_usage_client = __esm({
|
|
|
4655
5130
|
this.#cachePath = options.cachePath;
|
|
4656
5131
|
}
|
|
4657
5132
|
async readUsage(options = { mode: "incremental" }) {
|
|
5133
|
+
if (this.#provider === "grok" && !this.#grokCustomModelsLoaded) {
|
|
5134
|
+
this.#grokCustomModelsLoaded = true;
|
|
5135
|
+
for (const root of this.#roots) {
|
|
5136
|
+
try {
|
|
5137
|
+
const configPath = join3(dirname(root), "config.toml");
|
|
5138
|
+
const content = await readFile3(configPath, "utf8");
|
|
5139
|
+
for (const [k, v] of loadGrokConfigCustomModels(content)) {
|
|
5140
|
+
this.#grokCustomModels.set(k, v);
|
|
5141
|
+
}
|
|
5142
|
+
} catch {
|
|
5143
|
+
}
|
|
5144
|
+
}
|
|
5145
|
+
}
|
|
4658
5146
|
await this.#loadCache();
|
|
4659
5147
|
if (options.mode === "hard-rebuild") this.#fileCache.clear();
|
|
4660
5148
|
const cutoff = this.#clock().getTime() - this.#lookbackDays * 24 * 60 * 60 * 1e3;
|
|
@@ -4702,6 +5190,22 @@ var init_local_transcript_usage_client = __esm({
|
|
|
4702
5190
|
const cacheKey = stableId(file.path);
|
|
4703
5191
|
const cached = this.#fileCache.get(cacheKey);
|
|
4704
5192
|
if (cached && cached.size === file.size && cached.mtimeMs === file.mtimeMs) {
|
|
5193
|
+
if (this.#provider === "grok") {
|
|
5194
|
+
const remapped = cached.records.map((r) => {
|
|
5195
|
+
const expectedDomain = resolveGrokBillingDomain(
|
|
5196
|
+
r.observation.model,
|
|
5197
|
+
this.#grokCustomModels
|
|
5198
|
+
);
|
|
5199
|
+
if (r.observation.billingDomainId !== expectedDomain) {
|
|
5200
|
+
return {
|
|
5201
|
+
...r,
|
|
5202
|
+
observation: { ...r.observation, billingDomainId: expectedDomain }
|
|
5203
|
+
};
|
|
5204
|
+
}
|
|
5205
|
+
return r;
|
|
5206
|
+
});
|
|
5207
|
+
return { records: remapped, complete: true, unsupportedFormat: false };
|
|
5208
|
+
}
|
|
4705
5209
|
return { records: cached.records, complete: true, unsupportedFormat: false };
|
|
4706
5210
|
}
|
|
4707
5211
|
const records = [];
|
|
@@ -4745,7 +5249,7 @@ var init_local_transcript_usage_client = __esm({
|
|
|
4745
5249
|
if (this.#provider === "dsh") {
|
|
4746
5250
|
return DSH_LINE_HINTS.some((hint) => line.includes(hint)) ? parseDshTranscriptLine(line, dshState) : [];
|
|
4747
5251
|
}
|
|
4748
|
-
return line.includes('"turn_completed"') ? parseGrokTranscriptLine(line) : [];
|
|
5252
|
+
return line.includes('"turn_completed"') ? parseGrokTranscriptLine(line, this.#grokCustomModels) : [];
|
|
4749
5253
|
}
|
|
4750
5254
|
async #loadCache() {
|
|
4751
5255
|
if (this.#cacheLoaded) return;
|
|
@@ -4800,7 +5304,7 @@ function unsupportedFormatFailure() {
|
|
|
4800
5304
|
recovery: "Update Agent Usage; stored dsh history from earlier scans is retained."
|
|
4801
5305
|
};
|
|
4802
5306
|
}
|
|
4803
|
-
function
|
|
5307
|
+
function safeFailure6(error) {
|
|
4804
5308
|
if (error instanceof Error && "code" in error && typeof error.code === "string" && "recovery" in error && typeof error.recovery === "string") {
|
|
4805
5309
|
return { code: error.code, message: error.message, recovery: error.recovery };
|
|
4806
5310
|
}
|
|
@@ -4832,7 +5336,7 @@ var init_dsh_connector = __esm({
|
|
|
4832
5336
|
try {
|
|
4833
5337
|
history = await this.#historyClient.readUsage(options);
|
|
4834
5338
|
} catch (error) {
|
|
4835
|
-
warnings.push(
|
|
5339
|
+
warnings.push(safeFailure6(error));
|
|
4836
5340
|
}
|
|
4837
5341
|
if (history?.unsupportedFormat) warnings.push(unsupportedFormatFailure());
|
|
4838
5342
|
else if (history && !history.complete) warnings.push(incompleteSessionLogFailure());
|
|
@@ -4857,151 +5361,696 @@ var init_dsh_connector = __esm({
|
|
|
4857
5361
|
}
|
|
4858
5362
|
});
|
|
4859
5363
|
|
|
4860
|
-
// src/
|
|
4861
|
-
import {
|
|
4862
|
-
|
|
4863
|
-
|
|
4864
|
-
|
|
4865
|
-
|
|
4866
|
-
|
|
4867
|
-
|
|
4868
|
-
|
|
4869
|
-
|
|
4870
|
-
|
|
4871
|
-
|
|
4872
|
-
|
|
4873
|
-
|
|
5364
|
+
// src/server/antigravity-quota-client.ts
|
|
5365
|
+
import { readdirSync, readFileSync } from "fs";
|
|
5366
|
+
import { homedir as homedir2 } from "os";
|
|
5367
|
+
import { join as join4 } from "path";
|
|
5368
|
+
function mapQuotaGroups(groups) {
|
|
5369
|
+
const buckets = [];
|
|
5370
|
+
for (const group of groups) {
|
|
5371
|
+
const isGemini = /gemini/i.test(group.displayName ?? "");
|
|
5372
|
+
const isClaudeOrGpt = /claude|gpt/i.test(group.displayName ?? "");
|
|
5373
|
+
for (const rawBucket of group.buckets ?? []) {
|
|
5374
|
+
const windowStr = (rawBucket.window ?? "").toLowerCase();
|
|
5375
|
+
const displayStr = (rawBucket.displayName ?? "").toLowerCase();
|
|
5376
|
+
const is5h = windowStr === "5h" || /5[- ]?hour/i.test(displayStr);
|
|
5377
|
+
const isWeekly = windowStr === "weekly" || /week/i.test(displayStr);
|
|
5378
|
+
let durationMinutes;
|
|
5379
|
+
let windowName;
|
|
5380
|
+
if (is5h) {
|
|
5381
|
+
durationMinutes = 300;
|
|
5382
|
+
windowName = "5 hour";
|
|
5383
|
+
} else if (isWeekly) {
|
|
5384
|
+
durationMinutes = 10080;
|
|
5385
|
+
windowName = "Week";
|
|
5386
|
+
} else {
|
|
5387
|
+
continue;
|
|
5388
|
+
}
|
|
5389
|
+
let label = windowName;
|
|
5390
|
+
if (!isGemini) {
|
|
5391
|
+
if (isClaudeOrGpt) {
|
|
5392
|
+
label = `Claude / GPT \xB7 ${windowName}`;
|
|
5393
|
+
} else if (group.displayName) {
|
|
5394
|
+
label = `${group.displayName} \xB7 ${windowName}`;
|
|
5395
|
+
}
|
|
5396
|
+
}
|
|
5397
|
+
const usedPercent = typeof rawBucket.remainingFraction === "number" ? Math.max(0, Math.min(100, Math.round((1 - rawBucket.remainingFraction) * 100))) : null;
|
|
5398
|
+
buckets.push({
|
|
5399
|
+
id: rawBucket.bucketId || `${isGemini ? "gemini" : "3p"}-${windowStr}`,
|
|
5400
|
+
billingDomainId: ANTIGRAVITY_PRIMARY_BILLING_DOMAIN_ID,
|
|
5401
|
+
label,
|
|
5402
|
+
usedPercent,
|
|
5403
|
+
windowDurationMinutes: durationMinutes,
|
|
5404
|
+
resetsAt: rawBucket.resetTime ?? null,
|
|
5405
|
+
authority: "official-client",
|
|
5406
|
+
scope: "account-wide"
|
|
5407
|
+
});
|
|
5408
|
+
}
|
|
5409
|
+
}
|
|
5410
|
+
return buckets;
|
|
4874
5411
|
}
|
|
4875
|
-
|
|
4876
|
-
|
|
4877
|
-
|
|
4878
|
-
|
|
4879
|
-
|
|
4880
|
-
|
|
4881
|
-
|
|
4882
|
-
|
|
5412
|
+
var AntigravityQuotaClient;
|
|
5413
|
+
var init_antigravity_quota_client = __esm({
|
|
5414
|
+
"src/server/antigravity-quota-client.ts"() {
|
|
5415
|
+
"use strict";
|
|
5416
|
+
init_antigravity_connector();
|
|
5417
|
+
AntigravityQuotaClient = class {
|
|
5418
|
+
#logRoots;
|
|
5419
|
+
#ports;
|
|
5420
|
+
#fetchFn;
|
|
5421
|
+
#timeoutMs;
|
|
5422
|
+
constructor(options = {}) {
|
|
5423
|
+
this.#logRoots = options.logRoots ?? [
|
|
5424
|
+
join4(homedir2(), "Library/Logs/Antigravity"),
|
|
5425
|
+
join4(homedir2(), ".gemini/antigravity-cli/log"),
|
|
5426
|
+
join4(homedir2(), ".gemini/antigravity/log")
|
|
5427
|
+
];
|
|
5428
|
+
this.#ports = options.ports;
|
|
5429
|
+
this.#fetchFn = options.fetchFn ?? globalThis.fetch;
|
|
5430
|
+
this.#timeoutMs = options.timeoutMs ?? 1500;
|
|
5431
|
+
}
|
|
5432
|
+
async readQuota() {
|
|
5433
|
+
const { ports, csrfToken } = this.discoverCandidates();
|
|
5434
|
+
const candidatePorts = this.#ports ?? ports;
|
|
5435
|
+
if (candidatePorts.length === 0) {
|
|
5436
|
+
return null;
|
|
5437
|
+
}
|
|
5438
|
+
for (const port of candidatePorts) {
|
|
5439
|
+
const quota = await this.queryPort(port, csrfToken);
|
|
5440
|
+
if (quota) {
|
|
5441
|
+
return quota;
|
|
5442
|
+
}
|
|
5443
|
+
}
|
|
5444
|
+
return null;
|
|
5445
|
+
}
|
|
5446
|
+
discoverCandidates() {
|
|
5447
|
+
let csrfToken = process.env.ANTIGRAVITY_CSRF_TOKEN ?? null;
|
|
5448
|
+
const ports = [];
|
|
5449
|
+
const httpPortRegex = /(?:Language server listening on random port at|Reloading all windows with URL: https?:\/\/127\.0\.0\.1:|Local:\s+https?:\/\/127\.0\.0\.1:|Host bridge server listening on http:\/\/127\.0\.0\.1:)\s*(\d+)/g;
|
|
5450
|
+
const csrfRegex = /--csrf_token[= ]([a-f0-9-]+)/;
|
|
5451
|
+
for (const root of this.#logRoots) {
|
|
5452
|
+
try {
|
|
5453
|
+
const files = readdirSync(root).filter((file) => file.endsWith(".log")).sort().reverse().slice(0, 10);
|
|
5454
|
+
for (const file of files) {
|
|
5455
|
+
const filePath = join4(root, file);
|
|
5456
|
+
try {
|
|
5457
|
+
const content = readFileSync(filePath, "utf8");
|
|
5458
|
+
if (!csrfToken) {
|
|
5459
|
+
const csrfMatch = csrfRegex.exec(content);
|
|
5460
|
+
if (csrfMatch) csrfToken = csrfMatch[1];
|
|
5461
|
+
}
|
|
5462
|
+
let match;
|
|
5463
|
+
while ((match = httpPortRegex.exec(content)) !== null) {
|
|
5464
|
+
const basePort = Number(match[1]);
|
|
5465
|
+
ports.push(basePort);
|
|
5466
|
+
ports.push(basePort + 1);
|
|
5467
|
+
ports.push(basePort + 2);
|
|
5468
|
+
}
|
|
5469
|
+
} catch {
|
|
5470
|
+
}
|
|
5471
|
+
}
|
|
5472
|
+
} catch {
|
|
5473
|
+
}
|
|
5474
|
+
}
|
|
5475
|
+
return {
|
|
5476
|
+
ports: [...new Set(ports.reverse())],
|
|
5477
|
+
csrfToken
|
|
5478
|
+
};
|
|
5479
|
+
}
|
|
5480
|
+
discoverCandidatePorts() {
|
|
5481
|
+
return this.discoverCandidates().ports;
|
|
5482
|
+
}
|
|
5483
|
+
async queryPort(port, csrfToken = null) {
|
|
5484
|
+
try {
|
|
5485
|
+
const url = `http://127.0.0.1:${port}/exa.language_server_pb.LanguageServerService/RetrieveUserQuotaSummary`;
|
|
5486
|
+
const response = await this.#fetchFn(url, {
|
|
5487
|
+
method: "POST",
|
|
5488
|
+
headers: {
|
|
5489
|
+
"Content-Type": "application/json",
|
|
5490
|
+
"Connect-Protocol-Version": "1",
|
|
5491
|
+
...csrfToken ? { "x-codeium-csrf-token": csrfToken } : {}
|
|
5492
|
+
},
|
|
5493
|
+
body: JSON.stringify({}),
|
|
5494
|
+
signal: AbortSignal.timeout(this.#timeoutMs)
|
|
5495
|
+
});
|
|
5496
|
+
if (!response.ok) {
|
|
5497
|
+
return null;
|
|
5498
|
+
}
|
|
5499
|
+
const body = await response.json();
|
|
5500
|
+
const groups = body.response?.groups;
|
|
5501
|
+
if (!Array.isArray(groups) || groups.length === 0) {
|
|
5502
|
+
return null;
|
|
5503
|
+
}
|
|
5504
|
+
return mapQuotaGroups(groups);
|
|
5505
|
+
} catch {
|
|
5506
|
+
return null;
|
|
5507
|
+
}
|
|
5508
|
+
}
|
|
5509
|
+
};
|
|
5510
|
+
}
|
|
5511
|
+
});
|
|
5512
|
+
|
|
5513
|
+
// src/connectors/antigravity/antigravity-connector.ts
|
|
5514
|
+
function buildAntigravityQuotaBuckets(usage, nowMs, limits = DEFAULT_ANTIGRAVITY_QUOTA_LIMITS) {
|
|
5515
|
+
const fiveHoursMs = 300 * 60 * 1e3;
|
|
5516
|
+
const sevenDaysMs = 7 * 24 * 60 * 60 * 1e3;
|
|
5517
|
+
const cutoff5h = nowMs - fiveHoursMs;
|
|
5518
|
+
const cutoff7d = nowMs - sevenDaysMs;
|
|
5519
|
+
const obs5h = [];
|
|
5520
|
+
const obs7d = [];
|
|
5521
|
+
for (const obs of usage) {
|
|
5522
|
+
const t = new Date(obs.observedAt).getTime();
|
|
5523
|
+
if (t >= cutoff5h) obs5h.push(obs);
|
|
5524
|
+
if (t >= cutoff7d) obs7d.push(obs);
|
|
5525
|
+
}
|
|
5526
|
+
const tokens5h = obs5h.reduce(
|
|
5527
|
+
(acc, obs) => acc + obs.inputTokens + obs.outputTokens + obs.cacheReadTokens,
|
|
5528
|
+
0
|
|
5529
|
+
);
|
|
5530
|
+
const usedPercent5h = Math.min(100, Math.round(tokens5h / limits.rolling5hTokens * 100));
|
|
5531
|
+
let resetsAt5h;
|
|
5532
|
+
if (obs5h.length > 0) {
|
|
5533
|
+
const oldestMs = Math.min(...obs5h.map((o) => new Date(o.observedAt).getTime()));
|
|
5534
|
+
resetsAt5h = new Date(oldestMs + fiveHoursMs).toISOString();
|
|
5535
|
+
} else {
|
|
5536
|
+
resetsAt5h = new Date(nowMs + fiveHoursMs).toISOString();
|
|
5537
|
+
}
|
|
5538
|
+
const tokens7d = obs7d.reduce(
|
|
5539
|
+
(acc, obs) => acc + obs.inputTokens + obs.outputTokens + obs.cacheReadTokens,
|
|
5540
|
+
0
|
|
5541
|
+
);
|
|
5542
|
+
const usedPercent7d = Math.min(100, Math.round(tokens7d / limits.weeklyTokens * 100));
|
|
5543
|
+
let resetsAt7d;
|
|
5544
|
+
if (obs7d.length > 0) {
|
|
5545
|
+
const oldestMs = Math.min(...obs7d.map((o) => new Date(o.observedAt).getTime()));
|
|
5546
|
+
resetsAt7d = new Date(oldestMs + sevenDaysMs).toISOString();
|
|
5547
|
+
} else {
|
|
5548
|
+
resetsAt7d = new Date(nowMs + sevenDaysMs).toISOString();
|
|
5549
|
+
}
|
|
4883
5550
|
return [
|
|
4884
5551
|
{
|
|
4885
|
-
id:
|
|
4886
|
-
billingDomainId:
|
|
4887
|
-
label:
|
|
4888
|
-
usedPercent,
|
|
4889
|
-
windowDurationMinutes:
|
|
4890
|
-
|
|
4891
|
-
|
|
4892
|
-
|
|
4893
|
-
|
|
4894
|
-
|
|
4895
|
-
|
|
4896
|
-
|
|
4897
|
-
|
|
5552
|
+
id: "gemini-5h",
|
|
5553
|
+
billingDomainId: ANTIGRAVITY_PRIMARY_BILLING_DOMAIN_ID,
|
|
5554
|
+
label: "5 hour",
|
|
5555
|
+
usedPercent: usedPercent5h,
|
|
5556
|
+
windowDurationMinutes: 300,
|
|
5557
|
+
resetsAt: resetsAt5h,
|
|
5558
|
+
authority: "local-observation",
|
|
5559
|
+
scope: "local-only"
|
|
5560
|
+
},
|
|
5561
|
+
{
|
|
5562
|
+
id: "gemini-weekly",
|
|
5563
|
+
billingDomainId: ANTIGRAVITY_PRIMARY_BILLING_DOMAIN_ID,
|
|
5564
|
+
label: "Week",
|
|
5565
|
+
usedPercent: usedPercent7d,
|
|
5566
|
+
windowDurationMinutes: 10080,
|
|
5567
|
+
resetsAt: resetsAt7d,
|
|
5568
|
+
authority: "local-observation",
|
|
5569
|
+
scope: "local-only"
|
|
4898
5570
|
}
|
|
4899
5571
|
];
|
|
4900
5572
|
}
|
|
4901
|
-
function
|
|
4902
|
-
const
|
|
4903
|
-
|
|
4904
|
-
|
|
4905
|
-
|
|
4906
|
-
|
|
4907
|
-
|
|
4908
|
-
if (period === "monthly") return 43200;
|
|
4909
|
-
return null;
|
|
4910
|
-
}
|
|
4911
|
-
function nativePeriod(type, fallback) {
|
|
4912
|
-
if (type === "USAGE_PERIOD_TYPE_WEEKLY") return { id: "weekly", label: "Weekly limit" };
|
|
4913
|
-
if (type === "USAGE_PERIOD_TYPE_MONTHLY" || fallback === "monthly") {
|
|
4914
|
-
return { id: "monthly", label: "Monthly limit" };
|
|
4915
|
-
}
|
|
4916
|
-
return { id: "usage", label: "Usage" };
|
|
5573
|
+
function billingDomains2(usage) {
|
|
5574
|
+
const primary = {
|
|
5575
|
+
id: ANTIGRAVITY_PRIMARY_BILLING_DOMAIN_ID,
|
|
5576
|
+
displayName: "Gemini Code Assist"
|
|
5577
|
+
};
|
|
5578
|
+
const observedRoutes = [...new Set(usage.map((obs) => obs.billingDomainId))].filter((id) => id !== primary.id).sort();
|
|
5579
|
+
return [primary, ...observedRoutes.map((id) => ({ id, displayName: id }))];
|
|
4917
5580
|
}
|
|
4918
|
-
function
|
|
4919
|
-
|
|
4920
|
-
|
|
5581
|
+
function incompleteSessionScanFailure() {
|
|
5582
|
+
return {
|
|
5583
|
+
code: "antigravity-session-scan-incomplete",
|
|
5584
|
+
message: "Some local Antigravity conversation databases could not be read.",
|
|
5585
|
+
recovery: "Agent Usage will retry automatically on the next scan without removing stored history."
|
|
5586
|
+
};
|
|
4921
5587
|
}
|
|
4922
|
-
function
|
|
4923
|
-
if (error instanceof Error && "code" in error && typeof error.code === "string" && "recovery" in error && typeof error.recovery === "string") {
|
|
4924
|
-
return { code: error.code, message: error.message, recovery: error.recovery };
|
|
4925
|
-
}
|
|
5588
|
+
function safeFailure7() {
|
|
4926
5589
|
return {
|
|
4927
|
-
code: "
|
|
4928
|
-
message: "
|
|
4929
|
-
recovery: "
|
|
5590
|
+
code: "antigravity-sqlite-read-failed",
|
|
5591
|
+
message: "Failed to read local Antigravity conversation stores.",
|
|
5592
|
+
recovery: "Check read permissions for ~/.gemini/antigravity-cli and ~/.gemini/antigravity directories."
|
|
4930
5593
|
};
|
|
4931
5594
|
}
|
|
4932
|
-
var
|
|
4933
|
-
var
|
|
4934
|
-
"src/connectors/
|
|
5595
|
+
var ANTIGRAVITY_PRIMARY_BILLING_DOMAIN_ID, DEFAULT_ANTIGRAVITY_QUOTA_LIMITS, AntigravityConnector;
|
|
5596
|
+
var init_antigravity_connector = __esm({
|
|
5597
|
+
"src/connectors/antigravity/antigravity-connector.ts"() {
|
|
4935
5598
|
"use strict";
|
|
4936
|
-
|
|
4937
|
-
|
|
4938
|
-
|
|
4939
|
-
|
|
4940
|
-
|
|
4941
|
-
}
|
|
4942
|
-
|
|
4943
|
-
|
|
4944
|
-
|
|
4945
|
-
|
|
4946
|
-
used: centSchema.optional(),
|
|
4947
|
-
billingPeriodStart: z6.string().optional(),
|
|
4948
|
-
billingPeriodEnd: z6.string().optional(),
|
|
4949
|
-
isUnifiedBillingUser: z6.boolean().optional()
|
|
4950
|
-
}).passthrough();
|
|
4951
|
-
grokBillingResponseSchema = z6.object({
|
|
4952
|
-
config: billingConfigSchema.nullable(),
|
|
4953
|
-
onDemandEnabled: z6.boolean().nullable().optional(),
|
|
4954
|
-
subscriptionTier: z6.string().optional(),
|
|
4955
|
-
sourceObservedAt: z6.string().datetime({ offset: true }).optional()
|
|
4956
|
-
}).passthrough();
|
|
4957
|
-
GrokBuildConnector = class {
|
|
4958
|
-
id = "grok";
|
|
4959
|
-
displayName = "Grok";
|
|
4960
|
-
consentId = "grok";
|
|
4961
|
-
#billingClient;
|
|
5599
|
+
init_antigravity_quota_client();
|
|
5600
|
+
ANTIGRAVITY_PRIMARY_BILLING_DOMAIN_ID = "code-assist-subscription";
|
|
5601
|
+
DEFAULT_ANTIGRAVITY_QUOTA_LIMITS = {
|
|
5602
|
+
rolling5hTokens: 15e6,
|
|
5603
|
+
weeklyTokens: 1e8
|
|
5604
|
+
};
|
|
5605
|
+
AntigravityConnector = class {
|
|
5606
|
+
id = "antigravity";
|
|
5607
|
+
displayName = "Antigravity";
|
|
5608
|
+
consentId = "antigravity";
|
|
4962
5609
|
#historyClient;
|
|
5610
|
+
#quotaClient;
|
|
4963
5611
|
#clock;
|
|
5612
|
+
#quotaLimits;
|
|
4964
5613
|
constructor(options) {
|
|
4965
|
-
this.#billingClient = options.billingClient;
|
|
4966
5614
|
this.#historyClient = options.historyClient;
|
|
5615
|
+
this.#quotaClient = options.quotaClient ?? new AntigravityQuotaClient();
|
|
4967
5616
|
this.#clock = options.clock ?? (() => /* @__PURE__ */ new Date());
|
|
5617
|
+
this.#quotaLimits = {
|
|
5618
|
+
rolling5hTokens: options.quotaLimits?.rolling5hTokens ?? DEFAULT_ANTIGRAVITY_QUOTA_LIMITS.rolling5hTokens,
|
|
5619
|
+
weeklyTokens: options.quotaLimits?.weeklyTokens ?? DEFAULT_ANTIGRAVITY_QUOTA_LIMITS.weeklyTokens
|
|
5620
|
+
};
|
|
4968
5621
|
}
|
|
4969
5622
|
async collect(options = { mode: "incremental" }) {
|
|
5623
|
+
const observedAt = this.#clock().toISOString();
|
|
5624
|
+
const nowMs = this.#clock().getTime();
|
|
4970
5625
|
const warnings = [];
|
|
5626
|
+
let history = null;
|
|
5627
|
+
try {
|
|
5628
|
+
history = await this.#historyClient.readUsage(options);
|
|
5629
|
+
} catch {
|
|
5630
|
+
warnings.push(safeFailure7());
|
|
5631
|
+
}
|
|
5632
|
+
if (history && !history.complete) {
|
|
5633
|
+
warnings.push(incompleteSessionScanFailure());
|
|
5634
|
+
}
|
|
5635
|
+
const usage = history?.usage ?? [];
|
|
4971
5636
|
let quotaBuckets = [];
|
|
4972
|
-
let observedAt = this.#clock().toISOString();
|
|
4973
5637
|
try {
|
|
4974
|
-
const
|
|
4975
|
-
|
|
4976
|
-
|
|
4977
|
-
|
|
4978
|
-
|
|
4979
|
-
|
|
4980
|
-
|
|
4981
|
-
|
|
4982
|
-
|
|
5638
|
+
const liveQuota = await this.#quotaClient.readQuota();
|
|
5639
|
+
if (liveQuota && liveQuota.length > 0) {
|
|
5640
|
+
quotaBuckets = [...liveQuota];
|
|
5641
|
+
}
|
|
5642
|
+
} catch {
|
|
5643
|
+
}
|
|
5644
|
+
const localBuckets = buildAntigravityQuotaBuckets(usage, nowMs, this.#quotaLimits);
|
|
5645
|
+
const has5h = quotaBuckets.some((b) => b.label === "5 hour" || b.id === "gemini-5h");
|
|
5646
|
+
const hasWeekly = quotaBuckets.some((b) => b.label === "Week" || b.id === "gemini-weekly");
|
|
5647
|
+
if (!has5h || !hasWeekly) {
|
|
5648
|
+
for (const localBucket of localBuckets) {
|
|
5649
|
+
if (!quotaBuckets.some((b) => b.id === localBucket.id || b.label === localBucket.label)) {
|
|
5650
|
+
quotaBuckets.push(localBucket);
|
|
5651
|
+
}
|
|
5652
|
+
}
|
|
5653
|
+
}
|
|
5654
|
+
return {
|
|
5655
|
+
provider: { id: this.id, displayName: this.displayName },
|
|
5656
|
+
billingDomains: billingDomains2(usage),
|
|
5657
|
+
quotaBuckets,
|
|
5658
|
+
usage,
|
|
5659
|
+
...usage.length > 0 && history?.complete ? {
|
|
5660
|
+
usageReconciliation: {
|
|
5661
|
+
authoritativeIdPrefixes: ["antigravity:"],
|
|
5662
|
+
retiredIdPrefixes: []
|
|
5663
|
+
}
|
|
5664
|
+
} : {},
|
|
5665
|
+
costs: history?.costs ?? [],
|
|
5666
|
+
warnings,
|
|
5667
|
+
observedAt
|
|
5668
|
+
};
|
|
5669
|
+
}
|
|
5670
|
+
};
|
|
5671
|
+
}
|
|
5672
|
+
});
|
|
5673
|
+
|
|
5674
|
+
// src/server/antigravity-sqlite-usage-client.ts
|
|
5675
|
+
import { createHash as createHash3 } from "crypto";
|
|
5676
|
+
import { readdir, readFile as readFile4, rename as rename3, stat as stat2, writeFile as writeFile3, mkdir as mkdir3 } from "fs/promises";
|
|
5677
|
+
import { createRequire as createRequire2 } from "module";
|
|
5678
|
+
import { dirname as dirname2, join as join5 } from "path";
|
|
5679
|
+
import protobuf from "protobufjs";
|
|
5680
|
+
function parseAntigravityDatabase(dbPath, conversationId, fallbackMtimeMs) {
|
|
5681
|
+
const db = new DatabaseSync2(dbPath, { readOnly: true });
|
|
5682
|
+
try {
|
|
5683
|
+
const tableExists = db.prepare("SELECT 1 FROM sqlite_master WHERE type='table' AND name='gen_metadata'").get();
|
|
5684
|
+
if (!tableExists) return [];
|
|
5685
|
+
const stepTimestamps = /* @__PURE__ */ new Map();
|
|
5686
|
+
try {
|
|
5687
|
+
const stepRows = db.prepare("SELECT idx, metadata FROM steps WHERE length(metadata) > 0").all();
|
|
5688
|
+
for (const row of stepRows) {
|
|
5689
|
+
const ts = extractTimestampFromStepMetadata(row.metadata);
|
|
5690
|
+
if (ts !== null) stepTimestamps.set(row.idx, ts);
|
|
5691
|
+
}
|
|
5692
|
+
} catch {
|
|
5693
|
+
}
|
|
5694
|
+
const genRows = db.prepare("SELECT idx, data FROM gen_metadata ORDER BY idx ASC").all();
|
|
5695
|
+
const records = [];
|
|
5696
|
+
for (const row of genRows) {
|
|
5697
|
+
if (!row.data || row.data.length === 0) continue;
|
|
5698
|
+
const parsed = decodeGenMetadata(row.data);
|
|
5699
|
+
if (parsed.inputTokens === 0 && parsed.outputTokens === 0 && parsed.cacheReadTokens === 0) {
|
|
5700
|
+
continue;
|
|
5701
|
+
}
|
|
5702
|
+
const timestampMs = stepTimestamps.get(row.idx) ?? fallbackMtimeMs;
|
|
5703
|
+
const observedAt = new Date(timestampMs).toISOString();
|
|
5704
|
+
const dedupeKey = `antigravity:${conversationId}:${row.idx}`;
|
|
5705
|
+
const observation = {
|
|
5706
|
+
id: dedupeKey,
|
|
5707
|
+
billingDomainId: "code-assist-subscription",
|
|
5708
|
+
model: parsed.canonicalModel,
|
|
5709
|
+
observedAt,
|
|
5710
|
+
inputTokens: parsed.inputTokens,
|
|
5711
|
+
outputTokens: parsed.outputTokens,
|
|
5712
|
+
reasoningTokens: 0,
|
|
5713
|
+
cacheReadTokens: parsed.cacheReadTokens,
|
|
5714
|
+
cacheWriteTokens: 0,
|
|
5715
|
+
tokenSemantics: {
|
|
5716
|
+
reasoning: "included-in-output",
|
|
5717
|
+
cacheRead: "separate",
|
|
5718
|
+
cacheWrite: "separate"
|
|
5719
|
+
},
|
|
5720
|
+
modelAttribution: "known",
|
|
5721
|
+
timePrecision: "event",
|
|
5722
|
+
usageScope: "this-mac",
|
|
5723
|
+
aggregationTemporality: "delta",
|
|
5724
|
+
authority: "local-observation"
|
|
5725
|
+
};
|
|
5726
|
+
normalizeTokenObservation(observation);
|
|
5727
|
+
records.push({ dedupeKey, observation });
|
|
5728
|
+
}
|
|
5729
|
+
return records;
|
|
5730
|
+
} finally {
|
|
5731
|
+
db.close();
|
|
5732
|
+
}
|
|
5733
|
+
}
|
|
5734
|
+
function decodeGenMetadata(buf) {
|
|
5735
|
+
let rawModel = "unknown";
|
|
5736
|
+
let inputTokens = 0;
|
|
5737
|
+
const outputTokens = 0;
|
|
5738
|
+
let cacheReadTokens = 0;
|
|
5739
|
+
try {
|
|
5740
|
+
const r = protobuf.Reader.create(buf);
|
|
5741
|
+
while (r.pos < r.len) {
|
|
5742
|
+
const tag = r.uint32();
|
|
5743
|
+
const fn = tag >>> 3;
|
|
5744
|
+
const wt = tag & 7;
|
|
5745
|
+
if (fn === 1 && wt === 2) {
|
|
5746
|
+
const sub1 = r.bytes();
|
|
5747
|
+
const rSub = protobuf.Reader.create(sub1);
|
|
5748
|
+
while (rSub.pos < rSub.len) {
|
|
5749
|
+
const sTag = rSub.uint32();
|
|
5750
|
+
const sFn = sTag >>> 3;
|
|
5751
|
+
const sWt = sTag & 7;
|
|
5752
|
+
if (sFn === 19 && sWt === 2) {
|
|
5753
|
+
rawModel = Buffer.from(rSub.bytes()).toString("utf8");
|
|
5754
|
+
} else if (sFn === 9 && sWt === 2) {
|
|
5755
|
+
const sub9 = rSub.bytes();
|
|
5756
|
+
const r9 = protobuf.Reader.create(sub9);
|
|
5757
|
+
while (r9.pos < r9.len) {
|
|
5758
|
+
const t9 = r9.uint32();
|
|
5759
|
+
const fn9 = t9 >>> 3;
|
|
5760
|
+
const wt9 = t9 & 7;
|
|
5761
|
+
if (fn9 === 10 && wt9 === 2) {
|
|
5762
|
+
const sub10 = r9.bytes();
|
|
5763
|
+
const r10 = protobuf.Reader.create(sub10);
|
|
5764
|
+
while (r10.pos < r10.len) {
|
|
5765
|
+
const t10 = r10.uint32();
|
|
5766
|
+
const fn10 = t10 >>> 3;
|
|
5767
|
+
const wt10 = t10 & 7;
|
|
5768
|
+
if (fn10 === 1 && wt10 === 0) {
|
|
5769
|
+
inputTokens = toNumeric(r10.uint64());
|
|
5770
|
+
} else if (fn10 === 3 && wt10 === 2) {
|
|
5771
|
+
const sub3 = r10.bytes();
|
|
5772
|
+
const r3 = protobuf.Reader.create(sub3);
|
|
5773
|
+
while (r3.pos < r3.len) {
|
|
5774
|
+
const t3 = r3.uint32();
|
|
5775
|
+
const fn3 = t3 >>> 3;
|
|
5776
|
+
const wt3 = t3 & 7;
|
|
5777
|
+
if (fn3 === 2 && wt3 === 0) {
|
|
5778
|
+
cacheReadTokens = toNumeric(r3.uint64());
|
|
5779
|
+
} else {
|
|
5780
|
+
r3.skipType(wt3);
|
|
5781
|
+
}
|
|
5782
|
+
}
|
|
5783
|
+
} else {
|
|
5784
|
+
r10.skipType(wt10);
|
|
5785
|
+
}
|
|
5786
|
+
}
|
|
5787
|
+
} else {
|
|
5788
|
+
r9.skipType(wt9);
|
|
5789
|
+
}
|
|
5790
|
+
}
|
|
5791
|
+
} else {
|
|
5792
|
+
rSub.skipType(sWt);
|
|
5793
|
+
}
|
|
5794
|
+
}
|
|
5795
|
+
} else {
|
|
5796
|
+
r.skipType(wt);
|
|
5797
|
+
}
|
|
5798
|
+
}
|
|
5799
|
+
} catch {
|
|
5800
|
+
}
|
|
5801
|
+
return {
|
|
5802
|
+
rawModel,
|
|
5803
|
+
canonicalModel: canonicalizeAntigravityModel(rawModel),
|
|
5804
|
+
inputTokens,
|
|
5805
|
+
outputTokens,
|
|
5806
|
+
cacheReadTokens
|
|
5807
|
+
};
|
|
5808
|
+
}
|
|
5809
|
+
function canonicalizeAntigravityModel(raw) {
|
|
5810
|
+
const normalized = raw.trim().toLowerCase().replace(/[\s_]+/g, "-");
|
|
5811
|
+
if (normalized.startsWith("gemini-3p7") || normalized.startsWith("gemini-3.7")) {
|
|
5812
|
+
return "gemini-3.7-flash";
|
|
5813
|
+
}
|
|
5814
|
+
if (normalized.startsWith("gemini-3p6") || normalized.startsWith("gemini-3.6")) {
|
|
5815
|
+
return "gemini-3.6-flash";
|
|
5816
|
+
}
|
|
5817
|
+
if (normalized.startsWith("gemini-3p1") || normalized.startsWith("gemini-3.1")) {
|
|
5818
|
+
return "gemini-3.1-pro";
|
|
5819
|
+
}
|
|
5820
|
+
if (normalized.includes("claude-sonnet")) {
|
|
5821
|
+
return "claude-sonnet-4-6";
|
|
5822
|
+
}
|
|
5823
|
+
if (normalized.includes("claude-opus")) {
|
|
5824
|
+
return "claude-opus-4-6-thinking";
|
|
5825
|
+
}
|
|
5826
|
+
if (normalized.includes("gpt-oss")) {
|
|
5827
|
+
return "gpt-oss-120b-medium";
|
|
5828
|
+
}
|
|
5829
|
+
return raw.trim() || "unknown";
|
|
5830
|
+
}
|
|
5831
|
+
function extractTimestampFromStepMetadata(buf) {
|
|
5832
|
+
try {
|
|
5833
|
+
const r = protobuf.Reader.create(buf);
|
|
5834
|
+
while (r.pos < r.len) {
|
|
5835
|
+
const tag = r.uint32();
|
|
5836
|
+
const fn = tag >>> 3;
|
|
5837
|
+
const wt = tag & 7;
|
|
5838
|
+
if (fn === 1 && wt === 2) {
|
|
5839
|
+
const tsBytes = r.bytes();
|
|
5840
|
+
const rTs = protobuf.Reader.create(tsBytes);
|
|
5841
|
+
let seconds = 0;
|
|
5842
|
+
let nanos = 0;
|
|
5843
|
+
while (rTs.pos < rTs.len) {
|
|
5844
|
+
const t = rTs.uint32();
|
|
5845
|
+
const tFn = t >>> 3;
|
|
5846
|
+
const tWt = t & 7;
|
|
5847
|
+
if (tFn === 1 && tWt === 0) {
|
|
5848
|
+
seconds = toNumeric(rTs.uint64());
|
|
5849
|
+
} else if (tFn === 2 && tWt === 0) {
|
|
5850
|
+
nanos = toNumeric(rTs.uint64());
|
|
5851
|
+
} else {
|
|
5852
|
+
rTs.skipType(tWt);
|
|
5853
|
+
}
|
|
5854
|
+
}
|
|
5855
|
+
if (seconds > 0) {
|
|
5856
|
+
return seconds * 1e3 + Math.floor(nanos / 1e6);
|
|
5857
|
+
}
|
|
5858
|
+
} else {
|
|
5859
|
+
r.skipType(wt);
|
|
5860
|
+
}
|
|
5861
|
+
}
|
|
5862
|
+
} catch {
|
|
5863
|
+
}
|
|
5864
|
+
return null;
|
|
5865
|
+
}
|
|
5866
|
+
function toNumeric(val) {
|
|
5867
|
+
return Number(val?.toString?.() ?? 0);
|
|
5868
|
+
}
|
|
5869
|
+
function stableId2(value) {
|
|
5870
|
+
return createHash3("sha256").update(value).digest("hex").slice(0, 16);
|
|
5871
|
+
}
|
|
5872
|
+
function isCachedDatabaseFile(value) {
|
|
5873
|
+
if (typeof value !== "object" || value === null) return false;
|
|
5874
|
+
const rec = value;
|
|
5875
|
+
return typeof rec.path === "string" && typeof rec.size === "number" && typeof rec.mtimeMs === "number" && Array.isArray(rec.records) && typeof rec.recordsDigest === "string";
|
|
5876
|
+
}
|
|
5877
|
+
var DatabaseSync2, AntigravitySqliteUsageClient;
|
|
5878
|
+
var init_antigravity_sqlite_usage_client = __esm({
|
|
5879
|
+
"src/server/antigravity-sqlite-usage-client.ts"() {
|
|
5880
|
+
"use strict";
|
|
5881
|
+
init_token_normalization();
|
|
5882
|
+
init_retail_pricing();
|
|
5883
|
+
({ DatabaseSync: DatabaseSync2 } = createRequire2(import.meta.url)(
|
|
5884
|
+
"node:sqlite"
|
|
5885
|
+
));
|
|
5886
|
+
AntigravitySqliteUsageClient = class {
|
|
5887
|
+
#roots;
|
|
5888
|
+
#clock;
|
|
5889
|
+
#lookbackDays;
|
|
5890
|
+
#cachePath;
|
|
5891
|
+
#priceCatalog;
|
|
5892
|
+
#fileCache = /* @__PURE__ */ new Map();
|
|
5893
|
+
#cacheLoaded = false;
|
|
5894
|
+
constructor(options) {
|
|
5895
|
+
this.#roots = options.roots;
|
|
5896
|
+
this.#clock = options.clock ?? (() => /* @__PURE__ */ new Date());
|
|
5897
|
+
this.#lookbackDays = options.lookbackDays ?? 90;
|
|
5898
|
+
this.#cachePath = options.cachePath;
|
|
5899
|
+
this.#priceCatalog = options.priceCatalog ?? OFFICIAL_PRICING_CATALOG;
|
|
5900
|
+
}
|
|
5901
|
+
async readUsage(options = { mode: "incremental" }) {
|
|
5902
|
+
await this.#loadCache();
|
|
5903
|
+
if (options.mode === "hard-rebuild") this.#fileCache.clear();
|
|
5904
|
+
const cutoff = this.#clock().getTime() - this.#lookbackDays * 24 * 60 * 60 * 1e3;
|
|
5905
|
+
const discoveredFiles = await this.#discoverDatabases(cutoff);
|
|
5906
|
+
const livePaths = new Set(discoveredFiles.map((file) => stableId2(file.path)));
|
|
5907
|
+
for (const path of this.#fileCache.keys()) {
|
|
5908
|
+
if (!livePaths.has(path)) this.#fileCache.delete(path);
|
|
5909
|
+
}
|
|
5910
|
+
const usage = [];
|
|
5911
|
+
const seenDedupeKeys = /* @__PURE__ */ new Set();
|
|
5912
|
+
let allComplete = true;
|
|
5913
|
+
for (const file of discoveredFiles) {
|
|
5914
|
+
const parsed = await this.#parseDatabaseFile(file);
|
|
5915
|
+
allComplete &&= parsed.complete;
|
|
5916
|
+
for (const record of parsed.records) {
|
|
5917
|
+
if (new Date(record.observation.observedAt).getTime() < cutoff) continue;
|
|
5918
|
+
if (seenDedupeKeys.has(record.dedupeKey)) continue;
|
|
5919
|
+
seenDedupeKeys.add(record.dedupeKey);
|
|
5920
|
+
usage.push(record.observation);
|
|
4983
5921
|
}
|
|
4984
|
-
} catch (error) {
|
|
4985
|
-
warnings.push(safeFailure6(error));
|
|
4986
5922
|
}
|
|
4987
|
-
|
|
4988
|
-
|
|
5923
|
+
usage.sort((a, b) => a.observedAt.localeCompare(b.observedAt) || a.id.localeCompare(b.id));
|
|
5924
|
+
const { costs } = deriveRetailEquivalentCosts(
|
|
5925
|
+
{
|
|
5926
|
+
provider: { id: "antigravity", displayName: "Antigravity" },
|
|
5927
|
+
billingDomains: [{ id: "code-assist-subscription", displayName: "Gemini Code Assist" }],
|
|
5928
|
+
quotaBuckets: [],
|
|
5929
|
+
usage,
|
|
5930
|
+
costs: [],
|
|
5931
|
+
observedAt: this.#clock().toISOString()
|
|
5932
|
+
},
|
|
5933
|
+
this.#priceCatalog
|
|
5934
|
+
);
|
|
5935
|
+
await this.#persistCache();
|
|
4989
5936
|
return {
|
|
4990
|
-
|
|
4991
|
-
|
|
4992
|
-
|
|
4993
|
-
usage: history.usage,
|
|
4994
|
-
...history.usage.length > 0 && history.complete ? {
|
|
4995
|
-
usageReconciliation: {
|
|
4996
|
-
authoritativeIdPrefixes: ["grok-transcript:"],
|
|
4997
|
-
retiredIdPrefixes: ["grok-otel:", "grok-headless:"]
|
|
4998
|
-
}
|
|
4999
|
-
} : {},
|
|
5000
|
-
costs: history.costs,
|
|
5001
|
-
warnings,
|
|
5002
|
-
observedAt
|
|
5937
|
+
usage,
|
|
5938
|
+
costs,
|
|
5939
|
+
complete: allComplete
|
|
5003
5940
|
};
|
|
5004
5941
|
}
|
|
5942
|
+
async #discoverDatabases(cutoff) {
|
|
5943
|
+
const results = [];
|
|
5944
|
+
const seenDbPaths = /* @__PURE__ */ new Set();
|
|
5945
|
+
for (const root of this.#roots) {
|
|
5946
|
+
try {
|
|
5947
|
+
const rootStat = await stat2(root);
|
|
5948
|
+
if (!rootStat.isDirectory()) continue;
|
|
5949
|
+
} catch {
|
|
5950
|
+
continue;
|
|
5951
|
+
}
|
|
5952
|
+
const summariesPath = join5(root, "conversation_summaries.db");
|
|
5953
|
+
const candidateIds = /* @__PURE__ */ new Set();
|
|
5954
|
+
let summariesLoaded = false;
|
|
5955
|
+
try {
|
|
5956
|
+
const summariesStat = await stat2(summariesPath);
|
|
5957
|
+
if (summariesStat.isFile()) {
|
|
5958
|
+
const db = new DatabaseSync2(summariesPath, { readOnly: true });
|
|
5959
|
+
try {
|
|
5960
|
+
const rows = db.prepare("SELECT conversation_id, last_modified_time FROM conversation_summaries").all();
|
|
5961
|
+
for (const row of rows) {
|
|
5962
|
+
if (!row.conversation_id) continue;
|
|
5963
|
+
const modifiedMs = row.last_modified_time ? new Date(row.last_modified_time).getTime() : 0;
|
|
5964
|
+
if (modifiedMs >= cutoff || modifiedMs === 0) {
|
|
5965
|
+
candidateIds.add(row.conversation_id);
|
|
5966
|
+
}
|
|
5967
|
+
}
|
|
5968
|
+
summariesLoaded = true;
|
|
5969
|
+
} finally {
|
|
5970
|
+
db.close();
|
|
5971
|
+
}
|
|
5972
|
+
}
|
|
5973
|
+
} catch {
|
|
5974
|
+
}
|
|
5975
|
+
const convDir = join5(root, "conversations");
|
|
5976
|
+
try {
|
|
5977
|
+
const entries = await readdir(convDir);
|
|
5978
|
+
for (const entry of entries) {
|
|
5979
|
+
if (!entry.endsWith(".db")) continue;
|
|
5980
|
+
const convId = entry.slice(0, -3);
|
|
5981
|
+
if (summariesLoaded && candidateIds.size > 0 && !candidateIds.has(convId)) {
|
|
5982
|
+
continue;
|
|
5983
|
+
}
|
|
5984
|
+
const fullPath = join5(convDir, entry);
|
|
5985
|
+
if (seenDbPaths.has(fullPath)) continue;
|
|
5986
|
+
seenDbPaths.add(fullPath);
|
|
5987
|
+
try {
|
|
5988
|
+
const fileStat = await stat2(fullPath);
|
|
5989
|
+
if (fileStat.mtimeMs < cutoff && summariesLoaded) continue;
|
|
5990
|
+
results.push({
|
|
5991
|
+
path: fullPath,
|
|
5992
|
+
size: fileStat.size,
|
|
5993
|
+
mtimeMs: fileStat.mtimeMs,
|
|
5994
|
+
conversationId: convId
|
|
5995
|
+
});
|
|
5996
|
+
} catch {
|
|
5997
|
+
}
|
|
5998
|
+
}
|
|
5999
|
+
} catch {
|
|
6000
|
+
}
|
|
6001
|
+
}
|
|
6002
|
+
return results;
|
|
6003
|
+
}
|
|
6004
|
+
async #parseDatabaseFile(file) {
|
|
6005
|
+
const cached = this.#fileCache.get(stableId2(file.path));
|
|
6006
|
+
if (cached && cached.size === file.size && cached.mtimeMs === file.mtimeMs) {
|
|
6007
|
+
return { records: cached.records, complete: true };
|
|
6008
|
+
}
|
|
6009
|
+
try {
|
|
6010
|
+
const records = parseAntigravityDatabase(file.path, file.conversationId, file.mtimeMs);
|
|
6011
|
+
const digest = stableId2(JSON.stringify(records));
|
|
6012
|
+
this.#fileCache.set(stableId2(file.path), {
|
|
6013
|
+
path: file.path,
|
|
6014
|
+
size: file.size,
|
|
6015
|
+
mtimeMs: file.mtimeMs,
|
|
6016
|
+
records,
|
|
6017
|
+
recordsDigest: digest
|
|
6018
|
+
});
|
|
6019
|
+
return { records, complete: true };
|
|
6020
|
+
} catch {
|
|
6021
|
+
return { records: [], complete: false };
|
|
6022
|
+
}
|
|
6023
|
+
}
|
|
6024
|
+
async #loadCache() {
|
|
6025
|
+
if (this.#cacheLoaded) return;
|
|
6026
|
+
this.#cacheLoaded = true;
|
|
6027
|
+
if (!this.#cachePath) return;
|
|
6028
|
+
try {
|
|
6029
|
+
const content = await readFile4(this.#cachePath, "utf8");
|
|
6030
|
+
const stored = JSON.parse(content);
|
|
6031
|
+
if (stored.version !== 1 || !Array.isArray(stored.files)) return;
|
|
6032
|
+
for (const item of stored.files) {
|
|
6033
|
+
if (!isCachedDatabaseFile(item)) continue;
|
|
6034
|
+
if (item.recordsDigest !== stableId2(JSON.stringify(item.records))) continue;
|
|
6035
|
+
this.#fileCache.set(stableId2(item.path), item);
|
|
6036
|
+
}
|
|
6037
|
+
} catch {
|
|
6038
|
+
}
|
|
6039
|
+
}
|
|
6040
|
+
async #persistCache() {
|
|
6041
|
+
if (!this.#cachePath) return;
|
|
6042
|
+
try {
|
|
6043
|
+
await mkdir3(dirname2(this.#cachePath), { recursive: true, mode: 448 });
|
|
6044
|
+
const temporary = `${this.#cachePath}.${process.pid}.tmp`;
|
|
6045
|
+
await writeFile3(
|
|
6046
|
+
temporary,
|
|
6047
|
+
JSON.stringify({ version: 1, files: [...this.#fileCache.values()] }),
|
|
6048
|
+
{ mode: 384 }
|
|
6049
|
+
);
|
|
6050
|
+
await rename3(temporary, this.#cachePath);
|
|
6051
|
+
} catch {
|
|
6052
|
+
}
|
|
6053
|
+
}
|
|
5005
6054
|
};
|
|
5006
6055
|
}
|
|
5007
6056
|
});
|
|
@@ -5066,7 +6115,7 @@ function parseGrokOtlpMetrics(payload, receivedAt) {
|
|
|
5066
6115
|
return snapshot(
|
|
5067
6116
|
[...usage.entries()].map(([key, item]) => ({
|
|
5068
6117
|
id: `grok-otel:${key}`,
|
|
5069
|
-
billingDomainId:
|
|
6118
|
+
billingDomainId: resolveGrokBillingDomain(item.model),
|
|
5070
6119
|
model: item.model,
|
|
5071
6120
|
sessionId: item.sessionId,
|
|
5072
6121
|
observedAt: item.timestamp,
|
|
@@ -5093,7 +6142,7 @@ function parseGrokOtlpMetrics(payload, receivedAt) {
|
|
|
5093
6142
|
function snapshot(usage, warnings, receivedAt) {
|
|
5094
6143
|
return {
|
|
5095
6144
|
provider: { id: "grok", displayName: "Grok" },
|
|
5096
|
-
billingDomains:
|
|
6145
|
+
billingDomains: grokBuildBillingDomains(usage),
|
|
5097
6146
|
quotaBuckets: [],
|
|
5098
6147
|
usage,
|
|
5099
6148
|
costs: [],
|
|
@@ -5123,8 +6172,8 @@ var init_grok_telemetry = __esm({
|
|
|
5123
6172
|
// src/connectors/grok-build/stdio-grok-billing-client.ts
|
|
5124
6173
|
import { spawn as spawn3 } from "child_process";
|
|
5125
6174
|
import { open } from "fs/promises";
|
|
5126
|
-
import { homedir as
|
|
5127
|
-
import { join as
|
|
6175
|
+
import { homedir as homedir3 } from "os";
|
|
6176
|
+
import { join as join6 } from "path";
|
|
5128
6177
|
import { z as z7 } from "zod";
|
|
5129
6178
|
function billingIsFresh(billing, now) {
|
|
5130
6179
|
if (!billing.sourceObservedAt) return false;
|
|
@@ -5249,7 +6298,7 @@ var init_stdio_grok_billing_client = __esm({
|
|
|
5249
6298
|
stdio: ["pipe", "pipe", "pipe"]
|
|
5250
6299
|
}));
|
|
5251
6300
|
this.#readUnifiedLog = options.readUnifiedLog ?? (() => readLogTail(
|
|
5252
|
-
|
|
6301
|
+
join6(process.env.GROK_HOME ?? join6(homedir3(), ".grok"), "logs", "unified.jsonl")
|
|
5253
6302
|
));
|
|
5254
6303
|
this.#refreshBillingLog = options.refreshBillingLog ?? (options.readUnifiedLog ? async () => void 0 : () => refreshBillingLogViaDashboard(this.#command, this.#timeoutMs));
|
|
5255
6304
|
this.#clock = options.clock ?? (() => /* @__PURE__ */ new Date());
|
|
@@ -5620,7 +6669,7 @@ function endpointFailure(error, label) {
|
|
|
5620
6669
|
recovery: "Check network access and xAI status, then retry."
|
|
5621
6670
|
};
|
|
5622
6671
|
}
|
|
5623
|
-
function
|
|
6672
|
+
function safeFailure8(error) {
|
|
5624
6673
|
if (error instanceof Error && "code" in error && typeof error.code === "string" && "recovery" in error && typeof error.recovery === "string") {
|
|
5625
6674
|
return { code: error.code, message: error.message, recovery: error.recovery };
|
|
5626
6675
|
}
|
|
@@ -5875,7 +6924,7 @@ var init_xai_api_connector = __esm({
|
|
|
5875
6924
|
costs: [],
|
|
5876
6925
|
balances: [],
|
|
5877
6926
|
invoices: [],
|
|
5878
|
-
warnings: [
|
|
6927
|
+
warnings: [safeFailure8(error)],
|
|
5879
6928
|
observedAt
|
|
5880
6929
|
};
|
|
5881
6930
|
}
|
|
@@ -6074,8 +7123,8 @@ var init_macos_notifier = __esm({
|
|
|
6074
7123
|
});
|
|
6075
7124
|
|
|
6076
7125
|
// src/server/macos-start-at-login-manager.ts
|
|
6077
|
-
import { mkdir as
|
|
6078
|
-
import { dirname as
|
|
7126
|
+
import { mkdir as mkdir4, rm, writeFile as writeFile4 } from "fs/promises";
|
|
7127
|
+
import { dirname as dirname3, isAbsolute, join as join7 } from "path";
|
|
6079
7128
|
function launchAgentPlist(options) {
|
|
6080
7129
|
const label = options.label ?? LABEL;
|
|
6081
7130
|
const arguments_ = [
|
|
@@ -6127,15 +7176,15 @@ var init_macos_start_at_login_manager = __esm({
|
|
|
6127
7176
|
const label = validateLaunchAgentLabel(options.label ?? LABEL);
|
|
6128
7177
|
if (options.nodeImport) validateNodeImport(options.nodeImport);
|
|
6129
7178
|
this.#options = { ...options, label };
|
|
6130
|
-
this.#path =
|
|
7179
|
+
this.#path = join7(options.userHome, "Library", "LaunchAgents", `${label}.plist`);
|
|
6131
7180
|
}
|
|
6132
7181
|
async setEnabled(enabled) {
|
|
6133
7182
|
if (!enabled) {
|
|
6134
7183
|
await rm(this.#path, { force: true });
|
|
6135
7184
|
return;
|
|
6136
7185
|
}
|
|
6137
|
-
await
|
|
6138
|
-
await
|
|
7186
|
+
await mkdir4(dirname3(this.#path), { recursive: true, mode: 448 });
|
|
7187
|
+
await writeFile4(this.#path, launchAgentPlist(this.#options), { mode: 384 });
|
|
6139
7188
|
}
|
|
6140
7189
|
async isEnabled() {
|
|
6141
7190
|
try {
|
|
@@ -6252,7 +7301,7 @@ var init_otlp_protobuf = __esm({
|
|
|
6252
7301
|
// src/server/local-server.ts
|
|
6253
7302
|
import { createReadStream as createReadStream2, existsSync, statSync } from "fs";
|
|
6254
7303
|
import { createServer } from "http";
|
|
6255
|
-
import { extname, join as
|
|
7304
|
+
import { extname, join as join8, normalize, resolve } from "path";
|
|
6256
7305
|
import { randomBytes } from "crypto";
|
|
6257
7306
|
import { z as z9 } from "zod";
|
|
6258
7307
|
async function startLocalServer(options) {
|
|
@@ -6432,6 +7481,53 @@ async function startLocalServer(options) {
|
|
|
6432
7481
|
sendJson(response, 200, await options.application.updatePlanSubscription(input));
|
|
6433
7482
|
return;
|
|
6434
7483
|
}
|
|
7484
|
+
if (request.method === "GET" && requestUrl.pathname === "/api/custom-rates") {
|
|
7485
|
+
const rates = await options.application.getCustomModelRates();
|
|
7486
|
+
sendJson(response, 200, { rates });
|
|
7487
|
+
return;
|
|
7488
|
+
}
|
|
7489
|
+
if (request.method === "GET" && requestUrl.pathname.startsWith("/api/custom-rates/")) {
|
|
7490
|
+
const id = decodeURIComponent(requestUrl.pathname.slice("/api/custom-rates/".length));
|
|
7491
|
+
const rate = await options.application.getCustomModelRate(id);
|
|
7492
|
+
if (!rate) {
|
|
7493
|
+
sendJson(response, 404, { error: "rate-not-found" });
|
|
7494
|
+
return;
|
|
7495
|
+
}
|
|
7496
|
+
sendJson(response, 200, { rate });
|
|
7497
|
+
return;
|
|
7498
|
+
}
|
|
7499
|
+
if (request.method === "POST" && requestUrl.pathname === "/api/custom-rates") {
|
|
7500
|
+
if (!validMutationOrigin(authentication, request, origin)) {
|
|
7501
|
+
sendJson(response, 403, { error: "invalid-origin" });
|
|
7502
|
+
return;
|
|
7503
|
+
}
|
|
7504
|
+
const input = customModelRateSchema.parse(await readJsonBody(request));
|
|
7505
|
+
const rate = await options.application.setCustomModelRate(input);
|
|
7506
|
+
sendJson(response, 200, { rate });
|
|
7507
|
+
return;
|
|
7508
|
+
}
|
|
7509
|
+
if ((request.method === "PUT" || request.method === "PATCH") && requestUrl.pathname.startsWith("/api/custom-rates/")) {
|
|
7510
|
+
if (!validMutationOrigin(authentication, request, origin)) {
|
|
7511
|
+
sendJson(response, 403, { error: "invalid-origin" });
|
|
7512
|
+
return;
|
|
7513
|
+
}
|
|
7514
|
+
const id = decodeURIComponent(requestUrl.pathname.slice("/api/custom-rates/".length));
|
|
7515
|
+
const body = await readJsonBody(request);
|
|
7516
|
+
const input = customModelRateSchema.parse({ ...body, id });
|
|
7517
|
+
const rate = await options.application.setCustomModelRate(input);
|
|
7518
|
+
sendJson(response, 200, { rate });
|
|
7519
|
+
return;
|
|
7520
|
+
}
|
|
7521
|
+
if (request.method === "DELETE" && requestUrl.pathname.startsWith("/api/custom-rates/")) {
|
|
7522
|
+
if (!validMutationOrigin(authentication, request, origin)) {
|
|
7523
|
+
sendJson(response, 403, { error: "invalid-origin" });
|
|
7524
|
+
return;
|
|
7525
|
+
}
|
|
7526
|
+
const id = decodeURIComponent(requestUrl.pathname.slice("/api/custom-rates/".length));
|
|
7527
|
+
const deleted = await options.application.deleteCustomModelRate(id);
|
|
7528
|
+
sendJson(response, 200, { deleted });
|
|
7529
|
+
return;
|
|
7530
|
+
}
|
|
6435
7531
|
if (request.method === "GET" && requestUrl.pathname === "/api/monitoring") {
|
|
6436
7532
|
sendJson(response, 200, await options.application.getMonitoringStatus());
|
|
6437
7533
|
return;
|
|
@@ -6488,8 +7584,7 @@ async function startLocalServer(options) {
|
|
|
6488
7584
|
}
|
|
6489
7585
|
sendJson(response, 404, { error: "not-found" });
|
|
6490
7586
|
} catch (error) {
|
|
6491
|
-
|
|
6492
|
-
sendJson(response, 500, { error: "internal-error", message });
|
|
7587
|
+
respondWithFailure(response, error);
|
|
6493
7588
|
}
|
|
6494
7589
|
});
|
|
6495
7590
|
await new Promise((resolveListening, reject) => {
|
|
@@ -6575,8 +7670,8 @@ async function serveStatic(response, pathname, staticDirectory) {
|
|
|
6575
7670
|
const root = resolve(staticDirectory);
|
|
6576
7671
|
const requested = pathname === "/" ? "index.html" : pathname.replace(/^\/+/, "");
|
|
6577
7672
|
const normalized = normalize(requested);
|
|
6578
|
-
const candidate = resolve(
|
|
6579
|
-
const indexFile =
|
|
7673
|
+
const candidate = resolve(join8(root, normalized));
|
|
7674
|
+
const indexFile = join8(root, "index.html");
|
|
6580
7675
|
const file = candidate.startsWith(`${root}/`) && existsSync(candidate) && statSync(candidate).isFile() ? candidate : indexFile;
|
|
6581
7676
|
if (!existsSync(file)) {
|
|
6582
7677
|
sendText(response, 404, "Dashboard assets are not built");
|
|
@@ -6609,11 +7704,28 @@ function secureToken() {
|
|
|
6609
7704
|
return randomBytes(32).toString("base64url");
|
|
6610
7705
|
}
|
|
6611
7706
|
function sendJson(response, status, body) {
|
|
7707
|
+
const payload = JSON.stringify(body);
|
|
6612
7708
|
response.writeHead(status, {
|
|
6613
7709
|
"content-type": "application/json; charset=utf-8",
|
|
6614
7710
|
"cache-control": "no-store"
|
|
6615
7711
|
});
|
|
6616
|
-
response.end(
|
|
7712
|
+
response.end(payload);
|
|
7713
|
+
}
|
|
7714
|
+
function respondWithFailure(response, error) {
|
|
7715
|
+
const message = publicErrorMessage(error);
|
|
7716
|
+
if (response.headersSent || response.writableEnded) {
|
|
7717
|
+
process.stderr.write(`Agent Usage: a started response failed to finish: ${message}
|
|
7718
|
+
`);
|
|
7719
|
+
response.destroy();
|
|
7720
|
+
return;
|
|
7721
|
+
}
|
|
7722
|
+
try {
|
|
7723
|
+
sendJson(response, 500, { error: "internal-error", message });
|
|
7724
|
+
} catch {
|
|
7725
|
+
process.stderr.write(`Agent Usage: a request failed without a reportable reason.
|
|
7726
|
+
`);
|
|
7727
|
+
response.destroy();
|
|
7728
|
+
}
|
|
6617
7729
|
}
|
|
6618
7730
|
function sendOtlpProtobuf(response, status) {
|
|
6619
7731
|
response.writeHead(status, {
|
|
@@ -6630,7 +7742,7 @@ function sendHtml(response, status, body) {
|
|
|
6630
7742
|
response.writeHead(status, { "content-type": "text/html; charset=utf-8" });
|
|
6631
7743
|
response.end(body);
|
|
6632
7744
|
}
|
|
6633
|
-
var SESSION_COOKIE, connectorActionSchema, usageQuerySchema, monitoringSettingsSchema, planSubscriptionSchema, clearDataSchema, hardRebuildSchema;
|
|
7745
|
+
var SESSION_COOKIE, connectorActionSchema, usageQuerySchema, monitoringSettingsSchema, planSubscriptionSchema, customModelRateSchema, clearDataSchema, hardRebuildSchema;
|
|
6634
7746
|
var init_local_server = __esm({
|
|
6635
7747
|
"src/server/local-server.ts"() {
|
|
6636
7748
|
"use strict";
|
|
@@ -6664,6 +7776,15 @@ var init_local_server = __esm({
|
|
|
6664
7776
|
anchorDate: z9.string().regex(/^\d{4}-\d{2}-\d{2}$/).nullable().optional()
|
|
6665
7777
|
}).nullable()
|
|
6666
7778
|
});
|
|
7779
|
+
customModelRateSchema = z9.object({
|
|
7780
|
+
id: z9.string().optional(),
|
|
7781
|
+
providerId: z9.string().min(1),
|
|
7782
|
+
billingDomainId: z9.string().nullable().optional(),
|
|
7783
|
+
model: z9.string().min(1),
|
|
7784
|
+
inputRate: z9.number().nonnegative(),
|
|
7785
|
+
outputRate: z9.number().nonnegative(),
|
|
7786
|
+
cacheReadRate: z9.number().nonnegative().optional()
|
|
7787
|
+
});
|
|
6667
7788
|
clearDataSchema = z9.object({ deleteProductSecrets: z9.boolean().default(false) });
|
|
6668
7789
|
hardRebuildSchema = z9.object({ confirmExpensiveOperation: z9.literal(true) });
|
|
6669
7790
|
}
|
|
@@ -6672,7 +7793,7 @@ var init_local_server = __esm({
|
|
|
6672
7793
|
// src/server/path-discovery-probe.ts
|
|
6673
7794
|
import { constants } from "fs";
|
|
6674
7795
|
import { access } from "fs/promises";
|
|
6675
|
-
import { delimiter, isAbsolute as isAbsolute2, join as
|
|
7796
|
+
import { delimiter, isAbsolute as isAbsolute2, join as join9, resolve as resolve2 } from "path";
|
|
6676
7797
|
async function isExecutable(path) {
|
|
6677
7798
|
try {
|
|
6678
7799
|
await access(path, constants.X_OK);
|
|
@@ -6718,7 +7839,7 @@ var init_path_discovery_probe = __esm({
|
|
|
6718
7839
|
async #findExecutable(command) {
|
|
6719
7840
|
if (command.includes("/")) return await isExecutable(command) ? resolve2(command) : null;
|
|
6720
7841
|
for (const directory of this.#path.split(delimiter).filter(Boolean)) {
|
|
6721
|
-
const candidate =
|
|
7842
|
+
const candidate = join9(directory, command);
|
|
6722
7843
|
if (await isExecutable(candidate)) return candidate;
|
|
6723
7844
|
}
|
|
6724
7845
|
return null;
|
|
@@ -6729,8 +7850,8 @@ var init_path_discovery_probe = __esm({
|
|
|
6729
7850
|
|
|
6730
7851
|
// src/server/sqlite-usage-repository.ts
|
|
6731
7852
|
import { mkdirSync } from "fs";
|
|
6732
|
-
import { createRequire as
|
|
6733
|
-
import { dirname as
|
|
7853
|
+
import { createRequire as createRequire3 } from "module";
|
|
7854
|
+
import { dirname as dirname4 } from "path";
|
|
6734
7855
|
import { Worker } from "worker_threads";
|
|
6735
7856
|
async function runDatabaseWorker(workerData) {
|
|
6736
7857
|
return new Promise((resolve5, reject) => {
|
|
@@ -7096,7 +8217,7 @@ function buildGlobalSummary(providers, riskSummary, now, query) {
|
|
|
7096
8217
|
for (const observedAt of [
|
|
7097
8218
|
domain.history.lastObservedAt,
|
|
7098
8219
|
...domain.quotaBuckets.map((bucket) => bucket.observedAt ?? null),
|
|
7099
|
-
|
|
8220
|
+
domain.lastCostObservedAt,
|
|
7100
8221
|
...domain.balances.map((balance) => balance.observedAt),
|
|
7101
8222
|
...domain.invoices.map((invoice) => invoice.createdAt)
|
|
7102
8223
|
]) {
|
|
@@ -7358,7 +8479,7 @@ function allDomainHistories(providers) {
|
|
|
7358
8479
|
provider,
|
|
7359
8480
|
domain,
|
|
7360
8481
|
history: domain.history,
|
|
7361
|
-
includedInHeadline: domain.id === provider.summaryBillingDomainId
|
|
8482
|
+
includedInHeadline: provider.id === "dsh" || provider.id === "grok" && domain.id !== "xai-api" ? true : domain.id === provider.summaryBillingDomainId
|
|
7362
8483
|
}))
|
|
7363
8484
|
);
|
|
7364
8485
|
}
|
|
@@ -7436,25 +8557,28 @@ function buildWorkbenchModelRanking(histories, buckets, comparisonCurrency, reco
|
|
|
7436
8557
|
const entries = histories.flatMap(
|
|
7437
8558
|
({ provider, domain, history, includedInHeadline }) => history.models.map((model) => {
|
|
7438
8559
|
const retailEquivalent = buildWorkbenchMetric(
|
|
7439
|
-
model.priceEvidence,
|
|
8560
|
+
model.priceEvidence ?? [],
|
|
7440
8561
|
"retail-equivalent",
|
|
7441
8562
|
comparisonCurrency,
|
|
7442
8563
|
model.tokenEvidence.recordedTokens,
|
|
7443
8564
|
history.exchangeRates
|
|
7444
8565
|
);
|
|
7445
8566
|
const reportedEstimate = buildWorkbenchMetric(
|
|
7446
|
-
model.priceEvidence,
|
|
8567
|
+
model.priceEvidence ?? [],
|
|
7447
8568
|
"reported-estimate",
|
|
7448
8569
|
comparisonCurrency,
|
|
7449
8570
|
model.tokenEvidence.recordedTokens,
|
|
7450
8571
|
history.exchangeRates
|
|
7451
8572
|
);
|
|
8573
|
+
const observations = model.observations ?? [];
|
|
8574
|
+
const priceEvidence = model.priceEvidence ?? [];
|
|
7452
8575
|
const authorities = [
|
|
7453
|
-
...new Set(
|
|
8576
|
+
...new Set(observations.map((observation) => observation.authority))
|
|
7454
8577
|
].sort();
|
|
7455
|
-
const lastObservedAt =
|
|
7456
|
-
(
|
|
7457
|
-
|
|
8578
|
+
const lastObservedAt = observations.reduce(
|
|
8579
|
+
(latest, observation) => latest === null || observation.observedAt > latest ? observation.observedAt : latest,
|
|
8580
|
+
null
|
|
8581
|
+
) ?? null;
|
|
7458
8582
|
return {
|
|
7459
8583
|
id: modelRankingId(provider.id, domain.id, model.model),
|
|
7460
8584
|
providerId: provider.id,
|
|
@@ -7472,28 +8596,28 @@ function buildWorkbenchModelRanking(histories, buckets, comparisonCurrency, reco
|
|
|
7472
8596
|
reportedShare: includedInHeadline && reportedEstimate.status === "available" && reportedEstimate.amount !== null && totalReportedEstimate.status === "available" && totalReportedEstimate.amount !== null && totalReportedEstimate.amount !== 0 ? reportedEstimate.amount / totalReportedEstimate.amount : null,
|
|
7473
8597
|
authorities,
|
|
7474
8598
|
lastObservedAt,
|
|
7475
|
-
|
|
7476
|
-
|
|
8599
|
+
composition: nonOverlappingComposition(observations, model.tokenTotals),
|
|
8600
|
+
priceSnapshots: distinctPriceSnapshots(priceEvidence),
|
|
7477
8601
|
trend: buckets.map((bucket) => {
|
|
7478
|
-
const
|
|
8602
|
+
const bucketObservations = observations.filter(
|
|
7479
8603
|
(observation) => observation.observedAt >= bucket.start && observation.observedAt < bucket.end
|
|
7480
8604
|
);
|
|
7481
|
-
const
|
|
8605
|
+
const bucketPriceEvidence = priceEvidence.filter(
|
|
7482
8606
|
(cost) => (cost.observedAt ?? "") >= bucket.start && (cost.observedAt ?? "") < bucket.end
|
|
7483
8607
|
);
|
|
7484
|
-
const tokenTotals =
|
|
8608
|
+
const tokenTotals = bucketObservations.reduce(
|
|
7485
8609
|
(total, observation) => addTokenTotals(total, observation.tokenTotals),
|
|
7486
8610
|
zeroTokenTotals()
|
|
7487
8611
|
);
|
|
7488
8612
|
const intervalRetail = buildWorkbenchMetric(
|
|
7489
|
-
|
|
8613
|
+
bucketPriceEvidence,
|
|
7490
8614
|
"retail-equivalent",
|
|
7491
8615
|
comparisonCurrency,
|
|
7492
8616
|
tokenTotals.total,
|
|
7493
8617
|
history.exchangeRates
|
|
7494
8618
|
);
|
|
7495
8619
|
const intervalReported = buildWorkbenchMetric(
|
|
7496
|
-
|
|
8620
|
+
bucketPriceEvidence,
|
|
7497
8621
|
"reported-estimate",
|
|
7498
8622
|
comparisonCurrency,
|
|
7499
8623
|
tokenTotals.total,
|
|
@@ -7503,14 +8627,19 @@ function buildWorkbenchModelRanking(histories, buckets, comparisonCurrency, reco
|
|
|
7503
8627
|
start: bucket.start,
|
|
7504
8628
|
end: bucket.end,
|
|
7505
8629
|
label: bucket.label,
|
|
7506
|
-
gap:
|
|
8630
|
+
gap: bucketObservations.length === 0,
|
|
7507
8631
|
tokenTotals,
|
|
8632
|
+
recordedTokens: bucketObservations.reduce(
|
|
8633
|
+
(total, observation) => total + observation.recordedTokens,
|
|
8634
|
+
0
|
|
8635
|
+
),
|
|
7508
8636
|
authorities: [
|
|
7509
|
-
...new Set(
|
|
8637
|
+
...new Set(bucketObservations.map((observation) => observation.authority))
|
|
7510
8638
|
].sort(),
|
|
7511
|
-
lastObservedAt:
|
|
7512
|
-
(
|
|
7513
|
-
|
|
8639
|
+
lastObservedAt: bucketObservations.reduce(
|
|
8640
|
+
(latest, observation) => latest === null || observation.observedAt > latest ? observation.observedAt : latest,
|
|
8641
|
+
null
|
|
8642
|
+
) ?? null,
|
|
7514
8643
|
retailEquivalent: {
|
|
7515
8644
|
status: intervalRetail.status,
|
|
7516
8645
|
amount: intervalRetail.amount,
|
|
@@ -7587,6 +8716,49 @@ function buildWorkbenchModelRanking(histories, buckets, comparisonCurrency, reco
|
|
|
7587
8716
|
unclassified
|
|
7588
8717
|
};
|
|
7589
8718
|
}
|
|
8719
|
+
function dropAuditEvidence(providers) {
|
|
8720
|
+
for (const provider of providers) {
|
|
8721
|
+
for (const domain of provider.billingDomains) {
|
|
8722
|
+
for (const model of domain.history.models) {
|
|
8723
|
+
delete model.observations;
|
|
8724
|
+
delete model.priceEvidence;
|
|
8725
|
+
}
|
|
8726
|
+
delete domain.history.unclassified.observations;
|
|
8727
|
+
}
|
|
8728
|
+
}
|
|
8729
|
+
}
|
|
8730
|
+
function nonOverlappingComposition(observations, fallback) {
|
|
8731
|
+
if (observations.length === 0) {
|
|
8732
|
+
return {
|
|
8733
|
+
...fallback,
|
|
8734
|
+
total: fallback.input + fallback.output + fallback.cacheRead + fallback.cacheWrite
|
|
8735
|
+
};
|
|
8736
|
+
}
|
|
8737
|
+
const totals = zeroTokenTotals();
|
|
8738
|
+
for (const observation of observations) {
|
|
8739
|
+
totals.input += observation.tokenTotals.input;
|
|
8740
|
+
totals.output += observation.tokenTotals.output;
|
|
8741
|
+
if (observation.tokenSemantics.reasoning === "separate") {
|
|
8742
|
+
totals.reasoning += observation.tokenTotals.reasoning;
|
|
8743
|
+
}
|
|
8744
|
+
if (observation.tokenSemantics.cacheRead === "separate") {
|
|
8745
|
+
totals.cacheRead += observation.tokenTotals.cacheRead;
|
|
8746
|
+
}
|
|
8747
|
+
if (observation.tokenSemantics.cacheWrite === "separate") {
|
|
8748
|
+
totals.cacheWrite += observation.tokenTotals.cacheWrite;
|
|
8749
|
+
}
|
|
8750
|
+
}
|
|
8751
|
+
totals.total = totals.input + totals.output + totals.reasoning + totals.cacheRead + totals.cacheWrite;
|
|
8752
|
+
return totals;
|
|
8753
|
+
}
|
|
8754
|
+
function distinctPriceSnapshots(priceEvidence) {
|
|
8755
|
+
const snapshots = /* @__PURE__ */ new Map();
|
|
8756
|
+
for (const evidence of priceEvidence) {
|
|
8757
|
+
const snapshot2 = evidence.priceSnapshot;
|
|
8758
|
+
if (snapshot2 && !snapshots.has(snapshot2.id)) snapshots.set(snapshot2.id, snapshot2);
|
|
8759
|
+
}
|
|
8760
|
+
return [...snapshots.values()];
|
|
8761
|
+
}
|
|
7590
8762
|
function modelRankingId(providerId, billingDomainId, model) {
|
|
7591
8763
|
return `${providerId}::${billingDomainId}::${model}`;
|
|
7592
8764
|
}
|
|
@@ -8034,7 +9206,7 @@ function freshnessStatus(lastSuccessAt, now) {
|
|
|
8034
9206
|
if (!lastSuccessAt) return "unavailable";
|
|
8035
9207
|
return now.getTime() - new Date(lastSuccessAt).getTime() <= FRESHNESS_WINDOW_MS ? "fresh" : "stale";
|
|
8036
9208
|
}
|
|
8037
|
-
var FRESHNESS_WINDOW_MS, QUERY_INDEXES_SQL, DELETE_DERIVED_RETAIL_COSTS_SQL, DELETE_DEMO_PROVIDER_DATA_SQL,
|
|
9209
|
+
var FRESHNESS_WINDOW_MS, QUERY_INDEXES_SQL, DELETE_DERIVED_RETAIL_COSTS_SQL, DELETE_DEMO_PROVIDER_DATA_SQL, DatabaseSync3, RETENTION_AGGREGATE_SQL, SqliteUsageRepository;
|
|
8038
9210
|
var init_sqlite_usage_repository = __esm({
|
|
8039
9211
|
"src/server/sqlite-usage-repository.ts"() {
|
|
8040
9212
|
"use strict";
|
|
@@ -8075,7 +9247,7 @@ var init_sqlite_usage_repository = __esm({
|
|
|
8075
9247
|
DELETE FROM connector_settings WHERE id = 'demo';
|
|
8076
9248
|
DELETE FROM providers WHERE id = 'demo';
|
|
8077
9249
|
`;
|
|
8078
|
-
({ DatabaseSync:
|
|
9250
|
+
({ DatabaseSync: DatabaseSync3 } = createRequire3(import.meta.url)(
|
|
8079
9251
|
"node:sqlite"
|
|
8080
9252
|
));
|
|
8081
9253
|
RETENTION_AGGREGATE_SQL = `
|
|
@@ -8106,8 +9278,8 @@ var init_sqlite_usage_repository = __esm({
|
|
|
8106
9278
|
constructor(databasePath, options = {}) {
|
|
8107
9279
|
this.#databasePath = databasePath;
|
|
8108
9280
|
this.#hideDemoProvider = options.hideDemoProvider ?? false;
|
|
8109
|
-
mkdirSync(
|
|
8110
|
-
this.#database = new
|
|
9281
|
+
mkdirSync(dirname4(databasePath), { recursive: true });
|
|
9282
|
+
this.#database = new DatabaseSync3(databasePath);
|
|
8111
9283
|
this.#database.exec("PRAGMA journal_mode = WAL; PRAGMA foreign_keys = ON;");
|
|
8112
9284
|
this.#migrate();
|
|
8113
9285
|
}
|
|
@@ -8171,6 +9343,22 @@ var init_sqlite_usage_repository = __esm({
|
|
|
8171
9343
|
limit_currency = excluded.limit_currency,
|
|
8172
9344
|
fallback_status = excluded.fallback_status`
|
|
8173
9345
|
);
|
|
9346
|
+
const reportedQuotaDomains = [
|
|
9347
|
+
...new Set(snapshot2.quotaBuckets.map((bucket) => bucket.billingDomainId))
|
|
9348
|
+
];
|
|
9349
|
+
if (reportedQuotaDomains.length > 0) {
|
|
9350
|
+
const retiredQuotaStatement = this.#database.prepare(
|
|
9351
|
+
`DELETE FROM quota_buckets
|
|
9352
|
+
WHERE provider_id = ? AND billing_domain_id = ? AND id NOT IN (${snapshot2.quotaBuckets.map(() => "?").join(", ")})`
|
|
9353
|
+
);
|
|
9354
|
+
for (const billingDomainId of reportedQuotaDomains) {
|
|
9355
|
+
retiredQuotaStatement.run(
|
|
9356
|
+
snapshot2.provider.id,
|
|
9357
|
+
billingDomainId,
|
|
9358
|
+
...snapshot2.quotaBuckets.map((bucket) => bucket.id)
|
|
9359
|
+
);
|
|
9360
|
+
}
|
|
9361
|
+
}
|
|
8174
9362
|
for (const bucket of snapshot2.quotaBuckets) {
|
|
8175
9363
|
quotaStatement.run(
|
|
8176
9364
|
snapshot2.provider.id,
|
|
@@ -8532,7 +9720,12 @@ var init_sqlite_usage_repository = __esm({
|
|
|
8532
9720
|
price_snapshot_source_url, price_snapshot_context_tier,
|
|
8533
9721
|
model, usage_observation_id, priced_tokens, line_items_json, calculated_at
|
|
8534
9722
|
) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
|
|
8535
|
-
ON CONFLICT(provider_id, id) DO
|
|
9723
|
+
ON CONFLICT(provider_id, id) DO UPDATE SET
|
|
9724
|
+
billing_domain_id = excluded.billing_domain_id,
|
|
9725
|
+
amount = excluded.amount,
|
|
9726
|
+
price_snapshot_rates_json = excluded.price_snapshot_rates_json,
|
|
9727
|
+
line_items_json = excluded.line_items_json,
|
|
9728
|
+
calculated_at = excluded.calculated_at`
|
|
8536
9729
|
);
|
|
8537
9730
|
this.#database.exec("BEGIN IMMEDIATE");
|
|
8538
9731
|
try {
|
|
@@ -8602,7 +9795,7 @@ var init_sqlite_usage_repository = __esm({
|
|
|
8602
9795
|
);
|
|
8603
9796
|
const riskSummary = buildRiskSummary(overviews);
|
|
8604
9797
|
const planSubscriptions = this.getPlanSubscriptions();
|
|
8605
|
-
|
|
9798
|
+
const overview = {
|
|
8606
9799
|
generatedAt: now.toISOString(),
|
|
8607
9800
|
globalSummary: buildGlobalSummary(overviews, riskSummary, now, query),
|
|
8608
9801
|
workbench: buildTokenMoneyWorkbench(
|
|
@@ -8615,13 +9808,15 @@ var init_sqlite_usage_repository = __esm({
|
|
|
8615
9808
|
providers: overviews,
|
|
8616
9809
|
riskSummary
|
|
8617
9810
|
};
|
|
9811
|
+
if (!query.auditEvidence) dropAuditEvidence(overviews);
|
|
9812
|
+
return overview;
|
|
8618
9813
|
}
|
|
8619
9814
|
getAgentProviderIndex(now) {
|
|
8620
9815
|
const providers = this.#database.prepare("SELECT id, display_name FROM providers ORDER BY id").all();
|
|
8621
9816
|
return {
|
|
8622
9817
|
generatedAt: now.toISOString(),
|
|
8623
9818
|
providers: providers.filter(
|
|
8624
|
-
(provider) => provider.id !== "opencode" && (!this.#hideDemoProvider || provider.id !== "demo")
|
|
9819
|
+
(provider) => provider.id !== "opencode" && provider.id !== "dsh" && (!this.#hideDemoProvider || provider.id !== "demo")
|
|
8625
9820
|
).map((provider) => ({ id: provider.id, displayName: provider.display_name }))
|
|
8626
9821
|
};
|
|
8627
9822
|
}
|
|
@@ -8631,7 +9826,10 @@ var init_sqlite_usage_repository = __esm({
|
|
|
8631
9826
|
`SELECT id, display_name, last_success_at, last_error, last_error_code, last_recovery
|
|
8632
9827
|
FROM providers WHERE id = ?`
|
|
8633
9828
|
).get(providerId);
|
|
8634
|
-
|
|
9829
|
+
if (!provider) return null;
|
|
9830
|
+
const overview = this.#getProviderOverview(provider, now, query);
|
|
9831
|
+
if (!query.auditEvidence) dropAuditEvidence([overview]);
|
|
9832
|
+
return overview;
|
|
8635
9833
|
}
|
|
8636
9834
|
saveExchangeRateSnapshot(snapshot2) {
|
|
8637
9835
|
this.#database.prepare(
|
|
@@ -8759,6 +9957,95 @@ var init_sqlite_usage_repository = __esm({
|
|
|
8759
9957
|
deletePlanSubscription(providerId, billingDomainId) {
|
|
8760
9958
|
this.#database.prepare("DELETE FROM plan_subscriptions WHERE provider_id = ? AND billing_domain_id = ?").run(providerId, billingDomainId);
|
|
8761
9959
|
}
|
|
9960
|
+
getCustomModelRates() {
|
|
9961
|
+
const rows = this.#database.prepare(
|
|
9962
|
+
`SELECT id, provider_id, billing_domain_id, model,
|
|
9963
|
+
input_rate, output_rate, cache_read_rate, updated_at
|
|
9964
|
+
FROM custom_model_rates
|
|
9965
|
+
ORDER BY updated_at DESC`
|
|
9966
|
+
).all();
|
|
9967
|
+
return rows.map((row) => ({
|
|
9968
|
+
id: row.id,
|
|
9969
|
+
providerId: row.provider_id,
|
|
9970
|
+
billingDomainId: row.billing_domain_id ?? null,
|
|
9971
|
+
model: row.model,
|
|
9972
|
+
ratesPerMillion: {
|
|
9973
|
+
input: row.input_rate,
|
|
9974
|
+
output: row.output_rate,
|
|
9975
|
+
cacheRead: row.cache_read_rate
|
|
9976
|
+
},
|
|
9977
|
+
updatedAt: row.updated_at
|
|
9978
|
+
}));
|
|
9979
|
+
}
|
|
9980
|
+
getCustomModelRate(id) {
|
|
9981
|
+
const row = this.#database.prepare(
|
|
9982
|
+
`SELECT id, provider_id, billing_domain_id, model,
|
|
9983
|
+
input_rate, output_rate, cache_read_rate, updated_at
|
|
9984
|
+
FROM custom_model_rates
|
|
9985
|
+
WHERE id = ?`
|
|
9986
|
+
).get(id);
|
|
9987
|
+
if (!row) return null;
|
|
9988
|
+
return {
|
|
9989
|
+
id: row.id,
|
|
9990
|
+
providerId: row.provider_id,
|
|
9991
|
+
billingDomainId: row.billing_domain_id ?? null,
|
|
9992
|
+
model: row.model,
|
|
9993
|
+
ratesPerMillion: {
|
|
9994
|
+
input: row.input_rate,
|
|
9995
|
+
output: row.output_rate,
|
|
9996
|
+
cacheRead: row.cache_read_rate
|
|
9997
|
+
},
|
|
9998
|
+
updatedAt: row.updated_at
|
|
9999
|
+
};
|
|
10000
|
+
}
|
|
10001
|
+
saveCustomModelRate(rate) {
|
|
10002
|
+
const byId = this.#database.prepare("SELECT id FROM custom_model_rates WHERE id = ?").get(rate.id);
|
|
10003
|
+
const byKey = this.#database.prepare(
|
|
10004
|
+
`SELECT id FROM custom_model_rates
|
|
10005
|
+
WHERE provider_id = ? AND COALESCE(billing_domain_id, '') = COALESCE(?, '') AND lower(model) = lower(?)`
|
|
10006
|
+
).get(rate.providerId, rate.billingDomainId, rate.model);
|
|
10007
|
+
if (byId && byKey && byId.id !== byKey.id) {
|
|
10008
|
+
this.#database.prepare("DELETE FROM custom_model_rates WHERE id = ?").run(byKey.id);
|
|
10009
|
+
}
|
|
10010
|
+
const existingId = byId?.id ?? byKey?.id;
|
|
10011
|
+
if (existingId) {
|
|
10012
|
+
this.#database.prepare(
|
|
10013
|
+
`UPDATE custom_model_rates SET
|
|
10014
|
+
provider_id = ?, billing_domain_id = ?, model = ?,
|
|
10015
|
+
input_rate = ?, output_rate = ?, cache_read_rate = ?, updated_at = ?
|
|
10016
|
+
WHERE id = ?`
|
|
10017
|
+
).run(
|
|
10018
|
+
rate.providerId,
|
|
10019
|
+
rate.billingDomainId,
|
|
10020
|
+
rate.model,
|
|
10021
|
+
rate.ratesPerMillion.input,
|
|
10022
|
+
rate.ratesPerMillion.output,
|
|
10023
|
+
rate.ratesPerMillion.cacheRead,
|
|
10024
|
+
rate.updatedAt,
|
|
10025
|
+
existingId
|
|
10026
|
+
);
|
|
10027
|
+
} else {
|
|
10028
|
+
this.#database.prepare(
|
|
10029
|
+
`INSERT INTO custom_model_rates (
|
|
10030
|
+
id, provider_id, billing_domain_id, model,
|
|
10031
|
+
input_rate, output_rate, cache_read_rate, updated_at
|
|
10032
|
+
) VALUES (?, ?, ?, ?, ?, ?, ?, ?)`
|
|
10033
|
+
).run(
|
|
10034
|
+
rate.id,
|
|
10035
|
+
rate.providerId,
|
|
10036
|
+
rate.billingDomainId,
|
|
10037
|
+
rate.model,
|
|
10038
|
+
rate.ratesPerMillion.input,
|
|
10039
|
+
rate.ratesPerMillion.output,
|
|
10040
|
+
rate.ratesPerMillion.cacheRead,
|
|
10041
|
+
rate.updatedAt
|
|
10042
|
+
);
|
|
10043
|
+
}
|
|
10044
|
+
}
|
|
10045
|
+
deleteCustomModelRate(id) {
|
|
10046
|
+
const result = this.#database.prepare("DELETE FROM custom_model_rates WHERE id = ?").run(id);
|
|
10047
|
+
return result.changes > 0;
|
|
10048
|
+
}
|
|
8762
10049
|
getNotificationState(key) {
|
|
8763
10050
|
const row = this.#database.prepare("SELECT value FROM notification_state WHERE key = ?").get(key);
|
|
8764
10051
|
return row?.value ?? null;
|
|
@@ -8976,7 +10263,7 @@ var init_sqlite_usage_repository = __esm({
|
|
|
8976
10263
|
FROM billing_domains WHERE provider_id = ? ORDER BY id`
|
|
8977
10264
|
).all(provider.id);
|
|
8978
10265
|
const summaryBillingDomainId = selectSummaryBillingDomainId(provider.id, domainRows);
|
|
8979
|
-
const
|
|
10266
|
+
const billingDomains3 = domainRows.map(
|
|
8980
10267
|
(domain) => this.#getBillingDomainOverview(
|
|
8981
10268
|
provider.id,
|
|
8982
10269
|
domain,
|
|
@@ -8988,7 +10275,7 @@ var init_sqlite_usage_repository = __esm({
|
|
|
8988
10275
|
domainRows.length === 1 ? provider : null
|
|
8989
10276
|
)
|
|
8990
10277
|
);
|
|
8991
|
-
const summaryDomain =
|
|
10278
|
+
const summaryDomain = billingDomains3.find((domain) => domain.id === summaryBillingDomainId);
|
|
8992
10279
|
const emptyTotals = zeroTokenTotals();
|
|
8993
10280
|
const emptyEvidence = finishTokenEvidence(emptyTokenEvidence());
|
|
8994
10281
|
const emptyCoverage = {
|
|
@@ -9003,6 +10290,24 @@ var init_sqlite_usage_repository = __esm({
|
|
|
9003
10290
|
message: provider.last_error,
|
|
9004
10291
|
recovery: provider.last_recovery
|
|
9005
10292
|
} : { status: "healthy", errorCode: null, message: null, recovery: null };
|
|
10293
|
+
let providerTokenTotals = summaryDomain?.tokenTotals ?? emptyTotals;
|
|
10294
|
+
let providerTokenEvidence = summaryDomain?.tokenEvidence ?? emptyEvidence;
|
|
10295
|
+
if ((provider.id === "dsh" || provider.id === "grok") && billingDomains3.length > 1) {
|
|
10296
|
+
const combinedTotals = zeroTokenTotals();
|
|
10297
|
+
const combinedEvidence = emptyTokenEvidence();
|
|
10298
|
+
for (const d of billingDomains3) {
|
|
10299
|
+
if (provider.id === "grok" && d.id === "xai-api") continue;
|
|
10300
|
+
combinedTotals.total += d.tokenTotals.total;
|
|
10301
|
+
combinedTotals.input += d.tokenTotals.input;
|
|
10302
|
+
combinedTotals.output += d.tokenTotals.output;
|
|
10303
|
+
combinedTotals.reasoning += d.tokenTotals.reasoning;
|
|
10304
|
+
combinedTotals.cacheRead += d.tokenTotals.cacheRead;
|
|
10305
|
+
combinedTotals.cacheWrite += d.tokenTotals.cacheWrite;
|
|
10306
|
+
addAggregatedTokenEvidence(combinedEvidence, d.tokenEvidence);
|
|
10307
|
+
}
|
|
10308
|
+
providerTokenTotals = combinedTotals;
|
|
10309
|
+
providerTokenEvidence = finishTokenEvidence(combinedEvidence);
|
|
10310
|
+
}
|
|
9006
10311
|
return {
|
|
9007
10312
|
id: provider.id,
|
|
9008
10313
|
displayName: provider.display_name,
|
|
@@ -9014,10 +10319,10 @@ var init_sqlite_usage_repository = __esm({
|
|
|
9014
10319
|
health: summaryDomain?.health ?? providerFallbackHealth,
|
|
9015
10320
|
coverage: summaryDomain?.coverage ?? emptyCoverage,
|
|
9016
10321
|
quotaBuckets: summaryDomain?.quotaBuckets ?? [],
|
|
9017
|
-
tokenTotals:
|
|
9018
|
-
tokenEvidence:
|
|
10322
|
+
tokenTotals: providerTokenTotals,
|
|
10323
|
+
tokenEvidence: providerTokenEvidence,
|
|
9019
10324
|
tokenAuthority: summaryDomain?.tokenAuthority ?? null,
|
|
9020
|
-
billingDomains:
|
|
10325
|
+
billingDomains: billingDomains3,
|
|
9021
10326
|
forecasts: summaryDomain?.forecasts ?? [],
|
|
9022
10327
|
forecastCoverage: summaryDomain?.forecastCoverage ?? "insufficient"
|
|
9023
10328
|
};
|
|
@@ -9049,7 +10354,7 @@ var init_sqlite_usage_repository = __esm({
|
|
|
9049
10354
|
FROM usage_observations
|
|
9050
10355
|
WHERE provider_id = ? AND billing_domain_id = ? AND ${additiveUsagePredicate()}`
|
|
9051
10356
|
).get(providerId, domain.id);
|
|
9052
|
-
const costs = this.#database.prepare(
|
|
10357
|
+
const costs = query.auditEvidence ? this.#database.prepare(
|
|
9053
10358
|
`SELECT id, source_id, billing_domain_id, observed_at, kind, amount, currency, authority,
|
|
9054
10359
|
price_snapshot_id, price_snapshot_version, price_snapshot_source,
|
|
9055
10360
|
price_snapshot_canonical_model, price_snapshot_effective_at,
|
|
@@ -9058,7 +10363,11 @@ var init_sqlite_usage_repository = __esm({
|
|
|
9058
10363
|
price_snapshot_context_tier, model, usage_observation_id, priced_tokens,
|
|
9059
10364
|
line_items_json, calculated_at
|
|
9060
10365
|
FROM cost_records WHERE provider_id = ? AND billing_domain_id = ? ORDER BY observed_at DESC, id`
|
|
9061
|
-
).all(providerId, domain.id);
|
|
10366
|
+
).all(providerId, domain.id) : null;
|
|
10367
|
+
const lastCostObservedAt = this.#database.prepare(
|
|
10368
|
+
`SELECT MAX(observed_at) AS observed_at FROM cost_records
|
|
10369
|
+
WHERE provider_id = ? AND billing_domain_id = ?`
|
|
10370
|
+
).get(providerId, domain.id).observed_at ?? null;
|
|
9062
10371
|
const balances = this.#database.prepare(
|
|
9063
10372
|
`SELECT id, source_id, billing_domain_id, observed_at, kind, amount, currency, authority
|
|
9064
10373
|
FROM balance_records WHERE provider_id = ? AND billing_domain_id = ? ORDER BY observed_at DESC, id`
|
|
@@ -9067,7 +10376,12 @@ var init_sqlite_usage_repository = __esm({
|
|
|
9067
10376
|
`SELECT id, billing_domain_id, created_at, number, status, amount, currency, authority
|
|
9068
10377
|
FROM invoice_records WHERE provider_id = ? AND billing_domain_id = ? ORDER BY created_at DESC, id`
|
|
9069
10378
|
).all(providerId, domain.id);
|
|
9070
|
-
const actualCostCount =
|
|
10379
|
+
const actualCostCount = Number(
|
|
10380
|
+
this.#database.prepare(
|
|
10381
|
+
`SELECT COUNT(*) AS count FROM cost_records
|
|
10382
|
+
WHERE provider_id = ? AND billing_domain_id = ? AND kind = 'actual'`
|
|
10383
|
+
).get(providerId, domain.id).count
|
|
10384
|
+
);
|
|
9071
10385
|
const nonAdditiveTokenCount = this.#database.prepare(
|
|
9072
10386
|
`SELECT COUNT(*) AS count FROM usage_observations
|
|
9073
10387
|
WHERE provider_id = ? AND billing_domain_id = ?
|
|
@@ -9097,22 +10411,25 @@ var init_sqlite_usage_repository = __esm({
|
|
|
9097
10411
|
tokenTotals: mapTokenTotals(tokens),
|
|
9098
10412
|
tokenEvidence: mapTokenEvidence(tokens),
|
|
9099
10413
|
tokenAuthority: tokenAuthority(tokens.authorities),
|
|
9100
|
-
costs
|
|
9101
|
-
|
|
9102
|
-
|
|
9103
|
-
|
|
9104
|
-
|
|
9105
|
-
|
|
9106
|
-
|
|
9107
|
-
|
|
9108
|
-
|
|
9109
|
-
|
|
9110
|
-
|
|
9111
|
-
|
|
9112
|
-
|
|
9113
|
-
|
|
9114
|
-
|
|
9115
|
-
|
|
10414
|
+
...costs ? {
|
|
10415
|
+
costs: costs.map((row) => ({
|
|
10416
|
+
id: row.id,
|
|
10417
|
+
sourceId: row.source_id,
|
|
10418
|
+
billingDomainId: row.billing_domain_id,
|
|
10419
|
+
observedAt: row.observed_at,
|
|
10420
|
+
kind: row.kind,
|
|
10421
|
+
amount: row.amount,
|
|
10422
|
+
currency: row.currency,
|
|
10423
|
+
authority: row.authority,
|
|
10424
|
+
priceSnapshot: priceSnapshotFromRow(row),
|
|
10425
|
+
model: row.model,
|
|
10426
|
+
usageObservationId: row.usage_observation_id,
|
|
10427
|
+
pricedTokens: row.priced_tokens,
|
|
10428
|
+
lineItems: parseLineItems(row.line_items_json),
|
|
10429
|
+
calculatedAt: row.calculated_at
|
|
10430
|
+
}))
|
|
10431
|
+
} : {},
|
|
10432
|
+
lastCostObservedAt,
|
|
9116
10433
|
balances: balances.map((row) => ({
|
|
9117
10434
|
id: row.id,
|
|
9118
10435
|
sourceId: row.source_id,
|
|
@@ -9733,6 +11050,18 @@ var init_sqlite_usage_repository = __esm({
|
|
|
9733
11050
|
updated_at TEXT NOT NULL,
|
|
9734
11051
|
PRIMARY KEY (provider_id, billing_domain_id)
|
|
9735
11052
|
);
|
|
11053
|
+
CREATE TABLE IF NOT EXISTS custom_model_rates (
|
|
11054
|
+
id TEXT PRIMARY KEY,
|
|
11055
|
+
provider_id TEXT NOT NULL,
|
|
11056
|
+
billing_domain_id TEXT,
|
|
11057
|
+
model TEXT NOT NULL,
|
|
11058
|
+
input_rate REAL NOT NULL,
|
|
11059
|
+
output_rate REAL NOT NULL,
|
|
11060
|
+
cache_read_rate REAL NOT NULL,
|
|
11061
|
+
updated_at TEXT NOT NULL
|
|
11062
|
+
);
|
|
11063
|
+
CREATE UNIQUE INDEX IF NOT EXISTS idx_custom_model_rates_key
|
|
11064
|
+
ON custom_model_rates(provider_id, COALESCE(billing_domain_id, ''), lower(model));
|
|
9736
11065
|
`);
|
|
9737
11066
|
const usageColumns = this.#database.prepare("PRAGMA table_info(usage_observations)").all();
|
|
9738
11067
|
if (!usageColumns.some((column) => column.name === "total_tokens")) {
|
|
@@ -9890,9 +11219,9 @@ var init_sqlite_usage_repository = __esm({
|
|
|
9890
11219
|
`);
|
|
9891
11220
|
const quotaColumns = this.#database.prepare("PRAGMA table_info(quota_buckets)").all();
|
|
9892
11221
|
for (const [name, type] of [
|
|
11222
|
+
["window_duration_minutes", "INTEGER"],
|
|
9893
11223
|
["scope", "TEXT"],
|
|
9894
11224
|
["status", "TEXT"],
|
|
9895
|
-
["window_duration_minutes", "INTEGER"],
|
|
9896
11225
|
["limit_amount", "REAL"],
|
|
9897
11226
|
["limit_currency", "TEXT"],
|
|
9898
11227
|
["fallback_status", "TEXT"]
|
|
@@ -9916,14 +11245,14 @@ __export(runtime_exports, {
|
|
|
9916
11245
|
runDaemon: () => runDaemon
|
|
9917
11246
|
});
|
|
9918
11247
|
import { existsSync as existsSync2 } from "fs";
|
|
9919
|
-
import { mkdir as
|
|
9920
|
-
import { homedir as
|
|
9921
|
-
import { isAbsolute as isAbsolute3, join as
|
|
11248
|
+
import { mkdir as mkdir5, rm as rm2 } from "fs/promises";
|
|
11249
|
+
import { homedir as homedir4 } from "os";
|
|
11250
|
+
import { isAbsolute as isAbsolute3, join as join10, resolve as resolve3 } from "path";
|
|
9922
11251
|
import { fileURLToPath } from "url";
|
|
9923
11252
|
async function runDaemon(home) {
|
|
9924
|
-
await
|
|
11253
|
+
await mkdir5(home, { recursive: true, mode: 448 });
|
|
9925
11254
|
const demoEnabled = process.env.AGENT_USAGE_DEMO === "1";
|
|
9926
|
-
const repository = new SqliteUsageRepository(
|
|
11255
|
+
const repository = new SqliteUsageRepository(join10(home, "usage.sqlite"), {
|
|
9927
11256
|
hideDemoProvider: !demoEnabled
|
|
9928
11257
|
});
|
|
9929
11258
|
const keychainService = process.env.AGENT_USAGE_KEYCHAIN_SERVICE;
|
|
@@ -9958,7 +11287,16 @@ async function runDaemon(home) {
|
|
|
9958
11287
|
historyClient: localTranscriptClient("grok", home)
|
|
9959
11288
|
}),
|
|
9960
11289
|
new XaiApiConnector({ accountClient: new XaiManagementApiClient({ secretStore }) }),
|
|
9961
|
-
new DshConnector({ historyClient: localTranscriptClient("dsh", home) })
|
|
11290
|
+
new DshConnector({ historyClient: localTranscriptClient("dsh", home) }),
|
|
11291
|
+
new AntigravityConnector({
|
|
11292
|
+
historyClient: new AntigravitySqliteUsageClient({
|
|
11293
|
+
roots: [
|
|
11294
|
+
join10(homedir4(), ".gemini/antigravity-cli"),
|
|
11295
|
+
join10(homedir4(), ".gemini/antigravity")
|
|
11296
|
+
],
|
|
11297
|
+
cachePath: join10(home, "antigravity-usage-cache.json")
|
|
11298
|
+
})
|
|
11299
|
+
})
|
|
9962
11300
|
],
|
|
9963
11301
|
connectorDefinitions: defaultConnectorDefinitions,
|
|
9964
11302
|
discoveryProbe: new PathDiscoveryProbe(),
|
|
@@ -9966,7 +11304,7 @@ async function runDaemon(home) {
|
|
|
9966
11304
|
exchangeRateProvider: new EcbExchangeRateProvider(),
|
|
9967
11305
|
notifier: new MacOsNotifier(),
|
|
9968
11306
|
startAtLoginManager: new MacOsStartAtLoginManager({
|
|
9969
|
-
userHome:
|
|
11307
|
+
userHome: homedir4(),
|
|
9970
11308
|
executable: process.execPath,
|
|
9971
11309
|
cliPath: process.argv[1],
|
|
9972
11310
|
applicationHome: home,
|
|
@@ -9981,7 +11319,16 @@ async function runDaemon(home) {
|
|
|
9981
11319
|
}
|
|
9982
11320
|
}),
|
|
9983
11321
|
connectorPolicies: Object.fromEntries(
|
|
9984
|
-
[
|
|
11322
|
+
[
|
|
11323
|
+
"codex",
|
|
11324
|
+
"claude-code",
|
|
11325
|
+
"opencode-go",
|
|
11326
|
+
"opencode",
|
|
11327
|
+
"grok",
|
|
11328
|
+
"xai-api",
|
|
11329
|
+
"dsh",
|
|
11330
|
+
"antigravity"
|
|
11331
|
+
].map((id) => [
|
|
9985
11332
|
id,
|
|
9986
11333
|
{ minimumIntervalMs: 5 * 60 * 1e3, timeoutMs: id === "claude-code" ? 25e3 : 2e4 }
|
|
9987
11334
|
])
|
|
@@ -10032,7 +11379,7 @@ async function runDaemon(home) {
|
|
|
10032
11379
|
scheduler.stop();
|
|
10033
11380
|
await server.close();
|
|
10034
11381
|
repository.close();
|
|
10035
|
-
await rm2(
|
|
11382
|
+
await rm2(join10(home, "daemon.json"), { force: true });
|
|
10036
11383
|
resolveStop();
|
|
10037
11384
|
};
|
|
10038
11385
|
process.once("SIGTERM", () => void stop());
|
|
@@ -10043,27 +11390,27 @@ function localTranscriptClient(provider, applicationHome) {
|
|
|
10043
11390
|
return new LocalTranscriptUsageClient({
|
|
10044
11391
|
provider,
|
|
10045
11392
|
roots: localTranscriptRoots(provider),
|
|
10046
|
-
cachePath:
|
|
11393
|
+
cachePath: join10(applicationHome, "cache", `${provider}-transcripts.json`)
|
|
10047
11394
|
});
|
|
10048
11395
|
}
|
|
10049
11396
|
function localTranscriptRoots(provider) {
|
|
10050
11397
|
if (provider === "codex") {
|
|
10051
11398
|
const home = resolveHomeOverride(process.env.CODEX_HOME, ".codex");
|
|
10052
|
-
return [
|
|
11399
|
+
return [join10(home, "sessions"), join10(home, "archived_sessions")];
|
|
10053
11400
|
}
|
|
10054
11401
|
if (provider === "claude-code") {
|
|
10055
|
-
return [
|
|
11402
|
+
return [join10(resolveHomeOverride(process.env.CLAUDE_CONFIG_DIR, ".claude"), "projects")];
|
|
10056
11403
|
}
|
|
10057
11404
|
if (provider === "dsh") {
|
|
10058
|
-
return [
|
|
11405
|
+
return [join10(resolveHomeOverride(process.env.DSH_HOME, ".dsh"), "sessions")];
|
|
10059
11406
|
}
|
|
10060
|
-
return [
|
|
11407
|
+
return [join10(resolveHomeOverride(process.env.GROK_HOME, ".grok"), "sessions")];
|
|
10061
11408
|
}
|
|
10062
11409
|
function resolveHomeOverride(value, fallback) {
|
|
10063
11410
|
const configured = value?.trim();
|
|
10064
|
-
if (!configured) return
|
|
10065
|
-
if (configured === "~") return
|
|
10066
|
-
if (configured.startsWith("~/")) return
|
|
11411
|
+
if (!configured) return join10(homedir4(), fallback);
|
|
11412
|
+
if (configured === "~") return homedir4();
|
|
11413
|
+
if (configured.startsWith("~/")) return join10(homedir4(), configured.slice(2));
|
|
10067
11414
|
return isAbsolute3(configured) ? configured : resolve3(configured);
|
|
10068
11415
|
}
|
|
10069
11416
|
function createDemoConnector() {
|
|
@@ -10109,7 +11456,7 @@ function locateStaticDirectory() {
|
|
|
10109
11456
|
fileURLToPath(new URL("./web", import.meta.url)),
|
|
10110
11457
|
fileURLToPath(new URL("../../dist/web", import.meta.url))
|
|
10111
11458
|
];
|
|
10112
|
-
return candidates.find((candidate) => existsSync2(
|
|
11459
|
+
return candidates.find((candidate) => existsSync2(join10(candidate, "index.html")));
|
|
10113
11460
|
}
|
|
10114
11461
|
var init_runtime = __esm({
|
|
10115
11462
|
"src/server/runtime.ts"() {
|
|
@@ -10127,6 +11474,8 @@ var init_runtime = __esm({
|
|
|
10127
11474
|
init_opencode_auth_reader();
|
|
10128
11475
|
init_opencode_go_connector();
|
|
10129
11476
|
init_dsh_connector();
|
|
11477
|
+
init_antigravity_connector();
|
|
11478
|
+
init_antigravity_sqlite_usage_client();
|
|
10130
11479
|
init_grok_build_connector();
|
|
10131
11480
|
init_grok_telemetry();
|
|
10132
11481
|
init_stdio_grok_billing_client();
|
|
@@ -10149,8 +11498,8 @@ init_redaction();
|
|
|
10149
11498
|
init_daemon_state();
|
|
10150
11499
|
import { spawn as spawn6 } from "child_process";
|
|
10151
11500
|
import { connect as tcpConnect } from "net";
|
|
10152
|
-
import { homedir as
|
|
10153
|
-
import { join as
|
|
11501
|
+
import { homedir as homedir5 } from "os";
|
|
11502
|
+
import { join as join11, resolve as resolve4 } from "path";
|
|
10154
11503
|
import { Command } from "commander";
|
|
10155
11504
|
import open2 from "open";
|
|
10156
11505
|
var program = new Command();
|
|
@@ -10332,6 +11681,97 @@ program.command("start-at-login <action>").description("enable, disable, or show
|
|
|
10332
11681
|
process.stdout.write(`${status.settings.startAtLogin ? "enabled" : "disabled"}
|
|
10333
11682
|
`);
|
|
10334
11683
|
});
|
|
11684
|
+
var ratesCommand = program.command("rates").description("view and manage custom model rates for custom endpoints");
|
|
11685
|
+
ratesCommand.command("list").description("list configured custom model rates").option("--json", "emit machine-readable JSON").action(async (options) => {
|
|
11686
|
+
const home = resolve4(program.opts().home);
|
|
11687
|
+
const state = await requireDaemonState(home);
|
|
11688
|
+
const response = await fetch(`${state.origin}/api/custom-rates`, {
|
|
11689
|
+
headers: { authorization: `Bearer ${state.apiToken}` }
|
|
11690
|
+
});
|
|
11691
|
+
if (!response.ok) throw new Error(`Daemon returned HTTP ${response.status}`);
|
|
11692
|
+
const data = await response.json();
|
|
11693
|
+
if (options.json) {
|
|
11694
|
+
process.stdout.write(`${JSON.stringify(data.rates, null, 2)}
|
|
11695
|
+
`);
|
|
11696
|
+
return;
|
|
11697
|
+
}
|
|
11698
|
+
if (data.rates.length === 0) {
|
|
11699
|
+
process.stdout.write("No custom model rates configured.\n");
|
|
11700
|
+
return;
|
|
11701
|
+
}
|
|
11702
|
+
for (const rate of data.rates) {
|
|
11703
|
+
const domain = rate.billingDomainId ?? "*";
|
|
11704
|
+
process.stdout.write(
|
|
11705
|
+
`${rate.id} | ${rate.providerId} | domain: ${domain} | model: ${rate.model} | in: $${rate.ratesPerMillion.input}/M | out: $${rate.ratesPerMillion.output}/M | cache: $${rate.ratesPerMillion.cacheRead}/M
|
|
11706
|
+
`
|
|
11707
|
+
);
|
|
11708
|
+
}
|
|
11709
|
+
});
|
|
11710
|
+
ratesCommand.command("set <model>").description("set custom model rate").requiredOption("--provider <provider>", "provider id (e.g. dsh)").option("--domain <domain>", "billing domain id (omit for wildcard across all routes)").requiredOption("--input <rate>", "input rate in USD per million tokens", parseFloat).requiredOption("--output <rate>", "output rate in USD per million tokens", parseFloat).option("--cache-read <rate>", "cache read rate in USD per million tokens", parseFloat, 0).option("--id <id>", "custom model rate ID to update").action(
|
|
11711
|
+
async (model, options) => {
|
|
11712
|
+
const home = resolve4(program.opts().home);
|
|
11713
|
+
const state = await requireDaemonState(home);
|
|
11714
|
+
const response = await fetch(`${state.origin}/api/custom-rates`, {
|
|
11715
|
+
method: "POST",
|
|
11716
|
+
headers: {
|
|
11717
|
+
authorization: `Bearer ${state.apiToken}`,
|
|
11718
|
+
"content-type": "application/json",
|
|
11719
|
+
origin: state.origin
|
|
11720
|
+
},
|
|
11721
|
+
body: JSON.stringify({
|
|
11722
|
+
...options.id ? { id: options.id } : {},
|
|
11723
|
+
providerId: options.provider,
|
|
11724
|
+
billingDomainId: options.domain || null,
|
|
11725
|
+
model,
|
|
11726
|
+
inputRate: options.input,
|
|
11727
|
+
outputRate: options.output,
|
|
11728
|
+
cacheReadRate: options.cacheRead
|
|
11729
|
+
})
|
|
11730
|
+
});
|
|
11731
|
+
if (!response.ok) throw new Error(`Daemon returned HTTP ${response.status}`);
|
|
11732
|
+
const data = await response.json();
|
|
11733
|
+
process.stdout.write(
|
|
11734
|
+
`Custom model rate configured for ${data.rate.model} (ID: ${data.rate.id})
|
|
11735
|
+
`
|
|
11736
|
+
);
|
|
11737
|
+
}
|
|
11738
|
+
);
|
|
11739
|
+
ratesCommand.command("get <id>").description("get details of a custom model rate by ID").option("--json", "emit machine-readable JSON").action(async (id, options) => {
|
|
11740
|
+
const home = resolve4(program.opts().home);
|
|
11741
|
+
const state = await requireDaemonState(home);
|
|
11742
|
+
const response = await fetch(`${state.origin}/api/custom-rates/${encodeURIComponent(id)}`, {
|
|
11743
|
+
headers: { authorization: `Bearer ${state.apiToken}` }
|
|
11744
|
+
});
|
|
11745
|
+
if (!response.ok) {
|
|
11746
|
+
if (response.status === 404) throw new Error(`Custom model rate not found: ${id}`);
|
|
11747
|
+
throw new Error(`Daemon returned HTTP ${response.status}`);
|
|
11748
|
+
}
|
|
11749
|
+
const data = await response.json();
|
|
11750
|
+
if (options.json) {
|
|
11751
|
+
process.stdout.write(`${JSON.stringify(data.rate, null, 2)}
|
|
11752
|
+
`);
|
|
11753
|
+
return;
|
|
11754
|
+
}
|
|
11755
|
+
const domain = data.rate.billingDomainId ?? "*";
|
|
11756
|
+
process.stdout.write(
|
|
11757
|
+
`${data.rate.id} | ${data.rate.providerId} | domain: ${domain} | model: ${data.rate.model} | in: $${data.rate.ratesPerMillion.input}/M | out: $${data.rate.ratesPerMillion.output}/M | cache: $${data.rate.ratesPerMillion.cacheRead}/M | updated: ${data.rate.updatedAt}
|
|
11758
|
+
`
|
|
11759
|
+
);
|
|
11760
|
+
});
|
|
11761
|
+
ratesCommand.command("delete <id>").description("delete custom model rate by ID").action(async (id) => {
|
|
11762
|
+
const home = resolve4(program.opts().home);
|
|
11763
|
+
const state = await requireDaemonState(home);
|
|
11764
|
+
const response = await fetch(`${state.origin}/api/custom-rates/${encodeURIComponent(id)}`, {
|
|
11765
|
+
method: "DELETE",
|
|
11766
|
+
headers: {
|
|
11767
|
+
authorization: `Bearer ${state.apiToken}`,
|
|
11768
|
+
origin: state.origin
|
|
11769
|
+
}
|
|
11770
|
+
});
|
|
11771
|
+
if (!response.ok) throw new Error(`Daemon returned HTTP ${response.status}`);
|
|
11772
|
+
process.stdout.write(`Deleted custom model rate ${id}
|
|
11773
|
+
`);
|
|
11774
|
+
});
|
|
10335
11775
|
program.command("serve").description("run the internal local daemon").action(async () => {
|
|
10336
11776
|
const home = resolve4(program.opts().home);
|
|
10337
11777
|
const { runDaemon: runDaemon2 } = await Promise.resolve().then(() => (init_runtime(), runtime_exports));
|
|
@@ -10515,6 +11955,6 @@ function formatDoctor(report) {
|
|
|
10515
11955
|
].join("\n");
|
|
10516
11956
|
}
|
|
10517
11957
|
function defaultHome() {
|
|
10518
|
-
return
|
|
11958
|
+
return join11(homedir5(), "Library", "Application Support", "Agent Usage");
|
|
10519
11959
|
}
|
|
10520
11960
|
//# sourceMappingURL=cli.js.map
|