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