@ai-sdk/google 3.0.79 → 3.0.80

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,15 @@
1
1
  # @ai-sdk/google
2
2
 
3
+ ## 3.0.80
4
+
5
+ ### Patch Changes
6
+
7
+ - f62ffe0: fix(google): auto-inject `skip_thought_signature_validator` for Gemini 3 tool-call replays without a signature
8
+
9
+ Gemini 3 models reject requests when an assistant `functionCall` part lacks a `thoughtSignature` with HTTP 400 `"Function call is missing a thought_signature in functionCall parts."` This is easy to hit when application code persists/serializes messages and drops `providerOptions.google.thoughtSignature` (custom DB schemas, `useChat` server routes that rebuild messages, synthetic tool-call injection).
10
+
11
+ The provider now detects this case (Gemini 3 model + missing signature under `google`, `googleVertex`, and `vertex` namespaces) and injects the documented `skip_thought_signature_validator` sentinel into the outbound `functionCall`, plus surfaces a one-shot warning per request listing the affected tool names so the developer can find and fix the upstream serialization. Non-Gemini-3 models are unaffected, and real signatures take precedence when present.
12
+
3
13
  ## 3.0.79
4
14
 
5
15
  ### Patch Changes
package/dist/index.js CHANGED
@@ -30,7 +30,7 @@ module.exports = __toCommonJS(index_exports);
30
30
  var import_provider_utils23 = require("@ai-sdk/provider-utils");
31
31
 
32
32
  // src/version.ts
33
- var VERSION = true ? "3.0.79" : "0.0.0-test";
33
+ var VERSION = true ? "3.0.80" : "0.0.0-test";
34
34
 
35
35
  // src/google-generative-ai-embedding-model.ts
36
36
  var import_provider = require("@ai-sdk/provider");
