Skip to content

Tool inputs lost during streaming with Vertex AI integration (beta messages) #1020

@matthicksj

Description

@matthicksj

Description

When using Claude models through Anthropic's Vertex AI integration with the beta messages API and streaming enabled, tool input parameters are not populated correctly. The SDK returns a plain Stream object instead of BetaMessageStreamManager, which bypasses the event accumulation logic entirely. This causes all tool calls to fail with validation errors.

Environment

  • Library: anthropic[vertex] v0.64.0
  • Python: 3.8+
  • Vertex AI Region: us-east5 (or any region)
  • Models affected: All Claude models via Vertex (e.g., claude-3-5-sonnet@20240620)

Steps to Reproduce

from anthropic import AnthropicVertex

# Initialize client
client = AnthropicVertex(
    project_id="your-project",  # Replace with your GCP project ID
    region="us-east5"
)

# Define a tool
tools = [{
    "name": "get_weather",
    "description": "Get the current weather for a location",
    "input_schema": {
        "type": "object",
        "properties": {
            "location": {
                "type": "string",
                "description": "The city to get weather for"
            }
        },
        "required": ["location"]
    }
}]

# This fails - tool inputs are empty
response = client.beta.messages.create(
    model="claude-3-5-sonnet@20240620",
    max_tokens=1024,
    messages=[{"role": "user", "content": "What's the weather in Paris?"}],
    tools=tools,
    stream=True  # Issue only occurs with streaming
)

# Process the stream
for event in response:
    if hasattr(event, 'type') and event.type == 'content_block_start':
        if hasattr(event, 'content_block'):
            if event.content_block.type == 'tool_use':
                print(f"Tool: {event.content_block.name}")
                print(f"Input: {event.content_block.input}")  # Will be {} instead of {"location": "Paris"}

Expected Behavior

Tool inputs should be properly populated from the input_json_delta events:

# Expected
{"location": "Paris"}

Actual Behavior

Tool inputs remain empty:

# Actual
{}

This causes validation errors:

Input validation error: 'location' is a required property

Root Cause Analysis

The issue is in /src/anthropic/lib/vertex/_beta_messages.py:

  1. The Vertex beta messages implementation delegates directly to FirstPartyMessagesAPI.create
  2. This returns a plain Stream object instead of BetaMessageStream with accumulation logic
  3. The accumulation logic in BetaMessageStream is never reached
  4. Vertex DOES send proper input_json_delta events, but they're not accumulated

Debug output showing the issue:

# With current implementation
type(client.beta.messages.create(..., stream=True))
# <class 'anthropic._streaming.Stream'>  ❌ Wrong!

# Should be wrapped in BetaMessageStreamManager
# which returns BetaMessageStream that accumulates deltas

Impact

  • Severity: High - Makes streaming completely unusable with tools in Vertex AI beta API
  • Scope: All Vertex AI users using beta messages with tools and streaming
  • Workaround: Disable streaming (stream=False) but loses streaming benefits

Workaround

Use non-streaming mode (but this limits the thinking budget to 4096 in Opus 4):

response = client.beta.messages.create(
    # ... same parameters ...
    stream=False  # Works correctly without streaming
)

Solution Implemented

The Vertex beta messages implementation now properly wraps streaming responses:

Changes Made

  1. create() method: When stream=True, wraps the raw Stream in BetaMessageStream
  2. stream() method: Returns BetaMessageStreamManager as expected
  3. Async versions: Same fixes applied to AsyncMessages
# In /src/anthropic/lib/vertex/_beta_messages.py
if stream is True:
    raw_stream = FirstPartyMessagesAPI.create(..., stream=True)
    # Wrap in BetaMessageStream for accumulation
    return BetaMessageStream(raw_stream)

Additional Context

  • The regular (non-beta) Vertex messages API has a similar issue
  • Vertex correctly sends input_json_delta events - they're just not being processed
  • The accumulation logic exists and works, it's just not being used due to wrong stream class
  • Issue confirmed with extensive testing and debugging

Related Issues

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions