
多 Agent 系统里最常见的抽象是「等待所有协作者完成」。codex 的 MultiAgentV2 没有用这个抽象。它把协调拆成一组很窄的动作:发消息是排队,发任务也是排队但带唤醒标记,等待是订阅活动信号,子 Agent 完成只是往父 Agent 的 mailbox 里投一条消息。
这组设计里最容易读错的是 wait_agent。它看起来像 join,实际不是。
wait_agent 不是 join
wait_agent 可以因为四种情况返回:一条普通消息到达、一条完成通知成功投递、新的用户输入、或者超时。返回只说明「等待点附近发生了活动」,并不说明某个指定 Agent 已经结束,更不说明所有子 Agent 已经一起结束。
V1 的同名工具确实曾按 Agent final status 等待。V2 的 tool description 已经把语义改成「wait for a mailbox update from any live agent」。把 V1 的 status map 解释搬到 V2,是最容易制造错误心智模型的兼容性混读——新版代码里没有 join 分支。
消息是什么,与收到后是否立即运行,是两个字段
send_message 和 followup_task 共用同一个 message handler:先解析 target 成 Thread,确认它在 Agent registry 中可识别,必要时恢复 V2 residency,最后构造 InterAgentCommunication。真正不同的只有一个 MessageDeliveryMode:
QueueOnly→trigger_turn: false:只进 mailbox,不唤醒TriggerTurn→trigger_turn: true:进 mailbox 并请求开新 turn
InterAgentCommunication 把 routing、content、encrypted content 和 trigger_turn 保持为独立字段。「消息是什么」与「收到后是否立即运行」不是同一个字段——这是多 Agent 通信里最容易被忽略的分离。

mailbox 负责排队,activity 只负责叫醒等待者
InputQueue 是 session-scoped mailbox owner。它把 mailbox 消息存在一个 VecDeque 中,而 watch channel 只报告 Mailbox 或 Steer activity。用户 steer 写进 turn-local pending input,并把 activity 更新成 Steer。
get_pending_input 只有在 active turn 的 delivery phase 接受时才 drain mailbox item,并把它们合并在 turn-local 的 pending input 之后。先处理已 pending 的 steer,再检查 mailbox——这个顺序防止一个已经等待处理的用户输入被旧 mailbox item 遮住。但它不代表 mailbox 内容消失,真正的内容要等后续 input projection 才进入模型上下文。
child 完成只是父 mailbox 的一种消息
子 Agent 的 terminal event 之后,会调用 maybe_notify_parent_of_terminal_turn,尝试向父 Thread 投递一个 Result item——trigger_turn=false。V2 result 只包含一个 summary message 和 timed_out,不返回 mailbox 内容或 agent status。
也就是说:子 Agent 完成,父 Agent 只是「多了一条消息」。父 Agent 要不要开新 turn、什么时候处理这条消息,是父 Agent 自己的调度决定。interrupt 是另一个动作:打断目标 Agent 的当前 turn——它不关闭线程,也不保证目标会停下处理。
拆完这章的三个判断
第一,多 Agent 的「等待」是一个有边界的活动信号,不是完成证明——完成通知到达 ≠ 副作用全部落盘,跨进程调度和消息理解都不在 wait 的承诺里。第二,通信原语要拆开:发消息、唤醒、等待、打断、关闭是五个不同动作,合在一起就会产生「等待所有协作者」这种无法实现的抽象。第三,读到「等」字的时候,先问一句:等的是什么活动,谁来决定等待结束,结束之后谁能证明子任务真的完成了——三个问题答不上来,这个「等」多半是假的。
源码依据:codex-rs/core/src/tools/handlers/multi_agents_v2/message_tool.rs L12-L31、send_message.rs L24-L39、followup_task.rs L24-L39,rust-v0.144.6,commit 5d1fbf26c43abc65a203928b2e31561cb039e06d。