@openclaw/ai 2026.9.1 → 2026.9.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.
Files changed (71) hide show
  1. package/dist/{anthropic-hk7F7ptG.mjs → anthropic-BDdqdVLK.mjs} +208 -205
  2. package/dist/{anthropic-compaction-replay-OMJZ0uyo.mjs → anthropic-compaction-replay-DB2FGLQc.mjs} +130 -41
  3. package/dist/{anthropic-payload-policy-DBT1itQ-.d.mts → anthropic-payload-policy-d46X2pR0.d.mts} +27 -3
  4. package/dist/{api-registry-Cs6HGNqY.d.mts → api-registry-DWtPjzyn.d.mts} +2 -2
  5. package/dist/{azure-openai-responses-CN4Fy5zV.mjs → azure-openai-responses-C5bZRfAP.mjs} +5 -5
  6. package/dist/{diagnostics-KhXK-QJI.mjs → diagnostics-DfFyKeX_.mjs} +1 -1
  7. package/dist/diagnostics.mjs +2 -2
  8. package/dist/{event-stream-uSMZJ3FA.mjs → event-stream-BgDvQeum.mjs} +3 -9
  9. package/dist/{event-stream-vK_7r3bj.d.mts → event-stream-BhT5T1Ay.d.mts} +1 -1
  10. package/dist/event-stream-zctLx0yr.d.mts +1 -0
  11. package/dist/event-stream.d.mts +2 -2
  12. package/dist/event-stream.mjs +1 -1
  13. package/dist/{google-CC-nrwXg.mjs → google-4qeuE8iX.mjs} +4 -4
  14. package/dist/{google-shared-CjPY0hZM.mjs → google-shared-CWeG8RIl.mjs} +7 -5
  15. package/dist/{google-vertex-DCr0pyzQ.mjs → google-vertex-O9BcnB6X.mjs} +4 -4
  16. package/dist/{host-BIaiBURL.mjs → host-CEvLw30U.mjs} +54 -9
  17. package/dist/{host-BztR4tQj.d.mts → host-DjzGmdZ2.d.mts} +3 -3
  18. package/dist/{index-AfaxKT8w.d.mts → index-FnHM2FcI.d.mts} +11 -5
  19. package/dist/index.d.mts +7 -7
  20. package/dist/index.mjs +4 -4
  21. package/dist/internal/anthropic.d.mts +12 -9
  22. package/dist/internal/anthropic.mjs +5 -5
  23. package/dist/internal/openai-responses-payload-policy.d.mts +1 -1
  24. package/dist/internal/openai-responses-payload-policy.mjs +1 -1
  25. package/dist/internal/openai.d.mts +7 -7
  26. package/dist/internal/openai.mjs +10 -10
  27. package/dist/internal/runtime.d.mts +5 -5
  28. package/dist/internal/runtime.mjs +3 -3
  29. package/dist/internal/shared.d.mts +2 -2
  30. package/dist/internal/shared.mjs +3 -3
  31. package/dist/{mistral-B7etBd_H.mjs → mistral-Tb6oalqH.mjs} +10 -8
  32. package/dist/{openai-chatgpt-responses-BAJ4gq3i.mjs → openai-chatgpt-responses-yUXjPNfu.mjs} +26 -28
  33. package/dist/{openai-completions-D0QZ0AyB.mjs → openai-completions-BIUV3RDT.mjs} +8 -8
  34. package/dist/{openai-completions-compat-4IjSBpr6.d.mts → openai-completions-compat-CpjYUArk.d.mts} +3 -3
  35. package/dist/{openai-completions-stream-DZjwK8vp.mjs → openai-completions-stream-BsrBe3Gg.mjs} +16 -16
  36. package/dist/openai-prompt-cache-CGnVB74a.mjs +21 -0
  37. package/dist/openai-prompt-cache-CNoIfHYC.d.mts +16 -0
  38. package/dist/{openai-responses-BEUlxfDu.mjs → openai-responses-CCL41ALM.mjs} +8 -11
  39. package/dist/{openai-responses-compaction-window-DO7yV7az.mjs → openai-responses-compaction-window-BMVHFOtq.mjs} +18 -7
  40. package/dist/{openai-responses-contracts-bPzSN_Ba.d.mts → openai-responses-contracts-rF5DDRNS.d.mts} +12 -4
  41. package/dist/{openai-responses-prompt-observer-internal-C7x4IK7r.mjs → openai-responses-prompt-observer-internal-D0bhBfgL.mjs} +3 -3
  42. package/dist/{openai-responses-shared-DiAdpNAM.mjs → openai-responses-shared-Bmma_3Qc.mjs} +185 -109
  43. package/dist/{openai-tool-schema-BMiHFH36.mjs → openai-tool-schema-_pTAJqKF.mjs} +20 -32
  44. package/dist/{provider-error-B6EGq6gg.mjs → provider-error-9TraxGvt.mjs} +6 -7
  45. package/dist/{provider-options-CxFPtvh7.d.mts → provider-options-Bcc_p-TU.d.mts} +18 -6
  46. package/dist/provider-replay-context-BuSUaAk5.mjs +21 -0
  47. package/dist/{provider-transcript-transform-WvJmFUAf.mjs → provider-transcript-transform-BaMbI1hr.mjs} +1 -1
  48. package/dist/provider-types.d.mts +6 -6
  49. package/dist/providers.d.mts +2 -2
  50. package/dist/providers.mjs +11 -11
  51. package/dist/{reasoning-tag-text-partitioner-C-4uedDb.mjs → reasoning-tag-text-partitioner-DLCNXki6.mjs} +72 -24
  52. package/dist/{sanitize-unicode-S6binQG-.mjs → sanitize-unicode-D6xUvZaS.mjs} +1 -1
  53. package/dist/{simple-options-0PLDyJ-d.mjs → simple-options-BjHCCh4v.mjs} +2 -2
  54. package/dist/{src-C8U7lkoa.mjs → src-2qBGKg8O.mjs} +9 -1
  55. package/dist/{tool-schema-json-projection-BtZiml7r.mjs → tool-schema-json-projection-mJhXDcyz.mjs} +1 -1
  56. package/dist/{transport-stream-shared-CytPVLIg.mjs → transport-stream-shared-CZqMhfIw.mjs} +4 -4
  57. package/dist/{transport-stream-shared-BrvFTkoO.d.mts → transport-stream-shared-xnaqxmbP.d.mts} +4 -4
  58. package/dist/{transport-utils-CtuS1Upe.mjs → transport-utils-7il795_9.mjs} +1 -1
  59. package/dist/transports.d.mts +11 -10
  60. package/dist/transports.mjs +567 -253
  61. package/dist/types-3Lnm-QSJ.d.mts +1 -0
  62. package/dist/{types-DbrhszyQ.d.mts → types-CJ1-Ht7A.d.mts} +29 -7
  63. package/dist/types.d.mts +6 -6
  64. package/dist/types.mjs +3 -3
  65. package/dist/{validation-BOwtcl9X.d.mts → validation-AKZBDGQd.d.mts} +1 -1
  66. package/dist/validation.d.mts +1 -1
  67. package/package.json +2 -2
  68. package/dist/event-stream-DeDhbCc5.d.mts +0 -1
  69. package/dist/openai-prompt-cache-2uo_1OR1.d.mts +0 -7
  70. package/dist/openai-prompt-cache-mZTCdRPo.mjs +0 -12
  71. package/dist/types-B5EFUmXs.d.mts +0 -1
