@narumitw/pi-usage 0.64.3 → 0.65.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +20 -4
- package/dist/chunks/{chunk-ACPQJ2CM.ts → chunk-N2ZD5X4K.ts} +4 -4
- package/dist/chunks/{chunk-ACPQJ2CM.ts.map → chunk-N2ZD5X4K.ts.map} +2 -2
- package/dist/chunks/{openai-companion-auth-FGFC6DBT.ts → openai-companion-auth-QIKCD3WA.ts} +2 -2
- package/dist/chunks/{openai-companion-usage-TGHK2OQR.ts → openai-companion-usage-ZFAHCGEY.ts} +2 -2
- package/dist/index.ts +439 -149
- package/dist/index.ts.map +4 -4
- package/docs/providers.md +7 -7
- package/package.json +1 -1
- package/src/codex-fast-catalog.ts +272 -0
- package/src/codex-fast-runtime.ts +107 -26
- package/src/codex-fast.ts +28 -19
- package/src/format.ts +96 -34
- package/src/index.ts +3 -1
- package/src/query.ts +2 -1
- package/src/usage.ts +45 -22
- /package/dist/chunks/{openai-companion-auth-FGFC6DBT.ts.map → openai-companion-auth-QIKCD3WA.ts.map} +0 -0
- /package/dist/chunks/{openai-companion-usage-TGHK2OQR.ts.map → openai-companion-usage-ZFAHCGEY.ts.map} +0 -0
package/dist/index.ts
CHANGED
|
@@ -47,23 +47,17 @@ import {
|
|
|
47
47
|
runWithConcurrency,
|
|
48
48
|
sanitizeDisplayText,
|
|
49
49
|
usageAdapters
|
|
50
|
-
} from "./chunks/chunk-
|
|
50
|
+
} from "./chunks/chunk-N2ZD5X4K.ts";
|
|
51
51
|
|
|
52
52
|
// src/codex-fast.ts
|
|
53
53
|
import { calculateCost, hasApi } from "@earendil-works/pi-ai";
|
|
54
54
|
var CODEX_FAST_SERVICE_TIER = "priority";
|
|
55
55
|
var CODEX_STANDARD_SERVICE_TIER = "default";
|
|
56
|
-
var
|
|
57
|
-
"
|
|
58
|
-
"
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
"gpt-6-astra",
|
|
62
|
-
"gpt-6-luna",
|
|
63
|
-
"gpt-6-sol",
|
|
64
|
-
"gpt-6.1-sol"
|
|
65
|
-
]);
|
|
66
|
-
function codexFastAvailability(model, enabled) {
|
|
56
|
+
var UNKNOWN_CODEX_FAST_CAPABILITY = {
|
|
57
|
+
kind: "unknown",
|
|
58
|
+
reason: "Codex Fast capability information has not been fetched."
|
|
59
|
+
};
|
|
60
|
+
function codexFastAvailability(model, enabled, capability = UNKNOWN_CODEX_FAST_CAPABILITY) {
|
|
67
61
|
if (model?.provider !== "openai-codex") return { kind: "not-codex" };
|
|
68
62
|
if (!isOfficialCodexModel(model)) {
|
|
69
63
|
return {
|
|
@@ -71,7 +65,8 @@ function codexFastAvailability(model, enabled) {
|
|
|
71
65
|
reason: "Fast mode requires the official OpenAI Codex Responses endpoint."
|
|
72
66
|
};
|
|
73
67
|
}
|
|
74
|
-
if (
|
|
68
|
+
if (capability.kind === "unknown") return capability;
|
|
69
|
+
if (capability.kind === "unsupported") {
|
|
75
70
|
return {
|
|
76
71
|
kind: "unavailable",
|
|
77
72
|
reason: `${model.id} does not advertise Codex Fast support.`
|
|
@@ -79,20 +74,20 @@ function codexFastAvailability(model, enabled) {
|
|
|
79
74
|
}
|
|
80
75
|
return { kind: "available", enabled };
|
|
81
76
|
}
|
|
82
|
-
function codexFastIsEffective(model, enabled) {
|
|
83
|
-
return codexFastAvailability(model, enabled).kind === "available" && enabled;
|
|
77
|
+
function codexFastIsEffective(model, enabled, capability = UNKNOWN_CODEX_FAST_CAPABILITY) {
|
|
78
|
+
return codexFastAvailability(model, enabled, capability).kind === "available" && enabled;
|
|
84
79
|
}
|
|
85
|
-
function codexFastRequestTier(model, enabled) {
|
|
80
|
+
function codexFastRequestTier(model, enabled, capability = UNKNOWN_CODEX_FAST_CAPABILITY) {
|
|
86
81
|
if (!isOfficialCodexModel(model)) return void 0;
|
|
87
|
-
return enabled &&
|
|
82
|
+
return enabled && capability.kind === "supported" ? CODEX_FAST_SERVICE_TIER : CODEX_STANDARD_SERVICE_TIER;
|
|
88
83
|
}
|
|
89
|
-
function rewriteCodexFastPayload(payload, model, enabled) {
|
|
90
|
-
const serviceTier = codexFastRequestTier(model, enabled);
|
|
84
|
+
function rewriteCodexFastPayload(payload, model, enabled, capability = UNKNOWN_CODEX_FAST_CAPABILITY) {
|
|
85
|
+
const serviceTier = codexFastRequestTier(model, enabled, capability);
|
|
91
86
|
if (!serviceTier || !isRecord(payload)) return void 0;
|
|
92
87
|
return { ...payload, service_tier: serviceTier };
|
|
93
88
|
}
|
|
94
|
-
function correctCodexFastMessageCost(message, model, fastRequested) {
|
|
95
|
-
if (!codexFastIsEffective(model, fastRequested) || !isRecord(message) || message.role !== "assistant" || message.provider !== model?.provider || message.model !== model?.id) {
|
|
89
|
+
function correctCodexFastMessageCost(message, model, fastRequested, capability = UNKNOWN_CODEX_FAST_CAPABILITY) {
|
|
90
|
+
if (!codexFastIsEffective(model, fastRequested, capability) || !isRecord(message) || message.role !== "assistant" || message.provider !== model?.provider || message.model !== model?.id) {
|
|
96
91
|
return void 0;
|
|
97
92
|
}
|
|
98
93
|
const usage = isRecord(message.usage) ? message.usage : void 0;
|
|
@@ -426,6 +421,14 @@ function formatUsageReport(report, displayState) {
|
|
|
426
421
|
return lines.join("\n").trimEnd();
|
|
427
422
|
}
|
|
428
423
|
function formatUsageStatusline(report, model, now = Date.now(), showCodexResetCountdown = true, codexStatusPercentage = "remaining") {
|
|
424
|
+
return formatUsageStatuslineWithCountdown(report, model, now, showCodexResetCountdown, codexStatusPercentage).value;
|
|
425
|
+
}
|
|
426
|
+
function formatUsageStatuslineWithCountdown(report, model, now = Date.now(), showCodexResetCountdown = true, codexStatusPercentage = "remaining") {
|
|
427
|
+
const countdown = { now, active: false };
|
|
428
|
+
const value = formatStatusline(report, model, now, showCodexResetCountdown, codexStatusPercentage, countdown);
|
|
429
|
+
return { value, hasCountdown: countdown.active };
|
|
430
|
+
}
|
|
431
|
+
function formatStatusline(report, model, now, showCodexResetCountdown, codexStatusPercentage, countdown) {
|
|
429
432
|
if (report.providerId === "openai" && report.source === "openai-chatgpt-auth") return "chatgpt usage: web only";
|
|
430
433
|
if (report.source === "openai-chatgpt-companion") {
|
|
431
434
|
const windows = report.buckets.filter((bucket) => bucket.groupId === "chatgpt-plan").map((bucket) => {
|
|
@@ -442,24 +445,24 @@ function formatUsageStatusline(report, model, now = Date.now(), showCodexResetCo
|
|
|
442
445
|
if (report.providerId === "deepseek") return formatDeepSeekStatusline(report);
|
|
443
446
|
if (report.providerId === "fireworks") return formatFireworksStatusline(report);
|
|
444
447
|
if (report.providerId === "vercel-ai-gateway") return formatVercelAIGatewayStatusline(report);
|
|
445
|
-
if (report.providerId === "github-copilot") return formatGitHubCopilotStatusline(report);
|
|
448
|
+
if (report.providerId === "github-copilot") return formatGitHubCopilotStatusline(report, countdown);
|
|
446
449
|
if (report.providerId === "openrouter") {
|
|
447
450
|
const limit = report.buckets.find((bucket) => bucket.id === "key-limit");
|
|
448
451
|
if (limit?.remaining !== void 0) return `openrouter ${formatUsd(limit.remaining)} left`;
|
|
449
452
|
const total = report.metrics.find((metric) => metric.id === "usage-total");
|
|
450
453
|
if (typeof total?.value === "number") return `openrouter ${formatUsd(total.value)} used`;
|
|
451
454
|
}
|
|
452
|
-
if (report.providerId === "opencode-go") return formatOpenCodeZenStatusline(report);
|
|
453
|
-
if (report.providerId === "command-code") return formatCommandCodeStatusline(report);
|
|
454
|
-
if (report.providerId === "kimi-coding") return formatKimiCodingStatusline(report);
|
|
455
|
+
if (report.providerId === "opencode-go") return formatOpenCodeZenStatusline(report, countdown);
|
|
456
|
+
if (report.providerId === "command-code") return formatCommandCodeStatusline(report, countdown);
|
|
457
|
+
if (report.providerId === "kimi-coding") return formatKimiCodingStatusline(report, countdown);
|
|
455
458
|
if (report.providerId === "moonshotai" || report.providerId === "moonshotai-cn") {
|
|
456
459
|
return formatMoonshotStatusline(report);
|
|
457
460
|
}
|
|
458
461
|
if (report.providerId === "minimax" || report.providerId === "minimax-cn") {
|
|
459
|
-
return formatMiniMaxStatusline(report, model);
|
|
462
|
+
return formatMiniMaxStatusline(report, countdown, model);
|
|
460
463
|
}
|
|
461
464
|
if (report.providerId === "zai" || report.providerId === "zai-coding-cn") {
|
|
462
|
-
return formatZaiStatusline(report);
|
|
465
|
+
return formatZaiStatusline(report, countdown);
|
|
463
466
|
}
|
|
464
467
|
return void 0;
|
|
465
468
|
}
|
|
@@ -577,7 +580,7 @@ function formatGitHubCopilotReport(lines, report) {
|
|
|
577
580
|
lines.push(`${"Additional usage:".padEnd(VALUE_COLUMN)}${overage.value} ${quota.label}`);
|
|
578
581
|
}
|
|
579
582
|
}
|
|
580
|
-
function formatGitHubCopilotStatusline(report) {
|
|
583
|
+
function formatGitHubCopilotStatusline(report, countdown) {
|
|
581
584
|
const quota = findGitHubCopilotQuota(report);
|
|
582
585
|
const kind = compactGitHubCopilotQuotaKind(quota);
|
|
583
586
|
if (!quota || quota.limit === void 0 || quota.remaining === void 0) {
|
|
@@ -585,7 +588,8 @@ function formatGitHubCopilotStatusline(report) {
|
|
|
585
588
|
}
|
|
586
589
|
const overage = report.metrics.find((metric) => metric.id === "overage-used");
|
|
587
590
|
const overageSuffix = typeof overage?.value === "number" && overage.value > 0 ? ` +${overage.value} over` : "";
|
|
588
|
-
|
|
591
|
+
const reset = formatQuotaCountdown(quota, countdown);
|
|
592
|
+
return `copilot ${kind === "premium" ? "" : `${kind} `}${quota.remaining}/${quota.limit} ${percentRemaining(quota)}%${overageSuffix}${reset ? ` \u21BB ${reset}` : ""}`;
|
|
589
593
|
}
|
|
590
594
|
function findGitHubCopilotQuota(report) {
|
|
591
595
|
return report.buckets.find((bucket) => ["ai-credits", "premium-requests", "chat-requests"].includes(bucket.id));
|
|
@@ -621,14 +625,14 @@ function formatOpenCodeZenReport(lines, report) {
|
|
|
621
625
|
lines.push(`${`${bucket.label}:`.padEnd(VALUE_COLUMN)}${used}% used${reset}`);
|
|
622
626
|
}
|
|
623
627
|
}
|
|
624
|
-
function formatOpenCodeZenStatusline(report) {
|
|
625
|
-
const parts = [
|
|
628
|
+
function formatOpenCodeZenStatusline(report, countdown) {
|
|
629
|
+
const parts = [];
|
|
626
630
|
for (const bucket of report.buckets) {
|
|
627
631
|
if (bucket.used === void 0) continue;
|
|
628
632
|
const compact = bucket.id === "rolling" ? "r" : bucket.id === "weekly" ? "w" : "m";
|
|
629
|
-
parts.push(`${clampPercent(bucket.used).toFixed(0)}
|
|
633
|
+
parts.push(formatQuotaWindow(bucket, `${clampPercent(bucket.used).toFixed(0)}%`, compact, countdown));
|
|
630
634
|
}
|
|
631
|
-
return parts.length >
|
|
635
|
+
return parts.length > 0 ? `zen ${parts.join(" \xB7 ")}` : void 0;
|
|
632
636
|
}
|
|
633
637
|
function formatCommandCodeReport(lines, report) {
|
|
634
638
|
for (const bucket of report.buckets) {
|
|
@@ -645,8 +649,8 @@ function formatCommandCodeReport(lines, report) {
|
|
|
645
649
|
lines.push(`${`${metric.label}:`.padEnd(VALUE_COLUMN)}${formatMetricValue(metric.value, metric.unit)}`);
|
|
646
650
|
}
|
|
647
651
|
}
|
|
648
|
-
function formatCommandCodeStatusline(report) {
|
|
649
|
-
const parts = [
|
|
652
|
+
function formatCommandCodeStatusline(report, countdown) {
|
|
653
|
+
const parts = [];
|
|
650
654
|
for (const [id, label] of [
|
|
651
655
|
["five-hour", "5h"],
|
|
652
656
|
["weekly", "wk"],
|
|
@@ -654,9 +658,9 @@ function formatCommandCodeStatusline(report) {
|
|
|
654
658
|
]) {
|
|
655
659
|
const bucket = report.buckets.find((candidate) => candidate.id === id);
|
|
656
660
|
if (bucket?.unit !== "usd" || bucket.limit === void 0 || bucket.remaining === void 0) continue;
|
|
657
|
-
parts.push(`${percentRemaining(bucket)}
|
|
661
|
+
parts.push(formatQuotaWindow(bucket, `${percentRemaining(bucket)}%`, label, countdown));
|
|
658
662
|
}
|
|
659
|
-
return parts.length >
|
|
663
|
+
return parts.length > 0 ? `cmd ${parts.join(" \xB7 ")}` : void 0;
|
|
660
664
|
}
|
|
661
665
|
function formatKimiCodingReport(lines, report) {
|
|
662
666
|
for (const bucket of report.buckets) {
|
|
@@ -692,7 +696,7 @@ function formatKimiCodingReport(lines, report) {
|
|
|
692
696
|
lines.push(`${"Monthly limit:".padEnd(VALUE_COLUMN)}${formatCurrencyMetric(monthlyLimit)}`);
|
|
693
697
|
}
|
|
694
698
|
}
|
|
695
|
-
function formatKimiCodingStatusline(report) {
|
|
699
|
+
function formatKimiCodingStatusline(report, countdown) {
|
|
696
700
|
const fiveHour = report.buckets.find((bucket) => bucket.id === "five-hour");
|
|
697
701
|
const weekly = report.buckets.find((bucket) => bucket.id === "weekly");
|
|
698
702
|
const monthly = report.buckets.find((bucket) => bucket.id === "monthly");
|
|
@@ -700,15 +704,15 @@ function formatKimiCodingStatusline(report) {
|
|
|
700
704
|
const selected = [subWindow, weekly, monthly].filter(
|
|
701
705
|
(bucket, index, buckets) => bucket !== void 0 && buckets.indexOf(bucket) === index
|
|
702
706
|
);
|
|
703
|
-
const parts = [
|
|
707
|
+
const parts = [];
|
|
704
708
|
for (const bucket of selected) {
|
|
705
709
|
if (bucket.remaining === void 0 || bucket.unit !== "percent" && !bucket.limit) continue;
|
|
706
710
|
const fallback = bucket.id === "weekly" ? "weekly" : "5h";
|
|
707
711
|
const window = bucket.id === "monthly" ? "mo" : formatWindowLabel(bucket.windowMinutes, fallback, true);
|
|
708
712
|
const remaining = bucket.unit === "percent" ? Math.round(clampPercent(bucket.remaining)) : percentRemaining(bucket);
|
|
709
|
-
parts.push(`${remaining}
|
|
713
|
+
parts.push(formatQuotaWindow(bucket, `${remaining}%`, window, countdown));
|
|
710
714
|
}
|
|
711
|
-
return parts.length >
|
|
715
|
+
return parts.length > 0 ? `kimi ${parts.join(" \xB7 ")}` : void 0;
|
|
712
716
|
}
|
|
713
717
|
function formatMoonshotReport(lines, report) {
|
|
714
718
|
for (const metric of report.metrics) {
|
|
@@ -736,7 +740,7 @@ function formatMiniMaxReport(lines, report) {
|
|
|
736
740
|
lines.push(`${`${bucket.label}:`.padEnd(VALUE_COLUMN)}${value}`);
|
|
737
741
|
}
|
|
738
742
|
}
|
|
739
|
-
function formatMiniMaxStatusline(report, model) {
|
|
743
|
+
function formatMiniMaxStatusline(report, countdown, model) {
|
|
740
744
|
const prefix = report.providerId === "minimax-cn" ? "minimax cn" : "minimax";
|
|
741
745
|
if (report.source === "minimax-account-balance") {
|
|
742
746
|
const available = report.metrics.find((metric) => metric.id === "available-balance");
|
|
@@ -745,22 +749,22 @@ function formatMiniMaxStatusline(report, model) {
|
|
|
745
749
|
const selectedGroup = selectMiniMaxGroup(report, model);
|
|
746
750
|
if (!selectedGroup) return void 0;
|
|
747
751
|
const selected = report.buckets.filter((bucket) => bucket.groupId === selectedGroup);
|
|
748
|
-
const parts = [
|
|
752
|
+
const parts = [];
|
|
749
753
|
for (const bucket of selected) {
|
|
750
754
|
const fallback = bucket.id.endsWith(":weekly") ? "weekly" : "5h";
|
|
751
755
|
const window = formatWindowLabel(bucket.windowMinutes, fallback, true);
|
|
752
756
|
if (bucket.period === "unlimited") {
|
|
753
|
-
parts.push(
|
|
757
|
+
parts.push(`${window}:unlimited`);
|
|
754
758
|
continue;
|
|
755
759
|
}
|
|
756
760
|
if (bucket.unit === "percent" && bucket.remaining !== void 0) {
|
|
757
|
-
parts.push(`${bucket.remaining}
|
|
761
|
+
parts.push(formatQuotaWindow(bucket, `${bucket.remaining}%`, window, countdown));
|
|
758
762
|
continue;
|
|
759
763
|
}
|
|
760
764
|
if (bucket.limit === void 0 || bucket.remaining === void 0) continue;
|
|
761
|
-
parts.push(`${percentRemaining(bucket)}
|
|
765
|
+
parts.push(formatQuotaWindow(bucket, `${percentRemaining(bucket)}%`, window, countdown));
|
|
762
766
|
}
|
|
763
|
-
return parts.length >
|
|
767
|
+
return parts.length > 0 ? `${prefix} ${parts.join(" \xB7 ")}` : void 0;
|
|
764
768
|
}
|
|
765
769
|
function selectMiniMaxGroup(report, model) {
|
|
766
770
|
const groups = [
|
|
@@ -802,18 +806,25 @@ function wildcardKeyMatches(pattern, value) {
|
|
|
802
806
|
const last = segments.at(-1);
|
|
803
807
|
return pattern.endsWith("*") || last !== void 0 && value.endsWith(last);
|
|
804
808
|
}
|
|
805
|
-
function formatZaiStatusline(report) {
|
|
809
|
+
function formatZaiStatusline(report, countdown) {
|
|
806
810
|
const selected = [
|
|
807
811
|
report.buckets.find((bucket) => bucket.id === "five-hour"),
|
|
808
812
|
report.buckets.find((bucket) => bucket.id === "weekly")
|
|
809
813
|
];
|
|
810
|
-
const parts = [
|
|
814
|
+
const parts = [];
|
|
811
815
|
for (const bucket of selected) {
|
|
812
816
|
if (!bucket?.limit || bucket.remaining === void 0) continue;
|
|
813
817
|
const fallback = bucket.id === "weekly" ? "weekly" : "5h";
|
|
814
|
-
parts.push(
|
|
818
|
+
parts.push(
|
|
819
|
+
formatQuotaWindow(
|
|
820
|
+
bucket,
|
|
821
|
+
`${percentRemaining(bucket)}%`,
|
|
822
|
+
formatWindowLabel(bucket.windowMinutes, fallback, true),
|
|
823
|
+
countdown
|
|
824
|
+
)
|
|
825
|
+
);
|
|
815
826
|
}
|
|
816
|
-
return parts.length >
|
|
827
|
+
return parts.length > 0 ? `zai ${parts.join(" \xB7 ")}` : void 0;
|
|
817
828
|
}
|
|
818
829
|
function formatCurrencyMetric(metric) {
|
|
819
830
|
if (typeof metric.value !== "number") return String(metric.value);
|
|
@@ -896,7 +907,8 @@ function formatCodexStatusline(report, model, now = Date.now(), showResetCountdo
|
|
|
896
907
|
if (!group) return formatCodexCreditsStatus(report);
|
|
897
908
|
const buckets = report.buckets.filter((bucket) => (bucket.groupId ?? bucket.id) === group);
|
|
898
909
|
const labelBucket = buckets[0];
|
|
899
|
-
const
|
|
910
|
+
const prefix = group === "codex" ? "codex" : `codex ${compactLimitLabel(labelBucket?.groupLabel ?? group)}`;
|
|
911
|
+
const parts = [];
|
|
900
912
|
for (const bucket of buckets) {
|
|
901
913
|
if (bucket.remaining === void 0) continue;
|
|
902
914
|
const displayedPercentage = percentage === "used" ? bucket.used ?? 100 - bucket.remaining : bucket.remaining;
|
|
@@ -904,13 +916,13 @@ function formatCodexStatusline(report, model, now = Date.now(), showResetCountdo
|
|
|
904
916
|
const fallback = bucket.id.endsWith(":secondary") ? "weekly" : "5h";
|
|
905
917
|
const window = formatWindowLabel(bucket.windowMinutes, fallback, true);
|
|
906
918
|
if (!showResetCountdown) {
|
|
907
|
-
parts.push(`${
|
|
919
|
+
parts.push(`${window}:${percent}`);
|
|
908
920
|
continue;
|
|
909
921
|
}
|
|
910
922
|
const reset = formatResetCountdown(bucket.resetsAt, now);
|
|
911
|
-
parts.push(`${percent}
|
|
923
|
+
parts.push(reset ? `${percent} \u21BB ${reset}` : `${window}:${percent}`);
|
|
912
924
|
}
|
|
913
|
-
return parts.length >
|
|
925
|
+
return parts.length > 0 ? `${prefix} ${parts.join(" \xB7 ")}` : formatCodexCreditsStatus(report);
|
|
914
926
|
}
|
|
915
927
|
function formatCodexCreditsStatus(report) {
|
|
916
928
|
const credits = report.metrics.find((metric) => metric.id === "credits");
|
|
@@ -989,6 +1001,17 @@ function formatWindowLabel(minutes, fallback, compact) {
|
|
|
989
1001
|
if (minutes % 60 === 0) return `${minutes / 60}h`;
|
|
990
1002
|
return `${minutes}m`;
|
|
991
1003
|
}
|
|
1004
|
+
function formatQuotaWindow(bucket, percent, window, countdown) {
|
|
1005
|
+
const reset = formatQuotaCountdown(bucket, countdown);
|
|
1006
|
+
return reset ? `${percent} \u21BB ${reset}` : `${window}:${percent}`;
|
|
1007
|
+
}
|
|
1008
|
+
function formatQuotaCountdown(bucket, countdown) {
|
|
1009
|
+
if (bucket.period === "unlimited" || bucket.resetsAt === void 0 || !Number.isFinite(bucket.resetsAt * 1e3) || !Number.isFinite(countdown.now) || bucket.resetsAt * 1e3 <= countdown.now)
|
|
1010
|
+
return void 0;
|
|
1011
|
+
const reset = formatResetCountdown(bucket.resetsAt, countdown.now);
|
|
1012
|
+
if (reset !== void 0) countdown.active = true;
|
|
1013
|
+
return reset;
|
|
1014
|
+
}
|
|
992
1015
|
function formatResetCountdown(resetsAt, now) {
|
|
993
1016
|
if (resetsAt === void 0 || !Number.isFinite(resetsAt) || !Number.isFinite(now)) return void 0;
|
|
994
1017
|
const totalMinutes = Math.max(0, Math.ceil((resetsAt * 1e3 - now) / 6e4));
|
|
@@ -1289,6 +1312,231 @@ function isProviderId(value) {
|
|
|
1289
1312
|
// src/usage.ts
|
|
1290
1313
|
import { randomUUID as randomUUID2 } from "node:crypto";
|
|
1291
1314
|
|
|
1315
|
+
// src/codex-fast-catalog.ts
|
|
1316
|
+
import { VERSION } from "@earendil-works/pi-coding-agent";
|
|
1317
|
+
|
|
1318
|
+
// src/usage-helpers.ts
|
|
1319
|
+
function configuredAdapters(ctx) {
|
|
1320
|
+
return usageAdapters().filter(
|
|
1321
|
+
(adapter) => adapter.id === ctx.model?.provider || providerIsConfigured(ctx, adapter.id)
|
|
1322
|
+
);
|
|
1323
|
+
}
|
|
1324
|
+
function providerDisplayName(ctx, providerId) {
|
|
1325
|
+
try {
|
|
1326
|
+
return sanitizeDisplayText(ctx.modelRegistry.getProviderDisplayName(providerId), 80);
|
|
1327
|
+
} catch {
|
|
1328
|
+
return sanitizeDisplayText(providerId, 80);
|
|
1329
|
+
}
|
|
1330
|
+
}
|
|
1331
|
+
function setBoundedMap(map, key, value, limit) {
|
|
1332
|
+
map.delete(key);
|
|
1333
|
+
while (map.size >= limit) {
|
|
1334
|
+
const oldest = map.keys().next().value;
|
|
1335
|
+
if (oldest === void 0) break;
|
|
1336
|
+
map.delete(oldest);
|
|
1337
|
+
}
|
|
1338
|
+
map.set(key, value);
|
|
1339
|
+
}
|
|
1340
|
+
function modelIdentity(model) {
|
|
1341
|
+
return model ? `${model.provider}/${model.id}` : void 0;
|
|
1342
|
+
}
|
|
1343
|
+
function isAbortError(error) {
|
|
1344
|
+
return error instanceof Error && error.name === "AbortError";
|
|
1345
|
+
}
|
|
1346
|
+
function isTimeoutError(error) {
|
|
1347
|
+
return error instanceof Error && error.name === "TimeoutError";
|
|
1348
|
+
}
|
|
1349
|
+
|
|
1350
|
+
// src/codex-fast-catalog.ts
|
|
1351
|
+
var CACHE_TTL_MS = 5 * 60 * 1e3;
|
|
1352
|
+
var FAILURE_BACKOFF_MS = 3e4;
|
|
1353
|
+
var MAX_ACCOUNT_STATES = 32;
|
|
1354
|
+
var MAX_DIRECTORY_BODY_BYTES = 8 * 1024 * 1024;
|
|
1355
|
+
var DIRECTORY_URL = new URL("https://chatgpt.com/backend-api/codex/models");
|
|
1356
|
+
DIRECTORY_URL.searchParams.set("client_version", VERSION);
|
|
1357
|
+
function createCodexFastCatalog(options = {}) {
|
|
1358
|
+
const accounts = /* @__PURE__ */ new Map();
|
|
1359
|
+
const requests = /* @__PURE__ */ new Map();
|
|
1360
|
+
const latestRequests = /* @__PURE__ */ new Map();
|
|
1361
|
+
const timeoutMs = options.timeoutMs ?? 15e3;
|
|
1362
|
+
let requestSequence = 0;
|
|
1363
|
+
let identitySequence = 0;
|
|
1364
|
+
let generation = 0;
|
|
1365
|
+
let active;
|
|
1366
|
+
let issue = UNKNOWN_CODEX_FAST_CAPABILITY.reason;
|
|
1367
|
+
const current = (scope, ctx, signal) => !signal.aborted && generation === scope.generation && active?.key === scope.key && active.fingerprint === scope.fingerprint && active.model === scope.model && active.session === scope.session && modelIdentity2(ctx.model) === scope.model && ctx.sessionManager.getSessionId() === scope.session;
|
|
1368
|
+
const capability = (model, key = active?.key) => {
|
|
1369
|
+
const entry = key ? accounts.get(key) : void 0;
|
|
1370
|
+
const supported = model ? entry?.models?.get(model.id) : void 0;
|
|
1371
|
+
if (supported !== void 0) return { kind: supported ? "supported" : "unsupported" };
|
|
1372
|
+
return {
|
|
1373
|
+
kind: "unknown",
|
|
1374
|
+
reason: entry?.issue ?? (entry?.models && model ? `The Codex model directory has no Fast capability information for ${model.id}.` : issue)
|
|
1375
|
+
};
|
|
1376
|
+
};
|
|
1377
|
+
const identify = async (ctx, signal) => {
|
|
1378
|
+
const identity = ++identitySequence;
|
|
1379
|
+
const owner = generation;
|
|
1380
|
+
const model = modelIdentity2(ctx.model);
|
|
1381
|
+
const session = ctx.sessionManager.getSessionId();
|
|
1382
|
+
if (!isOfficialCodexModel(ctx.model)) {
|
|
1383
|
+
active = void 0;
|
|
1384
|
+
return void 0;
|
|
1385
|
+
}
|
|
1386
|
+
try {
|
|
1387
|
+
const auth = await awaitWithDeadline(
|
|
1388
|
+
resolveCodexResetAuth(ctx, void 0, options.credentialReader, options.candidateReader),
|
|
1389
|
+
signal,
|
|
1390
|
+
timeoutMs,
|
|
1391
|
+
"resolving the current Codex model-directory account"
|
|
1392
|
+
);
|
|
1393
|
+
if (signal.aborted || owner !== generation || identity !== identitySequence || modelIdentity2(ctx.model) !== model || ctx.sessionManager.getSessionId() !== session) {
|
|
1394
|
+
return void 0;
|
|
1395
|
+
}
|
|
1396
|
+
const accountId = auth.headers["chatgpt-account-id"];
|
|
1397
|
+
if (!accountId) throw new Error("The active Codex account ID is unavailable.");
|
|
1398
|
+
const scope = {
|
|
1399
|
+
key: fingerprintResolvedAuth({ headers: { "chatgpt-account-id": accountId } }, AUTH_FINGERPRINT_SALT),
|
|
1400
|
+
fingerprint: auth.fingerprint,
|
|
1401
|
+
model,
|
|
1402
|
+
session,
|
|
1403
|
+
generation: owner
|
|
1404
|
+
};
|
|
1405
|
+
const changed = active?.key !== scope.key;
|
|
1406
|
+
active = scope;
|
|
1407
|
+
issue = "Codex Fast capability information has not been fetched for this account.";
|
|
1408
|
+
if (changed) options.onChanged?.(ctx);
|
|
1409
|
+
return { auth, scope };
|
|
1410
|
+
} catch (error) {
|
|
1411
|
+
if (signal.aborted || owner !== generation || identity !== identitySequence) return void 0;
|
|
1412
|
+
active = void 0;
|
|
1413
|
+
issue = `Codex Fast capability is unknown: ${redactUsageError(errorMessage(error))}`;
|
|
1414
|
+
options.onChanged?.(ctx);
|
|
1415
|
+
return void 0;
|
|
1416
|
+
}
|
|
1417
|
+
};
|
|
1418
|
+
const load = async (ctx, auth, scope, signal, force) => {
|
|
1419
|
+
const entry = accounts.get(scope.key);
|
|
1420
|
+
if (!force && (entry?.models && entry.fingerprint === auth.fingerprint && Date.now() - entry.fetchedAt < CACHE_TTL_MS || entry?.retryAt && Date.now() < entry.retryAt)) {
|
|
1421
|
+
return;
|
|
1422
|
+
}
|
|
1423
|
+
const before = capability(ctx.model, scope.key);
|
|
1424
|
+
const existing = requests.get(auth.fingerprint);
|
|
1425
|
+
let promise = existing?.promise;
|
|
1426
|
+
if (!promise) {
|
|
1427
|
+
const sequence = ++requestSequence;
|
|
1428
|
+
latestRequests.set(scope.key, sequence);
|
|
1429
|
+
const controller = new AbortController();
|
|
1430
|
+
const combined = AbortSignal.any([signal, controller.signal]);
|
|
1431
|
+
let status;
|
|
1432
|
+
promise = (async () => {
|
|
1433
|
+
try {
|
|
1434
|
+
const payload = await fetchProviderJson(
|
|
1435
|
+
DIRECTORY_URL.href,
|
|
1436
|
+
auth,
|
|
1437
|
+
combined,
|
|
1438
|
+
timeoutMs,
|
|
1439
|
+
"Codex model directory",
|
|
1440
|
+
{
|
|
1441
|
+
redirect: "error",
|
|
1442
|
+
maxSuccessBodyBytes: MAX_DIRECTORY_BODY_BYTES,
|
|
1443
|
+
responseError: (responseStatus) => {
|
|
1444
|
+
status = responseStatus;
|
|
1445
|
+
return void 0;
|
|
1446
|
+
}
|
|
1447
|
+
}
|
|
1448
|
+
);
|
|
1449
|
+
const models = normalizeDirectory(payload);
|
|
1450
|
+
if (combined.aborted || scope.generation !== generation || latestRequests.get(scope.key) !== sequence) return;
|
|
1451
|
+
setBoundedMap(
|
|
1452
|
+
accounts,
|
|
1453
|
+
scope.key,
|
|
1454
|
+
{ models, fetchedAt: Date.now(), fingerprint: auth.fingerprint },
|
|
1455
|
+
MAX_ACCOUNT_STATES
|
|
1456
|
+
);
|
|
1457
|
+
} catch (error) {
|
|
1458
|
+
if (combined.aborted || scope.generation !== generation || latestRequests.get(scope.key) !== sequence) return;
|
|
1459
|
+
const previous = accounts.get(scope.key);
|
|
1460
|
+
const transient = status === void 0 || status >= 500 || status === 429;
|
|
1461
|
+
setBoundedMap(
|
|
1462
|
+
accounts,
|
|
1463
|
+
scope.key,
|
|
1464
|
+
{
|
|
1465
|
+
...transient && previous?.models ? previous : { fetchedAt: 0 },
|
|
1466
|
+
retryAt: Date.now() + FAILURE_BACKOFF_MS,
|
|
1467
|
+
issue: `Codex Fast capability is unknown: ${redactUsageError(errorMessage(error), auth.secrets)}`
|
|
1468
|
+
},
|
|
1469
|
+
MAX_ACCOUNT_STATES
|
|
1470
|
+
);
|
|
1471
|
+
} finally {
|
|
1472
|
+
if (requests.get(auth.fingerprint)?.controller === controller) requests.delete(auth.fingerprint);
|
|
1473
|
+
if (latestRequests.get(scope.key) === sequence) latestRequests.delete(scope.key);
|
|
1474
|
+
}
|
|
1475
|
+
})();
|
|
1476
|
+
requests.set(auth.fingerprint, { controller, promise });
|
|
1477
|
+
}
|
|
1478
|
+
try {
|
|
1479
|
+
await awaitWithDeadline(promise, signal, timeoutMs, "fetching the Codex model directory");
|
|
1480
|
+
} catch (error) {
|
|
1481
|
+
if (signal.aborted) return;
|
|
1482
|
+
throw error;
|
|
1483
|
+
}
|
|
1484
|
+
const after = capability(ctx.model, scope.key);
|
|
1485
|
+
if (current(scope, ctx, signal) && JSON.stringify(before) !== JSON.stringify(after)) options.onChanged?.(ctx);
|
|
1486
|
+
};
|
|
1487
|
+
return {
|
|
1488
|
+
get(model) {
|
|
1489
|
+
return capability(model);
|
|
1490
|
+
},
|
|
1491
|
+
async read(ctx, signal, refresh = false, force = false) {
|
|
1492
|
+
const resolved = await identify(ctx, signal);
|
|
1493
|
+
if (!resolved) return void 0;
|
|
1494
|
+
const { auth, scope } = resolved;
|
|
1495
|
+
if (refresh) await load(ctx, auth, scope, signal, force || capability(ctx.model, scope.key).kind === "unknown");
|
|
1496
|
+
else void load(ctx, auth, scope, signal, false);
|
|
1497
|
+
return current(scope, ctx, signal) ? capability(ctx.model, scope.key) : void 0;
|
|
1498
|
+
},
|
|
1499
|
+
reset(clearCache = false) {
|
|
1500
|
+
generation += 1;
|
|
1501
|
+
identitySequence += 1;
|
|
1502
|
+
active = void 0;
|
|
1503
|
+
issue = UNKNOWN_CODEX_FAST_CAPABILITY.reason;
|
|
1504
|
+
for (const { controller } of requests.values()) controller.abort();
|
|
1505
|
+
requests.clear();
|
|
1506
|
+
latestRequests.clear();
|
|
1507
|
+
if (clearCache) accounts.clear();
|
|
1508
|
+
}
|
|
1509
|
+
};
|
|
1510
|
+
}
|
|
1511
|
+
function normalizeDirectory(payload) {
|
|
1512
|
+
if (!Array.isArray(payload.models)) throw new Error("The Codex model directory returned invalid models.");
|
|
1513
|
+
const models = /* @__PURE__ */ new Map();
|
|
1514
|
+
for (const item of payload.models) {
|
|
1515
|
+
if (!isRecord3(item) || typeof item.slug !== "string" || !item.slug.trim() || models.has(item.slug)) {
|
|
1516
|
+
throw new Error("The Codex model directory returned an invalid or duplicate model ID.");
|
|
1517
|
+
}
|
|
1518
|
+
const hasTiers = item.service_tiers !== void 0;
|
|
1519
|
+
const hasLegacy = item.additional_speed_tiers !== void 0;
|
|
1520
|
+
if (hasTiers && (!Array.isArray(item.service_tiers) || item.service_tiers.some((tier) => !isRecord3(tier) || typeof tier.id !== "string")) || hasLegacy && (!Array.isArray(item.additional_speed_tiers) || item.additional_speed_tiers.some((tier) => typeof tier !== "string"))) {
|
|
1521
|
+
throw new Error("The Codex model directory returned invalid service tiers.");
|
|
1522
|
+
}
|
|
1523
|
+
if (!hasTiers && !hasLegacy) {
|
|
1524
|
+
models.set(item.slug, void 0);
|
|
1525
|
+
continue;
|
|
1526
|
+
}
|
|
1527
|
+
const tiers = item.service_tiers ?? [];
|
|
1528
|
+
const legacy = item.additional_speed_tiers ?? [];
|
|
1529
|
+
models.set(item.slug, tiers.some((tier) => tier.id === "priority") || legacy.includes("fast"));
|
|
1530
|
+
}
|
|
1531
|
+
return models;
|
|
1532
|
+
}
|
|
1533
|
+
function modelIdentity2(model) {
|
|
1534
|
+
return model ? `${model.provider}/${model.id}` : "";
|
|
1535
|
+
}
|
|
1536
|
+
function isRecord3(value) {
|
|
1537
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
1538
|
+
}
|
|
1539
|
+
|
|
1292
1540
|
// src/codex-fast-runtime.ts
|
|
1293
1541
|
var NO_FAST_REQUEST = /* @__PURE__ */ Symbol("no-fast-request");
|
|
1294
1542
|
var FAST_USAGE_WARNING = "Fast is about 1.5\xD7 faster and uses more of your plan allowance.";
|
|
@@ -1296,14 +1544,58 @@ function registerCodexFastMode(pi, settingsRuntime, refreshStatus, options = {})
|
|
|
1296
1544
|
let sessionController = new AbortController();
|
|
1297
1545
|
let generation = 0;
|
|
1298
1546
|
const pendingFastRequests = /* @__PURE__ */ new Map();
|
|
1547
|
+
const catalog = createCodexFastCatalog({
|
|
1548
|
+
credentialReader: options.credentialReader,
|
|
1549
|
+
candidateReader: options.candidateReader ?? createOAuthCredentialCandidateReader(pi, options.credentialReader),
|
|
1550
|
+
timeoutMs: options.timeoutMs,
|
|
1551
|
+
onChanged(ctx) {
|
|
1552
|
+
if (sessionController.signal.aborted || !settingsRuntime.get().settings.codexFastMode) return;
|
|
1553
|
+
try {
|
|
1554
|
+
refreshStatus(ctx);
|
|
1555
|
+
} catch (error) {
|
|
1556
|
+
if (!isStaleExtensionContextError(error)) throw error;
|
|
1557
|
+
}
|
|
1558
|
+
}
|
|
1559
|
+
});
|
|
1299
1560
|
const toggle = async (ctx, enabled, callerSignal) => {
|
|
1300
1561
|
const ownerGeneration = generation;
|
|
1301
1562
|
const sessionId = ctx.sessionManager.getSessionId();
|
|
1302
1563
|
const signal = callerSignal ? AbortSignal.any([callerSignal, sessionController.signal]) : sessionController.signal;
|
|
1564
|
+
if (ctx.model?.provider !== "openai-codex") {
|
|
1565
|
+
ctx.ui.notify("/fast is available only for the active OpenAI Codex model.", "warning");
|
|
1566
|
+
return false;
|
|
1567
|
+
}
|
|
1568
|
+
if (!isOfficialCodexModel(ctx.model)) {
|
|
1569
|
+
ctx.ui.notify("Fast mode requires the official OpenAI Codex Responses endpoint.", "warning");
|
|
1570
|
+
return false;
|
|
1571
|
+
}
|
|
1572
|
+
if (settingsRuntime.get().kind === "invalid") {
|
|
1573
|
+
ctx.ui.notify("pi-usage.json is invalid; repair it and run /reload before changing Fast mode.", "error");
|
|
1574
|
+
return false;
|
|
1575
|
+
}
|
|
1576
|
+
if (enabled) {
|
|
1577
|
+
const capability = await catalog.read(ctx, signal, true, catalog.get(ctx.model).kind !== "supported");
|
|
1578
|
+
if (signal.aborted || ownerGeneration !== generation) return false;
|
|
1579
|
+
if (!capability) {
|
|
1580
|
+
const latest = catalog.get(ctx.model);
|
|
1581
|
+
ctx.ui.notify(
|
|
1582
|
+
latest.kind === "unknown" ? latest.reason : "The active Codex account changed while checking Fast capability.",
|
|
1583
|
+
"warning"
|
|
1584
|
+
);
|
|
1585
|
+
return false;
|
|
1586
|
+
}
|
|
1587
|
+
const availability = codexFastAvailability(ctx.model, false, capability);
|
|
1588
|
+
if (availability.kind !== "available") {
|
|
1589
|
+
if (availability.kind === "unknown" || availability.kind === "unavailable") {
|
|
1590
|
+
ctx.ui.notify(availability.reason, "warning");
|
|
1591
|
+
}
|
|
1592
|
+
return false;
|
|
1593
|
+
}
|
|
1594
|
+
}
|
|
1303
1595
|
try {
|
|
1304
1596
|
await settingsRuntime.update({ codexFastMode: enabled }, signal);
|
|
1305
1597
|
} catch (error) {
|
|
1306
|
-
if (
|
|
1598
|
+
if (isAbortError2(error) || isStaleExtensionContextError(error)) return false;
|
|
1307
1599
|
ctx.ui.notify(`Could not save pi-usage.json: ${errorMessage(error)}`, "error");
|
|
1308
1600
|
return false;
|
|
1309
1601
|
}
|
|
@@ -1326,26 +1618,18 @@ function registerCodexFastMode(pi, settingsRuntime, refreshStatus, options = {})
|
|
|
1326
1618
|
return;
|
|
1327
1619
|
}
|
|
1328
1620
|
if (!ctx.hasUI) throw new Error("/fast requires TUI or RPC mode.");
|
|
1329
|
-
|
|
1330
|
-
if (availability.kind === "not-codex") {
|
|
1331
|
-
ctx.ui.notify("/fast is available only for the active OpenAI Codex model.", "warning");
|
|
1332
|
-
return;
|
|
1333
|
-
}
|
|
1334
|
-
if (availability.kind === "unavailable") {
|
|
1335
|
-
ctx.ui.notify(availability.reason, "warning");
|
|
1336
|
-
return;
|
|
1337
|
-
}
|
|
1338
|
-
if (settingsRuntime.get().kind === "invalid") {
|
|
1339
|
-
ctx.ui.notify("pi-usage.json is invalid; repair it and run /reload before changing Fast mode.", "error");
|
|
1340
|
-
return;
|
|
1341
|
-
}
|
|
1342
|
-
await toggle(ctx, !availability.enabled);
|
|
1621
|
+
await toggle(ctx, !settingsRuntime.get().settings.codexFastMode);
|
|
1343
1622
|
}
|
|
1344
1623
|
});
|
|
1624
|
+
const refreshCapabilities = (ctx, callerSignal, force = false) => {
|
|
1625
|
+
const signal = callerSignal ? AbortSignal.any([callerSignal, sessionController.signal]) : sessionController.signal;
|
|
1626
|
+
return catalog.read(ctx, signal, true, force);
|
|
1627
|
+
};
|
|
1345
1628
|
const prepareSession = (ctx) => {
|
|
1346
1629
|
const sessionId = ctx.sessionManager.getSessionId();
|
|
1347
1630
|
generation += 1;
|
|
1348
1631
|
sessionController.abort();
|
|
1632
|
+
catalog.reset();
|
|
1349
1633
|
pendingFastRequests.clear();
|
|
1350
1634
|
sessionController = new AbortController();
|
|
1351
1635
|
const ownerGeneration = generation;
|
|
@@ -1367,18 +1651,28 @@ function registerCodexFastMode(pi, settingsRuntime, refreshStatus, options = {})
|
|
|
1367
1651
|
ctx.ui.notify(`Invalid pi-usage.json; using defaults without overwriting it. ${state.issue}`, "warning");
|
|
1368
1652
|
}
|
|
1369
1653
|
refreshStatus(ctx);
|
|
1654
|
+
if (state.kind !== "invalid" && isOfficialCodexModel(ctx.model)) void refreshCapabilities(ctx);
|
|
1370
1655
|
})();
|
|
1371
1656
|
};
|
|
1372
1657
|
if (options.registerSessionStart !== false) {
|
|
1373
1658
|
pi.on("session_start", async (_event, ctx) => prepareSession(ctx));
|
|
1374
1659
|
}
|
|
1375
|
-
pi.on("
|
|
1376
|
-
|
|
1377
|
-
|
|
1378
|
-
|
|
1660
|
+
pi.on("model_select", (_event, ctx) => {
|
|
1661
|
+
void refreshCapabilities(ctx);
|
|
1662
|
+
});
|
|
1663
|
+
pi.on("before_provider_request", async (event, ctx) => {
|
|
1664
|
+
const ownerGeneration = generation;
|
|
1665
|
+
const model = ctx.model;
|
|
1666
|
+
const enabled = settingsRuntime.get().settings.codexFastMode;
|
|
1667
|
+
const capability = enabled && isOfficialCodexModel(model) ? await catalog.read(ctx, sessionController.signal) ?? UNKNOWN_CODEX_FAST_CAPABILITY : UNKNOWN_CODEX_FAST_CAPABILITY;
|
|
1668
|
+
if (sessionController.signal.aborted || ownerGeneration !== generation) return void 0;
|
|
1669
|
+
const rewritten = rewriteCodexFastPayload(event.payload, model, enabled, capability);
|
|
1670
|
+
const key = activeRequestKey(ctx, model);
|
|
1671
|
+
if (key && model) {
|
|
1379
1672
|
pendingFastRequests.set(key, {
|
|
1380
|
-
fastRequested:
|
|
1381
|
-
model
|
|
1673
|
+
fastRequested: isRecord4(rewritten) && rewritten.service_tier === "priority",
|
|
1674
|
+
model,
|
|
1675
|
+
capability
|
|
1382
1676
|
});
|
|
1383
1677
|
}
|
|
1384
1678
|
return rewritten;
|
|
@@ -1386,32 +1680,43 @@ function registerCodexFastMode(pi, settingsRuntime, refreshStatus, options = {})
|
|
|
1386
1680
|
pi.on("message_end", (event, ctx) => {
|
|
1387
1681
|
const request = consumeFastRequest(ctx, event.message, pendingFastRequests);
|
|
1388
1682
|
if (request === NO_FAST_REQUEST) return void 0;
|
|
1389
|
-
const message = correctCodexFastMessageCost(
|
|
1683
|
+
const message = correctCodexFastMessageCost(
|
|
1684
|
+
event.message,
|
|
1685
|
+
request.model,
|
|
1686
|
+
request.fastRequested,
|
|
1687
|
+
request.capability
|
|
1688
|
+
);
|
|
1390
1689
|
return message ? { message } : void 0;
|
|
1391
1690
|
});
|
|
1392
1691
|
pi.on("session_shutdown", async () => {
|
|
1393
1692
|
generation += 1;
|
|
1394
1693
|
sessionController.abort();
|
|
1694
|
+
catalog.reset(true);
|
|
1395
1695
|
pendingFastRequests.clear();
|
|
1396
1696
|
await settingsRuntime.flush();
|
|
1397
1697
|
});
|
|
1398
1698
|
return {
|
|
1399
1699
|
prepareSession,
|
|
1700
|
+
refreshCapabilities,
|
|
1400
1701
|
availability(model) {
|
|
1401
|
-
return codexFastAvailability(model, settingsRuntime.get().settings.codexFastMode);
|
|
1702
|
+
return codexFastAvailability(model, settingsRuntime.get().settings.codexFastMode, catalog.get(model));
|
|
1402
1703
|
},
|
|
1403
1704
|
decorateStatus(model, status) {
|
|
1404
|
-
|
|
1705
|
+
const enabled = settingsRuntime.get().settings.codexFastMode;
|
|
1706
|
+
const capability = catalog.get(model);
|
|
1707
|
+
if (enabled && codexFastAvailability(model, enabled, capability).kind === "unknown" && /^codex(?:\s|$)/u.test(status)) {
|
|
1708
|
+
return `codex (Fast unknown)${status.slice("codex".length)}`;
|
|
1709
|
+
}
|
|
1710
|
+
return codexFastStatusLabel(status, codexFastIsEffective(model, enabled, capability));
|
|
1405
1711
|
},
|
|
1406
1712
|
toggle
|
|
1407
1713
|
};
|
|
1408
1714
|
}
|
|
1409
|
-
function activeRequestKey(ctx) {
|
|
1410
|
-
const model = ctx.model;
|
|
1715
|
+
function activeRequestKey(ctx, model = ctx.model) {
|
|
1411
1716
|
return model ? `${ctx.sessionManager.getSessionId()}:${model.provider}/${model.id}` : void 0;
|
|
1412
1717
|
}
|
|
1413
1718
|
function consumeFastRequest(ctx, message, pending) {
|
|
1414
|
-
if (!
|
|
1719
|
+
if (!isRecord4(message) || message.role !== "assistant") return NO_FAST_REQUEST;
|
|
1415
1720
|
const key = messageRequestKey(ctx, message);
|
|
1416
1721
|
if (!key) return NO_FAST_REQUEST;
|
|
1417
1722
|
const request = pending.get(key);
|
|
@@ -1422,44 +1727,12 @@ function messageRequestKey(ctx, message) {
|
|
|
1422
1727
|
if (typeof message.provider !== "string" || typeof message.model !== "string") return void 0;
|
|
1423
1728
|
return `${ctx.sessionManager.getSessionId()}:${message.provider}/${message.model}`;
|
|
1424
1729
|
}
|
|
1425
|
-
function
|
|
1730
|
+
function isRecord4(value) {
|
|
1426
1731
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
1427
1732
|
}
|
|
1428
|
-
function isAbortError(error) {
|
|
1429
|
-
return error instanceof Error && error.name === "AbortError";
|
|
1430
|
-
}
|
|
1431
|
-
|
|
1432
|
-
// src/usage-helpers.ts
|
|
1433
|
-
function configuredAdapters(ctx) {
|
|
1434
|
-
return usageAdapters().filter(
|
|
1435
|
-
(adapter) => adapter.id === ctx.model?.provider || providerIsConfigured(ctx, adapter.id)
|
|
1436
|
-
);
|
|
1437
|
-
}
|
|
1438
|
-
function providerDisplayName(ctx, providerId) {
|
|
1439
|
-
try {
|
|
1440
|
-
return sanitizeDisplayText(ctx.modelRegistry.getProviderDisplayName(providerId), 80);
|
|
1441
|
-
} catch {
|
|
1442
|
-
return sanitizeDisplayText(providerId, 80);
|
|
1443
|
-
}
|
|
1444
|
-
}
|
|
1445
|
-
function setBoundedMap(map, key, value, limit) {
|
|
1446
|
-
map.delete(key);
|
|
1447
|
-
while (map.size >= limit) {
|
|
1448
|
-
const oldest = map.keys().next().value;
|
|
1449
|
-
if (oldest === void 0) break;
|
|
1450
|
-
map.delete(oldest);
|
|
1451
|
-
}
|
|
1452
|
-
map.set(key, value);
|
|
1453
|
-
}
|
|
1454
|
-
function modelIdentity(model) {
|
|
1455
|
-
return model ? `${model.provider}/${model.id}` : void 0;
|
|
1456
|
-
}
|
|
1457
1733
|
function isAbortError2(error) {
|
|
1458
1734
|
return error instanceof Error && error.name === "AbortError";
|
|
1459
1735
|
}
|
|
1460
|
-
function isTimeoutError(error) {
|
|
1461
|
-
return error instanceof Error && error.name === "TimeoutError";
|
|
1462
|
-
}
|
|
1463
1736
|
|
|
1464
1737
|
// src/usage-settings-ui.ts
|
|
1465
1738
|
import { stripVTControlCharacters } from "node:util";
|
|
@@ -1599,13 +1872,13 @@ async function showUsageSettings(ctx, settingsRuntime, parentSignal, isCurrent,
|
|
|
1599
1872
|
}
|
|
1600
1873
|
|
|
1601
1874
|
// src/usage.ts
|
|
1602
|
-
var
|
|
1875
|
+
var CACHE_TTL_MS2 = 5 * 60 * 1e3;
|
|
1603
1876
|
var STATUS_COUNTDOWN_REFRESH_MS = 60 * 1e3;
|
|
1604
1877
|
var DEFAULT_TIMEOUT_MS = 15e3;
|
|
1605
1878
|
var COMMAND_CODE_REVALIDATION_RESERVE_MS = 1e3;
|
|
1606
1879
|
var ALL_PROVIDER_CONCURRENCY = 2;
|
|
1607
|
-
var
|
|
1608
|
-
var
|
|
1880
|
+
var FAILURE_BACKOFF_MS2 = 3e4;
|
|
1881
|
+
var MAX_ACCOUNT_STATES2 = 32;
|
|
1609
1882
|
var STATUS_KEY = "usage";
|
|
1610
1883
|
var REFRESH_CURRENT = "Refresh current usage";
|
|
1611
1884
|
var VIEW_ANOTHER = "View another configured provider\u2026";
|
|
@@ -1622,7 +1895,7 @@ function usageExtension(pi, dependencies = {}) {
|
|
|
1622
1895
|
const createRedemptionId = dependencies.createRedemptionId ?? randomUUID2;
|
|
1623
1896
|
const settingsRuntime = dependencies.settingsRuntime ?? createUsageSettingsRuntime();
|
|
1624
1897
|
const resolveUsageAuth2 = resolveUsageAuth;
|
|
1625
|
-
const cache = new UsageCache(
|
|
1898
|
+
const cache = new UsageCache(CACHE_TTL_MS2);
|
|
1626
1899
|
const failureBackoff = /* @__PURE__ */ new Map();
|
|
1627
1900
|
const latestQueries = /* @__PURE__ */ new Map();
|
|
1628
1901
|
const activeControllers = /* @__PURE__ */ new Set();
|
|
@@ -1671,7 +1944,7 @@ function usageExtension(pi, dependencies = {}) {
|
|
|
1671
1944
|
statusRefreshTimer = void 0;
|
|
1672
1945
|
if (!sessionActive || generation !== statusGeneration) return;
|
|
1673
1946
|
startStatusRefresh(ctx, model, true);
|
|
1674
|
-
},
|
|
1947
|
+
}, CACHE_TTL_MS2);
|
|
1675
1948
|
statusRefreshTimer.unref?.();
|
|
1676
1949
|
};
|
|
1677
1950
|
const publishStatus = (ctx, outcome, model, shouldSchedule) => {
|
|
@@ -1697,23 +1970,23 @@ function usageExtension(pi, dependencies = {}) {
|
|
|
1697
1970
|
const showCodexResetCountdown = outcome.state.report.providerId === "openai-codex" && settings.codexStatusResetCountdown;
|
|
1698
1971
|
const isCompanionReport = outcome.state.report.source === "openai-chatgpt-companion";
|
|
1699
1972
|
const now = Date.now();
|
|
1700
|
-
const
|
|
1973
|
+
const status = formatUsageStatuslineWithCountdown(
|
|
1701
1974
|
outcome.state.report,
|
|
1702
1975
|
model,
|
|
1703
1976
|
now,
|
|
1704
1977
|
showCodexResetCountdown,
|
|
1705
1978
|
settings.codexStatusPercentage
|
|
1706
1979
|
);
|
|
1707
|
-
const value =
|
|
1980
|
+
const value = status.value ? fastRuntime.decorateStatus(model, status.value) : void 0;
|
|
1708
1981
|
if (!safeSetStatus(ctx, value)) return;
|
|
1709
1982
|
if (shouldSchedule && sessionActive) scheduleStatusRefresh(ctx, model);
|
|
1710
|
-
if (sessionActive && (showCodexResetCountdown || isCompanionReport) && outcome.state.report.buckets.some(
|
|
1983
|
+
if (sessionActive && (status.hasCountdown || (showCodexResetCountdown || isCompanionReport) && outcome.state.report.buckets.some(
|
|
1711
1984
|
(bucket) => (!isCompanionReport || bucket.groupId === "chatgpt-plan") && bucket.resetsAt !== void 0 && Number.isFinite(bucket.resetsAt) && bucket.resetsAt * 1e3 > now
|
|
1712
|
-
)) {
|
|
1985
|
+
))) {
|
|
1713
1986
|
const generation = statusGeneration;
|
|
1714
1987
|
statusCountdownTimer = setTimeout(() => {
|
|
1715
|
-
statusCountdownTimer = void 0;
|
|
1716
1988
|
if (!sessionActive || generation !== statusGeneration) return;
|
|
1989
|
+
statusCountdownTimer = void 0;
|
|
1717
1990
|
publishStatus(ctx, outcome, model, false);
|
|
1718
1991
|
}, STATUS_COUNTDOWN_REFRESH_MS);
|
|
1719
1992
|
statusCountdownTimer.unref?.();
|
|
@@ -1754,7 +2027,7 @@ function usageExtension(pi, dependencies = {}) {
|
|
|
1754
2027
|
`resolving ${adapter.displayName} runtime auth`
|
|
1755
2028
|
);
|
|
1756
2029
|
} catch (error) {
|
|
1757
|
-
if (isStaleExtensionContextError(error) ||
|
|
2030
|
+
if (isStaleExtensionContextError(error) || isAbortError(error)) throw error;
|
|
1758
2031
|
if (adapter.id === "openai") invalidateProviderState(adapter.id);
|
|
1759
2032
|
const authState = error instanceof UnsupportedOpenAIUsageAuthError ? "unsupported" : adapter.id === "openai" && !isTimeoutError(error) ? "failed" : void 0;
|
|
1760
2033
|
if (displayState === "current") {
|
|
@@ -1903,7 +2176,7 @@ function usageExtension(pi, dependencies = {}) {
|
|
|
1903
2176
|
failureBackoff.delete(failureKey);
|
|
1904
2177
|
querySequence += 1;
|
|
1905
2178
|
queryId = querySequence;
|
|
1906
|
-
setBoundedMap(latestQueries, failureKey, queryId,
|
|
2179
|
+
setBoundedMap(latestQueries, failureKey, queryId, MAX_ACCOUNT_STATES2);
|
|
1907
2180
|
const queryTimeoutMs = Math.max(
|
|
1908
2181
|
1,
|
|
1909
2182
|
deadlineAt - Date.now() - (adapter.id === "command-code" ? COMMAND_CODE_REVALIDATION_RESERVE_MS : 0)
|
|
@@ -1934,7 +2207,7 @@ function usageExtension(pi, dependencies = {}) {
|
|
|
1934
2207
|
rememberedTargetId: expectedTargetId
|
|
1935
2208
|
};
|
|
1936
2209
|
} catch (error) {
|
|
1937
|
-
if (isStaleExtensionContextError(error) ||
|
|
2210
|
+
if (isStaleExtensionContextError(error) || isAbortError(error)) throw error;
|
|
1938
2211
|
if (retryableAuthChanged && authRetry === 0 && !signal.aborted && !requestContextChanged() && Date.now() < deadlineAt) {
|
|
1939
2212
|
if (queryId !== void 0 && latestQueries.get(failureKey) === queryId) {
|
|
1940
2213
|
latestQueries.delete(failureKey);
|
|
@@ -1948,7 +2221,7 @@ function usageExtension(pi, dependencies = {}) {
|
|
|
1948
2221
|
}
|
|
1949
2222
|
if (queryId === void 0 || latestQueries.get(failureKey) === queryId) {
|
|
1950
2223
|
if (adapter.invalidateCacheOnFailure) cache.delete(adapter.id, queryFingerprint);
|
|
1951
|
-
setBoundedMap(failureBackoff, failureKey, { until: now +
|
|
2224
|
+
setBoundedMap(failureBackoff, failureKey, { until: now + FAILURE_BACKOFF_MS2, message }, MAX_ACCOUNT_STATES2);
|
|
1952
2225
|
}
|
|
1953
2226
|
return {
|
|
1954
2227
|
state: {
|
|
@@ -2065,7 +2338,7 @@ function usageExtension(pi, dependencies = {}) {
|
|
|
2065
2338
|
};
|
|
2066
2339
|
const startStatusRefresh = (ctx, model, force) => {
|
|
2067
2340
|
void refreshCurrentStatus(ctx, model, force).catch((error) => {
|
|
2068
|
-
if (isStaleExtensionContextError(error) ||
|
|
2341
|
+
if (isStaleExtensionContextError(error) || isAbortError(error)) return;
|
|
2069
2342
|
const message = errorMessage(error);
|
|
2070
2343
|
console.error("[pi-usage] refresh failed:", message);
|
|
2071
2344
|
safeSetStatus(ctx, `usage err: ${message.slice(0, 50)}`);
|
|
@@ -2109,7 +2382,7 @@ function usageExtension(pi, dependencies = {}) {
|
|
|
2109
2382
|
);
|
|
2110
2383
|
return generation === statusGeneration && modelIdentity(ctx.model) === modelIdentity(model) && (!adapter.targets || settingsRuntime.get().settings.selectedTargets[adapter.id] === outcome.rememberedTargetId) && outcome.authState === "unavailable" && auth === void 0;
|
|
2111
2384
|
} catch (error) {
|
|
2112
|
-
if (
|
|
2385
|
+
if (isAbortError(error) || isStaleExtensionContextError(error)) throw error;
|
|
2113
2386
|
const unchangedFailure = outcome.authState === "unsupported" && error instanceof UnsupportedOpenAIUsageAuthError || outcome.authState === "failed" && outcome.state.status === "auth-unavailable" && !(error instanceof UnsupportedOpenAIUsageAuthError) && !isTimeoutError(error) && errorMessage(error) === outcome.state.message;
|
|
2114
2387
|
return unchangedFailure && generation === statusGeneration && modelIdentity(ctx.model) === modelIdentity(model) && (!adapter.targets || settingsRuntime.get().settings.selectedTargets[adapter.id] === outcome.rememberedTargetId);
|
|
2115
2388
|
}
|
|
@@ -2125,7 +2398,7 @@ function usageExtension(pi, dependencies = {}) {
|
|
|
2125
2398
|
);
|
|
2126
2399
|
return generation === statusGeneration && modelIdentity(ctx.model) === modelIdentity(model) && (!adapter.targets || settingsRuntime.get().settings.selectedTargets[adapter.id] === outcome.rememberedTargetId) && auth?.fingerprint === outcome.fingerprint;
|
|
2127
2400
|
} catch (error) {
|
|
2128
|
-
if (
|
|
2401
|
+
if (isAbortError(error) || isStaleExtensionContextError(error)) throw error;
|
|
2129
2402
|
return false;
|
|
2130
2403
|
}
|
|
2131
2404
|
};
|
|
@@ -2165,14 +2438,26 @@ function usageExtension(pi, dependencies = {}) {
|
|
|
2165
2438
|
};
|
|
2166
2439
|
const showMenu = async (ctx) => {
|
|
2167
2440
|
if (!ctx.hasUI) throw new Error("/usage requires TUI or RPC mode.");
|
|
2168
|
-
statusGeneration += 1;
|
|
2169
|
-
const menuGeneration = statusGeneration;
|
|
2170
|
-
statusController?.abort();
|
|
2171
|
-
statusController = void 0;
|
|
2172
|
-
clearStatusTimers();
|
|
2173
2441
|
const controller = new AbortController();
|
|
2174
2442
|
activeControllers.add(controller);
|
|
2175
2443
|
try {
|
|
2444
|
+
if (isOfficialCodexModel(ctx.model)) {
|
|
2445
|
+
const refreshed = await runMenuOperation(
|
|
2446
|
+
ctx,
|
|
2447
|
+
"Checking Codex Fast capability\u2026",
|
|
2448
|
+
controller.signal,
|
|
2449
|
+
async (signal) => {
|
|
2450
|
+
await fastRuntime.refreshCapabilities(ctx, signal);
|
|
2451
|
+
return true;
|
|
2452
|
+
}
|
|
2453
|
+
);
|
|
2454
|
+
if (!refreshed || controller.signal.aborted) return;
|
|
2455
|
+
}
|
|
2456
|
+
statusGeneration += 1;
|
|
2457
|
+
const menuGeneration = statusGeneration;
|
|
2458
|
+
statusController?.abort();
|
|
2459
|
+
statusController = void 0;
|
|
2460
|
+
clearStatusTimers();
|
|
2176
2461
|
let stableCurrent = await queryStableCurrent(ctx, false, controller, "Checking current usage\u2026");
|
|
2177
2462
|
if (!stableCurrent) return;
|
|
2178
2463
|
publishStableCurrent(ctx, stableCurrent);
|
|
@@ -2277,7 +2562,7 @@ function usageExtension(pi, dependencies = {}) {
|
|
|
2277
2562
|
const fastAvailability = fastRuntime.availability(ctx.model);
|
|
2278
2563
|
const targetState = actionableTargetState();
|
|
2279
2564
|
const targetAdapter = adapterForProvider(targetState?.providerId);
|
|
2280
|
-
const fastLines = fastAvailability.kind === "available" ? [`Fast mode: ${fastAvailability.enabled ? "On" : "Off"}`, FAST_USAGE_WARNING] : fastAvailability.kind === "unavailable" ? [`Fast mode: Unavailable \xB7 ${fastAvailability.reason}`] : [];
|
|
2565
|
+
const fastLines = fastAvailability.kind === "available" ? [`Fast mode: ${fastAvailability.enabled ? "On" : "Off"}`, FAST_USAGE_WARNING] : fastAvailability.kind === "unavailable" ? [`Fast mode: Unavailable \xB7 ${fastAvailability.reason}`] : fastAvailability.kind === "unknown" ? [`Fast mode: Unknown \xB7 ${fastAvailability.reason}`] : [];
|
|
2281
2566
|
return {
|
|
2282
2567
|
kind: "actions",
|
|
2283
2568
|
title: "Provider usage",
|
|
@@ -2292,10 +2577,10 @@ function usageExtension(pi, dependencies = {}) {
|
|
|
2292
2577
|
action: "target"
|
|
2293
2578
|
}
|
|
2294
2579
|
] : [],
|
|
2295
|
-
...fastAvailability.kind === "available" ? [
|
|
2580
|
+
...fastAvailability.kind === "available" || fastState.settings.codexFastMode && isOfficialCodexModel(ctx.model) ? [
|
|
2296
2581
|
{
|
|
2297
2582
|
id: "toggle-fast",
|
|
2298
|
-
label:
|
|
2583
|
+
label: fastState.settings.codexFastMode ? "Turn Fast mode off" : "Turn Fast mode on",
|
|
2299
2584
|
description: fastState.kind === "invalid" ? "Repair pi-usage.json and reload before changing Fast mode." : FAST_USAGE_WARNING,
|
|
2300
2585
|
disabled: fastState.kind === "invalid",
|
|
2301
2586
|
action: "toggle-fast"
|
|
@@ -2424,7 +2709,7 @@ function usageExtension(pi, dependencies = {}) {
|
|
|
2424
2709
|
];
|
|
2425
2710
|
return { kind: "stay" };
|
|
2426
2711
|
} catch (error) {
|
|
2427
|
-
if (
|
|
2712
|
+
if (isAbortError(error) || isStaleExtensionContextError(error)) {
|
|
2428
2713
|
return { kind: "stay" };
|
|
2429
2714
|
}
|
|
2430
2715
|
ctx.ui.notify(`Could not select target: ${errorMessage(error)}`, "error");
|
|
@@ -2454,10 +2739,11 @@ function usageExtension(pi, dependencies = {}) {
|
|
|
2454
2739
|
},
|
|
2455
2740
|
"toggle-fast": async () => {
|
|
2456
2741
|
const availability = fastRuntime.availability(ctx.model);
|
|
2457
|
-
|
|
2742
|
+
const enabled = settingsRuntime.get().settings.codexFastMode;
|
|
2743
|
+
if (availability.kind !== "available" && !enabled || fastState.kind === "invalid") {
|
|
2458
2744
|
return { kind: "rejected" };
|
|
2459
2745
|
}
|
|
2460
|
-
const changed = await fastRuntime.toggle(ctx, !
|
|
2746
|
+
const changed = await fastRuntime.toggle(ctx, !enabled, controller.signal);
|
|
2461
2747
|
if (!changed) return { kind: "rejected" };
|
|
2462
2748
|
fastState = settingsRuntime.get();
|
|
2463
2749
|
return { kind: "stay" };
|
|
@@ -2481,7 +2767,7 @@ function usageExtension(pi, dependencies = {}) {
|
|
|
2481
2767
|
try {
|
|
2482
2768
|
availability = await listCodexResetCredits(auth, signal, DEFAULT_TIMEOUT_MS);
|
|
2483
2769
|
} catch (error) {
|
|
2484
|
-
if (
|
|
2770
|
+
if (isAbortError(error) || summaryCount === void 0 || summaryCount <= 0) {
|
|
2485
2771
|
throw error;
|
|
2486
2772
|
}
|
|
2487
2773
|
availability = {
|
|
@@ -2514,7 +2800,7 @@ function usageExtension(pi, dependencies = {}) {
|
|
|
2514
2800
|
screen: loaded.availability.availableCount > 0 ? "reset-picker" : "reset-result"
|
|
2515
2801
|
};
|
|
2516
2802
|
} catch (error) {
|
|
2517
|
-
if (
|
|
2803
|
+
if (isAbortError(error) || isStaleExtensionContextError(error)) {
|
|
2518
2804
|
return { kind: "stay" };
|
|
2519
2805
|
}
|
|
2520
2806
|
ctx.ui.notify(`Couldn't load usage limit resets: ${errorMessage(error)}`, "error");
|
|
@@ -2576,7 +2862,7 @@ function usageExtension(pi, dependencies = {}) {
|
|
|
2576
2862
|
}
|
|
2577
2863
|
return { kind: "to", screen: "reset-result" };
|
|
2578
2864
|
} catch (error) {
|
|
2579
|
-
if (
|
|
2865
|
+
if (isAbortError(error) || isStaleExtensionContextError(error)) {
|
|
2580
2866
|
return { kind: "close" };
|
|
2581
2867
|
}
|
|
2582
2868
|
resetFailure = `Couldn't reset usage: ${errorMessage(error)}. Try again with the same request.`;
|
|
@@ -2730,7 +3016,7 @@ function usageExtension(pi, dependencies = {}) {
|
|
|
2730
3016
|
try {
|
|
2731
3017
|
await showMenu(ctx);
|
|
2732
3018
|
} catch (error) {
|
|
2733
|
-
if (isStaleExtensionContextError(error) ||
|
|
3019
|
+
if (isStaleExtensionContextError(error) || isAbortError(error)) return;
|
|
2734
3020
|
throw error;
|
|
2735
3021
|
}
|
|
2736
3022
|
}
|
|
@@ -2776,15 +3062,18 @@ function usageExtension(pi, dependencies = {}) {
|
|
|
2776
3062
|
safeSetStatus(ctx, void 0);
|
|
2777
3063
|
});
|
|
2778
3064
|
fastRuntime = registerCodexFastMode(pi, settingsRuntime, (ctx) => startStatusRefresh(ctx, ctx.model, false), {
|
|
2779
|
-
registerSessionStart: false
|
|
3065
|
+
registerSessionStart: false,
|
|
3066
|
+
credentialReader,
|
|
3067
|
+
candidateReader: credentialCandidates,
|
|
3068
|
+
timeoutMs: DEFAULT_TIMEOUT_MS
|
|
2780
3069
|
});
|
|
2781
3070
|
}
|
|
2782
3071
|
export {
|
|
2783
|
-
CODEX_FAST_MODEL_IDS,
|
|
2784
3072
|
CODEX_FAST_SERVICE_TIER,
|
|
2785
3073
|
CODEX_STANDARD_SERVICE_TIER,
|
|
2786
3074
|
DEFAULT_USAGE_SETTINGS,
|
|
2787
3075
|
SUPPORTED_ADAPTERS,
|
|
3076
|
+
UNKNOWN_CODEX_FAST_CAPABILITY,
|
|
2788
3077
|
UsageCache,
|
|
2789
3078
|
XAI_ADAPTER,
|
|
2790
3079
|
abortError,
|
|
@@ -2807,6 +3096,7 @@ export {
|
|
|
2807
3096
|
formatUsageReport,
|
|
2808
3097
|
formatUsageStatusline,
|
|
2809
3098
|
isBoundedTargetId,
|
|
3099
|
+
isOfficialCodexModel,
|
|
2810
3100
|
isStaleExtensionContextError,
|
|
2811
3101
|
listCodexResetCredits,
|
|
2812
3102
|
listUsageTargets,
|