Skip to content

[Bug]: Empty Text Content Blocks Cause Errors with Anthropic API in Tool Calling #5576

@aditya-dange-cloudredux

Description

@aditya-dange-cloudredux

Description

The Vercel AI SDK generates assistant messages with empty text content blocks (e.g., {"type": "text", "text": ""}) when using tool calling with the Anthropic API (e.g., claude-3-5-sonnet-latest). This triggers the error [AI_APICallError: messages: text content blocks must be non-empty], breaking chat functionality. The Anthropic API requires non-empty text blocks, unlike other models.

Steps to Reproduce

  1. Set up a chat stream using the Vercel AI SDK and configure it to use an Anthropic Claude model (e.g., claude-3-5-sonnet-latest).
  2. Implement a function call within the chat flow that the Anthropic model can trigger mid-response.
  3. Initiate a conversation that leads the Anthropic model to invoke the defined tool.
  4. Observe the streamed response from the assistant. You will notice an assistant message containing a tool_call and a preceding or subsequent content block with {"type": "text", "text": ""}.
  5. Attempt to send the tool call result back to the Anthropic API. This action will fail with the [AI_APICallError: messages: text content blocks must be non-empty] error.

Expected Behavior

The Vercel AI SDK should automatically filter out any text content blocks with empty text values in messages being sent to the Anthropic API. This would ensure that only valid, non-empty text blocks and tool calls are included in the API request, allowing for seamless tool calling and continued chat functionality without errors.

Actual Behavior

The Vercel AI SDK includes empty text content blocks in the messages sent to the Anthropic API when a tool call is triggered mid-response. This violates the Anthropic API's requirement for non-empty text blocks, leading to the API rejecting the request and throwing the [AI_APICallError: messages: text content blocks must be non-empty] error, thus breaking the chat flow.

Additional context

import { streamText } from 'ai';
import { createAnthropic } from '@ai-sdk/anthropic';

// Configure Anthropic provider (replace with your API key)
const anthropic = createAnthropic({
  apiKey: process.env.ANTHROPIC_API_KEY || 'your-api-key-here',
});

// Define a simple tool
const tools = {
  getData: {
    description: 'Fetches data based on a query',
    parameters: {
      type: 'object',
      properties: {
        query: { type: 'string' },
      },
      required: ['query'],
    },
    execute: async ({ query }) => {
      return `Data for: ${query}`;
    },
  },
};

// Sample system prompt
const systemPrompt = 'You are a helpful assistant that can fetch data using tools.';

// Function to simulate the chat stream
async function reproduceBug() {
  try {
    // Initial messages array with a user query
    const messages = [
      {
        role: 'user',
        content: 'Tell me something and fetch data about "example"',
      },
    ];

    // Start streaming with tool calling enabled
    const result = await streamText({
      model: anthropic('claude-3-5-sonnet-latest'),
      system: systemPrompt,
      messages,
      tools,
      maxSteps: 5,
    });

    // Process the stream (simulating tool call response)
    let toolCallDetected = false;
    const updatedMessages = [...messages];

    for await (const chunk of result.fullStream) {
      if (chunk.type === 'tool-call') {
        toolCallDetected = true;
        const toolCall = chunk.args;
        const toolResult = await tools.getData.execute({ query: toolCall.query });

        // Simulate Claude's behavior: Assistant message with empty text + tool call
        updatedMessages.push({
          role: 'assistant',
          content: [
            { type: 'text', text: '' }, // Empty text block causing the bug
            {
              type: 'tool_use',
              id: chunk.toolCallId,
              name: 'getData',
              input: { query: toolCall.query },
            },
          ],
        });

        // Add tool result message
        updatedMessages.push({
          role: 'user',
          content: [
            {
              type: 'tool_result',
              tool_call_id: chunk.toolCallId,
              content: toolResult,
            },
          ],
        });

        // Attempt to continue the stream with the tool result
        const continuedResult = await streamText({
          model: anthropic('claude-3-5-sonnet-latest'),
          system: systemPrompt,
          messages: updatedMessages,
          tools,
          maxSteps: 5,
        });

        for await (const nextChunk of continuedResult.fullStream) {
          console.log(nextChunk);
        }
      }
    }

    if (!toolCallDetected) {
      console.log('No tool call occurred.');
    }
  } catch (error) {
    console.error('Error in chat stream:', error);
    // Expected output: [AI_APICallError: messages: text content blocks must be non-empty]
  }
}

// Run the reproduction
reproduceBug();

Metadata

Metadata

Labels

ai/providerrelated to a provider package. Must be assigned together with at least one `provider/*` labelbugSomething isn't working as documentedprovider/anthropicIssues related to the @ai-sdk/anthropic provider

Type

No type
No fields configured for issues without a type.

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions