@openclaw/ai 2026.9.2 → 2026.9.3

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 (108) hide show
  1. package/README.md +3 -2
  2. package/dist/anthropic-CZy5U0NY.mjs +376 -0
  3. package/dist/{anthropic-payload-policy-d46X2pR0.d.mts → anthropic-payload-policy-wuRCb6MH.d.mts} +16 -6
  4. package/dist/{anthropic-compaction-replay-DB2FGLQc.mjs → anthropic-stream-reducer-B_yo_7pf.mjs} +923 -181
  5. package/dist/{api-registry-DWtPjzyn.d.mts → api-registry-CB1-1oQ2.d.mts} +2 -2
  6. package/dist/assistant-output-iqnlJCV2.mjs +16 -0
  7. package/dist/assistant-text-phase-C20rxWwP.mjs +55 -0
  8. package/dist/{azure-openai-responses-C5bZRfAP.mjs → azure-openai-responses-Crpa40QR.mjs} +5 -5
  9. package/dist/{base64-CEFBpSkN.mjs → base64-D-su8YVo.mjs} +1 -27
  10. package/dist/{diagnostics-DfFyKeX_.mjs → diagnostics-dV98PqIy.mjs} +96 -21
  11. package/dist/diagnostics.d.mts +3 -1
  12. package/dist/diagnostics.mjs +3 -3
  13. package/dist/{event-stream-BhT5T1Ay.d.mts → event-stream-C1Z2piyk.d.mts} +11 -3
  14. package/dist/{event-stream-BgDvQeum.mjs → event-stream-D8PARQfL.mjs} +45 -1
  15. package/dist/event-stream-I_GlBsuZ.d.mts +1 -0
  16. package/dist/event-stream.d.mts +2 -2
  17. package/dist/event-stream.mjs +1 -1
  18. package/dist/{github-copilot-headers-NCJtz9i0.mjs → github-copilot-headers-B37TB3rB.mjs} +3 -10
  19. package/dist/github-copilot-request-facts-BTEBMeOv.mjs +16 -0
  20. package/dist/{google-4qeuE8iX.mjs → google-BDPriaVe.mjs} +10 -10
  21. package/dist/google-messages-CVn9eFpF.mjs +449 -0
  22. package/dist/google-shared-BedY23XS.mjs +185 -0
  23. package/dist/{google-vertex-O9BcnB6X.mjs → google-vertex-DMz8XQCn.mjs} +7 -6
  24. package/dist/{host-CEvLw30U.mjs → host-CWuF-sS3.mjs} +44 -39
  25. package/dist/{host-DjzGmdZ2.d.mts → host-DK3wmS3e.d.mts} +3 -3
  26. package/dist/host-policy-CAopLRKA.mjs +37 -0
  27. package/dist/{index-FnHM2FcI.d.mts → index-CQ6LTHw8.d.mts} +3 -3
  28. package/dist/index.d.mts +6 -6
  29. package/dist/index.mjs +4 -4
  30. package/dist/internal/anthropic.d.mts +7 -7
  31. package/dist/internal/anthropic.mjs +4 -4
  32. package/dist/internal/google-model-family.d.mts +5 -0
  33. package/dist/internal/google-model-family.mjs +15 -0
  34. package/dist/internal/openai-responses-payload-policy.d.mts +1 -1
  35. package/dist/internal/openai-responses-payload-policy.mjs +1 -1
  36. package/dist/internal/openai.d.mts +8 -103
  37. package/dist/internal/openai.mjs +10 -10
  38. package/dist/internal/retry-after.d.mts +2 -4
  39. package/dist/internal/retry-after.mjs +57 -8
  40. package/dist/internal/runtime.d.mts +7 -6
  41. package/dist/internal/runtime.mjs +8 -7
  42. package/dist/internal/shared.d.mts +14 -3
  43. package/dist/internal/shared.mjs +6 -4
  44. package/dist/internal/tool-schema.d.mts +63 -0
  45. package/dist/internal/tool-schema.mjs +3 -0
  46. package/dist/{json-parse-BuAJEbdW.mjs → json-parse-Dw_hnxsA.mjs} +1 -1
  47. package/dist/{mistral-Tb6oalqH.mjs → mistral--m-Jm6VZ.mjs} +13 -37
  48. package/dist/model-transport-url-DKocrEsb.d.mts +28 -0
  49. package/dist/{openai-chatgpt-responses-yUXjPNfu.mjs → openai-chatgpt-responses-nDZccFW-.mjs} +48 -38
  50. package/dist/openai-completions-KuoZyx0d.mjs +187 -0
  51. package/dist/{openai-completions-compat-CpjYUArk.d.mts → openai-completions-compat-CXn3T1we.d.mts} +26 -4
  52. package/dist/{openai-completions-stream-BsrBe3Gg.mjs → openai-completions-stream-BQk3SkLD.mjs} +622 -452
  53. package/dist/openai-prompt-cache-BI0rkM-5.mjs +220 -0
  54. package/dist/openai-prompt-cache-rrutvqxq.d.mts +16 -0
  55. package/dist/openai-provider-client-ha_WxTyj.mjs +24 -0
  56. package/dist/openai-reasoning-effort-BK7FbcLT.mjs +167 -0
  57. package/dist/{openai-responses-CCL41ALM.mjs → openai-responses-D99dOzKI.mjs} +14 -29
  58. package/dist/{openai-responses-compaction-window-BMVHFOtq.mjs → openai-responses-compaction-window-D5jbzCi3.mjs} +7 -170
  59. package/dist/{openai-responses-contracts-rF5DDRNS.d.mts → openai-responses-contracts-B55afwRo.d.mts} +3 -3
  60. package/dist/{openai-responses-prompt-observer-internal-D0bhBfgL.mjs → openai-responses-prompt-observer-internal-tApyTLVu.mjs} +3 -3
  61. package/dist/{openai-responses-shared-Bmma_3Qc.mjs → openai-responses-shared-ZyQEzS5i.mjs} +44 -115
  62. package/dist/openai-tool-projection-793cE3QX.d.mts +37 -0
  63. package/dist/{openai-tool-schema-_pTAJqKF.mjs → openai-tool-schema-CzjyYXun.mjs} +38 -556
  64. package/dist/openai-tool-schema-ynZBgqW-.d.mts +38 -0
  65. package/dist/openai-transport-params-DNasp2fU.mjs +674 -0
  66. package/dist/{provider-error-9TraxGvt.mjs → provider-error-C6TbKiey.mjs} +23 -6
  67. package/dist/{provider-options-Bcc_p-TU.d.mts → provider-options-BXr9Ec83.d.mts} +4 -39
  68. package/dist/{provider-transcript-transform-BaMbI1hr.mjs → provider-transcript-transform-pPmUIwKt.mjs} +1 -1
  69. package/dist/provider-types-CAV0Og3m.d.mts +29 -0
  70. package/dist/provider-types.d.mts +6 -31
  71. package/dist/providers.d.mts +2 -2
  72. package/dist/providers.mjs +11 -11
  73. package/dist/{reasoning-tag-text-partitioner-DLCNXki6.mjs → reasoning-tag-text-partitioner-BQBi4B9d.mjs} +19 -12
  74. package/dist/record-coerce-DwRYMj3t.mjs +32 -0
  75. package/dist/retry-after-CdCURCVg.d.mts +15 -0
  76. package/dist/{sanitize-unicode-D6xUvZaS.mjs → sanitize-unicode-Bb-v9meu.mjs} +1 -1
  77. package/dist/session-affinity-CCH7eYdB.mjs +20 -0
  78. package/dist/{simple-options-BjHCCh4v.mjs → simple-options-tcKOqnpF.mjs} +3 -3
  79. package/dist/{src-2qBGKg8O.mjs → src-B2Q_6G8V.mjs} +1 -1
  80. package/dist/{stream-first-event-timeout-DcNjoFQE.mjs → stream-first-event-timeout-2hfrquuz.mjs} +1 -1
  81. package/dist/string-coerce-fsri9iCu.mjs +34 -0
  82. package/dist/{string-normalization--fwJ4S2q.mjs → string-normalization-CmLIasuf.mjs} +1 -1
  83. package/dist/{tool-schema-json-projection-mJhXDcyz.mjs → tool-schema-json-projection-ClptDdAO.mjs} +2 -38
  84. package/dist/{transport-stream-shared-CZqMhfIw.mjs → transport-stream-shared-Cu3ZPhNW.mjs} +5 -5
  85. package/dist/{transport-stream-shared-xnaqxmbP.d.mts → transport-stream-shared-DOxpGJ-H.d.mts} +4 -4
  86. package/dist/transport-utils-CCooe-cr.mjs +121 -0
  87. package/dist/transports.d.mts +113 -41
  88. package/dist/transports.mjs +162 -1276
  89. package/dist/types-BADKjDBI.d.mts +1 -0
  90. package/dist/{types-CJ1-Ht7A.d.mts → types-Dy1q0CSu.d.mts} +72 -57
  91. package/dist/types.d.mts +5 -5
  92. package/dist/types.mjs +3 -3
  93. package/dist/utf16-slice-CvGodqok.mjs +29 -0
  94. package/dist/{validation-CJZtym2g.mjs → validation-BDzVDnTs.mjs} +9 -1
  95. package/dist/{validation-AKZBDGQd.d.mts → validation-CaFUZN9B.d.mts} +1 -1
  96. package/dist/validation.d.mts +1 -1
  97. package/dist/validation.mjs +1 -1
  98. package/package.json +13 -3
  99. package/dist/anthropic-BDdqdVLK.mjs +0 -886
  100. package/dist/event-stream-zctLx0yr.d.mts +0 -1
  101. package/dist/google-shared-CWeG8RIl.mjs +0 -636
  102. package/dist/google-thinking-level-C-V3tecN.mjs +0 -9
  103. package/dist/openai-completions-BIUV3RDT.mjs +0 -403
  104. package/dist/openai-prompt-cache-CGnVB74a.mjs +0 -21
  105. package/dist/openai-prompt-cache-CNoIfHYC.d.mts +0 -16
  106. package/dist/transport-utils-7il795_9.mjs +0 -138
  107. package/dist/types-3Lnm-QSJ.d.mts +0 -1
  108. package/dist/utf16-slice-qz3nsy87.mjs +0 -84
