@narumitw/pi-usage 0.58.0 → 0.59.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 +83 -1
- package/dist/index.ts +813 -197
- package/dist/index.ts.map +4 -4
- package/package.json +7 -1
- package/src/format.ts +161 -7
- package/src/index.ts +13 -0
- package/src/providers/baseten.ts +55 -0
- package/src/providers/minimax.ts +264 -0
- package/src/providers/moonshot.ts +64 -0
- package/src/providers/vercel-ai-gateway.ts +43 -0
- package/src/query.ts +214 -6
- package/src/types.ts +30 -0
- package/src/usage.ts +19 -13
package/dist/index.ts
CHANGED
|
@@ -109,7 +109,7 @@ var UsageCache = class {
|
|
|
109
109
|
this.sweepExpired(now);
|
|
110
110
|
return this.entries.get(cacheKey(providerId, fingerprint))?.report;
|
|
111
111
|
}
|
|
112
|
-
set(providerId, fingerprint,
|
|
112
|
+
set(providerId, fingerprint, report2, now = Date.now()) {
|
|
113
113
|
this.sweepExpired(now);
|
|
114
114
|
const key = cacheKey(providerId, fingerprint);
|
|
115
115
|
this.entries.delete(key);
|
|
@@ -118,7 +118,7 @@ var UsageCache = class {
|
|
|
118
118
|
if (oldest === void 0) break;
|
|
119
119
|
this.entries.delete(oldest);
|
|
120
120
|
}
|
|
121
|
-
this.entries.set(key, { createdAt: now, report });
|
|
121
|
+
this.entries.set(key, { createdAt: now, report: report2 });
|
|
122
122
|
}
|
|
123
123
|
clearProvider(providerId) {
|
|
124
124
|
for (const key of this.entries.keys()) {
|
|
@@ -328,13 +328,56 @@ function cloneOAuthCredential(value) {
|
|
|
328
328
|
import { randomBytes } from "node:crypto";
|
|
329
329
|
import { readStoredCredential as readStoredCredential2 } from "@earendil-works/pi-coding-agent";
|
|
330
330
|
|
|
331
|
+
// src/providers/baseten.ts
|
|
332
|
+
var DECIMAL_AMOUNT = /^(?:0|[1-9]\d*)(?:\.\d+)?$/u;
|
|
333
|
+
function normalizeBasetenBillingUsagePayload(payload, capturedAt) {
|
|
334
|
+
if (payload.model_apis_usage === void 0 || payload.model_apis_usage === null) {
|
|
335
|
+
return report(capturedAt, [], ["Baseten returned no Model APIs usage for the last 30 days."]);
|
|
336
|
+
}
|
|
337
|
+
const usage = asObject(payload.model_apis_usage);
|
|
338
|
+
if (!usage) throw new Error("Baseten Model APIs usage was not an object.");
|
|
339
|
+
const metrics = [
|
|
340
|
+
metric("gross-usage", "Gross usage", usage.total),
|
|
341
|
+
metric("credits-used", "Credits used", usage.credits_used),
|
|
342
|
+
metric("net-subtotal", "Net subtotal", usage.subtotal)
|
|
343
|
+
];
|
|
344
|
+
return report(capturedAt, metrics);
|
|
345
|
+
}
|
|
346
|
+
function report(capturedAt, metrics, notes) {
|
|
347
|
+
return {
|
|
348
|
+
providerId: "baseten",
|
|
349
|
+
providerName: "Baseten",
|
|
350
|
+
capturedAt,
|
|
351
|
+
source: "baseten-billing-usage-summary",
|
|
352
|
+
semantics: { kind: "api-key", label: "Organization Model APIs spend" },
|
|
353
|
+
buckets: [],
|
|
354
|
+
metrics,
|
|
355
|
+
...notes ? { notes } : {}
|
|
356
|
+
};
|
|
357
|
+
}
|
|
358
|
+
function metric(id, label, value) {
|
|
359
|
+
const amount2 = decimalAmount(value, label);
|
|
360
|
+
return { id, label, value: amount2, unit: "currency", currency: "USD" };
|
|
361
|
+
}
|
|
362
|
+
function decimalAmount(value, label) {
|
|
363
|
+
const normalized = typeof value === "number" && Number.isFinite(value) ? String(value) : value;
|
|
364
|
+
if (typeof normalized !== "string" || normalized.length > 64 || !DECIMAL_AMOUNT.test(normalized)) {
|
|
365
|
+
throw new Error(`Baseten ${label.toLowerCase()} was not a valid nonnegative amount.`);
|
|
366
|
+
}
|
|
367
|
+
return normalized;
|
|
368
|
+
}
|
|
369
|
+
function asObject(value) {
|
|
370
|
+
if (!value || typeof value !== "object" || Array.isArray(value)) return void 0;
|
|
371
|
+
return value;
|
|
372
|
+
}
|
|
373
|
+
|
|
331
374
|
// src/providers/codex.ts
|
|
332
375
|
function normalizeCodexBackendPayload(payload, capturedAt) {
|
|
333
376
|
const buckets = [];
|
|
334
377
|
normalizeRateLimitGroup(buckets, "codex", "Codex", payload.rate_limit, false);
|
|
335
378
|
const additional = Array.isArray(payload.additional_rate_limits) ? payload.additional_rate_limits : [];
|
|
336
379
|
for (const item of additional) {
|
|
337
|
-
const value =
|
|
380
|
+
const value = asObject2(item);
|
|
338
381
|
const id = asString(value?.metered_feature) ?? asString(value?.limit_name);
|
|
339
382
|
if (!value || !id) continue;
|
|
340
383
|
try {
|
|
@@ -349,7 +392,7 @@ function normalizeCodexBackendPayload(payload, capturedAt) {
|
|
|
349
392
|
}
|
|
350
393
|
}
|
|
351
394
|
const metrics = [];
|
|
352
|
-
const credits =
|
|
395
|
+
const credits = asObject2(payload.credits);
|
|
353
396
|
if (credits?.has_credits === true) {
|
|
354
397
|
if (credits.unlimited === true) {
|
|
355
398
|
metrics.push({ id: "credits", label: "Credits", value: "unlimited" });
|
|
@@ -364,7 +407,7 @@ function normalizeCodexBackendPayload(payload, capturedAt) {
|
|
|
364
407
|
} else if (credits?.has_credits === false) {
|
|
365
408
|
metrics.push({ id: "credits", label: "Credits", value: "none" });
|
|
366
409
|
}
|
|
367
|
-
const resetCredits =
|
|
410
|
+
const resetCredits = asObject2(payload.rate_limit_reset_credits);
|
|
368
411
|
const resetCount = asNonnegativeInteger(resetCredits?.available_count);
|
|
369
412
|
if (resetCount !== void 0) {
|
|
370
413
|
metrics.push({
|
|
@@ -394,7 +437,7 @@ function normalizeCodexBackendPayload(payload, capturedAt) {
|
|
|
394
437
|
}
|
|
395
438
|
function normalizeRateLimitGroup(buckets, groupId, groupLabel, raw, optional) {
|
|
396
439
|
if (raw === void 0 || raw === null) return;
|
|
397
|
-
const details =
|
|
440
|
+
const details = asObject2(raw);
|
|
398
441
|
if (!details) {
|
|
399
442
|
if (optional) return;
|
|
400
443
|
throw new Error("Codex rate limit was not an object.");
|
|
@@ -404,7 +447,7 @@ function normalizeRateLimitGroup(buckets, groupId, groupLabel, raw, optional) {
|
|
|
404
447
|
}
|
|
405
448
|
function addWindow(buckets, groupId, groupLabel, position, raw) {
|
|
406
449
|
if (raw === void 0 || raw === null) return;
|
|
407
|
-
const value =
|
|
450
|
+
const value = asObject2(raw);
|
|
408
451
|
if (!value) throw new Error("Codex rate-limit window was not an object.");
|
|
409
452
|
const used = asNumber(value.used_percent);
|
|
410
453
|
if (used === void 0) return;
|
|
@@ -424,7 +467,7 @@ function addWindow(buckets, groupId, groupLabel, position, raw) {
|
|
|
424
467
|
...resetsAt !== void 0 ? { resetsAt } : {}
|
|
425
468
|
});
|
|
426
469
|
}
|
|
427
|
-
function
|
|
470
|
+
function asObject2(value) {
|
|
428
471
|
if (!value || typeof value !== "object" || Array.isArray(value)) return void 0;
|
|
429
472
|
return value;
|
|
430
473
|
}
|
|
@@ -465,7 +508,7 @@ function normalizeDeepSeekBalancePayload(payload, capturedAt) {
|
|
|
465
508
|
}
|
|
466
509
|
const balances = /* @__PURE__ */ new Map();
|
|
467
510
|
for (const raw of payload.balance_infos) {
|
|
468
|
-
const balance =
|
|
511
|
+
const balance = asObject3(raw);
|
|
469
512
|
if (!balance) throw new Error("DeepSeek API balance row was not an object.");
|
|
470
513
|
const currency = deepSeekCurrency(balance.currency);
|
|
471
514
|
if (!currency) throw new Error("DeepSeek API balance row returned an unsupported currency.");
|
|
@@ -473,7 +516,7 @@ function normalizeDeepSeekBalancePayload(payload, capturedAt) {
|
|
|
473
516
|
throw new Error(`DeepSeek API balance response repeated ${currency}.`);
|
|
474
517
|
}
|
|
475
518
|
for (const [, label, field] of BALANCE_FIELDS) {
|
|
476
|
-
if (!
|
|
519
|
+
if (!decimalAmount2(balance[field])) {
|
|
477
520
|
throw new Error(`DeepSeek API balance ${label.toLowerCase()} was not a valid amount.`);
|
|
478
521
|
}
|
|
479
522
|
}
|
|
@@ -509,14 +552,14 @@ function normalizeDeepSeekBalancePayload(payload, capturedAt) {
|
|
|
509
552
|
metrics
|
|
510
553
|
};
|
|
511
554
|
}
|
|
512
|
-
function
|
|
555
|
+
function asObject3(value) {
|
|
513
556
|
if (!value || typeof value !== "object" || Array.isArray(value)) return void 0;
|
|
514
557
|
return value;
|
|
515
558
|
}
|
|
516
559
|
function deepSeekCurrency(value) {
|
|
517
560
|
return CURRENCIES.find((currency) => currency === value);
|
|
518
561
|
}
|
|
519
|
-
function
|
|
562
|
+
function decimalAmount2(value) {
|
|
520
563
|
return typeof value === "string" && value.length <= 64 && /^(?:0|[1-9]\d*)(?:\.\d+)?$/u.test(value);
|
|
521
564
|
}
|
|
522
565
|
|
|
@@ -545,7 +588,7 @@ function normalizeFireworksAccountsPayload(payload) {
|
|
|
545
588
|
}
|
|
546
589
|
const accounts = [];
|
|
547
590
|
for (const raw of payload.accounts) {
|
|
548
|
-
const account =
|
|
591
|
+
const account = asObject4(raw);
|
|
549
592
|
if (!account) throw new Error("Fireworks accounts response row was not an object.");
|
|
550
593
|
if (typeof account.name !== "string") {
|
|
551
594
|
throw new Error("Fireworks accounts response omitted the account resource name.");
|
|
@@ -571,7 +614,7 @@ function normalizeFireworksBillingSummaryPayload(payload, accountId, capturedAt)
|
|
|
571
614
|
}
|
|
572
615
|
const totals = /* @__PURE__ */ new Map();
|
|
573
616
|
for (const raw of payload.lineItems ?? []) {
|
|
574
|
-
const lineItem =
|
|
617
|
+
const lineItem = asObject4(raw);
|
|
575
618
|
if (!lineItem) throw new Error("Fireworks billing line item was not an object.");
|
|
576
619
|
const cost = moneyAmount(lineItem.totalCost, "line item total cost");
|
|
577
620
|
const series = seriesKey(lineItem.series);
|
|
@@ -592,12 +635,12 @@ function normalizeFireworksBillingSummaryPayload(payload, accountId, capturedAt)
|
|
|
592
635
|
currency
|
|
593
636
|
});
|
|
594
637
|
for (const series of SERIES_KEYS) {
|
|
595
|
-
const
|
|
596
|
-
if (
|
|
638
|
+
const amount2 = amounts.get(series);
|
|
639
|
+
if (amount2 === void 0) continue;
|
|
597
640
|
metrics.push({
|
|
598
641
|
id: `${currency.toLowerCase()}-${series}`,
|
|
599
642
|
label: SERIES_LABELS[series],
|
|
600
|
-
value: formatMoneyAmount(
|
|
643
|
+
value: formatMoneyAmount(amount2),
|
|
601
644
|
unit: "currency",
|
|
602
645
|
currency
|
|
603
646
|
});
|
|
@@ -622,7 +665,7 @@ function normalizeFireworksBillingSummaryPayload(payload, accountId, capturedAt)
|
|
|
622
665
|
};
|
|
623
666
|
}
|
|
624
667
|
function moneyAmount(value, description) {
|
|
625
|
-
const money =
|
|
668
|
+
const money = asObject4(value);
|
|
626
669
|
if (!money) throw new Error(`Fireworks billing ${description} was not a money object.`);
|
|
627
670
|
const currency = typeof money.currencyCode === "string" ? money.currencyCode : void 0;
|
|
628
671
|
if (!currency || !CURRENCY_PATTERN.test(currency)) {
|
|
@@ -658,25 +701,25 @@ function seriesKey(value) {
|
|
|
658
701
|
}
|
|
659
702
|
function sumSeries(amounts) {
|
|
660
703
|
let total = 0n;
|
|
661
|
-
for (const
|
|
704
|
+
for (const amount2 of amounts.values()) total += amount2;
|
|
662
705
|
return total;
|
|
663
706
|
}
|
|
664
|
-
function formatMoneyAmount(
|
|
665
|
-
const negative =
|
|
666
|
-
const magnitude = negative ? -
|
|
707
|
+
function formatMoneyAmount(amount2) {
|
|
708
|
+
const negative = amount2 < 0n;
|
|
709
|
+
const magnitude = negative ? -amount2 : amount2;
|
|
667
710
|
const units = magnitude / NANOS_PER_UNIT;
|
|
668
711
|
const nanos = (magnitude % NANOS_PER_UNIT).toString().padStart(9, "0").replace(/0+$/u, "");
|
|
669
712
|
return `${negative ? "-" : ""}${units.toString()}${nanos ? `.${nanos}` : ""}`;
|
|
670
713
|
}
|
|
671
|
-
function
|
|
714
|
+
function asObject4(value) {
|
|
672
715
|
if (!value || typeof value !== "object" || Array.isArray(value)) return void 0;
|
|
673
716
|
return value;
|
|
674
717
|
}
|
|
675
718
|
|
|
676
719
|
// src/providers/github-copilot.ts
|
|
677
720
|
function normalizeGitHubCopilotUsagePayload(payload, capturedAt) {
|
|
678
|
-
const snapshots =
|
|
679
|
-
const premium =
|
|
721
|
+
const snapshots = asObject5(payload.quota_snapshots);
|
|
722
|
+
const premium = asObject5(snapshots?.premium_interactions);
|
|
680
723
|
const metrics = [];
|
|
681
724
|
let semanticsLabel;
|
|
682
725
|
let bucket;
|
|
@@ -717,8 +760,8 @@ function normalizeGitHubCopilotUsagePayload(payload, capturedAt) {
|
|
|
717
760
|
};
|
|
718
761
|
}
|
|
719
762
|
} else {
|
|
720
|
-
const limited =
|
|
721
|
-
const monthly =
|
|
763
|
+
const limited = asObject5(payload.limited_user_quotas);
|
|
764
|
+
const monthly = asObject5(payload.monthly_quotas);
|
|
722
765
|
const remaining = asNonnegativeNumber(limited?.chat);
|
|
723
766
|
const entitlement = asNonnegativeNumber(monthly?.chat);
|
|
724
767
|
if (remaining === void 0 || entitlement === void 0) {
|
|
@@ -757,7 +800,7 @@ function resetTimestamp(payload) {
|
|
|
757
800
|
const milliseconds = Date.parse(raw);
|
|
758
801
|
return Number.isNaN(milliseconds) ? {} : { resetsAt: Math.floor(milliseconds / 1e3) };
|
|
759
802
|
}
|
|
760
|
-
function
|
|
803
|
+
function asObject5(value) {
|
|
761
804
|
if (!value || typeof value !== "object" || Array.isArray(value)) return void 0;
|
|
762
805
|
return value;
|
|
763
806
|
}
|
|
@@ -780,7 +823,7 @@ var DAILY_WINDOW_MINUTES = 1440;
|
|
|
780
823
|
var WEEKLY_WINDOW_MINUTES = 10080;
|
|
781
824
|
var FIXED_POINT_UNITS_PER_CENT = 1e6;
|
|
782
825
|
function normalizeKimiCodingUsagePayload(payload, capturedAt) {
|
|
783
|
-
const root =
|
|
826
|
+
const root = asObject6(payload);
|
|
784
827
|
if (!root) throw new Error("Kimi Coding usage response was not an object.");
|
|
785
828
|
const candidates = [];
|
|
786
829
|
let omittedWindow = false;
|
|
@@ -789,7 +832,7 @@ function normalizeKimiCodingUsagePayload(payload, capturedAt) {
|
|
|
789
832
|
else if (root.usage !== void 0) omittedWindow = true;
|
|
790
833
|
if (Array.isArray(root.limits)) {
|
|
791
834
|
for (const raw of root.limits) {
|
|
792
|
-
const item =
|
|
835
|
+
const item = asObject6(raw);
|
|
793
836
|
const windowMinutes = parseWindowMinutes(item?.window);
|
|
794
837
|
const label = sanitizedLabel(item?.name);
|
|
795
838
|
const bucket = windowMinutes === void 0 ? void 0 : parseUsageRow(item?.detail, windowMinutes, label ?? defaultWindowLabel(windowMinutes));
|
|
@@ -826,7 +869,7 @@ function normalizeKimiCodingUsagePayload(payload, capturedAt) {
|
|
|
826
869
|
};
|
|
827
870
|
}
|
|
828
871
|
function parseUsageRow(value, windowMinutes, label) {
|
|
829
|
-
const row =
|
|
872
|
+
const row = asObject6(value);
|
|
830
873
|
if (!row) return void 0;
|
|
831
874
|
const used = asNonnegativeInteger2(row.used);
|
|
832
875
|
const limit = asNonnegativeInteger2(row.limit);
|
|
@@ -844,7 +887,7 @@ function parseUsageRow(value, windowMinutes, label) {
|
|
|
844
887
|
};
|
|
845
888
|
}
|
|
846
889
|
function parseWindowMinutes(value) {
|
|
847
|
-
const window =
|
|
890
|
+
const window = asObject6(value);
|
|
848
891
|
if (!window) return void 0;
|
|
849
892
|
const duration = asPositiveInteger(window.duration);
|
|
850
893
|
if (duration === void 0) return void 0;
|
|
@@ -854,8 +897,8 @@ function parseWindowMinutes(value) {
|
|
|
854
897
|
return Number.isSafeInteger(minutes) ? minutes : void 0;
|
|
855
898
|
}
|
|
856
899
|
function parseBoosterWallet(value) {
|
|
857
|
-
const wallet =
|
|
858
|
-
const balance =
|
|
900
|
+
const wallet = asObject6(value);
|
|
901
|
+
const balance = asObject6(wallet?.balance);
|
|
859
902
|
if (!wallet || !balance || balance.type !== "BOOSTER") return [];
|
|
860
903
|
const totalRaw = asPositiveInteger(balance.amount);
|
|
861
904
|
if (totalRaw === void 0) return [];
|
|
@@ -906,7 +949,7 @@ function parseBoosterWallet(value) {
|
|
|
906
949
|
return metrics;
|
|
907
950
|
}
|
|
908
951
|
function parseMoney(value) {
|
|
909
|
-
const money =
|
|
952
|
+
const money = asObject6(value);
|
|
910
953
|
if (!money) return void 0;
|
|
911
954
|
const cents = asNonnegativeInteger2(money.priceInCents);
|
|
912
955
|
if (cents === void 0) return void 0;
|
|
@@ -920,7 +963,7 @@ function fixedPointToMajor(value) {
|
|
|
920
963
|
const major = roundedCents / 100;
|
|
921
964
|
return Number.isSafeInteger(roundedCents) && Number.isFinite(major) ? major : void 0;
|
|
922
965
|
}
|
|
923
|
-
function
|
|
966
|
+
function asObject6(value) {
|
|
924
967
|
if (!value || typeof value !== "object" || Array.isArray(value)) return void 0;
|
|
925
968
|
return value;
|
|
926
969
|
}
|
|
@@ -987,6 +1030,246 @@ function defaultWindowLabel(minutes) {
|
|
|
987
1030
|
return `${minutes}m window`;
|
|
988
1031
|
}
|
|
989
1032
|
|
|
1033
|
+
// src/providers/minimax.ts
|
|
1034
|
+
var PROVIDERS = {
|
|
1035
|
+
minimax: { name: "MiniMax", currency: "USD" },
|
|
1036
|
+
"minimax-cn": { name: "MiniMax CN", currency: "CNY" }
|
|
1037
|
+
};
|
|
1038
|
+
var DECIMAL_AMOUNT2 = /^-?(?:0|[1-9]\d*)(?:\.\d+)?$/u;
|
|
1039
|
+
var PERCENT_TOLERANCE = 1;
|
|
1040
|
+
function miniMaxUsageKind(apiKey) {
|
|
1041
|
+
return apiKey.startsWith("sk-api-") ? "account-balance" : "token-plan";
|
|
1042
|
+
}
|
|
1043
|
+
function normalizeMiniMaxUsagePayload(providerId, kind, payload, capturedAt) {
|
|
1044
|
+
return kind === "account-balance" ? normalizeBalance(providerId, payload, capturedAt) : normalizeTokenPlan(providerId, payload, capturedAt);
|
|
1045
|
+
}
|
|
1046
|
+
function normalizeBalance(providerId, payload, capturedAt) {
|
|
1047
|
+
assertSuccess(payload);
|
|
1048
|
+
const provider = PROVIDERS[providerId];
|
|
1049
|
+
const metrics = [
|
|
1050
|
+
balanceMetric(
|
|
1051
|
+
"available-balance",
|
|
1052
|
+
"Available balance",
|
|
1053
|
+
payload.available_amount,
|
|
1054
|
+
provider.currency
|
|
1055
|
+
),
|
|
1056
|
+
balanceMetric("cash-balance", "Cash balance", payload.cash_balance, provider.currency, true),
|
|
1057
|
+
balanceMetric("voucher-balance", "Voucher balance", payload.voucher_balance, provider.currency),
|
|
1058
|
+
balanceMetric("credit-balance", "Credit balance", payload.credit_balance, provider.currency),
|
|
1059
|
+
balanceMetric("owed-amount", "Owed amount", payload.owed_amount, provider.currency)
|
|
1060
|
+
];
|
|
1061
|
+
return {
|
|
1062
|
+
providerId,
|
|
1063
|
+
providerName: provider.name,
|
|
1064
|
+
capturedAt,
|
|
1065
|
+
source: "minimax-account-balance",
|
|
1066
|
+
semantics: { kind: "api-key", label: "MiniMax pay-as-you-go account balance" },
|
|
1067
|
+
buckets: [],
|
|
1068
|
+
metrics
|
|
1069
|
+
};
|
|
1070
|
+
}
|
|
1071
|
+
function normalizeTokenPlan(providerId, payload, capturedAt) {
|
|
1072
|
+
assertSuccess(payload);
|
|
1073
|
+
if (!Array.isArray(payload.model_remains) || payload.model_remains.length === 0) {
|
|
1074
|
+
throw new Error("MiniMax Token Plan returned no quota rows.");
|
|
1075
|
+
}
|
|
1076
|
+
const provider = PROVIDERS[providerId];
|
|
1077
|
+
const buckets = [];
|
|
1078
|
+
const groups = /* @__PURE__ */ new Set();
|
|
1079
|
+
for (const [index, raw] of payload.model_remains.entries()) {
|
|
1080
|
+
const row = asObject7(raw);
|
|
1081
|
+
if (!row) throw new Error("MiniMax Token Plan quota row was not an object.");
|
|
1082
|
+
const groupLabel = safeLabel(row.model_name, `Quota ${index + 1}`);
|
|
1083
|
+
const groupId = uniqueGroupId(groupLabel, index, groups);
|
|
1084
|
+
buckets.push(
|
|
1085
|
+
normalizeWindow(row, {
|
|
1086
|
+
id: `${groupId}:interval`,
|
|
1087
|
+
label: "Rolling window",
|
|
1088
|
+
groupId,
|
|
1089
|
+
groupLabel,
|
|
1090
|
+
countField: "current_interval_usage_count",
|
|
1091
|
+
totalField: "current_interval_total_count",
|
|
1092
|
+
percentField: "current_interval_remaining_percent",
|
|
1093
|
+
statusField: "current_interval_status",
|
|
1094
|
+
startField: "start_time",
|
|
1095
|
+
endField: "end_time"
|
|
1096
|
+
}),
|
|
1097
|
+
normalizeWindow(row, {
|
|
1098
|
+
id: `${groupId}:weekly`,
|
|
1099
|
+
label: "Weekly window",
|
|
1100
|
+
groupId,
|
|
1101
|
+
groupLabel,
|
|
1102
|
+
countField: "current_weekly_usage_count",
|
|
1103
|
+
totalField: "current_weekly_total_count",
|
|
1104
|
+
percentField: "current_weekly_remaining_percent",
|
|
1105
|
+
statusField: "current_weekly_status",
|
|
1106
|
+
startField: "weekly_start_time",
|
|
1107
|
+
endField: "weekly_end_time",
|
|
1108
|
+
boostPermille: row.weekly_boost_permille
|
|
1109
|
+
})
|
|
1110
|
+
);
|
|
1111
|
+
}
|
|
1112
|
+
return {
|
|
1113
|
+
providerId,
|
|
1114
|
+
providerName: provider.name,
|
|
1115
|
+
capturedAt,
|
|
1116
|
+
source: "minimax-token-plan",
|
|
1117
|
+
semantics: { kind: "consumer-subscription", label: "MiniMax Token Plan quota" },
|
|
1118
|
+
buckets,
|
|
1119
|
+
metrics: []
|
|
1120
|
+
};
|
|
1121
|
+
}
|
|
1122
|
+
function normalizeWindow(row, fields) {
|
|
1123
|
+
const status = optionalInteger(row[fields.statusField], fields.statusField);
|
|
1124
|
+
if (status !== void 0 && ![1, 2, 3].includes(status)) {
|
|
1125
|
+
throw new Error(`MiniMax Token Plan ${fields.label} status was unsupported.`);
|
|
1126
|
+
}
|
|
1127
|
+
const percent = optionalPercent(row[fields.percentField], fields.percentField);
|
|
1128
|
+
validateBoost(fields.boostPermille);
|
|
1129
|
+
const start = timestamp(row[fields.startField], fields.startField);
|
|
1130
|
+
const end = timestamp(row[fields.endField], fields.endField);
|
|
1131
|
+
if (end < start) throw new Error(`MiniMax Token Plan ${fields.label} timestamps were reversed.`);
|
|
1132
|
+
const resetsAt = Math.floor(end / 1e3);
|
|
1133
|
+
const windowMinutes = Math.max(1, Math.round((end - start) / 6e4));
|
|
1134
|
+
if (status === 3) {
|
|
1135
|
+
return {
|
|
1136
|
+
id: fields.id,
|
|
1137
|
+
label: fields.label,
|
|
1138
|
+
groupId: fields.groupId,
|
|
1139
|
+
groupLabel: fields.groupLabel,
|
|
1140
|
+
remaining: 100,
|
|
1141
|
+
unit: "percent",
|
|
1142
|
+
period: "unlimited",
|
|
1143
|
+
windowMinutes
|
|
1144
|
+
};
|
|
1145
|
+
}
|
|
1146
|
+
const total = nonnegativeInteger(row[fields.totalField], fields.totalField);
|
|
1147
|
+
const count = nonnegativeInteger(row[fields.countField], fields.countField);
|
|
1148
|
+
const resolved = resolveQuotaCounts(count, total, percent);
|
|
1149
|
+
if (!resolved) throw new Error(`MiniMax Token Plan ${fields.label} counts were inconsistent.`);
|
|
1150
|
+
return {
|
|
1151
|
+
id: fields.id,
|
|
1152
|
+
label: fields.label,
|
|
1153
|
+
groupId: fields.groupId,
|
|
1154
|
+
groupLabel: fields.groupLabel,
|
|
1155
|
+
...resolved,
|
|
1156
|
+
unit: "count",
|
|
1157
|
+
windowMinutes,
|
|
1158
|
+
resetsAt
|
|
1159
|
+
};
|
|
1160
|
+
}
|
|
1161
|
+
function resolveQuotaCounts(reportedCount, total, remainingPercent) {
|
|
1162
|
+
if (total <= 0 || reportedCount > total) return void 0;
|
|
1163
|
+
let remaining = reportedCount;
|
|
1164
|
+
if (remainingPercent !== void 0) {
|
|
1165
|
+
const asRemaining = reportedCount / total * 100;
|
|
1166
|
+
const asUsed = (total - reportedCount) / total * 100;
|
|
1167
|
+
const remainingDistance = Math.abs(asRemaining - remainingPercent);
|
|
1168
|
+
const usedDistance = Math.abs(asUsed - remainingPercent);
|
|
1169
|
+
if (Math.min(remainingDistance, usedDistance) > PERCENT_TOLERANCE) return void 0;
|
|
1170
|
+
if (usedDistance < remainingDistance) remaining = total - reportedCount;
|
|
1171
|
+
}
|
|
1172
|
+
return { used: total - remaining, remaining, limit: total };
|
|
1173
|
+
}
|
|
1174
|
+
function assertSuccess(payload) {
|
|
1175
|
+
const base = asObject7(payload.base_resp);
|
|
1176
|
+
if (base?.status_code !== 0) {
|
|
1177
|
+
throw new Error("MiniMax usage response did not report success.");
|
|
1178
|
+
}
|
|
1179
|
+
}
|
|
1180
|
+
function balanceMetric(id, label, value, currency, allowNegative = false) {
|
|
1181
|
+
if (typeof value !== "string" || value.length > 64 || !DECIMAL_AMOUNT2.test(value) || !allowNegative && value.startsWith("-")) {
|
|
1182
|
+
throw new Error(`MiniMax ${label.toLowerCase()} was not a valid amount.`);
|
|
1183
|
+
}
|
|
1184
|
+
return { id, label, value, unit: "currency", currency };
|
|
1185
|
+
}
|
|
1186
|
+
function asObject7(value) {
|
|
1187
|
+
if (!value || typeof value !== "object" || Array.isArray(value)) return void 0;
|
|
1188
|
+
return value;
|
|
1189
|
+
}
|
|
1190
|
+
function safeLabel(value, fallback) {
|
|
1191
|
+
if (typeof value !== "string") throw new Error("MiniMax Token Plan model name was not a string.");
|
|
1192
|
+
return sanitizeDisplayText(value, 80) || fallback;
|
|
1193
|
+
}
|
|
1194
|
+
function uniqueGroupId(label, index, groups) {
|
|
1195
|
+
const base = label.toLowerCase().replace(/[^a-z0-9]+/gu, "-").replace(/^-|-$/gu, "") || "quota";
|
|
1196
|
+
const id = groups.has(base) ? `${base}-${index + 1}` : base;
|
|
1197
|
+
groups.add(id);
|
|
1198
|
+
return id;
|
|
1199
|
+
}
|
|
1200
|
+
function nonnegativeInteger(value, field) {
|
|
1201
|
+
if (!Number.isSafeInteger(value) || value < 0) {
|
|
1202
|
+
throw new Error(`MiniMax Token Plan ${field} was not a nonnegative safe integer.`);
|
|
1203
|
+
}
|
|
1204
|
+
return value;
|
|
1205
|
+
}
|
|
1206
|
+
function optionalInteger(value, field) {
|
|
1207
|
+
if (value === void 0 || value === null) return void 0;
|
|
1208
|
+
return nonnegativeInteger(value, field);
|
|
1209
|
+
}
|
|
1210
|
+
function optionalPercent(value, field) {
|
|
1211
|
+
if (value === void 0 || value === null) return void 0;
|
|
1212
|
+
if (typeof value !== "number" || !Number.isFinite(value) || value < 0 || value > 100) {
|
|
1213
|
+
throw new Error(`MiniMax Token Plan ${field} was not a percentage.`);
|
|
1214
|
+
}
|
|
1215
|
+
return value;
|
|
1216
|
+
}
|
|
1217
|
+
function validateBoost(boost) {
|
|
1218
|
+
if (boost === void 0 || boost === null) return;
|
|
1219
|
+
const permille = nonnegativeInteger(boost, "weekly_boost_permille");
|
|
1220
|
+
if (permille > 1e4) throw new Error("MiniMax Token Plan weekly boost was unreasonable.");
|
|
1221
|
+
}
|
|
1222
|
+
function timestamp(value, field) {
|
|
1223
|
+
if (!Number.isSafeInteger(value) || value <= 0) {
|
|
1224
|
+
throw new Error(`MiniMax Token Plan ${field} was not a valid timestamp.`);
|
|
1225
|
+
}
|
|
1226
|
+
return value;
|
|
1227
|
+
}
|
|
1228
|
+
|
|
1229
|
+
// src/providers/moonshot.ts
|
|
1230
|
+
var PROVIDERS2 = {
|
|
1231
|
+
moonshotai: { name: "Moonshot AI", currency: "USD" },
|
|
1232
|
+
"moonshotai-cn": { name: "Moonshot AI CN", currency: "CNY" }
|
|
1233
|
+
};
|
|
1234
|
+
function normalizeMoonshotBalancePayload(providerId, payload, capturedAt) {
|
|
1235
|
+
if (payload.code !== 0 || payload.status !== true) {
|
|
1236
|
+
throw new Error("Moonshot AI balance response did not report success.");
|
|
1237
|
+
}
|
|
1238
|
+
const data = asObject8(payload.data);
|
|
1239
|
+
if (!data) throw new Error("Moonshot AI balance response data was not an object.");
|
|
1240
|
+
const provider = PROVIDERS2[providerId];
|
|
1241
|
+
const available = amount(data.available_balance, "available balance", false);
|
|
1242
|
+
const voucher = amount(data.voucher_balance, "voucher balance", false);
|
|
1243
|
+
const cash = amount(data.cash_balance, "cash balance", true);
|
|
1244
|
+
const metrics = [
|
|
1245
|
+
currencyMetric("available-balance", "Available balance", available, provider.currency),
|
|
1246
|
+
currencyMetric("voucher-balance", "Voucher balance", voucher, provider.currency),
|
|
1247
|
+
currencyMetric("cash-balance", "Cash balance", cash, provider.currency)
|
|
1248
|
+
];
|
|
1249
|
+
return {
|
|
1250
|
+
providerId,
|
|
1251
|
+
providerName: provider.name,
|
|
1252
|
+
capturedAt,
|
|
1253
|
+
source: "moonshot-balance",
|
|
1254
|
+
semantics: { kind: "api-key", label: "Moonshot API account balance" },
|
|
1255
|
+
buckets: [],
|
|
1256
|
+
metrics
|
|
1257
|
+
};
|
|
1258
|
+
}
|
|
1259
|
+
function currencyMetric(id, label, value, currency) {
|
|
1260
|
+
return { id, label, value, unit: "currency", currency };
|
|
1261
|
+
}
|
|
1262
|
+
function asObject8(value) {
|
|
1263
|
+
if (!value || typeof value !== "object" || Array.isArray(value)) return void 0;
|
|
1264
|
+
return value;
|
|
1265
|
+
}
|
|
1266
|
+
function amount(value, label, allowNegative) {
|
|
1267
|
+
if (typeof value !== "number" || !Number.isFinite(value) || !allowNegative && value < 0 || Math.abs(value) > Number.MAX_SAFE_INTEGER) {
|
|
1268
|
+
throw new Error(`Moonshot AI ${label} was not a valid amount.`);
|
|
1269
|
+
}
|
|
1270
|
+
return String(value);
|
|
1271
|
+
}
|
|
1272
|
+
|
|
990
1273
|
// src/providers/opencode-zen.ts
|
|
991
1274
|
var ZEN_WINDOWS = [
|
|
992
1275
|
{ key: "rolling", label: "Rolling" },
|
|
@@ -994,12 +1277,12 @@ var ZEN_WINDOWS = [
|
|
|
994
1277
|
{ key: "monthly", label: "Monthly" }
|
|
995
1278
|
];
|
|
996
1279
|
function normalizeOpenCodeZenPayload(payload, capturedAt) {
|
|
997
|
-
const usage =
|
|
1280
|
+
const usage = asObject9(payload.usage);
|
|
998
1281
|
if (!usage) throw new Error("OpenCode Zen usage response was not an object.");
|
|
999
1282
|
const buckets = [];
|
|
1000
1283
|
const notes = [];
|
|
1001
1284
|
for (const window of ZEN_WINDOWS) {
|
|
1002
|
-
const raw =
|
|
1285
|
+
const raw = asObject9(usage[window.key]);
|
|
1003
1286
|
if (!raw) continue;
|
|
1004
1287
|
const status = asString3(raw.status);
|
|
1005
1288
|
if (status !== "ok" && status !== "rate-limited") {
|
|
@@ -1036,7 +1319,7 @@ function normalizeOpenCodeZenPayload(payload, capturedAt) {
|
|
|
1036
1319
|
...notes.length > 0 ? { notes } : {}
|
|
1037
1320
|
};
|
|
1038
1321
|
}
|
|
1039
|
-
function
|
|
1322
|
+
function asObject9(value) {
|
|
1040
1323
|
if (!value || typeof value !== "object" || Array.isArray(value)) return void 0;
|
|
1041
1324
|
return value;
|
|
1042
1325
|
}
|
|
@@ -1060,7 +1343,7 @@ function clampPercent2(value) {
|
|
|
1060
1343
|
|
|
1061
1344
|
// src/providers/openrouter.ts
|
|
1062
1345
|
function normalizeOpenRouterKeyPayload(payload, capturedAt) {
|
|
1063
|
-
const data =
|
|
1346
|
+
const data = asObject10(payload.data);
|
|
1064
1347
|
if (!data) throw new Error("OpenRouter key response data was not an object.");
|
|
1065
1348
|
const limit = asNonnegativeNumber3(data.limit);
|
|
1066
1349
|
const remaining = asNonnegativeNumber3(data.limit_remaining);
|
|
@@ -1102,11 +1385,11 @@ function normalizeOpenRouterKeyPayload(payload, capturedAt) {
|
|
|
1102
1385
|
};
|
|
1103
1386
|
}
|
|
1104
1387
|
function addUsageMetric(metrics, id, label, value) {
|
|
1105
|
-
const
|
|
1106
|
-
if (
|
|
1107
|
-
metrics.push({ id, label, value:
|
|
1388
|
+
const amount2 = typeof value === "number" ? asNonnegativeNumber3(value) : void 0;
|
|
1389
|
+
if (amount2 === void 0) return;
|
|
1390
|
+
metrics.push({ id, label, value: amount2, unit: "usd" });
|
|
1108
1391
|
}
|
|
1109
|
-
function
|
|
1392
|
+
function asObject10(value) {
|
|
1110
1393
|
if (!value || typeof value !== "object" || Array.isArray(value)) return void 0;
|
|
1111
1394
|
return value;
|
|
1112
1395
|
}
|
|
@@ -1119,6 +1402,44 @@ function asNonnegativeNumber3(value) {
|
|
|
1119
1402
|
return value;
|
|
1120
1403
|
}
|
|
1121
1404
|
|
|
1405
|
+
// src/providers/vercel-ai-gateway.ts
|
|
1406
|
+
var DECIMAL_AMOUNT3 = /^(?:0|[1-9]\d*)(?:\.\d+)?$/u;
|
|
1407
|
+
function normalizeVercelAIGatewayCreditsPayload(payload, capturedAt) {
|
|
1408
|
+
const balance = decimalAmount3(payload.balance, "balance");
|
|
1409
|
+
const totalUsed = decimalAmount3(payload.total_used, "total used");
|
|
1410
|
+
const metrics = [
|
|
1411
|
+
{
|
|
1412
|
+
id: "credit-balance",
|
|
1413
|
+
label: "Credit balance",
|
|
1414
|
+
value: balance,
|
|
1415
|
+
unit: "currency",
|
|
1416
|
+
currency: "USD"
|
|
1417
|
+
},
|
|
1418
|
+
{
|
|
1419
|
+
id: "lifetime-spend",
|
|
1420
|
+
label: "Lifetime spend",
|
|
1421
|
+
value: totalUsed,
|
|
1422
|
+
unit: "currency",
|
|
1423
|
+
currency: "USD"
|
|
1424
|
+
}
|
|
1425
|
+
];
|
|
1426
|
+
return {
|
|
1427
|
+
providerId: "vercel-ai-gateway",
|
|
1428
|
+
providerName: "Vercel AI Gateway",
|
|
1429
|
+
capturedAt,
|
|
1430
|
+
source: "vercel-ai-gateway-credits",
|
|
1431
|
+
semantics: { kind: "api-key", label: "AI Gateway credits and lifetime spend" },
|
|
1432
|
+
buckets: [],
|
|
1433
|
+
metrics
|
|
1434
|
+
};
|
|
1435
|
+
}
|
|
1436
|
+
function decimalAmount3(value, label) {
|
|
1437
|
+
if (typeof value !== "string" || value.length > 64 || !DECIMAL_AMOUNT3.test(value)) {
|
|
1438
|
+
throw new Error(`Vercel AI Gateway ${label} was not a valid nonnegative amount.`);
|
|
1439
|
+
}
|
|
1440
|
+
return value;
|
|
1441
|
+
}
|
|
1442
|
+
|
|
1122
1443
|
// src/providers/xai.ts
|
|
1123
1444
|
var MAX_SAFE_CENTS = Number.MAX_SAFE_INTEGER;
|
|
1124
1445
|
function normalizeXaiBillingPayload(payload, subscriptionTier, capturedAt) {
|
|
@@ -1136,7 +1457,7 @@ function normalizeXaiBillingPayload(payload, subscriptionTier, capturedAt) {
|
|
|
1136
1457
|
config.billingPeriodStart,
|
|
1137
1458
|
config.billingPeriodEnd
|
|
1138
1459
|
);
|
|
1139
|
-
const preferredPercent =
|
|
1460
|
+
const preferredPercent = optionalPercent2(config.creditUsagePercent, "creditUsagePercent");
|
|
1140
1461
|
if (preferredPercent !== void 0) {
|
|
1141
1462
|
buckets.push({
|
|
1142
1463
|
id: "included-allowance",
|
|
@@ -1246,7 +1567,7 @@ function optionalUsd(value, field) {
|
|
|
1246
1567
|
}
|
|
1247
1568
|
return cents / 100;
|
|
1248
1569
|
}
|
|
1249
|
-
function
|
|
1570
|
+
function optionalPercent2(value, field) {
|
|
1250
1571
|
if (value === void 0 || value === null) return void 0;
|
|
1251
1572
|
if (typeof value !== "number" || !Number.isFinite(value) || value < 0 || value > 100) {
|
|
1252
1573
|
throw new Error(`xAI billing ${field} was outside 0\u2013100.`);
|
|
@@ -1284,13 +1605,13 @@ function isRecord2(value) {
|
|
|
1284
1605
|
var FIVE_HOUR_WINDOW_MINUTES2 = 300;
|
|
1285
1606
|
var WEEKLY_WINDOW_MINUTES2 = 10080;
|
|
1286
1607
|
function normalizeZaiQuotaPayload(providerId, providerName, payload, capturedAt) {
|
|
1287
|
-
const data =
|
|
1608
|
+
const data = asObject11(payload.data);
|
|
1288
1609
|
if (!data) throw new Error("Z.AI quota response data was not an object.");
|
|
1289
1610
|
const limits = Array.isArray(data.limits) ? data.limits : [];
|
|
1290
1611
|
const buckets = [];
|
|
1291
1612
|
const metrics = [];
|
|
1292
1613
|
for (const raw of limits) {
|
|
1293
|
-
const limit =
|
|
1614
|
+
const limit = asObject11(raw);
|
|
1294
1615
|
if (!limit) continue;
|
|
1295
1616
|
const type = asString5(limit.type);
|
|
1296
1617
|
const unit = asNonnegativeNumber4(limit.unit);
|
|
@@ -1362,7 +1683,7 @@ function addCountBucket(buckets, limit, id, label, windowMinutes) {
|
|
|
1362
1683
|
function addUsageDetailMetrics(metrics, value) {
|
|
1363
1684
|
if (!Array.isArray(value)) return;
|
|
1364
1685
|
for (const raw of value) {
|
|
1365
|
-
const detail =
|
|
1686
|
+
const detail = asObject11(raw);
|
|
1366
1687
|
if (!detail) continue;
|
|
1367
1688
|
const label = asString5(detail.modelCode);
|
|
1368
1689
|
const usage = asNonnegativeNumber4(detail.usage);
|
|
@@ -1370,7 +1691,7 @@ function addUsageDetailMetrics(metrics, value) {
|
|
|
1370
1691
|
metrics.push({ id: `mcp-${kebabCase(label)}`, label, value: usage, unit: "count" });
|
|
1371
1692
|
}
|
|
1372
1693
|
}
|
|
1373
|
-
function
|
|
1694
|
+
function asObject11(value) {
|
|
1374
1695
|
if (!value || typeof value !== "object" || Array.isArray(value)) return void 0;
|
|
1375
1696
|
return value;
|
|
1376
1697
|
}
|
|
@@ -1395,6 +1716,8 @@ function clampPercent3(value) {
|
|
|
1395
1716
|
}
|
|
1396
1717
|
|
|
1397
1718
|
// src/query.ts
|
|
1719
|
+
var BASETEN_BILLING_USAGE_URL = "https://api.baseten.co/v1/billing/usage_summary";
|
|
1720
|
+
var BASETEN_USAGE_WINDOW_DAYS = 30;
|
|
1398
1721
|
var CODEX_USAGE_URL = "https://chatgpt.com/backend-api/wham/usage";
|
|
1399
1722
|
var DEEPSEEK_BALANCE_URL = "https://api.deepseek.com/user/balance";
|
|
1400
1723
|
var FIREWORKS_BILLING_SUMMARY_ORIGIN = "https://api.fireworks.ai";
|
|
@@ -1402,8 +1725,18 @@ var FIREWORKS_SPEND_WINDOW_DAYS = 30;
|
|
|
1402
1725
|
var FIREWORKS_MAX_ACCOUNT_PAGES = 5;
|
|
1403
1726
|
var GITHUB_COPILOT_USAGE_URL = "https://api.github.com/copilot_internal/user";
|
|
1404
1727
|
var OPENROUTER_KEY_URL = "https://openrouter.ai/api/v1/key";
|
|
1728
|
+
var VERCEL_AI_GATEWAY_CREDITS_URL = "https://ai-gateway.vercel.sh/v1/credits";
|
|
1405
1729
|
var OPENCODE_GO_USAGE_URL = "https://opencode.ai/zen/go/v1/usage";
|
|
1406
1730
|
var KIMI_CODING_USAGE_URL = "https://api.kimi.com/coding/v1/usages";
|
|
1731
|
+
var MINIMAX_API_ROOTS = Object.freeze({
|
|
1732
|
+
minimax: "https://api.minimax.io",
|
|
1733
|
+
"minimax-cn": "https://api.minimaxi.com"
|
|
1734
|
+
});
|
|
1735
|
+
var MOONSHOT_BALANCE_URLS = Object.freeze({
|
|
1736
|
+
moonshotai: "https://api.moonshot.ai/v1/users/me/balance",
|
|
1737
|
+
"moonshotai-cn": "https://api.moonshot.cn/v1/users/me/balance"
|
|
1738
|
+
});
|
|
1739
|
+
var SHARED_MOONSHOT_ENV_VAR = "MOONSHOT_API_KEY";
|
|
1407
1740
|
var XAI_USER_URL = "https://cli-chat-proxy.grok.com/v1/user?include=subscription";
|
|
1408
1741
|
var XAI_BILLING_URL = "https://cli-chat-proxy.grok.com/v1/billing?format=credits";
|
|
1409
1742
|
var XAI_CLIENT_HEADERS = Object.freeze({
|
|
@@ -1415,6 +1748,27 @@ var MAX_SUCCESS_BODY_BYTES = 64 * 1024;
|
|
|
1415
1748
|
var MAX_ERROR_BODY_BYTES = 4 * 1024;
|
|
1416
1749
|
var AUTH_FINGERPRINT_SALT = randomBytes(32);
|
|
1417
1750
|
var SUPPORTED_ADAPTERS = [
|
|
1751
|
+
{
|
|
1752
|
+
id: "baseten",
|
|
1753
|
+
displayName: "Baseten",
|
|
1754
|
+
semantics: { kind: "api-key", label: "Organization Model APIs spend" },
|
|
1755
|
+
async query(auth, signal, timeoutMs, guard) {
|
|
1756
|
+
if (!guard) throw new Error("Baseten billing usage requires request-boundary revalidation.");
|
|
1757
|
+
const startedAt = Date.now();
|
|
1758
|
+
await guard();
|
|
1759
|
+
const windowAt = Date.now();
|
|
1760
|
+
const payload = await fetchProviderJson(
|
|
1761
|
+
basetenBillingUsageUrl(windowAt),
|
|
1762
|
+
auth,
|
|
1763
|
+
signal,
|
|
1764
|
+
remainingTimeout(timeoutMs, startedAt, "fetching Baseten billing usage"),
|
|
1765
|
+
"Baseten billing usage endpoint",
|
|
1766
|
+
{ redirect: "error" }
|
|
1767
|
+
);
|
|
1768
|
+
await guard();
|
|
1769
|
+
return normalizeBasetenBillingUsagePayload(payload, Date.now());
|
|
1770
|
+
}
|
|
1771
|
+
},
|
|
1418
1772
|
{
|
|
1419
1773
|
id: "openai-codex",
|
|
1420
1774
|
displayName: "OpenAI Codex",
|
|
@@ -1487,6 +1841,27 @@ var SUPPORTED_ADAPTERS = [
|
|
|
1487
1841
|
return normalizeOpenRouterKeyPayload(payload, Date.now());
|
|
1488
1842
|
}
|
|
1489
1843
|
},
|
|
1844
|
+
{
|
|
1845
|
+
id: "vercel-ai-gateway",
|
|
1846
|
+
displayName: "Vercel AI Gateway",
|
|
1847
|
+
semantics: { kind: "api-key", label: "AI Gateway credits and lifetime spend" },
|
|
1848
|
+
async query(auth, signal, timeoutMs, guard) {
|
|
1849
|
+
if (!guard)
|
|
1850
|
+
throw new Error("Vercel AI Gateway usage requires request-boundary revalidation.");
|
|
1851
|
+
const startedAt = Date.now();
|
|
1852
|
+
await guard();
|
|
1853
|
+
const payload = await fetchProviderJson(
|
|
1854
|
+
VERCEL_AI_GATEWAY_CREDITS_URL,
|
|
1855
|
+
auth,
|
|
1856
|
+
signal,
|
|
1857
|
+
remainingTimeout(timeoutMs, startedAt, "fetching Vercel AI Gateway credits"),
|
|
1858
|
+
"Vercel AI Gateway credits endpoint",
|
|
1859
|
+
{ redirect: "error" }
|
|
1860
|
+
);
|
|
1861
|
+
await guard();
|
|
1862
|
+
return normalizeVercelAIGatewayCreditsPayload(payload, Date.now());
|
|
1863
|
+
}
|
|
1864
|
+
},
|
|
1490
1865
|
{
|
|
1491
1866
|
id: "fireworks",
|
|
1492
1867
|
displayName: "Fireworks",
|
|
@@ -1547,6 +1922,38 @@ var SUPPORTED_ADAPTERS = [
|
|
|
1547
1922
|
return normalizeKimiCodingUsagePayload(payload, Date.now());
|
|
1548
1923
|
}
|
|
1549
1924
|
},
|
|
1925
|
+
{
|
|
1926
|
+
id: "minimax",
|
|
1927
|
+
displayName: "MiniMax",
|
|
1928
|
+
semantics: { kind: "consumer-subscription", label: "MiniMax usage" },
|
|
1929
|
+
async query(auth, signal, timeoutMs, guard) {
|
|
1930
|
+
return queryMiniMaxUsage("minimax", auth, signal, timeoutMs, guard);
|
|
1931
|
+
}
|
|
1932
|
+
},
|
|
1933
|
+
{
|
|
1934
|
+
id: "minimax-cn",
|
|
1935
|
+
displayName: "MiniMax CN",
|
|
1936
|
+
semantics: { kind: "consumer-subscription", label: "MiniMax usage" },
|
|
1937
|
+
async query(auth, signal, timeoutMs, guard) {
|
|
1938
|
+
return queryMiniMaxUsage("minimax-cn", auth, signal, timeoutMs, guard);
|
|
1939
|
+
}
|
|
1940
|
+
},
|
|
1941
|
+
{
|
|
1942
|
+
id: "moonshotai",
|
|
1943
|
+
displayName: "Moonshot AI",
|
|
1944
|
+
semantics: { kind: "api-key", label: "Moonshot API account balance" },
|
|
1945
|
+
async query(auth, signal, timeoutMs, guard) {
|
|
1946
|
+
return queryMoonshotBalance("moonshotai", auth, signal, timeoutMs, guard);
|
|
1947
|
+
}
|
|
1948
|
+
},
|
|
1949
|
+
{
|
|
1950
|
+
id: "moonshotai-cn",
|
|
1951
|
+
displayName: "Moonshot AI CN",
|
|
1952
|
+
semantics: { kind: "api-key", label: "Moonshot API account balance" },
|
|
1953
|
+
async query(auth, signal, timeoutMs, guard) {
|
|
1954
|
+
return queryMoonshotBalance("moonshotai-cn", auth, signal, timeoutMs, guard);
|
|
1955
|
+
}
|
|
1956
|
+
},
|
|
1550
1957
|
{
|
|
1551
1958
|
id: "zai",
|
|
1552
1959
|
displayName: "Z.AI",
|
|
@@ -1655,17 +2062,20 @@ async function resolveUsageAuth(ctx, adapter, salt = AUTH_FINGERPRINT_SALT, cred
|
|
|
1655
2062
|
if (!result.ok) throw new Error(redactUsageError(result.error));
|
|
1656
2063
|
return authorizationFrom(result) ? result : void 0;
|
|
1657
2064
|
};
|
|
1658
|
-
|
|
2065
|
+
const resolveSelectedAuthLast = ["deepseek", "minimax", "minimax-cn"].includes(adapter.id);
|
|
2066
|
+
if (!resolveSelectedAuthLast) modelAuth = await resolveCurrentModelAuth();
|
|
1659
2067
|
if (typeof registry.getProviderAuth !== "function") {
|
|
1660
2068
|
throw new Error("pi-usage requires Pi 0.81.0 or newer to validate resolved provider auth.");
|
|
1661
2069
|
}
|
|
2070
|
+
if (!moonshotProviderAuthIsAllowed(ctx, adapter.id)) return void 0;
|
|
1662
2071
|
const providerResult = await registry.getProviderAuth(adapter.id);
|
|
2072
|
+
if (!moonshotProviderAuthIsAllowed(ctx, adapter.id)) return void 0;
|
|
1663
2073
|
if (providerResult?.auth.baseUrl && !hasOfficialUrlOrigin(providerResult.auth.baseUrl, adapter.id)) {
|
|
1664
2074
|
throw new Error(
|
|
1665
2075
|
`${adapter.displayName} usage cannot send a proxy-resolved credential to the official usage endpoint.`
|
|
1666
2076
|
);
|
|
1667
2077
|
}
|
|
1668
|
-
if (
|
|
2078
|
+
if (resolveSelectedAuthLast) modelAuth = await resolveCurrentModelAuth();
|
|
1669
2079
|
const auth = modelAuth ?? providerResult?.auth;
|
|
1670
2080
|
if (!auth) return void 0;
|
|
1671
2081
|
if (adapter.id === "github-copilot") {
|
|
@@ -1730,11 +2140,30 @@ async function queryProviderUsage(adapter, auth, signal, timeoutMs, guard, setti
|
|
|
1730
2140
|
}
|
|
1731
2141
|
function providerIsConfigured(ctx, providerId) {
|
|
1732
2142
|
try {
|
|
1733
|
-
|
|
2143
|
+
const status = ctx.modelRegistry.getProviderAuthStatus(providerId);
|
|
2144
|
+
return status.configured && moonshotProviderAuthSourceIsAllowed(ctx, providerId, status.source, status.label);
|
|
1734
2145
|
} catch {
|
|
1735
|
-
return candidateModels(ctx, providerId).length > 0;
|
|
2146
|
+
return !isMoonshotSiblingProvider(ctx, providerId) && candidateModels(ctx, providerId).length > 0;
|
|
1736
2147
|
}
|
|
1737
2148
|
}
|
|
2149
|
+
function moonshotProviderAuthIsAllowed(ctx, providerId) {
|
|
2150
|
+
if (!isMoonshotSiblingProvider(ctx, providerId)) return true;
|
|
2151
|
+
try {
|
|
2152
|
+
const status = ctx.modelRegistry.getProviderAuthStatus(providerId);
|
|
2153
|
+
return moonshotProviderAuthSourceIsAllowed(ctx, providerId, status.source, status.label);
|
|
2154
|
+
} catch {
|
|
2155
|
+
return false;
|
|
2156
|
+
}
|
|
2157
|
+
}
|
|
2158
|
+
function moonshotProviderAuthSourceIsAllowed(ctx, providerId, source, label) {
|
|
2159
|
+
if (!isMoonshotSiblingProvider(ctx, providerId)) return true;
|
|
2160
|
+
if (source === void 0) return false;
|
|
2161
|
+
if (source !== "environment") return true;
|
|
2162
|
+
return label !== void 0 && !label.split(",").map((name) => name.trim()).includes(SHARED_MOONSHOT_ENV_VAR);
|
|
2163
|
+
}
|
|
2164
|
+
function isMoonshotSiblingProvider(ctx, providerId) {
|
|
2165
|
+
return (providerId === "moonshotai" || providerId === "moonshotai-cn") && ctx.model?.provider !== providerId;
|
|
2166
|
+
}
|
|
1738
2167
|
function candidateModels(ctx, providerId) {
|
|
1739
2168
|
const candidates = [];
|
|
1740
2169
|
const seen = /* @__PURE__ */ new Set();
|
|
@@ -1863,7 +2292,7 @@ function resolveXaiUsageAuth(auth, model, salt, candidates) {
|
|
|
1863
2292
|
const matches = [];
|
|
1864
2293
|
for (const candidate of candidates) {
|
|
1865
2294
|
try {
|
|
1866
|
-
const credential =
|
|
2295
|
+
const credential = asObject12(candidate);
|
|
1867
2296
|
if (credential?.type !== "oauth") continue;
|
|
1868
2297
|
sawOAuth = true;
|
|
1869
2298
|
if (credential.access !== resolvedAccess) continue;
|
|
@@ -1917,7 +2346,7 @@ function resolveGitHubCopilotUsageAuth(auth, model, salt, candidates, standalone
|
|
|
1917
2346
|
const matches = /* @__PURE__ */ new Map();
|
|
1918
2347
|
for (const candidate of candidates) {
|
|
1919
2348
|
try {
|
|
1920
|
-
const credential =
|
|
2349
|
+
const credential = asObject12(candidate);
|
|
1921
2350
|
if (credential?.type !== "oauth") continue;
|
|
1922
2351
|
sawOAuth = true;
|
|
1923
2352
|
const storedAccess2 = typeof credential.access === "string" && credential.access ? credential.access : void 0;
|
|
@@ -1979,7 +2408,7 @@ function bearerToken(authorization) {
|
|
|
1979
2408
|
const match = /^Bearer\s+(.+)$/iu.exec(authorization ?? "");
|
|
1980
2409
|
return match?.[1];
|
|
1981
2410
|
}
|
|
1982
|
-
function
|
|
2411
|
+
function asObject12(value) {
|
|
1983
2412
|
if (!value || typeof value !== "object" || Array.isArray(value)) return void 0;
|
|
1984
2413
|
return value;
|
|
1985
2414
|
}
|
|
@@ -1997,12 +2426,20 @@ function hasOfficialOrigin(model, providerId) {
|
|
|
1997
2426
|
function hasOfficialUrlOrigin(value, providerId) {
|
|
1998
2427
|
try {
|
|
1999
2428
|
const url = new URL(value);
|
|
2429
|
+
if (providerId === "baseten") {
|
|
2430
|
+
return ["https://inference.baseten.co", "https://api.baseten.co"].includes(url.origin);
|
|
2431
|
+
}
|
|
2000
2432
|
if (providerId === "openai-codex") return url.origin === "https://chatgpt.com";
|
|
2001
2433
|
if (providerId === "deepseek") return url.origin === "https://api.deepseek.com";
|
|
2002
2434
|
if (providerId === "fireworks") return url.origin === FIREWORKS_BILLING_SUMMARY_ORIGIN;
|
|
2003
2435
|
if (providerId === "openrouter") return url.origin === "https://openrouter.ai";
|
|
2436
|
+
if (providerId === "vercel-ai-gateway") return url.origin === "https://ai-gateway.vercel.sh";
|
|
2004
2437
|
if (providerId === "opencode-go") return url.origin === "https://opencode.ai";
|
|
2005
2438
|
if (providerId === "kimi-coding") return url.origin === "https://api.kimi.com";
|
|
2439
|
+
if (providerId === "minimax") return url.origin === "https://api.minimax.io";
|
|
2440
|
+
if (providerId === "minimax-cn") return url.origin === "https://api.minimaxi.com";
|
|
2441
|
+
if (providerId === "moonshotai") return url.origin === "https://api.moonshot.ai";
|
|
2442
|
+
if (providerId === "moonshotai-cn") return url.origin === "https://api.moonshot.cn";
|
|
2006
2443
|
if (providerId === "xai") return url.origin === "https://api.x.ai";
|
|
2007
2444
|
if (providerId === "zai") return url.origin === "https://api.z.ai";
|
|
2008
2445
|
if (providerId === "zai-coding-cn") return url.origin === "https://open.bigmodel.cn";
|
|
@@ -2029,6 +2466,49 @@ function validatedXaiUserId(value) {
|
|
|
2029
2466
|
}
|
|
2030
2467
|
return value;
|
|
2031
2468
|
}
|
|
2469
|
+
function basetenBillingUsageUrl(windowAt) {
|
|
2470
|
+
const url = new URL(BASETEN_BILLING_USAGE_URL);
|
|
2471
|
+
url.searchParams.set(
|
|
2472
|
+
"start_date",
|
|
2473
|
+
new Date(windowAt - BASETEN_USAGE_WINDOW_DAYS * 24 * 60 * 60 * 1e3).toISOString()
|
|
2474
|
+
);
|
|
2475
|
+
url.searchParams.set("end_date", new Date(windowAt).toISOString());
|
|
2476
|
+
return url.toString();
|
|
2477
|
+
}
|
|
2478
|
+
async function queryMiniMaxUsage(providerId, auth, signal, timeoutMs, guard) {
|
|
2479
|
+
if (!guard) throw new Error("MiniMax usage requires request-boundary revalidation.");
|
|
2480
|
+
const apiKey = bearerToken(headerValue(auth.headers, "Authorization")) ?? auth.apiKey;
|
|
2481
|
+
if (!apiKey) throw new Error("MiniMax runtime API key was unavailable.");
|
|
2482
|
+
const kind = miniMaxUsageKind(apiKey);
|
|
2483
|
+
const path = kind === "account-balance" ? "/account/query_balance" : "/v1/token_plan/remains";
|
|
2484
|
+
const startedAt = Date.now();
|
|
2485
|
+
await guard();
|
|
2486
|
+
const payload = await fetchProviderJson(
|
|
2487
|
+
`${MINIMAX_API_ROOTS[providerId]}${path}`,
|
|
2488
|
+
auth,
|
|
2489
|
+
signal,
|
|
2490
|
+
remainingTimeout(timeoutMs, startedAt, "fetching MiniMax usage"),
|
|
2491
|
+
"MiniMax usage endpoint",
|
|
2492
|
+
{ redirect: "error" }
|
|
2493
|
+
);
|
|
2494
|
+
await guard();
|
|
2495
|
+
return normalizeMiniMaxUsagePayload(providerId, kind, payload, Date.now());
|
|
2496
|
+
}
|
|
2497
|
+
async function queryMoonshotBalance(providerId, auth, signal, timeoutMs, guard) {
|
|
2498
|
+
if (!guard) throw new Error("Moonshot AI balance requires request-boundary revalidation.");
|
|
2499
|
+
const startedAt = Date.now();
|
|
2500
|
+
await guard();
|
|
2501
|
+
const payload = await fetchProviderJson(
|
|
2502
|
+
MOONSHOT_BALANCE_URLS[providerId],
|
|
2503
|
+
auth,
|
|
2504
|
+
signal,
|
|
2505
|
+
remainingTimeout(timeoutMs, startedAt, "fetching Moonshot AI balance"),
|
|
2506
|
+
"Moonshot AI balance endpoint",
|
|
2507
|
+
{ redirect: "error" }
|
|
2508
|
+
);
|
|
2509
|
+
await guard();
|
|
2510
|
+
return normalizeMoonshotBalancePayload(providerId, payload, Date.now());
|
|
2511
|
+
}
|
|
2032
2512
|
function remainingTimeout(timeoutMs, startedAt, description = "fetching xAI consumer usage") {
|
|
2033
2513
|
const remaining = timeoutMs - (Date.now() - startedAt);
|
|
2034
2514
|
if (remaining <= 0) throw new Error(`Timed out while ${description}.`);
|
|
@@ -2130,12 +2610,12 @@ var CODEX_RESET_CREDITS_URL = "https://chatgpt.com/backend-api/wham/rate-limit-r
|
|
|
2130
2610
|
var CODEX_RESET_CONSUME_URL = `${CODEX_RESET_CREDITS_URL}/consume`;
|
|
2131
2611
|
var MAX_RESET_OPTIONS = 32;
|
|
2132
2612
|
var MAX_CREDIT_ID_CHARS = 1024;
|
|
2133
|
-
function codexResetCount(
|
|
2134
|
-
const value =
|
|
2613
|
+
function codexResetCount(report2) {
|
|
2614
|
+
const value = report2.metrics.find((metric2) => metric2.id === "reset-credits")?.value;
|
|
2135
2615
|
return typeof value === "number" && Number.isSafeInteger(value) && value >= 0 ? value : void 0;
|
|
2136
2616
|
}
|
|
2137
|
-
function codexResetActionDescription(
|
|
2138
|
-
const count = codexResetCount(
|
|
2617
|
+
function codexResetActionDescription(report2) {
|
|
2618
|
+
const count = codexResetCount(report2);
|
|
2139
2619
|
if (count === void 0) return "Check reset availability.";
|
|
2140
2620
|
if (count === 0) return "No usage limit resets available.";
|
|
2141
2621
|
return `You have ${count} ${resetLabel(count)} available.`;
|
|
@@ -2248,14 +2728,14 @@ async function consumeCodexResetCredit(auth, option, redeemRequestId, signal, ti
|
|
|
2248
2728
|
if (!isCodexResetOutcomeCode(code)) {
|
|
2249
2729
|
throw new Error("Codex reset consume endpoint returned an unknown outcome code.");
|
|
2250
2730
|
}
|
|
2251
|
-
const windowsReset = payload.windows_reset === void 0 ? 0 :
|
|
2731
|
+
const windowsReset = payload.windows_reset === void 0 ? 0 : nonnegativeInteger2(payload.windows_reset);
|
|
2252
2732
|
if (windowsReset === void 0) {
|
|
2253
2733
|
throw new Error("Codex reset consume endpoint returned an invalid windows_reset value.");
|
|
2254
2734
|
}
|
|
2255
2735
|
return { code, windowsReset };
|
|
2256
2736
|
}
|
|
2257
2737
|
function normalizeCodexResetCreditsPayload(payload) {
|
|
2258
|
-
const availableCount =
|
|
2738
|
+
const availableCount = nonnegativeInteger2(payload.available_count);
|
|
2259
2739
|
if (availableCount === void 0) {
|
|
2260
2740
|
throw new Error("Codex reset credits response returned an invalid available_count.");
|
|
2261
2741
|
}
|
|
@@ -2263,7 +2743,7 @@ function normalizeCodexResetCreditsPayload(payload) {
|
|
|
2263
2743
|
if (rawCredits !== void 0 && !Array.isArray(rawCredits)) {
|
|
2264
2744
|
throw new Error("Codex reset credits response returned invalid credits.");
|
|
2265
2745
|
}
|
|
2266
|
-
const options = (rawCredits ?? []).map(
|
|
2746
|
+
const options = (rawCredits ?? []).map(asObject13).filter((credit) => Boolean(credit)).filter((credit) => credit.status === "available" && credit.reset_type === "codex_rate_limits").map(normalizeResetOption).sort(
|
|
2267
2747
|
(left, right) => (left.expiresAt ?? Number.MAX_SAFE_INTEGER) - (right.expiresAt ?? Number.MAX_SAFE_INTEGER)
|
|
2268
2748
|
).slice(0, Math.min(availableCount, MAX_RESET_OPTIONS));
|
|
2269
2749
|
if (availableCount > 0 && options.length === 0) {
|
|
@@ -2278,7 +2758,7 @@ function selectCodexResetCredential(candidates, resolvedAccess, resolvedAccountI
|
|
|
2278
2758
|
const matches = /* @__PURE__ */ new Map();
|
|
2279
2759
|
for (const candidate of candidates) {
|
|
2280
2760
|
try {
|
|
2281
|
-
const credential =
|
|
2761
|
+
const credential = asObject13(candidate);
|
|
2282
2762
|
if (credential?.type !== "oauth") continue;
|
|
2283
2763
|
sawOAuth = true;
|
|
2284
2764
|
const storedAccess = asNonemptyString(credential.access);
|
|
@@ -2317,7 +2797,7 @@ function codexAccountIdFromAccessToken(access) {
|
|
|
2317
2797
|
const parts = access.split(".");
|
|
2318
2798
|
if (parts.length !== 3 || !parts[1]) return void 0;
|
|
2319
2799
|
const payload = JSON.parse(Buffer.from(parts[1], "base64url").toString("utf8"));
|
|
2320
|
-
const claims =
|
|
2800
|
+
const claims = asObject13(asObject13(payload)?.["https://api.openai.com/auth"]);
|
|
2321
2801
|
return validHeaderValue(claims?.chatgpt_account_id);
|
|
2322
2802
|
} catch {
|
|
2323
2803
|
return void 0;
|
|
@@ -2349,7 +2829,7 @@ function normalizeResetOption(credit) {
|
|
|
2349
2829
|
function isCodexResetOutcomeCode(value) {
|
|
2350
2830
|
return value === "reset" || value === "nothing_to_reset" || value === "no_credit" || value === "already_redeemed";
|
|
2351
2831
|
}
|
|
2352
|
-
function
|
|
2832
|
+
function asObject13(value) {
|
|
2353
2833
|
if (!value || typeof value !== "object" || Array.isArray(value)) return void 0;
|
|
2354
2834
|
return value;
|
|
2355
2835
|
}
|
|
@@ -2371,7 +2851,7 @@ function validHeaderValue(value) {
|
|
|
2371
2851
|
if (/[^\x20-\x7e]/u.test(value)) return void 0;
|
|
2372
2852
|
return value;
|
|
2373
2853
|
}
|
|
2374
|
-
function
|
|
2854
|
+
function nonnegativeInteger2(value) {
|
|
2375
2855
|
const parsed = typeof value === "number" ? value : typeof value === "string" && value.trim() ? Number(value) : Number.NaN;
|
|
2376
2856
|
if (!Number.isSafeInteger(parsed) || parsed < 0) return void 0;
|
|
2377
2857
|
return parsed;
|
|
@@ -2388,45 +2868,59 @@ function headerValue2(headers, name) {
|
|
|
2388
2868
|
// src/format.ts
|
|
2389
2869
|
var BAR_SEGMENTS = 20;
|
|
2390
2870
|
var VALUE_COLUMN = 29;
|
|
2391
|
-
function formatUsageReport(
|
|
2871
|
+
function formatUsageReport(report2, displayState) {
|
|
2392
2872
|
const stateLabel = displayState === "current" ? "Current" : "Configured";
|
|
2393
|
-
const title =
|
|
2873
|
+
const title = report2.providerId === "baseten" ? "Baseten Model APIs Spend" : report2.providerId === "deepseek" ? "DeepSeek API Balance" : report2.providerId === "fireworks" ? "Fireworks API Spend" : report2.providerId === "vercel-ai-gateway" ? "Vercel AI Gateway Credits" : report2.providerId === "moonshotai" || report2.providerId === "moonshotai-cn" ? `${report2.providerName} Balance` : report2.providerId === "minimax" || report2.providerId === "minimax-cn" ? report2.source === "minimax-account-balance" ? `${report2.providerName} API Balance` : `${report2.providerName} Token Plan` : `${report2.providerName} Usage`;
|
|
2394
2874
|
const lines = [`${title} \xB7 ${stateLabel}`];
|
|
2395
|
-
if (
|
|
2396
|
-
lines.push(`Semantics: ${
|
|
2397
|
-
if (
|
|
2398
|
-
else if (
|
|
2399
|
-
else if (
|
|
2400
|
-
else if (
|
|
2401
|
-
else if (
|
|
2402
|
-
else if (
|
|
2403
|
-
else if (
|
|
2404
|
-
else if (
|
|
2405
|
-
else if (
|
|
2406
|
-
|
|
2407
|
-
|
|
2408
|
-
if (
|
|
2409
|
-
|
|
2875
|
+
if (report2.accountLabel) lines.push(`Account: ${report2.accountLabel}`);
|
|
2876
|
+
lines.push(`Semantics: ${report2.semantics.label}`, "");
|
|
2877
|
+
if (report2.providerId === "baseten") formatBasetenReport(lines, report2);
|
|
2878
|
+
else if (report2.providerId === "openai-codex") formatCodexReport(lines, report2);
|
|
2879
|
+
else if (report2.providerId === "deepseek") formatDeepSeekReport(lines, report2);
|
|
2880
|
+
else if (report2.providerId === "fireworks") formatFireworksReport(lines, report2);
|
|
2881
|
+
else if (report2.providerId === "vercel-ai-gateway") formatVercelAIGatewayReport(lines, report2);
|
|
2882
|
+
else if (report2.providerId === "github-copilot") formatGitHubCopilotReport(lines, report2);
|
|
2883
|
+
else if (report2.providerId === "openrouter") formatOpenRouterReport(lines, report2);
|
|
2884
|
+
else if (report2.providerId === "opencode-go") formatOpenCodeZenReport(lines, report2);
|
|
2885
|
+
else if (report2.providerId === "kimi-coding") formatKimiCodingReport(lines, report2);
|
|
2886
|
+
else if (report2.providerId === "moonshotai" || report2.providerId === "moonshotai-cn") {
|
|
2887
|
+
formatMoonshotReport(lines, report2);
|
|
2888
|
+
} else if (report2.providerId === "minimax" || report2.providerId === "minimax-cn") {
|
|
2889
|
+
formatMiniMaxReport(lines, report2);
|
|
2890
|
+
} else if (report2.providerId === "xai") formatXaiReport(lines, report2);
|
|
2891
|
+
else if (report2.providerId === "zai" || report2.providerId === "zai-coding-cn") {
|
|
2892
|
+
formatZaiReport(lines, report2);
|
|
2893
|
+
} else formatGenericReport(lines, report2);
|
|
2894
|
+
if (report2.notes) {
|
|
2895
|
+
for (const note of report2.notes) lines.push(note);
|
|
2410
2896
|
}
|
|
2411
2897
|
return lines.join("\n").trimEnd();
|
|
2412
2898
|
}
|
|
2413
|
-
function formatUsageStatusline(
|
|
2414
|
-
if (
|
|
2415
|
-
|
|
2416
|
-
|
|
2417
|
-
|
|
2418
|
-
if (
|
|
2419
|
-
if (
|
|
2420
|
-
if (
|
|
2421
|
-
|
|
2899
|
+
function formatUsageStatusline(report2, model, now = Date.now(), showCodexResetCountdown = true) {
|
|
2900
|
+
if (report2.providerId === "baseten") return formatBasetenStatusline(report2);
|
|
2901
|
+
if (report2.providerId === "openai-codex") {
|
|
2902
|
+
return formatCodexStatusline(report2, model, now, showCodexResetCountdown);
|
|
2903
|
+
}
|
|
2904
|
+
if (report2.providerId === "deepseek") return formatDeepSeekStatusline(report2);
|
|
2905
|
+
if (report2.providerId === "fireworks") return formatFireworksStatusline(report2);
|
|
2906
|
+
if (report2.providerId === "vercel-ai-gateway") return formatVercelAIGatewayStatusline(report2);
|
|
2907
|
+
if (report2.providerId === "github-copilot") return formatGitHubCopilotStatusline(report2);
|
|
2908
|
+
if (report2.providerId === "openrouter") {
|
|
2909
|
+
const limit = report2.buckets.find((bucket) => bucket.id === "key-limit");
|
|
2422
2910
|
if (limit?.remaining !== void 0) return `openrouter ${formatUsd(limit.remaining)} left`;
|
|
2423
|
-
const total =
|
|
2911
|
+
const total = report2.metrics.find((metric2) => metric2.id === "usage-total");
|
|
2424
2912
|
if (typeof total?.value === "number") return `openrouter ${formatUsd(total.value)} used`;
|
|
2425
2913
|
}
|
|
2426
|
-
if (
|
|
2427
|
-
if (
|
|
2428
|
-
if (
|
|
2429
|
-
return
|
|
2914
|
+
if (report2.providerId === "opencode-go") return formatOpenCodeZenStatusline(report2);
|
|
2915
|
+
if (report2.providerId === "kimi-coding") return formatKimiCodingStatusline(report2);
|
|
2916
|
+
if (report2.providerId === "moonshotai" || report2.providerId === "moonshotai-cn") {
|
|
2917
|
+
return formatMoonshotStatusline(report2);
|
|
2918
|
+
}
|
|
2919
|
+
if (report2.providerId === "minimax" || report2.providerId === "minimax-cn") {
|
|
2920
|
+
return formatMiniMaxStatusline(report2, model);
|
|
2921
|
+
}
|
|
2922
|
+
if (report2.providerId === "zai" || report2.providerId === "zai-coding-cn") {
|
|
2923
|
+
return formatZaiStatusline(report2);
|
|
2430
2924
|
}
|
|
2431
2925
|
return void 0;
|
|
2432
2926
|
}
|
|
@@ -2439,9 +2933,19 @@ function formatProviderStates(states) {
|
|
|
2439
2933
|
${status}: ${state.message}`;
|
|
2440
2934
|
}).join("\n\n");
|
|
2441
2935
|
}
|
|
2442
|
-
function
|
|
2936
|
+
function formatBasetenReport(lines, report2) {
|
|
2937
|
+
lines.push(`${"Spend window:".padEnd(VALUE_COLUMN)}Last 30 days`);
|
|
2938
|
+
for (const metric2 of report2.metrics) {
|
|
2939
|
+
lines.push(`${`${metric2.label}:`.padEnd(VALUE_COLUMN)}USD ${metric2.value}`);
|
|
2940
|
+
}
|
|
2941
|
+
}
|
|
2942
|
+
function formatBasetenStatusline(report2) {
|
|
2943
|
+
const subtotal = report2.metrics.find((metric2) => metric2.id === "net-subtotal");
|
|
2944
|
+
return subtotal ? `baseten USD ${subtotal.value} net` : "baseten no Model APIs usage";
|
|
2945
|
+
}
|
|
2946
|
+
function formatCodexReport(lines, report2) {
|
|
2443
2947
|
let previousGroup;
|
|
2444
|
-
for (const bucket of
|
|
2948
|
+
for (const bucket of report2.buckets) {
|
|
2445
2949
|
const group = bucket.groupId ?? bucket.id;
|
|
2446
2950
|
if (group !== previousGroup && group !== "codex") {
|
|
2447
2951
|
lines.push(`${bucket.groupLabel ?? group} limit:`);
|
|
@@ -2451,66 +2955,75 @@ function formatCodexReport(lines, report) {
|
|
|
2451
2955
|
const label = `${formatWindowLabel(bucket.windowMinutes, fallback, false)} limit:`;
|
|
2452
2956
|
lines.push(`${label.padEnd(VALUE_COLUMN)}${formatPercentBucket(bucket)}`);
|
|
2453
2957
|
}
|
|
2454
|
-
for (const
|
|
2455
|
-
if (
|
|
2456
|
-
lines.push(`${"Usage limit resets:".padEnd(VALUE_COLUMN)}${
|
|
2457
|
-
} else if (
|
|
2958
|
+
for (const metric2 of report2.metrics) {
|
|
2959
|
+
if (metric2.id === "reset-credits") {
|
|
2960
|
+
lines.push(`${"Usage limit resets:".padEnd(VALUE_COLUMN)}${metric2.value} available`);
|
|
2961
|
+
} else if (metric2.id === "credits") {
|
|
2458
2962
|
lines.push(
|
|
2459
|
-
`${"Credits:".padEnd(VALUE_COLUMN)}${formatMetricValue(
|
|
2963
|
+
`${"Credits:".padEnd(VALUE_COLUMN)}${formatMetricValue(metric2.value, metric2.unit)}`
|
|
2460
2964
|
);
|
|
2461
2965
|
}
|
|
2462
2966
|
}
|
|
2463
2967
|
}
|
|
2464
|
-
function formatDeepSeekReport(lines,
|
|
2465
|
-
const availability =
|
|
2968
|
+
function formatDeepSeekReport(lines, report2) {
|
|
2969
|
+
const availability = report2.metrics.find((metric2) => metric2.id === "api-availability");
|
|
2466
2970
|
lines.push(
|
|
2467
2971
|
`${"API calls:".padEnd(VALUE_COLUMN)}${availability?.value === "available" ? "Available" : "Unavailable"}`
|
|
2468
2972
|
);
|
|
2469
2973
|
for (const currency of ["CNY", "USD"]) {
|
|
2470
|
-
const metrics =
|
|
2974
|
+
const metrics = report2.metrics.filter((metric2) => metric2.currency === currency);
|
|
2471
2975
|
if (metrics.length === 0) continue;
|
|
2472
2976
|
lines.push("", `${currency} balance:`);
|
|
2473
|
-
for (const
|
|
2474
|
-
lines.push(`${`${
|
|
2977
|
+
for (const metric2 of metrics) {
|
|
2978
|
+
lines.push(`${`${metric2.label}:`.padEnd(VALUE_COLUMN)}${currency} ${metric2.value}`);
|
|
2475
2979
|
}
|
|
2476
2980
|
}
|
|
2477
2981
|
}
|
|
2478
|
-
function formatDeepSeekStatusline(
|
|
2479
|
-
const availability =
|
|
2982
|
+
function formatDeepSeekStatusline(report2) {
|
|
2983
|
+
const availability = report2.metrics.find((metric2) => metric2.id === "api-availability");
|
|
2480
2984
|
if (availability?.value !== "available") return "deepseek API unavailable";
|
|
2481
2985
|
const totals = ["CNY", "USD"].flatMap((currency) => {
|
|
2482
|
-
const
|
|
2986
|
+
const metric2 = report2.metrics.find(
|
|
2483
2987
|
(candidate) => candidate.id === `${currency.toLowerCase()}-total`
|
|
2484
2988
|
);
|
|
2485
|
-
return
|
|
2989
|
+
return metric2 ? [`${currency} ${metric2.value}`] : [];
|
|
2486
2990
|
});
|
|
2487
2991
|
return totals.length > 0 ? `deepseek ${totals.join(" \xB7 ")}` : "deepseek balance unavailable";
|
|
2488
2992
|
}
|
|
2489
|
-
function formatFireworksReport(lines,
|
|
2993
|
+
function formatFireworksReport(lines, report2) {
|
|
2490
2994
|
lines.push(`${"Spend window:".padEnd(VALUE_COLUMN)}Last 30 days (rated)`);
|
|
2491
|
-
for (const currency of fireworksCurrencies(
|
|
2995
|
+
for (const currency of fireworksCurrencies(report2)) {
|
|
2492
2996
|
lines.push("", `${currency} rated spend:`);
|
|
2493
|
-
for (const
|
|
2494
|
-
if (
|
|
2495
|
-
lines.push(`${`${
|
|
2997
|
+
for (const metric2 of report2.metrics) {
|
|
2998
|
+
if (metric2.currency !== currency) continue;
|
|
2999
|
+
lines.push(`${`${metric2.label}:`.padEnd(VALUE_COLUMN)}${currency} ${metric2.value}`);
|
|
2496
3000
|
}
|
|
2497
3001
|
}
|
|
2498
3002
|
}
|
|
2499
|
-
function formatFireworksStatusline(
|
|
2500
|
-
const totals =
|
|
3003
|
+
function formatFireworksStatusline(report2) {
|
|
3004
|
+
const totals = report2.metrics.filter((metric2) => metric2.id.endsWith("-total"));
|
|
2501
3005
|
if (totals.length === 0) return "fireworks no rated usage";
|
|
2502
|
-
return `fireworks ${totals.map((
|
|
3006
|
+
return `fireworks ${totals.map((metric2) => `${metric2.currency} ${metric2.value}`).join(" \xB7 ")}`;
|
|
2503
3007
|
}
|
|
2504
|
-
function fireworksCurrencies(
|
|
3008
|
+
function fireworksCurrencies(report2) {
|
|
2505
3009
|
const currencies = [];
|
|
2506
|
-
for (const
|
|
2507
|
-
if (!
|
|
2508
|
-
currencies.push(
|
|
3010
|
+
for (const metric2 of report2.metrics) {
|
|
3011
|
+
if (!metric2.currency || currencies.includes(metric2.currency)) continue;
|
|
3012
|
+
currencies.push(metric2.currency);
|
|
2509
3013
|
}
|
|
2510
3014
|
return currencies;
|
|
2511
3015
|
}
|
|
2512
|
-
function
|
|
2513
|
-
const
|
|
3016
|
+
function formatVercelAIGatewayReport(lines, report2) {
|
|
3017
|
+
for (const metric2 of report2.metrics) {
|
|
3018
|
+
lines.push(`${`${metric2.label}:`.padEnd(VALUE_COLUMN)}USD ${metric2.value}`);
|
|
3019
|
+
}
|
|
3020
|
+
}
|
|
3021
|
+
function formatVercelAIGatewayStatusline(report2) {
|
|
3022
|
+
const balance = report2.metrics.find((metric2) => metric2.id === "credit-balance");
|
|
3023
|
+
return balance ? `vercel USD ${balance.value} left` : "vercel credits unavailable";
|
|
3024
|
+
}
|
|
3025
|
+
function formatGitHubCopilotReport(lines, report2) {
|
|
3026
|
+
const quota = findGitHubCopilotQuota(report2);
|
|
2514
3027
|
if (!quota || quota.limit === void 0 || quota.remaining === void 0) {
|
|
2515
3028
|
lines.push(`${`${quota?.label ?? "Copilot quota"}:`.padEnd(VALUE_COLUMN)}unlimited`);
|
|
2516
3029
|
return;
|
|
@@ -2520,23 +3033,23 @@ function formatGitHubCopilotReport(lines, report) {
|
|
|
2520
3033
|
lines.push(
|
|
2521
3034
|
`${`${quota.label}:`.padEnd(VALUE_COLUMN)}${quota.remaining} of ${quota.limit} left \xB7 ${percent}%${reset}`
|
|
2522
3035
|
);
|
|
2523
|
-
const overage =
|
|
3036
|
+
const overage = report2.metrics.find((metric2) => metric2.id === "overage-used");
|
|
2524
3037
|
if (typeof overage?.value === "number" && overage.value > 0) {
|
|
2525
3038
|
lines.push(`${"Additional usage:".padEnd(VALUE_COLUMN)}${overage.value} ${quota.label}`);
|
|
2526
3039
|
}
|
|
2527
3040
|
}
|
|
2528
|
-
function formatGitHubCopilotStatusline(
|
|
2529
|
-
const quota = findGitHubCopilotQuota(
|
|
3041
|
+
function formatGitHubCopilotStatusline(report2) {
|
|
3042
|
+
const quota = findGitHubCopilotQuota(report2);
|
|
2530
3043
|
const kind = compactGitHubCopilotQuotaKind(quota);
|
|
2531
3044
|
if (!quota || quota.limit === void 0 || quota.remaining === void 0) {
|
|
2532
3045
|
return `copilot ${kind} unlimited`;
|
|
2533
3046
|
}
|
|
2534
|
-
const overage =
|
|
3047
|
+
const overage = report2.metrics.find((metric2) => metric2.id === "overage-used");
|
|
2535
3048
|
const overageSuffix = typeof overage?.value === "number" && overage.value > 0 ? ` +${overage.value} over` : "";
|
|
2536
3049
|
return `copilot ${kind === "premium" ? "" : `${kind} `}${quota.remaining}/${quota.limit} ${percentRemaining(quota)}%${overageSuffix}`;
|
|
2537
3050
|
}
|
|
2538
|
-
function findGitHubCopilotQuota(
|
|
2539
|
-
return
|
|
3051
|
+
function findGitHubCopilotQuota(report2) {
|
|
3052
|
+
return report2.buckets.find(
|
|
2540
3053
|
(bucket) => ["ai-credits", "premium-requests", "chat-requests"].includes(bucket.id)
|
|
2541
3054
|
);
|
|
2542
3055
|
}
|
|
@@ -2549,37 +3062,37 @@ function percentRemaining(bucket) {
|
|
|
2549
3062
|
if (!bucket.limit || bucket.remaining === void 0) return 0;
|
|
2550
3063
|
return Math.round(clampPercent4(bucket.remaining / bucket.limit * 100));
|
|
2551
3064
|
}
|
|
2552
|
-
function formatOpenRouterReport(lines,
|
|
2553
|
-
const limit =
|
|
3065
|
+
function formatOpenRouterReport(lines, report2) {
|
|
3066
|
+
const limit = report2.buckets.find((bucket) => bucket.id === "key-limit");
|
|
2554
3067
|
if (limit) {
|
|
2555
3068
|
const period = limit.period ? ` (${limit.period})` : "";
|
|
2556
3069
|
const value = limit.remaining === void 0 ? `${formatUsd(limit.limit ?? 0)} cap; remaining unavailable` : `${formatUsd(limit.remaining)} of ${formatUsd(limit.limit ?? 0)} left`;
|
|
2557
3070
|
lines.push(`${`Key limit${period}:`.padEnd(VALUE_COLUMN)}${value}`);
|
|
2558
3071
|
}
|
|
2559
|
-
for (const
|
|
3072
|
+
for (const metric2 of report2.metrics) {
|
|
2560
3073
|
lines.push(
|
|
2561
|
-
`${`${
|
|
3074
|
+
`${`${metric2.label}:`.padEnd(VALUE_COLUMN)}${formatMetricValue(metric2.value, metric2.unit)}`
|
|
2562
3075
|
);
|
|
2563
3076
|
}
|
|
2564
3077
|
}
|
|
2565
|
-
function formatOpenCodeZenReport(lines,
|
|
2566
|
-
for (const bucket of
|
|
3078
|
+
function formatOpenCodeZenReport(lines, report2) {
|
|
3079
|
+
for (const bucket of report2.buckets) {
|
|
2567
3080
|
const reset = bucket.resetsAt ? ` (resets ${formatReset(bucket.resetsAt)})` : "";
|
|
2568
3081
|
const used = bucket.used ?? "unavailable";
|
|
2569
3082
|
lines.push(`${`${bucket.label}:`.padEnd(VALUE_COLUMN)}${used}% used${reset}`);
|
|
2570
3083
|
}
|
|
2571
3084
|
}
|
|
2572
|
-
function formatOpenCodeZenStatusline(
|
|
3085
|
+
function formatOpenCodeZenStatusline(report2) {
|
|
2573
3086
|
const parts = ["zen"];
|
|
2574
|
-
for (const bucket of
|
|
3087
|
+
for (const bucket of report2.buckets) {
|
|
2575
3088
|
if (bucket.used === void 0) continue;
|
|
2576
3089
|
const compact = bucket.id === "rolling" ? "r" : bucket.id === "weekly" ? "w" : "m";
|
|
2577
3090
|
parts.push(`${clampPercent4(bucket.used).toFixed(0)}% ${compact}`);
|
|
2578
3091
|
}
|
|
2579
3092
|
return parts.length > 1 ? parts.join(" ") : void 0;
|
|
2580
3093
|
}
|
|
2581
|
-
function formatKimiCodingReport(lines,
|
|
2582
|
-
for (const bucket of
|
|
3094
|
+
function formatKimiCodingReport(lines, report2) {
|
|
3095
|
+
for (const bucket of report2.buckets) {
|
|
2583
3096
|
const reset = bucket.resetsAt ? ` (resets ${formatReset(bucket.resetsAt)})` : "";
|
|
2584
3097
|
if (bucket.used === void 0 || bucket.limit === void 0) {
|
|
2585
3098
|
lines.push(`${`${bucket.label}:`.padEnd(VALUE_COLUMN)}unavailable${reset}`);
|
|
@@ -2589,10 +3102,10 @@ function formatKimiCodingReport(lines, report) {
|
|
|
2589
3102
|
`${`${bucket.label}:`.padEnd(VALUE_COLUMN)}${bucket.used} of ${bucket.limit} used \xB7 ${percentRemaining(bucket)}% left${reset}`
|
|
2590
3103
|
);
|
|
2591
3104
|
}
|
|
2592
|
-
const balance =
|
|
2593
|
-
const total =
|
|
2594
|
-
const monthlyUsed =
|
|
2595
|
-
const monthlyLimit =
|
|
3105
|
+
const balance = report2.metrics.find((metric2) => metric2.id === "booster-balance");
|
|
3106
|
+
const total = report2.metrics.find((metric2) => metric2.id === "booster-total");
|
|
3107
|
+
const monthlyUsed = report2.metrics.find((metric2) => metric2.id === "booster-monthly-used");
|
|
3108
|
+
const monthlyLimit = report2.metrics.find((metric2) => metric2.id === "booster-monthly-limit");
|
|
2596
3109
|
if (!balance && !monthlyUsed && !monthlyLimit) return;
|
|
2597
3110
|
lines.push("", "Extra usage wallet:");
|
|
2598
3111
|
if (balance) {
|
|
@@ -2606,10 +3119,10 @@ function formatKimiCodingReport(lines, report) {
|
|
|
2606
3119
|
lines.push(`${"Monthly limit:".padEnd(VALUE_COLUMN)}${formatCurrencyMetric(monthlyLimit)}`);
|
|
2607
3120
|
}
|
|
2608
3121
|
}
|
|
2609
|
-
function formatKimiCodingStatusline(
|
|
2610
|
-
const fiveHour =
|
|
2611
|
-
const weekly =
|
|
2612
|
-
const subWindow = fiveHour ??
|
|
3122
|
+
function formatKimiCodingStatusline(report2) {
|
|
3123
|
+
const fiveHour = report2.buckets.find((bucket) => bucket.id === "five-hour");
|
|
3124
|
+
const weekly = report2.buckets.find((bucket) => bucket.id === "weekly");
|
|
3125
|
+
const subWindow = fiveHour ?? report2.buckets.find((bucket) => bucket.id !== "weekly");
|
|
2613
3126
|
const selected = [subWindow, weekly].filter(
|
|
2614
3127
|
(bucket, index, buckets) => bucket !== void 0 && buckets.indexOf(bucket) === index
|
|
2615
3128
|
);
|
|
@@ -2623,10 +3136,98 @@ function formatKimiCodingStatusline(report) {
|
|
|
2623
3136
|
}
|
|
2624
3137
|
return parts.length > 1 ? parts.join(" ") : void 0;
|
|
2625
3138
|
}
|
|
2626
|
-
function
|
|
3139
|
+
function formatMoonshotReport(lines, report2) {
|
|
3140
|
+
for (const metric2 of report2.metrics) {
|
|
3141
|
+
lines.push(`${`${metric2.label}:`.padEnd(VALUE_COLUMN)}${metric2.currency} ${metric2.value}`);
|
|
3142
|
+
}
|
|
3143
|
+
}
|
|
3144
|
+
function formatMoonshotStatusline(report2) {
|
|
3145
|
+
const available = report2.metrics.find((metric2) => metric2.id === "available-balance");
|
|
3146
|
+
if (!available) return "moonshot balance unavailable";
|
|
3147
|
+
return `moonshot ${available.currency ?? ""} ${available.value}`.replace(/\s+/gu, " ");
|
|
3148
|
+
}
|
|
3149
|
+
function formatMiniMaxReport(lines, report2) {
|
|
3150
|
+
if (report2.source === "minimax-account-balance") {
|
|
3151
|
+
for (const metric2 of report2.metrics) {
|
|
3152
|
+
lines.push(`${`${metric2.label}:`.padEnd(VALUE_COLUMN)}${metric2.currency} ${metric2.value}`);
|
|
3153
|
+
}
|
|
3154
|
+
return;
|
|
3155
|
+
}
|
|
3156
|
+
let previousGroup;
|
|
3157
|
+
for (const bucket of report2.buckets) {
|
|
3158
|
+
if (bucket.groupId !== previousGroup) lines.push(`${bucket.groupLabel ?? "Token Plan"}:`);
|
|
3159
|
+
previousGroup = bucket.groupId;
|
|
3160
|
+
const reset = bucket.resetsAt ? ` (resets ${formatReset(bucket.resetsAt)})` : "";
|
|
3161
|
+
const value = bucket.period === "unlimited" ? "unlimited" : bucket.limit && bucket.remaining !== void 0 ? `${bucket.remaining} of ${bucket.limit} left \xB7 ${percentRemaining(bucket)}%${reset}` : "unavailable";
|
|
3162
|
+
lines.push(`${`${bucket.label}:`.padEnd(VALUE_COLUMN)}${value}`);
|
|
3163
|
+
}
|
|
3164
|
+
}
|
|
3165
|
+
function formatMiniMaxStatusline(report2, model) {
|
|
3166
|
+
const prefix = report2.providerId === "minimax-cn" ? "minimax cn" : "minimax";
|
|
3167
|
+
if (report2.source === "minimax-account-balance") {
|
|
3168
|
+
const available = report2.metrics.find((metric2) => metric2.id === "available-balance");
|
|
3169
|
+
return available ? `${prefix} ${available.currency} ${available.value}` : void 0;
|
|
3170
|
+
}
|
|
3171
|
+
const selectedGroup = selectMiniMaxGroup(report2, model);
|
|
3172
|
+
if (!selectedGroup) return void 0;
|
|
3173
|
+
const selected = report2.buckets.filter((bucket) => bucket.groupId === selectedGroup);
|
|
3174
|
+
const parts = [prefix];
|
|
3175
|
+
for (const bucket of selected) {
|
|
3176
|
+
const fallback = bucket.id.endsWith(":weekly") ? "weekly" : "5h";
|
|
3177
|
+
const window = formatWindowLabel(bucket.windowMinutes, fallback, true);
|
|
3178
|
+
if (bucket.period === "unlimited") {
|
|
3179
|
+
parts.push(`unlimited ${window}`);
|
|
3180
|
+
continue;
|
|
3181
|
+
}
|
|
3182
|
+
if (!bucket.limit || bucket.remaining === void 0) continue;
|
|
3183
|
+
parts.push(`${percentRemaining(bucket)}% ${window}`);
|
|
3184
|
+
}
|
|
3185
|
+
return parts.length > 1 ? parts.join(" ") : void 0;
|
|
3186
|
+
}
|
|
3187
|
+
function selectMiniMaxGroup(report2, model) {
|
|
3188
|
+
const groups = [
|
|
3189
|
+
...new Set(
|
|
3190
|
+
report2.buckets.map((bucket) => bucket.groupId).filter((group) => group !== void 0)
|
|
3191
|
+
)
|
|
3192
|
+
];
|
|
3193
|
+
if (groups.length <= 1) return groups[0];
|
|
3194
|
+
if (model?.provider !== report2.providerId) return void 0;
|
|
3195
|
+
const modelKeys = [model.id, model.name].map(normalizeMiniMaxModelKey).filter((key) => key !== void 0);
|
|
3196
|
+
const candidates = groups.map((group) => {
|
|
3197
|
+
const bucket = report2.buckets.find((candidate) => candidate.groupId === group);
|
|
3198
|
+
const patterns = [bucket?.groupLabel, ...bucket?.modelKeys ?? [], group].map(normalizeMiniMaxModelKey).filter((key) => key !== void 0);
|
|
3199
|
+
return { group, patterns };
|
|
3200
|
+
});
|
|
3201
|
+
const exact = candidates.find(
|
|
3202
|
+
({ patterns }) => patterns.some((pattern) => !pattern.includes("*") && modelKeys.includes(pattern))
|
|
3203
|
+
);
|
|
3204
|
+
if (exact) return exact.group;
|
|
3205
|
+
return candidates.find(
|
|
3206
|
+
({ patterns }) => patterns.some(
|
|
3207
|
+
(pattern) => pattern.includes("*") && modelKeys.some((key) => wildcardKeyMatches(pattern, key))
|
|
3208
|
+
)
|
|
3209
|
+
)?.group;
|
|
3210
|
+
}
|
|
3211
|
+
function normalizeMiniMaxModelKey(value) {
|
|
3212
|
+
const key = value?.toLowerCase().replace(/[^a-z0-9*]+/gu, "");
|
|
3213
|
+
return key && /[a-z0-9]/u.test(key) ? key : void 0;
|
|
3214
|
+
}
|
|
3215
|
+
function wildcardKeyMatches(pattern, value) {
|
|
3216
|
+
if (!pattern.includes("*")) return pattern === value;
|
|
3217
|
+
const segments = pattern.split("*").filter(Boolean);
|
|
3218
|
+
let offset = 0;
|
|
3219
|
+
for (const [index, segment] of segments.entries()) {
|
|
3220
|
+
const found = value.indexOf(segment, offset);
|
|
3221
|
+
if (found < 0 || index === 0 && !pattern.startsWith("*") && found !== 0) return false;
|
|
3222
|
+
offset = found + segment.length;
|
|
3223
|
+
}
|
|
3224
|
+
const last = segments.at(-1);
|
|
3225
|
+
return pattern.endsWith("*") || last !== void 0 && value.endsWith(last);
|
|
3226
|
+
}
|
|
3227
|
+
function formatZaiStatusline(report2) {
|
|
2627
3228
|
const selected = [
|
|
2628
|
-
|
|
2629
|
-
|
|
3229
|
+
report2.buckets.find((bucket) => bucket.id === "five-hour"),
|
|
3230
|
+
report2.buckets.find((bucket) => bucket.id === "weekly")
|
|
2630
3231
|
];
|
|
2631
3232
|
const parts = ["zai"];
|
|
2632
3233
|
for (const bucket of selected) {
|
|
@@ -2638,15 +3239,15 @@ function formatZaiStatusline(report) {
|
|
|
2638
3239
|
}
|
|
2639
3240
|
return parts.length > 1 ? parts.join(" ") : void 0;
|
|
2640
3241
|
}
|
|
2641
|
-
function formatCurrencyMetric(
|
|
2642
|
-
if (typeof
|
|
2643
|
-
if (!
|
|
2644
|
-
if (
|
|
2645
|
-
if (
|
|
2646
|
-
return `${
|
|
3242
|
+
function formatCurrencyMetric(metric2) {
|
|
3243
|
+
if (typeof metric2.value !== "number") return String(metric2.value);
|
|
3244
|
+
if (!metric2.currency) return "unavailable";
|
|
3245
|
+
if (metric2.currency === "USD") return `$${metric2.value.toFixed(2)}`;
|
|
3246
|
+
if (metric2.currency === "CNY") return `\xA5${metric2.value.toFixed(2)}`;
|
|
3247
|
+
return `${metric2.value.toFixed(2)} ${metric2.currency}`;
|
|
2647
3248
|
}
|
|
2648
|
-
function formatXaiReport(lines,
|
|
2649
|
-
const included =
|
|
3249
|
+
function formatXaiReport(lines, report2) {
|
|
3250
|
+
const included = report2.buckets.find((bucket) => bucket.id === "included-allowance");
|
|
2650
3251
|
if (included) {
|
|
2651
3252
|
let value = "unavailable";
|
|
2652
3253
|
if (included.unit === "percent" && included.used !== void 0) {
|
|
@@ -2662,20 +3263,20 @@ function formatXaiReport(lines, report) {
|
|
|
2662
3263
|
const reset = included.resetsAt ? ` (resets ${formatReset(included.resetsAt)})` : "";
|
|
2663
3264
|
lines.push(`${"Included allowance:".padEnd(VALUE_COLUMN)}${value}${period}${reset}`);
|
|
2664
3265
|
}
|
|
2665
|
-
const onDemand =
|
|
3266
|
+
const onDemand = report2.buckets.find((bucket) => bucket.id === "on-demand");
|
|
2666
3267
|
if (onDemand) {
|
|
2667
3268
|
let value = onDemand.used === void 0 ? "usage unavailable" : `${formatUsd(onDemand.used)} used`;
|
|
2668
3269
|
if (onDemand.limit !== void 0) value += ` of ${formatUsd(onDemand.limit)} cap`;
|
|
2669
3270
|
lines.push(`${"On-demand usage:".padEnd(VALUE_COLUMN)}${value}`);
|
|
2670
3271
|
}
|
|
2671
|
-
for (const
|
|
3272
|
+
for (const metric2 of report2.metrics) {
|
|
2672
3273
|
lines.push(
|
|
2673
|
-
`${`${
|
|
3274
|
+
`${`${metric2.label}:`.padEnd(VALUE_COLUMN)}${formatMetricValue(metric2.value, metric2.unit)}`
|
|
2674
3275
|
);
|
|
2675
3276
|
}
|
|
2676
3277
|
}
|
|
2677
|
-
function formatZaiReport(lines,
|
|
2678
|
-
for (const bucket of
|
|
3278
|
+
function formatZaiReport(lines, report2) {
|
|
3279
|
+
for (const bucket of report2.buckets) {
|
|
2679
3280
|
const reset = bucket.resetsAt ? ` (resets ${formatReset(bucket.resetsAt)})` : "";
|
|
2680
3281
|
let value = "unavailable";
|
|
2681
3282
|
if (bucket.unit === "percent" && bucket.used !== void 0) {
|
|
@@ -2691,28 +3292,28 @@ function formatZaiReport(lines, report) {
|
|
|
2691
3292
|
}
|
|
2692
3293
|
lines.push(`${`${bucket.label}:`.padEnd(VALUE_COLUMN)}${value}${reset}`);
|
|
2693
3294
|
}
|
|
2694
|
-
for (const
|
|
3295
|
+
for (const metric2 of report2.metrics) {
|
|
2695
3296
|
lines.push(
|
|
2696
|
-
`${`${
|
|
3297
|
+
`${`${metric2.label}:`.padEnd(VALUE_COLUMN)}${formatMetricValue(metric2.value, metric2.unit)}`
|
|
2697
3298
|
);
|
|
2698
3299
|
}
|
|
2699
3300
|
}
|
|
2700
|
-
function formatGenericReport(lines,
|
|
2701
|
-
for (const bucket of
|
|
3301
|
+
function formatGenericReport(lines, report2) {
|
|
3302
|
+
for (const bucket of report2.buckets) {
|
|
2702
3303
|
lines.push(
|
|
2703
3304
|
`${`${bucket.label}:`.padEnd(VALUE_COLUMN)}${formatMetricValue(bucket.remaining ?? bucket.used ?? "unavailable", bucket.unit)}`
|
|
2704
3305
|
);
|
|
2705
3306
|
}
|
|
2706
|
-
for (const
|
|
3307
|
+
for (const metric2 of report2.metrics) {
|
|
2707
3308
|
lines.push(
|
|
2708
|
-
`${`${
|
|
3309
|
+
`${`${metric2.label}:`.padEnd(VALUE_COLUMN)}${formatMetricValue(metric2.value, metric2.unit)}`
|
|
2709
3310
|
);
|
|
2710
3311
|
}
|
|
2711
3312
|
}
|
|
2712
|
-
function formatCodexStatusline(
|
|
2713
|
-
const group = selectCodexGroup(
|
|
2714
|
-
if (!group) return formatCodexCreditsStatus(
|
|
2715
|
-
const buckets =
|
|
3313
|
+
function formatCodexStatusline(report2, model, now = Date.now(), showResetCountdown = true) {
|
|
3314
|
+
const group = selectCodexGroup(report2, model);
|
|
3315
|
+
if (!group) return formatCodexCreditsStatus(report2);
|
|
3316
|
+
const buckets = report2.buckets.filter((bucket) => (bucket.groupId ?? bucket.id) === group);
|
|
2716
3317
|
const labelBucket = buckets[0];
|
|
2717
3318
|
const parts = [
|
|
2718
3319
|
group === "codex" ? "codex" : `codex ${compactLimitLabel(labelBucket?.groupLabel ?? group)}`
|
|
@@ -2729,24 +3330,24 @@ function formatCodexStatusline(report, model, now = Date.now(), showResetCountdo
|
|
|
2729
3330
|
const reset = formatResetCountdown(bucket.resetsAt, now);
|
|
2730
3331
|
parts.push(`${percent} ${reset ? `\u21BB ${reset}` : window}`);
|
|
2731
3332
|
}
|
|
2732
|
-
return parts.length > 1 ? parts.join(" ") : formatCodexCreditsStatus(
|
|
3333
|
+
return parts.length > 1 ? parts.join(" ") : formatCodexCreditsStatus(report2);
|
|
2733
3334
|
}
|
|
2734
|
-
function formatCodexCreditsStatus(
|
|
2735
|
-
const credits =
|
|
3335
|
+
function formatCodexCreditsStatus(report2) {
|
|
3336
|
+
const credits = report2.metrics.find((metric2) => metric2.id === "credits");
|
|
2736
3337
|
if (!credits) return "codex usage unavailable";
|
|
2737
3338
|
if (credits.value === "none") return "codex no credits";
|
|
2738
3339
|
if (credits.value === "available") return "codex credits available";
|
|
2739
3340
|
if (credits.value === "unlimited") return "codex credits unlimited";
|
|
2740
3341
|
return `codex ${formatMetricValue(credits.value, "count")} credits`;
|
|
2741
3342
|
}
|
|
2742
|
-
function selectCodexGroup(
|
|
2743
|
-
const groups = [...new Set(
|
|
3343
|
+
function selectCodexGroup(report2, model) {
|
|
3344
|
+
const groups = [...new Set(report2.buckets.map((bucket) => bucket.groupId ?? bucket.id))];
|
|
2744
3345
|
if (model?.provider !== "openai-codex") {
|
|
2745
3346
|
return groups.includes("codex") ? "codex" : groups[0];
|
|
2746
3347
|
}
|
|
2747
3348
|
const modelKeys = normalizedModelKeys(model);
|
|
2748
3349
|
for (const group of groups) {
|
|
2749
|
-
const bucket =
|
|
3350
|
+
const bucket = report2.buckets.find(
|
|
2750
3351
|
(candidate) => (candidate.groupId ?? candidate.id) === group
|
|
2751
3352
|
);
|
|
2752
3353
|
const keys = [group, bucket?.groupLabel, ...bucket?.modelKeys ?? []].map(normalizeKey).filter((key) => key !== void 0);
|
|
@@ -3492,9 +4093,7 @@ function usageExtension(pi, dependencies = {}) {
|
|
|
3492
4093
|
const generation = statusGeneration;
|
|
3493
4094
|
statusCountdownTimer = setTimeout(() => {
|
|
3494
4095
|
statusCountdownTimer = void 0;
|
|
3495
|
-
if (!sessionActive || generation !== statusGeneration
|
|
3496
|
-
return;
|
|
3497
|
-
}
|
|
4096
|
+
if (!sessionActive || generation !== statusGeneration) return;
|
|
3498
4097
|
publishStatus(ctx, outcome, model, false);
|
|
3499
4098
|
}, STATUS_COUNTDOWN_REFRESH_MS);
|
|
3500
4099
|
statusCountdownTimer.unref?.();
|
|
@@ -3549,7 +4148,17 @@ function usageExtension(pi, dependencies = {}) {
|
|
|
3549
4148
|
}
|
|
3550
4149
|
};
|
|
3551
4150
|
}
|
|
3552
|
-
const requiresRequestBoundaryGuard = [
|
|
4151
|
+
const requiresRequestBoundaryGuard = [
|
|
4152
|
+
"baseten",
|
|
4153
|
+
"deepseek",
|
|
4154
|
+
"fireworks",
|
|
4155
|
+
"minimax",
|
|
4156
|
+
"minimax-cn",
|
|
4157
|
+
"moonshotai",
|
|
4158
|
+
"moonshotai-cn",
|
|
4159
|
+
"vercel-ai-gateway",
|
|
4160
|
+
"xai"
|
|
4161
|
+
].includes(adapter.id);
|
|
3553
4162
|
const requestContextChanged = () => expectedSessionGeneration !== sessionGeneration || ctx.sessionManager.getSessionId() !== expectedSessionId || modelIdentity(ctx.model) !== expectedModelIdentity || adapter.id === "fireworks" && settingsRuntime.get().settings.fireworksAccountId !== expectedFireworksAccountId;
|
|
3554
4163
|
if (requiresRequestBoundaryGuard && requestContextChanged()) throw abortError();
|
|
3555
4164
|
if (!auth) {
|
|
@@ -3602,7 +4211,7 @@ function usageExtension(pi, dependencies = {}) {
|
|
|
3602
4211
|
querySequence += 1;
|
|
3603
4212
|
const queryId = querySequence;
|
|
3604
4213
|
setBoundedMap(latestQueries, failureKey, queryId, MAX_ACCOUNT_STATES);
|
|
3605
|
-
let
|
|
4214
|
+
let retryableAuthChanged = false;
|
|
3606
4215
|
try {
|
|
3607
4216
|
const remainingMs = Math.max(1, deadlineAt - Date.now());
|
|
3608
4217
|
const guard = requiresRequestBoundaryGuard ? async () => {
|
|
@@ -3615,14 +4224,16 @@ function usageExtension(pi, dependencies = {}) {
|
|
|
3615
4224
|
);
|
|
3616
4225
|
if (signal.aborted || requestContextChanged()) throw abortError();
|
|
3617
4226
|
if (revalidated?.fingerprint !== auth.fingerprint) {
|
|
3618
|
-
if (
|
|
3619
|
-
|
|
3620
|
-
throw new Error(
|
|
4227
|
+
if (["deepseek", "minimax", "minimax-cn"].includes(adapter.id)) {
|
|
4228
|
+
retryableAuthChanged = true;
|
|
4229
|
+
throw new Error(
|
|
4230
|
+
`${adapter.displayName} runtime credential changed during the usage query.`
|
|
4231
|
+
);
|
|
3621
4232
|
}
|
|
3622
4233
|
throw abortError();
|
|
3623
4234
|
}
|
|
3624
4235
|
} : void 0;
|
|
3625
|
-
const
|
|
4236
|
+
const report2 = await queryProviderUsage(
|
|
3626
4237
|
adapter,
|
|
3627
4238
|
auth,
|
|
3628
4239
|
signal,
|
|
@@ -3632,7 +4243,7 @@ function usageExtension(pi, dependencies = {}) {
|
|
|
3632
4243
|
);
|
|
3633
4244
|
if (guard) await guard();
|
|
3634
4245
|
if (latestQueries.get(failureKey) === queryId) {
|
|
3635
|
-
cache.set(adapter.id, queryFingerprint,
|
|
4246
|
+
cache.set(adapter.id, queryFingerprint, report2);
|
|
3636
4247
|
failureBackoff.delete(failureKey);
|
|
3637
4248
|
}
|
|
3638
4249
|
return {
|
|
@@ -3641,13 +4252,13 @@ function usageExtension(pi, dependencies = {}) {
|
|
|
3641
4252
|
providerName: adapter.displayName,
|
|
3642
4253
|
displayState,
|
|
3643
4254
|
status: "ready",
|
|
3644
|
-
report
|
|
4255
|
+
report: report2
|
|
3645
4256
|
},
|
|
3646
4257
|
fingerprint: auth.fingerprint
|
|
3647
4258
|
};
|
|
3648
4259
|
} catch (error) {
|
|
3649
4260
|
if (isStaleExtensionContextError(error) || isAbortError3(error)) throw error;
|
|
3650
|
-
if (
|
|
4261
|
+
if (retryableAuthChanged && authRetry === 0 && !signal.aborted && !requestContextChanged() && Date.now() < deadlineAt) {
|
|
3651
4262
|
if (latestQueries.get(failureKey) === queryId) latestQueries.delete(failureKey);
|
|
3652
4263
|
return queryAdapterState(
|
|
3653
4264
|
ctx,
|
|
@@ -4335,6 +4946,8 @@ export {
|
|
|
4335
4946
|
isStaleExtensionContextError,
|
|
4336
4947
|
listCodexResetCredits,
|
|
4337
4948
|
loadUsageSettings,
|
|
4949
|
+
miniMaxUsageKind,
|
|
4950
|
+
normalizeBasetenBillingUsagePayload,
|
|
4338
4951
|
normalizeCodexBackendPayload,
|
|
4339
4952
|
normalizeCodexResetCreditsPayload,
|
|
4340
4953
|
normalizeDeepSeekBalancePayload,
|
|
@@ -4342,9 +4955,12 @@ export {
|
|
|
4342
4955
|
normalizeFireworksBillingSummaryPayload,
|
|
4343
4956
|
normalizeGitHubCopilotUsagePayload,
|
|
4344
4957
|
normalizeKimiCodingUsagePayload,
|
|
4958
|
+
normalizeMiniMaxUsagePayload,
|
|
4959
|
+
normalizeMoonshotBalancePayload,
|
|
4345
4960
|
normalizeOpenCodeZenPayload,
|
|
4346
4961
|
normalizeOpenRouterKeyPayload,
|
|
4347
4962
|
normalizeUsageSettings,
|
|
4963
|
+
normalizeVercelAIGatewayCreditsPayload,
|
|
4348
4964
|
normalizeXaiBillingPayload,
|
|
4349
4965
|
normalizeZaiQuotaPayload,
|
|
4350
4966
|
providerIsConfigured,
|