Repository navigation
Python: fix(orchestration): add ensure_trailing_user_turn to SequentialBuilder for providers that return empty text on assistant-ending prompts - #8779
Conversation
…r for providers that return empty text on assistant-ending prompt
There was a problem hiding this comment.
Copilot review overview
🟢 Approval recommended
The implementation and coverage are sound; remaining comments concern minor documentation and logging corrections.
Review effort: Balanced
Findings: 2
Open (2)
What changed in this PR
Adds an opt-in synthetic trailing user turn to prevent empty completions from providers that reject assistant-ending prompts.
Changes:
- Extends agent and sequential executors with
ensure_trailing_user_turn. - Propagates the option through approval-wrapped agents.
- Adds unit and end-to-end coverage for chaining scenarios.
| File | Description |
|---|---|
python/packages/core/agent_framework/_workflows/_agent_executor.py |
Implements synthetic user-turn insertion. |
python/packages/core/tests/workflow/test_agent_executor.py |
Tests core executor behavior. |
python/packages/orchestrations/agent_framework_orchestrations/_sequential.py |
Exposes and propagates the builder option. |
python/packages/orchestrations/agent_framework_orchestrations/_orchestration_request_info.py |
Propagates the option through approval workflows. |
python/packages/orchestrations/tests/test_sequential.py |
Tests sequential chaining configurations. |
python/packages/orchestrations/tests/test_orchestration_request_info.py |
Tests approval-executor propagation. |
💡 Add a code-review agent skill for context-aware, tailored reviews. Learn more in the docs.
…ebug message literals' Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
|
Can you have a look at the file conflict please |
|
The single failing test test_cancellation_signal_preempts_stuck_agent_call in |
|
Hi Eduard van Valkenburg (@eavanvalkenburg), Evan Mattson (@moonbox3), and westey (@westey-m), It should be ready to merge now, but let me know if you need any further changes. Thanks! |

Motivation & Context
When using
SequentialBuilderwith multiple agent participants, the second (and later) participant is invoked with the prior agent'sfull_conversation, which produces a history ending on anassistantmessage (e.g.,[user, assistant(writer output)]). Some chat-completions providers (e.g.,qwen3.8-27b@4bitbehind an OpenAI-compatible chat-completions API) return essentially empty text (finish_reason=stop,contents empty,usage.output_token_count ≈ 1) when the prompt ends on anassistantmessage. The second participant (e.g., a "reviewer") then "runs successfully" but produces no assistant text, breaking downstream AG-UI workflow streaming (TEXT_MESSAGE_*events are never emitted for that turn).The bug reporter themselves confirmed that adding any trailing user message resolves the issue:
This PR provides an opt-in mechanism to append a synthetic user continuation message before invoking an agent when the cache ends on an
assistantturn.Description & Review Guide
What are the major changes?
ensure_trailing_user_turn: bool = Falseparameter toAgentExecutor.__init__. When enabled, a new private method_ensure_cache_not_assistant_ending()is invoked at the start of_handle_request. If the cache is non-empty and ends on anassistantmessage, a syntheticMessage(role="user", contents=["please continue."])is appended before the agent runs.AgentApprovalExecutor.__init__→ its innerAgentExecutor, so request-info-wrapped agents also honor the flag.SequentialBuilder.__init__→ all participant executors (both theAgentApprovalExecutorbranch and the plainAgentExecutorbranch).chain_only_agent_responses=Trueinteraction, and propagation throughAgentApprovalExecutor→ innerAgentExecutor.What is the impact of these changes?
Falseeverywhere, preserving all existing behavior.ensure_trailing_user_turn=TruetoSequentialBuilder.AgentExecutorlevel, so it also works for non-Sequentialworkflows that chainAgentExecutorinstances manually (verified bytest_from_response_ensure_trailing_user_turn_end_to_end_full_mode).What do you want reviewers to focus on?
"please continue."is acceptable as a hardcoded default, or whether it should be configurable (e.g.,ensure_trailing_user_turn: bool | str = False). For non-continuation agents like a "reviewer," "please continue." is semantically odd but functionally sufficient.full_conversationpropagation so that downstream agents (3rd, 4th in a chain) don't accumulate synthetic turns in their context. Currently the synthetic turn is appended toself._cacheonly, but it may still appear in the agent's persisted history depending on the agent implementation. This PR does not test the 3-agent accumulation case.True. We choseFalsefor backward compatibility, but maintainers may want to discuss whether the empty-completion behavior should be considered a bug to fix by default rather than a workaround to opt into.Related Issue
Fixes #8240
Contribution Checklist
breaking changelabel (or add "[BREAKING]" to the title prefix, before or after any language prefix) — a workflow keeps the label and title prefix in sync automatically.