@openclaw/ai 2026.7.2-beta.7 → 2026.8.1-beta.1

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.
Files changed (57) hide show
  1. package/dist/{anthropic-CH4UUnZr.mjs → anthropic-CE-7SkF6.mjs} +28 -191
  2. package/dist/{anthropic-usage-DWU-x8MI.mjs → anthropic-usage-Ma4iX6uG.mjs} +262 -4
  3. package/dist/{api-registry-DlMgPR39.d.mts → api-registry-EpJoVwM1.d.mts} +1 -1
  4. package/dist/{azure-openai-responses-CImcwB83.mjs → azure-openai-responses-Cc_kasye.mjs} +4 -4
  5. package/dist/{event-stream-D8n2uFee.mjs → event-stream-CEV9t6da.mjs} +10 -2
  6. package/dist/{event-stream-YjaPW20U.d.mts → event-stream-DRmDMRHH.d.mts} +2 -1
  7. package/dist/event-stream.d.mts +1 -1
  8. package/dist/event-stream.mjs +1 -1
  9. package/dist/{google-CtSg0iTS.mjs → google-CGQu21aw.mjs} +5 -5
  10. package/dist/{google-shared-DNBz5rcD.mjs → google-shared-Cq2UKx1l.mjs} +151 -85
  11. package/dist/{google-vertex-31f1uS9L.mjs → google-vertex-CusxWzvE.mjs} +10 -7
  12. package/dist/{host-Dog2WQiR.mjs → host-Bl7Kgddo.mjs} +40 -2
  13. package/dist/{host-B9GUmcra.d.mts → host-Dn4_SZI2.d.mts} +2 -2
  14. package/dist/index.d.mts +5 -5
  15. package/dist/index.mjs +2 -2
  16. package/dist/internal/anthropic.d.mts +19 -3
  17. package/dist/internal/anthropic.mjs +4 -4
  18. package/dist/internal/openai.d.mts +4 -4
  19. package/dist/internal/openai.mjs +7 -7
  20. package/dist/internal/runtime.d.mts +2 -2
  21. package/dist/internal/runtime.mjs +3 -3
  22. package/dist/internal/shared.d.mts +1 -1
  23. package/dist/internal/shared.mjs +3 -4
  24. package/dist/{mistral-CWmpvWYh.mjs → mistral-Dx6VzNjf.mjs} +25 -9
  25. package/dist/model-utils-Dau5dlgm.mjs +64 -0
  26. package/dist/number-coercion-1Miyb5MO.mjs +66 -0
  27. package/dist/{openai-chatgpt-responses-B84Ibtrd.mjs → openai-chatgpt-responses-SC9m0FSf.mjs} +94 -131
  28. package/dist/{openai-completions-DsOxhOD1.mjs → openai-completions-BaIpl93j.mjs} +47 -66
  29. package/dist/{openai-reasoning-compat-YgeLncHw.mjs → openai-reasoning-compat-DKebnIBL.mjs} +147 -6
  30. package/dist/{openai-responses-BT7A3sLu.mjs → openai-responses-Bdx3V_Yu.mjs} +6 -22
  31. package/dist/openai-responses-contracts-BBKBfAqR.d.mts +116 -0
  32. package/dist/openai-responses-prompt-observer-internal-DDZPxRfr.mjs +46 -0
  33. package/dist/{openai-responses-shared-pXl6Wd8S.mjs → openai-responses-shared-CCyMvg7M.mjs} +21 -10
  34. package/dist/{openai-responses-stream-internal-Cw5txaGW.mjs → openai-responses-stream-internal-Bl8YyVtF.mjs} +244 -81
  35. package/dist/{openai-tool-projection-OhX64DoP.mjs → openai-transport-shared-Cipt7egQ.mjs} +129 -29
  36. package/dist/{provider-error-CAEvRjry.mjs → provider-error-DI0Ts28U.mjs} +1 -1
  37. package/dist/{provider-options-D8bB3z9b.d.mts → provider-options-C5kYML7i.d.mts} +1 -1
  38. package/dist/providers.d.mts +1 -1
  39. package/dist/providers.mjs +9 -9
  40. package/dist/{stream-first-event-timeout-BBys9hSb.mjs → stream-first-event-timeout-BIBomOGq.mjs} +1 -1
  41. package/dist/{tool-result-text-CTpIRbYd.mjs → tool-result-text-Dvkp2Dus.mjs} +51 -2
  42. package/dist/{tool-schema-json-projection-BwNu3nDi.mjs → tool-schema-json-projection-B1b-XCn5.mjs} +28 -1
  43. package/dist/transform-messages-DfjpNXNQ.mjs +2 -0
  44. package/dist/{transport-stream-shared-D81p90xq.mjs → transport-stream-shared-CPNv7A3r.mjs} +4 -4
  45. package/dist/transports.d.mts +41 -73
  46. package/dist/transports.mjs +317 -601
  47. package/dist/{types-bzp5k29J.d.mts → types-CH7ReIcU.d.mts} +4 -0
  48. package/dist/types.d.mts +3 -3
  49. package/dist/types.mjs +1 -1
  50. package/dist/{validation-B-j7cOYp.d.mts → validation-CcPcuEbR.d.mts} +1 -1
  51. package/dist/validation.d.mts +1 -1
  52. package/package.json +1 -1
  53. package/dist/error-coercion-DgxlWC0n.mjs +0 -15
  54. package/dist/number-coercion-DvG7SNMg.mjs +0 -129
  55. package/dist/openai-completions-compat-DBWjXoMZ.d.mts +0 -43
  56. package/dist/simple-options-9lhRrN73.mjs +0 -50
  57. package/dist/transform-messages-C8mBqZxF.mjs +0 -2
