Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .changeset/bright-needles-talk.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@ai-sdk/google': patch
---

Add code execution provider defined tool
20 changes: 20 additions & 0 deletions content/providers/01-ai-sdk-providers/15-google-generative-ai.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -340,6 +340,26 @@ const { text: meatLasangaRecipe } = await generateText({
});
```

### Code Execution

With [Code Execution](https://ai.google.dev/gemini-api/docs/code-execution), certain models can generate and execute Python code to perform calculations, solve problems, or provide more accurate information.

You can enable code execution by adding the `code_execution` tool to your request.

```ts
import { google } from '@ai-sdk/google';
import { googleTools } from '@ai-sdk/google/internal';
import { generateText } from 'ai';

const { text, toolCalls, toolResults } = await generateText({
model: google('gemini-2.5-pro'),
tools: { code_execution: google.tools.codeExecution({}) },
prompt: 'Use python to calculate the 20th fibonacci number.',
});
```

The response will contain the tool calls and results from the code execution.

### Google Search

With [search grounding](https://ai.google.dev/gemini-api/docs/google-search),
Expand Down
21 changes: 21 additions & 0 deletions content/providers/01-ai-sdk-providers/16-google-vertex.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -326,6 +326,27 @@ const { text } = await generateText({
Google Vertex language models can also be used in the `streamText` function
(see [AI SDK Core](/docs/ai-sdk-core)).

#### Code Execution

With [Code Execution](https://cloud.google.com/vertex-ai/generative-ai/docs/multimodal/code-execution), certain Gemini models on Vertex AI can generate and execute Python code. This allows the model to perform calculations, data manipulation, and other programmatic tasks to enhance its responses.

You can enable code execution by adding the `code_execution` tool to your request.

```ts
import { vertex } from '@ai-sdk/google-vertex';
import { googleTools } from '@ai-sdk/google/internal';
import { generateText } from 'ai';

