@openclaw/ai 2026.9.4 → 2026.9.5

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 (97) hide show
  1. package/README.md +1 -1
  2. package/dist/{anthropic-C4Qu4H0Z.mjs → anthropic-COtDvgtt.mjs} +10 -11
  3. package/dist/{anthropic-payload-policy-BZ8umAbk.d.mts → anthropic-payload-policy-5Erq1Nzy.d.mts} +3 -3
  4. package/dist/{anthropic-stream-reducer-CILWF7JD.mjs → anthropic-stream-reducer-BvdYYWL8.mjs} +47 -43
  5. package/dist/{api-registry-ByUwIR0e.d.mts → api-registry-Ba2Cv-ut.d.mts} +2 -2
  6. package/dist/{assistant-output-tLt4H-iQ.mjs → assistant-output-BsEkB-vU.mjs} +1 -1
  7. package/dist/{azure-openai-responses-BAlqlKKc.mjs → azure-openai-responses-YrgnD583.mjs} +6 -9
  8. package/dist/{base64-D-su8YVo.mjs → base64-BQOzsvUH.mjs} +4 -4
  9. package/dist/credential-redaction-BKv49aiv.d.mts +24 -0
  10. package/dist/{diagnostics-QuErwCIl.mjs → diagnostics-Dm4bisWG.mjs} +89 -2
  11. package/dist/diagnostics.d.mts +4 -23
  12. package/dist/diagnostics.mjs +3 -3
  13. package/dist/{event-stream-Bt5Y4Pav.d.mts → event-stream-CCoa-qSI.d.mts} +1 -1
  14. package/dist/event-stream-DmSCpi1T.d.mts +1 -0
  15. package/dist/event-stream.d.mts +2 -2
  16. package/dist/expect-lbe3Hgrh.mjs +8 -0
  17. package/dist/{google-DPBAOaOW.mjs → google-BuhpRO9r.mjs} +6 -9
  18. package/dist/{google-messages-6JkpHrhJ.mjs → google-messages-CyWnYlh0.mjs} +3 -3
  19. package/dist/{google-shared-BvBeW9aq.mjs → google-shared-BT5ZeNer.mjs} +13 -13
  20. package/dist/{google-vertex-k-TMCAYD.mjs → google-vertex-C7EplRvt.mjs} +5 -8
  21. package/dist/{host-B8YfDGd4.mjs → host-B4MeUNBc.mjs} +25 -27
  22. package/dist/{host-4atIX-2V.d.mts → host-FZ1RA_qD.d.mts} +5 -3
  23. package/dist/{host-policy-Zcg_cNz8.mjs → host-policy-DUnXSx0I.mjs} +1 -1
  24. package/dist/{index-DdD3qerf.d.mts → index-DaF2QbwS.d.mts} +4 -9
  25. package/dist/index.d.mts +6 -7
  26. package/dist/index.mjs +3 -4
  27. package/dist/internal/anthropic.d.mts +6 -7
  28. package/dist/internal/anthropic.mjs +4 -4
  29. package/dist/internal/openai-completions-compat.d.mts +2 -0
  30. package/dist/internal/openai-completions-compat.mjs +2 -0
  31. package/dist/internal/openai-responses-payload-policy.d.mts +2 -2
  32. package/dist/internal/openai-responses-payload-policy.mjs +2 -2
  33. package/dist/internal/openai.d.mts +10 -53
  34. package/dist/internal/openai.mjs +11 -9
  35. package/dist/internal/runtime.d.mts +6 -8
  36. package/dist/internal/runtime.mjs +5 -9
  37. package/dist/internal/shared.d.mts +6 -5
  38. package/dist/internal/shared.mjs +4 -3
  39. package/dist/internal/tool-schema.d.mts +3 -3
  40. package/dist/internal/tool-schema.mjs +2 -2
  41. package/dist/{mistral-CxUZ1jUb.mjs → mistral-moA-mbwl.mjs} +9 -13
  42. package/dist/{openai-chatgpt-responses-CgO6kZfo.mjs → openai-chatgpt-responses-DWID3EFO.mjs} +73 -29
  43. package/dist/{openai-completions-yJuk7eis.mjs → openai-completions-DJ1Vm-CD.mjs} +11 -12
  44. package/dist/{openai-prompt-cache-Bds-n_9Q.mjs → openai-completions-compat-CkwdxTZx.mjs} +5 -50
  45. package/dist/{openai-completions-compat-eHgh5UPE.d.mts → openai-completions-compat-JE7gqxb9.d.mts} +4 -4
  46. package/dist/{openai-completions-stream-Da2vvl-S.mjs → openai-completions-stream-Bu98b0Hv.mjs} +94 -96
  47. package/dist/openai-prompt-cache-1wfaIszn.mjs +46 -0
  48. package/dist/{openai-prompt-cache-B4eYo2-I.d.mts → openai-prompt-cache-CJ_xEevu.d.mts} +2 -2
  49. package/dist/{openai-provider-client-S2gCrM2Z.mjs → openai-provider-client-DPo0Hmak.mjs} +2 -2
  50. package/dist/openai-reasoning-effort-NlFZmfEu.mjs +235 -0
  51. package/dist/{openai-responses-DaYwH05E.mjs → openai-responses-BejZzQCP.mjs} +8 -12
  52. package/dist/{openai-responses-compaction-window-CIhBAkkq.mjs → openai-responses-compaction-window-D6P5oZP5.mjs} +20 -62
  53. package/dist/openai-responses-contracts-DWrfMODE.mjs +81 -0
  54. package/dist/{openai-responses-contracts-BjBAqAg_.d.mts → openai-responses-contracts-Dflvrfa8.d.mts} +9 -5
  55. package/dist/{openai-responses-payload-policy-rLRPsSmB.d.mts → openai-responses-payload-policy-C7GsA1y0.d.mts} +5 -3
  56. package/dist/openai-responses-prompt-observer-internal-C15_-OwV.mjs +195 -0
  57. package/dist/{openai-responses-shared-B8RdBPCv.mjs → openai-responses-shared-CwsziD_m.mjs} +385 -178
  58. package/dist/openai-responses-terminal-usage-Dl3J6zrf.d.mts +47 -0
  59. package/dist/{openai-tool-schema-CzjyYXun.mjs → openai-tool-schema-BO8rwyAD.mjs} +92 -68
  60. package/dist/{openai-transport-params-9aPuV5YY.mjs → openai-transport-params-DQeuAvBl.mjs} +157 -47
  61. package/dist/{positive-integer-41zhOdcV.mjs → positive-integer-DtjCkbue.mjs} +1 -1
  62. package/dist/{provider-error-BA-v_tKd.mjs → provider-error-DDqw9Qda.mjs} +100 -38
  63. package/dist/{provider-options-Ceqv1OKk.d.mts → provider-options-DprLsWh9.d.mts} +9 -6
  64. package/dist/{provider-replay-context-CJ_YvcEW.mjs → provider-replay-context-CnUSOwhr.mjs} +1 -1
  65. package/dist/{provider-transcript-transform-V5YzU9zh.mjs → provider-transcript-transform-BsRAhuWJ.mjs} +1 -1
  66. package/dist/{provider-transport-turn-state-D5EXOFL2.mjs → provider-transport-turn-state-CkGToCD2.mjs} +1 -1
  67. package/dist/{provider-types-CVjKjsuq.d.mts → provider-types-CAKRC7N5.d.mts} +3 -3
  68. package/dist/provider-types.d.mts +5 -6
  69. package/dist/providers.d.mts +2 -2
  70. package/dist/providers.mjs +10 -10
  71. package/dist/{reasoning-tag-text-partitioner-BcR5pztD.mjs → reasoning-tag-text-partitioner-Dy9IO8Dc.mjs} +15 -7
  72. package/dist/{simple-options-BQbb4yQL.mjs → simple-options-C6cFWj_f.mjs} +5 -3
  73. package/dist/{usage-cost-BNWbbXav.mjs → src-DeKjbE8I.mjs} +3 -5
  74. package/dist/{stream-first-event-timeout-2hfrquuz.mjs → stream-first-event-timeout-C9ZadkJW.mjs} +1 -1
  75. package/dist/{string-normalization-CmLIasuf.mjs → string-normalization-J9ZiLfGO.mjs} +13 -1
  76. package/dist/tool-schema-json-projection-CD9c_fK8.mjs +134 -0
  77. package/dist/{transport-stream-shared-DNvmoWnv.d.mts → transport-stream-shared-BbUkFaHi.d.mts} +4 -4
  78. package/dist/{transport-stream-shared-zHll9BxO.mjs → transport-stream-shared-D-6FQSHm.mjs} +14 -14
  79. package/dist/{transport-utils-zrYjICLZ.mjs → transport-utils-1cyq5Y7x.mjs} +3 -3
  80. package/dist/transports.d.mts +26 -12
  81. package/dist/transports.mjs +130 -449
  82. package/dist/{types-Ntv5z2g2.d.mts → types-4_uVs5WH.d.mts} +47 -3
  83. package/dist/types-DkJfb4W3.d.mts +1 -0
  84. package/dist/types.d.mts +5 -6
  85. package/dist/types.mjs +2 -3
  86. package/dist/{validation-B0t_G2H6.d.mts → validation-Ctzu2DhF.d.mts} +1 -1
  87. package/dist/{validation-BDzVDnTs.mjs → validation-Dw7cb6BV.mjs} +1 -0
  88. package/dist/validation.d.mts +1 -1
  89. package/dist/validation.mjs +1 -1
  90. package/package.json +10 -5
  91. package/dist/diagnostics-DnPnOui6.d.mts +0 -29
  92. package/dist/event-stream-C3WGFsum.d.mts +0 -1
  93. package/dist/openai-responses-contracts-DDOHA62Y.mjs +0 -245
  94. package/dist/openai-responses-prompt-observer-internal-f8J7wpsk.mjs +0 -32
  95. package/dist/src-DDmEryvj.mjs +0 -2
  96. package/dist/tool-schema-json-projection-ClptDdAO.mjs +0 -82
  97. package/dist/types-DlfwzH3T.d.mts +0 -1
