Description
On current main (834eb7ff12c83aadee56d468e3b01b4f0fc4084c), AgentExecutor._resume_with_pending_responses assigns one role to an entire resumed response batch:
role = "tool" if all(r.type == "function_result" for r in self._pending_responses_to_agent) else "user"
When one paused workflow turn contains both a declaration-only (Host-owned) function call and an approval request, the Host's terminal function_result and the function_approval_response can arrive in the same batch. The approval response makes the condition false, so the resumed SupportsAgentRun.run receives user(function_result, function_approval_response). With the reverse input order it receives user(function_approval_response, function_result). In both cases the Host result has the wrong role at the executor boundary.
I expect the terminal result to remain in a tool-role message and the approval response in a user-role message, preserving input order and grouping only adjacent contents of the same role. For three interleaved responses this yields tool(function_result), user(function_approval_response), tool(function_result). This follows the Python core guidance and function-calling-loop specification.
A repository-local regression using a capturing fake agent checks both streaming and non-streaming resumes, both response orders, and interleaved Host results. All 5 focused cases fail against unchanged main at the role assertion and pass with a focused role-splitting change. The change applies cleanly to the above main; its workflow test file passes 19 tests, and the Python workspace suite passes 15,168 tests (541 skipped, 2 xfailed). Provider-specific serialization or a live provider failure has not been demonstrated; the observed bug is at the executor-to-agent boundary.
Code Sample
A minimal reproduction can be added to python/packages/core/tests/workflow/test_agent_executor_tool_calls.py: pause an AgentExecutor workflow whose captured agent response has one declaration-only function_call and one function_approval_request; resume with:
responses = {
host_request.request_id: Content.from_function_result(
call_id=host_request.data.call_id, result="Host result"
),
approval_request.request_id: approval_request.data.to_function_approval_response(
approved=True
),
}
await workflow.run(responses=responses)
# The capturing agent should receive tool(function_result), user(function_approval_response).
Error Messages / Stack Traces
The regression fails on the role sequence. No provider error or stack trace was observed.
Package Versions
agent-framework-core: current source main at 834eb7ff12c83aadee56d468e3b01b4f0fc4084c; released package version not verified.
Python Version
Python 3.12 in the local locked test environment.
Additional Context
This is distinct from #8573, which concerns ownership/correlation of Host responses to the active batch, and from #6385, which concerns which calls receive approval wrappers. This issue concerns the role of already-collected responses during AgentExecutor resume.
The Python contribution guidance asks external contributors to check with the core team before changing function-loop/approval-resume behavior. Could a maintainer confirm whether splitting this mixed batch into ordered tool/user messages at AgentExecutor._resume_with_pending_responses is the intended contract, or point to a preferred approach? I have a focused change and regression tests prepared, and will wait for direction before opening a PR.
Description
On current
main(834eb7ff12c83aadee56d468e3b01b4f0fc4084c),AgentExecutor._resume_with_pending_responsesassigns one role to an entire resumed response batch:When one paused workflow turn contains both a declaration-only (Host-owned) function call and an approval request, the Host's terminal
function_resultand thefunction_approval_responsecan arrive in the same batch. The approval response makes the condition false, so the resumedSupportsAgentRun.runreceivesuser(function_result, function_approval_response). With the reverse input order it receivesuser(function_approval_response, function_result). In both cases the Host result has the wrong role at the executor boundary.I expect the terminal result to remain in a tool-role message and the approval response in a user-role message, preserving input order and grouping only adjacent contents of the same role. For three interleaved responses this yields
tool(function_result), user(function_approval_response), tool(function_result). This follows the Python core guidance and function-calling-loop specification.A repository-local regression using a capturing fake agent checks both streaming and non-streaming resumes, both response orders, and interleaved Host results. All 5 focused cases fail against unchanged
mainat the role assertion and pass with a focused role-splitting change. The change applies cleanly to the abovemain; its workflow test file passes 19 tests, and the Python workspace suite passes 15,168 tests (541 skipped, 2 xfailed). Provider-specific serialization or a live provider failure has not been demonstrated; the observed bug is at the executor-to-agent boundary.Code Sample
A minimal reproduction can be added to
python/packages/core/tests/workflow/test_agent_executor_tool_calls.py: pause anAgentExecutorworkflow whose captured agent response has one declaration-onlyfunction_calland onefunction_approval_request; resume with:Error Messages / Stack Traces
The regression fails on the role sequence. No provider error or stack trace was observed.
Package Versions
agent-framework-core: current sourcemainat834eb7ff12c83aadee56d468e3b01b4f0fc4084c; released package version not verified.Python Version
Python 3.12 in the local locked test environment.
Additional Context
This is distinct from #8573, which concerns ownership/correlation of Host responses to the active batch, and from #6385, which concerns which calls receive approval wrappers. This issue concerns the role of already-collected responses during
AgentExecutorresume.The Python contribution guidance asks external contributors to check with the core team before changing function-loop/approval-resume behavior. Could a maintainer confirm whether splitting this mixed batch into ordered tool/user messages at
AgentExecutor._resume_with_pending_responsesis the intended contract, or point to a preferred approach? I have a focused change and regression tests prepared, and will wait for direction before opening a PR.