@narumitw/pi-usage 0.52.1 → 0.52.2
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 +78 -51
- package/dist/index.ts +190 -43
- package/dist/index.ts.map +4 -4
- package/package.json +5 -5
- package/src/codex-resets.ts +83 -18
- package/src/oauth-credential-source.ts +88 -0
- package/src/query.ts +77 -20
- package/src/usage.ts +8 -6
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@narumitw/pi-usage",
|
|
3
|
-
"version": "0.52.
|
|
3
|
+
"version": "0.52.2",
|
|
4
4
|
"description": "Pi extension that shows current-account usage for Codex, GitHub Copilot, OpenRouter, and OpenCode Zen.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "MIT",
|
|
@@ -43,11 +43,11 @@
|
|
|
43
43
|
"@earendil-works/pi-coding-agent": "*"
|
|
44
44
|
},
|
|
45
45
|
"devDependencies": {
|
|
46
|
-
"@biomejs/biome": "2.5.
|
|
47
|
-
"@earendil-works/pi-ai": "0.84.
|
|
48
|
-
"@earendil-works/pi-coding-agent": "0.84.
|
|
46
|
+
"@biomejs/biome": "2.5.10",
|
|
47
|
+
"@earendil-works/pi-ai": "0.84.3",
|
|
48
|
+
"@earendil-works/pi-coding-agent": "0.84.3",
|
|
49
49
|
"@types/node": "26.2.0",
|
|
50
|
-
"esbuild": "0.28.
|
|
50
|
+
"esbuild": "0.28.2",
|
|
51
51
|
"typescript": "7.0.2"
|
|
52
52
|
},
|
|
53
53
|
"repository": {
|
package/src/codex-resets.ts
CHANGED
|
@@ -1,6 +1,10 @@
|
|
|
1
1
|
import type { ExtensionContext } from "@earendil-works/pi-coding-agent";
|
|
2
2
|
import { readStoredCredential } from "@earendil-works/pi-coding-agent";
|
|
3
3
|
import { fingerprintResolvedAuth, sanitizeDisplayText } from "./core.js";
|
|
4
|
+
import {
|
|
5
|
+
fallbackOAuthCredentialCandidates,
|
|
6
|
+
type OAuthCredentialCandidateReader,
|
|
7
|
+
} from "./oauth-credential-source.js";
|
|
4
8
|
import {
|
|
5
9
|
AUTH_FINGERPRINT_SALT,
|
|
6
10
|
adapterForProvider,
|
|
@@ -98,6 +102,7 @@ export async function resolveCodexResetAuth(
|
|
|
98
102
|
ctx: ExtensionContext,
|
|
99
103
|
salt: Uint8Array = AUTH_FINGERPRINT_SALT,
|
|
100
104
|
credentialReader: StoredCredentialReader = readStoredCredential,
|
|
105
|
+
candidateReader?: OAuthCredentialCandidateReader,
|
|
101
106
|
): Promise<ResolvedUsageAuth> {
|
|
102
107
|
const model = ctx.model;
|
|
103
108
|
if (model?.provider !== "openai-codex") {
|
|
@@ -112,26 +117,22 @@ export async function resolveCodexResetAuth(
|
|
|
112
117
|
}
|
|
113
118
|
if (!auth) throw new Error("No runtime credential is configured for OpenAI Codex.");
|
|
114
119
|
|
|
115
|
-
const credential = asObject(credentialReader("openai-codex"));
|
|
116
|
-
if (credential?.type !== "oauth") {
|
|
117
|
-
throw new Error(
|
|
118
|
-
"Usage limit resets require the OpenAI Codex OAuth account configured through Pi /login.",
|
|
119
|
-
);
|
|
120
|
-
}
|
|
121
|
-
const storedAccess = asNonemptyString(credential.access);
|
|
122
120
|
const resolvedAccess = bearerToken(headerValue(auth.headers, "Authorization")) ?? auth.apiKey;
|
|
123
|
-
if (!
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
throw new Error(
|
|
128
|
-
"The active OpenAI Codex runtime account does not match Pi's stored OAuth account.",
|
|
129
|
-
);
|
|
121
|
+
if (!resolvedAccess) throw new Error("OpenAI Codex OAuth credentials were incomplete.");
|
|
122
|
+
const resolvedAccountId = codexAccountIdFromAccessToken(resolvedAccess);
|
|
123
|
+
if (!resolvedAccountId) {
|
|
124
|
+
throw new Error("The active OpenAI Codex access token did not contain a valid account ID.");
|
|
130
125
|
}
|
|
131
|
-
const
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
126
|
+
const offered = candidateReader
|
|
127
|
+
? candidateReader(ctx, "openai-codex")
|
|
128
|
+
: fallbackOAuthCredentialCandidates("openai-codex", credentialReader);
|
|
129
|
+
if (!offered.ok) throw new Error("OpenAI Codex OAuth credential discovery failed closed.");
|
|
130
|
+
const { accountId, storedAccess } = selectCodexResetCredential(
|
|
131
|
+
offered.candidates,
|
|
132
|
+
resolvedAccess,
|
|
133
|
+
resolvedAccountId,
|
|
134
|
+
offered.offeredCount === 0,
|
|
135
|
+
);
|
|
135
136
|
const authorization = `Bearer ${resolvedAccess}`;
|
|
136
137
|
const headers = {
|
|
137
138
|
Authorization: authorization,
|
|
@@ -226,6 +227,70 @@ export function normalizeCodexResetCreditsPayload(
|
|
|
226
227
|
return { availableCount, options };
|
|
227
228
|
}
|
|
228
229
|
|
|
230
|
+
function selectCodexResetCredential(
|
|
231
|
+
candidates: readonly unknown[],
|
|
232
|
+
resolvedAccess: string,
|
|
233
|
+
resolvedAccountId: string,
|
|
234
|
+
standaloneFallback: boolean,
|
|
235
|
+
): { accountId: string; storedAccess: string } {
|
|
236
|
+
let sawOAuth = false;
|
|
237
|
+
let sawMatchingAccess = false;
|
|
238
|
+
let sawInvalidAccountId = false;
|
|
239
|
+
const matches = new Map<string, { accountId: string; storedAccess: string }>();
|
|
240
|
+
for (const candidate of candidates) {
|
|
241
|
+
try {
|
|
242
|
+
const credential = asObject(candidate);
|
|
243
|
+
if (credential?.type !== "oauth") continue;
|
|
244
|
+
sawOAuth = true;
|
|
245
|
+
const storedAccess = asNonemptyString(credential.access);
|
|
246
|
+
if (storedAccess !== resolvedAccess) continue;
|
|
247
|
+
sawMatchingAccess = true;
|
|
248
|
+
const accountId = validHeaderValue(credential.accountId);
|
|
249
|
+
const refresh = asNonemptyString(credential.refresh);
|
|
250
|
+
if (!accountId || accountId !== resolvedAccountId || !refresh) {
|
|
251
|
+
sawInvalidAccountId = true;
|
|
252
|
+
continue;
|
|
253
|
+
}
|
|
254
|
+
matches.set(refresh, { accountId, storedAccess });
|
|
255
|
+
} catch {
|
|
256
|
+
// Malformed candidates never authorize a reset request.
|
|
257
|
+
}
|
|
258
|
+
}
|
|
259
|
+
if (sawInvalidAccountId) {
|
|
260
|
+
throw new Error("The OpenAI Codex OAuth credential did not include a valid account ID.");
|
|
261
|
+
}
|
|
262
|
+
if (matches.size > 1) {
|
|
263
|
+
throw new Error("Conflicting OAuth credentials match the active OpenAI Codex runtime account.");
|
|
264
|
+
}
|
|
265
|
+
const match = matches.values().next().value;
|
|
266
|
+
if (match) return match;
|
|
267
|
+
if (!sawOAuth) {
|
|
268
|
+
throw new Error(
|
|
269
|
+
standaloneFallback
|
|
270
|
+
? "Usage limit resets require the OpenAI Codex OAuth account configured through Pi /login."
|
|
271
|
+
: "Usage limit resets require an OpenAI Codex OAuth account configured through Pi /login or a compatible credential source.",
|
|
272
|
+
);
|
|
273
|
+
}
|
|
274
|
+
if (sawMatchingAccess) throw new Error("OpenAI Codex OAuth credentials were incomplete.");
|
|
275
|
+
throw new Error(
|
|
276
|
+
standaloneFallback
|
|
277
|
+
? "The active OpenAI Codex runtime account does not match Pi's stored OAuth account."
|
|
278
|
+
: "The active OpenAI Codex runtime account does not match any available OAuth account.",
|
|
279
|
+
);
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
function codexAccountIdFromAccessToken(access: string): string | undefined {
|
|
283
|
+
try {
|
|
284
|
+
const parts = access.split(".");
|
|
285
|
+
if (parts.length !== 3 || !parts[1]) return undefined;
|
|
286
|
+
const payload = JSON.parse(Buffer.from(parts[1], "base64url").toString("utf8")) as unknown;
|
|
287
|
+
const claims = asObject(asObject(payload)?.["https://api.openai.com/auth"]);
|
|
288
|
+
return validHeaderValue(claims?.chatgpt_account_id);
|
|
289
|
+
} catch {
|
|
290
|
+
return undefined;
|
|
291
|
+
}
|
|
292
|
+
}
|
|
293
|
+
|
|
229
294
|
function normalizeResetOption(credit: Record<string, unknown>): CodexResetOption {
|
|
230
295
|
const creditId = asOpaqueId(credit.id);
|
|
231
296
|
if (!creditId) throw new Error("Codex reset credits response returned an invalid credit ID.");
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
import type { OAuthCredential } from "@earendil-works/pi-ai";
|
|
2
|
+
import {
|
|
3
|
+
type ExtensionAPI,
|
|
4
|
+
type ExtensionContext,
|
|
5
|
+
readStoredCredential,
|
|
6
|
+
} from "@earendil-works/pi-coding-agent";
|
|
7
|
+
|
|
8
|
+
export const OAUTH_CREDENTIAL_SOURCE_CHANNEL = "oauth:credential-source:v1";
|
|
9
|
+
|
|
10
|
+
export type StoredCredentialReader = (providerId: string) => unknown;
|
|
11
|
+
|
|
12
|
+
export type OAuthCredentialCandidates =
|
|
13
|
+
| { ok: true; candidates: readonly OAuthCredential[]; offeredCount?: number }
|
|
14
|
+
| { ok: false };
|
|
15
|
+
|
|
16
|
+
export type OAuthCredentialCandidateReader = (
|
|
17
|
+
ctx: ExtensionContext,
|
|
18
|
+
providerId: string,
|
|
19
|
+
) => OAuthCredentialCandidates;
|
|
20
|
+
|
|
21
|
+
export function createOAuthCredentialCandidateReader(
|
|
22
|
+
pi: ExtensionAPI,
|
|
23
|
+
credentialReader: StoredCredentialReader = readStoredCredential,
|
|
24
|
+
): OAuthCredentialCandidateReader {
|
|
25
|
+
return (ctx, providerId) =>
|
|
26
|
+
collectOAuthCredentialCandidates(pi, ctx, providerId, credentialReader);
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
export function collectOAuthCredentialCandidates(
|
|
30
|
+
pi: Pick<ExtensionAPI, "events">,
|
|
31
|
+
ctx: ExtensionContext,
|
|
32
|
+
providerId: string,
|
|
33
|
+
credentialReader: StoredCredentialReader = readStoredCredential,
|
|
34
|
+
): OAuthCredentialCandidates {
|
|
35
|
+
const candidates: OAuthCredential[] = [];
|
|
36
|
+
let collecting = true;
|
|
37
|
+
const request = Object.freeze({
|
|
38
|
+
session: ctx.sessionManager,
|
|
39
|
+
provider: providerId,
|
|
40
|
+
offer(candidate: unknown) {
|
|
41
|
+
if (!collecting) return;
|
|
42
|
+
const clone = cloneOAuthCredential(candidate);
|
|
43
|
+
if (clone) candidates.push(clone);
|
|
44
|
+
},
|
|
45
|
+
});
|
|
46
|
+
try {
|
|
47
|
+
pi.events.emit(OAUTH_CREDENTIAL_SOURCE_CHANNEL, request);
|
|
48
|
+
} catch {
|
|
49
|
+
return { ok: false };
|
|
50
|
+
} finally {
|
|
51
|
+
collecting = false;
|
|
52
|
+
}
|
|
53
|
+
const offeredCount = candidates.length;
|
|
54
|
+
try {
|
|
55
|
+
const fallback = cloneOAuthCredential(credentialReader(providerId));
|
|
56
|
+
if (fallback) candidates.push(fallback);
|
|
57
|
+
} catch {
|
|
58
|
+
// A malformed or unavailable standalone credential is equivalent to no fallback.
|
|
59
|
+
}
|
|
60
|
+
return { ok: true, candidates, offeredCount };
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
export function fallbackOAuthCredentialCandidates(
|
|
64
|
+
providerId: string,
|
|
65
|
+
credentialReader: StoredCredentialReader,
|
|
66
|
+
): OAuthCredentialCandidates {
|
|
67
|
+
try {
|
|
68
|
+
const credential = cloneOAuthCredential(credentialReader(providerId));
|
|
69
|
+
return { ok: true, candidates: credential ? [credential] : [], offeredCount: 0 };
|
|
70
|
+
} catch {
|
|
71
|
+
return { ok: true, candidates: [], offeredCount: 0 };
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
function cloneOAuthCredential(value: unknown): OAuthCredential | undefined {
|
|
76
|
+
try {
|
|
77
|
+
if (!value || typeof value !== "object" || Array.isArray(value)) return undefined;
|
|
78
|
+
const clone = structuredClone(value) as OAuthCredential;
|
|
79
|
+
if (!clone || typeof clone !== "object" || Array.isArray(clone)) return undefined;
|
|
80
|
+
if (clone.type !== "oauth") return undefined;
|
|
81
|
+
if (typeof clone.access !== "string" || !clone.access) return undefined;
|
|
82
|
+
if (typeof clone.refresh !== "string" || !clone.refresh) return undefined;
|
|
83
|
+
if (typeof clone.expires !== "number" || !Number.isFinite(clone.expires)) return undefined;
|
|
84
|
+
return clone;
|
|
85
|
+
} catch {
|
|
86
|
+
return undefined;
|
|
87
|
+
}
|
|
88
|
+
}
|
package/src/query.ts
CHANGED
|
@@ -1,6 +1,10 @@
|
|
|
1
1
|
import { randomBytes } from "node:crypto";
|
|
2
2
|
import { type ExtensionContext, readStoredCredential } from "@earendil-works/pi-coding-agent";
|
|
3
3
|
import { errorMessage, fingerprintResolvedAuth, redactUsageError } from "./core.js";
|
|
4
|
+
import {
|
|
5
|
+
fallbackOAuthCredentialCandidates,
|
|
6
|
+
type OAuthCredentialCandidateReader,
|
|
7
|
+
} from "./oauth-credential-source.js";
|
|
4
8
|
import { normalizeCodexBackendPayload } from "./providers/codex.js";
|
|
5
9
|
import { normalizeGitHubCopilotUsagePayload } from "./providers/github-copilot.js";
|
|
6
10
|
import { normalizeOpenCodeZenPayload } from "./providers/opencode-zen.js";
|
|
@@ -111,6 +115,7 @@ export async function resolveUsageAuth(
|
|
|
111
115
|
adapter: UsageProviderAdapter,
|
|
112
116
|
salt: Uint8Array = AUTH_FINGERPRINT_SALT,
|
|
113
117
|
credentialReader: StoredCredentialReader = readStoredCredential,
|
|
118
|
+
candidateReader?: OAuthCredentialCandidateReader,
|
|
114
119
|
): Promise<ResolvedUsageAuth | undefined> {
|
|
115
120
|
if (ctx.model?.provider === adapter.id && !hasOfficialOrigin(ctx.model, adapter.id)) {
|
|
116
121
|
throw new Error(
|
|
@@ -144,7 +149,19 @@ export async function resolveUsageAuth(
|
|
|
144
149
|
const auth = modelAuth ?? providerResult?.auth;
|
|
145
150
|
if (!auth) return undefined;
|
|
146
151
|
if (adapter.id === "github-copilot") {
|
|
147
|
-
|
|
152
|
+
const offered = candidateReader
|
|
153
|
+
? candidateReader(ctx, adapter.id)
|
|
154
|
+
: fallbackOAuthCredentialCandidates(adapter.id, credentialReader);
|
|
155
|
+
if (!offered.ok) {
|
|
156
|
+
throw new Error("GitHub Copilot OAuth credential discovery failed closed.");
|
|
157
|
+
}
|
|
158
|
+
return resolveGitHubCopilotUsageAuth(
|
|
159
|
+
auth,
|
|
160
|
+
model,
|
|
161
|
+
salt,
|
|
162
|
+
offered.candidates,
|
|
163
|
+
offered.offeredCount === 0,
|
|
164
|
+
);
|
|
148
165
|
}
|
|
149
166
|
const authorization = authorizationFrom(auth);
|
|
150
167
|
if (!authorization) return undefined;
|
|
@@ -334,33 +351,73 @@ function resolveGitHubCopilotUsageAuth(
|
|
|
334
351
|
auth: RequestAuth,
|
|
335
352
|
model: PiModel,
|
|
336
353
|
salt: Uint8Array,
|
|
337
|
-
|
|
354
|
+
candidates: readonly unknown[],
|
|
355
|
+
standaloneFallback: boolean,
|
|
338
356
|
): ResolvedUsageAuth {
|
|
339
|
-
const
|
|
340
|
-
if (
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
357
|
+
const resolvedAccess = bearerToken(headerValue(auth.headers, "Authorization")) ?? auth.apiKey;
|
|
358
|
+
if (!resolvedAccess) throw new Error("GitHub Copilot OAuth credentials were incomplete.");
|
|
359
|
+
let sawOAuth = false;
|
|
360
|
+
let sawMatchingAccess = false;
|
|
361
|
+
let sawIncompleteMatch = false;
|
|
362
|
+
let sawEnterpriseMatch = false;
|
|
363
|
+
const matches = new Map<string, { refresh: string; storedAccess: string }>();
|
|
364
|
+
for (const candidate of candidates) {
|
|
365
|
+
try {
|
|
366
|
+
const credential = asObject(candidate);
|
|
367
|
+
if (credential?.type !== "oauth") continue;
|
|
368
|
+
sawOAuth = true;
|
|
369
|
+
const storedAccess =
|
|
370
|
+
typeof credential.access === "string" && credential.access ? credential.access : undefined;
|
|
371
|
+
if (storedAccess !== resolvedAccess) continue;
|
|
372
|
+
sawMatchingAccess = true;
|
|
373
|
+
const enterpriseUrl = credential.enterpriseUrl;
|
|
374
|
+
if (
|
|
375
|
+
typeof enterpriseUrl === "string" &&
|
|
376
|
+
enterpriseUrl &&
|
|
377
|
+
!isPublicGitHubDomain(enterpriseUrl)
|
|
378
|
+
) {
|
|
379
|
+
sawEnterpriseMatch = true;
|
|
380
|
+
continue;
|
|
381
|
+
}
|
|
382
|
+
const refresh =
|
|
383
|
+
typeof credential.refresh === "string" && credential.refresh
|
|
384
|
+
? credential.refresh
|
|
385
|
+
: undefined;
|
|
386
|
+
if (!refresh) {
|
|
387
|
+
sawIncompleteMatch = true;
|
|
388
|
+
continue;
|
|
389
|
+
}
|
|
390
|
+
matches.set(`${storedAccess.length}:${storedAccess}${refresh}`, { refresh, storedAccess });
|
|
391
|
+
} catch {
|
|
392
|
+
// Malformed candidates never authorize a provider request.
|
|
393
|
+
}
|
|
344
394
|
}
|
|
345
|
-
if (
|
|
346
|
-
typeof credential.enterpriseUrl === "string" &&
|
|
347
|
-
credential.enterpriseUrl &&
|
|
348
|
-
!isPublicGitHubDomain(credential.enterpriseUrl)
|
|
349
|
-
) {
|
|
395
|
+
if (sawEnterpriseMatch) {
|
|
350
396
|
throw new Error("GitHub Copilot usage does not yet support GitHub Enterprise accounts.");
|
|
351
397
|
}
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
398
|
+
if (sawIncompleteMatch) throw new Error("GitHub Copilot OAuth credentials were incomplete.");
|
|
399
|
+
if (matches.size > 1) {
|
|
400
|
+
throw new Error(
|
|
401
|
+
"Conflicting OAuth credentials match the active GitHub Copilot runtime account.",
|
|
402
|
+
);
|
|
357
403
|
}
|
|
358
|
-
|
|
404
|
+
const match = matches.values().next().value;
|
|
405
|
+
if (!match) {
|
|
406
|
+
if (!sawOAuth) {
|
|
407
|
+
throw new Error(
|
|
408
|
+
standaloneFallback
|
|
409
|
+
? "GitHub Copilot usage requires the OAuth account configured through Pi /login."
|
|
410
|
+
: "GitHub Copilot usage requires an OAuth account configured through Pi /login or a compatible credential source.",
|
|
411
|
+
);
|
|
412
|
+
}
|
|
413
|
+
if (sawMatchingAccess) throw new Error("GitHub Copilot OAuth credentials were incomplete.");
|
|
359
414
|
throw new Error(
|
|
360
|
-
|
|
415
|
+
standaloneFallback
|
|
416
|
+
? "The active GitHub Copilot runtime account does not match Pi's stored OAuth account."
|
|
417
|
+
: "The active GitHub Copilot runtime account does not match any available OAuth account.",
|
|
361
418
|
);
|
|
362
419
|
}
|
|
363
|
-
|
|
420
|
+
const { refresh, storedAccess } = match;
|
|
364
421
|
const authorization = `Bearer ${refresh}`;
|
|
365
422
|
const headers = {
|
|
366
423
|
Authorization: authorization,
|
package/src/usage.ts
CHANGED
|
@@ -22,6 +22,7 @@ import {
|
|
|
22
22
|
} from "./codex-resets.js";
|
|
23
23
|
import { awaitWithDeadline, errorMessage, runWithConcurrency, UsageCache } from "./core.js";
|
|
24
24
|
import { formatProviderStates, formatUsageStatusline } from "./format.js";
|
|
25
|
+
import { createOAuthCredentialCandidateReader } from "./oauth-credential-source.js";
|
|
25
26
|
import {
|
|
26
27
|
adapterForProvider,
|
|
27
28
|
isStaleExtensionContextError,
|
|
@@ -80,6 +81,7 @@ export default function usageExtension(
|
|
|
80
81
|
dependencies: UsageExtensionDependencies = {},
|
|
81
82
|
) {
|
|
82
83
|
const credentialReader = dependencies.credentialReader;
|
|
84
|
+
const credentialCandidates = createOAuthCredentialCandidateReader(pi, credentialReader);
|
|
83
85
|
const createRedemptionId = dependencies.createRedemptionId ?? randomUUID;
|
|
84
86
|
const settingsRuntime = dependencies.settingsRuntime ?? createUsageSettingsRuntime();
|
|
85
87
|
const cache = new UsageCache(CACHE_TTL_MS);
|
|
@@ -189,7 +191,7 @@ export default function usageExtension(
|
|
|
189
191
|
let auth: ResolvedUsageAuth | undefined;
|
|
190
192
|
try {
|
|
191
193
|
auth = await awaitWithDeadline(
|
|
192
|
-
resolveUsageAuth(ctx, adapter),
|
|
194
|
+
resolveUsageAuth(ctx, adapter, undefined, credentialReader, credentialCandidates),
|
|
193
195
|
signal,
|
|
194
196
|
DEFAULT_TIMEOUT_MS,
|
|
195
197
|
`resolving ${adapter.displayName} runtime auth`,
|
|
@@ -419,7 +421,7 @@ export default function usageExtension(
|
|
|
419
421
|
if (!adapter) return false;
|
|
420
422
|
try {
|
|
421
423
|
const auth = await awaitWithDeadline(
|
|
422
|
-
resolveUsageAuth(ctx, adapter),
|
|
424
|
+
resolveUsageAuth(ctx, adapter, undefined, credentialReader, credentialCandidates),
|
|
423
425
|
signal,
|
|
424
426
|
DEFAULT_TIMEOUT_MS,
|
|
425
427
|
`revalidating ${adapter.displayName} runtime auth`,
|
|
@@ -438,7 +440,7 @@ export default function usageExtension(
|
|
|
438
440
|
if (!adapter) return false;
|
|
439
441
|
try {
|
|
440
442
|
const auth = await awaitWithDeadline(
|
|
441
|
-
resolveUsageAuth(ctx, adapter),
|
|
443
|
+
resolveUsageAuth(ctx, adapter, undefined, credentialReader, credentialCandidates),
|
|
442
444
|
signal,
|
|
443
445
|
DEFAULT_TIMEOUT_MS,
|
|
444
446
|
`revalidating ${adapter.displayName} runtime auth`,
|
|
@@ -677,7 +679,7 @@ export default function usageExtension(
|
|
|
677
679
|
async (signal) => {
|
|
678
680
|
const expectedModel = modelIdentity(ctx.model);
|
|
679
681
|
const auth = await awaitWithDeadline(
|
|
680
|
-
resolveCodexResetAuth(ctx, undefined, credentialReader),
|
|
682
|
+
resolveCodexResetAuth(ctx, undefined, credentialReader, credentialCandidates),
|
|
681
683
|
signal,
|
|
682
684
|
DEFAULT_TIMEOUT_MS,
|
|
683
685
|
"resolving current Codex reset authentication",
|
|
@@ -695,7 +697,7 @@ export default function usageExtension(
|
|
|
695
697
|
};
|
|
696
698
|
}
|
|
697
699
|
const revalidated = await awaitWithDeadline(
|
|
698
|
-
resolveCodexResetAuth(ctx, undefined, credentialReader),
|
|
700
|
+
resolveCodexResetAuth(ctx, undefined, credentialReader, credentialCandidates),
|
|
699
701
|
signal,
|
|
700
702
|
DEFAULT_TIMEOUT_MS,
|
|
701
703
|
"revalidating current Codex reset authentication",
|
|
@@ -759,7 +761,7 @@ export default function usageExtension(
|
|
|
759
761
|
controller.signal,
|
|
760
762
|
async (signal) => {
|
|
761
763
|
const auth = await awaitWithDeadline(
|
|
762
|
-
resolveCodexResetAuth(ctx, undefined, credentialReader),
|
|
764
|
+
resolveCodexResetAuth(ctx, undefined, credentialReader, credentialCandidates),
|
|
763
765
|
signal,
|
|
764
766
|
DEFAULT_TIMEOUT_MS,
|
|
765
767
|
"revalidating current Codex reset authentication",
|