Skip to content

Guard empty Bedrock Converse tool results against empty text blocks - #55093

Open
MaxFreedomPollard wants to merge 1 commit into
NousResearch:mainfrom
MaxFreedomPollard:fix/bedrock-empty-tool-result
Open

Guard empty Bedrock Converse tool results against empty text blocks#55093
MaxFreedomPollard wants to merge 1 commit into
NousResearch:mainfrom
MaxFreedomPollard:fix/bedrock-empty-tool-result

Conversation

@MaxFreedomPollard

Copy link
Copy Markdown
Contributor

Fixes #55092

convert_messages_to_converse built the toolResult text block directly from the raw tool content with no empty-content guard:

result_content = content if isinstance(content, str) else json.dumps(content)
tool_result_block = {"toolResult": {"toolUseId": ..., "content": [{"text": result_content}]}}

When a tool returns an empty string, this is a {"text": ""} block. Bedrock Converse rejects empty text blocks (ValidationException: ... text content blocks must be non-empty). Because the block is part of the persisted history, every replay and retry fails identically, wedging the conversation.

_convert_content_to_converse already guards this for user and assistant content (issue #9486), but the tool-result branch does not go through that helper and was left unguarded.

Change

  • Substitute the same non-empty placeholder the user/assistant path uses when the serialized tool result is empty or whitespace-only.

Test

test_empty_tool_result_gets_placeholder converts a tool message with empty content and asserts the resulting toolResult text block is non-empty. It fails on the current code (the block is {"text": ""}) and passes with this change. The rest of tests/agent/test_bedrock_adapter.py continues to pass.

$ python -m pytest tests/agent/test_bedrock_adapter.py -q
133 passed

@alt-glitch alt-glitch added type/bug Something isn't working comp/agent Core agent runtime: loop, agent_init, prompt builder, context-compression, responses endpoint provider/bedrock AWS Bedrock (boto3, IAM) P3 Low — cosmetic, nice to have labels Jun 29, 2026
@Morad37

Morad37 commented Jun 29, 2026

Copy link
Copy Markdown
Contributor

Clean fix. Empty text blocks are a known Bedrock Converse constraint -- the existing _convert_content_to_converse guard (issue #9486) covers user/assistant content but missed the tool result path. This closes the gap.

One note: result_content = " " (space) is what the existing user/assistant guard uses too -- consistent and avoids the 400 without changing visible behavior since whitespace gets dropped downstream anyway.

@teknium1

Copy link
Copy Markdown
Contributor

Thanks for the focused Bedrock fix. The premise remains valid on current main: agent/bedrock_adapter.py:586-590 serializes an empty string unchanged into a Converse toolResult text block. The proposed guard matches the established whitespace-placeholder behavior in _convert_content_to_converse at agent/bedrock_adapter.py:504-507.

The regression test is targeted and exercises the affected converter path. The current-main file blobs equal the PR diff preimages, so this should be salvageable as a clean cherry-pick.

Automated hermes-sweeper review.

@teknium1 teknium1 added sweeper:risk-compatibility Sweeper risk: may break existing users, config, migrations, defaults, or upgrades sweeper:blast-contained Sweeper blast radius: contained — one narrow path / opt-in / few users labels Jul 15, 2026
@MaxFreedomPollard
MaxFreedomPollard force-pushed the fix/bedrock-empty-tool-result branch 3 times, most recently from d45a11c to 59d8596 Compare July 31, 2026 03:57
convert_messages_to_converse built the toolResult text block straight from
the raw tool content, with no empty-content guard. A tool returning an empty
string produced a {"text": ""} block, which Bedrock Converse rejects with
"text content blocks must be non-empty". The empty block is baked into the
persisted history, so every replay and retry 400s identically and the
conversation wedges.

Apply the same empty-content substitution the user/assistant path already
uses in _convert_content_to_converse (issue NousResearch#9486) to the tool-result text.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

comp/agent Core agent runtime: loop, agent_init, prompt builder, context-compression, responses endpoint P3 Low — cosmetic, nice to have provider/bedrock AWS Bedrock (boto3, IAM) sweeper:blast-contained Sweeper blast radius: contained — one narrow path / opt-in / few users sweeper:risk-compatibility Sweeper risk: may break existing users, config, migrations, defaults, or upgrades type/bug Something isn't working

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Bedrock Converse: empty tool result produces an empty text block and 400s the request

4 participants