@@ -1 +0,0 @@
1
- import "./event-stream-BhT5T1Ay.mjs";
@@ -1,636 +0,0 @@
1
- import { i as clampThinkingLevel, r as calculateCost, t as sanitizeSurrogates } from "./sanitize-unicode-D6xUvZaS.mjs";
2
- import { a as describeToolResultMediaPlaceholder, c as extractToolResultText, d as isImageWithMediaPayload } from "./host-CEvLw30U.mjs";
3
- import { d as stripSystemPromptCacheBoundary, m as sortPromptCacheToolsByName } from "./simple-options-BjHCCh4v.mjs";
4
- import { _ as transportAbortError, n as coerceTransportToolCallArguments, p as notifyProviderStreamOpened, t as assignTransportErrorDetails } from "./transport-stream-shared-CZqMhfIw.mjs";
5
- import { t as notifyLlmRequestActivity } from "./llm-request-activity-BjtkplhG.mjs";
6
- import { t as googleFlashSupportsMinimalThinking } from "./google-thinking-level-C-V3tecN.mjs";
7
- import { t as transformProviderMessages } from "./provider-transcript-transform-BaMbI1hr.mjs";
8
- import { FinishReason, FunctionCallingConfigMode, ThinkingLevel } from "@google/genai";
9
- //#region packages/ai/src/providers/google-shared.ts
10
- /**
11
- * Shared utilities for Google Generative AI and Google Vertex providers.
12
- */
13
- const GOOGLE_MODEL_RESOURCE_PREFIX = /^(?:(?:projects\/[^/]+\/locations\/[^/]+\/)?publishers\/google\/models\/|google\/|models\/)/u;
14
- /**
15
- * Determines whether a streamed Gemini `Part` should be treated as "thinking".
16
- *
17
- * Protocol note (Gemini / Vertex AI thought signatures):
18
- * - `thought: true` is the definitive marker for thinking content (thought summaries).
19
- * - `thoughtSignature` is an encrypted representation of the model's internal thought process
20
- * used to preserve reasoning context across multi-turn interactions.
21
- * - `thoughtSignature` can appear on ANY part type (text, functionCall, etc.) - it does NOT
22
- * indicate the part itself is thinking content.
23
- * - For non-functionCall responses, the signature appears on the last part for context replay.
24
- * - When persisting/replaying model outputs, signature-bearing parts must be preserved as-is;
25
- * do not merge/move signatures across parts.
26
- *
27
- * See: https://ai.google.dev/gemini-api/docs/thought-signatures
28
- */
29
- function isThinkingPart(part) {
30
- return part.thought === true;
31
- }
32
- /**
33
- * Retain thought signatures during streaming.
34
- *
35
- * Some backends only send `thoughtSignature` on the first delta for a given part/block; later deltas may omit it.
36
- * This helper preserves the last non-empty signature for the current block.
37
- *
38
- * Note: this does NOT merge or move signatures across distinct response parts. It only prevents
39
- * a signature from being overwritten with `undefined` within the same streamed block.
40
- * @internal Directly tested provider implementation detail.
41
- */
42
- function retainThoughtSignature(existing, incoming) {
43
- if (typeof incoming === "string" && incoming.length > 0) return incoming;
44
- return existing;
45
- }
46
- const base64SignaturePattern = /^[A-Za-z0-9+/]+={0,2}$/;
47
- function isValidThoughtSignature(signature) {
48
- if (!signature) return false;
49
- if (signature.length % 4 !== 0) return false;
50
- return base64SignaturePattern.test(signature);
51
- }
52
- /**
53
- * Only keep signatures from the same provider/model and with valid base64.
54
- */
55
- function resolveThoughtSignature(isSameProviderAndModel, signature) {
56
- return isSameProviderAndModel && isValidThoughtSignature(signature) ? signature : void 0;
57
- }
58
- /**
59
- * Models via Google APIs that require explicit tool call IDs in function calls/responses.
60
- * @internal Directly tested provider implementation detail.
61
- */
62
- function requiresToolCallId(modelId) {
63
- return modelId.startsWith("claude-") || modelId.startsWith("gpt-oss-");
64
- }
65
- function getGeminiMajorVersion(modelId) {
66
- const match = modelId.toLowerCase().match(/(?:^|\/)gemini(?:-live)?-(\d+)/);
67
- if (!match) return;
68
- const majorVersion = match.at(1);
69
- return majorVersion === void 0 ? void 0 : Number.parseInt(majorVersion, 10);
70
- }
71
- function supportsMultimodalFunctionResponse(modelId) {
72
- const geminiMajorVersion = getGeminiMajorVersion(modelId);
73
- if (geminiMajorVersion !== void 0) return geminiMajorVersion >= 3;
74
- return true;
75
- }
76
- /**
77
- * Convert internal messages to Gemini Content[] format.
78
- * @internal Directly tested provider implementation detail.
79
- */
80
- function convertMessages(model, context) {
81
- const contents = [];
82
- const normalizeToolCallId = (id) => {
83
- if (!requiresToolCallId(model.id)) return id;
84
- return id.replace(/[^a-zA-Z0-9_-]/g, "_").slice(0, 64);
85
- };
86
- const transformedMessages = transformProviderMessages(context.messages, model, normalizeToolCallId);
87
- const requiresToolCallThoughtSignature = model.provider !== "google-gemini-cli" && (isGemini3ProModel(model) || isGemini3FlashModel(model));
88
- const pendingToolResultImageTurns = [];
89
- const sameRouteToolCallIds = /* @__PURE__ */ new Set();
90
- let activeToolResultParts;
91
- const flushToolResultRun = () => {
92
- contents.push(...pendingToolResultImageTurns);
93
- pendingToolResultImageTurns.length = 0;
94
- activeToolResultParts = void 0;
95
- };
96
- for (const msg of transformedMessages) {
97
- if (msg.role !== "toolResult") flushToolResultRun();
98
- if (msg.role === "user") {
99
- if (typeof msg.content === "string") contents.push({
100
- role: "user",
101
- parts: [{ text: sanitizeSurrogates(msg.content) || " " }]
102
- });
103
- else {
104
- const parts = msg.content.map((item) => {
105
- if (item.type === "text") return { text: sanitizeSurrogates(item.text) || " " };
106
- return { inlineData: {
107
- mimeType: item.mimeType,
108
- data: item.data
109
- } };
110
- });
111
- if (parts.length === 0) parts.push({ text: " " });
112
- contents.push({
113
- role: "user",
114
- parts
115
- });
116
- }
117
- } else if (msg.role === "assistant") {
118
- const parts = [];
119
- let sawFunctionCall = false;
120
- const isSameProviderAndModel = msg.provider === model.provider && msg.api === model.api && msg.model === model.id;
121
- for (const block of msg.content) if (block.type === "text") {
122
- const thoughtSignature = resolveThoughtSignature(isSameProviderAndModel, block.textSignature);
123
- if ((!block.text || block.text.trim() === "") && !thoughtSignature) continue;
124
- parts.push({
125
- text: sanitizeSurrogates(block.text),
126
- ...thoughtSignature && { thoughtSignature }
127
- });
128
- } else if (block.type === "thinking") {
129
- const thoughtSignature = resolveThoughtSignature(isSameProviderAndModel, block.thinkingSignature);
130
- if ((!block.thinking || block.thinking.trim() === "") && !thoughtSignature) continue;
131
- if (isSameProviderAndModel) parts.push({
132
- thought: true,
133
- text: sanitizeSurrogates(block.thinking),
134
- ...thoughtSignature && { thoughtSignature }
135
- });
136
- else parts.push({ text: sanitizeSurrogates(block.thinking) });
137
- } else if (block.type === "toolCall") {
138
- if (isSameProviderAndModel && model.provider !== "google-gemini-cli") sameRouteToolCallIds.add(block.id);
139
- const args = coerceTransportToolCallArguments(block.arguments);
140
- const thoughtSignature = resolveThoughtSignature(isSameProviderAndModel, block.thoughtSignature) ?? (!sawFunctionCall && requiresToolCallThoughtSignature ? "skip_thought_signature_validator" : void 0);
141
- sawFunctionCall = true;
142
- const part = {
143
- functionCall: {
144
- name: block.name,
145
- args,
146
- ...sameRouteToolCallIds.has(block.id) || requiresToolCallId(model.id) ? { id: block.id } : {}
147
- },
148
- ...thoughtSignature && { thoughtSignature }
149
- };
150
- parts.push(part);
151
- }
152
- if (parts.length === 0) continue;
153
- contents.push({
154
- role: "model",
155
- parts
156
- });
157
- } else if (msg.role === "toolResult") {
158
- const textResult = extractToolResultText(msg.content);
159
- const imageContent = model.input.includes("image") ? msg.content.filter(isImageWithMediaPayload) : [];
160
- const hasText = textResult.length > 0;
161
- const hasImages = imageContent.length > 0;
162
- const mediaPlaceholder = describeToolResultMediaPlaceholder(msg.content);
163
- const modelSupportsMultimodalFunctionResponse = supportsMultimodalFunctionResponse(model.id);
164
- const responseValue = hasText ? sanitizeSurrogates(textResult) : mediaPlaceholder ?? "";
165
- const imageParts = imageContent.map((imageBlock) => ({ inlineData: {
166
- mimeType: imageBlock.mimeType,
167
- data: imageBlock.data
168
- } }));
169
- const includeId = sameRouteToolCallIds.has(msg.toolCallId) || requiresToolCallId(model.id);
170
- const functionResponsePart = { functionResponse: {
171
- name: msg.toolName,
172
- response: msg.isError ? { error: responseValue } : { output: responseValue },
173
- ...hasImages && modelSupportsMultimodalFunctionResponse && { parts: imageParts },
174
- ...includeId ? { id: msg.toolCallId } : {}
175
- } };
176
- if (activeToolResultParts) activeToolResultParts.push(functionResponsePart);
177
- else {
178
- activeToolResultParts = [functionResponsePart];
179
- contents.push({
180
- role: "user",
181
- parts: activeToolResultParts
182
- });
183
- }
184
- if (hasImages && !modelSupportsMultimodalFunctionResponse) pendingToolResultImageTurns.push({
185
- role: "user",
186
- parts: [{ text: "Tool result image:" }, ...imageParts]
187
- });
188
- }
189
- }
190
- flushToolResultRun();
191
- if (contents.length === 0) contents.push({
192
- role: "user",
193
- parts: [{ text: " " }]
194
- });
195
- return contents;
196
- }
197
- /**
198
- * Convert tools to Gemini function declarations format.
199
- * @internal Directly tested provider implementation detail.
200
- */
201
- function convertTools(tools) {
202
- if (tools.length === 0) return;
203
- return [{ functionDeclarations: sortPromptCacheToolsByName(tools).map((tool) => ({
204
- name: tool.name,
205
- description: tool.description,
206
- parametersJsonSchema: tool.parameters
207
- })) }];
208
- }
209
- /**
210
- * Map tool choice string to Gemini FunctionCallingConfigMode.
211
- * @internal Directly tested provider implementation detail.
212
- */
213
- function mapToolChoice(choice) {
214
- switch (choice) {
215
- case "auto": return FunctionCallingConfigMode.AUTO;
216
- case "none": return FunctionCallingConfigMode.NONE;
217
- case "any": return FunctionCallingConfigMode.ANY;
218
- default: return FunctionCallingConfigMode.AUTO;
219
- }
220
- }
221
- function createGoogleAssistantOutput(model, api = model.api) {
222
- return {
223
- role: "assistant",
224
- content: [],
225
- api,
226
- provider: model.provider,
227
- model: model.id,
228
- usage: {
229
- input: 0,
230
- output: 0,
231
- cacheRead: 0,
232
- cacheWrite: 0,
233
- totalTokens: 0,
234
- cost: {
235
- input: 0,
236
- output: 0,
237
- cacheRead: 0,
238
- cacheWrite: 0,
239
- total: 0
240
- }
241
- },
242
- stopReason: "stop",
243
- timestamp: Date.now()
244
- };
245
- }
246
- async function runGoogleGenerateContentLifecycle(params) {
247
- const { stream, model, output, options } = params;
248
- try {
249
- const client = params.createClient();
250
- let requestParams = params.buildParams();
251
- const nextParams = await options?.onPayload?.(requestParams, model);
252
- if (nextParams !== void 0) requestParams = nextParams;
253
- const googleIterator = (await client.models.generateContentStream(requestParams))[Symbol.asyncIterator]();
254
- await notifyProviderStreamOpened({
255
- options,
256
- cancelStream: async () => {
257
- await googleIterator.return?.();
258
- }
259
- });
260
- await consumeGoogleGenerateContentStream({
261
- chunks: { [Symbol.asyncIterator]: () => googleIterator },
262
- model,
263
- output,
264
- stream,
265
- signal: options?.signal,
266
- nextToolCallId: params.nextToolCallId
267
- });
268
- } catch (error) {
269
- for (const block of output.content) if ("index" in block) delete block.index;
270
- const failure = options?.signal?.aborted ? transportAbortError(options.signal) : error;
271
- assignTransportErrorDetails(output, failure, options?.signal);
272
- stream.push({
273
- type: "error",
274
- reason: output.stopReason === "aborted" ? "aborted" : "error",
275
- error: output
276
- });
277
- stream.end();
278
- }
279
- }
280
- function buildGoogleGenerateContentParams(model, context, options = {}) {
281
- const contents = convertMessages(model, context);
282
- const generationConfig = {};
283
- if (options.temperature !== void 0) generationConfig.temperature = options.temperature;
284
- if (options.maxTokens !== void 0) generationConfig.maxOutputTokens = options.maxTokens;
285
- if (options.stop !== void 0 && options.stop.length > 0) generationConfig.stopSequences = options.stop;
286
- const config = {
287
- ...Object.keys(generationConfig).length > 0 && generationConfig,
288
- ...context.systemPrompt && { systemInstruction: sanitizeSurrogates(stripSystemPromptCacheBoundary(context.systemPrompt)) },
289
- ...context.tools && context.tools.length > 0 && { tools: convertTools(context.tools) }
290
- };
291
- if (context.tools && context.tools.length > 0 && options.toolChoice) config.toolConfig = { functionCallingConfig: { mode: mapToolChoice(options.toolChoice) } };
292
- else config.toolConfig = void 0;
293
- if (options.thinking?.enabled && model.reasoning) {
294
- const thinkingConfig = { includeThoughts: true };
295
- if (options.thinking.level !== void 0) thinkingConfig.thinkingLevel = ThinkingLevel[options.thinking.level];
296
- else if (options.thinking.budgetTokens !== void 0) thinkingConfig.thinkingBudget = options.thinking.budgetTokens;
297
- config.thinkingConfig = thinkingConfig;
298
- } else if (model.reasoning && options.thinking && !options.thinking.enabled) {
299
- const disabledThinkingConfig = getDisabledGoogleThinkingConfig(model);
300
- if (Object.keys(disabledThinkingConfig).length > 0) config.thinkingConfig = disabledThinkingConfig;
301
- }
302
- if (options.signal) {
303
- if (options.signal.aborted) throw new Error("Request aborted");
304
- config.abortSignal = options.signal;
305
- }
306
- return {
307
- model: model.id,
308
- contents,
309
- config
310
- };
311
- }
312
- function isAdaptiveGoogleReasoningLevel(value) {
313
- return value === "adaptive";
314
- }
315
- function buildGoogleSimpleThinking(model, options, config) {
316
- if (!options?.reasoning || options.reasoning === "off") return { enabled: false };
317
- if (isAdaptiveGoogleReasoningLevel(options.reasoning)) {
318
- if (!model.reasoning) return { enabled: false };
319
- if (isGemma4Model(model)) return {
320
- enabled: true,
321
- level: ThinkingLevel.HIGH
322
- };
323
- return isGemini3ProModel(model) || isGemini3FlashModel(model) ? { enabled: true } : {
324
- enabled: true,
325
- budgetTokens: -1
326
- };
327
- }
328
- const clampedReasoning = clampThinkingLevel(model, options.reasoning);
329
- if (clampedReasoning === "off") return { enabled: false };
330
- const effort = clampedReasoning === "max" ? "high" : clampedReasoning;
331
- if (isGemini3ProModel(model) || isGemini3FlashModel(model) || config?.includeGemma4ThinkingLevel && isGemma4Model(model)) return {
332
- enabled: true,
333
- level: getGoogleThinkingLevel(effort, model, { includeGemma4: config?.includeGemma4ThinkingLevel })
334
- };
335
- return {
336
- enabled: true,
337
- budgetTokens: getGoogleBudget(model, effort, options.thinkingBudgets, { useFlashLiteBudgets: config?.useFlashLiteBudgets })
338
- };
339
- }
340
- function getDisabledGoogleThinkingConfig(model) {
341
- if (isGemini3ProModel(model)) return { thinkingLevel: ThinkingLevel.LOW };
342
- if (isGemini3FlashModel(model)) return { thinkingLevel: googleFlashSupportsMinimalThinking(model.id) ? ThinkingLevel.MINIMAL : ThinkingLevel.LOW };
343
- if (isGemma4Model(model) || model.id.toLowerCase().includes("gemini-2.5-pro")) return {};
344
- return { thinkingBudget: 0 };
345
- }
346
- /** @internal Directly tested provider implementation detail. */
347
- function isGemma4Model(model) {
348
- return /gemma-?4/.test(model.id.toLowerCase());
349
- }
350
- function isGemini3ProModel(model) {
351
- return /gemini-(?:3(?:\.\d+)?-pro|pro-latest)/.test(model.id.toLowerCase());
352
- }
353
- function isGemini3FlashModel(model) {
354
- return /gemini-(?:3(?:\.\d+)?-flash|flash(?:-lite)?-latest)/.test(model.id.toLowerCase());
355
- }
356
- function getGoogleThinkingLevel(effort, model, config) {
357
- if (isGemini3ProModel(model)) switch (effort) {
358
- case "minimal":
359
- case "low": return ThinkingLevel.LOW;
360
- case "medium":
361
- case "high": return ThinkingLevel.HIGH;
362
- }
363
- if (config?.includeGemma4 && isGemma4Model(model)) switch (effort) {
364
- case "minimal":
365
- case "low": return ThinkingLevel.MINIMAL;
366
- case "medium":
367
- case "high": return ThinkingLevel.HIGH;
368
- }
369
- switch (effort) {
370
- case "minimal": return isGemini3FlashModel(model) && !googleFlashSupportsMinimalThinking(model.id) ? ThinkingLevel.LOW : ThinkingLevel.MINIMAL;
371
- case "low": return ThinkingLevel.LOW;
372
- case "medium": return ThinkingLevel.MEDIUM;
373
- case "high": return ThinkingLevel.HIGH;
374
- }
375
- return ThinkingLevel.HIGH;
376
- }
377
- function getGoogleBudget(model, effort, customBudgets, config) {
378
- if (customBudgets?.[effort] !== void 0) return customBudgets[effort];
379
- if (model.id.includes("2.5-pro")) return {
380
- minimal: 128,
381
- low: 2048,
382
- medium: 8192,
383
- high: 32768
384
- }[effort];
385
- if (config?.useFlashLiteBudgets && model.id.includes("2.5-flash-lite")) return {
386
- minimal: 512,
387
- low: 2048,
388
- medium: 8192,
389
- high: 24576
390
- }[effort];
391
- if (model.id.includes("2.5-flash")) return {
392
- minimal: 128,
393
- low: 2048,
394
- medium: 8192,
395
- high: 24576
396
- }[effort];
397
- return -1;
398
- }
399
- /**
400
- * Map Gemini FinishReason to our StopReason.
401
- * @internal Directly tested provider implementation detail.
402
- */
403
- function mapStopReason(reason) {
404
- switch (reason) {
405
- case FinishReason.STOP: return "stop";
406
- case FinishReason.MAX_TOKENS: return "length";
407
- case FinishReason.BLOCKLIST:
408
- case FinishReason.PROHIBITED_CONTENT:
409
- case FinishReason.SPII:
410
- case FinishReason.SAFETY:
411
- case FinishReason.IMAGE_SAFETY:
412
- case FinishReason.IMAGE_PROHIBITED_CONTENT:
413
- case FinishReason.IMAGE_RECITATION:
414
- case FinishReason.IMAGE_OTHER:
415
- case FinishReason.RECITATION:
416
- case FinishReason.FINISH_REASON_UNSPECIFIED:
417
- case FinishReason.OTHER:
418
- case FinishReason.LANGUAGE:
419
- case FinishReason.MALFORMED_FUNCTION_CALL:
420
- case FinishReason.TOO_MANY_TOOL_CALLS:
421
- case FinishReason.UNEXPECTED_TOOL_CALL:
422
- case FinishReason.NO_IMAGE: return "error";
423
- default: throw new Error(`Unhandled stop reason: ${String(reason)}`);
424
- }
425
- }
426
- /** @internal Directly tested provider implementation detail. */
427
- async function consumeGoogleGenerateContentStream(params) {
428
- params.stream.push({
429
- type: "start",
430
- partial: params.output
431
- });
432
- let currentBlock = null;
433
- const blocks = params.output.content;
434
- let sawTerminalReason = false;
435
- let terminalGenerationError;
436
- const knownUsage = {
437
- promptTokenCount: 0,
438
- cachedContentTokenCount: 0,
439
- toolUsePromptTokenCount: 0,
440
- candidatesTokenCount: 0,
441
- thoughtsTokenCount: 0
442
- };
443
- const toolCallIds = /* @__PURE__ */ new Set();
444
- for (const block of blocks) if (block.type === "toolCall") toolCallIds.add(block.id);
445
- const blockIndex = () => blocks.length - 1;
446
- const endCurrentBlock = () => {
447
- if (!currentBlock) return;
448
- if (currentBlock.type === "text") params.stream.push({
449
- type: "text_end",
450
- contentIndex: blockIndex(),
451
- content: currentBlock.text,
452
- partial: params.output
453
- });
454
- else params.stream.push({
455
- type: "thinking_end",
456
- contentIndex: blockIndex(),
457
- content: currentBlock.thinking,
458
- partial: params.output
459
- });
460
- currentBlock = null;
461
- };
462
- for await (const chunk of params.chunks) {
463
- notifyLlmRequestActivity(params.signal);
464
- params.output.responseId ||= chunk.responseId;
465
- const responseModel = chunk.modelVersion?.trim();
466
- if (responseModel && params.model.id.replace(GOOGLE_MODEL_RESOURCE_PREFIX, "") !== responseModel.replace(GOOGLE_MODEL_RESOURCE_PREFIX, "")) params.output.responseModel ||= responseModel;
467
- if (chunk.usageMetadata) {
468
- for (const field of Object.keys(knownUsage)) {
469
- const value = chunk.usageMetadata[field];
470
- if (typeof value === "number") knownUsage[field] = value;
471
- }
472
- const promptTokens = knownUsage.promptTokenCount;
473
- const cacheRead = knownUsage.cachedContentTokenCount;
474
- const toolUsePromptTokens = knownUsage.toolUsePromptTokenCount;
475
- const outputTokens = knownUsage.candidatesTokenCount + knownUsage.thoughtsTokenCount;
476
- params.output.usage = {
477
- input: Math.max(0, promptTokens - cacheRead) + toolUsePromptTokens,
478
- output: outputTokens,
479
- cacheRead,
480
- cacheWrite: 0,
481
- totalTokens: chunk.usageMetadata.totalTokenCount ?? promptTokens + outputTokens + toolUsePromptTokens,
482
- cost: {
483
- input: 0,
484
- output: 0,
485
- cacheRead: 0,
486
- cacheWrite: 0,
487
- total: 0
488
- }
489
- };
490
- calculateCost(params.model, params.output.usage);
491
- }
492
- const candidate = chunk.candidates?.[0];
493
- const promptFeedback = chunk.promptFeedback;
494
- if (!candidate && promptFeedback) {
495
- const blockReason = promptFeedback.blockReason ?? "PROMPT_BLOCKED";
496
- const blockMessage = promptFeedback.blockReasonMessage?.trim();
497
- params.output.errorCode = blockReason;
498
- params.output.errorType = "google_prompt_blocked";
499
- throw new Error(`Google prompt blocked (${blockReason})${blockMessage ? `: ${blockMessage}` : ""}`);
500
- }
501
- if (candidate?.content?.parts) for (const [partIndex, part] of candidate.content.parts.entries()) {
502
- const text = part.text;
503
- const hasText = typeof text === "string";
504
- const hasThoughtSignature = typeof part.thoughtSignature === "string" && part.thoughtSignature.length > 0;
505
- const signatureOnly = hasThoughtSignature && (!hasText || text.length === 0) && Object.keys(part).every((key) => key === "thought" || key === "thoughtSignature" || key === "text");
506
- if (signatureOnly) {
507
- if (!hasText && part.thought !== true) {
508
- const latestBlock = blocks.at(-1);
509
- if (partIndex === 0 && latestBlock?.type === "toolCall" && !latestBlock.thoughtSignature) {
510
- latestBlock.thoughtSignature = retainThoughtSignature(latestBlock.thoughtSignature, part.thoughtSignature);
511
- continue;
512
- }
513
- }
514
- endCurrentBlock();
515
- }
516
- if (hasText || signatureOnly) {
517
- if (currentBlock && (hasThoughtSignature || partIndex > 0)) {
518
- const currentSignature = currentBlock.type === "thinking" ? currentBlock.thinkingSignature : currentBlock.textSignature;
519
- if ((currentBlock.type === "thinking" ? currentBlock.thinking : currentBlock.text).length > 0 && (currentSignature !== part.thoughtSignature || partIndex > 0 && (currentSignature || hasThoughtSignature))) endCurrentBlock();
520
- }
521
- const isThinking = isThinkingPart(part);
522
- if (!currentBlock || isThinking && currentBlock.type !== "thinking" || !isThinking && currentBlock.type !== "text") {
523
- endCurrentBlock();
524
- if (isThinking) {
525
- currentBlock = {
526
- type: "thinking",
527
- thinking: "",
528
- thinkingSignature: void 0
529
- };
530
- params.output.content.push(currentBlock);
531
- params.stream.push({
532
- type: "thinking_start",
533
- contentIndex: blockIndex(),
534
- partial: params.output
535
- });
536
- } else {
537
- currentBlock = {
538
- type: "text",
539
- text: ""
540
- };
541
- params.output.content.push(currentBlock);
542
- params.stream.push({
543
- type: "text_start",
544
- contentIndex: blockIndex(),
545
- partial: params.output
546
- });
547
- }
548
- }
549
- const delta = hasText ? text : "";
550
- if (currentBlock.type === "thinking") {
551
- currentBlock.thinking += delta;
552
- currentBlock.thinkingSignature = retainThoughtSignature(currentBlock.thinkingSignature, part.thoughtSignature);
553
- params.stream.push({
554
- type: "thinking_delta",
555
- contentIndex: blockIndex(),
556
- delta,
557
- partial: params.output
558
- });
559
- } else {
560
- currentBlock.text += delta;
561
- currentBlock.textSignature = retainThoughtSignature(currentBlock.textSignature, part.thoughtSignature);
562
- params.stream.push({
563
- type: "text_delta",
564
- contentIndex: blockIndex(),
565
- delta,
566
- partial: params.output
567
- });
568
- }
569
- if (signatureOnly) endCurrentBlock();
570
- }
571
- if (part.functionCall) {
572
- endCurrentBlock();
573
- const providedId = part.functionCall.id;
574
- const toolCall = {
575
- type: "toolCall",
576
- id: !providedId || toolCallIds.has(providedId) ? params.nextToolCallId(part.functionCall.name) : providedId,
577
- name: part.functionCall.name || "",
578
- arguments: part.functionCall.args ?? {},
579
- ...part.thoughtSignature && { thoughtSignature: part.thoughtSignature }
580
- };
581
- params.output.content.push(toolCall);
582
- toolCallIds.add(toolCall.id);
583
- params.stream.push({
584
- type: "toolcall_start",
585
- contentIndex: blockIndex(),
586
- partial: params.output
587
- });
588
- params.stream.push({
589
- type: "toolcall_delta",
590
- contentIndex: blockIndex(),
591
- delta: JSON.stringify(toolCall.arguments),
592
- partial: params.output
593
- });
594
- params.stream.push({
595
- type: "toolcall_end",
596
- contentIndex: blockIndex(),
597
- toolCall,
598
- partial: params.output
599
- });
600
- }
601
- }
602
- if (candidate?.finishReason && candidate.finishReason !== FinishReason.FINISH_REASON_UNSPECIFIED) {
603
- sawTerminalReason = true;
604
- params.output.stopReason = mapStopReason(candidate.finishReason);
605
- if (params.output.stopReason === "error") {
606
- const finishMessage = candidate.finishMessage?.trim();
607
- terminalGenerationError = Object.assign(/* @__PURE__ */ new Error(`Google generation stopped (${candidate.finishReason})${finishMessage ? `: ${finishMessage}` : ""}`), {
608
- code: candidate.finishReason,
609
- type: "google_generation_failed"
610
- });
611
- }
612
- if (params.output.stopReason === "stop" && params.output.content.some((block) => block.type === "toolCall")) params.output.stopReason = "toolUse";
613
- }
614
- }
615
- endCurrentBlock();
616
- if (params.signal?.aborted) throw transportAbortError(params.signal);
617
- if (terminalGenerationError) {
618
- params.output.errorCode = terminalGenerationError.code;
619
- params.output.errorType = terminalGenerationError.type;
620
- throw terminalGenerationError;
621
- }
622
- if (!sawTerminalReason) {
623
- params.output.errorCode = "STREAM_INCOMPLETE";
624
- params.output.errorType = "google_incomplete_stream";
625
- throw new Error("Google stream ended before a terminal finish reason");
626
- }
627
- if (params.output.stopReason === "aborted" || params.output.stopReason === "error") throw new Error("An unknown error occurred");
628
- params.stream.push({
629
- type: "done",
630
- reason: params.output.stopReason,
631
- message: params.output
632
- });
633
- params.stream.end();
634
- }
635
- //#endregion
636
- export { runGoogleGenerateContentLifecycle as i, buildGoogleSimpleThinking as n, createGoogleAssistantOutput as r, buildGoogleGenerateContentParams as t };
@@ -1,9 +0,0 @@
1
- //#region packages/ai/src/transports/google-thinking-level.ts
2
- /** Returns whether a Gemini Flash model accepts the MINIMAL thinking level. */
3
- function googleFlashSupportsMinimalThinking(modelId) {
4
- const match = modelId.toLowerCase().match(/(?:^|\/)gemini-3\.(\d+)-flash(?:-|$)/);
5
- if (!match) return true;
6
- return Number.parseInt(match[1] ?? "0", 10) < 7;
7
- }
8
- //#endregion
9
- export { googleFlashSupportsMinimalThinking as t };