Skip to content

fix: save intermediate tool messages to prevent missing tool_result errors#459

Open
ahmed-sekka wants to merge 1 commit into
2FastLabs:mainfrom
ahmed-sekka:fix/missing-tool-results
Open

fix: save intermediate tool messages to prevent missing tool_result errors#459
ahmed-sekka wants to merge 1 commit into
2FastLabs:mainfrom
ahmed-sekka:fix/missing-tool-results

Conversation

@ahmed-sekka

Copy link
Copy Markdown

Summary

Fixes #396

When BedrockLLMAgent uses tools, the intermediate toolUse/toolResult conversation messages were only kept in a local list and never persisted to storage. This caused subsequent requests to fail with Bedrock validation errors about missing tool_result blocks.

  • BedrockLLMAgent now collects intermediate tool messages in tool_conversation during both single and streaming responses
  • Orchestrator saves these intermediate messages to storage alongside user input and final response
  • When max_recursions is exhausted, toolUse blocks are stripped from the response to prevent saving orphaned toolUse without toolResult

Test plan

  • Added unit tests for BedrockLLMAgent tool message collection (test_bedrock_llm_agent.py)
  • Added unit tests for Orchestrator intermediate message persistence (test_orchestrator.py)
  • Manual test: verify multi-turn conversations with tool-using BedrockLLMAgent + DynamoDBStorage no longer raise ValidationException

🤖 Generated with Claude Code

…rrors (2FastLabs#396)

When BedrockLLMAgent uses tools, the intermediate toolUse/toolResult
conversation messages were only kept in a local list and never persisted
to storage. This caused subsequent requests to fail with Bedrock
validation errors about missing tool_result blocks.

Changes:
- BedrockLLMAgent now collects intermediate tool messages in
  tool_conversation during both single and streaming responses
- Orchestrator saves these intermediate messages to storage alongside
  user input and final response
- When max_recursions is exhausted, toolUse blocks are stripped from
  the response to prevent saving orphaned toolUse without toolResult
@brnaba-aws

Copy link
Copy Markdown
Collaborator

Thanks for you PR, we will review it and provide feedback. thanks

@cornelcroi

Copy link
Copy Markdown
Collaborator

Hey @ahmed-sekka, the fix solves a real problem but there are two things that need to be addressed before this can merge.

dispatch_to_agent is a public method and changing its return type from ConversationMessage | AsyncIterable[Any] to a tuple is a breaking change — any caller who has subclassed AgentSquad or called this method directly will get a silent runtime error. You need a backward-compatible approach, for example returning the tool conversation as part of the existing response object or through a separate optional channel. Second, in the streaming path tool_conversation is populated inside the stream_generator coroutine, but the orchestrator saves it before the stream is consumed, so it will always be empty at that point — the save inside process_stream is correct, the one before it is dead code and should be removed.

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.

Bug?: Missing Tool Results

3 participants