@openclaw/ai 2026.9.6 → 2026.9.7

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 (99) hide show
  1. package/dist/{anthropic-DZQ_7gD1.mjs → anthropic-Cw2pgccz.mjs} +37 -66
  2. package/dist/{anthropic-payload-policy-DyfwikYJ.d.mts → anthropic-payload-policy-NIPVYXPq.d.mts} +7 -5
  3. package/dist/{anthropic-stream-reducer-D6ZI1wwj.mjs → anthropic-stream-reducer-D9MCkl8Z.mjs} +192 -261
  4. package/dist/{api-registry-C2T3lTV7.d.mts → api-registry-D-nbmSqr.d.mts} +2 -2
  5. package/dist/{azure-openai-responses-DS86GYzq.mjs → azure-openai-responses-BwT3-X8P.mjs} +22 -33
  6. package/dist/{base64-CPmadnUf.mjs → base64-C1PsYcRQ.mjs} +15 -9
  7. package/dist/{diagnostics-CH8j2wIG.mjs → diagnostics-CJaB6g8J.mjs} +3 -3
  8. package/dist/diagnostics.d.mts +4 -4
  9. package/dist/diagnostics.mjs +2 -2
  10. package/dist/{env-api-keys-bktO00EJ.mjs → env-api-keys-CyX4VKGO.mjs} +7 -5
  11. package/dist/event-stream-CMQfX_yr.d.mts +1 -0
  12. package/dist/{event-stream-CjnIZZst.d.mts → event-stream-DOPFYVqs.d.mts} +2 -2
  13. package/dist/{event-stream-D8PARQfL.mjs → event-stream-vd9UnCAU.mjs} +10 -0
  14. package/dist/event-stream.d.mts +2 -2
  15. package/dist/event-stream.mjs +1 -1
  16. package/dist/{google-BZJFjhuC.mjs → google-BfapkS_K.mjs} +8 -11
  17. package/dist/google-interactions-DW3iXzjc.mjs +574 -0
  18. package/dist/{google-messages-DB7GKkDk.mjs → google-messages-CtjVtVot.mjs} +35 -71
  19. package/dist/{google-shared-Bok4I6zB.mjs → google-shared-Y2YfotEu.mjs} +43 -47
  20. package/dist/{google-vertex-3eVNR2qW.mjs → google-vertex-Dov4kBWu.mjs} +16 -30
  21. package/dist/{host-yTvBrYM2.mjs → host-CHi3X87F.mjs} +29 -188
  22. package/dist/{host-policy-DZO3oPPk.mjs → host-policy-BOAwRg_M.mjs} +2 -14
  23. package/dist/{host-DH-Z-LDb.d.mts → host-rxlNaBwm.d.mts} +9 -3
  24. package/dist/{index-C25RT6bP.d.mts → index-D6KsSE74.d.mts} +28 -8
  25. package/dist/index.d.mts +7 -7
  26. package/dist/index.mjs +6 -6
  27. package/dist/internal/anthropic.d.mts +8 -7
  28. package/dist/internal/anthropic.mjs +5 -5
  29. package/dist/internal/openai-completions-compat.d.mts +1 -1
  30. package/dist/internal/openai-completions-compat.mjs +1 -1
  31. package/dist/internal/openai-responses-payload-policy.d.mts +1 -1
  32. package/dist/internal/openai-responses-payload-policy.mjs +2 -2
  33. package/dist/internal/openai.d.mts +31 -8
  34. package/dist/internal/openai.mjs +13 -13
  35. package/dist/internal/runtime.d.mts +31 -70
  36. package/dist/internal/runtime.mjs +10 -65
  37. package/dist/internal/shared.d.mts +14 -12
  38. package/dist/internal/shared.mjs +5 -4
  39. package/dist/internal/tool-schema.d.mts +1 -1
  40. package/dist/internal/tool-schema.mjs +2 -2
  41. package/dist/{mistral-C_13dVBn.mjs → mistral-RS6mboC-.mjs} +46 -93
  42. package/dist/{openai-chatgpt-responses-sTxPl4zM.mjs → openai-chatgpt-responses-CYbidtrn.mjs} +26 -30
  43. package/dist/{openai-completions-BO6D_hrB.mjs → openai-completions-D14ihPYk.mjs} +14 -12
  44. package/dist/{openai-completions-compat-CUollwl6.mjs → openai-completions-compat-BOVWBZDn.mjs} +3 -5
  45. package/dist/{openai-completions-compat-DfJG1wSO.d.mts → openai-completions-compat-qJjmqQ71.d.mts} +3 -3
  46. package/dist/{openai-completions-stream-BpuJ0ZOA.mjs → openai-completions-stream-CDCuw3DP.mjs} +101 -173
  47. package/dist/{openai-prompt-cache-C4RHdN4n.d.mts → openai-prompt-cache-CouErLh7.d.mts} +2 -2
  48. package/dist/{openai-prompt-cache-CjV_2IRI.mjs → openai-prompt-cache-D2V7MqR7.mjs} +1 -1
  49. package/dist/{openai-provider-client-BP8J1aeg.mjs → openai-provider-client-CwfsGBbA.mjs} +2 -2
  50. package/dist/{openai-reasoning-effort-ash8dPrd.mjs → openai-reasoning-effort-ConhwkeX.mjs} +2 -1
  51. package/dist/{openai-responses-BJ_IEoMU.mjs → openai-responses-CKCBEc2W.mjs} +12 -11
  52. package/dist/openai-responses-compaction-replay-DiYn-gFM.d.mts +12 -0
  53. package/dist/{openai-responses-compaction-window-BiNCT0bS.mjs → openai-responses-compaction-window-UNK1GDpy.mjs} +5 -5
  54. package/dist/{openai-responses-contracts-DWrfMODE.mjs → openai-responses-contracts-CLxnqS9p.mjs} +1 -1
  55. package/dist/{openai-responses-contracts-B1ENJFpI.d.mts → openai-responses-contracts-D1iZ0njF.d.mts} +4 -4
  56. package/dist/{openai-responses-prompt-observer-internal-DPHWgbBH.mjs → openai-responses-prompt-observer-internal-iAqLb4tk.mjs} +12 -12
  57. package/dist/{openai-responses-request-lifecycle-DFuyO1pQ.mjs → openai-responses-request-lifecycle-Fsag-IGZ.mjs} +1 -1
  58. package/dist/{openai-responses-shared-DvSqtJ6_.mjs → openai-responses-shared-DL4ulQn7.mjs} +312 -122
  59. package/dist/{openai-responses-terminal-usage-BNFbvY9f.d.mts → openai-responses-terminal-usage-BE7lf7nW.d.mts} +2 -2
  60. package/dist/{openai-stop-reason-Drnn_6Qj.mjs → openai-stop-reason-8s70vDXj.mjs} +2 -12
  61. package/dist/{openai-tool-schema-ynZBgqW-.d.mts → openai-tool-schema-a5ysBBga.d.mts} +0 -6
  62. package/dist/{openai-tool-schema-D4BMcj2D.mjs → openai-tool-schema-vsl-cE-n.mjs} +243 -383
  63. package/dist/{openai-transport-params-DZKOTSfH.mjs → openai-transport-params-BwlpzX-2.mjs} +60 -105
  64. package/dist/{positive-integer-BiUxrd71.mjs → positive-integer-CjN5OJbH.mjs} +1 -1
  65. package/dist/{provider-error-CRhW7lkJ.mjs → provider-error-CwT_j2v0.mjs} +43 -4
  66. package/dist/{provider-options-DZYq53lj.d.mts → provider-options-Df7ov0K1.d.mts} +2 -2
  67. package/dist/{provider-replay-context-DPr3w20a.mjs → provider-replay-context-DsyI5jOP.mjs} +1 -1
  68. package/dist/{provider-transcript-transform-BTocjCRs.mjs → provider-transcript-transform-JbFbHV8h.mjs} +17 -2
  69. package/dist/{provider-transport-turn-state-lrXEFkYr.mjs → provider-transport-turn-state-BheUi_hl.mjs} +1 -1
  70. package/dist/{provider-types-w1rEqrGP.d.mts → provider-types-d4XnoZMd.d.mts} +3 -3
  71. package/dist/provider-types.d.mts +6 -6
  72. package/dist/providers.d.mts +2 -2
  73. package/dist/providers.mjs +15 -11
  74. package/dist/{reasoning-tag-text-partitioner-Di38crhI.mjs → reasoning-tag-text-partitioner-B6FIIBt6.mjs} +47 -71
  75. package/dist/{record-coerce-DwRYMj3t.mjs → record-coerce-CNDovvft.mjs} +1 -1
  76. package/dist/simple-options-CGAkCwtM.mjs +349 -0
  77. package/dist/{src-DwGYYyZp.mjs → src-H4aXcFuX.mjs} +43 -25
  78. package/dist/{stream-CREqxHgU.mjs → stream-DDsCBgd-.mjs} +1 -7
  79. package/dist/{stream-first-event-timeout-BeptfRL6.mjs → stream-first-event-timeout-B9o0S4SZ.mjs} +1 -1
  80. package/dist/{tool-schema-json-projection-CD9c_fK8.mjs → tool-schema-json-projection-Ct8SeBeJ.mjs} +63 -23
  81. package/dist/{transport-stream-shared-B5RioB_Q.mjs → transport-stream-shared-Dh5qKJ8e.mjs} +62 -28
  82. package/dist/{transport-stream-shared-B7Z9oCYg.d.mts → transport-stream-shared-yYhXa4kX.d.mts} +12 -6
  83. package/dist/{transport-utils-03Qi0CN2.mjs → transport-utils-C-4bf2Ok.mjs} +3 -4
  84. package/dist/transports.d.mts +36 -32
  85. package/dist/transports.mjs +160 -216
  86. package/dist/types-CB-_vNyI.d.mts +1 -0
  87. package/dist/{types-qZFbaDbK.d.mts → types-CLLR3eB4.d.mts} +3 -1
  88. package/dist/types.d.mts +6 -6
  89. package/dist/types.mjs +4 -4
  90. package/dist/{validation-Dw7cb6BV.mjs → validation-BFZc40Ig.mjs} +80 -54
  91. package/dist/{validation-DhQhmt6t.d.mts → validation-Cat2wQsc.d.mts} +1 -1
  92. package/dist/validation.d.mts +1 -1
  93. package/dist/validation.mjs +1 -1
  94. package/package.json +5 -5
  95. package/dist/assistant-output-DM1JBNs1.mjs +0 -16
  96. package/dist/event-stream-C0nsgbj2.d.mts +0 -1
  97. package/dist/simple-options-np1XPuhm.mjs +0 -175
  98. package/dist/types-DTvddOfm.d.mts +0 -1
  99. package/dist/utf16-slice-CvGodqok.mjs +0 -29
