@opengeni/codex 0.2.7 → 0.2.10
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 +57 -0
- package/dist/billing.d.ts +11 -0
- package/dist/bounded-operation.d.ts +16 -0
- package/dist/{chunk-YGKQDUY7.js → chunk-HT463QWA.js} +10 -2
- package/dist/chunk-HT463QWA.js.map +1 -0
- package/dist/chunk-MFVGCR3N.js +236 -0
- package/dist/chunk-MFVGCR3N.js.map +1 -0
- package/dist/constants.d.ts +37 -35
- package/dist/constants.js +9 -1
- package/dist/device-code.d.ts +36 -0
- package/dist/fetch.d.ts +84 -0
- package/dist/index.d.ts +15 -515
- package/dist/index.js +373 -14
- 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/realtime-v3.d.ts +86 -0
- package/dist/realtime-v3.js +25 -0
- package/dist/realtime-v3.js.map +1 -0
- package/dist/realtime.d.ts +48 -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 +7 -3
- package/src/api-client.ts +26 -9
- package/src/constants.ts +8 -1
- package/src/fetch.ts +67 -2
- package/src/index.ts +2 -0
- package/src/normalize.ts +6 -3
- package/src/realtime-v3.ts +349 -0
- package/src/realtime.ts +356 -0
- package/src/request-context.ts +20 -0
- package/dist/chunk-YGKQDUY7.js.map +0 -1
package/dist/index.js
CHANGED
|
@@ -21,6 +21,10 @@ import {
|
|
|
21
21
|
CODEX_ORIGINATOR,
|
|
22
22
|
CODEX_PROVIDER_BASE_URL,
|
|
23
23
|
CODEX_PROVIDER_ID,
|
|
24
|
+
CODEX_REALTIME_CALL_TIMEOUT_MS,
|
|
25
|
+
CODEX_REALTIME_DEFAULT_VOICE,
|
|
26
|
+
CODEX_REALTIME_MODEL,
|
|
27
|
+
CODEX_REALTIME_VERSION,
|
|
24
28
|
CODEX_REFRESH_FALLBACK_MS,
|
|
25
29
|
CODEX_REFRESH_WINDOW_MS,
|
|
26
30
|
CODEX_RESPONSES_BASE,
|
|
@@ -32,7 +36,19 @@ import {
|
|
|
32
36
|
CODEX_RESPONSE_WHOLE_TIMEOUT_MS,
|
|
33
37
|
CODEX_TOKEN_URL,
|
|
34
38
|
CODEX_WHAM_BASE
|
|
35
|
-
} from "./chunk-
|
|
39
|
+
} from "./chunk-HT463QWA.js";
|
|
40
|
+
import {
|
|
41
|
+
CODEX_REALTIME_CONTEXT_APPEND_MAX_BYTES,
|
|
42
|
+
CODEX_REALTIME_INITIAL_ITEMS_MAX_COUNT,
|
|
43
|
+
CODEX_REALTIME_INITIAL_ITEMS_MAX_TOKENS,
|
|
44
|
+
CODEX_REALTIME_V3_MAX_EVENT_BYTES,
|
|
45
|
+
CODEX_REALTIME_V3_MAX_IDENTIFIER_BYTES,
|
|
46
|
+
CODEX_REALTIME_V3_MAX_TEXT_BYTES,
|
|
47
|
+
contextAppendChunks,
|
|
48
|
+
encodeCodexRealtimeV3DelegationContextAppend,
|
|
49
|
+
encodeCodexRealtimeV3SessionContextAppend,
|
|
50
|
+
parseCodexRealtimeV3Event
|
|
51
|
+
} from "./chunk-MFVGCR3N.js";
|
|
36
52
|
|
|
37
53
|
// src/billing.ts
|
|
38
54
|
function isCodexBilledModel(model) {
|
|
@@ -261,7 +277,8 @@ var CODEX_ALLOWED_TOP_LEVEL_KEYS = /* @__PURE__ */ new Set([
|
|
|
261
277
|
"stream",
|
|
262
278
|
"include",
|
|
263
279
|
"prompt_cache_key",
|
|
264
|
-
"text"
|
|
280
|
+
"text",
|
|
281
|
+
"service_tier"
|
|
265
282
|
]);
|
|
266
283
|
function normalizeCodexRequestBody(body, resolveModel) {
|
|
267
284
|
body.store = false;
|
|
@@ -566,7 +583,7 @@ function normalizeCodexUsage(httpStatus, rawPayload) {
|
|
|
566
583
|
var CODEX_READ_TIMEOUT_MS = 5e3;
|
|
567
584
|
var RESET_CREDIT_DETAILS_TIMEOUT_MS = 5e3;
|
|
568
585
|
var RESET_CREDIT_CONSUME_TIMEOUT_MS = 1e4;
|
|
569
|
-
function
|
|
586
|
+
function codexSubscriptionHeaders(a) {
|
|
570
587
|
return {
|
|
571
588
|
Authorization: `Bearer ${a.accessToken}`,
|
|
572
589
|
...a.chatgptAccountId ? { "ChatGPT-Account-ID": a.chatgptAccountId } : {},
|
|
@@ -580,7 +597,7 @@ async function fetchCodexModels(a, fetchImpl = fetch, timeoutMs = CODEX_READ_TIM
|
|
|
580
597
|
const fetched = await runBoundedCodexOperation(async (signal) => {
|
|
581
598
|
const res = await fetchImpl(
|
|
582
599
|
`${CODEX_RESPONSES_BASE}/models?client_version=${encodeURIComponent(a.clientVersion)}`,
|
|
583
|
-
{ method: "GET", headers:
|
|
600
|
+
{ method: "GET", headers: codexSubscriptionHeaders(a), signal }
|
|
584
601
|
);
|
|
585
602
|
if (!res.ok) {
|
|
586
603
|
await res.arrayBuffer().catch(() => void 0);
|
|
@@ -596,7 +613,7 @@ async function fetchCodexUsage(a, fetchImpl = fetch, timeoutMs = CODEX_READ_TIME
|
|
|
596
613
|
const fetched = await runBoundedCodexOperation(async (signal) => {
|
|
597
614
|
const res = await fetchImpl(`${CODEX_WHAM_BASE}/wham/usage`, {
|
|
598
615
|
method: "GET",
|
|
599
|
-
headers:
|
|
616
|
+
headers: codexSubscriptionHeaders(a),
|
|
600
617
|
signal
|
|
601
618
|
});
|
|
602
619
|
const payload = res.ok || res.status === 404 ? await res.json().catch(() => null) : null;
|
|
@@ -610,15 +627,23 @@ async function fetchCodexRateLimitResetCredits(a, fetchImpl = fetch, timeoutMs =
|
|
|
610
627
|
const fetched = await runBoundedCodexOperation(async (signal) => {
|
|
611
628
|
const res = await fetchImpl(`${CODEX_WHAM_BASE}/wham/rate-limit-reset-credits`, {
|
|
612
629
|
method: "GET",
|
|
613
|
-
headers:
|
|
630
|
+
headers: codexSubscriptionHeaders(a),
|
|
614
631
|
signal
|
|
615
632
|
});
|
|
616
633
|
if (!res.ok) {
|
|
617
634
|
await res.arrayBuffer().catch(() => void 0);
|
|
618
|
-
return {
|
|
635
|
+
return {
|
|
636
|
+
ok: false,
|
|
637
|
+
status: res.status,
|
|
638
|
+
reason: "http_error"
|
|
639
|
+
};
|
|
619
640
|
}
|
|
620
641
|
const details = parseCodexRateLimitResetCreditsDetails(await res.json().catch(() => null));
|
|
621
|
-
return details ? { ok: true, status: res.status, details } : {
|
|
642
|
+
return details ? { ok: true, status: res.status, details } : {
|
|
643
|
+
ok: false,
|
|
644
|
+
status: res.status,
|
|
645
|
+
reason: "invalid_response"
|
|
646
|
+
};
|
|
622
647
|
}, timeoutMs);
|
|
623
648
|
return fetched.ok ? fetched.value : { ok: false, status: 0, reason: fetched.reason };
|
|
624
649
|
}
|
|
@@ -630,7 +655,7 @@ async function consumeCodexRateLimitResetCredit(a, input, fetchImpl = fetch, tim
|
|
|
630
655
|
const res = await fetchImpl(`${CODEX_WHAM_BASE}/wham/rate-limit-reset-credits/consume`, {
|
|
631
656
|
method: "POST",
|
|
632
657
|
headers: {
|
|
633
|
-
...
|
|
658
|
+
...codexSubscriptionHeaders(a),
|
|
634
659
|
"content-type": "application/json"
|
|
635
660
|
},
|
|
636
661
|
body: JSON.stringify({
|
|
@@ -641,10 +666,18 @@ async function consumeCodexRateLimitResetCredit(a, input, fetchImpl = fetch, tim
|
|
|
641
666
|
});
|
|
642
667
|
if (!res.ok) {
|
|
643
668
|
await res.arrayBuffer().catch(() => void 0);
|
|
644
|
-
return {
|
|
669
|
+
return {
|
|
670
|
+
ok: false,
|
|
671
|
+
status: res.status,
|
|
672
|
+
reason: "http_error"
|
|
673
|
+
};
|
|
645
674
|
}
|
|
646
675
|
const result = parseCodexRateLimitResetConsumeResponse(await res.json().catch(() => null));
|
|
647
|
-
return result ? { ok: true, status: res.status, result } : {
|
|
676
|
+
return result ? { ok: true, status: res.status, result } : {
|
|
677
|
+
ok: false,
|
|
678
|
+
status: res.status,
|
|
679
|
+
reason: "invalid_response"
|
|
680
|
+
};
|
|
648
681
|
}, timeoutMs);
|
|
649
682
|
return fetched.ok ? fetched.value : { ok: false, status: 0, reason: fetched.reason };
|
|
650
683
|
}
|
|
@@ -652,6 +685,11 @@ async function consumeCodexRateLimitResetCredit(a, input, fetchImpl = fetch, tim
|
|
|
652
685
|
// src/request-context.ts
|
|
653
686
|
import { AsyncLocalStorage } from "async_hooks";
|
|
654
687
|
var codexRequestStorage = new AsyncLocalStorage();
|
|
688
|
+
function withCodexRequestOverrides(overrides, fn) {
|
|
689
|
+
const current = codexRequestStorage.getStore();
|
|
690
|
+
if (!current) return fn();
|
|
691
|
+
return codexRequestStorage.run({ ...current, ...overrides }, fn);
|
|
692
|
+
}
|
|
655
693
|
|
|
656
694
|
// src/response-timeout.ts
|
|
657
695
|
var CODEX_RESPONSE_TIMEOUT_ERROR_TYPE = "opengeni_codex_response_timeout";
|
|
@@ -767,6 +805,31 @@ function isCodexTransportError(error) {
|
|
|
767
805
|
}
|
|
768
806
|
return false;
|
|
769
807
|
}
|
|
808
|
+
function classifyCodexEncryptedArtifactRejection(error) {
|
|
809
|
+
if (!isCodexTransportError(error)) return null;
|
|
810
|
+
let current = error;
|
|
811
|
+
for (let depth = 0; depth < 6 && current && typeof current === "object"; depth += 1) {
|
|
812
|
+
const value = current;
|
|
813
|
+
const body = value.error && typeof value.error === "object" ? value.error : null;
|
|
814
|
+
const status = Number(value.status ?? body?.status);
|
|
815
|
+
const message = [
|
|
816
|
+
typeof value.message === "string" ? value.message : "",
|
|
817
|
+
typeof body?.message === "string" ? body.message : "",
|
|
818
|
+
typeof value.code === "string" ? value.code : "",
|
|
819
|
+
typeof body?.code === "string" ? body.code : "",
|
|
820
|
+
typeof value.type === "string" ? value.type : "",
|
|
821
|
+
typeof body?.type === "string" ? body.type : ""
|
|
822
|
+
].join(" ").toLowerCase();
|
|
823
|
+
const unsupportedFieldShape = /(?:invalid value|supported values?|unsupported|unknown (?:field|parameter|value))/.test(
|
|
824
|
+
message
|
|
825
|
+
);
|
|
826
|
+
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)) {
|
|
827
|
+
return { status: 400, kind: "encrypted_content_rejected" };
|
|
828
|
+
}
|
|
829
|
+
current = value.cause;
|
|
830
|
+
}
|
|
831
|
+
return null;
|
|
832
|
+
}
|
|
770
833
|
function parseIntHeader(value) {
|
|
771
834
|
if (value === null) {
|
|
772
835
|
return null;
|
|
@@ -930,7 +993,9 @@ async function observedResponse(res, audit, externalSignal) {
|
|
|
930
993
|
if (externalSignal?.aborted) {
|
|
931
994
|
abortFromOutside();
|
|
932
995
|
} else {
|
|
933
|
-
externalSignal?.addEventListener("abort", abortFromOutside, {
|
|
996
|
+
externalSignal?.addEventListener("abort", abortFromOutside, {
|
|
997
|
+
once: true
|
|
998
|
+
});
|
|
934
999
|
}
|
|
935
1000
|
},
|
|
936
1001
|
async pull(controller) {
|
|
@@ -990,7 +1055,11 @@ async function observedResponse(res, audit, externalSignal) {
|
|
|
990
1055
|
});
|
|
991
1056
|
const headers = new Headers(res.headers);
|
|
992
1057
|
headers.delete("content-length");
|
|
993
|
-
return new Response(body, {
|
|
1058
|
+
return new Response(body, {
|
|
1059
|
+
status: res.status,
|
|
1060
|
+
statusText: res.statusText,
|
|
1061
|
+
headers
|
|
1062
|
+
});
|
|
994
1063
|
}
|
|
995
1064
|
function timeoutErrorResponse(info) {
|
|
996
1065
|
return new Response(
|
|
@@ -1045,6 +1114,12 @@ function codexSubscriptionFetch(base = globalThis.fetch) {
|
|
|
1045
1114
|
}
|
|
1046
1115
|
headers.delete("OpenAI-Beta");
|
|
1047
1116
|
headers.delete("x-api-key");
|
|
1117
|
+
if (ctx.betaFeatures && ctx.betaFeatures.length > 0) {
|
|
1118
|
+
headers.set("x-codex-beta-features", ctx.betaFeatures.join(","));
|
|
1119
|
+
}
|
|
1120
|
+
if (ctx.turnMetadata && Object.keys(ctx.turnMetadata).length > 0) {
|
|
1121
|
+
headers.set("x-codex-turn-metadata", JSON.stringify(ctx.turnMetadata));
|
|
1122
|
+
}
|
|
1048
1123
|
let callerWantsStream = true;
|
|
1049
1124
|
let model;
|
|
1050
1125
|
const nextInit = { ...init, headers };
|
|
@@ -2176,6 +2251,269 @@ function isResponsesProtocolContentPrefix(output) {
|
|
|
2176
2251
|
function isImageDataUrl(value) {
|
|
2177
2252
|
return /^data:image\/[a-z0-9.+-]+;base64,/i.test(value);
|
|
2178
2253
|
}
|
|
2254
|
+
|
|
2255
|
+
// src/realtime.ts
|
|
2256
|
+
var CODEX_REALTIME_CALL_URL = `${CODEX_RESPONSES_BASE}/realtime/calls?intent=quicksilver&architecture=avas`;
|
|
2257
|
+
var MAX_REALTIME_SDP_BYTES = 1024 * 1024;
|
|
2258
|
+
var REALTIME_CALL_ID = /^(?:rtc_.+|[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12})$/i;
|
|
2259
|
+
var CODEX_REALTIME_VOICES = [
|
|
2260
|
+
"juniper",
|
|
2261
|
+
"maple",
|
|
2262
|
+
"spruce",
|
|
2263
|
+
"ember",
|
|
2264
|
+
"vale",
|
|
2265
|
+
"breeze",
|
|
2266
|
+
"arbor",
|
|
2267
|
+
"sol",
|
|
2268
|
+
"cove"
|
|
2269
|
+
];
|
|
2270
|
+
var CodexRealtimeError = class extends Error {
|
|
2271
|
+
constructor(code, message, providerStatus = null) {
|
|
2272
|
+
super(message);
|
|
2273
|
+
this.code = code;
|
|
2274
|
+
this.providerStatus = providerStatus;
|
|
2275
|
+
this.name = "CodexRealtimeError";
|
|
2276
|
+
}
|
|
2277
|
+
};
|
|
2278
|
+
async function createCodexRealtimeCall(auth, input, fetchImpl = fetch, options = {}) {
|
|
2279
|
+
validateRealtimeInput(input);
|
|
2280
|
+
const timeoutMs = options.timeoutMs ?? CODEX_REALTIME_CALL_TIMEOUT_MS;
|
|
2281
|
+
if (!Number.isFinite(timeoutMs) || timeoutMs <= 0) {
|
|
2282
|
+
throw new CodexRealtimeError("invalid_request", "Codex realtime timeout must be positive");
|
|
2283
|
+
}
|
|
2284
|
+
if (options.signal?.aborted) {
|
|
2285
|
+
throw new CodexRealtimeError("cancelled", "Codex realtime request cancelled");
|
|
2286
|
+
}
|
|
2287
|
+
const controller = new AbortController();
|
|
2288
|
+
let timedOut = false;
|
|
2289
|
+
let timeout;
|
|
2290
|
+
let rejectCancellation;
|
|
2291
|
+
const cancellation = new Promise((_resolve, reject) => {
|
|
2292
|
+
rejectCancellation = reject;
|
|
2293
|
+
});
|
|
2294
|
+
const onAbort = () => {
|
|
2295
|
+
controller.abort(options.signal?.reason);
|
|
2296
|
+
rejectCancellation?.(new CodexRealtimeError("cancelled", "Codex realtime request cancelled"));
|
|
2297
|
+
};
|
|
2298
|
+
options.signal?.addEventListener("abort", onAbort, { once: true });
|
|
2299
|
+
const deadline = new Promise((_resolve, reject) => {
|
|
2300
|
+
timeout = setTimeout(() => {
|
|
2301
|
+
timedOut = true;
|
|
2302
|
+
controller.abort();
|
|
2303
|
+
reject(new CodexRealtimeError("timeout", "Codex realtime request timed out"));
|
|
2304
|
+
}, timeoutMs);
|
|
2305
|
+
});
|
|
2306
|
+
const request = (async () => {
|
|
2307
|
+
const response = await fetchImpl(CODEX_REALTIME_CALL_URL, {
|
|
2308
|
+
method: "POST",
|
|
2309
|
+
headers: {
|
|
2310
|
+
...codexSubscriptionHeaders(auth),
|
|
2311
|
+
"content-type": "application/json",
|
|
2312
|
+
"openai-alpha": "quicksilver=v2",
|
|
2313
|
+
"session-id": input.sessionId,
|
|
2314
|
+
"thread-id": input.sessionId
|
|
2315
|
+
},
|
|
2316
|
+
body: JSON.stringify({
|
|
2317
|
+
sdp: input.sdp,
|
|
2318
|
+
session: {
|
|
2319
|
+
instructions: input.instructions ?? "",
|
|
2320
|
+
audio: {
|
|
2321
|
+
output: { voice: input.voice ?? CODEX_REALTIME_DEFAULT_VOICE }
|
|
2322
|
+
},
|
|
2323
|
+
delegation: { type: "client" },
|
|
2324
|
+
model: CODEX_REALTIME_MODEL,
|
|
2325
|
+
...input.initialItems?.length ? {
|
|
2326
|
+
initial_items: input.initialItems.map((item) => ({
|
|
2327
|
+
type: "message",
|
|
2328
|
+
role: item.role,
|
|
2329
|
+
content: [
|
|
2330
|
+
{
|
|
2331
|
+
type: item.role === "assistant" ? "output_text" : "input_text",
|
|
2332
|
+
text: item.text
|
|
2333
|
+
}
|
|
2334
|
+
]
|
|
2335
|
+
}))
|
|
2336
|
+
} : {}
|
|
2337
|
+
}
|
|
2338
|
+
}),
|
|
2339
|
+
signal: controller.signal
|
|
2340
|
+
});
|
|
2341
|
+
if (!response.ok) {
|
|
2342
|
+
await response.body?.cancel().catch(() => void 0);
|
|
2343
|
+
throw providerHttpError(response.status);
|
|
2344
|
+
}
|
|
2345
|
+
const location = response.headers.get("location");
|
|
2346
|
+
if (!location || !validRealtimeLocation(location)) {
|
|
2347
|
+
await response.body?.cancel().catch(() => void 0);
|
|
2348
|
+
throw new CodexRealtimeError(
|
|
2349
|
+
"invalid_response",
|
|
2350
|
+
"Codex realtime response did not identify a compatible call",
|
|
2351
|
+
response.status
|
|
2352
|
+
);
|
|
2353
|
+
}
|
|
2354
|
+
const sdp = await readBoundedSdp(response);
|
|
2355
|
+
if (!isAudioSdp(sdp)) {
|
|
2356
|
+
throw new CodexRealtimeError(
|
|
2357
|
+
"invalid_response",
|
|
2358
|
+
"Codex realtime response was not an audio SDP answer",
|
|
2359
|
+
response.status
|
|
2360
|
+
);
|
|
2361
|
+
}
|
|
2362
|
+
return {
|
|
2363
|
+
sdp,
|
|
2364
|
+
version: CODEX_REALTIME_VERSION,
|
|
2365
|
+
model: CODEX_REALTIME_MODEL
|
|
2366
|
+
};
|
|
2367
|
+
})();
|
|
2368
|
+
try {
|
|
2369
|
+
return await Promise.race([request, cancellation, deadline]);
|
|
2370
|
+
} catch (error) {
|
|
2371
|
+
if (error instanceof CodexRealtimeError) throw error;
|
|
2372
|
+
if (options.signal?.aborted) {
|
|
2373
|
+
throw new CodexRealtimeError("cancelled", "Codex realtime request cancelled");
|
|
2374
|
+
}
|
|
2375
|
+
if (timedOut || controller.signal.aborted) {
|
|
2376
|
+
throw new CodexRealtimeError("timeout", "Codex realtime request timed out");
|
|
2377
|
+
}
|
|
2378
|
+
throw new CodexRealtimeError("network", "Codex realtime provider request failed");
|
|
2379
|
+
} finally {
|
|
2380
|
+
if (timeout) clearTimeout(timeout);
|
|
2381
|
+
options.signal?.removeEventListener("abort", onAbort);
|
|
2382
|
+
}
|
|
2383
|
+
}
|
|
2384
|
+
function selectCodexCredentialId(args) {
|
|
2385
|
+
if (args.sessionPinnedCredentialId && args.connectedIds.has(args.sessionPinnedCredentialId)) {
|
|
2386
|
+
return args.sessionPinnedCredentialId;
|
|
2387
|
+
}
|
|
2388
|
+
if (args.activeCredentialId && args.connectedIds.has(args.activeCredentialId)) {
|
|
2389
|
+
return args.activeCredentialId;
|
|
2390
|
+
}
|
|
2391
|
+
return null;
|
|
2392
|
+
}
|
|
2393
|
+
function validateRealtimeInput(input) {
|
|
2394
|
+
if (input.version !== CODEX_REALTIME_VERSION) {
|
|
2395
|
+
throw new CodexRealtimeError(
|
|
2396
|
+
"incompatible",
|
|
2397
|
+
`Codex realtime requires ${CODEX_REALTIME_VERSION}`
|
|
2398
|
+
);
|
|
2399
|
+
}
|
|
2400
|
+
if (!input.sessionId || input.sessionId.length > 128) {
|
|
2401
|
+
throw new CodexRealtimeError("invalid_request", "Codex realtime session id is invalid");
|
|
2402
|
+
}
|
|
2403
|
+
if (new TextEncoder().encode(input.sdp).byteLength > MAX_REALTIME_SDP_BYTES) {
|
|
2404
|
+
throw new CodexRealtimeError("invalid_request", "Codex realtime SDP offer is too large");
|
|
2405
|
+
}
|
|
2406
|
+
if (!isAudioSdp(input.sdp)) {
|
|
2407
|
+
throw new CodexRealtimeError("invalid_request", "Codex realtime requires an audio SDP offer");
|
|
2408
|
+
}
|
|
2409
|
+
if (input.voice !== void 0 && !CODEX_REALTIME_VOICES.includes(input.voice)) {
|
|
2410
|
+
throw new CodexRealtimeError("invalid_request", "Codex realtime voice is unsupported");
|
|
2411
|
+
}
|
|
2412
|
+
const initialItems = input.initialItems ?? [];
|
|
2413
|
+
if (initialItems.length > CODEX_REALTIME_INITIAL_ITEMS_MAX_COUNT) {
|
|
2414
|
+
throw new CodexRealtimeError(
|
|
2415
|
+
"invalid_request",
|
|
2416
|
+
`Codex realtime history exceeds ${CODEX_REALTIME_INITIAL_ITEMS_MAX_COUNT} items`
|
|
2417
|
+
);
|
|
2418
|
+
}
|
|
2419
|
+
let estimatedTokens = 0;
|
|
2420
|
+
for (const item of initialItems) {
|
|
2421
|
+
if (item.role !== "user" && item.role !== "developer" && item.role !== "assistant" || typeof item.text !== "string") {
|
|
2422
|
+
throw new CodexRealtimeError("invalid_request", "Codex realtime history item is invalid");
|
|
2423
|
+
}
|
|
2424
|
+
const itemTokens = Math.ceil(new TextEncoder().encode(item.text).byteLength / 4);
|
|
2425
|
+
if (itemTokens > CODEX_REALTIME_INITIAL_ITEMS_MAX_TOKENS) {
|
|
2426
|
+
throw new CodexRealtimeError("invalid_request", "Codex realtime history item is too large");
|
|
2427
|
+
}
|
|
2428
|
+
estimatedTokens += itemTokens;
|
|
2429
|
+
}
|
|
2430
|
+
if (estimatedTokens > CODEX_REALTIME_INITIAL_ITEMS_MAX_TOKENS) {
|
|
2431
|
+
throw new CodexRealtimeError("invalid_request", "Codex realtime history is too large");
|
|
2432
|
+
}
|
|
2433
|
+
}
|
|
2434
|
+
function providerHttpError(status) {
|
|
2435
|
+
if (status === 401) {
|
|
2436
|
+
return new CodexRealtimeError(
|
|
2437
|
+
"authentication",
|
|
2438
|
+
"Codex subscription rejected authentication",
|
|
2439
|
+
status
|
|
2440
|
+
);
|
|
2441
|
+
}
|
|
2442
|
+
if (status === 403) {
|
|
2443
|
+
return new CodexRealtimeError(
|
|
2444
|
+
"entitlement",
|
|
2445
|
+
"Codex subscription lacks realtime entitlement",
|
|
2446
|
+
status
|
|
2447
|
+
);
|
|
2448
|
+
}
|
|
2449
|
+
if (status === 404) {
|
|
2450
|
+
return new CodexRealtimeError(
|
|
2451
|
+
"incompatible",
|
|
2452
|
+
"Codex subscription realtime is unavailable",
|
|
2453
|
+
status
|
|
2454
|
+
);
|
|
2455
|
+
}
|
|
2456
|
+
if (status === 429) {
|
|
2457
|
+
return new CodexRealtimeError("rate_limited", "Codex realtime is rate limited", status);
|
|
2458
|
+
}
|
|
2459
|
+
return new CodexRealtimeError("provider", "Codex realtime provider request failed", status);
|
|
2460
|
+
}
|
|
2461
|
+
function validRealtimeLocation(location) {
|
|
2462
|
+
const path = location.split("?", 1)[0] ?? "";
|
|
2463
|
+
const segment = path.split("/").filter(Boolean).at(-1) ?? "";
|
|
2464
|
+
return REALTIME_CALL_ID.test(segment);
|
|
2465
|
+
}
|
|
2466
|
+
function isAudioSdp(sdp) {
|
|
2467
|
+
return /^v=0(?:\r?\n)/.test(sdp) && /(?:^|\r?\n)m=audio\s/m.test(sdp);
|
|
2468
|
+
}
|
|
2469
|
+
async function readBoundedSdp(response) {
|
|
2470
|
+
const declared = Number(response.headers.get("content-length"));
|
|
2471
|
+
if (Number.isFinite(declared) && declared > MAX_REALTIME_SDP_BYTES) {
|
|
2472
|
+
await response.body?.cancel().catch(() => void 0);
|
|
2473
|
+
throw new CodexRealtimeError(
|
|
2474
|
+
"invalid_response",
|
|
2475
|
+
"Codex realtime SDP answer is too large",
|
|
2476
|
+
response.status
|
|
2477
|
+
);
|
|
2478
|
+
}
|
|
2479
|
+
if (!response.body) return "";
|
|
2480
|
+
const reader = response.body.getReader();
|
|
2481
|
+
const chunks = [];
|
|
2482
|
+
let total = 0;
|
|
2483
|
+
try {
|
|
2484
|
+
while (true) {
|
|
2485
|
+
const next = await reader.read();
|
|
2486
|
+
if (next.done) break;
|
|
2487
|
+
total += next.value.byteLength;
|
|
2488
|
+
if (total > MAX_REALTIME_SDP_BYTES) {
|
|
2489
|
+
await reader.cancel();
|
|
2490
|
+
throw new CodexRealtimeError(
|
|
2491
|
+
"invalid_response",
|
|
2492
|
+
"Codex realtime SDP answer is too large",
|
|
2493
|
+
response.status
|
|
2494
|
+
);
|
|
2495
|
+
}
|
|
2496
|
+
chunks.push(next.value);
|
|
2497
|
+
}
|
|
2498
|
+
} finally {
|
|
2499
|
+
reader.releaseLock();
|
|
2500
|
+
}
|
|
2501
|
+
const bytes = new Uint8Array(total);
|
|
2502
|
+
let offset = 0;
|
|
2503
|
+
for (const chunk of chunks) {
|
|
2504
|
+
bytes.set(chunk, offset);
|
|
2505
|
+
offset += chunk.byteLength;
|
|
2506
|
+
}
|
|
2507
|
+
try {
|
|
2508
|
+
return new TextDecoder("utf-8", { fatal: true }).decode(bytes);
|
|
2509
|
+
} catch {
|
|
2510
|
+
throw new CodexRealtimeError(
|
|
2511
|
+
"invalid_response",
|
|
2512
|
+
"Codex realtime SDP answer was not valid UTF-8",
|
|
2513
|
+
response.status
|
|
2514
|
+
);
|
|
2515
|
+
}
|
|
2516
|
+
}
|
|
2179
2517
|
export {
|
|
2180
2518
|
CODEX_APPS_MCP_SERVER_ID,
|
|
2181
2519
|
CODEX_APPS_MCP_SERVER_NAME,
|
|
@@ -2202,6 +2540,17 @@ export {
|
|
|
2202
2540
|
CODEX_PROVIDER_BASE_URL,
|
|
2203
2541
|
CODEX_PROVIDER_ID,
|
|
2204
2542
|
CODEX_RATE_LIMIT_RESET_OUTCOMES,
|
|
2543
|
+
CODEX_REALTIME_CALL_TIMEOUT_MS,
|
|
2544
|
+
CODEX_REALTIME_CONTEXT_APPEND_MAX_BYTES,
|
|
2545
|
+
CODEX_REALTIME_DEFAULT_VOICE,
|
|
2546
|
+
CODEX_REALTIME_INITIAL_ITEMS_MAX_COUNT,
|
|
2547
|
+
CODEX_REALTIME_INITIAL_ITEMS_MAX_TOKENS,
|
|
2548
|
+
CODEX_REALTIME_MODEL,
|
|
2549
|
+
CODEX_REALTIME_V3_MAX_EVENT_BYTES,
|
|
2550
|
+
CODEX_REALTIME_V3_MAX_IDENTIFIER_BYTES,
|
|
2551
|
+
CODEX_REALTIME_V3_MAX_TEXT_BYTES,
|
|
2552
|
+
CODEX_REALTIME_VERSION,
|
|
2553
|
+
CODEX_REALTIME_VOICES,
|
|
2205
2554
|
CODEX_REFRESH_FALLBACK_MS,
|
|
2206
2555
|
CODEX_REFRESH_WINDOW_MS,
|
|
2207
2556
|
CODEX_RESPONSES_BASE,
|
|
@@ -2219,6 +2568,7 @@ export {
|
|
|
2219
2568
|
CODEX_WEEKLY_WINDOW_SECONDS,
|
|
2220
2569
|
CODEX_WHAM_BASE,
|
|
2221
2570
|
CodexDeviceError,
|
|
2571
|
+
CodexRealtimeError,
|
|
2222
2572
|
CodexRefreshTransient,
|
|
2223
2573
|
CodexReloginRequired,
|
|
2224
2574
|
CodexResponseTimeoutError,
|
|
@@ -2234,13 +2584,19 @@ export {
|
|
|
2234
2584
|
boundModelToolOutputItems,
|
|
2235
2585
|
buildCodexUsageWindowFromCache,
|
|
2236
2586
|
buildModelResolver,
|
|
2587
|
+
classifyCodexEncryptedArtifactRejection,
|
|
2237
2588
|
classifyCodexResponseTimeoutError,
|
|
2238
2589
|
classifyCodexUsageLimitError,
|
|
2239
2590
|
codexAppsSanitizingFetch,
|
|
2240
2591
|
codexRequestStorage,
|
|
2241
2592
|
codexSubscriptionFetch,
|
|
2593
|
+
codexSubscriptionHeaders,
|
|
2242
2594
|
consumeCodexRateLimitResetCredit,
|
|
2595
|
+
contextAppendChunks,
|
|
2596
|
+
createCodexRealtimeCall,
|
|
2243
2597
|
decodeJwtPayload,
|
|
2598
|
+
encodeCodexRealtimeV3DelegationContextAppend,
|
|
2599
|
+
encodeCodexRealtimeV3SessionContextAppend,
|
|
2244
2600
|
exchangeDeviceCode,
|
|
2245
2601
|
fetchCodexModels,
|
|
2246
2602
|
fetchCodexRateLimitResetCredits,
|
|
@@ -2254,6 +2610,7 @@ export {
|
|
|
2254
2610
|
parseCodexRateLimitResetConsumeResponse,
|
|
2255
2611
|
parseCodexRateLimitResetCreditsDetails,
|
|
2256
2612
|
parseCodexRateLimitResetCreditsSummary,
|
|
2613
|
+
parseCodexRealtimeV3Event,
|
|
2257
2614
|
parseCodexUsageHeaders,
|
|
2258
2615
|
parseIdToken,
|
|
2259
2616
|
pollDeviceCode,
|
|
@@ -2262,7 +2619,9 @@ export {
|
|
|
2262
2619
|
resolveCodexResponseTimeoutPolicy,
|
|
2263
2620
|
sanitizeMcpJsonBody,
|
|
2264
2621
|
sanitizeMcpSseBody,
|
|
2622
|
+
selectCodexCredentialId,
|
|
2265
2623
|
startDeviceCode,
|
|
2266
|
-
truncateMiddleWithTokenBudget
|
|
2624
|
+
truncateMiddleWithTokenBudget,
|
|
2625
|
+
withCodexRequestOverrides
|
|
2267
2626
|
};
|
|
2268
2627
|
//# sourceMappingURL=index.js.map
|