Skip to content
Merged
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
31 changes: 29 additions & 2 deletions src/strands/models/bedrock.py
Original file line number Diff line number Diff line change
Expand Up @@ -432,6 +432,8 @@ def _stream(
logger.debug("got response from model")
if streaming:
response = self.client.converse_stream(**request)
# Track tool use events to fix stopReason for streaming responses
has_tool_use = False
for chunk in response["stream"]:
if (
"metadata" in chunk
Expand All @@ -443,7 +445,24 @@ def _stream(
for event in self._generate_redaction_events():
callback(event)

callback(chunk)
# Track if we see tool use events
if "contentBlockStart" in chunk and chunk["contentBlockStart"].get("start", {}).get("toolUse"):
has_tool_use = True

# Fix stopReason for streaming responses that contain tool use
if "messageStop" in chunk and has_tool_use:
message_stop = chunk["messageStop"]
if message_stop.get("stopReason") == "end_turn":
# Create corrected chunk with tool_use stopReason
modified_chunk = chunk.copy()
modified_chunk["messageStop"] = message_stop.copy()
modified_chunk["messageStop"]["stopReason"] = "tool_use"
logger.info("Override stop reason from end_turn to tool_use")
callback(modified_chunk)
else:
callback(chunk)
else:
callback(chunk)

else:
response = self.client.converse(**request)
Expand Down Expand Up @@ -579,9 +598,17 @@ def _convert_non_streaming_to_streaming(self, response: dict[str, Any]) -> Itera
yield {"contentBlockStop": {}}

# Yield messageStop event
# Fix stopReason for models that return end_turn when they should return tool_use on non-streaming side
current_stop_reason = response["stopReason"]
if current_stop_reason == "end_turn":
message_content = response["output"]["message"]["content"]
if any("toolUse" in content for content in message_content):
current_stop_reason = "tool_use"
logger.info("Override stop reason from end_turn to tool_use")

yield {
"messageStop": {
"stopReason": response["stopReason"],
"stopReason": current_stop_reason,
"additionalModelResponseFields": response.get("additionalModelResponseFields"),
}
}
Expand Down
Loading