@ai-sdk/google 4.0.0-beta.14 → 4.0.0-beta.15

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.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,16 @@
1
1
  # @ai-sdk/google
2
2
 
3
+ ## 4.0.0-beta.15
4
+
5
+ ### Patch Changes
6
+
7
+ - 18c1970: feat(provider/google): Add multimodal tool-result support for Google function responses.
8
+
9
+ Tool results with `output.type = 'content'` now map media parts into
10
+ `functionResponse.parts` for Google models, including `image-data`,
11
+ `file-data`, and base64 `data:` URLs in URL-style content parts.
12
+ Remote HTTP(S) URLs in URL-style tool-result parts are not supported.
13
+
3
14
  ## 4.0.0-beta.14
4
15
 
5
16
  ### Patch Changes
package/dist/index.js CHANGED
@@ -30,7 +30,7 @@ module.exports = __toCommonJS(index_exports);
30
30
  var import_provider_utils16 = require("@ai-sdk/provider-utils");
31
31
 
32
32
  // src/version.ts
33
- var VERSION = true ? "4.0.0-beta.14" : "0.0.0-test";
33
+ var VERSION = true ? "4.0.0-beta.15" : "0.0.0-test";
34
34
 
35
35
  // src/google-generative-ai-embedding-model.ts
36
36
  var import_provider = require("@ai-sdk/provider");
