Skip to content

Python: Fix #3970: Python: [Bug]: AgentResponse.value is None when streaming workflow#4283

Closed
moonbox3 wants to merge 1 commit intomicrosoft:mainfrom
moonbox3:agent/fix-3970-9
Closed

Python: Fix #3970: Python: [Bug]: AgentResponse.value is None when streaming workflow#4283
moonbox3 wants to merge 1 commit intomicrosoft:mainfrom
moonbox3:agent/fix-3970-9

Conversation

@moonbox3
Copy link
Contributor

Automated fix for #3970.

Verification passed after 0 retries.

microsoft#3970)

The streaming path in Agent.run() was reading response_format from the raw
options parameter, which doesn't include values from default_options. The
non-streaming path correctly read from ctx["chat_options"] which merges
default_options with runtime options.

Changed the streaming finalizer to lazily read response_format from the
prepared run context (ctx_holder), ensuring default_options.response_format
is properly propagated when the stream is finalized.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot AI review requested due to automatic review settings February 26, 2026 00:54
@moonbox3 moonbox3 closed this Feb 26, 2026
@moonbox3 moonbox3 deleted the agent/fix-3970-9 branch February 26, 2026 00:54
@github-actions github-actions bot changed the title Fix #3970: Python: [Bug]: AgentResponse.value is None when streaming workflow Python: Fix #3970: Python: [Bug]: AgentResponse.value is None when streaming workflow Feb 26, 2026
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Fixes a Python streaming bug where AgentResponse.value is not populated when response_format is provided via an agent’s default_options (reported in #3970), by ensuring the streaming finalizer uses the merged run context options.

Changes:

  • Update the streaming Agent.run(..., stream=True) finalizer to derive response_format from the prepared run context (chat_options) rather than the raw options argument.
  • Add a regression test verifying structured output parsing works in streaming when response_format is set in default_options.
  • Minor test-only formatting cleanup for long assertion messages.

Reviewed changes

Copilot reviewed 3 out of 3 changed files in this pull request and generated 1 comment.

File Description
python/packages/core/agent_framework/_agents.py Fixes streaming finalization to use merged context options (including default_options response_format).
python/packages/core/tests/core/test_agents.py Adds regression coverage for streaming + default_options["response_format"] parsing (#3970).
python/packages/core/tests/core/test_function_invocation_logic.py Collapses multi-line f-strings in assertions (formatting only).


def _finalize_with_context(updates: Sequence[AgentResponseUpdate]) -> AgentResponse:
ctx = ctx_holder["ctx"]
response_format = ctx["chat_options"].get("response_format") if ctx else None
Copy link

Copilot AI Feb 26, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Streaming finalizer pulls response_format from ctx["chat_options"] but doesn’t apply the same BaseModel subclass validation that the non-streaming path does (where non-BaseModel values are normalized to None). This can lead to inconsistent AgentResponse.response_format contents between streaming and non-streaming runs and can violate the annotated type. Consider reusing the non-streaming validation logic here (or inside _finalize_response_updates) so only type[BaseModel] is propagated for parsing.

Suggested change
response_format = ctx["chat_options"].get("response_format") if ctx else None
raw_response_format = ctx["chat_options"].get("response_format") if ctx else None
# Normalize response_format so only BaseModel subclasses are propagated, matching non-streaming behavior.
if isinstance(raw_response_format, type) and issubclass(raw_response_format, BaseModel):
response_format = raw_response_format
else:
response_format = None

Copilot uses AI. Check for mistakes.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants