任务 ID: task-announce-step  |  文件: session.md  |  最后修改: 2026-02-25 01:17:53

Session Log — task-announce-step

任务目标

调研 OpenClaw 中 sessions_send 完成后触发的 announce step 机制,以及如何可靠地阻止它。


执行过程

文档检索

查阅了以下 OpenClaw 本地文档:

  1. /usr/lib/node_modules/openclaw/docs/concepts/session-tool.md — sessions_send 完整机制(核心文档)
  2. /usr/lib/node_modules/openclaw/docs/tools/subagents.md — sub-agent announce 机制
  3. /usr/lib/node_modules/openclaw/docs/tools/index.md — 工具总览(含 sessions_send 快速说明)
  4. /usr/lib/node_modules/openclaw/docs/reference/transcript-hygiene.md — inter-session 消息 provenance 标记
  5. /usr/lib/node_modules/openclaw/docs/gateway/configuration-reference.md — agentToAgent 配置
  6. /usr/lib/node_modules/openclaw/docs/concepts/multi-agent.md — 多 Agent 架构

关键发现(原文引用)

sessions_send 的完整执行流程(来自 session-tool.md)

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.

关于 inter-session 消息的 provenance(来自 transcript-hygiene.md)

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.

announce step 向哪里发送(来自 tools/index.md)

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。


五个问题的答案

Q1: announce step 是什么?什么时候触发、向哪里发送?

触发时机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 回复。

Q2: 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 的推送。

Q3: NO_REPLYANNOUNCE_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。

Q4: announce step 是否会导致爱衣收到两条相同通知?

是的,会导致双重通知,原因如下:

第一条通知(有 [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。

Q5: 如何在 AGENTS.md 中正确配置规则,确保 announce step 被阻止?

有两种方式:

方式一(推荐):在 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