@@ -400,13 +400,118 @@ function isEmptyObjectSchema(jsonSchema) {
400
400
  // src/convert-to-google-generative-ai-messages.ts
401
401
  var import_provider2 = require("@ai-sdk/provider");
402
402
  var import_provider_utils4 = require("@ai-sdk/provider-utils");
403
+ var dataUrlRegex = /^data:([^;,]+);base64,(.+)$/s;
404
+ function parseBase64DataUrl(value) {
405
+ const match = dataUrlRegex.exec(value);
406
+ if (match == null) {
407
+ return void 0;
408
+ }
409
+ return {
410
+ mediaType: match[1],
411
+ data: match[2]
412
+ };
413
+ }
414
+ function convertUrlToolResultPart(url) {
415
+ const parsedDataUrl = parseBase64DataUrl(url);
416
+ if (parsedDataUrl == null) {
417
+ return void 0;
418
+ }
419
+ return {
420
+ inlineData: {
421
+ mimeType: parsedDataUrl.mediaType,
422
+ data: parsedDataUrl.data
423
+ }
424
+ };
425
+ }
426
+ function appendToolResultParts(parts, toolName, outputValue) {
427
+ const functionResponseParts = [];
428
+ const responseTextParts = [];
429
+ for (const contentPart of outputValue) {
430
+ switch (contentPart.type) {
431
+ case "text": {
432
+ responseTextParts.push(contentPart.text);
433
+ break;
434
+ }
435
+ case "image-data":
436
+ case "file-data": {
437
+ functionResponseParts.push({
438
+ inlineData: {
439
+ mimeType: contentPart.mediaType,
440
+ data: contentPart.data
441
+ }
442
+ });
443
+ break;
444
+ }
445
+ case "image-url":
446
+ case "file-url": {
447
+ const functionResponsePart = convertUrlToolResultPart(
448
+ contentPart.url
449
+ );
450
+ if (functionResponsePart != null) {
451
+ functionResponseParts.push(functionResponsePart);
452
+ } else {
453
+ responseTextParts.push(JSON.stringify(contentPart));
454
+ }
455
+ break;
456
+ }
457
+ default: {
458
+ responseTextParts.push(JSON.stringify(contentPart));
459
+ break;
460
+ }
461
+ }
462
+ }
463
+ parts.push({
464
+ functionResponse: {
465
+ name: toolName,
466
+ response: {
467
+ name: toolName,
468
+ content: responseTextParts.length > 0 ? responseTextParts.join("\n") : "Tool executed successfully."
469
+ },
470
+ ...functionResponseParts.length > 0 ? { parts: functionResponseParts } : {}
471
+ }
472
+ });
473
+ }
474
+ function appendLegacyToolResultParts(parts, toolName, outputValue) {
475
+ for (const contentPart of outputValue) {
476
+ switch (contentPart.type) {
477
+ case "text":
478
+ parts.push({
479
+ functionResponse: {
480
+ name: toolName,
481
+ response: {
482
+ name: toolName,
483
+ content: contentPart.text
484
+ }
485
+ }
486
+ });
487
+ break;
488
+ case "image-data":
489
+ parts.push(
490
+ {
491
+ inlineData: {
492
+ mimeType: String(contentPart.mediaType),
493
+ data: String(contentPart.data)
494
+ }
495
+ },
496
+ {
497
+ text: "Tool executed successfully and returned this image as a response"
498
+ }
499
+ );
500
+ break;
501
+ default:
502
+ parts.push({ text: JSON.stringify(contentPart) });
503
+ break;
504
+ }
505
+ }
506
+ }
403
507
  function convertToGoogleGenerativeAIMessages(prompt, options) {
404
- var _a, _b, _c;
508
+ var _a, _b, _c, _d;
405
509
  const systemInstructionParts = [];
406
510
  const contents = [];
407
511
  let systemMessagesAllowed = true;
408
512
  const isGemmaModel = (_a = options == null ? void 0 : options.isGemmaModel) != null ? _a : false;
409
513
  const providerOptionsName = (_b = options == null ? void 0 : options.providerOptionsName) != null ? _b : "google";
514
+ const supportsFunctionResponseParts = (_c = options == null ? void 0 : options.supportsFunctionResponseParts) != null ? _c : true;
410
515
  for (const { role, content } of prompt) {
411
516
  switch (role) {
412
517
  case "system": {
@@ -454,8 +559,8 @@ function convertToGoogleGenerativeAIMessages(prompt, options) {
454
559
  contents.push({
455
560
  role: "model",
456
561
  parts: content.map((part) => {
457
- var _a2, _b2, _c2, _d;
458
- const providerOpts = (_d = (_a2 = part.providerOptions) == null ? void 0 : _a2[providerOptionsName]) != null ? _d : providerOptionsName !== "google" ? (_b2 = part.providerOptions) == null ? void 0 : _b2.google : (_c2 = part.providerOptions) == null ? void 0 : _c2.vertex;
562
+ var _a2, _b2, _c2, _d2;
563
+ const providerOpts = (_d2 = (_a2 = part.providerOptions) == null ? void 0 : _a2[providerOptionsName]) != null ? _d2 : providerOptionsName !== "google" ? (_b2 = part.providerOptions) == null ? void 0 : _b2.google : (_c2 = part.providerOptions) == null ? void 0 : _c2.vertex;
459
564
  const thoughtSignature = (providerOpts == null ? void 0 : providerOpts.thoughtSignature) != null ? String(providerOpts.thoughtSignature) : void 0;
460
565
  switch (part.type) {
461
566
  case "text": {
@@ -524,36 +629,10 @@ function convertToGoogleGenerativeAIMessages(prompt, options) {
524
629
  }
525
630
  const output = part.output;
526
631
  if (output.type === "content") {
527
- for (const contentPart of output.value) {
528
- switch (contentPart.type) {
529
- case "text":
530
- parts.push({
531
- functionResponse: {
532
- name: part.toolName,
533
- response: {
534
- name: part.toolName,
535
- content: contentPart.text
536
- }
537
- }
538
- });
539
- break;
540
- case "image-data":
541
- parts.push(
542
- {
543
- inlineData: {
544
- mimeType: contentPart.mediaType,
545
- data: contentPart.data
546
- }
547
- },
548
- {
549
- text: "Tool executed successfully and returned this image as a response"
550
- }
551
- );
552
- break;
553
- default:
554
- parts.push({ text: JSON.stringify(contentPart) });
555
- break;
556
- }
632
+ if (supportsFunctionResponseParts) {
633
+ appendToolResultParts(parts, part.toolName, output.value);
634
+ } else {
635
+ appendLegacyToolResultParts(parts, part.toolName, output.value);
557
636
  }
558
637
  } else {
559
638
  parts.push({
@@ -561,7 +640,7 @@ function convertToGoogleGenerativeAIMessages(prompt, options) {
561
640
  name: part.toolName,
562
641
  response: {
563
642
  name: part.toolName,
564
- content: output.type === "execution-denied" ? (_c = output.reason) != null ? _c : "Tool execution denied." : output.value
643
+ content: output.type === "execution-denied" ? (_d = output.reason) != null ? _d : "Tool execution denied." : output.value
565
644
  }
566
645
  }
567
646
  });
@@ -1004,9 +1083,14 @@ var GoogleGenerativeAILanguageModel = class {
1004
1083
  });
1005
1084
  }
1006
1085
  const isGemmaModel = this.modelId.toLowerCase().startsWith("gemma-");
1086
+ const supportsFunctionResponseParts = this.modelId.startsWith("gemini-3");
1007
1087
  const { contents, systemInstruction } = convertToGoogleGenerativeAIMessages(
1008
1088
  prompt,
1009
- { isGemmaModel, providerOptionsName }
1089
+ {
1090
+ isGemmaModel,
1091
+ providerOptionsName,
1092
+ supportsFunctionResponseParts
1093
+ }
1010
1094
  );
1011
1095
  const {
1012
1096
  tools: googleTools2,