Repository navigation
Python: fire loop turn-scoped after_run only on clean streaming exit - #9818
RongJie G (CorgiBoyG) wants to merge 1 commit into
Conversation
There was a problem hiding this comment.
🟢 Approval recommended
No active review issues were identified for the change restricting streaming turn-scoped finalization to clean loop exits.
No open issues 🎉
What changed in this PR
Addresses #9817 by aligning streaming loop turn-scoped after_run behavior with non-streaming runs, preventing finalization with a stale response after an exception or early stream closure.
Changes:
- Gates turn-scoped providers on clean loop completion while preserving unconditional iteration-token cleanup.
- Converts normal-stop returns to breaks so successful exits still trigger finalization.
- Adds regression tests for streaming exceptions, early closure, and the non-streaming exception control.
| File | Description |
|---|---|
python/packages/core/tests/core/test_harness_loop.py |
Adds regression coverage for failed and early-closed loop runs. |
python/packages/core/agent_framework/_harness/_loop.py |
Restricts streaming turn-scoped finalization to clean exits. |
Review effort: Balanced
The streaming AgentLoopMiddleware path fired turn-scoped after_run providers (after_run_once_per_turn, e.g. CompactionProvider) from a finally block, so an iteration that raised - or an early stream close - still ran them with the stale final response from a prior iteration. That diverged from the non-streaming path and the normal non-loop run contract, both of which skip after_run when the run raises. Gate the streaming finally call on a completed_cleanly flag set only after a clean loop exit (should_continue stop, max_iterations, approval escape hatch, or MiddlewareTermination), converting the normal-stop returns to break. Normal completion behavior is unchanged; exception and early-close paths no longer fire turn-scoped after_run. Adds deterministic regressions for the streaming exception, streaming early-close, and the non-streaming exception control. Fixes microsoft#9817 Signed-off-by: CorgiBoyG <111257566+CorgiBoyG@users.noreply.github.com>
40fb9ac to
e93cf0d
Compare
|
Eduard van Valkenburg (@eavanvalkenburg) Thanks for marking #9817 ready for implementation. This PR is now ready for review. CI for |
Motivation & Context
After a successful streaming loop iteration, an exception or early close during a later iteration still invokes turn-scoped
after_runproviders with the previous iteration's response. The streaming loop invokes them unconditionally fromfinally, while the non-streaming loop skips them when execution fails.This makes provider finalization depend on the streaming mode. Providers can receive a stale response and run side effects after an incomplete loop. For example,
CompactionProviderwith anafter_strategycan run its stored-history compaction through this unexpected callback.Description & Review Guide
completed_cleanly, set after the loop exits normally. Convert the three normal-stop returns to breaks so they reach that point.MiddlewareTerminationretain their existing behavior. Propagating exceptions, cancellation and early close skip turn-scoped finalization. The inner stream's context manager and iteration-token cleanup remain unchanged.Related Issue
Fixes #9817
Eduard van Valkenburg (@eavanvalkenburg) marked the issue
ready-for-implementation. No competing open PR was found.AI Assistance
AI assistance details: Source analysis, implementation, regression tests and PR description. Verification includes deterministic reproduction and regression testing.
Contribution Checklist
breaking changelabel (or add "[BREAKING]" to the title prefix, before or after any language prefix) — a workflow keeps the label and title prefix in sync automatically.CI on
e93cf0dpasses; its Python 3.11 Ubuntu run reports 20,456 passed, 52 skipped and 2 xfailed. Local verification of the patch combined with current main reports 1,201 related tests passed. Lint, formatting and strict type checks pass. The clean-build checkbox is left unchecked because test and dependency setup output includes existing warnings.