Skip to content

fix(anthropic): strip content from assistant messages with tool call for bedrock#1599

Open
Pnkcaht wants to merge 3 commits intodocker:mainfrom
Pnkcaht:fix/bedrock-validationexception-1593
Open

fix(anthropic): strip content from assistant messages with tool call for bedrock#1599
Pnkcaht wants to merge 3 commits intodocker:mainfrom
Pnkcaht:fix/bedrock-validationexception-1593

Conversation

@Pnkcaht
Copy link
Contributor

@Pnkcaht Pnkcaht commented Feb 4, 2026

What I Did

  • In pkg/model/provider/anthropic/client.go, updated the convertMessages function to strictly separate content (text) and tool_use blocks in assistant messages.
  • When msg.ToolCalls exists, we now ignore any msg.Content (text) to comply with Anthropic / AWS Bedrock strict protocol (no mixing allowed).
  • Added logging (warn/error) for:
    • Ignored content (helps debug when LLM ignores system prompt)
    • Missing tool call IDs
    • JSON unmarshal failures on tool arguments
  • Preserved thinking blocks (allowed with tool_use)
  • This fixes the ValidationException on Bedrock when using transfer_task in multi-agent setups.

Releated Issue

Closes #1593

Before & After

Before

Before (caused ValidationException on Bedrock):

{
  "role": "assistant",
  "content": "Let me proceed with analyzing the issue...",
  "tool_calls": [
    {
      "id": "tooluse_ABC123",
      "type": "function",
      "function": {
        "name": "transfer_task",
        "arguments": "{\"agent\": \"scout\", \"task\": \"Retrieve data from source A\", \"expected_output\": \"Summary of findings\"}"
      }
    },
    {
      "id": "tooluse_XYZ789",
      "type": "function",
      "function": {
        "name": "transfer_task",
        "arguments": "{\"agent\": \"coder\", \"task\": \"Analyze the implementation\", \"expected_output\": \"Technical analysis\"}"
      }
    }
  ]
}

After

After (now compliant with Anthropic/Bedrock protocol):

{
  "role": "assistant",
  "tool_calls": [
    {
      "id": "tooluse_ABC123",
      "type": "function",
      "function": {
        "name": "transfer_task",
        "arguments": "{\"agent\": \"scout\", \"task\": \"Retrieve data from source A\", \"expected_output\": \"Summary of findings\"}"
      }
    },
    {
      "id": "tooluse_XYZ789",
      "type": "function",
      "function": {
        "name": "transfer_task",
        "arguments": "{\"agent\": \"coder\", \"task\": \"Analyze the implementation\", \"expected_output\": \"Technical analysis\"}"
      }
    }
  ]
}

Diagram

sequenceDiagram
    participant Coordinator as Coordinator Agent
    participant LLM as Anthropic/Bedrock
    participant Subagents as Subagents (scout, coder)

    Note over Coordinator,Subagents: Before (broken)
    Coordinator->>LLM: Send message with text + transfer_task calls
    LLM-->>Coordinator: Returns assistant msg with content + tool_calls
    Coordinator->>Bedrock: Send conversation history
    Bedrock-->>Coordinator: ValidationException (mixing forbidden)

    Note over Coordinator,Subagents: After (fixed)
    Coordinator->>LLM: Send prompt (no text + tool calls)
    LLM-->>Coordinator: Returns assistant msg with only tool_use blocks
    Coordinator->>Subagents: Execute transfer_task
    Subagents-->>Coordinator: Return tool results
    Coordinator->>LLM: Send next turn with tool_results
    LLM-->>Coordinator: Final analysis (only content, no tool_calls)
    Coordinator->>User: Response
Loading

… for Bedrock

Signed-off-by: pnkcaht <samzoovsk19@gmail.com>
@Pnkcaht Pnkcaht requested a review from a team as a code owner February 4, 2026 18:56
@krissetto
Copy link
Contributor

/review

Copy link
Contributor

@github-actions github-actions bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Review Summary

Found 1 potential issue in the changed code related to tool call handling that could cause message sequencing problems.

Key Finding:
The new validation logic skips tool calls with missing IDs but still appends the message, which could cause mismatches between tool_use and tool_result blocks.

Note: The JSON unmarshal fallback behavior exists in both old and new code - the PR only adds logging, so that's not a new issue.

@krissetto
Copy link
Contributor

we now ignore any msg.Content

I'm not sure we should do this, maybe it'd be better to split it out into its own message before the tool calls

@Pnkcaht
Copy link
Contributor Author

Pnkcaht commented Feb 4, 2026

we now ignore any msg.Content

I'm not sure we should do this, maybe it'd be better to split it out into its own message before the tool calls

Do you want me to do it? I'll do it without a problem, it needs to be perfect :)

… in convertMessages (docker#1593)

Signed-off-by: pnkcaht <samzoovsk19@gmail.com>
… improve logging (docker#1593)

Signed-off-by: pnkcaht <samzoovsk19@gmail.com>
@Pnkcaht
Copy link
Contributor Author

Pnkcaht commented Feb 4, 2026

@krissetto Done! I implemented the split: if there's content + tool calls, I send the message first with just the text/reasoning (preserving the logic) and then only with the use of the tool.

Full history, Bedrock protocol ok. Suggestion made by the AI ​​also resolved in the other commit.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

AWS Bedrock ValidationException: Protocol violation when assistant message contains both tool_calls and content

2 participants