@narumitw/pi-usage 0.58.0 → 0.60.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 +86 -7
- package/dist/index.ts +948 -235
- package/dist/index.ts.map +4 -4
- package/package.json +7 -1
- package/src/format.ts +176 -15
- package/src/index.ts +14 -1
- 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/providers/zai.ts +109 -5
- package/src/query.ts +276 -32
- package/src/types.ts +41 -0
- package/src/usage.ts +21 -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.`);
|
|
@@ -1283,14 +1604,14 @@ function isRecord2(value) {
|
|
|
1283
1604
|
// src/providers/zai.ts
|
|
1284
1605
|
var FIVE_HOUR_WINDOW_MINUTES2 = 300;
|
|
1285
1606
|
var WEEKLY_WINDOW_MINUTES2 = 10080;
|
|
1286
|
-
function normalizeZaiQuotaPayload(providerId, providerName, payload, capturedAt) {
|
|
1287
|
-
const data =
|
|
1607
|
+
function normalizeZaiQuotaPayload(providerId, providerName, payload, capturedAt, plan) {
|
|
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);
|
|
@@ -1299,14 +1620,20 @@ function normalizeZaiQuotaPayload(providerId, providerName, payload, capturedAt)
|
|
|
1299
1620
|
addCountBucket(buckets, limit, "mcp-monthly", "MCP monthly allowance");
|
|
1300
1621
|
addUsageDetailMetrics(metrics, limit.usageDetails);
|
|
1301
1622
|
} else if (isPlanUsage && unit === 3) {
|
|
1302
|
-
addPercentBucket(
|
|
1623
|
+
addPercentBucket(
|
|
1624
|
+
buckets,
|
|
1625
|
+
limit,
|
|
1626
|
+
"five-hour",
|
|
1627
|
+
sessionWindowLabel(limit),
|
|
1628
|
+
sessionWindowMinutes(limit)
|
|
1629
|
+
);
|
|
1303
1630
|
} else if (isPlanUsage && unit === 6) {
|
|
1304
1631
|
const used = asNonnegativeNumber4(limit.currentValue);
|
|
1305
1632
|
const quota = asNonnegativeNumber4(limit.usage);
|
|
1306
1633
|
if (used !== void 0 && quota !== void 0) {
|
|
1307
|
-
addCountBucket(buckets, limit, "weekly", "Weekly window",
|
|
1634
|
+
addCountBucket(buckets, limit, "weekly", "Weekly window", weeklyWindowMinutes(limit));
|
|
1308
1635
|
} else {
|
|
1309
|
-
addPercentBucket(buckets, limit, "weekly", "Weekly window",
|
|
1636
|
+
addPercentBucket(buckets, limit, "weekly", "Weekly window", weeklyWindowMinutes(limit));
|
|
1310
1637
|
}
|
|
1311
1638
|
}
|
|
1312
1639
|
}
|
|
@@ -1315,7 +1642,12 @@ function normalizeZaiQuotaPayload(providerId, providerName, payload, capturedAt)
|
|
|
1315
1642
|
}
|
|
1316
1643
|
const notes = [];
|
|
1317
1644
|
const level = asString5(data.level);
|
|
1318
|
-
|
|
1645
|
+
const planLabel = plan?.name ?? level;
|
|
1646
|
+
if (planLabel) {
|
|
1647
|
+
notes.push(
|
|
1648
|
+
plan?.renewsAt ? `Plan: ${planLabel} \xB7 renews ${plan.renewsAt}` : `Plan: ${planLabel}`
|
|
1649
|
+
);
|
|
1650
|
+
}
|
|
1319
1651
|
return {
|
|
1320
1652
|
providerId,
|
|
1321
1653
|
providerName,
|
|
@@ -1327,6 +1659,57 @@ function normalizeZaiQuotaPayload(providerId, providerName, payload, capturedAt)
|
|
|
1327
1659
|
...notes.length > 0 ? { notes } : {}
|
|
1328
1660
|
};
|
|
1329
1661
|
}
|
|
1662
|
+
function normalizeZaiSubscriptionPayload(payload) {
|
|
1663
|
+
if (payload.success === false) return void 0;
|
|
1664
|
+
if (typeof payload.code === "number" && payload.code !== 0 && payload.code !== 200) {
|
|
1665
|
+
return void 0;
|
|
1666
|
+
}
|
|
1667
|
+
if (!Array.isArray(payload.data)) return void 0;
|
|
1668
|
+
const candidates = [];
|
|
1669
|
+
for (const raw of payload.data) {
|
|
1670
|
+
const entry = asObject11(raw);
|
|
1671
|
+
if (!entry) continue;
|
|
1672
|
+
const name = asString5(entry.productName);
|
|
1673
|
+
if (!name) continue;
|
|
1674
|
+
const renewsAt = planRenewalDate(entry.nextRenewTime);
|
|
1675
|
+
const status = asString5(entry.status)?.toUpperCase();
|
|
1676
|
+
const inCurrentPeriod = asBoolean(entry.inCurrentPeriod);
|
|
1677
|
+
candidates.push({
|
|
1678
|
+
plan: { name, ...renewsAt !== void 0 ? { renewsAt } : {} },
|
|
1679
|
+
...status !== void 0 ? { status } : {},
|
|
1680
|
+
...inCurrentPeriod !== void 0 ? { inCurrentPeriod } : {}
|
|
1681
|
+
});
|
|
1682
|
+
}
|
|
1683
|
+
const hasStateMetadata = candidates.some(
|
|
1684
|
+
(candidate) => candidate.status !== void 0 || candidate.inCurrentPeriod !== void 0
|
|
1685
|
+
);
|
|
1686
|
+
if (!hasStateMetadata) return candidates[0]?.plan;
|
|
1687
|
+
return candidates.find(
|
|
1688
|
+
(candidate) => candidate.inCurrentPeriod === true && candidate.status === "VALID"
|
|
1689
|
+
)?.plan ?? candidates.find(
|
|
1690
|
+
(candidate) => candidate.inCurrentPeriod === true && candidate.status === void 0
|
|
1691
|
+
)?.plan ?? candidates.find(
|
|
1692
|
+
(candidate) => candidate.status === "VALID" && candidate.inCurrentPeriod === void 0
|
|
1693
|
+
)?.plan;
|
|
1694
|
+
}
|
|
1695
|
+
function planRenewalDate(value) {
|
|
1696
|
+
if (typeof value === "string" && /^\d{4}-\d{2}-\d{2}/u.test(value)) return value.slice(0, 10);
|
|
1697
|
+
const millis = asNonnegativeNumber4(value);
|
|
1698
|
+
if (millis === void 0 || millis === 0) return void 0;
|
|
1699
|
+
return new Date(millis).toISOString().slice(0, 10);
|
|
1700
|
+
}
|
|
1701
|
+
function sessionWindowMinutes(limit) {
|
|
1702
|
+
const hours = asPositiveNumber(limit.number);
|
|
1703
|
+
return hours === void 0 ? FIVE_HOUR_WINDOW_MINUTES2 : Math.round(hours * 60);
|
|
1704
|
+
}
|
|
1705
|
+
function sessionWindowLabel(limit) {
|
|
1706
|
+
const minutes = sessionWindowMinutes(limit);
|
|
1707
|
+
return minutes === FIVE_HOUR_WINDOW_MINUTES2 ? "5h window" : `${Math.round(minutes / 60)}h window`;
|
|
1708
|
+
}
|
|
1709
|
+
function weeklyWindowMinutes(limit) {
|
|
1710
|
+
const weeks = asPositiveNumber(limit.number);
|
|
1711
|
+
return weeks === void 0 ? WEEKLY_WINDOW_MINUTES2 : Math.round(weeks * WEEKLY_WINDOW_MINUTES2);
|
|
1712
|
+
}
|
|
1330
1713
|
function addPercentBucket(buckets, limit, id, label, windowMinutes) {
|
|
1331
1714
|
const used = asNonnegativeNumber4(limit.percentage);
|
|
1332
1715
|
if (used === void 0) return;
|
|
@@ -1362,7 +1745,7 @@ function addCountBucket(buckets, limit, id, label, windowMinutes) {
|
|
|
1362
1745
|
function addUsageDetailMetrics(metrics, value) {
|
|
1363
1746
|
if (!Array.isArray(value)) return;
|
|
1364
1747
|
for (const raw of value) {
|
|
1365
|
-
const detail =
|
|
1748
|
+
const detail = asObject11(raw);
|
|
1366
1749
|
if (!detail) continue;
|
|
1367
1750
|
const label = asString5(detail.modelCode);
|
|
1368
1751
|
const usage = asNonnegativeNumber4(detail.usage);
|
|
@@ -1370,7 +1753,7 @@ function addUsageDetailMetrics(metrics, value) {
|
|
|
1370
1753
|
metrics.push({ id: `mcp-${kebabCase(label)}`, label, value: usage, unit: "count" });
|
|
1371
1754
|
}
|
|
1372
1755
|
}
|
|
1373
|
-
function
|
|
1756
|
+
function asObject11(value) {
|
|
1374
1757
|
if (!value || typeof value !== "object" || Array.isArray(value)) return void 0;
|
|
1375
1758
|
return value;
|
|
1376
1759
|
}
|
|
@@ -1382,6 +1765,16 @@ function asNonnegativeNumber4(value) {
|
|
|
1382
1765
|
if (typeof value !== "number" || !Number.isFinite(value) || value < 0) return void 0;
|
|
1383
1766
|
return value;
|
|
1384
1767
|
}
|
|
1768
|
+
function asPositiveNumber(value) {
|
|
1769
|
+
const number = asNonnegativeNumber4(value);
|
|
1770
|
+
return number !== void 0 && number > 0 ? number : void 0;
|
|
1771
|
+
}
|
|
1772
|
+
function asBoolean(value) {
|
|
1773
|
+
if (typeof value === "boolean") return value;
|
|
1774
|
+
if (value === 1) return true;
|
|
1775
|
+
if (value === 0) return false;
|
|
1776
|
+
return void 0;
|
|
1777
|
+
}
|
|
1385
1778
|
function asEpochSeconds2(value) {
|
|
1386
1779
|
const millis = asNonnegativeNumber4(value);
|
|
1387
1780
|
if (millis === void 0) return void 0;
|
|
@@ -1395,6 +1788,8 @@ function clampPercent3(value) {
|
|
|
1395
1788
|
}
|
|
1396
1789
|
|
|
1397
1790
|
// src/query.ts
|
|
1791
|
+
var BASETEN_BILLING_USAGE_URL = "https://api.baseten.co/v1/billing/usage_summary";
|
|
1792
|
+
var BASETEN_USAGE_WINDOW_DAYS = 30;
|
|
1398
1793
|
var CODEX_USAGE_URL = "https://chatgpt.com/backend-api/wham/usage";
|
|
1399
1794
|
var DEEPSEEK_BALANCE_URL = "https://api.deepseek.com/user/balance";
|
|
1400
1795
|
var FIREWORKS_BILLING_SUMMARY_ORIGIN = "https://api.fireworks.ai";
|
|
@@ -1402,8 +1797,18 @@ var FIREWORKS_SPEND_WINDOW_DAYS = 30;
|
|
|
1402
1797
|
var FIREWORKS_MAX_ACCOUNT_PAGES = 5;
|
|
1403
1798
|
var GITHUB_COPILOT_USAGE_URL = "https://api.github.com/copilot_internal/user";
|
|
1404
1799
|
var OPENROUTER_KEY_URL = "https://openrouter.ai/api/v1/key";
|
|
1800
|
+
var VERCEL_AI_GATEWAY_CREDITS_URL = "https://ai-gateway.vercel.sh/v1/credits";
|
|
1405
1801
|
var OPENCODE_GO_USAGE_URL = "https://opencode.ai/zen/go/v1/usage";
|
|
1406
1802
|
var KIMI_CODING_USAGE_URL = "https://api.kimi.com/coding/v1/usages";
|
|
1803
|
+
var MINIMAX_API_ROOTS = Object.freeze({
|
|
1804
|
+
minimax: "https://api.minimax.io",
|
|
1805
|
+
"minimax-cn": "https://api.minimaxi.com"
|
|
1806
|
+
});
|
|
1807
|
+
var MOONSHOT_BALANCE_URLS = Object.freeze({
|
|
1808
|
+
moonshotai: "https://api.moonshot.ai/v1/users/me/balance",
|
|
1809
|
+
"moonshotai-cn": "https://api.moonshot.cn/v1/users/me/balance"
|
|
1810
|
+
});
|
|
1811
|
+
var SHARED_MOONSHOT_ENV_VAR = "MOONSHOT_API_KEY";
|
|
1407
1812
|
var XAI_USER_URL = "https://cli-chat-proxy.grok.com/v1/user?include=subscription";
|
|
1408
1813
|
var XAI_BILLING_URL = "https://cli-chat-proxy.grok.com/v1/billing?format=credits";
|
|
1409
1814
|
var XAI_CLIENT_HEADERS = Object.freeze({
|
|
@@ -1415,6 +1820,27 @@ var MAX_SUCCESS_BODY_BYTES = 64 * 1024;
|
|
|
1415
1820
|
var MAX_ERROR_BODY_BYTES = 4 * 1024;
|
|
1416
1821
|
var AUTH_FINGERPRINT_SALT = randomBytes(32);
|
|
1417
1822
|
var SUPPORTED_ADAPTERS = [
|
|
1823
|
+
{
|
|
1824
|
+
id: "baseten",
|
|
1825
|
+
displayName: "Baseten",
|
|
1826
|
+
semantics: { kind: "api-key", label: "Organization Model APIs spend" },
|
|
1827
|
+
async query(auth, signal, timeoutMs, guard) {
|
|
1828
|
+
if (!guard) throw new Error("Baseten billing usage requires request-boundary revalidation.");
|
|
1829
|
+
const startedAt = Date.now();
|
|
1830
|
+
await guard();
|
|
1831
|
+
const windowAt = Date.now();
|
|
1832
|
+
const payload = await fetchProviderJson(
|
|
1833
|
+
basetenBillingUsageUrl(windowAt),
|
|
1834
|
+
auth,
|
|
1835
|
+
signal,
|
|
1836
|
+
remainingTimeout(timeoutMs, startedAt, "fetching Baseten billing usage"),
|
|
1837
|
+
"Baseten billing usage endpoint",
|
|
1838
|
+
{ redirect: "error" }
|
|
1839
|
+
);
|
|
1840
|
+
await guard();
|
|
1841
|
+
return normalizeBasetenBillingUsagePayload(payload, Date.now());
|
|
1842
|
+
}
|
|
1843
|
+
},
|
|
1418
1844
|
{
|
|
1419
1845
|
id: "openai-codex",
|
|
1420
1846
|
displayName: "OpenAI Codex",
|
|
@@ -1487,6 +1913,27 @@ var SUPPORTED_ADAPTERS = [
|
|
|
1487
1913
|
return normalizeOpenRouterKeyPayload(payload, Date.now());
|
|
1488
1914
|
}
|
|
1489
1915
|
},
|
|
1916
|
+
{
|
|
1917
|
+
id: "vercel-ai-gateway",
|
|
1918
|
+
displayName: "Vercel AI Gateway",
|
|
1919
|
+
semantics: { kind: "api-key", label: "AI Gateway credits and lifetime spend" },
|
|
1920
|
+
async query(auth, signal, timeoutMs, guard) {
|
|
1921
|
+
if (!guard)
|
|
1922
|
+
throw new Error("Vercel AI Gateway usage requires request-boundary revalidation.");
|
|
1923
|
+
const startedAt = Date.now();
|
|
1924
|
+
await guard();
|
|
1925
|
+
const payload = await fetchProviderJson(
|
|
1926
|
+
VERCEL_AI_GATEWAY_CREDITS_URL,
|
|
1927
|
+
auth,
|
|
1928
|
+
signal,
|
|
1929
|
+
remainingTimeout(timeoutMs, startedAt, "fetching Vercel AI Gateway credits"),
|
|
1930
|
+
"Vercel AI Gateway credits endpoint",
|
|
1931
|
+
{ redirect: "error" }
|
|
1932
|
+
);
|
|
1933
|
+
await guard();
|
|
1934
|
+
return normalizeVercelAIGatewayCreditsPayload(payload, Date.now());
|
|
1935
|
+
}
|
|
1936
|
+
},
|
|
1490
1937
|
{
|
|
1491
1938
|
id: "fireworks",
|
|
1492
1939
|
displayName: "Fireworks",
|
|
@@ -1547,39 +1994,52 @@ var SUPPORTED_ADAPTERS = [
|
|
|
1547
1994
|
return normalizeKimiCodingUsagePayload(payload, Date.now());
|
|
1548
1995
|
}
|
|
1549
1996
|
},
|
|
1997
|
+
{
|
|
1998
|
+
id: "minimax",
|
|
1999
|
+
displayName: "MiniMax",
|
|
2000
|
+
semantics: { kind: "consumer-subscription", label: "MiniMax usage" },
|
|
2001
|
+
async query(auth, signal, timeoutMs, guard) {
|
|
2002
|
+
return queryMiniMaxUsage("minimax", auth, signal, timeoutMs, guard);
|
|
2003
|
+
}
|
|
2004
|
+
},
|
|
2005
|
+
{
|
|
2006
|
+
id: "minimax-cn",
|
|
2007
|
+
displayName: "MiniMax CN",
|
|
2008
|
+
semantics: { kind: "consumer-subscription", label: "MiniMax usage" },
|
|
2009
|
+
async query(auth, signal, timeoutMs, guard) {
|
|
2010
|
+
return queryMiniMaxUsage("minimax-cn", auth, signal, timeoutMs, guard);
|
|
2011
|
+
}
|
|
2012
|
+
},
|
|
2013
|
+
{
|
|
2014
|
+
id: "moonshotai",
|
|
2015
|
+
displayName: "Moonshot AI",
|
|
2016
|
+
semantics: { kind: "api-key", label: "Moonshot API account balance" },
|
|
2017
|
+
async query(auth, signal, timeoutMs, guard) {
|
|
2018
|
+
return queryMoonshotBalance("moonshotai", auth, signal, timeoutMs, guard);
|
|
2019
|
+
}
|
|
2020
|
+
},
|
|
2021
|
+
{
|
|
2022
|
+
id: "moonshotai-cn",
|
|
2023
|
+
displayName: "Moonshot AI CN",
|
|
2024
|
+
semantics: { kind: "api-key", label: "Moonshot API account balance" },
|
|
2025
|
+
async query(auth, signal, timeoutMs, guard) {
|
|
2026
|
+
return queryMoonshotBalance("moonshotai-cn", auth, signal, timeoutMs, guard);
|
|
2027
|
+
}
|
|
2028
|
+
},
|
|
1550
2029
|
{
|
|
1551
2030
|
id: "zai",
|
|
1552
2031
|
displayName: "Z.AI",
|
|
1553
2032
|
semantics: { kind: "consumer-subscription", label: "GLM Coding Plan usage" },
|
|
1554
|
-
async query(auth, signal, timeoutMs) {
|
|
1555
|
-
|
|
1556
|
-
zaiMonitorUrl(auth.model.baseUrl),
|
|
1557
|
-
zaiMonitorAuth(auth),
|
|
1558
|
-
signal,
|
|
1559
|
-
timeoutMs,
|
|
1560
|
-
"Z.AI quota endpoint"
|
|
1561
|
-
);
|
|
1562
|
-
return normalizeZaiQuotaPayload("zai", "Z.AI", payload, Date.now());
|
|
2033
|
+
async query(auth, signal, timeoutMs, guard) {
|
|
2034
|
+
return queryZaiUsage("zai", "Z.AI", auth, signal, timeoutMs, guard);
|
|
1563
2035
|
}
|
|
1564
2036
|
},
|
|
1565
2037
|
{
|
|
1566
2038
|
id: "zai-coding-cn",
|
|
1567
2039
|
displayName: "Z.AI Coding CN",
|
|
1568
2040
|
semantics: { kind: "consumer-subscription", label: "GLM Coding Plan usage" },
|
|
1569
|
-
async query(auth, signal, timeoutMs) {
|
|
1570
|
-
|
|
1571
|
-
zaiMonitorUrl(auth.model.baseUrl),
|
|
1572
|
-
zaiMonitorAuth(auth),
|
|
1573
|
-
signal,
|
|
1574
|
-
timeoutMs,
|
|
1575
|
-
"Z.AI Coding CN quota endpoint"
|
|
1576
|
-
);
|
|
1577
|
-
return normalizeZaiQuotaPayload(
|
|
1578
|
-
"zai-coding-cn",
|
|
1579
|
-
"Z.AI Coding CN",
|
|
1580
|
-
payload,
|
|
1581
|
-
Date.now()
|
|
1582
|
-
);
|
|
2041
|
+
async query(auth, signal, timeoutMs, guard) {
|
|
2042
|
+
return queryZaiUsage("zai-coding-cn", "Z.AI Coding CN", auth, signal, timeoutMs, guard);
|
|
1583
2043
|
}
|
|
1584
2044
|
}
|
|
1585
2045
|
];
|
|
@@ -1655,17 +2115,20 @@ async function resolveUsageAuth(ctx, adapter, salt = AUTH_FINGERPRINT_SALT, cred
|
|
|
1655
2115
|
if (!result.ok) throw new Error(redactUsageError(result.error));
|
|
1656
2116
|
return authorizationFrom(result) ? result : void 0;
|
|
1657
2117
|
};
|
|
1658
|
-
|
|
2118
|
+
const resolveSelectedAuthLast = ["deepseek", "minimax", "minimax-cn"].includes(adapter.id);
|
|
2119
|
+
if (!resolveSelectedAuthLast) modelAuth = await resolveCurrentModelAuth();
|
|
1659
2120
|
if (typeof registry.getProviderAuth !== "function") {
|
|
1660
2121
|
throw new Error("pi-usage requires Pi 0.81.0 or newer to validate resolved provider auth.");
|
|
1661
2122
|
}
|
|
2123
|
+
if (!moonshotProviderAuthIsAllowed(ctx, adapter.id)) return void 0;
|
|
1662
2124
|
const providerResult = await registry.getProviderAuth(adapter.id);
|
|
2125
|
+
if (!moonshotProviderAuthIsAllowed(ctx, adapter.id)) return void 0;
|
|
1663
2126
|
if (providerResult?.auth.baseUrl && !hasOfficialUrlOrigin(providerResult.auth.baseUrl, adapter.id)) {
|
|
1664
2127
|
throw new Error(
|
|
1665
2128
|
`${adapter.displayName} usage cannot send a proxy-resolved credential to the official usage endpoint.`
|
|
1666
2129
|
);
|
|
1667
2130
|
}
|
|
1668
|
-
if (
|
|
2131
|
+
if (resolveSelectedAuthLast) modelAuth = await resolveCurrentModelAuth();
|
|
1669
2132
|
const auth = modelAuth ?? providerResult?.auth;
|
|
1670
2133
|
if (!auth) return void 0;
|
|
1671
2134
|
if (adapter.id === "github-copilot") {
|
|
@@ -1730,11 +2193,30 @@ async function queryProviderUsage(adapter, auth, signal, timeoutMs, guard, setti
|
|
|
1730
2193
|
}
|
|
1731
2194
|
function providerIsConfigured(ctx, providerId) {
|
|
1732
2195
|
try {
|
|
1733
|
-
|
|
2196
|
+
const status = ctx.modelRegistry.getProviderAuthStatus(providerId);
|
|
2197
|
+
return status.configured && moonshotProviderAuthSourceIsAllowed(ctx, providerId, status.source, status.label);
|
|
1734
2198
|
} catch {
|
|
1735
|
-
return candidateModels(ctx, providerId).length > 0;
|
|
2199
|
+
return !isMoonshotSiblingProvider(ctx, providerId) && candidateModels(ctx, providerId).length > 0;
|
|
1736
2200
|
}
|
|
1737
2201
|
}
|
|
2202
|
+
function moonshotProviderAuthIsAllowed(ctx, providerId) {
|
|
2203
|
+
if (!isMoonshotSiblingProvider(ctx, providerId)) return true;
|
|
2204
|
+
try {
|
|
2205
|
+
const status = ctx.modelRegistry.getProviderAuthStatus(providerId);
|
|
2206
|
+
return moonshotProviderAuthSourceIsAllowed(ctx, providerId, status.source, status.label);
|
|
2207
|
+
} catch {
|
|
2208
|
+
return false;
|
|
2209
|
+
}
|
|
2210
|
+
}
|
|
2211
|
+
function moonshotProviderAuthSourceIsAllowed(ctx, providerId, source, label) {
|
|
2212
|
+
if (!isMoonshotSiblingProvider(ctx, providerId)) return true;
|
|
2213
|
+
if (source === void 0) return false;
|
|
2214
|
+
if (source !== "environment") return true;
|
|
2215
|
+
return label !== void 0 && !label.split(",").map((name) => name.trim()).includes(SHARED_MOONSHOT_ENV_VAR);
|
|
2216
|
+
}
|
|
2217
|
+
function isMoonshotSiblingProvider(ctx, providerId) {
|
|
2218
|
+
return (providerId === "moonshotai" || providerId === "moonshotai-cn") && ctx.model?.provider !== providerId;
|
|
2219
|
+
}
|
|
1738
2220
|
function candidateModels(ctx, providerId) {
|
|
1739
2221
|
const candidates = [];
|
|
1740
2222
|
const seen = /* @__PURE__ */ new Set();
|
|
@@ -1863,7 +2345,7 @@ function resolveXaiUsageAuth(auth, model, salt, candidates) {
|
|
|
1863
2345
|
const matches = [];
|
|
1864
2346
|
for (const candidate of candidates) {
|
|
1865
2347
|
try {
|
|
1866
|
-
const credential =
|
|
2348
|
+
const credential = asObject12(candidate);
|
|
1867
2349
|
if (credential?.type !== "oauth") continue;
|
|
1868
2350
|
sawOAuth = true;
|
|
1869
2351
|
if (credential.access !== resolvedAccess) continue;
|
|
@@ -1917,7 +2399,7 @@ function resolveGitHubCopilotUsageAuth(auth, model, salt, candidates, standalone
|
|
|
1917
2399
|
const matches = /* @__PURE__ */ new Map();
|
|
1918
2400
|
for (const candidate of candidates) {
|
|
1919
2401
|
try {
|
|
1920
|
-
const credential =
|
|
2402
|
+
const credential = asObject12(candidate);
|
|
1921
2403
|
if (credential?.type !== "oauth") continue;
|
|
1922
2404
|
sawOAuth = true;
|
|
1923
2405
|
const storedAccess2 = typeof credential.access === "string" && credential.access ? credential.access : void 0;
|
|
@@ -1979,7 +2461,7 @@ function bearerToken(authorization) {
|
|
|
1979
2461
|
const match = /^Bearer\s+(.+)$/iu.exec(authorization ?? "");
|
|
1980
2462
|
return match?.[1];
|
|
1981
2463
|
}
|
|
1982
|
-
function
|
|
2464
|
+
function asObject12(value) {
|
|
1983
2465
|
if (!value || typeof value !== "object" || Array.isArray(value)) return void 0;
|
|
1984
2466
|
return value;
|
|
1985
2467
|
}
|
|
@@ -1997,12 +2479,20 @@ function hasOfficialOrigin(model, providerId) {
|
|
|
1997
2479
|
function hasOfficialUrlOrigin(value, providerId) {
|
|
1998
2480
|
try {
|
|
1999
2481
|
const url = new URL(value);
|
|
2482
|
+
if (providerId === "baseten") {
|
|
2483
|
+
return ["https://inference.baseten.co", "https://api.baseten.co"].includes(url.origin);
|
|
2484
|
+
}
|
|
2000
2485
|
if (providerId === "openai-codex") return url.origin === "https://chatgpt.com";
|
|
2001
2486
|
if (providerId === "deepseek") return url.origin === "https://api.deepseek.com";
|
|
2002
2487
|
if (providerId === "fireworks") return url.origin === FIREWORKS_BILLING_SUMMARY_ORIGIN;
|
|
2003
2488
|
if (providerId === "openrouter") return url.origin === "https://openrouter.ai";
|
|
2489
|
+
if (providerId === "vercel-ai-gateway") return url.origin === "https://ai-gateway.vercel.sh";
|
|
2004
2490
|
if (providerId === "opencode-go") return url.origin === "https://opencode.ai";
|
|
2005
2491
|
if (providerId === "kimi-coding") return url.origin === "https://api.kimi.com";
|
|
2492
|
+
if (providerId === "minimax") return url.origin === "https://api.minimax.io";
|
|
2493
|
+
if (providerId === "minimax-cn") return url.origin === "https://api.minimaxi.com";
|
|
2494
|
+
if (providerId === "moonshotai") return url.origin === "https://api.moonshot.ai";
|
|
2495
|
+
if (providerId === "moonshotai-cn") return url.origin === "https://api.moonshot.cn";
|
|
2006
2496
|
if (providerId === "xai") return url.origin === "https://api.x.ai";
|
|
2007
2497
|
if (providerId === "zai") return url.origin === "https://api.z.ai";
|
|
2008
2498
|
if (providerId === "zai-coding-cn") return url.origin === "https://open.bigmodel.cn";
|
|
@@ -2029,6 +2519,49 @@ function validatedXaiUserId(value) {
|
|
|
2029
2519
|
}
|
|
2030
2520
|
return value;
|
|
2031
2521
|
}
|
|
2522
|
+
function basetenBillingUsageUrl(windowAt) {
|
|
2523
|
+
const url = new URL(BASETEN_BILLING_USAGE_URL);
|
|
2524
|
+
url.searchParams.set(
|
|
2525
|
+
"start_date",
|
|
2526
|
+
new Date(windowAt - BASETEN_USAGE_WINDOW_DAYS * 24 * 60 * 60 * 1e3).toISOString()
|
|
2527
|
+
);
|
|
2528
|
+
url.searchParams.set("end_date", new Date(windowAt).toISOString());
|
|
2529
|
+
return url.toString();
|
|
2530
|
+
}
|
|
2531
|
+
async function queryMiniMaxUsage(providerId, auth, signal, timeoutMs, guard) {
|
|
2532
|
+
if (!guard) throw new Error("MiniMax usage requires request-boundary revalidation.");
|
|
2533
|
+
const apiKey = bearerToken(headerValue(auth.headers, "Authorization")) ?? auth.apiKey;
|
|
2534
|
+
if (!apiKey) throw new Error("MiniMax runtime API key was unavailable.");
|
|
2535
|
+
const kind = miniMaxUsageKind(apiKey);
|
|
2536
|
+
const path = kind === "account-balance" ? "/account/query_balance" : "/v1/token_plan/remains";
|
|
2537
|
+
const startedAt = Date.now();
|
|
2538
|
+
await guard();
|
|
2539
|
+
const payload = await fetchProviderJson(
|
|
2540
|
+
`${MINIMAX_API_ROOTS[providerId]}${path}`,
|
|
2541
|
+
auth,
|
|
2542
|
+
signal,
|
|
2543
|
+
remainingTimeout(timeoutMs, startedAt, "fetching MiniMax usage"),
|
|
2544
|
+
"MiniMax usage endpoint",
|
|
2545
|
+
{ redirect: "error" }
|
|
2546
|
+
);
|
|
2547
|
+
await guard();
|
|
2548
|
+
return normalizeMiniMaxUsagePayload(providerId, kind, payload, Date.now());
|
|
2549
|
+
}
|
|
2550
|
+
async function queryMoonshotBalance(providerId, auth, signal, timeoutMs, guard) {
|
|
2551
|
+
if (!guard) throw new Error("Moonshot AI balance requires request-boundary revalidation.");
|
|
2552
|
+
const startedAt = Date.now();
|
|
2553
|
+
await guard();
|
|
2554
|
+
const payload = await fetchProviderJson(
|
|
2555
|
+
MOONSHOT_BALANCE_URLS[providerId],
|
|
2556
|
+
auth,
|
|
2557
|
+
signal,
|
|
2558
|
+
remainingTimeout(timeoutMs, startedAt, "fetching Moonshot AI balance"),
|
|
2559
|
+
"Moonshot AI balance endpoint",
|
|
2560
|
+
{ redirect: "error" }
|
|
2561
|
+
);
|
|
2562
|
+
await guard();
|
|
2563
|
+
return normalizeMoonshotBalancePayload(providerId, payload, Date.now());
|
|
2564
|
+
}
|
|
2032
2565
|
function remainingTimeout(timeoutMs, startedAt, description = "fetching xAI consumer usage") {
|
|
2033
2566
|
const remaining = timeoutMs - (Date.now() - startedAt);
|
|
2034
2567
|
if (remaining <= 0) throw new Error(`Timed out while ${description}.`);
|
|
@@ -2110,10 +2643,13 @@ function fireworksBillingSummaryUrl(accountId, startedAt) {
|
|
|
2110
2643
|
url.searchParams.set("endTime", dayFloor(startedAt + dayMs));
|
|
2111
2644
|
return url.toString();
|
|
2112
2645
|
}
|
|
2113
|
-
function
|
|
2646
|
+
function zaiOrigin(baseUrl) {
|
|
2114
2647
|
const base = baseUrl?.trim();
|
|
2115
2648
|
if (!base) throw new Error("Z.AI model base URL is unavailable.");
|
|
2116
|
-
return
|
|
2649
|
+
return new URL(base).origin;
|
|
2650
|
+
}
|
|
2651
|
+
function zaiMonitorUrl(baseUrl) {
|
|
2652
|
+
return `${zaiOrigin(baseUrl)}/api/monitor/usage/quota/limit`;
|
|
2117
2653
|
}
|
|
2118
2654
|
function zaiMonitorAuth(auth) {
|
|
2119
2655
|
const authorization = headerValue(auth.headers, "Authorization");
|
|
@@ -2121,6 +2657,38 @@ function zaiMonitorAuth(auth) {
|
|
|
2121
2657
|
if (token === void 0 || token === authorization) return auth;
|
|
2122
2658
|
return { ...auth, headers: { ...auth.headers, Authorization: token } };
|
|
2123
2659
|
}
|
|
2660
|
+
async function queryZaiUsage(providerId, providerName, auth, signal, timeoutMs, guard) {
|
|
2661
|
+
if (!guard) throw new Error("Z.AI usage requires request-boundary revalidation.");
|
|
2662
|
+
const startedAt = Date.now();
|
|
2663
|
+
await guard();
|
|
2664
|
+
const payload = await fetchProviderJson(
|
|
2665
|
+
zaiMonitorUrl(auth.model.baseUrl),
|
|
2666
|
+
zaiMonitorAuth(auth),
|
|
2667
|
+
signal,
|
|
2668
|
+
remainingTimeout(timeoutMs, startedAt, `fetching ${providerName} quota`),
|
|
2669
|
+
`${providerName} quota endpoint`
|
|
2670
|
+
);
|
|
2671
|
+
await guard();
|
|
2672
|
+
const planTimeoutMs = timeoutMs - (Date.now() - startedAt);
|
|
2673
|
+
const plan = await fetchZaiPlan(providerName, auth, signal, planTimeoutMs);
|
|
2674
|
+
return normalizeZaiQuotaPayload(providerId, providerName, payload, Date.now(), plan);
|
|
2675
|
+
}
|
|
2676
|
+
async function fetchZaiPlan(providerName, auth, signal, timeoutMs) {
|
|
2677
|
+
if (timeoutMs <= 0 || signal.aborted) return void 0;
|
|
2678
|
+
try {
|
|
2679
|
+
const payload = await fetchProviderJson(
|
|
2680
|
+
`${zaiOrigin(auth.model.baseUrl)}/api/biz/subscription/list`,
|
|
2681
|
+
zaiMonitorAuth(auth),
|
|
2682
|
+
signal,
|
|
2683
|
+
timeoutMs,
|
|
2684
|
+
`${providerName} plan endpoint`
|
|
2685
|
+
);
|
|
2686
|
+
return normalizeZaiSubscriptionPayload(payload);
|
|
2687
|
+
} catch (error) {
|
|
2688
|
+
if (isAbortError(error)) throw error;
|
|
2689
|
+
return void 0;
|
|
2690
|
+
}
|
|
2691
|
+
}
|
|
2124
2692
|
function isAbortError(error) {
|
|
2125
2693
|
return error instanceof Error && error.name === "AbortError";
|
|
2126
2694
|
}
|
|
@@ -2130,12 +2698,12 @@ var CODEX_RESET_CREDITS_URL = "https://chatgpt.com/backend-api/wham/rate-limit-r
|
|
|
2130
2698
|
var CODEX_RESET_CONSUME_URL = `${CODEX_RESET_CREDITS_URL}/consume`;
|
|
2131
2699
|
var MAX_RESET_OPTIONS = 32;
|
|
2132
2700
|
var MAX_CREDIT_ID_CHARS = 1024;
|
|
2133
|
-
function codexResetCount(
|
|
2134
|
-
const value =
|
|
2701
|
+
function codexResetCount(report2) {
|
|
2702
|
+
const value = report2.metrics.find((metric2) => metric2.id === "reset-credits")?.value;
|
|
2135
2703
|
return typeof value === "number" && Number.isSafeInteger(value) && value >= 0 ? value : void 0;
|
|
2136
2704
|
}
|
|
2137
|
-
function codexResetActionDescription(
|
|
2138
|
-
const count = codexResetCount(
|
|
2705
|
+
function codexResetActionDescription(report2) {
|
|
2706
|
+
const count = codexResetCount(report2);
|
|
2139
2707
|
if (count === void 0) return "Check reset availability.";
|
|
2140
2708
|
if (count === 0) return "No usage limit resets available.";
|
|
2141
2709
|
return `You have ${count} ${resetLabel(count)} available.`;
|
|
@@ -2248,14 +2816,14 @@ async function consumeCodexResetCredit(auth, option, redeemRequestId, signal, ti
|
|
|
2248
2816
|
if (!isCodexResetOutcomeCode(code)) {
|
|
2249
2817
|
throw new Error("Codex reset consume endpoint returned an unknown outcome code.");
|
|
2250
2818
|
}
|
|
2251
|
-
const windowsReset = payload.windows_reset === void 0 ? 0 :
|
|
2819
|
+
const windowsReset = payload.windows_reset === void 0 ? 0 : nonnegativeInteger2(payload.windows_reset);
|
|
2252
2820
|
if (windowsReset === void 0) {
|
|
2253
2821
|
throw new Error("Codex reset consume endpoint returned an invalid windows_reset value.");
|
|
2254
2822
|
}
|
|
2255
2823
|
return { code, windowsReset };
|
|
2256
2824
|
}
|
|
2257
2825
|
function normalizeCodexResetCreditsPayload(payload) {
|
|
2258
|
-
const availableCount =
|
|
2826
|
+
const availableCount = nonnegativeInteger2(payload.available_count);
|
|
2259
2827
|
if (availableCount === void 0) {
|
|
2260
2828
|
throw new Error("Codex reset credits response returned an invalid available_count.");
|
|
2261
2829
|
}
|
|
@@ -2263,7 +2831,7 @@ function normalizeCodexResetCreditsPayload(payload) {
|
|
|
2263
2831
|
if (rawCredits !== void 0 && !Array.isArray(rawCredits)) {
|
|
2264
2832
|
throw new Error("Codex reset credits response returned invalid credits.");
|
|
2265
2833
|
}
|
|
2266
|
-
const options = (rawCredits ?? []).map(
|
|
2834
|
+
const options = (rawCredits ?? []).map(asObject13).filter((credit) => Boolean(credit)).filter((credit) => credit.status === "available" && credit.reset_type === "codex_rate_limits").map(normalizeResetOption).sort(
|
|
2267
2835
|
(left, right) => (left.expiresAt ?? Number.MAX_SAFE_INTEGER) - (right.expiresAt ?? Number.MAX_SAFE_INTEGER)
|
|
2268
2836
|
).slice(0, Math.min(availableCount, MAX_RESET_OPTIONS));
|
|
2269
2837
|
if (availableCount > 0 && options.length === 0) {
|
|
@@ -2278,7 +2846,7 @@ function selectCodexResetCredential(candidates, resolvedAccess, resolvedAccountI
|
|
|
2278
2846
|
const matches = /* @__PURE__ */ new Map();
|
|
2279
2847
|
for (const candidate of candidates) {
|
|
2280
2848
|
try {
|
|
2281
|
-
const credential =
|
|
2849
|
+
const credential = asObject13(candidate);
|
|
2282
2850
|
if (credential?.type !== "oauth") continue;
|
|
2283
2851
|
sawOAuth = true;
|
|
2284
2852
|
const storedAccess = asNonemptyString(credential.access);
|
|
@@ -2317,7 +2885,7 @@ function codexAccountIdFromAccessToken(access) {
|
|
|
2317
2885
|
const parts = access.split(".");
|
|
2318
2886
|
if (parts.length !== 3 || !parts[1]) return void 0;
|
|
2319
2887
|
const payload = JSON.parse(Buffer.from(parts[1], "base64url").toString("utf8"));
|
|
2320
|
-
const claims =
|
|
2888
|
+
const claims = asObject13(asObject13(payload)?.["https://api.openai.com/auth"]);
|
|
2321
2889
|
return validHeaderValue(claims?.chatgpt_account_id);
|
|
2322
2890
|
} catch {
|
|
2323
2891
|
return void 0;
|
|
@@ -2349,7 +2917,7 @@ function normalizeResetOption(credit) {
|
|
|
2349
2917
|
function isCodexResetOutcomeCode(value) {
|
|
2350
2918
|
return value === "reset" || value === "nothing_to_reset" || value === "no_credit" || value === "already_redeemed";
|
|
2351
2919
|
}
|
|
2352
|
-
function
|
|
2920
|
+
function asObject13(value) {
|
|
2353
2921
|
if (!value || typeof value !== "object" || Array.isArray(value)) return void 0;
|
|
2354
2922
|
return value;
|
|
2355
2923
|
}
|
|
@@ -2371,7 +2939,7 @@ function validHeaderValue(value) {
|
|
|
2371
2939
|
if (/[^\x20-\x7e]/u.test(value)) return void 0;
|
|
2372
2940
|
return value;
|
|
2373
2941
|
}
|
|
2374
|
-
function
|
|
2942
|
+
function nonnegativeInteger2(value) {
|
|
2375
2943
|
const parsed = typeof value === "number" ? value : typeof value === "string" && value.trim() ? Number(value) : Number.NaN;
|
|
2376
2944
|
if (!Number.isSafeInteger(parsed) || parsed < 0) return void 0;
|
|
2377
2945
|
return parsed;
|
|
@@ -2388,45 +2956,59 @@ function headerValue2(headers, name) {
|
|
|
2388
2956
|
// src/format.ts
|
|
2389
2957
|
var BAR_SEGMENTS = 20;
|
|
2390
2958
|
var VALUE_COLUMN = 29;
|
|
2391
|
-
function formatUsageReport(
|
|
2959
|
+
function formatUsageReport(report2, displayState) {
|
|
2392
2960
|
const stateLabel = displayState === "current" ? "Current" : "Configured";
|
|
2393
|
-
const title =
|
|
2961
|
+
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
2962
|
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
|
-
|
|
2963
|
+
if (report2.accountLabel) lines.push(`Account: ${report2.accountLabel}`);
|
|
2964
|
+
lines.push(`Semantics: ${report2.semantics.label}`, "");
|
|
2965
|
+
if (report2.providerId === "baseten") formatBasetenReport(lines, report2);
|
|
2966
|
+
else if (report2.providerId === "openai-codex") formatCodexReport(lines, report2);
|
|
2967
|
+
else if (report2.providerId === "deepseek") formatDeepSeekReport(lines, report2);
|
|
2968
|
+
else if (report2.providerId === "fireworks") formatFireworksReport(lines, report2);
|
|
2969
|
+
else if (report2.providerId === "vercel-ai-gateway") formatVercelAIGatewayReport(lines, report2);
|
|
2970
|
+
else if (report2.providerId === "github-copilot") formatGitHubCopilotReport(lines, report2);
|
|
2971
|
+
else if (report2.providerId === "openrouter") formatOpenRouterReport(lines, report2);
|
|
2972
|
+
else if (report2.providerId === "opencode-go") formatOpenCodeZenReport(lines, report2);
|
|
2973
|
+
else if (report2.providerId === "kimi-coding") formatKimiCodingReport(lines, report2);
|
|
2974
|
+
else if (report2.providerId === "moonshotai" || report2.providerId === "moonshotai-cn") {
|
|
2975
|
+
formatMoonshotReport(lines, report2);
|
|
2976
|
+
} else if (report2.providerId === "minimax" || report2.providerId === "minimax-cn") {
|
|
2977
|
+
formatMiniMaxReport(lines, report2);
|
|
2978
|
+
} else if (report2.providerId === "xai") formatXaiReport(lines, report2);
|
|
2979
|
+
else if (report2.providerId === "zai" || report2.providerId === "zai-coding-cn") {
|
|
2980
|
+
formatZaiReport(lines, report2);
|
|
2981
|
+
} else formatGenericReport(lines, report2);
|
|
2982
|
+
if (report2.notes) {
|
|
2983
|
+
for (const note of report2.notes) lines.push(note);
|
|
2410
2984
|
}
|
|
2411
2985
|
return lines.join("\n").trimEnd();
|
|
2412
2986
|
}
|
|
2413
|
-
function formatUsageStatusline(
|
|
2414
|
-
if (
|
|
2415
|
-
|
|
2416
|
-
|
|
2417
|
-
|
|
2418
|
-
if (
|
|
2419
|
-
if (
|
|
2420
|
-
if (
|
|
2421
|
-
|
|
2987
|
+
function formatUsageStatusline(report2, model, now = Date.now(), showCodexResetCountdown = true) {
|
|
2988
|
+
if (report2.providerId === "baseten") return formatBasetenStatusline(report2);
|
|
2989
|
+
if (report2.providerId === "openai-codex") {
|
|
2990
|
+
return formatCodexStatusline(report2, model, now, showCodexResetCountdown);
|
|
2991
|
+
}
|
|
2992
|
+
if (report2.providerId === "deepseek") return formatDeepSeekStatusline(report2);
|
|
2993
|
+
if (report2.providerId === "fireworks") return formatFireworksStatusline(report2);
|
|
2994
|
+
if (report2.providerId === "vercel-ai-gateway") return formatVercelAIGatewayStatusline(report2);
|
|
2995
|
+
if (report2.providerId === "github-copilot") return formatGitHubCopilotStatusline(report2);
|
|
2996
|
+
if (report2.providerId === "openrouter") {
|
|
2997
|
+
const limit = report2.buckets.find((bucket) => bucket.id === "key-limit");
|
|
2422
2998
|
if (limit?.remaining !== void 0) return `openrouter ${formatUsd(limit.remaining)} left`;
|
|
2423
|
-
const total =
|
|
2999
|
+
const total = report2.metrics.find((metric2) => metric2.id === "usage-total");
|
|
2424
3000
|
if (typeof total?.value === "number") return `openrouter ${formatUsd(total.value)} used`;
|
|
2425
3001
|
}
|
|
2426
|
-
if (
|
|
2427
|
-
if (
|
|
2428
|
-
if (
|
|
2429
|
-
return
|
|
3002
|
+
if (report2.providerId === "opencode-go") return formatOpenCodeZenStatusline(report2);
|
|
3003
|
+
if (report2.providerId === "kimi-coding") return formatKimiCodingStatusline(report2);
|
|
3004
|
+
if (report2.providerId === "moonshotai" || report2.providerId === "moonshotai-cn") {
|
|
3005
|
+
return formatMoonshotStatusline(report2);
|
|
3006
|
+
}
|
|
3007
|
+
if (report2.providerId === "minimax" || report2.providerId === "minimax-cn") {
|
|
3008
|
+
return formatMiniMaxStatusline(report2, model);
|
|
3009
|
+
}
|
|
3010
|
+
if (report2.providerId === "zai" || report2.providerId === "zai-coding-cn") {
|
|
3011
|
+
return formatZaiStatusline(report2);
|
|
2430
3012
|
}
|
|
2431
3013
|
return void 0;
|
|
2432
3014
|
}
|
|
@@ -2439,9 +3021,19 @@ function formatProviderStates(states) {
|
|
|
2439
3021
|
${status}: ${state.message}`;
|
|
2440
3022
|
}).join("\n\n");
|
|
2441
3023
|
}
|
|
2442
|
-
function
|
|
3024
|
+
function formatBasetenReport(lines, report2) {
|
|
3025
|
+
lines.push(`${"Spend window:".padEnd(VALUE_COLUMN)}Last 30 days`);
|
|
3026
|
+
for (const metric2 of report2.metrics) {
|
|
3027
|
+
lines.push(`${`${metric2.label}:`.padEnd(VALUE_COLUMN)}USD ${metric2.value}`);
|
|
3028
|
+
}
|
|
3029
|
+
}
|
|
3030
|
+
function formatBasetenStatusline(report2) {
|
|
3031
|
+
const subtotal = report2.metrics.find((metric2) => metric2.id === "net-subtotal");
|
|
3032
|
+
return subtotal ? `baseten USD ${subtotal.value} net` : "baseten no Model APIs usage";
|
|
3033
|
+
}
|
|
3034
|
+
function formatCodexReport(lines, report2) {
|
|
2443
3035
|
let previousGroup;
|
|
2444
|
-
for (const bucket of
|
|
3036
|
+
for (const bucket of report2.buckets) {
|
|
2445
3037
|
const group = bucket.groupId ?? bucket.id;
|
|
2446
3038
|
if (group !== previousGroup && group !== "codex") {
|
|
2447
3039
|
lines.push(`${bucket.groupLabel ?? group} limit:`);
|
|
@@ -2451,66 +3043,75 @@ function formatCodexReport(lines, report) {
|
|
|
2451
3043
|
const label = `${formatWindowLabel(bucket.windowMinutes, fallback, false)} limit:`;
|
|
2452
3044
|
lines.push(`${label.padEnd(VALUE_COLUMN)}${formatPercentBucket(bucket)}`);
|
|
2453
3045
|
}
|
|
2454
|
-
for (const
|
|
2455
|
-
if (
|
|
2456
|
-
lines.push(`${"Usage limit resets:".padEnd(VALUE_COLUMN)}${
|
|
2457
|
-
} else if (
|
|
3046
|
+
for (const metric2 of report2.metrics) {
|
|
3047
|
+
if (metric2.id === "reset-credits") {
|
|
3048
|
+
lines.push(`${"Usage limit resets:".padEnd(VALUE_COLUMN)}${metric2.value} available`);
|
|
3049
|
+
} else if (metric2.id === "credits") {
|
|
2458
3050
|
lines.push(
|
|
2459
|
-
`${"Credits:".padEnd(VALUE_COLUMN)}${formatMetricValue(
|
|
3051
|
+
`${"Credits:".padEnd(VALUE_COLUMN)}${formatMetricValue(metric2.value, metric2.unit)}`
|
|
2460
3052
|
);
|
|
2461
3053
|
}
|
|
2462
3054
|
}
|
|
2463
3055
|
}
|
|
2464
|
-
function formatDeepSeekReport(lines,
|
|
2465
|
-
const availability =
|
|
3056
|
+
function formatDeepSeekReport(lines, report2) {
|
|
3057
|
+
const availability = report2.metrics.find((metric2) => metric2.id === "api-availability");
|
|
2466
3058
|
lines.push(
|
|
2467
3059
|
`${"API calls:".padEnd(VALUE_COLUMN)}${availability?.value === "available" ? "Available" : "Unavailable"}`
|
|
2468
3060
|
);
|
|
2469
3061
|
for (const currency of ["CNY", "USD"]) {
|
|
2470
|
-
const metrics =
|
|
3062
|
+
const metrics = report2.metrics.filter((metric2) => metric2.currency === currency);
|
|
2471
3063
|
if (metrics.length === 0) continue;
|
|
2472
3064
|
lines.push("", `${currency} balance:`);
|
|
2473
|
-
for (const
|
|
2474
|
-
lines.push(`${`${
|
|
3065
|
+
for (const metric2 of metrics) {
|
|
3066
|
+
lines.push(`${`${metric2.label}:`.padEnd(VALUE_COLUMN)}${currency} ${metric2.value}`);
|
|
2475
3067
|
}
|
|
2476
3068
|
}
|
|
2477
3069
|
}
|
|
2478
|
-
function formatDeepSeekStatusline(
|
|
2479
|
-
const availability =
|
|
3070
|
+
function formatDeepSeekStatusline(report2) {
|
|
3071
|
+
const availability = report2.metrics.find((metric2) => metric2.id === "api-availability");
|
|
2480
3072
|
if (availability?.value !== "available") return "deepseek API unavailable";
|
|
2481
3073
|
const totals = ["CNY", "USD"].flatMap((currency) => {
|
|
2482
|
-
const
|
|
3074
|
+
const metric2 = report2.metrics.find(
|
|
2483
3075
|
(candidate) => candidate.id === `${currency.toLowerCase()}-total`
|
|
2484
3076
|
);
|
|
2485
|
-
return
|
|
3077
|
+
return metric2 ? [`${currency} ${metric2.value}`] : [];
|
|
2486
3078
|
});
|
|
2487
3079
|
return totals.length > 0 ? `deepseek ${totals.join(" \xB7 ")}` : "deepseek balance unavailable";
|
|
2488
3080
|
}
|
|
2489
|
-
function formatFireworksReport(lines,
|
|
3081
|
+
function formatFireworksReport(lines, report2) {
|
|
2490
3082
|
lines.push(`${"Spend window:".padEnd(VALUE_COLUMN)}Last 30 days (rated)`);
|
|
2491
|
-
for (const currency of fireworksCurrencies(
|
|
3083
|
+
for (const currency of fireworksCurrencies(report2)) {
|
|
2492
3084
|
lines.push("", `${currency} rated spend:`);
|
|
2493
|
-
for (const
|
|
2494
|
-
if (
|
|
2495
|
-
lines.push(`${`${
|
|
3085
|
+
for (const metric2 of report2.metrics) {
|
|
3086
|
+
if (metric2.currency !== currency) continue;
|
|
3087
|
+
lines.push(`${`${metric2.label}:`.padEnd(VALUE_COLUMN)}${currency} ${metric2.value}`);
|
|
2496
3088
|
}
|
|
2497
3089
|
}
|
|
2498
3090
|
}
|
|
2499
|
-
function formatFireworksStatusline(
|
|
2500
|
-
const totals =
|
|
3091
|
+
function formatFireworksStatusline(report2) {
|
|
3092
|
+
const totals = report2.metrics.filter((metric2) => metric2.id.endsWith("-total"));
|
|
2501
3093
|
if (totals.length === 0) return "fireworks no rated usage";
|
|
2502
|
-
return `fireworks ${totals.map((
|
|
3094
|
+
return `fireworks ${totals.map((metric2) => `${metric2.currency} ${metric2.value}`).join(" \xB7 ")}`;
|
|
2503
3095
|
}
|
|
2504
|
-
function fireworksCurrencies(
|
|
3096
|
+
function fireworksCurrencies(report2) {
|
|
2505
3097
|
const currencies = [];
|
|
2506
|
-
for (const
|
|
2507
|
-
if (!
|
|
2508
|
-
currencies.push(
|
|
3098
|
+
for (const metric2 of report2.metrics) {
|
|
3099
|
+
if (!metric2.currency || currencies.includes(metric2.currency)) continue;
|
|
3100
|
+
currencies.push(metric2.currency);
|
|
2509
3101
|
}
|
|
2510
3102
|
return currencies;
|
|
2511
3103
|
}
|
|
2512
|
-
function
|
|
2513
|
-
const
|
|
3104
|
+
function formatVercelAIGatewayReport(lines, report2) {
|
|
3105
|
+
for (const metric2 of report2.metrics) {
|
|
3106
|
+
lines.push(`${`${metric2.label}:`.padEnd(VALUE_COLUMN)}USD ${metric2.value}`);
|
|
3107
|
+
}
|
|
3108
|
+
}
|
|
3109
|
+
function formatVercelAIGatewayStatusline(report2) {
|
|
3110
|
+
const balance = report2.metrics.find((metric2) => metric2.id === "credit-balance");
|
|
3111
|
+
return balance ? `vercel USD ${balance.value} left` : "vercel credits unavailable";
|
|
3112
|
+
}
|
|
3113
|
+
function formatGitHubCopilotReport(lines, report2) {
|
|
3114
|
+
const quota = findGitHubCopilotQuota(report2);
|
|
2514
3115
|
if (!quota || quota.limit === void 0 || quota.remaining === void 0) {
|
|
2515
3116
|
lines.push(`${`${quota?.label ?? "Copilot quota"}:`.padEnd(VALUE_COLUMN)}unlimited`);
|
|
2516
3117
|
return;
|
|
@@ -2520,23 +3121,23 @@ function formatGitHubCopilotReport(lines, report) {
|
|
|
2520
3121
|
lines.push(
|
|
2521
3122
|
`${`${quota.label}:`.padEnd(VALUE_COLUMN)}${quota.remaining} of ${quota.limit} left \xB7 ${percent}%${reset}`
|
|
2522
3123
|
);
|
|
2523
|
-
const overage =
|
|
3124
|
+
const overage = report2.metrics.find((metric2) => metric2.id === "overage-used");
|
|
2524
3125
|
if (typeof overage?.value === "number" && overage.value > 0) {
|
|
2525
3126
|
lines.push(`${"Additional usage:".padEnd(VALUE_COLUMN)}${overage.value} ${quota.label}`);
|
|
2526
3127
|
}
|
|
2527
3128
|
}
|
|
2528
|
-
function formatGitHubCopilotStatusline(
|
|
2529
|
-
const quota = findGitHubCopilotQuota(
|
|
3129
|
+
function formatGitHubCopilotStatusline(report2) {
|
|
3130
|
+
const quota = findGitHubCopilotQuota(report2);
|
|
2530
3131
|
const kind = compactGitHubCopilotQuotaKind(quota);
|
|
2531
3132
|
if (!quota || quota.limit === void 0 || quota.remaining === void 0) {
|
|
2532
3133
|
return `copilot ${kind} unlimited`;
|
|
2533
3134
|
}
|
|
2534
|
-
const overage =
|
|
3135
|
+
const overage = report2.metrics.find((metric2) => metric2.id === "overage-used");
|
|
2535
3136
|
const overageSuffix = typeof overage?.value === "number" && overage.value > 0 ? ` +${overage.value} over` : "";
|
|
2536
3137
|
return `copilot ${kind === "premium" ? "" : `${kind} `}${quota.remaining}/${quota.limit} ${percentRemaining(quota)}%${overageSuffix}`;
|
|
2537
3138
|
}
|
|
2538
|
-
function findGitHubCopilotQuota(
|
|
2539
|
-
return
|
|
3139
|
+
function findGitHubCopilotQuota(report2) {
|
|
3140
|
+
return report2.buckets.find(
|
|
2540
3141
|
(bucket) => ["ai-credits", "premium-requests", "chat-requests"].includes(bucket.id)
|
|
2541
3142
|
);
|
|
2542
3143
|
}
|
|
@@ -2549,37 +3150,41 @@ function percentRemaining(bucket) {
|
|
|
2549
3150
|
if (!bucket.limit || bucket.remaining === void 0) return 0;
|
|
2550
3151
|
return Math.round(clampPercent4(bucket.remaining / bucket.limit * 100));
|
|
2551
3152
|
}
|
|
2552
|
-
function formatOpenRouterReport(lines,
|
|
2553
|
-
const limit =
|
|
3153
|
+
function formatOpenRouterReport(lines, report2) {
|
|
3154
|
+
const limit = report2.buckets.find((bucket) => bucket.id === "key-limit");
|
|
2554
3155
|
if (limit) {
|
|
2555
3156
|
const period = limit.period ? ` (${limit.period})` : "";
|
|
2556
3157
|
const value = limit.remaining === void 0 ? `${formatUsd(limit.limit ?? 0)} cap; remaining unavailable` : `${formatUsd(limit.remaining)} of ${formatUsd(limit.limit ?? 0)} left`;
|
|
2557
3158
|
lines.push(`${`Key limit${period}:`.padEnd(VALUE_COLUMN)}${value}`);
|
|
2558
3159
|
}
|
|
2559
|
-
for (const
|
|
3160
|
+
for (const metric2 of report2.metrics) {
|
|
2560
3161
|
lines.push(
|
|
2561
|
-
`${`${
|
|
3162
|
+
`${`${metric2.label}:`.padEnd(VALUE_COLUMN)}${formatMetricValue(metric2.value, metric2.unit)}`
|
|
2562
3163
|
);
|
|
2563
3164
|
}
|
|
2564
3165
|
}
|
|
2565
|
-
function formatOpenCodeZenReport(lines,
|
|
2566
|
-
for (const bucket of
|
|
3166
|
+
function formatOpenCodeZenReport(lines, report2) {
|
|
3167
|
+
for (const bucket of report2.buckets) {
|
|
3168
|
+
if (bucket.unit === "percent" && bucket.used !== void 0) {
|
|
3169
|
+
lines.push(`${`${bucket.label}:`.padEnd(VALUE_COLUMN)}${formatPercentBucket(bucket)}`);
|
|
3170
|
+
continue;
|
|
3171
|
+
}
|
|
2567
3172
|
const reset = bucket.resetsAt ? ` (resets ${formatReset(bucket.resetsAt)})` : "";
|
|
2568
3173
|
const used = bucket.used ?? "unavailable";
|
|
2569
3174
|
lines.push(`${`${bucket.label}:`.padEnd(VALUE_COLUMN)}${used}% used${reset}`);
|
|
2570
3175
|
}
|
|
2571
3176
|
}
|
|
2572
|
-
function formatOpenCodeZenStatusline(
|
|
3177
|
+
function formatOpenCodeZenStatusline(report2) {
|
|
2573
3178
|
const parts = ["zen"];
|
|
2574
|
-
for (const bucket of
|
|
3179
|
+
for (const bucket of report2.buckets) {
|
|
2575
3180
|
if (bucket.used === void 0) continue;
|
|
2576
3181
|
const compact = bucket.id === "rolling" ? "r" : bucket.id === "weekly" ? "w" : "m";
|
|
2577
3182
|
parts.push(`${clampPercent4(bucket.used).toFixed(0)}% ${compact}`);
|
|
2578
3183
|
}
|
|
2579
3184
|
return parts.length > 1 ? parts.join(" ") : void 0;
|
|
2580
3185
|
}
|
|
2581
|
-
function formatKimiCodingReport(lines,
|
|
2582
|
-
for (const bucket of
|
|
3186
|
+
function formatKimiCodingReport(lines, report2) {
|
|
3187
|
+
for (const bucket of report2.buckets) {
|
|
2583
3188
|
const reset = bucket.resetsAt ? ` (resets ${formatReset(bucket.resetsAt)})` : "";
|
|
2584
3189
|
if (bucket.used === void 0 || bucket.limit === void 0) {
|
|
2585
3190
|
lines.push(`${`${bucket.label}:`.padEnd(VALUE_COLUMN)}unavailable${reset}`);
|
|
@@ -2589,10 +3194,10 @@ function formatKimiCodingReport(lines, report) {
|
|
|
2589
3194
|
`${`${bucket.label}:`.padEnd(VALUE_COLUMN)}${bucket.used} of ${bucket.limit} used \xB7 ${percentRemaining(bucket)}% left${reset}`
|
|
2590
3195
|
);
|
|
2591
3196
|
}
|
|
2592
|
-
const balance =
|
|
2593
|
-
const total =
|
|
2594
|
-
const monthlyUsed =
|
|
2595
|
-
const monthlyLimit =
|
|
3197
|
+
const balance = report2.metrics.find((metric2) => metric2.id === "booster-balance");
|
|
3198
|
+
const total = report2.metrics.find((metric2) => metric2.id === "booster-total");
|
|
3199
|
+
const monthlyUsed = report2.metrics.find((metric2) => metric2.id === "booster-monthly-used");
|
|
3200
|
+
const monthlyLimit = report2.metrics.find((metric2) => metric2.id === "booster-monthly-limit");
|
|
2596
3201
|
if (!balance && !monthlyUsed && !monthlyLimit) return;
|
|
2597
3202
|
lines.push("", "Extra usage wallet:");
|
|
2598
3203
|
if (balance) {
|
|
@@ -2606,10 +3211,10 @@ function formatKimiCodingReport(lines, report) {
|
|
|
2606
3211
|
lines.push(`${"Monthly limit:".padEnd(VALUE_COLUMN)}${formatCurrencyMetric(monthlyLimit)}`);
|
|
2607
3212
|
}
|
|
2608
3213
|
}
|
|
2609
|
-
function formatKimiCodingStatusline(
|
|
2610
|
-
const fiveHour =
|
|
2611
|
-
const weekly =
|
|
2612
|
-
const subWindow = fiveHour ??
|
|
3214
|
+
function formatKimiCodingStatusline(report2) {
|
|
3215
|
+
const fiveHour = report2.buckets.find((bucket) => bucket.id === "five-hour");
|
|
3216
|
+
const weekly = report2.buckets.find((bucket) => bucket.id === "weekly");
|
|
3217
|
+
const subWindow = fiveHour ?? report2.buckets.find((bucket) => bucket.id !== "weekly");
|
|
2613
3218
|
const selected = [subWindow, weekly].filter(
|
|
2614
3219
|
(bucket, index, buckets) => bucket !== void 0 && buckets.indexOf(bucket) === index
|
|
2615
3220
|
);
|
|
@@ -2623,10 +3228,98 @@ function formatKimiCodingStatusline(report) {
|
|
|
2623
3228
|
}
|
|
2624
3229
|
return parts.length > 1 ? parts.join(" ") : void 0;
|
|
2625
3230
|
}
|
|
2626
|
-
function
|
|
3231
|
+
function formatMoonshotReport(lines, report2) {
|
|
3232
|
+
for (const metric2 of report2.metrics) {
|
|
3233
|
+
lines.push(`${`${metric2.label}:`.padEnd(VALUE_COLUMN)}${metric2.currency} ${metric2.value}`);
|
|
3234
|
+
}
|
|
3235
|
+
}
|
|
3236
|
+
function formatMoonshotStatusline(report2) {
|
|
3237
|
+
const available = report2.metrics.find((metric2) => metric2.id === "available-balance");
|
|
3238
|
+
if (!available) return "moonshot balance unavailable";
|
|
3239
|
+
return `moonshot ${available.currency ?? ""} ${available.value}`.replace(/\s+/gu, " ");
|
|
3240
|
+
}
|
|
3241
|
+
function formatMiniMaxReport(lines, report2) {
|
|
3242
|
+
if (report2.source === "minimax-account-balance") {
|
|
3243
|
+
for (const metric2 of report2.metrics) {
|
|
3244
|
+
lines.push(`${`${metric2.label}:`.padEnd(VALUE_COLUMN)}${metric2.currency} ${metric2.value}`);
|
|
3245
|
+
}
|
|
3246
|
+
return;
|
|
3247
|
+
}
|
|
3248
|
+
let previousGroup;
|
|
3249
|
+
for (const bucket of report2.buckets) {
|
|
3250
|
+
if (bucket.groupId !== previousGroup) lines.push(`${bucket.groupLabel ?? "Token Plan"}:`);
|
|
3251
|
+
previousGroup = bucket.groupId;
|
|
3252
|
+
const reset = bucket.resetsAt ? ` (resets ${formatReset(bucket.resetsAt)})` : "";
|
|
3253
|
+
const value = bucket.period === "unlimited" ? "unlimited" : bucket.limit && bucket.remaining !== void 0 ? `${bucket.remaining} of ${bucket.limit} left \xB7 ${percentRemaining(bucket)}%${reset}` : "unavailable";
|
|
3254
|
+
lines.push(`${`${bucket.label}:`.padEnd(VALUE_COLUMN)}${value}`);
|
|
3255
|
+
}
|
|
3256
|
+
}
|
|
3257
|
+
function formatMiniMaxStatusline(report2, model) {
|
|
3258
|
+
const prefix = report2.providerId === "minimax-cn" ? "minimax cn" : "minimax";
|
|
3259
|
+
if (report2.source === "minimax-account-balance") {
|
|
3260
|
+
const available = report2.metrics.find((metric2) => metric2.id === "available-balance");
|
|
3261
|
+
return available ? `${prefix} ${available.currency} ${available.value}` : void 0;
|
|
3262
|
+
}
|
|
3263
|
+
const selectedGroup = selectMiniMaxGroup(report2, model);
|
|
3264
|
+
if (!selectedGroup) return void 0;
|
|
3265
|
+
const selected = report2.buckets.filter((bucket) => bucket.groupId === selectedGroup);
|
|
3266
|
+
const parts = [prefix];
|
|
3267
|
+
for (const bucket of selected) {
|
|
3268
|
+
const fallback = bucket.id.endsWith(":weekly") ? "weekly" : "5h";
|
|
3269
|
+
const window = formatWindowLabel(bucket.windowMinutes, fallback, true);
|
|
3270
|
+
if (bucket.period === "unlimited") {
|
|
3271
|
+
parts.push(`unlimited ${window}`);
|
|
3272
|
+
continue;
|
|
3273
|
+
}
|
|
3274
|
+
if (!bucket.limit || bucket.remaining === void 0) continue;
|
|
3275
|
+
parts.push(`${percentRemaining(bucket)}% ${window}`);
|
|
3276
|
+
}
|
|
3277
|
+
return parts.length > 1 ? parts.join(" ") : void 0;
|
|
3278
|
+
}
|
|
3279
|
+
function selectMiniMaxGroup(report2, model) {
|
|
3280
|
+
const groups = [
|
|
3281
|
+
...new Set(
|
|
3282
|
+
report2.buckets.map((bucket) => bucket.groupId).filter((group) => group !== void 0)
|
|
3283
|
+
)
|
|
3284
|
+
];
|
|
3285
|
+
if (groups.length <= 1) return groups[0];
|
|
3286
|
+
if (model?.provider !== report2.providerId) return void 0;
|
|
3287
|
+
const modelKeys = [model.id, model.name].map(normalizeMiniMaxModelKey).filter((key) => key !== void 0);
|
|
3288
|
+
const candidates = groups.map((group) => {
|
|
3289
|
+
const bucket = report2.buckets.find((candidate) => candidate.groupId === group);
|
|
3290
|
+
const patterns = [bucket?.groupLabel, ...bucket?.modelKeys ?? [], group].map(normalizeMiniMaxModelKey).filter((key) => key !== void 0);
|
|
3291
|
+
return { group, patterns };
|
|
3292
|
+
});
|
|
3293
|
+
const exact = candidates.find(
|
|
3294
|
+
({ patterns }) => patterns.some((pattern) => !pattern.includes("*") && modelKeys.includes(pattern))
|
|
3295
|
+
);
|
|
3296
|
+
if (exact) return exact.group;
|
|
3297
|
+
return candidates.find(
|
|
3298
|
+
({ patterns }) => patterns.some(
|
|
3299
|
+
(pattern) => pattern.includes("*") && modelKeys.some((key) => wildcardKeyMatches(pattern, key))
|
|
3300
|
+
)
|
|
3301
|
+
)?.group;
|
|
3302
|
+
}
|
|
3303
|
+
function normalizeMiniMaxModelKey(value) {
|
|
3304
|
+
const key = value?.toLowerCase().replace(/[^a-z0-9*]+/gu, "");
|
|
3305
|
+
return key && /[a-z0-9]/u.test(key) ? key : void 0;
|
|
3306
|
+
}
|
|
3307
|
+
function wildcardKeyMatches(pattern, value) {
|
|
3308
|
+
if (!pattern.includes("*")) return pattern === value;
|
|
3309
|
+
const segments = pattern.split("*").filter(Boolean);
|
|
3310
|
+
let offset = 0;
|
|
3311
|
+
for (const [index, segment] of segments.entries()) {
|
|
3312
|
+
const found = value.indexOf(segment, offset);
|
|
3313
|
+
if (found < 0 || index === 0 && !pattern.startsWith("*") && found !== 0) return false;
|
|
3314
|
+
offset = found + segment.length;
|
|
3315
|
+
}
|
|
3316
|
+
const last = segments.at(-1);
|
|
3317
|
+
return pattern.endsWith("*") || last !== void 0 && value.endsWith(last);
|
|
3318
|
+
}
|
|
3319
|
+
function formatZaiStatusline(report2) {
|
|
2627
3320
|
const selected = [
|
|
2628
|
-
|
|
2629
|
-
|
|
3321
|
+
report2.buckets.find((bucket) => bucket.id === "five-hour"),
|
|
3322
|
+
report2.buckets.find((bucket) => bucket.id === "weekly")
|
|
2630
3323
|
];
|
|
2631
3324
|
const parts = ["zai"];
|
|
2632
3325
|
for (const bucket of selected) {
|
|
@@ -2638,20 +3331,19 @@ function formatZaiStatusline(report) {
|
|
|
2638
3331
|
}
|
|
2639
3332
|
return parts.length > 1 ? parts.join(" ") : void 0;
|
|
2640
3333
|
}
|
|
2641
|
-
function formatCurrencyMetric(
|
|
2642
|
-
if (typeof
|
|
2643
|
-
if (!
|
|
2644
|
-
if (
|
|
2645
|
-
if (
|
|
2646
|
-
return `${
|
|
3334
|
+
function formatCurrencyMetric(metric2) {
|
|
3335
|
+
if (typeof metric2.value !== "number") return String(metric2.value);
|
|
3336
|
+
if (!metric2.currency) return "unavailable";
|
|
3337
|
+
if (metric2.currency === "USD") return `$${metric2.value.toFixed(2)}`;
|
|
3338
|
+
if (metric2.currency === "CNY") return `\xA5${metric2.value.toFixed(2)}`;
|
|
3339
|
+
return `${metric2.value.toFixed(2)} ${metric2.currency}`;
|
|
2647
3340
|
}
|
|
2648
|
-
function formatXaiReport(lines,
|
|
2649
|
-
const included =
|
|
3341
|
+
function formatXaiReport(lines, report2) {
|
|
3342
|
+
const included = report2.buckets.find((bucket) => bucket.id === "included-allowance");
|
|
2650
3343
|
if (included) {
|
|
2651
3344
|
let value = "unavailable";
|
|
2652
3345
|
if (included.unit === "percent" && included.used !== void 0) {
|
|
2653
|
-
value =
|
|
2654
|
-
if (included.remaining !== void 0) value += ` \xB7 ${included.remaining}% left`;
|
|
3346
|
+
value = formatPercentBar(included);
|
|
2655
3347
|
} else if (included.used !== void 0) {
|
|
2656
3348
|
value = `${formatUsd(included.used)} used`;
|
|
2657
3349
|
if (included.limit !== void 0) value += ` of ${formatUsd(included.limit)}`;
|
|
@@ -2662,26 +3354,27 @@ function formatXaiReport(lines, report) {
|
|
|
2662
3354
|
const reset = included.resetsAt ? ` (resets ${formatReset(included.resetsAt)})` : "";
|
|
2663
3355
|
lines.push(`${"Included allowance:".padEnd(VALUE_COLUMN)}${value}${period}${reset}`);
|
|
2664
3356
|
}
|
|
2665
|
-
const onDemand =
|
|
3357
|
+
const onDemand = report2.buckets.find((bucket) => bucket.id === "on-demand");
|
|
2666
3358
|
if (onDemand) {
|
|
2667
3359
|
let value = onDemand.used === void 0 ? "usage unavailable" : `${formatUsd(onDemand.used)} used`;
|
|
2668
3360
|
if (onDemand.limit !== void 0) value += ` of ${formatUsd(onDemand.limit)} cap`;
|
|
2669
3361
|
lines.push(`${"On-demand usage:".padEnd(VALUE_COLUMN)}${value}`);
|
|
2670
3362
|
}
|
|
2671
|
-
for (const
|
|
3363
|
+
for (const metric2 of report2.metrics) {
|
|
2672
3364
|
lines.push(
|
|
2673
|
-
`${`${
|
|
3365
|
+
`${`${metric2.label}:`.padEnd(VALUE_COLUMN)}${formatMetricValue(metric2.value, metric2.unit)}`
|
|
2674
3366
|
);
|
|
2675
3367
|
}
|
|
2676
3368
|
}
|
|
2677
|
-
function formatZaiReport(lines,
|
|
2678
|
-
for (const bucket of
|
|
3369
|
+
function formatZaiReport(lines, report2) {
|
|
3370
|
+
for (const bucket of report2.buckets) {
|
|
3371
|
+
if (bucket.unit === "percent" && bucket.used !== void 0) {
|
|
3372
|
+
lines.push(`${`${bucket.label}:`.padEnd(VALUE_COLUMN)}${formatPercentBucket(bucket)}`);
|
|
3373
|
+
continue;
|
|
3374
|
+
}
|
|
2679
3375
|
const reset = bucket.resetsAt ? ` (resets ${formatReset(bucket.resetsAt)})` : "";
|
|
2680
3376
|
let value = "unavailable";
|
|
2681
|
-
if (bucket.
|
|
2682
|
-
value = `${bucket.used}% used`;
|
|
2683
|
-
if (bucket.remaining !== void 0) value += ` \xB7 ${bucket.remaining}% left`;
|
|
2684
|
-
} else if (bucket.used !== void 0 && bucket.limit !== void 0) {
|
|
3377
|
+
if (bucket.used !== void 0 && bucket.limit !== void 0) {
|
|
2685
3378
|
value = `${bucket.used} of ${bucket.limit} used`;
|
|
2686
3379
|
if (bucket.remaining !== void 0) value += ` \xB7 ${bucket.remaining} left`;
|
|
2687
3380
|
} else if (bucket.used !== void 0) {
|
|
@@ -2691,28 +3384,28 @@ function formatZaiReport(lines, report) {
|
|
|
2691
3384
|
}
|
|
2692
3385
|
lines.push(`${`${bucket.label}:`.padEnd(VALUE_COLUMN)}${value}${reset}`);
|
|
2693
3386
|
}
|
|
2694
|
-
for (const
|
|
3387
|
+
for (const metric2 of report2.metrics) {
|
|
2695
3388
|
lines.push(
|
|
2696
|
-
`${`${
|
|
3389
|
+
`${`${metric2.label}:`.padEnd(VALUE_COLUMN)}${formatMetricValue(metric2.value, metric2.unit)}`
|
|
2697
3390
|
);
|
|
2698
3391
|
}
|
|
2699
3392
|
}
|
|
2700
|
-
function formatGenericReport(lines,
|
|
2701
|
-
for (const bucket of
|
|
3393
|
+
function formatGenericReport(lines, report2) {
|
|
3394
|
+
for (const bucket of report2.buckets) {
|
|
2702
3395
|
lines.push(
|
|
2703
3396
|
`${`${bucket.label}:`.padEnd(VALUE_COLUMN)}${formatMetricValue(bucket.remaining ?? bucket.used ?? "unavailable", bucket.unit)}`
|
|
2704
3397
|
);
|
|
2705
3398
|
}
|
|
2706
|
-
for (const
|
|
3399
|
+
for (const metric2 of report2.metrics) {
|
|
2707
3400
|
lines.push(
|
|
2708
|
-
`${`${
|
|
3401
|
+
`${`${metric2.label}:`.padEnd(VALUE_COLUMN)}${formatMetricValue(metric2.value, metric2.unit)}`
|
|
2709
3402
|
);
|
|
2710
3403
|
}
|
|
2711
3404
|
}
|
|
2712
|
-
function formatCodexStatusline(
|
|
2713
|
-
const group = selectCodexGroup(
|
|
2714
|
-
if (!group) return formatCodexCreditsStatus(
|
|
2715
|
-
const buckets =
|
|
3405
|
+
function formatCodexStatusline(report2, model, now = Date.now(), showResetCountdown = true) {
|
|
3406
|
+
const group = selectCodexGroup(report2, model);
|
|
3407
|
+
if (!group) return formatCodexCreditsStatus(report2);
|
|
3408
|
+
const buckets = report2.buckets.filter((bucket) => (bucket.groupId ?? bucket.id) === group);
|
|
2716
3409
|
const labelBucket = buckets[0];
|
|
2717
3410
|
const parts = [
|
|
2718
3411
|
group === "codex" ? "codex" : `codex ${compactLimitLabel(labelBucket?.groupLabel ?? group)}`
|
|
@@ -2729,24 +3422,24 @@ function formatCodexStatusline(report, model, now = Date.now(), showResetCountdo
|
|
|
2729
3422
|
const reset = formatResetCountdown(bucket.resetsAt, now);
|
|
2730
3423
|
parts.push(`${percent} ${reset ? `\u21BB ${reset}` : window}`);
|
|
2731
3424
|
}
|
|
2732
|
-
return parts.length > 1 ? parts.join(" ") : formatCodexCreditsStatus(
|
|
3425
|
+
return parts.length > 1 ? parts.join(" ") : formatCodexCreditsStatus(report2);
|
|
2733
3426
|
}
|
|
2734
|
-
function formatCodexCreditsStatus(
|
|
2735
|
-
const credits =
|
|
3427
|
+
function formatCodexCreditsStatus(report2) {
|
|
3428
|
+
const credits = report2.metrics.find((metric2) => metric2.id === "credits");
|
|
2736
3429
|
if (!credits) return "codex usage unavailable";
|
|
2737
3430
|
if (credits.value === "none") return "codex no credits";
|
|
2738
3431
|
if (credits.value === "available") return "codex credits available";
|
|
2739
3432
|
if (credits.value === "unlimited") return "codex credits unlimited";
|
|
2740
3433
|
return `codex ${formatMetricValue(credits.value, "count")} credits`;
|
|
2741
3434
|
}
|
|
2742
|
-
function selectCodexGroup(
|
|
2743
|
-
const groups = [...new Set(
|
|
3435
|
+
function selectCodexGroup(report2, model) {
|
|
3436
|
+
const groups = [...new Set(report2.buckets.map((bucket) => bucket.groupId ?? bucket.id))];
|
|
2744
3437
|
if (model?.provider !== "openai-codex") {
|
|
2745
3438
|
return groups.includes("codex") ? "codex" : groups[0];
|
|
2746
3439
|
}
|
|
2747
3440
|
const modelKeys = normalizedModelKeys(model);
|
|
2748
3441
|
for (const group of groups) {
|
|
2749
|
-
const bucket =
|
|
3442
|
+
const bucket = report2.buckets.find(
|
|
2750
3443
|
(candidate) => (candidate.groupId ?? candidate.id) === group
|
|
2751
3444
|
);
|
|
2752
3445
|
const keys = [group, bucket?.groupLabel, ...bucket?.modelKeys ?? []].map(normalizeKey).filter((key) => key !== void 0);
|
|
@@ -2793,10 +3486,12 @@ function compactLimitLabel(label) {
|
|
|
2793
3486
|
return (suffix || normalized).toLowerCase().replace(/\s+/g, " ");
|
|
2794
3487
|
}
|
|
2795
3488
|
function formatPercentBucket(bucket) {
|
|
3489
|
+
return `${formatPercentBar(bucket)}${bucket.resetsAt ? ` (resets ${formatReset(bucket.resetsAt)})` : ""}`;
|
|
3490
|
+
}
|
|
3491
|
+
function formatPercentBar(bucket) {
|
|
2796
3492
|
const remaining = clampPercent4(bucket.remaining ?? 0);
|
|
2797
3493
|
const filled = Math.round(remaining / 100 * BAR_SEGMENTS);
|
|
2798
|
-
|
|
2799
|
-
return `[${"\u2588".repeat(filled)}${"\u2591".repeat(BAR_SEGMENTS - filled)}] ${remaining.toFixed(0)}% left${reset}`;
|
|
3494
|
+
return `[${"\u2588".repeat(filled)}${"\u2591".repeat(BAR_SEGMENTS - filled)}] ${remaining.toFixed(0)}% left`;
|
|
2800
3495
|
}
|
|
2801
3496
|
function formatWindowLabel(minutes, fallback, compact) {
|
|
2802
3497
|
if (!minutes || !Number.isFinite(minutes) || minutes <= 0) {
|
|
@@ -3492,9 +4187,7 @@ function usageExtension(pi, dependencies = {}) {
|
|
|
3492
4187
|
const generation = statusGeneration;
|
|
3493
4188
|
statusCountdownTimer = setTimeout(() => {
|
|
3494
4189
|
statusCountdownTimer = void 0;
|
|
3495
|
-
if (!sessionActive || generation !== statusGeneration
|
|
3496
|
-
return;
|
|
3497
|
-
}
|
|
4190
|
+
if (!sessionActive || generation !== statusGeneration) return;
|
|
3498
4191
|
publishStatus(ctx, outcome, model, false);
|
|
3499
4192
|
}, STATUS_COUNTDOWN_REFRESH_MS);
|
|
3500
4193
|
statusCountdownTimer.unref?.();
|
|
@@ -3549,7 +4242,19 @@ function usageExtension(pi, dependencies = {}) {
|
|
|
3549
4242
|
}
|
|
3550
4243
|
};
|
|
3551
4244
|
}
|
|
3552
|
-
const requiresRequestBoundaryGuard = [
|
|
4245
|
+
const requiresRequestBoundaryGuard = [
|
|
4246
|
+
"baseten",
|
|
4247
|
+
"deepseek",
|
|
4248
|
+
"fireworks",
|
|
4249
|
+
"minimax",
|
|
4250
|
+
"minimax-cn",
|
|
4251
|
+
"moonshotai",
|
|
4252
|
+
"moonshotai-cn",
|
|
4253
|
+
"vercel-ai-gateway",
|
|
4254
|
+
"xai",
|
|
4255
|
+
"zai",
|
|
4256
|
+
"zai-coding-cn"
|
|
4257
|
+
].includes(adapter.id);
|
|
3553
4258
|
const requestContextChanged = () => expectedSessionGeneration !== sessionGeneration || ctx.sessionManager.getSessionId() !== expectedSessionId || modelIdentity(ctx.model) !== expectedModelIdentity || adapter.id === "fireworks" && settingsRuntime.get().settings.fireworksAccountId !== expectedFireworksAccountId;
|
|
3554
4259
|
if (requiresRequestBoundaryGuard && requestContextChanged()) throw abortError();
|
|
3555
4260
|
if (!auth) {
|
|
@@ -3602,7 +4307,7 @@ function usageExtension(pi, dependencies = {}) {
|
|
|
3602
4307
|
querySequence += 1;
|
|
3603
4308
|
const queryId = querySequence;
|
|
3604
4309
|
setBoundedMap(latestQueries, failureKey, queryId, MAX_ACCOUNT_STATES);
|
|
3605
|
-
let
|
|
4310
|
+
let retryableAuthChanged = false;
|
|
3606
4311
|
try {
|
|
3607
4312
|
const remainingMs = Math.max(1, deadlineAt - Date.now());
|
|
3608
4313
|
const guard = requiresRequestBoundaryGuard ? async () => {
|
|
@@ -3615,14 +4320,16 @@ function usageExtension(pi, dependencies = {}) {
|
|
|
3615
4320
|
);
|
|
3616
4321
|
if (signal.aborted || requestContextChanged()) throw abortError();
|
|
3617
4322
|
if (revalidated?.fingerprint !== auth.fingerprint) {
|
|
3618
|
-
if (
|
|
3619
|
-
|
|
3620
|
-
throw new Error(
|
|
4323
|
+
if (["deepseek", "minimax", "minimax-cn"].includes(adapter.id)) {
|
|
4324
|
+
retryableAuthChanged = true;
|
|
4325
|
+
throw new Error(
|
|
4326
|
+
`${adapter.displayName} runtime credential changed during the usage query.`
|
|
4327
|
+
);
|
|
3621
4328
|
}
|
|
3622
4329
|
throw abortError();
|
|
3623
4330
|
}
|
|
3624
4331
|
} : void 0;
|
|
3625
|
-
const
|
|
4332
|
+
const report2 = await queryProviderUsage(
|
|
3626
4333
|
adapter,
|
|
3627
4334
|
auth,
|
|
3628
4335
|
signal,
|
|
@@ -3632,7 +4339,7 @@ function usageExtension(pi, dependencies = {}) {
|
|
|
3632
4339
|
);
|
|
3633
4340
|
if (guard) await guard();
|
|
3634
4341
|
if (latestQueries.get(failureKey) === queryId) {
|
|
3635
|
-
cache.set(adapter.id, queryFingerprint,
|
|
4342
|
+
cache.set(adapter.id, queryFingerprint, report2);
|
|
3636
4343
|
failureBackoff.delete(failureKey);
|
|
3637
4344
|
}
|
|
3638
4345
|
return {
|
|
@@ -3641,13 +4348,13 @@ function usageExtension(pi, dependencies = {}) {
|
|
|
3641
4348
|
providerName: adapter.displayName,
|
|
3642
4349
|
displayState,
|
|
3643
4350
|
status: "ready",
|
|
3644
|
-
report
|
|
4351
|
+
report: report2
|
|
3645
4352
|
},
|
|
3646
4353
|
fingerprint: auth.fingerprint
|
|
3647
4354
|
};
|
|
3648
4355
|
} catch (error) {
|
|
3649
4356
|
if (isStaleExtensionContextError(error) || isAbortError3(error)) throw error;
|
|
3650
|
-
if (
|
|
4357
|
+
if (retryableAuthChanged && authRetry === 0 && !signal.aborted && !requestContextChanged() && Date.now() < deadlineAt) {
|
|
3651
4358
|
if (latestQueries.get(failureKey) === queryId) latestQueries.delete(failureKey);
|
|
3652
4359
|
return queryAdapterState(
|
|
3653
4360
|
ctx,
|
|
@@ -4335,6 +5042,8 @@ export {
|
|
|
4335
5042
|
isStaleExtensionContextError,
|
|
4336
5043
|
listCodexResetCredits,
|
|
4337
5044
|
loadUsageSettings,
|
|
5045
|
+
miniMaxUsageKind,
|
|
5046
|
+
normalizeBasetenBillingUsagePayload,
|
|
4338
5047
|
normalizeCodexBackendPayload,
|
|
4339
5048
|
normalizeCodexResetCreditsPayload,
|
|
4340
5049
|
normalizeDeepSeekBalancePayload,
|
|
@@ -4342,11 +5051,15 @@ export {
|
|
|
4342
5051
|
normalizeFireworksBillingSummaryPayload,
|
|
4343
5052
|
normalizeGitHubCopilotUsagePayload,
|
|
4344
5053
|
normalizeKimiCodingUsagePayload,
|
|
5054
|
+
normalizeMiniMaxUsagePayload,
|
|
5055
|
+
normalizeMoonshotBalancePayload,
|
|
4345
5056
|
normalizeOpenCodeZenPayload,
|
|
4346
5057
|
normalizeOpenRouterKeyPayload,
|
|
4347
5058
|
normalizeUsageSettings,
|
|
5059
|
+
normalizeVercelAIGatewayCreditsPayload,
|
|
4348
5060
|
normalizeXaiBillingPayload,
|
|
4349
5061
|
normalizeZaiQuotaPayload,
|
|
5062
|
+
normalizeZaiSubscriptionPayload,
|
|
4350
5063
|
providerIsConfigured,
|
|
4351
5064
|
queryProviderUsage,
|
|
4352
5065
|
redactUsageError,
|