const result = await generateText({
model: vertex('gemini-2.5-pro'),
tools: { code_execution: googleTools.codeExecution({}) },
prompt:
'Use python to calculate 20th fibonacci number. Then find the nearest palindrome to it.',
});
```

The response will contain `tool-call` and `tool-result` parts for the executed code.

#### Reasoning (Thinking Tokens)

Google Vertex AI, through its support for Gemini models, can also emit "thinking" tokens, representing the model's reasoning process. The AI SDK exposes these as reasoning information.
Expand Down
18 changes: 18 additions & 0 deletions examples/ai-core/src/generate-text/google-vertex-code-execution.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import { vertex } from '@ai-sdk/google-vertex';
import { googleTools } from '@ai-sdk/google/internal';
import { generateText } from 'ai';
import 'dotenv/config';

async function main() {
const result = await generateText({
model: vertex('gemini-2.5-pro'),
tools: { code_execution: googleTools.codeExecution({}) },
maxOutputTokens: 2048,
prompt:
'Use python to calculate 20th fibonacci number. Then find the nearest palindrome to it.',
});

console.log(JSON.stringify(result, null, 2));
}

main().catch(console.error);
71 changes: 71 additions & 0 deletions examples/ai-core/src/stream-text/google-vertex-code-execution.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
import { vertex } from '@ai-sdk/google-vertex';
import { googleTools } from '@ai-sdk/google/internal';
import { ModelMessage, streamText, ToolCallPart, ToolResultPart } from 'ai';
import 'dotenv/config';
import * as process from 'process';

const messages: ModelMessage[] = [];
async function main() {
let toolResponseAvailable = false;

const result = streamText({
model: vertex('gemini-2.5-pro'),
tools: { code_execution: googleTools.codeExecution({}) },
maxOutputTokens: 10000,
prompt:
'Calculate 20th fibonacci number. Then find the nearest palindrome to it.',
});

let fullResponse = '';
const toolCalls: ToolCallPart[] = [];
const toolResponses: ToolResultPart[] = [];

for await (const delta of result.fullStream) {
switch (delta.type) {
case 'text-delta': {
fullResponse += delta.text;
process.stdout.write(delta.text);
break;
}

case 'tool-call': {
toolCalls.push(delta);

process.stdout.write(
`\nTool call: '${delta.toolName}' ${JSON.stringify(delta.input)}`,
);
break;
}

case 'tool-result': {
const transformedDelta: ToolResultPart = {
...delta,
output: { type: 'json', value: delta.output as any },
};
toolResponses.push(transformedDelta);

process.stdout.write(
`\nTool response: '${delta.toolName}' ${JSON.stringify(
delta.output,
)}`,
);
break;
}
}
}
process.stdout.write('\n\n');

messages.push({
role: 'assistant',
content: [{ type: 'text', text: fullResponse }, ...toolCalls],
});

if (toolResponses.length > 0) {
messages.push({ role: 'tool', content: toolResponses });
}

toolResponseAvailable = toolCalls.length > 0;
console.log('Messages:', messages[0].content);
}

main().catch(console.error);
141 changes: 140 additions & 1 deletion packages/google/src/google-generative-ai-language-model.test.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,7 @@
import { LanguageModelV2Prompt } from '@ai-sdk/provider';
import {
LanguageModelV2Prompt,
LanguageModelV2ProviderDefinedTool,
} from '@ai-sdk/provider';
import {
convertReadableStreamToArray,
createTestServer,
Expand Down Expand Up @@ -985,6 +988,67 @@ describe('doGenerate', () => {
});
});

it('should handle code execution tool calls', async () => {
server.urls[TEST_URL_GEMINI_2_0_PRO].response = {
type: 'json-value',
body: {
candidates: [
{
content: {
parts: [
{
executableCode: {
language: 'PYTHON',
code: 'print(1+1)',
},
},
{
codeExecutionResult: {
outcome: 'OUTCOME_OK',
output: '2',
},
},
],
role: 'model',
},
finishReason: 'STOP',
},
],
},
};

const model = provider.languageModel('gemini-2.0-pro');
const { content } = await model.doGenerate({
tools: [
provider.tools.codeExecution({}) as LanguageModelV2ProviderDefinedTool,
],
prompt: TEST_PROMPT,
});

const requestBody = await server.calls[0].requestBodyJson;
expect(requestBody.tools).toEqual({ codeExecution: {} });

expect(content).toEqual([
{
type: 'tool-call',
toolCallId: 'test-id',
toolName: 'code_execution',
input: '{"language":"PYTHON","code":"print(1+1)"}',
providerExecuted: true,
},
{
type: 'tool-result',
toolCallId: 'test-id',
toolName: 'code_execution',
result: {
outcome: 'OUTCOME_OK',
output: '2',
},
providerExecuted: true,
},
]);
});

describe('search tool selection', () => {
const provider = createGoogleGenerativeAI({
apiKey: 'test-api-key',
Expand Down Expand Up @@ -1774,6 +1838,81 @@ describe('doStream', () => {
]);
});

it('should stream code execution tool calls and results', async () => {
server.urls[TEST_URL_GEMINI_2_0_PRO].response = {
type: 'stream-chunks',
chunks: [
`data: ${JSON.stringify({
candidates: [
{
content: {
parts: [
{
executableCode: {
language: 'PYTHON',
code: 'print("hello")',
},
},
],
},
},
],
})}\n\n`,
`data: ${JSON.stringify({
candidates: [
{
content: {
parts: [
{
codeExecutionResult: {
outcome: 'OUTCOME_OK',
output: 'hello\n',
},
},
],
},
finishReason: 'STOP',
},
],
})}\n\n`,
],
};

const model = provider.languageModel('gemini-2.0-pro');
const { stream } = await model.doStream({
tools: [
provider.tools.codeExecution({}) as LanguageModelV2ProviderDefinedTool,
],
prompt: TEST_PROMPT,
});

const events = await convertReadableStreamToArray(stream);

const toolEvents = events.filter(
e => e.type === 'tool-call' || e.type === 'tool-result',
);

expect(toolEvents).toEqual([
{
type: 'tool-call',
toolCallId: 'test-id',
toolName: 'code_execution',
input: '{"language":"PYTHON","code":"print(\\"hello\\")"}',
providerExecuted: true,
},
{
type: 'tool-result',
toolCallId: 'test-id',
toolName: 'code_execution',
result: {
outcome: 'OUTCOME_OK',
output: 'hello\n',
},
providerExecuted: true,
},
]);
});

describe('search tool selection', () => {
const provider = createGoogleGenerativeAI({
apiKey: 'test-api-key',
Expand Down
Loading
Loading