feat(provider/google): support combining built-in tools with function calling on Gemini 3#13920
Conversation
… calling on Gemini 3 Gemini 3 models now support combining built-in tools (Google Search, Google Maps, URL Context, etc.) with custom function calling in a single API request via the tool combination API. Previously, prepareTools treated provider-defined tools and function tools as mutually exclusive — when both were present, it emitted an "unsupported" warning and dropped all function declarations, sending only the provider tools. This caused models to emit function calls as inline JSON text since no function declarations were registered. Changes: - Merge provider tools and functionDeclarations into the same tools array when both are present on Gemini 3+ models - Set includeServerSideToolInvocations: true in toolConfig to enable server-side tool context circulation - Use VALIDATED function calling mode (required by the tool combination API) - Parse toolCall/toolResponse parts from the API response as provider-executed tool calls/results - Serialize them back correctly in subsequent turns to maintain cross-tool context circulation - For older models (Gemini 2.x and below), preserve existing behavior Ref: https://ai.google.dev/gemini-api/docs/tool-combination Made-with: Cursor
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: e42c6dcb4f
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| } else if ('toolCall' in part && part.toolCall) { | ||
| const toolCallId = part.toolCall.id ?? this.config.generateId(); |
There was a problem hiding this comment.
Parse toolCall/toolResponse in response schema
The new handling for part.toolCall/part.toolResponse in doGenerate and doStream is effectively unreachable because responseSchema/chunkSchema still parse content.parts with getContentSchema(), which only models functionCall, inlineData, and executable/text fields. With Zod object parsing, unknown keys are stripped, so Gemini tool-combination parts are reduced before this branch and server-side tool invocations/results are silently dropped, breaking multi-turn context circulation for combined tools.
Useful? React with 👍 / 👎.
| const partProviderOpts = | ||
| part.providerMetadata?.[providerOptionsName] ?? | ||
| (providerOptionsName !== 'google' |
There was a problem hiding this comment.
Read provider options from tool parts, not providerMetadata
In the role: 'tool' conversion path, this reads part.providerMetadata, but prompt tool parts carry provider data under providerOptions (including when produced by toResponseMessages/convertToLanguageModelPrompt). That means serverToolCallId/serverToolType are never recovered, so provider-executed server tool results are serialized as generic function responses instead of toolResponse, which loses the tool-combination state on the next Gemini turn.
Useful? React with 👍 / 👎.
VALIDATED mode rejects anyOf schemas in function parameters, which breaks tools using discriminated unions. The Gemini API docs say "default to VALIDATED" but omitting functionCallingConfig works and lets the API handle mode selection internally. Made-with: Cursor
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: e554ab5934
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| } | ||
| }); | ||
|
|
||
| if (hasFunctionTools && isGemini3orNewer && googleTools.length > 0) { |
There was a problem hiding this comment.
Keep function declarations when provider tools are filtered out
This branch only combines function declarations when googleTools.length > 0, so on Gemini 3 a request that includes valid function tools plus only unsupported/typoed provider tools falls through and returns without any functionDeclarations. In that case the warning reports unsupported provider tools, but function calling is silently disabled even though the function tools are valid.
Useful? React with 👍 / 👎.
| if (serverToolCallId && serverToolType) { | ||
| return { | ||
| toolCall: { | ||
| toolType: serverToolType, |
There was a problem hiding this comment.
Avoid hard-failing on non-JSON server tool-call input
The server-tool replay path unconditionally calls JSON.parse on part.input when it is a string. If persisted or user-supplied prompt history contains a non-JSON string, prompt conversion throws before the API call and the entire request fails. This path should parse defensively (or fall back) instead of crashing on malformed input.
Useful? React with 👍 / 👎.
| serverToolCallId: part.toolCall.id, | ||
| serverToolType: part.toolCall.toolType, |
There was a problem hiding this comment.
Persist fallback server tool IDs into provider metadata
When a server toolCall arrives without an id, this code generates a fallback toolCallId for emitted content but still stores serverToolCallId: part.toolCall.id (undefined) in provider metadata. On the next turn, server-tool replay requires both serverToolType and serverToolCallId, so these calls/responses are downgraded and lose server-side tool-context linkage.
Useful? React with 👍 / 👎.
…ol call annotations
felixarntz
left a comment
There was a problem hiding this comment.
@edwardwc Thank you for the PR! This was looking good for starters, however we needed some examples to verify the behavior, so I added them. From there, I ran into a few follow up issues, which should be addressed now.
|
|
|
🚀 Published in:
|
…h function calling on Gemini 3 (#13993) This is an automated backport of #13920 to the release-v6.0 branch. FYI @edwardwc ~~This backport has conflicts that need to be resolved manually.~~ Conflicts resolved. ### `git cherry-pick` output ``` Auto-merging packages/google/src/convert-to-google-generative-ai-messages.test.ts Auto-merging packages/google/src/convert-to-google-generative-ai-messages.ts Auto-merging packages/google/src/google-generative-ai-language-model.test.ts Auto-merging packages/google/src/google-generative-ai-language-model.ts CONFLICT (content): Merge conflict in packages/google/src/google-generative-ai-language-model.ts Auto-merging packages/google/src/google-prepare-tools.test.ts Auto-merging packages/google/src/google-prepare-tools.ts error: could not apply 01fa606... feat(provider/google): support combining built-in tools with function calling on Gemini 3 (#13920) hint: After resolving the conflicts, mark them with hint: "git add/rm <pathspec>", then run hint: "git cherry-pick --continue". hint: You can instead skip this commit with "git cherry-pick --skip". hint: To abort and get back to the state before "git cherry-pick", hint: run "git cherry-pick --abort". hint: Disable this message with "git config set advice.mergeConflict false" ``` --------- Co-authored-by: edwardwc <edwardwc@protonmail.com> Co-authored-by: Felix Arntz <felix.arntz@vercel.com>
Summary
Gemini 3 models now support combining built-in tools (Google Search, Google Maps, URL Context, etc.) with custom function calling in a single API request via the tool combination API (announced March 17, 2026).
Previously,
prepareToolstreated provider-defined tools and function tools as mutually exclusive — when both were present, it emitted an "unsupported" warning and dropped all function declarations, sending only the provider tools. This caused models to emit function calls as inline JSON text since no function declarations were registered.This PR enables tool combination for Gemini 3+ models by:
functionDeclarationsinto the sametoolsarray when both are present on Gemini 3+ modelsincludeServerSideToolInvocations: trueintoolConfigto enable server-side tool context circulationVALIDATEDfunction calling mode (required by the tool combination API)toolCall/toolResponseparts from the API response as provider-executed tool calls/resultsFor older models (Gemini 2.x and below), the existing behavior is preserved — a warning is emitted and only provider tools are sent.
Test plan
prepareToolstests updated for new merge behavior on Gemini 3+[{ googleSearch: {} }, { functionDeclarations: [...] }]gemini-3-flash-previewtoolCall/toolResponseparts are preserved across multi-turn conversationsMade with Cursor