@langchain/google 0.2.11 → 0.2.13

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 (138) hide show
  1. package/CHANGELOG.md +29 -0
  2. package/dist/chat_models/{api-types.d.ts → api_types/generate_content.d.cts} +198 -200
  3. package/dist/chat_models/{api-types.d.cts → api_types/generate_content.d.ts} +198 -200
  4. package/dist/chat_models/api_types/interactions.d.cts +1423 -0
  5. package/dist/chat_models/api_types/interactions.d.ts +1423 -0
  6. package/dist/chat_models/base.cjs +60 -403
  7. package/dist/chat_models/base.cjs.map +1 -1
  8. package/dist/chat_models/base.d.cts +13 -200
  9. package/dist/chat_models/base.d.ts +15 -202
  10. package/dist/chat_models/base.js +61 -402
  11. package/dist/chat_models/base.js.map +1 -1
  12. package/dist/chat_models/handlers/base.cjs +62 -0
  13. package/dist/chat_models/handlers/base.cjs.map +1 -0
  14. package/dist/chat_models/handlers/base.d.cts +46 -0
  15. package/dist/chat_models/handlers/base.d.ts +46 -0
  16. package/dist/chat_models/handlers/base.js +62 -0
  17. package/dist/chat_models/handlers/base.js.map +1 -0
  18. package/dist/chat_models/handlers/generate_content.cjs +344 -0
  19. package/dist/chat_models/handlers/generate_content.cjs.map +1 -0
  20. package/dist/chat_models/handlers/generate_content.d.cts +32 -0
  21. package/dist/chat_models/handlers/generate_content.d.ts +32 -0
  22. package/dist/chat_models/handlers/generate_content.js +344 -0
  23. package/dist/chat_models/handlers/generate_content.js.map +1 -0
  24. package/dist/chat_models/handlers/index.cjs +6 -0
  25. package/dist/chat_models/handlers/index.d.cts +4 -0
  26. package/dist/chat_models/handlers/index.d.ts +4 -0
  27. package/dist/chat_models/handlers/index.js +4 -0
  28. package/dist/chat_models/handlers/interactions.cjs +303 -0
  29. package/dist/chat_models/handlers/interactions.cjs.map +1 -0
  30. package/dist/chat_models/handlers/interactions.d.cts +33 -0
  31. package/dist/chat_models/handlers/interactions.d.ts +33 -0
  32. package/dist/chat_models/handlers/interactions.js +303 -0
  33. package/dist/chat_models/handlers/interactions.js.map +1 -0
  34. package/dist/chat_models/index.cjs +14 -6
  35. package/dist/chat_models/index.cjs.map +1 -1
  36. package/dist/chat_models/index.d.cts +7 -3
  37. package/dist/chat_models/index.d.ts +7 -3
  38. package/dist/chat_models/index.js +8 -4
  39. package/dist/chat_models/index.js.map +1 -1
  40. package/dist/chat_models/node.cjs +4 -5
  41. package/dist/chat_models/node.cjs.map +1 -1
  42. package/dist/chat_models/node.d.cts +1 -3
  43. package/dist/chat_models/node.d.ts +1 -3
  44. package/dist/chat_models/node.js +3 -4
  45. package/dist/chat_models/node.js.map +1 -1
  46. package/dist/chat_models/profiles.cjs +1 -2
  47. package/dist/chat_models/profiles.js +1 -2
  48. package/dist/chat_models/types.cjs +1 -2
  49. package/dist/chat_models/types.cjs.map +1 -1
  50. package/dist/chat_models/types.d.cts +776 -88
  51. package/dist/chat_models/types.d.ts +776 -88
  52. package/dist/chat_models/types.js +1 -2
  53. package/dist/chat_models/types.js.map +1 -1
  54. package/dist/clients/index.cjs +3 -4
  55. package/dist/clients/index.d.cts +0 -2
  56. package/dist/clients/index.d.ts +0 -2
  57. package/dist/clients/index.js +3 -4
  58. package/dist/clients/node.cjs +4 -5
  59. package/dist/clients/node.d.cts +0 -2
  60. package/dist/clients/node.d.ts +0 -2
  61. package/dist/clients/node.js +4 -5
  62. package/dist/const.cjs +1 -2
  63. package/dist/const.js +1 -2
  64. package/dist/converters/{messages.cjs → generate_content/messages.cjs} +4 -5
  65. package/dist/converters/generate_content/messages.cjs.map +1 -0
  66. package/dist/converters/{messages.js → generate_content/messages.js} +4 -5
  67. package/dist/converters/generate_content/messages.js.map +1 -0
  68. package/dist/converters/generate_content/params.cjs +135 -0
  69. package/dist/converters/generate_content/params.cjs.map +1 -0
  70. package/dist/converters/generate_content/params.js +131 -0
  71. package/dist/converters/generate_content/params.js.map +1 -0
  72. package/dist/{utils → converters/generate_content}/stream_events.cjs +2 -3
  73. package/dist/converters/generate_content/stream_events.cjs.map +1 -0
  74. package/dist/{utils → converters/generate_content}/stream_events.js +2 -3
  75. package/dist/converters/generate_content/stream_events.js.map +1 -0
  76. package/dist/converters/{tools.cjs → generate_content/tools.cjs} +4 -5
  77. package/dist/converters/generate_content/tools.cjs.map +1 -0
  78. package/dist/converters/{tools.js → generate_content/tools.js} +4 -5
  79. package/dist/converters/generate_content/tools.js.map +1 -0
  80. package/dist/converters/interactions/messages.cjs +766 -0
  81. package/dist/converters/interactions/messages.cjs.map +1 -0
  82. package/dist/converters/interactions/messages.js +759 -0
  83. package/dist/converters/interactions/messages.js.map +1 -0
  84. package/dist/converters/interactions/params.cjs +244 -0
  85. package/dist/converters/interactions/params.cjs.map +1 -0
  86. package/dist/converters/interactions/params.js +237 -0
  87. package/dist/converters/interactions/params.js.map +1 -0
  88. package/dist/converters/interactions/stream_events.cjs +769 -0
  89. package/dist/converters/interactions/stream_events.cjs.map +1 -0
  90. package/dist/converters/interactions/stream_events.js +768 -0
  91. package/dist/converters/interactions/stream_events.js.map +1 -0
  92. package/dist/converters/interactions/tools.cjs +229 -0
  93. package/dist/converters/interactions/tools.cjs.map +1 -0
  94. package/dist/converters/interactions/tools.js +228 -0
  95. package/dist/converters/interactions/tools.js.map +1 -0
  96. package/dist/converters/{params.cjs → shared/params.cjs} +8 -94
  97. package/dist/converters/shared/params.cjs.map +1 -0
  98. package/dist/converters/{params.js → shared/params.js} +8 -92
  99. package/dist/converters/shared/params.js.map +1 -0
  100. package/dist/index.cjs +8 -0
  101. package/dist/index.d.cts +6 -1
  102. package/dist/index.d.ts +6 -1
  103. package/dist/index.js +5 -1
  104. package/dist/node.cjs +1 -1
  105. package/dist/node.d.cts +1 -1
  106. package/dist/node.d.ts +1 -1
  107. package/dist/node.js +1 -1
  108. package/dist/utils/errors.cjs +1 -2
  109. package/dist/utils/errors.js +1 -2
  110. package/dist/utils/gcp-auth.cjs +3 -4
  111. package/dist/utils/gcp-auth.d.cts +0 -2
  112. package/dist/utils/gcp-auth.d.ts +0 -2
  113. package/dist/utils/gcp-auth.js +3 -4
  114. package/dist/utils/handler.cjs +1 -2
  115. package/dist/utils/handler.d.cts +0 -2
  116. package/dist/utils/handler.d.ts +0 -2
  117. package/dist/utils/handler.js +1 -2
  118. package/dist/utils/metadata.cjs +9 -2
  119. package/dist/utils/metadata.cjs.map +1 -1
  120. package/dist/utils/metadata.js +9 -3
  121. package/dist/utils/metadata.js.map +1 -1
  122. package/dist/utils/misc.cjs +1 -2
  123. package/dist/utils/misc.cjs.map +1 -1
  124. package/dist/utils/misc.d.cts +2 -3
  125. package/dist/utils/misc.d.ts +2 -3
  126. package/dist/utils/misc.js +1 -2
  127. package/dist/utils/misc.js.map +1 -1
  128. package/dist/utils/stream.cjs +1 -2
  129. package/dist/utils/stream.js +1 -2
  130. package/package.json +12 -10
  131. package/dist/converters/messages.cjs.map +0 -1
  132. package/dist/converters/messages.js.map +0 -1
  133. package/dist/converters/params.cjs.map +0 -1
  134. package/dist/converters/params.js.map +0 -1
  135. package/dist/converters/tools.cjs.map +0 -1
  136. package/dist/converters/tools.js.map +0 -1
  137. package/dist/utils/stream_events.cjs.map +0 -1
  138. package/dist/utils/stream_events.js.map +0 -1
