diff --git a/.gitignore b/.gitignore index 55316c4..1f11cc5 100644 --- a/.gitignore +++ b/.gitignore @@ -16,3 +16,5 @@ Thumbs.db *.env secrets/ credentials/ +.harness/ +CLAUDE.md diff --git a/README.md b/README.md index 8f60b35..6969e59 100644 --- a/README.md +++ b/README.md @@ -14,19 +14,23 @@ --- -## 📢 近况更新(2026 年 3 月 19 日) +## 📢 近况更新(2026 年 4 月) -感谢越来越多的同学关注 OpenCrew。项目有一段时间没更新了,但这也是我自己一直在用的架构——**项目没有停,方向没有变。** 后续会在合适的时机持续更新,也欢迎大家多提 Issue 反馈问题和需求。 +### A2A v2:Agent 之间能真正讨论了 -OpenCrew 还在早期,很多实现方式还不够高效,但核心目标始终清晰:**让每个人都能管好一支多 Agent 团队——有机协同、稳定迭代。** +我们解决了 OpenCrew 自诞生以来最大的架构限制:**Agent 之间现在可以像真人一样在同一个 Slack 频道里讨论问题**,而不只是单向派任务。 -目前在做的事:看板与聊天界面的项目管理融合、Agent 智能 Onboarding(从海量开源 Agent 和 Skills 中精炼选型方法论,让系统能自动引入新 Agent)、架构简化(当前 A2A 依赖补丁方案,正跟踪 OpenClaw 上游的系统级支持)、以及探索更适合多 Agent 架构的记忆管理体系。各方向都在测试新技术,但我不想推未经验证的临时方案——开源生态在快速革新,我会在时机成熟时做一次有质量的更新。 +**之前**:所有 Agent 共享一个 Slack bot → bot 不能触发自己 → Agent 之间只能靠 `sessions_send` 单向委派。 -就我个人体感来说,**Slack 目前仍是多 Agent 管理的最优解。** 我在一个 Workspace 管理两台设备上的 17 个 Agent,体验已经很流畅。Slack 新上线的 Activity 页面(类似邮件收件箱)非常适合批量处理 Agent 通知。 +**现在**:给少数关键 Agent(如你的幕僚长 / 编排者)创建一个独立 Slack App → 把它拉进任意 Agent 的频道 → 两个 Agent 直接对话,你可以实时旁观。 -我相信关注这个仓库的同学,大多已经有了深度的 Agent 和 AI 协作经验,并且希望利用多 Agent 在工作和生活中创造更大的价值。在这个基础上,可能不少人也在思考一个更进一步的问题:**如何真正发挥 Coding Agent 的能力去打造生产级应用,而不只是用 Lovable 之类的工具做一个 demo。** 我最近在做的另一个项目 **[Agent-First Development](https://github.com/AlexAnys/agent-first-dev)** 就围绕这个方向——面向非技术或全栈背景的构建者,内容框架参考 Stanford (已获授权) 和 Chicago Booth 的相关课程,同样在持续开发中,欢迎关注。 +![A2A v2 架构](docs/OpenCrew-A2A-V2-架构图.svg) -**感谢每一位关注者的耐心。下一个更新不远了。** +这个架构借鉴了 [Anthropic Harness Design](https://www.anthropic.com/engineering/harness-design-long-running-apps) 的核心洞察:**生成者(执行)和评估者(QC)必须分离**——因为同一个 AI 既做事又自检时,它倾向于对自己宽容。在 OpenCrew 中,编排者负责规划和质量把关,执行层 Agent 负责干活,两者通过 @mention 在 Slack 频道里自然协作。 + +**设置只需三步**:创建一个独立 Slack App → 配置多账号 → 把 bot 拉进目标频道。详见 → [Discussion Mode 配置指南](docs/A2A_SETUP_GUIDE.md) + +> 更多技术细节和实战踩坑记录 → [A2A 协议 v2](shared/A2A_PROTOCOL.md) · [核心概念](docs/CONCEPTS.md#a2a-的两种模式delegation-与-discussion) --- @@ -226,9 +230,14 @@ OpenCrew 的运转靠几个关键机制。下面是 30 秒速览,详细说明 | P | 项目(多步骤、跨天) | 需要 + Checkpoint | | S | 系统变更 | 需要 + Ops 审计 | -**A2A 两步触发** — Agent 之间怎么协作 +**A2A 两种模式** — Agent 之间怎么协作 + +| 模式 | 适用场景 | 机制 | 平台 | +|------|---------|------|------| +| **Delegation(委派)** | 派具体任务 | `sessions_send` 两步触发 | Slack / Discord / 飞书 | +| **Discussion(讨论)** | 多方讨论、评审、协商 | 独立 Bot @mention 对话 | Slack | -因为所有 Agent 共用一个 Slack bot,bot 自己发的消息不会触发自己。所以跨 Agent 协作需要两步:先在目标频道发一条可见消息(锚点),再用 `sessions_send` 真正触发对方。细节见 → [A2A 协议](shared/A2A_PROTOCOL.md) +Delegation 是基础——CTO 给 Builder 派活。Discussion 是增强——编排者走进 CTO 的频道,两个 Agent 直接讨论方案,你在旁边看着。细节见 → [A2A 协议 v2](shared/A2A_PROTOCOL.md) **三层知识沉淀** — 经验怎么从聊天记录变成组织资产 @@ -243,12 +252,18 @@ Layer 2: KO 提炼的抽象知识(原则 / 模式 / 踩坑记录) ## 跑通 A2A 闭环 > 部署完成后,每个 Agent 各自能回复消息 ≠ Agent 之间能协作。 -> A2A(Agent-to-Agent)闭环需要额外配置和验证。 +> A2A(Agent-to-Agent)需要额外配置。OpenCrew 支持两种模式: -### 什么是 A2A 闭环? +### Delegation(委派)— 派任务 你在 `#cto` 给 CTO 一个开发任务 → CTO 自动在 `#build` 给 Builder 派单 → Builder 在 thread 里分轮执行 → 每轮进展在 Slack 可见 → CTO 回到 `#cto` 汇报结果。**全程你只需要看 Slack。** +### Discussion(讨论)— 多 Agent 协作 `NEW` + +选一个 Agent 作为你的编排者(如 CoS),给它创建独立 Slack App → 把它拉进 CTO 和 Builder 的频道 → 编排者在频道里 @mention 执行 Agent 发起讨论 → 执行 Agent 回复 → 编排者评估、追问或结束 → **你看到的是两个 Agent 在 Slack 里像同事一样讨论问题。** + +> 为什么要分离?借鉴 Anthropic Harness Design:同一个 AI 既执行又自检时倾向于宽容自己。编排者专注规划和 QC,执行 Agent 专注干活——这是让 AI 协作真正有效的关键分工。 + ### 让你的 Agent 自动完成 A2A 设置 > ⚠️ **首次设置提醒**:A2A 闭环流程中,Agent 会检查并补全 `openclaw.json` 的 A2A 配置(如 `agentToAgent.allow`、`maxPingPongTurns`)。配置变更会**自动触发 OpenClaw gateway 重启**,导致所有 Agent 的当前会话短暂中断。这是正常的一次性设置过程——重启完成后 Agent 会自动恢复,你只需要重新发起验证步骤即可。 @@ -288,7 +303,7 @@ Layer 2: KO 提炼的抽象知识(原则 / 模式 / 踩坑记录) | **[完整上手指南](docs/GETTING_STARTED.md)** | 从零到跑通的详细步骤 + 常见问题 | 第一次部署 | | **[核心概念详解](docs/CONCEPTS.md)** | 自主等级、QAPS、A2A、知识沉淀的完整说明 | 想深度理解系统 | | **[架构设计](docs/ARCHITECTURE.md)** | 三层架构、设计取舍、为什么这么做 | 想理解设计思路 | -| **[A2A 跑通指南](docs/A2A_SETUP_GUIDE.md)** | A2A 配置、workspace 补丁、验证步骤 | 让 Agent 间能协作 | +| **[A2A 跑通指南](docs/A2A_SETUP_GUIDE.md)** | Delegation + Discussion 配置、多账号设置、验证步骤 | 让 Agent 间能协作 | | **[自定义指南](docs/CUSTOMIZATION.md)** | 增删改 Agent、替换领域专家 | 想调整团队配置 | | **[已知问题](docs/KNOWN_ISSUES.md)** | 系统的真实边界和当前最佳实践 | 遇到奇怪行为时 | | **[开发历程](docs/JOURNEY.md)** | 从一个人的痛点到一支虚拟团队 | 想了解来龙去脉 | @@ -312,7 +327,8 @@ Layer 2: KO 提炼的抽象知识(原则 / 模式 / 踩坑记录) ### ✅ 已稳定运行 - 多 Agent 领域分工 + 频道绑定(Slack / 飞书 / Discord) -- A2A 两步触发(Slack 可见锚点 + sessions_send) +- A2A Delegation(两步触发:Slack 可见锚点 + `sessions_send`) +- A2A Discussion(独立 Bot @mention 协作,Slack 已验证)`NEW` - A2A 闭环(多轮 WAIT 纪律 + 双通道留痕 + 闭环 DoD) - Closeout / Checkpoint 强制结构化产物 - Autonomy Ladder(L0-L3) @@ -323,7 +339,7 @@ Layer 2: KO 提炼的抽象知识(原则 / 模式 / 踩坑记录) - 更好的知识系统(跨 session 语义检索) - 更轻量的架构(v2-lite:7 Agent → 5,9 个 shared 文件 → 3) -- Slack root message 独立 session 的更稳定方案 +- Discord Discussion 模式(受 OpenClaw 代码层 bug 阻塞,非平台限制) --- diff --git a/docs/A2A_SETUP_GUIDE.md b/docs/A2A_SETUP_GUIDE.md index 46de8c9..7c5a3d0 100644 --- a/docs/A2A_SETUP_GUIDE.md +++ b/docs/A2A_SETUP_GUIDE.md @@ -1,266 +1,324 @@ -**中文** | [English](en/A2A_SETUP_GUIDE.md) +# Discussion Mode 实操指南 — 独立 Bot 引入 + 协作机制 -# A2A 跑通指南 — 给 Agent 读的设置文档 - -> **这个文档的读者是 Agent(推荐由 Ops 执行),不是人。** -> 目标:用最小必要变更,让你的 OpenCrew 的 A2A 闭环真正跑通。 -> 如果你是人类用户,可以直接把 [README 里的 prompt](#快速-prompt) 发给你的 Ops / CTO / 任一 Agent。 +> 供审计用。基于 2026-03-30 ~ 2026-04-02 实战测试。 +> PR: https://github.com/AlexAnys/opencrew/pull/38 --- -## 0. 前置条件 - -- OpenCrew 已部署(最小可用:CoS + CTO + Builder,各自能在 Slack 频道正常回复) -- 如果部署了 Ops,Ops 可以执行本指南;否则可由 CTO 或任一 Agent 执行 -- `openclaw.json` 中 `tools.agentToAgent.enabled: true` -- Agent 间的 Slack 频道绑定(bindings)已配好 - ---- +## 第一部分:如何引入独立 Bot -## 1. 关键认知:为什么 A2A 需要"设置" +### 背景 -OpenCrew 部署完成后,每个 Agent 都能独立回答问题。但 **跨 Agent 协作(A2A)** 需要额外条件: +OpenCrew 默认所有 Agent 共享一个 Slack App(一个 bot user)。这意味着 Bot A 发到 Bot B 频道的消息会被 self-reply filter 忽略(同一个 bot user)。 -| 问题 | 原因 | 解法 | -|------|------|------| -| CTO 在 #build 发消息,Builder 不响应 | 同一个 bot 的消息默认被忽略(防自循环) | 两步触发:Slack 锚点 + `sessions_send` | -| `sessions_send` 返回 timeout | OpenClaw 默认超时较短 | timeout ≠ 失败;需要 thread 兜底消息 | -| Builder 做完了但用户不知道 | 结果只在 A2A 内部流转 | 双通道:A2A reply + Slack thread 留痕 | -| 任务做完但没人汇报 | 没有闭环规则 | DoD 硬规则:回发起频道汇报 | - ---- +**Discussion Mode** 的前提是"选择性独立化":让少数高价值 Agent(如 Orchestrator)拥有独立 Slack App,然后拉进其他 Agent 的频道直接对话。 -## 2. 配置层变更(openclaw.json) +### Step 1:创建独立 Slack App -以下是跑通 A2A 的**最小必要配置变更**。用 `config.patch` 或手动编辑均可。 - -### 2.1 agentToAgent.allow — 谁能发起 A2A +在 [api.slack.com/apps](https://api.slack.com/apps) → Create New App → **From manifest**: ```json { - "tools": { - "agentToAgent": { - "enabled": true, - "allow": ["cos", "cto", "ops", "ko", "builder"] + "display_information": { + "name": "Ali-Bot", + "description": "OpenClaw Discussion Mode agent" + }, + "features": { + "bot_user": { + "display_name": "Ali-Bot", + "always_online": true + }, + "app_home": { + "messages_tab_enabled": true, + "messages_tab_read_only_enabled": false + } + }, + "oauth_config": { + "scopes": { + "bot": [ + "chat:write", + "im:write", + "channels:history", + "groups:history", + "groups:read", + "im:history", + "im:read", + "mpim:history", + "mpim:read", + "channels:read", + "users:read", + "app_mentions:read", + "assistant:write", + "reactions:read", + "reactions:write", + "pins:read", + "pins:write", + "emoji:read", + "files:read", + "files:write" + ] + } + }, + "settings": { + "event_subscriptions": { + "bot_events": [ + "app_mention", + "message.channels", + "message.groups", + "message.im", + "message.mpim", + "reaction_added", + "reaction_removed", + "member_joined_channel", + "member_left_channel", + "channel_rename", + "pin_added", + "pin_removed" + ] + }, + "socket_mode_enabled": true, + "org_deploy_enabled": false, + "is_hosted": false, + "token_rotation_enabled": false } - } } ``` -> **为什么 builder 也在里面?** Builder 需要能用 `sessions_send` 回复 CTO 的多轮指导。如果你的 Builder 仅通过 Slack thread 回复(不走 A2A reply),可以不加 builder。 +创建后: +1. Basic Information → App-Level Tokens → Generate Token(scope: `connections:write`)→ 拿到 `xapp-...` +2. Install to Workspace → 拿到 `xoxb-...` +3. 记录 Bot User ID(Settings → Basic Info 或在 Slack 中查看 bot profile) -### 2.2 maxPingPongTurns — 多轮迭代上限 +### Step 2:配置 OpenClaw 多账号 -```json -{ - "session": { - "agentToAgent": { - "maxPingPongTurns": 5 - } - } -} -``` +> ⚠️ **硬性要求:必须同时声明 `accounts.default`** +> +> `account-helpers.ts:listAccountIds()` 的逻辑:一旦 `accounts` 对象存在且有任何 key,OpenClaw **只启动显式声明的账号**,不再隐式创建 default。 +> +> 如果只添加 `accounts.ali-bot` 而不添加 `accounts.default`,主 bot 的 provider 不会启动,所有现有 Agent 的 Slack 连接将断开。 +> +> 这不是 bug,是设计如此。 -> 默认 4 轮。建议 5 轮(给 Round0 握手 + 3-4 轮实际工作留空间)。 +**正确配置**(增量修改 `openclaw.json`): -### 2.3 subagents 防无限扇出(通常已默认配好) - -```json +```jsonc { - "tools": { - "subagents": { - "tools": { - "deny": ["group:sessions"] + "channels": { + "slack": { + // 顶层 token 保留为 fallback + "botToken": "xoxb-main-...", + "appToken": "xapp-main-...", + + // ★ 关键:显式声明 accounts.default + "accounts": { + "default": { + "botToken": "xoxb-main-...", // 与顶层相同 + "appToken": "xapp-main-..." // 与顶层相同 + }, + "ali-bot": { + "botToken": "xoxb-ali-...", + "appToken": "xapp-ali-...", + "channels": { + "": { + "allow": true, + "requireMention": true, // 只响应显式 @mention + "allowBots": true // 能看到其他 bot 的消息 + } + } + } + }, + + // 目标频道开启 allowBots(让原有 Agent 看到 Ali-Bot 的消息) + "channels": { + "": { + "allow": true, + "requireMention": true, // 建议改为 true(见第二部分) + "allowBots": true + } + } + } + }, + + // Ali-Bot 的路由绑定 + "bindings": [ + // ★ 放在目标频道的 peer binding 之前(更具体的匹配优先) + { + "agentId": "main", + "match": { + "channel": "slack", + "accountId": "ali-bot", + "peer": { "kind": "channel", "id": "" } + } + }, + // 现有 binding 不变 + { + "agentId": "ops", + "match": { + "channel": "slack", + "peer": { "kind": "channel", "id": "" } } } - } + ] } ``` ---- - -## 3. Workspace 文件变更(最小必要) - -以下是需要在各 Agent 的 `AGENTS.md` 中**追加**的内容。不需要重写整个文件,只需在合适位置加入对应 section。 - -### 3.1 CTO 的 AGENTS.md — 追加 A2A 派单 section +### Step 3:邀请 Bot 并验证 -在 CTO 的 `AGENTS.md` 中,找到任务处理流程之后,追加: +1. 在目标频道执行 `/invite @Ali-Bot` +2. 写入 config 后**等待热重载**(不要立即 SIGTERM,热重载会自动检测变更) +3. 检查 gateway 日志确认两个 provider 都启动: -```markdown -## A2A 派单(主流程:跨频道 thread) - -当进入实施阶段: -- 在 **#build**(或 #research)创建任务 root message(锚点): - `A2A CTO→Builder | | TID:<...>` -- 正文给完整任务包(建议 `shared/SUBAGENT_PACKET_TEMPLATE.md`)。 -- ⚠️ 不要依赖 Slack 的"看到消息就自动触发"(bot-authored inbound 默认会被忽略,避免自循环)。 -- 必须用 **sessions_send** 把任务真正触发到目标 thread sessionKey: - `agent:builder:slack:channel:<#build_id>:thread:<root_ts>` - -执行期间(CTO 负责到底): -- **#build thread 留痕**:每轮 ping-pong 中,用 `message(send, channel=slack, target=<#build_id>, threadId=<root_ts>)` 把你这轮的指令/反馈贴到 #build thread,格式 `[CTO] 内容...`。Builder 也会在 thread 里贴它的进展。 -- **#cto checkpoint**:每次收到 Builder 的 checkpoint/结果后,在 #cto 的对应协调 thread 同步一条 checkpoint(让用户不用去 #build 捞信息)。 - -sessions_send timeout 容错: -- `sessions_send` 返回 timeout **≠ 没送达**。 -- 规避:在 thread 里补发一条兜底消息("已通过 A2A 发送,如未收到可在此查看全文")。 - -完成后(DoD 硬规则,缺一不可): -1. 在 Builder thread 贴 closeout(产物路径 + 验证命令)。 -2. **CTO 本机复核**(CLI-first):至少执行关键命令 + 贴 exit code,确认产出可用。 -3. **回 #cto 汇报**:在 #cto 发起 thread 同步最终结果 + 如何验证 + 风险遗留。**这是闭环关键,不做视为任务未完成**。 +``` +[slack] [default] starting provider ✅ +[slack] [ali-bot] starting provider ✅ +channels resolved: ...(无 missing_scope) ✅ +socket mode connected ✅(出现两次) ``` -### 3.2 Builder 的 AGENTS.md — 追加 A2A 协作 section - -在 Builder 的 `AGENTS.md` 中,执行流程之后追加: - -```markdown -## A2A 协作(收到 sessions_send 任务时) - -当通过 `sessions_send` 收到来自 CTO 的 A2A 任务: - -1. **识别 thread_id**:A2A 消息中会包含 `#build thread_id`(message_id) -2. **多轮 WAIT 纪律**: - - 每轮只聚焦 1-2 个改动点,完成后**必须 WAIT** - - 输出格式固定:`Done: ... / Run: ... / Output: ... / WAIT` - - **禁止一次性做完所有步骤**——等 CTO 下一轮指令后再继续 -3. **贴进展到 thread**:每轮回复前,先用 `message(send, channel=slack, target=<#build_id>, threadId=<thread_id>)` 把本轮进展/结果贴到 #build thread,格式 `[Builder] 内容...` -4. **返回 A2A reply**:正常返回结果给 CTO(sessions_send 的 ping-pong 机制) -5. **最终轮**:贴 closeout 到 thread(产物路径 + 验证命令),A2A reply 中回复 `REPLY_SKIP` 表示完成 +### 回滚 -> ⚠️ thread 留痕是为了用户能在 #build 直接看到完整过程。A2A reply 是给 CTO 的结构化回复。两者都要做。 +```bash +cp ~/.openclaw/openclaw.json.bak-before-xxx ~/.openclaw/openclaw.json +# 等待热重载,或: +launchctl kill SIGTERM gui/501/ai.openclaw.gateway ``` -### 3.3 CoS 的 AGENTS.md — 追加 A2A 指派 section +### 已知陷阱 -CoS 是用户的主入口,向 CTO/CIO 指派任务是常见路径: +| 陷阱 | 后果 | 防范 | +|------|------|------| +| 只加 `accounts.ali-bot` 不加 `accounts.default` | 主 bot 断连,所有 Agent 失联 | 必须同时声明 default | +| config 写入后立即 SIGTERM | 热重载的 in-memory 修复被杀掉 | 等热重载完成再验证 | +| Ali-Bot Slack App 缺 scope | `channels resolved` 报 `missing_scope` | 用完整 manifest 创建 | +| Binding 顺序错误 | ali-bot 的消息路由到错误的 agent | accountId+peer binding 放在 peer-only binding 之前 | -```markdown -## A2A 指派(CoS → CTO / CIO) +--- -当需要让 CTO 处理技术任务: -- 在 **#cto** 创建任务 root message: - `A2A CoS→CTO | <TITLE> | TID:<...>` -- 正文给完整任务包(建议 `shared/SUBAGENT_PACKET_TEMPLATE.md`)。 -- 用 `sessions_send` 触发 CTO: - `agent:cto:slack:channel:<#cto_id>:thread:<root_ts>` -- 等待 CTO 在 #cto 的结果汇报,收到后同步到 #hq 向用户汇报。 +## 第二部分:引入后的协作机制 -当需要让 CIO 处理领域任务(如投资分析): -- 同理在 **#invest** 创建 root message 并用 `sessions_send` 触发。 +### 核心挑战 -sessions_send timeout 容错:同 CTO(timeout ≠ 失败,需 thread 兜底)。 -``` +两个 bot 在同一 Slack thread 中,会遇到三个问题: +1. **双响应**:人类发一条消息,两个 bot 都回复 +2. **循环**:Bot A 回复 → Bot B 被触发也回复 → Bot A 又被触发 → ∞ +3. **无路由**:没有机制决定"谁该回复、谁该沉默" ---- +### 为什么 Config 不够(源码验证) -## 4. 验证步骤(跑通检查清单) +| Config 选项 | 预期 | 实际 | +|---|---|---| +| `requireMention: true` | Thread 内只响应显式 @mention | ❌ 一旦 bot 在 thread 中回复过,`implicitMention` 永远为 true,绕过 requireMention | +| `allowBots: "mentions"` | 只处理显式 @mention 自己的 bot 消息 | ❌ Slack provider 只做 truthy/falsy 检查,`"mentions"` 等同于 `true`(仅 Discord 有效) | -### 4.1 配置验证 +**源码证据**(`resolveMentionGating`): -```bash -# 检查 agentToAgent 是否启用 -# 在 openclaw.json 中确认: -# tools.agentToAgent.enabled = true -# tools.agentToAgent.allow 包含 cos, cto, ops -# session.agentToAgent.maxPingPongTurns >= 5 +```js +implicitMention = !isDirectMessage && botUserId && message.thread_ts && + (message.parent_user_id === botUserId || hasSlackThreadParticipation(...)) +// → 一旦 bot 参与过 thread,implicitMention 永远 true +// → requireMention: true 被永久绕过 ``` -### 4.2 CTO → Builder 闭环验证 +### 解决方案:两层防线 -在 `#cto` 频道告诉 CTO: +#### 第 1 层:Config — `requireMention: true`(Channel 级生效) -``` -请执行一次 A2A 闭环测试: -1. 在 #build 创建一个测试任务(让 Builder 执行 `pwd && ls -la | head` 并回报) -2. 用 sessions_send 触发 Builder -3. 确认 Builder 在 Slack thread 里回复了(Round0 握手) -4. 完成后回 #cto 汇报结果 +```jsonc +"<CHANNEL_ID>": { + "allow": true, + "requireMention": true, // 对 channel 根消息有效 + "allowBots": true +} ``` -**验收标准**: -- ✅ #build 出现了 root message(A2A CTO→Builder | ...) -- ✅ Builder 在该 thread 里回复了(`[Builder] Done: ... / WAIT`) -- ✅ CTO 回到 #cto 汇报了结果 +**效果**:Channel 根消息必须显式 @ 才触发 → 只有被 @ 的 bot 进入 thread。 +**局限**:Thread 内无效(implicitMention 绕过)。 -### 4.3 CoS → CTO 闭环验证 +#### 第 2 层:Prompt 规则 — 显式 @mention 协议(Thread 级生效) -在 `#hq` 频道告诉 CoS: +在每个参与 Discussion Mode 的 Agent 的 workspace 文件中加入: -``` -请执行一次 A2A 闭环测试: -1. 在 #cto 创建一个任务 root message(让 CTO 检查当前 workspace 目录结构并回报) -2. 用 sessions_send 触发 CTO -3. 确认 CTO 在 Slack thread 里回复了 -4. CTO 完成后,回 #hq 向我汇报结果 -``` - -**验收标准**: -- ✅ #cto 出现了 root message(A2A CoS→CTO | ...) -- ✅ CTO 在该 thread 里回复了 -- ✅ CoS 回到 #hq 汇报了结果 +```markdown +## Multi-Agent Thread 协作规则 ---- +在 Slack thread 中如果有其他 bot 也在参与: -## 5. 已验证的关键模式(从实战中沉淀) +1. **显式 @mention 检查**:检查消息文本是否包含 `<@你的BotID>`。 + 如果没有 → 整条回复只输出 `NO_REPLY`,不解释、不叙述、不加任何其他文字。 -这些模式经过 CTO↔Builder 和 CTO↔Ops 的真实 A2A 闭环验证: +2. **发送消息时必须 @mention 目标**:`<@目标BotID>` 显式 mention 目标 bot。 + 不 @ 任何 bot = 对话终止信号。 -### 5.1 Round0 审计握手 +3. **角色分工**: + - Coordinator(发起方):选择 @Worker / @Human / 不@(结束) + - Worker(执行方):每次回复必须 @ Coordinator -在正式任务前,先做一个**极小的真实动作**验证审计链路: -- 要求目标 Agent 执行 `pwd` 并把结果贴到 Slack thread -- **看不到 Round0 回传就停止**——说明目标 Agent 的 session 可能没绑定 Slack +4. **终止**:说"完毕/done/结论"后不再发送,除非被重新 @。 -### 5.2 多轮 WAIT 纪律 +5. **轮次上限**:同一 thread 内最多 8 轮回复,超过后暂停并向人类汇报。 -每轮只做 1-2 个改动点,输出后 WAIT: -``` -[Builder] Round 1/3 -Done: 创建了 xxx 文件 -Run: node xxx.js -Output: exit 0 -WAIT: 等待 CTO 指令 +Bot ID 速查: +- Ali-Bot: U0AP8JFFD7Z +- Default Bot (Ops/CTO/Builder 等): U0AD60Q0EKU ``` -**禁止一次性做完所有步骤**——这会跳过指导链路,失去多轮迭代的审计和纠错价值。 +### 协作流程(文件 + 频道) -### 5.3 sessions_send timeout 容错 +借鉴 Anthropic Harness Design 的**双角色架构**: -`sessions_send` 返回 timeout **不等于失败**。消息可能已送达。 -规避:在 Slack thread 里补发一条兜底消息。 - -### 5.4 闭环 DoD(Definition of Done) +``` +Alex → @Orchestrator: "调查 XXX" -任务完成的标准不是"Builder 做完了",而是: -1. Builder thread closeout ✅ -2. CTO 本机复核(CLI-first)✅ -3. **回 #cto 汇报**(这一步是闭环关键)✅ -4. 通知 KO 沉淀(可选)✅ +Orchestrator 输出 DISCUSSION SPEC(Phase 0): + → 📁 discussions/<topic>/spec.md(目标 + 验收标准 + 终止条件) + → Thread 消息:「展开了 spec,N 条验收标准。@Worker 请先...」 -### 5.5 SessionKey 注意事项 +Round 1: + Orchestrator → @Worker: 具体问题 + Worker → @Orchestrator: 回复 + 📁 round-1.md(详细分析) + Thread 消息只放摘要 -- 不要手打 sessionKey,从 `sessions_list` 复制 -- 注意 channel ID 大小写一致性(大小写不一致可能导致 session 路由到 webchat) +Round 2: + Orchestrator 评估 → 📁 review-1.md → @Worker 反馈 + ... ---- +终止(三选一): + ✅ 达成共识 → DISCUSSION_CLOSE + ⚠️ 达到最大轮次 → 请人类介入 + 🔄 连续 2 轮无进展 → 请人类介入 +``` -## 6. 常见问题 +**关键原则**: +1. **文件是主通信通道**——Slack thread 只放摘要和 @mention 路由,详细分析/方案写文件 +2. **先 spec 再讨论**——Orchestrator 第一条消息必须定义验收标准和终止条件 +3. **自评失效,必须分离**——Orchestrator 不生成方案,只协调和评估 +4. **正式 A2A 任务走 `sessions_send`**——有硬性 `maxPingPongTurns` (0-5),Slack thread 仅做留痕 -**Q:配置改完需要重启吗?** -A:用 `config.patch` 会自动重启。手动编辑需要 `openclaw gateway restart`。⚠️ **注意**:gateway 重启会中断所有 Agent 的当前会话。首次 A2A 设置时这是预期行为(一次性),重启后 Agent 会自动恢复。如果 Agent 在设置过程中"突然停止工作",大概率是重启导致的——等恢复后重新发起验证即可。 +### 终止机制 -**Q:Builder 在 thread 里没回复怎么办?** -A:检查 `bindings` 是否正确、频道是否 `allow: true`、Builder 的 session 是否绑定了 Slack(而非 webchat)。 +| 层级 | 机制 | 类型 | +|------|------|------| +| Prompt | @mention 协议 + Round N/M 计数 + DISCUSSION_CLOSE | 软约束(指令遵从) | +| Config | `requireMention: true`(Channel 根消息) | 硬约束(系统级) | +| Config | `loopDetection.pingPong: true` | 硬约束(tool-call 级别) | +| A2A | `maxPingPongTurns` (sessions_send) | 硬约束(系统级) | -**Q:可以让 Builder 直接给 CTO 发 A2A 吗?** -A:可以,但组织纪律上 Builder 是"只接单执行"。如果 Builder 需要澄清,建议在 Slack thread 里直接提问(CTO 能看到)。 +### 已知局限 -**Q:CIO 也需要 A2A 吗?** -A:取决于你的使用场景。CIO 通常独立运作,只在需要 Research 时用 spawn。如果需要 CoS→CIO 派单,按同样模式配即可。 +1. **Input token 仍消耗**——消息被送达所有 bot,只是 agent 选择 NO_REPLY;无法从 config 阻止送达 +2. **Prompt 是软约束**——LLM 可能偶尔违反(特别在复杂上下文中) +3. **`allowBots: "mentions"` 仅 Discord 可用**——Slack 需要 OpenClaw 代码改动 +4. **`requireMention: true` 在 thread 内被绕过**——需要 OpenClaw 增加 `thread.requireExplicitMention` 才能系统级解决 --- -> 📖 相关文档 → [A2A 协议](../shared/A2A_PROTOCOL.md) · [核心概念](CONCEPTS.md) · [Agent 入职指南](AGENT_ONBOARDING.md) · [自定义指南](CUSTOMIZATION.md) +## 平台能力对比 + +| 能力 | Slack | Discord | Feishu | +|------|-------|---------|--------| +| Delegation (sessions_send) | ✅ | ✅ | ✅ | +| Discussion (跨 bot 对话) | ✅ 已验证 | ❌ (OpenClaw bug) | ❌ (平台限制) | +| `allowBots: "mentions"` | ❌ (不支持) | ✅ | N/A | +| `requireMention` 在 thread | ❌ (implicitMention 绕过) | ❌ (同理) | N/A | +| Multi-Account | ✅ | ✅ | ✅ | +| 硬性轮次控制 | 仅 sessions_send | 仅 sessions_send | 仅 sessions_send | diff --git a/docs/CONCEPTS.md b/docs/CONCEPTS.md index 200ca33..7b42211 100644 --- a/docs/CONCEPTS.md +++ b/docs/CONCEPTS.md @@ -119,6 +119,59 @@ Builder → 不能派单(只接单执行) CIO → 独立运作(必要时与 CoS 同步) ``` +### A2A 的两种模式:Delegation 与 Discussion + +上面描述的两步触发是 **Delegation(委派)** 模式——一个 Agent 通过 `sessions_send` 把结构化任务交给另一个 Agent。这是 A2A 的基础,所有平台都支持,流程清晰、单向可控。 + +v2 引入了第二种模式:**Discussion(讨论)**。少数高价值 Agent(如 Orchestrator)拥有独立 Slack App,直接进入其他 Agent 的频道进行实时讨论。 + +**核心思路:选择性独立化。** 不需要每个 Agent 都有独立 App——执行层(CTO、Builder、CIO 等)继续共享一个 Slack App。只让需要跨域协作的 Agent(如 Orchestrator)拥有独立 App,把它拉进目标频道就能直接对话。 + +这里借鉴了 **Anthropic Harness Design** 的核心洞察:当一个 AI 既做执行又做 QA 时,它倾向于宽容自己的错误;既做规划又做执行时,倾向于投机取巧。将"想"和"做"分给不同 Agent——Orchestrator 负责规划和评估,执行层 Agent 负责实现——是解决 AI 自评失效最有效的杠杆。 + +**什么时候用哪个?** + +| | Delegation(委派) | Discussion(讨论) | +|--|-------------------|-------------------| +| 场景 | "CTO 给 Builder 派一个具体任务" | "Orchestrator 进 #cto 跟 CTO 讨论方案,然后去 #build 跟 Builder 确认可行性" | +| 触发方式 | `sessions_send` | 显式 @mention | +| 方向性 | 单向,一对一 | 多向,多对多 | +| 平台 | Slack / Discord / Feishu | 仅 Slack(需独立 App) | + +两种模式共存,不互相替代。Delegation 是"给任务",Discussion 是"一起想"。 + +**为什么需要 Discussion?** Delegation 是任务分发:CTO 说做什么,Builder 照做。但真实团队不只是派活——他们讨论。Orchestrator 走进 CTO 的办公室说"这个方向你怎么看?",CTO 说"技术上可以但成本高",Orchestrator 又去问 Builder"你觉得多久能做完?"。Discussion 模式让 Agent 也能这样协作——Orchestrator-Bot 被拉进 #cto 频道,直接在 CTO 的地盘上对话,你可以实时旁观、随时插话。 + +### 平台能力对比 + +| 能力 | Slack | Discord | Feishu | +|------|-------|---------|--------| +| Delegation(sessions_send) | ✅ | ✅ | ✅ | +| Discussion(跨 bot 对话)| ✅ 已验证 | 不支持(OpenClaw 代码层 bug) | 不支持(飞书平台限制) | +| Thread / Topic 隔离 | 原生 thread | Thread(自动归档) | groupSessionScope(>= 2026.3.1) | + +**为什么 Discord 和 Feishu 不支持 Discussion?** + +- **Discord**:平台本身支持跨 bot 消息可见,但 OpenClaw 的 bot 消息过滤代码存在 bug(Issue #11199),把所有已配置的 bot 都当作"自己"并丢弃消息。属于代码层问题,理论上可修复,但修复 PR 均已关闭。 +- **Feishu**:飞书的 `im.message.receive_v1` 事件**只投递用户发送的消息**——bot 发的消息对其他 bot 完全不可见。这是飞书平台 API 的设计决策,无法通过配置绕过。 + +### Discussion 模式的当前状态 + +Discussion 模式已通过端到端验证(2026-04-02)。两个独立 bot 可以在同一频道互相看到消息并进行结构化讨论。 + +通过 OpenClaw 源码验证 + 实测确认: +- Self-loop 过滤是 per-account 的(不同 Slack App 不互相过滤)✅ +- `allowBots` 支持三级 fallback(per-channel > per-account > global)✅ +- Per-account channel config 可以给同一频道的不同 bot 设置不同的 `requireMention` ✅ +- 多账号配置需要**同时声明 `accounts.default`**(否则主 bot 断连)⚠️ + +**实战发现的限制**: +- `requireMention: true` 在 Thread 内被 `implicitMention` 绕过——需要 Prompt 规则配合 +- `allowBots: "mentions"` 在 Slack 无效(仅 Discord 支持) +- Input token 无法避免——所有消息送达所有 bot,只能让 agent 回复 NO_REPLY + +详细配置指南和陷阱清单见 [Discussion Mode 实操指南](A2A_SETUP_GUIDE.md)。完整协议见 `shared/A2A_PROTOCOL.md`。 + --- ## 5. 结构化产物:Closeout 和 Checkpoint @@ -270,8 +323,9 @@ Layer 2: 抽象知识 ├─ 任务按 QAPS 分类处理 │ └─ Q 轻量处理,A/P/S 必须 Closeout │ - ├─ Agent 之间通过 A2A 两步触发协作 - │ └─ 权限矩阵 + 循环保护 + ├─ Agent 之间通过 A2A 协作 + │ ├─ Delegation:两步触发 + 权限矩阵 + │ └─ Discussion:@mention 多 Agent 讨论 [已验证] │ └─ 知识通过三层沉淀积累 └─ 对话 → Closeout → KO 抽象知识 diff --git a/docs/en/CONCEPTS.md b/docs/en/CONCEPTS.md index 63f706b..372646e 100644 --- a/docs/en/CONCEPTS.md +++ b/docs/en/CONCEPTS.md @@ -119,6 +119,59 @@ Builder -> Cannot assign tasks (receives and executes only) CIO -> Operates independently (syncs with CoS when needed) ``` +### Two A2A Modes: Delegation and Discussion + +The two-step trigger described above is the **Delegation** mode -- one Agent hands a structured task to another via `sessions_send`. This is the foundation of A2A, supported on all platforms, with a clear one-directional flow. + +v2 introduces a second mode: **Discussion**. A small number of high-value Agents (e.g., Orchestrator) get their own independent Slack App, then join other Agents' channels to collaborate in real-time. + +**Core idea: selective independence.** Not every Agent needs its own App -- execution-layer Agents (CTO, Builder, CIO, etc.) keep sharing one Slack App. Only Agents that need cross-domain collaboration (like the Orchestrator) get their own App, then get invited into target channels for direct conversation. + +This borrows a core insight from **Anthropic's Harness Design**: when an AI both executes and does QA, it tends to go easy on its own mistakes; when it both plans and executes, it tends to cut corners. Separating "thinking" and "doing" into different Agents -- Orchestrator handles planning and evaluation, execution-layer Agents handle implementation -- is the most effective lever for solving AI self-evaluation failure. + +**When to use which?** + +| | Delegation | Discussion | +|--|------------|------------| +| Scenario | "CTO assigns a specific task to Builder" | "Orchestrator walks into #cto to discuss the approach with CTO, then checks feasibility with Builder in #build" | +| Trigger | `sessions_send` | Explicit @mention | +| Directionality | One-way, one-to-one | Multi-directional, many-to-many | +| Platform | Slack / Discord / Feishu | Slack only (requires independent App) | + +The two modes coexist -- they do not replace each other. Delegation is for "assign the work." Discussion is for "think it through together." + +**Why Discussion?** Delegation is task distribution: CTO says what to do, Builder executes. But real teams don't just assign tasks -- they discuss. The Orchestrator walks into CTO's office and asks "what do you think about this direction?", CTO says "technically feasible but expensive", then the Orchestrator asks Builder "how long would this take?". Discussion mode lets Agents work the same way -- the Orchestrator-Bot gets invited into #cto and talks directly on CTO's home turf. You can watch in real-time and intervene at any point. + +### Platform Capability Comparison + +| Capability | Slack | Discord | Feishu | +|------------|-------|---------|--------| +| Delegation (sessions_send) | YES | YES | YES | +| Discussion (cross-bot) | ✅ Verified | Not supported (OpenClaw code-level bug) | Not supported (platform limitation) | +| Thread / Topic isolation | Native thread | Thread (auto-archive) | groupSessionScope (>= 2026.3.1) | + +**Why can't Discord and Feishu support Discussion?** + +- **Discord**: The platform itself supports cross-bot message visibility, but OpenClaw's bot message filter (Issue #11199) treats ALL configured bots as "self" and drops their messages. This is a code-level bug, not a platform limitation -- but fix PRs have all been closed. +- **Feishu**: Feishu's `im.message.receive_v1` event **only delivers user-sent messages** -- bot messages are completely invisible to other bots. This is a platform API design decision and cannot be worked around through configuration. + +### Current Status of Discussion Mode + +Discussion mode has been verified end-to-end (2026-04-02). Two independent bots can see each other's messages in the same channel and conduct structured discussions. + +Through OpenClaw source code verification + live testing: +- Self-loop filtering is per-account (different Slack Apps don't filter each other) ✅ +- `allowBots` supports three-tier fallback (per-channel > per-account > global) ✅ +- Per-account channel config can give different bots different `requireMention` settings ✅ +- Multi-account config requires **explicit `accounts.default` declaration** (otherwise main bot disconnects) ⚠️ + +**Limitations discovered in practice**: +- `requireMention: true` is bypassed in threads by `implicitMention` -- requires prompt rules to compensate +- `allowBots: "mentions"` does not work on Slack (Discord only) +- Input token cost is unavoidable -- all messages reach all bots; agents can only reply NO_REPLY + +For detailed setup guide and pitfall checklist, see [Discussion Mode Setup Guide](A2A_SETUP_GUIDE.md). Full protocol in `shared/A2A_PROTOCOL.md`. + --- ## 5. Structured Artifacts: Closeout and Checkpoint @@ -270,8 +323,9 @@ You (decision-maker) |-- Tasks are classified and handled via QAPS | +-- Q gets lightweight handling; A/P/S require Closeout | - |-- Agents collaborate via A2A two-step trigger - | +-- Permission matrix + loop prevention + |-- Agents collaborate via A2A + | |-- Delegation: two-step trigger + permission matrix + | +-- Discussion: @mention multi-agent deliberation [Verified] | +-- Knowledge accumulates through three-layer distillation +-- Conversation -> Closeout -> KO abstract knowledge diff --git a/shared/A2A_PROTOCOL.md b/shared/A2A_PROTOCOL.md index d9f3bd5..538ac4e 100644 --- a/shared/A2A_PROTOCOL.md +++ b/shared/A2A_PROTOCOL.md @@ -1,141 +1,428 @@ -# A2A 协作协议(Slack 多 Agent) +# A2A 协作协议 v2(跨平台多 Agent) -> 目标:让 Agent 之间的协作 **自动发生在正确的 Slack 频道/线程里**,做到: +> 目标:让 Agent 之间的协作 **自动发生在正确的频道/线程里**,做到: > - 可见(用户 能在频道里看到) > - 可追踪(每个任务一个 thread/session) > - 不串上下文(thread 级隔离 + 任务包完整) +> +> v2 覆盖平台:Slack / Feishu / Discord +> v2 协作模式:**Delegation**(全平台)+ **Discussion**(Slack 多 Bot)[已验证] +> +> 配置指南:[Discussion Mode 实操指南](../docs/A2A_SETUP_GUIDE.md) --- ## 0. 术语 -- **A2A(本文)**:Agent-to-Agent 协作流程(不等同于 OpenClaw 的某一个单独工具名)。 -- **Task Thread**:在目标 Agent 的 Slack 频道里创建的任务线程;该线程即该任务的独立 Session。 +- **A2A**:Agent-to-Agent 协作流程总称,包含 Delegation 和 Discussion 两种模式。 +- **Task Thread**:在目标 Agent 频道里创建的任务线程;该线程即该任务的独立 Session。 +- **Delegation(委派)**:由 `sessions_send` 触发的结构化任务委派,全平台可用。 +- **Discussion(讨论)**:由 @mention 触发的多 Agent 实时讨论,仅 Slack 多 Bot [已验证]。 +- **Multi-Account(多账户)**:每个 Agent 使用独立 Slack App(独立 bot token / app token / bot user ID)。 +- **Orchestrator(编排者)**:控制讨论节奏的角色。默认是 CoS(代表用户推进),也可以是人类。 --- ## 1) 权限矩阵(必须遵守) -- CoS → 只能给 CTO 派单/对齐方向(默认不直达 Builder) -- CTO → 可以派单给 Builder / Research / KO / Ops +- CoS → CTO(默认不直达 Builder);Discussion 模式中 CoS 是编排者 +- CTO → Builder / Research / KO / Ops - Builder → 只接单执行;需要澄清时回到 CTO thread 提问 - CIO → 尽量独立;仅必要时与 CoS/KO 同步 - KO/Ops → 作为审计/沉淀,通常不主动派单 -(注:技术上 Slack bot 可以给任意频道发消息,但这是组织纪律,不遵守视为 bug。) +(注:技术上 bot 可以给任意频道发消息,但这是组织纪律,不遵守视为 bug。) --- -## 2) A2A 触发方式(核心) +## 2a) Delegation Mode(委派模式 — 全平台) 当 A 想让 B 开工时(**不允许人工复制粘贴**): -> ⚠️ 重要现实:Slack 中所有 Agent 共用同一个 bot 身份。 -> **bot 自己发到别的频道的消息,默认不会触发对方 Agent 自动运行**(OpenClaw 默认忽略 bot-authored inbound,避免自循环)。 -> 因此:跨 Agent 的"真正触发"必须通过 **sessions_send(agent-to-agent)** 完成;Slack 发消息仅作为"可见性锚点"。 +> ⚠️ 重要现实:单 Bot 模式下所有 Agent 共用一个 bot 身份。 +> **bot 自己发到别的频道的消息,默认不会触发对方 Agent**(OpenClaw 忽略 bot-authored inbound,防自循环)。 +> 因此:跨 Agent 触发必须通过 **sessions_send** 完成;频道消息仅作"可见性锚点"。 ### Step 1 - 在目标频道创建可见的 root message(锚点) -A 在 B 的 Slack 频道创建一个任务根消息(root message),第一行固定前缀: +A 在 B 的频道创建 root message,第一行固定前缀: ``` A2A <FROM>→<TO> | <TITLE> | TID:<YYYYMMDD-HHMM>-<short> ``` 正文必须是完整任务包(建议使用 `~/.openclaw/shared/SUBAGENT_PACKET_TEMPLATE.md`): -- Objective(目标) -- DoD(完成标准) -- Inputs(已有信息/链接/文件) -- Constraints(约束/边界) -- Output format(输出格式) -- CC(需要同步到哪个频道/人) +- Objective / DoD / Inputs / Constraints / Output format / CC -> 前置条件:OpenClaw bot 必须被邀请进目标频道,否则会报 `not_in_channel`。 +> 前置条件:bot 必须已加入目标频道,否则报 `not_in_channel`。 -### Step 2 - 用 sessions_send 触发 B 在该 thread/session 中运行 -A 读取 root message 的 Slack message id(ts),拼出 thread sessionKey: +### Step 2 - 用 sessions_send 触发目标 Agent +A 读取 root message 的 message id(ts),拼出 thread sessionKey: -- 频道 session:`agent:<B>:slack:channel:<channelId>` -- 线程 session:`agent:<B>:slack:channel:<channelId>:thread:<root_ts>` +| 平台 | Session Key 格式 | +|------|-----------------| +| Slack | `agent:<B>:slack:channel:<channelId>:thread:<root_ts>` | +| Discord | `agent:<B>:discord:channel:<channelId>:thread:<root_ts>` | +| Feishu | `agent:<B>:feishu:group:<chatId>:topic:<root_id>` | -然后 A 用 `sessions_send(sessionKey=..., message=<完整任务包或第一步的引用>)` 触发 B。 +然后 A 用 `sessions_send(sessionKey=..., message=<完整任务包>)` 触发 B。 -> ⚠️ **timeout 容错**:`sessions_send` 返回 timeout **≠ 没送达**。消息可能已送达并被处理。 -> 规避:在 Slack thread 里补发一条兜底消息("已通过 A2A 发送,如未收到可在此查看全文")。 - -> ⚠️ **SessionKey 注意**:不要手打 sessionKey。优先从 `sessions_list` 复制 `deliveryContext=slack` 的 key。 -> 注意 channel ID 大小写一致性——大小写不一致可能导致 session 被拆分,路由到 webchat 而非 Slack。 +> ⚠️ **timeout ≠ 失败**。消息可能已送达。规避:在 thread 里补发兜底消息。 +> ⚠️ **SessionKey 不要手打**。从 `sessions_list` 复制 `deliveryContext` 匹配的 key。 ### Step 3 — 执行与汇报 - B 的执行与产出都留在该 thread。 -- 需要上游(如 CTO)掌控节奏时,上游应在自己的协调 thread 里同步 checkpoint/closeout(见第 3 节)。 +- 上游在自己的协调 thread 里同步 checkpoint/closeout。 --- ## 2.5) 多轮 WAIT 纪律(实战验证) -当 A2A 任务需要多轮迭代时(大部分非 Q 类任务都是): +当 A2A 任务需要多轮迭代时: - **每轮只聚焦 1-2 个改动点**,完成后**必须 WAIT**。 -- **禁止一次性做完所有步骤**--等上游下一轮指令后再继续。 -- 每轮输出格式固定: +- **禁止一次性做完所有步骤**——等上游指令后再继续。 +- 每轮输出格式: ``` [<角色>] Round N/M Done: <做了什么> Run: <执行了什么命令> - Output: <关键输出,允许截断> + Output: <关键输出> WAIT: 等待上游指令 ``` -- 最终轮贴 closeout 到 thread,A2A reply 中回复 `REPLY_SKIP` 表示完成。 +- 最终轮贴 closeout,A2A reply 中回复 `REPLY_SKIP`。 ### Round0 审计握手(推荐) +在 Round1 前,先验证审计链路:要求目标 Agent 执行 `pwd` 并贴到 thread。看不到回传就停止。 + +--- + +## 2b) Discussion Mode(讨论模式 — Slack 多 Bot)[已验证] + +> Discussion 是 Delegation 的增强,不是替代。适用于需要多方实时讨论的场景。 +> 仅 Slack 平台支持。原因见 §7。 +> 完整配置指南见 [A2A_SETUP_GUIDE.md](../docs/A2A_SETUP_GUIDE.md)。 + +### 核心思路:选择性独立化 + +不需要每个 Agent 都有独立 Slack App。只需让**少数高价值的横向 Agent**(如 Orchestrator)拥有独立 App,然后**把它们拉进现有 Agent 的频道**进行协作: + +``` + 独立 Slack App 共享 Slack App (现有) + ┌──────────────┐ ┌─────────────────┐ + │ Orchestrator │ │ Default-Bot │ + └──────┬───────┘ └───┬───┬───┬─────┘ + │ │ │ │ + 频道: #hq(home) #cto #build #cto #build #invest ... + ────────────────────────────────────────────────────── + Agent: Orchestrator ← 进入协作 → CTO Builder CIO ... +``` + +这里的 Orchestrator 融合了 Anthropic Harness Design 中 **Planner + Evaluator** 的职责: +- 展开需求为验收标准(Planner) +- 评估参与者的产出(Evaluator) +- 控制讨论节奏和终止(Orchestrator) + +执行层 Agent(CTO/Builder 等)是 **Generator**:执行具体工作,不自评通过。 + +> **为什么要分离?** 当一个 AI 既做执行又做 QA 时,它倾向于宽容自己的错误;既做规划又做执行时,倾向于投机取巧。将"想"和"做"分给不同 Agent,是解决 AI 自评失效最有效的杠杆。 + +### 技术原理(源码验证) + +1. **Self-loop 按 account 隔离**:每个 Slack App 有独立 `botUserId`,OpenClaw 只过滤来自自己的消息(`message.user === ctx.botUserId`),不同 App 之间不互相过滤。 +2. **`allowBots: true`**:允许处理其他 bot 的消息。须在目标频道的 channel config 中开启。 +3. **Per-account channel config**:同一频道可以给不同 account 设置不同的 `requireMention`。 + +### ⚠️ Thread 内的隐式触发问题(实战发现) + +`requireMention: true` 只在 **Channel 根消息**(非 thread)有效。一旦 bot 在 thread 中回复过,`implicitMention` 永远为 true,绕过 `requireMention`。 + +源码证据(`resolveMentionGating`): + +```js +implicitMention = !isDirectMessage && botUserId && message.thread_ts && + (message.parent_user_id === botUserId || hasSlackThreadParticipation(...)) +``` + +**影响**:Thread 内所有消息都会触发已参与的 bot,可能导致双响应或循环。 + +**解决:两层防线** + +| 层级 | 机制 | 效果 | 类型 | +|------|------|------|------| +| Config | `requireMention: true` | 防止 Channel 根消息双触发 | 硬约束 | +| Prompt | 显式 @mention 协议(见下文) | 防止 Thread 内双响应和循环 | 软约束 | + +### 显式 @mention 协议(Multi-Agent Thread 规则) + +每个参与 Discussion Mode 的 Agent 必须在 workspace 文件中包含此规则: + +```markdown +## Multi-Agent Thread 协作规则 + +在 Slack thread 中如果有其他 bot 也在参与: + +1. **显式 @mention 检查**:检查消息文本是否包含 `<@你的BotID>`。 + 如果没有 → 整条回复只输出 `NO_REPLY`,不解释、不叙述。 + +2. **发送消息时必须 @mention 目标**:`<@目标BotID>` 显式 mention。 + 不 @ 任何 bot = 对话终止信号。 + +3. **角色分工**: + - Orchestrator(编排者):选择 @Worker / @Human / 不@(结束) + - Worker(执行方):每次回复必须 @ Orchestrator + +4. **终止**:说"完毕/done/结论"后不再发送,除非被重新 @。 + +5. **轮次上限**:同一 thread 内最多 8 轮,超过后暂停并向人类汇报。 +``` + +### 协作流程(融合 Anthropic Harness Design) + +``` +用户 → @Orchestrator: "讨论 X 议题" + +Phase 0(Orchestrator 展开 spec): + → 📁 discussions/<topic>/spec.md(目标 + 验收标准 + 终止条件) + → Thread: 「DISCUSSION SPEC: 目标...验收标准 N 条。@Worker 请先...」 + +Round 1/M: + Orchestrator → @Worker: 具体问题 + Worker → @Orchestrator: 摘要 + 📁 round-1.md(详细分析) + +Round 2/M: + Orchestrator 评估 → 📁 review-1.md → @Worker 反馈 + ... + +终止(三选一): + ✅ 所有验收标准满足 → DISCUSSION_CLOSE + ⚠️ 达到最大轮次 → WARNING,请人类介入 + 🔄 连续 2 轮无进展 → 请人类介入 +``` + +**关键原则**(源自 Anthropic Harness Design): +1. **先 spec 再讨论**——Phase 0 定义验收标准,不能跳过 +2. **文件是主通信通道**——Thread 只放摘要和 @mention 路由,详细内容写文件 +3. **自评失效,必须分离**——Orchestrator 不生成方案,只协调和评估 +4. **Orchestrator 默认太宽松**——需刻意严格,逐条对照标准判断 +5. **正式任务走 `sessions_send`**——Discussion 的 Action Item 通过 Delegation 执行 + +### Discussion 终止协议 -在正式 Round1 前,先做一个**极小的真实动作**验证审计链路: -- 要求目标 Agent 执行一个无副作用命令(如 `pwd`)并把结果贴到 Slack thread。 -- **看不到 Round0 回传就停止**--说明目标 Agent 的 session 可能没绑定 Slack(deliveryContext 落到 webchat),继续执行会导致"在跑但 Slack 不可审计"。 +讨论结束时,Orchestrator 发送: + +``` +DISCUSSION_CLOSE +Topic: <讨论主题> +Consensus: <共识 / "未达成共识,原因:..."> +Criteria Status: + 1. ✅/❌ <标准 1>: <状态> + 2. ✅/❌ <标准 2>: <状态> +Actions: <后续 Delegation 任务列表,含负责人> +Participants: <参与 Agent> +Rounds Used: N/M +``` + +--- + +## 2c) 平台能力矩阵 + +| 能力 | Slack | Discord | Feishu | +|------|-------|---------|--------| +| Delegation | YES | YES | YES | +| Discussion | ✅ 已验证 | NO(OpenClaw 代码层阻塞) | NO(飞书平台限制) | +| Multi-Account | YES | YES | YES(注意 #47436) | +| Thread/Topic 隔离 | YES (native) | YES (auto-archive) | YES (groupSessionScope >= 2026.3.1) | + +**为什么 Discord 和 Feishu 不能用 Discussion?** + +- **Discord**:平台层面支持跨 bot 消息可见,但 OpenClaw 的 bot 消息过滤器(Issue #11199)将所有已配置 bot 视为"自己"并丢弃,导致 Bot-A 的消息被 Bot-B 的 handler 忽略。此外 `requireMention` 在多账户下也失效(Issue #45300)。两个 issue 均已关闭但未修复——属于 OpenClaw 代码层 bug,非平台限制。 +- **Feishu**:飞书 `im.message.receive_v1` 事件**仅投递用户发送的消息**,bot 发送的消息对其他 bot 完全不可见。这是飞书平台的 API 设计,无法通过 OpenClaw 配置绕过。 --- ## 3) 可见性(用户 必须能看到) -- 任务根消息必须在目标频道可见(root message 作为锚点)。 -- 关键 checkpoint(开始/阻塞/完成)至少更新 1 次。 -- **上游负责到底**:谁派单(例如 CTO 派给 Builder),谁负责在自己的协调 thread 里持续跟进: - - Builder thread 的输出由 CTO 通过 sessions_send 的 tool result 捕获 - - CTO 必须在 #cto 的对应协调 thread 里同步 checkpoint(避免 用户 去多个频道"捞信息") -- **双通道留痕**: - - A2A reply(给上游的结构化回复) - - Slack thread message(给用户可见的审计日志,格式 `[角色] 内容...`) - - **两者都要做**--A2A reply 只有上游能看到,thread message 用户才能看到。 -- 完成后必须 closeout(DoD 硬规则,缺一不可): - 1. 在目标 Agent thread 贴 closeout(产物路径 + 验证命令) - 2. **上游本机复核**(CLI-first):至少执行关键命令 + 贴 exit code - 3. **回发起方频道汇报**:同步最终结果 + 如何验证 + 风险遗留。**不做视为任务未完成** - 4. 通知 KO 沉淀(默认:同步到 #know + 触发 KO ingest) +- 任务根消息必须在目标频道可见。 +- 关键 checkpoint 至少更新 1 次。 +- **上游负责到底**:派单方在自己的频道同步 checkpoint。 +- **双通道留痕**:A2A reply(上游可见)+ Thread message(用户可见),两者都要做。 +- 完成后必须 closeout: + 1. 在目标 thread 贴 closeout + 2. 上游本机复核(CLI-first) + 3. 回发起方频道汇报(**不做视为未完成**) + 4. 通知 KO 沉淀 --- -## 4) 频道映射(约定) +## 4) 频道映射 -- #hq → CoS +- #hq → CoS(home) - #cto → CTO - #build → Builder - #invest → CIO - #know → KO - #ops → Ops - #research → Research -- #main(可选:你的主入口频道) → Main Agent(可选)(不属于本系统,但可作为 用户 的总入口) + +Discussion 模式下,CoS-Bot 进入其他 Agent 的频道(如 #cto、#build)进行协作,无需额外创建共享频道。 --- -## 5) 命名与并行 +## 5) Session Key 格式与命名 + +**一个任务 = 一个 thread = 一个 session。** -- **一个任务 = 一个 thread = 一个 session**。 -- 同一个频道可以并行多个任务 thread;不要在频道主线里混聊多个任务。 +| 平台 | Session Key | +|------|------------| +| Slack (thread) | `agent:<B>:slack:channel:<channelId>:thread:<root_ts>` | +| Discord (thread) | `agent:<B>:discord:channel:<channelId>:thread:<root_ts>` | +| Feishu (topic) | `agent:<B>:feishu:group:<chatId>:topic:<root_id>` | --- ## 6) 失败回退 -如果 Slack thread 行为异常: -- 退回到"单频道单任务":临时在频道主线完成该任务 -- 或让 CTO/CoS 在 thread 里发 /new 重置(开始新 session id) +| 模式 | 故障 | 回退 | +|------|------|------| +| Delegation | `sessions_send` timeout | 在 thread 补兜底消息;检查 session key | +| Delegation | Agent 无回复 | Round0 审计握手可提前发现;检查 deliveryContext | +| Discussion | Agent 未响应 @mention | 检查 `allowBots` + `requireMention` 配置;检查 bot 是否在频道 | +| Discussion | 讨论死循环 | Orchestrator 强制 DISCUSSION_CLOSE | +| Discussion | 平台不支持 | 降级为 Delegation(`sessions_send` 串联意见) | + +--- + +## 7) 已知限制 + +1. **Slack Discussion [已验证]**:端到端链路已通过实测验证(2026-04-02)。两个 bot 可在同一频道互相看到消息并进行结构化讨论。但 Thread 内的隐式触发需要 Prompt 规则配合(见 §2b)。 +2. **Discord Discussion [NO]**:OpenClaw Issues #11199(bot filter 全局化)+ #45300(requireMention 多账户失效),均已关闭未修复。 +3. **Feishu Discussion [NO]**:飞书 `im.message.receive_v1` 仅投递用户消息(平台限制,非 OpenClaw bug)。 +4. **Issue #15836**:OpenClaw 关闭了 Slack A2A routing 请求(NOT_PLANNED)。`sessions_send` 仍是官方推荐方式。Discussion 作为增强,非替代。 +5. **`allowBots: "mentions"` 仅 Discord 可用**:Slack provider 只做 truthy/falsy 检查,`"mentions"` 等同于 `true`。需要 OpenClaw 代码改动才能在 Slack 支持。 +6. **`requireMention: true` 在 Thread 内被绕过**:`implicitMention`(thread participation)会永久绕过 `requireMention`。需要 OpenClaw 增加 `thread.requireExplicitMention` 选项才能从系统层解决。 +7. **Input token 无法避免**:Thread 中所有消息都会送达所有 bot,Prompt 规则只让 agent 回复 NO_REPLY,但 input token 消耗不可避免。 +8. **多账号 `accounts.default` 必须显式声明**:详见附录 A 的警告。实战中因遗漏导致过 ~13h 全 Agent 断连。 + +--- + +## 附录 A:Discussion Mode 配置指南(Slack) + +> 详细实操指南见 [A2A_SETUP_GUIDE.md](../docs/A2A_SETUP_GUIDE.md),包含完整 manifest、陷阱清单和回滚方式。 +> 以下是精简版。 + +### 人工操作(一次性) + +1. **创建独立 Slack App**:前往 [api.slack.com/apps](https://api.slack.com/apps) → Create New App → **From manifest** + - 使用 [A2A_SETUP_GUIDE.md](../docs/A2A_SETUP_GUIDE.md) 中的完整 manifest(含所有必要 scope 和 event) + - 创建后:Basic Information → App-Level Tokens → Generate(scope: `connections:write`)→ 拿到 `xapp-` + - Install to Workspace → 拿到 `xoxb-` + +2. **邀请 Bot 到目标频道**:`/invite @Bot-Name` + +### Agent 可执行的配置 + +> ⚠️ **硬性要求:必须同时声明 `accounts.default`** +> +> OpenClaw 的 `account-helpers.ts:listAccountIds()` 逻辑:一旦 `accounts` 对象存在且有任何 key, +> 只启动显式声明的账号。漏掉 `accounts.default` = 主 bot 断连,所有现有 Agent 失联。 +> +> 这是设计如此,不是 bug。实战中因此导致过约 13 小时的全 Agent 断连事故。 + +将以下配置提示发给你的 OpenClaw agent(替换凭证): + +``` +请帮我配置 Discussion Mode。 + +Bot 凭证(写入配置,不要回显): +- Bot Token: xoxb-xxx +- App Token: xapp-xxx + +请在 openclaw.json 中执行以下增量修改: + +1. 在 channels.slack.accounts 下: + ★ 必须同时声明 accounts.default(用现有顶层 token) + - accounts.default = { botToken: 现有, appToken: 现有 } + - accounts.<new-bot> = { botToken: 新的, appToken: 新的, channels: {...} } + +2. 在目标频道开启双向 allowBots: + - 全局 channel config: allowBots: true(让原有 Agent 看到新 bot) + - 新 account channel config: allowBots: true, requireMention: true + +3. 添加 binding(accountId + peer,放在现有 peer binding 之前) + +4. 等待热重载,不要立即 SIGTERM + +5. 验证日志:两个 provider 都 starting + channels resolved 无 missing_scope +``` + +### 配置结构参考 + +```jsonc +{ + "channels": { + "slack": { + "accounts": { + "default": { + "botToken": "${SLACK_BOT_TOKEN}", + "appToken": "${SLACK_APP_TOKEN}" + }, + "cos": { + "botToken": "${SLACK_BOT_TOKEN_COS}", + "appToken": "${SLACK_APP_TOKEN_COS}", + "channels": { + "<CTO_CHANNEL_ID>": { + "requireMention": true, // CoS 在 #cto 只响应 @mention + "allowBots": true // CoS 能看到 CTO 的回复 + } + } + } + }, + "channels": { + "<CTO_CHANNEL_ID>": { + "allow": true, + "allowBots": true // CTO 能看到 CoS-Bot 的消息 + } + }, + "thread": { + "historyScope": "thread", + "initialHistoryLimit": 50 + } + } + }, + "bindings": [ + // CoS: account-level binding + { "agentId": "cos", "match": { "channel": "slack", "accountId": "cos" } }, + // 执行层 agents: peer-level binding(现有,不变) + { "agentId": "cto", "match": { "channel": "slack", "peer": { "kind": "channel", "id": "<CTO_CHANNEL_ID>" } } } + // ... builder, cio, ko, ops, research 同理 + ] +} +``` + +--- + +## 附录 B:POC 验证步骤 + +``` +测试 1:基础跨 bot 消息传递 + - 在 #cto 中用人类账号 @mention CoS-Bot + - 验证 CoS 响应 + - 验证 CTO 不会"抢答"(如果 CTO 也回复了,属正常——requireMention: false) + +测试 2:CoS 和 CTO 在 thread 中对话 + - CoS 在 #cto thread 中 @mention CTO(或直接发消息,CTO 的 requireMention 为 false) + - 验证 CTO 回复 + - 验证 CoS 收到 CTO 的回复(thread participation 隐式 mention) + - 验证 CoS 可以继续对话(第二轮) + +测试 3:轮次控制 + - 在 CoS 的 AGENTS.md 中设定 maxDiscussionTurns: 3 + - 发起讨论 + - 验证 CoS 在第 3 轮后发布 DISCUSSION_CLOSE + +测试 4:多 Agent 讨论 + - 邀请 CoS-Bot 到 #build + - 在 #cto thread 中 CoS @mention Builder + - 验证 Builder 收到并响应 + - 验证 CoS 能综合 CTO + Builder 的意见 +```