@narumitw/pi-usage 0.64.3 → 0.65.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 +9 -3
- 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 +372 -110
- package/dist/index.ts.map +4 -4
- 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/index.ts +3 -1
- package/src/query.ts +2 -1
- package/src/usage.ts +31 -10
- /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;
|
|
@@ -1289,6 +1284,231 @@ function isProviderId(value) {
|
|
|
1289
1284
|
// src/usage.ts
|
|
1290
1285
|
import { randomUUID as randomUUID2 } from "node:crypto";
|
|
1291
1286
|
|
|
1287
|
+
// src/codex-fast-catalog.ts
|
|
1288
|
+
import { VERSION } from "@earendil-works/pi-coding-agent";
|
|
1289
|
+
|
|
1290
|
+
// src/usage-helpers.ts
|
|
1291
|
+
function configuredAdapters(ctx) {
|
|
1292
|
+
return usageAdapters().filter(
|
|
1293
|
+
(adapter) => adapter.id === ctx.model?.provider || providerIsConfigured(ctx, adapter.id)
|
|
1294
|
+
);
|
|
1295
|
+
}
|
|
1296
|
+
function providerDisplayName(ctx, providerId) {
|
|
1297
|
+
try {
|
|
1298
|
+
return sanitizeDisplayText(ctx.modelRegistry.getProviderDisplayName(providerId), 80);
|
|
1299
|
+
} catch {
|
|
1300
|
+
return sanitizeDisplayText(providerId, 80);
|
|
1301
|
+
}
|
|
1302
|
+
}
|
|
1303
|
+
function setBoundedMap(map, key, value, limit) {
|
|
1304
|
+
map.delete(key);
|
|
1305
|
+
while (map.size >= limit) {
|
|
1306
|
+
const oldest = map.keys().next().value;
|
|
1307
|
+
if (oldest === void 0) break;
|
|
1308
|
+
map.delete(oldest);
|
|
1309
|
+
}
|
|
1310
|
+
map.set(key, value);
|
|
1311
|
+
}
|
|
1312
|
+
function modelIdentity(model) {
|
|
1313
|
+
return model ? `${model.provider}/${model.id}` : void 0;
|
|
1314
|
+
}
|
|
1315
|
+
function isAbortError(error) {
|
|
1316
|
+
return error instanceof Error && error.name === "AbortError";
|
|
1317
|
+
}
|
|
1318
|
+
function isTimeoutError(error) {
|
|
1319
|
+
return error instanceof Error && error.name === "TimeoutError";
|
|
1320
|
+
}
|
|
1321
|
+
|
|
1322
|
+
// src/codex-fast-catalog.ts
|
|
1323
|
+
var CACHE_TTL_MS = 5 * 60 * 1e3;
|
|
1324
|
+
var FAILURE_BACKOFF_MS = 3e4;
|
|
1325
|
+
var MAX_ACCOUNT_STATES = 32;
|
|
1326
|
+
var MAX_DIRECTORY_BODY_BYTES = 8 * 1024 * 1024;
|
|
1327
|
+
var DIRECTORY_URL = new URL("https://chatgpt.com/backend-api/codex/models");
|
|
1328
|
+
DIRECTORY_URL.searchParams.set("client_version", VERSION);
|
|
1329
|
+
function createCodexFastCatalog(options = {}) {
|
|
1330
|
+
const accounts = /* @__PURE__ */ new Map();
|
|
1331
|
+
const requests = /* @__PURE__ */ new Map();
|
|
1332
|
+
const latestRequests = /* @__PURE__ */ new Map();
|
|
1333
|
+
const timeoutMs = options.timeoutMs ?? 15e3;
|
|
1334
|
+
let requestSequence = 0;
|
|
1335
|
+
let identitySequence = 0;
|
|
1336
|
+
let generation = 0;
|
|
1337
|
+
let active;
|
|
1338
|
+
let issue = UNKNOWN_CODEX_FAST_CAPABILITY.reason;
|
|
1339
|
+
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;
|
|
1340
|
+
const capability = (model, key = active?.key) => {
|
|
1341
|
+
const entry = key ? accounts.get(key) : void 0;
|
|
1342
|
+
const supported = model ? entry?.models?.get(model.id) : void 0;
|
|
1343
|
+
if (supported !== void 0) return { kind: supported ? "supported" : "unsupported" };
|
|
1344
|
+
return {
|
|
1345
|
+
kind: "unknown",
|
|
1346
|
+
reason: entry?.issue ?? (entry?.models && model ? `The Codex model directory has no Fast capability information for ${model.id}.` : issue)
|
|
1347
|
+
};
|
|
1348
|
+
};
|
|
1349
|
+
const identify = async (ctx, signal) => {
|
|
1350
|
+
const identity = ++identitySequence;
|
|
1351
|
+
const owner = generation;
|
|
1352
|
+
const model = modelIdentity2(ctx.model);
|
|
1353
|
+
const session = ctx.sessionManager.getSessionId();
|
|
1354
|
+
if (!isOfficialCodexModel(ctx.model)) {
|
|
1355
|
+
active = void 0;
|
|
1356
|
+
return void 0;
|
|
1357
|
+
}
|
|
1358
|
+
try {
|
|
1359
|
+
const auth = await awaitWithDeadline(
|
|
1360
|
+
resolveCodexResetAuth(ctx, void 0, options.credentialReader, options.candidateReader),
|
|
1361
|
+
signal,
|
|
1362
|
+
timeoutMs,
|
|
1363
|
+
"resolving the current Codex model-directory account"
|
|
1364
|
+
);
|
|
1365
|
+
if (signal.aborted || owner !== generation || identity !== identitySequence || modelIdentity2(ctx.model) !== model || ctx.sessionManager.getSessionId() !== session) {
|
|
1366
|
+
return void 0;
|
|
1367
|
+
}
|
|
1368
|
+
const accountId = auth.headers["chatgpt-account-id"];
|
|
1369
|
+
if (!accountId) throw new Error("The active Codex account ID is unavailable.");
|
|
1370
|
+
const scope = {
|
|
1371
|
+
key: fingerprintResolvedAuth({ headers: { "chatgpt-account-id": accountId } }, AUTH_FINGERPRINT_SALT),
|
|
1372
|
+
fingerprint: auth.fingerprint,
|
|
1373
|
+
model,
|
|
1374
|
+
session,
|
|
1375
|
+
generation: owner
|
|
1376
|
+
};
|
|
1377
|
+
const changed = active?.key !== scope.key;
|
|
1378
|
+
active = scope;
|
|
1379
|
+
issue = "Codex Fast capability information has not been fetched for this account.";
|
|
1380
|
+
if (changed) options.onChanged?.(ctx);
|
|
1381
|
+
return { auth, scope };
|
|
1382
|
+
} catch (error) {
|
|
1383
|
+
if (signal.aborted || owner !== generation || identity !== identitySequence) return void 0;
|
|
1384
|
+
active = void 0;
|
|
1385
|
+
issue = `Codex Fast capability is unknown: ${redactUsageError(errorMessage(error))}`;
|
|
1386
|
+
options.onChanged?.(ctx);
|
|
1387
|
+
return void 0;
|
|
1388
|
+
}
|
|
1389
|
+
};
|
|
1390
|
+
const load = async (ctx, auth, scope, signal, force) => {
|
|
1391
|
+
const entry = accounts.get(scope.key);
|
|
1392
|
+
if (!force && (entry?.models && entry.fingerprint === auth.fingerprint && Date.now() - entry.fetchedAt < CACHE_TTL_MS || entry?.retryAt && Date.now() < entry.retryAt)) {
|
|
1393
|
+
return;
|
|
1394
|
+
}
|
|
1395
|
+
const before = capability(ctx.model, scope.key);
|
|
1396
|
+
const existing = requests.get(auth.fingerprint);
|
|
1397
|
+
let promise = existing?.promise;
|
|
1398
|
+
if (!promise) {
|
|
1399
|
+
const sequence = ++requestSequence;
|
|
1400
|
+
latestRequests.set(scope.key, sequence);
|
|
1401
|
+
const controller = new AbortController();
|
|
1402
|
+
const combined = AbortSignal.any([signal, controller.signal]);
|
|
1403
|
+
let status;
|
|
1404
|
+
promise = (async () => {
|
|
1405
|
+
try {
|
|
1406
|
+
const payload = await fetchProviderJson(
|
|
1407
|
+
DIRECTORY_URL.href,
|
|
1408
|
+
auth,
|
|
1409
|
+
combined,
|
|
1410
|
+
timeoutMs,
|
|
1411
|
+
"Codex model directory",
|
|
1412
|
+
{
|
|
1413
|
+
redirect: "error",
|
|
1414
|
+
maxSuccessBodyBytes: MAX_DIRECTORY_BODY_BYTES,
|
|
1415
|
+
responseError: (responseStatus) => {
|
|
1416
|
+
status = responseStatus;
|
|
1417
|
+
return void 0;
|
|
1418
|
+
}
|
|
1419
|
+
}
|
|
1420
|
+
);
|
|
1421
|
+
const models = normalizeDirectory(payload);
|
|
1422
|
+
if (combined.aborted || scope.generation !== generation || latestRequests.get(scope.key) !== sequence) return;
|
|
1423
|
+
setBoundedMap(
|
|
1424
|
+
accounts,
|
|
1425
|
+
scope.key,
|
|
1426
|
+
{ models, fetchedAt: Date.now(), fingerprint: auth.fingerprint },
|
|
1427
|
+
MAX_ACCOUNT_STATES
|
|
1428
|
+
);
|
|
1429
|
+
} catch (error) {
|
|
1430
|
+
if (combined.aborted || scope.generation !== generation || latestRequests.get(scope.key) !== sequence) return;
|
|
1431
|
+
const previous = accounts.get(scope.key);
|
|
1432
|
+
const transient = status === void 0 || status >= 500 || status === 429;
|
|
1433
|
+
setBoundedMap(
|
|
1434
|
+
accounts,
|
|
1435
|
+
scope.key,
|
|
1436
|
+
{
|
|
1437
|
+
...transient && previous?.models ? previous : { fetchedAt: 0 },
|
|
1438
|
+
retryAt: Date.now() + FAILURE_BACKOFF_MS,
|
|
1439
|
+
issue: `Codex Fast capability is unknown: ${redactUsageError(errorMessage(error), auth.secrets)}`
|
|
1440
|
+
},
|
|
1441
|
+
MAX_ACCOUNT_STATES
|
|
1442
|
+
);
|
|
1443
|
+
} finally {
|
|
1444
|
+
if (requests.get(auth.fingerprint)?.controller === controller) requests.delete(auth.fingerprint);
|
|
1445
|
+
if (latestRequests.get(scope.key) === sequence) latestRequests.delete(scope.key);
|
|
1446
|
+
}
|
|
1447
|
+
})();
|
|
1448
|
+
requests.set(auth.fingerprint, { controller, promise });
|
|
1449
|
+
}
|
|
1450
|
+
try {
|
|
1451
|
+
await awaitWithDeadline(promise, signal, timeoutMs, "fetching the Codex model directory");
|
|
1452
|
+
} catch (error) {
|
|
1453
|
+
if (signal.aborted) return;
|
|
1454
|
+
throw error;
|
|
1455
|
+
}
|
|
1456
|
+
const after = capability(ctx.model, scope.key);
|
|
1457
|
+
if (current(scope, ctx, signal) && JSON.stringify(before) !== JSON.stringify(after)) options.onChanged?.(ctx);
|
|
1458
|
+
};
|
|
1459
|
+
return {
|
|
1460
|
+
get(model) {
|
|
1461
|
+
return capability(model);
|
|
1462
|
+
},
|
|
1463
|
+
async read(ctx, signal, refresh = false, force = false) {
|
|
1464
|
+
const resolved = await identify(ctx, signal);
|
|
1465
|
+
if (!resolved) return void 0;
|
|
1466
|
+
const { auth, scope } = resolved;
|
|
1467
|
+
if (refresh) await load(ctx, auth, scope, signal, force || capability(ctx.model, scope.key).kind === "unknown");
|
|
1468
|
+
else void load(ctx, auth, scope, signal, false);
|
|
1469
|
+
return current(scope, ctx, signal) ? capability(ctx.model, scope.key) : void 0;
|
|
1470
|
+
},
|
|
1471
|
+
reset(clearCache = false) {
|
|
1472
|
+
generation += 1;
|
|
1473
|
+
identitySequence += 1;
|
|
1474
|
+
active = void 0;
|
|
1475
|
+
issue = UNKNOWN_CODEX_FAST_CAPABILITY.reason;
|
|
1476
|
+
for (const { controller } of requests.values()) controller.abort();
|
|
1477
|
+
requests.clear();
|
|
1478
|
+
latestRequests.clear();
|
|
1479
|
+
if (clearCache) accounts.clear();
|
|
1480
|
+
}
|
|
1481
|
+
};
|
|
1482
|
+
}
|
|
1483
|
+
function normalizeDirectory(payload) {
|
|
1484
|
+
if (!Array.isArray(payload.models)) throw new Error("The Codex model directory returned invalid models.");
|
|
1485
|
+
const models = /* @__PURE__ */ new Map();
|
|
1486
|
+
for (const item of payload.models) {
|
|
1487
|
+
if (!isRecord3(item) || typeof item.slug !== "string" || !item.slug.trim() || models.has(item.slug)) {
|
|
1488
|
+
throw new Error("The Codex model directory returned an invalid or duplicate model ID.");
|
|
1489
|
+
}
|
|
1490
|
+
const hasTiers = item.service_tiers !== void 0;
|
|
1491
|
+
const hasLegacy = item.additional_speed_tiers !== void 0;
|
|
1492
|
+
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"))) {
|
|
1493
|
+
throw new Error("The Codex model directory returned invalid service tiers.");
|
|
1494
|
+
}
|
|
1495
|
+
if (!hasTiers && !hasLegacy) {
|
|
1496
|
+
models.set(item.slug, void 0);
|
|
1497
|
+
continue;
|
|
1498
|
+
}
|
|
1499
|
+
const tiers = item.service_tiers ?? [];
|
|
1500
|
+
const legacy = item.additional_speed_tiers ?? [];
|
|
1501
|
+
models.set(item.slug, tiers.some((tier) => tier.id === "priority") || legacy.includes("fast"));
|
|
1502
|
+
}
|
|
1503
|
+
return models;
|
|
1504
|
+
}
|
|
1505
|
+
function modelIdentity2(model) {
|
|
1506
|
+
return model ? `${model.provider}/${model.id}` : "";
|
|
1507
|
+
}
|
|
1508
|
+
function isRecord3(value) {
|
|
1509
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
1510
|
+
}
|
|
1511
|
+
|
|
1292
1512
|
// src/codex-fast-runtime.ts
|
|
1293
1513
|
var NO_FAST_REQUEST = /* @__PURE__ */ Symbol("no-fast-request");
|
|
1294
1514
|
var FAST_USAGE_WARNING = "Fast is about 1.5\xD7 faster and uses more of your plan allowance.";
|
|
@@ -1296,14 +1516,58 @@ function registerCodexFastMode(pi, settingsRuntime, refreshStatus, options = {})
|
|
|
1296
1516
|
let sessionController = new AbortController();
|
|
1297
1517
|
let generation = 0;
|
|
1298
1518
|
const pendingFastRequests = /* @__PURE__ */ new Map();
|
|
1519
|
+
const catalog = createCodexFastCatalog({
|
|
1520
|
+
credentialReader: options.credentialReader,
|
|
1521
|
+
candidateReader: options.candidateReader ?? createOAuthCredentialCandidateReader(pi, options.credentialReader),
|
|
1522
|
+
timeoutMs: options.timeoutMs,
|
|
1523
|
+
onChanged(ctx) {
|
|
1524
|
+
if (sessionController.signal.aborted || !settingsRuntime.get().settings.codexFastMode) return;
|
|
1525
|
+
try {
|
|
1526
|
+
refreshStatus(ctx);
|
|
1527
|
+
} catch (error) {
|
|
1528
|
+
if (!isStaleExtensionContextError(error)) throw error;
|
|
1529
|
+
}
|
|
1530
|
+
}
|
|
1531
|
+
});
|
|
1299
1532
|
const toggle = async (ctx, enabled, callerSignal) => {
|
|
1300
1533
|
const ownerGeneration = generation;
|
|
1301
1534
|
const sessionId = ctx.sessionManager.getSessionId();
|
|
1302
1535
|
const signal = callerSignal ? AbortSignal.any([callerSignal, sessionController.signal]) : sessionController.signal;
|
|
1536
|
+
if (ctx.model?.provider !== "openai-codex") {
|
|
1537
|
+
ctx.ui.notify("/fast is available only for the active OpenAI Codex model.", "warning");
|
|
1538
|
+
return false;
|
|
1539
|
+
}
|
|
1540
|
+
if (!isOfficialCodexModel(ctx.model)) {
|
|
1541
|
+
ctx.ui.notify("Fast mode requires the official OpenAI Codex Responses endpoint.", "warning");
|
|
1542
|
+
return false;
|
|
1543
|
+
}
|
|
1544
|
+
if (settingsRuntime.get().kind === "invalid") {
|
|
1545
|
+
ctx.ui.notify("pi-usage.json is invalid; repair it and run /reload before changing Fast mode.", "error");
|
|
1546
|
+
return false;
|
|
1547
|
+
}
|
|
1548
|
+
if (enabled) {
|
|
1549
|
+
const capability = await catalog.read(ctx, signal, true, catalog.get(ctx.model).kind !== "supported");
|
|
1550
|
+
if (signal.aborted || ownerGeneration !== generation) return false;
|
|
1551
|
+
if (!capability) {
|
|
1552
|
+
const latest = catalog.get(ctx.model);
|
|
1553
|
+
ctx.ui.notify(
|
|
1554
|
+
latest.kind === "unknown" ? latest.reason : "The active Codex account changed while checking Fast capability.",
|
|
1555
|
+
"warning"
|
|
1556
|
+
);
|
|
1557
|
+
return false;
|
|
1558
|
+
}
|
|
1559
|
+
const availability = codexFastAvailability(ctx.model, false, capability);
|
|
1560
|
+
if (availability.kind !== "available") {
|
|
1561
|
+
if (availability.kind === "unknown" || availability.kind === "unavailable") {
|
|
1562
|
+
ctx.ui.notify(availability.reason, "warning");
|
|
1563
|
+
}
|
|
1564
|
+
return false;
|
|
1565
|
+
}
|
|
1566
|
+
}
|
|
1303
1567
|
try {
|
|
1304
1568
|
await settingsRuntime.update({ codexFastMode: enabled }, signal);
|
|
1305
1569
|
} catch (error) {
|
|
1306
|
-
if (
|
|
1570
|
+
if (isAbortError2(error) || isStaleExtensionContextError(error)) return false;
|
|
1307
1571
|
ctx.ui.notify(`Could not save pi-usage.json: ${errorMessage(error)}`, "error");
|
|
1308
1572
|
return false;
|
|
1309
1573
|
}
|
|
@@ -1326,26 +1590,18 @@ function registerCodexFastMode(pi, settingsRuntime, refreshStatus, options = {})
|
|
|
1326
1590
|
return;
|
|
1327
1591
|
}
|
|
1328
1592
|
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);
|
|
1593
|
+
await toggle(ctx, !settingsRuntime.get().settings.codexFastMode);
|
|
1343
1594
|
}
|
|
1344
1595
|
});
|
|
1596
|
+
const refreshCapabilities = (ctx, callerSignal, force = false) => {
|
|
1597
|
+
const signal = callerSignal ? AbortSignal.any([callerSignal, sessionController.signal]) : sessionController.signal;
|
|
1598
|
+
return catalog.read(ctx, signal, true, force);
|
|
1599
|
+
};
|
|
1345
1600
|
const prepareSession = (ctx) => {
|
|
1346
1601
|
const sessionId = ctx.sessionManager.getSessionId();
|
|
1347
1602
|
generation += 1;
|
|
1348
1603
|
sessionController.abort();
|
|
1604
|
+
catalog.reset();
|
|
1349
1605
|
pendingFastRequests.clear();
|
|
1350
1606
|
sessionController = new AbortController();
|
|
1351
1607
|
const ownerGeneration = generation;
|
|
@@ -1367,18 +1623,28 @@ function registerCodexFastMode(pi, settingsRuntime, refreshStatus, options = {})
|
|
|
1367
1623
|
ctx.ui.notify(`Invalid pi-usage.json; using defaults without overwriting it. ${state.issue}`, "warning");
|
|
1368
1624
|
}
|
|
1369
1625
|
refreshStatus(ctx);
|
|
1626
|
+
if (state.kind !== "invalid" && isOfficialCodexModel(ctx.model)) void refreshCapabilities(ctx);
|
|
1370
1627
|
})();
|
|
1371
1628
|
};
|
|
1372
1629
|
if (options.registerSessionStart !== false) {
|
|
1373
1630
|
pi.on("session_start", async (_event, ctx) => prepareSession(ctx));
|
|
1374
1631
|
}
|
|
1375
|
-
pi.on("
|
|
1376
|
-
|
|
1377
|
-
|
|
1378
|
-
|
|
1632
|
+
pi.on("model_select", (_event, ctx) => {
|
|
1633
|
+
void refreshCapabilities(ctx);
|
|
1634
|
+
});
|
|
1635
|
+
pi.on("before_provider_request", async (event, ctx) => {
|
|
1636
|
+
const ownerGeneration = generation;
|
|
1637
|
+
const model = ctx.model;
|
|
1638
|
+
const enabled = settingsRuntime.get().settings.codexFastMode;
|
|
1639
|
+
const capability = enabled && isOfficialCodexModel(model) ? await catalog.read(ctx, sessionController.signal) ?? UNKNOWN_CODEX_FAST_CAPABILITY : UNKNOWN_CODEX_FAST_CAPABILITY;
|
|
1640
|
+
if (sessionController.signal.aborted || ownerGeneration !== generation) return void 0;
|
|
1641
|
+
const rewritten = rewriteCodexFastPayload(event.payload, model, enabled, capability);
|
|
1642
|
+
const key = activeRequestKey(ctx, model);
|
|
1643
|
+
if (key && model) {
|
|
1379
1644
|
pendingFastRequests.set(key, {
|
|
1380
|
-
fastRequested:
|
|
1381
|
-
model
|
|
1645
|
+
fastRequested: isRecord4(rewritten) && rewritten.service_tier === "priority",
|
|
1646
|
+
model,
|
|
1647
|
+
capability
|
|
1382
1648
|
});
|
|
1383
1649
|
}
|
|
1384
1650
|
return rewritten;
|
|
@@ -1386,32 +1652,43 @@ function registerCodexFastMode(pi, settingsRuntime, refreshStatus, options = {})
|
|
|
1386
1652
|
pi.on("message_end", (event, ctx) => {
|
|
1387
1653
|
const request = consumeFastRequest(ctx, event.message, pendingFastRequests);
|
|
1388
1654
|
if (request === NO_FAST_REQUEST) return void 0;
|
|
1389
|
-
const message = correctCodexFastMessageCost(
|
|
1655
|
+
const message = correctCodexFastMessageCost(
|
|
1656
|
+
event.message,
|
|
1657
|
+
request.model,
|
|
1658
|
+
request.fastRequested,
|
|
1659
|
+
request.capability
|
|
1660
|
+
);
|
|
1390
1661
|
return message ? { message } : void 0;
|
|
1391
1662
|
});
|
|
1392
1663
|
pi.on("session_shutdown", async () => {
|
|
1393
1664
|
generation += 1;
|
|
1394
1665
|
sessionController.abort();
|
|
1666
|
+
catalog.reset(true);
|
|
1395
1667
|
pendingFastRequests.clear();
|
|
1396
1668
|
await settingsRuntime.flush();
|
|
1397
1669
|
});
|
|
1398
1670
|
return {
|
|
1399
1671
|
prepareSession,
|
|
1672
|
+
refreshCapabilities,
|
|
1400
1673
|
availability(model) {
|
|
1401
|
-
return codexFastAvailability(model, settingsRuntime.get().settings.codexFastMode);
|
|
1674
|
+
return codexFastAvailability(model, settingsRuntime.get().settings.codexFastMode, catalog.get(model));
|
|
1402
1675
|
},
|
|
1403
1676
|
decorateStatus(model, status) {
|
|
1404
|
-
|
|
1677
|
+
const enabled = settingsRuntime.get().settings.codexFastMode;
|
|
1678
|
+
const capability = catalog.get(model);
|
|
1679
|
+
if (enabled && codexFastAvailability(model, enabled, capability).kind === "unknown" && /^codex(?:\s|$)/u.test(status)) {
|
|
1680
|
+
return `codex (Fast unknown)${status.slice("codex".length)}`;
|
|
1681
|
+
}
|
|
1682
|
+
return codexFastStatusLabel(status, codexFastIsEffective(model, enabled, capability));
|
|
1405
1683
|
},
|
|
1406
1684
|
toggle
|
|
1407
1685
|
};
|
|
1408
1686
|
}
|
|
1409
|
-
function activeRequestKey(ctx) {
|
|
1410
|
-
const model = ctx.model;
|
|
1687
|
+
function activeRequestKey(ctx, model = ctx.model) {
|
|
1411
1688
|
return model ? `${ctx.sessionManager.getSessionId()}:${model.provider}/${model.id}` : void 0;
|
|
1412
1689
|
}
|
|
1413
1690
|
function consumeFastRequest(ctx, message, pending) {
|
|
1414
|
-
if (!
|
|
1691
|
+
if (!isRecord4(message) || message.role !== "assistant") return NO_FAST_REQUEST;
|
|
1415
1692
|
const key = messageRequestKey(ctx, message);
|
|
1416
1693
|
if (!key) return NO_FAST_REQUEST;
|
|
1417
1694
|
const request = pending.get(key);
|
|
@@ -1422,44 +1699,12 @@ function messageRequestKey(ctx, message) {
|
|
|
1422
1699
|
if (typeof message.provider !== "string" || typeof message.model !== "string") return void 0;
|
|
1423
1700
|
return `${ctx.sessionManager.getSessionId()}:${message.provider}/${message.model}`;
|
|
1424
1701
|
}
|
|
1425
|
-
function
|
|
1702
|
+
function isRecord4(value) {
|
|
1426
1703
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
1427
1704
|
}
|
|
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
1705
|
function isAbortError2(error) {
|
|
1458
1706
|
return error instanceof Error && error.name === "AbortError";
|
|
1459
1707
|
}
|
|
1460
|
-
function isTimeoutError(error) {
|
|
1461
|
-
return error instanceof Error && error.name === "TimeoutError";
|
|
1462
|
-
}
|
|
1463
1708
|
|
|
1464
1709
|
// src/usage-settings-ui.ts
|
|
1465
1710
|
import { stripVTControlCharacters } from "node:util";
|
|
@@ -1599,13 +1844,13 @@ async function showUsageSettings(ctx, settingsRuntime, parentSignal, isCurrent,
|
|
|
1599
1844
|
}
|
|
1600
1845
|
|
|
1601
1846
|
// src/usage.ts
|
|
1602
|
-
var
|
|
1847
|
+
var CACHE_TTL_MS2 = 5 * 60 * 1e3;
|
|
1603
1848
|
var STATUS_COUNTDOWN_REFRESH_MS = 60 * 1e3;
|
|
1604
1849
|
var DEFAULT_TIMEOUT_MS = 15e3;
|
|
1605
1850
|
var COMMAND_CODE_REVALIDATION_RESERVE_MS = 1e3;
|
|
1606
1851
|
var ALL_PROVIDER_CONCURRENCY = 2;
|
|
1607
|
-
var
|
|
1608
|
-
var
|
|
1852
|
+
var FAILURE_BACKOFF_MS2 = 3e4;
|
|
1853
|
+
var MAX_ACCOUNT_STATES2 = 32;
|
|
1609
1854
|
var STATUS_KEY = "usage";
|
|
1610
1855
|
var REFRESH_CURRENT = "Refresh current usage";
|
|
1611
1856
|
var VIEW_ANOTHER = "View another configured provider\u2026";
|
|
@@ -1622,7 +1867,7 @@ function usageExtension(pi, dependencies = {}) {
|
|
|
1622
1867
|
const createRedemptionId = dependencies.createRedemptionId ?? randomUUID2;
|
|
1623
1868
|
const settingsRuntime = dependencies.settingsRuntime ?? createUsageSettingsRuntime();
|
|
1624
1869
|
const resolveUsageAuth2 = resolveUsageAuth;
|
|
1625
|
-
const cache = new UsageCache(
|
|
1870
|
+
const cache = new UsageCache(CACHE_TTL_MS2);
|
|
1626
1871
|
const failureBackoff = /* @__PURE__ */ new Map();
|
|
1627
1872
|
const latestQueries = /* @__PURE__ */ new Map();
|
|
1628
1873
|
const activeControllers = /* @__PURE__ */ new Set();
|
|
@@ -1671,7 +1916,7 @@ function usageExtension(pi, dependencies = {}) {
|
|
|
1671
1916
|
statusRefreshTimer = void 0;
|
|
1672
1917
|
if (!sessionActive || generation !== statusGeneration) return;
|
|
1673
1918
|
startStatusRefresh(ctx, model, true);
|
|
1674
|
-
},
|
|
1919
|
+
}, CACHE_TTL_MS2);
|
|
1675
1920
|
statusRefreshTimer.unref?.();
|
|
1676
1921
|
};
|
|
1677
1922
|
const publishStatus = (ctx, outcome, model, shouldSchedule) => {
|
|
@@ -1754,7 +1999,7 @@ function usageExtension(pi, dependencies = {}) {
|
|
|
1754
1999
|
`resolving ${adapter.displayName} runtime auth`
|
|
1755
2000
|
);
|
|
1756
2001
|
} catch (error) {
|
|
1757
|
-
if (isStaleExtensionContextError(error) ||
|
|
2002
|
+
if (isStaleExtensionContextError(error) || isAbortError(error)) throw error;
|
|
1758
2003
|
if (adapter.id === "openai") invalidateProviderState(adapter.id);
|
|
1759
2004
|
const authState = error instanceof UnsupportedOpenAIUsageAuthError ? "unsupported" : adapter.id === "openai" && !isTimeoutError(error) ? "failed" : void 0;
|
|
1760
2005
|
if (displayState === "current") {
|
|
@@ -1903,7 +2148,7 @@ function usageExtension(pi, dependencies = {}) {
|
|
|
1903
2148
|
failureBackoff.delete(failureKey);
|
|
1904
2149
|
querySequence += 1;
|
|
1905
2150
|
queryId = querySequence;
|
|
1906
|
-
setBoundedMap(latestQueries, failureKey, queryId,
|
|
2151
|
+
setBoundedMap(latestQueries, failureKey, queryId, MAX_ACCOUNT_STATES2);
|
|
1907
2152
|
const queryTimeoutMs = Math.max(
|
|
1908
2153
|
1,
|
|
1909
2154
|
deadlineAt - Date.now() - (adapter.id === "command-code" ? COMMAND_CODE_REVALIDATION_RESERVE_MS : 0)
|
|
@@ -1934,7 +2179,7 @@ function usageExtension(pi, dependencies = {}) {
|
|
|
1934
2179
|
rememberedTargetId: expectedTargetId
|
|
1935
2180
|
};
|
|
1936
2181
|
} catch (error) {
|
|
1937
|
-
if (isStaleExtensionContextError(error) ||
|
|
2182
|
+
if (isStaleExtensionContextError(error) || isAbortError(error)) throw error;
|
|
1938
2183
|
if (retryableAuthChanged && authRetry === 0 && !signal.aborted && !requestContextChanged() && Date.now() < deadlineAt) {
|
|
1939
2184
|
if (queryId !== void 0 && latestQueries.get(failureKey) === queryId) {
|
|
1940
2185
|
latestQueries.delete(failureKey);
|
|
@@ -1948,7 +2193,7 @@ function usageExtension(pi, dependencies = {}) {
|
|
|
1948
2193
|
}
|
|
1949
2194
|
if (queryId === void 0 || latestQueries.get(failureKey) === queryId) {
|
|
1950
2195
|
if (adapter.invalidateCacheOnFailure) cache.delete(adapter.id, queryFingerprint);
|
|
1951
|
-
setBoundedMap(failureBackoff, failureKey, { until: now +
|
|
2196
|
+
setBoundedMap(failureBackoff, failureKey, { until: now + FAILURE_BACKOFF_MS2, message }, MAX_ACCOUNT_STATES2);
|
|
1952
2197
|
}
|
|
1953
2198
|
return {
|
|
1954
2199
|
state: {
|
|
@@ -2065,7 +2310,7 @@ function usageExtension(pi, dependencies = {}) {
|
|
|
2065
2310
|
};
|
|
2066
2311
|
const startStatusRefresh = (ctx, model, force) => {
|
|
2067
2312
|
void refreshCurrentStatus(ctx, model, force).catch((error) => {
|
|
2068
|
-
if (isStaleExtensionContextError(error) ||
|
|
2313
|
+
if (isStaleExtensionContextError(error) || isAbortError(error)) return;
|
|
2069
2314
|
const message = errorMessage(error);
|
|
2070
2315
|
console.error("[pi-usage] refresh failed:", message);
|
|
2071
2316
|
safeSetStatus(ctx, `usage err: ${message.slice(0, 50)}`);
|
|
@@ -2109,7 +2354,7 @@ function usageExtension(pi, dependencies = {}) {
|
|
|
2109
2354
|
);
|
|
2110
2355
|
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
2356
|
} catch (error) {
|
|
2112
|
-
if (
|
|
2357
|
+
if (isAbortError(error) || isStaleExtensionContextError(error)) throw error;
|
|
2113
2358
|
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
2359
|
return unchangedFailure && generation === statusGeneration && modelIdentity(ctx.model) === modelIdentity(model) && (!adapter.targets || settingsRuntime.get().settings.selectedTargets[adapter.id] === outcome.rememberedTargetId);
|
|
2115
2360
|
}
|
|
@@ -2125,7 +2370,7 @@ function usageExtension(pi, dependencies = {}) {
|
|
|
2125
2370
|
);
|
|
2126
2371
|
return generation === statusGeneration && modelIdentity(ctx.model) === modelIdentity(model) && (!adapter.targets || settingsRuntime.get().settings.selectedTargets[adapter.id] === outcome.rememberedTargetId) && auth?.fingerprint === outcome.fingerprint;
|
|
2127
2372
|
} catch (error) {
|
|
2128
|
-
if (
|
|
2373
|
+
if (isAbortError(error) || isStaleExtensionContextError(error)) throw error;
|
|
2129
2374
|
return false;
|
|
2130
2375
|
}
|
|
2131
2376
|
};
|
|
@@ -2165,14 +2410,26 @@ function usageExtension(pi, dependencies = {}) {
|
|
|
2165
2410
|
};
|
|
2166
2411
|
const showMenu = async (ctx) => {
|
|
2167
2412
|
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
2413
|
const controller = new AbortController();
|
|
2174
2414
|
activeControllers.add(controller);
|
|
2175
2415
|
try {
|
|
2416
|
+
if (isOfficialCodexModel(ctx.model)) {
|
|
2417
|
+
const refreshed = await runMenuOperation(
|
|
2418
|
+
ctx,
|
|
2419
|
+
"Checking Codex Fast capability\u2026",
|
|
2420
|
+
controller.signal,
|
|
2421
|
+
async (signal) => {
|
|
2422
|
+
await fastRuntime.refreshCapabilities(ctx, signal);
|
|
2423
|
+
return true;
|
|
2424
|
+
}
|
|
2425
|
+
);
|
|
2426
|
+
if (!refreshed || controller.signal.aborted) return;
|
|
2427
|
+
}
|
|
2428
|
+
statusGeneration += 1;
|
|
2429
|
+
const menuGeneration = statusGeneration;
|
|
2430
|
+
statusController?.abort();
|
|
2431
|
+
statusController = void 0;
|
|
2432
|
+
clearStatusTimers();
|
|
2176
2433
|
let stableCurrent = await queryStableCurrent(ctx, false, controller, "Checking current usage\u2026");
|
|
2177
2434
|
if (!stableCurrent) return;
|
|
2178
2435
|
publishStableCurrent(ctx, stableCurrent);
|
|
@@ -2277,7 +2534,7 @@ function usageExtension(pi, dependencies = {}) {
|
|
|
2277
2534
|
const fastAvailability = fastRuntime.availability(ctx.model);
|
|
2278
2535
|
const targetState = actionableTargetState();
|
|
2279
2536
|
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}`] : [];
|
|
2537
|
+
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
2538
|
return {
|
|
2282
2539
|
kind: "actions",
|
|
2283
2540
|
title: "Provider usage",
|
|
@@ -2292,10 +2549,10 @@ function usageExtension(pi, dependencies = {}) {
|
|
|
2292
2549
|
action: "target"
|
|
2293
2550
|
}
|
|
2294
2551
|
] : [],
|
|
2295
|
-
...fastAvailability.kind === "available" ? [
|
|
2552
|
+
...fastAvailability.kind === "available" || fastState.settings.codexFastMode && isOfficialCodexModel(ctx.model) ? [
|
|
2296
2553
|
{
|
|
2297
2554
|
id: "toggle-fast",
|
|
2298
|
-
label:
|
|
2555
|
+
label: fastState.settings.codexFastMode ? "Turn Fast mode off" : "Turn Fast mode on",
|
|
2299
2556
|
description: fastState.kind === "invalid" ? "Repair pi-usage.json and reload before changing Fast mode." : FAST_USAGE_WARNING,
|
|
2300
2557
|
disabled: fastState.kind === "invalid",
|
|
2301
2558
|
action: "toggle-fast"
|
|
@@ -2424,7 +2681,7 @@ function usageExtension(pi, dependencies = {}) {
|
|
|
2424
2681
|
];
|
|
2425
2682
|
return { kind: "stay" };
|
|
2426
2683
|
} catch (error) {
|
|
2427
|
-
if (
|
|
2684
|
+
if (isAbortError(error) || isStaleExtensionContextError(error)) {
|
|
2428
2685
|
return { kind: "stay" };
|
|
2429
2686
|
}
|
|
2430
2687
|
ctx.ui.notify(`Could not select target: ${errorMessage(error)}`, "error");
|
|
@@ -2454,10 +2711,11 @@ function usageExtension(pi, dependencies = {}) {
|
|
|
2454
2711
|
},
|
|
2455
2712
|
"toggle-fast": async () => {
|
|
2456
2713
|
const availability = fastRuntime.availability(ctx.model);
|
|
2457
|
-
|
|
2714
|
+
const enabled = settingsRuntime.get().settings.codexFastMode;
|
|
2715
|
+
if (availability.kind !== "available" && !enabled || fastState.kind === "invalid") {
|
|
2458
2716
|
return { kind: "rejected" };
|
|
2459
2717
|
}
|
|
2460
|
-
const changed = await fastRuntime.toggle(ctx, !
|
|
2718
|
+
const changed = await fastRuntime.toggle(ctx, !enabled, controller.signal);
|
|
2461
2719
|
if (!changed) return { kind: "rejected" };
|
|
2462
2720
|
fastState = settingsRuntime.get();
|
|
2463
2721
|
return { kind: "stay" };
|
|
@@ -2481,7 +2739,7 @@ function usageExtension(pi, dependencies = {}) {
|
|
|
2481
2739
|
try {
|
|
2482
2740
|
availability = await listCodexResetCredits(auth, signal, DEFAULT_TIMEOUT_MS);
|
|
2483
2741
|
} catch (error) {
|
|
2484
|
-
if (
|
|
2742
|
+
if (isAbortError(error) || summaryCount === void 0 || summaryCount <= 0) {
|
|
2485
2743
|
throw error;
|
|
2486
2744
|
}
|
|
2487
2745
|
availability = {
|
|
@@ -2514,7 +2772,7 @@ function usageExtension(pi, dependencies = {}) {
|
|
|
2514
2772
|
screen: loaded.availability.availableCount > 0 ? "reset-picker" : "reset-result"
|
|
2515
2773
|
};
|
|
2516
2774
|
} catch (error) {
|
|
2517
|
-
if (
|
|
2775
|
+
if (isAbortError(error) || isStaleExtensionContextError(error)) {
|
|
2518
2776
|
return { kind: "stay" };
|
|
2519
2777
|
}
|
|
2520
2778
|
ctx.ui.notify(`Couldn't load usage limit resets: ${errorMessage(error)}`, "error");
|
|
@@ -2576,7 +2834,7 @@ function usageExtension(pi, dependencies = {}) {
|
|
|
2576
2834
|
}
|
|
2577
2835
|
return { kind: "to", screen: "reset-result" };
|
|
2578
2836
|
} catch (error) {
|
|
2579
|
-
if (
|
|
2837
|
+
if (isAbortError(error) || isStaleExtensionContextError(error)) {
|
|
2580
2838
|
return { kind: "close" };
|
|
2581
2839
|
}
|
|
2582
2840
|
resetFailure = `Couldn't reset usage: ${errorMessage(error)}. Try again with the same request.`;
|
|
@@ -2730,7 +2988,7 @@ function usageExtension(pi, dependencies = {}) {
|
|
|
2730
2988
|
try {
|
|
2731
2989
|
await showMenu(ctx);
|
|
2732
2990
|
} catch (error) {
|
|
2733
|
-
if (isStaleExtensionContextError(error) ||
|
|
2991
|
+
if (isStaleExtensionContextError(error) || isAbortError(error)) return;
|
|
2734
2992
|
throw error;
|
|
2735
2993
|
}
|
|
2736
2994
|
}
|
|
@@ -2776,15 +3034,18 @@ function usageExtension(pi, dependencies = {}) {
|
|
|
2776
3034
|
safeSetStatus(ctx, void 0);
|
|
2777
3035
|
});
|
|
2778
3036
|
fastRuntime = registerCodexFastMode(pi, settingsRuntime, (ctx) => startStatusRefresh(ctx, ctx.model, false), {
|
|
2779
|
-
registerSessionStart: false
|
|
3037
|
+
registerSessionStart: false,
|
|
3038
|
+
credentialReader,
|
|
3039
|
+
candidateReader: credentialCandidates,
|
|
3040
|
+
timeoutMs: DEFAULT_TIMEOUT_MS
|
|
2780
3041
|
});
|
|
2781
3042
|
}
|
|
2782
3043
|
export {
|
|
2783
|
-
CODEX_FAST_MODEL_IDS,
|
|
2784
3044
|
CODEX_FAST_SERVICE_TIER,
|
|
2785
3045
|
CODEX_STANDARD_SERVICE_TIER,
|
|
2786
3046
|
DEFAULT_USAGE_SETTINGS,
|
|
2787
3047
|
SUPPORTED_ADAPTERS,
|
|
3048
|
+
UNKNOWN_CODEX_FAST_CAPABILITY,
|
|
2788
3049
|
UsageCache,
|
|
2789
3050
|
XAI_ADAPTER,
|
|
2790
3051
|
abortError,
|
|
@@ -2807,6 +3068,7 @@ export {
|
|
|
2807
3068
|
formatUsageReport,
|
|
2808
3069
|
formatUsageStatusline,
|
|
2809
3070
|
isBoundedTargetId,
|
|
3071
|
+
isOfficialCodexModel,
|
|
2810
3072
|
isStaleExtensionContextError,
|
|
2811
3073
|
listCodexResetCredits,
|
|
2812
3074
|
listUsageTargets,
|