Skip to content

Python: release functional workflow stream on agent response close - #10220

Closed
袁永旗(Yuan Yongqi) (Yongthyuan) wants to merge 2 commits into
microsoft:mainfrom
Yongthyuan:codex/fix-functional-agent-stream-close
Closed

袁永旗(Yuan Yongqi) (Yongthyuan) wants to merge 2 commits into
microsoft:mainfrom
Yongthyuan:codex/fix-functional-agent-stream-close

Conversation

@Yongthyuan

@Yongthyuan 袁永旗(Yuan Yongqi) (Yongthyuan) commented Nov 10, 2026 •

Copy link
Copy Markdown
Contributor

Motivation & Context

Closing a streaming FunctionalWorkflowAgent response leaves its owned workflow marked as running. The next sequential agent.run() raises RuntimeError: Workflow is already running, even after await response.close() returns. This affects cancellation or disconnect cleanup followed by another turn.

Description & Review Guide

  • What are the major changes? Register workflow_stream.close as a cleanup hook on the outer ResponseStream, using the existing cleanup lifecycle to close the owned stream and release the run guard.
  • What is the impact of these changes? The same agent can immediately run again after closing an unstarted or partially consumed response. The regression tests also cover full consumption, workflow exceptions, cancellation, and repeated close of an old response while a newer run is active.
  • What do you want reviewers to focus on? Cleanup must work before the first pull and must remain idempotent, so an old response cannot release a newer run's guard. The fix does not change the public API or persisted state.

Related Issue

Fixes #10164.

This submits the original patch I shared on November 7. On November 9, a maintainer marked the issue ready-for-implementation and assigned it to me. The branch preserves that original commit and incorporates the latest main.

AI Assistance

  • No material AI assistance was used.
  • This is an AI-assisted contribution.

AI assistance details: implementation, regression tests, local validation, and this description were prepared with AI assistance. I personally ran the original minimal reproduction and observed the reported failure.

Contribution Checklist

  • The core wheel and source distribution build successfully.
  • All unit tests pass, and I have added new tests where possible — the relevant 249 functional workflow tests and 114 ResponseStream tests pass; the full repository suite was not run.
  • The PR follows the Contribution Guidelines.
  • This PR links to an issue marked ready-for-implementation by a maintainer.
  • This is not a breaking change.

The two early-close regressions fail against the original implementation and pass with this fix. The original minimal reproduction now prints result: 2. Ruff lint and format, strict source Pyright, and test Pyright, mypy, Pyrefly, ty, and zuban checks pass for the changed files using the repository's pinned versions. Pyrefly reports three warnings in unchanged tests; the workflow tests emit the existing experimental-feature warning.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Copilot was unable to review this pull request because the user who requested the review has insufficient remaining quota. Try requesting a review at a lower effort level.

@Yongthyuan

Copy link
Copy Markdown
Contributor Author

@microsoft-github-policy-service agree

@eavanvalkenburg

Copy link
Copy Markdown
Member

/review

@github-actions github-actions Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

MAF Automated Review — Iteration 1

Result: Findings reported
Scope: full PR (2 commit(s)): f61d1898842a, 85cfe2aa3ab7
Model: gpt-5.6-sol

Overview

The change correctly connects the outer agent response lifecycle to its owned workflow stream, and the one-shot cleanup hook plus new tests protect unstarted, consumed, failed, cancelled, and stale-close cases. However, the hook also exposes a close-versus-active-pull race that can release the workflow's run guard before the original execution terminates. That permits overlapping runs on an instance whose state and side effects are explicitly designed for single-run execution.

Reviewed the supplied pull-request change set across correctness, security/reliability, architecture, and failure behavior.
1 verified finding remained after source verification (1 high) across 1 file. Details are attached to the affected lines below.

Affected areas: python/packages/core/agent_framework/_workflows/_functional.py

return ResponseStream(
_generate_updates(),
finalizer=AgentResponse.from_updates,
cleanup_hooks=[workflow_stream.close],

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

If close() races an active anext(), the outer generator's aclose() raises, but ResponseStream.close() still runs this hook; the inner close then releases _is_running even though the original workflow remains active. A subsequent run is accepted concurrently, violating the single-run invariant and risking duplicate side effects or checkpoint state corruption. Please coordinate close with in-flight pulls, or otherwise retain the guard until the inner workflow has actually terminated, and cover this race with a regression test.

@eavanvalkenburg

Copy link
Copy Markdown
Member

袁永旗(Yuan Yongqi) (@Yongthyuan) Thanks for the fix. This implementation was already merged to main in #10204, which cherry-picked this PR's fix and closed #10164. The current diff against main is empty, so I'm closing this PR as superseded.

@Yongthyuan

Copy link
Copy Markdown
Contributor Author

Thanks for clarifying that the original fix has already been merged.

The automated review on this PR also identified a separate issue with closing a stream while a read is still in progress. That issue is present on current main as well. I have a fix and regression tests ready, and I’ll submit them in a follow-up PR referencing #10164.

This branch was previously deployed

1 inactive deployment
github-app-auth — 85cfe2aa Deployed Nov 10, 2026 by Yongthyuan via add_label #27456
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

python Usage: [Issues, PRs], Target: Python

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Python: [Bug]: Closing a FunctionalWorkflowAgent stream leaves the workflow marked as running

3 participants