diff --git a/docs/design/13-toolchain-and-dev-workflow.md b/docs/design/13-toolchain-and-dev-workflow.md index ca9d151..1040797 100644 --- a/docs/design/13-toolchain-and-dev-workflow.md +++ b/docs/design/13-toolchain-and-dev-workflow.md @@ -1,6 +1,6 @@ # 三国团队工具链与开发流程设计 -> **状态**: v3.1 — P3 端到端验证通过 + 调研结论写入 + Review API 枚举值修正 +> **状态**: v3.3 — #19 上下文四层改造合并 + CI 修复 + A13 修订 > **作者**: 庞统(副军师)🐦 > **评审**: 司马懿(仲达)🗡️ > **日期**: 2026-06-06 @@ -2765,3 +2765,378 @@ Gitea v1.23.4 自带完整的 CI 管理界面: | §16.8 #10 | Gitea v1.23.4 review payload 调研结论(姜维 2026-06-08):Gitea v1.23.4 review payload 只有 `type` + `content`,没有 `state`/`body`/`user`,这不是 org vs repo 差异而是 Gitea 设计。v1.24.0 格式不变。双格式兼容是防御性编码,保持现状 | | §16.8 #11 | Spawner compact 检测窗口修复:窗口 300s→900s,尾部读取 50KB→1MB。实测长对话中 compact 记录被推出窗口导致漏检 | | §16.8 #12 | inform 类型 Mail crash 误标 done bug 修复:`_mail_auto_complete` 增加 outcome 感知,inform 用白名单(completed/claimed/no_reply)控制 done 标记。spawner crash cooldown 300s→60s | + +--- + +### 一、问题诊断 + +#### 1.1 E2E 真实场景测试暴露的三个断层 + +主公在 moziplus-v2 仓库创建了 Issue #32(添加 /api/stats 端点),指派张飞。链条在第一步就断了。 + +| 断层 | 现象 | 根因 | +|------|------|------| +| **Agent 不知道该做什么** | 张飞收到 Issue 指派 Mail,回复"已阅"就结束了 | Mail 模板(issue_assigned.md)5 行信息,无流程引导;spawn prompt 说"已阅即可" | +| **Agent 去错了仓库** | 张飞去读了 sanguo_moziplus_v2 平台代码,而不是空的实验仓库 moziplus-v2 | Mail 模板没有仓库 clone URL,张飞凭习惯去了开发目录 | +| **Agent 在 Control UI 提问** | 张飞遇到问题直接在 Control UI 问主公,没有去 Gitea Issue 评论 | 没有任何地方引导"有疑问去 Gitea Issue 评论" | +| **Agent 不知道怎么协作** | 张飞判断任务需要澄清,但不知道该怎么请求澄清 | 没有"做不了→在 Issue 评论 / Mail 庞统"的回退路径 | +| **跨 Agent @mention 无法通知** | 张飞在 Issue 评论 @赵云,赵云收不到通知 | issue_comment handler 只处理 [CI] 评论,@mention 被忽略 | + +#### 1.2 根因:工具链在四层架构中的断层 + +| 层 | 应该有 | 实际有 | Gap | +|---|---|---|---| +| **L0 铁律** | — | — | 无需改动 | +| **L1 角色** | 工具链协作行为规范(所有 Agent 共享) | 无 | AGENTS.md 没有工具链相关内容 | +| **L2 引擎注入** | 事件上下文(仓库 clone URL、Gitea API、Issue/PR 详情) | Mail 模板只有 5 行摘要 | 缺仓库信息和流程引导 | +| **L3 被动参考** | 技术细节(分支命名、commit 规范、PR 创建方式) | git-workflow 等 Skill 已存在但没人触发 | Agent 不知道该加载哪个 Skill | + +--- + +### 二、改造方案:四层归属 + +#### 2.1 分层原则 + +| 层 | 放什么 | 不放什么 | 理由 | +|---|---|---|---| +| **L0** | 不放 | — | 工具链不是安全底线 | +| **L1** | 协作行为规范:收到什么通知该做什么、遇到问题怎么办 | 技术细节(分支命名、commit 格式) | 行为规范是团队常识,每个 Agent 都要知道 | +| **L2** | 事件上下文:仓库 clone URL、Gitea API URL、Issue/PR 链接、动态信息 | 固定的协作流程 | 动态信息每次不同,由 Mail 模板 + spawn 时注入 | +| **L3** | 技术细节:git-workflow、code-review 等 Skill 全文 | — | 按需加载,Agent 知道"我要提 PR"后自己读 | + +#### 2.2 各层具体内容 + +##### L1:AGENTS.md 加工具链协作行为段(所有 Agent 统一) + +```markdown +## 工具链协作(Gitea) + +收到 Gitea 事件通知(Issue 指派、Review 请求、CI 失败等)时,按以下流程操作: + +### 基本流程 +- **Issue 指派** → clone 仓库 → 开分支 → 编码 → 提 PR(参考 git-workflow Skill) +- **Review 请求** → 读 PR diff(Gitea API)→ 提交 Review(参考 code-review Skill) +- **Review 通过** → 等 merge +- **Review 驳回** → 看 review body → 修代码 → 重新 push +- **CI 失败** → 看错误摘要 → 修代码 → push(自动重触发 CI) +- **部署失败** → 查 deploy 日志 → 修复 + +### 协作规则 +- **有疑问?** 在 Gitea Issue 下评论,不要在 Control UI 或 Mail 里问 +- **需要别人帮忙?** 在 Issue 评论中 @mention 对应 Agent(如 @zhaoyun-data) +- **做不了?** 回复 Mail 说明原因和建议的接手人 +- **获取完整上下文** → 用 Gitea API 拉取 Issue 详情和评论,不要只看 Mail 里的快照 + +### Gitea API 速查 +> 其中 `{owner}/{repo}` 替换为实际仓库,如 `sanguo/sanguo_moziplus_v2` +- Issue 详情: GET /api/v1/repos/{owner}/{repo}/issues/{number} +- Issue 评论: GET /api/v1/repos/{owner}/{repo}/issues/{number}/comments +- PR diff: GET /api/v1/repos/{owner}/{repo}/pulls/{number}.diff +- 提交 Review: POST /api/v1/repos/{owner}/{repo}/pulls/{number}/reviews +``` + +**改动范围**:6 个 Agent 的 AGENTS.md 各加一段(内容统一)。 + +##### L2:Mail 模板精简 + 事件上下文注入 + +**原则**:模板只放摘要 + 链接 + 仓库信息,不写固定步骤(步骤在 L1)。 + +**issue_assigned.md** 改为: + +```markdown +Issue 指派 + +Issue: {issue_url} +标题: {issue_title} +标签: {labels} + +📋 获取完整上下文(先读再动手): +- Issue 详情: GET {gitea_api}/repos/{repo}/issues/{issue_number} +- Issue 评论: GET {gitea_api}/repos/{repo}/issues/{issue_number}/comments + +仓库: {repo_clone_url} +建议分支: feat/issue-{issue_number}-{brief} +``` + +**review_request.md** 改为: + +```markdown +PR Review 请求 + +PR: {pr_url} +标题: {pr_title} +作者: {pr_author} +分支: {branch} +风险级别: {risk_level} + +📋 获取完整上下文: +- PR diff: GET {gitea_api}/repos/{repo}/pulls/{pr_number}.diff +- PR 文件列表: GET {gitea_api}/repos/{repo}/pulls/{pr_number}/files +``` + +**review_result.md** 改为: + +```markdown +Review {result} + +PR: {pr_url} +标题: {pr_title} +审查者: {reviewer} + +{review_body} +``` + +**ci_failure.md** 改为: + +```markdown +CI 失败 + +Issue: {issue_url} +分支: {branch} + +错误摘要: +{error_summary} + +📋 CI 日志: {gitea_url}/{repo}/actions +修复后 push 会自动重触发 CI。 +``` + +**deploy_failure.md** 改为: + +```markdown +部署失败 + +仓库: {repo} +Commit: {commit_sha} + +📋 排查步骤: +- CI 日志: {gitea_url}/{repo}/actions +- 服务器: pm2 logs {service_name} +``` + +**L2 代码改动**(`toolchain_routes.py`): + +1. 从 Webhook payload 的 `repository` 对象提取 `clone_url` 和 `html_url` +2. `render_template()` 传入新变量:`gitea_api`、`gitea_url`、`repo_clone_url` +3. 所有模板变量统一补齐 + +##### L3:Skill 按需加载(不改 Skill 本身) + +git-workflow、code-review 等 Skill 保持不变。 + +L1 的协作行为段里会引用 Skill 名称("参考 git-workflow Skill"),Agent 收到 Mail 后根据 L1 的引导自主加载对应 Skill。 + +**不改 Skill 路由机制**——靠 L1 的文案触发 Agent 的 Skill 路由器匹配。 + +--- + +### 三、新增功能:issue_comment @mention 通知 + +#### 3.1 设计 + +当前 `_handle_issue_comment` 只处理 `[CI]` 前缀评论。扩展为: + +``` +issue_comment 事件 + ├── 含 [CI] / CI 失败 → 原有 CI 失败通知逻辑 + └── 含 @username → 解析 @mention → Mail 通知被 @的 Agent +``` + +#### 3.2 实现 + +**`toolchain_routes.py` 新增 `_handle_issue_comment_mention()`**: + +```python +AGENT_IDS = { + "zhangfei-dev", "guanyu-dev", "zhaoyun-data", + "jiangwei-infra", "simayi-challenger", "pangtong-fujunshi", +} + +# 前缀映射:@张飞 → zhangfei-dev +# 中文名映射:Agent 在 Gitea Issue 评论中可能用中文名 @mention +# 英文短名映射:Agent 可能用不带 -dev/-infra 后缀的短名 +AGENT_ALIAS = { + "张飞": "zhangfei-dev", + "关羽": "guanyu-dev", + "赵云": "zhaoyun-data", + "姜维": "jiangwei-infra", + "司马懿": "simayi-challenger", + "庞统": "pangtong-fujunshi", + "pangtong": "pangtong-fujunshi", + "simayi": "simayi-challenger", + "zhangfei": "zhangfei-dev", + "guanyu": "guanyu-dev", + "zhaoyun": "zhaoyun-data", + "jiangwei": "jiangwei-infra", +} + +def extract_mentions(body: str, sender: str) -> list[str]: + """从评论 body 中提取 @mention 的 Agent ID""" + candidates = re.findall(r"@([a-zA-Z\u4e00-\u9fa5][a-zA-Z0-9\u4e00-\u9fff-]*)", body) + result = set() + for c in candidates: + # 精确匹配 + if c in AGENT_IDS: + result.add(c) + # 前缀/别名匹配 + elif c in AGENT_ALIAS: + result.add(AGENT_ALIAS[c]) + else: + # 前缀模糊匹配:@zhangfei → zhangfei-dev + for aid in AGENT_IDS: + if aid.startswith(c): + result.add(aid) + break + # 过滤掉评论者自己 + result.discard(sender) + return list(result) +``` + +**新增 mention 通知模板** `templates/toolchain/mention.md`: + +```markdown +你在 Issue 中被 @mention + +Issue: {issue_url} +评论者: {commenter} +评论内容: +{comment_body} + +📋 获取完整上下文: +- Issue 详情: GET {gitea_api}/repos/{repo}/issues/{issue_number} +- Issue 评论: GET {gitea_api}/repos/{repo}/issues/{issue_number}/comments +``` + +**改动 `_handle_issue_comment`**: + +```python +async def _handle_issue_comment(payload): + comment = payload.get("comment", {}) + body = comment.get("body", "") + sender = comment.get("user", {}).get("login", "") + repo = _repo_fullname(payload) + issue = payload.get("issue", {}) + + # 原有 CI 失败逻辑(不变) + if "[CI]" in body or "CI 失败" in body: + # ... 原有逻辑 ... + + # 新增:@mention 通知 + mentions = extract_mentions(body, sender) + if mentions: + issue_number = issue.get("number", 0) + issue_title = issue.get("title", "") + text = render_template("mention", { + "repo": repo, + "issue_number": str(issue_number), + "issue_url": issue.get("html_url", ""), + "commenter": sender, + "comment_body": body[:500], + "gitea_api": "http://192.168.2.154:3000/api/v1", + }) + title = f"@mention: {issue_title} ({repo}#{issue_number})" + for agent_id in mentions: + _send_mail(agent_id, title, text) +``` + +#### 3.3 去重 + +- 同一条评论 @多人:每人一封 Mail(不同 to,内容相同) +- 同一事件 org webhook + repo webhook 双触发:现有 delivery UUID 去重机制覆盖 +- 同一人被 @多次:`extract_mentions` 返回 set,自动去重 + +--- + +### 四、Mail Spawn Prompt 改造 + +#### 4.1 问题 + +当前工具链 Mail 走 Mail 通道,spawn prompt 是: + +``` +你收到一封飞鸽传书(纯通知)。 +发件者: system +主题: Issue 指派: xxx +内容: [工具链模板] +已阅即可。 +``` + +"已阅即可"直接让 Agent 不做事。 + +#### 4.2 方案 + +**不改 MAIL_INFORM_TEMPLATE / MAIL_REQUEST_TEMPLATE 本身**(那是 Mail 系统通用的)。 + +改为:**工具链 Mail 使用 `type=request`(而不是默认的 inform)**。 + +在 `_send_mail()` 中,工具链事件创建的 Mail 默认 `performative=request`,这样 Agent 收到时走 `MAIL_REQUEST_TEMPLATE`,知道需要处理。 + +具体改动在 `_send_mail()` 函数或其调用处:工具链路由调用 `_send_mail` 时传入 `performative="request"`。 + +**⚠️ 验证要点**:改为 request 后,Agent spawn prompt 变为 "请处理以下请求",需确认: +1. Agent 不再把工具链 Mail 当纯通知忽略 +2. Agent 能正确处理「已阅型」工具链事件(如 CI 失败通知——不需要回复,但需要知道) +3. 对已关闭 PR/Issue 的延迟通知,Agent 不会尝试去处理 + +验证方法:部署后发一条 Issue 指派 Mail,观察 Agent 行为是否符合预期。 + +--- + +### 五、完整改动清单 + +| # | 改什么 | 改动内容 | 层 | 风险 | +|---|--------|---------|---|------| +| 1 | 6 个 Agent 的 `AGENTS.md` | 加"工具链协作"段(内容统一) | L1 | 低(纯追加) | +| 2 | `templates/toolchain/issue_assigned.md` | 精简 + 加仓库上下文 + Gitea API 引导 | L2 | 低 | +| 3 | `templates/toolchain/review_request.md` | 精简 + 加 Gitea API 引导 | L2 | 低 | +| 4 | `templates/toolchain/review_result.md` | 精简 | L2 | 低 | +| 5 | `templates/toolchain/ci_failure.md` | 精简 + 加 CI 日志链接 | L2 | 低 | +| 6 | `templates/toolchain/deploy_failure.md` | 精简 + 加排查步骤 | L2 | 低 | +| 7 | **新建** `templates/toolchain/mention.md` | @mention 通知模板 | L2 | 低 | +| 8 | `src/api/toolchain_routes.py` | 提取 clone_url/html_url 传入模板;issue_comment 增加 @mention 解析;工具链 Mail 改为 request 类型 | L2 | 中 | +| 9 | 不改 | git-workflow 等 Skill 保持不变 | L3 | — | +| 10 | 不改 | daemon 核心逻辑、BootstrapBuilder、Skill 路由 | — | — | + +--- + +### 六、验证方案 + +#### 6.1 单元验证 + +| 验证点 | 方法 | +|--------|------| +| `extract_mentions()` 提取 `@zhangfei-dev` | unit test | +| `extract_mentions()` 别名匹配 `@张飞` → zhangfei-dev | unit test | +| `extract_mentions()` 前缀匹配 `@zhangfei` → zhangfei-dev | unit test | +| `extract_mentions()` 过滤自己 | unit test | +| 模板渲染新变量不报错 | unit test | + +#### 6.2 真实场景 E2E 验证 + +重复 Issue #32 的场景: +1. 创建 Issue 指派张飞 +2. **验证**:张飞收到的 Mail 含 clone URL + Gitea API 引导 +3. **验证**:张飞 spawn 后知道该做什么(L1 AGENTS.md 有流程引导) +4. **验证**:张飞有疑问时去 Gitea Issue 评论(而不是 Control UI) +5. 在 Issue 评论 @赵云 +6. **验证**:赵云收到 @mention Mail + +--- + +### 七、不做的事(标记为后续) + +| 标记 | 描述 | 原因 | +|------|------|------| +| 后续-1 | Agent 离开工具链讨论后,是否有意识回到工具链 | 需要更多真实场景观察 | +| 后续-2 | 工具链使用标准在所有 Agent 间的一致性验证 | L1 统一段落是第一步,需要 E2E 验证 | +| 后续-3 | Mail 通道接入 BootstrapBuilder L2 注入 | 改动大,当前方案(L1 统一段落 + 模板引导)够用 | +| 后续-4 | Skill 路由器自动触发(引擎注入) | 改动 daemon 核心,当前靠 L1 文案触发 | + +--- + +### 八、变更记录 + +| 日期 | 版本 | 变更 | +|------|------|------| +| 2026-06-09 | v1.0 | 初版:E2E 真实场景暴露问题 → 四层改造方案 + @mention 通知 + Mail type 改造 | + diff --git a/docs/design/19-toolchain-context-layers.md b/docs/design/19-toolchain-context-layers.md deleted file mode 100644 index fec21e7..0000000 --- a/docs/design/19-toolchain-context-layers.md +++ /dev/null @@ -1,382 +0,0 @@ -# #19 工具链事件中枢 — 上下文四层改造方案 - -> 版本: v1.0 -> 日期: 2026-06-09 -> 作者: 庞统(副军师) -> 状态: 待主公确认 -> 前置: #13 工具链与开发流程 §16, #05 上下文四层架构 -> 来源: E2E 真实场景测试暴露的三个断层 - ---- - -## 一、问题诊断 - -### 1.1 E2E 真实场景测试暴露的三个断层 - -主公在 moziplus-v2 仓库创建了 Issue #32(添加 /api/stats 端点),指派张飞。链条在第一步就断了。 - -| 断层 | 现象 | 根因 | -|------|------|------| -| **Agent 不知道该做什么** | 张飞收到 Issue 指派 Mail,回复"已阅"就结束了 | Mail 模板(issue_assigned.md)5 行信息,无流程引导;spawn prompt 说"已阅即可" | -| **Agent 去错了仓库** | 张飞去读了 sanguo_moziplus_v2 平台代码,而不是空的实验仓库 moziplus-v2 | Mail 模板没有仓库 clone URL,张飞凭习惯去了开发目录 | -| **Agent 在 Control UI 提问** | 张飞遇到问题直接在 Control UI 问主公,没有去 Gitea Issue 评论 | 没有任何地方引导"有疑问去 Gitea Issue 评论" | -| **Agent 不知道怎么协作** | 张飞判断任务需要澄清,但不知道该怎么请求澄清 | 没有"做不了→在 Issue 评论 / Mail 庞统"的回退路径 | -| **跨 Agent @mention 无法通知** | 张飞在 Issue 评论 @赵云,赵云收不到通知 | issue_comment handler 只处理 [CI] 评论,@mention 被忽略 | - -### 1.2 根因:工具链在四层架构中的断层 - -| 层 | 应该有 | 实际有 | Gap | -|---|---|---|---| -| **L0 铁律** | — | — | 无需改动 | -| **L1 角色** | 工具链协作行为规范(所有 Agent 共享) | 无 | AGENTS.md 没有工具链相关内容 | -| **L2 引擎注入** | 事件上下文(仓库 clone URL、Gitea API、Issue/PR 详情) | Mail 模板只有 5 行摘要 | 缺仓库信息和流程引导 | -| **L3 被动参考** | 技术细节(分支命名、commit 规范、PR 创建方式) | git-workflow 等 Skill 已存在但没人触发 | Agent 不知道该加载哪个 Skill | - ---- - -## 二、改造方案:四层归属 - -### 2.1 分层原则 - -| 层 | 放什么 | 不放什么 | 理由 | -|---|---|---|---| -| **L0** | 不放 | — | 工具链不是安全底线 | -| **L1** | 协作行为规范:收到什么通知该做什么、遇到问题怎么办 | 技术细节(分支命名、commit 格式) | 行为规范是团队常识,每个 Agent 都要知道 | -| **L2** | 事件上下文:仓库 clone URL、Gitea API URL、Issue/PR 链接、动态信息 | 固定的协作流程 | 动态信息每次不同,由 Mail 模板 + spawn 时注入 | -| **L3** | 技术细节:git-workflow、code-review 等 Skill 全文 | — | 按需加载,Agent 知道"我要提 PR"后自己读 | - -### 2.2 各层具体内容 - -#### L1:AGENTS.md 加工具链协作行为段(所有 Agent 统一) - -```markdown -## 工具链协作(Gitea) - -收到 Gitea 事件通知(Issue 指派、Review 请求、CI 失败等)时,按以下流程操作: - -### 基本流程 -- **Issue 指派** → clone 仓库 → 开分支 → 编码 → 提 PR(参考 git-workflow Skill) -- **Review 请求** → 读 PR diff(Gitea API)→ 提交 Review(参考 code-review Skill) -- **Review 通过** → 等 merge -- **Review 驳回** → 看 review body → 修代码 → 重新 push -- **CI 失败** → 看错误摘要 → 修代码 → push(自动重触发 CI) -- **部署失败** → 查 deploy 日志 → 修复 - -### 协作规则 -- **有疑问?** 在 Gitea Issue 下评论,不要在 Control UI 或 Mail 里问 -- **需要别人帮忙?** 在 Issue 评论中 @mention 对应 Agent(如 @zhaoyun-data) -- **做不了?** 回复 Mail 说明原因和建议的接手人 -- **获取完整上下文** → 用 Gitea API 拉取 Issue 详情和评论,不要只看 Mail 里的快照 - -### Gitea API 速查 -> 其中 `{owner}/{repo}` 替换为实际仓库,如 `sanguo/sanguo_moziplus_v2` -- Issue 详情: GET /api/v1/repos/{owner}/{repo}/issues/{number} -- Issue 评论: GET /api/v1/repos/{owner}/{repo}/issues/{number}/comments -- PR diff: GET /api/v1/repos/{owner}/{repo}/pulls/{number}.diff -- 提交 Review: POST /api/v1/repos/{owner}/{repo}/pulls/{number}/reviews -``` - -**改动范围**:6 个 Agent 的 AGENTS.md 各加一段(内容统一)。 - -#### L2:Mail 模板精简 + 事件上下文注入 - -**原则**:模板只放摘要 + 链接 + 仓库信息,不写固定步骤(步骤在 L1)。 - -**issue_assigned.md** 改为: - -```markdown -Issue 指派 - -Issue: {issue_url} -标题: {issue_title} -标签: {labels} - -📋 获取完整上下文(先读再动手): -- Issue 详情: GET {gitea_api}/repos/{repo}/issues/{issue_number} -- Issue 评论: GET {gitea_api}/repos/{repo}/issues/{issue_number}/comments - -仓库: {repo_clone_url} -建议分支: feat/issue-{issue_number}-{brief} -``` - -**review_request.md** 改为: - -```markdown -PR Review 请求 - -PR: {pr_url} -标题: {pr_title} -作者: {pr_author} -分支: {branch} -风险级别: {risk_level} - -📋 获取完整上下文: -- PR diff: GET {gitea_api}/repos/{repo}/pulls/{pr_number}.diff -- PR 文件列表: GET {gitea_api}/repos/{repo}/pulls/{pr_number}/files -``` - -**review_result.md** 改为: - -```markdown -Review {result} - -PR: {pr_url} -标题: {pr_title} -审查者: {reviewer} - -{review_body} -``` - -**ci_failure.md** 改为: - -```markdown -CI 失败 - -Issue: {issue_url} -分支: {branch} - -错误摘要: -{error_summary} - -📋 CI 日志: {gitea_url}/{repo}/actions -修复后 push 会自动重触发 CI。 -``` - -**deploy_failure.md** 改为: - -```markdown -部署失败 - -仓库: {repo} -Commit: {commit_sha} - -📋 排查步骤: -- CI 日志: {gitea_url}/{repo}/actions -- 服务器: pm2 logs {service_name} -``` - -**L2 代码改动**(`toolchain_routes.py`): - -1. 从 Webhook payload 的 `repository` 对象提取 `clone_url` 和 `html_url` -2. `render_template()` 传入新变量:`gitea_api`、`gitea_url`、`repo_clone_url` -3. 所有模板变量统一补齐 - -#### L3:Skill 按需加载(不改 Skill 本身) - -git-workflow、code-review 等 Skill 保持不变。 - -L1 的协作行为段里会引用 Skill 名称("参考 git-workflow Skill"),Agent 收到 Mail 后根据 L1 的引导自主加载对应 Skill。 - -**不改 Skill 路由机制**——靠 L1 的文案触发 Agent 的 Skill 路由器匹配。 - ---- - -## 三、新增功能:issue_comment @mention 通知 - -### 3.1 设计 - -当前 `_handle_issue_comment` 只处理 `[CI]` 前缀评论。扩展为: - -``` -issue_comment 事件 - ├── 含 [CI] / CI 失败 → 原有 CI 失败通知逻辑 - └── 含 @username → 解析 @mention → Mail 通知被 @的 Agent -``` - -### 3.2 实现 - -**`toolchain_routes.py` 新增 `_handle_issue_comment_mention()`**: - -```python -AGENT_IDS = { - "zhangfei-dev", "guanyu-dev", "zhaoyun-data", - "jiangwei-infra", "simayi-challenger", "pangtong-fujunshi", -} - -# 前缀映射:@张飞 → zhangfei-dev -# 中文名映射:Agent 在 Gitea Issue 评论中可能用中文名 @mention -# 英文短名映射:Agent 可能用不带 -dev/-infra 后缀的短名 -AGENT_ALIAS = { - "张飞": "zhangfei-dev", - "关羽": "guanyu-dev", - "赵云": "zhaoyun-data", - "姜维": "jiangwei-infra", - "司马懿": "simayi-challenger", - "庞统": "pangtong-fujunshi", - "pangtong": "pangtong-fujunshi", - "simayi": "simayi-challenger", - "zhangfei": "zhangfei-dev", - "guanyu": "guanyu-dev", - "zhaoyun": "zhaoyun-data", - "jiangwei": "jiangwei-infra", -} - -def extract_mentions(body: str, sender: str) -> list[str]: - """从评论 body 中提取 @mention 的 Agent ID""" - candidates = re.findall(r"@([a-zA-Z\u4e00-\u9fa5][a-zA-Z0-9\u4e00-\u9fff-]*)", body) - result = set() - for c in candidates: - # 精确匹配 - if c in AGENT_IDS: - result.add(c) - # 前缀/别名匹配 - elif c in AGENT_ALIAS: - result.add(AGENT_ALIAS[c]) - else: - # 前缀模糊匹配:@zhangfei → zhangfei-dev - for aid in AGENT_IDS: - if aid.startswith(c): - result.add(aid) - break - # 过滤掉评论者自己 - result.discard(sender) - return list(result) -``` - -**新增 mention 通知模板** `templates/toolchain/mention.md`: - -```markdown -你在 Issue 中被 @mention - -Issue: {issue_url} -评论者: {commenter} -评论内容: -{comment_body} - -📋 获取完整上下文: -- Issue 详情: GET {gitea_api}/repos/{repo}/issues/{issue_number} -- Issue 评论: GET {gitea_api}/repos/{repo}/issues/{issue_number}/comments -``` - -**改动 `_handle_issue_comment`**: - -```python -async def _handle_issue_comment(payload): - comment = payload.get("comment", {}) - body = comment.get("body", "") - sender = comment.get("user", {}).get("login", "") - repo = _repo_fullname(payload) - issue = payload.get("issue", {}) - - # 原有 CI 失败逻辑(不变) - if "[CI]" in body or "CI 失败" in body: - # ... 原有逻辑 ... - - # 新增:@mention 通知 - mentions = extract_mentions(body, sender) - if mentions: - issue_number = issue.get("number", 0) - issue_title = issue.get("title", "") - text = render_template("mention", { - "repo": repo, - "issue_number": str(issue_number), - "issue_url": issue.get("html_url", ""), - "commenter": sender, - "comment_body": body[:500], - "gitea_api": "http://192.168.2.154:3000/api/v1", - }) - title = f"@mention: {issue_title} ({repo}#{issue_number})" - for agent_id in mentions: - _send_mail(agent_id, title, text) -``` - -### 3.3 去重 - -- 同一条评论 @多人:每人一封 Mail(不同 to,内容相同) -- 同一事件 org webhook + repo webhook 双触发:现有 delivery UUID 去重机制覆盖 -- 同一人被 @多次:`extract_mentions` 返回 set,自动去重 - ---- - -## 四、Mail Spawn Prompt 改造 - -### 4.1 问题 - -当前工具链 Mail 走 Mail 通道,spawn prompt 是: - -``` -你收到一封飞鸽传书(纯通知)。 -发件者: system -主题: Issue 指派: xxx -内容: [工具链模板] -已阅即可。 -``` - -"已阅即可"直接让 Agent 不做事。 - -### 4.2 方案 - -**不改 MAIL_INFORM_TEMPLATE / MAIL_REQUEST_TEMPLATE 本身**(那是 Mail 系统通用的)。 - -改为:**工具链 Mail 使用 `type=request`(而不是默认的 inform)**。 - -在 `_send_mail()` 中,工具链事件创建的 Mail 默认 `performative=request`,这样 Agent 收到时走 `MAIL_REQUEST_TEMPLATE`,知道需要处理。 - -具体改动在 `_send_mail()` 函数或其调用处:工具链路由调用 `_send_mail` 时传入 `performative="request"`。 - -**⚠️ 验证要点**:改为 request 后,Agent spawn prompt 变为 "请处理以下请求",需确认: -1. Agent 不再把工具链 Mail 当纯通知忽略 -2. Agent 能正确处理「已阅型」工具链事件(如 CI 失败通知——不需要回复,但需要知道) -3. 对已关闭 PR/Issue 的延迟通知,Agent 不会尝试去处理 - -验证方法:部署后发一条 Issue 指派 Mail,观察 Agent 行为是否符合预期。 - ---- - -## 五、完整改动清单 - -| # | 改什么 | 改动内容 | 层 | 风险 | -|---|--------|---------|---|------| -| 1 | 6 个 Agent 的 `AGENTS.md` | 加"工具链协作"段(内容统一) | L1 | 低(纯追加) | -| 2 | `templates/toolchain/issue_assigned.md` | 精简 + 加仓库上下文 + Gitea API 引导 | L2 | 低 | -| 3 | `templates/toolchain/review_request.md` | 精简 + 加 Gitea API 引导 | L2 | 低 | -| 4 | `templates/toolchain/review_result.md` | 精简 | L2 | 低 | -| 5 | `templates/toolchain/ci_failure.md` | 精简 + 加 CI 日志链接 | L2 | 低 | -| 6 | `templates/toolchain/deploy_failure.md` | 精简 + 加排查步骤 | L2 | 低 | -| 7 | **新建** `templates/toolchain/mention.md` | @mention 通知模板 | L2 | 低 | -| 8 | `src/api/toolchain_routes.py` | 提取 clone_url/html_url 传入模板;issue_comment 增加 @mention 解析;工具链 Mail 改为 request 类型 | L2 | 中 | -| 9 | 不改 | git-workflow 等 Skill 保持不变 | L3 | — | -| 10 | 不改 | daemon 核心逻辑、BootstrapBuilder、Skill 路由 | — | — | - ---- - -## 六、验证方案 - -### 6.1 单元验证 - -| 验证点 | 方法 | -|--------|------| -| `extract_mentions()` 提取 `@zhangfei-dev` | unit test | -| `extract_mentions()` 别名匹配 `@张飞` → zhangfei-dev | unit test | -| `extract_mentions()` 前缀匹配 `@zhangfei` → zhangfei-dev | unit test | -| `extract_mentions()` 过滤自己 | unit test | -| 模板渲染新变量不报错 | unit test | - -### 6.2 真实场景 E2E 验证 - -重复 Issue #32 的场景: -1. 创建 Issue 指派张飞 -2. **验证**:张飞收到的 Mail 含 clone URL + Gitea API 引导 -3. **验证**:张飞 spawn 后知道该做什么(L1 AGENTS.md 有流程引导) -4. **验证**:张飞有疑问时去 Gitea Issue 评论(而不是 Control UI) -5. 在 Issue 评论 @赵云 -6. **验证**:赵云收到 @mention Mail - ---- - -## 七、不做的事(标记为后续) - -| 标记 | 描述 | 原因 | -|------|------|------| -| 后续-1 | Agent 离开工具链讨论后,是否有意识回到工具链 | 需要更多真实场景观察 | -| 后续-2 | 工具链使用标准在所有 Agent 间的一致性验证 | L1 统一段落是第一步,需要 E2E 验证 | -| 后续-3 | Mail 通道接入 BootstrapBuilder L2 注入 | 改动大,当前方案(L1 统一段落 + 模板引导)够用 | -| 后续-4 | Skill 路由器自动触发(引擎注入) | 改动 daemon 核心,当前靠 L1 文案触发 | - ---- - -## 八、变更记录 - -| 日期 | 版本 | 变更 | -|------|------|------| -| 2026-06-09 | v1.0 | 初版:E2E 真实场景暴露问题 → 四层改造方案 + @mention 通知 + Mail type 改造 |