@openclaw/ai 2026.8.1-beta.1 → 2026.8.1-beta.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/dist/{anthropic-CE-7SkF6.mjs → anthropic-B6dLpq5L.mjs} +37 -22
- package/dist/{src-QkygScBs.mjs → anthropic-JsNA5KCu.mjs} +0 -1
- package/dist/{anthropic-usage-Ma4iX6uG.mjs → anthropic-compaction-replay-8lJNKXOE.mjs} +225 -102
- package/dist/anthropic-payload-policy-CiEuQS72.d.mts +49 -0
- package/dist/{api-registry-EpJoVwM1.d.mts → api-registry-k3zTz0cV.d.mts} +1 -1
- package/dist/{azure-openai-responses-Cc_kasye.mjs → azure-openai-responses-mxIOtUnn.mjs} +23 -29
- package/dist/diagnostics.d.mts +24 -1
- package/dist/diagnostics.mjs +2 -1
- package/dist/{event-stream-DRmDMRHH.d.mts → event-stream-BP6AWT8j.d.mts} +3 -1
- package/dist/{event-stream-CEV9t6da.mjs → event-stream-uSMZJ3FA.mjs} +16 -3
- package/dist/event-stream.d.mts +1 -1
- package/dist/event-stream.mjs +1 -1
- package/dist/{google-CGQu21aw.mjs → google-C7h2QzDX.mjs} +4 -4
- package/dist/{google-shared-Cq2UKx1l.mjs → google-shared-B0Qr9OR7.mjs} +9 -18
- package/dist/google-thinking-level-C-V3tecN.mjs +9 -0
- package/dist/{google-vertex-CusxWzvE.mjs → google-vertex-Bhc3TjDl.mjs} +5 -4
- package/dist/{llm-request-activity-BjtkplhG.mjs → headers-DdOQtGuU.mjs} +9 -1
- package/dist/{host-Bl7Kgddo.mjs → host-DTqNc7ad.mjs} +227 -168
- package/dist/{host-Dn4_SZI2.d.mts → host-vWgMMhiJ.d.mts} +9 -4
- package/dist/index.d.mts +6 -6
- package/dist/index.mjs +7 -5
- package/dist/internal/anthropic.d.mts +13 -5
- package/dist/internal/anthropic.mjs +5 -5
- package/dist/internal/openai-responses-payload-policy.d.mts +3 -0
- package/dist/internal/openai-responses-payload-policy.mjs +3 -0
- package/dist/internal/openai.d.mts +6 -6
- package/dist/internal/openai.mjs +8 -7
- package/dist/internal/runtime.d.mts +17 -5
- package/dist/internal/runtime.mjs +85 -73
- package/dist/internal/shared.d.mts +1 -6
- package/dist/internal/shared.mjs +3 -4
- package/dist/{json-parse-BvXNt1-7.mjs → json-parse-CDnesDM_.mjs} +4 -6
- package/dist/{mistral-Dx6VzNjf.mjs → mistral-CEWoQI_g.mjs} +26 -45
- package/dist/{number-coercion-1Miyb5MO.mjs → number-coercion-H9qHik3g.mjs} +7 -2
- package/dist/openai-chatgpt-jwt-KWcgd0d_.mjs +19 -0
- package/dist/{openai-chatgpt-responses-SC9m0FSf.mjs → openai-chatgpt-responses-CrPmqERt.mjs} +225 -144
- package/dist/{openai-completions-BaIpl93j.mjs → openai-completions-BPnt4Sml.mjs} +28 -43
- package/dist/openai-completions-compat-Dt3dcawL.d.mts +43 -0
- package/dist/{openai-responses-Bdx3V_Yu.mjs → openai-responses-DhIKtOup.mjs} +17 -24
- package/dist/openai-responses-contracts-CyfIkQi5.mjs +253 -0
- package/dist/openai-responses-contracts-XpZJxrRG.d.mts +68 -0
- package/dist/openai-responses-payload-policy-BDxV-W0c.mjs +206 -0
- package/dist/openai-responses-payload-policy-BSs371VM.d.mts +40 -0
- package/dist/{openai-responses-prompt-observer-internal-DDZPxRfr.mjs → openai-responses-prompt-observer-internal-DgNTYnRY.mjs} +3 -3
- package/dist/{openai-responses-stream-internal-Bl8YyVtF.mjs → openai-responses-shared-DXIt3iY5.mjs} +1211 -908
- package/dist/{openai-reasoning-compat-DKebnIBL.mjs → openai-stop-reason-BkFkqqK0.mjs} +198 -172
- package/dist/{openai-transport-shared-Cipt7egQ.mjs → openai-tool-projection-CY04OcvQ.mjs} +151 -128
- package/dist/provider-error-BUwEnjXq.mjs +429 -0
- package/dist/provider-error-CzNw4BWX.d.mts +12 -0
- package/dist/{provider-options-C5kYML7i.d.mts → provider-options-B96RdNpH.d.mts} +9 -3
- package/dist/provider-transcript-transform-ePx-Bbfr.mjs +155 -0
- package/dist/provider-types.d.mts +31 -0
- package/dist/provider-types.mjs +8 -0
- package/dist/providers.d.mts +1 -1
- package/dist/providers.mjs +17 -19
- package/dist/{reasoning-tag-text-partitioner-CGDyLWUR.mjs → reasoning-tag-text-partitioner-rnPwX2pg.mjs} +14 -8
- package/dist/record-coerce-DdXsgUd_.mjs +23 -0
- package/dist/{model-utils-Dau5dlgm.mjs → sanitize-unicode-BYqrYtC_.mjs} +28 -2
- package/dist/session-resources-CkR4WWy1.mjs +21 -0
- package/dist/simple-options-D58D5Kvw.mjs +117 -0
- package/dist/src-D2H6yKkH.mjs +2 -0
- package/dist/{stream-first-event-timeout-BIBomOGq.mjs → stream-first-event-timeout-MK28puvq.mjs} +2 -2
- package/dist/string-coerce-fsri9iCu.mjs +34 -0
- package/dist/{tool-schema-json-projection-B1b-XCn5.mjs → tool-schema-json-projection-q5d7QX5c.mjs} +5 -7
- package/dist/transport-utils-DJqkxbhC.mjs +138 -0
- package/dist/transports.d.mts +135 -178
- package/dist/transports.mjs +1732 -1294
- package/dist/types-BDdaOVi2.mjs +6 -0
- package/dist/{types-CH7ReIcU.d.mts → types-BHNrPS1l.d.mts} +19 -1
- package/dist/types.d.mts +4 -4
- package/dist/types.mjs +6 -4
- package/dist/utf16-slice-CvGodqok.mjs +29 -0
- package/dist/{validation-DAa_yFOM.mjs → validation-B61OhAio.mjs} +6 -6
- package/dist/{validation-CcPcuEbR.d.mts → validation-DT9SrFn3.d.mts} +1 -1
- package/dist/validation.d.mts +1 -1
- package/dist/validation.mjs +1 -1
- package/package.json +15 -1
- package/dist/headers-B_e4-1J0.mjs +0 -9
- package/dist/openai-chatgpt-jwt-DhAAzLkj.mjs +0 -39
- package/dist/openai-responses-contracts-BBKBfAqR.d.mts +0 -116
- package/dist/openai-responses-shared-CCyMvg7M.mjs +0 -403
- package/dist/provider-error-DI0Ts28U.mjs +0 -47
- package/dist/sanitize-unicode-DT5o51ur.mjs +0 -26
- package/dist/tool-result-text-Dvkp2Dus.mjs +0 -274
- package/dist/transform-messages-DfjpNXNQ.mjs +0 -2
- package/dist/transport-stream-shared-CPNv7A3r.mjs +0 -297
package/dist/{openai-chatgpt-responses-SC9m0FSf.mjs → openai-chatgpt-responses-CrPmqERt.mjs}
RENAMED
|
@@ -1,18 +1,23 @@
|
|
|
1
1
|
import { n as getEnvApiKey } from "./env-api-keys-DrgeBuva.mjs";
|
|
2
2
|
import { i as formatThrownValue, n as createAssistantMessageDiagnostic, t as appendAssistantMessageDiagnostic } from "./diagnostics-COpOtRwq.mjs";
|
|
3
|
-
import { t as AssistantMessageEventStream } from "./event-stream-
|
|
4
|
-
import { n as getAiTransportHost, r as resolveAiTransportHeaderSentinels } from "./host-
|
|
3
|
+
import { t as AssistantMessageEventStream } from "./event-stream-uSMZJ3FA.mjs";
|
|
4
|
+
import { n as getAiTransportHost, r as resolveAiTransportHeaderSentinels } from "./host-DTqNc7ad.mjs";
|
|
5
|
+
import { n as projectProviderError } from "./provider-error-BUwEnjXq.mjs";
|
|
6
|
+
import { n as toErrorObject, t as createResponsesPromptEgressObserver } from "./openai-responses-prompt-observer-internal-DgNTYnRY.mjs";
|
|
7
|
+
import { c as resolveTimerTimeoutMs, i as clampTimerTimeoutMs } from "./number-coercion-H9qHik3g.mjs";
|
|
8
|
+
import { S as supportsOpenAITemperature, m as responsesPromptObserver } from "./openai-responses-contracts-CyfIkQi5.mjs";
|
|
5
9
|
import { n as clampOpenAIPromptCacheKey } from "./openai-prompt-cache-mZTCdRPo.mjs";
|
|
6
|
-
import {
|
|
7
|
-
import {
|
|
8
|
-
import {
|
|
9
|
-
import {
|
|
10
|
+
import { l as stripSystemPromptCacheBoundary, n as buildBaseOptions } from "./simple-options-D58D5Kvw.mjs";
|
|
11
|
+
import { t as headersToRecord } from "./headers-DdOQtGuU.mjs";
|
|
12
|
+
import { F as commitResponsesEncryptedContentAttempt, G as suppressOpenAIResponsesCompaction, L as isInvalidEncryptedContentError, U as buildOpenAIResponsesReasoningReplayMetadata, a as resolveResponsesReasoningEffort, c as processResponsesStream, i as createResponsesAssistantOutput, n as applyResponsesServiceTierPricing, p as ResponsesStreamFailure, r as convertResponsesMessages, s as convertResponsesToolPayload, z as resolveNextResponsesEncryptedContentAttempt } from "./openai-responses-shared-DXIt3iY5.mjs";
|
|
13
|
+
import { f as transportAbortError, p as withProviderResponseHook } from "./provider-transcript-transform-ePx-Bbfr.mjs";
|
|
10
14
|
import { parseRetryAfterHttpDateMs } from "./internal/retry-after.mjs";
|
|
11
|
-
import {
|
|
12
|
-
import {
|
|
13
|
-
import { t as
|
|
14
|
-
import {
|
|
15
|
-
import
|
|
15
|
+
import { t as MALFORMED_STREAMING_FRAGMENT_ERROR_MESSAGE } from "./transport-utils-DJqkxbhC.mjs";
|
|
16
|
+
import { o as createOpenAIResponseHook } from "./openai-tool-projection-CY04OcvQ.mjs";
|
|
17
|
+
import { a as withFirstStreamEventTimeout, i as getFirstStreamEventTimeoutMs, r as getFirstStreamEventTimeoutHandler, t as createFirstStreamEventAbortController } from "./stream-first-event-timeout-MK28puvq.mjs";
|
|
18
|
+
import { n as registerSessionResourceCleanup } from "./session-resources-CkR4WWy1.mjs";
|
|
19
|
+
import "./diagnostics.mjs";
|
|
20
|
+
import { n as resolveOpenAICodexAccountId } from "./openai-chatgpt-jwt-KWcgd0d_.mjs";
|
|
16
21
|
import { t as createSseByteGuard } from "./streaming-byte-guard-BrbkbwUu.mjs";
|
|
17
22
|
import { t as inspectTlsCertificateError } from "./tls-certificate-errors-DXSpluKI.mjs";
|
|
18
23
|
//#region packages/ai/src/internal/retry-sleep.ts
|
|
@@ -35,6 +40,63 @@ function sleepWithAbort(ms, signal) {
|
|
|
35
40
|
});
|
|
36
41
|
}
|
|
37
42
|
//#endregion
|
|
43
|
+
//#region packages/ai/src/providers/openai-chatgpt-responses-protocol.ts
|
|
44
|
+
const OPENAI_CHATGPT_RESPONSES_SUCCESS_BODY_MAX_BYTES = 16 * 1024 * 1024;
|
|
45
|
+
var CodexProtocolError = class extends Error {
|
|
46
|
+
constructor(message, options) {
|
|
47
|
+
super(message);
|
|
48
|
+
this.name = "CodexProtocolError";
|
|
49
|
+
this.payload = options?.payload;
|
|
50
|
+
this.cause = options?.cause;
|
|
51
|
+
}
|
|
52
|
+
};
|
|
53
|
+
async function* parseOpenAIChatGptResponsesSse(response) {
|
|
54
|
+
if (!response.body) return;
|
|
55
|
+
const reader = response.body.getReader();
|
|
56
|
+
const guard = createSseByteGuard(reader, {
|
|
57
|
+
maxBytes: OPENAI_CHATGPT_RESPONSES_SUCCESS_BODY_MAX_BYTES,
|
|
58
|
+
onOverflow: ({ size, maxBytes }) => /* @__PURE__ */ new Error(`OpenAI ChatGPT Responses success body exceeded ${maxBytes} bytes (received ${size})`)
|
|
59
|
+
});
|
|
60
|
+
const decoder = new TextDecoder();
|
|
61
|
+
let buffer = "";
|
|
62
|
+
try {
|
|
63
|
+
while (true) {
|
|
64
|
+
const { done, value } = await guard.read();
|
|
65
|
+
if (value) buffer += decoder.decode(value, { stream: true });
|
|
66
|
+
if (done) buffer += decoder.decode();
|
|
67
|
+
while (true) {
|
|
68
|
+
const searchable = !done && buffer.endsWith("\r") && !buffer.endsWith("\r\r") && !buffer.endsWith("\n\r") ? buffer.slice(0, -1) : buffer;
|
|
69
|
+
const boundary = /(?:\r\n|\r(?!\n)|\n)(?:\r\n|\r(?!\n)|\n)/.exec(searchable);
|
|
70
|
+
if (!boundary) break;
|
|
71
|
+
const chunk = buffer.slice(0, boundary.index);
|
|
72
|
+
buffer = buffer.slice(boundary.index + boundary[0].length);
|
|
73
|
+
const dataLines = chunk.split(/\r\n|\r|\n/).filter((line) => line.startsWith("data:")).map((line) => line.slice(5).trim());
|
|
74
|
+
if (dataLines.length > 0) {
|
|
75
|
+
const data = dataLines.join("\n").trim();
|
|
76
|
+
if (data && data !== "[DONE]") {
|
|
77
|
+
let event;
|
|
78
|
+
try {
|
|
79
|
+
event = JSON.parse(data);
|
|
80
|
+
} catch (cause) {
|
|
81
|
+
if (!(cause instanceof SyntaxError)) throw cause;
|
|
82
|
+
throw new CodexProtocolError(MALFORMED_STREAMING_FRAGMENT_ERROR_MESSAGE, { cause });
|
|
83
|
+
}
|
|
84
|
+
yield event;
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
if (done) break;
|
|
89
|
+
}
|
|
90
|
+
} finally {
|
|
91
|
+
try {
|
|
92
|
+
await guard.cancel();
|
|
93
|
+
} catch {}
|
|
94
|
+
try {
|
|
95
|
+
reader.releaseLock();
|
|
96
|
+
} catch {}
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
//#endregion
|
|
38
100
|
//#region packages/ai/src/providers/openai-chatgpt-responses.ts
|
|
39
101
|
const dynamicImport = (specifier) => import(specifier);
|
|
40
102
|
function loadNodeOs() {
|
|
@@ -50,7 +112,6 @@ const CODEX_TOOL_CALL_PROVIDERS = /* @__PURE__ */ new Set(["openai", "opencode"]
|
|
|
50
112
|
const WEBSOCKET_MESSAGE_TOO_BIG_CLOSE_CODE = 1009;
|
|
51
113
|
const WEBSOCKET_CONNECTION_LIMIT_REACHED_CODE = "websocket_connection_limit_reached";
|
|
52
114
|
const OPENAI_CHATGPT_RESPONSES_ERROR_BODY_MAX_BYTES = 16 * 1024;
|
|
53
|
-
const OPENAI_CHATGPT_RESPONSES_SUCCESS_BODY_MAX_BYTES = 16 * 1024 * 1024;
|
|
54
115
|
const CODEX_RESPONSE_STATUSES = /* @__PURE__ */ new Set([
|
|
55
116
|
"completed",
|
|
56
117
|
"incomplete",
|
|
@@ -123,9 +184,17 @@ const streamOpenAICodexResponses = (model, context, options) => {
|
|
|
123
184
|
const modelHeaders = resolveAiTransportHeaderSentinels(model.headers);
|
|
124
185
|
const optionHeaders = resolveAiTransportHeaderSentinels(options?.headers);
|
|
125
186
|
const accountId = extractOpenAICodexAccountId(apiKey);
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
187
|
+
const buildBody = async (replayMode) => {
|
|
188
|
+
let body = buildRequestBody(model, context, options, replayMode);
|
|
189
|
+
const nextBody = await options?.onPayload?.(body, model);
|
|
190
|
+
if (nextBody !== void 0) body = nextBody;
|
|
191
|
+
return body;
|
|
192
|
+
};
|
|
193
|
+
let semanticAttempt = {
|
|
194
|
+
kind: "initial",
|
|
195
|
+
request: await buildBody("checkpoint")
|
|
196
|
+
};
|
|
197
|
+
const commitSemanticAttempt = (attempt) => commitResponsesEncryptedContentAttempt(attempt, (checkpoint) => suppressOpenAIResponsesCompaction(output, model, options, checkpoint));
|
|
129
198
|
const observePromptEgress = createResponsesPromptEgressObserver(options, context.systemPrompt);
|
|
130
199
|
const sessionId = clampOpenAIPromptCacheKey(options?.sessionId);
|
|
131
200
|
requestTimeoutMs = resolveRequestTimeoutMs(options);
|
|
@@ -141,13 +210,19 @@ const streamOpenAICodexResponses = (model, context, options) => {
|
|
|
141
210
|
if (transport !== "sse" && !websocketDisabledForSession) {
|
|
142
211
|
const websocketHeaders = buildWebSocketHeaders(modelHeaders, optionHeaders, accountId, apiKey, sessionId || createCodexRequestId());
|
|
143
212
|
let websocketStarted = false;
|
|
213
|
+
let websocketRequestSent = false;
|
|
144
214
|
let retriedWebSocketConnectionLimit = false;
|
|
145
215
|
while (true) {
|
|
216
|
+
const activeAttempt = semanticAttempt;
|
|
146
217
|
websocketStarted = false;
|
|
218
|
+
websocketRequestSent = false;
|
|
147
219
|
try {
|
|
148
|
-
await processWebSocketStream(resolveCodexWebSocketUrl(model.baseUrl),
|
|
220
|
+
await processWebSocketStream(resolveCodexWebSocketUrl(model.baseUrl), activeAttempt.request, websocketHeaders, output, stream, model, () => {
|
|
221
|
+
commitSemanticAttempt(activeAttempt);
|
|
149
222
|
websocketStarted = true;
|
|
150
|
-
}, requestOptions, firstEventAbort.abort, observePromptEgress)
|
|
223
|
+
}, requestOptions, firstEventAbort.abort, observePromptEgress, activeAttempt.kind, () => {
|
|
224
|
+
websocketRequestSent = true;
|
|
225
|
+
});
|
|
151
226
|
if (activeSignal?.aborted) throw transportAbortError(activeSignal);
|
|
152
227
|
if (output.stopReason === "aborted" || output.stopReason === "error") throw new CodexApiError(output.errorMessage ?? "An unknown error occurred");
|
|
153
228
|
stream.push({
|
|
@@ -159,6 +234,12 @@ const streamOpenAICodexResponses = (model, context, options) => {
|
|
|
159
234
|
return;
|
|
160
235
|
} catch (error) {
|
|
161
236
|
const aborted = activeSignal?.aborted;
|
|
237
|
+
const nextSemanticAttempt = !aborted && websocketRequestSent && !websocketStarted && error instanceof CodexApiError && isInvalidEncryptedContentError(error) ? await resolveNextResponsesEncryptedContentAttempt(activeAttempt, error, { buildFullHistoryRequest: () => buildBody("full-history") }) : void 0;
|
|
238
|
+
if (nextSemanticAttempt) {
|
|
239
|
+
semanticAttempt = nextSemanticAttempt;
|
|
240
|
+
retriedWebSocketConnectionLimit = false;
|
|
241
|
+
continue;
|
|
242
|
+
}
|
|
162
243
|
const connectionLimitBeforeStart = !websocketStarted && isWebSocketConnectionLimitReachedError(error);
|
|
163
244
|
if (!aborted && connectionLimitBeforeStart && !retriedWebSocketConnectionLimit) {
|
|
164
245
|
retriedWebSocketConnectionLimit = true;
|
|
@@ -170,7 +251,7 @@ const streamOpenAICodexResponses = (model, context, options) => {
|
|
|
170
251
|
fallbackTransport: transport === "auto" && !websocketStarted ? "sse" : void 0,
|
|
171
252
|
eventsEmitted: websocketStarted,
|
|
172
253
|
phase: websocketStarted ? "after_message_stream_start" : "before_message_stream_start",
|
|
173
|
-
requestBytes: new TextEncoder().encode(JSON.stringify(
|
|
254
|
+
requestBytes: new TextEncoder().encode(JSON.stringify(activeAttempt.request)).byteLength
|
|
174
255
|
}));
|
|
175
256
|
if (transport === "auto" && options?.sessionId) websocketSseFallbackSessions.add(options.sessionId);
|
|
176
257
|
if (websocketStarted || transport !== "auto") throw error;
|
|
@@ -178,64 +259,102 @@ const streamOpenAICodexResponses = (model, context, options) => {
|
|
|
178
259
|
}
|
|
179
260
|
}
|
|
180
261
|
}
|
|
181
|
-
const sseHeaders = buildSSEHeaders(modelHeaders, optionHeaders, accountId, apiKey, sessionId);
|
|
182
|
-
const bodyJson = JSON.stringify(body);
|
|
183
|
-
const compressedBody = model.provider === "openai" && !sseHeaders.has("content-encoding") ? compressRequestBodyZstd(bodyJson) : null;
|
|
184
|
-
if (compressedBody) sseHeaders.set("content-encoding", "zstd");
|
|
185
|
-
const sseBody = compressedBody ?? bodyJson;
|
|
186
262
|
let response;
|
|
187
|
-
let lastError;
|
|
188
263
|
const maxRetries = options?.maxRetries ?? DEFAULT_MAX_RETRIES;
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
264
|
+
while (true) {
|
|
265
|
+
const activeAttempt = semanticAttempt;
|
|
266
|
+
response = void 0;
|
|
267
|
+
const sseHeaders = buildSSEHeaders(modelHeaders, optionHeaders, accountId, apiKey, sessionId);
|
|
268
|
+
const bodyJson = JSON.stringify(activeAttempt.request);
|
|
269
|
+
const compressedBody = model.provider === "openai" && !sseHeaders.has("content-encoding") ? compressRequestBodyZstd(bodyJson) : null;
|
|
270
|
+
if (compressedBody) sseHeaders.set("content-encoding", "zstd");
|
|
271
|
+
const sseBody = compressedBody ?? bodyJson;
|
|
272
|
+
let terminalResponseError;
|
|
273
|
+
for (let attempt = 0; attempt <= maxRetries; attempt++) {
|
|
274
|
+
if (activeSignal?.aborted) throw transportAbortError(activeSignal);
|
|
275
|
+
observePromptEgress?.(activeAttempt.request, {
|
|
195
276
|
egress: "native-codex-sse",
|
|
196
|
-
payloadVariant:
|
|
197
|
-
});
|
|
198
|
-
attemptResponse = await fetch(resolveCodexUrl(model.baseUrl), {
|
|
199
|
-
method: "POST",
|
|
200
|
-
headers: sseHeaders,
|
|
201
|
-
body: sseBody,
|
|
202
|
-
signal: activeSignal
|
|
277
|
+
payloadVariant: activeAttempt.kind
|
|
203
278
|
});
|
|
279
|
+
let attemptResponse;
|
|
280
|
+
try {
|
|
281
|
+
attemptResponse = await fetch(resolveCodexUrl(model.baseUrl), {
|
|
282
|
+
method: "POST",
|
|
283
|
+
headers: sseHeaders,
|
|
284
|
+
body: sseBody,
|
|
285
|
+
signal: activeSignal
|
|
286
|
+
});
|
|
287
|
+
} catch (error) {
|
|
288
|
+
if (error instanceof Error) {
|
|
289
|
+
if (isRequestTimeoutError(error, options?.signal, requestTimeoutSignal, requestTimeoutMs) && requestTimeoutMs !== void 0) throw formatRequestTimeoutError(requestTimeoutMs, error);
|
|
290
|
+
if (error.name === "AbortError" || error.message === "Request was aborted") throw new Error("Request was aborted", { cause: error });
|
|
291
|
+
if (error.name === "TimeoutError" && requestTimeoutMs !== void 0) throw new Error(`Request timed out after ${requestTimeoutMs}ms`, { cause: error });
|
|
292
|
+
}
|
|
293
|
+
const tlsCertificateError = inspectTlsCertificateError(error);
|
|
294
|
+
const lastError = toErrorObject(error, String(error));
|
|
295
|
+
if (attempt < maxRetries && !lastError.message.includes("usage limit") && !tlsCertificateError) {
|
|
296
|
+
await sleepWithAbort(BASE_DELAY_MS * 2 ** attempt, activeSignal);
|
|
297
|
+
continue;
|
|
298
|
+
}
|
|
299
|
+
throw lastError;
|
|
300
|
+
}
|
|
204
301
|
response = attemptResponse;
|
|
205
|
-
await options?.onResponse?.({
|
|
206
|
-
status: attemptResponse.status,
|
|
207
|
-
headers: headersToRecord(attemptResponse.headers)
|
|
208
|
-
}, model);
|
|
209
302
|
if (attemptResponse.ok) break;
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
303
|
+
const hookStream = withFirstStreamEventTimeout(withProviderResponseHook({
|
|
304
|
+
signal: firstEventAbort.signal,
|
|
305
|
+
abort: firstEventAbort.abort,
|
|
306
|
+
hook: createOpenAIResponseHook(options?.onResponse, attemptResponse, model)
|
|
307
|
+
}), {
|
|
308
|
+
provider: model.provider,
|
|
309
|
+
api: model.api,
|
|
310
|
+
model: model.id,
|
|
311
|
+
timeoutMs: getFirstStreamEventTimeoutMs(options) ?? 0,
|
|
312
|
+
stage: "responses",
|
|
313
|
+
abort: firstEventAbort.abort,
|
|
314
|
+
onTimeout: getFirstStreamEventTimeoutHandler(options)
|
|
315
|
+
});
|
|
316
|
+
const [errorText] = await Promise.all([readChatGptResponsesErrorTextLimited(attemptResponse, activeSignal), hookStream[Symbol.asyncIterator]().next()]);
|
|
317
|
+
if (attempt < maxRetries && isRetryableError(attemptResponse.status, errorText)) {
|
|
318
|
+
await sleepWithAbort(resolveHttpRetryDelayMs(attemptResponse, attempt), activeSignal);
|
|
221
319
|
continue;
|
|
222
320
|
}
|
|
223
|
-
|
|
321
|
+
const info = parseErrorResponseText(errorText, attemptResponse.status, attemptResponse.statusText);
|
|
322
|
+
terminalResponseError = new CodexApiError(info.friendlyMessage || info.message, { code: info.code });
|
|
323
|
+
break;
|
|
224
324
|
}
|
|
225
|
-
if (
|
|
226
|
-
|
|
227
|
-
|
|
325
|
+
if (response?.ok) {
|
|
326
|
+
if (!response.body) throw new Error("No response body");
|
|
327
|
+
if (activeSignal?.aborted) throw transportAbortError(activeSignal);
|
|
328
|
+
commitSemanticAttempt(activeAttempt);
|
|
329
|
+
break;
|
|
228
330
|
}
|
|
229
|
-
|
|
230
|
-
|
|
331
|
+
if (activeSignal?.aborted) throw transportAbortError(activeSignal);
|
|
332
|
+
const nextSemanticAttempt = terminalResponseError ? await resolveNextResponsesEncryptedContentAttempt(activeAttempt, terminalResponseError, { buildFullHistoryRequest: () => buildBody("full-history") }) : void 0;
|
|
333
|
+
if (!nextSemanticAttempt) throw terminalResponseError ?? /* @__PURE__ */ new Error("Failed after retries");
|
|
334
|
+
semanticAttempt = nextSemanticAttempt;
|
|
231
335
|
}
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
336
|
+
await processResponsesStream(withProviderResponseHook({
|
|
337
|
+
stream: mapCodexEvents(parseOpenAIChatGptResponsesSse(response)),
|
|
338
|
+
signal: firstEventAbort.signal,
|
|
339
|
+
abort: firstEventAbort.abort,
|
|
340
|
+
hook: createOpenAIResponseHook(options?.onResponse, response, model),
|
|
341
|
+
onReady: () => stream.push({
|
|
342
|
+
type: "start",
|
|
343
|
+
partial: output
|
|
344
|
+
})
|
|
345
|
+
}), output, stream, model, {
|
|
346
|
+
serviceTier: options?.serviceTier,
|
|
347
|
+
firstEventTimeoutMs: getFirstStreamEventTimeoutMs(options),
|
|
348
|
+
abortFirstEventStream: firstEventAbort.abort,
|
|
349
|
+
onFirstEventTimeout: getFirstStreamEventTimeoutHandler(options),
|
|
350
|
+
signal: options?.signal,
|
|
351
|
+
reasoningReplayMetadata: buildOpenAIResponsesReasoningReplayMetadata(model, {
|
|
352
|
+
sessionId: options?.sessionId,
|
|
353
|
+
authProfileId: options?.authProfileId
|
|
354
|
+
}),
|
|
355
|
+
resolveServiceTier: resolveCodexServiceTier,
|
|
356
|
+
applyServiceTierPricing: (usage, serviceTier) => applyResponsesServiceTierPricing(usage, serviceTier, model)
|
|
237
357
|
});
|
|
238
|
-
await processStream(response, output, stream, model, options, firstEventAbort.abort);
|
|
239
358
|
if (activeSignal?.aborted) throw transportAbortError(activeSignal);
|
|
240
359
|
if (output.stopReason === "aborted" || output.stopReason === "error") throw new Error(output.errorMessage ?? "An unknown error occurred");
|
|
241
360
|
stream.push({
|
|
@@ -247,11 +366,11 @@ const streamOpenAICodexResponses = (model, context, options) => {
|
|
|
247
366
|
} catch (error) {
|
|
248
367
|
const normalizedError = isRequestTimeoutError(error, options?.signal, requestTimeoutSignal, requestTimeoutMs) && requestTimeoutMs !== void 0 ? formatRequestTimeoutError(requestTimeoutMs, error) : error;
|
|
249
368
|
for (const block of output.content) delete block.partialJson;
|
|
250
|
-
|
|
251
|
-
output
|
|
369
|
+
const terminal = projectProviderError(normalizedError, options?.signal);
|
|
370
|
+
Object.assign(output, terminal);
|
|
252
371
|
stream.push({
|
|
253
372
|
type: "error",
|
|
254
|
-
reason:
|
|
373
|
+
reason: terminal.stopReason,
|
|
255
374
|
error: output
|
|
256
375
|
});
|
|
257
376
|
stream.end();
|
|
@@ -266,15 +385,19 @@ const streamSimpleOpenAICodexResponses = (model, context, options) => {
|
|
|
266
385
|
if (!apiKey) throw new Error(`No API key for provider: ${model.provider}`);
|
|
267
386
|
const resolvedOptions = {
|
|
268
387
|
...buildBaseOptions(model, options, apiKey),
|
|
388
|
+
authProfileId: options?.authProfileId,
|
|
269
389
|
reasoningEffort: resolveResponsesReasoningEffort(model, options?.reasoning)
|
|
270
390
|
};
|
|
271
391
|
responsesPromptObserver.copy(options, resolvedOptions);
|
|
272
392
|
return streamOpenAICodexResponses(model, context, resolvedOptions);
|
|
273
393
|
};
|
|
274
|
-
function buildRequestBody(model, context, options) {
|
|
394
|
+
function buildRequestBody(model, context, options, replayMode = "checkpoint") {
|
|
275
395
|
const messages = convertResponsesMessages(model, context, CODEX_TOOL_CALL_PROVIDERS, {
|
|
276
396
|
includeSystemPrompt: false,
|
|
277
|
-
replayResponsesItemIds: false
|
|
397
|
+
replayResponsesItemIds: false,
|
|
398
|
+
sessionId: options?.sessionId,
|
|
399
|
+
authProfileId: options?.authProfileId,
|
|
400
|
+
replayMode
|
|
278
401
|
});
|
|
279
402
|
const body = {
|
|
280
403
|
model: model.id,
|
|
@@ -321,17 +444,6 @@ function resolveCodexWebSocketUrl(baseUrl) {
|
|
|
321
444
|
if (url.protocol === "http:") url.protocol = "ws:";
|
|
322
445
|
return url.toString();
|
|
323
446
|
}
|
|
324
|
-
async function processStream(response, output, stream, model, options, abortFirstEventStream) {
|
|
325
|
-
await processResponsesStream(mapCodexEvents(parseSSE(response)), output, stream, model, {
|
|
326
|
-
serviceTier: options?.serviceTier,
|
|
327
|
-
firstEventTimeoutMs: getFirstStreamEventTimeoutMs(options),
|
|
328
|
-
abortFirstEventStream,
|
|
329
|
-
onFirstEventTimeout: getFirstStreamEventTimeoutHandler(options),
|
|
330
|
-
signal: options?.signal,
|
|
331
|
-
resolveServiceTier: resolveCodexServiceTier,
|
|
332
|
-
applyServiceTierPricing: (usage, serviceTier) => applyResponsesServiceTierPricing(usage, serviceTier, model)
|
|
333
|
-
});
|
|
334
|
-
}
|
|
335
447
|
var CodexApiError = class extends Error {
|
|
336
448
|
constructor(message, options) {
|
|
337
449
|
super(message);
|
|
@@ -341,14 +453,6 @@ var CodexApiError = class extends Error {
|
|
|
341
453
|
this.cause = options?.cause;
|
|
342
454
|
}
|
|
343
455
|
};
|
|
344
|
-
var CodexProtocolError = class extends Error {
|
|
345
|
-
constructor(message, options) {
|
|
346
|
-
super(message);
|
|
347
|
-
this.name = "CodexProtocolError";
|
|
348
|
-
this.payload = options?.payload;
|
|
349
|
-
this.cause = options?.cause;
|
|
350
|
-
}
|
|
351
|
-
};
|
|
352
456
|
function isCodexNonTransportError(error) {
|
|
353
457
|
return error instanceof CodexApiError || error instanceof CodexProtocolError || error instanceof ResponsesStreamFailure;
|
|
354
458
|
}
|
|
@@ -393,53 +497,6 @@ function normalizeCodexStatus(status) {
|
|
|
393
497
|
if (typeof status !== "string") return;
|
|
394
498
|
return CODEX_RESPONSE_STATUSES.has(status) ? status : void 0;
|
|
395
499
|
}
|
|
396
|
-
async function* parseSSE(response) {
|
|
397
|
-
if (!response.body) return;
|
|
398
|
-
const reader = response.body.getReader();
|
|
399
|
-
const guard = createSseByteGuard(reader, {
|
|
400
|
-
maxBytes: OPENAI_CHATGPT_RESPONSES_SUCCESS_BODY_MAX_BYTES,
|
|
401
|
-
onOverflow: ({ size, maxBytes }) => /* @__PURE__ */ new Error(`OpenAI ChatGPT Responses success body exceeded ${maxBytes} bytes (received ${size})`)
|
|
402
|
-
});
|
|
403
|
-
const decoder = new TextDecoder();
|
|
404
|
-
let buffer = "";
|
|
405
|
-
try {
|
|
406
|
-
while (true) {
|
|
407
|
-
const { done, value } = await guard.read();
|
|
408
|
-
if (value) buffer += decoder.decode(value, { stream: true });
|
|
409
|
-
if (done) buffer += decoder.decode();
|
|
410
|
-
while (true) {
|
|
411
|
-
const searchable = !done && buffer.endsWith("\r") && !buffer.endsWith("\r\r") && !buffer.endsWith("\n\r") ? buffer.slice(0, -1) : buffer;
|
|
412
|
-
const boundary = /(?:\r\n|\r(?!\n)|\n)(?:\r\n|\r(?!\n)|\n)/.exec(searchable);
|
|
413
|
-
if (!boundary) break;
|
|
414
|
-
const chunk = buffer.slice(0, boundary.index);
|
|
415
|
-
buffer = buffer.slice(boundary.index + boundary[0].length);
|
|
416
|
-
const dataLines = chunk.split(/\r\n|\r|\n/).filter((l) => l.startsWith("data:")).map((l) => l.slice(5).trim());
|
|
417
|
-
if (dataLines.length > 0) {
|
|
418
|
-
const data = dataLines.join("\n").trim();
|
|
419
|
-
if (data && data !== "[DONE]") {
|
|
420
|
-
let event;
|
|
421
|
-
try {
|
|
422
|
-
event = JSON.parse(data);
|
|
423
|
-
} catch (cause) {
|
|
424
|
-
if (!(cause instanceof SyntaxError)) throw cause;
|
|
425
|
-
throw new CodexProtocolError(MALFORMED_STREAMING_FRAGMENT_ERROR_MESSAGE, { cause });
|
|
426
|
-
}
|
|
427
|
-
yield event;
|
|
428
|
-
}
|
|
429
|
-
}
|
|
430
|
-
}
|
|
431
|
-
if (done) break;
|
|
432
|
-
}
|
|
433
|
-
} finally {
|
|
434
|
-
try {
|
|
435
|
-
await guard.cancel();
|
|
436
|
-
} catch {}
|
|
437
|
-
try {
|
|
438
|
-
reader.releaseLock();
|
|
439
|
-
} catch {}
|
|
440
|
-
}
|
|
441
|
-
}
|
|
442
|
-
const parseSSEForTest = parseSSE;
|
|
443
500
|
const OPENAI_BETA_RESPONSES_WEBSOCKETS = "responses_websockets=2026-02-06";
|
|
444
501
|
const SESSION_WEBSOCKET_CACHE_TTL_MS = 300 * 1e3;
|
|
445
502
|
const SESSION_WEBSOCKET_MAX_AGE_MS = 3300 * 1e3;
|
|
@@ -829,7 +886,7 @@ async function* startWebSocketOutputOnFirstEvent(events, output, stream, onStart
|
|
|
829
886
|
yield event;
|
|
830
887
|
}
|
|
831
888
|
}
|
|
832
|
-
async function processWebSocketStream(url, body, headers, output, stream, model, onStart, options, abortFirstEventStream, observePromptEgress) {
|
|
889
|
+
async function processWebSocketStream(url, body, headers, output, stream, model, onStart, options, abortFirstEventStream, observePromptEgress, payloadVariant = "initial", onRequestSent) {
|
|
833
890
|
const { socket, entry, release } = await acquireWebSocket(url, headers, options?.sessionId, options?.signal);
|
|
834
891
|
let keepConnection = true;
|
|
835
892
|
const useCachedContext = options?.transport === "websocket-cached" || options?.transport === "auto";
|
|
@@ -839,18 +896,23 @@ async function processWebSocketStream(url, body, headers, output, stream, model,
|
|
|
839
896
|
if (options?.signal?.aborted) throw transportAbortError(options.signal);
|
|
840
897
|
observePromptEgress?.(requestBody, {
|
|
841
898
|
egress: "native-codex-websocket",
|
|
842
|
-
payloadVariant
|
|
899
|
+
payloadVariant
|
|
843
900
|
});
|
|
844
901
|
socket.send(JSON.stringify({
|
|
845
902
|
type: "response.create",
|
|
846
903
|
...requestBody
|
|
847
904
|
}));
|
|
905
|
+
onRequestSent?.();
|
|
848
906
|
await processResponsesStream(startWebSocketOutputOnFirstEvent(mapCodexEvents(parseWebSocket(socket, options?.signal)), output, stream, onStart), output, stream, model, {
|
|
849
907
|
serviceTier: options?.serviceTier,
|
|
850
908
|
firstEventTimeoutMs: getFirstStreamEventTimeoutMs(options),
|
|
851
909
|
abortFirstEventStream,
|
|
852
910
|
onFirstEventTimeout: getFirstStreamEventTimeoutHandler(options),
|
|
853
911
|
signal: options?.signal,
|
|
912
|
+
reasoningReplayMetadata: buildOpenAIResponsesReasoningReplayMetadata(model, {
|
|
913
|
+
sessionId: options?.sessionId,
|
|
914
|
+
authProfileId: options?.authProfileId
|
|
915
|
+
}),
|
|
854
916
|
resolveServiceTier: resolveCodexServiceTier,
|
|
855
917
|
applyServiceTierPricing: (usage, serviceTier) => applyResponsesServiceTierPricing(usage, serviceTier, model)
|
|
856
918
|
});
|
|
@@ -858,7 +920,9 @@ async function processWebSocketStream(url, body, headers, output, stream, model,
|
|
|
858
920
|
else if (useCachedContext && entry && output.responseId) {
|
|
859
921
|
const responseItems = convertResponsesMessages(model, { messages: [output] }, CODEX_TOOL_CALL_PROVIDERS, {
|
|
860
922
|
includeSystemPrompt: false,
|
|
861
|
-
replayResponsesItemIds: false
|
|
923
|
+
replayResponsesItemIds: false,
|
|
924
|
+
sessionId: options?.sessionId,
|
|
925
|
+
authProfileId: options?.authProfileId
|
|
862
926
|
}).filter((item) => item.type !== "function_call_output");
|
|
863
927
|
entry.continuation = {
|
|
864
928
|
lastRequestBody: fullBody,
|
|
@@ -874,17 +938,31 @@ async function processWebSocketStream(url, body, headers, output, stream, model,
|
|
|
874
938
|
release({ keep: keepConnection });
|
|
875
939
|
}
|
|
876
940
|
}
|
|
877
|
-
async function readChatGptResponsesErrorTextLimited(response) {
|
|
941
|
+
async function readChatGptResponsesErrorTextLimited(response, signal) {
|
|
878
942
|
const reader = response.body?.getReader();
|
|
879
943
|
if (!reader) return "";
|
|
880
944
|
const decoder = new TextDecoder();
|
|
881
945
|
let total = 0;
|
|
882
946
|
let text = "";
|
|
883
947
|
let reachedLimit = false;
|
|
948
|
+
let completed = false;
|
|
949
|
+
let cancelPromise;
|
|
950
|
+
const cancel = () => {
|
|
951
|
+
cancelPromise ??= reader.cancel(signal?.reason).catch(() => {});
|
|
952
|
+
return cancelPromise;
|
|
953
|
+
};
|
|
954
|
+
const onAbort = () => {
|
|
955
|
+
cancel();
|
|
956
|
+
};
|
|
957
|
+
if (signal?.aborted) onAbort();
|
|
958
|
+
else signal?.addEventListener("abort", onAbort, { once: true });
|
|
884
959
|
try {
|
|
885
960
|
while (true) {
|
|
886
961
|
const { value, done } = await reader.read();
|
|
887
|
-
if (done)
|
|
962
|
+
if (done) {
|
|
963
|
+
completed = true;
|
|
964
|
+
break;
|
|
965
|
+
}
|
|
888
966
|
if (!value || value.byteLength === 0) continue;
|
|
889
967
|
const remaining = OPENAI_CHATGPT_RESPONSES_ERROR_BODY_MAX_BYTES - total;
|
|
890
968
|
if (remaining <= 0) {
|
|
@@ -901,7 +979,8 @@ async function readChatGptResponsesErrorTextLimited(response) {
|
|
|
901
979
|
}
|
|
902
980
|
if (!reachedLimit) text += decoder.decode();
|
|
903
981
|
} finally {
|
|
904
|
-
|
|
982
|
+
signal?.removeEventListener("abort", onAbort);
|
|
983
|
+
if (!completed) await cancel();
|
|
905
984
|
try {
|
|
906
985
|
reader.releaseLock();
|
|
907
986
|
} catch {}
|
|
@@ -911,11 +990,12 @@ async function readChatGptResponsesErrorTextLimited(response) {
|
|
|
911
990
|
function parseErrorResponseText(raw, status, statusText) {
|
|
912
991
|
let message = raw || statusText || "Request failed";
|
|
913
992
|
let friendlyMessage;
|
|
993
|
+
let code;
|
|
914
994
|
try {
|
|
915
995
|
const err = JSON.parse(raw)?.error;
|
|
916
996
|
if (err) {
|
|
917
|
-
|
|
918
|
-
if (/usage_limit_reached|usage_not_included|rate_limit_exceeded/i.test(code) || status === 429) {
|
|
997
|
+
code = err.code || err.type || void 0;
|
|
998
|
+
if (/usage_limit_reached|usage_not_included|rate_limit_exceeded/i.test(code ?? "") || status === 429) {
|
|
919
999
|
const plan = err.plan_type ? ` (${err.plan_type.toLowerCase()} plan)` : "";
|
|
920
1000
|
const mins = err.resets_at ? Math.max(0, Math.round((err.resets_at * 1e3 - Date.now()) / 6e4)) : void 0;
|
|
921
1001
|
friendlyMessage = `You have hit your ChatGPT usage limit${plan}.${mins !== void 0 ? ` Try again in ~${mins} min.` : ""}`.trim();
|
|
@@ -924,6 +1004,7 @@ function parseErrorResponseText(raw, status, statusText) {
|
|
|
924
1004
|
}
|
|
925
1005
|
} catch {}
|
|
926
1006
|
return {
|
|
1007
|
+
...code ? { code } : {},
|
|
927
1008
|
message,
|
|
928
1009
|
friendlyMessage
|
|
929
1010
|
};
|
|
@@ -975,4 +1056,4 @@ function buildWebSocketHeaders(initHeaders, additionalHeaders, accountId, token,
|
|
|
975
1056
|
return headers;
|
|
976
1057
|
}
|
|
977
1058
|
//#endregion
|
|
978
|
-
export { closeOpenAICodexWebSocketSessions, extractOpenAICodexAccountId,
|
|
1059
|
+
export { closeOpenAICodexWebSocketSessions, extractOpenAICodexAccountId, resetOpenAICodexWebSocketStateForTest, streamOpenAICodexResponses, streamSimpleOpenAICodexResponses };
|