@@ -0,0 +1,47 @@
1
+ import { K as StopReason, a as AssistantMessage, ot as Usage } from "./types-4_uVs5WH.mjs";
2
+ import "./types-DkJfb4W3.mjs";
3
+ import OpenAI from "openai";
4
+ //#region packages/ai/src/providers/openai-responses-terminal-usage.d.ts
5
+ /** A known output ceiling can resume sampling after admitted tools have settled. */
6
+ declare function isResponsesOutputLimitToolCallError(message: Pick<AssistantMessage, "stopReason" | "errorCode" | "diagnostics">): boolean;
7
+ /** Terminal usage payload, modeled structurally so untyped callers can pass raw records. */
8
+ type ResponsesTerminalUsagePayload = {
9
+ input_tokens?: number | null;
10
+ output_tokens?: number | null;
11
+ total_tokens?: number | null;
12
+ input_tokens_details?: {
13
+ cached_tokens?: number | null;
14
+ cache_write_tokens?: number | null;
15
+ } | null;
16
+ output_tokens_details?: {
17
+ reasoning_tokens?: number | null;
18
+ } | null;
19
+ };
20
+ /**
21
+ * Split a terminal usage payload into the priced buckets.
22
+ *
23
+ * OpenAI includes cache reads and writes in `input_tokens`, so both are subtracted out of the
24
+ * billable input bucket. `total_tokens` comes from the payload, but never below the sum of the
25
+ * split buckets: proxies routinely omit it (reporting 0 would understate the turn), and a payload
26
+ * whose `cached_tokens` exceeds `input_tokens` clamps the input bucket, leaving the reported total
27
+ * short of what the buckets actually price.
28
+ */
29
+ declare function mapResponsesTerminalUsage(usage: ResponsesTerminalUsagePayload | undefined | null): Pick<Usage, "input" | "output" | "cacheRead" | "cacheWrite" | "contextUsage" | "totalTokens"> | undefined;
30
+ /** Reasoning tokens are reported by the agent path only; the package path does not track them. */
31
+ declare function readResponsesReasoningTokens(usage: ResponsesTerminalUsagePayload | undefined | null): number | undefined;
32
+ /**
33
+ * Resolve the terminal stop reason, including the two overrides every Responses path shares: a
34
+ * content-filtered turn is a provider error rather than a truncated answer, and a turn that
35
+ * produced tool calls reports `toolUse` instead of a plain stop.
36
+ */
37
+ declare function resolveResponsesTerminalStopReason(params: {
38
+ status: OpenAI.Responses.ResponseStatus | undefined;
39
+ terminalEventType?: "response.completed" | "response.incomplete";
40
+ incompleteReason?: string;
41
+ hasToolCall: boolean;
42
+ }): {
43
+ stopReason: StopReason;
44
+ errorMessage?: string;
45
+ };
46
+ //#endregion
47
+ export { resolveResponsesTerminalStopReason as a, readResponsesReasoningTokens as i, isResponsesOutputLimitToolCallError as n, mapResponsesTerminalUsage as r, ResponsesTerminalUsagePayload as t };
@@ -1,6 +1,6 @@
1
1
  import { n as normalizeLowercaseStringOrEmpty } from "./string-coerce-fsri9iCu.mjs";
2
2
  import { o as isRecord } from "./record-coerce-DwRYMj3t.mjs";
3
- import { r as uniqueValues, t as normalizeStringEntries } from "./string-normalization-CmLIasuf.mjs";
3
+ import { i as uniqueValues, t as normalizeStringEntries } from "./string-normalization-J9ZiLfGO.mjs";
4
4
  //#region packages/ai/src/providers/clean-for-gemini.ts
