Python: bound stateless pause batches to user turns - #8449
Eduard van Valkenburg (eavanvalkenburg) merged 10 commits into
Conversation
0c5bf48 to
8cb5920
Compare
There was a problem hiding this comment.
🔵 Needs a closer look
Later reused Host call IDs can satisfy an older mixed batch incorrectly, and significant AG-UI API changes are undocumented in the PR scope.
Pull request overview
Fixes stateless pause batching across user turns and extends approval-resume context handling.
Changes:
- Adds user-turn boundaries while preserving unresolved mixed-batch detection.
- Refactors pause-response correlation and streaming order handling.
- Adds session-authority and AG-UI invocation-context support.
File summaries
| File | Description |
|---|---|
python/packages/core/agent_framework/_tools.py |
Refactors mixed-pause discovery and session authority. |
python/packages/core/agent_framework/_agents.py |
Marks framework-created sessions as non-authoritative. |
python/packages/core/agent_framework/_harness/_tool_approval.py |
Preserves streamed mixed-pause ordering. |
python/packages/core/tests/core/test_function_invocation_logic.py |
Adds stateless mixed-batch regressions. |
python/packages/core/tests/core/test_harness_tool_approval.py |
Tests session authority and streaming order. |
python/packages/ag-ui/agent_framework_ag_ui/_agent.py |
Exposes invocation kwargs through the wrapper. |
python/packages/ag-ui/agent_framework_ag_ui/_agent_run.py |
Propagates and merges invocation kwargs. |
python/packages/ag-ui/tests/ag_ui/test_approval_result_event.py |
Tests invocation-argument precedence. |
python/packages/ag-ui/tests/ag_ui/test_agent_wrapper_comprehensive.py |
Tests context preservation across resume. |
python/packages/ag-ui/AGENTS.md |
Documents AG-UI invocation context behavior. |
docs/specs/004-python-function-calling-loop.md |
Updates mixed-pause invariants and test mapping. |
Review details
Suppressed comments (1)
python/packages/core/agent_framework/_tools.py:3212
- This unbounded response scan can bind a later occurrence's result to an older mixed batch. If an incomplete mixed batch has Host call ID
x, and a later standalone Host request reusesxand returns a result withoutContent.id(a supported compatibility form),_match_mixed_pause_responsessees only the old batch's item and treats the later result as its missing response. The old approval can then execute even though that result belongs to the newer request. Account for intervening request occurrences—either exclude responses owned by later batches or treat call-ID-only matching as ambiguous when a later request reuses the ID.
responses = [
content
for content in flattened_contents[batch_end + 1 :]
if content.type in {"function_approval_response", "function_result"}
- Files reviewed: 3/3 changed files
- Comments generated: 0
- Review effort level: Balanced (auto)
Note
Copilot is running an experiment and ran this review at Balanced.
💡 Add a code-review agent skill for context-aware, tailored reviews. Learn more in the docs.
There was a problem hiding this comment.
MAF Automated Review — Iteration 1
Result: Findings reported
Scope: full PR (1 commit(s)): 8cb5920f98cc
Model: gpt-5.6-sol-fast
Overview
The change introduces an explicit unrelated-user-turn boundary while retaining reverse discovery and fail-closed handling for genuine mixed approval/Host batches. The added tests cover distinct-call-ID separation and preserve non-user split-output behavior. One occurrence-correlation gap remains: separated standalone pauses that reuse a call_id can become response-order dependent and silently suppress a valid approval.
Reviewed the supplied pull-request change set across correctness, security/reliability, architecture, and failure behavior.
1 verified finding remained after source verification (1 medium) across 1 file. Details are attached to the affected lines below.
Affected areas: python/packages/core/agent_framework/_tools.py
There was a problem hiding this comment.
MAF Automated Review — Iteration 2
Result: Findings reported
Scope: 3 net-new commit(s): a3fc29dbd63a, 57b204e22e48, 68c4c159952a
Model: gpt-5.6-sol-fast
Overview
The change adds user-turn boundaries and newest-to-oldest ownership for stateless pause responses, with focused regressions for reused call IDs, incomplete mixed batches, and completed-batch replay. The Purview changes also broaden content evaluation and make identity, execution-mode, and cached blocking behavior fail closed across Python and .NET. Two residual issues remain in the stateless ownership pass: compatible but unassignable responses can be reinterpreted by older batches, and scanning every standalone batch makes caller-controlled history processing quadratic.
Reviewed the supplied incremental change set across correctness, security/reliability, architecture, and failure behavior.
2 verified findings remained after source verification (1 high, 1 medium) across 1 file. Details are attached to the affected lines below.
Affected areas: python/packages/core/agent_framework/_tools.py
# Conflicts: # docs/specs/004-python-function-calling-loop.md
Motivation & Context
Stateless mixed-pause discovery currently infers request batches from flattened message history. A standalone approval request that is abandoned before an unrelated user turn can therefore be combined with a later standalone Host-owned request. Supplying the Host result then spuriously requires an approval response for the abandoned request and raises before the provider is called.
Separating those batches also requires occurrence-safe response ownership: when standalone approval and Host requests reuse a
call_id, a Host result must not consume a valid approval decision or satisfy an older mixed batch, exact Host occurrence identity must survive newer call-ID-only candidates, and a completed mixed batch must not reinterpret the local terminal result as another Host response.This follow-up preserves fail-closed behavior for genuine mixed approval/Host batches while keeping standalone pauses from separate turns independent.
Description & Review Guide
_stateless_mixed_pause_batch_status, exact-before-id-less matching and provenance-gated duplicate handling in_match_mixed_pause_responses, and Host-only occurrence closure in_replace_approval_contents_with_results.Related Issue
Fixes #8448
Partially addresses #8436 by fixing occurrence-identified/id-less Host assignment and preserving stateless conflict rejection. The provider-invalidation outbox recovery scenario remains a separate state-lifecycle change.
No other open pull request references either issue.
Contribution Checklist
breaking changelabel (or add "[BREAKING]" to the title prefix, before or after any language prefix) — a workflow keeps the label and the title prefix in sync automatically.