@@ -0,0 +1,574 @@
1
+ import { t as AssistantMessageEventStream } from "./event-stream-vd9UnCAU.mjs";
2
+ import { a as asRecord, i as asOptionalRecord, s as readStringField } from "./record-coerce-CNDovvft.mjs";
3
+ import { n as getAiTransportHost, r as resolveAiTransportHeaderSentinels, w as calculateCost } from "./host-CHi3X87F.mjs";
4
+ import { t as buildGuardedModelFetch } from "./host-policy-BOAwRg_M.mjs";
5
+ import { b as transportAbortError, c as failTransportStream, g as parseTerminalToolCallArguments, h as notifyProviderStreamOpened, j as sanitizeSurrogates, m as notifyProviderHttpResponse, w as parseJsonPreservingUnsafeIntegers } from "./transport-stream-shared-Dh5qKJ8e.mjs";
6
+ import { C as stripSystemPromptCacheBoundary, n as buildBaseOptions } from "./simple-options-CGAkCwtM.mjs";
7
+ import { n as getEnvApiKey } from "./env-api-keys-CyX4VKGO.mjs";
8
+ import { n as createAssistantOutput, t as transformProviderMessages } from "./provider-transcript-transform-JbFbHV8h.mjs";
9
+ import { n as buildGoogleInteractionsSimpleThinking } from "./google-shared-Y2YfotEu.mjs";
10
+ import { createRequire } from "node:module";
11
+ //#region packages/ai/src/providers/google-interactions-request.ts
12
+ const DEFAULT_GOOGLE_API_BASE_URL = "https://generativelanguage.googleapis.com";
13
+ let packageVersionMemo;
14
+ function resolvePackageVersion() {
15
+ if (packageVersionMemo) return packageVersionMemo;
16
+ if (typeof process !== "undefined" && process.env?.OPENCLAW_VERSION) {
17
+ packageVersionMemo = process.env.OPENCLAW_VERSION;
18
+ return packageVersionMemo;
19
+ }
20
+ try {
21
+ const require = createRequire(import.meta.url);
22
+ for (const candidate of [
23
+ "../package.json",
24
+ "../../package.json",
25
+ "../../../package.json",
26
+ "../../../../package.json"
27
+ ]) try {
28
+ const parsed = asRecord(require(candidate));
29
+ const name = readStringField(parsed, "name");
30
+ const version = readStringField(parsed, "version");
31
+ if (version && (name === "openclaw" || name === "@openclaw/ai")) {
32
+ packageVersionMemo = version;
33
+ return packageVersionMemo;
34
+ }
35
+ } catch {}
36
+ } catch {}
37
+ packageVersionMemo = "0.0";
38
+ return packageVersionMemo;
39
+ }
40
+ function resolveGoogleApiClientHeaders(params) {
41
+ const hostHeaders = getAiTransportHost().resolveProviderRequestHeaders({
42
+ provider: "google",
43
+ api: params?.api ?? params?.model?.api ?? "google-generative-ai",
44
+ baseUrl: params?.baseUrl ?? DEFAULT_GOOGLE_API_BASE_URL,
45
+ model: params?.model
46
+ });
47
+ if (hostHeaders?.["x-goog-api-client"]) return hostHeaders;
48
+ return {
49
+ ...hostHeaders,
50
+ "x-goog-api-client": `openclaw/${resolvePackageVersion()}`
51
+ };
52
+ }
53
+ function convertToolResultContent(content) {
54
+ if (!Array.isArray(content)) return content;
55
+ return content.map((item) => {
56
+ if (item.type === "image") return {
57
+ type: "image",
58
+ mime_type: item.mimeType,
59
+ data: item.data
60
+ };
61
+ if (item.type === "text") return {
62
+ type: "text",
63
+ text: sanitizeSurrogates(item.text)
64
+ };
65
+ return item;
66
+ });
67
+ }
68
+ function convertMessages(model, context) {
69
+ const steps = [];
70
+ const messages = transformProviderMessages(context.messages, model);
71
+ for (const message of messages) {
72
+ if (message.role === "user") {
73
+ if (typeof message.content === "string") {
74
+ steps.push({
75
+ type: "user_input",
76
+ content: [{
77
+ type: "text",
78
+ text: sanitizeSurrogates(message.content) || " "
79
+ }]
80
+ });
81
+ continue;
82
+ }
83
+ const content = message.content.map((item) => item.type === "text" ? {
84
+ type: "text",
85
+ text: sanitizeSurrogates(item.text) || " "
86
+ } : {
87
+ type: "image",
88
+ mime_type: item.mimeType,
89
+ data: item.data
90
+ });
91
+ steps.push({
92
+ type: "user_input",
93
+ content: content.length > 0 ? content : [{
94
+ type: "text",
95
+ text: " "
96
+ }]
97
+ });
98
+ continue;
99
+ }
100
+ if (message.role === "toolResult") {
101
+ steps.push({
102
+ type: "function_result",
103
+ call_id: message.toolCallId,
104
+ name: message.toolName || "tool",
105
+ result: convertToolResultContent(message.content),
106
+ is_error: message.isError
107
+ });
108
+ continue;
109
+ }
110
+ if (message.stopReason === "error") continue;
111
+ if (message.content.length === 1 && message.content[0]?.type === "text" && message.content[0].text.includes("[assistant turn failed before producing content]")) continue;
112
+ let pendingText = [];
113
+ const flushText = () => {
114
+ if (pendingText.length === 0) return;
115
+ steps.push({
116
+ type: "model_output",
117
+ content: [{
118
+ type: "text",
119
+ text: pendingText.join("\n\n")
120
+ }]
121
+ });
122
+ pendingText = [];
123
+ };
124
+ for (const block of message.content) {
125
+ if (block.type === "thinking") {
126
+ flushText();
127
+ if (block.thinkingSignature) steps.push({
128
+ type: "thought",
129
+ signature: block.thinkingSignature,
130
+ ...block.thinking.trim() ? { summary: [{
131
+ type: "text",
132
+ text: sanitizeSurrogates(block.thinking)
133
+ }] } : {}
134
+ });
135
+ continue;
136
+ }
137
+ if (block.type === "text") {
138
+ if (block.text.trim()) pendingText.push(sanitizeSurrogates(block.text));
139
+ continue;
140
+ }
141
+ flushText();
142
+ if (block.thoughtSignature && block.thoughtSignature !== "skip_thought_signature_validator" && !message.content.some((candidate) => candidate.type === "thinking")) steps.push({
143
+ type: "thought",
144
+ signature: block.thoughtSignature
145
+ });
146
+ steps.push({
147
+ type: "function_call",
148
+ id: block.id,
149
+ name: block.name,
150
+ arguments: block.arguments ?? {}
151
+ });
152
+ }
153
+ flushText();
154
+ }
155
+ return steps;
156
+ }
157
+ function buildGoogleInteractionsParams(model, context, options = {}) {
158
+ const optionRecord = asRecord(options);
159
+ if (optionRecord.cachedContent || optionRecord.cached_content) throw new Error("Explicit prompt caching ('cachedContent') is not supported with the Gemini Interactions API. The Interactions API handles caching implicitly on the server.");
160
+ if (optionRecord.videoMetadata || optionRecord.video_metadata) throw new Error("video_metadata clipping offsets are not supported with the Gemini Interactions API.");
161
+ const generationConfig = {};
162
+ if (options.temperature !== void 0) generationConfig.temperature = options.temperature;
163
+ if (options.maxTokens !== void 0) generationConfig.max_output_tokens = options.maxTokens;
164
+ if (options.stop && options.stop.length > 0) generationConfig.stop_sequences = options.stop;
165
+ if (options.thinking) {
166
+ generationConfig.thinking_summaries = options.thinking.enabled ? "auto" : "none";
167
+ const thinkingLevel = options.thinking.level ?? (options.thinking.enabled ? void 0 : buildGoogleInteractionsSimpleThinking(model, { reasoning: "off" }).level);
168
+ if (thinkingLevel) generationConfig.thinking_level = thinkingLevel.toLowerCase();
169
+ }
170
+ if (options.toolChoice) generationConfig.tool_choice = options.toolChoice;
171
+ const tools = context.tools?.map((tool) => ({
172
+ type: "function",
173
+ name: tool.name,
174
+ description: tool.description || "",
175
+ parameters: asRecord(tool.parameters)
176
+ }));
177
+ return {
178
+ model: model.id,
179
+ input: convertMessages(model, context),
180
+ ...context.systemPrompt ? { system_instruction: sanitizeSurrogates(stripSystemPromptCacheBoundary(context.systemPrompt)) } : {},
181
+ ...tools && tools.length > 0 ? { tools } : {},
182
+ ...Object.keys(generationConfig).length > 0 ? { generation_config: generationConfig } : {},
183
+ store: false,
184
+ stream: true
185
+ };
186
+ }
187
+ //#endregion
188
+ //#region packages/ai/src/providers/google-interactions-shared.ts
189
+ /**
190
+ * Gemini Interactions API adapter and lifecycle for OpenClaw.
191
+ * POST /v1beta/interactions
192
+ */
193
+ function resolveGoogleInteractionsApiKey(model, options, apiKey) {
194
+ return apiKey || options?.apiKey || getEnvApiKey(model.provider) || process.env.GEMINI_API_KEY || process.env.GOOGLE_API_KEY || "";
195
+ }
196
+ function logGoogleInteractionsDebug(message, data) {
197
+ getAiTransportHost().logDebug("google-interactions", () => ({
198
+ message,
199
+ data
200
+ }));
201
+ }
202
+ function isGoogleInteractionsRequestBody(value) {
203
+ const record = asOptionalRecord(value);
204
+ if (!record) return false;
205
+ return typeof record.model === "string" && Array.isArray(record.input) && typeof record.store === "boolean" && typeof record.stream === "boolean";
206
+ }
207
+ async function runGoogleInteractionsLifecycle(params) {
208
+ const { stream, model, output, options, context, nextToolCallId } = params;
209
+ let reader;
210
+ try {
211
+ const host = getAiTransportHost();
212
+ const unresolvedApiKey = resolveGoogleInteractionsApiKey(model, options, params.apiKey);
213
+ const apiKey = host.resolveSecretSentinel(unresolvedApiKey);
214
+ if (!apiKey.trim()) throw new Error(`No API key for provider: ${model.provider}`);
215
+ let body = buildGoogleInteractionsParams(model, context, options);
216
+ const nextBody = await options?.onPayload?.(body, model);
217
+ if (nextBody !== void 0) {
218
+ if (!isGoogleInteractionsRequestBody(nextBody)) throw new Error("Google Interactions onPayload returned an invalid request body");
219
+ body = nextBody;
220
+ }
221
+ let baseUrl = (model.baseUrl || "https://generativelanguage.googleapis.com/v1beta").trim().replace(/\/+$/, "");
222
+ if (/^https:\/\/generativelanguage\.googleapis\.com$/i.test(baseUrl)) baseUrl = "https://generativelanguage.googleapis.com/v1beta";
223
+ const url = `${baseUrl}/interactions?alt=sse`;
224
+ const googleClientHeaders = resolveGoogleApiClientHeaders({
225
+ baseUrl,
226
+ api: "google-generative-ai",
227
+ model
228
+ });
229
+ const headers = resolveAiTransportHeaderSentinels({
230
+ "Content-Type": "application/json",
231
+ "x-goog-api-key": apiKey,
232
+ "Api-Revision": "2026-05-20",
233
+ ...googleClientHeaders,
234
+ ...model.headers,
235
+ ...options?.headers
236
+ }) ?? {
237
+ "Content-Type": "application/json",
238
+ "x-goog-api-key": apiKey
239
+ };
240
+ logGoogleInteractionsDebug("request", {
241
+ method: "POST",
242
+ url,
243
+ model: model.id,
244
+ inputSteps: body.input.length,
245
+ tools: body.tools?.length ?? 0
246
+ });
247
+ const response = await buildGuardedModelFetch({
248
+ ...model,
249
+ baseUrl
250
+ }, options?.timeoutMs, { sanitizeSse: true })(url, {
251
+ method: "POST",
252
+ headers,
253
+ body: JSON.stringify(body),
254
+ signal: options?.signal
255
+ });
256
+ await notifyProviderHttpResponse({
257
+ options,
258
+ response,
259
+ model
260
+ });
261
+ logGoogleInteractionsDebug("response", {
262
+ status: response.status,
263
+ statusText: response.statusText
264
+ });
265
+ if (!response.ok) {
266
+ const errorText = await response.text();
267
+ logGoogleInteractionsDebug("request failed", { status: response.status });
268
+ throw new Error(`Google Interactions API error HTTP ${response.status}: ${errorText}`);
269
+ }
270
+ if (!response.body) throw new Error("Google Interactions API returned empty response body");
271
+ reader = response.body.getReader();
272
+ await notifyProviderStreamOpened({
273
+ options,
274
+ cancelStream: () => reader?.cancel()
275
+ });
276
+ stream.push({
277
+ type: "start",
278
+ partial: output
279
+ });
280
+ const decoder = new TextDecoder();
281
+ let buffer = "";
282
+ let currentBlockType = null;
283
+ let currentBlockIndex = -1;
284
+ let currentToolCall = null;
285
+ let currentToolArgs = "";
286
+ let latestThoughtSignature;
287
+ let latestUsage;
288
+ const endCurrentBlock = () => {
289
+ if (currentBlockType === "text") {
290
+ const block = output.content[currentBlockIndex];
291
+ const textBlock = block?.type === "text" ? block : void 0;
292
+ stream.push({
293
+ type: "text_end",
294
+ contentIndex: currentBlockIndex,
295
+ content: textBlock?.text ?? "",
296
+ partial: output
297
+ });
298
+ } else if (currentBlockType === "thinking") {
299
+ const block = output.content[currentBlockIndex];
300
+ const thinkingBlock = block?.type === "thinking" ? block : void 0;
301
+ if (thinkingBlock && !thinkingBlock.thinkingSignature && latestThoughtSignature) thinkingBlock.thinkingSignature = latestThoughtSignature;
302
+ stream.push({
303
+ type: "thinking_end",
304
+ contentIndex: currentBlockIndex,
305
+ content: thinkingBlock?.thinking ?? "",
306
+ partial: output
307
+ });
308
+ latestThoughtSignature = void 0;
309
+ } else if (currentBlockType === "toolCall" && currentToolCall) {
310
+ if (currentToolArgs.trim()) currentToolCall.arguments = parseTerminalToolCallArguments(currentToolArgs);
311
+ stream.push({
312
+ type: "toolcall_end",
313
+ contentIndex: currentBlockIndex,
314
+ toolCall: currentToolCall,
315
+ partial: output
316
+ });
317
+ currentToolCall = null;
318
+ currentToolArgs = "";
319
+ }
320
+ currentBlockType = null;
321
+ };
322
+ const startTextBlock = (type, text = "") => {
323
+ endCurrentBlock();
324
+ currentBlockIndex = output.content.length;
325
+ output.content.push(type === "text" ? {
326
+ type,
327
+ text
328
+ } : {
329
+ type,
330
+ thinking: text,
331
+ ...latestThoughtSignature ? { thinkingSignature: latestThoughtSignature } : {}
332
+ });
333
+ stream.push({
334
+ type: type === "text" ? "text_start" : "thinking_start",
335
+ contentIndex: currentBlockIndex,
336
+ partial: output
337
+ });
338
+ if (text) stream.push({
339
+ type: type === "text" ? "text_delta" : "thinking_delta",
340
+ contentIndex: currentBlockIndex,
341
+ delta: text,
342
+ partial: output
343
+ });
344
+ return type;
345
+ };
346
+ const startToolCallBlock = (source, args = {}) => {
347
+ endCurrentBlock();
348
+ currentBlockIndex = output.content.length;
349
+ const name = readStringField(source, "name") ?? "tool";
350
+ const toolCall = {
351
+ type: "toolCall",
352
+ id: readStringField(source, "id") ?? nextToolCallId(name),
353
+ name,
354
+ arguments: args
355
+ };
356
+ currentToolArgs = Object.keys(args).length > 0 ? JSON.stringify(args) : "";
357
+ output.content.push(toolCall);
358
+ stream.push({
359
+ type: "toolcall_start",
360
+ contentIndex: currentBlockIndex,
361
+ partial: output
362
+ });
363
+ return toolCall;
364
+ };
365
+ let streamDone = false;
366
+ let sawCompletion = false;
367
+ while (!streamDone) {
368
+ const { done, value } = await reader.read();
369
+ if (done) break;
370
+ buffer += decoder.decode(value, { stream: true });
371
+ const lines = buffer.split("\n");
372
+ buffer = lines.pop() ?? "";
373
+ for (const line of lines) {
374
+ const trimmed = line.trim();
375
+ if (!trimmed || !trimmed.startsWith("data:")) continue;
376
+ const dataStr = trimmed.slice(5).trim();
377
+ if (dataStr === "[DONE]") {
378
+ streamDone = true;
379
+ break;
380
+ }
381
+ let event;
382
+ try {
383
+ event = asRecord(parseJsonPreservingUnsafeIntegers(dataStr));
384
+ } catch {
385
+ continue;
386
+ }
387
+ const eventType = event.event_type || event.type;
388
+ logGoogleInteractionsDebug("stream event", { eventType: typeof eventType === "string" ? eventType : "unknown" });
389
+ if (eventType === "error") {
390
+ const providerError = asOptionalRecord(event.error);
391
+ const message = readStringField(providerError, "message") ?? "Google Interactions stream failed";
392
+ throw Object.assign(new Error(message), {
393
+ code: readStringField(providerError, "code"),
394
+ type: "google_interactions_stream_error"
395
+ });
396
+ } else if (eventType === "step.delta") {
397
+ const delta = asOptionalRecord(event.delta);
398
+ const deltaType = delta?.type;
399
+ if (deltaType === "text") {
400
+ const text = readStringField(delta, "text") ?? "";
401
+ if (text) {
402
+ if (currentBlockType !== "text") currentBlockType = startTextBlock("text");
403
+ const block = output.content[currentBlockIndex];
404
+ if (!block || block.type !== "text") throw new Error("Google Interactions text delta has no active text block");
405
+ block.text += text;
406
+ stream.push({
407
+ type: "text_delta",
408
+ contentIndex: currentBlockIndex,
409
+ delta: text,
410
+ partial: output
411
+ });
412
+ }
413
+ } else if (deltaType === "thought" || deltaType === "thought_summary" || deltaType === "raw_thought") {
414
+ let thinkingText = "";
415
+ if (typeof delta?.text === "string") thinkingText = delta.text;
416
+ else if (typeof delta?.content === "string") thinkingText = delta.content;
417
+ else if (Array.isArray(delta?.content)) thinkingText = delta.content.map((content) => readStringField(asOptionalRecord(content), "text") ?? "").join("");
418
+ else thinkingText = readStringField(asOptionalRecord(delta?.content), "text") ?? "";
419
+ if (thinkingText) {
420
+ if (currentBlockType !== "thinking") currentBlockType = startTextBlock("thinking");
421
+ const block = output.content[currentBlockIndex];
422
+ if (!block || block.type !== "thinking") throw new Error("Google Interactions thought delta has no active thought block");
423
+ block.thinking += thinkingText;
424
+ stream.push({
425
+ type: "thinking_delta",
426
+ contentIndex: currentBlockIndex,
427
+ delta: thinkingText,
428
+ partial: output
429
+ });
430
+ }
431
+ } else if (deltaType === "thought_signature" || delta && typeof delta.signature === "string" && !delta.text) {
432
+ const signature = readStringField(delta, "signature") ?? "";
433
+ if (signature) {
434
+ latestThoughtSignature = signature;
435
+ if (currentBlockType === "thinking") {
436
+ const block = output.content[currentBlockIndex];
437
+ if (block?.type === "thinking") block.thinkingSignature = signature;
438
+ } else {
439
+ const lastThinking = output.content.findLast((block) => block.type === "thinking");
440
+ if (lastThinking && !lastThinking.thinkingSignature) lastThinking.thinkingSignature = signature;
441
+ else if (!lastThinking) output.content.push({
442
+ type: "thinking",
443
+ thinking: "",
444
+ thinkingSignature: signature
445
+ });
446
+ }
447
+ }
448
+ } else if (deltaType === "arguments" || deltaType === "arguments_delta") {
449
+ const argText = readStringField(delta, "arguments") ?? readStringField(delta, "text") ?? "";
450
+ if (currentBlockType !== "toolCall") {
451
+ currentToolCall = startToolCallBlock(delta);
452
+ currentBlockType = "toolCall";
453
+ }
454
+ const streamedToolName = readStringField(delta, "name");
455
+ if (streamedToolName && currentToolCall && (!currentToolCall.name || currentToolCall.name === "tool")) currentToolCall.name = streamedToolName;
456
+ const streamedToolCallId = readStringField(delta, "id");
457
+ if (streamedToolCallId && currentToolCall) currentToolCall.id = streamedToolCallId;
458
+ currentToolArgs += argText;
459
+ stream.push({
460
+ type: "toolcall_delta",
461
+ contentIndex: currentBlockIndex,
462
+ delta: argText,
463
+ partial: output
464
+ });
465
+ }
466
+ } else if (eventType === "step.start") {
467
+ const step = asOptionalRecord(event.step);
468
+ if (step?.type === "thought") {
469
+ const stepSignature = readStringField(step, "signature");
470
+ if (stepSignature) latestThoughtSignature = stepSignature;
471
+ let initialThinking = "";
472
+ if (Array.isArray(step.summary)) initialThinking = step.summary.map((content) => readStringField(asOptionalRecord(content), "text") ?? "").join("");
473
+ if (currentBlockType !== "thinking") currentBlockType = startTextBlock("thinking", initialThinking);
474
+ } else if (step?.type === "model_output") currentBlockType = startTextBlock("text", Array.isArray(step.content) ? step.content.map((content) => readStringField(asOptionalRecord(content), "text") ?? "").join("") : "");
475
+ else if (step?.type === "function_call") {
476
+ currentToolCall = startToolCallBlock(step, asRecord(step.arguments));
477
+ currentBlockType = "toolCall";
478
+ }
479
+ } else if (eventType === "step.stop") {
480
+ latestUsage = asOptionalRecord(event.usage) ?? latestUsage;
481
+ endCurrentBlock();
482
+ } else if (eventType === "interaction.completed" || eventType === "interaction.complete") {
483
+ sawCompletion = true;
484
+ const interaction = asOptionalRecord(event.interaction) ?? event;
485
+ const usage = asOptionalRecord(interaction.usage) ?? latestUsage ?? {};
486
+ const promptTokens = Number(usage.total_input_tokens ?? 0);
487
+ const cacheRead = Number(usage.total_cached_tokens ?? 0);
488
+ const candidatesTokens = Number(usage.total_output_tokens ?? 0);
489
+ const thoughtTokens = Number(usage.total_thought_tokens ?? 0);
490
+ const toolUseTokens = Number(usage.total_tool_use_tokens ?? 0);
491
+ const outputTokens = candidatesTokens + thoughtTokens;
492
+ const totalTokens = Number(usage.total_tokens ?? promptTokens + outputTokens + toolUseTokens);
493
+ output.usage = {
494
+ input: Math.max(0, promptTokens - cacheRead) + toolUseTokens,
495
+ output: outputTokens,
496
+ cacheRead,
497
+ cacheWrite: 0,
498
+ cacheTelemetry: { state: "available" },
499
+ totalTokens,
500
+ cost: {
501
+ input: 0,
502
+ output: 0,
503
+ cacheRead: 0,
504
+ cacheWrite: 0,
505
+ total: 0
506
+ }
507
+ };
508
+ if (model.cost) calculateCost(model, output.usage);
509
+ const status = typeof interaction.status === "string" ? interaction.status : "completed";
510
+ if (status === "failed" || status === "cancelled" || status === "budget_exceeded") throw new Error(`Google Interactions API completed with status: ${status}`);
511
+ if (status === "incomplete") output.stopReason = "length";
512
+ else output.stopReason = output.content.some((b) => b.type === "toolCall") ? "toolUse" : "stop";
513
+ }
514
+ }
515
+ }
516
+ endCurrentBlock();
517
+ if (!sawCompletion) throw Object.assign(/* @__PURE__ */ new Error("Google Interactions stream ended before a terminal event"), {
518
+ code: "STREAM_INCOMPLETE",
519
+ type: "google_incomplete_stream"
520
+ });
521
+ if (latestThoughtSignature) {
522
+ for (const block of output.content) if (block.type === "thinking" && !block.thinkingSignature) block.thinkingSignature = latestThoughtSignature;
523
+ }
524
+ if (!output.stopReason) output.stopReason = output.content.some((b) => b.type === "toolCall") ? "toolUse" : "stop";
525
+ if (output.stopReason === "aborted" || output.stopReason === "error") throw new Error("An unknown error occurred");
526
+ stream.push({
527
+ type: "done",
528
+ reason: output.stopReason,
529
+ message: output
530
+ });
531
+ stream.end();
532
+ } catch (error) {
533
+ const failure = options?.signal?.aborted ? transportAbortError(options.signal) : error;
534
+ failTransportStream({
535
+ stream,
536
+ output,
537
+ signal: options?.signal,
538
+ error: failure
539
+ });
540
+ } finally {
541
+ if (reader) {
542
+ const cancellation = reader.cancel().catch(() => void 0);
543
+ reader.releaseLock();
544
+ getAiTransportHost().observePendingProviderWork?.(cancellation);
545
+ }
546
+ }
547
+ }
548
+ //#endregion
549
+ //#region packages/ai/src/providers/google-interactions.ts
550
+ let toolCallCounter = 0;
551
+ const streamGoogleInteractions = (model, context, options) => {
552
+ const stream = new AssistantMessageEventStream();
553
+ runGoogleInteractionsLifecycle({
554
+ stream,
555
+ model,
556
+ output: createAssistantOutput(model, "google-interactions"),
557
+ options,
558
+ context,
559
+ nextToolCallId: (name) => `${name}_${Date.now()}_${++toolCallCounter}`,
560
+ apiKey: resolveGoogleInteractionsApiKey(model, options)
561
+ });
562
+ return stream;
563
+ };
564
+ const streamSimpleGoogleInteractions = (model, context, options) => {
565
+ const apiKey = resolveGoogleInteractionsApiKey(model, options);
566
+ if (!apiKey) throw new Error(`No API key for provider: ${model.provider}`);
567
+ const base = buildBaseOptions(model, options, apiKey);
568
+ return streamGoogleInteractions(model, context, {
569
+ ...base,
570
+ thinking: buildGoogleInteractionsSimpleThinking(model, options)
571
+ });
572
+ };
573
+ //#endregion
574
+ export { streamGoogleInteractions, streamSimpleGoogleInteractions };