5
5
  const GEMINI_UNSUPPORTED_SCHEMA_KEYWORDS = /* @__PURE__ */ new Set([
6
6
  "patternProperties",
@@ -272,9 +272,7 @@ function flattenUnionFallback(obj, variants) {
272
272
  return merged;
273
273
  }
274
274
  function cleanSchemaForGemini(schema) {
275
- if (!schema || typeof schema !== "object") return schema;
276
- if (Array.isArray(schema)) return schema.map(cleanSchemaForGemini);
277
- return cleanSchemaForGeminiWithDefs(schema, extendSchemaDefs$1(void 0, schema), void 0);
275
+ return cleanSchemaForGeminiWithDefs(schema, void 0, void 0);
278
276
  }
279
277
  //#endregion
280
278
  //#region packages/ai/src/providers/clean-for-llamacpp-gbnf.ts
@@ -420,6 +418,58 @@ function stripUnsupportedSchemaKeywords(schema, unsupportedKeywords) {
420
418
  return cleaned;
421
419
  }
422
420
  //#endregion
421
+ //#region packages/ai/src/providers/tool-schema-normalization-cache.ts
422
+ let preparedSchemas;
423
+ /** Only synchronous conversion owns these fresh projections; no facts survive its return. */
424
+ function withPreparedToolSchemaNormalization(schemas, convert) {
425
+ const previous = preparedSchemas;
426
+ preparedSchemas = schemas;
427
+ try {
428
+ return convert();
429
+ } finally {
430
+ preparedSchemas = previous;
431
+ }
432
+ }
433
+ function createBoundedSchemaCache(maxEntries) {
434
+ const schemas = /* @__PURE__ */ new WeakMap();
435
+ return {
436
+ get(source, key) {
437
+ return schemas.get(source)?.find((entry) => entry.key === key)?.value;
438
+ },
439
+ remember(source, key, value) {
440
+ const entries = schemas.get(source) ?? [];
441
+ schemas.set(source, [{
442
+ key,
443
+ value
444
+ }, ...entries.filter((entry) => entry.key !== key)].slice(0, maxEntries));
445
+ return value;
446
+ }
447
+ };
448
+ }
449
+ /** Prepared variants cannot evict direct callers' identity-preserving cache entries. */
450
+ function createToolSchemaNormalizationCache(maxEntries) {
451
+ const directCache = createBoundedSchemaCache(maxEntries);
452
+ const preparedCache = createBoundedSchemaCache(maxEntries);
453
+ return {
454
+ get(source, key) {
455
+ const prepared = preparedSchemas?.get(source);
456
+ if (!prepared) return directCache.get(source, key);
457
+ const entry = preparedCache.get(prepared.source, key);
458
+ return entry?.inputJson === prepared.inputJson ? JSON.parse(entry.outputJson) : void 0;
459
+ },
460
+ remember(source, key, value) {
461
+ const prepared = preparedSchemas?.get(source);
462
+ if (!prepared) return directCache.remember(source, key, value);
463
+ const outputJson = JSON.stringify(value);
464
+ if (outputJson !== void 0) preparedCache.remember(prepared.source, key, {
465
+ inputJson: prepared.inputJson,
466
+ outputJson
467
+ });
468
+ return value;
469
+ }
470
+ };
471
+ }
472
+ //#endregion
423
473
  //#region packages/ai/src/providers/agent-tools-parameter-schema.ts
424
474
  /**
425
475
  * Normalizes model-facing tool parameter schemas across provider quirks.
@@ -444,8 +494,7 @@ function resolveUnsupportedToolSchemaKeywords(modelOrCompat) {
444
494
  function shouldOmitEmptyArrayItems(modelOrCompat) {
445
495
  return extractToolSchemaModelCompat(modelOrCompat)?.omitEmptyArrayItems === true;
446
496
  }
447
- const MAX_TOOL_PARAMETER_SCHEMA_CACHE_ENTRIES_PER_SCHEMA = 8;
448
- const toolParameterSchemaCache = /* @__PURE__ */ new WeakMap();
497
+ const toolParameterSchemaCache = createToolSchemaNormalizationCache(8);
449
498
  function resolveToolParameterSchemaCacheKey(options) {
450
499
  const normalizedProvider = normalizeLowercaseStringOrEmpty(options?.modelProvider);
451
500
  const normalizedModelId = normalizeLowercaseStringOrEmpty(options?.modelId);
@@ -460,17 +509,6 @@ function resolveToolParameterSchemaCacheKey(options) {
460
509
  omitEmptyArrayItems
461
510
  ]);
462
511
  }
463
- function getCachedToolParameterSchema(schema, key) {
464
- return toolParameterSchemaCache.get(schema)?.find((entry) => entry.key === key)?.value;
465
- }
466
- function rememberCachedToolParameterSchema(schema, key, value) {
467
- const entries = toolParameterSchemaCache.get(schema) ?? [];
468
- toolParameterSchemaCache.set(schema, [{
469
- key,
470
- value
471
- }, ...entries.filter((entry) => entry.key !== key)].slice(0, MAX_TOOL_PARAMETER_SCHEMA_CACHE_ENTRIES_PER_SCHEMA));
472
- return value;
473
- }
474
512
  function isGeminiModelId(modelId) {
475
513
  return /(?:^|[/:])gemini(?:$|[-/:.])/.test(modelId);
476
514
  }
@@ -570,7 +608,8 @@ function normalizeArraySchemaItems(schema, mode) {
570
608
  }
571
609
  let next = value;
572
610
  if (SCHEMA_MAP_KEYS.has(key) && isRecord(value)) {
573
- const entries = Object.entries(value).map(([entryKey, entry]) => [entryKey, normalizeArraySchemaItems(entry, mode)]);
611
+ const entries = Object.entries(value);
612
+ for (const entry of entries) entry[1] = normalizeArraySchemaItems(entry[1], mode);
574
613
  if (entries.some(([entryKey, entry]) => entry !== value[entryKey])) next = Object.fromEntries(entries);
575
614
  } else if (SCHEMA_OBJECT_KEYS.has(key) || SCHEMA_ARRAY_KEYS.has(key)) {
576
615
  const valueMode = SCHEMA_OBJECT_KEYS.has(key) || Array.isArray(value) ? mode : "add";
@@ -699,7 +738,9 @@ function inlineLocalSchemaRefsWithDefs(schema, defs, refStack, state, rootDocume
699
738
  continue;
700
739
  }
701
740
  if (SCHEMA_MAP_KEYS.has(key) && isRecord(value)) {
702
- setOwnSchemaProperty(result, key, Object.fromEntries(Object.entries(value).map(([entryKey, entryValue]) => [entryKey, inlineLocalSchemaRefsWithDefs(entryValue, nextDefs, refStack, state, rootDocument)])));
741
+ const entries = Object.entries(value);
742
+ for (const entry of entries) entry[1] = inlineLocalSchemaRefsWithDefs(entry[1], nextDefs, refStack, state, rootDocument);
743
+ setOwnSchemaProperty(result, key, Object.fromEntries(entries));
703
744
  continue;
704
745
  }
705
746
  if (SCHEMA_OBJECT_KEYS.has(key) && isRecord(value)) {
@@ -722,7 +763,8 @@ function inlineLocalSchemaRefsWithDefs(schema, defs, refStack, state, rootDocume
722
763
  /** Inline local $ref pointers so providers receive self-contained tool schemas. */
723
764
  function inlineLocalToolSchemaRefs(schema) {
724
765
  if (!schema || typeof schema !== "object") return schema;
725
- return inlineLocalSchemaRefsWithDefs(schema, extendSchemaDefs(void 0, schema), void 0, { unresolvedLocalRefs: false }, schema);
766
+ const schemaRecord = schema;
767
+ return inlineLocalSchemaRefsWithDefs(schema, Array.isArray(schema) ? extendSchemaDefs(void 0, schemaRecord) : void 0, void 0, { unresolvedLocalRefs: false }, schema);
726
768
  }
727
769
  const OPENAPI_SCHEMA_ANNOTATION_KEYS = /* @__PURE__ */ new Set([
728
770
  "discriminator",
@@ -774,46 +816,40 @@ function normalizeOpenApiSchemaKeywords(schema) {
774
816
  if (!isRecord(schema)) return schema;
775
817
  let changed = false;
776
818
  const nullable = schema.nullable === true;
777
- const normalized = {};
778
- for (const [key, value] of Object.entries(schema)) {
819
+ const entries = Object.entries(schema);
820
+ let normalized;
821
+ for (const [key, value] of entries) {
779
822
  if (key === "nullable" || OPENAPI_SCHEMA_ANNOTATION_KEYS.has(key)) {
823
+ normalized ??= Object.fromEntries(entries);
824
+ delete normalized[key];
780
825
  changed = true;
781
826
  continue;
782
827
  }
783
- if (SCHEMA_LITERAL_KEYS.has(key)) {
784
- normalized[key] = value;
785
- continue;
786
- }
828
+ if (SCHEMA_LITERAL_KEYS.has(key) || key === "components") continue;
829
+ let next = value;
787
830
  if (SCHEMA_MAP_KEYS.has(key) && isRecord(value)) {
788
831
  let mapChanged = false;
789
- const next = Object.fromEntries(Object.entries(value).map(([entryKey, entryValue]) => {
790
- const nextEntry = normalizeOpenApiSchemaKeywords(entryValue);
791
- mapChanged ||= nextEntry !== entryValue;
792
- return [entryKey, nextEntry];
793
- }));
794
- normalized[key] = mapChanged ? next : value;
795
- changed ||= mapChanged;
832
+ const mapEntries = Object.entries(value);
833
+ for (const entry of mapEntries) {
834
+ const nextEntry = normalizeOpenApiSchemaKeywords(entry[1]);
835
+ mapChanged ||= nextEntry !== entry[1];
836
+ entry[1] = nextEntry;
837
+ }
838
+ next = mapChanged ? Object.fromEntries(mapEntries) : value;
839
+ } else if (SCHEMA_OBJECT_KEYS.has(key) && isRecord(value)) next = normalizeOpenApiSchemaKeywords(value);
840
+ else if (SCHEMA_ARRAY_KEYS.has(key) && Array.isArray(value)) {
841
+ const nextEntries = value.map(normalizeOpenApiSchemaKeywords);
842
+ (normalized ??= Object.fromEntries(entries))[key] = nextEntries;
843
+ changed ||= nextEntries.some((entry, index) => entry !== value[index]);
796
844
  continue;
797
845
  }
798
- if (key === "components") {
799
- normalized[key] = value;
800
- continue;
801
- }
802
- if (SCHEMA_OBJECT_KEYS.has(key) && isRecord(value)) {
803
- const next = normalizeOpenApiSchemaKeywords(value);
804
- normalized[key] = next;
805
- changed ||= next !== value;
806
- continue;
807
- }
808
- if (SCHEMA_ARRAY_KEYS.has(key) && Array.isArray(value)) {
809
- const next = value.map(normalizeOpenApiSchemaKeywords);
810
- normalized[key] = next;
811
- changed ||= next.some((entry, index) => entry !== value[index]);
812
- continue;
846
+ if (next !== value) {
847
+ (normalized ??= Object.fromEntries(entries))[key] = next;
848
+ changed = true;
813
849
  }
814
- setOwnSchemaProperty(normalized, key, value);
815
850
  }
816
851
  if (nullable) {
852
+ normalized ??= Object.fromEntries(entries);
817
853
  if (hasOpenApiComposition(normalized)) return wrapNullableComposedSchema(normalized);
818
854
  if ("type" in normalized) {
819
855
  const nextType = appendNullSchemaType(normalized.type);
@@ -821,7 +857,7 @@ function normalizeOpenApiSchemaKeywords(schema) {
821
857
  }
822
858
  if (Array.isArray(normalized.enum) && !normalized.enum.includes(null)) normalized.enum = [...normalized.enum, null];
823
859
  }
824
- return changed || nullable ? normalized : schema;
860
+ return changed || nullable ? normalized ?? schema : schema;
825
861
  }
826
862
  function normalizeToolParameterSchemaUncached(schema, options) {
827
863
  const inlinedSchema = normalizeOpenApiSchemaKeywords(inlineLocalToolSchemaRefs(schema));
@@ -897,9 +933,9 @@ function normalizeToolParameterSchemaUncached(schema, options) {
897
933
  function normalizeToolParameterSchema(schema, options) {
898
934
  if (!schema || typeof schema !== "object") return normalizeToolParameterSchemaUncached(schema, options);
899
935
  const cacheKey = resolveToolParameterSchemaCacheKey(options);
900
- const cached = getCachedToolParameterSchema(schema, cacheKey);
936
+ const cached = toolParameterSchemaCache.get(schema, cacheKey);
901
937
  if (cached) return cached;
902
- return rememberCachedToolParameterSchema(schema, cacheKey, normalizeToolParameterSchemaUncached(schema, options));
938
+ return toolParameterSchemaCache.remember(schema, cacheKey, normalizeToolParameterSchemaUncached(schema, options));
903
939
  }
904
940
  //#endregion
905
941
  //#region packages/ai/src/providers/openai-tool-schema-compat.ts
@@ -1048,8 +1084,7 @@ function findOpenAIStrictSchemaViolations(schema, path, options) {
1048
1084
  *
1049
1085
  * Caches normalized object inputs by provider compatibility so repeated inventory builds preserve identity.
1050
1086
  */
1051
- const MAX_STRICT_SCHEMA_CACHE_ENTRIES_PER_SCHEMA = 8;
1052
- const strictOpenAISchemaCache = /* @__PURE__ */ new WeakMap();
1087
+ const strictOpenAISchemaCache = createToolSchemaNormalizationCache(8);
1053
1088
  function resolveToolSchemaModelCompat(compat) {
1054
1089
  if (!compat) return;
1055
1090
  const unsupportedToolSchemaKeywords = Array.isArray(compat.unsupportedToolSchemaKeywords) ? compat.unsupportedToolSchemaKeywords.filter((keyword) => typeof keyword === "string") : [];
@@ -1063,25 +1098,14 @@ function resolveStrictOpenAISchemaCacheKey(modelCompat) {
1063
1098
  const compat = resolveToolSchemaModelCompat(modelCompat);
1064
1099
  return JSON.stringify([[...compat?.unsupportedToolSchemaKeywords ?? []].toSorted(), shouldOmitEmptyArrayItems(compat)]);
1065
1100
  }
1066
- function readCachedStrictOpenAISchema(schema, key) {
1067
- return strictOpenAISchemaCache.get(schema)?.find((entry) => entry.key === key)?.value;
1068
- }
1069
- function rememberStrictOpenAISchema(schema, key, value) {
1070
- const entries = strictOpenAISchemaCache.get(schema) ?? [];
1071
- strictOpenAISchemaCache.set(schema, [{
1072
- key,
1073
- value
1074
- }, ...entries.filter((entry) => entry.key !== key)].slice(0, MAX_STRICT_SCHEMA_CACHE_ENTRIES_PER_SCHEMA));
1075
- return value;
1076
- }
1077
1101
  /** Normalizes a tool parameter schema into the OpenAI strict JSON-schema subset. */
1078
1102
  function normalizeStrictOpenAIJsonSchema(schema, modelCompat) {
1079
1103
  const schemaInput = schema ?? {};
1080
1104
  if (!schemaInput || typeof schemaInput !== "object") return normalizeStrictOpenAIJsonSchemaRecursive(normalizeToolParameterSchema(schemaInput, { modelCompat: resolveToolSchemaModelCompat(modelCompat) }), 0);
1081
1105
  const cacheKey = resolveStrictOpenAISchemaCacheKey(modelCompat);
1082
- const cached = readCachedStrictOpenAISchema(schemaInput, cacheKey);
1106
+ const cached = strictOpenAISchemaCache.get(schemaInput, cacheKey);
1083
1107
  if (cached !== void 0) return cached;
1084
- return rememberStrictOpenAISchema(schemaInput, cacheKey, normalizeStrictOpenAIJsonSchemaRecursive(normalizeToolParameterSchema(schemaInput, { modelCompat: resolveToolSchemaModelCompat(modelCompat) }), 0));
1108
+ return strictOpenAISchemaCache.remember(schemaInput, cacheKey, normalizeStrictOpenAIJsonSchemaRecursive(normalizeToolParameterSchema(schemaInput, { modelCompat: resolveToolSchemaModelCompat(modelCompat) }), 0));
1085
1109
  }
1086
1110
  function normalizeStrictOpenAIJsonSchemaRecursive(schema, depth) {
1087
1111
  if (Array.isArray(schema)) {
@@ -1164,4 +1188,4 @@ function resolveOpenAIProjectedToolsStrictToolFlag(projection, strict) {
1164
1188
  return projection.tools.every((tool) => isStrictOpenAIJsonSchemaCompatible(tool.parameters));
1165
1189
  }
1166
1190
  //#endregion
1167
- export { cleanSchemaForGemini as _, resolveOpenAIProjectedToolsStrictToolFlag as a, extractToolSchemaModelCompat as c, shouldOmitEmptyArrayItems as d, stripUnsupportedSchemaKeywords as f, GEMINI_UNSUPPORTED_SCHEMA_KEYWORDS as g, findLlamacppGbnfSchemaViolations as h, normalizeStrictOpenAIJsonSchema as i, normalizeToolParameterSchema as l, cleanSchemaForLlamacppGbnf as m, isStrictOpenAIJsonSchemaCompatible as n, findOpenAIStrictSchemaViolations as o, LLAMACPP_GBNF_MAX_REPETITION_THRESHOLD as p, normalizeOpenAIStrictToolParameters as r, normalizeOpenAIStrictCompatSchema as s, findOpenAIStrictToolProjectionDiagnostics as t, resolveUnsupportedToolSchemaKeywords as u };
1191
+ export { GEMINI_UNSUPPORTED_SCHEMA_KEYWORDS as _, resolveOpenAIProjectedToolsStrictToolFlag as a, extractToolSchemaModelCompat as c, shouldOmitEmptyArrayItems as d, withPreparedToolSchemaNormalization as f, findLlamacppGbnfSchemaViolations as g, cleanSchemaForLlamacppGbnf as h, normalizeStrictOpenAIJsonSchema as i, normalizeToolParameterSchema as l, LLAMACPP_GBNF_MAX_REPETITION_THRESHOLD as m, isStrictOpenAIJsonSchemaCompatible as n, findOpenAIStrictSchemaViolations as o, stripUnsupportedSchemaKeywords as p, normalizeOpenAIStrictToolParameters as r, normalizeOpenAIStrictCompatSchema as s, findOpenAIStrictToolProjectionDiagnostics as t, resolveUnsupportedToolSchemaKeywords as u, cleanSchemaForGemini as v };
@@ -1,18 +1,20 @@
1
1
  import { a as normalizeOptionalString, n as normalizeLowercaseStringOrEmpty } from "./string-coerce-fsri9iCu.mjs";
2
- import { A as applyProviderReportedUsageCost, j as calculateCost, n as getAiTransportHost } from "./host-B8YfDGd4.mjs";
3
2
  import { o as isRecord, r as asOptionalObjectRecord } from "./record-coerce-DwRYMj3t.mjs";
4
- import { l as usesNativeOpenAICodexResponsesBackend, n as clampOpenAIPromptCacheKey, s as resolveOpenAICompletionsCompat } from "./openai-prompt-cache-Bds-n_9Q.mjs";
5
- import { i as isCodeModeModelVisibleToolName } from "./transport-utils-zrYjICLZ.mjs";
6
- import { n as resolveModelRequestTimeoutMs, o as resolveProviderRequestPolicyConfig } from "./host-policy-Zcg_cNz8.mjs";
7
- import { t as projectRuntimeToolInputSchema } from "./tool-schema-json-projection-ClptDdAO.mjs";
8
- import { O as headersToRecord, p as notifyProviderHttpResponse, v as transportAbortError } from "./transport-stream-shared-zHll9BxO.mjs";
3
+ import { a as resolveOpenAIModelReasoningEfforts, d as MODEL_CATALOG_THINKING_LEVELS, i as normalizeOpenAIReasoningEffort, l as supportsOpenAIReasoningEffort, o as resolveOpenAIReasoningEffortForModel, p as resolveOpenAIThinkingApi, s as resolveOpenAIReasoningEffortMapping } from "./openai-reasoning-effort-NlFZmfEu.mjs";
4
+ import { A as applyProviderReportedUsageCost, M as clampThinkingLevel, j as calculateCost, n as getAiTransportHost } from "./host-B4MeUNBc.mjs";
5
+ import { n as clampOpenAIPromptCacheKey } from "./openai-prompt-cache-1wfaIszn.mjs";
6
+ import { i as isCodeModeModelVisibleToolName } from "./transport-utils-1cyq5Y7x.mjs";
7
+ import { i as resolveOpenAICompletionsCompat, o as usesNativeOpenAICodexResponsesBackend } from "./openai-completions-compat-CkwdxTZx.mjs";
8
+ import { n as resolveModelRequestTimeoutMs, o as resolveProviderRequestPolicyConfig } from "./host-policy-DUnXSx0I.mjs";
9
+ import { n as projectRuntimeToolInputSchema, t as prepareRuntimeToolInputSchema } from "./tool-schema-json-projection-CD9c_fK8.mjs";
10
+ import { O as headersToRecord, p as notifyProviderHttpResponse, v as transportAbortError } from "./transport-stream-shared-D-6FQSHm.mjs";
9
11
  import { n as resolveOpencodeSessionHeaders } from "./session-affinity-Bcunsn4I.mjs";
10
- import { i as OPENAI_RESPONSES_APIS } from "./openai-responses-contracts-DDOHA62Y.mjs";
11
- import { a as resolveOpenAIProjectedToolsStrictToolFlag, t as findOpenAIStrictToolProjectionDiagnostics } from "./openai-tool-schema-CzjyYXun.mjs";
12
- import { createHash } from "node:crypto";
12
+ import { a as resolveOpenAIProjectedToolsStrictToolFlag, t as findOpenAIStrictToolProjectionDiagnostics } from "./openai-tool-schema-BO8rwyAD.mjs";
13
+ import { i as OPENAI_RESPONSES_APIS } from "./openai-responses-contracts-DWrfMODE.mjs";
14
+ import { hash } from "node:crypto";
13
15
  //#region packages/normalization-core/src/node-crypto.ts
14
16
  function sha256Hex(input) {
15
- return createHash("sha256").update(input).digest("hex");
17
+ return hash("sha256", input, "hex");
16
18
  }
17
19
  function sha256HexPrefixCore(input, length) {
18
20
  return sha256Hex(input).slice(0, length);
@@ -29,6 +31,16 @@ function redactIdentifier(value, opts) {
29
31
  /** Shared options, usage shape, cache identity, ordering, and stream scheduling for OpenAI APIs. */
30
32
  const MODEL_STREAM_COOPERATIVE_YIELD_INTERVAL_MS = 12;
31
33
  const MODEL_STREAM_COOPERATIVE_YIELD_MAX_EVENTS = 64;
34
+ const OPENAI_RESPONSE_MODEL_HEADER_NAMES = /* @__PURE__ */ new Set(["openai-model", "x-openai-model"]);
35
+ const OPENAI_RESPONSE_MODEL_EVENT_TYPES = /* @__PURE__ */ new Set([
36
+ "response.created",
37
+ "response.in_progress",
38
+ "response.completed",
39
+ "response.done",
40
+ "response.incomplete",
41
+ "response.failed"
42
+ ]);
43
+ const OPENAI_DATED_MODEL_SUFFIX = /-(?:\d{8}|\d{4}-\d{2}-\d{2})$/;
32
44
  const GEMINI_THOUGHT_SIGNATURE_VALIDATOR_SKIP = "skip_thought_signature_validator";
33
45
  const log = {
34
46
  debug(message, data) {
@@ -44,6 +56,69 @@ const log = {
44
56
  getAiTransportHost().logWarn("openai-transport", message, data);
45
57
  }
46
58
  };
59
+ const OPENAI_RESPONSE_MODEL_CONFLICT = "Conflicting OpenAI response model attestations";
60
+ function splitOpenAIResponseModelHeader(value) {
61
+ return value ? value.split(",").map((part) => part.trim()).filter(Boolean) : [];
62
+ }
63
+ function readOpenAIResponseModelHeaders(headers) {
64
+ return [...OPENAI_RESPONSE_MODEL_HEADER_NAMES].flatMap((name) => splitOpenAIResponseModelHeader(headers.get(name)));
65
+ }
66
+ function readOpenAIResponseModelHeaderRecord(headers) {
67
+ if (!isRecord(headers)) return [];
68
+ return Object.entries(headers).filter(([name]) => OPENAI_RESPONSE_MODEL_HEADER_NAMES.has(name.toLowerCase())).flatMap(([, value]) => typeof value === "string" ? splitOpenAIResponseModelHeader(value) : []);
69
+ }
70
+ function readOpenAIResponseModelEvent(event) {
71
+ if (!isRecord(event)) return [];
72
+ const response = isRecord(event.response) ? event.response : void 0;
73
+ return [
74
+ ...OPENAI_RESPONSE_MODEL_EVENT_TYPES.has(String(event.type)) && typeof response?.model === "string" && response.model.trim() ? [response.model.trim()] : [],
75
+ ...readOpenAIResponseModelHeaderRecord(response?.headers),
76
+ ...readOpenAIResponseModelHeaderRecord(event.headers)
77
+ ];
78
+ }
79
+ function reconcileOpenAIResponseModels(current, observed) {
80
+ if (!current || current === observed) return observed;
81
+ const currentBase = current.replace(OPENAI_DATED_MODEL_SUFFIX, "");
82
+ const observedBase = observed.replace(OPENAI_DATED_MODEL_SUFFIX, "");
83
+ if (currentBase !== observedBase) return;
84
+ if (currentBase === current && observedBase !== observed) return observed;
85
+ if (observedBase === observed && currentBase !== current) return current;
86
+ }
87
+ function createResponseModelTracker(enabled = true) {
88
+ let responseModel;
89
+ const observe = (models) => {
90
+ for (const model of models) {
91
+ const reconciled = reconcileOpenAIResponseModels(responseModel, model);
92
+ if (!reconciled) throw new Error(OPENAI_RESPONSE_MODEL_CONFLICT);
93
+ responseModel = reconciled;
94
+ }
95
+ };
96
+ const begin = (headers) => {
97
+ responseModel = void 0;
98
+ if (enabled && headers) observe(readOpenAIResponseModelHeaders(headers));
99
+ };
100
+ const observeEvent = (event) => {
101
+ if (enabled) observe(readOpenAIResponseModelEvent(event));
102
+ return responseModel;
103
+ };
104
+ const resolve = () => responseModel;
105
+ return {
106
+ begin,
107
+ observeEvent,
108
+ resolve,
109
+ track(response, stream) {
110
+ if (!enabled) return stream;
111
+ return (async function* () {
112
+ begin(response?.headers);
113
+ for await (const event of stream) {
114
+ observeEvent(event);
115
+ yield event;
116
+ }
117
+ })();
118
+ },
119
+ terminalOptions: enabled ? { resolveResponseModel: resolve } : {}
120
+ };
121
+ }
47
122
  function resolveOpenAIClientBaseUrl(model, baseUrl = model.baseUrl) {
48
123
  if (baseUrl?.trim()) return baseUrl;
49
124
  if (model.provider.trim().toLowerCase() === "openai") return;
@@ -192,14 +267,13 @@ function createModelStreamCooperativeScheduler(signal) {
192
267
  return { async afterEvent() {
193
268
  throwIfModelStreamAborted(signal);
194
269
  eventsSinceYield += 1;
195
- const now = Date.now();
196
- if (eventsSinceYield < MODEL_STREAM_COOPERATIVE_YIELD_MAX_EVENTS && now - lastYieldedAt < MODEL_STREAM_COOPERATIVE_YIELD_INTERVAL_MS) return;
270
+ if (eventsSinceYield < MODEL_STREAM_COOPERATIVE_YIELD_MAX_EVENTS && Date.now() - lastYieldedAt < MODEL_STREAM_COOPERATIVE_YIELD_INTERVAL_MS) return;
197
271
  eventsSinceYield = 0;
198
- lastYieldedAt = now;
199
272
  await new Promise((resolve) => {
200
273
  setTimeout(resolve, 0);
201
274
  });
202
275
  throwIfModelStreamAborted(signal);
276
+ lastYieldedAt = Date.now();
203
277
  } };
204
278
  }
205
279
  function resolvePromptCacheKey(options, cacheRetention) {
@@ -262,6 +336,45 @@ function readOpenAICompletionsContentPartDeltas(content) {
262
336
  return [];
263
337
  }
264
338
  //#endregion
339
+ //#region packages/ai/src/transports/openai-reasoning-compat.ts
340
+ /** Explicit model reasoning-effort compatibility metadata. */
341
+ function readCompatReasoningEffortMap(compat) {
342
+ const rawMap = asOptionalObjectRecord(asOptionalObjectRecord(compat)?.reasoningEffortMap);
343
+ if (!rawMap) return {};
344
+ return Object.fromEntries(Object.entries(rawMap).filter((entry) => typeof entry[1] === "string"));
345
+ }
346
+ /** Resolves the reasoning effort remap for an OpenAI-compatible model. */
347
+ function resolveOpenAIReasoningEffortMap(model, fallbackMap = {}) {
348
+ return {
349
+ ...fallbackMap,
350
+ ...readCompatReasoningEffortMap(model.compat)
351
+ };
352
+ }
353
+ //#endregion
354
+ //#region packages/ai/src/providers/openai-request-reasoning.ts
355
+ /** Preserve explicit off until the selected route maps it to its native value. */
356
+ function resolveOpenAISimpleReasoningEffort(model, reasoning) {
357
+ return reasoning === void 0 ? void 0 : clampThinkingLevel(model, reasoning);
358
+ }
359
+ function resolveOpenAIRequestReasoning(model, reasoning) {
360
+ const requested = normalizeOpenAIReasoningEffort(reasoning ?? "off");
361
+ const modelLevel = MODEL_CATALOG_THINKING_LEVELS.find((candidate) => candidate === requested);
362
+ const modelMapped = modelLevel ? model.thinkingLevelMap?.[modelLevel] : void 0;
363
+ const mapped = modelMapped === null ? null : resolveOpenAIReasoningEffortMapping(requested, resolveOpenAIReasoningEffortMap(model)) ?? modelMapped;
364
+ const intent = mapped !== void 0 ? mapped?.trim() : reasoning === void 0 ? void 0 : requested;
365
+ const normalizedIntent = normalizeOpenAIReasoningEffort(intent ?? "off");
366
+ const supported = resolveOpenAIModelReasoningEfforts(model);
367
+ const effort = !model.reasoning || supported?.length === 0 || intent === void 0 ? void 0 : supported === void 0 ? mapped !== void 0 ? intent : requested === "off" ? "none" : requested : resolveOpenAIReasoningEffortForModel({
368
+ model,
369
+ effort: requested,
370
+ fallbackMap: { [requested]: intent }
371
+ });
372
+ return {
373
+ effort: effort === "none" && resolveOpenAIThinkingApi(model.api) === "openai-chatgpt-responses" && !supportsOpenAIReasoningEffort({ compat: model.compat }, "none") ? void 0 : effort,
374
+ thinkingEnabled: intent === void 0 ? void 0 : model.reasoning && normalizedIntent !== "off" && normalizedIntent !== "none"
375
+ };
376
+ }
377
+ //#endregion
265
378
  //#region packages/ai/src/providers/openai-tool-projection.ts
266
379
  function unreadableToolDiagnostic(toolIndex) {
267
380
  return {
@@ -271,6 +384,17 @@ function unreadableToolDiagnostic(toolIndex) {
271
384
  }
272
385
  /** Snapshots direct/custom tool descriptors before OpenAI payload construction. */
273
386
  function projectOpenAITools(tools) {
387
+ return projectOpenAIToolDescriptors(tools);
388
+ }
389
+ /** Package-private facts are consumed before the projection or payload can escape. */
390
+ function prepareOpenAITools(tools) {
391
+ const schemas = /* @__PURE__ */ new Map();
392
+ return {
393
+ projection: projectOpenAIToolDescriptors(tools, schemas),
394
+ schemas
395
+ };
396
+ }
397
+ function projectOpenAIToolDescriptors(tools, schemas) {
274
398
  let inputToolCount;
275
399
  try {
276
400
  inputToolCount = tools.length;
@@ -324,7 +448,8 @@ function projectOpenAITools(tools) {
324
448
  });
325
449
  continue;
326
450
  }
327
- const schemaProjection = projectRuntimeToolInputSchema(parameters ?? {}, `${name}.parameters`);
451
+ const prepared = schemas ? prepareRuntimeToolInputSchema(parameters ?? {}, `${name}.parameters`) : void 0;
452
+ const schemaProjection = prepared?.projection ?? projectRuntimeToolInputSchema(parameters ?? {}, `${name}.parameters`);
328
453
  if (!isRecord(schemaProjection.schema) || schemaProjection.violations.length > 0) {
329
454
  diagnostics.push({
330
455
  toolIndex,
@@ -333,6 +458,7 @@ function projectOpenAITools(tools) {
333
458
  });
334
459
  continue;
335
460
  }
461
+ if (prepared?.normalization) schemas?.set(schemaProjection.schema, prepared.normalization);
336
462
  let descriptionValue;
337
463
  try {
338
464
  descriptionValue = tool.description;
@@ -448,36 +574,10 @@ function reconcileOpenAICompletionsToolChoice(choice, projection) {
448
574
  };
449
575
  }
450
576
  //#endregion
451
- //#region packages/ai/src/transports/openai-reasoning-compat.ts
452
- /**
453
- * OpenAI reasoning-effort compatibility helpers.
454
- *
455
- * Keeps provider metadata and built-in model exceptions on one path before request payloads are built.
456
- */
457
- const OPENAI_MEDIUM_ONLY_REASONING_MODEL_IDS = /* @__PURE__ */ new Set(["gpt-5.1-codex-mini"]);
458
- function readCompatReasoningEffortMap(compat) {
459
- const rawMap = asOptionalObjectRecord(asOptionalObjectRecord(compat)?.reasoningEffortMap);
460
- if (!rawMap) return {};
461
- return Object.fromEntries(Object.entries(rawMap).filter((entry) => typeof entry[0] === "string" && typeof entry[1] === "string"));
462
- }
463
- /** Resolves the reasoning effort remap for an OpenAI-compatible model. */
464
- function resolveOpenAIReasoningEffortMap(model, fallbackMap = {}) {
465
- const provider = normalizeLowercaseStringOrEmpty(model.provider ?? "");
466
- const id = normalizeLowercaseStringOrEmpty(model.id ?? "");
467
- const builtinMap = provider === "openai" && OPENAI_MEDIUM_ONLY_REASONING_MODEL_IDS.has(id) ? {
468
- minimal: "medium",
469
- low: "medium"
470
- } : {};
471
- return {
472
- ...fallbackMap,
473
- ...builtinMap,
474
- ...readCompatReasoningEffortMap(model.compat)
475
- };
476
- }
477
- //#endregion
478
577
  //#region packages/ai/src/transports/openai-transport-params.ts
479
578
  const MAX_OPENAI_STRICT_TOOL_DOWNGRADE_DIAGNOSTIC_KEYS = 256;
480
579
  const loggedOpenAIStrictToolDowngradeDiagnosticKeys = /* @__PURE__ */ new Set();
580
+ const OPENAI_COMPLETIONS_APIS = /* @__PURE__ */ new Set(["openai-completions", "openclaw-openai-completions-transport"]);
481
581
  function readToolPayloadField(record, field) {
482
582
  try {
483
583
  return Object.hasOwn(record, field) ? record[field] : void 0;
@@ -616,6 +716,19 @@ function resolveOpenAIStrictToolFlagWithDiagnostics(projection, strictSetting, c
616
716
  function buildOpenAIClientHeaders(model, context, optionHeaders, turnHeaders, sessionId, cacheRetention) {
617
717
  const providerHeaders = { ...model.headers };
618
718
  if (model.provider === "github-copilot") Object.assign(providerHeaders, getAiTransportHost().buildCopilotDynamicHeaders(context.messages));
719
+ if (OPENAI_COMPLETIONS_APIS.has(model.api) && sessionId && cacheRetention !== "none") {
720
+ const { sessionAffinity } = resolveOpenAICompletionsCompat(model);
721
+ if (sessionAffinity !== "none") {
722
+ const affinityValue = clampOpenAIPromptCacheKey(sessionId) ?? sessionId;
723
+ const affinityHeaders = sessionAffinity === "openrouter" ? ["x-session-id"] : [
724
+ "session_id",
725
+ "x-client-request-id",
726
+ "x-session-affinity"
727
+ ];
728
+ const configuredHeaders = new Set(Object.keys(providerHeaders).map((key) => key.toLowerCase()));
729
+ for (const name of affinityHeaders) if (!configuredHeaders.has(name)) providerHeaders[name] = affinityValue;
730
+ }
731
+ }
619
732
  const callerHeaders = {
620
733
  ...optionHeaders,
621
734
  ...turnHeaders
@@ -637,18 +750,15 @@ function buildOpenAIClientHeaders(model, context, optionHeaders, turnHeaders, se
637
750
  headers: resolvedHeaders
638
751
  }) ?? resolvedHeaders;
639
752
  }
640
- function resolveOpenAISdkTimeoutMs(model, timeoutMs) {
641
- return resolveModelRequestTimeoutMs(model, timeoutMs);
642
- }
643
753
  function buildOpenAISdkClientOptions(model) {
644
- const timeout = resolveOpenAISdkTimeoutMs(model);
754
+ const timeout = resolveModelRequestTimeoutMs(model);
645
755
  return {
646
756
  ...timeout === void 0 ? {} : { timeout },
647
757
  maxRetries: 0
648
758
  };
649
759
  }
650
760
  function buildOpenAISdkRequestOptions(model, signal, options) {
651
- const timeout = resolveOpenAISdkTimeoutMs(model, options?.timeoutMs);
761
+ const timeout = resolveModelRequestTimeoutMs(model, options?.timeoutMs);
652
762
  const headers = options?.stream === true && usesNativeOpenAICodexResponsesBackend(model) ? { Accept: "text/event-stream" } : void 0;
653
763
  if (timeout === void 0 && !signal && !headers) return;
654
764
  return {
@@ -672,4 +782,4 @@ function getCompat(model) {
672
782
  };
673
783
  }
674
784
  //#endregion
675
- export { readOpenAICompletionsContentDeltas as C, throwIfModelStreamAborted as D, resolvePromptCacheKey as E, redactIdentifier as O, parseOpenAICompletionsUsage as S, resolveOpenAIClientBaseUrl as T, createOpenAIProviderAcceptanceHook as _, enforceCodeModeResponsesToolSurface as a, log as b, readCodeModePayloadToolName as c, resolveOpenAIReasoningEffortMap as d, projectOpenAITools as f, createModelStreamCooperativeScheduler as g, GEMINI_THOUGHT_SIGNATURE_VALIDATOR_SKIP as h, buildOpenAISdkRequestOptions as i, sha256Hex as k, resolveCodeModeResponsesVisibleToolNames as l, reconcileOpenAIResponsesToolChoice as m, buildOpenAIClientHeaders as n, filterCodeModePayloadTools as o, reconcileOpenAICompletionsToolChoice as p, buildOpenAISdkClientOptions as r, getCompat as s, assertCodeModeResponsesToolSurface as t, resolveOpenAIStrictToolFlagWithDiagnostics as u, createOpenAIResponseHook as v, readOpenAICompletionsReasoningBatch as w, measureUtf8AppendBytes as x, isOpenAICompletionsThinkingEnabled as y };
785
+ export { resolvePromptCacheKey as A, isOpenAICompletionsThinkingEnabled as C, readOpenAICompletionsContentDeltas as D, parseOpenAICompletionsUsage as E, redactIdentifier as M, sha256Hex as N, readOpenAICompletionsReasoningBatch as O, createResponseModelTracker as S, measureUtf8AppendBytes as T, resolveOpenAIReasoningEffortMap as _, enforceCodeModeResponsesToolSurface as a, createOpenAIProviderAcceptanceHook as b, readCodeModePayloadToolName as c, prepareOpenAITools as d, projectOpenAITools as f, resolveOpenAISimpleReasoningEffort as g, resolveOpenAIRequestReasoning as h, buildOpenAISdkRequestOptions as i, throwIfModelStreamAborted as j, resolveOpenAIClientBaseUrl as k, resolveCodeModeResponsesVisibleToolNames as l, reconcileOpenAIResponsesToolChoice as m, buildOpenAIClientHeaders as n, filterCodeModePayloadTools as o, reconcileOpenAICompletionsToolChoice as p, buildOpenAISdkClientOptions as r, getCompat as s, assertCodeModeResponsesToolSurface as t, resolveOpenAIStrictToolFlagWithDiagnostics as u, GEMINI_THOUGHT_SIGNATURE_VALIDATOR_SKIP as v, log as w, createOpenAIResponseHook as x, createModelStreamCooperativeScheduler as y };
@@ -1,4 +1,4 @@
1
- import { o as parseStrictPositiveInteger } from "./base64-D-su8YVo.mjs";
1
+ import { o as parseStrictPositiveInteger } from "./base64-BQOzsvUH.mjs";
2
2
  //#region packages/ai/src/transports/positive-integer.ts
3
3
  function parsePositiveInteger(value) {
4
4
  if (typeof value === "number" && Number.isFinite(value) && value > 0) return Math.floor(value);