Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -221,13 +221,12 @@ def _build_workflow(self, agent: SupportsAgentRun, *, terminal: bool) -> Workflo
request_info_cls = _TerminalAgentRequestInfoExecutor if terminal else AgentRequestInfoExecutor
request_info_executor = request_info_cls(id="agent_request_info_executor")

# Both inner executors yield the inner workflow's terminal output (the agent
# during its turn; the _TerminalAgentRequestInfoExecutor after approval), so
# both must be designated for WorkflowExecutor.get_outputs() to surface them.
# Only the request info executor surfaces approved responses. The agent's
# unapproved response remains available through the request_info event.
return (
WorkflowBuilder(
start_executor=agent_executor,
output_from=[agent_executor, request_info_executor],
output_from=[request_info_executor],
)
# Create a loop between agent executor and request info executor
.add_edge(agent_executor, request_info_executor)
Expand Down
20 changes: 12 additions & 8 deletions python/packages/orchestrations/tests/test_sequential.py
Original file line number Diff line number Diff line change
Expand Up @@ -539,11 +539,7 @@ async def test_chain_only_agent_responses_three_agents() -> None:

async def test_sequential_request_info_last_participant_emits_output() -> None:
"""When the last participant is wrapped via with_request_info(), the workflow
still emits a terminal output event after approval.

This exercises the _EndWithConversation.end_with_agent_executor_response path
that converts the AgentApprovalExecutor's forwarded AgentExecutorResponse into
the workflow's final AgentResponse output.
emits a terminal output event only after approval.
"""
from agent_framework_orchestrations._orchestration_request_info import AgentRequestInfoResponse

Expand All @@ -552,14 +548,20 @@ async def test_sequential_request_info_last_participant_emits_output() -> None:

wf = SequentialBuilder(participants=[a1, a2]).with_request_info().build()

# First run: collect request_info events for both agents
# First run: collect the first request_info event.
request_events: list[Any] = []
output_events: list[Any] = []
async for ev in wf.run("hello with approval", stream=True):
if ev.type == "request_info" and isinstance(ev.data, AgentExecutorResponse):
request_events.append(ev)
elif ev.type == "output":
output_events.append(ev)

# Approve each agent in sequence until the workflow completes
output_events: list[Any] = []
assert request_events
assert output_events == []

# Approve each agent in sequence until the workflow completes. A run that
# pauses for another approval must not expose that unapproved response.
while request_events:
responses = {req.request_id: AgentRequestInfoResponse.approve() for req in request_events}
request_events = []
Expand All @@ -569,6 +571,8 @@ async def test_sequential_request_info_last_participant_emits_output() -> None:
request_events.append(ev)
elif ev.type == "output":
output_events.append(ev)
if request_events:
assert output_events == []

# The workflow must produce a terminal output with the last agent's response.
assert len(output_events) == 1
Expand Down
Loading