feat(core): implement mid-turn queue drain for agent execution#2854
feat(core): implement mid-turn queue drain for agent execution#2854wenshao merged 6 commits intoQwenLM:mainfrom
Conversation
Inject queued user messages between tool execution steps within a single turn, so the model sees them immediately instead of waiting for the entire round to complete. - Add `dequeueAll()` to AsyncMessageQueue - Add `midTurnDrain` callback to ReasoningLoopOptions - Drain queue after processFunctionCalls, inject as text parts - AgentComposer always enqueues directly (no local buffering) - Add QUEUE_MESSAGES_CONSUMED event for UI sync Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
📋 Review SummaryThis PR implements mid-turn queue drain functionality, allowing user messages queued during tool execution to be injected into the current reasoning turn rather than waiting for the entire round to complete. The implementation is well-structured with comprehensive test coverage and clean separation of concerns across the queue utility, agent core, interactive agent, and UI components. 🔍 General Feedback
🎯 Specific Feedback🟢 Medium
🔵 Low
✅ Highlights
|
Extend mid-turn queue drain to the main session's tool execution path (useGeminiStream). Previously only agent tabs had this feature. - Add midTurnDrainRef parameter to useGeminiStream - Inject queued messages in handleCompletedTools before submitQuery - Bridge useMessageQueue to drain ref in AppContainer via ref pattern Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
There was a problem hiding this comment.
Pull request overview
Adds “mid-turn” draining of queued user messages so that messages typed during tool execution can be injected into the very next model call (instead of waiting until the entire round completes), improving interactivity for both in-process agents and the main CLI stream loop.
Changes:
- Add
dequeueAll()toAsyncMessageQueueto atomically drain pending items. - Introduce
midTurnDraincallback plumbing throughAgentCore.runReasoningLoopand implement queue draining + event emission inAgentInteractive. - Wire CLI UI/streaming to enqueue immediately and drain mid-turn (via new event + a ref bridge).
Reviewed changes
Copilot reviewed 9 out of 9 changed files in this pull request and generated 3 comments.
Show a summary per file
| File | Description |
|---|---|
| packages/core/src/utils/asyncMessageQueue.ts | Adds dequeueAll() for draining all queued items. |
| packages/core/src/utils/asyncMessageQueue.test.ts | Adds tests for dequeueAll() behavior. |
| packages/core/src/agents/runtime/agent-interactive.ts | Implements queue draining + event emission; passes midTurnDrain into core loop. |
| packages/core/src/agents/runtime/agent-interactive.test.ts | Adds tests for mid-turn draining and event emission. |
| packages/core/src/agents/runtime/agent-events.ts | Adds QUEUE_MESSAGES_CONSUMED event and payload type. |
| packages/core/src/agents/runtime/agent-core.ts | Calls midTurnDrain() after tool execution to inject messages into the next API call. |
| packages/cli/src/ui/hooks/useGeminiStream.ts | Injects drained queued messages into the next tool-result submission. |
| packages/cli/src/ui/components/agent-view/AgentComposer.tsx | Always enqueues messages directly; clears pending display on drain/status events. |
| packages/cli/src/ui/AppContainer.tsx | Bridges useMessageQueue to useGeminiStream via a midTurnDrainRef. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
- Guard midTurnDrain with abort check to prevent message loss on cancel - Synchronously clear messageQueueRef to prevent duplicate drains - Only clear pending display on IDLE status, not all status changes Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 9 out of 9 changed files in this pull request and generated no new comments.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
Revert subagent-path changes (AgentCore, AgentInteractive, AgentComposer, AsyncMessageQueue, agent-events) to keep the PR focused on the main session, which is easier to test and validate. Subagent mid-turn drain can be added in a follow-up PR. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 2 out of 2 changed files in this pull request and generated 2 comments.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
- Move synchronous queue ref into useMessageQueue itself, expose drainQueue() for atomic drain (fixes race between addMessage and drain) - Record drained messages as USER history items so the transcript stays complete - Simplify AppContainer bridge to just midTurnDrainRef.current = drainQueue Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 3 out of 3 changed files in this pull request and generated 1 comment.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
- Skip drain when turnCancelledRef or abortController signal is set, so queued messages stay for the next turn instead of being lost - Restore ref-based queue bridge (drainQueue removed from useMessageQueue) - Keep synchronous ref clear to prevent duplicate drains Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 3 out of 3 changed files in this pull request and generated no new comments.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
Major additions to qwen-code-improvement-report.md: 1. New P0 item: Mid-Turn Queue Drain (PR QwenLM/qwen-code#2854 open) 2. Upgraded P2→P1: Tool parallelism with Kind-based batching (PR QwenLM/qwen-code#2864 open) 3. New P1 items: startup optimization, CLAUDE.md conditional rules 4. New P2 items: shell security, MDM enterprise, API token counting 5. Added Fork Subagent deep-dive cross-reference link 6. Expanded summary table from 10→16 dimensions with "进展" column tracking Qwen Code PR status 7. Fixed forkSubagent.ts line count 211→210 Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…rt (#34) * docs: add English terms to technical concepts, fix leaked source reference and relative paths - Remove 'leaked' reference in qwen-code-improvement-report.md - Fix 14 relative paths from '../claude-code-leaked/' to 'claude-code/' - Add English annotations to technical terms across 10 comparison docs (Speculation, Context Compression, Subagent, Telemetry, etc.) Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com> * docs: convert source code references to clickable local links in qwen-code-improvement-report.md - Add local source paths section (claude-code-leaked + qwen-code) - Convert 14 Claude Code source refs to clickable links - Convert 7 Qwen Code source refs to clickable links Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com> * docs: fix qwen-code-improvement-report.md local links - Replace external source code links with internal article links - Convert 21 external file links to internal documentation links - Add related article references for all 5 Top 5 improvement sections - Use '源码:' format for source code references instead of clickable links Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com> * fix: correct improvement report accuracy issues 1. reactiveCompact.ts does NOT exist — changed to apiMicrocompact.ts 2. Qwen Code speculation is complete in v0.15.0 (563 lines + overlayFs + speculationToolGate), only default-disabled — updated description, matrix row, summary table, and suggestions 3. Claude Code speculation.ts: 992 → 991 lines Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * fix: replace 'leaked 源码' with '源码分析' in startup-optimization disclaimer Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * fix: address Copilot review — rename claude-code-leaked path reference Changed `../claude-code-leaked/` → `../claude-code/`(源码快照)in the source path hint to avoid inconsistency with "源码分析" description. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * feat: enhance improvement report with deep-dive findings and PR status Major additions to qwen-code-improvement-report.md: 1. New P0 item: Mid-Turn Queue Drain (PR QwenLM/qwen-code#2854 open) 2. Upgraded P2→P1: Tool parallelism with Kind-based batching (PR QwenLM/qwen-code#2864 open) 3. New P1 items: startup optimization, CLAUDE.md conditional rules 4. New P2 items: shell security, MDM enterprise, API token counting 5. Added Fork Subagent deep-dive cross-reference link 6. Expanded summary table from 10→16 dimensions with "进展" column tracking Qwen Code PR status 7. Fixed forkSubagent.ts line count 211→210 Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * fix: simplify improvement matrix table to 5 columns, add deep-dive links - Reduced matrix from 7 columns to 5 (优先级/改进点/现状/难度/进展) to eliminate GitHub horizontal scrollbar - Added section 五 with 12 deep-dive cross-reference links - Tracked Qwen Code PR status: #2854 (mid-turn drain), #2864 (parallelism), #2525 (speculation, merged) Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * fix: correct line counts and anchor link in improvement report - compact.ts: 1706→1705 - AgentTool.tsx: 1398→1397 - runAgent.ts: 974→973 - autoDream.ts: 325→324 - Fix anchor: #相关-deep-dive-文章 → #五相关-deep-dive-文章 Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com> Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Summary
Implement mid-turn queue drain for the main session, allowing the model to see user messages immediately during tool execution instead of waiting for the entire round to complete.
Before (Between-Round Drain)
User messages sent during tool execution are buffered locally in React state. They are only flushed after the entire round completes, then processed as a new round:
The user cannot redirect or supplement the agent mid-execution — they must wait for all tool steps to finish.
After (Mid-Turn Queue Drain)
After each tool execution step, the queue is drained and messages are injected as text parts alongside tool results, so the model sees them in the very next API call:
Changes
useGeminiStream.tsmidTurnDrainRefparameter; drain queue inhandleCompletedToolsbeforesubmitQueryAppContainer.tsxuseMessageQueueto it via ref pattern (avoids stale closures)Test plan
Automated tests
npx vitest run packages/cli/src/ui/hooks/useGeminiStream.test.tsx— 56 tests pass (no regression)npx vitest run packages/cli/src/ui/AppContainer.test.tsx— 32 tests pass (no regression)npx tsc --noEmitpasses for both core and cli packagesManual test case
sleep 15is executing (you have a 15-second window), type:src/result.ts:"modified by user"(model saw the message before creating the file)🤖 Generated with Claude Code