Skip to content

Fix for Bedrock Parallel Tool Call User message issue for certain models #1656

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 8 commits into
base: main
Choose a base branch
from

Conversation

pandersen-uncharted
Copy link
Contributor

Please see the comments on PR #1600 and #1645. This PR is based on seanw7:bedrock_multi_tool_support with DouweM's requested changes.

seanw7 and others added 7 commits May 6, 2025 09:28
…o a single user message for Bedrock models. NOTE: Was previously breaking when the LLM was attempting to call multiple tools in one request, because the code was appending multiple user messages in a row. Which breaks the subsequent user/assistant messages required for nova and claude
@DouweM DouweM changed the title Corrected version of PR #1600 Fix for Bedrock Parallel Tool Call User message issue for certain models May 8, 2025
Copy link
Contributor

@DouweM DouweM left a comment

Choose a reason for hiding this comment

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

@pandersen-uncharted Thanks Paul for picking up the older PR! We're almost there, just a couple of nitpicky notes on the new code.

last_message is None
or current_message['role'] != last_message['role']
or current_message['role'] != 'user'
): # Remove the "user" test to also allow merging sequential "assistant" messages
Copy link
Contributor

Choose a reason for hiding this comment

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

Should we also merge assistant messages? If not, can you please remove the comment? If so, the test? :)

Copy link
Contributor

Choose a reason for hiding this comment

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

I also think this code will be a little easier to follow organized like this:

for current_message in bedrock_messages:
    if last_message and ...:
        # special behavior
        continue
    
    # standard behavior

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Comment removed, code reworked.


# Merge together sequential user messages.
processed_messages: list[MessageUnionTypeDef] = []
last_message: dict[str, Any] | None = None
Copy link
Contributor

Choose a reason for hiding this comment

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

Can we type this as MessageUnionTypeDef instead of an arbitrary dict?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Not easily. When I make that change I get the error below. Attempting to fix that error leads to other errors and in the end I don't know how deep the rabbit hole will be nor how complicated the code will get. This solution keeps the code compact and reasonably easy to follow.

Could not assign item in TypedDict
  "list[ContentBlockUnionTypeDef]" is not assignable to "list[ContentBlockOutputTypeDef]"
    Type parameter "_T@list" is invariant, but "ContentBlockUnionTypeDef" is not the same as "ContentBlockOutputTypeDef"
    Consider switching from "list" to "Sequence" which is covariant

import datetime

from pydantic_ai.messages import ModelRequest, ToolReturnPart
from pydantic_ai.models.bedrock import BedrockConverseModel
Copy link
Contributor

Choose a reason for hiding this comment

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

Can we move these imports to the top of the file please?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Done

]
)
# Call the mapping function directly
_, bedrock_messages = await model._map_messages([req]) # type: ignore[reportPrivateUsage]
Copy link
Contributor

Choose a reason for hiding this comment

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

Can we add a ModelResponse and some other parts as well, to ensure this correctly affects only subsequent User parts and not anything else?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Done.

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

Successfully merging this pull request may close these issues.

3 participants