@opengeni/codex 0.2.5 → 0.2.9
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/dist/api-client.d.ts +55 -0
- package/dist/billing.d.ts +11 -0
- package/dist/bounded-operation.d.ts +16 -0
- package/dist/{chunk-AMRVHBCD.js → chunk-YGKQDUY7.js} +13 -1
- package/dist/{chunk-AMRVHBCD.js.map → chunk-YGKQDUY7.js.map} +1 -1
- package/dist/constants.d.ts +33 -29
- package/dist/constants.js +13 -1
- package/dist/device-code.d.ts +36 -0
- package/dist/fetch.d.ts +84 -0
- package/dist/index.d.ts +13 -377
- package/dist/index.js +684 -68
- package/dist/index.js.map +1 -1
- package/dist/mcp-sanitize.d.ts +33 -0
- package/dist/model-output-truncation.d.ts +36 -0
- package/dist/normalize.d.ts +8 -0
- package/dist/oversized-image-card.d.ts +17 -0
- package/dist/refresh.d.ts +28 -0
- package/dist/request-context.d.ts +99 -0
- package/dist/reset-credits.d.ts +33 -0
- package/dist/response-timeout.d.ts +28 -0
- package/dist/usage-normalize.d.ts +61 -0
- package/package.json +3 -3
- package/src/api-client.ts +131 -22
- package/src/bounded-operation.ts +43 -0
- package/src/constants.ts +18 -0
- package/src/fetch.ts +416 -11
- package/src/index.ts +2 -0
- package/src/normalize.ts +6 -3
- package/src/refresh.ts +21 -10
- package/src/request-context.ts +58 -0
- package/src/reset-credits.ts +157 -0
- package/src/response-timeout.ts +159 -0
- package/src/usage-normalize.ts +20 -2
package/dist/index.js
CHANGED
|
@@ -24,9 +24,15 @@ import {
|
|
|
24
24
|
CODEX_REFRESH_FALLBACK_MS,
|
|
25
25
|
CODEX_REFRESH_WINDOW_MS,
|
|
26
26
|
CODEX_RESPONSES_BASE,
|
|
27
|
+
CODEX_RESPONSE_HEADERS_TIMEOUT_MS,
|
|
28
|
+
CODEX_RESPONSE_NO_BYTE_RETRIES,
|
|
29
|
+
CODEX_RESPONSE_RETRY_BACKOFF_MS,
|
|
30
|
+
CODEX_RESPONSE_SDK_OUTER_TIMEOUT_MS,
|
|
31
|
+
CODEX_RESPONSE_STREAM_IDLE_TIMEOUT_MS,
|
|
32
|
+
CODEX_RESPONSE_WHOLE_TIMEOUT_MS,
|
|
27
33
|
CODEX_TOKEN_URL,
|
|
28
34
|
CODEX_WHAM_BASE
|
|
29
|
-
} from "./chunk-
|
|
35
|
+
} from "./chunk-YGKQDUY7.js";
|
|
30
36
|
|
|
31
37
|
// src/billing.ts
|
|
32
38
|
function isCodexBilledModel(model) {
|
|
@@ -107,7 +113,37 @@ async function exchangeDeviceCode(input, fetchImpl = fetch) {
|
|
|
107
113
|
};
|
|
108
114
|
}
|
|
109
115
|
|
|
116
|
+
// src/bounded-operation.ts
|
|
117
|
+
async function runBoundedCodexOperation(operation, timeoutMs) {
|
|
118
|
+
if (!Number.isFinite(timeoutMs) || timeoutMs <= 0) {
|
|
119
|
+
throw new Error("Codex operation timeout must be positive");
|
|
120
|
+
}
|
|
121
|
+
const controller = new AbortController();
|
|
122
|
+
let timedOut = false;
|
|
123
|
+
let timeout;
|
|
124
|
+
const work = operation(controller.signal).then(
|
|
125
|
+
(value) => ({ ok: true, value }),
|
|
126
|
+
() => ({
|
|
127
|
+
ok: false,
|
|
128
|
+
reason: timedOut || controller.signal.aborted ? "timeout" : "network_error"
|
|
129
|
+
})
|
|
130
|
+
);
|
|
131
|
+
const deadline = new Promise((resolve) => {
|
|
132
|
+
timeout = setTimeout(() => {
|
|
133
|
+
timedOut = true;
|
|
134
|
+
controller.abort();
|
|
135
|
+
resolve({ ok: false, reason: "timeout" });
|
|
136
|
+
}, timeoutMs);
|
|
137
|
+
});
|
|
138
|
+
try {
|
|
139
|
+
return await Promise.race([work, deadline]);
|
|
140
|
+
} finally {
|
|
141
|
+
if (timeout) clearTimeout(timeout);
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
|
|
110
145
|
// src/refresh.ts
|
|
146
|
+
var CODEX_REFRESH_TIMEOUT_MS = 5e3;
|
|
111
147
|
var CodexReloginRequired = class extends Error {
|
|
112
148
|
constructor(message) {
|
|
113
149
|
super(message);
|
|
@@ -120,17 +156,24 @@ var CodexRefreshTransient = class extends Error {
|
|
|
120
156
|
this.name = "CodexRefreshTransient";
|
|
121
157
|
}
|
|
122
158
|
};
|
|
123
|
-
async function refreshCodexToken(refreshToken, fetchImpl = fetch) {
|
|
124
|
-
const
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
159
|
+
async function refreshCodexToken(refreshToken, fetchImpl = fetch, timeoutMs = CODEX_REFRESH_TIMEOUT_MS) {
|
|
160
|
+
const fetched = await runBoundedCodexOperation(async (signal) => {
|
|
161
|
+
const res2 = await fetchImpl(CODEX_TOKEN_URL, {
|
|
162
|
+
method: "POST",
|
|
163
|
+
headers: { "Content-Type": "application/json" },
|
|
164
|
+
body: JSON.stringify({
|
|
165
|
+
client_id: CODEX_CLIENT_ID,
|
|
166
|
+
grant_type: "refresh_token",
|
|
167
|
+
refresh_token: refreshToken
|
|
168
|
+
}),
|
|
169
|
+
signal
|
|
170
|
+
});
|
|
171
|
+
return { res: res2, text: await res2.text() };
|
|
172
|
+
}, timeoutMs);
|
|
173
|
+
if (!fetched.ok) {
|
|
174
|
+
throw new CodexRefreshTransient(`Codex token refresh ${fetched.reason}`);
|
|
175
|
+
}
|
|
176
|
+
const { res, text } = fetched.value;
|
|
134
177
|
if (!res.ok) {
|
|
135
178
|
const code = extractRefreshErrorCode(text);
|
|
136
179
|
const msg = code ? PERMANENT_REFRESH_FAILURES[code] : void 0;
|
|
@@ -218,7 +261,8 @@ var CODEX_ALLOWED_TOP_LEVEL_KEYS = /* @__PURE__ */ new Set([
|
|
|
218
261
|
"stream",
|
|
219
262
|
"include",
|
|
220
263
|
"prompt_cache_key",
|
|
221
|
-
"text"
|
|
264
|
+
"text",
|
|
265
|
+
"service_tier"
|
|
222
266
|
]);
|
|
223
267
|
function normalizeCodexRequestBody(body, resolveModel) {
|
|
224
268
|
body.store = false;
|
|
@@ -280,7 +324,89 @@ function buildModelResolver(liveSlugs, fallbackSlug) {
|
|
|
280
324
|
}
|
|
281
325
|
|
|
282
326
|
// src/usage-normalize.ts
|
|
327
|
+
import * as z2 from "zod/v4";
|
|
328
|
+
|
|
329
|
+
// src/reset-credits.ts
|
|
283
330
|
import * as z from "zod/v4";
|
|
331
|
+
var CODEX_RATE_LIMIT_RESET_OUTCOMES = [
|
|
332
|
+
"reset",
|
|
333
|
+
"nothingToReset",
|
|
334
|
+
"noCredit",
|
|
335
|
+
"alreadyRedeemed"
|
|
336
|
+
];
|
|
337
|
+
var nonNegativeInteger = z.number().int().nonnegative();
|
|
338
|
+
var backendTimestamp = z.string().datetime({ offset: true });
|
|
339
|
+
var backendCreditSchema = z.object({
|
|
340
|
+
id: z.string().min(1),
|
|
341
|
+
reset_type: z.string().min(1),
|
|
342
|
+
status: z.string().min(1),
|
|
343
|
+
granted_at: backendTimestamp,
|
|
344
|
+
expires_at: backendTimestamp.nullish(),
|
|
345
|
+
title: z.string().nullish(),
|
|
346
|
+
description: z.string().nullish()
|
|
347
|
+
}).passthrough();
|
|
348
|
+
var backendDetailsSchema = z.object({
|
|
349
|
+
credits: z.array(backendCreditSchema),
|
|
350
|
+
available_count: nonNegativeInteger
|
|
351
|
+
}).passthrough();
|
|
352
|
+
var backendUsageSummarySchema = z.object({
|
|
353
|
+
rate_limit_reset_credits: z.object({ available_count: nonNegativeInteger }).passthrough().nullish()
|
|
354
|
+
}).passthrough();
|
|
355
|
+
var backendConsumeOutcomes = [
|
|
356
|
+
"reset",
|
|
357
|
+
"nothing_to_reset",
|
|
358
|
+
"no_credit",
|
|
359
|
+
"already_redeemed"
|
|
360
|
+
];
|
|
361
|
+
var backendConsumeSchema = z.object({
|
|
362
|
+
code: z.enum(backendConsumeOutcomes),
|
|
363
|
+
// The app-server intentionally discards this field. OpenGeni also refetches
|
|
364
|
+
// rather than inferring post-redemption state from it.
|
|
365
|
+
windows_reset: nonNegativeInteger.default(0)
|
|
366
|
+
}).passthrough();
|
|
367
|
+
function normalizedResetType(value) {
|
|
368
|
+
return value === "codex_rate_limits" ? "codexRateLimits" : "unknown";
|
|
369
|
+
}
|
|
370
|
+
function normalizedCreditStatus(value) {
|
|
371
|
+
if (value === "available" || value === "redeeming" || value === "redeemed") {
|
|
372
|
+
return value;
|
|
373
|
+
}
|
|
374
|
+
return "unknown";
|
|
375
|
+
}
|
|
376
|
+
function parseCodexRateLimitResetCreditsDetails(payload) {
|
|
377
|
+
const parsed = backendDetailsSchema.safeParse(payload);
|
|
378
|
+
if (!parsed.success) return null;
|
|
379
|
+
return {
|
|
380
|
+
availableCount: parsed.data.available_count,
|
|
381
|
+
credits: parsed.data.credits.map((credit) => ({
|
|
382
|
+
id: credit.id,
|
|
383
|
+
resetType: normalizedResetType(credit.reset_type),
|
|
384
|
+
status: normalizedCreditStatus(credit.status),
|
|
385
|
+
grantedAt: Math.floor(Date.parse(credit.granted_at) / 1e3),
|
|
386
|
+
expiresAt: credit.expires_at == null ? null : Math.floor(Date.parse(credit.expires_at) / 1e3),
|
|
387
|
+
title: credit.title ?? null,
|
|
388
|
+
description: credit.description ?? null
|
|
389
|
+
}))
|
|
390
|
+
};
|
|
391
|
+
}
|
|
392
|
+
function parseCodexRateLimitResetCreditsSummary(payload) {
|
|
393
|
+
const parsed = backendUsageSummarySchema.safeParse(payload);
|
|
394
|
+
const availableCount = parsed.success ? parsed.data.rate_limit_reset_credits?.available_count : void 0;
|
|
395
|
+
return availableCount === void 0 ? null : { availableCount, credits: null };
|
|
396
|
+
}
|
|
397
|
+
function parseCodexRateLimitResetConsumeResponse(payload) {
|
|
398
|
+
const parsed = backendConsumeSchema.safeParse(payload);
|
|
399
|
+
if (!parsed.success) return null;
|
|
400
|
+
const outcomes = {
|
|
401
|
+
reset: "reset",
|
|
402
|
+
nothing_to_reset: "nothingToReset",
|
|
403
|
+
no_credit: "noCredit",
|
|
404
|
+
already_redeemed: "alreadyRedeemed"
|
|
405
|
+
};
|
|
406
|
+
return { outcome: outcomes[parsed.data.code] };
|
|
407
|
+
}
|
|
408
|
+
|
|
409
|
+
// src/usage-normalize.ts
|
|
284
410
|
var CODEX_FIVE_HOUR_WINDOW_SECONDS = 18e3;
|
|
285
411
|
var CODEX_WEEKLY_WINDOW_SECONDS = 604800;
|
|
286
412
|
function buildCodexUsageWindowFromCache(usedPercent, resetAt, limitWindowSeconds) {
|
|
@@ -301,34 +427,34 @@ function buildCodexUsageWindowFromCache(usedPercent, resetAt, limitWindowSeconds
|
|
|
301
427
|
limitWindowSeconds
|
|
302
428
|
};
|
|
303
429
|
}
|
|
304
|
-
var windowSchema =
|
|
305
|
-
used_percent:
|
|
306
|
-
reset_after_seconds:
|
|
307
|
-
reset_at:
|
|
308
|
-
limit_window_seconds:
|
|
430
|
+
var windowSchema = z2.object({
|
|
431
|
+
used_percent: z2.number().optional(),
|
|
432
|
+
reset_after_seconds: z2.number().optional(),
|
|
433
|
+
reset_at: z2.number().optional(),
|
|
434
|
+
limit_window_seconds: z2.number().optional()
|
|
309
435
|
}).nullish();
|
|
310
|
-
var rateLimitSchema =
|
|
311
|
-
allowed:
|
|
312
|
-
limit_reached:
|
|
436
|
+
var rateLimitSchema = z2.object({
|
|
437
|
+
allowed: z2.boolean().optional(),
|
|
438
|
+
limit_reached: z2.boolean().optional(),
|
|
313
439
|
primary_window: windowSchema,
|
|
314
440
|
secondary_window: windowSchema
|
|
315
441
|
}).nullish();
|
|
316
|
-
var additionalLimitSchema =
|
|
317
|
-
limit_name:
|
|
318
|
-
metered_feature:
|
|
442
|
+
var additionalLimitSchema = z2.object({
|
|
443
|
+
limit_name: z2.string().optional(),
|
|
444
|
+
metered_feature: z2.string().optional(),
|
|
319
445
|
primary_window: windowSchema,
|
|
320
446
|
secondary_window: windowSchema
|
|
321
447
|
});
|
|
322
|
-
var creditsSchema =
|
|
323
|
-
has_credits:
|
|
324
|
-
unlimited:
|
|
325
|
-
overage_limit_reached:
|
|
326
|
-
balance:
|
|
448
|
+
var creditsSchema = z2.object({
|
|
449
|
+
has_credits: z2.boolean().optional(),
|
|
450
|
+
unlimited: z2.boolean().optional(),
|
|
451
|
+
overage_limit_reached: z2.boolean().optional(),
|
|
452
|
+
balance: z2.union([z2.string(), z2.number()]).optional()
|
|
327
453
|
}).nullish();
|
|
328
|
-
var usageBodySchema =
|
|
329
|
-
plan_type:
|
|
454
|
+
var usageBodySchema = z2.object({
|
|
455
|
+
plan_type: z2.string().nullish(),
|
|
330
456
|
rate_limit: rateLimitSchema,
|
|
331
|
-
additional_limits:
|
|
457
|
+
additional_limits: z2.array(additionalLimitSchema).nullish(),
|
|
332
458
|
credits: creditsSchema
|
|
333
459
|
});
|
|
334
460
|
function clampPercent(value) {
|
|
@@ -391,7 +517,8 @@ function normalizeCodexUsage(httpStatus, rawPayload) {
|
|
|
391
517
|
fiveHour: null,
|
|
392
518
|
weekly: null,
|
|
393
519
|
limitReached: false,
|
|
394
|
-
fetchedAt
|
|
520
|
+
fetchedAt,
|
|
521
|
+
rateLimitResetCredits: parseCodexRateLimitResetCreditsSummary(rawPayload)
|
|
395
522
|
};
|
|
396
523
|
if (httpStatus >= 400 && httpStatus !== 404 || body == null) {
|
|
397
524
|
return { ...base, status: "error" };
|
|
@@ -437,6 +564,9 @@ function normalizeCodexUsage(httpStatus, rawPayload) {
|
|
|
437
564
|
}
|
|
438
565
|
|
|
439
566
|
// src/api-client.ts
|
|
567
|
+
var CODEX_READ_TIMEOUT_MS = 5e3;
|
|
568
|
+
var RESET_CREDIT_DETAILS_TIMEOUT_MS = 5e3;
|
|
569
|
+
var RESET_CREDIT_CONSUME_TIMEOUT_MS = 1e4;
|
|
440
570
|
function subscriptionHeaders(a) {
|
|
441
571
|
return {
|
|
442
572
|
Authorization: `Bearer ${a.accessToken}`,
|
|
@@ -447,35 +577,183 @@ function subscriptionHeaders(a) {
|
|
|
447
577
|
...a.isFedramp ? { "X-OpenAI-Fedramp": "true" } : {}
|
|
448
578
|
};
|
|
449
579
|
}
|
|
450
|
-
async function fetchCodexModels(a, fetchImpl = fetch) {
|
|
451
|
-
const
|
|
452
|
-
|
|
453
|
-
|
|
580
|
+
async function fetchCodexModels(a, fetchImpl = fetch, timeoutMs = CODEX_READ_TIMEOUT_MS) {
|
|
581
|
+
const fetched = await runBoundedCodexOperation(async (signal) => {
|
|
582
|
+
const res = await fetchImpl(
|
|
583
|
+
`${CODEX_RESPONSES_BASE}/models?client_version=${encodeURIComponent(a.clientVersion)}`,
|
|
584
|
+
{ method: "GET", headers: subscriptionHeaders(a), signal }
|
|
585
|
+
);
|
|
586
|
+
if (!res.ok) {
|
|
587
|
+
await res.arrayBuffer().catch(() => void 0);
|
|
588
|
+
return { ok: false, status: res.status, slugs: [] };
|
|
589
|
+
}
|
|
590
|
+
const body = await res.json();
|
|
591
|
+
const slugs = (body.models ?? []).map((model) => model.slug).filter((slug) => typeof slug === "string");
|
|
592
|
+
return { ok: true, status: res.status, slugs };
|
|
593
|
+
}, timeoutMs);
|
|
594
|
+
return fetched.ok ? fetched.value : { ok: false, status: 0, slugs: [] };
|
|
595
|
+
}
|
|
596
|
+
async function fetchCodexUsage(a, fetchImpl = fetch, timeoutMs = CODEX_READ_TIMEOUT_MS) {
|
|
597
|
+
const fetched = await runBoundedCodexOperation(async (signal) => {
|
|
598
|
+
const res = await fetchImpl(`${CODEX_WHAM_BASE}/wham/usage`, {
|
|
599
|
+
method: "GET",
|
|
600
|
+
headers: subscriptionHeaders(a),
|
|
601
|
+
signal
|
|
602
|
+
});
|
|
603
|
+
const payload = res.ok || res.status === 404 ? await res.json().catch(() => null) : null;
|
|
604
|
+
if (!res.ok && res.status !== 404) await res.arrayBuffer().catch(() => void 0);
|
|
605
|
+
return { status: res.status, payload };
|
|
606
|
+
}, timeoutMs);
|
|
607
|
+
if (!fetched.ok) throw new Error(`Codex usage request ${fetched.reason}`);
|
|
608
|
+
return fetched.value;
|
|
609
|
+
}
|
|
610
|
+
async function fetchCodexRateLimitResetCredits(a, fetchImpl = fetch, timeoutMs = RESET_CREDIT_DETAILS_TIMEOUT_MS) {
|
|
611
|
+
const fetched = await runBoundedCodexOperation(async (signal) => {
|
|
612
|
+
const res = await fetchImpl(`${CODEX_WHAM_BASE}/wham/rate-limit-reset-credits`, {
|
|
454
613
|
method: "GET",
|
|
455
|
-
headers: subscriptionHeaders(a)
|
|
614
|
+
headers: subscriptionHeaders(a),
|
|
615
|
+
signal
|
|
616
|
+
});
|
|
617
|
+
if (!res.ok) {
|
|
618
|
+
await res.arrayBuffer().catch(() => void 0);
|
|
619
|
+
return { ok: false, status: res.status, reason: "http_error" };
|
|
456
620
|
}
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
}
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
}
|
|
465
|
-
|
|
466
|
-
const
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
621
|
+
const details = parseCodexRateLimitResetCreditsDetails(await res.json().catch(() => null));
|
|
622
|
+
return details ? { ok: true, status: res.status, details } : { ok: false, status: res.status, reason: "invalid_response" };
|
|
623
|
+
}, timeoutMs);
|
|
624
|
+
return fetched.ok ? fetched.value : { ok: false, status: 0, reason: fetched.reason };
|
|
625
|
+
}
|
|
626
|
+
async function consumeCodexRateLimitResetCredit(a, input, fetchImpl = fetch, timeoutMs = RESET_CREDIT_CONSUME_TIMEOUT_MS) {
|
|
627
|
+
if (input.idempotencyKey.length === 0 || input.creditId === "") {
|
|
628
|
+
return { ok: false, status: 0, reason: "invalid_request" };
|
|
629
|
+
}
|
|
630
|
+
const fetched = await runBoundedCodexOperation(async (signal) => {
|
|
631
|
+
const res = await fetchImpl(`${CODEX_WHAM_BASE}/wham/rate-limit-reset-credits/consume`, {
|
|
632
|
+
method: "POST",
|
|
633
|
+
headers: {
|
|
634
|
+
...subscriptionHeaders(a),
|
|
635
|
+
"content-type": "application/json"
|
|
636
|
+
},
|
|
637
|
+
body: JSON.stringify({
|
|
638
|
+
redeem_request_id: input.idempotencyKey,
|
|
639
|
+
...input.creditId ? { credit_id: input.creditId } : {}
|
|
640
|
+
}),
|
|
641
|
+
signal
|
|
642
|
+
});
|
|
643
|
+
if (!res.ok) {
|
|
644
|
+
await res.arrayBuffer().catch(() => void 0);
|
|
645
|
+
return { ok: false, status: res.status, reason: "http_error" };
|
|
646
|
+
}
|
|
647
|
+
const result = parseCodexRateLimitResetConsumeResponse(await res.json().catch(() => null));
|
|
648
|
+
return result ? { ok: true, status: res.status, result } : { ok: false, status: res.status, reason: "invalid_response" };
|
|
649
|
+
}, timeoutMs);
|
|
650
|
+
return fetched.ok ? fetched.value : { ok: false, status: 0, reason: fetched.reason };
|
|
472
651
|
}
|
|
473
652
|
|
|
474
653
|
// src/request-context.ts
|
|
475
654
|
import { AsyncLocalStorage } from "async_hooks";
|
|
476
655
|
var codexRequestStorage = new AsyncLocalStorage();
|
|
656
|
+
function withCodexRequestOverrides(overrides, fn) {
|
|
657
|
+
const current = codexRequestStorage.getStore();
|
|
658
|
+
if (!current) return fn();
|
|
659
|
+
return codexRequestStorage.run({ ...current, ...overrides }, fn);
|
|
660
|
+
}
|
|
661
|
+
|
|
662
|
+
// src/response-timeout.ts
|
|
663
|
+
var CODEX_RESPONSE_TIMEOUT_ERROR_TYPE = "opengeni_codex_response_timeout";
|
|
664
|
+
var DEFAULT_CODEX_RESPONSE_TIMEOUT_POLICY = Object.freeze({
|
|
665
|
+
headersTimeoutMs: CODEX_RESPONSE_HEADERS_TIMEOUT_MS,
|
|
666
|
+
streamIdleTimeoutMs: CODEX_RESPONSE_STREAM_IDLE_TIMEOUT_MS,
|
|
667
|
+
wholeRequestTimeoutMs: CODEX_RESPONSE_WHOLE_TIMEOUT_MS,
|
|
668
|
+
noByteRetries: CODEX_RESPONSE_NO_BYTE_RETRIES,
|
|
669
|
+
retryBackoffMs: CODEX_RESPONSE_RETRY_BACKOFF_MS
|
|
670
|
+
});
|
|
671
|
+
function positiveFinite(value, fallback) {
|
|
672
|
+
return value !== void 0 && Number.isFinite(value) && value > 0 ? value : fallback;
|
|
673
|
+
}
|
|
674
|
+
function resolveCodexResponseTimeoutPolicy(override) {
|
|
675
|
+
return {
|
|
676
|
+
headersTimeoutMs: positiveFinite(
|
|
677
|
+
override?.headersTimeoutMs,
|
|
678
|
+
DEFAULT_CODEX_RESPONSE_TIMEOUT_POLICY.headersTimeoutMs
|
|
679
|
+
),
|
|
680
|
+
streamIdleTimeoutMs: positiveFinite(
|
|
681
|
+
override?.streamIdleTimeoutMs,
|
|
682
|
+
DEFAULT_CODEX_RESPONSE_TIMEOUT_POLICY.streamIdleTimeoutMs
|
|
683
|
+
),
|
|
684
|
+
wholeRequestTimeoutMs: positiveFinite(
|
|
685
|
+
override?.wholeRequestTimeoutMs,
|
|
686
|
+
DEFAULT_CODEX_RESPONSE_TIMEOUT_POLICY.wholeRequestTimeoutMs
|
|
687
|
+
),
|
|
688
|
+
// Automatic replay is fail-closed until the provider operation can be
|
|
689
|
+
// durably read/reconciled. Keep the field for policy/event compatibility,
|
|
690
|
+
// but never let a caller opt back into an unproved retry.
|
|
691
|
+
noByteRetries: 0,
|
|
692
|
+
retryBackoffMs: override?.retryBackoffMs !== void 0 && Number.isFinite(override.retryBackoffMs) && override.retryBackoffMs >= 0 ? override.retryBackoffMs : DEFAULT_CODEX_RESPONSE_TIMEOUT_POLICY.retryBackoffMs
|
|
693
|
+
};
|
|
694
|
+
}
|
|
695
|
+
var CodexResponseTimeoutError = class extends Error {
|
|
696
|
+
constructor(timeoutClass, requestId, responseObserved, message = `Codex response ${timeoutClass.replaceAll("_", " ")} timed out`) {
|
|
697
|
+
super(message);
|
|
698
|
+
this.timeoutClass = timeoutClass;
|
|
699
|
+
this.requestId = requestId;
|
|
700
|
+
this.responseObserved = responseObserved;
|
|
701
|
+
this.name = "CodexResponseTimeoutError";
|
|
702
|
+
}
|
|
703
|
+
code = CODEX_RESPONSE_TIMEOUT_ERROR_TYPE;
|
|
704
|
+
type = CODEX_RESPONSE_TIMEOUT_ERROR_TYPE;
|
|
705
|
+
};
|
|
706
|
+
function parseTimeoutClass(value) {
|
|
707
|
+
return value === "connect" || value === "headers" || value === "idle_stream" || value === "whole_request" ? value : null;
|
|
708
|
+
}
|
|
709
|
+
function classifyCodexResponseTimeoutError(error, options = {}) {
|
|
710
|
+
let current = error;
|
|
711
|
+
for (let depth = 0; depth < 8 && current && typeof current === "object"; depth += 1) {
|
|
712
|
+
const value = current;
|
|
713
|
+
const nested = value.error && typeof value.error === "object" ? value.error : void 0;
|
|
714
|
+
const type = (typeof value.type === "string" ? value.type : void 0) ?? (typeof value.code === "string" ? value.code : void 0) ?? (typeof nested?.type === "string" ? nested.type : void 0) ?? (typeof nested?.code === "string" ? nested.code : void 0);
|
|
715
|
+
if (type === CODEX_RESPONSE_TIMEOUT_ERROR_TYPE || value.name === "CodexResponseTimeoutError") {
|
|
716
|
+
const klass = parseTimeoutClass(value.timeoutClass) ?? parseTimeoutClass(nested?.timeout_class) ?? "headers";
|
|
717
|
+
return {
|
|
718
|
+
timeoutClass: klass,
|
|
719
|
+
requestId: (typeof value.requestId === "string" ? value.requestId : void 0) ?? (typeof nested?.request_id === "string" ? nested.request_id : null),
|
|
720
|
+
responseObserved: typeof value.responseObserved === "boolean" ? value.responseObserved : nested?.response_observed === true,
|
|
721
|
+
message: (typeof value.message === "string" ? value.message : void 0) ?? (typeof nested?.message === "string" ? nested.message : "Codex response timed out")
|
|
722
|
+
};
|
|
723
|
+
}
|
|
724
|
+
current = value.cause;
|
|
725
|
+
}
|
|
726
|
+
if (options.allowLegacyRequestTimeout && error && typeof error === "object") {
|
|
727
|
+
const value = error;
|
|
728
|
+
if (value.name === "APIConnectionTimeoutError" || value.message === "Request timed out." && value.name === "Error") {
|
|
729
|
+
return {
|
|
730
|
+
timeoutClass: "headers",
|
|
731
|
+
requestId: null,
|
|
732
|
+
responseObserved: false,
|
|
733
|
+
message: String(value.message ?? "Request timed out.")
|
|
734
|
+
};
|
|
735
|
+
}
|
|
736
|
+
}
|
|
737
|
+
return null;
|
|
738
|
+
}
|
|
739
|
+
function isPreHeadersTimeoutError(error) {
|
|
740
|
+
const structured = classifyCodexResponseTimeoutError(error);
|
|
741
|
+
if (structured && !structured.responseObserved) {
|
|
742
|
+
return structured.timeoutClass;
|
|
743
|
+
}
|
|
744
|
+
if (!error || typeof error !== "object") return null;
|
|
745
|
+
const value = error;
|
|
746
|
+
const code = typeof value.code === "string" ? value.code : "";
|
|
747
|
+
const name = typeof value.name === "string" ? value.name : "";
|
|
748
|
+
const message = typeof value.message === "string" ? value.message : String(error);
|
|
749
|
+
if (/^(?:ETIMEDOUT|UND_ERR_CONNECT_TIMEOUT)$/i.test(code) || /ConnectTimeout/i.test(name)) {
|
|
750
|
+
return "connect";
|
|
751
|
+
}
|
|
752
|
+
return /connect(?:ion)?[^.]*timed?\s*out/i.test(`${name} ${message}`) ? "connect" : null;
|
|
753
|
+
}
|
|
477
754
|
|
|
478
755
|
// src/fetch.ts
|
|
756
|
+
import { randomUUID } from "crypto";
|
|
479
757
|
var CODEX_TRANSPORT_ERROR_HEADER = "x-opengeni-codex-transport-error";
|
|
480
758
|
function headersCarryCodexTransportMarker(headers) {
|
|
481
759
|
if (!headers || typeof headers !== "object") return false;
|
|
@@ -495,6 +773,31 @@ function isCodexTransportError(error) {
|
|
|
495
773
|
}
|
|
496
774
|
return false;
|
|
497
775
|
}
|
|
776
|
+
function classifyCodexEncryptedArtifactRejection(error) {
|
|
777
|
+
if (!isCodexTransportError(error)) return null;
|
|
778
|
+
let current = error;
|
|
779
|
+
for (let depth = 0; depth < 6 && current && typeof current === "object"; depth += 1) {
|
|
780
|
+
const value = current;
|
|
781
|
+
const body = value.error && typeof value.error === "object" ? value.error : null;
|
|
782
|
+
const status = Number(value.status ?? body?.status);
|
|
783
|
+
const message = [
|
|
784
|
+
typeof value.message === "string" ? value.message : "",
|
|
785
|
+
typeof body?.message === "string" ? body.message : "",
|
|
786
|
+
typeof value.code === "string" ? value.code : "",
|
|
787
|
+
typeof body?.code === "string" ? body.code : "",
|
|
788
|
+
typeof value.type === "string" ? value.type : "",
|
|
789
|
+
typeof body?.type === "string" ? body.type : ""
|
|
790
|
+
].join(" ").toLowerCase();
|
|
791
|
+
const unsupportedFieldShape = /(?:invalid value|supported values?|unsupported|unknown (?:field|parameter|value))/.test(
|
|
792
|
+
message
|
|
793
|
+
);
|
|
794
|
+
if (status === 400 && !unsupportedFieldShape && /(?:encrypted[_ ]content|encrypted reasoning|reasoning artifact)/.test(message) && /(?:decrypt(?:ed|ion)?|could not be parsed|cannot be parsed|failed to parse)/.test(message)) {
|
|
795
|
+
return { status: 400, kind: "encrypted_content_rejected" };
|
|
796
|
+
}
|
|
797
|
+
current = value.cause;
|
|
798
|
+
}
|
|
799
|
+
return null;
|
|
800
|
+
}
|
|
498
801
|
function parseIntHeader(value) {
|
|
499
802
|
if (value === null) {
|
|
500
803
|
return null;
|
|
@@ -538,6 +841,216 @@ function parseCodexUsageHeaders(headers) {
|
|
|
538
841
|
checkedAt: new Date(nowMs)
|
|
539
842
|
};
|
|
540
843
|
}
|
|
844
|
+
async function emitRequestEvent(audit, event) {
|
|
845
|
+
await audit.ctx.onModelRequestEvent?.({
|
|
846
|
+
requestId: audit.requestId,
|
|
847
|
+
transportAttempt: audit.transportAttempt,
|
|
848
|
+
...audit.model ? { model: audit.model } : {},
|
|
849
|
+
durationMs: Math.max(0, Date.now() - audit.attemptStartedAt),
|
|
850
|
+
timeoutPolicy: audit.policy,
|
|
851
|
+
...event
|
|
852
|
+
});
|
|
853
|
+
}
|
|
854
|
+
function providerRequestId(headers) {
|
|
855
|
+
return headers.get("x-request-id") ?? headers.get("request-id") ?? void 0;
|
|
856
|
+
}
|
|
857
|
+
async function fetchBeforeHeaders(base, input, init, audit) {
|
|
858
|
+
const elapsed = Date.now() - audit.logicalStartedAt;
|
|
859
|
+
const wholeRemainingMs = audit.policy.wholeRequestTimeoutMs - elapsed;
|
|
860
|
+
const timeoutClass = wholeRemainingMs <= audit.policy.headersTimeoutMs ? "whole_request" : "headers";
|
|
861
|
+
const deadlineMs = Math.max(1, Math.min(audit.policy.headersTimeoutMs, wholeRemainingMs));
|
|
862
|
+
if (wholeRemainingMs <= 0) {
|
|
863
|
+
throw new CodexResponseTimeoutError("whole_request", audit.requestId, false);
|
|
864
|
+
}
|
|
865
|
+
const externalSignal = init.signal;
|
|
866
|
+
if (externalSignal?.aborted) throw externalSignal.reason;
|
|
867
|
+
const controller = new AbortController();
|
|
868
|
+
const forwardAbort = () => controller.abort(externalSignal?.reason);
|
|
869
|
+
externalSignal?.addEventListener("abort", forwardAbort, { once: true });
|
|
870
|
+
const basePromise = base(input, { ...init, signal: controller.signal });
|
|
871
|
+
let deadlineError = null;
|
|
872
|
+
let timer;
|
|
873
|
+
const deadline = new Promise((_resolve, reject) => {
|
|
874
|
+
timer = setTimeout(() => {
|
|
875
|
+
deadlineError = new CodexResponseTimeoutError(timeoutClass, audit.requestId, false);
|
|
876
|
+
reject(deadlineError);
|
|
877
|
+
}, deadlineMs);
|
|
878
|
+
});
|
|
879
|
+
try {
|
|
880
|
+
return await Promise.race([basePromise, deadline]);
|
|
881
|
+
} catch (error) {
|
|
882
|
+
if (deadlineError) {
|
|
883
|
+
controller.abort(deadlineError);
|
|
884
|
+
void basePromise.then((late) => late.body?.cancel(deadlineError ?? void 0)).catch(() => void 0);
|
|
885
|
+
throw deadlineError;
|
|
886
|
+
}
|
|
887
|
+
throw error;
|
|
888
|
+
} finally {
|
|
889
|
+
if (timer) clearTimeout(timer);
|
|
890
|
+
externalSignal?.removeEventListener("abort", forwardAbort);
|
|
891
|
+
}
|
|
892
|
+
}
|
|
893
|
+
async function observedResponse(res, audit, externalSignal) {
|
|
894
|
+
const requestId = providerRequestId(res.headers);
|
|
895
|
+
if (!res.body) {
|
|
896
|
+
await emitRequestEvent(audit, {
|
|
897
|
+
phase: res.ok ? "completed" : "failed",
|
|
898
|
+
responseObserved: true,
|
|
899
|
+
status: res.status,
|
|
900
|
+
...requestId ? { providerRequestId: requestId } : {}
|
|
901
|
+
});
|
|
902
|
+
return res;
|
|
903
|
+
}
|
|
904
|
+
const reader = res.body.getReader();
|
|
905
|
+
let terminal = false;
|
|
906
|
+
let firstByte = false;
|
|
907
|
+
let idleTimer;
|
|
908
|
+
let wholeTimer;
|
|
909
|
+
let armIdle = () => void 0;
|
|
910
|
+
let abortFromOutside;
|
|
911
|
+
const clearTimers = () => {
|
|
912
|
+
if (idleTimer) clearTimeout(idleTimer);
|
|
913
|
+
if (wholeTimer) clearTimeout(wholeTimer);
|
|
914
|
+
if (abortFromOutside) externalSignal?.removeEventListener("abort", abortFromOutside);
|
|
915
|
+
};
|
|
916
|
+
const body = new ReadableStream({
|
|
917
|
+
start(controller) {
|
|
918
|
+
const timeOut = (klass) => {
|
|
919
|
+
if (terminal) return;
|
|
920
|
+
terminal = true;
|
|
921
|
+
clearTimers();
|
|
922
|
+
const error = new CodexResponseTimeoutError(klass, audit.requestId, true);
|
|
923
|
+
void reader.cancel(error).catch(() => void 0);
|
|
924
|
+
void emitRequestEvent(audit, {
|
|
925
|
+
phase: "timed_out",
|
|
926
|
+
responseObserved: true,
|
|
927
|
+
timeoutClass: klass,
|
|
928
|
+
status: res.status,
|
|
929
|
+
...requestId ? { providerRequestId: requestId } : {}
|
|
930
|
+
}).then(
|
|
931
|
+
() => controller.error(error),
|
|
932
|
+
() => controller.error(error)
|
|
933
|
+
);
|
|
934
|
+
};
|
|
935
|
+
armIdle = () => {
|
|
936
|
+
if (idleTimer) clearTimeout(idleTimer);
|
|
937
|
+
idleTimer = setTimeout(() => timeOut("idle_stream"), audit.policy.streamIdleTimeoutMs);
|
|
938
|
+
};
|
|
939
|
+
armIdle();
|
|
940
|
+
const wholeRemaining = Math.max(
|
|
941
|
+
1,
|
|
942
|
+
audit.policy.wholeRequestTimeoutMs - (Date.now() - audit.logicalStartedAt)
|
|
943
|
+
);
|
|
944
|
+
wholeTimer = setTimeout(() => timeOut("whole_request"), wholeRemaining);
|
|
945
|
+
abortFromOutside = () => {
|
|
946
|
+
if (terminal) return;
|
|
947
|
+
terminal = true;
|
|
948
|
+
clearTimers();
|
|
949
|
+
const reason = externalSignal?.reason ?? new DOMException("Aborted", "AbortError");
|
|
950
|
+
void reader.cancel(reason).catch(() => void 0);
|
|
951
|
+
void emitRequestEvent(audit, {
|
|
952
|
+
phase: "failed",
|
|
953
|
+
responseObserved: true,
|
|
954
|
+
status: res.status,
|
|
955
|
+
...requestId ? { providerRequestId: requestId } : {}
|
|
956
|
+
}).then(
|
|
957
|
+
() => controller.error(reason),
|
|
958
|
+
() => controller.error(reason)
|
|
959
|
+
);
|
|
960
|
+
};
|
|
961
|
+
if (externalSignal?.aborted) {
|
|
962
|
+
abortFromOutside();
|
|
963
|
+
} else {
|
|
964
|
+
externalSignal?.addEventListener("abort", abortFromOutside, {
|
|
965
|
+
once: true
|
|
966
|
+
});
|
|
967
|
+
}
|
|
968
|
+
},
|
|
969
|
+
async pull(controller) {
|
|
970
|
+
if (terminal) return;
|
|
971
|
+
try {
|
|
972
|
+
const chunk = await reader.read();
|
|
973
|
+
if (terminal) return;
|
|
974
|
+
if (chunk.done) {
|
|
975
|
+
terminal = true;
|
|
976
|
+
clearTimers();
|
|
977
|
+
await emitRequestEvent(audit, {
|
|
978
|
+
phase: res.ok ? "completed" : "failed",
|
|
979
|
+
responseObserved: true,
|
|
980
|
+
status: res.status,
|
|
981
|
+
...requestId ? { providerRequestId: requestId } : {}
|
|
982
|
+
});
|
|
983
|
+
controller.close();
|
|
984
|
+
return;
|
|
985
|
+
}
|
|
986
|
+
armIdle();
|
|
987
|
+
if (!firstByte) {
|
|
988
|
+
firstByte = true;
|
|
989
|
+
await emitRequestEvent(audit, {
|
|
990
|
+
phase: "first_byte",
|
|
991
|
+
responseObserved: true,
|
|
992
|
+
status: res.status,
|
|
993
|
+
...requestId ? { providerRequestId: requestId } : {}
|
|
994
|
+
});
|
|
995
|
+
}
|
|
996
|
+
controller.enqueue(chunk.value);
|
|
997
|
+
} catch (error) {
|
|
998
|
+
if (terminal) return;
|
|
999
|
+
terminal = true;
|
|
1000
|
+
clearTimers();
|
|
1001
|
+
await emitRequestEvent(audit, {
|
|
1002
|
+
phase: "failed",
|
|
1003
|
+
responseObserved: true,
|
|
1004
|
+
status: res.status,
|
|
1005
|
+
...requestId ? { providerRequestId: requestId } : {}
|
|
1006
|
+
});
|
|
1007
|
+
controller.error(error);
|
|
1008
|
+
}
|
|
1009
|
+
},
|
|
1010
|
+
async cancel(reason) {
|
|
1011
|
+
if (!terminal) {
|
|
1012
|
+
terminal = true;
|
|
1013
|
+
clearTimers();
|
|
1014
|
+
await emitRequestEvent(audit, {
|
|
1015
|
+
phase: "failed",
|
|
1016
|
+
responseObserved: true,
|
|
1017
|
+
status: res.status,
|
|
1018
|
+
...requestId ? { providerRequestId: requestId } : {}
|
|
1019
|
+
}).catch(() => void 0);
|
|
1020
|
+
}
|
|
1021
|
+
await reader.cancel(reason).catch(() => void 0);
|
|
1022
|
+
}
|
|
1023
|
+
});
|
|
1024
|
+
const headers = new Headers(res.headers);
|
|
1025
|
+
headers.delete("content-length");
|
|
1026
|
+
return new Response(body, {
|
|
1027
|
+
status: res.status,
|
|
1028
|
+
statusText: res.statusText,
|
|
1029
|
+
headers
|
|
1030
|
+
});
|
|
1031
|
+
}
|
|
1032
|
+
function timeoutErrorResponse(info) {
|
|
1033
|
+
return new Response(
|
|
1034
|
+
JSON.stringify({
|
|
1035
|
+
error: {
|
|
1036
|
+
type: CODEX_RESPONSE_TIMEOUT_ERROR_TYPE,
|
|
1037
|
+
code: CODEX_RESPONSE_TIMEOUT_ERROR_TYPE,
|
|
1038
|
+
message: info.message,
|
|
1039
|
+
timeout_class: info.timeoutClass,
|
|
1040
|
+
response_observed: info.responseObserved,
|
|
1041
|
+
request_id: info.requestId
|
|
1042
|
+
}
|
|
1043
|
+
}),
|
|
1044
|
+
{
|
|
1045
|
+
status: 504,
|
|
1046
|
+
headers: {
|
|
1047
|
+
"content-type": "application/json",
|
|
1048
|
+
"x-should-retry": "false",
|
|
1049
|
+
[CODEX_TRANSPORT_ERROR_HEADER]: "1"
|
|
1050
|
+
}
|
|
1051
|
+
}
|
|
1052
|
+
);
|
|
1053
|
+
}
|
|
541
1054
|
function codexSubscriptionFetch(base = globalThis.fetch) {
|
|
542
1055
|
return async (input, init) => {
|
|
543
1056
|
const ctx = codexRequestStorage.getStore();
|
|
@@ -546,7 +1059,11 @@ function codexSubscriptionFetch(base = globalThis.fetch) {
|
|
|
546
1059
|
}
|
|
547
1060
|
const rawUrl = typeof input === "string" ? input : input instanceof URL ? input.toString() : input.url;
|
|
548
1061
|
const rewritten = rawUrl.replace(/(?<!\/codex)\/responses(\b|$)/, "/codex/responses$1");
|
|
549
|
-
const
|
|
1062
|
+
const policy = resolveCodexResponseTimeoutPolicy(ctx.responseTimeoutPolicy);
|
|
1063
|
+
const requestId = ctx.nextRequestId?.() ?? randomUUID();
|
|
1064
|
+
const logicalStartedAt = Date.now();
|
|
1065
|
+
let transportAttempt = 0;
|
|
1066
|
+
const attempt = async (auth, authenticationAttempt) => {
|
|
550
1067
|
const headers = new Headers(init?.headers);
|
|
551
1068
|
headers.set("Authorization", `Bearer ${auth.accessToken}`);
|
|
552
1069
|
if (auth.chatgptAccountId) {
|
|
@@ -565,42 +1082,121 @@ function codexSubscriptionFetch(base = globalThis.fetch) {
|
|
|
565
1082
|
}
|
|
566
1083
|
headers.delete("OpenAI-Beta");
|
|
567
1084
|
headers.delete("x-api-key");
|
|
1085
|
+
if (ctx.betaFeatures && ctx.betaFeatures.length > 0) {
|
|
1086
|
+
headers.set("x-codex-beta-features", ctx.betaFeatures.join(","));
|
|
1087
|
+
}
|
|
1088
|
+
if (ctx.turnMetadata && Object.keys(ctx.turnMetadata).length > 0) {
|
|
1089
|
+
headers.set("x-codex-turn-metadata", JSON.stringify(ctx.turnMetadata));
|
|
1090
|
+
}
|
|
568
1091
|
let callerWantsStream = true;
|
|
1092
|
+
let model;
|
|
569
1093
|
const nextInit = { ...init, headers };
|
|
570
1094
|
if (typeof init?.body === "string") {
|
|
571
1095
|
try {
|
|
572
1096
|
const parsed = JSON.parse(init.body);
|
|
573
1097
|
callerWantsStream = parsed.stream === true;
|
|
574
|
-
|
|
1098
|
+
const normalized = normalizeCodexRequestBody(parsed, ctx.resolveModel);
|
|
1099
|
+
model = typeof normalized.model === "string" ? normalized.model : void 0;
|
|
1100
|
+
nextInit.body = JSON.stringify(normalized);
|
|
575
1101
|
} catch {
|
|
576
1102
|
}
|
|
577
1103
|
}
|
|
1104
|
+
headers.set(
|
|
1105
|
+
"Idempotency-Key",
|
|
1106
|
+
authenticationAttempt === 0 ? requestId : `${requestId}:auth-${authenticationAttempt}`
|
|
1107
|
+
);
|
|
578
1108
|
if (process.env.CODEX_DEBUG) {
|
|
579
|
-
|
|
1109
|
+
let keys = [];
|
|
1110
|
+
if (typeof nextInit.body === "string") {
|
|
1111
|
+
try {
|
|
1112
|
+
keys = Object.keys(JSON.parse(nextInit.body));
|
|
1113
|
+
} catch {
|
|
1114
|
+
}
|
|
1115
|
+
}
|
|
580
1116
|
console.error(
|
|
581
1117
|
`[codex-debug] POST ${rewritten} stream=${callerWantsStream} bodyKeys=[${keys.join(",")}]`
|
|
582
1118
|
);
|
|
583
1119
|
}
|
|
584
|
-
|
|
585
|
-
|
|
1120
|
+
let res;
|
|
1121
|
+
transportAttempt += 1;
|
|
1122
|
+
const audit = {
|
|
1123
|
+
ctx,
|
|
1124
|
+
requestId,
|
|
1125
|
+
transportAttempt,
|
|
1126
|
+
...model ? { model } : {},
|
|
1127
|
+
logicalStartedAt,
|
|
1128
|
+
attemptStartedAt: Date.now(),
|
|
1129
|
+
policy
|
|
1130
|
+
};
|
|
1131
|
+
await emitRequestEvent(audit, {
|
|
1132
|
+
phase: "started",
|
|
1133
|
+
responseObserved: false
|
|
1134
|
+
});
|
|
1135
|
+
try {
|
|
1136
|
+
res = await fetchBeforeHeaders(base, rewritten, nextInit, audit);
|
|
1137
|
+
const upstreamRequestId = providerRequestId(res.headers);
|
|
1138
|
+
await emitRequestEvent(audit, {
|
|
1139
|
+
phase: "headers",
|
|
1140
|
+
responseObserved: true,
|
|
1141
|
+
status: res.status,
|
|
1142
|
+
...upstreamRequestId ? { providerRequestId: upstreamRequestId } : {}
|
|
1143
|
+
});
|
|
1144
|
+
const observed = await observedResponse(res, audit, nextInit.signal);
|
|
1145
|
+
res = observed;
|
|
1146
|
+
} catch (error) {
|
|
1147
|
+
if (nextInit.signal?.aborted) {
|
|
1148
|
+
await emitRequestEvent(audit, {
|
|
1149
|
+
phase: "failed",
|
|
1150
|
+
responseObserved: false
|
|
1151
|
+
}).catch(() => void 0);
|
|
1152
|
+
throw error;
|
|
1153
|
+
}
|
|
1154
|
+
const klass = isPreHeadersTimeoutError(error);
|
|
1155
|
+
if (!klass) {
|
|
1156
|
+
await emitRequestEvent(audit, {
|
|
1157
|
+
phase: "failed",
|
|
1158
|
+
responseObserved: false
|
|
1159
|
+
});
|
|
1160
|
+
throw error;
|
|
1161
|
+
}
|
|
1162
|
+
await emitRequestEvent(audit, {
|
|
1163
|
+
phase: "timed_out",
|
|
1164
|
+
responseObserved: false,
|
|
1165
|
+
timeoutClass: klass,
|
|
1166
|
+
willRetry: false
|
|
1167
|
+
}).catch(() => void 0);
|
|
1168
|
+
throw new CodexResponseTimeoutError(klass, requestId, false);
|
|
1169
|
+
}
|
|
1170
|
+
const usage = parseCodexUsageHeaders(res.headers);
|
|
586
1171
|
if (usage) {
|
|
587
1172
|
ctx.onUsageHeaders?.(usage);
|
|
588
1173
|
}
|
|
589
|
-
if (process.env.CODEX_DEBUG && !
|
|
1174
|
+
if (process.env.CODEX_DEBUG && !res.ok) {
|
|
590
1175
|
console.error(
|
|
591
|
-
`[codex-debug] <- ${
|
|
1176
|
+
`[codex-debug] <- ${res.status} requestId=${res.headers.get("x-request-id") ?? "unknown"}`
|
|
592
1177
|
);
|
|
593
1178
|
}
|
|
594
|
-
if (!
|
|
595
|
-
return await bufferCodexErrorResponse(
|
|
1179
|
+
if (!res.ok) {
|
|
1180
|
+
return await bufferCodexErrorResponse(res);
|
|
596
1181
|
}
|
|
597
|
-
return callerWantsStream ? repairCodexStream(
|
|
1182
|
+
return callerWantsStream ? repairCodexStream(res) : await sseToJsonResponse(res);
|
|
598
1183
|
};
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
res
|
|
1184
|
+
try {
|
|
1185
|
+
let res = await attempt(await ctx.getToken(), 0);
|
|
1186
|
+
if (res.status === 401) {
|
|
1187
|
+
res = await attempt(await ctx.refresh(), 1);
|
|
1188
|
+
}
|
|
1189
|
+
return res;
|
|
1190
|
+
} catch (error) {
|
|
1191
|
+
const timeout = classifyCodexResponseTimeoutError(error);
|
|
1192
|
+
if (!timeout) throw error;
|
|
1193
|
+
return timeoutErrorResponse({
|
|
1194
|
+
timeoutClass: timeout.timeoutClass,
|
|
1195
|
+
requestId: timeout.requestId ?? requestId,
|
|
1196
|
+
responseObserved: timeout.responseObserved,
|
|
1197
|
+
message: timeout.message
|
|
1198
|
+
});
|
|
602
1199
|
}
|
|
603
|
-
return res;
|
|
604
1200
|
};
|
|
605
1201
|
}
|
|
606
1202
|
var CODEX_USAGE_LIMIT_ERROR_TYPE = "usage_limit_reached";
|
|
@@ -1648,9 +2244,17 @@ export {
|
|
|
1648
2244
|
CODEX_ORIGINATOR,
|
|
1649
2245
|
CODEX_PROVIDER_BASE_URL,
|
|
1650
2246
|
CODEX_PROVIDER_ID,
|
|
2247
|
+
CODEX_RATE_LIMIT_RESET_OUTCOMES,
|
|
1651
2248
|
CODEX_REFRESH_FALLBACK_MS,
|
|
1652
2249
|
CODEX_REFRESH_WINDOW_MS,
|
|
1653
2250
|
CODEX_RESPONSES_BASE,
|
|
2251
|
+
CODEX_RESPONSE_HEADERS_TIMEOUT_MS,
|
|
2252
|
+
CODEX_RESPONSE_NO_BYTE_RETRIES,
|
|
2253
|
+
CODEX_RESPONSE_RETRY_BACKOFF_MS,
|
|
2254
|
+
CODEX_RESPONSE_SDK_OUTER_TIMEOUT_MS,
|
|
2255
|
+
CODEX_RESPONSE_STREAM_IDLE_TIMEOUT_MS,
|
|
2256
|
+
CODEX_RESPONSE_TIMEOUT_ERROR_TYPE,
|
|
2257
|
+
CODEX_RESPONSE_WHOLE_TIMEOUT_MS,
|
|
1654
2258
|
CODEX_TOKEN_URL,
|
|
1655
2259
|
CODEX_TOOL_OUTPUT_SERIALIZATION_ALLOWANCE,
|
|
1656
2260
|
CODEX_TRANSPORT_ERROR_HEADER,
|
|
@@ -1660,7 +2264,9 @@ export {
|
|
|
1660
2264
|
CodexDeviceError,
|
|
1661
2265
|
CodexRefreshTransient,
|
|
1662
2266
|
CodexReloginRequired,
|
|
2267
|
+
CodexResponseTimeoutError,
|
|
1663
2268
|
CodexStreamingTerminalError,
|
|
2269
|
+
DEFAULT_CODEX_RESPONSE_TIMEOUT_POLICY,
|
|
1664
2270
|
DEFAULT_MODEL_TOOL_OUTPUT_TRUNCATION_TOKENS,
|
|
1665
2271
|
MODEL_TOOL_OUTPUT_OPAQUE_PAYLOAD_MAX_BYTES,
|
|
1666
2272
|
MODEL_TOOL_OUTPUT_OVERSIZED_IMAGE_CARD_DATA_URL,
|
|
@@ -1671,27 +2277,37 @@ export {
|
|
|
1671
2277
|
boundModelToolOutputItems,
|
|
1672
2278
|
buildCodexUsageWindowFromCache,
|
|
1673
2279
|
buildModelResolver,
|
|
2280
|
+
classifyCodexEncryptedArtifactRejection,
|
|
2281
|
+
classifyCodexResponseTimeoutError,
|
|
1674
2282
|
classifyCodexUsageLimitError,
|
|
1675
2283
|
codexAppsSanitizingFetch,
|
|
1676
2284
|
codexRequestStorage,
|
|
1677
2285
|
codexSubscriptionFetch,
|
|
2286
|
+
consumeCodexRateLimitResetCredit,
|
|
1678
2287
|
decodeJwtPayload,
|
|
1679
2288
|
exchangeDeviceCode,
|
|
1680
2289
|
fetchCodexModels,
|
|
2290
|
+
fetchCodexRateLimitResetCredits,
|
|
1681
2291
|
fetchCodexUsage,
|
|
1682
2292
|
isCodexBilledModel,
|
|
1683
2293
|
isCodexTransportError,
|
|
2294
|
+
isPreHeadersTimeoutError,
|
|
1684
2295
|
modelToolOutputSerializationBudgetTokens,
|
|
1685
2296
|
normalizeCodexRequestBody,
|
|
1686
2297
|
normalizeCodexUsage,
|
|
2298
|
+
parseCodexRateLimitResetConsumeResponse,
|
|
2299
|
+
parseCodexRateLimitResetCreditsDetails,
|
|
2300
|
+
parseCodexRateLimitResetCreditsSummary,
|
|
1687
2301
|
parseCodexUsageHeaders,
|
|
1688
2302
|
parseIdToken,
|
|
1689
2303
|
pollDeviceCode,
|
|
1690
2304
|
refreshCodexToken,
|
|
1691
2305
|
remapToolCallRequestBody,
|
|
2306
|
+
resolveCodexResponseTimeoutPolicy,
|
|
1692
2307
|
sanitizeMcpJsonBody,
|
|
1693
2308
|
sanitizeMcpSseBody,
|
|
1694
2309
|
startDeviceCode,
|
|
1695
|
-
truncateMiddleWithTokenBudget
|
|
2310
|
+
truncateMiddleWithTokenBudget,
|
|
2311
|
+
withCodexRequestOverrides
|
|
1696
2312
|
};
|
|
1697
2313
|
//# sourceMappingURL=index.js.map
|