@@ -1,18 +1,17 @@
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-D8n2uFee.mjs";
4
- import { n as getAiTransportHost, r as resolveAiTransportHeaderSentinels } from "./host-Dog2WQiR.mjs";
3
+ import { t as AssistantMessageEventStream } from "./event-stream-CEV9t6da.mjs";
4
+ import { n as getAiTransportHost, r as resolveAiTransportHeaderSentinels } from "./host-Bl7Kgddo.mjs";
5
5
  import { n as clampOpenAIPromptCacheKey } from "./openai-prompt-cache-mZTCdRPo.mjs";
6
- import { d as stripSystemPromptCacheBoundary } from "./tool-result-text-CTpIRbYd.mjs";
7
- import { t as toErrorObject } from "./error-coercion-DgxlWC0n.mjs";
8
- import { n as clampTimerTimeoutMs, o as resolveTimerTimeoutMs } from "./number-coercion-DvG7SNMg.mjs";
6
+ import { c as buildBaseOptions, h as stripSystemPromptCacheBoundary } from "./tool-result-text-Dvkp2Dus.mjs";
7
+ import { n as toErrorObject, t as createResponsesPromptEgressObserver } from "./openai-responses-prompt-observer-internal-DDZPxRfr.mjs";
8
+ import { B as responsesPromptObserver, n as processResponsesStream, pt as supportsOpenAITemperature, t as ResponsesStreamFailure } from "./openai-responses-stream-internal-Bl8YyVtF.mjs";
9
+ import { n as clampTimerTimeoutMs, o as resolveTimerTimeoutMs } from "./number-coercion-1Miyb5MO.mjs";
9
10
  import { parseRetryAfterHttpDateMs } from "./internal/retry-after.mjs";
10
- import { d as transportAbortError } from "./transport-stream-shared-D81p90xq.mjs";
11
- import { _t as supportsOpenAITemperature, n as processResponsesStream } from "./openai-responses-stream-internal-Cw5txaGW.mjs";
12
- import { i as getFirstStreamEventTimeoutMs, r as getFirstStreamEventTimeoutHandler, t as createFirstStreamEventAbortController } from "./stream-first-event-timeout-BBys9hSb.mjs";
11
+ import { d as transportAbortError, f as MALFORMED_STREAMING_FRAGMENT_ERROR_MESSAGE } from "./transport-stream-shared-CPNv7A3r.mjs";
12
+ import { i as getFirstStreamEventTimeoutMs, r as getFirstStreamEventTimeoutHandler, t as createFirstStreamEventAbortController } from "./stream-first-event-timeout-BIBomOGq.mjs";
13
13
  import { t as headersToRecord } from "./headers-B_e4-1J0.mjs";
14
- import { n as buildBaseOptions } from "./simple-options-9lhRrN73.mjs";
15
- import { i as resolveResponsesReasoningEffort, n as convertResponsesMessages, o as convertResponsesToolPayload } from "./openai-responses-shared-pXl6Wd8S.mjs";
14
+ import { a as resolveResponsesReasoningEffort, i as createResponsesAssistantOutput, n as applyResponsesServiceTierPricing, r as convertResponsesMessages, s as convertResponsesToolPayload } from "./openai-responses-shared-CCyMvg7M.mjs";
16
15
  import { i as registerSessionResourceCleanup, n as resolveOpenAICodexAccountId } from "./openai-chatgpt-jwt-DhAAzLkj.mjs";
17
16
  import { t as createSseByteGuard } from "./streaming-byte-guard-BrbkbwUu.mjs";
18
17
  import { t as inspectTlsCertificateError } from "./tls-certificate-errors-DXSpluKI.mjs";