@@ -1,18 +1,20 @@
1
1
  import { c as normalizeLowercaseStringOrEmpty, d as normalizeOptionalString, o as isRecord, t as truncateUtf16Safe } from "./utf16-slice-qz3nsy87.mjs";
2
- import { i as clampThinkingLevel, r as calculateCost } from "./sanitize-unicode-S6binQG-.mjs";
3
- import { a as describeToolResultMediaPlaceholder, c as extractToolResultText, d as isImageWithMediaPayload, n as getAiTransportHost } from "./host-BIaiBURL.mjs";
2
+ import { i as clampThinkingLevel, r as calculateCost } from "./sanitize-unicode-D6xUvZaS.mjs";
3
+ import { a as describeToolResultMediaPlaceholder, c as extractToolResultText, d as isImageWithMediaPayload, n as getAiTransportHost } from "./host-CEvLw30U.mjs";
4
+ import { i as stableStringify } from "./provider-error-9TraxGvt.mjs";
4
5
  import { r as asFiniteNumber } from "./base64-CEFBpSkN.mjs";
5
- import { d as stripSystemPromptCacheBoundary, m as sortPromptCacheToolsByName } from "./simple-options-0PLDyJ-d.mjs";
6
- import { c as transformTransportMessages } from "./tool-schema-json-projection-BtZiml7r.mjs";
7
- import { d as redactSensitiveText, u as redactIdentifier } from "./transport-utils-CtuS1Upe.mjs";
8
- import { _ as transportAbortError, c as finalizeTransportStream, g as sanitizeTransportPayloadText, h as sanitizeNonEmptyTransportPayloadText, m as parseTerminalToolCallArguments, o as failTransportStream, y as withProviderResponseHook } from "./transport-stream-shared-CytPVLIg.mjs";
6
+ import { d as stripSystemPromptCacheBoundary, m as sortPromptCacheToolsByName } from "./simple-options-BjHCCh4v.mjs";
7
+ import { c as transformTransportMessages } from "./tool-schema-json-projection-mJhXDcyz.mjs";
8
+ import { d as redactSensitiveText, p as sha256Hex, u as redactIdentifier } from "./transport-utils-7il795_9.mjs";
9
+ import { _ as transportAbortError, c as finalizeTransportStream, g as sanitizeTransportPayloadText, h as sanitizeNonEmptyTransportPayloadText, m as parseTerminalToolCallArguments, o as failTransportStream, y as withProviderResponseHook } from "./transport-stream-shared-CZqMhfIw.mjs";
9
10
  import { r as parseStreamingJson, t as createToolArgumentPreviewSchedule } from "./json-parse-BuAJEbdW.mjs";
10
11
  import { t as notifyLlmRequestActivity } from "./llm-request-activity-BjtkplhG.mjs";
11
12
  import { t as shortHash } from "./hash-CHgqbJmD.mjs";
12
- import { C as createOpenAIProviderAcceptanceHook, E as log, S as createModelStreamCooperativeScheduler, a as resolveOpenAIProjectedToolsStrictToolFlag, r as normalizeOpenAIStrictToolParameters, t as findOpenAIStrictToolProjectionDiagnostics, v as projectOpenAITools } from "./openai-tool-schema-BMiHFH36.mjs";
13
+ import { n as providerReplayContextMatches, t as buildProviderReplayContext } from "./provider-replay-context-BuSUaAk5.mjs";
14
+ import { C as createOpenAIProviderAcceptanceHook, E as log, S as createModelStreamCooperativeScheduler, a as resolveOpenAIProjectedToolsStrictToolFlag, r as normalizeOpenAIStrictToolParameters, t as findOpenAIStrictToolProjectionDiagnostics, v as projectOpenAITools } from "./openai-tool-schema-_pTAJqKF.mjs";
13
15
  import { a as withFirstStreamEventTimeout, i as getFirstStreamEventTimeoutMs, r as getFirstStreamEventTimeoutHandler, t as createFirstStreamEventAbortController } from "./stream-first-event-timeout-DcNjoFQE.mjs";
14
- import { t as transformProviderMessages } from "./provider-transcript-transform-WvJmFUAf.mjs";
15
- import { A as supportsOpenAITemperature, D as resolveOpenAIReasoningEffortForModel, b as RESPONSE_FAILED_NO_DETAILS_MESSAGE, g as OPENAI_RESPONSES_RETAINED_COMPACTION_REPLAY_TYPE, h as OPENAI_RESPONSES_REASONING_REPLAY_META_KEY, k as supportsOpenAIReasoningEffort, m as OPENAI_RESPONSES_REASONING_REPLAY_BLOCK_META_KEY, n as isOpenAIResponsesCompactionOutput, p as OPENAI_RESPONSES_COMPACTION_REPLAY_TYPE, r as readOpenAIResponsesCompactionWindow } from "./openai-responses-compaction-window-DO7yV7az.mjs";
16
+ import { t as transformProviderMessages } from "./provider-transcript-transform-BaMbI1hr.mjs";
17
+ import { D as resolveOpenAIModelReasoningEfforts, O as resolveOpenAIReasoningEffortForModel, b as RESPONSE_FAILED_NO_DETAILS_MESSAGE, g as OPENAI_RESPONSES_RETAINED_COMPACTION_REPLAY_TYPE, h as OPENAI_RESPONSES_REASONING_REPLAY_META_KEY, j as supportsOpenAITemperature, m as OPENAI_RESPONSES_REASONING_REPLAY_BLOCK_META_KEY, n as isOpenAIResponsesCompactionOutput, p as OPENAI_RESPONSES_COMPACTION_REPLAY_TYPE, r as readOpenAIResponsesCompactionWindow } from "./openai-responses-compaction-window-BMVHFOtq.mjs";
16
18
  import { createHash, randomUUID } from "node:crypto";
17
19
  //#region packages/ai/src/transports/model-transport-debug.ts
