Python: stream tool results for approval-resolution execution#7243
Open
he-yufeng wants to merge 2 commits into
Open
Python: stream tool results for approval-resolution execution#7243he-yufeng wants to merge 2 commits into
he-yufeng wants to merge 2 commits into
Conversation
The approval-resolution branch of _process_function_requests executed the approved calls and spliced their results into the local history, but returned update_role=None / function_call_results=None, and the first call site in the streaming loop has no yield gate. A tool approved and executed in-run therefore ran silently: nothing streamed, so AG-UI emits no TOOL_CALL_RESULT and the result is absent from MESSAGES_SNAPSHOT, asymmetric with statically executed approvals. Populate update_role/function_call_results from the approval branch when calls were actually executed, and mirror the existing yield gate at the first call site. Adds a regression test that approves a guarded tool over a streaming run and asserts the function_result shows up.
Contributor
There was a problem hiding this comment.
Pull request overview
This PR fixes a streaming gap in the Python function-invocation layer where tools executed during approval resolution (rather than during the model’s normal tool-call turn) would run but never emit streamed function_result updates, preventing downstream streaming consumers (e.g., AG-UI) from observing TOOL_CALL_RESULT events.
Changes:
- Return
update_role="tool"andfunction_call_resultsfrom_process_function_requestswhen approval-resolution execution actually runs tools. - Add a yield gate after the first
_process_function_requestscall in the streaming loop so approval-resolution tool results stream like normal tool results. - Add a regression test covering approval-resolution tool-result streaming.
Reviewed changes
Copilot reviewed 2 out of 2 changed files in this pull request and generated 2 comments.
| File | Description |
|---|---|
| python/packages/core/agent_framework/_tools.py | Streams tool results produced during approval-resolution by returning update_role/results and yielding a ChatResponseUpdate in the first streaming loop call site. |
| python/packages/core/tests/core/test_harness_tool_approval.py | Adds a regression test asserting approval-resolution execution produces a streamed function_result update. |
Comment on lines
+2371
to
+2372
| "update_role": "tool" if executed_count else None, | ||
| "function_call_results": approved_function_results or None, |
Comment on lines
+598
to
+606
| tool_results = [ | ||
| content | ||
| for update in second_updates | ||
| if update.role == "tool" | ||
| for content in update.contents | ||
| if content.type == "function_result" | ||
| ] | ||
| assert tool_results, "approval-resolution execution must stream its function_result" | ||
| assert calls == 1 |
Contributor
|
@he-yufeng please have a look at Copilot's comments. |
5 tasks
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Fixes #7241.
Problem
When a tool is executed while resolving an approval (rather than in the model's normal tool-call turn), its
function_resultnever reaches streaming consumers. The approval-resolution branch of_process_function_requestsruns the approved calls and splices results into the local history for the next model call, but returnsupdate_role=None / function_call_results=None— and the first_process_function_requestscall site in the streaming loop has no yield gate. The approved tool fires its side effect invisibly: noTOOL_CALL_RESULTfrom the AG-UI emitter, and the result is absent fromMESSAGES_SNAPSHOT, asymmetric with statically executed approvals (which AG-UI emits explicitly via_make_approval_tool_result_events).Fix
update_role="tool"and the executedapproved_function_resultswhenever calls actually ran (rejected-only approvals still stream nothing).role="tool"update just like normal tool results.Normal (non-approval) tool streaming is untouched.
Verification
test_tool_approval_resolution_streams_tool_results: approves a guarded tool over a streaming run and asserts thefunction_resultappears in the updates. Fails without the fix (assert []), passes with it.pytest packages/core/tests/core/test_harness_tool_approval.py packages/core/tests/core/test_tools.py packages/core/tests/core/test_function_invocation_logic.py— 211 passed, 2 skipped.test_run.py -k approval) — 6 passed.