@@ -406,6 +406,23 @@ function isEmptyObjectSchema(jsonSchema) {
406
406
  // src/convert-to-google-generative-ai-messages.ts
407
407
  var import_provider2 = require("@ai-sdk/provider");
408
408
  var import_provider_utils4 = require("@ai-sdk/provider-utils");
409
+ var SKIP_THOUGHT_SIGNATURE_VALIDATOR = "skip_thought_signature_validator";
410
+ function getGoogleProviderOptions(providerOptions, providerOptionsName) {
411
+ const namespaces = [
412
+ providerOptionsName,
413
+ "google",
414
+ "googleVertex",
415
+ "vertex"
416
+ ].filter((namespace, index, allNamespaces) => {
417
+ return allNamespaces.indexOf(namespace) === index;
418
+ });
419
+ for (const namespace of namespaces) {
420
+ const options = providerOptions == null ? void 0 : providerOptions[namespace];
421
+ if (options != null) {
422
+ return options;
423
+ }
424
+ }
425
+ }
409
426
  var dataUrlRegex = /^data:([^;,]+);base64,(.+)$/s;
410
427
  function parseBase64DataUrl(value) {
411
428
  const match = dataUrlRegex.exec(value);
@@ -513,13 +530,22 @@ function appendLegacyToolResultParts(parts, toolName, outputValue, toolCallId) {
513
530
  }
514
531
  }
515
532
  function convertToGoogleGenerativeAIMessages(prompt, options) {
516
- var _a, _b, _c, _d, _e, _f, _g, _h;
533
+ var _a, _b, _c, _d, _e;
517
534
  const systemInstructionParts = [];
518
535
  const contents = [];
519
536
  let systemMessagesAllowed = true;
520
537
  const isGemmaModel = (_a = options == null ? void 0 : options.isGemmaModel) != null ? _a : false;
521
- const providerOptionsName = (_b = options == null ? void 0 : options.providerOptionsName) != null ? _b : "google";
522
- const supportsFunctionResponseParts = (_c = options == null ? void 0 : options.supportsFunctionResponseParts) != null ? _c : true;
538
+ const isGemini3Model = (_b = options == null ? void 0 : options.isGemini3Model) != null ? _b : false;
539
+ const providerOptionsName = (_c = options == null ? void 0 : options.providerOptionsName) != null ? _c : "google";
540
+ const supportsFunctionResponseParts = (_d = options == null ? void 0 : options.supportsFunctionResponseParts) != null ? _d : true;
541
+ const onWarning = options == null ? void 0 : options.onWarning;
542
+ let sentinelInjected = false;
543
+ const missingSignatureToolNames = [];
544
+ const injectSkipSignature = (toolName) => {
545
+ missingSignatureToolNames.push(toolName);
546
+ sentinelInjected = true;
547
+ return SKIP_THOUGHT_SIGNATURE_VALIDATOR;
548
+ };
523
549
  for (const { role, content } of prompt) {
524
550
  switch (role) {
525
551
  case "system": {
@@ -567,8 +593,10 @@ function convertToGoogleGenerativeAIMessages(prompt, options) {
567
593
  contents.push({
568
594
  role: "model",
569
595
  parts: content.map((part) => {
570
- var _a2, _b2, _c2, _d2;
571
- 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;
596
+ const providerOpts = getGoogleProviderOptions(
597
+ part.providerOptions,
598
+ providerOptionsName
599
+ );
572
600
  const thoughtSignature = (providerOpts == null ? void 0 : providerOpts.thoughtSignature) != null ? String(providerOpts.thoughtSignature) : void 0;
573
601
  switch (part.type) {
574
602
  case "text": {
@@ -602,6 +630,7 @@ function convertToGoogleGenerativeAIMessages(prompt, options) {
602
630
  case "tool-call": {
603
631
  const serverToolCallId = (providerOpts == null ? void 0 : providerOpts.serverToolCallId) != null ? String(providerOpts.serverToolCallId) : void 0;
604
632
  const serverToolType = (providerOpts == null ? void 0 : providerOpts.serverToolType) != null ? String(providerOpts.serverToolType) : void 0;
633
+ const effectiveThoughtSignature = thoughtSignature != null ? thoughtSignature : isGemini3Model ? injectSkipSignature(part.toolName) : void 0;
605
634
  if (serverToolCallId && serverToolType) {
606
635
  return {
607
636
  toolCall: {
@@ -609,7 +638,7 @@ function convertToGoogleGenerativeAIMessages(prompt, options) {
609
638
  args: typeof part.input === "string" ? JSON.parse(part.input) : part.input,
610
639
  id: serverToolCallId
611
640
  },
612
- thoughtSignature
641
+ thoughtSignature: effectiveThoughtSignature
613
642
  };
614
643
  }
615
644
  return {
@@ -618,7 +647,7 @@ function convertToGoogleGenerativeAIMessages(prompt, options) {
618
647
  name: part.toolName,
619
648
  args: part.input
620
649
  },
621
- thoughtSignature
650
+ thoughtSignature: effectiveThoughtSignature
622
651
  };
623
652
  }
624
653
  case "tool-result": {
@@ -648,7 +677,10 @@ function convertToGoogleGenerativeAIMessages(prompt, options) {
648
677
  if (part.type === "tool-approval-response") {
649
678
  continue;
650
679
  }
651
- const partProviderOpts = (_g = (_d = part.providerOptions) == null ? void 0 : _d[providerOptionsName]) != null ? _g : providerOptionsName !== "google" ? (_e = part.providerOptions) == null ? void 0 : _e.google : (_f = part.providerOptions) == null ? void 0 : _f.vertex;
680
+ const partProviderOpts = getGoogleProviderOptions(
681
+ part.providerOptions,
682
+ providerOptionsName
683
+ );
652
684
  const serverToolCallId = (partProviderOpts == null ? void 0 : partProviderOpts.serverToolCallId) != null ? String(partProviderOpts.serverToolCallId) : void 0;
653
685
  const serverToolType = (partProviderOpts == null ? void 0 : partProviderOpts.serverToolType) != null ? String(partProviderOpts.serverToolType) : void 0;
654
686
  if (serverToolCallId && serverToolType) {
@@ -692,7 +724,7 @@ function convertToGoogleGenerativeAIMessages(prompt, options) {
692
724
  name: part.toolName,
693
725
  response: {
694
726
  name: part.toolName,
695
- content: output.type === "execution-denied" ? (_h = output.reason) != null ? _h : "Tool execution denied." : output.value
727
+ content: output.type === "execution-denied" ? (_e = output.reason) != null ? _e : "Tool execution denied." : output.value
696
728
  }
697
729
  }
698
730
  });
@@ -710,6 +742,13 @@ function convertToGoogleGenerativeAIMessages(prompt, options) {
710
742
  const systemText = systemInstructionParts.map((part) => part.text).join("\n\n");
711
743
  contents[0].parts.unshift({ text: systemText + "\n\n" });
712
744
  }
745
+ if (sentinelInjected && onWarning != null) {
746
+ const uniqueToolNames = Array.from(new Set(missingSignatureToolNames));
747
+ onWarning({
748
+ type: "other",
749
+ message: `Replayed ${missingSignatureToolNames.length} \`functionCall\` part(s) for a Gemini 3 model without a \`thoughtSignature\` (tools: ${uniqueToolNames.map((name) => `\`${name}\``).join(", ")}). Injected the documented \`skip_thought_signature_validator\` sentinel to keep the request from failing with HTTP 400. The likely cause is application code that drops \`providerOptions.google.thoughtSignature\` when persisting or serializing assistant tool-call messages. See https://ai.google.dev/gemini-api/docs/thought-signatures.`
750
+ });
751
+ }
713
752
  return {
714
753
  systemInstruction: systemInstructionParts.length > 0 && !isGemmaModel ? { parts: systemInstructionParts } : void 0,
715
754
  contents
@@ -1463,13 +1502,16 @@ var GoogleGenerativeAILanguageModel = class {
1463
1502
  } : void 0;
1464
1503
  const bodyServiceTier = isVertexProvider ? void 0 : googleOptions == null ? void 0 : googleOptions.serviceTier;
1465
1504
  const isGemmaModel = this.modelId.toLowerCase().startsWith("gemma-");
1466
- const supportsFunctionResponseParts = this.modelId.startsWith("gemini-3");
1505
+ const isGemini3Model = /^gemini-3[.-]/.test(this.modelId);
1506
+ const supportsFunctionResponseParts = isGemini3Model;
1467
1507
  const { contents, systemInstruction } = convertToGoogleGenerativeAIMessages(
1468
1508
  prompt,
1469
1509
  {
1470
1510
  isGemmaModel,
1511
+ isGemini3Model,
1471
1512
  providerOptionsName,
1472
- supportsFunctionResponseParts
1513
+ supportsFunctionResponseParts,
1514
+ onWarning: (warning) => warnings.push(warning)
1473
1515
  }
1474
1516
  );
1475
1517
  const {