Skip to content

Bug: OpenAI models on Bedrock don't execute tools due to stopReason handling #644

@jsamuel1

Description

@jsamuel1

Bug: OpenAI models on Bedrock don't execute tools due to stopReason handling

Summary

OpenAI models on Bedrock return stopReason: "end_turn" even when making tool calls, but Strands only executes tools when stopReason: "tool_use". This causes tool calls to be displayed but never executed.

Environment

  • Strands Agents version: Latest
  • Model: openai.gpt-oss-120b-1:0 on AWS Bedrock
  • Working model: us.anthropic.claude-sonnet-4-20250514-v1:0

Reproduction Code

#!/usr/bin/env python3
import asyncio
import os
from strands import Agent
from strands.models import BedrockModel
from strands_tools.current_time import current_time

def create_agent():
    model = BedrockModel(
        model_id="openai.gpt-oss-120b-1:0",  # Broken
        # model_id="us.anthropic.claude-sonnet-4-20250514-v1:0",  # Works
        max_tokens=1000,
        temperature=0.2
    )
    
    return Agent(
        model=model,
        system_prompt="You are a helpful assistant.",
        tools=[current_time]
    )

async def test_tool_execution():
    agent = create_agent()
    async for event in agent.stream_async("what time is it?"):
        if "message" in event:
            print("Event:", event)

asyncio.run(test_tool_execution())

Expected Behavior

  1. Model makes tool call
  2. Tool is executed
  3. Tool result is returned
  4. Model generates final response

Actual Behavior

  1. Model makes tool call ✓
  2. Tool execution is skipped ❌
  3. Conversation ends without tool result

Root Cause Analysis

OpenAI Response (Broken)

{
  "output": {
    "message": {
      "content": [
        {"toolUse": {"name": "current_time", "toolUseId": "tooluse_123", "input": {}}}
      ]
    }
  },
  "stopReason": "end_turn"  // ← Problem: should trigger tool execution
}

Claude Response (Working)

{
  "output": {
    "message": {
      "content": [
        {"toolUse": {"name": "current_time", "toolUseId": "tooluse_456", "input": {}}}
      ]
    }
  },
  "stopReason": "tool_use"  // ← Correctly triggers tool execution
}

Framework Logic Issue

In strands/event_loop/event_loop.py:

# Current logic - only executes tools for "tool_use" stop reason
if stop_reason == "tool_use":
    events = _handle_tool_execution(...)
    # Execute tools and continue
else:
    # End conversation - this happens for OpenAI's "end_turn"
    return

Suggested Fix

Change the logic to check for tool calls in message content regardless of stop reason:

# Check if message contains tool calls, regardless of stop reason
has_tool_calls = any(
    "toolUse" in content_item 
    for content_item in message.get("content", [])
)

if has_tool_calls:
    events = _handle_tool_execution(...)
    # Execute tools and continue
else:
    # End conversation only if no tools to execute
    return

Impact

  • Affects all OpenAI models on Bedrock
  • Tool calls are visible but never executed
  • Breaks tool-based workflows for OpenAI models

Workaround

Use Claude models instead of OpenAI models on Bedrock.

Additional Context

This appears to be a difference in how OpenAI vs Anthropic models signal tool usage completion. The framework should handle both patterns consistently.

Metadata

Metadata

Assignees

No one assigned

    Labels

    area-providerRelated to model providers

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions