@openclaw/ai 2026.7.2-beta.6 → 2026.7.33

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 (78) hide show
  1. package/README.md +5 -6
  2. package/dist/{anthropic-CH4UUnZr.mjs → anthropic-BML72tLz.mjs} +468 -101
  3. package/dist/{api-registry-DlMgPR39.d.mts → api-registry-BXYnCOIR.d.mts} +2 -1
  4. package/dist/{azure-openai-responses-client-compat-C7K7QfUE.mjs → azure-openai-responses-client-compat-a_O_GVQV.mjs} +2 -23
  5. package/dist/{azure-openai-responses-CImcwB83.mjs → azure-openai-responses-kEN8II8I.mjs} +13 -11
  6. package/dist/{env-api-keys-DrgeBuva.mjs → env-api-keys-CtMlqaQ4.mjs} +4 -5
  7. package/dist/{event-stream-YjaPW20U.d.mts → event-stream-0nZeBKl2.d.mts} +1 -1
  8. package/dist/{event-stream-D8n2uFee.mjs → event-stream-ReMmOTzX.mjs} +6 -14
  9. package/dist/event-stream.d.mts +1 -1
  10. package/dist/event-stream.mjs +1 -1
  11. package/dist/{github-copilot-headers-NCJtz9i0.mjs → github-copilot-headers-BsH5cqGj.mjs} +12 -1
  12. package/dist/{google-CtSg0iTS.mjs → google-DTM4O3e9.mjs} +5 -5
  13. package/dist/{google-shared-DNBz5rcD.mjs → google-shared-BAP0BQVi.mjs} +22 -34
  14. package/dist/{google-vertex-31f1uS9L.mjs → google-vertex-D58MZHCQ.mjs} +19 -6
  15. package/dist/host-4t713IeR.mjs +37 -0
  16. package/dist/{anthropic-SrGtwsJu.d.mts → index-BoTnz8cv.d.mts} +1 -27
  17. package/dist/index.d.mts +50 -7
  18. package/dist/index.mjs +5 -5
  19. package/dist/internal/anthropic.d.mts +62 -22
  20. package/dist/internal/anthropic.mjs +4 -5
  21. package/dist/internal/openai.d.mts +82 -98
  22. package/dist/internal/openai.mjs +6 -8
  23. package/dist/internal/runtime.d.mts +34 -13
  24. package/dist/internal/runtime.mjs +14 -26
  25. package/dist/internal/shared.d.mts +9 -26
  26. package/dist/internal/shared.mjs +2 -6
  27. package/dist/{json-parse-BvXNt1-7.mjs → json-parse-DzNSIQBq.mjs} +6 -4
  28. package/dist/{llm-request-activity-BjtkplhG.mjs → llm-request-activity-CehVkZP-.mjs} +19 -1
  29. package/dist/{mistral-CWmpvWYh.mjs → mistral-CePVNdws.mjs} +39 -141
  30. package/dist/model-utils-DgmOla96.mjs +69 -0
  31. package/dist/{openai-chatgpt-responses-B84Ibtrd.mjs → openai-chatgpt-responses-BHqbcipc.mjs} +154 -101
  32. package/dist/{openai-completions-DsOxhOD1.mjs → openai-completions-9qYFVS7H.mjs} +295 -81
  33. package/dist/{openai-responses-BT7A3sLu.mjs → openai-responses-D6l9URyV.mjs} +8 -10
  34. package/dist/openai-responses-shared-L3PWZvkm.mjs +1949 -0
  35. package/dist/{openai-tool-projection-OhX64DoP.mjs → openai-tool-projection-BPlyXt8H.mjs} +12 -32
  36. package/dist/providers.d.mts +2 -3
  37. package/dist/providers.mjs +10 -11
  38. package/dist/reasoning-tag-text-partitioner-axhAdUwg.mjs +394 -0
  39. package/dist/{src-QkygScBs.mjs → src-CZ503MYJ.mjs} +5 -24
  40. package/dist/{stream-first-event-timeout-BBys9hSb.mjs → stream-first-event-timeout-RjWszj8c.mjs} +22 -2
  41. package/dist/transform-messages-BhGF_fF4.mjs +507 -0
  42. package/dist/{types-bzp5k29J.d.mts → types-DRgdPqaZ.d.mts} +0 -19
  43. package/dist/types.d.mts +5 -5
  44. package/dist/types.mjs +4 -4
  45. package/dist/{validation-B-j7cOYp.d.mts → validation-BDMWOr8d.d.mts} +1 -1
  46. package/dist/{validation-DAa_yFOM.mjs → validation-FrchoOlv.mjs} +7 -2
  47. package/dist/validation.d.mts +1 -1
  48. package/dist/validation.mjs +1 -1
  49. package/npm-shrinkwrap.json +645 -0
  50. package/package.json +11 -36
  51. package/dist/anthropic-usage-DWU-x8MI.mjs +0 -459
  52. package/dist/cache-retention-0x979a5V.mjs +0 -12
  53. package/dist/deferred-event-buffer-DAvyP7qA.mjs +0 -19
  54. package/dist/error-coercion-DgxlWC0n.mjs +0 -15
  55. package/dist/host-B9GUmcra.d.mts +0 -173
  56. package/dist/host-Dog2WQiR.mjs +0 -369
  57. package/dist/index-BVVgDSdq.d.mts +0 -1
  58. package/dist/internal/retry-after.d.mts +0 -5
  59. package/dist/internal/retry-after.mjs +0 -101
  60. package/dist/number-coercion-DvG7SNMg.mjs +0 -129
  61. package/dist/openai-completions-compat-DBWjXoMZ.d.mts +0 -43
  62. package/dist/openai-prompt-cache-2uo_1OR1.d.mts +0 -7
  63. package/dist/openai-prompt-cache-mZTCdRPo.mjs +0 -12
  64. package/dist/openai-reasoning-compat-YgeLncHw.mjs +0 -396
  65. package/dist/openai-responses-shared-pXl6Wd8S.mjs +0 -392
  66. package/dist/openai-responses-stream-internal-Cw5txaGW.mjs +0 -2964
  67. package/dist/prompt-cache-stability-Cwcjv_fx.d.mts +0 -13
  68. package/dist/provider-error-CAEvRjry.mjs +0 -47
  69. package/dist/provider-options-D8bB3z9b.d.mts +0 -144
  70. package/dist/reasoning-tag-text-partitioner-CGDyLWUR.mjs +0 -12209
  71. package/dist/simple-options-9lhRrN73.mjs +0 -50
  72. package/dist/stream-first-event-timeout-DvDeSucC.d.mts +0 -29
  73. package/dist/tls-certificate-errors-DXSpluKI.mjs +0 -93
  74. package/dist/tool-result-text-CTpIRbYd.mjs +0 -225
  75. package/dist/transform-messages-C8mBqZxF.mjs +0 -2
  76. package/dist/transport-stream-shared-D81p90xq.mjs +0 -297
  77. package/dist/transports.d.mts +0 -573
  78. package/dist/transports.mjs +0 -4110
