fix(swarm): label each member with its own item
Every member was launched with the swarm's description, so the pager drew N identical subagent blocks: the user could not tell which member was running, and a failure could not be attributed to an item. This is also why K6 does not port upstream's progress grid. A member IS an ordinary subagent, so the pager already renders one block per member with live status, duration, tool-call and turn counts — richer than a grid cell. The gap was the label, not the widget; upstream's grid (and the estimator behind it, which infers progress from tool-call rate) answers a different TUI's shortcomings. The parent tool call already reads "<description> (N members)" and `is_task_variant` already knows `AgentSwarm`, so the blocking-wait spinner registers.
This commit is contained in:
@@ -341,7 +341,10 @@ fn build_request(pending: &Pending, config: &SwarmRunConfig) -> SubagentRequest
|
||||
SubagentRequest {
|
||||
id: uuid::Uuid::now_v7().to_string(),
|
||||
prompt: pending.spec.prompt.clone(),
|
||||
description: config.description.clone(),
|
||||
// The ITEM, not the swarm's description: every member would otherwise
|
||||
// render as an identical subagent block and the user could not tell
|
||||
// which one is running, or which one failed.
|
||||
description: pending.spec.item.clone(),
|
||||
subagent_type: config.subagent_type.clone(),
|
||||
parent_session_id: config.parent_session_id.clone(),
|
||||
parent_prompt_id: config.parent_prompt_id.clone(),
|
||||
@@ -690,6 +693,41 @@ mod tests {
|
||||
);
|
||||
}
|
||||
|
||||
/// Each member must be identifiable while it runs: the TUI renders one
|
||||
/// subagent block per member from this description, so a shared one leaves
|
||||
/// the user staring at N identical rows.
|
||||
#[tokio::test(start_paused = true)]
|
||||
async fn each_member_is_labelled_with_its_own_item() {
|
||||
let backend = Arc::new(FakeBackend::default());
|
||||
let seen = Arc::new(Mutex::new(Vec::new()));
|
||||
let recorder = seen.clone();
|
||||
let specs = specs(&["a.rs", "b.rs"]);
|
||||
let config = SwarmRunConfig {
|
||||
description: "review files".into(),
|
||||
..config(None)
|
||||
};
|
||||
// `build_request` is the only place the label is set, so assert on it
|
||||
// directly rather than through the backend's prompt log.
|
||||
for (index, spec) in specs.iter().enumerate() {
|
||||
let pending = Pending {
|
||||
index,
|
||||
spec: spec.clone(),
|
||||
attempts: 0,
|
||||
not_before: None,
|
||||
};
|
||||
recorder
|
||||
.lock()
|
||||
.unwrap()
|
||||
.push(build_request(&pending, &config).description);
|
||||
}
|
||||
assert_eq!(
|
||||
*seen.lock().unwrap(),
|
||||
vec!["a.rs".to_string(), "b.rs".to_string()],
|
||||
"each member must carry its own item, not the swarm description"
|
||||
);
|
||||
drop(backend);
|
||||
}
|
||||
|
||||
/// Dropping the runner is what a send-now interrupt does; the members must
|
||||
/// be cancelled rather than silently detached onto the user's tree.
|
||||
#[tokio::test(start_paused = true)]
|
||||
|
||||
Reference in New Issue
Block a user