diff --git a/packages/ai/src/generate-text/parse-tool-call.ts b/packages/ai/src/generate-text/parse-tool-call.ts index 0525b65f1a4e..4e7be5b59893 100644 --- a/packages/ai/src/generate-text/parse-tool-call.ts +++ b/packages/ai/src/generate-text/parse-tool-call.ts @@ -8,7 +8,7 @@ import { import { InvalidToolInputError } from '../error/invalid-tool-input-error'; import { NoSuchToolError } from '../error/no-such-tool-error'; import { ToolCallRepairError } from '../error/tool-call-repair-error'; -import { TypedToolCall } from './tool-call'; +import { DynamicToolCall, TypedToolCall } from './tool-call'; import { ToolCallRepairFunction } from './tool-call-repair-function'; import { ToolSet } from './tool-set'; @@ -27,6 +27,11 @@ export async function parseToolCall({ }): Promise> { try { if (tools == null) { + // provider-executed dynamic tools are not part of our list of tools: + if (toolCall.providerExecuted && toolCall.dynamic) { + return await parseProviderExecutedDynamicToolCall(toolCall); + } + throw new NoSuchToolError({ toolName: toolCall.toolName }); } @@ -90,6 +95,33 @@ export async function parseToolCall({ } } +async function parseProviderExecutedDynamicToolCall( + toolCall: LanguageModelV2ToolCall, +): Promise { + const parseResult = + toolCall.input.trim() === '' + ? { success: true as const, value: {} } + : await safeParseJSON({ text: toolCall.input }); + + if (parseResult.success === false) { + throw new InvalidToolInputError({ + toolName: toolCall.toolName, + toolInput: toolCall.input, + cause: parseResult.error, + }); + } + + return { + type: 'tool-call', + toolCallId: toolCall.toolCallId, + toolName: toolCall.toolName, + input: parseResult.value, + providerExecuted: true, + dynamic: true, + providerMetadata: toolCall.providerMetadata, + }; +} + async function doParseToolCall({ toolCall, tools, @@ -102,6 +134,11 @@ async function doParseToolCall({ const tool = tools[toolName]; if (tool == null) { + // provider-executed dynamic tools are not part of our list of tools: + if (toolCall.providerExecuted && toolCall.dynamic) { + return await parseProviderExecutedDynamicToolCall(toolCall); + } + throw new NoSuchToolError({ toolName: toolCall.toolName, availableTools: Object.keys(tools),