@narumitw/pi-usage 0.57.0 → 0.59.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +118 -2
- package/dist/index.ts +1247 -240
- package/dist/index.ts.map +4 -4
- package/package.json +8 -1
- package/src/codex-fast-runtime.ts +34 -26
- package/src/format.ts +189 -3
- package/src/index.ts +20 -0
- package/src/providers/baseten.ts +55 -0
- package/src/providers/fireworks.ts +198 -0
- package/src/providers/minimax.ts +264 -0
- package/src/providers/moonshot.ts +64 -0
- package/src/providers/vercel-ai-gateway.ts +43 -0
- package/src/query.ts +355 -9
- package/src/settings.ts +16 -1
- package/src/types.ts +44 -0
- package/src/usage-settings-ui.ts +125 -33
- package/src/usage.ts +55 -23
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,21 +552,174 @@ 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
|
|
|
566
|
+
// src/providers/fireworks.ts
|
|
567
|
+
var NANOS_PER_UNIT = 1000000000n;
|
|
568
|
+
var CURRENCY_PATTERN = /^[A-Z]{3}$/u;
|
|
569
|
+
var ACCOUNT_ID_PATTERN = /^[A-Za-z0-9][A-Za-z0-9._~-]{0,127}$/u;
|
|
570
|
+
var INTEGER_PATTERN = /^-?\d+$/u;
|
|
571
|
+
var INT64_MIN = -(2n ** 63n);
|
|
572
|
+
var INT64_MAX = 2n ** 63n - 1n;
|
|
573
|
+
var MAX_UNITS_CHARS = 20;
|
|
574
|
+
var MAX_NANOS_CHARS = 11;
|
|
575
|
+
var SERIES_KEYS = ["serverless", "dedicated", "training", "other"];
|
|
576
|
+
var SERIES_LABELS = {
|
|
577
|
+
serverless: "Serverless",
|
|
578
|
+
dedicated: "Dedicated deployments",
|
|
579
|
+
training: "Training",
|
|
580
|
+
other: "Other"
|
|
581
|
+
};
|
|
582
|
+
function isFireworksAccountId(value) {
|
|
583
|
+
return typeof value === "string" && ACCOUNT_ID_PATTERN.test(value);
|
|
584
|
+
}
|
|
585
|
+
function normalizeFireworksAccountsPayload(payload) {
|
|
586
|
+
if (!Array.isArray(payload.accounts)) {
|
|
587
|
+
throw new Error("Fireworks accounts response did not contain an accounts array.");
|
|
588
|
+
}
|
|
589
|
+
const accounts = [];
|
|
590
|
+
for (const raw of payload.accounts) {
|
|
591
|
+
const account = asObject4(raw);
|
|
592
|
+
if (!account) throw new Error("Fireworks accounts response row was not an object.");
|
|
593
|
+
if (typeof account.name !== "string") {
|
|
594
|
+
throw new Error("Fireworks accounts response omitted the account resource name.");
|
|
595
|
+
}
|
|
596
|
+
const match = /^accounts\/([^/]+)$/u.exec(account.name);
|
|
597
|
+
if (!match || !isFireworksAccountId(match[1])) {
|
|
598
|
+
throw new Error("Fireworks accounts response returned an unsafe account resource name.");
|
|
599
|
+
}
|
|
600
|
+
const accountId = match[1];
|
|
601
|
+
if (accounts.includes(accountId)) {
|
|
602
|
+
throw new Error(`Fireworks accounts response repeated ${accountId}.`);
|
|
603
|
+
}
|
|
604
|
+
accounts.push(accountId);
|
|
605
|
+
}
|
|
606
|
+
return accounts;
|
|
607
|
+
}
|
|
608
|
+
function normalizeFireworksBillingSummaryPayload(payload, accountId, capturedAt) {
|
|
609
|
+
if (!isFireworksAccountId(accountId)) {
|
|
610
|
+
throw new Error("Fireworks billing summary received an unsafe account identifier.");
|
|
611
|
+
}
|
|
612
|
+
if (payload.lineItems !== void 0 && !Array.isArray(payload.lineItems)) {
|
|
613
|
+
throw new Error("Fireworks billing summary lineItems was not an array.");
|
|
614
|
+
}
|
|
615
|
+
const totals = /* @__PURE__ */ new Map();
|
|
616
|
+
for (const raw of payload.lineItems ?? []) {
|
|
617
|
+
const lineItem = asObject4(raw);
|
|
618
|
+
if (!lineItem) throw new Error("Fireworks billing line item was not an object.");
|
|
619
|
+
const cost = moneyAmount(lineItem.totalCost, "line item total cost");
|
|
620
|
+
const series = seriesKey(lineItem.series);
|
|
621
|
+
let amounts = totals.get(cost.currency);
|
|
622
|
+
if (!amounts) {
|
|
623
|
+
amounts = /* @__PURE__ */ new Map();
|
|
624
|
+
totals.set(cost.currency, amounts);
|
|
625
|
+
}
|
|
626
|
+
amounts.set(series, (amounts.get(series) ?? 0n) + cost.amount);
|
|
627
|
+
}
|
|
628
|
+
const metrics = [];
|
|
629
|
+
for (const [currency, amounts] of totals) {
|
|
630
|
+
metrics.push({
|
|
631
|
+
id: `${currency.toLowerCase()}-total`,
|
|
632
|
+
label: "Total spend",
|
|
633
|
+
value: formatMoneyAmount(sumSeries(amounts)),
|
|
634
|
+
unit: "currency",
|
|
635
|
+
currency
|
|
636
|
+
});
|
|
637
|
+
for (const series of SERIES_KEYS) {
|
|
638
|
+
const amount2 = amounts.get(series);
|
|
639
|
+
if (amount2 === void 0) continue;
|
|
640
|
+
metrics.push({
|
|
641
|
+
id: `${currency.toLowerCase()}-${series}`,
|
|
642
|
+
label: SERIES_LABELS[series],
|
|
643
|
+
value: formatMoneyAmount(amount2),
|
|
644
|
+
unit: "currency",
|
|
645
|
+
currency
|
|
646
|
+
});
|
|
647
|
+
}
|
|
648
|
+
}
|
|
649
|
+
const notes = [
|
|
650
|
+
"Rated line items may differ from the final invoice once credits or adjustments are applied."
|
|
651
|
+
];
|
|
652
|
+
if (metrics.length === 0) {
|
|
653
|
+
notes.push("Fireworks returned no rated line items for the last 30 days.");
|
|
654
|
+
}
|
|
655
|
+
return {
|
|
656
|
+
providerId: "fireworks",
|
|
657
|
+
providerName: "Fireworks",
|
|
658
|
+
capturedAt,
|
|
659
|
+
source: "fireworks-billing-summary",
|
|
660
|
+
semantics: { kind: "api-key", label: "Fireworks API spend" },
|
|
661
|
+
accountLabel: sanitizeDisplayText(accountId, 80),
|
|
662
|
+
buckets: [],
|
|
663
|
+
metrics,
|
|
664
|
+
notes
|
|
665
|
+
};
|
|
666
|
+
}
|
|
667
|
+
function moneyAmount(value, description) {
|
|
668
|
+
const money = asObject4(value);
|
|
669
|
+
if (!money) throw new Error(`Fireworks billing ${description} was not a money object.`);
|
|
670
|
+
const currency = typeof money.currencyCode === "string" ? money.currencyCode : void 0;
|
|
671
|
+
if (!currency || !CURRENCY_PATTERN.test(currency)) {
|
|
672
|
+
throw new Error(`Fireworks billing ${description} currency was not an ISO 4217 code.`);
|
|
673
|
+
}
|
|
674
|
+
const units = money.units === void 0 ? 0n : integerComponent(money.units, description, "whole units", MAX_UNITS_CHARS);
|
|
675
|
+
if (units < INT64_MIN || units > INT64_MAX) {
|
|
676
|
+
throw new Error(`Fireworks billing ${description} whole units exceeded the int64 range.`);
|
|
677
|
+
}
|
|
678
|
+
const nanos = money.nanos === void 0 ? 0n : integerComponent(money.nanos, description, "nano units", MAX_NANOS_CHARS);
|
|
679
|
+
if (nanos <= -NANOS_PER_UNIT || nanos >= NANOS_PER_UNIT) {
|
|
680
|
+
throw new Error(`Fireworks billing ${description} nano units exceeded the Money range.`);
|
|
681
|
+
}
|
|
682
|
+
if (units > 0n && nanos < 0n || units < 0n && nanos > 0n) {
|
|
683
|
+
throw new Error(`Fireworks billing ${description} mixed unit and nano signs.`);
|
|
684
|
+
}
|
|
685
|
+
return { currency, amount: units * NANOS_PER_UNIT + nanos };
|
|
686
|
+
}
|
|
687
|
+
function integerComponent(value, description, component, maxChars) {
|
|
688
|
+
const text = typeof value === "number" && Number.isSafeInteger(value) ? String(value) : typeof value === "string" && INTEGER_PATTERN.test(value) ? value : void 0;
|
|
689
|
+
if (text === void 0 || text.length > maxChars) {
|
|
690
|
+
throw new Error(`Fireworks billing ${description} ${component} was not a bounded integer.`);
|
|
691
|
+
}
|
|
692
|
+
return BigInt(text);
|
|
693
|
+
}
|
|
694
|
+
function seriesKey(value) {
|
|
695
|
+
if (value === void 0 || value === null) return "other";
|
|
696
|
+
if (typeof value !== "string") throw new Error("Fireworks billing line item series was invalid.");
|
|
697
|
+
if (value === "SERVERLESS") return "serverless";
|
|
698
|
+
if (value === "DEDICATED_DEPLOYMENT") return "dedicated";
|
|
699
|
+
if (value === "TRAINING") return "training";
|
|
700
|
+
return "other";
|
|
701
|
+
}
|
|
702
|
+
function sumSeries(amounts) {
|
|
703
|
+
let total = 0n;
|
|
704
|
+
for (const amount2 of amounts.values()) total += amount2;
|
|
705
|
+
return total;
|
|
706
|
+
}
|
|
707
|
+
function formatMoneyAmount(amount2) {
|
|
708
|
+
const negative = amount2 < 0n;
|
|
709
|
+
const magnitude = negative ? -amount2 : amount2;
|
|
710
|
+
const units = magnitude / NANOS_PER_UNIT;
|
|
711
|
+
const nanos = (magnitude % NANOS_PER_UNIT).toString().padStart(9, "0").replace(/0+$/u, "");
|
|
712
|
+
return `${negative ? "-" : ""}${units.toString()}${nanos ? `.${nanos}` : ""}`;
|
|
713
|
+
}
|
|
714
|
+
function asObject4(value) {
|
|
715
|
+
if (!value || typeof value !== "object" || Array.isArray(value)) return void 0;
|
|
716
|
+
return value;
|
|
717
|
+
}
|
|
718
|
+
|
|
523
719
|
// src/providers/github-copilot.ts
|
|
524
720
|
function normalizeGitHubCopilotUsagePayload(payload, capturedAt) {
|
|
525
|
-
const snapshots =
|
|
526
|
-
const premium =
|
|
721
|
+
const snapshots = asObject5(payload.quota_snapshots);
|
|
722
|
+
const premium = asObject5(snapshots?.premium_interactions);
|
|
527
723
|
const metrics = [];
|
|
528
724
|
let semanticsLabel;
|
|
529
725
|
let bucket;
|
|
@@ -564,8 +760,8 @@ function normalizeGitHubCopilotUsagePayload(payload, capturedAt) {
|
|
|
564
760
|
};
|
|
565
761
|
}
|
|
566
762
|
} else {
|
|
567
|
-
const limited =
|
|
568
|
-
const monthly =
|
|
763
|
+
const limited = asObject5(payload.limited_user_quotas);
|
|
764
|
+
const monthly = asObject5(payload.monthly_quotas);
|
|
569
765
|
const remaining = asNonnegativeNumber(limited?.chat);
|
|
570
766
|
const entitlement = asNonnegativeNumber(monthly?.chat);
|
|
571
767
|
if (remaining === void 0 || entitlement === void 0) {
|
|
@@ -604,7 +800,7 @@ function resetTimestamp(payload) {
|
|
|
604
800
|
const milliseconds = Date.parse(raw);
|
|
605
801
|
return Number.isNaN(milliseconds) ? {} : { resetsAt: Math.floor(milliseconds / 1e3) };
|
|
606
802
|
}
|
|
607
|
-
function
|
|
803
|
+
function asObject5(value) {
|
|
608
804
|
if (!value || typeof value !== "object" || Array.isArray(value)) return void 0;
|
|
609
805
|
return value;
|
|
610
806
|
}
|
|
@@ -627,7 +823,7 @@ var DAILY_WINDOW_MINUTES = 1440;
|
|
|
627
823
|
var WEEKLY_WINDOW_MINUTES = 10080;
|
|
628
824
|
var FIXED_POINT_UNITS_PER_CENT = 1e6;
|
|
629
825
|
function normalizeKimiCodingUsagePayload(payload, capturedAt) {
|
|
630
|
-
const root =
|
|
826
|
+
const root = asObject6(payload);
|
|
631
827
|
if (!root) throw new Error("Kimi Coding usage response was not an object.");
|
|
632
828
|
const candidates = [];
|
|
633
829
|
let omittedWindow = false;
|
|
@@ -636,7 +832,7 @@ function normalizeKimiCodingUsagePayload(payload, capturedAt) {
|
|
|
636
832
|
else if (root.usage !== void 0) omittedWindow = true;
|
|
637
833
|
if (Array.isArray(root.limits)) {
|
|
638
834
|
for (const raw of root.limits) {
|
|
639
|
-
const item =
|
|
835
|
+
const item = asObject6(raw);
|
|
640
836
|
const windowMinutes = parseWindowMinutes(item?.window);
|
|
641
837
|
const label = sanitizedLabel(item?.name);
|
|
642
838
|
const bucket = windowMinutes === void 0 ? void 0 : parseUsageRow(item?.detail, windowMinutes, label ?? defaultWindowLabel(windowMinutes));
|
|
@@ -673,7 +869,7 @@ function normalizeKimiCodingUsagePayload(payload, capturedAt) {
|
|
|
673
869
|
};
|
|
674
870
|
}
|
|
675
871
|
function parseUsageRow(value, windowMinutes, label) {
|
|
676
|
-
const row =
|
|
872
|
+
const row = asObject6(value);
|
|
677
873
|
if (!row) return void 0;
|
|
678
874
|
const used = asNonnegativeInteger2(row.used);
|
|
679
875
|
const limit = asNonnegativeInteger2(row.limit);
|
|
@@ -691,7 +887,7 @@ function parseUsageRow(value, windowMinutes, label) {
|
|
|
691
887
|
};
|
|
692
888
|
}
|
|
693
889
|
function parseWindowMinutes(value) {
|
|
694
|
-
const window =
|
|
890
|
+
const window = asObject6(value);
|
|
695
891
|
if (!window) return void 0;
|
|
696
892
|
const duration = asPositiveInteger(window.duration);
|
|
697
893
|
if (duration === void 0) return void 0;
|
|
@@ -701,8 +897,8 @@ function parseWindowMinutes(value) {
|
|
|
701
897
|
return Number.isSafeInteger(minutes) ? minutes : void 0;
|
|
702
898
|
}
|
|
703
899
|
function parseBoosterWallet(value) {
|
|
704
|
-
const wallet =
|
|
705
|
-
const balance =
|
|
900
|
+
const wallet = asObject6(value);
|
|
901
|
+
const balance = asObject6(wallet?.balance);
|
|
706
902
|
if (!wallet || !balance || balance.type !== "BOOSTER") return [];
|
|
707
903
|
const totalRaw = asPositiveInteger(balance.amount);
|
|
708
904
|
if (totalRaw === void 0) return [];
|
|
@@ -753,7 +949,7 @@ function parseBoosterWallet(value) {
|
|
|
753
949
|
return metrics;
|
|
754
950
|
}
|
|
755
951
|
function parseMoney(value) {
|
|
756
|
-
const money =
|
|
952
|
+
const money = asObject6(value);
|
|
757
953
|
if (!money) return void 0;
|
|
758
954
|
const cents = asNonnegativeInteger2(money.priceInCents);
|
|
759
955
|
if (cents === void 0) return void 0;
|
|
@@ -767,7 +963,7 @@ function fixedPointToMajor(value) {
|
|
|
767
963
|
const major = roundedCents / 100;
|
|
768
964
|
return Number.isSafeInteger(roundedCents) && Number.isFinite(major) ? major : void 0;
|
|
769
965
|
}
|
|
770
|
-
function
|
|
966
|
+
function asObject6(value) {
|
|
771
967
|
if (!value || typeof value !== "object" || Array.isArray(value)) return void 0;
|
|
772
968
|
return value;
|
|
773
969
|
}
|
|
@@ -834,6 +1030,246 @@ function defaultWindowLabel(minutes) {
|
|
|
834
1030
|
return `${minutes}m window`;
|
|
835
1031
|
}
|
|
836
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
|
+
|
|
837
1273
|
// src/providers/opencode-zen.ts
|
|
838
1274
|
var ZEN_WINDOWS = [
|
|
839
1275
|
{ key: "rolling", label: "Rolling" },
|
|
@@ -841,12 +1277,12 @@ var ZEN_WINDOWS = [
|
|
|
841
1277
|
{ key: "monthly", label: "Monthly" }
|
|
842
1278
|
];
|
|
843
1279
|
function normalizeOpenCodeZenPayload(payload, capturedAt) {
|
|
844
|
-
const usage =
|
|
1280
|
+
const usage = asObject9(payload.usage);
|
|
845
1281
|
if (!usage) throw new Error("OpenCode Zen usage response was not an object.");
|
|
846
1282
|
const buckets = [];
|
|
847
1283
|
const notes = [];
|
|
848
1284
|
for (const window of ZEN_WINDOWS) {
|
|
849
|
-
const raw =
|
|
1285
|
+
const raw = asObject9(usage[window.key]);
|
|
850
1286
|
if (!raw) continue;
|
|
851
1287
|
const status = asString3(raw.status);
|
|
852
1288
|
if (status !== "ok" && status !== "rate-limited") {
|
|
@@ -883,7 +1319,7 @@ function normalizeOpenCodeZenPayload(payload, capturedAt) {
|
|
|
883
1319
|
...notes.length > 0 ? { notes } : {}
|
|
884
1320
|
};
|
|
885
1321
|
}
|
|
886
|
-
function
|
|
1322
|
+
function asObject9(value) {
|
|
887
1323
|
if (!value || typeof value !== "object" || Array.isArray(value)) return void 0;
|
|
888
1324
|
return value;
|
|
889
1325
|
}
|
|
@@ -907,7 +1343,7 @@ function clampPercent2(value) {
|
|
|
907
1343
|
|
|
908
1344
|
// src/providers/openrouter.ts
|
|
909
1345
|
function normalizeOpenRouterKeyPayload(payload, capturedAt) {
|
|
910
|
-
const data =
|
|
1346
|
+
const data = asObject10(payload.data);
|
|
911
1347
|
if (!data) throw new Error("OpenRouter key response data was not an object.");
|
|
912
1348
|
const limit = asNonnegativeNumber3(data.limit);
|
|
913
1349
|
const remaining = asNonnegativeNumber3(data.limit_remaining);
|
|
@@ -949,11 +1385,11 @@ function normalizeOpenRouterKeyPayload(payload, capturedAt) {
|
|
|
949
1385
|
};
|
|
950
1386
|
}
|
|
951
1387
|
function addUsageMetric(metrics, id, label, value) {
|
|
952
|
-
const
|
|
953
|
-
if (
|
|
954
|
-
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" });
|
|
955
1391
|
}
|
|
956
|
-
function
|
|
1392
|
+
function asObject10(value) {
|
|
957
1393
|
if (!value || typeof value !== "object" || Array.isArray(value)) return void 0;
|
|
958
1394
|
return value;
|
|
959
1395
|
}
|
|
@@ -966,6 +1402,44 @@ function asNonnegativeNumber3(value) {
|
|
|
966
1402
|
return value;
|
|
967
1403
|
}
|
|
968
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
|
+
|
|
969
1443
|
// src/providers/xai.ts
|
|
970
1444
|
var MAX_SAFE_CENTS = Number.MAX_SAFE_INTEGER;
|
|
971
1445
|
function normalizeXaiBillingPayload(payload, subscriptionTier, capturedAt) {
|
|
@@ -983,7 +1457,7 @@ function normalizeXaiBillingPayload(payload, subscriptionTier, capturedAt) {
|
|
|
983
1457
|
config.billingPeriodStart,
|
|
984
1458
|
config.billingPeriodEnd
|
|
985
1459
|
);
|
|
986
|
-
const preferredPercent =
|
|
1460
|
+
const preferredPercent = optionalPercent2(config.creditUsagePercent, "creditUsagePercent");
|
|
987
1461
|
if (preferredPercent !== void 0) {
|
|
988
1462
|
buckets.push({
|
|
989
1463
|
id: "included-allowance",
|
|
@@ -1093,7 +1567,7 @@ function optionalUsd(value, field) {
|
|
|
1093
1567
|
}
|
|
1094
1568
|
return cents / 100;
|
|
1095
1569
|
}
|
|
1096
|
-
function
|
|
1570
|
+
function optionalPercent2(value, field) {
|
|
1097
1571
|
if (value === void 0 || value === null) return void 0;
|
|
1098
1572
|
if (typeof value !== "number" || !Number.isFinite(value) || value < 0 || value > 100) {
|
|
1099
1573
|
throw new Error(`xAI billing ${field} was outside 0\u2013100.`);
|
|
@@ -1131,13 +1605,13 @@ function isRecord2(value) {
|
|
|
1131
1605
|
var FIVE_HOUR_WINDOW_MINUTES2 = 300;
|
|
1132
1606
|
var WEEKLY_WINDOW_MINUTES2 = 10080;
|
|
1133
1607
|
function normalizeZaiQuotaPayload(providerId, providerName, payload, capturedAt) {
|
|
1134
|
-
const data =
|
|
1608
|
+
const data = asObject11(payload.data);
|
|
1135
1609
|
if (!data) throw new Error("Z.AI quota response data was not an object.");
|
|
1136
1610
|
const limits = Array.isArray(data.limits) ? data.limits : [];
|
|
1137
1611
|
const buckets = [];
|
|
1138
1612
|
const metrics = [];
|
|
1139
1613
|
for (const raw of limits) {
|
|
1140
|
-
const limit =
|
|
1614
|
+
const limit = asObject11(raw);
|
|
1141
1615
|
if (!limit) continue;
|
|
1142
1616
|
const type = asString5(limit.type);
|
|
1143
1617
|
const unit = asNonnegativeNumber4(limit.unit);
|
|
@@ -1209,7 +1683,7 @@ function addCountBucket(buckets, limit, id, label, windowMinutes) {
|
|
|
1209
1683
|
function addUsageDetailMetrics(metrics, value) {
|
|
1210
1684
|
if (!Array.isArray(value)) return;
|
|
1211
1685
|
for (const raw of value) {
|
|
1212
|
-
const detail =
|
|
1686
|
+
const detail = asObject11(raw);
|
|
1213
1687
|
if (!detail) continue;
|
|
1214
1688
|
const label = asString5(detail.modelCode);
|
|
1215
1689
|
const usage = asNonnegativeNumber4(detail.usage);
|
|
@@ -1217,7 +1691,7 @@ function addUsageDetailMetrics(metrics, value) {
|
|
|
1217
1691
|
metrics.push({ id: `mcp-${kebabCase(label)}`, label, value: usage, unit: "count" });
|
|
1218
1692
|
}
|
|
1219
1693
|
}
|
|
1220
|
-
function
|
|
1694
|
+
function asObject11(value) {
|
|
1221
1695
|
if (!value || typeof value !== "object" || Array.isArray(value)) return void 0;
|
|
1222
1696
|
return value;
|
|
1223
1697
|
}
|
|
@@ -1242,12 +1716,27 @@ function clampPercent3(value) {
|
|
|
1242
1716
|
}
|
|
1243
1717
|
|
|
1244
1718
|
// src/query.ts
|
|
1719
|
+
var BASETEN_BILLING_USAGE_URL = "https://api.baseten.co/v1/billing/usage_summary";
|
|
1720
|
+
var BASETEN_USAGE_WINDOW_DAYS = 30;
|
|
1245
1721
|
var CODEX_USAGE_URL = "https://chatgpt.com/backend-api/wham/usage";
|
|
1246
1722
|
var DEEPSEEK_BALANCE_URL = "https://api.deepseek.com/user/balance";
|
|
1723
|
+
var FIREWORKS_BILLING_SUMMARY_ORIGIN = "https://api.fireworks.ai";
|
|
1724
|
+
var FIREWORKS_SPEND_WINDOW_DAYS = 30;
|
|
1725
|
+
var FIREWORKS_MAX_ACCOUNT_PAGES = 5;
|
|
1247
1726
|
var GITHUB_COPILOT_USAGE_URL = "https://api.github.com/copilot_internal/user";
|
|
1248
1727
|
var OPENROUTER_KEY_URL = "https://openrouter.ai/api/v1/key";
|
|
1728
|
+
var VERCEL_AI_GATEWAY_CREDITS_URL = "https://ai-gateway.vercel.sh/v1/credits";
|
|
1249
1729
|
var OPENCODE_GO_USAGE_URL = "https://opencode.ai/zen/go/v1/usage";
|
|
1250
1730
|
var KIMI_CODING_USAGE_URL = "https://api.kimi.com/coding/v1/usages";
|
|
1731
|
+
var MINIMAX_API_ROOTS = Object.freeze({
|
|
1732
|
+
minimax: "https://api.minimax.io",
|
|
1733
|
+
"minimax-cn": "https://api.minimaxi.com"
|
|
1734
|
+
});
|
|
1735
|
+
var MOONSHOT_BALANCE_URLS = Object.freeze({
|
|
1736
|
+
moonshotai: "https://api.moonshot.ai/v1/users/me/balance",
|
|
1737
|
+
"moonshotai-cn": "https://api.moonshot.cn/v1/users/me/balance"
|
|
1738
|
+
});
|
|
1739
|
+
var SHARED_MOONSHOT_ENV_VAR = "MOONSHOT_API_KEY";
|
|
1251
1740
|
var XAI_USER_URL = "https://cli-chat-proxy.grok.com/v1/user?include=subscription";
|
|
1252
1741
|
var XAI_BILLING_URL = "https://cli-chat-proxy.grok.com/v1/billing?format=credits";
|
|
1253
1742
|
var XAI_CLIENT_HEADERS = Object.freeze({
|
|
@@ -1259,6 +1748,27 @@ var MAX_SUCCESS_BODY_BYTES = 64 * 1024;
|
|
|
1259
1748
|
var MAX_ERROR_BODY_BYTES = 4 * 1024;
|
|
1260
1749
|
var AUTH_FINGERPRINT_SALT = randomBytes(32);
|
|
1261
1750
|
var SUPPORTED_ADAPTERS = [
|
|
1751
|
+
{
|
|
1752
|
+
id: "baseten",
|
|
1753
|
+
displayName: "Baseten",
|
|
1754
|
+
semantics: { kind: "api-key", label: "Organization Model APIs spend" },
|
|
1755
|
+
async query(auth, signal, timeoutMs, guard) {
|
|
1756
|
+
if (!guard) throw new Error("Baseten billing usage requires request-boundary revalidation.");
|
|
1757
|
+
const startedAt = Date.now();
|
|
1758
|
+
await guard();
|
|
1759
|
+
const windowAt = Date.now();
|
|
1760
|
+
const payload = await fetchProviderJson(
|
|
1761
|
+
basetenBillingUsageUrl(windowAt),
|
|
1762
|
+
auth,
|
|
1763
|
+
signal,
|
|
1764
|
+
remainingTimeout(timeoutMs, startedAt, "fetching Baseten billing usage"),
|
|
1765
|
+
"Baseten billing usage endpoint",
|
|
1766
|
+
{ redirect: "error" }
|
|
1767
|
+
);
|
|
1768
|
+
await guard();
|
|
1769
|
+
return normalizeBasetenBillingUsagePayload(payload, Date.now());
|
|
1770
|
+
}
|
|
1771
|
+
},
|
|
1262
1772
|
{
|
|
1263
1773
|
id: "openai-codex",
|
|
1264
1774
|
displayName: "OpenAI Codex",
|
|
@@ -1331,6 +1841,56 @@ var SUPPORTED_ADAPTERS = [
|
|
|
1331
1841
|
return normalizeOpenRouterKeyPayload(payload, Date.now());
|
|
1332
1842
|
}
|
|
1333
1843
|
},
|
|
1844
|
+
{
|
|
1845
|
+
id: "vercel-ai-gateway",
|
|
1846
|
+
displayName: "Vercel AI Gateway",
|
|
1847
|
+
semantics: { kind: "api-key", label: "AI Gateway credits and lifetime spend" },
|
|
1848
|
+
async query(auth, signal, timeoutMs, guard) {
|
|
1849
|
+
if (!guard)
|
|
1850
|
+
throw new Error("Vercel AI Gateway usage requires request-boundary revalidation.");
|
|
1851
|
+
const startedAt = Date.now();
|
|
1852
|
+
await guard();
|
|
1853
|
+
const payload = await fetchProviderJson(
|
|
1854
|
+
VERCEL_AI_GATEWAY_CREDITS_URL,
|
|
1855
|
+
auth,
|
|
1856
|
+
signal,
|
|
1857
|
+
remainingTimeout(timeoutMs, startedAt, "fetching Vercel AI Gateway credits"),
|
|
1858
|
+
"Vercel AI Gateway credits endpoint",
|
|
1859
|
+
{ redirect: "error" }
|
|
1860
|
+
);
|
|
1861
|
+
await guard();
|
|
1862
|
+
return normalizeVercelAIGatewayCreditsPayload(payload, Date.now());
|
|
1863
|
+
}
|
|
1864
|
+
},
|
|
1865
|
+
{
|
|
1866
|
+
id: "fireworks",
|
|
1867
|
+
displayName: "Fireworks",
|
|
1868
|
+
semantics: { kind: "api-key", label: "Fireworks API spend" },
|
|
1869
|
+
async query(auth, signal, timeoutMs, guard, settings) {
|
|
1870
|
+
if (!guard) throw new Error("Fireworks API spend requires request-boundary revalidation.");
|
|
1871
|
+
const startedAt = Date.now();
|
|
1872
|
+
await guard();
|
|
1873
|
+
const accountId = await resolveFireworksAccountId(
|
|
1874
|
+
auth,
|
|
1875
|
+
signal,
|
|
1876
|
+
remainingTimeout(timeoutMs, startedAt, "resolving the Fireworks account"),
|
|
1877
|
+
guard,
|
|
1878
|
+
settings?.fireworksAccountId
|
|
1879
|
+
);
|
|
1880
|
+
await guard();
|
|
1881
|
+
const billingWindowAt = Date.now();
|
|
1882
|
+
const payload = await fetchProviderJson(
|
|
1883
|
+
fireworksBillingSummaryUrl(accountId, billingWindowAt),
|
|
1884
|
+
auth,
|
|
1885
|
+
signal,
|
|
1886
|
+
remainingTimeout(timeoutMs, startedAt, "fetching Fireworks rated spend"),
|
|
1887
|
+
"Fireworks billing summary endpoint",
|
|
1888
|
+
{ redirect: "error" }
|
|
1889
|
+
);
|
|
1890
|
+
await guard();
|
|
1891
|
+
return normalizeFireworksBillingSummaryPayload(payload, accountId, Date.now());
|
|
1892
|
+
}
|
|
1893
|
+
},
|
|
1334
1894
|
{
|
|
1335
1895
|
id: "opencode-go",
|
|
1336
1896
|
displayName: "OpenCode Go",
|
|
@@ -1362,6 +1922,38 @@ var SUPPORTED_ADAPTERS = [
|
|
|
1362
1922
|
return normalizeKimiCodingUsagePayload(payload, Date.now());
|
|
1363
1923
|
}
|
|
1364
1924
|
},
|
|
1925
|
+
{
|
|
1926
|
+
id: "minimax",
|
|
1927
|
+
displayName: "MiniMax",
|
|
1928
|
+
semantics: { kind: "consumer-subscription", label: "MiniMax usage" },
|
|
1929
|
+
async query(auth, signal, timeoutMs, guard) {
|
|
1930
|
+
return queryMiniMaxUsage("minimax", auth, signal, timeoutMs, guard);
|
|
1931
|
+
}
|
|
1932
|
+
},
|
|
1933
|
+
{
|
|
1934
|
+
id: "minimax-cn",
|
|
1935
|
+
displayName: "MiniMax CN",
|
|
1936
|
+
semantics: { kind: "consumer-subscription", label: "MiniMax usage" },
|
|
1937
|
+
async query(auth, signal, timeoutMs, guard) {
|
|
1938
|
+
return queryMiniMaxUsage("minimax-cn", auth, signal, timeoutMs, guard);
|
|
1939
|
+
}
|
|
1940
|
+
},
|
|
1941
|
+
{
|
|
1942
|
+
id: "moonshotai",
|
|
1943
|
+
displayName: "Moonshot AI",
|
|
1944
|
+
semantics: { kind: "api-key", label: "Moonshot API account balance" },
|
|
1945
|
+
async query(auth, signal, timeoutMs, guard) {
|
|
1946
|
+
return queryMoonshotBalance("moonshotai", auth, signal, timeoutMs, guard);
|
|
1947
|
+
}
|
|
1948
|
+
},
|
|
1949
|
+
{
|
|
1950
|
+
id: "moonshotai-cn",
|
|
1951
|
+
displayName: "Moonshot AI CN",
|
|
1952
|
+
semantics: { kind: "api-key", label: "Moonshot API account balance" },
|
|
1953
|
+
async query(auth, signal, timeoutMs, guard) {
|
|
1954
|
+
return queryMoonshotBalance("moonshotai-cn", auth, signal, timeoutMs, guard);
|
|
1955
|
+
}
|
|
1956
|
+
},
|
|
1365
1957
|
{
|
|
1366
1958
|
id: "zai",
|
|
1367
1959
|
displayName: "Z.AI",
|
|
@@ -1470,17 +2062,20 @@ async function resolveUsageAuth(ctx, adapter, salt = AUTH_FINGERPRINT_SALT, cred
|
|
|
1470
2062
|
if (!result.ok) throw new Error(redactUsageError(result.error));
|
|
1471
2063
|
return authorizationFrom(result) ? result : void 0;
|
|
1472
2064
|
};
|
|
1473
|
-
|
|
2065
|
+
const resolveSelectedAuthLast = ["deepseek", "minimax", "minimax-cn"].includes(adapter.id);
|
|
2066
|
+
if (!resolveSelectedAuthLast) modelAuth = await resolveCurrentModelAuth();
|
|
1474
2067
|
if (typeof registry.getProviderAuth !== "function") {
|
|
1475
2068
|
throw new Error("pi-usage requires Pi 0.81.0 or newer to validate resolved provider auth.");
|
|
1476
2069
|
}
|
|
2070
|
+
if (!moonshotProviderAuthIsAllowed(ctx, adapter.id)) return void 0;
|
|
1477
2071
|
const providerResult = await registry.getProviderAuth(adapter.id);
|
|
2072
|
+
if (!moonshotProviderAuthIsAllowed(ctx, adapter.id)) return void 0;
|
|
1478
2073
|
if (providerResult?.auth.baseUrl && !hasOfficialUrlOrigin(providerResult.auth.baseUrl, adapter.id)) {
|
|
1479
2074
|
throw new Error(
|
|
1480
2075
|
`${adapter.displayName} usage cannot send a proxy-resolved credential to the official usage endpoint.`
|
|
1481
2076
|
);
|
|
1482
2077
|
}
|
|
1483
|
-
if (
|
|
2078
|
+
if (resolveSelectedAuthLast) modelAuth = await resolveCurrentModelAuth();
|
|
1484
2079
|
const auth = modelAuth ?? providerResult?.auth;
|
|
1485
2080
|
if (!auth) return void 0;
|
|
1486
2081
|
if (adapter.id === "github-copilot") {
|
|
@@ -1535,9 +2130,9 @@ async function resolveUsageAuth(ctx, adapter, salt = AUTH_FINGERPRINT_SALT, cred
|
|
|
1535
2130
|
model
|
|
1536
2131
|
};
|
|
1537
2132
|
}
|
|
1538
|
-
async function queryProviderUsage(adapter, auth, signal, timeoutMs, guard) {
|
|
2133
|
+
async function queryProviderUsage(adapter, auth, signal, timeoutMs, guard, settings) {
|
|
1539
2134
|
try {
|
|
1540
|
-
return await adapter.query(auth, signal, timeoutMs, guard);
|
|
2135
|
+
return await adapter.query(auth, signal, timeoutMs, guard, settings);
|
|
1541
2136
|
} catch (error) {
|
|
1542
2137
|
if (isStaleExtensionContextError(error) || isAbortError(error)) throw error;
|
|
1543
2138
|
throw new Error(redactUsageError(errorMessage(error), auth.secrets));
|
|
@@ -1545,11 +2140,30 @@ async function queryProviderUsage(adapter, auth, signal, timeoutMs, guard) {
|
|
|
1545
2140
|
}
|
|
1546
2141
|
function providerIsConfigured(ctx, providerId) {
|
|
1547
2142
|
try {
|
|
1548
|
-
|
|
2143
|
+
const status = ctx.modelRegistry.getProviderAuthStatus(providerId);
|
|
2144
|
+
return status.configured && moonshotProviderAuthSourceIsAllowed(ctx, providerId, status.source, status.label);
|
|
1549
2145
|
} catch {
|
|
1550
|
-
return candidateModels(ctx, providerId).length > 0;
|
|
2146
|
+
return !isMoonshotSiblingProvider(ctx, providerId) && candidateModels(ctx, providerId).length > 0;
|
|
1551
2147
|
}
|
|
1552
2148
|
}
|
|
2149
|
+
function moonshotProviderAuthIsAllowed(ctx, providerId) {
|
|
2150
|
+
if (!isMoonshotSiblingProvider(ctx, providerId)) return true;
|
|
2151
|
+
try {
|
|
2152
|
+
const status = ctx.modelRegistry.getProviderAuthStatus(providerId);
|
|
2153
|
+
return moonshotProviderAuthSourceIsAllowed(ctx, providerId, status.source, status.label);
|
|
2154
|
+
} catch {
|
|
2155
|
+
return false;
|
|
2156
|
+
}
|
|
2157
|
+
}
|
|
2158
|
+
function moonshotProviderAuthSourceIsAllowed(ctx, providerId, source, label) {
|
|
2159
|
+
if (!isMoonshotSiblingProvider(ctx, providerId)) return true;
|
|
2160
|
+
if (source === void 0) return false;
|
|
2161
|
+
if (source !== "environment") return true;
|
|
2162
|
+
return label !== void 0 && !label.split(",").map((name) => name.trim()).includes(SHARED_MOONSHOT_ENV_VAR);
|
|
2163
|
+
}
|
|
2164
|
+
function isMoonshotSiblingProvider(ctx, providerId) {
|
|
2165
|
+
return (providerId === "moonshotai" || providerId === "moonshotai-cn") && ctx.model?.provider !== providerId;
|
|
2166
|
+
}
|
|
1553
2167
|
function candidateModels(ctx, providerId) {
|
|
1554
2168
|
const candidates = [];
|
|
1555
2169
|
const seen = /* @__PURE__ */ new Set();
|
|
@@ -1678,7 +2292,7 @@ function resolveXaiUsageAuth(auth, model, salt, candidates) {
|
|
|
1678
2292
|
const matches = [];
|
|
1679
2293
|
for (const candidate of candidates) {
|
|
1680
2294
|
try {
|
|
1681
|
-
const credential =
|
|
2295
|
+
const credential = asObject12(candidate);
|
|
1682
2296
|
if (credential?.type !== "oauth") continue;
|
|
1683
2297
|
sawOAuth = true;
|
|
1684
2298
|
if (credential.access !== resolvedAccess) continue;
|
|
@@ -1732,7 +2346,7 @@ function resolveGitHubCopilotUsageAuth(auth, model, salt, candidates, standalone
|
|
|
1732
2346
|
const matches = /* @__PURE__ */ new Map();
|
|
1733
2347
|
for (const candidate of candidates) {
|
|
1734
2348
|
try {
|
|
1735
|
-
const credential =
|
|
2349
|
+
const credential = asObject12(candidate);
|
|
1736
2350
|
if (credential?.type !== "oauth") continue;
|
|
1737
2351
|
sawOAuth = true;
|
|
1738
2352
|
const storedAccess2 = typeof credential.access === "string" && credential.access ? credential.access : void 0;
|
|
@@ -1794,7 +2408,7 @@ function bearerToken(authorization) {
|
|
|
1794
2408
|
const match = /^Bearer\s+(.+)$/iu.exec(authorization ?? "");
|
|
1795
2409
|
return match?.[1];
|
|
1796
2410
|
}
|
|
1797
|
-
function
|
|
2411
|
+
function asObject12(value) {
|
|
1798
2412
|
if (!value || typeof value !== "object" || Array.isArray(value)) return void 0;
|
|
1799
2413
|
return value;
|
|
1800
2414
|
}
|
|
@@ -1812,11 +2426,20 @@ function hasOfficialOrigin(model, providerId) {
|
|
|
1812
2426
|
function hasOfficialUrlOrigin(value, providerId) {
|
|
1813
2427
|
try {
|
|
1814
2428
|
const url = new URL(value);
|
|
2429
|
+
if (providerId === "baseten") {
|
|
2430
|
+
return ["https://inference.baseten.co", "https://api.baseten.co"].includes(url.origin);
|
|
2431
|
+
}
|
|
1815
2432
|
if (providerId === "openai-codex") return url.origin === "https://chatgpt.com";
|
|
1816
2433
|
if (providerId === "deepseek") return url.origin === "https://api.deepseek.com";
|
|
2434
|
+
if (providerId === "fireworks") return url.origin === FIREWORKS_BILLING_SUMMARY_ORIGIN;
|
|
1817
2435
|
if (providerId === "openrouter") return url.origin === "https://openrouter.ai";
|
|
2436
|
+
if (providerId === "vercel-ai-gateway") return url.origin === "https://ai-gateway.vercel.sh";
|
|
1818
2437
|
if (providerId === "opencode-go") return url.origin === "https://opencode.ai";
|
|
1819
2438
|
if (providerId === "kimi-coding") return url.origin === "https://api.kimi.com";
|
|
2439
|
+
if (providerId === "minimax") return url.origin === "https://api.minimax.io";
|
|
2440
|
+
if (providerId === "minimax-cn") return url.origin === "https://api.minimaxi.com";
|
|
2441
|
+
if (providerId === "moonshotai") return url.origin === "https://api.moonshot.ai";
|
|
2442
|
+
if (providerId === "moonshotai-cn") return url.origin === "https://api.moonshot.cn";
|
|
1820
2443
|
if (providerId === "xai") return url.origin === "https://api.x.ai";
|
|
1821
2444
|
if (providerId === "zai") return url.origin === "https://api.z.ai";
|
|
1822
2445
|
if (providerId === "zai-coding-cn") return url.origin === "https://open.bigmodel.cn";
|
|
@@ -1843,11 +2466,130 @@ function validatedXaiUserId(value) {
|
|
|
1843
2466
|
}
|
|
1844
2467
|
return value;
|
|
1845
2468
|
}
|
|
1846
|
-
function
|
|
2469
|
+
function basetenBillingUsageUrl(windowAt) {
|
|
2470
|
+
const url = new URL(BASETEN_BILLING_USAGE_URL);
|
|
2471
|
+
url.searchParams.set(
|
|
2472
|
+
"start_date",
|
|
2473
|
+
new Date(windowAt - BASETEN_USAGE_WINDOW_DAYS * 24 * 60 * 60 * 1e3).toISOString()
|
|
2474
|
+
);
|
|
2475
|
+
url.searchParams.set("end_date", new Date(windowAt).toISOString());
|
|
2476
|
+
return url.toString();
|
|
2477
|
+
}
|
|
2478
|
+
async function queryMiniMaxUsage(providerId, auth, signal, timeoutMs, guard) {
|
|
2479
|
+
if (!guard) throw new Error("MiniMax usage requires request-boundary revalidation.");
|
|
2480
|
+
const apiKey = bearerToken(headerValue(auth.headers, "Authorization")) ?? auth.apiKey;
|
|
2481
|
+
if (!apiKey) throw new Error("MiniMax runtime API key was unavailable.");
|
|
2482
|
+
const kind = miniMaxUsageKind(apiKey);
|
|
2483
|
+
const path = kind === "account-balance" ? "/account/query_balance" : "/v1/token_plan/remains";
|
|
2484
|
+
const startedAt = Date.now();
|
|
2485
|
+
await guard();
|
|
2486
|
+
const payload = await fetchProviderJson(
|
|
2487
|
+
`${MINIMAX_API_ROOTS[providerId]}${path}`,
|
|
2488
|
+
auth,
|
|
2489
|
+
signal,
|
|
2490
|
+
remainingTimeout(timeoutMs, startedAt, "fetching MiniMax usage"),
|
|
2491
|
+
"MiniMax usage endpoint",
|
|
2492
|
+
{ redirect: "error" }
|
|
2493
|
+
);
|
|
2494
|
+
await guard();
|
|
2495
|
+
return normalizeMiniMaxUsagePayload(providerId, kind, payload, Date.now());
|
|
2496
|
+
}
|
|
2497
|
+
async function queryMoonshotBalance(providerId, auth, signal, timeoutMs, guard) {
|
|
2498
|
+
if (!guard) throw new Error("Moonshot AI balance requires request-boundary revalidation.");
|
|
2499
|
+
const startedAt = Date.now();
|
|
2500
|
+
await guard();
|
|
2501
|
+
const payload = await fetchProviderJson(
|
|
2502
|
+
MOONSHOT_BALANCE_URLS[providerId],
|
|
2503
|
+
auth,
|
|
2504
|
+
signal,
|
|
2505
|
+
remainingTimeout(timeoutMs, startedAt, "fetching Moonshot AI balance"),
|
|
2506
|
+
"Moonshot AI balance endpoint",
|
|
2507
|
+
{ redirect: "error" }
|
|
2508
|
+
);
|
|
2509
|
+
await guard();
|
|
2510
|
+
return normalizeMoonshotBalancePayload(providerId, payload, Date.now());
|
|
2511
|
+
}
|
|
2512
|
+
function remainingTimeout(timeoutMs, startedAt, description = "fetching xAI consumer usage") {
|
|
1847
2513
|
const remaining = timeoutMs - (Date.now() - startedAt);
|
|
1848
|
-
if (remaining <= 0) throw new Error(
|
|
2514
|
+
if (remaining <= 0) throw new Error(`Timed out while ${description}.`);
|
|
1849
2515
|
return remaining;
|
|
1850
2516
|
}
|
|
2517
|
+
async function resolveFireworksAccountId(auth, signal, timeoutMs, guard, configuredAccountId) {
|
|
2518
|
+
if (configuredAccountId !== void 0 && !isFireworksAccountId(configuredAccountId)) {
|
|
2519
|
+
throw new Error("The Fireworks account setting was not a safe account slug.");
|
|
2520
|
+
}
|
|
2521
|
+
const startedAt = Date.now();
|
|
2522
|
+
const accounts = [];
|
|
2523
|
+
let pageToken;
|
|
2524
|
+
for (let page = 0; page < FIREWORKS_MAX_ACCOUNT_PAGES; page += 1) {
|
|
2525
|
+
await guard();
|
|
2526
|
+
const payload = await fetchProviderJson(
|
|
2527
|
+
fireworksAccountsUrl(pageToken),
|
|
2528
|
+
auth,
|
|
2529
|
+
signal,
|
|
2530
|
+
remainingTimeout(timeoutMs, startedAt, "fetching Fireworks accounts"),
|
|
2531
|
+
"Fireworks accounts endpoint",
|
|
2532
|
+
{ redirect: "error" }
|
|
2533
|
+
);
|
|
2534
|
+
for (const accountId of normalizeFireworksAccountsPayload(
|
|
2535
|
+
payload
|
|
2536
|
+
)) {
|
|
2537
|
+
if (accounts.includes(accountId)) {
|
|
2538
|
+
throw new Error(`Fireworks accounts listing repeated ${accountId}.`);
|
|
2539
|
+
}
|
|
2540
|
+
accounts.push(accountId);
|
|
2541
|
+
if (configuredAccountId === accountId) return accountId;
|
|
2542
|
+
}
|
|
2543
|
+
pageToken = fireworksNextPageToken(payload.nextPageToken);
|
|
2544
|
+
if (!pageToken) break;
|
|
2545
|
+
}
|
|
2546
|
+
if (pageToken) {
|
|
2547
|
+
throw new Error(
|
|
2548
|
+
configuredAccountId ? `The configured Fireworks account was not found within the first ${FIREWORKS_MAX_ACCOUNT_PAGES} listing pages.` : `Fireworks account listing exceeded ${FIREWORKS_MAX_ACCOUNT_PAGES} pages; set fireworksAccountId in pi-usage.json to an account returned in those pages.`
|
|
2549
|
+
);
|
|
2550
|
+
}
|
|
2551
|
+
if (accounts.length === 0) {
|
|
2552
|
+
throw new Error("Fireworks account discovery returned no accounts for this API key.");
|
|
2553
|
+
}
|
|
2554
|
+
if (configuredAccountId) {
|
|
2555
|
+
throw new Error(
|
|
2556
|
+
"The configured Fireworks account does not match an account visible to this API key."
|
|
2557
|
+
);
|
|
2558
|
+
}
|
|
2559
|
+
if (accounts.length === 1) return accounts[0];
|
|
2560
|
+
const preview = accounts.slice(0, 8).join(", ");
|
|
2561
|
+
const suffix = accounts.length > 8 ? ` \u2026and ${accounts.length - 8} more` : "";
|
|
2562
|
+
throw new Error(
|
|
2563
|
+
`The Fireworks key can see ${accounts.length} accounts (${preview}${suffix}); set fireworksAccountId in pi-usage.json to one of them.`
|
|
2564
|
+
);
|
|
2565
|
+
}
|
|
2566
|
+
function fireworksAccountsUrl(pageToken) {
|
|
2567
|
+
const url = new URL("/v1/accounts", FIREWORKS_BILLING_SUMMARY_ORIGIN);
|
|
2568
|
+
url.searchParams.set("pageSize", "200");
|
|
2569
|
+
if (pageToken !== void 0) url.searchParams.set("pageToken", pageToken);
|
|
2570
|
+
return url.toString();
|
|
2571
|
+
}
|
|
2572
|
+
function fireworksNextPageToken(value) {
|
|
2573
|
+
if (value === void 0 || value === null) return void 0;
|
|
2574
|
+
if (typeof value !== "string" || !value || value.length > 512) {
|
|
2575
|
+
throw new Error("Fireworks accounts listing returned an invalid page token.");
|
|
2576
|
+
}
|
|
2577
|
+
return value;
|
|
2578
|
+
}
|
|
2579
|
+
function fireworksBillingSummaryUrl(accountId, startedAt) {
|
|
2580
|
+
const dayMs = 24 * 60 * 60 * 1e3;
|
|
2581
|
+
const dayFloor = (time) => `${new Date(time).toISOString().slice(0, 10)}T00:00:00Z`;
|
|
2582
|
+
const url = new URL(
|
|
2583
|
+
`/v1/accounts/${accountId}/billing/summary`,
|
|
2584
|
+
FIREWORKS_BILLING_SUMMARY_ORIGIN
|
|
2585
|
+
);
|
|
2586
|
+
url.searchParams.set(
|
|
2587
|
+
"startTime",
|
|
2588
|
+
dayFloor(startedAt - (FIREWORKS_SPEND_WINDOW_DAYS - 1) * dayMs)
|
|
2589
|
+
);
|
|
2590
|
+
url.searchParams.set("endTime", dayFloor(startedAt + dayMs));
|
|
2591
|
+
return url.toString();
|
|
2592
|
+
}
|
|
1851
2593
|
function zaiMonitorUrl(baseUrl) {
|
|
1852
2594
|
const base = baseUrl?.trim();
|
|
1853
2595
|
if (!base) throw new Error("Z.AI model base URL is unavailable.");
|
|
@@ -1868,12 +2610,12 @@ var CODEX_RESET_CREDITS_URL = "https://chatgpt.com/backend-api/wham/rate-limit-r
|
|
|
1868
2610
|
var CODEX_RESET_CONSUME_URL = `${CODEX_RESET_CREDITS_URL}/consume`;
|
|
1869
2611
|
var MAX_RESET_OPTIONS = 32;
|
|
1870
2612
|
var MAX_CREDIT_ID_CHARS = 1024;
|
|
1871
|
-
function codexResetCount(
|
|
1872
|
-
const value =
|
|
2613
|
+
function codexResetCount(report2) {
|
|
2614
|
+
const value = report2.metrics.find((metric2) => metric2.id === "reset-credits")?.value;
|
|
1873
2615
|
return typeof value === "number" && Number.isSafeInteger(value) && value >= 0 ? value : void 0;
|
|
1874
2616
|
}
|
|
1875
|
-
function codexResetActionDescription(
|
|
1876
|
-
const count = codexResetCount(
|
|
2617
|
+
function codexResetActionDescription(report2) {
|
|
2618
|
+
const count = codexResetCount(report2);
|
|
1877
2619
|
if (count === void 0) return "Check reset availability.";
|
|
1878
2620
|
if (count === 0) return "No usage limit resets available.";
|
|
1879
2621
|
return `You have ${count} ${resetLabel(count)} available.`;
|
|
@@ -1986,14 +2728,14 @@ async function consumeCodexResetCredit(auth, option, redeemRequestId, signal, ti
|
|
|
1986
2728
|
if (!isCodexResetOutcomeCode(code)) {
|
|
1987
2729
|
throw new Error("Codex reset consume endpoint returned an unknown outcome code.");
|
|
1988
2730
|
}
|
|
1989
|
-
const windowsReset = payload.windows_reset === void 0 ? 0 :
|
|
2731
|
+
const windowsReset = payload.windows_reset === void 0 ? 0 : nonnegativeInteger2(payload.windows_reset);
|
|
1990
2732
|
if (windowsReset === void 0) {
|
|
1991
2733
|
throw new Error("Codex reset consume endpoint returned an invalid windows_reset value.");
|
|
1992
2734
|
}
|
|
1993
2735
|
return { code, windowsReset };
|
|
1994
2736
|
}
|
|
1995
2737
|
function normalizeCodexResetCreditsPayload(payload) {
|
|
1996
|
-
const availableCount =
|
|
2738
|
+
const availableCount = nonnegativeInteger2(payload.available_count);
|
|
1997
2739
|
if (availableCount === void 0) {
|
|
1998
2740
|
throw new Error("Codex reset credits response returned an invalid available_count.");
|
|
1999
2741
|
}
|
|
@@ -2001,7 +2743,7 @@ function normalizeCodexResetCreditsPayload(payload) {
|
|
|
2001
2743
|
if (rawCredits !== void 0 && !Array.isArray(rawCredits)) {
|
|
2002
2744
|
throw new Error("Codex reset credits response returned invalid credits.");
|
|
2003
2745
|
}
|
|
2004
|
-
const options = (rawCredits ?? []).map(
|
|
2746
|
+
const options = (rawCredits ?? []).map(asObject13).filter((credit) => Boolean(credit)).filter((credit) => credit.status === "available" && credit.reset_type === "codex_rate_limits").map(normalizeResetOption).sort(
|
|
2005
2747
|
(left, right) => (left.expiresAt ?? Number.MAX_SAFE_INTEGER) - (right.expiresAt ?? Number.MAX_SAFE_INTEGER)
|
|
2006
2748
|
).slice(0, Math.min(availableCount, MAX_RESET_OPTIONS));
|
|
2007
2749
|
if (availableCount > 0 && options.length === 0) {
|
|
@@ -2016,7 +2758,7 @@ function selectCodexResetCredential(candidates, resolvedAccess, resolvedAccountI
|
|
|
2016
2758
|
const matches = /* @__PURE__ */ new Map();
|
|
2017
2759
|
for (const candidate of candidates) {
|
|
2018
2760
|
try {
|
|
2019
|
-
const credential =
|
|
2761
|
+
const credential = asObject13(candidate);
|
|
2020
2762
|
if (credential?.type !== "oauth") continue;
|
|
2021
2763
|
sawOAuth = true;
|
|
2022
2764
|
const storedAccess = asNonemptyString(credential.access);
|
|
@@ -2055,7 +2797,7 @@ function codexAccountIdFromAccessToken(access) {
|
|
|
2055
2797
|
const parts = access.split(".");
|
|
2056
2798
|
if (parts.length !== 3 || !parts[1]) return void 0;
|
|
2057
2799
|
const payload = JSON.parse(Buffer.from(parts[1], "base64url").toString("utf8"));
|
|
2058
|
-
const claims =
|
|
2800
|
+
const claims = asObject13(asObject13(payload)?.["https://api.openai.com/auth"]);
|
|
2059
2801
|
return validHeaderValue(claims?.chatgpt_account_id);
|
|
2060
2802
|
} catch {
|
|
2061
2803
|
return void 0;
|
|
@@ -2087,7 +2829,7 @@ function normalizeResetOption(credit) {
|
|
|
2087
2829
|
function isCodexResetOutcomeCode(value) {
|
|
2088
2830
|
return value === "reset" || value === "nothing_to_reset" || value === "no_credit" || value === "already_redeemed";
|
|
2089
2831
|
}
|
|
2090
|
-
function
|
|
2832
|
+
function asObject13(value) {
|
|
2091
2833
|
if (!value || typeof value !== "object" || Array.isArray(value)) return void 0;
|
|
2092
2834
|
return value;
|
|
2093
2835
|
}
|
|
@@ -2109,7 +2851,7 @@ function validHeaderValue(value) {
|
|
|
2109
2851
|
if (/[^\x20-\x7e]/u.test(value)) return void 0;
|
|
2110
2852
|
return value;
|
|
2111
2853
|
}
|
|
2112
|
-
function
|
|
2854
|
+
function nonnegativeInteger2(value) {
|
|
2113
2855
|
const parsed = typeof value === "number" ? value : typeof value === "string" && value.trim() ? Number(value) : Number.NaN;
|
|
2114
2856
|
if (!Number.isSafeInteger(parsed) || parsed < 0) return void 0;
|
|
2115
2857
|
return parsed;
|
|
@@ -2126,43 +2868,59 @@ function headerValue2(headers, name) {
|
|
|
2126
2868
|
// src/format.ts
|
|
2127
2869
|
var BAR_SEGMENTS = 20;
|
|
2128
2870
|
var VALUE_COLUMN = 29;
|
|
2129
|
-
function formatUsageReport(
|
|
2871
|
+
function formatUsageReport(report2, displayState) {
|
|
2130
2872
|
const stateLabel = displayState === "current" ? "Current" : "Configured";
|
|
2131
|
-
const title =
|
|
2873
|
+
const title = report2.providerId === "baseten" ? "Baseten Model APIs Spend" : report2.providerId === "deepseek" ? "DeepSeek API Balance" : report2.providerId === "fireworks" ? "Fireworks API Spend" : report2.providerId === "vercel-ai-gateway" ? "Vercel AI Gateway Credits" : report2.providerId === "moonshotai" || report2.providerId === "moonshotai-cn" ? `${report2.providerName} Balance` : report2.providerId === "minimax" || report2.providerId === "minimax-cn" ? report2.source === "minimax-account-balance" ? `${report2.providerName} API Balance` : `${report2.providerName} Token Plan` : `${report2.providerName} Usage`;
|
|
2132
2874
|
const lines = [`${title} \xB7 ${stateLabel}`];
|
|
2133
|
-
if (
|
|
2134
|
-
lines.push(`Semantics: ${
|
|
2135
|
-
if (
|
|
2136
|
-
else if (
|
|
2137
|
-
else if (
|
|
2138
|
-
else if (
|
|
2139
|
-
else if (
|
|
2140
|
-
else if (
|
|
2141
|
-
else if (
|
|
2142
|
-
else if (
|
|
2143
|
-
|
|
2144
|
-
|
|
2145
|
-
|
|
2146
|
-
|
|
2875
|
+
if (report2.accountLabel) lines.push(`Account: ${report2.accountLabel}`);
|
|
2876
|
+
lines.push(`Semantics: ${report2.semantics.label}`, "");
|
|
2877
|
+
if (report2.providerId === "baseten") formatBasetenReport(lines, report2);
|
|
2878
|
+
else if (report2.providerId === "openai-codex") formatCodexReport(lines, report2);
|
|
2879
|
+
else if (report2.providerId === "deepseek") formatDeepSeekReport(lines, report2);
|
|
2880
|
+
else if (report2.providerId === "fireworks") formatFireworksReport(lines, report2);
|
|
2881
|
+
else if (report2.providerId === "vercel-ai-gateway") formatVercelAIGatewayReport(lines, report2);
|
|
2882
|
+
else if (report2.providerId === "github-copilot") formatGitHubCopilotReport(lines, report2);
|
|
2883
|
+
else if (report2.providerId === "openrouter") formatOpenRouterReport(lines, report2);
|
|
2884
|
+
else if (report2.providerId === "opencode-go") formatOpenCodeZenReport(lines, report2);
|
|
2885
|
+
else if (report2.providerId === "kimi-coding") formatKimiCodingReport(lines, report2);
|
|
2886
|
+
else if (report2.providerId === "moonshotai" || report2.providerId === "moonshotai-cn") {
|
|
2887
|
+
formatMoonshotReport(lines, report2);
|
|
2888
|
+
} else if (report2.providerId === "minimax" || report2.providerId === "minimax-cn") {
|
|
2889
|
+
formatMiniMaxReport(lines, report2);
|
|
2890
|
+
} else if (report2.providerId === "xai") formatXaiReport(lines, report2);
|
|
2891
|
+
else if (report2.providerId === "zai" || report2.providerId === "zai-coding-cn") {
|
|
2892
|
+
formatZaiReport(lines, report2);
|
|
2893
|
+
} else formatGenericReport(lines, report2);
|
|
2894
|
+
if (report2.notes) {
|
|
2895
|
+
for (const note of report2.notes) lines.push(note);
|
|
2147
2896
|
}
|
|
2148
2897
|
return lines.join("\n").trimEnd();
|
|
2149
2898
|
}
|
|
2150
|
-
function formatUsageStatusline(
|
|
2151
|
-
if (
|
|
2152
|
-
|
|
2153
|
-
|
|
2154
|
-
|
|
2155
|
-
if (
|
|
2156
|
-
if (
|
|
2157
|
-
|
|
2899
|
+
function formatUsageStatusline(report2, model, now = Date.now(), showCodexResetCountdown = true) {
|
|
2900
|
+
if (report2.providerId === "baseten") return formatBasetenStatusline(report2);
|
|
2901
|
+
if (report2.providerId === "openai-codex") {
|
|
2902
|
+
return formatCodexStatusline(report2, model, now, showCodexResetCountdown);
|
|
2903
|
+
}
|
|
2904
|
+
if (report2.providerId === "deepseek") return formatDeepSeekStatusline(report2);
|
|
2905
|
+
if (report2.providerId === "fireworks") return formatFireworksStatusline(report2);
|
|
2906
|
+
if (report2.providerId === "vercel-ai-gateway") return formatVercelAIGatewayStatusline(report2);
|
|
2907
|
+
if (report2.providerId === "github-copilot") return formatGitHubCopilotStatusline(report2);
|
|
2908
|
+
if (report2.providerId === "openrouter") {
|
|
2909
|
+
const limit = report2.buckets.find((bucket) => bucket.id === "key-limit");
|
|
2158
2910
|
if (limit?.remaining !== void 0) return `openrouter ${formatUsd(limit.remaining)} left`;
|
|
2159
|
-
const total =
|
|
2911
|
+
const total = report2.metrics.find((metric2) => metric2.id === "usage-total");
|
|
2160
2912
|
if (typeof total?.value === "number") return `openrouter ${formatUsd(total.value)} used`;
|
|
2161
2913
|
}
|
|
2162
|
-
if (
|
|
2163
|
-
if (
|
|
2164
|
-
if (
|
|
2165
|
-
return
|
|
2914
|
+
if (report2.providerId === "opencode-go") return formatOpenCodeZenStatusline(report2);
|
|
2915
|
+
if (report2.providerId === "kimi-coding") return formatKimiCodingStatusline(report2);
|
|
2916
|
+
if (report2.providerId === "moonshotai" || report2.providerId === "moonshotai-cn") {
|
|
2917
|
+
return formatMoonshotStatusline(report2);
|
|
2918
|
+
}
|
|
2919
|
+
if (report2.providerId === "minimax" || report2.providerId === "minimax-cn") {
|
|
2920
|
+
return formatMiniMaxStatusline(report2, model);
|
|
2921
|
+
}
|
|
2922
|
+
if (report2.providerId === "zai" || report2.providerId === "zai-coding-cn") {
|
|
2923
|
+
return formatZaiStatusline(report2);
|
|
2166
2924
|
}
|
|
2167
2925
|
return void 0;
|
|
2168
2926
|
}
|
|
@@ -2175,9 +2933,19 @@ function formatProviderStates(states) {
|
|
|
2175
2933
|
${status}: ${state.message}`;
|
|
2176
2934
|
}).join("\n\n");
|
|
2177
2935
|
}
|
|
2178
|
-
function
|
|
2936
|
+
function formatBasetenReport(lines, report2) {
|
|
2937
|
+
lines.push(`${"Spend window:".padEnd(VALUE_COLUMN)}Last 30 days`);
|
|
2938
|
+
for (const metric2 of report2.metrics) {
|
|
2939
|
+
lines.push(`${`${metric2.label}:`.padEnd(VALUE_COLUMN)}USD ${metric2.value}`);
|
|
2940
|
+
}
|
|
2941
|
+
}
|
|
2942
|
+
function formatBasetenStatusline(report2) {
|
|
2943
|
+
const subtotal = report2.metrics.find((metric2) => metric2.id === "net-subtotal");
|
|
2944
|
+
return subtotal ? `baseten USD ${subtotal.value} net` : "baseten no Model APIs usage";
|
|
2945
|
+
}
|
|
2946
|
+
function formatCodexReport(lines, report2) {
|
|
2179
2947
|
let previousGroup;
|
|
2180
|
-
for (const bucket of
|
|
2948
|
+
for (const bucket of report2.buckets) {
|
|
2181
2949
|
const group = bucket.groupId ?? bucket.id;
|
|
2182
2950
|
if (group !== previousGroup && group !== "codex") {
|
|
2183
2951
|
lines.push(`${bucket.groupLabel ?? group} limit:`);
|
|
@@ -2187,43 +2955,75 @@ function formatCodexReport(lines, report) {
|
|
|
2187
2955
|
const label = `${formatWindowLabel(bucket.windowMinutes, fallback, false)} limit:`;
|
|
2188
2956
|
lines.push(`${label.padEnd(VALUE_COLUMN)}${formatPercentBucket(bucket)}`);
|
|
2189
2957
|
}
|
|
2190
|
-
for (const
|
|
2191
|
-
if (
|
|
2192
|
-
lines.push(`${"Usage limit resets:".padEnd(VALUE_COLUMN)}${
|
|
2193
|
-
} else if (
|
|
2958
|
+
for (const metric2 of report2.metrics) {
|
|
2959
|
+
if (metric2.id === "reset-credits") {
|
|
2960
|
+
lines.push(`${"Usage limit resets:".padEnd(VALUE_COLUMN)}${metric2.value} available`);
|
|
2961
|
+
} else if (metric2.id === "credits") {
|
|
2194
2962
|
lines.push(
|
|
2195
|
-
`${"Credits:".padEnd(VALUE_COLUMN)}${formatMetricValue(
|
|
2963
|
+
`${"Credits:".padEnd(VALUE_COLUMN)}${formatMetricValue(metric2.value, metric2.unit)}`
|
|
2196
2964
|
);
|
|
2197
2965
|
}
|
|
2198
2966
|
}
|
|
2199
2967
|
}
|
|
2200
|
-
function formatDeepSeekReport(lines,
|
|
2201
|
-
const availability =
|
|
2968
|
+
function formatDeepSeekReport(lines, report2) {
|
|
2969
|
+
const availability = report2.metrics.find((metric2) => metric2.id === "api-availability");
|
|
2202
2970
|
lines.push(
|
|
2203
2971
|
`${"API calls:".padEnd(VALUE_COLUMN)}${availability?.value === "available" ? "Available" : "Unavailable"}`
|
|
2204
2972
|
);
|
|
2205
2973
|
for (const currency of ["CNY", "USD"]) {
|
|
2206
|
-
const metrics =
|
|
2974
|
+
const metrics = report2.metrics.filter((metric2) => metric2.currency === currency);
|
|
2207
2975
|
if (metrics.length === 0) continue;
|
|
2208
2976
|
lines.push("", `${currency} balance:`);
|
|
2209
|
-
for (const
|
|
2210
|
-
lines.push(`${`${
|
|
2977
|
+
for (const metric2 of metrics) {
|
|
2978
|
+
lines.push(`${`${metric2.label}:`.padEnd(VALUE_COLUMN)}${currency} ${metric2.value}`);
|
|
2211
2979
|
}
|
|
2212
2980
|
}
|
|
2213
2981
|
}
|
|
2214
|
-
function formatDeepSeekStatusline(
|
|
2215
|
-
const availability =
|
|
2982
|
+
function formatDeepSeekStatusline(report2) {
|
|
2983
|
+
const availability = report2.metrics.find((metric2) => metric2.id === "api-availability");
|
|
2216
2984
|
if (availability?.value !== "available") return "deepseek API unavailable";
|
|
2217
2985
|
const totals = ["CNY", "USD"].flatMap((currency) => {
|
|
2218
|
-
const
|
|
2986
|
+
const metric2 = report2.metrics.find(
|
|
2219
2987
|
(candidate) => candidate.id === `${currency.toLowerCase()}-total`
|
|
2220
2988
|
);
|
|
2221
|
-
return
|
|
2989
|
+
return metric2 ? [`${currency} ${metric2.value}`] : [];
|
|
2222
2990
|
});
|
|
2223
2991
|
return totals.length > 0 ? `deepseek ${totals.join(" \xB7 ")}` : "deepseek balance unavailable";
|
|
2224
2992
|
}
|
|
2225
|
-
function
|
|
2226
|
-
|
|
2993
|
+
function formatFireworksReport(lines, report2) {
|
|
2994
|
+
lines.push(`${"Spend window:".padEnd(VALUE_COLUMN)}Last 30 days (rated)`);
|
|
2995
|
+
for (const currency of fireworksCurrencies(report2)) {
|
|
2996
|
+
lines.push("", `${currency} rated spend:`);
|
|
2997
|
+
for (const metric2 of report2.metrics) {
|
|
2998
|
+
if (metric2.currency !== currency) continue;
|
|
2999
|
+
lines.push(`${`${metric2.label}:`.padEnd(VALUE_COLUMN)}${currency} ${metric2.value}`);
|
|
3000
|
+
}
|
|
3001
|
+
}
|
|
3002
|
+
}
|
|
3003
|
+
function formatFireworksStatusline(report2) {
|
|
3004
|
+
const totals = report2.metrics.filter((metric2) => metric2.id.endsWith("-total"));
|
|
3005
|
+
if (totals.length === 0) return "fireworks no rated usage";
|
|
3006
|
+
return `fireworks ${totals.map((metric2) => `${metric2.currency} ${metric2.value}`).join(" \xB7 ")}`;
|
|
3007
|
+
}
|
|
3008
|
+
function fireworksCurrencies(report2) {
|
|
3009
|
+
const currencies = [];
|
|
3010
|
+
for (const metric2 of report2.metrics) {
|
|
3011
|
+
if (!metric2.currency || currencies.includes(metric2.currency)) continue;
|
|
3012
|
+
currencies.push(metric2.currency);
|
|
3013
|
+
}
|
|
3014
|
+
return currencies;
|
|
3015
|
+
}
|
|
3016
|
+
function formatVercelAIGatewayReport(lines, report2) {
|
|
3017
|
+
for (const metric2 of report2.metrics) {
|
|
3018
|
+
lines.push(`${`${metric2.label}:`.padEnd(VALUE_COLUMN)}USD ${metric2.value}`);
|
|
3019
|
+
}
|
|
3020
|
+
}
|
|
3021
|
+
function formatVercelAIGatewayStatusline(report2) {
|
|
3022
|
+
const balance = report2.metrics.find((metric2) => metric2.id === "credit-balance");
|
|
3023
|
+
return balance ? `vercel USD ${balance.value} left` : "vercel credits unavailable";
|
|
3024
|
+
}
|
|
3025
|
+
function formatGitHubCopilotReport(lines, report2) {
|
|
3026
|
+
const quota = findGitHubCopilotQuota(report2);
|
|
2227
3027
|
if (!quota || quota.limit === void 0 || quota.remaining === void 0) {
|
|
2228
3028
|
lines.push(`${`${quota?.label ?? "Copilot quota"}:`.padEnd(VALUE_COLUMN)}unlimited`);
|
|
2229
3029
|
return;
|
|
@@ -2233,23 +3033,23 @@ function formatGitHubCopilotReport(lines, report) {
|
|
|
2233
3033
|
lines.push(
|
|
2234
3034
|
`${`${quota.label}:`.padEnd(VALUE_COLUMN)}${quota.remaining} of ${quota.limit} left \xB7 ${percent}%${reset}`
|
|
2235
3035
|
);
|
|
2236
|
-
const overage =
|
|
3036
|
+
const overage = report2.metrics.find((metric2) => metric2.id === "overage-used");
|
|
2237
3037
|
if (typeof overage?.value === "number" && overage.value > 0) {
|
|
2238
3038
|
lines.push(`${"Additional usage:".padEnd(VALUE_COLUMN)}${overage.value} ${quota.label}`);
|
|
2239
3039
|
}
|
|
2240
3040
|
}
|
|
2241
|
-
function formatGitHubCopilotStatusline(
|
|
2242
|
-
const quota = findGitHubCopilotQuota(
|
|
3041
|
+
function formatGitHubCopilotStatusline(report2) {
|
|
3042
|
+
const quota = findGitHubCopilotQuota(report2);
|
|
2243
3043
|
const kind = compactGitHubCopilotQuotaKind(quota);
|
|
2244
3044
|
if (!quota || quota.limit === void 0 || quota.remaining === void 0) {
|
|
2245
3045
|
return `copilot ${kind} unlimited`;
|
|
2246
3046
|
}
|
|
2247
|
-
const overage =
|
|
3047
|
+
const overage = report2.metrics.find((metric2) => metric2.id === "overage-used");
|
|
2248
3048
|
const overageSuffix = typeof overage?.value === "number" && overage.value > 0 ? ` +${overage.value} over` : "";
|
|
2249
3049
|
return `copilot ${kind === "premium" ? "" : `${kind} `}${quota.remaining}/${quota.limit} ${percentRemaining(quota)}%${overageSuffix}`;
|
|
2250
3050
|
}
|
|
2251
|
-
function findGitHubCopilotQuota(
|
|
2252
|
-
return
|
|
3051
|
+
function findGitHubCopilotQuota(report2) {
|
|
3052
|
+
return report2.buckets.find(
|
|
2253
3053
|
(bucket) => ["ai-credits", "premium-requests", "chat-requests"].includes(bucket.id)
|
|
2254
3054
|
);
|
|
2255
3055
|
}
|
|
@@ -2262,37 +3062,37 @@ function percentRemaining(bucket) {
|
|
|
2262
3062
|
if (!bucket.limit || bucket.remaining === void 0) return 0;
|
|
2263
3063
|
return Math.round(clampPercent4(bucket.remaining / bucket.limit * 100));
|
|
2264
3064
|
}
|
|
2265
|
-
function formatOpenRouterReport(lines,
|
|
2266
|
-
const limit =
|
|
3065
|
+
function formatOpenRouterReport(lines, report2) {
|
|
3066
|
+
const limit = report2.buckets.find((bucket) => bucket.id === "key-limit");
|
|
2267
3067
|
if (limit) {
|
|
2268
3068
|
const period = limit.period ? ` (${limit.period})` : "";
|
|
2269
3069
|
const value = limit.remaining === void 0 ? `${formatUsd(limit.limit ?? 0)} cap; remaining unavailable` : `${formatUsd(limit.remaining)} of ${formatUsd(limit.limit ?? 0)} left`;
|
|
2270
3070
|
lines.push(`${`Key limit${period}:`.padEnd(VALUE_COLUMN)}${value}`);
|
|
2271
3071
|
}
|
|
2272
|
-
for (const
|
|
3072
|
+
for (const metric2 of report2.metrics) {
|
|
2273
3073
|
lines.push(
|
|
2274
|
-
`${`${
|
|
3074
|
+
`${`${metric2.label}:`.padEnd(VALUE_COLUMN)}${formatMetricValue(metric2.value, metric2.unit)}`
|
|
2275
3075
|
);
|
|
2276
3076
|
}
|
|
2277
3077
|
}
|
|
2278
|
-
function formatOpenCodeZenReport(lines,
|
|
2279
|
-
for (const bucket of
|
|
3078
|
+
function formatOpenCodeZenReport(lines, report2) {
|
|
3079
|
+
for (const bucket of report2.buckets) {
|
|
2280
3080
|
const reset = bucket.resetsAt ? ` (resets ${formatReset(bucket.resetsAt)})` : "";
|
|
2281
3081
|
const used = bucket.used ?? "unavailable";
|
|
2282
3082
|
lines.push(`${`${bucket.label}:`.padEnd(VALUE_COLUMN)}${used}% used${reset}`);
|
|
2283
3083
|
}
|
|
2284
3084
|
}
|
|
2285
|
-
function formatOpenCodeZenStatusline(
|
|
3085
|
+
function formatOpenCodeZenStatusline(report2) {
|
|
2286
3086
|
const parts = ["zen"];
|
|
2287
|
-
for (const bucket of
|
|
3087
|
+
for (const bucket of report2.buckets) {
|
|
2288
3088
|
if (bucket.used === void 0) continue;
|
|
2289
3089
|
const compact = bucket.id === "rolling" ? "r" : bucket.id === "weekly" ? "w" : "m";
|
|
2290
3090
|
parts.push(`${clampPercent4(bucket.used).toFixed(0)}% ${compact}`);
|
|
2291
3091
|
}
|
|
2292
3092
|
return parts.length > 1 ? parts.join(" ") : void 0;
|
|
2293
3093
|
}
|
|
2294
|
-
function formatKimiCodingReport(lines,
|
|
2295
|
-
for (const bucket of
|
|
3094
|
+
function formatKimiCodingReport(lines, report2) {
|
|
3095
|
+
for (const bucket of report2.buckets) {
|
|
2296
3096
|
const reset = bucket.resetsAt ? ` (resets ${formatReset(bucket.resetsAt)})` : "";
|
|
2297
3097
|
if (bucket.used === void 0 || bucket.limit === void 0) {
|
|
2298
3098
|
lines.push(`${`${bucket.label}:`.padEnd(VALUE_COLUMN)}unavailable${reset}`);
|
|
@@ -2302,10 +3102,10 @@ function formatKimiCodingReport(lines, report) {
|
|
|
2302
3102
|
`${`${bucket.label}:`.padEnd(VALUE_COLUMN)}${bucket.used} of ${bucket.limit} used \xB7 ${percentRemaining(bucket)}% left${reset}`
|
|
2303
3103
|
);
|
|
2304
3104
|
}
|
|
2305
|
-
const balance =
|
|
2306
|
-
const total =
|
|
2307
|
-
const monthlyUsed =
|
|
2308
|
-
const monthlyLimit =
|
|
3105
|
+
const balance = report2.metrics.find((metric2) => metric2.id === "booster-balance");
|
|
3106
|
+
const total = report2.metrics.find((metric2) => metric2.id === "booster-total");
|
|
3107
|
+
const monthlyUsed = report2.metrics.find((metric2) => metric2.id === "booster-monthly-used");
|
|
3108
|
+
const monthlyLimit = report2.metrics.find((metric2) => metric2.id === "booster-monthly-limit");
|
|
2309
3109
|
if (!balance && !monthlyUsed && !monthlyLimit) return;
|
|
2310
3110
|
lines.push("", "Extra usage wallet:");
|
|
2311
3111
|
if (balance) {
|
|
@@ -2319,10 +3119,10 @@ function formatKimiCodingReport(lines, report) {
|
|
|
2319
3119
|
lines.push(`${"Monthly limit:".padEnd(VALUE_COLUMN)}${formatCurrencyMetric(monthlyLimit)}`);
|
|
2320
3120
|
}
|
|
2321
3121
|
}
|
|
2322
|
-
function formatKimiCodingStatusline(
|
|
2323
|
-
const fiveHour =
|
|
2324
|
-
const weekly =
|
|
2325
|
-
const subWindow = fiveHour ??
|
|
3122
|
+
function formatKimiCodingStatusline(report2) {
|
|
3123
|
+
const fiveHour = report2.buckets.find((bucket) => bucket.id === "five-hour");
|
|
3124
|
+
const weekly = report2.buckets.find((bucket) => bucket.id === "weekly");
|
|
3125
|
+
const subWindow = fiveHour ?? report2.buckets.find((bucket) => bucket.id !== "weekly");
|
|
2326
3126
|
const selected = [subWindow, weekly].filter(
|
|
2327
3127
|
(bucket, index, buckets) => bucket !== void 0 && buckets.indexOf(bucket) === index
|
|
2328
3128
|
);
|
|
@@ -2336,10 +3136,98 @@ function formatKimiCodingStatusline(report) {
|
|
|
2336
3136
|
}
|
|
2337
3137
|
return parts.length > 1 ? parts.join(" ") : void 0;
|
|
2338
3138
|
}
|
|
2339
|
-
function
|
|
3139
|
+
function formatMoonshotReport(lines, report2) {
|
|
3140
|
+
for (const metric2 of report2.metrics) {
|
|
3141
|
+
lines.push(`${`${metric2.label}:`.padEnd(VALUE_COLUMN)}${metric2.currency} ${metric2.value}`);
|
|
3142
|
+
}
|
|
3143
|
+
}
|
|
3144
|
+
function formatMoonshotStatusline(report2) {
|
|
3145
|
+
const available = report2.metrics.find((metric2) => metric2.id === "available-balance");
|
|
3146
|
+
if (!available) return "moonshot balance unavailable";
|
|
3147
|
+
return `moonshot ${available.currency ?? ""} ${available.value}`.replace(/\s+/gu, " ");
|
|
3148
|
+
}
|
|
3149
|
+
function formatMiniMaxReport(lines, report2) {
|
|
3150
|
+
if (report2.source === "minimax-account-balance") {
|
|
3151
|
+
for (const metric2 of report2.metrics) {
|
|
3152
|
+
lines.push(`${`${metric2.label}:`.padEnd(VALUE_COLUMN)}${metric2.currency} ${metric2.value}`);
|
|
3153
|
+
}
|
|
3154
|
+
return;
|
|
3155
|
+
}
|
|
3156
|
+
let previousGroup;
|
|
3157
|
+
for (const bucket of report2.buckets) {
|
|
3158
|
+
if (bucket.groupId !== previousGroup) lines.push(`${bucket.groupLabel ?? "Token Plan"}:`);
|
|
3159
|
+
previousGroup = bucket.groupId;
|
|
3160
|
+
const reset = bucket.resetsAt ? ` (resets ${formatReset(bucket.resetsAt)})` : "";
|
|
3161
|
+
const value = bucket.period === "unlimited" ? "unlimited" : bucket.limit && bucket.remaining !== void 0 ? `${bucket.remaining} of ${bucket.limit} left \xB7 ${percentRemaining(bucket)}%${reset}` : "unavailable";
|
|
3162
|
+
lines.push(`${`${bucket.label}:`.padEnd(VALUE_COLUMN)}${value}`);
|
|
3163
|
+
}
|
|
3164
|
+
}
|
|
3165
|
+
function formatMiniMaxStatusline(report2, model) {
|
|
3166
|
+
const prefix = report2.providerId === "minimax-cn" ? "minimax cn" : "minimax";
|
|
3167
|
+
if (report2.source === "minimax-account-balance") {
|
|
3168
|
+
const available = report2.metrics.find((metric2) => metric2.id === "available-balance");
|
|
3169
|
+
return available ? `${prefix} ${available.currency} ${available.value}` : void 0;
|
|
3170
|
+
}
|
|
3171
|
+
const selectedGroup = selectMiniMaxGroup(report2, model);
|
|
3172
|
+
if (!selectedGroup) return void 0;
|
|
3173
|
+
const selected = report2.buckets.filter((bucket) => bucket.groupId === selectedGroup);
|
|
3174
|
+
const parts = [prefix];
|
|
3175
|
+
for (const bucket of selected) {
|
|
3176
|
+
const fallback = bucket.id.endsWith(":weekly") ? "weekly" : "5h";
|
|
3177
|
+
const window = formatWindowLabel(bucket.windowMinutes, fallback, true);
|
|
3178
|
+
if (bucket.period === "unlimited") {
|
|
3179
|
+
parts.push(`unlimited ${window}`);
|
|
3180
|
+
continue;
|
|
3181
|
+
}
|
|
3182
|
+
if (!bucket.limit || bucket.remaining === void 0) continue;
|
|
3183
|
+
parts.push(`${percentRemaining(bucket)}% ${window}`);
|
|
3184
|
+
}
|
|
3185
|
+
return parts.length > 1 ? parts.join(" ") : void 0;
|
|
3186
|
+
}
|
|
3187
|
+
function selectMiniMaxGroup(report2, model) {
|
|
3188
|
+
const groups = [
|
|
3189
|
+
...new Set(
|
|
3190
|
+
report2.buckets.map((bucket) => bucket.groupId).filter((group) => group !== void 0)
|
|
3191
|
+
)
|
|
3192
|
+
];
|
|
3193
|
+
if (groups.length <= 1) return groups[0];
|
|
3194
|
+
if (model?.provider !== report2.providerId) return void 0;
|
|
3195
|
+
const modelKeys = [model.id, model.name].map(normalizeMiniMaxModelKey).filter((key) => key !== void 0);
|
|
3196
|
+
const candidates = groups.map((group) => {
|
|
3197
|
+
const bucket = report2.buckets.find((candidate) => candidate.groupId === group);
|
|
3198
|
+
const patterns = [bucket?.groupLabel, ...bucket?.modelKeys ?? [], group].map(normalizeMiniMaxModelKey).filter((key) => key !== void 0);
|
|
3199
|
+
return { group, patterns };
|
|
3200
|
+
});
|
|
3201
|
+
const exact = candidates.find(
|
|
3202
|
+
({ patterns }) => patterns.some((pattern) => !pattern.includes("*") && modelKeys.includes(pattern))
|
|
3203
|
+
);
|
|
3204
|
+
if (exact) return exact.group;
|
|
3205
|
+
return candidates.find(
|
|
3206
|
+
({ patterns }) => patterns.some(
|
|
3207
|
+
(pattern) => pattern.includes("*") && modelKeys.some((key) => wildcardKeyMatches(pattern, key))
|
|
3208
|
+
)
|
|
3209
|
+
)?.group;
|
|
3210
|
+
}
|
|
3211
|
+
function normalizeMiniMaxModelKey(value) {
|
|
3212
|
+
const key = value?.toLowerCase().replace(/[^a-z0-9*]+/gu, "");
|
|
3213
|
+
return key && /[a-z0-9]/u.test(key) ? key : void 0;
|
|
3214
|
+
}
|
|
3215
|
+
function wildcardKeyMatches(pattern, value) {
|
|
3216
|
+
if (!pattern.includes("*")) return pattern === value;
|
|
3217
|
+
const segments = pattern.split("*").filter(Boolean);
|
|
3218
|
+
let offset = 0;
|
|
3219
|
+
for (const [index, segment] of segments.entries()) {
|
|
3220
|
+
const found = value.indexOf(segment, offset);
|
|
3221
|
+
if (found < 0 || index === 0 && !pattern.startsWith("*") && found !== 0) return false;
|
|
3222
|
+
offset = found + segment.length;
|
|
3223
|
+
}
|
|
3224
|
+
const last = segments.at(-1);
|
|
3225
|
+
return pattern.endsWith("*") || last !== void 0 && value.endsWith(last);
|
|
3226
|
+
}
|
|
3227
|
+
function formatZaiStatusline(report2) {
|
|
2340
3228
|
const selected = [
|
|
2341
|
-
|
|
2342
|
-
|
|
3229
|
+
report2.buckets.find((bucket) => bucket.id === "five-hour"),
|
|
3230
|
+
report2.buckets.find((bucket) => bucket.id === "weekly")
|
|
2343
3231
|
];
|
|
2344
3232
|
const parts = ["zai"];
|
|
2345
3233
|
for (const bucket of selected) {
|
|
@@ -2351,15 +3239,15 @@ function formatZaiStatusline(report) {
|
|
|
2351
3239
|
}
|
|
2352
3240
|
return parts.length > 1 ? parts.join(" ") : void 0;
|
|
2353
3241
|
}
|
|
2354
|
-
function formatCurrencyMetric(
|
|
2355
|
-
if (typeof
|
|
2356
|
-
if (!
|
|
2357
|
-
if (
|
|
2358
|
-
if (
|
|
2359
|
-
return `${
|
|
3242
|
+
function formatCurrencyMetric(metric2) {
|
|
3243
|
+
if (typeof metric2.value !== "number") return String(metric2.value);
|
|
3244
|
+
if (!metric2.currency) return "unavailable";
|
|
3245
|
+
if (metric2.currency === "USD") return `$${metric2.value.toFixed(2)}`;
|
|
3246
|
+
if (metric2.currency === "CNY") return `\xA5${metric2.value.toFixed(2)}`;
|
|
3247
|
+
return `${metric2.value.toFixed(2)} ${metric2.currency}`;
|
|
2360
3248
|
}
|
|
2361
|
-
function formatXaiReport(lines,
|
|
2362
|
-
const included =
|
|
3249
|
+
function formatXaiReport(lines, report2) {
|
|
3250
|
+
const included = report2.buckets.find((bucket) => bucket.id === "included-allowance");
|
|
2363
3251
|
if (included) {
|
|
2364
3252
|
let value = "unavailable";
|
|
2365
3253
|
if (included.unit === "percent" && included.used !== void 0) {
|
|
@@ -2375,20 +3263,20 @@ function formatXaiReport(lines, report) {
|
|
|
2375
3263
|
const reset = included.resetsAt ? ` (resets ${formatReset(included.resetsAt)})` : "";
|
|
2376
3264
|
lines.push(`${"Included allowance:".padEnd(VALUE_COLUMN)}${value}${period}${reset}`);
|
|
2377
3265
|
}
|
|
2378
|
-
const onDemand =
|
|
3266
|
+
const onDemand = report2.buckets.find((bucket) => bucket.id === "on-demand");
|
|
2379
3267
|
if (onDemand) {
|
|
2380
3268
|
let value = onDemand.used === void 0 ? "usage unavailable" : `${formatUsd(onDemand.used)} used`;
|
|
2381
3269
|
if (onDemand.limit !== void 0) value += ` of ${formatUsd(onDemand.limit)} cap`;
|
|
2382
3270
|
lines.push(`${"On-demand usage:".padEnd(VALUE_COLUMN)}${value}`);
|
|
2383
3271
|
}
|
|
2384
|
-
for (const
|
|
3272
|
+
for (const metric2 of report2.metrics) {
|
|
2385
3273
|
lines.push(
|
|
2386
|
-
`${`${
|
|
3274
|
+
`${`${metric2.label}:`.padEnd(VALUE_COLUMN)}${formatMetricValue(metric2.value, metric2.unit)}`
|
|
2387
3275
|
);
|
|
2388
3276
|
}
|
|
2389
3277
|
}
|
|
2390
|
-
function formatZaiReport(lines,
|
|
2391
|
-
for (const bucket of
|
|
3278
|
+
function formatZaiReport(lines, report2) {
|
|
3279
|
+
for (const bucket of report2.buckets) {
|
|
2392
3280
|
const reset = bucket.resetsAt ? ` (resets ${formatReset(bucket.resetsAt)})` : "";
|
|
2393
3281
|
let value = "unavailable";
|
|
2394
3282
|
if (bucket.unit === "percent" && bucket.used !== void 0) {
|
|
@@ -2404,28 +3292,28 @@ function formatZaiReport(lines, report) {
|
|
|
2404
3292
|
}
|
|
2405
3293
|
lines.push(`${`${bucket.label}:`.padEnd(VALUE_COLUMN)}${value}${reset}`);
|
|
2406
3294
|
}
|
|
2407
|
-
for (const
|
|
3295
|
+
for (const metric2 of report2.metrics) {
|
|
2408
3296
|
lines.push(
|
|
2409
|
-
`${`${
|
|
3297
|
+
`${`${metric2.label}:`.padEnd(VALUE_COLUMN)}${formatMetricValue(metric2.value, metric2.unit)}`
|
|
2410
3298
|
);
|
|
2411
3299
|
}
|
|
2412
3300
|
}
|
|
2413
|
-
function formatGenericReport(lines,
|
|
2414
|
-
for (const bucket of
|
|
3301
|
+
function formatGenericReport(lines, report2) {
|
|
3302
|
+
for (const bucket of report2.buckets) {
|
|
2415
3303
|
lines.push(
|
|
2416
3304
|
`${`${bucket.label}:`.padEnd(VALUE_COLUMN)}${formatMetricValue(bucket.remaining ?? bucket.used ?? "unavailable", bucket.unit)}`
|
|
2417
3305
|
);
|
|
2418
3306
|
}
|
|
2419
|
-
for (const
|
|
3307
|
+
for (const metric2 of report2.metrics) {
|
|
2420
3308
|
lines.push(
|
|
2421
|
-
`${`${
|
|
3309
|
+
`${`${metric2.label}:`.padEnd(VALUE_COLUMN)}${formatMetricValue(metric2.value, metric2.unit)}`
|
|
2422
3310
|
);
|
|
2423
3311
|
}
|
|
2424
3312
|
}
|
|
2425
|
-
function formatCodexStatusline(
|
|
2426
|
-
const group = selectCodexGroup(
|
|
2427
|
-
if (!group) return formatCodexCreditsStatus(
|
|
2428
|
-
const buckets =
|
|
3313
|
+
function formatCodexStatusline(report2, model, now = Date.now(), showResetCountdown = true) {
|
|
3314
|
+
const group = selectCodexGroup(report2, model);
|
|
3315
|
+
if (!group) return formatCodexCreditsStatus(report2);
|
|
3316
|
+
const buckets = report2.buckets.filter((bucket) => (bucket.groupId ?? bucket.id) === group);
|
|
2429
3317
|
const labelBucket = buckets[0];
|
|
2430
3318
|
const parts = [
|
|
2431
3319
|
group === "codex" ? "codex" : `codex ${compactLimitLabel(labelBucket?.groupLabel ?? group)}`
|
|
@@ -2442,24 +3330,24 @@ function formatCodexStatusline(report, model, now = Date.now(), showResetCountdo
|
|
|
2442
3330
|
const reset = formatResetCountdown(bucket.resetsAt, now);
|
|
2443
3331
|
parts.push(`${percent} ${reset ? `\u21BB ${reset}` : window}`);
|
|
2444
3332
|
}
|
|
2445
|
-
return parts.length > 1 ? parts.join(" ") : formatCodexCreditsStatus(
|
|
3333
|
+
return parts.length > 1 ? parts.join(" ") : formatCodexCreditsStatus(report2);
|
|
2446
3334
|
}
|
|
2447
|
-
function formatCodexCreditsStatus(
|
|
2448
|
-
const credits =
|
|
3335
|
+
function formatCodexCreditsStatus(report2) {
|
|
3336
|
+
const credits = report2.metrics.find((metric2) => metric2.id === "credits");
|
|
2449
3337
|
if (!credits) return "codex usage unavailable";
|
|
2450
3338
|
if (credits.value === "none") return "codex no credits";
|
|
2451
3339
|
if (credits.value === "available") return "codex credits available";
|
|
2452
3340
|
if (credits.value === "unlimited") return "codex credits unlimited";
|
|
2453
3341
|
return `codex ${formatMetricValue(credits.value, "count")} credits`;
|
|
2454
3342
|
}
|
|
2455
|
-
function selectCodexGroup(
|
|
2456
|
-
const groups = [...new Set(
|
|
3343
|
+
function selectCodexGroup(report2, model) {
|
|
3344
|
+
const groups = [...new Set(report2.buckets.map((bucket) => bucket.groupId ?? bucket.id))];
|
|
2457
3345
|
if (model?.provider !== "openai-codex") {
|
|
2458
3346
|
return groups.includes("codex") ? "codex" : groups[0];
|
|
2459
3347
|
}
|
|
2460
3348
|
const modelKeys = normalizedModelKeys(model);
|
|
2461
3349
|
for (const group of groups) {
|
|
2462
|
-
const bucket =
|
|
3350
|
+
const bucket = report2.buckets.find(
|
|
2463
3351
|
(candidate) => (candidate.groupId ?? candidate.id) === group
|
|
2464
3352
|
);
|
|
2465
3353
|
const keys = [group, bucket?.groupLabel, ...bucket?.modelKeys ?? []].map(normalizeKey).filter((key) => key !== void 0);
|
|
@@ -2583,9 +3471,13 @@ function normalizeUsageSettings(value) {
|
|
|
2583
3471
|
if (Object.hasOwn(value, "codexStatusResetCountdown") && typeof value.codexStatusResetCountdown !== "boolean") {
|
|
2584
3472
|
return void 0;
|
|
2585
3473
|
}
|
|
3474
|
+
if (Object.hasOwn(value, "fireworksAccountId") && !isFireworksAccountId(value.fireworksAccountId)) {
|
|
3475
|
+
return void 0;
|
|
3476
|
+
}
|
|
2586
3477
|
return {
|
|
2587
3478
|
codexFastMode: typeof value.codexFastMode === "boolean" ? value.codexFastMode : DEFAULT_USAGE_SETTINGS.codexFastMode,
|
|
2588
|
-
codexStatusResetCountdown: typeof value.codexStatusResetCountdown === "boolean" ? value.codexStatusResetCountdown : DEFAULT_USAGE_SETTINGS.codexStatusResetCountdown
|
|
3479
|
+
codexStatusResetCountdown: typeof value.codexStatusResetCountdown === "boolean" ? value.codexStatusResetCountdown : DEFAULT_USAGE_SETTINGS.codexStatusResetCountdown,
|
|
3480
|
+
...isFireworksAccountId(value.fireworksAccountId) ? { fireworksAccountId: value.fireworksAccountId } : {}
|
|
2589
3481
|
};
|
|
2590
3482
|
}
|
|
2591
3483
|
async function loadUsageSettings(path = usageSettingsPath(), signal) {
|
|
@@ -2669,7 +3561,11 @@ async function saveUsageSettingsPatch(path, patch, operations, signal) {
|
|
|
2669
3561
|
if (latest.kind === "invalid") {
|
|
2670
3562
|
throw new Error("Cannot overwrite an invalid pi-usage.json; repair it and reload first");
|
|
2671
3563
|
}
|
|
2672
|
-
const document = { ...latest.document
|
|
3564
|
+
const document = { ...latest.document };
|
|
3565
|
+
for (const [key, value] of Object.entries(patch)) {
|
|
3566
|
+
if (value === void 0) delete document[key];
|
|
3567
|
+
else document[key] = value;
|
|
3568
|
+
}
|
|
2673
3569
|
const settings = normalizeUsageSettings(document);
|
|
2674
3570
|
if (!settings) throw new Error("Refusing to save invalid pi-usage settings");
|
|
2675
3571
|
const directory = dirname(path);
|
|
@@ -2715,7 +3611,7 @@ import { randomUUID as randomUUID2 } from "node:crypto";
|
|
|
2715
3611
|
// src/codex-fast-runtime.ts
|
|
2716
3612
|
var NO_FAST_REQUEST = /* @__PURE__ */ Symbol("no-fast-request");
|
|
2717
3613
|
var FAST_USAGE_WARNING = "Fast is about 1.5\xD7 faster and uses more of your plan allowance.";
|
|
2718
|
-
function registerCodexFastMode(pi, settingsRuntime, refreshStatus) {
|
|
3614
|
+
function registerCodexFastMode(pi, settingsRuntime, refreshStatus, options = {}) {
|
|
2719
3615
|
let sessionController = new AbortController();
|
|
2720
3616
|
let generation = 0;
|
|
2721
3617
|
const pendingFastRequests = /* @__PURE__ */ new Map();
|
|
@@ -2771,37 +3667,42 @@ function registerCodexFastMode(pi, settingsRuntime, refreshStatus) {
|
|
|
2771
3667
|
await toggle(ctx, !availability.enabled);
|
|
2772
3668
|
}
|
|
2773
3669
|
});
|
|
2774
|
-
|
|
3670
|
+
const prepareSession = (ctx) => {
|
|
3671
|
+
const sessionId = ctx.sessionManager.getSessionId();
|
|
2775
3672
|
generation += 1;
|
|
2776
3673
|
sessionController.abort();
|
|
2777
3674
|
pendingFastRequests.clear();
|
|
2778
3675
|
sessionController = new AbortController();
|
|
2779
3676
|
const ownerGeneration = generation;
|
|
2780
|
-
|
|
2781
|
-
|
|
2782
|
-
|
|
2783
|
-
|
|
2784
|
-
|
|
2785
|
-
|
|
2786
|
-
|
|
3677
|
+
return (async () => {
|
|
3678
|
+
let state;
|
|
3679
|
+
try {
|
|
3680
|
+
state = await settingsRuntime.reload(sessionController.signal);
|
|
3681
|
+
} catch (error) {
|
|
3682
|
+
if (sessionController.signal.aborted || ownerGeneration !== generation) return;
|
|
3683
|
+
if (ctx.hasUI) {
|
|
3684
|
+
ctx.ui.notify(
|
|
3685
|
+
`Could not load pi-usage.json; using defaults. ${errorMessage(error)}`,
|
|
3686
|
+
"warning"
|
|
3687
|
+
);
|
|
3688
|
+
}
|
|
3689
|
+
return;
|
|
3690
|
+
}
|
|
3691
|
+
if (sessionController.signal.aborted || ownerGeneration !== generation || ctx.sessionManager.getSessionId() !== sessionId) {
|
|
3692
|
+
return;
|
|
3693
|
+
}
|
|
3694
|
+
if (ctx.hasUI && state.kind === "invalid") {
|
|
2787
3695
|
ctx.ui.notify(
|
|
2788
|
-
`
|
|
3696
|
+
`Invalid pi-usage.json; using defaults without overwriting it. ${state.issue}`,
|
|
2789
3697
|
"warning"
|
|
2790
3698
|
);
|
|
2791
3699
|
}
|
|
2792
|
-
|
|
2793
|
-
}
|
|
2794
|
-
|
|
2795
|
-
|
|
2796
|
-
|
|
2797
|
-
|
|
2798
|
-
ctx.ui.notify(
|
|
2799
|
-
`Invalid pi-usage.json; using defaults without overwriting it. ${state.issue}`,
|
|
2800
|
-
"warning"
|
|
2801
|
-
);
|
|
2802
|
-
}
|
|
2803
|
-
refreshStatus(ctx);
|
|
2804
|
-
});
|
|
3700
|
+
refreshStatus(ctx);
|
|
3701
|
+
})();
|
|
3702
|
+
};
|
|
3703
|
+
if (options.registerSessionStart !== false) {
|
|
3704
|
+
pi.on("session_start", async (_event, ctx) => prepareSession(ctx));
|
|
3705
|
+
}
|
|
2805
3706
|
pi.on("before_provider_request", (event, ctx) => {
|
|
2806
3707
|
const rewritten = rewriteCodexFastPayload(
|
|
2807
3708
|
event.payload,
|
|
@@ -2834,6 +3735,7 @@ function registerCodexFastMode(pi, settingsRuntime, refreshStatus) {
|
|
|
2834
3735
|
await settingsRuntime.flush();
|
|
2835
3736
|
});
|
|
2836
3737
|
return {
|
|
3738
|
+
prepareSession,
|
|
2837
3739
|
availability(model) {
|
|
2838
3740
|
return codexFastAvailability(model, settingsRuntime.get().settings.codexFastMode);
|
|
2839
3741
|
},
|
|
@@ -2912,6 +3814,8 @@ import {
|
|
|
2912
3814
|
SettingsList,
|
|
2913
3815
|
Text
|
|
2914
3816
|
} from "@earendil-works/pi-tui";
|
|
3817
|
+
var AUTO = "Auto";
|
|
3818
|
+
var EDIT = "Edit\u2026";
|
|
2915
3819
|
var OFF = "Off";
|
|
2916
3820
|
var ON = "On";
|
|
2917
3821
|
async function showUsageSettings(ctx, settingsRuntime, parentSignal, isCurrent, onApplied) {
|
|
@@ -2919,7 +3823,23 @@ async function showUsageSettings(ctx, settingsRuntime, parentSignal, isCurrent,
|
|
|
2919
3823
|
if (ctx.hasUI) ctx.ui.notify(`Edit settings manually: ${settingsRuntime.get().path}`, "info");
|
|
2920
3824
|
return false;
|
|
2921
3825
|
}
|
|
2922
|
-
|
|
3826
|
+
let changed = false;
|
|
3827
|
+
while (!parentSignal.aborted && isCurrent()) {
|
|
3828
|
+
const result = await showSettingsList(ctx, settingsRuntime, parentSignal, isCurrent, onApplied);
|
|
3829
|
+
if (!result) return changed;
|
|
3830
|
+
changed ||= result.changed;
|
|
3831
|
+
if (!result.editFireworksAccount) return changed;
|
|
3832
|
+
changed ||= await editFireworksAccount(
|
|
3833
|
+
ctx,
|
|
3834
|
+
settingsRuntime,
|
|
3835
|
+
parentSignal,
|
|
3836
|
+
isCurrent,
|
|
3837
|
+
onApplied
|
|
3838
|
+
);
|
|
3839
|
+
}
|
|
3840
|
+
return changed;
|
|
3841
|
+
}
|
|
3842
|
+
async function showSettingsList(ctx, settingsRuntime, parentSignal, isCurrent, onApplied) {
|
|
2923
3843
|
return ctx.ui.custom((tui, theme, _keybindings, done) => {
|
|
2924
3844
|
const localController = new AbortController();
|
|
2925
3845
|
const signal = AbortSignal.any([parentSignal, localController.signal]);
|
|
@@ -2927,6 +3847,7 @@ async function showUsageSettings(ctx, settingsRuntime, parentSignal, isCurrent,
|
|
|
2927
3847
|
let closing = false;
|
|
2928
3848
|
let saveQueue = Promise.resolve();
|
|
2929
3849
|
const state = settingsRuntime.get();
|
|
3850
|
+
const fireworksValue = state.settings.fireworksAccountId ?? AUTO;
|
|
2930
3851
|
const items = [
|
|
2931
3852
|
{
|
|
2932
3853
|
id: "codexFastMode",
|
|
@@ -2941,6 +3862,13 @@ async function showUsageSettings(ctx, settingsRuntime, parentSignal, isCurrent,
|
|
|
2941
3862
|
description: "Show time remaining until each Codex usage limit resets.",
|
|
2942
3863
|
currentValue: state.settings.codexStatusResetCountdown ? ON : OFF,
|
|
2943
3864
|
values: [OFF, ON]
|
|
3865
|
+
},
|
|
3866
|
+
{
|
|
3867
|
+
id: "fireworksAccountId",
|
|
3868
|
+
label: "Fireworks account",
|
|
3869
|
+
description: "Select Edit to enter a visible account slug, or submit blank to clear it.",
|
|
3870
|
+
currentValue: fireworksValue,
|
|
3871
|
+
values: state.settings.fireworksAccountId ? [state.settings.fireworksAccountId, EDIT] : [AUTO, EDIT]
|
|
2944
3872
|
}
|
|
2945
3873
|
];
|
|
2946
3874
|
const container = new Container();
|
|
@@ -2950,7 +3878,36 @@ async function showUsageSettings(ctx, settingsRuntime, parentSignal, isCurrent,
|
|
|
2950
3878
|
if (closing) return;
|
|
2951
3879
|
closing = true;
|
|
2952
3880
|
localController.abort();
|
|
2953
|
-
done(changed);
|
|
3881
|
+
done({ changed, editFireworksAccount: false });
|
|
3882
|
+
};
|
|
3883
|
+
const queueUpdate = (id, requested, display) => {
|
|
3884
|
+
saveQueue = saveQueue.then(async () => {
|
|
3885
|
+
const previous = settingsRuntime.get().settings[id];
|
|
3886
|
+
if (settingsRuntime.get().kind === "invalid") {
|
|
3887
|
+
settingsList.updateValue(id, displaySetting(id, previous));
|
|
3888
|
+
if (!signal.aborted && isCurrent()) {
|
|
3889
|
+
ctx.ui.notify("Repair pi-usage.json and reload before changing settings.", "error");
|
|
3890
|
+
tui.requestRender();
|
|
3891
|
+
}
|
|
3892
|
+
return;
|
|
3893
|
+
}
|
|
3894
|
+
try {
|
|
3895
|
+
await settingsRuntime.update({ [id]: requested }, signal);
|
|
3896
|
+
} catch (error) {
|
|
3897
|
+
if (signal.aborted || !isCurrent()) return;
|
|
3898
|
+
settingsList.updateValue(id, displaySetting(id, previous));
|
|
3899
|
+
ctx.ui.notify(`Could not save pi-usage.json: ${errorMessage(error)}`, "error");
|
|
3900
|
+
tui.requestRender();
|
|
3901
|
+
return;
|
|
3902
|
+
}
|
|
3903
|
+
if (previous !== requested) {
|
|
3904
|
+
changed = true;
|
|
3905
|
+
onApplied(id);
|
|
3906
|
+
}
|
|
3907
|
+
if (signal.aborted || !isCurrent()) return;
|
|
3908
|
+
settingsList.updateValue(id, display);
|
|
3909
|
+
tui.requestRender();
|
|
3910
|
+
});
|
|
2954
3911
|
};
|
|
2955
3912
|
settingsList = new SettingsList(
|
|
2956
3913
|
items,
|
|
@@ -2958,35 +3915,18 @@ async function showUsageSettings(ctx, settingsRuntime, parentSignal, isCurrent,
|
|
|
2958
3915
|
getSettingsListTheme(),
|
|
2959
3916
|
(id, value) => {
|
|
2960
3917
|
if (closing || signal.aborted || !isCurrent()) return;
|
|
2961
|
-
|
|
2962
|
-
|
|
2963
|
-
|
|
2964
|
-
|
|
2965
|
-
|
|
2966
|
-
|
|
2967
|
-
|
|
2968
|
-
ctx.ui.notify("Repair pi-usage.json and reload before changing settings.", "error");
|
|
2969
|
-
tui.requestRender();
|
|
2970
|
-
}
|
|
2971
|
-
return;
|
|
2972
|
-
}
|
|
2973
|
-
try {
|
|
2974
|
-
await settingsRuntime.update({ [settingId]: requested }, signal);
|
|
2975
|
-
} catch (error) {
|
|
2976
|
-
if (signal.aborted || !isCurrent()) return;
|
|
2977
|
-
settingsList.updateValue(id, displayValue(previous));
|
|
2978
|
-
ctx.ui.notify(`Could not save pi-usage.json: ${errorMessage(error)}`, "error");
|
|
2979
|
-
tui.requestRender();
|
|
2980
|
-
return;
|
|
2981
|
-
}
|
|
2982
|
-
if (previous !== requested) {
|
|
2983
|
-
changed = true;
|
|
2984
|
-
onApplied(settingId);
|
|
3918
|
+
if (id === "fireworksAccountId") {
|
|
3919
|
+
if (value === EDIT) {
|
|
3920
|
+
saveQueue = saveQueue.then(() => {
|
|
3921
|
+
if (closing || signal.aborted || !isCurrent()) return;
|
|
3922
|
+
closing = true;
|
|
3923
|
+
done({ changed, editFireworksAccount: true });
|
|
3924
|
+
});
|
|
2985
3925
|
}
|
|
2986
|
-
|
|
2987
|
-
|
|
2988
|
-
|
|
2989
|
-
|
|
3926
|
+
return;
|
|
3927
|
+
}
|
|
3928
|
+
const settingId = id;
|
|
3929
|
+
queueUpdate(settingId, value !== OFF, value);
|
|
2990
3930
|
},
|
|
2991
3931
|
cancel
|
|
2992
3932
|
);
|
|
@@ -3008,8 +3948,41 @@ async function showUsageSettings(ctx, settingsRuntime, parentSignal, isCurrent,
|
|
|
3008
3948
|
};
|
|
3009
3949
|
});
|
|
3010
3950
|
}
|
|
3011
|
-
function
|
|
3012
|
-
|
|
3951
|
+
async function editFireworksAccount(ctx, settingsRuntime, signal, isCurrent, onApplied) {
|
|
3952
|
+
while (!signal.aborted && isCurrent()) {
|
|
3953
|
+
const state = settingsRuntime.get();
|
|
3954
|
+
if (state.kind === "invalid") {
|
|
3955
|
+
ctx.ui.notify("Repair pi-usage.json and reload before changing settings.", "error");
|
|
3956
|
+
return false;
|
|
3957
|
+
}
|
|
3958
|
+
const entered = await ctx.ui.input(
|
|
3959
|
+
"Fireworks account slug \xB7 submit blank for Auto",
|
|
3960
|
+
state.settings.fireworksAccountId ?? "Example: acme",
|
|
3961
|
+
{ signal }
|
|
3962
|
+
);
|
|
3963
|
+
if (signal.aborted || !isCurrent() || entered === void 0) return false;
|
|
3964
|
+
const normalized = entered.trim();
|
|
3965
|
+
const requested = normalized || void 0;
|
|
3966
|
+
if (requested !== void 0 && !isFireworksAccountId(requested)) {
|
|
3967
|
+
ctx.ui.notify("Enter a URL-safe Fireworks account slug.", "warning");
|
|
3968
|
+
continue;
|
|
3969
|
+
}
|
|
3970
|
+
if (requested === state.settings.fireworksAccountId) return false;
|
|
3971
|
+
try {
|
|
3972
|
+
await settingsRuntime.update({ fireworksAccountId: requested }, signal);
|
|
3973
|
+
} catch (error) {
|
|
3974
|
+
if (signal.aborted || !isCurrent()) return false;
|
|
3975
|
+
ctx.ui.notify(`Could not save pi-usage.json: ${errorMessage(error)}`, "error");
|
|
3976
|
+
return false;
|
|
3977
|
+
}
|
|
3978
|
+
onApplied("fireworksAccountId");
|
|
3979
|
+
return true;
|
|
3980
|
+
}
|
|
3981
|
+
return false;
|
|
3982
|
+
}
|
|
3983
|
+
function displaySetting(id, value) {
|
|
3984
|
+
if (id === "fireworksAccountId") return typeof value === "string" ? value : AUTO;
|
|
3985
|
+
return value ? ON : OFF;
|
|
3013
3986
|
}
|
|
3014
3987
|
|
|
3015
3988
|
// src/usage.ts
|
|
@@ -3120,9 +4093,7 @@ function usageExtension(pi, dependencies = {}) {
|
|
|
3120
4093
|
const generation = statusGeneration;
|
|
3121
4094
|
statusCountdownTimer = setTimeout(() => {
|
|
3122
4095
|
statusCountdownTimer = void 0;
|
|
3123
|
-
if (!sessionActive || generation !== statusGeneration
|
|
3124
|
-
return;
|
|
3125
|
-
}
|
|
4096
|
+
if (!sessionActive || generation !== statusGeneration) return;
|
|
3126
4097
|
publishStatus(ctx, outcome, model, false);
|
|
3127
4098
|
}, STATUS_COUNTDOWN_REFRESH_MS);
|
|
3128
4099
|
statusCountdownTimer.unref?.();
|
|
@@ -3152,6 +4123,8 @@ function usageExtension(pi, dependencies = {}) {
|
|
|
3152
4123
|
const expectedSessionGeneration = sessionGeneration;
|
|
3153
4124
|
const expectedSessionId = ctx.sessionManager.getSessionId();
|
|
3154
4125
|
const expectedModelIdentity = modelIdentity(ctx.model);
|
|
4126
|
+
const expectedFireworksAccountId = adapter.id === "fireworks" ? settingsRuntime.get().settings.fireworksAccountId : void 0;
|
|
4127
|
+
const querySettings = adapter.id === "fireworks" ? { fireworksAccountId: expectedFireworksAccountId } : void 0;
|
|
3155
4128
|
let auth;
|
|
3156
4129
|
try {
|
|
3157
4130
|
auth = await awaitWithDeadline(
|
|
@@ -3175,8 +4148,18 @@ function usageExtension(pi, dependencies = {}) {
|
|
|
3175
4148
|
}
|
|
3176
4149
|
};
|
|
3177
4150
|
}
|
|
3178
|
-
const requiresRequestBoundaryGuard =
|
|
3179
|
-
|
|
4151
|
+
const requiresRequestBoundaryGuard = [
|
|
4152
|
+
"baseten",
|
|
4153
|
+
"deepseek",
|
|
4154
|
+
"fireworks",
|
|
4155
|
+
"minimax",
|
|
4156
|
+
"minimax-cn",
|
|
4157
|
+
"moonshotai",
|
|
4158
|
+
"moonshotai-cn",
|
|
4159
|
+
"vercel-ai-gateway",
|
|
4160
|
+
"xai"
|
|
4161
|
+
].includes(adapter.id);
|
|
4162
|
+
const requestContextChanged = () => expectedSessionGeneration !== sessionGeneration || ctx.sessionManager.getSessionId() !== expectedSessionId || modelIdentity(ctx.model) !== expectedModelIdentity || adapter.id === "fireworks" && settingsRuntime.get().settings.fireworksAccountId !== expectedFireworksAccountId;
|
|
3180
4163
|
if (requiresRequestBoundaryGuard && requestContextChanged()) throw abortError();
|
|
3181
4164
|
if (!auth) {
|
|
3182
4165
|
if (displayState === "current") {
|
|
@@ -3193,10 +4176,11 @@ function usageExtension(pi, dependencies = {}) {
|
|
|
3193
4176
|
authState: "unavailable"
|
|
3194
4177
|
};
|
|
3195
4178
|
}
|
|
4179
|
+
const queryFingerprint = adapter.id === "fireworks" ? `${auth.fingerprint}:account:${expectedFireworksAccountId ?? "auto"}` : auth.fingerprint;
|
|
3196
4180
|
if (displayState === "current") {
|
|
3197
|
-
transitionCurrentIdentity(`${adapter.id}:${
|
|
4181
|
+
transitionCurrentIdentity(`${adapter.id}:${queryFingerprint}`, adapter.id);
|
|
3198
4182
|
}
|
|
3199
|
-
const cached = !force ? cache.get(adapter.id,
|
|
4183
|
+
const cached = !force ? cache.get(adapter.id, queryFingerprint) : void 0;
|
|
3200
4184
|
if (cached) {
|
|
3201
4185
|
return {
|
|
3202
4186
|
state: {
|
|
@@ -3209,7 +4193,7 @@ function usageExtension(pi, dependencies = {}) {
|
|
|
3209
4193
|
fingerprint: auth.fingerprint
|
|
3210
4194
|
};
|
|
3211
4195
|
}
|
|
3212
|
-
const failureKey = `${adapter.id}:${
|
|
4196
|
+
const failureKey = `${adapter.id}:${queryFingerprint}`;
|
|
3213
4197
|
const previousFailure = failureBackoff.get(failureKey);
|
|
3214
4198
|
if (!force && previousFailure && previousFailure.until > Date.now()) {
|
|
3215
4199
|
return {
|
|
@@ -3227,7 +4211,7 @@ function usageExtension(pi, dependencies = {}) {
|
|
|
3227
4211
|
querySequence += 1;
|
|
3228
4212
|
const queryId = querySequence;
|
|
3229
4213
|
setBoundedMap(latestQueries, failureKey, queryId, MAX_ACCOUNT_STATES);
|
|
3230
|
-
let
|
|
4214
|
+
let retryableAuthChanged = false;
|
|
3231
4215
|
try {
|
|
3232
4216
|
const remainingMs = Math.max(1, deadlineAt - Date.now());
|
|
3233
4217
|
const guard = requiresRequestBoundaryGuard ? async () => {
|
|
@@ -3240,17 +4224,26 @@ function usageExtension(pi, dependencies = {}) {
|
|
|
3240
4224
|
);
|
|
3241
4225
|
if (signal.aborted || requestContextChanged()) throw abortError();
|
|
3242
4226
|
if (revalidated?.fingerprint !== auth.fingerprint) {
|
|
3243
|
-
if (
|
|
3244
|
-
|
|
3245
|
-
throw new Error(
|
|
4227
|
+
if (["deepseek", "minimax", "minimax-cn"].includes(adapter.id)) {
|
|
4228
|
+
retryableAuthChanged = true;
|
|
4229
|
+
throw new Error(
|
|
4230
|
+
`${adapter.displayName} runtime credential changed during the usage query.`
|
|
4231
|
+
);
|
|
3246
4232
|
}
|
|
3247
4233
|
throw abortError();
|
|
3248
4234
|
}
|
|
3249
4235
|
} : void 0;
|
|
3250
|
-
const
|
|
4236
|
+
const report2 = await queryProviderUsage(
|
|
4237
|
+
adapter,
|
|
4238
|
+
auth,
|
|
4239
|
+
signal,
|
|
4240
|
+
remainingMs,
|
|
4241
|
+
guard,
|
|
4242
|
+
querySettings
|
|
4243
|
+
);
|
|
3251
4244
|
if (guard) await guard();
|
|
3252
4245
|
if (latestQueries.get(failureKey) === queryId) {
|
|
3253
|
-
cache.set(adapter.id,
|
|
4246
|
+
cache.set(adapter.id, queryFingerprint, report2);
|
|
3254
4247
|
failureBackoff.delete(failureKey);
|
|
3255
4248
|
}
|
|
3256
4249
|
return {
|
|
@@ -3259,13 +4252,13 @@ function usageExtension(pi, dependencies = {}) {
|
|
|
3259
4252
|
providerName: adapter.displayName,
|
|
3260
4253
|
displayState,
|
|
3261
4254
|
status: "ready",
|
|
3262
|
-
report
|
|
4255
|
+
report: report2
|
|
3263
4256
|
},
|
|
3264
4257
|
fingerprint: auth.fingerprint
|
|
3265
4258
|
};
|
|
3266
4259
|
} catch (error) {
|
|
3267
4260
|
if (isStaleExtensionContextError(error) || isAbortError3(error)) throw error;
|
|
3268
|
-
if (
|
|
4261
|
+
if (retryableAuthChanged && authRetry === 0 && !signal.aborted && !requestContextChanged() && Date.now() < deadlineAt) {
|
|
3269
4262
|
if (latestQueries.get(failureKey) === queryId) latestQueries.delete(failureKey);
|
|
3270
4263
|
return queryAdapterState(
|
|
3271
4264
|
ctx,
|
|
@@ -3880,7 +4873,7 @@ function usageExtension(pi, dependencies = {}) {
|
|
|
3880
4873
|
}
|
|
3881
4874
|
}
|
|
3882
4875
|
});
|
|
3883
|
-
pi.on("session_start", (_event, ctx) => {
|
|
4876
|
+
pi.on("session_start", async (_event, ctx) => {
|
|
3884
4877
|
sessionGeneration += 1;
|
|
3885
4878
|
statusGeneration += 1;
|
|
3886
4879
|
clearStatusTimers();
|
|
@@ -3888,7 +4881,13 @@ function usageExtension(pi, dependencies = {}) {
|
|
|
3888
4881
|
activeControllers.clear();
|
|
3889
4882
|
statusController = void 0;
|
|
3890
4883
|
sessionActive = true;
|
|
3891
|
-
|
|
4884
|
+
const ownerGeneration = sessionGeneration;
|
|
4885
|
+
try {
|
|
4886
|
+
await fastRuntime.prepareSession(ctx);
|
|
4887
|
+
} catch (error) {
|
|
4888
|
+
if (isStaleExtensionContextError(error) || ownerGeneration !== sessionGeneration) return;
|
|
4889
|
+
throw error;
|
|
4890
|
+
}
|
|
3892
4891
|
});
|
|
3893
4892
|
pi.on("session_tree", (_event, ctx) => {
|
|
3894
4893
|
startStatusRefresh(ctx, ctx.model, false);
|
|
@@ -3916,7 +4915,8 @@ function usageExtension(pi, dependencies = {}) {
|
|
|
3916
4915
|
fastRuntime = registerCodexFastMode(
|
|
3917
4916
|
pi,
|
|
3918
4917
|
settingsRuntime,
|
|
3919
|
-
(ctx) => startStatusRefresh(ctx, ctx.model, false)
|
|
4918
|
+
(ctx) => startStatusRefresh(ctx, ctx.model, false),
|
|
4919
|
+
{ registerSessionStart: false }
|
|
3920
4920
|
);
|
|
3921
4921
|
}
|
|
3922
4922
|
export {
|
|
@@ -3946,14 +4946,21 @@ export {
|
|
|
3946
4946
|
isStaleExtensionContextError,
|
|
3947
4947
|
listCodexResetCredits,
|
|
3948
4948
|
loadUsageSettings,
|
|
4949
|
+
miniMaxUsageKind,
|
|
4950
|
+
normalizeBasetenBillingUsagePayload,
|
|
3949
4951
|
normalizeCodexBackendPayload,
|
|
3950
4952
|
normalizeCodexResetCreditsPayload,
|
|
3951
4953
|
normalizeDeepSeekBalancePayload,
|
|
4954
|
+
normalizeFireworksAccountsPayload,
|
|
4955
|
+
normalizeFireworksBillingSummaryPayload,
|
|
3952
4956
|
normalizeGitHubCopilotUsagePayload,
|
|
3953
4957
|
normalizeKimiCodingUsagePayload,
|
|
4958
|
+
normalizeMiniMaxUsagePayload,
|
|
4959
|
+
normalizeMoonshotBalancePayload,
|
|
3954
4960
|
normalizeOpenCodeZenPayload,
|
|
3955
4961
|
normalizeOpenRouterKeyPayload,
|
|
3956
4962
|
normalizeUsageSettings,
|
|
4963
|
+
normalizeVercelAIGatewayCreditsPayload,
|
|
3957
4964
|
normalizeXaiBillingPayload,
|
|
3958
4965
|
normalizeZaiQuotaPayload,
|
|
3959
4966
|
providerIsConfigured,
|