@@ -0,0 +1,768 @@
1
+ import { GoogleError } from "../../utils/errors.js";
2
+ import { convertGeminiPartToContentBlock, convertGeminiPartsToToolCalls } from "../generate_content/messages.js";
3
+ import { convertInteractionsContentToGeminiPart, convertInteractionsUsageToUsageMetadata, normalizeInteractionStep, synthesizeMetadataFromInteractions } from "./messages.js";
4
+ import { AIMessageChunk } from "@langchain/core/messages";
5
+ import { ChatGenerationChunk } from "@langchain/core/outputs";
6
+ import { v4 } from "@langchain/core/utils/uuid";
7
+ import { finalizeContentBlock } from "@langchain/core/language_models/compat";
8
+ // src/converters/interactions/stream_events.ts
9
+ /**
10
+ * Converts a stream of Interactions API SSE events (`InteractionSseEvent`) into
11
+ * LangChain `ChatGenerationChunk` instances for `streamResponseChunks`.
12
+ *
13
+ * ### ThoughtStep & `thoughtSignature` Streaming Design
14
+ *
15
+ * During SSE streaming, a `ThoughtStep` arrives as a sequence of `step.delta` events:
16
+ * - `{ type: "thought_summary", content: { type: "text", text: "..." } }`
17
+ * - `{ type: "thought_signature", signature: "..." }`
18
+ *
19
+ * Matching `convertInteractionToAIMessage`:
20
+ * 1. If a `ThoughtStep` emits one or more `thought_summary` deltas, we emit `AIMessageChunk`s
21
+ * containing `{ type: "text", thought: true, text }` and attach `thoughtSignature` when
22
+ * `thought_signature` arrives for that step. When concatenated via `concat()`, this forms
23
+ * a reasoning block with its `thoughtSignature`.
24
+ * 2. If a `ThoughtStep` only emits `thought_signature` (no `thought_summary`), we do NOT emit
25
+ * a `{ thought: true }` block (which would prevent single-text responses from collapsing to
26
+ * a string on `concat()`). Instead, we store `pendingThoughtSignature` and attach it to the
27
+ * subsequent `function_call` or `model_output` chunk (or as a metadata-only
28
+ * `{ type: "text", text: "", thoughtSignature }` chunk at the end of the stream).
29
+ */
30
+ async function* convertInteractionsStreamToChunks(source, options = {}) {
31
+ const shouldStreamUsage = options.streamUsage ?? true;
32
+ const runManager = options.runManager;
33
+ const stepStates = /* @__PURE__ */ new Map();
34
+ const textSegments = [];
35
+ const builtInToolSteps = [];
36
+ let interactionId;
37
+ let interactionStatus;
38
+ let interactionRole;
39
+ let previousInteractionId;
40
+ let modelName = options.model;
41
+ let latestUsage;
42
+ let pendingThoughtSignature;
43
+ let pendingFunctionCallSignature;
44
+ let hasEmittedStepDelta = false;
45
+ let nextToolIndex = 0;
46
+ const getOrCreateStepState = (index) => {
47
+ let state = stepStates.get(index);
48
+ if (!state) {
49
+ state = {};
50
+ stepStates.set(index, state);
51
+ }
52
+ return state;
53
+ };
54
+ const emitFunctionCallChunk = (fcState) => {
55
+ let parsedArgs = fcState.argsObject ?? {};
56
+ if (!fcState.argsObject && fcState.argsText.trim().length > 0) try {
57
+ const parsed = JSON.parse(fcState.argsText);
58
+ if (typeof parsed === "object" && parsed !== null) parsedArgs = parsed;
59
+ } catch {
60
+ parsedArgs = {};
61
+ }
62
+ const argsString = fcState.argsText.length > 0 ? fcState.argsText : JSON.stringify(parsedArgs);
63
+ const toolCall = {
64
+ type: "tool_call",
65
+ id: fcState.id,
66
+ name: fcState.name,
67
+ args: parsedArgs,
68
+ ...fcState.thoughtSignature ? { thoughtSignature: fcState.thoughtSignature } : {}
69
+ };
70
+ const toolCallChunk = {
71
+ type: "tool_call_chunk",
72
+ id: fcState.id,
73
+ name: fcState.name,
74
+ args: argsString,
75
+ index: fcState.toolIndex
76
+ };
77
+ const part = {
78
+ functionCall: {
79
+ id: fcState.id,
80
+ name: fcState.name,
81
+ args: parsedArgs
82
+ },
83
+ ...fcState.thoughtSignature ? { thoughtSignature: fcState.thoughtSignature } : {}
84
+ };
85
+ const block = convertGeminiPartToContentBlock(part);
86
+ fcState.emittedToolCall = true;
87
+ return new ChatGenerationChunk({
88
+ text: "",
89
+ message: new AIMessageChunk({
90
+ content: block ? [block] : "",
91
+ tool_calls: [toolCall],
92
+ tool_call_chunks: [toolCallChunk],
93
+ response_metadata: {
94
+ model_provider: "google",
95
+ ...modelName ? { model_name: modelName } : {}
96
+ }
97
+ })
98
+ });
99
+ };
100
+ for await (const event of source) switch (event.event_type) {
101
+ case "interaction.created":
102
+ case "interaction.start":
103
+ if (event.interaction) {
104
+ interactionId = event.interaction.id ?? interactionId;
105
+ interactionStatus = event.interaction.status ?? interactionStatus;
106
+ interactionRole = event.interaction.role ?? interactionRole;
107
+ previousInteractionId = event.interaction.previous_interaction_id ?? previousInteractionId;
108
+ modelName = event.interaction.model ?? modelName;
109
+ if (event.interaction.usage) latestUsage = event.interaction.usage;
110
+ }
111
+ break;
112
+ case "step.start":
113
+ case "content.start": {
114
+ const state = getOrCreateStepState(event.index);
115
+ const rawStep = event.step ?? event.content;
116
+ if (rawStep) {
117
+ const step = normalizeInteractionStep(rawStep);
118
+ state.stepType = step.type;
119
+ if (step.type === "function_call") {
120
+ const sig = pendingThoughtSignature ?? pendingFunctionCallSignature;
121
+ pendingThoughtSignature = void 0;
122
+ pendingFunctionCallSignature = void 0;
123
+ const hasInitialArgs = step.arguments && Object.keys(step.arguments).length > 0;
124
+ state.functionCall = {
125
+ id: step.id || `lc-tool-call-${v4().replace(/-/g, "")}`,
126
+ name: step.name || "",
127
+ argsText: hasInitialArgs ? JSON.stringify(step.arguments) : "",
128
+ argsObject: hasInitialArgs ? step.arguments : void 0,
129
+ thoughtSignature: sig,
130
+ toolIndex: nextToolIndex++,
131
+ emittedToolCall: false
132
+ };
133
+ } else if (step.type === "thought" && step.signature) {
134
+ state.thoughtSignature = step.signature;
135
+ pendingFunctionCallSignature = step.signature;
136
+ }
137
+ }
138
+ break;
139
+ }
140
+ case "step.delta":
141
+ case "content.delta": {
142
+ const state = getOrCreateStepState(event.index);
143
+ if (event.metadata?.total_usage) latestUsage = event.metadata.total_usage;
144
+ const delta = event.delta;
145
+ if (!delta) break;
146
+ switch (delta.type) {
147
+ case "text": {
148
+ hasEmittedStepDelta = true;
149
+ if (state.textIndex === void 0) {
150
+ state.textIndex = textSegments.length;
151
+ textSegments.push({
152
+ text: "",
153
+ annotations: []
154
+ });
155
+ }
156
+ const seg = textSegments[state.textIndex];
157
+ seg.text += delta.text;
158
+ const sig = pendingThoughtSignature;
159
+ pendingThoughtSignature = void 0;
160
+ pendingFunctionCallSignature = void 0;
161
+ const part = {
162
+ text: delta.text,
163
+ ...sig ? { thoughtSignature: sig } : {}
164
+ };
165
+ const textBlock = convertGeminiPartToContentBlock(part);
166
+ yield new ChatGenerationChunk({
167
+ text: delta.text,
168
+ message: new AIMessageChunk({
169
+ content: delta.text,
170
+ additional_kwargs: { originalTextContentBlock: textBlock },
171
+ response_metadata: {
172
+ model_provider: "google",
173
+ ...modelName ? { model_name: modelName } : {}
174
+ }
175
+ })
176
+ });
177
+ await runManager?.handleLLMNewToken(delta.text);
178
+ break;
179
+ }
180
+ case "text_annotation_delta":
181
+ case "text_annotation": {
182
+ if (state.textIndex === void 0) {
183
+ state.textIndex = textSegments.length;
184
+ textSegments.push({
185
+ text: "",
186
+ annotations: []
187
+ });
188
+ }
189
+ const seg = textSegments[state.textIndex];
190
+ seg.annotations = [...seg.annotations ?? [], ...delta.annotations ?? []];
191
+ break;
192
+ }
193
+ case "thought_summary": {
194
+ hasEmittedStepDelta = true;
195
+ state.hasThoughtSummary = true;
196
+ const summaryText = delta.content?.type === "text" ? delta.content.text : "";
197
+ if (summaryText) {
198
+ const part = {
199
+ text: summaryText,
200
+ thought: true,
201
+ ...state.thoughtSignature ? { thoughtSignature: state.thoughtSignature } : {}
202
+ };
203
+ const block = convertGeminiPartToContentBlock(part);
204
+ state.thoughtSignature = void 0;
205
+ yield new ChatGenerationChunk({
206
+ text: "",
207
+ message: new AIMessageChunk({
208
+ content: [block],
209
+ response_metadata: {
210
+ model_provider: "google",
211
+ ...modelName ? { model_name: modelName } : {}
212
+ }
213
+ })
214
+ });
215
+ await runManager?.handleLLMNewToken(summaryText);
216
+ }
217
+ break;
218
+ }
219
+ case "thought_signature":
220
+ if (delta.signature) {
221
+ pendingFunctionCallSignature = delta.signature;
222
+ if (state.hasThoughtSummary) {
223
+ hasEmittedStepDelta = true;
224
+ const part = {
225
+ text: "",
226
+ thought: true,
227
+ thoughtSignature: delta.signature
228
+ };
229
+ const block = convertGeminiPartToContentBlock(part);
230
+ yield new ChatGenerationChunk({
231
+ text: "",
232
+ message: new AIMessageChunk({
233
+ content: [block],
234
+ response_metadata: {
235
+ model_provider: "google",
236
+ ...modelName ? { model_name: modelName } : {}
237
+ }
238
+ })
239
+ });
240
+ } else {
241
+ pendingThoughtSignature = delta.signature;
242
+ state.thoughtSignature = delta.signature;
243
+ }
244
+ }
245
+ break;
246
+ case "arguments_delta":
247
+ case "function_call": {
248
+ hasEmittedStepDelta = true;
249
+ const fcSig = pendingThoughtSignature ?? pendingFunctionCallSignature;
250
+ if (!state.functionCall) {
251
+ pendingThoughtSignature = void 0;
252
+ pendingFunctionCallSignature = void 0;
253
+ state.functionCall = {
254
+ id: delta.id || `lc-tool-call-${v4().replace(/-/g, "")}`,
255
+ name: delta.name || "",
256
+ argsText: "",
257
+ thoughtSignature: fcSig,
258
+ toolIndex: nextToolIndex++,
259
+ emittedToolCall: false
260
+ };
261
+ } else {
262
+ if (delta.id) state.functionCall.id = delta.id;
263
+ if (delta.name) state.functionCall.name = delta.name;
264
+ if (fcSig && !state.functionCall.thoughtSignature) {
265
+ state.functionCall.thoughtSignature = fcSig;
266
+ pendingThoughtSignature = void 0;
267
+ pendingFunctionCallSignature = void 0;
268
+ }
269
+ }
270
+ if (typeof delta.arguments === "string") state.functionCall.argsText += delta.arguments;
271
+ else if (typeof delta.arguments === "object" && delta.arguments !== null) {
272
+ state.functionCall.argsObject = delta.arguments;
273
+ state.functionCall.argsText = JSON.stringify(delta.arguments);
274
+ yield emitFunctionCallChunk(state.functionCall);
275
+ await runManager?.handleLLMNewToken("");
276
+ }
277
+ break;
278
+ }
279
+ case "image":
280
+ case "audio":
281
+ case "document":
282
+ case "video": {
283
+ hasEmittedStepDelta = true;
284
+ const sig = pendingThoughtSignature;
285
+ pendingThoughtSignature = void 0;
286
+ pendingFunctionCallSignature = void 0;
287
+ const part = convertInteractionsContentToGeminiPart(delta, sig);
288
+ if (part) {
289
+ const block = convertGeminiPartToContentBlock(part);
290
+ if (block) {
291
+ yield new ChatGenerationChunk({
292
+ text: "",
293
+ message: new AIMessageChunk({
294
+ content: [block],
295
+ response_metadata: {
296
+ model_provider: "google",
297
+ ...modelName ? { model_name: modelName } : {}
298
+ }
299
+ })
300
+ });
301
+ await runManager?.handleLLMNewToken("");
302
+ }
303
+ }
304
+ break;
305
+ }
306
+ case "code_execution_call": {
307
+ hasEmittedStepDelta = true;
308
+ const sig = delta.signature ?? pendingThoughtSignature;
309
+ pendingThoughtSignature = void 0;
310
+ const part = {
311
+ executableCode: {
312
+ code: delta.arguments?.code ?? "",
313
+ language: "PYTHON"
314
+ },
315
+ ...sig ? { thoughtSignature: sig } : {}
316
+ };
317
+ const block = convertGeminiPartToContentBlock(part);
318
+ if (block) {
319
+ yield new ChatGenerationChunk({
320
+ text: "",
321
+ message: new AIMessageChunk({
322
+ content: [block],
323
+ response_metadata: {
324
+ model_provider: "google",
325
+ ...modelName ? { model_name: modelName } : {}
326
+ }
327
+ })
328
+ });
329
+ await runManager?.handleLLMNewToken("");
330
+ }
331
+ break;
332
+ }
333
+ case "code_execution_result": {
334
+ hasEmittedStepDelta = true;
335
+ const sig = delta.signature ?? pendingThoughtSignature;
336
+ pendingThoughtSignature = void 0;
337
+ const part = {
338
+ codeExecutionResult: {
339
+ output: delta.result ?? "",
340
+ outcome: delta.is_error ? "OUTCOME_FAILED" : "OUTCOME_OK"
341
+ },
342
+ ...sig ? { thoughtSignature: sig } : {}
343
+ };
344
+ const block = convertGeminiPartToContentBlock(part);
345
+ if (block) {
346
+ yield new ChatGenerationChunk({
347
+ text: "",
348
+ message: new AIMessageChunk({
349
+ content: [block],
350
+ response_metadata: {
351
+ model_provider: "google",
352
+ ...modelName ? { model_name: modelName } : {}
353
+ }
354
+ })
355
+ });
356
+ await runManager?.handleLLMNewToken("");
357
+ }
358
+ break;
359
+ }
360
+ case "google_search_call":
361
+ case "google_search_result":
362
+ case "google_maps_call":
363
+ case "google_maps_result":
364
+ case "file_search_call":
365
+ case "file_search_result":
366
+ case "url_context_call":
367
+ case "url_context_result":
368
+ case "mcp_server_tool_call":
369
+ case "mcp_server_tool_result":
370
+ case "processing_call":
371
+ case "processing_result":
372
+ case "retrieval_call":
373
+ case "retrieval_result": builtInToolSteps.push(delta);
374
+ }
375
+ break;
376
+ }
377
+ case "step.stop":
378
+ case "content.stop": {
379
+ const state = stepStates.get(event.index);
380
+ if (event.usage) latestUsage = event.usage;
381
+ else if (event.step_usage && !latestUsage) latestUsage = event.step_usage;
382
+ if (state?.functionCall && !state.functionCall.emittedToolCall) {
383
+ hasEmittedStepDelta = true;
384
+ yield emitFunctionCallChunk(state.functionCall);
385
+ await runManager?.handleLLMNewToken("");
386
+ }
387
+ break;
388
+ }
389
+ case "interaction.status_update":
390
+ interactionId = event.interaction_id ?? interactionId;
391
+ interactionStatus = event.status ?? interactionStatus;
392
+ if (event.usage) latestUsage = event.usage;
393
+ break;
394
+ case "interaction.completed":
395
+ case "interaction.complete":
396
+ if (event.interaction) {
397
+ interactionId = event.interaction.id ?? interactionId;
398
+ interactionStatus = event.interaction.status ?? interactionStatus;
399
+ interactionRole = event.interaction.role ?? interactionRole;
400
+ previousInteractionId = event.interaction.previous_interaction_id ?? previousInteractionId;
401
+ modelName = event.interaction.model ?? modelName;
402
+ if (event.interaction.usage) latestUsage = event.interaction.usage;
403
+ const completedItems = event.interaction.steps ?? event.interaction.outputs ?? [];
404
+ if (!hasEmittedStepDelta && completedItems.length > 0) {
405
+ const steps = completedItems.map(normalizeInteractionStep);
406
+ const parts = [];
407
+ for (const step of steps) if (step.type === "thought") {
408
+ const summaries = (step.summary ?? []).filter((c) => c.type === "text" && typeof c.text === "string" && c.text.length > 0);
409
+ if (summaries.length > 0) {
410
+ for (let i = 0; i < summaries.length; i++) parts.push({
411
+ text: summaries[i].text,
412
+ thought: true,
413
+ ...i === summaries.length - 1 && step.signature ? { thoughtSignature: step.signature } : {}
414
+ });
415
+ pendingThoughtSignature = void 0;
416
+ pendingFunctionCallSignature = step.signature;
417
+ } else if (step.signature) {
418
+ pendingThoughtSignature = step.signature;
419
+ pendingFunctionCallSignature = step.signature;
420
+ }
421
+ } else if (step.type === "model_output") {
422
+ const contents = typeof step.content === "string" ? [{
423
+ type: "text",
424
+ text: step.content
425
+ }] : step.content ?? [];
426
+ for (const c of contents) {
427
+ if (c.type === "text") textSegments.push({
428
+ text: c.text,
429
+ annotations: c.annotations
430
+ });
431
+ const p = convertInteractionsContentToGeminiPart(c, pendingThoughtSignature);
432
+ if (p) {
433
+ parts.push(p);
434
+ pendingThoughtSignature = void 0;
435
+ pendingFunctionCallSignature = void 0;
436
+ }
437
+ }
438
+ } else if (step.type === "function_call") {
439
+ const fcSig = pendingThoughtSignature ?? pendingFunctionCallSignature;
440
+ parts.push({
441
+ functionCall: {
442
+ id: step.id,
443
+ name: step.name,
444
+ args: step.arguments ?? {}
445
+ },
446
+ ...fcSig ? { thoughtSignature: fcSig } : {}
447
+ });
448
+ pendingThoughtSignature = void 0;
449
+ pendingFunctionCallSignature = void 0;
450
+ } else if (step.type === "google_search_call" || step.type === "google_search_result" || step.type === "google_maps_call" || step.type === "google_maps_result" || step.type === "file_search_call" || step.type === "file_search_result" || step.type === "url_context_call" || step.type === "url_context_result") builtInToolSteps.push(step);
451
+ if (parts.length > 0) {
452
+ const blockContent = parts.map((p) => convertGeminiPartToContentBlock(p)).filter((b) => b !== null);
453
+ const toolCalls = convertGeminiPartsToToolCalls(parts);
454
+ const toolCallChunks = toolCalls.map((tc, idx) => ({
455
+ type: "tool_call_chunk",
456
+ id: tc.id,
457
+ name: tc.name,
458
+ args: JSON.stringify(tc.args ?? {}),
459
+ index: idx
460
+ }));
461
+ const singleText = blockContent.length === 1 && blockContent[0].type === "text" && !blockContent[0].thought ? blockContent[0].text : void 0;
462
+ hasEmittedStepDelta = true;
463
+ yield new ChatGenerationChunk({
464
+ text: singleText ?? "",
465
+ message: new AIMessageChunk({
466
+ content: singleText ?? blockContent,
467
+ tool_calls: toolCalls,
468
+ tool_call_chunks: toolCallChunks,
469
+ additional_kwargs: singleText ? { originalTextContentBlock: blockContent[0] } : {},
470
+ response_metadata: {
471
+ model_provider: "google",
472
+ ...modelName ? { model_name: modelName } : {}
473
+ }
474
+ })
475
+ });
476
+ await runManager?.handleLLMNewToken(singleText ?? "");
477
+ }
478
+ }
479
+ }
480
+ break;
481
+ case "error": throw new GoogleError(`Google Interactions API stream error (${event.error?.code ?? "unknown"}): ${event.error?.message ?? "Unknown error"}`);
482
+ }
483
+ for (const state of stepStates.values()) if (state.functionCall && !state.functionCall.emittedToolCall) {
484
+ hasEmittedStepDelta = true;
485
+ yield emitFunctionCallChunk(state.functionCall);
486
+ await runManager?.handleLLMNewToken("");
487
+ }
488
+ const usageMetadata = shouldStreamUsage ? convertInteractionsUsageToUsageMetadata(latestUsage) : void 0;
489
+ const synthesized = synthesizeMetadataFromInteractions({
490
+ textSegments,
491
+ builtInToolSteps
492
+ });
493
+ let finishReason;
494
+ if (interactionStatus === "completed" || interactionStatus === "requires_action") finishReason = "STOP";
495
+ else if (interactionStatus) finishReason = interactionStatus.toUpperCase();
496
+ const trailingSigBlock = pendingThoughtSignature ? {
497
+ type: "text",
498
+ text: "",
499
+ thoughtSignature: pendingThoughtSignature
500
+ } : void 0;
501
+ if (usageMetadata || finishReason || trailingSigBlock || Object.keys(synthesized).length > 0 || interactionId || !hasEmittedStepDelta) yield new ChatGenerationChunk({
502
+ text: "",
503
+ generationInfo: { ...finishReason ? { finishReason } : {} },
504
+ message: new AIMessageChunk({
505
+ content: "",
506
+ ...usageMetadata ? { usage_metadata: usageMetadata } : {},
507
+ additional_kwargs: {
508
+ ...finishReason ? { finishReason } : {},
509
+ ...trailingSigBlock ? { originalTextContentBlock: trailingSigBlock } : {}
510
+ },
511
+ response_metadata: {
512
+ model_provider: "google",
513
+ ...modelName ? { model_name: modelName } : {},
514
+ ...finishReason ? { finishReason } : {},
515
+ ...synthesized,
516
+ ...builtInToolSteps.length > 0 ? { interactionSteps: builtInToolSteps } : {},
517
+ ...interactionId || interactionStatus ? { interaction: {
518
+ ...interactionId ? { id: interactionId } : {},
519
+ ...interactionStatus ? { status: interactionStatus } : {},
520
+ ...interactionRole ? { role: interactionRole } : {},
521
+ ...previousInteractionId ? { previous_interaction_id: previousInteractionId } : {}
522
+ } } : {}
523
+ }
524
+ })
525
+ });
526
+ }
527
+ /**
528
+ * Converts a stream of Interactions API SSE events (`InteractionSseEvent`) into
529
+ * LangChain `ChatModelStreamEvent`s for `streamChatModelEvents`.
530
+ */
531
+ async function* convertInteractionsStream(source, options = {}) {
532
+ const shouldStreamUsage = options.streamUsage ?? true;
533
+ const blockAccumulators = /* @__PURE__ */ new Map();
534
+ const blockKeyToIndex = /* @__PURE__ */ new Map();
535
+ let nextBlockIndex = 0;
536
+ let messageStarted = false;
537
+ let usageSnapshot;
538
+ const finishReason = "stop";
539
+ let pendingThoughtSignature;
540
+ let pendingFunctionCallSignature;
541
+ let nextToolIdx = 0;
542
+ const stepStates = /* @__PURE__ */ new Map();
543
+ const textSegments = [];
544
+ const builtInToolSteps = [];
545
+ const getOrCreateBlockIndex = (key, initial) => {
546
+ const existing = blockKeyToIndex.get(key);
547
+ if (existing !== void 0) return {
548
+ index: existing,
549
+ isNew: false
550
+ };
551
+ const index = nextBlockIndex++;
552
+ blockKeyToIndex.set(key, index);
553
+ blockAccumulators.set(index, { ...initial });
554
+ return {
555
+ index,
556
+ isNew: true
557
+ };
558
+ };
559
+ const ensureMessageStarted = () => {
560
+ if (!messageStarted) {
561
+ messageStarted = true;
562
+ return { event: "message-start" };
563
+ }
564
+ };
565
+ for await (const event of source) {
566
+ const startEv = ensureMessageStarted();
567
+ if (startEv) yield startEv;
568
+ if (event.event_type === "step.start" || event.event_type === "content.start") {
569
+ const rawStep = event.step ?? event.content;
570
+ if (rawStep) {
571
+ const step = normalizeInteractionStep(rawStep);
572
+ if (step.type === "function_call") stepStates.set(event.index, {
573
+ toolIdx: nextToolIdx++,
574
+ toolId: step.id,
575
+ toolName: step.name
576
+ });
577
+ else stepStates.set(event.index, {});
578
+ }
579
+ continue;
580
+ }
581
+ if (event.event_type === "step.delta" || event.event_type === "content.delta") {
582
+ if (shouldStreamUsage && event.metadata?.total_usage) {
583
+ usageSnapshot = convertInteractionsUsageToUsageMetadata(event.metadata.total_usage);
584
+ if (usageSnapshot) yield {
585
+ event: "usage",
586
+ usage: usageSnapshot
587
+ };
588
+ }
589
+ const delta = event.delta;
590
+ if (!delta) continue;
591
+ let state = stepStates.get(event.index);
592
+ if (!state) {
593
+ state = {};
594
+ stepStates.set(event.index, state);
595
+ }
596
+ if (delta.type === "text") {
597
+ if (state.textIndex === void 0) {
598
+ state.textIndex = textSegments.length;
599
+ textSegments.push({
600
+ text: "",
601
+ annotations: []
602
+ });
603
+ }
604
+ textSegments[state.textIndex].text += delta.text;
605
+ const { index, isNew } = getOrCreateBlockIndex("text", {
606
+ type: "text",
607
+ text: ""
608
+ });
609
+ if (isNew) yield {
610
+ event: "content-block-start",
611
+ index,
612
+ content: {
613
+ type: "text",
614
+ text: ""
615
+ }
616
+ };
617
+ const acc = blockAccumulators.get(index);
618
+ acc.text = (acc.text ?? "") + delta.text;
619
+ if (pendingThoughtSignature) {
620
+ acc.thoughtSignature = pendingThoughtSignature;
621
+ pendingThoughtSignature = void 0;
622
+ }
623
+ pendingFunctionCallSignature = void 0;
624
+ yield {
625
+ event: "content-block-delta",
626
+ index,
627
+ delta: {
628
+ type: "text-delta",
629
+ text: delta.text
630
+ }
631
+ };
632
+ } else if (delta.type === "text_annotation_delta" || delta.type === "text_annotation") {
633
+ if (state.textIndex === void 0) {
634
+ state.textIndex = textSegments.length;
635
+ textSegments.push({
636
+ text: "",
637
+ annotations: []
638
+ });
639
+ }
640
+ const seg = textSegments[state.textIndex];
641
+ seg.annotations = [...seg.annotations ?? [], ...delta.annotations ?? []];
642
+ } else if (delta.type === "thought_summary") {
643
+ state.hasThoughtSummary = true;
644
+ const summaryText = delta.content?.type === "text" ? delta.content.text : "";
645
+ if (summaryText) {
646
+ const { index, isNew } = getOrCreateBlockIndex("reasoning", {
647
+ type: "reasoning",
648
+ reasoning: ""
649
+ });
650
+ if (isNew) yield {
651
+ event: "content-block-start",
652
+ index,
653
+ content: {
654
+ type: "reasoning",
655
+ reasoning: ""
656
+ }
657
+ };
658
+ const acc = blockAccumulators.get(index);
659
+ acc.reasoning = (acc.reasoning ?? "") + summaryText;
660
+ yield {
661
+ event: "content-block-delta",
662
+ index,
663
+ delta: {
664
+ type: "reasoning-delta",
665
+ reasoning: summaryText
666
+ }
667
+ };
668
+ }
669
+ } else if (delta.type === "thought_signature") {
670
+ if (delta.signature) {
671
+ pendingFunctionCallSignature = delta.signature;
672
+ if (state.hasThoughtSummary) {
673
+ const existingIdx = blockKeyToIndex.get("reasoning");
674
+ if (existingIdx !== void 0) {
675
+ const acc = blockAccumulators.get(existingIdx);
676
+ acc.thoughtSignature = delta.signature;
677
+ }
678
+ } else pendingThoughtSignature = delta.signature;
679
+ }
680
+ } else if (delta.type === "arguments_delta" || delta.type === "function_call") {
681
+ if (state.toolIdx === void 0) state.toolIdx = nextToolIdx++;
682
+ const toolIdx = state.toolIdx;
683
+ const { index, isNew } = getOrCreateBlockIndex(`tool:${toolIdx}`, {
684
+ type: "tool_call_chunk",
685
+ id: delta.id || state.toolId || `lc-tool-call-${v4().replace(/-/g, "")}`,
686
+ name: delta.name || state.toolName || "",
687
+ args: "",
688
+ index: toolIdx
689
+ });
690
+ const acc = blockAccumulators.get(index);
691
+ if (delta.id) acc.id = delta.id;
692
+ if (delta.name) acc.name = delta.name;
693
+ const id = acc.id;
694
+ if (isNew) yield {
695
+ event: "content-block-start",
696
+ index,
697
+ content: {
698
+ type: "tool_call_chunk",
699
+ id,
700
+ name: acc.name,
701
+ args: "",
702
+ index: toolIdx
703
+ }
704
+ };
705
+ const argsDelta = typeof delta.arguments === "string" ? delta.arguments : JSON.stringify(delta.arguments ?? {});
706
+ acc.args = typeof delta.arguments === "string" ? (acc.args ?? "") + argsDelta : argsDelta;
707
+ const fcSig = pendingThoughtSignature ?? pendingFunctionCallSignature;
708
+ if (fcSig) {
709
+ acc.thoughtSignature = fcSig;
710
+ pendingThoughtSignature = void 0;
711
+ pendingFunctionCallSignature = void 0;
712
+ }
713
+ yield {
714
+ event: "content-block-delta",
715
+ index,
716
+ delta: {
717
+ type: "block-delta",
718
+ fields: {
719
+ type: "tool_call_chunk",
720
+ id,
721
+ name: acc.name,
722
+ args: argsDelta
723
+ }
724
+ }
725
+ };
726
+ } else if (delta.type === "google_search_call" || delta.type === "google_search_result" || delta.type === "google_maps_call" || delta.type === "google_maps_result" || delta.type === "file_search_call" || delta.type === "file_search_result" || delta.type === "url_context_call" || delta.type === "url_context_result") builtInToolSteps.push(delta);
727
+ continue;
728
+ }
729
+ if (event.event_type === "interaction.completed" || event.event_type === "interaction.complete") {
730
+ if (shouldStreamUsage && event.interaction?.usage) {
731
+ usageSnapshot = convertInteractionsUsageToUsageMetadata(event.interaction.usage);
732
+ if (usageSnapshot) yield {
733
+ event: "usage",
734
+ usage: usageSnapshot
735
+ };
736
+ }
737
+ continue;
738
+ }
739
+ if (event.event_type === "error") throw new GoogleError(`Google Interactions API stream error (${event.error?.code ?? "unknown"}): ${event.error?.message ?? "Unknown error"}`);
740
+ }
741
+ for (const [index, acc] of blockAccumulators) {
742
+ const finalized = finalizeContentBlock(acc);
743
+ yield {
744
+ event: "content-block-finish",
745
+ index,
746
+ content: acc.thoughtSignature ? {
747
+ ...finalized,
748
+ thoughtSignature: acc.thoughtSignature
749
+ } : finalized
750
+ };
751
+ }
752
+ const synthesized = synthesizeMetadataFromInteractions({
753
+ textSegments,
754
+ builtInToolSteps
755
+ });
756
+ yield {
757
+ event: "message-finish",
758
+ reason: finishReason,
759
+ ...usageSnapshot ? { usage: usageSnapshot } : {},
760
+ responseMetadata: {
761
+ model_provider: "google",
762
+ ...synthesized
763
+ }
764
+ };
765
+ }
766
+ export { convertInteractionsStream, convertInteractionsStreamToChunks };
767
+
768
+ //# sourceMappingURL=stream_events.js.map