Skip to content

Python: [Bug]: BedrockChatClient reports the client's default model on non-streaming responses, not the model it sent the request to #9398

Description

Observed Behavior

When I pass a model per call with options={"model": ...}, BedrockChatClient sends the request to that model, but the non-streaming ChatResponse.model is the model the client was created with. If the client has no default model, response.model is None.

This also lands in telemetry, since gen_ai.response.model is read from response.model.

Streaming is fine. It reports the model the request went to.

Expected Behavior

response.model is the model the request was sent to, same as the streaming path.

Steps to Reproduce

  1. Create BedrockChatClient(model="model-a", ...).
  2. Call get_response(..., options={"model": "model-b"}) without streaming.
  3. The Converse request uses modelId="model-b", but response.model is "model-a".

Minimal Reproduction

import asyncio
from typing import Any

from agent_framework import Message
from agent_framework_bedrock import BedrockChatClient


class ConverseStub:
    """Returns the real Converse response shape. Converse does not echo the model id."""

    def __init__(self) -> None:
        self.calls: list[dict[str, Any]] = []

    def converse(self, **kwargs: Any) -> dict[str, Any]:
        self.calls.append(kwargs)
        return {
            "output": {"message": {"role": "assistant", "content": [{"text": "hi"}]}},
            "stopReason": "end_turn",
            "usage": {"inputTokens": 3, "outputTokens": 1, "totalTokens": 4},
            "metrics": {"latencyMs": 10},
        }


async def main() -> None:
    stub = ConverseStub()
    client = BedrockChatClient(model="model-a", region="us-east-1", client=stub)
    response = await client.get_response(
        [Message(role="user", contents=["hello"])],
        options={"model": "model-b"},
    )
    print("sent modelId:     ", stub.calls[-1]["modelId"])
    print("response.model:   ", response.model)

    no_default = BedrockChatClient(region="us-east-1", client=stub)
    response = await no_default.get_response(
        [Message(role="user", contents=["hello"])],
        options={"model": "model-b"},
    )
    print("no client default:", response.model)


asyncio.run(main())

Output on main (95511ff):

sent modelId:      model-b
response.model:    model-a
no client default: None

Error Messages and Stack Traces

None. The value is just wrong.

Root cause

_process_converse_response sets model = response.get("modelId") or output.get("modelId") or self.model (python/packages/bedrock/agent_framework_bedrock/_chat_client.py:769). The Converse response has no modelId field (botocore ConverseResponse members: output, stopReason, usage, metrics, additionalModelResponseFields, trace, performanceConfig, serviceTier), so it always falls back to self.model. The streaming path already passes request["modelId"] (line 408).

Package Versions

agent-framework-bedrock: 1.0.0b261008, agent-framework-core: 1.21.0 (main at 95511ff)

Python Version

Python 3.12

Operating System

macOS

Regression

Unknown

Additional Context

Same kind of issue as #9138 for Gemini streaming. The review on #9139 asked to label responses with the resolved request model rather than the client default, which is what I'd do here: pass request["modelId"] into _process_converse_response. It's a few lines plus a test, so I can open a PR.

Acknowledgements

  • I searched existing issues and did not find a duplicate.
  • I personally verified this behavior and the reproduction details are authentic.
  • I will wait for explicit maintainer agreement before starting implementation of a non-trivial change.

Activity

  1. added
    pythonUsage: [Issues, PRs], Target: Python
    triageUsage: [Issues], Target: All issues that still need to be triaged
    on Oct 14, 2026
  2. added
    reproducedUsage: [Issues], Target: all issues that can be reproduced by the triage workflow
    on Oct 14, 2026
  3. github-actions commented on Oct 14, 2026

    @github-actions
    Contributor

    🤖 Automated triage reproduction notes (agent-authored — trust but verify)

    Agent analysis

    The defect reproduces in python/packages/bedrock/agent_framework_bedrock/_chat_client.py::_inner_get_response and _process_converse_response at lines 423 and 769 when a non-streaming call overrides the client model and Converse omits modelId. Minimal repro: use a stub returning a normal Converse response without modelId, call get_response with options={"model": "model-b"} on clients configured with model-a or no default, and assert response.model equals model-b.

    • Failing test: python/packages/bedrock/tests/test_bedrock_client.py
    • Files examined: python/packages/bedrock/agent_framework_bedrock/_chat_client.py, python/packages/bedrock/tests/test_bedrock_client.py, python/packages/bedrock/pyproject.toml, python/packages/core/agent_framework/observability.py, python/packages/core/agent_framework/_agent_hooks.py
    • Tests run: test_get_response_reports_requested_model_when_converse_response_omits_model, test_stream_yields_updates_as_converse_stream_events_arrive
    • Reported version: 1.0.0b261008
    • Current version: 1.0.0b261008
  4. added
    agentsUsage: [Issues, PRs], Target: Single agent
    and removed
    triageUsage: [Issues], Target: All issues that still need to be triaged
    on Oct 14, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Labels

agentsUsage: [Issues, PRs], Target: Single agentpythonUsage: [Issues, PRs], Target: PythonreproducedUsage: [Issues], Target: all issues that can be reproduced by the triage workflow

Type

Projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions