Clarify subagent coordination cards

This commit is contained in:
iris committed 2026-09-13 02:48:21 -04:00
1 parent cad0cbcfbe
commit 898e6b92d0
5 files changed
+152 -21

No files matched your search

+100 -14
View File
@@ -348,7 +348,15 @@ impl Translator {
if let Some(subagents) = &self.subagents {
subagents.reopen(id);
}
Vec::new()
item.get("id")
.and_then(Value::as_str)
.map(|call| {
vec![Event::ToolEnd {
id: call.to_string(),
output: String::new(),
}]
})
.unwrap_or_default()
}
Some("interacted") => {
self.ensure_child(id, &title, None);
@@ -591,14 +599,14 @@ fn tool(item: &Value) -> Option<(String, String, Value)> {
None => "Agent",
};
let mut input = json!({});
if let Some(prompt) = item.get("prompt") {
input["prompt"] = prompt.clone();
if let Some(prompt) = item.get("prompt").and_then(Value::as_str) {
input["prompt"] = Value::String(prompt.to_string());
}
if let Some(model) = item.get("model") {
input["model"] = model.clone();
if let Some(model) = item.get("model").and_then(Value::as_str) {
input["model"] = Value::String(model.to_string());
}
if let Some(effort) = item.get("reasoningEffort") {
input["reasoningEffort"] = effort.clone();
if let Some(effort) = item.get("reasoningEffort").and_then(Value::as_str) {
input["reasoningEffort"] = Value::String(effort.to_string());
}
(name.to_string(), input)
}
@@ -766,6 +774,11 @@ fn tool_output(item: &Value) -> String {
{
return String::new();
}
Some("collabAgentToolCall")
if item.get("status").and_then(Value::as_str) == Some("completed") =>
{
return String::new();
}
Some("dynamicToolCall") => {
return content_text(item.get("contentItems"), "inputText");
}
@@ -1131,15 +1144,17 @@ mod tests {
vec![Event::ToolStart {
id: "spawn-1".to_string(),
tool: "Task".to_string(),
input: json!({"prompt": "audit the history", "model": null, "reasoningEffort": null})
input: json!({"prompt": "audit the history"})
}]
);
assert!(
translator
.translate(&line(
r#"{"method":"item/completed","params":{"threadId":"parent-thread","turnId":"turn-1","item":{"id":"spawn-1","type":"subAgentActivity","kind":"started","agentThreadId":"child-thread","agentPath":"/root/history_boundaries"}}}"#
))
.is_empty()
assert_eq!(
translator.translate(&line(
r#"{"method":"item/completed","params":{"threadId":"parent-thread","turnId":"turn-1","item":{"id":"spawn-1","type":"subAgentActivity","kind":"started","agentThreadId":"child-thread","agentPath":"/root/history_boundaries"}}}"#
)),
vec![Event::ToolEnd {
id: "spawn-1".to_string(),
output: String::new()
}]
);
let rows = subagents.list(true);
assert_eq!(rows.len(), 1);
@@ -1203,6 +1218,77 @@ mod tests {
);
}
#[test]
fn codex_collaboration_coordination_has_clean_parent_tool_cards() {
let mut translator = Translator::default();
for (tool, name) in [
("wait", "TaskOutput"),
("sendInput", "SendMessage"),
("sendMessage", "SendMessage"),
("followupTask", "SendMessage"),
("closeAgent", "CloseAgent"),
("interruptAgent", "InterruptAgent"),
("listAgents", "ListAgents"),
("resumeAgent", "ResumeAgent"),
] {
let started = json!({
"method": "item/started",
"params": {
"threadId": "parent-thread",
"turnId": "turn-1",
"item": {
"id": format!("{tool}-1"),
"type": "collabAgentToolCall",
"tool": tool,
"status": "inProgress",
"senderThreadId": "parent-thread",
"receiverThreadIds": [],
"agentsStates": {},
"prompt": null,
"model": null,
"reasoningEffort": null
}
}
});
let completed = json!({
"method": "item/completed",
"params": {
"threadId": "parent-thread",
"turnId": "turn-1",
"item": {
"id": format!("{tool}-1"),
"type": "collabAgentToolCall",
"tool": tool,
"status": "completed",
"senderThreadId": "parent-thread",
"receiverThreadIds": [],
"agentsStates": {},
"prompt": null,
"model": null,
"reasoningEffort": null
}
}
});
assert_eq!(
translator.translate(&started),
vec![Event::ToolStart {
id: format!("{tool}-1"),
tool: name.to_string(),
input: json!({})
}],
"{tool} start"
);
assert_eq!(
translator.translate(&completed),
vec![Event::ToolEnd {
id: format!("{tool}-1"),
output: String::new()
}],
"{tool} completion"
);
}
}
#[test]
fn delivered_agent_messages_are_peer_messages_not_the_parents_reply() {
let event = final_item(&json!({