agent-usage-all-in-one 0.5.0 → 0.6.0
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 +1537 -191
- 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/BfTUk1IE.js +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/entry/app.Cr-3S01G.js +2 -0
- package/dist/web/_app/immutable/entry/start.BiLBur5x.js +1 -0
- package/dist/web/_app/immutable/nodes/0.Bc_BSNVt.js +1 -0
- package/dist/web/_app/immutable/nodes/1.BYavEZ8T.js +1 -0
- package/dist/web/_app/immutable/nodes/2.ehiOyFDQ.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/chunks/Kc2LV0tw.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
|
}
|
|
@@ -4765,14 +5028,785 @@ var init_local_transcript_usage_client = __esm({
|
|
|
4765
5028
|
async #persistCache() {
|
|
4766
5029
|
if (!this.#cachePath) return;
|
|
4767
5030
|
try {
|
|
4768
|
-
await mkdir2(dirname(this.#cachePath), { recursive: true, mode: 448 });
|
|
5031
|
+
await mkdir2(dirname(this.#cachePath), { recursive: true, mode: 448 });
|
|
5032
|
+
const temporary = `${this.#cachePath}.${process.pid}.tmp`;
|
|
5033
|
+
await writeFile2(
|
|
5034
|
+
temporary,
|
|
5035
|
+
JSON.stringify({ version: 1, files: [...this.#fileCache.values()] }),
|
|
5036
|
+
{ mode: 384 }
|
|
5037
|
+
);
|
|
5038
|
+
await rename2(temporary, this.#cachePath);
|
|
5039
|
+
} catch {
|
|
5040
|
+
}
|
|
5041
|
+
}
|
|
5042
|
+
};
|
|
5043
|
+
}
|
|
5044
|
+
});
|
|
5045
|
+
|
|
5046
|
+
// src/connectors/dsh/dsh-connector.ts
|
|
5047
|
+
function billingDomains(usage) {
|
|
5048
|
+
const primary = { id: DSH_PRIMARY_BILLING_DOMAIN_ID, displayName: "DeepSeek API" };
|
|
5049
|
+
const observedRoutes = [...new Set(usage.map((observation) => observation.billingDomainId))].filter((id) => id !== primary.id).sort();
|
|
5050
|
+
return [primary, ...observedRoutes.map((id) => ({ id, displayName: id }))];
|
|
5051
|
+
}
|
|
5052
|
+
function incompleteSessionLogFailure() {
|
|
5053
|
+
return {
|
|
5054
|
+
code: "dsh-session-log-scan-incomplete",
|
|
5055
|
+
message: "Some local dsh session history could not be read.",
|
|
5056
|
+
recovery: "Agent Usage will retry automatically without removing stored history."
|
|
5057
|
+
};
|
|
5058
|
+
}
|
|
5059
|
+
function unsupportedFormatFailure() {
|
|
5060
|
+
return {
|
|
5061
|
+
code: "dsh-session-format-unsupported",
|
|
5062
|
+
message: "A dsh session log declares an on-disk format this version does not read.",
|
|
5063
|
+
recovery: "Update Agent Usage; stored dsh history from earlier scans is retained."
|
|
5064
|
+
};
|
|
5065
|
+
}
|
|
5066
|
+
function safeFailure5(error) {
|
|
5067
|
+
if (error instanceof Error && "code" in error && typeof error.code === "string" && "recovery" in error && typeof error.recovery === "string") {
|
|
5068
|
+
return { code: error.code, message: error.message, recovery: error.recovery };
|
|
5069
|
+
}
|
|
5070
|
+
return {
|
|
5071
|
+
code: "dsh-session-log-read-failed",
|
|
5072
|
+
message: "Local dsh session history is unavailable.",
|
|
5073
|
+
recovery: "Run agent-usage doctor, then retry refresh."
|
|
5074
|
+
};
|
|
5075
|
+
}
|
|
5076
|
+
var DshConnector;
|
|
5077
|
+
var init_dsh_connector = __esm({
|
|
5078
|
+
"src/connectors/dsh/dsh-connector.ts"() {
|
|
5079
|
+
"use strict";
|
|
5080
|
+
init_local_transcript_usage_client();
|
|
5081
|
+
DshConnector = class {
|
|
5082
|
+
id = "dsh";
|
|
5083
|
+
displayName = "dsh";
|
|
5084
|
+
consentId = "dsh";
|
|
5085
|
+
#historyClient;
|
|
5086
|
+
#clock;
|
|
5087
|
+
constructor(options) {
|
|
5088
|
+
this.#historyClient = options.historyClient;
|
|
5089
|
+
this.#clock = options.clock ?? (() => /* @__PURE__ */ new Date());
|
|
5090
|
+
}
|
|
5091
|
+
async collect(options = { mode: "incremental" }) {
|
|
5092
|
+
const observedAt = this.#clock().toISOString();
|
|
5093
|
+
const warnings = [];
|
|
5094
|
+
let history = null;
|
|
5095
|
+
try {
|
|
5096
|
+
history = await this.#historyClient.readUsage(options);
|
|
5097
|
+
} catch (error) {
|
|
5098
|
+
warnings.push(safeFailure5(error));
|
|
5099
|
+
}
|
|
5100
|
+
if (history?.unsupportedFormat) warnings.push(unsupportedFormatFailure());
|
|
5101
|
+
else if (history && !history.complete) warnings.push(incompleteSessionLogFailure());
|
|
5102
|
+
const usage = history?.usage ?? [];
|
|
5103
|
+
return {
|
|
5104
|
+
provider: { id: this.id, displayName: this.displayName },
|
|
5105
|
+
billingDomains: billingDomains(usage),
|
|
5106
|
+
quotaBuckets: [],
|
|
5107
|
+
usage,
|
|
5108
|
+
...usage.length > 0 && history?.complete ? {
|
|
5109
|
+
usageReconciliation: {
|
|
5110
|
+
authoritativeIdPrefixes: ["dsh-transcript:"],
|
|
5111
|
+
retiredIdPrefixes: []
|
|
5112
|
+
}
|
|
5113
|
+
} : {},
|
|
5114
|
+
costs: history?.costs ?? [],
|
|
5115
|
+
warnings,
|
|
5116
|
+
observedAt
|
|
5117
|
+
};
|
|
5118
|
+
}
|
|
5119
|
+
};
|
|
5120
|
+
}
|
|
5121
|
+
});
|
|
5122
|
+
|
|
5123
|
+
// src/server/antigravity-quota-client.ts
|
|
5124
|
+
import { readdirSync, readFileSync } from "fs";
|
|
5125
|
+
import { homedir as homedir2 } from "os";
|
|
5126
|
+
import { join as join4 } from "path";
|
|
5127
|
+
function mapQuotaGroups(groups) {
|
|
5128
|
+
const buckets = [];
|
|
5129
|
+
for (const group of groups) {
|
|
5130
|
+
const isGemini = /gemini/i.test(group.displayName ?? "");
|
|
5131
|
+
const isClaudeOrGpt = /claude|gpt/i.test(group.displayName ?? "");
|
|
5132
|
+
for (const rawBucket of group.buckets ?? []) {
|
|
5133
|
+
const windowStr = (rawBucket.window ?? "").toLowerCase();
|
|
5134
|
+
const displayStr = (rawBucket.displayName ?? "").toLowerCase();
|
|
5135
|
+
const is5h = windowStr === "5h" || /5[- ]?hour/i.test(displayStr);
|
|
5136
|
+
const isWeekly = windowStr === "weekly" || /week/i.test(displayStr);
|
|
5137
|
+
let durationMinutes;
|
|
5138
|
+
let windowName;
|
|
5139
|
+
if (is5h) {
|
|
5140
|
+
durationMinutes = 300;
|
|
5141
|
+
windowName = "5 hour";
|
|
5142
|
+
} else if (isWeekly) {
|
|
5143
|
+
durationMinutes = 10080;
|
|
5144
|
+
windowName = "Week";
|
|
5145
|
+
} else {
|
|
5146
|
+
continue;
|
|
5147
|
+
}
|
|
5148
|
+
let label = windowName;
|
|
5149
|
+
if (!isGemini) {
|
|
5150
|
+
if (isClaudeOrGpt) {
|
|
5151
|
+
label = `Claude / GPT \xB7 ${windowName}`;
|
|
5152
|
+
} else if (group.displayName) {
|
|
5153
|
+
label = `${group.displayName} \xB7 ${windowName}`;
|
|
5154
|
+
}
|
|
5155
|
+
}
|
|
5156
|
+
const usedPercent = typeof rawBucket.remainingFraction === "number" ? Math.max(0, Math.min(100, Math.round((1 - rawBucket.remainingFraction) * 100))) : null;
|
|
5157
|
+
buckets.push({
|
|
5158
|
+
id: rawBucket.bucketId || `${isGemini ? "gemini" : "3p"}-${windowStr}`,
|
|
5159
|
+
billingDomainId: ANTIGRAVITY_PRIMARY_BILLING_DOMAIN_ID,
|
|
5160
|
+
label,
|
|
5161
|
+
usedPercent,
|
|
5162
|
+
windowDurationMinutes: durationMinutes,
|
|
5163
|
+
resetsAt: rawBucket.resetTime ?? null,
|
|
5164
|
+
authority: "official-client",
|
|
5165
|
+
scope: "account-wide"
|
|
5166
|
+
});
|
|
5167
|
+
}
|
|
5168
|
+
}
|
|
5169
|
+
return buckets;
|
|
5170
|
+
}
|
|
5171
|
+
var AntigravityQuotaClient;
|
|
5172
|
+
var init_antigravity_quota_client = __esm({
|
|
5173
|
+
"src/server/antigravity-quota-client.ts"() {
|
|
5174
|
+
"use strict";
|
|
5175
|
+
init_antigravity_connector();
|
|
5176
|
+
AntigravityQuotaClient = class {
|
|
5177
|
+
#logRoots;
|
|
5178
|
+
#ports;
|
|
5179
|
+
#fetchFn;
|
|
5180
|
+
#timeoutMs;
|
|
5181
|
+
constructor(options = {}) {
|
|
5182
|
+
this.#logRoots = options.logRoots ?? [
|
|
5183
|
+
join4(homedir2(), "Library/Logs/Antigravity"),
|
|
5184
|
+
join4(homedir2(), ".gemini/antigravity-cli/log"),
|
|
5185
|
+
join4(homedir2(), ".gemini/antigravity/log")
|
|
5186
|
+
];
|
|
5187
|
+
this.#ports = options.ports;
|
|
5188
|
+
this.#fetchFn = options.fetchFn ?? globalThis.fetch;
|
|
5189
|
+
this.#timeoutMs = options.timeoutMs ?? 1500;
|
|
5190
|
+
}
|
|
5191
|
+
async readQuota() {
|
|
5192
|
+
const { ports, csrfToken } = this.discoverCandidates();
|
|
5193
|
+
const candidatePorts = this.#ports ?? ports;
|
|
5194
|
+
if (candidatePorts.length === 0) {
|
|
5195
|
+
return null;
|
|
5196
|
+
}
|
|
5197
|
+
for (const port of candidatePorts) {
|
|
5198
|
+
const quota = await this.queryPort(port, csrfToken);
|
|
5199
|
+
if (quota) {
|
|
5200
|
+
return quota;
|
|
5201
|
+
}
|
|
5202
|
+
}
|
|
5203
|
+
return null;
|
|
5204
|
+
}
|
|
5205
|
+
discoverCandidates() {
|
|
5206
|
+
let csrfToken = process.env.ANTIGRAVITY_CSRF_TOKEN ?? null;
|
|
5207
|
+
const ports = [];
|
|
5208
|
+
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;
|
|
5209
|
+
const csrfRegex = /--csrf_token[= ]([a-f0-9-]+)/;
|
|
5210
|
+
for (const root of this.#logRoots) {
|
|
5211
|
+
try {
|
|
5212
|
+
const files = readdirSync(root).filter((file) => file.endsWith(".log")).sort().reverse().slice(0, 10);
|
|
5213
|
+
for (const file of files) {
|
|
5214
|
+
const filePath = join4(root, file);
|
|
5215
|
+
try {
|
|
5216
|
+
const content = readFileSync(filePath, "utf8");
|
|
5217
|
+
if (!csrfToken) {
|
|
5218
|
+
const csrfMatch = csrfRegex.exec(content);
|
|
5219
|
+
if (csrfMatch) csrfToken = csrfMatch[1];
|
|
5220
|
+
}
|
|
5221
|
+
let match;
|
|
5222
|
+
while ((match = httpPortRegex.exec(content)) !== null) {
|
|
5223
|
+
const basePort = Number(match[1]);
|
|
5224
|
+
ports.push(basePort);
|
|
5225
|
+
ports.push(basePort + 1);
|
|
5226
|
+
ports.push(basePort + 2);
|
|
5227
|
+
}
|
|
5228
|
+
} catch {
|
|
5229
|
+
}
|
|
5230
|
+
}
|
|
5231
|
+
} catch {
|
|
5232
|
+
}
|
|
5233
|
+
}
|
|
5234
|
+
return {
|
|
5235
|
+
ports: [...new Set(ports.reverse())],
|
|
5236
|
+
csrfToken
|
|
5237
|
+
};
|
|
5238
|
+
}
|
|
5239
|
+
discoverCandidatePorts() {
|
|
5240
|
+
return this.discoverCandidates().ports;
|
|
5241
|
+
}
|
|
5242
|
+
async queryPort(port, csrfToken = null) {
|
|
5243
|
+
try {
|
|
5244
|
+
const url = `http://127.0.0.1:${port}/exa.language_server_pb.LanguageServerService/RetrieveUserQuotaSummary`;
|
|
5245
|
+
const response = await this.#fetchFn(url, {
|
|
5246
|
+
method: "POST",
|
|
5247
|
+
headers: {
|
|
5248
|
+
"Content-Type": "application/json",
|
|
5249
|
+
"Connect-Protocol-Version": "1",
|
|
5250
|
+
...csrfToken ? { "x-codeium-csrf-token": csrfToken } : {}
|
|
5251
|
+
},
|
|
5252
|
+
body: JSON.stringify({}),
|
|
5253
|
+
signal: AbortSignal.timeout(this.#timeoutMs)
|
|
5254
|
+
});
|
|
5255
|
+
if (!response.ok) {
|
|
5256
|
+
return null;
|
|
5257
|
+
}
|
|
5258
|
+
const body = await response.json();
|
|
5259
|
+
const groups = body.response?.groups;
|
|
5260
|
+
if (!Array.isArray(groups) || groups.length === 0) {
|
|
5261
|
+
return null;
|
|
5262
|
+
}
|
|
5263
|
+
return mapQuotaGroups(groups);
|
|
5264
|
+
} catch {
|
|
5265
|
+
return null;
|
|
5266
|
+
}
|
|
5267
|
+
}
|
|
5268
|
+
};
|
|
5269
|
+
}
|
|
5270
|
+
});
|
|
5271
|
+
|
|
5272
|
+
// src/connectors/antigravity/antigravity-connector.ts
|
|
5273
|
+
function buildAntigravityQuotaBuckets(usage, nowMs, limits = DEFAULT_ANTIGRAVITY_QUOTA_LIMITS) {
|
|
5274
|
+
const fiveHoursMs = 300 * 60 * 1e3;
|
|
5275
|
+
const sevenDaysMs = 7 * 24 * 60 * 60 * 1e3;
|
|
5276
|
+
const cutoff5h = nowMs - fiveHoursMs;
|
|
5277
|
+
const cutoff7d = nowMs - sevenDaysMs;
|
|
5278
|
+
const obs5h = [];
|
|
5279
|
+
const obs7d = [];
|
|
5280
|
+
for (const obs of usage) {
|
|
5281
|
+
const t = new Date(obs.observedAt).getTime();
|
|
5282
|
+
if (t >= cutoff5h) obs5h.push(obs);
|
|
5283
|
+
if (t >= cutoff7d) obs7d.push(obs);
|
|
5284
|
+
}
|
|
5285
|
+
const tokens5h = obs5h.reduce(
|
|
5286
|
+
(acc, obs) => acc + obs.inputTokens + obs.outputTokens + obs.cacheReadTokens,
|
|
5287
|
+
0
|
|
5288
|
+
);
|
|
5289
|
+
const usedPercent5h = Math.min(100, Math.round(tokens5h / limits.rolling5hTokens * 100));
|
|
5290
|
+
let resetsAt5h;
|
|
5291
|
+
if (obs5h.length > 0) {
|
|
5292
|
+
const oldestMs = Math.min(...obs5h.map((o) => new Date(o.observedAt).getTime()));
|
|
5293
|
+
resetsAt5h = new Date(oldestMs + fiveHoursMs).toISOString();
|
|
5294
|
+
} else {
|
|
5295
|
+
resetsAt5h = new Date(nowMs + fiveHoursMs).toISOString();
|
|
5296
|
+
}
|
|
5297
|
+
const tokens7d = obs7d.reduce(
|
|
5298
|
+
(acc, obs) => acc + obs.inputTokens + obs.outputTokens + obs.cacheReadTokens,
|
|
5299
|
+
0
|
|
5300
|
+
);
|
|
5301
|
+
const usedPercent7d = Math.min(100, Math.round(tokens7d / limits.weeklyTokens * 100));
|
|
5302
|
+
let resetsAt7d;
|
|
5303
|
+
if (obs7d.length > 0) {
|
|
5304
|
+
const oldestMs = Math.min(...obs7d.map((o) => new Date(o.observedAt).getTime()));
|
|
5305
|
+
resetsAt7d = new Date(oldestMs + sevenDaysMs).toISOString();
|
|
5306
|
+
} else {
|
|
5307
|
+
resetsAt7d = new Date(nowMs + sevenDaysMs).toISOString();
|
|
5308
|
+
}
|
|
5309
|
+
return [
|
|
5310
|
+
{
|
|
5311
|
+
id: "gemini-5h",
|
|
5312
|
+
billingDomainId: ANTIGRAVITY_PRIMARY_BILLING_DOMAIN_ID,
|
|
5313
|
+
label: "5 hour",
|
|
5314
|
+
usedPercent: usedPercent5h,
|
|
5315
|
+
windowDurationMinutes: 300,
|
|
5316
|
+
resetsAt: resetsAt5h,
|
|
5317
|
+
authority: "local-observation",
|
|
5318
|
+
scope: "local-only"
|
|
5319
|
+
},
|
|
5320
|
+
{
|
|
5321
|
+
id: "gemini-weekly",
|
|
5322
|
+
billingDomainId: ANTIGRAVITY_PRIMARY_BILLING_DOMAIN_ID,
|
|
5323
|
+
label: "Week",
|
|
5324
|
+
usedPercent: usedPercent7d,
|
|
5325
|
+
windowDurationMinutes: 10080,
|
|
5326
|
+
resetsAt: resetsAt7d,
|
|
5327
|
+
authority: "local-observation",
|
|
5328
|
+
scope: "local-only"
|
|
5329
|
+
}
|
|
5330
|
+
];
|
|
5331
|
+
}
|
|
5332
|
+
function billingDomains2(usage) {
|
|
5333
|
+
const primary = {
|
|
5334
|
+
id: ANTIGRAVITY_PRIMARY_BILLING_DOMAIN_ID,
|
|
5335
|
+
displayName: "Gemini Code Assist"
|
|
5336
|
+
};
|
|
5337
|
+
const observedRoutes = [...new Set(usage.map((obs) => obs.billingDomainId))].filter((id) => id !== primary.id).sort();
|
|
5338
|
+
return [primary, ...observedRoutes.map((id) => ({ id, displayName: id }))];
|
|
5339
|
+
}
|
|
5340
|
+
function incompleteSessionScanFailure() {
|
|
5341
|
+
return {
|
|
5342
|
+
code: "antigravity-session-scan-incomplete",
|
|
5343
|
+
message: "Some local Antigravity conversation databases could not be read.",
|
|
5344
|
+
recovery: "Agent Usage will retry automatically on the next scan without removing stored history."
|
|
5345
|
+
};
|
|
5346
|
+
}
|
|
5347
|
+
function safeFailure6() {
|
|
5348
|
+
return {
|
|
5349
|
+
code: "antigravity-sqlite-read-failed",
|
|
5350
|
+
message: "Failed to read local Antigravity conversation stores.",
|
|
5351
|
+
recovery: "Check read permissions for ~/.gemini/antigravity-cli and ~/.gemini/antigravity directories."
|
|
5352
|
+
};
|
|
5353
|
+
}
|
|
5354
|
+
var ANTIGRAVITY_PRIMARY_BILLING_DOMAIN_ID, DEFAULT_ANTIGRAVITY_QUOTA_LIMITS, AntigravityConnector;
|
|
5355
|
+
var init_antigravity_connector = __esm({
|
|
5356
|
+
"src/connectors/antigravity/antigravity-connector.ts"() {
|
|
5357
|
+
"use strict";
|
|
5358
|
+
init_antigravity_quota_client();
|
|
5359
|
+
ANTIGRAVITY_PRIMARY_BILLING_DOMAIN_ID = "code-assist-subscription";
|
|
5360
|
+
DEFAULT_ANTIGRAVITY_QUOTA_LIMITS = {
|
|
5361
|
+
rolling5hTokens: 15e6,
|
|
5362
|
+
weeklyTokens: 1e8
|
|
5363
|
+
};
|
|
5364
|
+
AntigravityConnector = class {
|
|
5365
|
+
id = "antigravity";
|
|
5366
|
+
displayName = "Antigravity";
|
|
5367
|
+
consentId = "antigravity";
|
|
5368
|
+
#historyClient;
|
|
5369
|
+
#quotaClient;
|
|
5370
|
+
#clock;
|
|
5371
|
+
#quotaLimits;
|
|
5372
|
+
constructor(options) {
|
|
5373
|
+
this.#historyClient = options.historyClient;
|
|
5374
|
+
this.#quotaClient = options.quotaClient ?? new AntigravityQuotaClient();
|
|
5375
|
+
this.#clock = options.clock ?? (() => /* @__PURE__ */ new Date());
|
|
5376
|
+
this.#quotaLimits = {
|
|
5377
|
+
rolling5hTokens: options.quotaLimits?.rolling5hTokens ?? DEFAULT_ANTIGRAVITY_QUOTA_LIMITS.rolling5hTokens,
|
|
5378
|
+
weeklyTokens: options.quotaLimits?.weeklyTokens ?? DEFAULT_ANTIGRAVITY_QUOTA_LIMITS.weeklyTokens
|
|
5379
|
+
};
|
|
5380
|
+
}
|
|
5381
|
+
async collect(options = { mode: "incremental" }) {
|
|
5382
|
+
const observedAt = this.#clock().toISOString();
|
|
5383
|
+
const nowMs = this.#clock().getTime();
|
|
5384
|
+
const warnings = [];
|
|
5385
|
+
let history = null;
|
|
5386
|
+
try {
|
|
5387
|
+
history = await this.#historyClient.readUsage(options);
|
|
5388
|
+
} catch {
|
|
5389
|
+
warnings.push(safeFailure6());
|
|
5390
|
+
}
|
|
5391
|
+
if (history && !history.complete) {
|
|
5392
|
+
warnings.push(incompleteSessionScanFailure());
|
|
5393
|
+
}
|
|
5394
|
+
const usage = history?.usage ?? [];
|
|
5395
|
+
let quotaBuckets = [];
|
|
5396
|
+
try {
|
|
5397
|
+
const liveQuota = await this.#quotaClient.readQuota();
|
|
5398
|
+
if (liveQuota && liveQuota.length > 0) {
|
|
5399
|
+
quotaBuckets = [...liveQuota];
|
|
5400
|
+
}
|
|
5401
|
+
} catch {
|
|
5402
|
+
}
|
|
5403
|
+
const localBuckets = buildAntigravityQuotaBuckets(usage, nowMs, this.#quotaLimits);
|
|
5404
|
+
const has5h = quotaBuckets.some((b) => b.label === "5 hour" || b.id === "gemini-5h");
|
|
5405
|
+
const hasWeekly = quotaBuckets.some((b) => b.label === "Week" || b.id === "gemini-weekly");
|
|
5406
|
+
if (!has5h || !hasWeekly) {
|
|
5407
|
+
for (const localBucket of localBuckets) {
|
|
5408
|
+
if (!quotaBuckets.some((b) => b.id === localBucket.id || b.label === localBucket.label)) {
|
|
5409
|
+
quotaBuckets.push(localBucket);
|
|
5410
|
+
}
|
|
5411
|
+
}
|
|
5412
|
+
}
|
|
5413
|
+
return {
|
|
5414
|
+
provider: { id: this.id, displayName: this.displayName },
|
|
5415
|
+
billingDomains: billingDomains2(usage),
|
|
5416
|
+
quotaBuckets,
|
|
5417
|
+
usage,
|
|
5418
|
+
...usage.length > 0 && history?.complete ? {
|
|
5419
|
+
usageReconciliation: {
|
|
5420
|
+
authoritativeIdPrefixes: ["antigravity:"],
|
|
5421
|
+
retiredIdPrefixes: []
|
|
5422
|
+
}
|
|
5423
|
+
} : {},
|
|
5424
|
+
costs: history?.costs ?? [],
|
|
5425
|
+
warnings,
|
|
5426
|
+
observedAt
|
|
5427
|
+
};
|
|
5428
|
+
}
|
|
5429
|
+
};
|
|
5430
|
+
}
|
|
5431
|
+
});
|
|
5432
|
+
|
|
5433
|
+
// src/server/antigravity-sqlite-usage-client.ts
|
|
5434
|
+
import { createHash as createHash3 } from "crypto";
|
|
5435
|
+
import { readdir, readFile as readFile4, rename as rename3, stat as stat2, writeFile as writeFile3, mkdir as mkdir3 } from "fs/promises";
|
|
5436
|
+
import { createRequire as createRequire2 } from "module";
|
|
5437
|
+
import { dirname as dirname2, join as join5 } from "path";
|
|
5438
|
+
import protobuf from "protobufjs";
|
|
5439
|
+
function parseAntigravityDatabase(dbPath, conversationId, fallbackMtimeMs) {
|
|
5440
|
+
const db = new DatabaseSync2(dbPath, { readOnly: true });
|
|
5441
|
+
try {
|
|
5442
|
+
const tableExists = db.prepare("SELECT 1 FROM sqlite_master WHERE type='table' AND name='gen_metadata'").get();
|
|
5443
|
+
if (!tableExists) return [];
|
|
5444
|
+
const stepTimestamps = /* @__PURE__ */ new Map();
|
|
5445
|
+
try {
|
|
5446
|
+
const stepRows = db.prepare("SELECT idx, metadata FROM steps WHERE length(metadata) > 0").all();
|
|
5447
|
+
for (const row of stepRows) {
|
|
5448
|
+
const ts = extractTimestampFromStepMetadata(row.metadata);
|
|
5449
|
+
if (ts !== null) stepTimestamps.set(row.idx, ts);
|
|
5450
|
+
}
|
|
5451
|
+
} catch {
|
|
5452
|
+
}
|
|
5453
|
+
const genRows = db.prepare("SELECT idx, data FROM gen_metadata ORDER BY idx ASC").all();
|
|
5454
|
+
const records = [];
|
|
5455
|
+
for (const row of genRows) {
|
|
5456
|
+
if (!row.data || row.data.length === 0) continue;
|
|
5457
|
+
const parsed = decodeGenMetadata(row.data);
|
|
5458
|
+
if (parsed.inputTokens === 0 && parsed.outputTokens === 0 && parsed.cacheReadTokens === 0) {
|
|
5459
|
+
continue;
|
|
5460
|
+
}
|
|
5461
|
+
const timestampMs = stepTimestamps.get(row.idx) ?? fallbackMtimeMs;
|
|
5462
|
+
const observedAt = new Date(timestampMs).toISOString();
|
|
5463
|
+
const dedupeKey = `antigravity:${conversationId}:${row.idx}`;
|
|
5464
|
+
const observation = {
|
|
5465
|
+
id: dedupeKey,
|
|
5466
|
+
billingDomainId: "code-assist-subscription",
|
|
5467
|
+
model: parsed.canonicalModel,
|
|
5468
|
+
observedAt,
|
|
5469
|
+
inputTokens: parsed.inputTokens,
|
|
5470
|
+
outputTokens: parsed.outputTokens,
|
|
5471
|
+
reasoningTokens: 0,
|
|
5472
|
+
cacheReadTokens: parsed.cacheReadTokens,
|
|
5473
|
+
cacheWriteTokens: 0,
|
|
5474
|
+
tokenSemantics: {
|
|
5475
|
+
reasoning: "included-in-output",
|
|
5476
|
+
cacheRead: "separate",
|
|
5477
|
+
cacheWrite: "separate"
|
|
5478
|
+
},
|
|
5479
|
+
modelAttribution: "known",
|
|
5480
|
+
timePrecision: "event",
|
|
5481
|
+
usageScope: "this-mac",
|
|
5482
|
+
aggregationTemporality: "delta",
|
|
5483
|
+
authority: "local-observation"
|
|
5484
|
+
};
|
|
5485
|
+
normalizeTokenObservation(observation);
|
|
5486
|
+
records.push({ dedupeKey, observation });
|
|
5487
|
+
}
|
|
5488
|
+
return records;
|
|
5489
|
+
} finally {
|
|
5490
|
+
db.close();
|
|
5491
|
+
}
|
|
5492
|
+
}
|
|
5493
|
+
function decodeGenMetadata(buf) {
|
|
5494
|
+
let rawModel = "unknown";
|
|
5495
|
+
let inputTokens = 0;
|
|
5496
|
+
const outputTokens = 0;
|
|
5497
|
+
let cacheReadTokens = 0;
|
|
5498
|
+
try {
|
|
5499
|
+
const r = protobuf.Reader.create(buf);
|
|
5500
|
+
while (r.pos < r.len) {
|
|
5501
|
+
const tag = r.uint32();
|
|
5502
|
+
const fn = tag >>> 3;
|
|
5503
|
+
const wt = tag & 7;
|
|
5504
|
+
if (fn === 1 && wt === 2) {
|
|
5505
|
+
const sub1 = r.bytes();
|
|
5506
|
+
const rSub = protobuf.Reader.create(sub1);
|
|
5507
|
+
while (rSub.pos < rSub.len) {
|
|
5508
|
+
const sTag = rSub.uint32();
|
|
5509
|
+
const sFn = sTag >>> 3;
|
|
5510
|
+
const sWt = sTag & 7;
|
|
5511
|
+
if (sFn === 19 && sWt === 2) {
|
|
5512
|
+
rawModel = Buffer.from(rSub.bytes()).toString("utf8");
|
|
5513
|
+
} else if (sFn === 9 && sWt === 2) {
|
|
5514
|
+
const sub9 = rSub.bytes();
|
|
5515
|
+
const r9 = protobuf.Reader.create(sub9);
|
|
5516
|
+
while (r9.pos < r9.len) {
|
|
5517
|
+
const t9 = r9.uint32();
|
|
5518
|
+
const fn9 = t9 >>> 3;
|
|
5519
|
+
const wt9 = t9 & 7;
|
|
5520
|
+
if (fn9 === 10 && wt9 === 2) {
|
|
5521
|
+
const sub10 = r9.bytes();
|
|
5522
|
+
const r10 = protobuf.Reader.create(sub10);
|
|
5523
|
+
while (r10.pos < r10.len) {
|
|
5524
|
+
const t10 = r10.uint32();
|
|
5525
|
+
const fn10 = t10 >>> 3;
|
|
5526
|
+
const wt10 = t10 & 7;
|
|
5527
|
+
if (fn10 === 1 && wt10 === 0) {
|
|
5528
|
+
inputTokens = toNumeric(r10.uint64());
|
|
5529
|
+
} else if (fn10 === 3 && wt10 === 2) {
|
|
5530
|
+
const sub3 = r10.bytes();
|
|
5531
|
+
const r3 = protobuf.Reader.create(sub3);
|
|
5532
|
+
while (r3.pos < r3.len) {
|
|
5533
|
+
const t3 = r3.uint32();
|
|
5534
|
+
const fn3 = t3 >>> 3;
|
|
5535
|
+
const wt3 = t3 & 7;
|
|
5536
|
+
if (fn3 === 2 && wt3 === 0) {
|
|
5537
|
+
cacheReadTokens = toNumeric(r3.uint64());
|
|
5538
|
+
} else {
|
|
5539
|
+
r3.skipType(wt3);
|
|
5540
|
+
}
|
|
5541
|
+
}
|
|
5542
|
+
} else {
|
|
5543
|
+
r10.skipType(wt10);
|
|
5544
|
+
}
|
|
5545
|
+
}
|
|
5546
|
+
} else {
|
|
5547
|
+
r9.skipType(wt9);
|
|
5548
|
+
}
|
|
5549
|
+
}
|
|
5550
|
+
} else {
|
|
5551
|
+
rSub.skipType(sWt);
|
|
5552
|
+
}
|
|
5553
|
+
}
|
|
5554
|
+
} else {
|
|
5555
|
+
r.skipType(wt);
|
|
5556
|
+
}
|
|
5557
|
+
}
|
|
5558
|
+
} catch {
|
|
5559
|
+
}
|
|
5560
|
+
return {
|
|
5561
|
+
rawModel,
|
|
5562
|
+
canonicalModel: canonicalizeAntigravityModel(rawModel),
|
|
5563
|
+
inputTokens,
|
|
5564
|
+
outputTokens,
|
|
5565
|
+
cacheReadTokens
|
|
5566
|
+
};
|
|
5567
|
+
}
|
|
5568
|
+
function canonicalizeAntigravityModel(raw) {
|
|
5569
|
+
const normalized = raw.trim().toLowerCase().replace(/[\s_]+/g, "-");
|
|
5570
|
+
if (normalized.startsWith("gemini-3p7") || normalized.startsWith("gemini-3.7")) {
|
|
5571
|
+
return "gemini-3.7-flash";
|
|
5572
|
+
}
|
|
5573
|
+
if (normalized.startsWith("gemini-3p6") || normalized.startsWith("gemini-3.6")) {
|
|
5574
|
+
return "gemini-3.6-flash";
|
|
5575
|
+
}
|
|
5576
|
+
if (normalized.startsWith("gemini-3p1") || normalized.startsWith("gemini-3.1")) {
|
|
5577
|
+
return "gemini-3.1-pro";
|
|
5578
|
+
}
|
|
5579
|
+
if (normalized.includes("claude-sonnet")) {
|
|
5580
|
+
return "claude-sonnet-4-6";
|
|
5581
|
+
}
|
|
5582
|
+
if (normalized.includes("claude-opus")) {
|
|
5583
|
+
return "claude-opus-4-6-thinking";
|
|
5584
|
+
}
|
|
5585
|
+
if (normalized.includes("gpt-oss")) {
|
|
5586
|
+
return "gpt-oss-120b-medium";
|
|
5587
|
+
}
|
|
5588
|
+
return raw.trim() || "unknown";
|
|
5589
|
+
}
|
|
5590
|
+
function extractTimestampFromStepMetadata(buf) {
|
|
5591
|
+
try {
|
|
5592
|
+
const r = protobuf.Reader.create(buf);
|
|
5593
|
+
while (r.pos < r.len) {
|
|
5594
|
+
const tag = r.uint32();
|
|
5595
|
+
const fn = tag >>> 3;
|
|
5596
|
+
const wt = tag & 7;
|
|
5597
|
+
if (fn === 1 && wt === 2) {
|
|
5598
|
+
const tsBytes = r.bytes();
|
|
5599
|
+
const rTs = protobuf.Reader.create(tsBytes);
|
|
5600
|
+
let seconds = 0;
|
|
5601
|
+
let nanos = 0;
|
|
5602
|
+
while (rTs.pos < rTs.len) {
|
|
5603
|
+
const t = rTs.uint32();
|
|
5604
|
+
const tFn = t >>> 3;
|
|
5605
|
+
const tWt = t & 7;
|
|
5606
|
+
if (tFn === 1 && tWt === 0) {
|
|
5607
|
+
seconds = toNumeric(rTs.uint64());
|
|
5608
|
+
} else if (tFn === 2 && tWt === 0) {
|
|
5609
|
+
nanos = toNumeric(rTs.uint64());
|
|
5610
|
+
} else {
|
|
5611
|
+
rTs.skipType(tWt);
|
|
5612
|
+
}
|
|
5613
|
+
}
|
|
5614
|
+
if (seconds > 0) {
|
|
5615
|
+
return seconds * 1e3 + Math.floor(nanos / 1e6);
|
|
5616
|
+
}
|
|
5617
|
+
} else {
|
|
5618
|
+
r.skipType(wt);
|
|
5619
|
+
}
|
|
5620
|
+
}
|
|
5621
|
+
} catch {
|
|
5622
|
+
}
|
|
5623
|
+
return null;
|
|
5624
|
+
}
|
|
5625
|
+
function toNumeric(val) {
|
|
5626
|
+
return Number(val?.toString?.() ?? 0);
|
|
5627
|
+
}
|
|
5628
|
+
function stableId2(value) {
|
|
5629
|
+
return createHash3("sha256").update(value).digest("hex").slice(0, 16);
|
|
5630
|
+
}
|
|
5631
|
+
function isCachedDatabaseFile(value) {
|
|
5632
|
+
if (typeof value !== "object" || value === null) return false;
|
|
5633
|
+
const rec = value;
|
|
5634
|
+
return typeof rec.path === "string" && typeof rec.size === "number" && typeof rec.mtimeMs === "number" && Array.isArray(rec.records) && typeof rec.recordsDigest === "string";
|
|
5635
|
+
}
|
|
5636
|
+
var DatabaseSync2, AntigravitySqliteUsageClient;
|
|
5637
|
+
var init_antigravity_sqlite_usage_client = __esm({
|
|
5638
|
+
"src/server/antigravity-sqlite-usage-client.ts"() {
|
|
5639
|
+
"use strict";
|
|
5640
|
+
init_token_normalization();
|
|
5641
|
+
init_retail_pricing();
|
|
5642
|
+
({ DatabaseSync: DatabaseSync2 } = createRequire2(import.meta.url)(
|
|
5643
|
+
"node:sqlite"
|
|
5644
|
+
));
|
|
5645
|
+
AntigravitySqliteUsageClient = class {
|
|
5646
|
+
#roots;
|
|
5647
|
+
#clock;
|
|
5648
|
+
#lookbackDays;
|
|
5649
|
+
#cachePath;
|
|
5650
|
+
#priceCatalog;
|
|
5651
|
+
#fileCache = /* @__PURE__ */ new Map();
|
|
5652
|
+
#cacheLoaded = false;
|
|
5653
|
+
constructor(options) {
|
|
5654
|
+
this.#roots = options.roots;
|
|
5655
|
+
this.#clock = options.clock ?? (() => /* @__PURE__ */ new Date());
|
|
5656
|
+
this.#lookbackDays = options.lookbackDays ?? 90;
|
|
5657
|
+
this.#cachePath = options.cachePath;
|
|
5658
|
+
this.#priceCatalog = options.priceCatalog ?? OFFICIAL_PRICING_CATALOG;
|
|
5659
|
+
}
|
|
5660
|
+
async readUsage(options = { mode: "incremental" }) {
|
|
5661
|
+
await this.#loadCache();
|
|
5662
|
+
if (options.mode === "hard-rebuild") this.#fileCache.clear();
|
|
5663
|
+
const cutoff = this.#clock().getTime() - this.#lookbackDays * 24 * 60 * 60 * 1e3;
|
|
5664
|
+
const discoveredFiles = await this.#discoverDatabases(cutoff);
|
|
5665
|
+
const livePaths = new Set(discoveredFiles.map((file) => stableId2(file.path)));
|
|
5666
|
+
for (const path of this.#fileCache.keys()) {
|
|
5667
|
+
if (!livePaths.has(path)) this.#fileCache.delete(path);
|
|
5668
|
+
}
|
|
5669
|
+
const usage = [];
|
|
5670
|
+
const seenDedupeKeys = /* @__PURE__ */ new Set();
|
|
5671
|
+
let allComplete = true;
|
|
5672
|
+
for (const file of discoveredFiles) {
|
|
5673
|
+
const parsed = await this.#parseDatabaseFile(file);
|
|
5674
|
+
allComplete &&= parsed.complete;
|
|
5675
|
+
for (const record of parsed.records) {
|
|
5676
|
+
if (new Date(record.observation.observedAt).getTime() < cutoff) continue;
|
|
5677
|
+
if (seenDedupeKeys.has(record.dedupeKey)) continue;
|
|
5678
|
+
seenDedupeKeys.add(record.dedupeKey);
|
|
5679
|
+
usage.push(record.observation);
|
|
5680
|
+
}
|
|
5681
|
+
}
|
|
5682
|
+
usage.sort((a, b) => a.observedAt.localeCompare(b.observedAt) || a.id.localeCompare(b.id));
|
|
5683
|
+
const { costs } = deriveRetailEquivalentCosts(
|
|
5684
|
+
{
|
|
5685
|
+
provider: { id: "antigravity", displayName: "Antigravity" },
|
|
5686
|
+
billingDomains: [{ id: "code-assist-subscription", displayName: "Gemini Code Assist" }],
|
|
5687
|
+
quotaBuckets: [],
|
|
5688
|
+
usage,
|
|
5689
|
+
costs: [],
|
|
5690
|
+
observedAt: this.#clock().toISOString()
|
|
5691
|
+
},
|
|
5692
|
+
this.#priceCatalog
|
|
5693
|
+
);
|
|
5694
|
+
await this.#persistCache();
|
|
5695
|
+
return {
|
|
5696
|
+
usage,
|
|
5697
|
+
costs,
|
|
5698
|
+
complete: allComplete
|
|
5699
|
+
};
|
|
5700
|
+
}
|
|
5701
|
+
async #discoverDatabases(cutoff) {
|
|
5702
|
+
const results = [];
|
|
5703
|
+
const seenDbPaths = /* @__PURE__ */ new Set();
|
|
5704
|
+
for (const root of this.#roots) {
|
|
5705
|
+
try {
|
|
5706
|
+
const rootStat = await stat2(root);
|
|
5707
|
+
if (!rootStat.isDirectory()) continue;
|
|
5708
|
+
} catch {
|
|
5709
|
+
continue;
|
|
5710
|
+
}
|
|
5711
|
+
const summariesPath = join5(root, "conversation_summaries.db");
|
|
5712
|
+
const candidateIds = /* @__PURE__ */ new Set();
|
|
5713
|
+
let summariesLoaded = false;
|
|
5714
|
+
try {
|
|
5715
|
+
const summariesStat = await stat2(summariesPath);
|
|
5716
|
+
if (summariesStat.isFile()) {
|
|
5717
|
+
const db = new DatabaseSync2(summariesPath, { readOnly: true });
|
|
5718
|
+
try {
|
|
5719
|
+
const rows = db.prepare("SELECT conversation_id, last_modified_time FROM conversation_summaries").all();
|
|
5720
|
+
for (const row of rows) {
|
|
5721
|
+
if (!row.conversation_id) continue;
|
|
5722
|
+
const modifiedMs = row.last_modified_time ? new Date(row.last_modified_time).getTime() : 0;
|
|
5723
|
+
if (modifiedMs >= cutoff || modifiedMs === 0) {
|
|
5724
|
+
candidateIds.add(row.conversation_id);
|
|
5725
|
+
}
|
|
5726
|
+
}
|
|
5727
|
+
summariesLoaded = true;
|
|
5728
|
+
} finally {
|
|
5729
|
+
db.close();
|
|
5730
|
+
}
|
|
5731
|
+
}
|
|
5732
|
+
} catch {
|
|
5733
|
+
}
|
|
5734
|
+
const convDir = join5(root, "conversations");
|
|
5735
|
+
try {
|
|
5736
|
+
const entries = await readdir(convDir);
|
|
5737
|
+
for (const entry of entries) {
|
|
5738
|
+
if (!entry.endsWith(".db")) continue;
|
|
5739
|
+
const convId = entry.slice(0, -3);
|
|
5740
|
+
if (summariesLoaded && candidateIds.size > 0 && !candidateIds.has(convId)) {
|
|
5741
|
+
continue;
|
|
5742
|
+
}
|
|
5743
|
+
const fullPath = join5(convDir, entry);
|
|
5744
|
+
if (seenDbPaths.has(fullPath)) continue;
|
|
5745
|
+
seenDbPaths.add(fullPath);
|
|
5746
|
+
try {
|
|
5747
|
+
const fileStat = await stat2(fullPath);
|
|
5748
|
+
if (fileStat.mtimeMs < cutoff && summariesLoaded) continue;
|
|
5749
|
+
results.push({
|
|
5750
|
+
path: fullPath,
|
|
5751
|
+
size: fileStat.size,
|
|
5752
|
+
mtimeMs: fileStat.mtimeMs,
|
|
5753
|
+
conversationId: convId
|
|
5754
|
+
});
|
|
5755
|
+
} catch {
|
|
5756
|
+
}
|
|
5757
|
+
}
|
|
5758
|
+
} catch {
|
|
5759
|
+
}
|
|
5760
|
+
}
|
|
5761
|
+
return results;
|
|
5762
|
+
}
|
|
5763
|
+
async #parseDatabaseFile(file) {
|
|
5764
|
+
const cached = this.#fileCache.get(stableId2(file.path));
|
|
5765
|
+
if (cached && cached.size === file.size && cached.mtimeMs === file.mtimeMs) {
|
|
5766
|
+
return { records: cached.records, complete: true };
|
|
5767
|
+
}
|
|
5768
|
+
try {
|
|
5769
|
+
const records = parseAntigravityDatabase(file.path, file.conversationId, file.mtimeMs);
|
|
5770
|
+
const digest = stableId2(JSON.stringify(records));
|
|
5771
|
+
this.#fileCache.set(stableId2(file.path), {
|
|
5772
|
+
path: file.path,
|
|
5773
|
+
size: file.size,
|
|
5774
|
+
mtimeMs: file.mtimeMs,
|
|
5775
|
+
records,
|
|
5776
|
+
recordsDigest: digest
|
|
5777
|
+
});
|
|
5778
|
+
return { records, complete: true };
|
|
5779
|
+
} catch {
|
|
5780
|
+
return { records: [], complete: false };
|
|
5781
|
+
}
|
|
5782
|
+
}
|
|
5783
|
+
async #loadCache() {
|
|
5784
|
+
if (this.#cacheLoaded) return;
|
|
5785
|
+
this.#cacheLoaded = true;
|
|
5786
|
+
if (!this.#cachePath) return;
|
|
5787
|
+
try {
|
|
5788
|
+
const content = await readFile4(this.#cachePath, "utf8");
|
|
5789
|
+
const stored = JSON.parse(content);
|
|
5790
|
+
if (stored.version !== 1 || !Array.isArray(stored.files)) return;
|
|
5791
|
+
for (const item of stored.files) {
|
|
5792
|
+
if (!isCachedDatabaseFile(item)) continue;
|
|
5793
|
+
if (item.recordsDigest !== stableId2(JSON.stringify(item.records))) continue;
|
|
5794
|
+
this.#fileCache.set(stableId2(item.path), item);
|
|
5795
|
+
}
|
|
5796
|
+
} catch {
|
|
5797
|
+
}
|
|
5798
|
+
}
|
|
5799
|
+
async #persistCache() {
|
|
5800
|
+
if (!this.#cachePath) return;
|
|
5801
|
+
try {
|
|
5802
|
+
await mkdir3(dirname2(this.#cachePath), { recursive: true, mode: 448 });
|
|
4769
5803
|
const temporary = `${this.#cachePath}.${process.pid}.tmp`;
|
|
4770
|
-
await
|
|
5804
|
+
await writeFile3(
|
|
4771
5805
|
temporary,
|
|
4772
5806
|
JSON.stringify({ version: 1, files: [...this.#fileCache.values()] }),
|
|
4773
5807
|
{ mode: 384 }
|
|
4774
5808
|
);
|
|
4775
|
-
await
|
|
5809
|
+
await rename3(temporary, this.#cachePath);
|
|
4776
5810
|
} catch {
|
|
4777
5811
|
}
|
|
4778
5812
|
}
|
|
@@ -4780,83 +5814,6 @@ var init_local_transcript_usage_client = __esm({
|
|
|
4780
5814
|
}
|
|
4781
5815
|
});
|
|
4782
5816
|
|
|
4783
|
-
// src/connectors/dsh/dsh-connector.ts
|
|
4784
|
-
function billingDomains(usage) {
|
|
4785
|
-
const primary = { id: DSH_PRIMARY_BILLING_DOMAIN_ID, displayName: "DeepSeek API" };
|
|
4786
|
-
const observedRoutes = [...new Set(usage.map((observation) => observation.billingDomainId))].filter((id) => id !== primary.id).sort();
|
|
4787
|
-
return [primary, ...observedRoutes.map((id) => ({ id, displayName: id }))];
|
|
4788
|
-
}
|
|
4789
|
-
function incompleteSessionLogFailure() {
|
|
4790
|
-
return {
|
|
4791
|
-
code: "dsh-session-log-scan-incomplete",
|
|
4792
|
-
message: "Some local dsh session history could not be read.",
|
|
4793
|
-
recovery: "Agent Usage will retry automatically without removing stored history."
|
|
4794
|
-
};
|
|
4795
|
-
}
|
|
4796
|
-
function unsupportedFormatFailure() {
|
|
4797
|
-
return {
|
|
4798
|
-
code: "dsh-session-format-unsupported",
|
|
4799
|
-
message: "A dsh session log declares an on-disk format this version does not read.",
|
|
4800
|
-
recovery: "Update Agent Usage; stored dsh history from earlier scans is retained."
|
|
4801
|
-
};
|
|
4802
|
-
}
|
|
4803
|
-
function safeFailure5(error) {
|
|
4804
|
-
if (error instanceof Error && "code" in error && typeof error.code === "string" && "recovery" in error && typeof error.recovery === "string") {
|
|
4805
|
-
return { code: error.code, message: error.message, recovery: error.recovery };
|
|
4806
|
-
}
|
|
4807
|
-
return {
|
|
4808
|
-
code: "dsh-session-log-read-failed",
|
|
4809
|
-
message: "Local dsh session history is unavailable.",
|
|
4810
|
-
recovery: "Run agent-usage doctor, then retry refresh."
|
|
4811
|
-
};
|
|
4812
|
-
}
|
|
4813
|
-
var DshConnector;
|
|
4814
|
-
var init_dsh_connector = __esm({
|
|
4815
|
-
"src/connectors/dsh/dsh-connector.ts"() {
|
|
4816
|
-
"use strict";
|
|
4817
|
-
init_local_transcript_usage_client();
|
|
4818
|
-
DshConnector = class {
|
|
4819
|
-
id = "dsh";
|
|
4820
|
-
displayName = "dsh";
|
|
4821
|
-
consentId = "dsh";
|
|
4822
|
-
#historyClient;
|
|
4823
|
-
#clock;
|
|
4824
|
-
constructor(options) {
|
|
4825
|
-
this.#historyClient = options.historyClient;
|
|
4826
|
-
this.#clock = options.clock ?? (() => /* @__PURE__ */ new Date());
|
|
4827
|
-
}
|
|
4828
|
-
async collect(options = { mode: "incremental" }) {
|
|
4829
|
-
const observedAt = this.#clock().toISOString();
|
|
4830
|
-
const warnings = [];
|
|
4831
|
-
let history = null;
|
|
4832
|
-
try {
|
|
4833
|
-
history = await this.#historyClient.readUsage(options);
|
|
4834
|
-
} catch (error) {
|
|
4835
|
-
warnings.push(safeFailure5(error));
|
|
4836
|
-
}
|
|
4837
|
-
if (history?.unsupportedFormat) warnings.push(unsupportedFormatFailure());
|
|
4838
|
-
else if (history && !history.complete) warnings.push(incompleteSessionLogFailure());
|
|
4839
|
-
const usage = history?.usage ?? [];
|
|
4840
|
-
return {
|
|
4841
|
-
provider: { id: this.id, displayName: this.displayName },
|
|
4842
|
-
billingDomains: billingDomains(usage),
|
|
4843
|
-
quotaBuckets: [],
|
|
4844
|
-
usage,
|
|
4845
|
-
...usage.length > 0 && history?.complete ? {
|
|
4846
|
-
usageReconciliation: {
|
|
4847
|
-
authoritativeIdPrefixes: ["dsh-transcript:"],
|
|
4848
|
-
retiredIdPrefixes: []
|
|
4849
|
-
}
|
|
4850
|
-
} : {},
|
|
4851
|
-
costs: history?.costs ?? [],
|
|
4852
|
-
warnings,
|
|
4853
|
-
observedAt
|
|
4854
|
-
};
|
|
4855
|
-
}
|
|
4856
|
-
};
|
|
4857
|
-
}
|
|
4858
|
-
});
|
|
4859
|
-
|
|
4860
5817
|
// src/connectors/grok-build/grok-build-connector.ts
|
|
4861
5818
|
import { z as z6 } from "zod";
|
|
4862
5819
|
function incompleteTranscriptFailure3() {
|
|
@@ -4919,7 +5876,7 @@ function derivePercent(used, limit) {
|
|
|
4919
5876
|
if (used === void 0 || limit === void 0 || limit <= 0) return null;
|
|
4920
5877
|
return Math.min(100, Math.max(0, used / limit * 100));
|
|
4921
5878
|
}
|
|
4922
|
-
function
|
|
5879
|
+
function safeFailure7(error) {
|
|
4923
5880
|
if (error instanceof Error && "code" in error && typeof error.code === "string" && "recovery" in error && typeof error.recovery === "string") {
|
|
4924
5881
|
return { code: error.code, message: error.message, recovery: error.recovery };
|
|
4925
5882
|
}
|
|
@@ -4982,7 +5939,7 @@ var init_grok_build_connector = __esm({
|
|
|
4982
5939
|
});
|
|
4983
5940
|
}
|
|
4984
5941
|
} catch (error) {
|
|
4985
|
-
warnings.push(
|
|
5942
|
+
warnings.push(safeFailure7(error));
|
|
4986
5943
|
}
|
|
4987
5944
|
const history = this.#historyClient ? await this.#historyClient.readUsage(options) : { usage: [], costs: [], complete: true };
|
|
4988
5945
|
if (!history.complete) warnings.push(incompleteTranscriptFailure3());
|
|
@@ -5123,8 +6080,8 @@ var init_grok_telemetry = __esm({
|
|
|
5123
6080
|
// src/connectors/grok-build/stdio-grok-billing-client.ts
|
|
5124
6081
|
import { spawn as spawn3 } from "child_process";
|
|
5125
6082
|
import { open } from "fs/promises";
|
|
5126
|
-
import { homedir as
|
|
5127
|
-
import { join as
|
|
6083
|
+
import { homedir as homedir3 } from "os";
|
|
6084
|
+
import { join as join6 } from "path";
|
|
5128
6085
|
import { z as z7 } from "zod";
|
|
5129
6086
|
function billingIsFresh(billing, now) {
|
|
5130
6087
|
if (!billing.sourceObservedAt) return false;
|
|
@@ -5249,7 +6206,7 @@ var init_stdio_grok_billing_client = __esm({
|
|
|
5249
6206
|
stdio: ["pipe", "pipe", "pipe"]
|
|
5250
6207
|
}));
|
|
5251
6208
|
this.#readUnifiedLog = options.readUnifiedLog ?? (() => readLogTail(
|
|
5252
|
-
|
|
6209
|
+
join6(process.env.GROK_HOME ?? join6(homedir3(), ".grok"), "logs", "unified.jsonl")
|
|
5253
6210
|
));
|
|
5254
6211
|
this.#refreshBillingLog = options.refreshBillingLog ?? (options.readUnifiedLog ? async () => void 0 : () => refreshBillingLogViaDashboard(this.#command, this.#timeoutMs));
|
|
5255
6212
|
this.#clock = options.clock ?? (() => /* @__PURE__ */ new Date());
|
|
@@ -5620,7 +6577,7 @@ function endpointFailure(error, label) {
|
|
|
5620
6577
|
recovery: "Check network access and xAI status, then retry."
|
|
5621
6578
|
};
|
|
5622
6579
|
}
|
|
5623
|
-
function
|
|
6580
|
+
function safeFailure8(error) {
|
|
5624
6581
|
if (error instanceof Error && "code" in error && typeof error.code === "string" && "recovery" in error && typeof error.recovery === "string") {
|
|
5625
6582
|
return { code: error.code, message: error.message, recovery: error.recovery };
|
|
5626
6583
|
}
|
|
@@ -5875,7 +6832,7 @@ var init_xai_api_connector = __esm({
|
|
|
5875
6832
|
costs: [],
|
|
5876
6833
|
balances: [],
|
|
5877
6834
|
invoices: [],
|
|
5878
|
-
warnings: [
|
|
6835
|
+
warnings: [safeFailure8(error)],
|
|
5879
6836
|
observedAt
|
|
5880
6837
|
};
|
|
5881
6838
|
}
|
|
@@ -6074,8 +7031,8 @@ var init_macos_notifier = __esm({
|
|
|
6074
7031
|
});
|
|
6075
7032
|
|
|
6076
7033
|
// src/server/macos-start-at-login-manager.ts
|
|
6077
|
-
import { mkdir as
|
|
6078
|
-
import { dirname as
|
|
7034
|
+
import { mkdir as mkdir4, rm, writeFile as writeFile4 } from "fs/promises";
|
|
7035
|
+
import { dirname as dirname3, isAbsolute, join as join7 } from "path";
|
|
6079
7036
|
function launchAgentPlist(options) {
|
|
6080
7037
|
const label = options.label ?? LABEL;
|
|
6081
7038
|
const arguments_ = [
|
|
@@ -6127,15 +7084,15 @@ var init_macos_start_at_login_manager = __esm({
|
|
|
6127
7084
|
const label = validateLaunchAgentLabel(options.label ?? LABEL);
|
|
6128
7085
|
if (options.nodeImport) validateNodeImport(options.nodeImport);
|
|
6129
7086
|
this.#options = { ...options, label };
|
|
6130
|
-
this.#path =
|
|
7087
|
+
this.#path = join7(options.userHome, "Library", "LaunchAgents", `${label}.plist`);
|
|
6131
7088
|
}
|
|
6132
7089
|
async setEnabled(enabled) {
|
|
6133
7090
|
if (!enabled) {
|
|
6134
7091
|
await rm(this.#path, { force: true });
|
|
6135
7092
|
return;
|
|
6136
7093
|
}
|
|
6137
|
-
await
|
|
6138
|
-
await
|
|
7094
|
+
await mkdir4(dirname3(this.#path), { recursive: true, mode: 448 });
|
|
7095
|
+
await writeFile4(this.#path, launchAgentPlist(this.#options), { mode: 384 });
|
|
6139
7096
|
}
|
|
6140
7097
|
async isEnabled() {
|
|
6141
7098
|
try {
|
|
@@ -6252,7 +7209,7 @@ var init_otlp_protobuf = __esm({
|
|
|
6252
7209
|
// src/server/local-server.ts
|
|
6253
7210
|
import { createReadStream as createReadStream2, existsSync, statSync } from "fs";
|
|
6254
7211
|
import { createServer } from "http";
|
|
6255
|
-
import { extname, join as
|
|
7212
|
+
import { extname, join as join8, normalize, resolve } from "path";
|
|
6256
7213
|
import { randomBytes } from "crypto";
|
|
6257
7214
|
import { z as z9 } from "zod";
|
|
6258
7215
|
async function startLocalServer(options) {
|
|
@@ -6432,6 +7389,53 @@ async function startLocalServer(options) {
|
|
|
6432
7389
|
sendJson(response, 200, await options.application.updatePlanSubscription(input));
|
|
6433
7390
|
return;
|
|
6434
7391
|
}
|
|
7392
|
+
if (request.method === "GET" && requestUrl.pathname === "/api/custom-rates") {
|
|
7393
|
+
const rates = await options.application.getCustomModelRates();
|
|
7394
|
+
sendJson(response, 200, { rates });
|
|
7395
|
+
return;
|
|
7396
|
+
}
|
|
7397
|
+
if (request.method === "GET" && requestUrl.pathname.startsWith("/api/custom-rates/")) {
|
|
7398
|
+
const id = decodeURIComponent(requestUrl.pathname.slice("/api/custom-rates/".length));
|
|
7399
|
+
const rate = await options.application.getCustomModelRate(id);
|
|
7400
|
+
if (!rate) {
|
|
7401
|
+
sendJson(response, 404, { error: "rate-not-found" });
|
|
7402
|
+
return;
|
|
7403
|
+
}
|
|
7404
|
+
sendJson(response, 200, { rate });
|
|
7405
|
+
return;
|
|
7406
|
+
}
|
|
7407
|
+
if (request.method === "POST" && requestUrl.pathname === "/api/custom-rates") {
|
|
7408
|
+
if (!validMutationOrigin(authentication, request, origin)) {
|
|
7409
|
+
sendJson(response, 403, { error: "invalid-origin" });
|
|
7410
|
+
return;
|
|
7411
|
+
}
|
|
7412
|
+
const input = customModelRateSchema.parse(await readJsonBody(request));
|
|
7413
|
+
const rate = await options.application.setCustomModelRate(input);
|
|
7414
|
+
sendJson(response, 200, { rate });
|
|
7415
|
+
return;
|
|
7416
|
+
}
|
|
7417
|
+
if ((request.method === "PUT" || request.method === "PATCH") && requestUrl.pathname.startsWith("/api/custom-rates/")) {
|
|
7418
|
+
if (!validMutationOrigin(authentication, request, origin)) {
|
|
7419
|
+
sendJson(response, 403, { error: "invalid-origin" });
|
|
7420
|
+
return;
|
|
7421
|
+
}
|
|
7422
|
+
const id = decodeURIComponent(requestUrl.pathname.slice("/api/custom-rates/".length));
|
|
7423
|
+
const body = await readJsonBody(request);
|
|
7424
|
+
const input = customModelRateSchema.parse({ ...body, id });
|
|
7425
|
+
const rate = await options.application.setCustomModelRate(input);
|
|
7426
|
+
sendJson(response, 200, { rate });
|
|
7427
|
+
return;
|
|
7428
|
+
}
|
|
7429
|
+
if (request.method === "DELETE" && requestUrl.pathname.startsWith("/api/custom-rates/")) {
|
|
7430
|
+
if (!validMutationOrigin(authentication, request, origin)) {
|
|
7431
|
+
sendJson(response, 403, { error: "invalid-origin" });
|
|
7432
|
+
return;
|
|
7433
|
+
}
|
|
7434
|
+
const id = decodeURIComponent(requestUrl.pathname.slice("/api/custom-rates/".length));
|
|
7435
|
+
const deleted = await options.application.deleteCustomModelRate(id);
|
|
7436
|
+
sendJson(response, 200, { deleted });
|
|
7437
|
+
return;
|
|
7438
|
+
}
|
|
6435
7439
|
if (request.method === "GET" && requestUrl.pathname === "/api/monitoring") {
|
|
6436
7440
|
sendJson(response, 200, await options.application.getMonitoringStatus());
|
|
6437
7441
|
return;
|
|
@@ -6488,8 +7492,7 @@ async function startLocalServer(options) {
|
|
|
6488
7492
|
}
|
|
6489
7493
|
sendJson(response, 404, { error: "not-found" });
|
|
6490
7494
|
} catch (error) {
|
|
6491
|
-
|
|
6492
|
-
sendJson(response, 500, { error: "internal-error", message });
|
|
7495
|
+
respondWithFailure(response, error);
|
|
6493
7496
|
}
|
|
6494
7497
|
});
|
|
6495
7498
|
await new Promise((resolveListening, reject) => {
|
|
@@ -6575,8 +7578,8 @@ async function serveStatic(response, pathname, staticDirectory) {
|
|
|
6575
7578
|
const root = resolve(staticDirectory);
|
|
6576
7579
|
const requested = pathname === "/" ? "index.html" : pathname.replace(/^\/+/, "");
|
|
6577
7580
|
const normalized = normalize(requested);
|
|
6578
|
-
const candidate = resolve(
|
|
6579
|
-
const indexFile =
|
|
7581
|
+
const candidate = resolve(join8(root, normalized));
|
|
7582
|
+
const indexFile = join8(root, "index.html");
|
|
6580
7583
|
const file = candidate.startsWith(`${root}/`) && existsSync(candidate) && statSync(candidate).isFile() ? candidate : indexFile;
|
|
6581
7584
|
if (!existsSync(file)) {
|
|
6582
7585
|
sendText(response, 404, "Dashboard assets are not built");
|
|
@@ -6609,11 +7612,28 @@ function secureToken() {
|
|
|
6609
7612
|
return randomBytes(32).toString("base64url");
|
|
6610
7613
|
}
|
|
6611
7614
|
function sendJson(response, status, body) {
|
|
7615
|
+
const payload = JSON.stringify(body);
|
|
6612
7616
|
response.writeHead(status, {
|
|
6613
7617
|
"content-type": "application/json; charset=utf-8",
|
|
6614
7618
|
"cache-control": "no-store"
|
|
6615
7619
|
});
|
|
6616
|
-
response.end(
|
|
7620
|
+
response.end(payload);
|
|
7621
|
+
}
|
|
7622
|
+
function respondWithFailure(response, error) {
|
|
7623
|
+
const message = publicErrorMessage(error);
|
|
7624
|
+
if (response.headersSent || response.writableEnded) {
|
|
7625
|
+
process.stderr.write(`Agent Usage: a started response failed to finish: ${message}
|
|
7626
|
+
`);
|
|
7627
|
+
response.destroy();
|
|
7628
|
+
return;
|
|
7629
|
+
}
|
|
7630
|
+
try {
|
|
7631
|
+
sendJson(response, 500, { error: "internal-error", message });
|
|
7632
|
+
} catch {
|
|
7633
|
+
process.stderr.write(`Agent Usage: a request failed without a reportable reason.
|
|
7634
|
+
`);
|
|
7635
|
+
response.destroy();
|
|
7636
|
+
}
|
|
6617
7637
|
}
|
|
6618
7638
|
function sendOtlpProtobuf(response, status) {
|
|
6619
7639
|
response.writeHead(status, {
|
|
@@ -6630,7 +7650,7 @@ function sendHtml(response, status, body) {
|
|
|
6630
7650
|
response.writeHead(status, { "content-type": "text/html; charset=utf-8" });
|
|
6631
7651
|
response.end(body);
|
|
6632
7652
|
}
|
|
6633
|
-
var SESSION_COOKIE, connectorActionSchema, usageQuerySchema, monitoringSettingsSchema, planSubscriptionSchema, clearDataSchema, hardRebuildSchema;
|
|
7653
|
+
var SESSION_COOKIE, connectorActionSchema, usageQuerySchema, monitoringSettingsSchema, planSubscriptionSchema, customModelRateSchema, clearDataSchema, hardRebuildSchema;
|
|
6634
7654
|
var init_local_server = __esm({
|
|
6635
7655
|
"src/server/local-server.ts"() {
|
|
6636
7656
|
"use strict";
|
|
@@ -6664,6 +7684,15 @@ var init_local_server = __esm({
|
|
|
6664
7684
|
anchorDate: z9.string().regex(/^\d{4}-\d{2}-\d{2}$/).nullable().optional()
|
|
6665
7685
|
}).nullable()
|
|
6666
7686
|
});
|
|
7687
|
+
customModelRateSchema = z9.object({
|
|
7688
|
+
id: z9.string().optional(),
|
|
7689
|
+
providerId: z9.string().min(1),
|
|
7690
|
+
billingDomainId: z9.string().nullable().optional(),
|
|
7691
|
+
model: z9.string().min(1),
|
|
7692
|
+
inputRate: z9.number().nonnegative(),
|
|
7693
|
+
outputRate: z9.number().nonnegative(),
|
|
7694
|
+
cacheReadRate: z9.number().nonnegative().optional()
|
|
7695
|
+
});
|
|
6667
7696
|
clearDataSchema = z9.object({ deleteProductSecrets: z9.boolean().default(false) });
|
|
6668
7697
|
hardRebuildSchema = z9.object({ confirmExpensiveOperation: z9.literal(true) });
|
|
6669
7698
|
}
|
|
@@ -6672,7 +7701,7 @@ var init_local_server = __esm({
|
|
|
6672
7701
|
// src/server/path-discovery-probe.ts
|
|
6673
7702
|
import { constants } from "fs";
|
|
6674
7703
|
import { access } from "fs/promises";
|
|
6675
|
-
import { delimiter, isAbsolute as isAbsolute2, join as
|
|
7704
|
+
import { delimiter, isAbsolute as isAbsolute2, join as join9, resolve as resolve2 } from "path";
|
|
6676
7705
|
async function isExecutable(path) {
|
|
6677
7706
|
try {
|
|
6678
7707
|
await access(path, constants.X_OK);
|
|
@@ -6718,7 +7747,7 @@ var init_path_discovery_probe = __esm({
|
|
|
6718
7747
|
async #findExecutable(command) {
|
|
6719
7748
|
if (command.includes("/")) return await isExecutable(command) ? resolve2(command) : null;
|
|
6720
7749
|
for (const directory of this.#path.split(delimiter).filter(Boolean)) {
|
|
6721
|
-
const candidate =
|
|
7750
|
+
const candidate = join9(directory, command);
|
|
6722
7751
|
if (await isExecutable(candidate)) return candidate;
|
|
6723
7752
|
}
|
|
6724
7753
|
return null;
|
|
@@ -6729,8 +7758,8 @@ var init_path_discovery_probe = __esm({
|
|
|
6729
7758
|
|
|
6730
7759
|
// src/server/sqlite-usage-repository.ts
|
|
6731
7760
|
import { mkdirSync } from "fs";
|
|
6732
|
-
import { createRequire as
|
|
6733
|
-
import { dirname as
|
|
7761
|
+
import { createRequire as createRequire3 } from "module";
|
|
7762
|
+
import { dirname as dirname4 } from "path";
|
|
6734
7763
|
import { Worker } from "worker_threads";
|
|
6735
7764
|
async function runDatabaseWorker(workerData) {
|
|
6736
7765
|
return new Promise((resolve5, reject) => {
|
|
@@ -7096,7 +8125,7 @@ function buildGlobalSummary(providers, riskSummary, now, query) {
|
|
|
7096
8125
|
for (const observedAt of [
|
|
7097
8126
|
domain.history.lastObservedAt,
|
|
7098
8127
|
...domain.quotaBuckets.map((bucket) => bucket.observedAt ?? null),
|
|
7099
|
-
|
|
8128
|
+
domain.lastCostObservedAt,
|
|
7100
8129
|
...domain.balances.map((balance) => balance.observedAt),
|
|
7101
8130
|
...domain.invoices.map((invoice) => invoice.createdAt)
|
|
7102
8131
|
]) {
|
|
@@ -7358,7 +8387,7 @@ function allDomainHistories(providers) {
|
|
|
7358
8387
|
provider,
|
|
7359
8388
|
domain,
|
|
7360
8389
|
history: domain.history,
|
|
7361
|
-
includedInHeadline: domain.id === provider.summaryBillingDomainId
|
|
8390
|
+
includedInHeadline: provider.id === "dsh" ? true : domain.id === provider.summaryBillingDomainId
|
|
7362
8391
|
}))
|
|
7363
8392
|
);
|
|
7364
8393
|
}
|
|
@@ -7436,25 +8465,28 @@ function buildWorkbenchModelRanking(histories, buckets, comparisonCurrency, reco
|
|
|
7436
8465
|
const entries = histories.flatMap(
|
|
7437
8466
|
({ provider, domain, history, includedInHeadline }) => history.models.map((model) => {
|
|
7438
8467
|
const retailEquivalent = buildWorkbenchMetric(
|
|
7439
|
-
model.priceEvidence,
|
|
8468
|
+
model.priceEvidence ?? [],
|
|
7440
8469
|
"retail-equivalent",
|
|
7441
8470
|
comparisonCurrency,
|
|
7442
8471
|
model.tokenEvidence.recordedTokens,
|
|
7443
8472
|
history.exchangeRates
|
|
7444
8473
|
);
|
|
7445
8474
|
const reportedEstimate = buildWorkbenchMetric(
|
|
7446
|
-
model.priceEvidence,
|
|
8475
|
+
model.priceEvidence ?? [],
|
|
7447
8476
|
"reported-estimate",
|
|
7448
8477
|
comparisonCurrency,
|
|
7449
8478
|
model.tokenEvidence.recordedTokens,
|
|
7450
8479
|
history.exchangeRates
|
|
7451
8480
|
);
|
|
8481
|
+
const observations = model.observations ?? [];
|
|
8482
|
+
const priceEvidence = model.priceEvidence ?? [];
|
|
7452
8483
|
const authorities = [
|
|
7453
|
-
...new Set(
|
|
8484
|
+
...new Set(observations.map((observation) => observation.authority))
|
|
7454
8485
|
].sort();
|
|
7455
|
-
const lastObservedAt =
|
|
7456
|
-
(
|
|
7457
|
-
|
|
8486
|
+
const lastObservedAt = observations.reduce(
|
|
8487
|
+
(latest, observation) => latest === null || observation.observedAt > latest ? observation.observedAt : latest,
|
|
8488
|
+
null
|
|
8489
|
+
) ?? null;
|
|
7458
8490
|
return {
|
|
7459
8491
|
id: modelRankingId(provider.id, domain.id, model.model),
|
|
7460
8492
|
providerId: provider.id,
|
|
@@ -7472,28 +8504,28 @@ function buildWorkbenchModelRanking(histories, buckets, comparisonCurrency, reco
|
|
|
7472
8504
|
reportedShare: includedInHeadline && reportedEstimate.status === "available" && reportedEstimate.amount !== null && totalReportedEstimate.status === "available" && totalReportedEstimate.amount !== null && totalReportedEstimate.amount !== 0 ? reportedEstimate.amount / totalReportedEstimate.amount : null,
|
|
7473
8505
|
authorities,
|
|
7474
8506
|
lastObservedAt,
|
|
7475
|
-
|
|
7476
|
-
|
|
8507
|
+
composition: nonOverlappingComposition(observations, model.tokenTotals),
|
|
8508
|
+
priceSnapshots: distinctPriceSnapshots(priceEvidence),
|
|
7477
8509
|
trend: buckets.map((bucket) => {
|
|
7478
|
-
const
|
|
8510
|
+
const bucketObservations = observations.filter(
|
|
7479
8511
|
(observation) => observation.observedAt >= bucket.start && observation.observedAt < bucket.end
|
|
7480
8512
|
);
|
|
7481
|
-
const
|
|
8513
|
+
const bucketPriceEvidence = priceEvidence.filter(
|
|
7482
8514
|
(cost) => (cost.observedAt ?? "") >= bucket.start && (cost.observedAt ?? "") < bucket.end
|
|
7483
8515
|
);
|
|
7484
|
-
const tokenTotals =
|
|
8516
|
+
const tokenTotals = bucketObservations.reduce(
|
|
7485
8517
|
(total, observation) => addTokenTotals(total, observation.tokenTotals),
|
|
7486
8518
|
zeroTokenTotals()
|
|
7487
8519
|
);
|
|
7488
8520
|
const intervalRetail = buildWorkbenchMetric(
|
|
7489
|
-
|
|
8521
|
+
bucketPriceEvidence,
|
|
7490
8522
|
"retail-equivalent",
|
|
7491
8523
|
comparisonCurrency,
|
|
7492
8524
|
tokenTotals.total,
|
|
7493
8525
|
history.exchangeRates
|
|
7494
8526
|
);
|
|
7495
8527
|
const intervalReported = buildWorkbenchMetric(
|
|
7496
|
-
|
|
8528
|
+
bucketPriceEvidence,
|
|
7497
8529
|
"reported-estimate",
|
|
7498
8530
|
comparisonCurrency,
|
|
7499
8531
|
tokenTotals.total,
|
|
@@ -7503,14 +8535,19 @@ function buildWorkbenchModelRanking(histories, buckets, comparisonCurrency, reco
|
|
|
7503
8535
|
start: bucket.start,
|
|
7504
8536
|
end: bucket.end,
|
|
7505
8537
|
label: bucket.label,
|
|
7506
|
-
gap:
|
|
8538
|
+
gap: bucketObservations.length === 0,
|
|
7507
8539
|
tokenTotals,
|
|
8540
|
+
recordedTokens: bucketObservations.reduce(
|
|
8541
|
+
(total, observation) => total + observation.recordedTokens,
|
|
8542
|
+
0
|
|
8543
|
+
),
|
|
7508
8544
|
authorities: [
|
|
7509
|
-
...new Set(
|
|
8545
|
+
...new Set(bucketObservations.map((observation) => observation.authority))
|
|
7510
8546
|
].sort(),
|
|
7511
|
-
lastObservedAt:
|
|
7512
|
-
(
|
|
7513
|
-
|
|
8547
|
+
lastObservedAt: bucketObservations.reduce(
|
|
8548
|
+
(latest, observation) => latest === null || observation.observedAt > latest ? observation.observedAt : latest,
|
|
8549
|
+
null
|
|
8550
|
+
) ?? null,
|
|
7514
8551
|
retailEquivalent: {
|
|
7515
8552
|
status: intervalRetail.status,
|
|
7516
8553
|
amount: intervalRetail.amount,
|
|
@@ -7587,6 +8624,49 @@ function buildWorkbenchModelRanking(histories, buckets, comparisonCurrency, reco
|
|
|
7587
8624
|
unclassified
|
|
7588
8625
|
};
|
|
7589
8626
|
}
|
|
8627
|
+
function dropAuditEvidence(providers) {
|
|
8628
|
+
for (const provider of providers) {
|
|
8629
|
+
for (const domain of provider.billingDomains) {
|
|
8630
|
+
for (const model of domain.history.models) {
|
|
8631
|
+
delete model.observations;
|
|
8632
|
+
delete model.priceEvidence;
|
|
8633
|
+
}
|
|
8634
|
+
delete domain.history.unclassified.observations;
|
|
8635
|
+
}
|
|
8636
|
+
}
|
|
8637
|
+
}
|
|
8638
|
+
function nonOverlappingComposition(observations, fallback) {
|
|
8639
|
+
if (observations.length === 0) {
|
|
8640
|
+
return {
|
|
8641
|
+
...fallback,
|
|
8642
|
+
total: fallback.input + fallback.output + fallback.cacheRead + fallback.cacheWrite
|
|
8643
|
+
};
|
|
8644
|
+
}
|
|
8645
|
+
const totals = zeroTokenTotals();
|
|
8646
|
+
for (const observation of observations) {
|
|
8647
|
+
totals.input += observation.tokenTotals.input;
|
|
8648
|
+
totals.output += observation.tokenTotals.output;
|
|
8649
|
+
if (observation.tokenSemantics.reasoning === "separate") {
|
|
8650
|
+
totals.reasoning += observation.tokenTotals.reasoning;
|
|
8651
|
+
}
|
|
8652
|
+
if (observation.tokenSemantics.cacheRead === "separate") {
|
|
8653
|
+
totals.cacheRead += observation.tokenTotals.cacheRead;
|
|
8654
|
+
}
|
|
8655
|
+
if (observation.tokenSemantics.cacheWrite === "separate") {
|
|
8656
|
+
totals.cacheWrite += observation.tokenTotals.cacheWrite;
|
|
8657
|
+
}
|
|
8658
|
+
}
|
|
8659
|
+
totals.total = totals.input + totals.output + totals.reasoning + totals.cacheRead + totals.cacheWrite;
|
|
8660
|
+
return totals;
|
|
8661
|
+
}
|
|
8662
|
+
function distinctPriceSnapshots(priceEvidence) {
|
|
8663
|
+
const snapshots = /* @__PURE__ */ new Map();
|
|
8664
|
+
for (const evidence of priceEvidence) {
|
|
8665
|
+
const snapshot2 = evidence.priceSnapshot;
|
|
8666
|
+
if (snapshot2 && !snapshots.has(snapshot2.id)) snapshots.set(snapshot2.id, snapshot2);
|
|
8667
|
+
}
|
|
8668
|
+
return [...snapshots.values()];
|
|
8669
|
+
}
|
|
7590
8670
|
function modelRankingId(providerId, billingDomainId, model) {
|
|
7591
8671
|
return `${providerId}::${billingDomainId}::${model}`;
|
|
7592
8672
|
}
|
|
@@ -8034,7 +9114,7 @@ function freshnessStatus(lastSuccessAt, now) {
|
|
|
8034
9114
|
if (!lastSuccessAt) return "unavailable";
|
|
8035
9115
|
return now.getTime() - new Date(lastSuccessAt).getTime() <= FRESHNESS_WINDOW_MS ? "fresh" : "stale";
|
|
8036
9116
|
}
|
|
8037
|
-
var FRESHNESS_WINDOW_MS, QUERY_INDEXES_SQL, DELETE_DERIVED_RETAIL_COSTS_SQL, DELETE_DEMO_PROVIDER_DATA_SQL,
|
|
9117
|
+
var FRESHNESS_WINDOW_MS, QUERY_INDEXES_SQL, DELETE_DERIVED_RETAIL_COSTS_SQL, DELETE_DEMO_PROVIDER_DATA_SQL, DatabaseSync3, RETENTION_AGGREGATE_SQL, SqliteUsageRepository;
|
|
8038
9118
|
var init_sqlite_usage_repository = __esm({
|
|
8039
9119
|
"src/server/sqlite-usage-repository.ts"() {
|
|
8040
9120
|
"use strict";
|
|
@@ -8075,7 +9155,7 @@ var init_sqlite_usage_repository = __esm({
|
|
|
8075
9155
|
DELETE FROM connector_settings WHERE id = 'demo';
|
|
8076
9156
|
DELETE FROM providers WHERE id = 'demo';
|
|
8077
9157
|
`;
|
|
8078
|
-
({ DatabaseSync:
|
|
9158
|
+
({ DatabaseSync: DatabaseSync3 } = createRequire3(import.meta.url)(
|
|
8079
9159
|
"node:sqlite"
|
|
8080
9160
|
));
|
|
8081
9161
|
RETENTION_AGGREGATE_SQL = `
|
|
@@ -8106,8 +9186,8 @@ var init_sqlite_usage_repository = __esm({
|
|
|
8106
9186
|
constructor(databasePath, options = {}) {
|
|
8107
9187
|
this.#databasePath = databasePath;
|
|
8108
9188
|
this.#hideDemoProvider = options.hideDemoProvider ?? false;
|
|
8109
|
-
mkdirSync(
|
|
8110
|
-
this.#database = new
|
|
9189
|
+
mkdirSync(dirname4(databasePath), { recursive: true });
|
|
9190
|
+
this.#database = new DatabaseSync3(databasePath);
|
|
8111
9191
|
this.#database.exec("PRAGMA journal_mode = WAL; PRAGMA foreign_keys = ON;");
|
|
8112
9192
|
this.#migrate();
|
|
8113
9193
|
}
|
|
@@ -8171,6 +9251,22 @@ var init_sqlite_usage_repository = __esm({
|
|
|
8171
9251
|
limit_currency = excluded.limit_currency,
|
|
8172
9252
|
fallback_status = excluded.fallback_status`
|
|
8173
9253
|
);
|
|
9254
|
+
const reportedQuotaDomains = [
|
|
9255
|
+
...new Set(snapshot2.quotaBuckets.map((bucket) => bucket.billingDomainId))
|
|
9256
|
+
];
|
|
9257
|
+
if (reportedQuotaDomains.length > 0) {
|
|
9258
|
+
const retiredQuotaStatement = this.#database.prepare(
|
|
9259
|
+
`DELETE FROM quota_buckets
|
|
9260
|
+
WHERE provider_id = ? AND billing_domain_id = ? AND id NOT IN (${snapshot2.quotaBuckets.map(() => "?").join(", ")})`
|
|
9261
|
+
);
|
|
9262
|
+
for (const billingDomainId of reportedQuotaDomains) {
|
|
9263
|
+
retiredQuotaStatement.run(
|
|
9264
|
+
snapshot2.provider.id,
|
|
9265
|
+
billingDomainId,
|
|
9266
|
+
...snapshot2.quotaBuckets.map((bucket) => bucket.id)
|
|
9267
|
+
);
|
|
9268
|
+
}
|
|
9269
|
+
}
|
|
8174
9270
|
for (const bucket of snapshot2.quotaBuckets) {
|
|
8175
9271
|
quotaStatement.run(
|
|
8176
9272
|
snapshot2.provider.id,
|
|
@@ -8532,7 +9628,11 @@ var init_sqlite_usage_repository = __esm({
|
|
|
8532
9628
|
price_snapshot_source_url, price_snapshot_context_tier,
|
|
8533
9629
|
model, usage_observation_id, priced_tokens, line_items_json, calculated_at
|
|
8534
9630
|
) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
|
|
8535
|
-
ON CONFLICT(provider_id, id) DO
|
|
9631
|
+
ON CONFLICT(provider_id, id) DO UPDATE SET
|
|
9632
|
+
amount = excluded.amount,
|
|
9633
|
+
price_snapshot_rates_json = excluded.price_snapshot_rates_json,
|
|
9634
|
+
line_items_json = excluded.line_items_json,
|
|
9635
|
+
calculated_at = excluded.calculated_at`
|
|
8536
9636
|
);
|
|
8537
9637
|
this.#database.exec("BEGIN IMMEDIATE");
|
|
8538
9638
|
try {
|
|
@@ -8602,7 +9702,7 @@ var init_sqlite_usage_repository = __esm({
|
|
|
8602
9702
|
);
|
|
8603
9703
|
const riskSummary = buildRiskSummary(overviews);
|
|
8604
9704
|
const planSubscriptions = this.getPlanSubscriptions();
|
|
8605
|
-
|
|
9705
|
+
const overview = {
|
|
8606
9706
|
generatedAt: now.toISOString(),
|
|
8607
9707
|
globalSummary: buildGlobalSummary(overviews, riskSummary, now, query),
|
|
8608
9708
|
workbench: buildTokenMoneyWorkbench(
|
|
@@ -8615,13 +9715,15 @@ var init_sqlite_usage_repository = __esm({
|
|
|
8615
9715
|
providers: overviews,
|
|
8616
9716
|
riskSummary
|
|
8617
9717
|
};
|
|
9718
|
+
if (!query.auditEvidence) dropAuditEvidence(overviews);
|
|
9719
|
+
return overview;
|
|
8618
9720
|
}
|
|
8619
9721
|
getAgentProviderIndex(now) {
|
|
8620
9722
|
const providers = this.#database.prepare("SELECT id, display_name FROM providers ORDER BY id").all();
|
|
8621
9723
|
return {
|
|
8622
9724
|
generatedAt: now.toISOString(),
|
|
8623
9725
|
providers: providers.filter(
|
|
8624
|
-
(provider) => provider.id !== "opencode" && (!this.#hideDemoProvider || provider.id !== "demo")
|
|
9726
|
+
(provider) => provider.id !== "opencode" && provider.id !== "dsh" && (!this.#hideDemoProvider || provider.id !== "demo")
|
|
8625
9727
|
).map((provider) => ({ id: provider.id, displayName: provider.display_name }))
|
|
8626
9728
|
};
|
|
8627
9729
|
}
|
|
@@ -8631,7 +9733,10 @@ var init_sqlite_usage_repository = __esm({
|
|
|
8631
9733
|
`SELECT id, display_name, last_success_at, last_error, last_error_code, last_recovery
|
|
8632
9734
|
FROM providers WHERE id = ?`
|
|
8633
9735
|
).get(providerId);
|
|
8634
|
-
|
|
9736
|
+
if (!provider) return null;
|
|
9737
|
+
const overview = this.#getProviderOverview(provider, now, query);
|
|
9738
|
+
if (!query.auditEvidence) dropAuditEvidence([overview]);
|
|
9739
|
+
return overview;
|
|
8635
9740
|
}
|
|
8636
9741
|
saveExchangeRateSnapshot(snapshot2) {
|
|
8637
9742
|
this.#database.prepare(
|
|
@@ -8759,6 +9864,95 @@ var init_sqlite_usage_repository = __esm({
|
|
|
8759
9864
|
deletePlanSubscription(providerId, billingDomainId) {
|
|
8760
9865
|
this.#database.prepare("DELETE FROM plan_subscriptions WHERE provider_id = ? AND billing_domain_id = ?").run(providerId, billingDomainId);
|
|
8761
9866
|
}
|
|
9867
|
+
getCustomModelRates() {
|
|
9868
|
+
const rows = this.#database.prepare(
|
|
9869
|
+
`SELECT id, provider_id, billing_domain_id, model,
|
|
9870
|
+
input_rate, output_rate, cache_read_rate, updated_at
|
|
9871
|
+
FROM custom_model_rates
|
|
9872
|
+
ORDER BY updated_at DESC`
|
|
9873
|
+
).all();
|
|
9874
|
+
return rows.map((row) => ({
|
|
9875
|
+
id: row.id,
|
|
9876
|
+
providerId: row.provider_id,
|
|
9877
|
+
billingDomainId: row.billing_domain_id ?? null,
|
|
9878
|
+
model: row.model,
|
|
9879
|
+
ratesPerMillion: {
|
|
9880
|
+
input: row.input_rate,
|
|
9881
|
+
output: row.output_rate,
|
|
9882
|
+
cacheRead: row.cache_read_rate
|
|
9883
|
+
},
|
|
9884
|
+
updatedAt: row.updated_at
|
|
9885
|
+
}));
|
|
9886
|
+
}
|
|
9887
|
+
getCustomModelRate(id) {
|
|
9888
|
+
const row = this.#database.prepare(
|
|
9889
|
+
`SELECT id, provider_id, billing_domain_id, model,
|
|
9890
|
+
input_rate, output_rate, cache_read_rate, updated_at
|
|
9891
|
+
FROM custom_model_rates
|
|
9892
|
+
WHERE id = ?`
|
|
9893
|
+
).get(id);
|
|
9894
|
+
if (!row) return null;
|
|
9895
|
+
return {
|
|
9896
|
+
id: row.id,
|
|
9897
|
+
providerId: row.provider_id,
|
|
9898
|
+
billingDomainId: row.billing_domain_id ?? null,
|
|
9899
|
+
model: row.model,
|
|
9900
|
+
ratesPerMillion: {
|
|
9901
|
+
input: row.input_rate,
|
|
9902
|
+
output: row.output_rate,
|
|
9903
|
+
cacheRead: row.cache_read_rate
|
|
9904
|
+
},
|
|
9905
|
+
updatedAt: row.updated_at
|
|
9906
|
+
};
|
|
9907
|
+
}
|
|
9908
|
+
saveCustomModelRate(rate) {
|
|
9909
|
+
const byId = this.#database.prepare("SELECT id FROM custom_model_rates WHERE id = ?").get(rate.id);
|
|
9910
|
+
const byKey = this.#database.prepare(
|
|
9911
|
+
`SELECT id FROM custom_model_rates
|
|
9912
|
+
WHERE provider_id = ? AND COALESCE(billing_domain_id, '') = COALESCE(?, '') AND lower(model) = lower(?)`
|
|
9913
|
+
).get(rate.providerId, rate.billingDomainId, rate.model);
|
|
9914
|
+
if (byId && byKey && byId.id !== byKey.id) {
|
|
9915
|
+
this.#database.prepare("DELETE FROM custom_model_rates WHERE id = ?").run(byKey.id);
|
|
9916
|
+
}
|
|
9917
|
+
const existingId = byId?.id ?? byKey?.id;
|
|
9918
|
+
if (existingId) {
|
|
9919
|
+
this.#database.prepare(
|
|
9920
|
+
`UPDATE custom_model_rates SET
|
|
9921
|
+
provider_id = ?, billing_domain_id = ?, model = ?,
|
|
9922
|
+
input_rate = ?, output_rate = ?, cache_read_rate = ?, updated_at = ?
|
|
9923
|
+
WHERE id = ?`
|
|
9924
|
+
).run(
|
|
9925
|
+
rate.providerId,
|
|
9926
|
+
rate.billingDomainId,
|
|
9927
|
+
rate.model,
|
|
9928
|
+
rate.ratesPerMillion.input,
|
|
9929
|
+
rate.ratesPerMillion.output,
|
|
9930
|
+
rate.ratesPerMillion.cacheRead,
|
|
9931
|
+
rate.updatedAt,
|
|
9932
|
+
existingId
|
|
9933
|
+
);
|
|
9934
|
+
} else {
|
|
9935
|
+
this.#database.prepare(
|
|
9936
|
+
`INSERT INTO custom_model_rates (
|
|
9937
|
+
id, provider_id, billing_domain_id, model,
|
|
9938
|
+
input_rate, output_rate, cache_read_rate, updated_at
|
|
9939
|
+
) VALUES (?, ?, ?, ?, ?, ?, ?, ?)`
|
|
9940
|
+
).run(
|
|
9941
|
+
rate.id,
|
|
9942
|
+
rate.providerId,
|
|
9943
|
+
rate.billingDomainId,
|
|
9944
|
+
rate.model,
|
|
9945
|
+
rate.ratesPerMillion.input,
|
|
9946
|
+
rate.ratesPerMillion.output,
|
|
9947
|
+
rate.ratesPerMillion.cacheRead,
|
|
9948
|
+
rate.updatedAt
|
|
9949
|
+
);
|
|
9950
|
+
}
|
|
9951
|
+
}
|
|
9952
|
+
deleteCustomModelRate(id) {
|
|
9953
|
+
const result = this.#database.prepare("DELETE FROM custom_model_rates WHERE id = ?").run(id);
|
|
9954
|
+
return result.changes > 0;
|
|
9955
|
+
}
|
|
8762
9956
|
getNotificationState(key) {
|
|
8763
9957
|
const row = this.#database.prepare("SELECT value FROM notification_state WHERE key = ?").get(key);
|
|
8764
9958
|
return row?.value ?? null;
|
|
@@ -8976,7 +10170,7 @@ var init_sqlite_usage_repository = __esm({
|
|
|
8976
10170
|
FROM billing_domains WHERE provider_id = ? ORDER BY id`
|
|
8977
10171
|
).all(provider.id);
|
|
8978
10172
|
const summaryBillingDomainId = selectSummaryBillingDomainId(provider.id, domainRows);
|
|
8979
|
-
const
|
|
10173
|
+
const billingDomains3 = domainRows.map(
|
|
8980
10174
|
(domain) => this.#getBillingDomainOverview(
|
|
8981
10175
|
provider.id,
|
|
8982
10176
|
domain,
|
|
@@ -8988,7 +10182,7 @@ var init_sqlite_usage_repository = __esm({
|
|
|
8988
10182
|
domainRows.length === 1 ? provider : null
|
|
8989
10183
|
)
|
|
8990
10184
|
);
|
|
8991
|
-
const summaryDomain =
|
|
10185
|
+
const summaryDomain = billingDomains3.find((domain) => domain.id === summaryBillingDomainId);
|
|
8992
10186
|
const emptyTotals = zeroTokenTotals();
|
|
8993
10187
|
const emptyEvidence = finishTokenEvidence(emptyTokenEvidence());
|
|
8994
10188
|
const emptyCoverage = {
|
|
@@ -9003,6 +10197,23 @@ var init_sqlite_usage_repository = __esm({
|
|
|
9003
10197
|
message: provider.last_error,
|
|
9004
10198
|
recovery: provider.last_recovery
|
|
9005
10199
|
} : { status: "healthy", errorCode: null, message: null, recovery: null };
|
|
10200
|
+
let providerTokenTotals = summaryDomain?.tokenTotals ?? emptyTotals;
|
|
10201
|
+
let providerTokenEvidence = summaryDomain?.tokenEvidence ?? emptyEvidence;
|
|
10202
|
+
if (provider.id === "dsh" && billingDomains3.length > 1) {
|
|
10203
|
+
const combinedTotals = zeroTokenTotals();
|
|
10204
|
+
const combinedEvidence = emptyTokenEvidence();
|
|
10205
|
+
for (const d of billingDomains3) {
|
|
10206
|
+
combinedTotals.total += d.tokenTotals.total;
|
|
10207
|
+
combinedTotals.input += d.tokenTotals.input;
|
|
10208
|
+
combinedTotals.output += d.tokenTotals.output;
|
|
10209
|
+
combinedTotals.reasoning += d.tokenTotals.reasoning;
|
|
10210
|
+
combinedTotals.cacheRead += d.tokenTotals.cacheRead;
|
|
10211
|
+
combinedTotals.cacheWrite += d.tokenTotals.cacheWrite;
|
|
10212
|
+
addAggregatedTokenEvidence(combinedEvidence, d.tokenEvidence);
|
|
10213
|
+
}
|
|
10214
|
+
providerTokenTotals = combinedTotals;
|
|
10215
|
+
providerTokenEvidence = finishTokenEvidence(combinedEvidence);
|
|
10216
|
+
}
|
|
9006
10217
|
return {
|
|
9007
10218
|
id: provider.id,
|
|
9008
10219
|
displayName: provider.display_name,
|
|
@@ -9014,10 +10225,10 @@ var init_sqlite_usage_repository = __esm({
|
|
|
9014
10225
|
health: summaryDomain?.health ?? providerFallbackHealth,
|
|
9015
10226
|
coverage: summaryDomain?.coverage ?? emptyCoverage,
|
|
9016
10227
|
quotaBuckets: summaryDomain?.quotaBuckets ?? [],
|
|
9017
|
-
tokenTotals:
|
|
9018
|
-
tokenEvidence:
|
|
10228
|
+
tokenTotals: providerTokenTotals,
|
|
10229
|
+
tokenEvidence: providerTokenEvidence,
|
|
9019
10230
|
tokenAuthority: summaryDomain?.tokenAuthority ?? null,
|
|
9020
|
-
billingDomains:
|
|
10231
|
+
billingDomains: billingDomains3,
|
|
9021
10232
|
forecasts: summaryDomain?.forecasts ?? [],
|
|
9022
10233
|
forecastCoverage: summaryDomain?.forecastCoverage ?? "insufficient"
|
|
9023
10234
|
};
|
|
@@ -9049,7 +10260,7 @@ var init_sqlite_usage_repository = __esm({
|
|
|
9049
10260
|
FROM usage_observations
|
|
9050
10261
|
WHERE provider_id = ? AND billing_domain_id = ? AND ${additiveUsagePredicate()}`
|
|
9051
10262
|
).get(providerId, domain.id);
|
|
9052
|
-
const costs = this.#database.prepare(
|
|
10263
|
+
const costs = query.auditEvidence ? this.#database.prepare(
|
|
9053
10264
|
`SELECT id, source_id, billing_domain_id, observed_at, kind, amount, currency, authority,
|
|
9054
10265
|
price_snapshot_id, price_snapshot_version, price_snapshot_source,
|
|
9055
10266
|
price_snapshot_canonical_model, price_snapshot_effective_at,
|
|
@@ -9058,7 +10269,11 @@ var init_sqlite_usage_repository = __esm({
|
|
|
9058
10269
|
price_snapshot_context_tier, model, usage_observation_id, priced_tokens,
|
|
9059
10270
|
line_items_json, calculated_at
|
|
9060
10271
|
FROM cost_records WHERE provider_id = ? AND billing_domain_id = ? ORDER BY observed_at DESC, id`
|
|
9061
|
-
).all(providerId, domain.id);
|
|
10272
|
+
).all(providerId, domain.id) : null;
|
|
10273
|
+
const lastCostObservedAt = this.#database.prepare(
|
|
10274
|
+
`SELECT MAX(observed_at) AS observed_at FROM cost_records
|
|
10275
|
+
WHERE provider_id = ? AND billing_domain_id = ?`
|
|
10276
|
+
).get(providerId, domain.id).observed_at ?? null;
|
|
9062
10277
|
const balances = this.#database.prepare(
|
|
9063
10278
|
`SELECT id, source_id, billing_domain_id, observed_at, kind, amount, currency, authority
|
|
9064
10279
|
FROM balance_records WHERE provider_id = ? AND billing_domain_id = ? ORDER BY observed_at DESC, id`
|
|
@@ -9067,7 +10282,12 @@ var init_sqlite_usage_repository = __esm({
|
|
|
9067
10282
|
`SELECT id, billing_domain_id, created_at, number, status, amount, currency, authority
|
|
9068
10283
|
FROM invoice_records WHERE provider_id = ? AND billing_domain_id = ? ORDER BY created_at DESC, id`
|
|
9069
10284
|
).all(providerId, domain.id);
|
|
9070
|
-
const actualCostCount =
|
|
10285
|
+
const actualCostCount = Number(
|
|
10286
|
+
this.#database.prepare(
|
|
10287
|
+
`SELECT COUNT(*) AS count FROM cost_records
|
|
10288
|
+
WHERE provider_id = ? AND billing_domain_id = ? AND kind = 'actual'`
|
|
10289
|
+
).get(providerId, domain.id).count
|
|
10290
|
+
);
|
|
9071
10291
|
const nonAdditiveTokenCount = this.#database.prepare(
|
|
9072
10292
|
`SELECT COUNT(*) AS count FROM usage_observations
|
|
9073
10293
|
WHERE provider_id = ? AND billing_domain_id = ?
|
|
@@ -9097,22 +10317,25 @@ var init_sqlite_usage_repository = __esm({
|
|
|
9097
10317
|
tokenTotals: mapTokenTotals(tokens),
|
|
9098
10318
|
tokenEvidence: mapTokenEvidence(tokens),
|
|
9099
10319
|
tokenAuthority: tokenAuthority(tokens.authorities),
|
|
9100
|
-
costs
|
|
9101
|
-
|
|
9102
|
-
|
|
9103
|
-
|
|
9104
|
-
|
|
9105
|
-
|
|
9106
|
-
|
|
9107
|
-
|
|
9108
|
-
|
|
9109
|
-
|
|
9110
|
-
|
|
9111
|
-
|
|
9112
|
-
|
|
9113
|
-
|
|
9114
|
-
|
|
9115
|
-
|
|
10320
|
+
...costs ? {
|
|
10321
|
+
costs: costs.map((row) => ({
|
|
10322
|
+
id: row.id,
|
|
10323
|
+
sourceId: row.source_id,
|
|
10324
|
+
billingDomainId: row.billing_domain_id,
|
|
10325
|
+
observedAt: row.observed_at,
|
|
10326
|
+
kind: row.kind,
|
|
10327
|
+
amount: row.amount,
|
|
10328
|
+
currency: row.currency,
|
|
10329
|
+
authority: row.authority,
|
|
10330
|
+
priceSnapshot: priceSnapshotFromRow(row),
|
|
10331
|
+
model: row.model,
|
|
10332
|
+
usageObservationId: row.usage_observation_id,
|
|
10333
|
+
pricedTokens: row.priced_tokens,
|
|
10334
|
+
lineItems: parseLineItems(row.line_items_json),
|
|
10335
|
+
calculatedAt: row.calculated_at
|
|
10336
|
+
}))
|
|
10337
|
+
} : {},
|
|
10338
|
+
lastCostObservedAt,
|
|
9116
10339
|
balances: balances.map((row) => ({
|
|
9117
10340
|
id: row.id,
|
|
9118
10341
|
sourceId: row.source_id,
|
|
@@ -9733,6 +10956,18 @@ var init_sqlite_usage_repository = __esm({
|
|
|
9733
10956
|
updated_at TEXT NOT NULL,
|
|
9734
10957
|
PRIMARY KEY (provider_id, billing_domain_id)
|
|
9735
10958
|
);
|
|
10959
|
+
CREATE TABLE IF NOT EXISTS custom_model_rates (
|
|
10960
|
+
id TEXT PRIMARY KEY,
|
|
10961
|
+
provider_id TEXT NOT NULL,
|
|
10962
|
+
billing_domain_id TEXT,
|
|
10963
|
+
model TEXT NOT NULL,
|
|
10964
|
+
input_rate REAL NOT NULL,
|
|
10965
|
+
output_rate REAL NOT NULL,
|
|
10966
|
+
cache_read_rate REAL NOT NULL,
|
|
10967
|
+
updated_at TEXT NOT NULL
|
|
10968
|
+
);
|
|
10969
|
+
CREATE UNIQUE INDEX IF NOT EXISTS idx_custom_model_rates_key
|
|
10970
|
+
ON custom_model_rates(provider_id, COALESCE(billing_domain_id, ''), lower(model));
|
|
9736
10971
|
`);
|
|
9737
10972
|
const usageColumns = this.#database.prepare("PRAGMA table_info(usage_observations)").all();
|
|
9738
10973
|
if (!usageColumns.some((column) => column.name === "total_tokens")) {
|
|
@@ -9890,9 +11125,9 @@ var init_sqlite_usage_repository = __esm({
|
|
|
9890
11125
|
`);
|
|
9891
11126
|
const quotaColumns = this.#database.prepare("PRAGMA table_info(quota_buckets)").all();
|
|
9892
11127
|
for (const [name, type] of [
|
|
11128
|
+
["window_duration_minutes", "INTEGER"],
|
|
9893
11129
|
["scope", "TEXT"],
|
|
9894
11130
|
["status", "TEXT"],
|
|
9895
|
-
["window_duration_minutes", "INTEGER"],
|
|
9896
11131
|
["limit_amount", "REAL"],
|
|
9897
11132
|
["limit_currency", "TEXT"],
|
|
9898
11133
|
["fallback_status", "TEXT"]
|
|
@@ -9916,14 +11151,14 @@ __export(runtime_exports, {
|
|
|
9916
11151
|
runDaemon: () => runDaemon
|
|
9917
11152
|
});
|
|
9918
11153
|
import { existsSync as existsSync2 } from "fs";
|
|
9919
|
-
import { mkdir as
|
|
9920
|
-
import { homedir as
|
|
9921
|
-
import { isAbsolute as isAbsolute3, join as
|
|
11154
|
+
import { mkdir as mkdir5, rm as rm2 } from "fs/promises";
|
|
11155
|
+
import { homedir as homedir4 } from "os";
|
|
11156
|
+
import { isAbsolute as isAbsolute3, join as join10, resolve as resolve3 } from "path";
|
|
9922
11157
|
import { fileURLToPath } from "url";
|
|
9923
11158
|
async function runDaemon(home) {
|
|
9924
|
-
await
|
|
11159
|
+
await mkdir5(home, { recursive: true, mode: 448 });
|
|
9925
11160
|
const demoEnabled = process.env.AGENT_USAGE_DEMO === "1";
|
|
9926
|
-
const repository = new SqliteUsageRepository(
|
|
11161
|
+
const repository = new SqliteUsageRepository(join10(home, "usage.sqlite"), {
|
|
9927
11162
|
hideDemoProvider: !demoEnabled
|
|
9928
11163
|
});
|
|
9929
11164
|
const keychainService = process.env.AGENT_USAGE_KEYCHAIN_SERVICE;
|
|
@@ -9958,7 +11193,16 @@ async function runDaemon(home) {
|
|
|
9958
11193
|
historyClient: localTranscriptClient("grok", home)
|
|
9959
11194
|
}),
|
|
9960
11195
|
new XaiApiConnector({ accountClient: new XaiManagementApiClient({ secretStore }) }),
|
|
9961
|
-
new DshConnector({ historyClient: localTranscriptClient("dsh", home) })
|
|
11196
|
+
new DshConnector({ historyClient: localTranscriptClient("dsh", home) }),
|
|
11197
|
+
new AntigravityConnector({
|
|
11198
|
+
historyClient: new AntigravitySqliteUsageClient({
|
|
11199
|
+
roots: [
|
|
11200
|
+
join10(homedir4(), ".gemini/antigravity-cli"),
|
|
11201
|
+
join10(homedir4(), ".gemini/antigravity")
|
|
11202
|
+
],
|
|
11203
|
+
cachePath: join10(home, "antigravity-usage-cache.json")
|
|
11204
|
+
})
|
|
11205
|
+
})
|
|
9962
11206
|
],
|
|
9963
11207
|
connectorDefinitions: defaultConnectorDefinitions,
|
|
9964
11208
|
discoveryProbe: new PathDiscoveryProbe(),
|
|
@@ -9966,7 +11210,7 @@ async function runDaemon(home) {
|
|
|
9966
11210
|
exchangeRateProvider: new EcbExchangeRateProvider(),
|
|
9967
11211
|
notifier: new MacOsNotifier(),
|
|
9968
11212
|
startAtLoginManager: new MacOsStartAtLoginManager({
|
|
9969
|
-
userHome:
|
|
11213
|
+
userHome: homedir4(),
|
|
9970
11214
|
executable: process.execPath,
|
|
9971
11215
|
cliPath: process.argv[1],
|
|
9972
11216
|
applicationHome: home,
|
|
@@ -9981,7 +11225,16 @@ async function runDaemon(home) {
|
|
|
9981
11225
|
}
|
|
9982
11226
|
}),
|
|
9983
11227
|
connectorPolicies: Object.fromEntries(
|
|
9984
|
-
[
|
|
11228
|
+
[
|
|
11229
|
+
"codex",
|
|
11230
|
+
"claude-code",
|
|
11231
|
+
"opencode-go",
|
|
11232
|
+
"opencode",
|
|
11233
|
+
"grok",
|
|
11234
|
+
"xai-api",
|
|
11235
|
+
"dsh",
|
|
11236
|
+
"antigravity"
|
|
11237
|
+
].map((id) => [
|
|
9985
11238
|
id,
|
|
9986
11239
|
{ minimumIntervalMs: 5 * 60 * 1e3, timeoutMs: id === "claude-code" ? 25e3 : 2e4 }
|
|
9987
11240
|
])
|
|
@@ -10032,7 +11285,7 @@ async function runDaemon(home) {
|
|
|
10032
11285
|
scheduler.stop();
|
|
10033
11286
|
await server.close();
|
|
10034
11287
|
repository.close();
|
|
10035
|
-
await rm2(
|
|
11288
|
+
await rm2(join10(home, "daemon.json"), { force: true });
|
|
10036
11289
|
resolveStop();
|
|
10037
11290
|
};
|
|
10038
11291
|
process.once("SIGTERM", () => void stop());
|
|
@@ -10043,27 +11296,27 @@ function localTranscriptClient(provider, applicationHome) {
|
|
|
10043
11296
|
return new LocalTranscriptUsageClient({
|
|
10044
11297
|
provider,
|
|
10045
11298
|
roots: localTranscriptRoots(provider),
|
|
10046
|
-
cachePath:
|
|
11299
|
+
cachePath: join10(applicationHome, "cache", `${provider}-transcripts.json`)
|
|
10047
11300
|
});
|
|
10048
11301
|
}
|
|
10049
11302
|
function localTranscriptRoots(provider) {
|
|
10050
11303
|
if (provider === "codex") {
|
|
10051
11304
|
const home = resolveHomeOverride(process.env.CODEX_HOME, ".codex");
|
|
10052
|
-
return [
|
|
11305
|
+
return [join10(home, "sessions"), join10(home, "archived_sessions")];
|
|
10053
11306
|
}
|
|
10054
11307
|
if (provider === "claude-code") {
|
|
10055
|
-
return [
|
|
11308
|
+
return [join10(resolveHomeOverride(process.env.CLAUDE_CONFIG_DIR, ".claude"), "projects")];
|
|
10056
11309
|
}
|
|
10057
11310
|
if (provider === "dsh") {
|
|
10058
|
-
return [
|
|
11311
|
+
return [join10(resolveHomeOverride(process.env.DSH_HOME, ".dsh"), "sessions")];
|
|
10059
11312
|
}
|
|
10060
|
-
return [
|
|
11313
|
+
return [join10(resolveHomeOverride(process.env.GROK_HOME, ".grok"), "sessions")];
|
|
10061
11314
|
}
|
|
10062
11315
|
function resolveHomeOverride(value, fallback) {
|
|
10063
11316
|
const configured = value?.trim();
|
|
10064
|
-
if (!configured) return
|
|
10065
|
-
if (configured === "~") return
|
|
10066
|
-
if (configured.startsWith("~/")) return
|
|
11317
|
+
if (!configured) return join10(homedir4(), fallback);
|
|
11318
|
+
if (configured === "~") return homedir4();
|
|
11319
|
+
if (configured.startsWith("~/")) return join10(homedir4(), configured.slice(2));
|
|
10067
11320
|
return isAbsolute3(configured) ? configured : resolve3(configured);
|
|
10068
11321
|
}
|
|
10069
11322
|
function createDemoConnector() {
|
|
@@ -10109,7 +11362,7 @@ function locateStaticDirectory() {
|
|
|
10109
11362
|
fileURLToPath(new URL("./web", import.meta.url)),
|
|
10110
11363
|
fileURLToPath(new URL("../../dist/web", import.meta.url))
|
|
10111
11364
|
];
|
|
10112
|
-
return candidates.find((candidate) => existsSync2(
|
|
11365
|
+
return candidates.find((candidate) => existsSync2(join10(candidate, "index.html")));
|
|
10113
11366
|
}
|
|
10114
11367
|
var init_runtime = __esm({
|
|
10115
11368
|
"src/server/runtime.ts"() {
|
|
@@ -10127,6 +11380,8 @@ var init_runtime = __esm({
|
|
|
10127
11380
|
init_opencode_auth_reader();
|
|
10128
11381
|
init_opencode_go_connector();
|
|
10129
11382
|
init_dsh_connector();
|
|
11383
|
+
init_antigravity_connector();
|
|
11384
|
+
init_antigravity_sqlite_usage_client();
|
|
10130
11385
|
init_grok_build_connector();
|
|
10131
11386
|
init_grok_telemetry();
|
|
10132
11387
|
init_stdio_grok_billing_client();
|
|
@@ -10149,8 +11404,8 @@ init_redaction();
|
|
|
10149
11404
|
init_daemon_state();
|
|
10150
11405
|
import { spawn as spawn6 } from "child_process";
|
|
10151
11406
|
import { connect as tcpConnect } from "net";
|
|
10152
|
-
import { homedir as
|
|
10153
|
-
import { join as
|
|
11407
|
+
import { homedir as homedir5 } from "os";
|
|
11408
|
+
import { join as join11, resolve as resolve4 } from "path";
|
|
10154
11409
|
import { Command } from "commander";
|
|
10155
11410
|
import open2 from "open";
|
|
10156
11411
|
var program = new Command();
|
|
@@ -10332,6 +11587,97 @@ program.command("start-at-login <action>").description("enable, disable, or show
|
|
|
10332
11587
|
process.stdout.write(`${status.settings.startAtLogin ? "enabled" : "disabled"}
|
|
10333
11588
|
`);
|
|
10334
11589
|
});
|
|
11590
|
+
var ratesCommand = program.command("rates").description("view and manage custom model rates for custom endpoints");
|
|
11591
|
+
ratesCommand.command("list").description("list configured custom model rates").option("--json", "emit machine-readable JSON").action(async (options) => {
|
|
11592
|
+
const home = resolve4(program.opts().home);
|
|
11593
|
+
const state = await requireDaemonState(home);
|
|
11594
|
+
const response = await fetch(`${state.origin}/api/custom-rates`, {
|
|
11595
|
+
headers: { authorization: `Bearer ${state.apiToken}` }
|
|
11596
|
+
});
|
|
11597
|
+
if (!response.ok) throw new Error(`Daemon returned HTTP ${response.status}`);
|
|
11598
|
+
const data = await response.json();
|
|
11599
|
+
if (options.json) {
|
|
11600
|
+
process.stdout.write(`${JSON.stringify(data.rates, null, 2)}
|
|
11601
|
+
`);
|
|
11602
|
+
return;
|
|
11603
|
+
}
|
|
11604
|
+
if (data.rates.length === 0) {
|
|
11605
|
+
process.stdout.write("No custom model rates configured.\n");
|
|
11606
|
+
return;
|
|
11607
|
+
}
|
|
11608
|
+
for (const rate of data.rates) {
|
|
11609
|
+
const domain = rate.billingDomainId ?? "*";
|
|
11610
|
+
process.stdout.write(
|
|
11611
|
+
`${rate.id} | ${rate.providerId} | domain: ${domain} | model: ${rate.model} | in: $${rate.ratesPerMillion.input}/M | out: $${rate.ratesPerMillion.output}/M | cache: $${rate.ratesPerMillion.cacheRead}/M
|
|
11612
|
+
`
|
|
11613
|
+
);
|
|
11614
|
+
}
|
|
11615
|
+
});
|
|
11616
|
+
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(
|
|
11617
|
+
async (model, options) => {
|
|
11618
|
+
const home = resolve4(program.opts().home);
|
|
11619
|
+
const state = await requireDaemonState(home);
|
|
11620
|
+
const response = await fetch(`${state.origin}/api/custom-rates`, {
|
|
11621
|
+
method: "POST",
|
|
11622
|
+
headers: {
|
|
11623
|
+
authorization: `Bearer ${state.apiToken}`,
|
|
11624
|
+
"content-type": "application/json",
|
|
11625
|
+
origin: state.origin
|
|
11626
|
+
},
|
|
11627
|
+
body: JSON.stringify({
|
|
11628
|
+
...options.id ? { id: options.id } : {},
|
|
11629
|
+
providerId: options.provider,
|
|
11630
|
+
billingDomainId: options.domain || null,
|
|
11631
|
+
model,
|
|
11632
|
+
inputRate: options.input,
|
|
11633
|
+
outputRate: options.output,
|
|
11634
|
+
cacheReadRate: options.cacheRead
|
|
11635
|
+
})
|
|
11636
|
+
});
|
|
11637
|
+
if (!response.ok) throw new Error(`Daemon returned HTTP ${response.status}`);
|
|
11638
|
+
const data = await response.json();
|
|
11639
|
+
process.stdout.write(
|
|
11640
|
+
`Custom model rate configured for ${data.rate.model} (ID: ${data.rate.id})
|
|
11641
|
+
`
|
|
11642
|
+
);
|
|
11643
|
+
}
|
|
11644
|
+
);
|
|
11645
|
+
ratesCommand.command("get <id>").description("get details of a custom model rate by ID").option("--json", "emit machine-readable JSON").action(async (id, options) => {
|
|
11646
|
+
const home = resolve4(program.opts().home);
|
|
11647
|
+
const state = await requireDaemonState(home);
|
|
11648
|
+
const response = await fetch(`${state.origin}/api/custom-rates/${encodeURIComponent(id)}`, {
|
|
11649
|
+
headers: { authorization: `Bearer ${state.apiToken}` }
|
|
11650
|
+
});
|
|
11651
|
+
if (!response.ok) {
|
|
11652
|
+
if (response.status === 404) throw new Error(`Custom model rate not found: ${id}`);
|
|
11653
|
+
throw new Error(`Daemon returned HTTP ${response.status}`);
|
|
11654
|
+
}
|
|
11655
|
+
const data = await response.json();
|
|
11656
|
+
if (options.json) {
|
|
11657
|
+
process.stdout.write(`${JSON.stringify(data.rate, null, 2)}
|
|
11658
|
+
`);
|
|
11659
|
+
return;
|
|
11660
|
+
}
|
|
11661
|
+
const domain = data.rate.billingDomainId ?? "*";
|
|
11662
|
+
process.stdout.write(
|
|
11663
|
+
`${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}
|
|
11664
|
+
`
|
|
11665
|
+
);
|
|
11666
|
+
});
|
|
11667
|
+
ratesCommand.command("delete <id>").description("delete custom model rate by ID").action(async (id) => {
|
|
11668
|
+
const home = resolve4(program.opts().home);
|
|
11669
|
+
const state = await requireDaemonState(home);
|
|
11670
|
+
const response = await fetch(`${state.origin}/api/custom-rates/${encodeURIComponent(id)}`, {
|
|
11671
|
+
method: "DELETE",
|
|
11672
|
+
headers: {
|
|
11673
|
+
authorization: `Bearer ${state.apiToken}`,
|
|
11674
|
+
origin: state.origin
|
|
11675
|
+
}
|
|
11676
|
+
});
|
|
11677
|
+
if (!response.ok) throw new Error(`Daemon returned HTTP ${response.status}`);
|
|
11678
|
+
process.stdout.write(`Deleted custom model rate ${id}
|
|
11679
|
+
`);
|
|
11680
|
+
});
|
|
10335
11681
|
program.command("serve").description("run the internal local daemon").action(async () => {
|
|
10336
11682
|
const home = resolve4(program.opts().home);
|
|
10337
11683
|
const { runDaemon: runDaemon2 } = await Promise.resolve().then(() => (init_runtime(), runtime_exports));
|
|
@@ -10515,6 +11861,6 @@ function formatDoctor(report) {
|
|
|
10515
11861
|
].join("\n");
|
|
10516
11862
|
}
|
|
10517
11863
|
function defaultHome() {
|
|
10518
|
-
return
|
|
11864
|
+
return join11(homedir5(), "Library", "Application Support", "Agent Usage");
|
|
10519
11865
|
}
|
|
10520
11866
|
//# sourceMappingURL=cli.js.map
|