Skip to content
Closed
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
26 changes: 26 additions & 0 deletions crates/tui/src/core/engine/turn_loop.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1203,6 +1203,10 @@ impl Engine {
"Turn ending with {running} sub-agent(s) still running in the background; they'll report when done."
)))
.await;
// Inject a waiting hint so the model does not poll
// with peek/status/sleep on the next turn (issue #4097).
self.add_session_message(waiting_for_subagents_runtime_message(running))
.await;
}
}
if subagent_completions > 0 {
Expand Down Expand Up @@ -2507,6 +2511,28 @@ XML unless the user explicitly asks to debug sub-agent internals.\n\n\
)
}

fn waiting_for_subagents_runtime_message(running: usize) -> Message {
Message {
role: "user".to_string(),
content: vec![
ContentBlock::Text {
text: format!(
"<codewhale:runtime_event kind=\"waiting_for_subagents\" visibility=\"internal\">\n\
This is an internal runtime event, not user input. Your {running} sub-agent(s) \
are still running. Do NOT poll them with agent(action=\"peek\") or \
agent(action=\"status\"). Do NOT use sleep or any shell blocking primitive as a \
waiting strategy. The runtime will deliver <codewhale:subagent.done> sentinels \
automatically when each child finishes — polling will never make that happen \
sooner. Stop immediately: emit zero tool calls and end the turn.\n\
</codewhale:runtime_event>"
),
cache_control: None,
},
runtime_event_turn_metadata_block(UserInputProvenance::SubAgentHandoff),
],
}
}

fn subagent_completion_runtime_message(payload: &str) -> Message {
// Role is "user", not "system": some OpenAI-compatible backends apply a
// strict chat template (e.g. vLLM serving Qwen3) that requires any system
Expand Down
9 changes: 9 additions & 0 deletions crates/tui/src/prompts/constitution.md
Original file line number Diff line number Diff line change
Expand Up @@ -373,6 +373,15 @@ Reach for them when the work is genuinely independent:
launch more; do not invent a smaller per-turn limit. To fan out more gently
you can lower `[subagents].launch_concurrency` (how many start at once);
the default is the full running cap.
- **Waiting, not polling**: When you end a turn because every remaining task
depends on background results that haven't arrived yet, do **not** poll those
children with `agent(action="peek")` or `agent(action="status")` on your next
turn. Do not use `sleep` or any shell blocking primitive as a waiting strategy.
The runtime delivers `<codewhale:subagent.done>` sentinels automatically as
user messages the moment a child finishes — polling will never make that happen
sooner, it only burns turns and budget. If you receive a new turn with no new
user message and your children are still running, stop immediately: emit zero
tool calls and end the turn.

## Thinking Delegation

Expand Down