命令队列(Command Queue)(2026-01-16)
我们通过一个小型进程内队列将入站自动回复运行(所有频道)序列化,以防止多个智能体运行发生冲突,同时仍允许跨会话的安全并行性。
为什么
- 自动回复运行可能很昂贵(LLM 调用),当多个入站消息几乎同时到达时可能会发生冲突。
- 序列化避免争用共享资源(会话文件、日志、CLI stdin),并降低上游速率限制的可能性。
工作原理
- 一个车道感知(lane-aware)的 FIFO 队列以可配置的并发上限(未配置车道默认为 1;主车道默认为 4,子智能体默认为 8)排空每个车道。
- runEmbeddedPiAgent 通过**会话键(session key)**排队(车道 session:<key>),以保证每个会话只有一个活跃运行。
- 然后,每个会话运行被排队到一个全局车道(默认为 main),因此整体并行性由 agents.defaults.maxConcurrent 限制。
- 当启用详细日志记录时,如果在开始前等待超过约 2 秒,排队的运行会发出简短通知。
- 输入指示器(Typing indicators)仍然在排队时立即触发(当频道支持时),因此在我们等待轮次时用户体验不变。
队列模式(每个频道)
入站消息可以引导当前运行、等待后续轮次或两者兼而有之:
- steer:立即注入到当前运行中(在下一个工具边界之后取消挂起的工具调用)。如果没有流式传输,则回退到 followup。
- followup:在当前运行结束后排队等待下一个智能体轮次。
- collect:将所有排队的消息合并为单个 followup 轮次(默认)。如果消息针对不同的频道/线程,它们会单独排空以保持路由。
- steer-backlog(又名 steer+backlog):现在引导并保留消息以进行后续轮次。
- interrupt(旧版):中止该会话的活跃运行,然后运行最新消息。
- queue(旧版别名):与 steer 相同。
Steer-backlog 意味着您可以在引导运行后获得后续响应,因此流式传输表面可能看起来像重复。如果您希望每个入站消息一个响应,请首选 collect/steer。 发送 /queue collect 作为独立命令(每个会话)或设置 messages.queue.byChannel.discord: "collect"。
默认值(在配置中未设置时):
- 所有表面 → collect
通过 messages.queue 全局或每个频道配置:
{
messages: {
queue: {
mode: "collect",
debounceMs: 1000,
cap: 20,
drop: "summarize",
byChannel: { discord: "collect" }
}
}
}
队列选项
选项适用于 followup、collect 和 steer-backlog(以及当 steer 回退到 followup 时):
- debounceMs:在开始后续轮次之前等待静默(防止"继续,继续")。
- cap:每个会话的最大排队消息数。
- drop:溢出策略(old、new、summarize)。
Summarize 保留已删除消息的简短项目符号列表,并将其作为合成后续提示注入。 默认值:debounceMs: 1000,cap: 20,drop: summarize。
每个会话的覆盖
- 发送 /queue <mode> 作为独立命令以存储当前会话的模式。
- 选项可以组合:/queue collect debounce:2s cap:25 drop:summarize
- /queue default 或 /queue reset 清除会话覆盖。
范围和保证
- 适用于使用网关回复管道的所有入站频道的自动回复智能体运行(WhatsApp web、Telegram、Slack、Discord、Signal、iMessage、webchat 等)。
- 默认车道(main)对入站 + 主心跳是进程范围的;设置 agents.defaults.maxConcurrent 以允许多个会话并行运行。
- 可能存在其他车道(例如 cron、subagent),因此后台作业可以并行运行而不会阻塞入站回复。
- 每个会话车道保证一次只有一个智能体运行接触给定会话。
- 无外部依赖或后台工作线程;纯 TypeScript + promises。
故障排除
- 如果命令似乎卡住,启用详细日志并查找"queued for …ms"行以确认队列正在排空。
- 如果您需要队列深度,启用详细日志并查看队列计时行。