@@ -1,6 +1,5 @@
1
- import { E as Model, F as SimpleStreamOptions, H as ThinkingBudgets, T as Message, W as ThinkingLevel, i as AssistantMessage, n as Api, z as StreamOptions } from "../types-bzp5k29J.mjs";
1
+ import { E as Model, F as SimpleStreamOptions, H as ThinkingBudgets, T as Message, W as ThinkingLevel, i as AssistantMessage, n as Api, z as StreamOptions } from "../types-DRgdPqaZ.mjs";
2
2
  import { t as sanitizeSurrogates } from "../sanitize-unicode-BZiVbGwK.mjs";
3
- import { n as normalizeStructuredPromptSection, r as sortPromptCacheToolsByName, t as normalizePromptCapabilityIds } from "../prompt-cache-stability-Cwcjv_fx.mjs";
4
3
 
5
4
  //#region packages/ai/src/providers/simple-options.d.ts
6
5
  type FirstEventStreamOptions = {
@@ -8,9 +7,6 @@ type FirstEventStreamOptions = {
8
7
  onFirstEventTimeout?: (reason: Error) => void;
9
8
  };
10
9
  declare function buildBaseOptions(model: Model, options?: SimpleStreamOptions, apiKey?: string): StreamOptions & FirstEventStreamOptions;
11
- declare function clampMaxTokensToModel(model: Model, requestedMaxTokens: number): number;
12
- declare function clampMaxTokensToModel(model: Model, requestedMaxTokens: number | undefined): number | undefined;
13
- declare function clampReasoning(effort: ThinkingLevel): Exclude<ThinkingLevel, "xhigh">;
14
10
  declare function clampReasoning(effort: ThinkingLevel | undefined): Exclude<ThinkingLevel, "xhigh"> | undefined;
15
11
  declare function adjustMaxTokensForThinking(baseMaxTokens: number | undefined, modelMaxTokens: number, reasoningLevel: ThinkingLevel, customBudgets?: ThinkingBudgets): {
16
12
  maxTokens: number;
@@ -18,20 +14,11 @@ declare function adjustMaxTokensForThinking(baseMaxTokens: number | undefined, m
18
14
  };
19
15
  //#endregion
20
16
  //#region packages/ai/src/providers/tool-result-text.d.ts
21
- /** Media metadata alone is not an attachment; provider emitters need inline bytes. */
22
- declare function hasMediaPayload(block: unknown): block is Record<string, unknown> & {
23
- data: string;
24
- };
25
- /** Image metadata alone is not an attachment; provider emitters need inline bytes. */
26
- declare function isImageWithMediaPayload<T>(block: T): block is T & {
27
- type: "image";
28
- data: string;
29
- };
30
17
  declare function describeToolResultMediaPlaceholder(blocks: readonly unknown[]): string | undefined;
31
18
  declare function extractToolResultBlockText(block: unknown): string | undefined;
32
19
  declare function extractToolResultText(blocks: readonly unknown[]): string;
33
20
  //#endregion
34
- //#region packages/ai/src/transcript-transform.d.ts
21
+ //#region packages/ai/src/providers/transform-messages.d.ts
35
22
  /**
36
23
  * Normalize tool call ID for cross-provider compatibility.
37
24
  * OpenAI Responses API generates IDs that are 450+ chars with special characters like `|`.
@@ -39,6 +26,12 @@ declare function extractToolResultText(blocks: readonly unknown[]): string;
39
26
  */
40
27
  declare function transformMessages<TApi extends Api>(messages: Message[], model: Model<TApi>, normalizeToolCallId?: (id: string, model: Model<TApi>, source: AssistantMessage) => string): Message[];
41
28
  //#endregion
29
+ //#region packages/ai/src/utils/prompt-cache-stability.d.ts
30
+ /** Normalize structured prompt text before hashing or snapshot comparison. */
31
+ declare function normalizeStructuredPromptSection(text: string): string;
32
+ /** Normalize, de-dupe, and sort capability ids for stable prompt payloads. */
33
+ declare function normalizePromptCapabilityIds(capabilities: ReadonlyArray<string>): string[];
34
+ //#endregion
42
35
  //#region packages/ai/src/utils/system-prompt-cache-boundary.d.ts
43
36
  declare const SYSTEM_PROMPT_CACHE_BOUNDARY = "\n<!-- OPENCLAW_CACHE_BOUNDARY -->\n";
44
37
  declare function stripSystemPromptCacheBoundary(text: string): string;
@@ -52,14 +45,4 @@ declare function prependSystemPromptAdditionAfterCacheBoundary(params: {
52
45
  systemPromptAddition?: string;
53
46
  }): string;
54
47
  //#endregion
55
- //#region packages/ai/src/utils/tls-certificate-errors.d.ts
56
- type TlsCertificateErrorKind = "certificate_invalid" | "hostname_mismatch";
57
- type TlsCertificateErrorDetails = {
58
- kind: TlsCertificateErrorKind;
59
- code?: string;
60
- message: string;
61
- };
62
- /** Classify deterministic Node/OpenSSL certificate validation failures. */
63
- declare function inspectTlsCertificateError(error: unknown): TlsCertificateErrorDetails | null;
64
- //#endregion
65
- export { SYSTEM_PROMPT_CACHE_BOUNDARY, TlsCertificateErrorDetails, TlsCertificateErrorKind, adjustMaxTokensForThinking, buildBaseOptions, clampMaxTokensToModel, clampReasoning, describeToolResultMediaPlaceholder, ensureSystemPromptCacheBoundary, extractToolResultBlockText, extractToolResultText, hasMediaPayload, inspectTlsCertificateError, isImageWithMediaPayload, normalizePromptCapabilityIds, normalizeStructuredPromptSection, prependSystemPromptAdditionAfterCacheBoundary, sanitizeSurrogates, sortPromptCacheToolsByName, splitSystemPromptCacheBoundary, stripSystemPromptCacheBoundary, transformMessages };
48
+ export { SYSTEM_PROMPT_CACHE_BOUNDARY, adjustMaxTokensForThinking, buildBaseOptions, clampReasoning, describeToolResultMediaPlaceholder, ensureSystemPromptCacheBoundary, extractToolResultBlockText, extractToolResultText, normalizePromptCapabilityIds, normalizeStructuredPromptSection, prependSystemPromptAdditionAfterCacheBoundary, sanitizeSurrogates, splitSystemPromptCacheBoundary, stripSystemPromptCacheBoundary, transformMessages };
@@ -1,7 +1,3 @@
1
- import { i as transformMessages } from "../host-Dog2WQiR.mjs";
2
1
  import { t as sanitizeSurrogates } from "../sanitize-unicode-DT5o51ur.mjs";
3
- import { a as isImageWithMediaPayload, c as ensureSystemPromptCacheBoundary, d as stripSystemPromptCacheBoundary, f as normalizePromptCapabilityIds, i as hasMediaPayload, l as prependSystemPromptAdditionAfterCacheBoundary, m as sortPromptCacheToolsByName, n as extractToolResultBlockText, p as normalizeStructuredPromptSection, r as extractToolResultText, s as SYSTEM_PROMPT_CACHE_BOUNDARY, t as describeToolResultMediaPlaceholder, u as splitSystemPromptCacheBoundary } from "../tool-result-text-CTpIRbYd.mjs";
4
- import { i as clampReasoning, n as buildBaseOptions, r as clampMaxTokensToModel, t as adjustMaxTokensForThinking } from "../simple-options-9lhRrN73.mjs";
5
- import "../transform-messages-C8mBqZxF.mjs";
6
- import { t as inspectTlsCertificateError } from "../tls-certificate-errors-DXSpluKI.mjs";
7
- export { SYSTEM_PROMPT_CACHE_BOUNDARY, adjustMaxTokensForThinking, buildBaseOptions, clampMaxTokensToModel, clampReasoning, describeToolResultMediaPlaceholder, ensureSystemPromptCacheBoundary, extractToolResultBlockText, extractToolResultText, hasMediaPayload, inspectTlsCertificateError, isImageWithMediaPayload, normalizePromptCapabilityIds, normalizeStructuredPromptSection, prependSystemPromptAdditionAfterCacheBoundary, sanitizeSurrogates, sortPromptCacheToolsByName, splitSystemPromptCacheBoundary, stripSystemPromptCacheBoundary, transformMessages };
2
+ import { S as normalizeStructuredPromptSection, _ as ensureSystemPromptCacheBoundary, a as adjustMaxTokensForThinking, b as stripSystemPromptCacheBoundary, g as SYSTEM_PROMPT_CACHE_BOUNDARY, i as extractToolResultText, n as describeToolResultMediaPlaceholder, o as buildBaseOptions, r as extractToolResultBlockText, s as clampReasoning, t as transformMessages, v as prependSystemPromptAdditionAfterCacheBoundary, x as normalizePromptCapabilityIds, y as splitSystemPromptCacheBoundary } from "../transform-messages-BhGF_fF4.mjs";
3
+ export { SYSTEM_PROMPT_CACHE_BOUNDARY, adjustMaxTokensForThinking, buildBaseOptions, clampReasoning, describeToolResultMediaPlaceholder, ensureSystemPromptCacheBoundary, extractToolResultBlockText, extractToolResultText, normalizePromptCapabilityIds, normalizeStructuredPromptSection, prependSystemPromptAdditionAfterCacheBoundary, sanitizeSurrogates, splitSystemPromptCacheBoundary, stripSystemPromptCacheBoundary, transformMessages };
@@ -42,7 +42,7 @@ function repairJson(json) {
42
42
  let inString = false;
43
43
  let stringValuePrefix = "";
44
44
  for (let index = 0; index < json.length; index++) {
45
- const char = json.charAt(index);
45
+ const char = json[index];
46
46
  if (!inString) {
47
47
  repaired += char;
48
48
  if (char === "\"") {
@@ -58,8 +58,8 @@ function repairJson(json) {
58
58
  continue;
59
59
  }
60
60
  if (char === "\\") {
61
- const nextChar = json.charAt(index + 1);
62
- if (!nextChar) {
61
+ const nextChar = json[index + 1];
62
+ if (nextChar === void 0) {
63
63
  repaired += "\\\\";
64
64
  continue;
65
65
  }
@@ -96,7 +96,9 @@ function repairJson(json) {
96
96
  return repaired;
97
97
  }
98
98
  function parseJsonWithRepair(json) {
99
- return JSON.parse(repairJson(json));
99
+ const repairedJson = repairJson(json);
100
+ if (repairedJson !== json) return JSON.parse(repairedJson);
101
+ return JSON.parse(json);
100
102
  }
101
103
  function looksLikeWindowsPathPrefix(prefix) {
102
104
  const tail = prefix.slice(-160);
@@ -1,3 +1,21 @@
1
+ //#region packages/ai/src/utils/deferred-event-buffer.ts
2
+ function createDeferredEventBuffer(sink, onBufferedEvent) {
3
+ let events = [];
4
+ return {
5
+ push(event) {
6
+ events.push(event);
7
+ onBufferedEvent?.();
8
+ },
9
+ flush() {
10
+ for (const event of events) sink.push(event);
11
+ events = [];
12
+ },
13
+ discard() {
14
+ events = [];
15
+ }
16
+ };
17
+ }
18
+ //#endregion
1
19
  //#region packages/ai/src/utils/llm-request-activity.ts
2
20
  const requestActivityListeners = /* @__PURE__ */ new WeakMap();
3
21
  function notifyLlmRequestActivity(signal) {
@@ -14,4 +32,4 @@ function onLlmRequestActivity(signal, listener) {
14
32
  };
15
33
  }
16
34
  //#endregion
17
- export { onLlmRequestActivity as n, notifyLlmRequestActivity as t };
35
+ export { onLlmRequestActivity as n, createDeferredEventBuffer as r, notifyLlmRequestActivity as t };
@@ -1,16 +1,12 @@
1
- import { n as getEnvApiKey } from "./env-api-keys-DrgeBuva.mjs";
2
- import { t as AssistantMessageEventStream } from "./event-stream-D8n2uFee.mjs";
3
- import { i as transformMessages, n as getAiTransportHost } from "./host-Dog2WQiR.mjs";
1
+ import { n as getEnvApiKey } from "./env-api-keys-CtMlqaQ4.mjs";
2
+ import { t as AssistantMessageEventStream } from "./event-stream-ReMmOTzX.mjs";
3
+ import { n as getAiTransportHost } from "./host-4t713IeR.mjs";
4
+ import { n as calculateCost, r as clampThinkingLevel } from "./model-utils-DgmOla96.mjs";
5
+ import { n as parseStreamingJson } from "./json-parse-DzNSIQBq.mjs";
4
6
  import { t as sanitizeSurrogates } from "./sanitize-unicode-DT5o51ur.mjs";
5
- import { a as isImageWithMediaPayload, d as stripSystemPromptCacheBoundary, o as truncateUtf16Safe, r as extractToolResultText, t as describeToolResultMediaPlaceholder } from "./tool-result-text-CTpIRbYd.mjs";
6
- import { c as calculateCost, l as clampThinkingLevel } from "./number-coercion-DvG7SNMg.mjs";
7
- import { n as parseStreamingJson } from "./json-parse-BvXNt1-7.mjs";
8
- import { d as transportAbortError } from "./transport-stream-shared-D81p90xq.mjs";
7
+ import { b as stripSystemPromptCacheBoundary, i as extractToolResultText, n as describeToolResultMediaPlaceholder, o as buildBaseOptions, t as transformMessages } from "./transform-messages-BhGF_fF4.mjs";
9
8
  import { t as shortHash } from "./hash-CHgqbJmD.mjs";
10
- import { n as buildBaseOptions, r as clampMaxTokensToModel } from "./simple-options-9lhRrN73.mjs";
11
- import "./transform-messages-C8mBqZxF.mjs";
12
9
  import { t as createSseByteGuard } from "./streaming-byte-guard-BrbkbwUu.mjs";
13
- import { randomUUID } from "node:crypto";
14
10
  import { HTTPClient, Mistral } from "@mistralai/mistralai";
15
11
  //#region packages/ai/src/providers/mistral.ts
16
12
  const MISTRAL_TOOL_CALL_ID_LENGTH = 9;
@@ -74,21 +70,13 @@ const streamMistral = (model, context, options) => {
74
70
  let payload = buildChatPayload(model, context, transformMessages(context.messages, model, (id) => normalizeMistralToolCallId(id)), options);
75
71
  const nextPayload = await options?.onPayload?.(payload, model);
76
72
  if (nextPayload !== void 0) payload = nextPayload;
77
- const headers = {
78
- ...model.headers,
79
- ...options?.headers
80
- };
81
- if (resolveMistralPromptCacheKey(options) && options?.sessionId) headers["x-affinity"] ||= options.sessionId;
82
- const mistralStream = await mistral.chat.stream(payload, {
83
- headers,
84
- signal: options?.signal
85
- });
73
+ const mistralStream = await mistral.chat.stream(payload, buildRequestOptions(model, options));
86
74
  stream.push({
87
75
  type: "start",
88
76
  partial: output
89
77
  });
90
78
  await consumeChatStream(model, output, stream, mistralStream);
91
- if (options?.signal?.aborted) throw transportAbortError(options.signal);
79
+ if (options?.signal?.aborted) throw new Error("Request was aborted");
92
80
  if (output.stopReason === "aborted" || output.stopReason === "error") throw new Error("An unknown error occurred");
93
81
  stream.push({
94
82
  type: "done",
@@ -116,10 +104,7 @@ const streamMistral = (model, context, options) => {
116
104
  const streamSimpleMistral = (model, context, options) => {
117
105
  const apiKey = options?.apiKey || getEnvApiKey(model.provider);
118
106
  if (!apiKey) throw new Error(`No API key for provider: ${model.provider}`);
119
- const base = {
120
- ...buildBaseOptions(model, options, apiKey),
121
- maxTokens: clampMaxTokensToModel(model, options?.maxTokens)
122
- };
107
+ const base = buildBaseOptions(model, options, apiKey);
123
108
  const clampedReasoning = options?.reasoning ? clampThinkingLevel(model, options.reasoning) : void 0;
124
109
  const reasoning = clampedReasoning === "off" ? void 0 : clampedReasoning;
125
110
  const shouldUseReasoning = model.reasoning && reasoning !== void 0;
@@ -177,7 +162,7 @@ function deriveMistralToolCallId(id, attempt) {
177
162
  const normalized = id.replace(/[^a-zA-Z0-9]/g, "");
178
163
  if (attempt === 0 && normalized.length === MISTRAL_TOOL_CALL_ID_LENGTH) return normalized;
179
164
  const seedBase = normalized || id;
180
- return shortHash(attempt === 0 ? seedBase : `${seedBase}:${attempt}`).replace(/[^a-zA-Z0-9]/g, "").padEnd(MISTRAL_TOOL_CALL_ID_LENGTH, "0").slice(0, MISTRAL_TOOL_CALL_ID_LENGTH);
165
+ return shortHash(attempt === 0 ? seedBase : `${seedBase}:${attempt}`).replace(/[^a-zA-Z0-9]/g, "").slice(0, MISTRAL_TOOL_CALL_ID_LENGTH);
181
166
  }
182
167
  function formatMistralError(error) {
183
168
  if (error instanceof Error) {
@@ -192,8 +177,7 @@ function formatMistralError(error) {
192
177
  }
193
178
  function truncateErrorText(text, maxChars) {
194
179
  if (text.length <= maxChars) return text;
195
- const truncated = truncateUtf16Safe(text, maxChars);
196
- return `${truncated}... [truncated ${text.length - truncated.length} chars]`;
180
+ return `${text.slice(0, maxChars)}... [truncated ${text.length - maxChars} chars]`;
197
181
  }
198
182
  function safeJsonStringify(value) {
199
183
  try {
@@ -203,6 +187,16 @@ function safeJsonStringify(value) {
203
187
  return String(value);
204
188
  }
205
189
  }
190
+ function buildRequestOptions(model, options) {
191
+ const requestOptions = { retries: { strategy: "none" } };
192
+ if (options?.signal) requestOptions.signal = options.signal;
193
+ const headers = {};
194
+ if (model.headers) Object.assign(headers, model.headers);
195
+ if (options?.headers) Object.assign(headers, options.headers);
196
+ if (options?.sessionId && !headers["x-affinity"]) headers["x-affinity"] = options.sessionId;
197
+ if (Object.keys(headers).length > 0) requestOptions.headers = headers;
198
+ return requestOptions;
199
+ }
206
200
  function buildChatPayload(model, context, messages, options) {
207
201
  const payload = {
208
202
  model: model.id,
@@ -224,86 +218,17 @@ function buildChatPayload(model, context, messages, options) {
224
218
  }
225
219
  if (options?.promptMode) payload.promptMode = options.promptMode;
226
220
  if (options?.reasoningEffort) payload.reasoningEffort = options.reasoningEffort;
227
- const promptCacheKey = resolveMistralPromptCacheKey(options);
228
- if (promptCacheKey) payload.promptCacheKey = promptCacheKey;
229
221
  if (context.systemPrompt) payload.messages.unshift({
230
222
  role: "system",
231
223
  content: sanitizeSurrogates(stripSystemPromptCacheBoundary(context.systemPrompt))
232
224
  });
233
225
  return payload;
234
226
  }
235
- function resolveMistralPromptCacheKey(options) {
236
- if (options?.cacheRetention === "none") return;
237
- return options?.promptCacheKey?.trim() || options?.sessionId?.trim() || void 0;
238
- }
239
- function readMistralCachedPromptTokens(usage, promptTokens) {
240
- const record = usage;
241
- const rawCachedTokens = record.promptTokensDetails?.cachedTokens ?? record.prompt_tokens_details?.cached_tokens ?? record.cachedTokens ?? record.cached_tokens;
242
- return Math.min(promptTokens, Math.max(0, typeof rawCachedTokens === "number" && Number.isFinite(rawCachedTokens) ? rawCachedTokens : 0));
243
- }
244
227
  async function consumeChatStream(model, output, stream, mistralStream) {
245
228
  let currentBlock = null;
246
229
  const blocks = output.content;
247
230
  const blockIndex = () => blocks.length - 1;
248
- const toolBlockIdentities = /* @__PURE__ */ new Map();
249
- const normalizeMissingToolCallId = createMistralToolCallIdNormalizer();
250
- const missingToolCallIdScope = randomUUID();
251
- const createMissingToolCallId = (contentIndex) => normalizeMissingToolCallId(`${missingToolCallIdScope}:toolcall:${contentIndex}`);
252
- const findIdentityCandidates = (matches, excludedContentIndexes) => {
253
- const candidates = /* @__PURE__ */ new Set();
254
- for (const [contentIndex, identity] of toolBlockIdentities) if (!excludedContentIndexes?.has(contentIndex) && matches(identity)) candidates.add(contentIndex);
255
- return candidates;
256
- };
257
- const intersectCandidates = (left, right) => new Set([...left].filter((contentIndex) => right.has(contentIndex)));
258
- const requireSingleCandidate = (candidates) => {
259
- if (candidates.size > 1) throw new Error("Mistral streamed tool-call continuation is ambiguous; refusing to merge arguments");
260
- return candidates.values().next().value;
261
- };
262
- const requireExistingCandidate = (candidates) => {
263
- const candidate = requireSingleCandidate(candidates);
264
- if (candidate === void 0) throw new Error("Mistral streamed tool-call identities conflict; refusing to merge arguments");
265
- return candidate;
266
- };
267
- const resolveToolBlockIndex = (params) => {
268
- const explicitId = params.explicitId;
269
- const functionName = params.functionName;
270
- const toolCallIndex = params.index;
271
- const idCandidates = explicitId ? findIdentityCandidates((identity) => identity.explicitIds.has(explicitId), params.usedContentIndexes) : /* @__PURE__ */ new Set();
272
- const nameCandidates = functionName ? findIdentityCandidates((identity) => identity.functionNames.has(functionName), params.usedContentIndexes) : /* @__PURE__ */ new Set();
273
- const indexCandidates = toolCallIndex === void 0 ? /* @__PURE__ */ new Set() : findIdentityCandidates((identity) => identity.indexes.has(toolCallIndex), params.usedContentIndexes);
274
- if (idCandidates.size > 0) {
275
- let candidates = idCandidates;
276
- if (nameCandidates.size > 0) candidates = intersectCandidates(candidates, nameCandidates);
277
- return requireExistingCandidate(candidates);
278
- }
279
- if (nameCandidates.size > 0) {
280
- const idCompatibleCandidates = new Set([...nameCandidates].filter((contentIndex) => {
281
- const identity = toolBlockIdentities.get(contentIndex);
282
- if (!identity) return false;
283
- return !explicitId || identity.explicitIds.size === 0;
284
- }));
285
- if (idCompatibleCandidates.size <= 1 && (toolCallIndex === void 0 || toolCallIndex === 0)) return requireSingleCandidate(idCompatibleCandidates);
286
- const indexCompatibleCandidates = new Set([...idCompatibleCandidates].filter((contentIndex) => {
287
- const identity = toolBlockIdentities.get(contentIndex);
288
- if (!identity) return false;
289
- return toolCallIndex === void 0 || identity.indexes.size === 0 || identity.indexes.has(toolCallIndex);
290
- }));
291
- if (indexCompatibleCandidates.size === 0) return;
292
- return requireSingleCandidate(indexCompatibleCandidates);
293
- }
294
- if (functionName) {
295
- const namelessCandidates = new Set([...indexCandidates].filter((contentIndex) => {
296
- const identity = toolBlockIdentities.get(contentIndex);
297
- return identity?.functionNames.size === 0 && (!explicitId || identity.explicitIds.size === 0);
298
- }));
299
- return requireSingleCandidate(namelessCandidates);
300
- }
301
- if (explicitId) {
302
- const idlessCandidates = new Set([...indexCandidates].filter((contentIndex) => toolBlockIdentities.get(contentIndex)?.explicitIds.size === 0));
303
- return requireSingleCandidate(idlessCandidates);
304
- }
305
- return requireSingleCandidate(indexCandidates);
306
- };
231
+ const toolBlocksByKey = /* @__PURE__ */ new Map();
307
232
  const finishCurrentBlock = (block) => {
308
233
  if (!block) return;
309
234
  if (block.type === "text") {
@@ -326,13 +251,11 @@ async function consumeChatStream(model, output, stream, mistralStream) {
326
251
  const chunk = event.data;
327
252
  output.responseId ||= chunk.id;
328
253
  if (chunk.usage) {
329
- const promptTokens = chunk.usage.promptTokens || 0;
330
- const cachedPromptTokens = readMistralCachedPromptTokens(chunk.usage, promptTokens);
331
- output.usage.input = Math.max(0, promptTokens - cachedPromptTokens);
254
+ output.usage.input = chunk.usage.promptTokens || 0;
332
255
  output.usage.output = chunk.usage.completionTokens || 0;
333
- output.usage.cacheRead = cachedPromptTokens;
256
+ output.usage.cacheRead = 0;
334
257
  output.usage.cacheWrite = 0;
335
- output.usage.totalTokens = chunk.usage.totalTokens || output.usage.input + output.usage.output + output.usage.cacheRead;
258
+ output.usage.totalTokens = chunk.usage.totalTokens || output.usage.input + output.usage.output;
336
259
  calculateCost(model, output.usage);
337
260
  }
338
261
  const choice = chunk.choices[0];
@@ -417,77 +340,52 @@ async function consumeChatStream(model, output, stream, mistralStream) {
417
340
  }
418
341
  }
419
342
  const toolCalls = delta.toolCalls || [];
420
- const usedToolBlockIndexes = /* @__PURE__ */ new Set();
421
343
  for (const toolCall of toolCalls) {
422
344
  if (currentBlock) {
423
345
  finishCurrentBlock(currentBlock);
424
346
  currentBlock = null;
425
347
  }
426
- const toolCallIndex = typeof toolCall.index === "number" && Number.isInteger(toolCall.index) ? toolCall.index : void 0;
427
- const providedCallId = toolCall.id && toolCall.id !== "null" ? toolCall.id : void 0;
428
- const functionName = toolCall.function.name.trim() || void 0;
429
- const existingIndex = resolveToolBlockIndex({
430
- explicitId: providedCallId,
431
- functionName,
432
- index: toolCallIndex,
433
- usedContentIndexes: usedToolBlockIndexes
434
- });
348
+ const callId = toolCall.id && toolCall.id !== "null" ? toolCall.id : deriveMistralToolCallId(`toolcall:${toolCall.index ?? 0}`, 0);
349
+ const key = `${callId}:${toolCall.index || 0}`;
350
+ const existingIndex = toolBlocksByKey.get(key);
435
351
  let block;
436
352
  if (existingIndex !== void 0) {
437
353
  const existing = output.content[existingIndex];
438
354
  if (existing?.type === "toolCall") block = existing;
439
355
  }
440
356
  if (!block) {
441
- const contentIndex = output.content.length;
442
357
  block = {
443
358
  type: "toolCall",
444
- id: providedCallId ?? createMissingToolCallId(contentIndex),
445
- name: functionName ?? "",
359
+ id: callId,
360
+ name: toolCall.function.name,
446
361
  arguments: {},
447
362
  partialArgs: ""
448
363
  };
449
364
  output.content.push(block);
450
- toolBlockIdentities.set(contentIndex, {
451
- explicitIds: new Set(providedCallId ? [providedCallId] : []),
452
- functionNames: new Set(functionName ? [functionName] : []),
453
- indexes: new Set(toolCallIndex === void 0 ? [] : [toolCallIndex])
454
- });
365
+ toolBlocksByKey.set(key, output.content.length - 1);
455
366
  stream.push({
456
367
  type: "toolcall_start",
457
- contentIndex,
368
+ contentIndex: output.content.length - 1,
458
369
  partial: output
459
370
  });
460
371
  }
461
- const contentIndex = output.content.indexOf(block);
462
- const identity = toolBlockIdentities.get(contentIndex);
463
- if (!identity) throw new Error("Mistral streamed tool-call identity is missing");
464
- usedToolBlockIndexes.add(contentIndex);
465
- if (providedCallId) {
466
- block.id = providedCallId;
467
- identity.explicitIds.add(providedCallId);
468
- }
469
- if (functionName) {
470
- if (identity.functionNames.size > 0 && !identity.functionNames.has(functionName)) throw new Error("Mistral streamed tool-call continuation changed function name; refusing to merge arguments");
471
- block.name = functionName;
472
- identity.functionNames.add(functionName);
473
- }
474
- if (toolCallIndex !== void 0) identity.indexes.add(toolCallIndex);
475
372
  const argsDelta = typeof toolCall.function.arguments === "string" ? toolCall.function.arguments : JSON.stringify(toolCall.function.arguments || {});
476
373
  block.partialArgs = (block.partialArgs || "") + argsDelta;
477
374
  block.arguments = parseStreamingJson(block.partialArgs);
478
375
  stream.push({
479
376
  type: "toolcall_delta",
480
- contentIndex,
377
+ contentIndex: toolBlocksByKey.get(key),
481
378
  delta: argsDelta,
482
379
  partial: output
483
380
  });
484
381
  }
485
382
  }
486
383
  finishCurrentBlock(currentBlock);
487
- for (const index of toolBlockIdentities.keys()) {
488
- const block = output.content.at(index);
489
- if (block?.type !== "toolCall") continue;
384
+ for (const index of toolBlocksByKey.values()) {
385
+ const block = output.content[index];
386
+ if (block.type !== "toolCall") continue;
490
387
  const toolBlock = block;
388
+ toolBlock.arguments = parseStreamingJson(toolBlock.partialArgs);
491
389
  delete toolBlock.partialArgs;
492
390
  stream.push({
493
391
  type: "toolcall_end",
@@ -595,14 +493,14 @@ function toChatMessages(messages, supportsImages) {
595
493
  continue;
596
494
  }
597
495
  const toolContent = [];
598
- const toolText = buildToolResultText(extractToolResultText(msg.content), describeToolResultMediaPlaceholder(msg.content), msg.content.some(isImageWithMediaPayload), supportsImages, msg.isError);
496
+ const toolText = buildToolResultText(extractToolResultText(msg.content), describeToolResultMediaPlaceholder(msg.content), msg.content.some((part) => part.type === "image"), supportsImages, msg.isError);
599
497
  toolContent.push({
600
498
  type: "text",
601
499
  text: toolText
602
500
  });
603
501
  for (const part of msg.content) {
604
502
  if (!supportsImages) continue;
605
- if (!isImageWithMediaPayload(part)) continue;
503
+ if (part.type !== "image") continue;
606
504
  toolContent.push({
607
505
  type: "image_url",
608
506
  imageUrl: `data:${part.mimeType};base64,${part.data}`
@@ -0,0 +1,69 @@
1
+ import { c as resolveClaudeNativeThinkingLevelMap, i as requiresClaudeMandatoryAdaptiveThinking } from "./src-CZ503MYJ.mjs";
2
+ //#region packages/ai/src/model-utils.ts
3
+ /** Calculates and stores model cost fields from token usage and per-million pricing. */
4
+ function calculateCost(model, usage) {
5
+ usage.cost.input = model.cost.input / 1e6 * usage.input;
6
+ usage.cost.output = model.cost.output / 1e6 * usage.output;
7
+ usage.cost.cacheRead = model.cost.cacheRead / 1e6 * usage.cacheRead;
8
+ usage.cost.cacheWrite = model.cost.cacheWrite / 1e6 * usage.cacheWrite;
9
+ usage.cost.total = usage.cost.input + usage.cost.output + usage.cost.cacheRead + usage.cost.cacheWrite;
10
+ return usage.cost;
11
+ }
12
+ /** Replaces the catalog estimate when the provider reports an authoritative billed total. */
13
+ function applyProviderReportedUsageCost(usage, reportedCost) {
14
+ if (typeof reportedCost !== "number" || !Number.isFinite(reportedCost) || reportedCost < 0) return;
15
+ usage.cost.total = reportedCost;
16
+ usage.cost.totalOrigin = "provider-billed";
17
+ }
18
+ const EXTENDED_THINKING_LEVELS = [
19
+ "off",
20
+ "minimal",
21
+ "low",
22
+ "medium",
23
+ "high",
24
+ "xhigh",
25
+ "max"
26
+ ];
27
+ function resolveThinkingLevelMap(model) {
28
+ return model.api === "anthropic-messages" ? resolveClaudeNativeThinkingLevelMap(model) ?? model.thinkingLevelMap : model.thinkingLevelMap;
29
+ }
30
+ /** Returns thinking levels exposed by a reasoning-capable model. */
31
+ function getSupportedThinkingLevels(model) {
32
+ const mandatoryAdaptiveContract = model.api === "anthropic-messages" && requiresClaudeMandatoryAdaptiveThinking(model);
33
+ if (!model.reasoning && !mandatoryAdaptiveContract) return ["off"];
34
+ const thinkingLevelMap = resolveThinkingLevelMap(model);
35
+ return EXTENDED_THINKING_LEVELS.filter((level) => {
36
+ const mapped = thinkingLevelMap?.[level];
37
+ if (mapped === null) return false;
38
+ if (level === "xhigh" || level === "max") return mapped !== void 0;
39
+ return true;
40
+ });
41
+ }
42
+ /** Clamps a requested thinking level to the closest supported level for a model. */
43
+ function clampThinkingLevel(model, level) {
44
+ const availableLevels = getSupportedThinkingLevels(model);
45
+ if (availableLevels.includes(level)) return level;
46
+ const requestedIndex = EXTENDED_THINKING_LEVELS.indexOf(level);
47
+ if (requestedIndex === -1) return availableLevels[0] ?? "off";
48
+ const thinkingLevelMap = resolveThinkingLevelMap(model);
49
+ if ((level === "xhigh" || level === "max") && thinkingLevelMap?.[level] === null) for (let i = requestedIndex - 1; i >= 0; i--) {
50
+ const candidate = EXTENDED_THINKING_LEVELS[i];
51
+ if (availableLevels.includes(candidate)) return candidate;
52
+ }
53
+ for (let i = requestedIndex; i < EXTENDED_THINKING_LEVELS.length; i++) {
54
+ const candidate = EXTENDED_THINKING_LEVELS[i];
55
+ if (availableLevels.includes(candidate)) return candidate;
56
+ }
57
+ for (let i = requestedIndex - 1; i >= 0; i--) {
58
+ const candidate = EXTENDED_THINKING_LEVELS[i];
59
+ if (availableLevels.includes(candidate)) return candidate;
60
+ }
61
+ return availableLevels[0] ?? "off";
62
+ }
63
+ /** Compares model identity by provider and id. */
64
+ function modelsAreEqual(a, b) {
65
+ if (!a || !b) return false;
66
+ return a.id === b.id && a.provider === b.provider;
67
+ }
68
+ //#endregion
69
+ export { modelsAreEqual as a, getSupportedThinkingLevels as i, calculateCost as n, clampThinkingLevel as r, applyProviderReportedUsageCost as t };