diff --git a/.changeset/fix-duplicate-tool-parts.md b/.changeset/fix-duplicate-tool-parts.md new file mode 100644 index 000000000000..48b1acbffec7 --- /dev/null +++ b/.changeset/fix-duplicate-tool-parts.md @@ -0,0 +1,5 @@ +--- +'ai': patch +--- + +Fixed duplicate tool parts when model calls an unavailable tool. The `tool-input-start` chunk creates a static part without a `dynamic` flag, but the subsequent `tool-input-error` chunk arrives with `dynamic: true`, causing a second `dynamic-tool` part to be created with the same `toolCallId`. This led to providers like Amazon Bedrock rejecting the message for duplicate tool use IDs. diff --git a/packages/ai/src/ui/process-ui-message-stream.ts b/packages/ai/src/ui/process-ui-message-stream.ts index be5476768cf6..dac822b877de 100644 --- a/packages/ai/src/ui/process-ui-message-stream.ts +++ b/packages/ai/src/ui/process-ui-message-stream.ts @@ -558,7 +558,12 @@ export function processUIMessageStream({ } case 'tool-input-error': { - if (chunk.dynamic) { + const partialToolCall = state.partialToolCalls[chunk.toolCallId]; + const dynamic = partialToolCall + ? partialToolCall.dynamic + : chunk.dynamic; + + if (dynamic) { updateDynamicToolPart({ toolCallId: chunk.toolCallId, toolName: chunk.toolName,