@narumitw/pi-usage 0.64.2 → 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 +10 -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 -108
- 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 -17
- 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,21 +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-sol",
|
|
62
|
-
"gpt-6.1-sol"
|
|
63
|
-
]);
|
|
64
|
-
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) {
|
|
65
61
|
if (model?.provider !== "openai-codex") return { kind: "not-codex" };
|
|
66
62
|
if (!isOfficialCodexModel(model)) {
|
|
67
63
|
return {
|
|
@@ -69,7 +65,8 @@ function codexFastAvailability(model, enabled) {
|
|
|
69
65
|
reason: "Fast mode requires the official OpenAI Codex Responses endpoint."
|
|
70
66
|
};
|
|
71
67
|
}
|
|
72
|
-
if (
|
|
68
|
+
if (capability.kind === "unknown") return capability;
|
|
69
|
+
if (capability.kind === "unsupported") {
|
|
73
70
|
return {
|
|
74
71
|
kind: "unavailable",
|
|
75
72
|
reason: `${model.id} does not advertise Codex Fast support.`
|
|
@@ -77,20 +74,20 @@ function codexFastAvailability(model, enabled) {
|
|
|
77
74
|
}
|
|
78
75
|
return { kind: "available", enabled };
|
|
79
76
|
}
|
|
80
|
-
function codexFastIsEffective(model, enabled) {
|
|
81
|
-
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;
|
|
82
79
|
}
|
|
83
|
-
function codexFastRequestTier(model, enabled) {
|
|
80
|
+
function codexFastRequestTier(model, enabled, capability = UNKNOWN_CODEX_FAST_CAPABILITY) {
|
|
84
81
|
if (!isOfficialCodexModel(model)) return void 0;
|
|
85
|
-
return enabled &&
|
|
82
|
+
return enabled && capability.kind === "supported" ? CODEX_FAST_SERVICE_TIER : CODEX_STANDARD_SERVICE_TIER;
|
|
86
83
|
}
|
|
87
|
-
function rewriteCodexFastPayload(payload, model, enabled) {
|
|
88
|
-
const serviceTier = codexFastRequestTier(model, enabled);
|
|
84
|
+
function rewriteCodexFastPayload(payload, model, enabled, capability = UNKNOWN_CODEX_FAST_CAPABILITY) {
|
|
85
|
+
const serviceTier = codexFastRequestTier(model, enabled, capability);
|
|
89
86
|
if (!serviceTier || !isRecord(payload)) return void 0;
|
|
90
87
|
return { ...payload, service_tier: serviceTier };
|
|
91
88
|
}
|
|
92
|
-
function correctCodexFastMessageCost(message, model, fastRequested) {
|
|
93
|
-
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) {
|
|
94
91
|
return void 0;
|
|
95
92
|
}
|
|
96
93
|
const usage = isRecord(message.usage) ? message.usage : void 0;
|
|
@@ -1287,6 +1284,231 @@ function isProviderId(value) {
|
|
|
1287
1284
|
// src/usage.ts
|
|
1288
1285
|
import { randomUUID as randomUUID2 } from "node:crypto";
|
|
1289
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
|
+
|
|
1290
1512
|
// src/codex-fast-runtime.ts
|
|
1291
1513
|
var NO_FAST_REQUEST = /* @__PURE__ */ Symbol("no-fast-request");
|
|
1292
1514
|
var FAST_USAGE_WARNING = "Fast is about 1.5\xD7 faster and uses more of your plan allowance.";
|
|
@@ -1294,14 +1516,58 @@ function registerCodexFastMode(pi, settingsRuntime, refreshStatus, options = {})
|
|
|
1294
1516
|
let sessionController = new AbortController();
|
|
1295
1517
|
let generation = 0;
|
|
1296
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
|
+
});
|
|
1297
1532
|
const toggle = async (ctx, enabled, callerSignal) => {
|
|
1298
1533
|
const ownerGeneration = generation;
|
|
1299
1534
|
const sessionId = ctx.sessionManager.getSessionId();
|
|
1300
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
|
+
}
|
|
1301
1567
|
try {
|
|
1302
1568
|
await settingsRuntime.update({ codexFastMode: enabled }, signal);
|
|
1303
1569
|
} catch (error) {
|
|
1304
|
-
if (
|
|
1570
|
+
if (isAbortError2(error) || isStaleExtensionContextError(error)) return false;
|
|
1305
1571
|
ctx.ui.notify(`Could not save pi-usage.json: ${errorMessage(error)}`, "error");
|
|
1306
1572
|
return false;
|
|
1307
1573
|
}
|
|
@@ -1324,26 +1590,18 @@ function registerCodexFastMode(pi, settingsRuntime, refreshStatus, options = {})
|
|
|
1324
1590
|
return;
|
|
1325
1591
|
}
|
|
1326
1592
|
if (!ctx.hasUI) throw new Error("/fast requires TUI or RPC mode.");
|
|
1327
|
-
|
|
1328
|
-
if (availability.kind === "not-codex") {
|
|
1329
|
-
ctx.ui.notify("/fast is available only for the active OpenAI Codex model.", "warning");
|
|
1330
|
-
return;
|
|
1331
|
-
}
|
|
1332
|
-
if (availability.kind === "unavailable") {
|
|
1333
|
-
ctx.ui.notify(availability.reason, "warning");
|
|
1334
|
-
return;
|
|
1335
|
-
}
|
|
1336
|
-
if (settingsRuntime.get().kind === "invalid") {
|
|
1337
|
-
ctx.ui.notify("pi-usage.json is invalid; repair it and run /reload before changing Fast mode.", "error");
|
|
1338
|
-
return;
|
|
1339
|
-
}
|
|
1340
|
-
await toggle(ctx, !availability.enabled);
|
|
1593
|
+
await toggle(ctx, !settingsRuntime.get().settings.codexFastMode);
|
|
1341
1594
|
}
|
|
1342
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
|
+
};
|
|
1343
1600
|
const prepareSession = (ctx) => {
|
|
1344
1601
|
const sessionId = ctx.sessionManager.getSessionId();
|
|
1345
1602
|
generation += 1;
|
|
1346
1603
|
sessionController.abort();
|
|
1604
|
+
catalog.reset();
|
|
1347
1605
|
pendingFastRequests.clear();
|
|
1348
1606
|
sessionController = new AbortController();
|
|
1349
1607
|
const ownerGeneration = generation;
|
|
@@ -1365,18 +1623,28 @@ function registerCodexFastMode(pi, settingsRuntime, refreshStatus, options = {})
|
|
|
1365
1623
|
ctx.ui.notify(`Invalid pi-usage.json; using defaults without overwriting it. ${state.issue}`, "warning");
|
|
1366
1624
|
}
|
|
1367
1625
|
refreshStatus(ctx);
|
|
1626
|
+
if (state.kind !== "invalid" && isOfficialCodexModel(ctx.model)) void refreshCapabilities(ctx);
|
|
1368
1627
|
})();
|
|
1369
1628
|
};
|
|
1370
1629
|
if (options.registerSessionStart !== false) {
|
|
1371
1630
|
pi.on("session_start", async (_event, ctx) => prepareSession(ctx));
|
|
1372
1631
|
}
|
|
1373
|
-
pi.on("
|
|
1374
|
-
|
|
1375
|
-
|
|
1376
|
-
|
|
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) {
|
|
1377
1644
|
pendingFastRequests.set(key, {
|
|
1378
|
-
fastRequested:
|
|
1379
|
-
model
|
|
1645
|
+
fastRequested: isRecord4(rewritten) && rewritten.service_tier === "priority",
|
|
1646
|
+
model,
|
|
1647
|
+
capability
|
|
1380
1648
|
});
|
|
1381
1649
|
}
|
|
1382
1650
|
return rewritten;
|
|
@@ -1384,32 +1652,43 @@ function registerCodexFastMode(pi, settingsRuntime, refreshStatus, options = {})
|
|
|
1384
1652
|
pi.on("message_end", (event, ctx) => {
|
|
1385
1653
|
const request = consumeFastRequest(ctx, event.message, pendingFastRequests);
|
|
1386
1654
|
if (request === NO_FAST_REQUEST) return void 0;
|
|
1387
|
-
const message = correctCodexFastMessageCost(
|
|
1655
|
+
const message = correctCodexFastMessageCost(
|
|
1656
|
+
event.message,
|
|
1657
|
+
request.model,
|
|
1658
|
+
request.fastRequested,
|
|
1659
|
+
request.capability
|
|
1660
|
+
);
|
|
1388
1661
|
return message ? { message } : void 0;
|
|
1389
1662
|
});
|
|
1390
1663
|
pi.on("session_shutdown", async () => {
|
|
1391
1664
|
generation += 1;
|
|
1392
1665
|
sessionController.abort();
|
|
1666
|
+
catalog.reset(true);
|
|
1393
1667
|
pendingFastRequests.clear();
|
|
1394
1668
|
await settingsRuntime.flush();
|
|
1395
1669
|
});
|
|
1396
1670
|
return {
|
|
1397
1671
|
prepareSession,
|
|
1672
|
+
refreshCapabilities,
|
|
1398
1673
|
availability(model) {
|
|
1399
|
-
return codexFastAvailability(model, settingsRuntime.get().settings.codexFastMode);
|
|
1674
|
+
return codexFastAvailability(model, settingsRuntime.get().settings.codexFastMode, catalog.get(model));
|
|
1400
1675
|
},
|
|
1401
1676
|
decorateStatus(model, status) {
|
|
1402
|
-
|
|
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));
|
|
1403
1683
|
},
|
|
1404
1684
|
toggle
|
|
1405
1685
|
};
|
|
1406
1686
|
}
|
|
1407
|
-
function activeRequestKey(ctx) {
|
|
1408
|
-
const model = ctx.model;
|
|
1687
|
+
function activeRequestKey(ctx, model = ctx.model) {
|
|
1409
1688
|
return model ? `${ctx.sessionManager.getSessionId()}:${model.provider}/${model.id}` : void 0;
|
|
1410
1689
|
}
|
|
1411
1690
|
function consumeFastRequest(ctx, message, pending) {
|
|
1412
|
-
if (!
|
|
1691
|
+
if (!isRecord4(message) || message.role !== "assistant") return NO_FAST_REQUEST;
|
|
1413
1692
|
const key = messageRequestKey(ctx, message);
|
|
1414
1693
|
if (!key) return NO_FAST_REQUEST;
|
|
1415
1694
|
const request = pending.get(key);
|
|
@@ -1420,44 +1699,12 @@ function messageRequestKey(ctx, message) {
|
|
|
1420
1699
|
if (typeof message.provider !== "string" || typeof message.model !== "string") return void 0;
|
|
1421
1700
|
return `${ctx.sessionManager.getSessionId()}:${message.provider}/${message.model}`;
|
|
1422
1701
|
}
|
|
1423
|
-
function
|
|
1702
|
+
function isRecord4(value) {
|
|
1424
1703
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
1425
1704
|
}
|
|
1426
|
-
function isAbortError(error) {
|
|
1427
|
-
return error instanceof Error && error.name === "AbortError";
|
|
1428
|
-
}
|
|
1429
|
-
|
|
1430
|
-
// src/usage-helpers.ts
|
|
1431
|
-
function configuredAdapters(ctx) {
|
|
1432
|
-
return usageAdapters().filter(
|
|
1433
|
-
(adapter) => adapter.id === ctx.model?.provider || providerIsConfigured(ctx, adapter.id)
|
|
1434
|
-
);
|
|
1435
|
-
}
|
|
1436
|
-
function providerDisplayName(ctx, providerId) {
|
|
1437
|
-
try {
|
|
1438
|
-
return sanitizeDisplayText(ctx.modelRegistry.getProviderDisplayName(providerId), 80);
|
|
1439
|
-
} catch {
|
|
1440
|
-
return sanitizeDisplayText(providerId, 80);
|
|
1441
|
-
}
|
|
1442
|
-
}
|
|
1443
|
-
function setBoundedMap(map, key, value, limit) {
|
|
1444
|
-
map.delete(key);
|
|
1445
|
-
while (map.size >= limit) {
|
|
1446
|
-
const oldest = map.keys().next().value;
|
|
1447
|
-
if (oldest === void 0) break;
|
|
1448
|
-
map.delete(oldest);
|
|
1449
|
-
}
|
|
1450
|
-
map.set(key, value);
|
|
1451
|
-
}
|
|
1452
|
-
function modelIdentity(model) {
|
|
1453
|
-
return model ? `${model.provider}/${model.id}` : void 0;
|
|
1454
|
-
}
|
|
1455
1705
|
function isAbortError2(error) {
|
|
1456
1706
|
return error instanceof Error && error.name === "AbortError";
|
|
1457
1707
|
}
|
|
1458
|
-
function isTimeoutError(error) {
|
|
1459
|
-
return error instanceof Error && error.name === "TimeoutError";
|
|
1460
|
-
}
|
|
1461
1708
|
|
|
1462
1709
|
// src/usage-settings-ui.ts
|
|
1463
1710
|
import { stripVTControlCharacters } from "node:util";
|
|
@@ -1597,13 +1844,13 @@ async function showUsageSettings(ctx, settingsRuntime, parentSignal, isCurrent,
|
|
|
1597
1844
|
}
|
|
1598
1845
|
|
|
1599
1846
|
// src/usage.ts
|
|
1600
|
-
var
|
|
1847
|
+
var CACHE_TTL_MS2 = 5 * 60 * 1e3;
|
|
1601
1848
|
var STATUS_COUNTDOWN_REFRESH_MS = 60 * 1e3;
|
|
1602
1849
|
var DEFAULT_TIMEOUT_MS = 15e3;
|
|
1603
1850
|
var COMMAND_CODE_REVALIDATION_RESERVE_MS = 1e3;
|
|
1604
1851
|
var ALL_PROVIDER_CONCURRENCY = 2;
|
|
1605
|
-
var
|
|
1606
|
-
var
|
|
1852
|
+
var FAILURE_BACKOFF_MS2 = 3e4;
|
|
1853
|
+
var MAX_ACCOUNT_STATES2 = 32;
|
|
1607
1854
|
var STATUS_KEY = "usage";
|
|
1608
1855
|
var REFRESH_CURRENT = "Refresh current usage";
|
|
1609
1856
|
var VIEW_ANOTHER = "View another configured provider\u2026";
|
|
@@ -1620,7 +1867,7 @@ function usageExtension(pi, dependencies = {}) {
|
|
|
1620
1867
|
const createRedemptionId = dependencies.createRedemptionId ?? randomUUID2;
|
|
1621
1868
|
const settingsRuntime = dependencies.settingsRuntime ?? createUsageSettingsRuntime();
|
|
1622
1869
|
const resolveUsageAuth2 = resolveUsageAuth;
|
|
1623
|
-
const cache = new UsageCache(
|
|
1870
|
+
const cache = new UsageCache(CACHE_TTL_MS2);
|
|
1624
1871
|
const failureBackoff = /* @__PURE__ */ new Map();
|
|
1625
1872
|
const latestQueries = /* @__PURE__ */ new Map();
|
|
1626
1873
|
const activeControllers = /* @__PURE__ */ new Set();
|
|
@@ -1669,7 +1916,7 @@ function usageExtension(pi, dependencies = {}) {
|
|
|
1669
1916
|
statusRefreshTimer = void 0;
|
|
1670
1917
|
if (!sessionActive || generation !== statusGeneration) return;
|
|
1671
1918
|
startStatusRefresh(ctx, model, true);
|
|
1672
|
-
},
|
|
1919
|
+
}, CACHE_TTL_MS2);
|
|
1673
1920
|
statusRefreshTimer.unref?.();
|
|
1674
1921
|
};
|
|
1675
1922
|
const publishStatus = (ctx, outcome, model, shouldSchedule) => {
|
|
@@ -1752,7 +1999,7 @@ function usageExtension(pi, dependencies = {}) {
|
|
|
1752
1999
|
`resolving ${adapter.displayName} runtime auth`
|
|
1753
2000
|
);
|
|
1754
2001
|
} catch (error) {
|
|
1755
|
-
if (isStaleExtensionContextError(error) ||
|
|
2002
|
+
if (isStaleExtensionContextError(error) || isAbortError(error)) throw error;
|
|
1756
2003
|
if (adapter.id === "openai") invalidateProviderState(adapter.id);
|
|
1757
2004
|
const authState = error instanceof UnsupportedOpenAIUsageAuthError ? "unsupported" : adapter.id === "openai" && !isTimeoutError(error) ? "failed" : void 0;
|
|
1758
2005
|
if (displayState === "current") {
|
|
@@ -1901,7 +2148,7 @@ function usageExtension(pi, dependencies = {}) {
|
|
|
1901
2148
|
failureBackoff.delete(failureKey);
|
|
1902
2149
|
querySequence += 1;
|
|
1903
2150
|
queryId = querySequence;
|
|
1904
|
-
setBoundedMap(latestQueries, failureKey, queryId,
|
|
2151
|
+
setBoundedMap(latestQueries, failureKey, queryId, MAX_ACCOUNT_STATES2);
|
|
1905
2152
|
const queryTimeoutMs = Math.max(
|
|
1906
2153
|
1,
|
|
1907
2154
|
deadlineAt - Date.now() - (adapter.id === "command-code" ? COMMAND_CODE_REVALIDATION_RESERVE_MS : 0)
|
|
@@ -1932,7 +2179,7 @@ function usageExtension(pi, dependencies = {}) {
|
|
|
1932
2179
|
rememberedTargetId: expectedTargetId
|
|
1933
2180
|
};
|
|
1934
2181
|
} catch (error) {
|
|
1935
|
-
if (isStaleExtensionContextError(error) ||
|
|
2182
|
+
if (isStaleExtensionContextError(error) || isAbortError(error)) throw error;
|
|
1936
2183
|
if (retryableAuthChanged && authRetry === 0 && !signal.aborted && !requestContextChanged() && Date.now() < deadlineAt) {
|
|
1937
2184
|
if (queryId !== void 0 && latestQueries.get(failureKey) === queryId) {
|
|
1938
2185
|
latestQueries.delete(failureKey);
|
|
@@ -1946,7 +2193,7 @@ function usageExtension(pi, dependencies = {}) {
|
|
|
1946
2193
|
}
|
|
1947
2194
|
if (queryId === void 0 || latestQueries.get(failureKey) === queryId) {
|
|
1948
2195
|
if (adapter.invalidateCacheOnFailure) cache.delete(adapter.id, queryFingerprint);
|
|
1949
|
-
setBoundedMap(failureBackoff, failureKey, { until: now +
|
|
2196
|
+
setBoundedMap(failureBackoff, failureKey, { until: now + FAILURE_BACKOFF_MS2, message }, MAX_ACCOUNT_STATES2);
|
|
1950
2197
|
}
|
|
1951
2198
|
return {
|
|
1952
2199
|
state: {
|
|
@@ -2063,7 +2310,7 @@ function usageExtension(pi, dependencies = {}) {
|
|
|
2063
2310
|
};
|
|
2064
2311
|
const startStatusRefresh = (ctx, model, force) => {
|
|
2065
2312
|
void refreshCurrentStatus(ctx, model, force).catch((error) => {
|
|
2066
|
-
if (isStaleExtensionContextError(error) ||
|
|
2313
|
+
if (isStaleExtensionContextError(error) || isAbortError(error)) return;
|
|
2067
2314
|
const message = errorMessage(error);
|
|
2068
2315
|
console.error("[pi-usage] refresh failed:", message);
|
|
2069
2316
|
safeSetStatus(ctx, `usage err: ${message.slice(0, 50)}`);
|
|
@@ -2107,7 +2354,7 @@ function usageExtension(pi, dependencies = {}) {
|
|
|
2107
2354
|
);
|
|
2108
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;
|
|
2109
2356
|
} catch (error) {
|
|
2110
|
-
if (
|
|
2357
|
+
if (isAbortError(error) || isStaleExtensionContextError(error)) throw error;
|
|
2111
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;
|
|
2112
2359
|
return unchangedFailure && generation === statusGeneration && modelIdentity(ctx.model) === modelIdentity(model) && (!adapter.targets || settingsRuntime.get().settings.selectedTargets[adapter.id] === outcome.rememberedTargetId);
|
|
2113
2360
|
}
|
|
@@ -2123,7 +2370,7 @@ function usageExtension(pi, dependencies = {}) {
|
|
|
2123
2370
|
);
|
|
2124
2371
|
return generation === statusGeneration && modelIdentity(ctx.model) === modelIdentity(model) && (!adapter.targets || settingsRuntime.get().settings.selectedTargets[adapter.id] === outcome.rememberedTargetId) && auth?.fingerprint === outcome.fingerprint;
|
|
2125
2372
|
} catch (error) {
|
|
2126
|
-
if (
|
|
2373
|
+
if (isAbortError(error) || isStaleExtensionContextError(error)) throw error;
|
|
2127
2374
|
return false;
|
|
2128
2375
|
}
|
|
2129
2376
|
};
|
|
@@ -2163,14 +2410,26 @@ function usageExtension(pi, dependencies = {}) {
|
|
|
2163
2410
|
};
|
|
2164
2411
|
const showMenu = async (ctx) => {
|
|
2165
2412
|
if (!ctx.hasUI) throw new Error("/usage requires TUI or RPC mode.");
|
|
2166
|
-
statusGeneration += 1;
|
|
2167
|
-
const menuGeneration = statusGeneration;
|
|
2168
|
-
statusController?.abort();
|
|
2169
|
-
statusController = void 0;
|
|
2170
|
-
clearStatusTimers();
|
|
2171
2413
|
const controller = new AbortController();
|
|
2172
2414
|
activeControllers.add(controller);
|
|
2173
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();
|
|
2174
2433
|
let stableCurrent = await queryStableCurrent(ctx, false, controller, "Checking current usage\u2026");
|
|
2175
2434
|
if (!stableCurrent) return;
|
|
2176
2435
|
publishStableCurrent(ctx, stableCurrent);
|
|
@@ -2275,7 +2534,7 @@ function usageExtension(pi, dependencies = {}) {
|
|
|
2275
2534
|
const fastAvailability = fastRuntime.availability(ctx.model);
|
|
2276
2535
|
const targetState = actionableTargetState();
|
|
2277
2536
|
const targetAdapter = adapterForProvider(targetState?.providerId);
|
|
2278
|
-
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}`] : [];
|
|
2279
2538
|
return {
|
|
2280
2539
|
kind: "actions",
|
|
2281
2540
|
title: "Provider usage",
|
|
@@ -2290,10 +2549,10 @@ function usageExtension(pi, dependencies = {}) {
|
|
|
2290
2549
|
action: "target"
|
|
2291
2550
|
}
|
|
2292
2551
|
] : [],
|
|
2293
|
-
...fastAvailability.kind === "available" ? [
|
|
2552
|
+
...fastAvailability.kind === "available" || fastState.settings.codexFastMode && isOfficialCodexModel(ctx.model) ? [
|
|
2294
2553
|
{
|
|
2295
2554
|
id: "toggle-fast",
|
|
2296
|
-
label:
|
|
2555
|
+
label: fastState.settings.codexFastMode ? "Turn Fast mode off" : "Turn Fast mode on",
|
|
2297
2556
|
description: fastState.kind === "invalid" ? "Repair pi-usage.json and reload before changing Fast mode." : FAST_USAGE_WARNING,
|
|
2298
2557
|
disabled: fastState.kind === "invalid",
|
|
2299
2558
|
action: "toggle-fast"
|
|
@@ -2422,7 +2681,7 @@ function usageExtension(pi, dependencies = {}) {
|
|
|
2422
2681
|
];
|
|
2423
2682
|
return { kind: "stay" };
|
|
2424
2683
|
} catch (error) {
|
|
2425
|
-
if (
|
|
2684
|
+
if (isAbortError(error) || isStaleExtensionContextError(error)) {
|
|
2426
2685
|
return { kind: "stay" };
|
|
2427
2686
|
}
|
|
2428
2687
|
ctx.ui.notify(`Could not select target: ${errorMessage(error)}`, "error");
|
|
@@ -2452,10 +2711,11 @@ function usageExtension(pi, dependencies = {}) {
|
|
|
2452
2711
|
},
|
|
2453
2712
|
"toggle-fast": async () => {
|
|
2454
2713
|
const availability = fastRuntime.availability(ctx.model);
|
|
2455
|
-
|
|
2714
|
+
const enabled = settingsRuntime.get().settings.codexFastMode;
|
|
2715
|
+
if (availability.kind !== "available" && !enabled || fastState.kind === "invalid") {
|
|
2456
2716
|
return { kind: "rejected" };
|
|
2457
2717
|
}
|
|
2458
|
-
const changed = await fastRuntime.toggle(ctx, !
|
|
2718
|
+
const changed = await fastRuntime.toggle(ctx, !enabled, controller.signal);
|
|
2459
2719
|
if (!changed) return { kind: "rejected" };
|
|
2460
2720
|
fastState = settingsRuntime.get();
|
|
2461
2721
|
return { kind: "stay" };
|
|
@@ -2479,7 +2739,7 @@ function usageExtension(pi, dependencies = {}) {
|
|
|
2479
2739
|
try {
|
|
2480
2740
|
availability = await listCodexResetCredits(auth, signal, DEFAULT_TIMEOUT_MS);
|
|
2481
2741
|
} catch (error) {
|
|
2482
|
-
if (
|
|
2742
|
+
if (isAbortError(error) || summaryCount === void 0 || summaryCount <= 0) {
|
|
2483
2743
|
throw error;
|
|
2484
2744
|
}
|
|
2485
2745
|
availability = {
|
|
@@ -2512,7 +2772,7 @@ function usageExtension(pi, dependencies = {}) {
|
|
|
2512
2772
|
screen: loaded.availability.availableCount > 0 ? "reset-picker" : "reset-result"
|
|
2513
2773
|
};
|
|
2514
2774
|
} catch (error) {
|
|
2515
|
-
if (
|
|
2775
|
+
if (isAbortError(error) || isStaleExtensionContextError(error)) {
|
|
2516
2776
|
return { kind: "stay" };
|
|
2517
2777
|
}
|
|
2518
2778
|
ctx.ui.notify(`Couldn't load usage limit resets: ${errorMessage(error)}`, "error");
|
|
@@ -2574,7 +2834,7 @@ function usageExtension(pi, dependencies = {}) {
|
|
|
2574
2834
|
}
|
|
2575
2835
|
return { kind: "to", screen: "reset-result" };
|
|
2576
2836
|
} catch (error) {
|
|
2577
|
-
if (
|
|
2837
|
+
if (isAbortError(error) || isStaleExtensionContextError(error)) {
|
|
2578
2838
|
return { kind: "close" };
|
|
2579
2839
|
}
|
|
2580
2840
|
resetFailure = `Couldn't reset usage: ${errorMessage(error)}. Try again with the same request.`;
|
|
@@ -2728,7 +2988,7 @@ function usageExtension(pi, dependencies = {}) {
|
|
|
2728
2988
|
try {
|
|
2729
2989
|
await showMenu(ctx);
|
|
2730
2990
|
} catch (error) {
|
|
2731
|
-
if (isStaleExtensionContextError(error) ||
|
|
2991
|
+
if (isStaleExtensionContextError(error) || isAbortError(error)) return;
|
|
2732
2992
|
throw error;
|
|
2733
2993
|
}
|
|
2734
2994
|
}
|
|
@@ -2774,15 +3034,18 @@ function usageExtension(pi, dependencies = {}) {
|
|
|
2774
3034
|
safeSetStatus(ctx, void 0);
|
|
2775
3035
|
});
|
|
2776
3036
|
fastRuntime = registerCodexFastMode(pi, settingsRuntime, (ctx) => startStatusRefresh(ctx, ctx.model, false), {
|
|
2777
|
-
registerSessionStart: false
|
|
3037
|
+
registerSessionStart: false,
|
|
3038
|
+
credentialReader,
|
|
3039
|
+
candidateReader: credentialCandidates,
|
|
3040
|
+
timeoutMs: DEFAULT_TIMEOUT_MS
|
|
2778
3041
|
});
|
|
2779
3042
|
}
|
|
2780
3043
|
export {
|
|
2781
|
-
CODEX_FAST_MODEL_IDS,
|
|
2782
3044
|
CODEX_FAST_SERVICE_TIER,
|
|
2783
3045
|
CODEX_STANDARD_SERVICE_TIER,
|
|
2784
3046
|
DEFAULT_USAGE_SETTINGS,
|
|
2785
3047
|
SUPPORTED_ADAPTERS,
|
|
3048
|
+
UNKNOWN_CODEX_FAST_CAPABILITY,
|
|
2786
3049
|
UsageCache,
|
|
2787
3050
|
XAI_ADAPTER,
|
|
2788
3051
|
abortError,
|
|
@@ -2805,6 +3068,7 @@ export {
|
|
|
2805
3068
|
formatUsageReport,
|
|
2806
3069
|
formatUsageStatusline,
|
|
2807
3070
|
isBoundedTargetId,
|
|
3071
|
+
isOfficialCodexModel,
|
|
2808
3072
|
isStaleExtensionContextError,
|
|
2809
3073
|
listCodexResetCredits,
|
|
2810
3074
|
listUsageTargets,
|