18
20
  /**
@@ -66,19 +68,8 @@ function resolveReplayableResponsesMessageId(params) {
66
68
  //#region packages/ai/src/transports/openai-responses-compaction-replay.ts
67
69
  const OPENAI_RESPONSES_COMPACTION_SUPPRESSION_TYPE = "openai-responses-compaction-suppression";
68
70
  const OPENAI_RESPONSES_COMPACTION_SUPPRESSION_DATA = "rejected";
69
- function hashOptionalReplayContextValue(value) {
70
- const normalized = value?.trim();
71
- return normalized ? shortHash(normalized) : void 0;
72
- }
73
71
  function buildOpenAIResponsesReplayContext(model, options) {
74
- return {
75
- provider: model.provider,
76
- api: model.api,
77
- model: model.id,
78
- baseUrlHash: hashOptionalReplayContextValue(model.baseUrl),
79
- sessionHash: hashOptionalReplayContextValue(options?.sessionId),
80
- authProfileHash: hashOptionalReplayContextValue(options?.authProfileId)
81
- };
72
+ return buildProviderReplayContext(model, options);
82
73
  }
83
74
  function isOpenAIResponsesReplayContext(value) {
84
75
  if (!isRecord(value)) return false;
@@ -93,9 +84,6 @@ function isOpenAIResponsesCompactionState(state) {
93
84
  function readOpenAIResponsesCompactionReplayState(value) {
94
85
  return isRecord(value) && isOpenAIResponsesReplayContext(value) && isOpenAIResponsesCompactionState(value) ? value : void 0;
95
86
  }
96
- function openAIResponsesReplayContextMatches(state, context) {
97
- return state.provider === context.provider && state.api === context.api && state.model === context.model && state.baseUrlHash === context.baseUrlHash && state.sessionHash === context.sessionHash && state.authProfileHash === context.authProfileHash;
98
- }
99
87
  function captureOpenAIResponsesCompaction(output, item, boundary, model, captureMetadata, compactedOutput) {
100
88
  const metadata = captureMetadata ?? buildOpenAIResponsesReasoningReplayMetadata(model);
101
89
  if (!item.encrypted_content) return;
@@ -167,14 +155,14 @@ function resolveNewestOpenAIResponsesCompactionReplay(messages, model, options)
167
155
  if (message?.role !== "assistant") continue;
168
156
  const replay = readOpenAIResponsesCompactionReplayState(message.providerReplay);
169
157
  if (replay?.type === OPENAI_RESPONSES_COMPACTION_SUPPRESSION_TYPE) {
170
- if (openAIResponsesReplayContextMatches(replay, context)) return;
158
+ if (providerReplayContextMatches(replay, context)) return;
171
159
  continue;
172
160
  }
173
161
  if (replay?.type !== "openai-responses-compaction" && replay?.type !== "openai-responses-retained-compaction") {
174
162
  if (message.providerReplay?.type === "openai-responses-compaction" || message.providerReplay?.type === "openai-responses-retained-compaction") return;
175
163
  continue;
176
164
  }
177
- if (!openAIResponsesReplayContextMatches(replay, context)) return;
165
+ if (!providerReplayContextMatches(replay, context)) return;
178
166
  if (replay.compactedWindow !== void 0 || replay.type === "openai-responses-retained-compaction") {
179
167
  const output = readOpenAIResponsesCompactionWindow(replay, model);
180
168
  const item = output?.at(-1);
@@ -237,6 +225,63 @@ function buildOpenAIResponsesReasoningReplayMetadata(model, options) {
237
225
  };
238
226
  }
239
227
  //#endregion
228
+ //#region packages/ai/src/transports/openai-responses-input-replay.ts
229
+ function recordResponsesInputReplay(message, replay) {
230
+ if (replay) Object.assign(message, { openclawResponsesInputReplay: replay });
231
+ }
232
+ function readResponsesInputReplay(message) {
233
+ const replay = "openclawResponsesInputReplay" in message ? message.openclawResponsesInputReplay : void 0;
234
+ if (isRecord(replay) && typeof replay.afterResponseId === "string" && Array.isArray(replay.before) && replay.before.every((item) => typeof item === "string") && Array.isArray(replay.after) && replay.after.every((item) => typeof item === "string")) return {
235
+ afterResponseId: replay.afterResponseId,
236
+ before: replay.before,
237
+ after: replay.after
238
+ };
239
+ }
240
+ function responsesInputFingerprint(item) {
241
+ if (isRecord(item) && (item.type === "function_call_output" || item.type === "custom_tool_call_output") && typeof item.call_id === "string") return sha256Hex(stableStringify({
242
+ type: item.type,
243
+ call_id: item.call_id
244
+ }));
245
+ return sha256Hex(stableStringify(item));
246
+ }
247
+ /** Reconstruct delivery order without rewriting durable local completion events. */
248
+ function createResponsesInputReplay(model) {
249
+ const starts = /* @__PURE__ */ new Map();
250
+ const ends = /* @__PURE__ */ new Map();
251
+ const fingerprints = /* @__PURE__ */ new Map();
252
+ const fingerprint = (item) => {
253
+ const value = fingerprints.get(item) ?? responsesInputFingerprint(item);
254
+ fingerprints.set(item, value);
255
+ return value;
256
+ };
257
+ return (input, output, message) => {
258
+ const key = message.turnId || message.responseId;
259
+ const start = (key ? starts.get(key) : void 0) ?? output[0];
260
+ if (key && start) starts.set(key, start);
261
+ input.push(...output);
262
+ let end = input.at(-1);
263
+ const replay = readResponsesInputReplay(message);
264
+ const parent = replay ? ends.get(replay.afterResponseId) : void 0;
265
+ if (replay && parent && message.provider === model.provider && message.api === model.api && message.model === model.id) {
266
+ const take = (keys) => {
267
+ const moved = [];
268
+ for (const inputKey of keys.toReversed()) {
269
+ const boundary = input.indexOf(parent);
270
+ const index = input.findLastIndex((item, position) => position > boundary && fingerprint(item) === inputKey);
271
+ if (index > boundary) moved.unshift(...input.splice(index, 1));
272
+ }
273
+ return moved;
274
+ };
275
+ const before = take(replay.before);
276
+ const after = take(replay.after);
277
+ input.splice(start ? input.indexOf(start) : input.length, 0, ...before);
278
+ end = input.at(-1);
279
+ input.push(...after);
280
+ }
281
+ if (message.responseId && end) ends.set(message.responseId, end);
282
+ };
283
+ }
284
+ //#endregion
240
285
  //#region packages/ai/src/transports/openai-responses-replay-messages-internal.ts
