Skip to content

Python: fix(anthropic): set role='assistant' on message_start streaming update#4329

Open
leelakarthik wants to merge 2 commits intomicrosoft:mainfrom
leelakarthik:fix-anthropic-tool-use-error
Open

Python: fix(anthropic): set role='assistant' on message_start streaming update#4329
leelakarthik wants to merge 2 commits intomicrosoft:mainfrom
leelakarthik:fix-anthropic-tool-use-error

Conversation

@leelakarthik
Copy link

@leelakarthik leelakarthik commented Feb 26, 2026

Motivation and Context

Fixes #4328

When an AnthropicClient agent makes consecutive tool calls in streaming mode,
the Anthropic API rejects the request with HTTP 400:

messages.N: tool_use blocks can only be in assistant messages

This was observed when a tool call fails and the agent retries with corrected
arguments — two sequential streaming iterations. The non-streaming path was
unaffected.

Description

_process_stream_event in AnthropicClient did not set role on the
ChatResponseUpdate emitted for message_start events. _process_update
in _types.py only starts a new Message when update.role is truthy and
differs from the last message's role:

# agent_framework/_types.py
if (update.role and response.messages[-1].role != update.role):
    is_new_message = True

With role=None, this condition was never triggered by a role change. After
iteration 1 ended with a role="tool" message (injected by the tool layer),
iteration 2's tool_use content was appended to that same message instead of
starting a new assistant message. Serialisation then mapped role="tool"
"user" via ROLE_MAP, producing a user message containing both
tool_result and tool_use blocks — which Anthropic rejects.

The fix is a one-line change adding role="assistant" to the message_start
case, aligning it with the non-streaming path (_process_message) which already
hardcodes Message(role="assistant", ...) directly:

# agent_framework_anthropic/_chat_client.py
case "message_start":
    return ChatResponseUpdate(
        role="assistant",   # ← added; aligns with _process_message
        response_id=event.message.id,
        ...
    )

BetaMessage.role is typed as Literal["assistant"] in the Anthropic SDK so
this is always correct.

Contribution Checklist

  • The code builds clean without any errors or warnings
  • The PR follows the Contribution Guidelines
  • All unit tests pass, and I have added new tests where possible
  • Is this a breaking change? If yes, add "[BREAKING]" prefix to the title of the PR.

@github-actions github-actions bot changed the title fix(anthropic): set role='assistant' on message_start streaming update Python: fix(anthropic): set role='assistant' on message_start streaming update Feb 26, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Python: [Bug]: Anthropic Streaming agent fails with HTTP 400 on consecutive tool calls: tool_use blocks can only be in assistant messages

2 participants