@ai-sdk/google 4.0.62 → 4.0.64

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.
@@ -13,6 +13,7 @@ import type {
13
13
  } from '@ai-sdk/provider';
14
14
  import {
15
15
  combineHeaders,
16
+ createToolNameMapping,
16
17
  createEventSourceResponseHandler,
17
18
  createJsonResponseHandler,
18
19
  generateId,
@@ -297,6 +298,12 @@ export class GoogleLanguageModel implements LanguageModelV4 {
297
298
  modelId: this.modelId,
298
299
  isVertexProvider,
299
300
  });
301
+ const toolNameMapping = createToolNameMapping({
302
+ tools,
303
+ providerToolNames: {
304
+ 'google.code_execution': 'code_execution',
305
+ },
306
+ });
300
307
 
301
308
  const resolvedThinking = resolveThinkingConfig({
302
309
  reasoning,
@@ -394,6 +401,7 @@ export class GoogleLanguageModel implements LanguageModelV4 {
394
401
  warnings: [...warnings, ...toolWarnings],
395
402
  providerOptionsNames,
396
403
  extraHeaders: vertexPaygoHeaders,
404
+ toolNameMapping,
397
405
  };
398
406
  }
399
407
 
@@ -401,10 +409,12 @@ export class GoogleLanguageModel implements LanguageModelV4 {
401
409
  response,
402
410
  warnings,
403
411
  providerOptionsNames,
412
+ toolNameMapping,
404
413
  }: {
405
414
  response: InferSchema<typeof responseSchema>;
406
415
  warnings: SharedV4Warning[];
407
416
  providerOptionsNames: readonly string[];
417
+ toolNameMapping?: ReturnType<typeof createToolNameMapping>;
408
418
  }): LanguageModelV4GenerateResult {
409
419
  const wrapProviderMetadata = (payload: Record<string, unknown>) =>
410
420
  Object.fromEntries(
@@ -437,7 +447,9 @@ export class GoogleLanguageModel implements LanguageModelV4 {
437
447
  content.push({
438
448
  type: 'tool-call',
439
449
  toolCallId,
440
- toolName: 'code_execution',
450
+ toolName:
451
+ toolNameMapping?.toCustomToolName('code_execution') ??
452
+ 'code_execution',
441
453
  input: JSON.stringify(part.executableCode),
442
454
  providerExecuted: true,
443
455
  });
@@ -446,7 +458,9 @@ export class GoogleLanguageModel implements LanguageModelV4 {
446
458
  type: 'tool-result',
447
459
  // Results correspond to the most recent executable code part.
448
460
  toolCallId: lastCodeExecutionToolCallId!,
449
- toolName: 'code_execution',
461
+ toolName:
462
+ toolNameMapping?.toCustomToolName('code_execution') ??
463
+ 'code_execution',
450
464
  result: {
451
465
  outcome: part.codeExecutionResult.outcome,
452
466
  output: part.codeExecutionResult.output ?? '',
@@ -586,8 +600,13 @@ export class GoogleLanguageModel implements LanguageModelV4 {
586
600
  async doGenerate(
587
601
  options: LanguageModelV4CallOptions,
588
602
  ): Promise<LanguageModelV4GenerateResult> {
589
- const { args, warnings, providerOptionsNames, extraHeaders } =
590
- await this.getArgs(options);
603
+ const {
604
+ args,
605
+ warnings,
606
+ providerOptionsNames,
607
+ extraHeaders,
608
+ toolNameMapping,
609
+ } = await this.getArgs(options);
591
610
 
592
611
  const mergedHeaders = combineHeaders(
593
612
  this.config.headers ? await resolve(this.config.headers) : undefined,
@@ -615,6 +634,7 @@ export class GoogleLanguageModel implements LanguageModelV4 {
615
634
  response,
616
635
  warnings,
617
636
  providerOptionsNames,
637
+ toolNameMapping,
618
638
  });
619
639
 
620
640
  return {
@@ -631,8 +651,13 @@ export class GoogleLanguageModel implements LanguageModelV4 {
631
651
  async doStream(
632
652
  options: LanguageModelV4CallOptions,
633
653
  ): Promise<LanguageModelV4StreamResult> {
634
- const { args, warnings, providerOptionsNames, extraHeaders } =
635
- await this.getArgs(options, { isStreaming: true });
654
+ const {
655
+ args,
656
+ warnings,
657
+ providerOptionsNames,
658
+ extraHeaders,
659
+ toolNameMapping,
660
+ } = await this.getArgs(options, { isStreaming: true });
636
661
  const wrapProviderMetadata = (payload: Record<string, unknown>) =>
637
662
  Object.fromEntries(
638
663
  providerOptionsNames.map(name => [name, payload]),
@@ -820,7 +845,8 @@ export class GoogleLanguageModel implements LanguageModelV4 {
820
845
  controller.enqueue({
821
846
  type: 'tool-call',
822
847
  toolCallId,
823
- toolName: 'code_execution',
848
+ toolName:
849
+ toolNameMapping.toCustomToolName('code_execution'),
824
850
  input: JSON.stringify(part.executableCode),
825
851
  providerExecuted: true,
826
852
  });
@@ -835,7 +861,8 @@ export class GoogleLanguageModel implements LanguageModelV4 {
835
861
  controller.enqueue({
836
862
  type: 'tool-result',
837
863
  toolCallId,
838
- toolName: 'code_execution',
864
+ toolName:
865
+ toolNameMapping.toCustomToolName('code_execution'),
839
866
  result: {
840
867
  outcome: part.codeExecutionResult.outcome,
841
868
  output: part.codeExecutionResult.output ?? '',
package/src/index.ts CHANGED
@@ -37,6 +37,7 @@ export type { GoogleFilesUploadOptions } from './google-files';
37
37
  export type {
38
38
  GoogleLanguageModelInteractionsOptions,
39
39
  GoogleInteractionsModelId,
40
+ GoogleInteractionsVideoOptions,
40
41
  } from './interactions/google-interactions-language-model-options';
41
42
  export type { GoogleInteractionsProviderMetadata } from './interactions/google-interactions-provider-metadata';
42
43
  export type { GoogleInteractionsAgentName } from './interactions/google-interactions-agent';
@@ -103,6 +103,12 @@ type OpenBlockState =
103
103
  isError?: boolean;
104
104
  resultEmitted: boolean;
105
105
  }
106
+ | {
107
+ kind: 'custom';
108
+ id: string;
109
+ customKind: 'google.processing_call' | 'google.processing_result';
110
+ google: Record<string, string>;
111
+ }
106
112
  /**
107
113
  * A `model_output` step whose inner content-block kind has not yet been
108
114
  * disambiguated. `step.start` may arrive bare (`{type: 'model_output'}`,
@@ -337,6 +343,24 @@ export function buildGoogleInteractionsStreamTransform({
337
343
  }
338
344
  }
339
345
  }
346
+ } else if (
347
+ stepType === 'processing_call' ||
348
+ stepType === 'processing_result'
349
+ ) {
350
+ const google: Record<string, string> = {};
351
+ if (step?.signature != null) google.signature = step.signature;
352
+ if (interactionId != null) google.interactionId = interactionId;
353
+ if (stepType === 'processing_call') {
354
+ google.processingId = step?.id || blockId;
355
+ } else {
356
+ google.processingCallId = step?.call_id || blockId;
357
+ }
358
+ openBlocks.set(index, {
359
+ kind: 'custom',
360
+ id: blockId,
361
+ customKind: `google.${stepType}`,
362
+ google,
363
+ });
340
364
  } else if (stepType === 'function_call') {
341
365
  const toolCallId = step?.id || blockId;
342
366
  const toolName = step?.name ?? 'unknown';
@@ -544,7 +568,28 @@ export function buildGoogleInteractionsStreamTransform({
544
568
  }
545
569
  | undefined;
546
570
 
547
- if (open.kind === 'text' && delta?.type === 'text') {
571
+ if (
572
+ open.kind === 'custom' &&
573
+ (delta?.type === 'processing_call' ||
574
+ delta?.type === 'processing_result')
575
+ ) {
576
+ if (delta.signature != null)
577
+ open.google.signature = delta.signature;
578
+ if (
579
+ delta.type === 'processing_call' &&
580
+ delta.id != null &&
581
+ delta.id.length > 0
582
+ ) {
583
+ open.google.processingId = delta.id;
584
+ }
585
+ if (
586
+ delta.type === 'processing_result' &&
587
+ delta.call_id != null &&
588
+ delta.call_id.length > 0
589
+ ) {
590
+ open.google.processingCallId = delta.call_id;
591
+ }
592
+ } else if (open.kind === 'text' && delta?.type === 'text') {
548
593
  const text = delta.text ?? '';
549
594
  if (text.length > 0) {
550
595
  controller.enqueue({
@@ -724,6 +769,12 @@ export function buildGoogleInteractionsStreamTransform({
724
769
  input: accumulated,
725
770
  ...(providerMetadata ? { providerMetadata } : {}),
726
771
  });
772
+ } else if (open.kind === 'custom') {
773
+ controller.enqueue({
774
+ type: 'custom',
775
+ kind: open.customKind,
776
+ providerMetadata: { google: open.google },
777
+ });
727
778
  } else if (open.kind === 'builtin_tool_call' && !open.callEmitted) {
728
779
  controller.enqueue({
729
780
  type: 'tool-call',
@@ -20,6 +20,7 @@ import type {
20
20
  GoogleInteractionsInput,
21
21
  GoogleInteractionsStep,
22
22
  GoogleInteractionsTextContent,
23
+ GoogleInteractionsVideoProcessing,
23
24
  } from './google-interactions-prompt';
24
25
 
25
26
  export type GoogleInteractionsMediaResolution =
@@ -163,6 +164,44 @@ export function convertToGoogleInteractionsInput({
163
164
  if (fileBlock != null) {
164
165
  pendingModelOutput.push(fileBlock);
165
166
  }
167
+ } else if (part.type === 'custom') {
168
+ flushModelOutput();
169
+ const google = part.providerOptions?.google as
170
+ | {
171
+ processingId?: unknown;
172
+ processingCallId?: unknown;
173
+ signature?: unknown;
174
+ }
175
+ | undefined;
176
+ const signature =
177
+ typeof google?.signature === 'string'
178
+ ? google.signature
179
+ : undefined;
180
+
181
+ if (
182
+ part.kind === 'google.processing_call' &&
183
+ typeof google?.processingId === 'string'
184
+ ) {
185
+ steps.push({
186
+ type: 'processing_call',
187
+ id: google.processingId,
188
+ ...(signature != null ? { signature } : {}),
189
+ });
190
+ } else if (
191
+ part.kind === 'google.processing_result' &&
192
+ typeof google?.processingCallId === 'string'
193
+ ) {
194
+ steps.push({
195
+ type: 'processing_result',
196
+ call_id: google.processingCallId,
197
+ ...(signature != null ? { signature } : {}),
198
+ });
199
+ } else {
200
+ warnings.push({
201
+ type: 'other',
202
+ message: `google.interactions: unsupported or invalid custom assistant content part "${part.kind}"; part dropped.`,
203
+ });
204
+ }
166
205
  } else if (part.type === 'tool-call') {
167
206
  flushModelOutput();
168
207
  const signature = part.providerOptions?.google?.signature as
@@ -282,6 +321,8 @@ function convertFilePartToContent({
282
321
  mediaResolution != null && (kind === 'image' || kind === 'video')
283
322
  ? { resolution: mediaResolution }
284
323
  : {};
324
+ const processingField =
325
+ kind === 'video' ? getVideoProcessingField({ part, warnings }) : {};
285
326
 
286
327
  switch (part.data.type) {
287
328
  case 'data': {
@@ -291,6 +332,7 @@ function convertFilePartToContent({
291
332
  data: convertToBase64(part.data.data),
292
333
  mime_type: mimeType,
293
334
  ...resolutionField,
335
+ ...processingField,
294
336
  };
295
337
  }
296
338
  case 'url': {
@@ -301,6 +343,7 @@ function convertFilePartToContent({
301
343
  ? { mime_type: part.mediaType }
302
344
  : {}),
303
345
  ...resolutionField,
346
+ ...processingField,
304
347
  };
305
348
  }
306
349
  case 'reference': {
@@ -315,11 +358,67 @@ function convertFilePartToContent({
315
358
  ? { mime_type: part.mediaType }
316
359
  : {}),
317
360
  ...resolutionField,
361
+ ...processingField,
318
362
  };
319
363
  }
320
364
  }
321
365
  }
322
366
 
367
+ function getVideoProcessingField({
368
+ part,
369
+ warnings,
370
+ }: {
371
+ part: LanguageModelV4FilePart;
372
+ warnings: Array<SharedV4Warning>;
373
+ }): { processing?: GoogleInteractionsVideoProcessing } {
374
+ const processing = (
375
+ part.providerOptions?.google as
376
+ | {
377
+ processing?: unknown;
378
+ }
379
+ | undefined
380
+ )?.processing;
381
+
382
+ if (processing == null) {
383
+ return {};
384
+ }
385
+
386
+ if (processing === 'agentic' || processing === 'static') {
387
+ return { processing };
388
+ }
389
+
390
+ if (
391
+ typeof processing === 'object' &&
392
+ !Array.isArray(processing) &&
393
+ (processing as { type?: unknown }).type === 'static'
394
+ ) {
395
+ const config = processing as {
396
+ startOffset?: unknown;
397
+ endOffset?: unknown;
398
+ fps?: unknown;
399
+ };
400
+ return {
401
+ processing: {
402
+ type: 'static',
403
+ ...(typeof config.startOffset === 'number'
404
+ ? { start_offset: config.startOffset }
405
+ : {}),
406
+ ...(typeof config.endOffset === 'number'
407
+ ? { end_offset: config.endOffset }
408
+ : {}),
409
+ ...(typeof config.fps === 'number' ? { fps: config.fps } : {}),
410
+ },
411
+ };
412
+ }
413
+
414
+ warnings.push({
415
+ type: 'other',
416
+ message:
417
+ 'google.interactions: invalid providerOptions.google.processing on video file part; expected "agentic", "static", or a static processing configuration. Option dropped.',
418
+ });
419
+ return {};
420
+ }
421
+
323
422
  /*
324
423
  * Drops assistant messages that were part of the linked interaction
325
424
  * (`previousInteractionId`). Tool-result turns whose tool-call counterpart
@@ -222,6 +222,22 @@ const stepSchema = () => {
222
222
  })
223
223
  .loose();
224
224
 
225
+ const processingCallStep = z
226
+ .object({
227
+ type: z.literal('processing_call'),
228
+ id: z.string(),
229
+ signature: z.string().nullish(),
230
+ })
231
+ .loose();
232
+
233
+ const processingResultStep = z
234
+ .object({
235
+ type: z.literal('processing_result'),
236
+ call_id: z.string(),
237
+ signature: z.string().nullish(),
238
+ })
239
+ .loose();
240
+
225
241
  const builtinToolCallStep = z
226
242
  .object({
227
243
  type: z.enum(BUILTIN_TOOL_CALL_STEP_TYPES),
@@ -251,6 +267,8 @@ const stepSchema = () => {
251
267
  modelOutputStep,
252
268
  functionCallStep,
253
269
  thoughtStep,
270
+ processingCallStep,
271
+ processingResultStep,
254
272
  builtinToolCallStep,
255
273
  builtinToolResultStep,
256
274
  z.object({ type: z.string() }).loose(),
@@ -36,10 +36,34 @@ export type GoogleInteractionsModelId =
36
36
  | 'gemini-3.5-flash-lite'
37
37
  | 'gemini-3.6-flash'
38
38
  | 'gemini-3.7-flash'
39
+ | 'gemini-3.8-flash'
39
40
  | 'lyria-3-clip-preview'
40
41
  | 'lyria-3-pro-preview'
41
42
  | (string & {});
42
43
 
44
+ /**
45
+ * Provider options for an individual video file part sent to the Gemini
46
+ * Interactions API.
47
+ */
48
+ export type GoogleInteractionsVideoOptions = {
49
+ /**
50
+ * Controls how Gemini processes this video.
51
+ *
52
+ * Agentic processing dynamically explores the video timeline. Static
53
+ * processing samples frames at a fixed rate and optionally supports clipping
54
+ * and custom frame rates.
55
+ */
56
+ processing?:
57
+ | 'agentic'
58
+ | 'static'
59
+ | {
60
+ type: 'static';
61
+ startOffset?: number;
62
+ endOffset?: number;
63
+ fps?: number;
64
+ };
65
+ };
66
+
43
67
  /**
44
68
  * Provider-options schema for `google.interactions(...)` calls. Read from the
45
69
  * shared `providerOptions.google.*` namespace (per PRD); per-call options that
@@ -35,12 +35,23 @@ export type GoogleInteractionsDocumentContent = {
35
35
  uri?: string;
36
36
  };
37
37
 
38
+ export type GoogleInteractionsVideoProcessing =
39
+ | 'agentic'
40
+ | 'static'
41
+ | {
42
+ type: 'static';
43
+ start_offset?: number;
44
+ end_offset?: number;
45
+ fps?: number;
46
+ };
47
+
38
48
  export type GoogleInteractionsVideoContent = {
39
49
  type: 'video';
40
50
  data?: string;
41
51
  mime_type?: string;
42
52
  uri?: string;
43
53
  resolution?: 'low' | 'medium' | 'high' | 'ultra_high';
54
+ processing?: GoogleInteractionsVideoProcessing;
44
55
  };
45
56
 
46
57
  export type GoogleInteractionsThoughtSummaryItem =
@@ -127,6 +138,16 @@ export type GoogleInteractionsThoughtStepPayload = {
127
138
  summary?: Array<GoogleInteractionsThoughtSummaryItem>;
128
139
  };
129
140
 
141
+ export type GoogleInteractionsProcessingCallStepPayload = {
142
+ id: string;
143
+ signature?: string;
144
+ };
145
+
146
+ export type GoogleInteractionsProcessingResultStepPayload = {
147
+ call_id: string;
148
+ signature?: string;
149
+ };
150
+
130
151
  export type GoogleInteractionsCodeExecutionCallStepPayload = {
131
152
  id: string;
132
153
  arguments?: { code?: string; language?: string };
@@ -255,6 +276,14 @@ export type GoogleInteractionsThoughtStep = {
255
276
  type: 'thought';
256
277
  } & GoogleInteractionsThoughtStepPayload;
257
278
 
279
+ export type GoogleInteractionsProcessingCallStep = {
280
+ type: 'processing_call';
281
+ } & GoogleInteractionsProcessingCallStepPayload;
282
+
283
+ export type GoogleInteractionsProcessingResultStep = {
284
+ type: 'processing_result';
285
+ } & GoogleInteractionsProcessingResultStepPayload;
286
+
258
287
  export type GoogleInteractionsBuiltinToolCallStep =
259
288
  | ({
260
289
  type: 'google_search_call';
@@ -294,6 +323,8 @@ export type GoogleInteractionsStep =
294
323
  | GoogleInteractionsModelOutputStep
295
324
  | GoogleInteractionsFunctionCallStep
296
325
  | GoogleInteractionsThoughtStep
326
+ | GoogleInteractionsProcessingCallStep
327
+ | GoogleInteractionsProcessingResultStep
297
328
  | GoogleInteractionsBuiltinToolCallStep
298
329
  | GoogleInteractionsBuiltinToolResultStep
299
330
  | { type: string; [k: string]: unknown };
@@ -28,4 +28,16 @@ export type GoogleInteractionsProviderMetadata = {
28
28
  * reasoning / tool-call parts and round-tripped on input parts.
29
29
  */
30
30
  signature?: string;
31
+
32
+ /**
33
+ * ID of an agentic video `processing_call` step. Present on
34
+ * `google.processing_call` custom parts.
35
+ */
36
+ processingId?: string;
37
+
38
+ /**
39
+ * ID of the corresponding agentic video processing call. Present on
40
+ * `google.processing_result` custom parts.
41
+ */
42
+ processingCallId?: string;
31
43
  };
@@ -23,9 +23,13 @@ export type ParseGoogleInteractionsOutputsResult = {
23
23
  function googleProviderMetadata({
24
24
  signature,
25
25
  interactionId,
26
+ processingId,
27
+ processingCallId,
26
28
  }: {
27
29
  signature?: string | null;
28
30
  interactionId?: string;
31
+ processingId?: string;
32
+ processingCallId?: string;
29
33
  }): { providerMetadata: { google: Record<string, string> } } | object {
30
34
  const google: Record<string, string> = {};
31
35
  if (signature != null) {
@@ -34,6 +38,12 @@ function googleProviderMetadata({
34
38
  if (interactionId != null) {
35
39
  google.interactionId = interactionId;
36
40
  }
41
+ if (processingId != null) {
42
+ google.processingId = processingId;
43
+ }
44
+ if (processingCallId != null) {
45
+ google.processingCallId = processingCallId;
46
+ }
37
47
  return Object.keys(google).length > 0 ? { providerMetadata: { google } } : {};
38
48
  }
39
49
 
@@ -198,6 +208,40 @@ export function parseGoogleInteractionsOutputs({
198
208
  });
199
209
  break;
200
210
  }
211
+ case 'processing_call': {
212
+ const call = step as {
213
+ id?: string;
214
+ signature?: string | null;
215
+ };
216
+ const processingId = call.id || generateId();
217
+ content.push({
218
+ type: 'custom',
219
+ kind: 'google.processing_call',
220
+ ...googleProviderMetadata({
221
+ signature: call.signature,
222
+ interactionId,
223
+ processingId,
224
+ }),
225
+ });
226
+ break;
227
+ }
228
+ case 'processing_result': {
229
+ const result = step as {
230
+ call_id?: string;
231
+ signature?: string | null;
232
+ };
233
+ const processingCallId = result.call_id || generateId();
234
+ content.push({
235
+ type: 'custom',
236
+ kind: 'google.processing_result',
237
+ ...googleProviderMetadata({
238
+ signature: result.signature,
239
+ interactionId,
240
+ processingCallId,
241
+ }),
242
+ });
243
+ break;
244
+ }
201
245
  case 'function_call': {
202
246
  hasFunctionCall = true;
203
247
  const call = step as {