mirror of
https://github.com/microsoft/agent-framework.git
synced 2026-06-16 21:04:09 +08:00
Python: Fix response_format resolution in streaming finalizer (#4291)
* Python: Fix AgentResponse.value being None when streaming workflow (#3970) The streaming path in BaseAgent.run() used the raw 'options' parameter (passed by the caller) to bind response_format into the outer stream's finalizer. When response_format was set in default_options rather than runtime options, it was missing from the finalizer and value was None. Fix: Use the merged chat_options from the run context (via ctx_holder), matching the non-streaming path which already uses ctx['chat_options']. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Address review feedback for #3970: safer ctx access, add test coverage --------- Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
This commit is contained in:
committed by
GitHub
Unverified
parent
b295a16c0e
commit
a033721ac2
@@ -935,6 +935,11 @@ class RawAgent(BaseAgent, Generic[OptionsCoT]): # type: ignore[misc]
|
||||
session.service_session_id = conv_id
|
||||
return update
|
||||
|
||||
def _finalizer(updates: Sequence[AgentResponseUpdate]) -> AgentResponse[Any]:
|
||||
ctx = ctx_holder["ctx"]
|
||||
rf = ctx.get("chat_options", {}).get("response_format") if ctx else (options.get("response_format") if options else None)
|
||||
return self._finalize_response_updates(updates, response_format=rf)
|
||||
|
||||
return (
|
||||
ResponseStream
|
||||
.from_awaitable(_get_stream())
|
||||
@@ -943,9 +948,7 @@ class RawAgent(BaseAgent, Generic[OptionsCoT]): # type: ignore[misc]
|
||||
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=_finalizer,
|
||||
)
|
||||
.with_transform_hook(_propagate_conversation_id)
|
||||
.with_result_hook(_post_hook)
|
||||
|
||||
@@ -97,6 +97,58 @@ async def test_chat_client_agent_run_streaming(client: SupportsChatGetResponse)
|
||||
assert result.text == "test streaming response another update"
|
||||
|
||||
|
||||
async def test_chat_client_agent_streaming_response_format_from_default_options(
|
||||
client: SupportsChatGetResponse,
|
||||
) -> None:
|
||||
"""AgentResponse.value must be parsed when response_format is set in default_options and streaming."""
|
||||
from pydantic import BaseModel
|
||||
|
||||
class Greeting(BaseModel):
|
||||
greeting: str
|
||||
|
||||
json_text = '{"greeting": "Hello"}'
|
||||
client.streaming_responses.append( # type: ignore[attr-defined]
|
||||
[ChatResponseUpdate(contents=[Content.from_text(json_text)], role="assistant", finish_reason="stop")]
|
||||
)
|
||||
|
||||
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 == json_text
|
||||
assert result.value is not None
|
||||
assert isinstance(result.value, Greeting)
|
||||
assert result.value.greeting == "Hello"
|
||||
|
||||
|
||||
async def test_chat_client_agent_streaming_response_format_from_run_options(
|
||||
client: SupportsChatGetResponse,
|
||||
) -> None:
|
||||
"""AgentResponse.value must be parsed when response_format is passed via run() options kwarg."""
|
||||
from pydantic import BaseModel
|
||||
|
||||
class Greeting(BaseModel):
|
||||
greeting: str
|
||||
|
||||
json_text = '{"greeting": "Hi"}'
|
||||
client.streaming_responses.append( # type: ignore[attr-defined]
|
||||
[ChatResponseUpdate(contents=[Content.from_text(json_text)], role="assistant", finish_reason="stop")]
|
||||
)
|
||||
|
||||
agent = Agent(client=client)
|
||||
stream = agent.run("Hello", stream=True, options={"response_format": Greeting})
|
||||
async for _ in stream:
|
||||
pass
|
||||
result = await stream.get_final_response()
|
||||
|
||||
assert result.text == json_text
|
||||
assert result.value is not None
|
||||
assert isinstance(result.value, Greeting)
|
||||
assert result.value.greeting == "Hi"
|
||||
|
||||
|
||||
async def test_chat_client_agent_create_session(client: SupportsChatGetResponse) -> None:
|
||||
agent = Agent(client=client)
|
||||
session = agent.create_session()
|
||||
|
||||
Reference in New Issue
Block a user