@@ -116,29 +115,7 @@ const streamOpenAICodexResponses = (model, context, options) => {
116
115
  let requestTimeoutSignal;
117
116
  let activeSignal;
118
117
  let firstEventAbort;
119
- const output = {
120
- role: "assistant",
121
- content: [],
122
- api: "openai-chatgpt-responses",
123
- provider: model.provider,
124
- model: model.id,
125
- usage: {
126
- input: 0,
127
- output: 0,
128
- cacheRead: 0,
129
- cacheWrite: 0,
130
- totalTokens: 0,
131
- cost: {
132
- input: 0,
133
- output: 0,
134
- cacheRead: 0,
135
- cacheWrite: 0,
136
- total: 0
137
- }
138
- },
139
- stopReason: "stop",
140
- timestamp: Date.now()
141
- };
118
+ const output = createResponsesAssistantOutput(model);
142
119
  try {
143
120
  const unresolvedApiKey = options?.apiKey || getEnvApiKey(model.provider) || "";
144
121
  if (!unresolvedApiKey) throw new Error(`No API key for provider: ${model.provider}`);
@@ -149,6 +126,7 @@ const streamOpenAICodexResponses = (model, context, options) => {
149
126
  let body = buildRequestBody(model, context, options);
150
127
  const nextBody = await options?.onPayload?.(body, model);
151
128
  if (nextBody !== void 0) body = nextBody;
129
+ const observePromptEgress = createResponsesPromptEgressObserver(options, context.systemPrompt);
152
130
  const sessionId = clampOpenAIPromptCacheKey(options?.sessionId);
153
131
  requestTimeoutMs = resolveRequestTimeoutMs(options);
154
132
  requestTimeoutSignal = buildRequestSignal(options?.signal, requestTimeoutMs);
@@ -169,8 +147,9 @@ const streamOpenAICodexResponses = (model, context, options) => {
169
147
  try {
170
148
  await processWebSocketStream(resolveCodexWebSocketUrl(model.baseUrl), body, websocketHeaders, output, stream, model, () => {
171
149
  websocketStarted = true;
172
- }, requestOptions, firstEventAbort.abort);
150
+ }, requestOptions, firstEventAbort.abort, observePromptEgress);
173
151
  if (activeSignal?.aborted) throw transportAbortError(activeSignal);
152
+ if (output.stopReason === "aborted" || output.stopReason === "error") throw new CodexApiError(output.errorMessage ?? "An unknown error occurred");
174
153
  stream.push({
175
154
  type: "done",
176
155
  reason: output.stopReason,
@@ -212,6 +191,10 @@ const streamOpenAICodexResponses = (model, context, options) => {
212
191
  let attemptResponse;
213
192
  let errorText;
214
193
  try {
194
+ observePromptEgress?.(body, {
195
+ egress: "native-codex-sse",
196
+ payloadVariant: "initial"
197
+ });
215
198
  attemptResponse = await fetch(resolveCodexUrl(model.baseUrl), {
216
199
  method: "POST",
217
200
  headers: sseHeaders,
@@ -254,6 +237,7 @@ const streamOpenAICodexResponses = (model, context, options) => {
254
237
  });
255
238
  await processStream(response, output, stream, model, options, firstEventAbort.abort);
256
239
  if (activeSignal?.aborted) throw transportAbortError(activeSignal);
240
+ if (output.stopReason === "aborted" || output.stopReason === "error") throw new Error(output.errorMessage ?? "An unknown error occurred");
257
241
  stream.push({
258
242
  type: "done",
259
243
  reason: output.stopReason,
@@ -280,11 +264,12 @@ const streamOpenAICodexResponses = (model, context, options) => {
280
264
  const streamSimpleOpenAICodexResponses = (model, context, options) => {
281
265
  const apiKey = options?.apiKey || getEnvApiKey(model.provider);
282
266
  if (!apiKey) throw new Error(`No API key for provider: ${model.provider}`);
283
- const base = buildBaseOptions(model, options, apiKey);
284
- return streamOpenAICodexResponses(model, context, {
285
- ...base,
267
+ const resolvedOptions = {
268
+ ...buildBaseOptions(model, options, apiKey),
286
269
  reasoningEffort: resolveResponsesReasoningEffort(model, options?.reasoning)
287
- });
270
+ };
271
+ responsesPromptObserver.copy(options, resolvedOptions);
272
+ return streamOpenAICodexResponses(model, context, resolvedOptions);
288
273
  };
289
274
  function buildRequestBody(model, context, options) {
290
275
  const messages = convertResponsesMessages(model, context, CODEX_TOOL_CALL_PROVIDERS, {
@@ -299,21 +284,16 @@ function buildRequestBody(model, context, options) {
299
284
  input: messages,
300
285
  text: { verbosity: options?.textVerbosity || "low" },
301
286
  include: ["reasoning.encrypted_content"],
302
- prompt_cache_key: options?.cacheRetention === "none" ? void 0 : clampOpenAIPromptCacheKey(options?.promptCacheKey ?? options?.sessionId),
303
- tool_choice: "auto",
304
- parallel_tool_calls: true
287
+ prompt_cache_key: options?.cacheRetention === "none" ? void 0 : clampOpenAIPromptCacheKey(options?.promptCacheKey ?? options?.sessionId)
305
288
  };
306
289
  if (options?.temperature !== void 0 && supportsOpenAITemperature(model)) body.temperature = options.temperature;
307
290
  if (options?.serviceTier !== void 0) body.service_tier = options.serviceTier;
308
291
  if (context.tools) {
309
292
  const converted = convertResponsesToolPayload(context.tools, { strict: null });
310
- if (converted.projection.inputToolCount > 0 || converted.projection.diagnostics.length > 0) {
293
+ if (converted.tools.length > 0) {
311
294
  body.tools = converted.tools;
312
- if (body.tools.length === 0) {
313
- delete body.tools;
314
- delete body.tool_choice;
315
- delete body.parallel_tool_calls;
316
- }
295
+ body.tool_choice = "auto";
296
+ body.parallel_tool_calls = true;
317
297
  }
318
298
  }
319
299
  if (options?.reasoningEffort !== void 0) {
@@ -325,22 +305,6 @@ function buildRequestBody(model, context, options) {
325
305
  }
326
306
  return body;
327
307
  }
328
- function getServiceTierCostMultiplier(model, serviceTier) {
329
- switch (serviceTier) {
330
- case "flex": return .5;
331
- case "priority": return model.id === "gpt-5.5" ? 2.5 : 2;
332
- default: return 1;
333
- }
334
- }
335
- function applyServiceTierPricing(usage, serviceTier, model) {
336
- const multiplier = getServiceTierCostMultiplier(model, serviceTier);
337
- if (multiplier === 1) return;
338
- usage.cost.input *= multiplier;
339
- usage.cost.output *= multiplier;
340
- usage.cost.cacheRead *= multiplier;
341
- usage.cost.cacheWrite *= multiplier;
342
- usage.cost.total = usage.cost.input + usage.cost.output + usage.cost.cacheRead + usage.cost.cacheWrite;
343
- }
344
308
  function resolveCodexServiceTier(responseServiceTier, requestServiceTier) {
345
309
  if (responseServiceTier === "default" && (requestServiceTier === "flex" || requestServiceTier === "priority")) return requestServiceTier;
346
310
  return responseServiceTier ?? requestServiceTier;
@@ -365,7 +329,7 @@ async function processStream(response, output, stream, model, options, abortFirs
365
329
  onFirstEventTimeout: getFirstStreamEventTimeoutHandler(options),
366
330
  signal: options?.signal,
367
331
  resolveServiceTier: resolveCodexServiceTier,
368
- applyServiceTierPricing: (usage, serviceTier) => applyServiceTierPricing(usage, serviceTier, model)
332
+ applyServiceTierPricing: (usage, serviceTier) => applyResponsesServiceTierPricing(usage, serviceTier, model)
369
333
  });
370
334
  }
371
335
  var CodexApiError = class extends Error {
@@ -386,7 +350,7 @@ var CodexProtocolError = class extends Error {
386
350
  }
387
351
  };
388
352
  function isCodexNonTransportError(error) {
389
- return error instanceof CodexApiError || error instanceof CodexProtocolError;
353
+ return error instanceof CodexApiError || error instanceof CodexProtocolError || error instanceof ResponsesStreamFailure;
390
354
  }
391
355
  function isWebSocketConnectionLimitReachedError(error) {
392
356
  return error instanceof CodexApiError && error.code === WEBSOCKET_CONNECTION_LIMIT_REACHED_CODE;
@@ -409,15 +373,6 @@ async function* mapCodexEvents(events) {
409
373
  payload: event
410
374
  });
411
375
  }
412
- if (type === "response.failed") {
413
- const response = event.response;
414
- const code = response?.error?.code;
415
- const message = response?.error?.message;
416
- throw new CodexApiError(message || "Codex response failed", {
417
- code,
418
- payload: event
419
- });
420
- }
421
376
  if (type === "response.done" || type === "response.completed" || type === "response.incomplete") {
422
377
  const response = event.response;
423
378
  const normalizedResponse = response ? {
@@ -426,7 +381,7 @@ async function* mapCodexEvents(events) {
426
381
  } : response;
427
382
  yield {
428
383
  ...event,
429
- type: "response.completed",
384
+ type: type === "response.done" ? "response.completed" : type,
430
385
  response: normalizedResponse
431
386
  };
432
387
  return;
@@ -450,26 +405,30 @@ async function* parseSSE(response) {
450
405
  try {
451
406
  while (true) {
452
407
  const { done, value } = await guard.read();
453
- if (done) break;
454
- buffer += decoder.decode(value, { stream: true });
455
- let idx = buffer.indexOf("\n\n");
456
- while (idx !== -1) {
457
- const chunk = buffer.slice(0, idx);
458
- buffer = buffer.slice(idx + 2);
459
- const dataLines = chunk.split("\n").filter((l) => l.startsWith("data:")).map((l) => l.slice(5).trim());
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());
460
417
  if (dataLines.length > 0) {
461
418
  const data = dataLines.join("\n").trim();
462
- if (data && data !== "[DONE]") try {
463
- yield JSON.parse(data);
464
- } catch (cause) {
465
- throw new CodexProtocolError(`Invalid Codex SSE JSON: ${formatThrownValue(cause)}`, {
466
- cause,
467
- payload: data
468
- });
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;
469
428
  }
470
429
  }
471
- idx = buffer.indexOf("\n\n");
472
430
  }
431
+ if (done) break;
473
432
  }
474
433
  } finally {
475
434
  try {
@@ -497,6 +456,7 @@ function closeOpenAICodexWebSocketSessions(sessionId) {
497
456
  closeWebSocketSilently(entry.socket, 1e3, "debug_close");
498
457
  };
499
458
  if (sessionId) {
459
+ websocketSseFallbackSessions.delete(sessionId);
500
460
  const entry = websocketSessionCache.get(sessionId);
501
461
  if (entry) closeEntry(entry);
502
462
  websocketSessionCache.delete(sessionId);
@@ -504,6 +464,7 @@ function closeOpenAICodexWebSocketSessions(sessionId) {
504
464
  }
505
465
  for (const entry of websocketSessionCache.values()) closeEntry(entry);
506
466
  websocketSessionCache.clear();
467
+ websocketSseFallbackSessions.clear();
507
468
  }
508
469
  registerSessionResourceCleanup(closeOpenAICodexWebSocketSessions);
509
470
  function isWebSocketSseFallbackActive(sessionId) {
@@ -559,6 +520,13 @@ function closeWebSocketSilently(socket, code = 1e3, reason = "done") {
559
520
  function deleteOwnedWebSocketSession(sessionId, entry) {
560
521
  if (websocketSessionCache.get(sessionId) === entry) websocketSessionCache.delete(sessionId);
561
522
  }
523
+ function setOwnedWebSocketSession(sessionId, entry, expected) {
524
+ if (websocketSessionCache.get(sessionId) === expected) {
525
+ websocketSessionCache.set(sessionId, entry);
526
+ return true;
527
+ }
528
+ return false;
529
+ }
562
530
  function scheduleSessionWebSocketExpiry(sessionId, entry) {
563
531
  if (entry.idleTimer) clearTimeout(entry.idleTimer);
564
532
  entry.idleTimer = setTimeout(() => {
@@ -639,6 +607,7 @@ async function acquireWebSocket(url, headers, sessionId, signal) {
639
607
  };
640
608
  }
641
609
  const cached = websocketSessionCache.get(sessionId);
610
+ let expectedCacheValue = cached;
642
611
  if (cached) {
643
612
  if (cached.idleTimer) {
644
613
  clearTimeout(cached.idleTimer);
@@ -646,7 +615,8 @@ async function acquireWebSocket(url, headers, sessionId, signal) {
646
615
  }
647
616
  if (!cached.busy && isWebSocketSessionExpired(cached)) {
648
617
  closeWebSocketSilently(cached.socket, 1e3, "connection_age_limit");
649
- websocketSessionCache.delete(sessionId);
618
+ deleteOwnedWebSocketSession(sessionId, cached);
619
+ expectedCacheValue = void 0;
650
620
  } else if (!cached.busy && isWebSocketReusable(cached.socket)) {
651
621
  cached.busy = true;
652
622
  return {
@@ -674,7 +644,8 @@ async function acquireWebSocket(url, headers, sessionId, signal) {
674
644
  }
675
645
  if (!isWebSocketReusable(cached.socket)) {
676
646
  closeWebSocketSilently(cached.socket);
677
- websocketSessionCache.delete(sessionId);
647
+ deleteOwnedWebSocketSession(sessionId, cached);
648
+ expectedCacheValue = void 0;
678
649
  }
679
650
  }
680
651
  const socket = await connectWebSocket(url, headers, signal);
@@ -683,12 +654,12 @@ async function acquireWebSocket(url, headers, sessionId, signal) {
683
654
  busy: true,
684
655
  createdAt: Date.now()
685
656
  };
686
- websocketSessionCache.set(sessionId, entry);
657
+ const ownsCache = setOwnedWebSocketSession(sessionId, entry, expectedCacheValue);
687
658
  return {
688
659
  socket,
689
- entry,
660
+ entry: ownsCache ? entry : void 0,
690
661
  release: ({ keep } = {}) => {
691
- if (!keep || !isWebSocketReusable(entry.socket)) {
662
+ if (!ownsCache || !keep || !isWebSocketReusable(entry.socket)) {
692
663
  closeWebSocketSilently(entry.socket);
693
664
  if (entry.idleTimer) clearTimeout(entry.idleTimer);
694
665
  deleteOwnedWebSocketSession(sessionId, entry);
@@ -728,19 +699,6 @@ function extractWebSocketCloseError(event) {
728
699
  }
729
700
  return /* @__PURE__ */ new Error("WebSocket closed");
730
701
  }
731
- async function decodeWebSocketData(data) {
732
- if (typeof data === "string") return data;
733
- if (data instanceof ArrayBuffer) return new TextDecoder().decode(new Uint8Array(data));
734
- if (ArrayBuffer.isView(data)) {
735
- const view = data;
736
- return new TextDecoder().decode(new Uint8Array(view.buffer, view.byteOffset, view.byteLength));
737
- }
738
- if (data && typeof data === "object" && "arrayBuffer" in data) {
739
- const arrayBuffer = await data.arrayBuffer();
740
- return new TextDecoder().decode(new Uint8Array(arrayBuffer));
741
- }
742
- return null;
743
- }
744
702
  async function* parseWebSocket(socket, signal) {
745
703
  const queue = [];
746
704
  let pending = null;
@@ -754,29 +712,30 @@ async function* parseWebSocket(socket, signal) {
754
712
  resolve();
755
713
  };
756
714
  const onMessage = (event) => {
757
- (async () => {
758
- let text = null;
759
- try {
760
- if (!event || typeof event !== "object" || !("data" in event)) return;
761
- text = await decodeWebSocketData(event.data);
762
- if (!text) return;
763
- const parsed = JSON.parse(text);
764
- const type = typeof parsed.type === "string" ? parsed.type : "";
765
- if (type === "response.completed" || type === "response.done" || type === "response.incomplete") {
766
- sawCompletion = true;
767
- done = true;
768
- }
769
- queue.push(parsed);
770
- wake();
771
- } catch (cause) {
772
- failed = new CodexProtocolError(`Invalid Codex WebSocket JSON: ${formatThrownValue(cause)}`, {
773
- cause,
774
- payload: text
775
- });
715
+ const data = event && typeof event === "object" && "data" in event ? event.data : void 0;
716
+ if (typeof data !== "string") {
717
+ failed = new CodexProtocolError(MALFORMED_STREAMING_FRAGMENT_ERROR_MESSAGE, { payload: data });
718
+ done = true;
719
+ wake();
720
+ return;
721
+ }
722
+ try {
723
+ const parsed = JSON.parse(data);
724
+ const type = typeof parsed.type === "string" ? parsed.type : "";
725
+ if (type === "response.completed" || type === "response.done" || type === "response.incomplete") {
726
+ sawCompletion = true;
776
727
  done = true;
777
- wake();
778
728
  }
779
- })();
729
+ queue.push(parsed);
730
+ wake();
731
+ } catch (cause) {
732
+ failed = new CodexProtocolError(`Invalid Codex WebSocket JSON: ${formatThrownValue(cause)}`, {
733
+ cause,
734
+ payload: data
735
+ });
736
+ done = true;
737
+ wake();
738
+ }
780
739
  };
781
740
  const onError = (event) => {
782
741
  failed = extractWebSocketError(event);
@@ -870,7 +829,7 @@ async function* startWebSocketOutputOnFirstEvent(events, output, stream, onStart
870
829
  yield event;
871
830
  }
872
831
  }
873
- async function processWebSocketStream(url, body, headers, output, stream, model, onStart, options, abortFirstEventStream) {
832
+ async function processWebSocketStream(url, body, headers, output, stream, model, onStart, options, abortFirstEventStream, observePromptEgress) {
874
833
  const { socket, entry, release } = await acquireWebSocket(url, headers, options?.sessionId, options?.signal);
875
834
  let keepConnection = true;
876
835
  const useCachedContext = options?.transport === "websocket-cached" || options?.transport === "auto";
@@ -878,6 +837,10 @@ async function processWebSocketStream(url, body, headers, output, stream, model,
878
837
  const requestBody = useCachedContext && entry ? buildCachedWebSocketRequestBody(entry, fullBody) : fullBody;
879
838
  try {
880
839
  if (options?.signal?.aborted) throw transportAbortError(options.signal);
840
+ observePromptEgress?.(requestBody, {
841
+ egress: "native-codex-websocket",
842
+ payloadVariant: "initial"
843
+ });
881
844
  socket.send(JSON.stringify({
882
845
  type: "response.create",
883
846
  ...requestBody
@@ -889,7 +852,7 @@ async function processWebSocketStream(url, body, headers, output, stream, model,
889
852
  onFirstEventTimeout: getFirstStreamEventTimeoutHandler(options),
890
853
  signal: options?.signal,
891
854
  resolveServiceTier: resolveCodexServiceTier,
892
- applyServiceTierPricing: (usage, serviceTier) => applyServiceTierPricing(usage, serviceTier, model)
855
+ applyServiceTierPricing: (usage, serviceTier) => applyResponsesServiceTierPricing(usage, serviceTier, model)
893
856
  });
894
857
  if (options?.signal?.aborted) keepConnection = false;
895
858
  else if (useCachedContext && entry && output.responseId) {
@@ -1,21 +1,20 @@
1
1
  import { n as getEnvApiKey, r as __exportAll } from "./env-api-keys-DrgeBuva.mjs";
2
- import { t as AssistantMessageEventStream } from "./event-stream-D8n2uFee.mjs";
3
- import { n as getAiTransportHost } from "./host-Dog2WQiR.mjs";
2
+ import { t as AssistantMessageEventStream } from "./event-stream-CEV9t6da.mjs";
3
+ import { n as getAiTransportHost } from "./host-Bl7Kgddo.mjs";
4
+ import { r as clampThinkingLevel } from "./model-utils-Dau5dlgm.mjs";
4
5
  import { n as clampOpenAIPromptCacheKey } from "./openai-prompt-cache-mZTCdRPo.mjs";
5
6
  import { t as resolveCacheRetention } from "./cache-retention-0x979a5V.mjs";
6
- import { u as splitSystemPromptCacheBoundary } from "./tool-result-text-CTpIRbYd.mjs";
7
- import { n as reconcileOpenAICompletionsToolChoice, t as projectOpenAITools } from "./openai-tool-projection-OhX64DoP.mjs";
8
- import { c as calculateCost, l as clampThinkingLevel, s as applyProviderReportedUsageCost } from "./number-coercion-DvG7SNMg.mjs";
9
- import { a as resolveOpenAICompletionsCompat, c as clearPendingCommentaryText, l as rememberPendingCommentaryTags, n as mapOpenAIStopReason, o as resolveOpenAICompletionsResponseFormat, r as convertMessages, s as shouldOmitOllamaCompatResponseFormat, t as resolveOpenAIReasoningEffortMap, u as tagPendingCommentaryText } from "./openai-reasoning-compat-YgeLncHw.mjs";
7
+ import { c as buildBaseOptions, m as splitSystemPromptCacheBoundary } from "./tool-result-text-Dvkp2Dus.mjs";
8
+ import { a as convertMessages, c as resolveOpenAICompletionsResponseFormat, d as rememberPendingCommentaryTags, f as tagPendingCommentaryText, i as finalizeOpenAICompletionsToolCalls, l as shouldOmitOllamaCompatResponseFormat, n as mapOpenAIStopReason, r as createOpenAICompletionsToolCallDeltaNormalizer, s as resolveOpenAICompletionsCompat, t as resolveOpenAIReasoningEffortMap, u as clearPendingCommentaryText } from "./openai-reasoning-compat-DKebnIBL.mjs";
10
9
  import { n as parseStreamingJson } from "./json-parse-BvXNt1-7.mjs";
11
10
  import { t as notifyLlmRequestActivity } from "./llm-request-activity-BjtkplhG.mjs";
12
- import { d as transportAbortError } from "./transport-stream-shared-D81p90xq.mjs";
11
+ import { d as transportAbortError } from "./transport-stream-shared-CPNv7A3r.mjs";
12
+ import { a as parseOpenAICompletionsUsage, l as projectOpenAITools, o as readOpenAICompletionsContentDeltas, r as isOpenAICompletionsThinkingEnabled, u as reconcileOpenAICompletionsToolChoice } from "./openai-transport-shared-Cipt7egQ.mjs";
13
13
  import { t as createReasoningTagTextPartitioner } from "./reasoning-tag-text-partitioner-CGDyLWUR.mjs";
14
- import { a as withFirstStreamEventTimeout, i as getFirstStreamEventTimeoutMs, r as getFirstStreamEventTimeoutHandler, t as createFirstStreamEventAbortController } from "./stream-first-event-timeout-BBys9hSb.mjs";
14
+ import { a as withFirstStreamEventTimeout, i as getFirstStreamEventTimeoutMs, r as getFirstStreamEventTimeoutHandler, t as createFirstStreamEventAbortController } from "./stream-first-event-timeout-BIBomOGq.mjs";
15
15
  import { t as headersToRecord } from "./headers-B_e4-1J0.mjs";
16
- import { t as formatProviderError } from "./provider-error-CAEvRjry.mjs";
16
+ import { t as formatProviderError } from "./provider-error-DI0Ts28U.mjs";
17
17
  import { i as resolveCloudflareBaseUrl, n as hasCopilotVisionInput, r as isCloudflareProvider, t as buildCopilotDynamicHeaders } from "./github-copilot-headers-NCJtz9i0.mjs";
18
- import { n as buildBaseOptions } from "./simple-options-9lhRrN73.mjs";
19
18
  import OpenAI from "openai";
20
19
  //#region packages/ai/src/providers/openai-completions.ts
21
20
  var openai_completions_exports = /* @__PURE__ */ __exportAll({
@@ -100,6 +99,7 @@ const streamOpenAICompletions = (model, context, options) => {
100
99
  const toolCallBlocksByIndex = /* @__PURE__ */ new Map();
101
100
  const toolCallBlocksById = /* @__PURE__ */ new Map();
102
101
  const toolCallBlocksByFirstId = /* @__PURE__ */ new Map();
102
+ const normalizeToolCallDeltas = createOpenAICompletionsToolCallDeltaNormalizer();
103
103
  const pendingReasoningDetailsByToolCallId = /* @__PURE__ */ new Map();
104
104
  const blocks = output.content;
105
105
  const finishedBlocks = /* @__PURE__ */ new Set();
@@ -134,16 +134,12 @@ const streamOpenAICompletions = (model, context, options) => {
134
134
  content: block.thinking,
135
135
  partial: output
136
136
  });
137
- else if (block.type === "toolCall") {
138
- delete block.partialArgs;
139
- delete block.streamIndex;
140
- stream.push({
141
- type: "toolcall_end",
142
- contentIndex,
143
- toolCall: block,
144
- partial: output
145
- });
146
- }
137
+ else if (block.type === "toolCall") stream.push({
138
+ type: "toolcall_end",
139
+ contentIndex,
140
+ toolCall: block,
141
+ partial: output
142
+ });
147
143
  };
148
144
  const ensureTextBlock = () => {
149
145
  if (!textBlock) {
@@ -165,7 +161,7 @@ const streamOpenAICompletions = (model, context, options) => {
165
161
  thinkingBlock = {
166
162
  type: "thinking",
167
163
  thinking: "",
168
- thinkingSignature
164
+ ...thinkingSignature ? { thinkingSignature } : {}
169
165
  };
170
166
  appendBlock(thinkingBlock);
171
167
  stream.push({
@@ -258,26 +254,27 @@ const streamOpenAICompletions = (model, context, options) => {
258
254
  notifyLlmRequestActivity(options?.signal);
259
255
  output.responseId ||= chunk.id;
260
256
  if (typeof chunk.model === "string" && chunk.model.length > 0 && chunk.model !== model.id) output.responseModel ||= chunk.model;
261
- if (chunk.usage) output.usage = parseChunkUsage(chunk.usage, model);
257
+ if (chunk.usage) output.usage = parseOpenAICompletionsUsage(chunk.usage, model, { includeReasoningTokens: false });
262
258
  const choice = Array.isArray(chunk.choices) ? chunk.choices[0] : void 0;
263
259
  if (!choice) continue;
264
260
  const choiceUsage = choice.usage;
265
- if (!chunk.usage && choiceUsage) output.usage = parseChunkUsage(choiceUsage, model);
261
+ if (!chunk.usage && choiceUsage) output.usage = parseOpenAICompletionsUsage(choiceUsage, model, { includeReasoningTokens: false });
266
262
  if (choice.finish_reason) {
267
263
  const finishReasonResult = mapOpenAIStopReason(choice.finish_reason);
268
264
  output.stopReason = finishReasonResult.stopReason;
269
265
  if (finishReasonResult.errorMessage) output.errorMessage = finishReasonResult.errorMessage;
270
266
  hasFinishReason = true;
271
267
  }
272
- const choiceDelta = choice.delta ?? choice.message;
273
- if (choiceDelta) {
268
+ const rawChoiceDelta = choice.delta ?? choice.message;
269
+ if (rawChoiceDelta) for (const normalizedDelta of normalizeToolCallDeltas(rawChoiceDelta, choice.finish_reason)) {
270
+ const choiceDelta = normalizedDelta.delta;
274
271
  const reasoningFields = [
275
272
  "reasoning_content",
276
273
  "reasoning",
277
274
  "reasoning_text"
278
275
  ];
279
276
  const deltaFields = choiceDelta;
280
- const shouldEmitReasoning = Boolean(model.reasoning && options?.reasoningEffort);
277
+ const shouldEmitReasoning = Boolean(model.reasoning && options?.reasoningEffort && isOpenAICompletionsThinkingEnabled(options.reasoningEffort));
281
278
  let foundReasoningField = null;
282
279
  for (const field of reasoningFields) {
283
280
  const value = deltaFields[field];
@@ -291,14 +288,16 @@ const streamOpenAICompletions = (model, context, options) => {
291
288
  const delta = deltaFields[foundReasoningField];
292
289
  if (typeof delta === "string" && delta.length > 0) appendThinkingDelta(model.provider === "opencode-go" && foundReasoningField === "reasoning" ? "reasoning_content" : foundReasoningField, delta);
293
290
  }
294
- if (choiceDelta.content !== null && choiceDelta.content !== void 0 && choiceDelta.content.length > 0) appendPartitionedContent(choiceDelta.content, Boolean(foundReasoningField));
295
- const refusalText = typeof choiceDelta.refusal === "string" ? choiceDelta.refusal : "";
296
- if (refusalText.length > 0) appendPartitionedContent(refusalText, Boolean(foundReasoningField));
297
- if (choiceDelta.tool_calls && choiceDelta.tool_calls.length > 0) {
291
+ for (const contentDelta of readOpenAICompletionsContentDeltas(choiceDelta.content, choiceDelta.refusal, foundReasoningField ? [deltaFields[foundReasoningField]] : [])) if (contentDelta.kind === "thinking") {
292
+ if (reasoningTagTextPartitioner.hasPending()) reasoningTagTextPartitioner.markStrict();
293
+ if (shouldEmitReasoning) appendThinkingDelta(contentDelta.signature, contentDelta.text);
294
+ } else appendPartitionedContent(contentDelta.text, Boolean(foundReasoningField));
295
+ const toolCallDeltas = normalizedDelta.toolCalls;
296
+ if (toolCallDeltas.length > 0) {
298
297
  flushPartitionedContent();
299
298
  sealNativeReasoningBeforeText();
300
299
  rememberPendingCommentaryTags(provisionalCommentaryTags, tagPendingCommentaryText(output.content));
301
- for (const toolCall of choiceDelta.tool_calls) {
300
+ for (const toolCall of toolCallDeltas) {
302
301
  const block = ensureToolCallBlock(toolCall);
303
302
  if (!block.id && toolCall.id) {
304
303
  block.id = toolCall.id;
@@ -332,16 +331,21 @@ const streamOpenAICompletions = (model, context, options) => {
332
331
  }
333
332
  }
334
333
  flushPartitionedContent();
335
- for (const block of blocks) finishBlock(block);
336
- if (options?.signal?.aborted) throw transportAbortError(options.signal);
337
- if (output.stopReason === "aborted") throw new Error("Request was aborted");
338
- if (output.stopReason === "error") throw new Error(output.errorMessage || "Provider returned an error stop reason");
339
- if (!hasFinishReason) throw new Error("Stream ended without finish_reason");
340
- const hasToolCalls = output.content.some((block) => block.type === "toolCall");
341
- const hasVisibleText = output.content.some((block) => block.type === "text" && block.text.trim().length > 0);
342
- if (output.stopReason === "toolUse" && !hasToolCalls) output.stopReason = "stop";
343
- if (output.stopReason === "stop" && hasToolCalls && !hasVisibleText) output.stopReason = "toolUse";
344
- if (hasToolCalls && output.stopReason !== "toolUse") output.content = output.content.filter((block) => block.type !== "toolCall");
334
+ let terminalError;
335
+ if (options?.signal?.aborted) terminalError = transportAbortError(options.signal);
336
+ else if (output.stopReason === "aborted") terminalError = /* @__PURE__ */ new Error("Request was aborted");
337
+ else if (output.stopReason === "error") terminalError = new Error(output.errorMessage || "Provider returned an error stop reason");
338
+ else if (!hasFinishReason) terminalError = /* @__PURE__ */ new Error("Stream ended without finish_reason");
339
+ if (terminalError) {
340
+ for (const block of blocks) if (block.type !== "toolCall") finishBlock(block);
341
+ throw terminalError;
342
+ }
343
+ finalizeOpenAICompletionsToolCalls(output);
344
+ if (output.stopReason === "aborted" || output.stopReason === "error") {
345
+ for (const block of blocks) if (block.type !== "toolCall") finishBlock(block);
346
+ throw new Error(output.errorMessage || (output.stopReason === "aborted" ? "Request was aborted" : "Provider returned an invalid tool call"));
347
+ }
348
+ for (const block of blocks) if (block.type !== "toolCall" || output.stopReason === "toolUse") finishBlock(block);
345
349
  if (output.stopReason !== "toolUse") clearPendingCommentaryText(provisionalCommentaryTags);
346
350
  if (output.stopReason === "toolUse") tagPendingCommentaryText(output.content);
347
351
  stream.push({
@@ -351,12 +355,13 @@ const streamOpenAICompletions = (model, context, options) => {
351
355
  });
352
356
  stream.end();
353
357
  } catch (error) {
358
+ output.stopReason = options?.signal?.aborted ? "aborted" : "error";
359
+ finalizeOpenAICompletionsToolCalls(output, { allowSilentToolCallPromotion: false });
354
360
  for (const block of output.content) {
355
361
  delete block.index;
356
362
  delete block.partialArgs;
357
363
  delete block.streamIndex;
358
364
  }
359
- output.stopReason = options?.signal?.aborted ? "aborted" : "error";
360
365
  output.errorMessage = formatProviderError(error);
361
366
  const rawMetadata = error?.error?.metadata?.raw;
362
367
  if (rawMetadata && !output.errorMessage.includes(rawMetadata)) output.errorMessage += `\n${rawMetadata}`;
@@ -602,29 +607,5 @@ function convertTools(tools, compat) {
602
607
  }))
603
608
  };
604
609
  }
605
- function parseChunkUsage(rawUsage, model) {
606
- const promptTokens = rawUsage.prompt_tokens || 0;
607
- const cacheReadTokens = rawUsage.prompt_tokens_details?.cached_tokens ?? rawUsage.prompt_cache_hit_tokens ?? 0;
608
- const cacheWriteTokens = rawUsage.prompt_tokens_details?.cache_write_tokens || 0;
609
- const input = Math.max(0, promptTokens - cacheReadTokens - cacheWriteTokens);
610
- const outputTokens = rawUsage.completion_tokens || 0;
611
- const usage = {
612
- input,
613
- output: outputTokens,
614
- cacheRead: cacheReadTokens,
615
- cacheWrite: cacheWriteTokens,
616
- totalTokens: input + outputTokens + cacheReadTokens + cacheWriteTokens,
617
- cost: {
618
- input: 0,
619
- output: 0,
620
- cacheRead: 0,
621
- cacheWrite: 0,
622
- total: 0
623
- }
624
- };
625
- calculateCost(model, usage);
626
- applyProviderReportedUsageCost(usage, rawUsage.cost);
627
- return usage;
628
- }
629
610
  //#endregion
630
611
  export { streamOpenAICompletions as n, streamSimpleOpenAICompletions as r, openai_completions_exports as t };