调研 OpenClaw 中 sessions_send 完成后触发的 announce step 机制,以及如何可靠地阻止它。
查阅了以下 OpenClaw 本地文档:
/usr/lib/node_modules/openclaw/docs/concepts/session-tool.md — sessions_send 完整机制(核心文档)/usr/lib/node_modules/openclaw/docs/tools/subagents.md — sub-agent announce 机制/usr/lib/node_modules/openclaw/docs/tools/index.md — 工具总览(含 sessions_send 快速说明)/usr/lib/node_modules/openclaw/docs/reference/transcript-hygiene.md — inter-session 消息 provenance 标记/usr/lib/node_modules/openclaw/docs/gateway/configuration-reference.md — agentToAgent 配置/usr/lib/node_modules/openclaw/docs/concepts/multi-agent.md — 多 Agent 架构After the primary run completes, OpenClaw runs a reply-back loop:
- Round 2+ alternates between requester and target agents.
- Reply exactly `REPLY_SKIP` to stop the ping‑pong.
- Max turns is `session.agentToAgent.maxPingPongTurns` (0–5, default 5).
- Once the loop ends, OpenClaw runs the agent‑to‑agent announce step (target agent only):
- Reply exactly `ANNOUNCE_SKIP` to stay silent.
- Any other reply is sent to the target channel.
- Announce step includes the original request + round‑1 reply + latest ping‑pong reply.
When an agent sends a prompt into another session via sessions_send (including
agent-to-agent reply/announce steps), OpenClaw persists the created user turn with:
- message.provenance.kind = "inter_session"
During context rebuild, OpenClaw also prepends a short [Inter-session message]
marker to those user turns in-memory so the model can distinguish them from
external end-user instructions.
sessions_send runs a reply‑back ping‑pong (reply `REPLY_SKIP` to stop; max turns via `session.agentToAgent.maxPingPongTurns`, 0–5).
After the ping‑pong, the target agent runs an announce step; reply `ANNOUNCE_SKIP` to suppress the announcement.
关键结论:announce step 是在目标 agent(被 sessions_send 的那个 agent)上运行的,announce 结果发送到目标 agent 的频道(target channel),而非 requester。
即:爱衣(agent:main:main)向 researcher(agent:researcher:main)发 sessions_send 后,researcher 完成任务后会触发 announce step 并把结果发回爱衣的 Telegram。
触发时机:sessions_send 的 ping-pong 轮次结束后,OpenClaw 在目标 agent session(被发送消息的那个 agent)上自动发起一个额外的 LLM 推理步骤。
触发路径:
1. Requester 调用 sessions_send → target 执行主任务(round 1)
2. 如果 maxPingPongTurns > 0,进入 ping-pong 轮次(最多 0-5 轮,默认 5)
3. ping-pong 结束后 → 在 target agent 上运行 announce step(额外一次 LLM call)
4. announce step 的输出发送到目标 agent 的 channel(target channel)
发送目标:target agent(被通知方)的 channel。比如 researcher 完成任务后,announce 发到爱衣的 Telegram,而不是 researcher 自己的 webchat。
Announce 内容:包含原始请求 + round-1 回复 + 最新 ping-pong 回复。
ANNOUNCE_SKIP 关键字如何工作?在哪个消息里返回才能生效?ANNOUNCE_SKIP 必须由目标 agent(在 announce step 这次推理中)精确回复(完整消息只含这 7 个字符)。
生效位置:在 ping-pong 结束后的那次专门 announce step 推理中返回。
精确要求(来自原文):Reply exactly ANNOUNCE_SKIP to stay silent
这意味着 ANNOUNCE_SKIP 是 target agent 在 announce step 这次 LLM 调用时必须回复的内容。OpenClaw 会识别这个关键字并抑制向 target channel 的推送。
NO_REPLY 和 ANNOUNCE_SKIP 的区别| 关键字 | 作用层 | 触发时机 | 效果 |
|---|---|---|---|
NO_REPLY |
消息发送层 | 任何正常回复时 | 告诉路由系统不把这条回复发到当前 session 的 channel(webchat/telegram 等),但 不影响 announce step 的触发 |
ANNOUNCE_SKIP |
announce step | announce step 那次 LLM 推理 | 完全抑制 announce step 的 channel 推送 |
REPLY_SKIP |
ping-pong 控制 | ping-pong 轮次中 | 停止 ping-pong 循环,但 announce step 仍然会触发 |
关键结论:researcher 在主任务完成后回复 NO_REPLY,这只是告诉 webchat 不显示这条回复,完全不影响 announce step。OpenClaw 仍然会在后续触发 announce step,导致额外一次 LLM 推理,并可能把结果推送到爱衣的 Telegram。
是的,会导致双重通知,原因如下:
第一条通知(有 [Inter-session message] 前缀):
- 来源:researcher 完成任务后,调用 sessions_send 发给 agent:main:main
- 这是正式的 inter-session 消息,OpenClaw 标记 message.provenance.kind = "inter_session",在爱衣的 session 中注入时会加 [Inter-session message] 前缀
第二条通知(无前缀):
- 来源:sessions_send 触发的 announce step,由 researcher 的 announce step 推理完成后推送给爱衣的 channel(Telegram)
- 这是额外的 LLM 调用结果,直接发到 target channel(爱衣的 Telegram),绕过了 inter-session 标记
- 不含 [Inter-session message] 前缀
两条通知内容相似(都是 task_id + task.md 路径),所以爱衣的 collect 队列合并后发了两次 sessions_send 给 researcher。
有两种方式:
方式一(推荐):在 sessions_send 之后的正常回复中包含 ANNOUNCE_SKIP
这里有一个理解误区需要澄清:ANNOUNCE_SKIP 不是在 sessions_send 之前配置的,而是在 announce step 那次推理中回复的。所以 AGENTS.md 应该这样写:
7. 通知发出后,**必须回复 `ANNOUNCE_SKIP`** 作为最终输出(不是 `NO_REPLY`)。
这样 announce step 就不会推送到爱衣的 Telegram,避免双重通知。
方式二(推荐,更彻底):配置 maxPingPongTurns=0
通过 OpenClaw 配置,将 session.agentToAgent.maxPingPongTurns 设为 0,可以跳过 ping-pong 轮次。但 announce step 仍然会触发,只是没有 ping-pong 了。所以仍然需要 ANNOUNCE_SKIP。
方式三(最彻底):AGENTS.md 规则明确
## sessions_send 通知规则
完成任务,发出 sessions_send 通知后:
- ✅ 回复 `ANNOUNCE_SKIP`(精确,完整消息只含这 8 个字符)
- ❌ 不要回复 `NO_REPLY`(这只影响当前 session 频道,不阻止 announce step)
- ❌ 不要回复任何其他内容(会被作为 announce 推送给爱衣)
| 问题 | 答案 |
|---|---|
| announce step 是什么 | sessions_send ping-pong 结束后,在 target agent 上额外触发的 LLM 推理步骤,结果推送到 target agent 的 channel |
| ANNOUNCE_SKIP 生效位置 | target agent 在 announce step 那次推理中精确回复(完整消息只含 ANNOUNCE_SKIP) |
| NO_REPLY 能阻止 announce 吗 | 不能,NO_REPLY 只影响当前 session 的 channel 输出 |
| 为何爱衣收到两条通知 | 第一条:researcher 的 sessions_send;第二条:announce step 推送。两条都到了爱衣的 Telegram |
| 正确阻止方式 | researcher 发完 sessions_send 后,回复 ANNOUNCE_SKIP 而非 NO_REPLY |