From ee12352b62c23d09786edfa6a3e0f3915abd5891 Mon Sep 17 00:00:00 2001 From: Evan Mattson Date: Thu, 26 Feb 2026 09:11:26 +0900 Subject: [PATCH] Fix AgentResponse.value being None when streaming with default_options response_format (#3970) The streaming finalizer was using the raw `options` parameter from `run()` instead of the merged `chat_options` that include `default_options`. When `response_format` was set via `default_options` and not passed explicitly in the `run()` call, the finalizer received None and could not parse the value. Changed the finalizer to read from `ctx_holder` which contains the merged options (including default_options) after stream initialization. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- .../packages/core/agent_framework/_agents.py | 9 +++++-- .../packages/core/tests/core/test_agents.py | 26 +++++++++++++++++++ 2 files changed, 33 insertions(+), 2 deletions(-) diff --git a/python/packages/core/agent_framework/_agents.py b/python/packages/core/agent_framework/_agents.py index a3f4570b6e..afd3030f76 100644 --- a/python/packages/core/agent_framework/_agents.py +++ b/python/packages/core/agent_framework/_agents.py @@ -943,8 +943,13 @@ def _propagate_conversation_id(update: AgentResponseUpdate) -> AgentResponseUpda map_chat_to_agent_update, agent_name=self.name, ), - finalizer=partial( - self._finalize_response_updates, response_format=options.get("response_format") if options else None + finalizer=lambda updates: self._finalize_response_updates( + updates, + response_format=( + ctx_holder["ctx"]["chat_options"].get("response_format") + if ctx_holder["ctx"] + else (options.get("response_format") if options else None) + ), ), ) .with_transform_hook(_propagate_conversation_id) diff --git a/python/packages/core/tests/core/test_agents.py b/python/packages/core/tests/core/test_agents.py index 627987a1f2..e49666b5eb 100644 --- a/python/packages/core/tests/core/test_agents.py +++ b/python/packages/core/tests/core/test_agents.py @@ -97,6 +97,32 @@ async def test_chat_client_agent_run_streaming(client: SupportsChatGetResponse) assert result.text == "test streaming response another update" +async def test_chat_client_agent_run_streaming_with_default_response_format(client: SupportsChatGetResponse) -> None: + """Test that response_format set via default_options produces a parsed value when streaming.""" + from pydantic import BaseModel + + class Greeting(BaseModel): + greeting: str + + # Configure streaming responses to return valid JSON for the model + client.streaming_responses = [ # type: ignore[attr-defined] + [ + ChatResponseUpdate(contents=[Content.from_text('{"greeting": "Hello"}')], role="assistant"), + ] + ] + + agent = Agent(client=client, default_options={"response_format": Greeting}) + stream = agent.run("Hello", stream=True) + async for _ in stream: + pass + result = await stream.get_final_response() + + assert result.text == '{"greeting": "Hello"}' + assert result.value is not None + assert isinstance(result.value, Greeting) + assert result.value.greeting == "Hello" + + async def test_chat_client_agent_create_session(client: SupportsChatGetResponse) -> None: agent = Agent(client=client) session = agent.create_session()