241
286
  function stripEncryptedReasoningContentFields(value) {
242
287
  if (!value || typeof value !== "object") return {
@@ -306,7 +351,7 @@ function prepareOpenAIResponsesReasoningItemForReplay(item, context, blockMetada
306
351
  const { [OPENAI_RESPONSES_REASONING_REPLAY_META_KEY]: rawMetadata, ...rest } = record;
307
352
  if (!("encrypted_content" in rest)) return normalizeOpenAIResponsesReasoningReplayItem(rest);
308
353
  const metadata = blockMetadata !== void 0 ? blockMetadata ?? void 0 : isOpenAIResponsesReasoningReplayMetadata(rawMetadata) ? rawMetadata : void 0;
309
- if (blockMetadata === void 0 && !hasRawMetadata && options?.preserveUnattributedEncryptedContent === true || metadata && openAIResponsesReplayContextMatches(metadata, context)) return normalizeOpenAIResponsesReasoningReplayItem(rest);
354
+ if (blockMetadata === void 0 && !hasRawMetadata && options?.preserveUnattributedEncryptedContent === true || metadata && providerReplayContextMatches(metadata, context)) return normalizeOpenAIResponsesReasoningReplayItem(rest);
310
355
  return normalizeOpenAIResponsesReasoningReplayItem(stripEncryptedReasoningContentFields(rest).value);
311
356
  }
312
357
  function normalizeResponsesReplayItemId(id, prefix) {
@@ -321,6 +366,41 @@ function encodeTextSignatureV1(id, phase) {
321
366
  ...phase ? { phase } : {}
322
367
  });
323
368
  }
369
+ function orderResponsesAsyncToolResults(source) {
370
+ const turnKey = (message) => {
371
+ const id = message.turnId || message.responseId;
372
+ return id ? `${message.provider}:${message.api}:${message.model}:${id}` : void 0;
373
+ };
374
+ const lastAssistant = /* @__PURE__ */ new Map();
375
+ for (const [index, message] of source.entries()) if (message.role === "assistant") {
376
+ const key = turnKey(message);
377
+ if (key) lastAssistant.set(key, index);
378
+ }
379
+ const owners = /* @__PURE__ */ new Map();
380
+ const pending = /* @__PURE__ */ new Map();
381
+ const ordered = [];
382
+ for (const [index, message] of source.entries()) {
383
+ if (message.role === "assistant") {
384
+ const key = turnKey(message);
385
+ if (key) {
386
+ for (const block of message.content) if (block.type === "toolCall" && block.async) owners.set(block.id, key);
387
+ }
388
+ }
389
+ const owner = message.role === "toolResult" ? owners.get(message.toolCallId) : void 0;
390
+ const lastIndex = owner ? lastAssistant.get(owner) : void 0;
391
+ if (lastIndex !== void 0 && lastIndex > index) {
392
+ const results = pending.get(lastIndex) ?? [];
393
+ results.push(message);
394
+ pending.set(lastIndex, results);
395
+ } else ordered.push(message);
396
+ const results = pending.get(index);
397
+ if (results) {
398
+ ordered.push(...results);
399
+ pending.delete(index);
400
+ }
401
+ }
402
+ return ordered;
403
+ }
324
404
  function parseOpenAIResponsesTextSignature(signature) {
325
405
  if (!signature) return;
326
406
  if (signature.startsWith("{")) try {
@@ -416,7 +496,7 @@ function convertResponsesMessagesWithStyle(model, context, allowedToolCallProvid
416
496
  normalizeSameModelToolCallIds: shouldNormalizeSameModelToolCallIds,
417
497
  preserveUnframedToolResults: replayPlan.preserveUnframedToolResults
418
498
  });
419
- const transformedMessages = transformMessages(replayPlan.messages);
499
+ const transformedMessages = orderResponsesAsyncToolResults(transformMessages(replayPlan.messages));
420
500
  if ((options?.includeSystemPrompt ?? true) && context.systemPrompt) messages.push(buildResponsesInputMessage(model.reasoning && model.compat?.supportsDeveloperRole !== false ? "developer" : "system", [{
421
501
  type: "input_text",
422
502
  text: sanitizeTransportPayloadText(stripSystemPromptCacheBoundary(context.systemPrompt))
@@ -424,17 +504,21 @@ function convertResponsesMessagesWithStyle(model, context, allowedToolCallProvid
424
504
  if (replayPlan.compactedWindow) messages.push(...replayPlan.compactedWindow);
425
505
  let replayMessages = replayPlan.compaction ? [replayPlan.compaction, ...transformedMessages] : transformedMessages;
426
506
  const isCarrier = (message) => "role" in message && message.role === "user" && message.runtimeContextCarrier === true;
427
- const carriers = replayMessages.filter(isCarrier);
428
- if (carriers.length > 0) {
429
- const stableMessages = replayMessages.filter((message) => !isCarrier(message));
430
- const insertionIndex = stableMessages.findLastIndex((message) => "role" in message ? message.role === "user" : message.type === "compaction") + 1;
431
- if (insertionIndex > 0 || replayPlan.compactedWindow) replayMessages = [
432
- ...stableMessages.slice(0, insertionIndex),
433
- ...carriers,
434
- ...stableMessages.slice(insertionIndex)
435
- ];
507
+ if (replayMessages.some(isCarrier)) {
508
+ const anchored = [];
509
+ let insertionIndex = replayPlan.compactedWindow ? 0 : void 0;
510
+ for (const message of replayMessages) {
511
+ if (isCarrier(message) && insertionIndex !== void 0) {
512
+ anchored.splice(insertionIndex++, 0, message);
513
+ continue;
514
+ }
515
+ anchored.push(message);
516
+ if (!isCarrier(message) && ("role" in message ? message.role === "user" : message.type === "compaction")) insertionIndex = anchored.length;
517
+ }
518
+ replayMessages = anchored;
436
519
  }
437
520
  let msgIndex = 0;
521
+ const appendAssistant = createResponsesInputReplay(model);
438
522
  for (const msg of replayMessages) {
439
523
  if (!("role" in msg)) {
440
524
  messages.push(msg);
@@ -512,12 +596,18 @@ function convertResponsesMessagesWithStyle(model, context, allowedToolCallProvid
512
596
  ...itemId ? { id: itemId } : {},
513
597
  call_id: callId,
514
598
  name: block.name,
599
+ ...block.async ? { async: true } : {},
515
600
  arguments: providerStyle ? JSON.stringify(block.arguments) : typeof block.arguments === "string" ? block.arguments : JSON.stringify(block.arguments ?? {})
516
601
  });
517
602
  previousReplayItemWasReasoning = false;
518
603
  }
519
- if (output.length > 0) messages.push(...output);
520
- else if (providerStyle) continue;
604
+ while (true) {
605
+ const last = output.at(-1);
606
+ if (last?.type !== "reasoning" || !last.id?.startsWith("rs_") || typeof last.encrypted_content === "string" && last.encrypted_content.length > 0) break;
607
+ output.pop();
608
+ }
609
+ appendAssistant(messages, output, msg);
610
+ if (output.length === 0 && providerStyle) continue;
521
611
  } else if (msg.role === "toolResult") {
522
612
  const textResult = extractToolResultText(msg.content);
523
613
  const sanitizedTextResult = sanitizeTransportPayloadText(textResult);
@@ -1555,6 +1645,7 @@ async function processResponsesStream(openaiStream, output, stream, model, optio
1555
1645
  const outputSlots = createResponsesOutputSlotTracker();
1556
1646
  const outputs = createResponsesOutputTracker();
1557
1647
  let terminalResponse;
1648
+ let incompleteToolCall;
1558
1649
  let lastTextBlock = null;
1559
1650
  const blocks = output.content;
1560
1651
  const compactionTracker = createCompactionTracker(output, model, options);
@@ -1644,6 +1735,26 @@ async function processResponsesStream(openaiStream, output, stream, model, optio
1644
1735
  const materializeDeferredTextSlots = (except) => {
1645
1736
  for (const slot of outputSlots.values()) if (slot !== except && slot.type === "text") materializeDeferredTextSlot(slot);
1646
1737
  };
1738
+ const appendThinkingDelta = (slot, delta) => {
1739
+ slot.block.thinking += delta;
1740
+ stream.push({
1741
+ type: "thinking_delta",
1742
+ contentIndex: slot.contentIndex,
1743
+ delta,
1744
+ partial: output
1745
+ });
1746
+ };
1747
+ const projectTextDelta = (slot, delta) => {
1748
+ if (slot.pendingText !== null) appendResponsesPendingTextDelta(slot, delta, materializeDeferredTextSlot);
1749
+ else if (slot.block && slot.contentIndex !== void 0) {
1750
+ slot.block.text += delta;
1751
+ stream.push({
1752
+ type: "text_delta",
1753
+ contentIndex: slot.contentIndex,
1754
+ delta
1755
+ });
1756
+ }
1757
+ };
1647
1758
  const terminal = createResponsesTerminalController({
1648
1759
  output,
1649
1760
  stream,
@@ -1670,7 +1781,10 @@ async function processResponsesStream(openaiStream, output, stream, model, optio
1670
1781
  streamingToolCalls.forget(streamingToolCall);
1671
1782
  for (const slot of outputSlots.values()) if (slot.type === "toolCall" && slot.toolCall === streamingToolCall) outputSlots.forget(slot);
1672
1783
  }
1673
- terminal.emitToolCallCompletion(identity, finalOutputIndex, streamingToolCall, validated);
1784
+ terminal.emitToolCallCompletion(identity, finalOutputIndex, streamingToolCall, {
1785
+ ...validated,
1786
+ ...options?.asyncToolExecution && isRecord(item) && item.async === true ? { async: true } : {}
1787
+ });
1674
1788
  };
1675
1789
  const prepareTerminalToolCalls = (items) => {
1676
1790
  const prepared = /* @__PURE__ */ new Map();
@@ -1709,6 +1823,8 @@ async function processResponsesStream(openaiStream, output, stream, model, optio
1709
1823
  try {
1710
1824
  for await (const event of guardedStream) {
1711
1825
  notifyLlmRequestActivity(options?.signal);
1826
+ if (event.type === "response.output_item.done" && event.item.type === "function_call" && event.item.status === "incomplete") incompleteToolCall ??= event.item;
1827
+ if (incompleteToolCall && event.type !== "response.completed" && event.type !== "response.incomplete" && event.type !== "response.failed" && event.type !== "error") continue;
1712
1828
  if (event.type === "response.created") output.responseId = event.response.id;
1713
1829
  else if (event.type === "response.output_item.added") {
1714
1830
  materializeDeferredTextSlots();
@@ -1756,38 +1872,20 @@ async function processResponsesStream(openaiStream, output, stream, model, optio
1756
1872
  slot.item.summary = slot.item.summary || [];
1757
1873
  const lastPart = slot.item.summary[slot.item.summary.length - 1];
1758
1874
  if (!lastPart) continue;
1759
- slot.block.thinking += event.delta;
1760
1875
  lastPart.text += event.delta;
1761
- stream.push({
1762
- type: "thinking_delta",
1763
- contentIndex: slot.contentIndex,
1764
- delta: event.delta,
1765
- partial: output
1766
- });
1876
+ appendThinkingDelta(slot, event.delta);
1767
1877
  } else if (event.type === "response.reasoning_summary_part.done") {
1768
1878
  const slot = outputSlots.resolve(event, "thinking");
1769
1879
  if (!slot) continue;
1770
1880
  slot.item.summary = slot.item.summary || [];
1771
1881
  const lastPart = slot.item.summary[slot.item.summary.length - 1];
1772
1882
  if (!lastPart) continue;
1773
- slot.block.thinking += "\n\n";
1774
1883
  lastPart.text += "\n\n";
1775
- stream.push({
1776
- type: "thinking_delta",
1777
- contentIndex: slot.contentIndex,
1778
- delta: "\n\n",
1779
- partial: output
1780
- });
1884
+ appendThinkingDelta(slot, "\n\n");
1781
1885
  } else if (event.type === "response.reasoning_text.delta") {
1782
1886
  const slot = outputSlots.resolve(event, "thinking");
1783
1887
  if (!slot) continue;
1784
- slot.block.thinking += event.delta;
1785
- stream.push({
1786
- type: "thinking_delta",
1787
- contentIndex: slot.contentIndex,
1788
- delta: event.delta,
1789
- partial: output
1790
- });
1888
+ appendThinkingDelta(slot, event.delta);
1791
1889
  } else if (event.type === "response.content_part.added") {
1792
1890
  const slot = outputSlots.resolve(event, "text");
1793
1891
  if (!slot) continue;
@@ -1807,15 +1905,7 @@ async function processResponsesStream(openaiStream, output, stream, model, optio
1807
1905
  slot.item.content.push(lastPart);
1808
1906
  }
1809
1907
  lastPart.text += event.delta;
1810
- if (slot.pendingText !== null) appendResponsesPendingTextDelta(slot, event.delta, materializeDeferredTextSlot);
1811
- else if (slot.block && slot.contentIndex !== void 0) {
1812
- slot.block.text += event.delta;
1813
- stream.push({
1814
- type: "text_delta",
1815
- contentIndex: slot.contentIndex,
1816
- delta: event.delta
1817
- });
1818
- }
1908
+ projectTextDelta(slot, event.delta);
1819
1909
  } else if (isAzureResponsesTextDeltaEvent(event)) {
1820
1910
  const slot = outputSlots.resolve(event, "text");
1821
1911
  if (!slot) continue;
@@ -1829,15 +1919,7 @@ async function processResponsesStream(openaiStream, output, stream, model, optio
1829
1919
  slot.item.content.push(lastPart);
1830
1920
  }
1831
1921
  lastPart.text += event.delta;
1832
- if (slot.pendingText !== null) appendResponsesPendingTextDelta(slot, event.delta, materializeDeferredTextSlot);
1833
- else if (slot.block && slot.contentIndex !== void 0) {
1834
- slot.block.text += event.delta;
1835
- stream.push({
1836
- type: "text_delta",
1837
- contentIndex: slot.contentIndex,
1838
- delta: event.delta
1839
- });
1840
- }
1922
+ projectTextDelta(slot, event.delta);
1841
1923
  } else if (event.type === "response.refusal.delta") {
1842
1924
  const slot = outputSlots.resolve(event, "text");
1843
1925
  if (!slot) continue;
@@ -1851,15 +1933,7 @@ async function processResponsesStream(openaiStream, output, stream, model, optio
1851
1933
  slot.item.content.push(lastPart);
1852
1934
  }
1853
1935
  lastPart.refusal += event.delta;
1854
- if (slot.pendingText !== null) appendResponsesPendingTextDelta(slot, event.delta, materializeDeferredTextSlot);
1855
- else if (slot.block && slot.contentIndex !== void 0) {
1856
- slot.block.text += event.delta;
1857
- stream.push({
1858
- type: "text_delta",
1859
- contentIndex: slot.contentIndex,
1860
- delta: event.delta
1861
- });
1862
- }
1936
+ projectTextDelta(slot, event.delta);
1863
1937
  } else if (event.type === "response.function_call_arguments.delta") {
1864
1938
  const toolCall = streamingToolCalls.resolve(event);
1865
1939
  if (toolCall) {
@@ -1983,8 +2057,12 @@ async function processResponsesStream(openaiStream, output, stream, model, optio
1983
2057
  finalizeToolCall(item, readResponsesOutputIndex(event), streamingToolCall, validated);
1984
2058
  }
1985
2059
  } else if (event.type === "response.completed" || event.type === "response.incomplete") {
1986
- if (event.type === "response.incomplete" && streamingToolCalls.hasActive()) throw new Error("Responses stream completed with unresolved tool calls");
1987
2060
  terminal.finalizeResponse(event.response, event.type);
2061
+ if (incompleteToolCall) {
2062
+ if (output.errorMessage) throw new Error(output.errorMessage);
2063
+ resolveCompletedResponsesToolCall(incompleteToolCall);
2064
+ }
2065
+ if (event.type === "response.incomplete" && streamingToolCalls.hasActive()) throw new Error(output.errorMessage ?? "Responses stream completed with unresolved tool calls");
1988
2066
  if (event.type === "response.completed" || output.stopReason === "length") {
1989
2067
  const items = event.response.output ?? [];
1990
2068
  const completeToolCall = event.type === "response.completed" ? prepareTerminalToolCalls(items) : void 0;
@@ -2077,9 +2155,6 @@ function shouldLogStrictToolDowngradeDiagnostic(diagnostics, model) {
2077
2155
  }
2078
2156
  //#endregion
2079
2157
  //#region packages/ai/src/providers/openai-responses-shared.ts
2080
- function isResponsesReasoningEffort(effort) {
2081
- return effort === "minimal" || effort === "low" || effort === "medium" || effort === "high" || effort === "xhigh" || effort === "max";
2082
- }
2083
2158
  function convertResponsesMessages(model, context, allowedToolCallProviders, options) {
2084
2159
  return convertProviderResponsesMessages(model, context, allowedToolCallProviders, options);
2085
2160
  }
@@ -2096,17 +2171,17 @@ function applyResponsesServiceTierPricing(usage, serviceTier, model) {
2096
2171
  usage.cost.total = usage.cost.input + usage.cost.output + usage.cost.cacheRead + usage.cost.cacheWrite;
2097
2172
  }
2098
2173
  function resolveResponsesReasoningEffort(model, reasoning) {
2099
- const clampedReasoning = reasoning ? clampThinkingLevel(model, reasoning) : void 0;
2100
- if (!clampedReasoning || clampedReasoning === "off") return;
2101
- if (clampedReasoning === "max") return supportsOpenAIReasoningEffort(model, "max") ? "max" : "xhigh";
2102
- if (clampedReasoning === "minimal" && model.provider === "openai" && supportsOpenAIReasoningEffort(model, "max")) {
2103
- const effort = resolveOpenAIReasoningEffortForModel({
2104
- model,
2105
- effort: "minimal"
2106
- });
2107
- return isResponsesReasoningEffort(effort) ? effort : void 0;
2108
- }
2109
- return clampedReasoning;
2174
+ if (!reasoning) return;
2175
+ const clampedReasoning = model.reasoning && model.thinkingLevelMap?.[reasoning] === void 0 && resolveOpenAIModelReasoningEfforts(model)?.includes(reasoning) ? reasoning : clampThinkingLevel(model, reasoning);
2176
+ return clampedReasoning === "off" ? void 0 : clampedReasoning;
2177
+ }
2178
+ function resolveResponsesRequestReasoningEffort(model, reasoning) {
2179
+ const mapped = model.thinkingLevelMap?.[reasoning === "none" ? "off" : reasoning];
2180
+ if (mapped !== void 0) return mapped ?? void 0;
2181
+ return resolveOpenAIModelReasoningEfforts(model) === void 0 ? reasoning === "off" ? "none" : reasoning : resolveOpenAIReasoningEffortForModel({
2182
+ model,
2183
+ effort: reasoning
2184
+ });
2110
2185
  }
2111
2186
  function applyCommonResponsesParams(params, model, context, options, config) {
2112
2187
  if (options?.maxTokens) params.max_output_tokens = Math.max(options.maxTokens, 16);
@@ -2116,13 +2191,14 @@ function applyCommonResponsesParams(params, model, context, options, config) {
2116
2191
  if (converted.tools.length > 0) params.tools = converted.tools;
2117
2192
  }
2118
2193
  if (!model.reasoning) return;
2194
+ const requestedEffort = options?.reasoningEffort ?? (options?.reasoningSummary ? "medium" : config?.setDefaultReasoningOff ?? true ? "off" : void 0);
2195
+ const effort = requestedEffort === void 0 ? void 0 : resolveResponsesRequestReasoningEffort(model, requestedEffort);
2196
+ if (effort === void 0) return;
2197
+ params.reasoning = { effort };
2119
2198
  if (options?.reasoningEffort || options?.reasoningSummary) {
2120
- params.reasoning = {
2121
- effort: options?.reasoningEffort ? model.thinkingLevelMap?.[options.reasoningEffort] ?? options.reasoningEffort : "medium",
2122
- summary: options?.reasoningSummary || "auto"
2123
- };
2199
+ params.reasoning.summary = options?.reasoningSummary || "auto";
2124
2200
  params.include = ["reasoning.encrypted_content"];
2125
- } else if ((config?.setDefaultReasoningOff ?? true) && model.thinkingLevelMap?.off !== null) params.reasoning = { effort: model.thinkingLevelMap?.off ?? "none" };
2201
+ }
2126
2202
  }
2127
2203
  function buildResponsesRequestOptions(options) {
2128
2204
  return {
@@ -2213,4 +2289,4 @@ async function runResponsesStreamLifecycle(params) {
2213
2289
  }
2214
2290
  }
2215
2291
  //#endregion
2216
- export { isAzureResponsesTextDeltaEvent as A, buildResponsesInputMessage as B, summarizeResponsesTools as C, AZURE_RESPONSES_TEXT_DELTA_EVENT_TYPE as D, AZURE_RESPONSES_TEXT_CONTENT_PART_TYPE as E, commitResponsesEncryptedContentAttempt as F, captureOpenAIResponsesCompaction as G, createOpenAIResponsesAssistantOutput as H, createResponsesStreamWithEncryptedContentRetry as I, resolveReplayableResponsesMessageId as J, resolveNewestOpenAIResponsesCompactionReplay as K, isInvalidEncryptedContentError as L, isResponsesTextContentPartType as M, isResponsesTextDeltaEventType as N, OPENAI_RESPONSES_OUTPUT_TEXT_CONTENT_PART_TYPE as O, resolveResponsesMessageSnapshotCollapse as P, resolveAzureOpenAIApiVersion as R, summarizeResponsesPayload as S, readResponsesToolCallItemIdentity as T, CompactionReplayRefreshRequiredError as U, convertResponsesMessages$1 as V, buildOpenAIResponsesReasoningReplayMetadata as W, resolveModelPayloadDebugMode as X, emitModelTransportDebug as Y, resolveModelSseDebugMode as Z, safeDebugValue as _, resolveResponsesReasoningEffort as a, summarizeOpenAITransportError as b, processResponsesStream as c, resolveResponsesTerminalStopReason as d, observeResponsesStream as f, normalizeResponsesFailedEvent as g, logResponsesFailedNoDetails as h, createResponsesAssistantOutput as i, isAzureResponsesTextDeltaEventType as j, OPENAI_RESPONSES_OUTPUT_TEXT_DELTA_EVENT_TYPE as k, mapResponsesTerminalUsage as l, buildResponsesFailedNoDetailsObservation as m, applyResponsesServiceTierPricing as n, runResponsesStreamLifecycle as o, ResponsesStreamFailure as p, suppressOpenAIResponsesCompaction as q, convertResponsesMessages as r, convertResponsesToolPayload as s, applyCommonResponsesParams as t, readResponsesReasoningTokens as u, stringifyRedactedEvent as v, createResponsesToolCallTracker as w, summarizeResponsesFailedNoDetailsObservation as x, stringifyRedactedPayload as y, resolveNextResponsesEncryptedContentAttempt as z };
2292
+ export { resolveModelPayloadDebugMode as $, OPENAI_RESPONSES_OUTPUT_TEXT_DELTA_EVENT_TYPE as A, resolveNextResponsesEncryptedContentAttempt as B, summarizeResponsesPayload as C, AZURE_RESPONSES_TEXT_CONTENT_PART_TYPE as D, readResponsesToolCallItemIdentity as E, resolveResponsesMessageSnapshotCollapse as F, responsesInputFingerprint as G, convertResponsesMessages$1 as H, commitResponsesEncryptedContentAttempt as I, captureOpenAIResponsesCompaction as J, CompactionReplayRefreshRequiredError as K, createResponsesStreamWithEncryptedContentRetry as L, isAzureResponsesTextDeltaEventType as M, isResponsesTextContentPartType as N, AZURE_RESPONSES_TEXT_DELTA_EVENT_TYPE as O, isResponsesTextDeltaEventType as P, emitModelTransportDebug as Q, isInvalidEncryptedContentError as R, summarizeResponsesFailedNoDetailsObservation as S, createResponsesToolCallTracker as T, createOpenAIResponsesAssistantOutput as U, buildResponsesInputMessage as V, recordResponsesInputReplay as W, suppressOpenAIResponsesCompaction as X, resolveNewestOpenAIResponsesCompactionReplay as Y, resolveReplayableResponsesMessageId as Z, normalizeResponsesFailedEvent as _, resolveResponsesReasoningEffort as a, stringifyRedactedPayload as b, convertResponsesToolPayload as c, readResponsesReasoningTokens as d, resolveModelSseDebugMode as et, resolveResponsesTerminalStopReason as f, logResponsesFailedNoDetails as g, buildResponsesFailedNoDetailsObservation as h, createResponsesAssistantOutput as i, isAzureResponsesTextDeltaEvent as j, OPENAI_RESPONSES_OUTPUT_TEXT_CONTENT_PART_TYPE as k, processResponsesStream as l, ResponsesStreamFailure as m, applyResponsesServiceTierPricing as n, resolveResponsesRequestReasoningEffort as o, observeResponsesStream as p, buildOpenAIResponsesReasoningReplayMetadata as q, convertResponsesMessages as r, runResponsesStreamLifecycle as s, applyCommonResponsesParams as t, mapResponsesTerminalUsage as u, safeDebugValue as v, summarizeResponsesTools as w, summarizeOpenAITransportError as x, stringifyRedactedEvent as y, resolveAzureOpenAIApiVersion as z };
@@ -1,10 +1,10 @@
1
1
  import { c as normalizeLowercaseStringOrEmpty, o as isRecord } from "./utf16-slice-qz3nsy87.mjs";
2
- import { n as applyProviderReportedUsageCost, r as calculateCost } from "./sanitize-unicode-S6binQG-.mjs";
3
- import { n as getAiTransportHost } from "./host-BIaiBURL.mjs";
2
+ import { n as applyProviderReportedUsageCost, r as calculateCost } from "./sanitize-unicode-D6xUvZaS.mjs";
3
+ import { n as getAiTransportHost } from "./host-CEvLw30U.mjs";
4
4
  import { r as uniqueValues, t as normalizeStringEntries } from "./string-normalization--fwJ4S2q.mjs";
5
- import { n as clampOpenAIPromptCacheKey } from "./openai-prompt-cache-mZTCdRPo.mjs";
6
- import { t as projectRuntimeToolInputSchema } from "./tool-schema-json-projection-BtZiml7r.mjs";
7
- import { C as headersToRecord, _ as transportAbortError, f as notifyProviderHttpResponse } from "./transport-stream-shared-CytPVLIg.mjs";
5
+ import { n as clampOpenAIPromptCacheKey } from "./openai-prompt-cache-CGnVB74a.mjs";
6
+ import { t as projectRuntimeToolInputSchema } from "./tool-schema-json-projection-mJhXDcyz.mjs";
7
+ import { C as headersToRecord, _ as transportAbortError, f as notifyProviderHttpResponse } from "./transport-stream-shared-CZqMhfIw.mjs";
8
8
  //#region packages/ai/src/transports/openai-transport-shared.ts
9
9
  /** Shared options, usage shape, cache identity, ordering, and stream scheduling for OpenAI APIs. */
10
10
  const MODEL_STREAM_COOPERATIVE_YIELD_INTERVAL_MS = 12;
@@ -1328,7 +1328,7 @@ function normalizeOpenApiSchemaKeywords(schema) {
1328
1328
  changed ||= next.some((entry, index) => entry !== value[index]);
1329
1329
  continue;
1330
1330
  }
1331
- normalized[key] = value;
1331
+ setOwnSchemaProperty(normalized, key, value);
1332
1332
  }
1333
1333
  if (nullable) {
1334
1334
  if (hasOpenApiComposition(normalized)) return wrapNullableComposedSchema(normalized);
@@ -1392,13 +1392,7 @@ function normalizeToolParameterSchemaUncached(schema, options) {
1392
1392
  const props = entry.properties;
1393
1393
  if (!props || typeof props !== "object") continue;
1394
1394
  objectVariants += 1;
1395
- for (const [key, value] of Object.entries(props)) {
1396
- if (!(key in mergedProperties)) {
1397
- mergedProperties[key] = value;
1398
- continue;
1399
- }
1400
- mergedProperties[key] = mergePropertySchemas(mergedProperties[key], value);
1401
- }
1395
+ for (const [key, value] of Object.entries(props)) setOwnSchemaProperty(mergedProperties, key, mergePropertySchemas(Object.hasOwn(mergedProperties, key) ? mergedProperties[key] : void 0, value));
1402
1396
  const required = Array.isArray(entry.required) ? entry.required : [];
1403
1397
  for (const key of required) {
1404
1398
  if (typeof key !== "string") continue;
@@ -1463,12 +1457,11 @@ const OPENAI_STRICT_COMPAT_SCHEMA_NESTED_KEYS = /* @__PURE__ */ new Set([
1463
1457
  function normalizeOpenAIStrictCompatSchemaMap(schema) {
1464
1458
  if (!schema || typeof schema !== "object" || Array.isArray(schema)) return schema;
1465
1459
  let changed = false;
1466
- const normalized = {};
1467
- for (const [key, value] of Object.entries(schema)) {
1460
+ const normalized = Object.fromEntries(Object.entries(schema).map(([key, value]) => {
1468
1461
  const next = normalizeOpenAIStrictCompatSchemaRecursive(value, { promoteEmptyObject: false });
1469
- normalized[key] = next;
1470
1462
  changed ||= next !== value;
1471
- }
1463
+ return [key, next];
1464
+ }));
1472
1465
  return changed ? normalized : schema;
1473
1466
  }
1474
1467
  function normalizeOpenAIStrictCompatSchemaRecursive(schema, options) {
@@ -1485,21 +1478,17 @@ function normalizeOpenAIStrictCompatSchemaRecursive(schema, options) {
1485
1478
  const record = schema;
1486
1479
  let changed = false;
1487
1480
  let hadNullType = false;
1488
- const normalized = {};
1489
- for (const [key, value] of Object.entries(record)) {
1490
- if (value === null && OPENAI_NULLABLE_ANNOTATION_KEYS.has(key)) {
1491
- changed = true;
1492
- continue;
1493
- }
1494
- if (value === null && key === "type") {
1495
- hadNullType = true;
1481
+ const entries = Object.entries(record).flatMap(([key, value]) => {
1482
+ if (value === null && (OPENAI_NULLABLE_ANNOTATION_KEYS.has(key) || key === "type")) {
1483
+ hadNullType ||= key === "type";
1496
1484
  changed = true;
1497
- continue;
1485
+ return [];
1498
1486
  }
1499
1487
  const next = OPENAI_STRICT_COMPAT_SCHEMA_MAP_KEYS.has(key) ? normalizeOpenAIStrictCompatSchemaMap(value) : OPENAI_STRICT_COMPAT_SCHEMA_NESTED_KEYS.has(key) ? normalizeOpenAIStrictCompatSchemaRecursive(value, { promoteEmptyObject: false }) : value;
1500
- normalized[key] = next;
1501
1488
  changed ||= next !== value;
1502
- }
1489
+ return [[key, next]];
1490
+ });
1491
+ const normalized = Object.fromEntries(entries);
1503
1492
  if (Object.keys(normalized).length === 0) {
1504
1493
  if (!options.promoteEmptyObject) return schema;
1505
1494
  return {
@@ -1625,12 +1614,11 @@ function normalizeStrictOpenAIJsonSchemaRecursive(schema, depth) {
1625
1614
  if (!schema || typeof schema !== "object") return schema;
1626
1615
  const record = schema;
1627
1616
  let changed = false;
1628
- const normalized = {};
1629
- for (const [key, value] of Object.entries(record)) {
1617
+ const normalized = Object.fromEntries(Object.entries(record).map(([key, value]) => {
1630
1618
  const next = normalizeStrictOpenAIJsonSchemaRecursive(value, key === "properties" ? depth : depth + 1);
1631
- normalized[key] = next;
1632
1619
  changed ||= next !== value;
1633
- }
1620
+ return [key, next];
1621
+ }));
1634
1622
  if (normalized.type === "object") {
1635
1623
  const properties = normalized.properties && typeof normalized.properties === "object" && !Array.isArray(normalized.properties) ? normalized.properties : void 0;
1636
1624
  if (properties && Object.keys(properties).length === 0 && !Array.isArray(normalized.required)) {
@@ -134,8 +134,7 @@ function looksLikeDiagnosticJson(value) {
134
134
  function normalizeDiagnosticFieldName(value) {
135
135
  return value.toLowerCase().replaceAll(/[^a-z0-9]/g, "");
136
136
  }
137
- function isCredentialFieldName(key) {
138
- const normalized = normalizeDiagnosticFieldName(key);
137
+ function isCredentialFieldName(normalized) {
139
138
  if (!normalized || NON_CREDENTIAL_FIELD_NAMES.has(normalized)) return false;
140
139
  return normalized === "authorization" || normalized === "proxyauthorization" || CREDENTIAL_FIELD_SUFFIX_RE.test(normalized);
141
140
  }
@@ -159,8 +158,7 @@ function isDiagnosticMediaPayload(descriptors) {
159
158
  return typeof mime === "string" && /^(?:audio|image|video)\//iu.test(mime);
160
159
  });
161
160
  }
162
- function extractDiagnosticMediaField(key, value, parentMedia) {
163
- const normalized = normalizeDiagnosticFieldName(key);
161
+ function extractDiagnosticMediaField(key, normalized, value, parentMedia) {
164
162
  const privateField = normalized === "b64json";
165
163
  const mediaField = MEDIA_FIELD_NAME_RE.test(normalized) || MEDIA_WRAPPER_NAME_RE.test(key);
166
164
  const contextualPayload = parentMedia && MEDIA_PAYLOAD_SUFFIX_RE.test(normalized);
@@ -210,7 +208,7 @@ function projectDiagnosticValue(value, policy = {}, seen = /* @__PURE__ */ new W
210
208
  seen.add(value);
211
209
  const out = Array.isArray(value) ? [] : {};
212
210
  const rawName = typeof descriptors.name?.value === "string" ? descriptors.name.value : descriptors.key?.value;
213
- const redactValueField = keys.length > 64 || typeof rawName === "string" && isCredentialFieldName(rawName);
211
+ const redactValueField = keys.length > 64 || typeof rawName === "string" && isCredentialFieldName(normalizeDiagnosticFieldName(rawName));
214
212
  const redactMedia = mediaPayload || keys.length > 64 || isDiagnosticMediaPayload(descriptors);
215
213
  for (const [key, descriptor] of Object.entries(descriptors)) {
216
214
  if (!("value" in descriptor) || !descriptor.enumerable && (policy.propertyScope === "enumerable" || ![
@@ -221,7 +219,8 @@ function projectDiagnosticValue(value, policy = {}, seen = /* @__PURE__ */ new W
221
219
  "stack"
222
220
  ].includes(key)) || key === "length") continue;
223
221
  const child = descriptor.value;
224
- if (policy.omitField?.(key) || isCredentialFieldName(key)) {
222
+ const normalized = policy.omitField?.(key) ? void 0 : normalizeDiagnosticFieldName(key);
223
+ if (normalized === void 0 || isCredentialFieldName(normalized)) {
225
224
  state.changed = true;
226
225
  continue;
227
226
  }
@@ -230,7 +229,7 @@ function projectDiagnosticValue(value, policy = {}, seen = /* @__PURE__ */ new W
230
229
  state.changed = true;
231
230
  continue;
232
231
  }
233
- const media = extractDiagnosticMediaField(key, child, redactMedia);
232
+ const media = extractDiagnosticMediaField(key, normalized, child, redactMedia);
234
233
  if (media?.kind === "redacted") {
235
234
  const redacted = media.bytes === void 0 ? "<redacted>" : {
236
235
  redacted: "<redacted>",