Skip to content

Python: [Bug]: Mixed approval and Host results give a tool result the user role #8700

Description

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.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Labels

pythonUsage: [Issues, PRs], Target: PythonreproducedUsage: [Issues], Target: all issues that can be reproduced by the triage workflowworkflowsUsage: [Issues, PRs], Target: Workflows

Type

Projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions