@ai-sdk/google 3.0.78 → 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 +16 -0
- package/dist/index.d.mts +11 -0
- package/dist/index.d.ts +11 -0
- package/dist/index.js +96 -20
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +96 -20
- package/dist/index.mjs.map +1 -1
- package/dist/internal/index.js +53 -11
- package/dist/internal/index.js.map +1 -1
- package/dist/internal/index.mjs +53 -11
- package/dist/internal/index.mjs.map +1 -1
- package/package.json +1 -1
- package/src/convert-to-google-generative-ai-messages.ts +104 -12
- package/src/google-generative-ai-image-model.ts +55 -4
- package/src/google-generative-ai-language-model.ts +4 -1
- package/src/tool/google-search.ts +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,21 @@
|
|
|
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
|
+
|
|
13
|
+
## 3.0.79
|
|
14
|
+
|
|
15
|
+
### Patch Changes
|
|
16
|
+
|
|
17
|
+
- cfa0cb2: feat(provider/google): support Google search grounding when using `generateImage` with Gemini
|
|
18
|
+
|
|
3
19
|
## 3.0.78
|
|
4
20
|
|
|
5
21
|
### Patch Changes
|
package/dist/index.d.mts
CHANGED
|
@@ -225,6 +225,17 @@ interface GoogleGenerativeAIImageSettings {
|
|
|
225
225
|
declare const googleImageModelOptionsSchema: _ai_sdk_provider_utils.LazySchema<{
|
|
226
226
|
personGeneration?: "dont_allow" | "allow_adult" | "allow_all" | null | undefined;
|
|
227
227
|
aspectRatio?: "1:1" | "3:4" | "4:3" | "9:16" | "16:9" | null | undefined;
|
|
228
|
+
googleSearch?: {
|
|
229
|
+
[x: string]: unknown;
|
|
230
|
+
searchTypes?: {
|
|
231
|
+
webSearch?: Record<string, never> | undefined;
|
|
232
|
+
imageSearch?: Record<string, never> | undefined;
|
|
233
|
+
} | undefined;
|
|
234
|
+
timeRangeFilter?: {
|
|
235
|
+
startTime: string;
|
|
236
|
+
endTime: string;
|
|
237
|
+
} | undefined;
|
|
238
|
+
} | undefined;
|
|
228
239
|
}>;
|
|
229
240
|
type GoogleImageModelOptions = InferSchema<typeof googleImageModelOptionsSchema>;
|
|
230
241
|
|
package/dist/index.d.ts
CHANGED
|
@@ -225,6 +225,17 @@ interface GoogleGenerativeAIImageSettings {
|
|
|
225
225
|
declare const googleImageModelOptionsSchema: _ai_sdk_provider_utils.LazySchema<{
|
|
226
226
|
personGeneration?: "dont_allow" | "allow_adult" | "allow_all" | null | undefined;
|
|
227
227
|
aspectRatio?: "1:1" | "3:4" | "4:3" | "9:16" | "16:9" | null | undefined;
|
|
228
|
+
googleSearch?: {
|
|
229
|
+
[x: string]: unknown;
|
|
230
|
+
searchTypes?: {
|
|
231
|
+
webSearch?: Record<string, never> | undefined;
|
|
232
|
+
imageSearch?: Record<string, never> | undefined;
|
|
233
|
+
} | undefined;
|
|
234
|
+
timeRangeFilter?: {
|
|
235
|
+
startTime: string;
|
|
236
|
+
endTime: string;
|
|
237
|
+
} | undefined;
|
|
238
|
+
} | undefined;
|
|
228
239
|
}>;
|
|
229
240
|
type GoogleImageModelOptions = InferSchema<typeof googleImageModelOptionsSchema>;
|
|
230
241
|
|
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.
|
|
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
|
|
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
|
|
522
|
-
const
|
|
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
|
-
|
|
571
|
-
|
|
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 = (
|
|
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" ? (
|
|
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
|
|
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 {
|
|
@@ -2667,7 +2709,15 @@ var GoogleGenerativeAIImageModel = class {
|
|
|
2667
2709
|
parameters.aspectRatio = aspectRatio;
|
|
2668
2710
|
}
|
|
2669
2711
|
if (googleOptions) {
|
|
2670
|
-
|
|
2712
|
+
const { googleSearch: imagenGoogleSearch, ...imagenOptions } = googleOptions;
|
|
2713
|
+
if (imagenGoogleSearch != null) {
|
|
2714
|
+
warnings.push({
|
|
2715
|
+
type: "unsupported",
|
|
2716
|
+
feature: "googleSearch",
|
|
2717
|
+
details: "Google Search grounding is only supported on Gemini image models."
|
|
2718
|
+
});
|
|
2719
|
+
}
|
|
2720
|
+
Object.assign(parameters, imagenOptions);
|
|
2671
2721
|
}
|
|
2672
2722
|
const body = {
|
|
2673
2723
|
instances: [{ prompt }],
|
|
@@ -2704,7 +2754,7 @@ var GoogleGenerativeAIImageModel = class {
|
|
|
2704
2754
|
};
|
|
2705
2755
|
}
|
|
2706
2756
|
async doGenerateGemini(options) {
|
|
2707
|
-
var _a, _b, _c, _d, _e, _f, _g, _h, _i;
|
|
2757
|
+
var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k;
|
|
2708
2758
|
const {
|
|
2709
2759
|
prompt,
|
|
2710
2760
|
n,
|
|
@@ -2759,12 +2809,18 @@ var GoogleGenerativeAIImageModel = class {
|
|
|
2759
2809
|
const languageModelPrompt = [
|
|
2760
2810
|
{ role: "user", content: userContent }
|
|
2761
2811
|
];
|
|
2812
|
+
const googleImageOptions = await (0, import_provider_utils14.parseProviderOptions)({
|
|
2813
|
+
provider: "google",
|
|
2814
|
+
providerOptions,
|
|
2815
|
+
schema: googleImageModelOptionsSchema
|
|
2816
|
+
});
|
|
2817
|
+
const { googleSearch: _strippedGoogleSearch, ...passthroughGoogleOptions } = (_a = providerOptions == null ? void 0 : providerOptions.google) != null ? _a : {};
|
|
2762
2818
|
const languageModel = new GoogleGenerativeAILanguageModel(this.modelId, {
|
|
2763
2819
|
provider: this.config.provider,
|
|
2764
2820
|
baseURL: this.config.baseURL,
|
|
2765
|
-
headers: (
|
|
2821
|
+
headers: (_b = this.config.headers) != null ? _b : {},
|
|
2766
2822
|
fetch: this.config.fetch,
|
|
2767
|
-
generateId: (
|
|
2823
|
+
generateId: (_c = this.config.generateId) != null ? _c : import_provider_utils14.generateId
|
|
2768
2824
|
});
|
|
2769
2825
|
const result = await languageModel.doGenerate({
|
|
2770
2826
|
prompt: languageModelPrompt,
|
|
@@ -2775,9 +2831,17 @@ var GoogleGenerativeAIImageModel = class {
|
|
|
2775
2831
|
imageConfig: aspectRatio ? {
|
|
2776
2832
|
aspectRatio
|
|
2777
2833
|
} : void 0,
|
|
2778
|
-
...
|
|
2834
|
+
...passthroughGoogleOptions
|
|
2779
2835
|
}
|
|
2780
2836
|
},
|
|
2837
|
+
tools: (googleImageOptions == null ? void 0 : googleImageOptions.googleSearch) != null ? [
|
|
2838
|
+
{
|
|
2839
|
+
type: "provider",
|
|
2840
|
+
id: "google.google_search",
|
|
2841
|
+
name: "google_search",
|
|
2842
|
+
args: googleImageOptions.googleSearch
|
|
2843
|
+
}
|
|
2844
|
+
] : void 0,
|
|
2781
2845
|
headers,
|
|
2782
2846
|
abortSignal
|
|
2783
2847
|
});
|
|
@@ -2788,23 +2852,25 @@ var GoogleGenerativeAIImageModel = class {
|
|
|
2788
2852
|
images.push((0, import_provider_utils14.convertToBase64)(part.data));
|
|
2789
2853
|
}
|
|
2790
2854
|
}
|
|
2855
|
+
const languageModelGoogleMetadata = (_h = (_g = result.providerMetadata) == null ? void 0 : _g.google) != null ? _h : {};
|
|
2791
2856
|
return {
|
|
2792
2857
|
images,
|
|
2793
2858
|
warnings,
|
|
2794
2859
|
providerMetadata: {
|
|
2795
2860
|
google: {
|
|
2861
|
+
...languageModelGoogleMetadata,
|
|
2796
2862
|
images: images.map(() => ({}))
|
|
2797
2863
|
}
|
|
2798
2864
|
},
|
|
2799
2865
|
response: {
|
|
2800
2866
|
timestamp: currentDate,
|
|
2801
2867
|
modelId: this.modelId,
|
|
2802
|
-
headers: (
|
|
2868
|
+
headers: (_i = result.response) == null ? void 0 : _i.headers
|
|
2803
2869
|
},
|
|
2804
2870
|
usage: result.usage ? {
|
|
2805
2871
|
inputTokens: result.usage.inputTokens.total,
|
|
2806
2872
|
outputTokens: result.usage.outputTokens.total,
|
|
2807
|
-
totalTokens: ((
|
|
2873
|
+
totalTokens: ((_j = result.usage.inputTokens.total) != null ? _j : 0) + ((_k = result.usage.outputTokens.total) != null ? _k : 0)
|
|
2808
2874
|
} : void 0
|
|
2809
2875
|
};
|
|
2810
2876
|
}
|
|
@@ -2823,7 +2889,17 @@ var googleImageModelOptionsSchema = (0, import_provider_utils14.lazySchema)(
|
|
|
2823
2889
|
() => (0, import_provider_utils14.zodSchema)(
|
|
2824
2890
|
import_v413.z.object({
|
|
2825
2891
|
personGeneration: import_v413.z.enum(["dont_allow", "allow_adult", "allow_all"]).nullish(),
|
|
2826
|
-
aspectRatio: import_v413.z.enum(["1:1", "3:4", "4:3", "9:16", "16:9"]).nullish()
|
|
2892
|
+
aspectRatio: import_v413.z.enum(["1:1", "3:4", "4:3", "9:16", "16:9"]).nullish(),
|
|
2893
|
+
/**
|
|
2894
|
+
* Enable Google Search grounding for Gemini image models. The value is
|
|
2895
|
+
* forwarded as the args of the `google.tools.googleSearch` provider
|
|
2896
|
+
* tool on the underlying language-model call. Pass `{}` for defaults.
|
|
2897
|
+
*
|
|
2898
|
+
* `generateImage` does not accept a `tools` parameter, so this is the
|
|
2899
|
+
* dedicated escape hatch for grounding image generation the same way
|
|
2900
|
+
* `generateText` does.
|
|
2901
|
+
*/
|
|
2902
|
+
googleSearch: googleSearchToolArgsBaseSchema.optional()
|
|
2827
2903
|
})
|
|
2828
2904
|
)
|
|
2829
2905
|
);
|