1076 lines
45 KiB
Markdown
1076 lines
45 KiB
Markdown
---
|
||
title: "ToolchainHandler 强约束设计"
|
||
created: 2026-06-13
|
||
version: v1.0
|
||
status: draft
|
||
---
|
||
|
||
# ToolchainHandler 强约束设计
|
||
|
||
> **状态**: 草案
|
||
> **作者**: 庞统(副军师)🐦
|
||
> **日期**: 2026-06-13
|
||
> **定位**: 让 toolchain 事件走已有的 ToolchainHandler(§14 设计),并在 ToolchainHandler 中加入 L2 引擎层的强约束(输入/执行/输出),取代 §16 权宜方案中走 MailHandler inform 的路径
|
||
> **前置文档**: §14 TaskTypeRegistry + Handler 架构、§13 工具链与开发流程设计
|
||
> **推翻文档**: 原 §17 action Mail 类型设计(`17-action-mail-type.md`)
|
||
|
||
---
|
||
|
||
## §1. 问题陈述
|
||
|
||
### 1.1 现状
|
||
|
||
ToolchainHandler 已完整实现并注册(`src/daemon/toolchain_handler.py`,`virtual_project="_toolchain"`)。但实际的 toolchain 事件流从未走过 ToolchainHandler:
|
||
|
||
| 环节 | 设计(§14) | 实际(§16 权宜) |
|
||
|------|------------|----------------|
|
||
| 创建 task | `project_id="_toolchain"` + `task_type="toolchain"` | `project_id="_mail"` + `task_type="mail"` |
|
||
| 写入 DB | `_toolchain/blackboard.db` | `_mail/blackboard.db` |
|
||
| 路由 handler | ToolchainHandler | MailHandler |
|
||
| 完成验证 | verify action output | inform 始终通过 |
|
||
|
||
**根因**:§16 设计 toolchain 事件中枢时,没有用 ToolchainHandler,而是通过 `_send_mail`(`src/api/toolchain_routes.py` L203)创建 `task_type="mail"` + `type=inform"` 的 task。§16 D1 决策"不做第三种 task 类型"是基于权宜方案做的——但 §14 早已设计了 ToolchainHandler 作为独立的 task 类型,只是没有接线。
|
||
|
||
### 1.2 后果
|
||
|
||
所有 toolchain 事件走了 MailHandler 的 inform 路径:
|
||
|
||
1. MailHandler 的 inform PromptSection 说"已阅即可"、"不要执行任何状态转换命令"——Agent 收到 Review 驳回通知后当纯通知处理就 done 了
|
||
2. verify_completion 对 inform 始终返回 `VerifyResult(True)`——没有任何验证
|
||
3. 流程断链:Review 驳回 → Agent 不修 → 永远卡在驳回状态;CI 失败 → Agent 不修 → 永远卡在失败状态
|
||
|
||
### 1.3 主公要求
|
||
|
||
> "输入,执行过程和输出都要能确保流程的顺利执行,以及业务内容的承载"
|
||
> "L2 引擎这一层的 toolchain 必须是强约束的"
|
||
> "不强约束总是断链"
|
||
|
||
### 1.4 方向
|
||
|
||
**不是给 Mail 加类型,而是让 toolchain 事件回归 ToolchainHandler**。ToolchainHandler 已有独立的 DB、独立的 PromptSection、独立的 verify 逻辑。需要做的是:
|
||
|
||
1. 新增 `_send_toolchain_task` 函数,创建 `project_id="_toolchain"` + `task_type="toolchain"` 的 task
|
||
2. 强化 ToolchainHandler 的三个 PromptSection,实现 L2 引擎层的三层强约束
|
||
3. 强化 verify_completion,从"任意 comment ≥20 字符"升级为"action_report comment 存在"
|
||
|
||
---
|
||
|
||
## §2. 三层强约束总览
|
||
|
||
主公要求的"输入、执行过程和输出"三层,对应 ToolchainHandler 的三个核心环节:
|
||
|
||
```
|
||
┌─────────────────────────────────────────────────────────┐
|
||
│ ToolchainHandler 强约束 │
|
||
│ │
|
||
│ ┌─── 输入约束 ───┐ ┌─── 执行约束 ───┐ ┌─── 输出约束 ──┐ │
|
||
│ │ │ │ │ │ │ │
|
||
│ │ must_hives JSON │ │ PromptSection │ │ verify_ │ │
|
||
│ │ 携带结构化字段 │→ │ 强语气+Red Flag│→ │ completion │ │
|
||
│ │ │ │ │ │ │ │
|
||
│ │ ToolchainContext│ │ ToolchainCon- │ │ action_report│ │
|
||
│ │ Section 渲染 │ │ straintsSection│ │ comment 检查 │ │
|
||
│ │ 编号步骤列表 │ │ 必须执行 │ │ │ │
|
||
│ │ │ │ │ │ on_failure: │ │
|
||
│ │ │ │ │ │ 标failed+通知│ │
|
||
│ └────────────────┘ └────────────────┘ └──────────────┘ │
|
||
│ │
|
||
│ 数据流: webhook → _send_toolchain_task → _toolchain DB │
|
||
│ → spawner (ToolchainHandler.build_prompt) │
|
||
│ → Agent 执行 → comment (action_report) │
|
||
│ → verify_completion → done / failed │
|
||
└─────────────────────────────────────────────────────────┘
|
||
```
|
||
|
||
| 层 | 目标 | 机制 | 防什么 |
|
||
|----|------|------|--------|
|
||
| **输入约束** | Agent 收到的不是一句话摘要,而是结构化的编号步骤 + 事件上下文 | must_hives JSON(event_type, action_type, steps, context)+ ToolchainContextSection 渲染 | 防"Agent 不知道该做什么" |
|
||
| **执行约束** | Agent 知道必须执行,不会自合理化跳过 | ToolchainConstraintsSection 强语气"必须执行" + Red Flags 表 | 防"Agent 当纯通知忽略" |
|
||
| **输出约束** | Agent 执行后有可验证的产出 | verify_completion 检查 action_report comment | 防"Agent 假装执行" |
|
||
|
||
---
|
||
|
||
## §3. 输入约束(Agent 收到什么)
|
||
|
||
### 3.1 must_hives JSON 结构
|
||
|
||
toolchain task 的 `must_hives` 字段携带完整的结构化信息:
|
||
|
||
```json
|
||
{
|
||
"event_type": "review_result",
|
||
"action_type": "review_result",
|
||
"steps": [
|
||
"合并 PR(Gitea API: POST /repos/{repo}/pulls/{pr_number}/merge)",
|
||
"提交 action report(POST http://localhost:8083/api/projects/_toolchain/tasks/{task_id}/comments,comment_type=action_report)"
|
||
],
|
||
"context": {
|
||
"pr_number": 42,
|
||
"repo": "sanguo/sanguo_moziplus_v2",
|
||
"pr_title": "feat: add login page",
|
||
"result": "APPROVED",
|
||
"reviewer": "simayi-challenger",
|
||
"review_body": "代码质量良好,可以合并"
|
||
},
|
||
"from": "system",
|
||
"source": "webhook"
|
||
}
|
||
```
|
||
|
||
字段说明:
|
||
|
||
| 字段 | 类型 | 必填 | 说明 |
|
||
|------|------|------|------|
|
||
| `event_type` | string | ✅ | 事件类型,用于 ToolchainContextSection 模板选择 |
|
||
| `action_type` | string | ✅ | 动作分类,用于步骤选择和日志统计 |
|
||
| `steps` | string[] | ✅ | 结构化编号步骤列表,渲染到 Prompt 中 |
|
||
| `context` | object | ❌ | 事件上下文数据(PR 号、仓库名、review 意见等) |
|
||
| `from` | string | ✅ | 来源标识(`system` / webhook) |
|
||
| `source` | string | ❌ | 来源类型(`webhook`) |
|
||
|
||
### 3.2 ToolchainContextSection 渲染增强
|
||
|
||
现有 `ToolchainContextSection` 使用模板引擎渲染事件信息。增强后必须包含三部分内容:
|
||
|
||
**Part 1:事件类型 + 事件上下文**(现有,保留)
|
||
|
||
通过 `toolchain_templates.py` 的模板引擎渲染,展示事件的核心信息(PR 标题、审查结果、CI 错误摘要等)。
|
||
|
||
**Part 2:结构化编号步骤**(新增,从 must_hives 的 `steps` 字段读取)
|
||
|
||
```markdown
|
||
### 必须执行的步骤
|
||
|
||
1. 合并 PR(Gitea API: POST /repos/sanguo/sanguo_moziplus_v2/pulls/42/merge)
|
||
2. 提交 action report(POST http://localhost:8083/api/projects/_toolchain/tasks/<task_id>/comments,comment_type=action_report)
|
||
```
|
||
|
||
**Part 3:事件专属 action 指引**(新增,按 action_type 选择)
|
||
|
||
每种事件类型有对应的 action 指引文本,以"你收到一个需要执行动作的事件"开头,明确告诉 Agent 这不是纯通知。
|
||
|
||
渲染逻辑伪代码:
|
||
|
||
```python
|
||
class ToolchainContextSection:
|
||
def render(self, context: PromptContext) -> str:
|
||
# Part 1: 事件信息(现有模板引擎)
|
||
event_text = render_template(context.event_type, ...)
|
||
|
||
# Part 2: 结构化步骤(新增)
|
||
steps = context.action_steps # 从 PromptContext 获取
|
||
steps_text = ""
|
||
if steps:
|
||
lines = ["", "### 必须执行的步骤", ""]
|
||
for i, step in enumerate(steps, 1):
|
||
lines.append(f"{i}. {step}")
|
||
steps_text = "\n".join(lines)
|
||
|
||
# Part 3: action 指引(新增)
|
||
action_hint = self._get_action_hint(context.action_type)
|
||
|
||
return f"{action_hint}\n\n{event_text}{steps_text}"
|
||
|
||
def _get_action_hint(self, action_type: str) -> str:
|
||
hints = {
|
||
"review_result": "你收到一个 Review 结果通知,这是一个需要你执行动作的事件(不是纯通知)。",
|
||
"review_request": "你收到一个 Review 请求,这是一个需要你审查并提交 Review 的事件。",
|
||
"ci_failure": "你收到一个 CI 失败通知,这是一个需要你修复失败测试的事件。",
|
||
...
|
||
}
|
||
return hints.get(action_type, "你收到一个工具链事件,这是一个需要你执行动作的事件。")
|
||
```
|
||
|
||
### 3.3 与 §13 §15.5 强约束模板的关系
|
||
|
||
§13 §15.5 定义了 6 个流程强约束 Mail 模板,每个模板包含编号步骤和 Gitea API 调用指令。这些模板内容**不变**,但承载方式变了:
|
||
|
||
| 维度 | §16 权宜方案 | 本设计 |
|
||
|------|------------|--------|
|
||
| 模板渲染为 | Mail task 的 description | toolchain task 的 description(ToolchainContextSection 模板引擎) |
|
||
| 步骤固化在 | description 纯文本中 | must_hives JSON `steps` 字段 + PromptSection 渲染 |
|
||
| Agent 是否能看到步骤 | 受 MailHandler inform prompt 干扰("已阅即可") | ToolchainHandler prompt 强化("必须执行") |
|
||
|
||
---
|
||
|
||
## §4. 执行约束(Agent 知道必须做)
|
||
|
||
### 4.1 ToolchainConstraintsSection 强化
|
||
|
||
现有的 `ToolchainConstraintsSection` 有 5 条约束,但语气不够强,且缺少防自合理化机制。改写为:
|
||
|
||
```markdown
|
||
## 硬约束(必须遵守)
|
||
|
||
⚠️ 以下是强制要求,不是建议或参考。违反任何一条都会导致任务失败。
|
||
|
||
### 1. 必须按步骤执行
|
||
- 检查上方"必须执行的步骤"列表
|
||
- 逐条执行每个步骤,不可跳过
|
||
- 不要只读不做——这不是纯通知
|
||
|
||
### 2. 必须提交 action report
|
||
- 执行完所有步骤后,必须提交 action report
|
||
- 提交方式:POST comment(comment_type='action_report')
|
||
- 报告内容:简要描述你执行了什么操作、结果如何
|
||
- ⚠️ 不提交 action report 的任务会被标记为 failed
|
||
|
||
### 3. 不要执行任何状态转换命令
|
||
- 不要手动标 working/done/review/failed,系统会自动处理
|
||
|
||
### 4. 不需要回复
|
||
- action report 就是你的完成凭证
|
||
- 不要发送 Mail(飞鸽传书),你的所有操作在 toolchain 流程内完成
|
||
|
||
### 5. 所有协作通过 Gitea 完成
|
||
- 如果遇到问题需要其他角色支持,在关联的 PR/Issue 上创建 comment @对方
|
||
- 不要使用 Mail API(飞鸽传书)发送消息
|
||
- 你的所有操作都在 toolchain 流程内,通过 Gitea 留痕
|
||
|
||
### Red Flags(如果脑海中出现以下想法,说明你错了)
|
||
|
||
| Agent 想法 | Red Flag 驳回 |
|
||
|------------|--------------|
|
||
| "这个通知看看就行了" | ❌ 错!这是 action 指令,必须执行步骤列表中的每一项 |
|
||
| "我不需要做任何事" | ❌ 错!检查"必须执行的步骤"列表,每一步都要执行 |
|
||
| "先放着等会处理" | ❌ 错!立即执行,不要推迟 |
|
||
| "我已经知道了" | ❌ 知道不等于执行。执行步骤 + 提交 action report 才算完成 |
|
||
| "步骤太多了,选几个做就行" | ❌ 错!必须逐条执行,不可跳过 |
|
||
| "这个步骤不适用于当前情况" | ❌ 如果确实不适用,在 action report 中说明原因,但其他步骤必须执行 |
|
||
```
|
||
|
||
### 4.2 Red Flags 表设计原理
|
||
|
||
参考 Superpowers 模式的 Red Flags 防 self-rationalization 机制:
|
||
|
||
**问题**:LLM Agent 面对需要执行动作的 prompt 时,常见的 self-rationalization 模式:
|
||
1. **降级处理**:把 action 当 inform 处理("这个通知看看就行了")
|
||
2. **推迟执行**:识别到需要执行但不执行("先放着等会处理")
|
||
3. **部分执行**:选择性跳过步骤("选几个做就行")
|
||
4. **认知混淆**:知道但没行动("我已经知道了")
|
||
|
||
**解法**:提前列出这些 self-rationalization 模式,在 Agent 的 prompt 中以"Red Flag"表格形式呈现。当 Agent 的推理过程中出现这些模式时,表格中的"驳回"语句会激活,阻止 Agent 继续沿错误路径推理。
|
||
|
||
**来源**:Superpowers 框架的"Pre-commitment + Red Flag"模式。预先承诺一个规则,然后列出违反规则的常见借口,让 Agent 在推理时就识别出自己的 self-rationalization。
|
||
|
||
### 4.3 强语气设计
|
||
|
||
| 语气级别 | 用词 | 效果 | 使用场景 |
|
||
|---------|------|------|---------|
|
||
| **强制** | "必须"、"不可跳过"、"强制要求" | Agent 无法自合理化跳过 | 步骤执行、action report 提交 |
|
||
| **禁止** | "不要"、"违反会"、"failed" | Agent 不会越界 | 状态转换、发送 Mail |
|
||
| **提醒** | "⚠️" | 视觉强调 | 关键约束前缀 |
|
||
|
||
**避免的用词**:"建议"、"如需"、"可以考虑"、"参考"、"推荐"——这些词在 Agent 的推理中会被解读为"可选"。
|
||
|
||
### 4.4 ToolchainApiSection 调整
|
||
|
||
现有的 `ToolchainApiSection` 指示 Agent 标 done,但强约束设计中 done 由 verify_completion 自动触发。调整:
|
||
|
||
```markdown
|
||
## API 操作指令
|
||
|
||
项目 ID: `_toolchain`
|
||
任务 ID: {task_id}
|
||
|
||
### 完成后必须提交 action report
|
||
|
||
执行完所有步骤后,必须提交 action report:
|
||
|
||
```bash
|
||
curl -s -X POST "http://localhost:8083/api/projects/_toolchain/tasks/{task_id}/comments" \
|
||
-H "Content-Type: application/json" \
|
||
-d '{"author": "{agent_id}", "comment_type": "action_report", "body": "简要描述你执行了什么操作及结果"}'
|
||
```
|
||
|
||
⚠️ 不提交 action report 的任务会被标记为 failed。
|
||
|
||
### 提交产出
|
||
|
||
如有产出(如 review 结果、修复方案),提交到任务 outputs:
|
||
|
||
```bash
|
||
curl -s -X POST "http://localhost:8083/api/projects/_toolchain/tasks/{task_id}/outputs" \
|
||
-H "Content-Type: application/json" \
|
||
-d '{"content": "<你的产出内容>", "type": "text"}'
|
||
```
|
||
```
|
||
|
||
### 需要其他角色支持时
|
||
|
||
如果在执行过程中需要其他角色协助(如缺数据、需要审批等),在关联的 PR/Issue 上创建 comment @对方:
|
||
|
||
```bash
|
||
curl -s -X POST "http://192.168.2.154:3000/api/v1/repos/{repo}/issues/{pr_number}/comments" \
|
||
-H "Authorization: token <your-token>" \
|
||
-H "Content-Type: application/json" \
|
||
-d '{"body": "@{agent-id} 需要你的支持:{描述问题}"}'
|
||
```
|
||
|
||
⚠️ 不要使用 Mail API(飞鸽传书)。所有协作通过 Gitea 留痕。
|
||
|
||
**变化**:移除了"手动标 done"的 curl 示例(done 由 verify 自动处理),替换为 action report 提交指引。
|
||
|
||
---
|
||
|
||
## §5. 输出约束(Agent 执行后怎么验证)
|
||
|
||
### 5.1 verify_completion 设计
|
||
|
||
**D17-1: verify_completion 采用 action_report comment 机制**
|
||
|
||
现有逻辑:检查 output 或 comment(任意 comment 长度 ≥20 字符)→ 通过。
|
||
|
||
问题:Agent 可以随便写一条 comment 就通过验证,无法确认是否真正执行了步骤。
|
||
|
||
新逻辑:检查 `comment_type='action_report'` 的 comment 是否存在。
|
||
|
||
```python
|
||
def verify_completion(self, task_id: str, db_path: Path) -> VerifyResult:
|
||
"""检查 action report(精确验证)"""
|
||
try:
|
||
conn = get_connection(db_path)
|
||
try:
|
||
# 1. 优先检查 action_report comment
|
||
report_row = conn.execute(
|
||
"SELECT id FROM comments WHERE task_id=? "
|
||
"AND comment_type='action_report' LIMIT 1",
|
||
(task_id,)
|
||
).fetchone()
|
||
if report_row:
|
||
return VerifyResult(True, "has_action_report", "action_report found")
|
||
|
||
# 2. fallback:检查 output(向后兼容)
|
||
output_count = conn.execute(
|
||
"SELECT COUNT(*) FROM outputs WHERE task_id=?", (task_id,)
|
||
).fetchone()[0]
|
||
if output_count > 0:
|
||
return VerifyResult(True, "has_output", f"output_count={output_count}")
|
||
|
||
# 3. fallback:检查有实质内容的 comment(向后兼容)
|
||
comment_count = conn.execute(
|
||
"SELECT COUNT(*) FROM comments WHERE task_id=? "
|
||
"AND author != 'system' AND LENGTH(body) >= 20",
|
||
(task_id,)
|
||
).fetchone()[0]
|
||
if comment_count > 0:
|
||
return VerifyResult(True, "has_comment", f"comment_count={comment_count}")
|
||
|
||
return VerifyResult(False, "no_action", "no action_report, no output, no valid comment")
|
||
finally:
|
||
conn.close()
|
||
except Exception as e:
|
||
logger.error("Toolchain %s: verify error: %s", task_id, e)
|
||
return VerifyResult(False, "verify_error", str(e))
|
||
```
|
||
|
||
**验证优先级**:
|
||
1. `action_report` comment(首选——精确验证 Agent 执行了步骤)
|
||
2. output(fallback——Agent 可能通过 outputs API 提交了产出)
|
||
3. 有实质内容的 comment(fallback——向后兼容现有行为)
|
||
|
||
保留 fallback 层次是为了平滑过渡:改造初期 Agent 可能还不习惯提交 action_report,fallback 避免"改造后所有 task 都 failed"的问题。
|
||
|
||
### 5.2 on_failure 处理
|
||
|
||
**设计原则**:toolchain 事件全生命周期在 toolchain 流程内闭环,不走 Mail API。失败本身按错误类型分类,路由到不同的 Gitea 管理动作。
|
||
|
||
#### 错误分类三分路
|
||
|
||
| 错误类型 | 例子 | 处理方式 | 管道 |
|
||
|---------|------|---------|------|
|
||
| **业务失败** | verify 不过(no action_report)、Agent 忽略步骤 | 在关联 PR/Issue 上创建 comment @原始 assignee | Gitea webhook → §25 @mention → toolchain task |
|
||
| **系统失败** | spawner crash、timeout、max_retries、业务失败连续 3 次 | 创建 Gitea Issue 指派 pangtong-fujunshi | Gitea webhook → issue_assigned → toolchain task |
|
||
| **基础设施失败** | Gitea API 不可用、网络不通 | `_send_toolchain_task` 直接创建 toolchain task 指派 jiangwei-infra | toolchain 内部直接创建 |
|
||
|
||
三条路全在 toolchain 流程内,Mail 完全不参与。
|
||
|
||
#### 防递归保护
|
||
|
||
基础设施失败创建的 toolchain task(action_type=infrastructure_failure),其 verify_completion 始终返回 `VerifyResult(True)`,不再触发 on_failure。
|
||
|
||
#### 完整设计
|
||
|
||
三分路的详细伪代码、失败上限、决策依据见 §5.2.1~§5.2.3(on_failure 分路处理详细设计)。
|
||
|
||
### 5.3 action_report comment 格式
|
||
|
||
Agent 提交的 action_report comment:
|
||
|
||
```json
|
||
{
|
||
"comment_type": "action_report",
|
||
"author": "zhangfei-dev",
|
||
"body": "已修复 CI 失败:修正 import 错误(src/api/routes.py L23),push 到 feat/issue-42 分支。CI 已自动重跑。"
|
||
}
|
||
```
|
||
|
||
**comment body 要求**:
|
||
- 简要描述执行了什么操作
|
||
- 如有修改,说明修改的文件和大致内容
|
||
- 如有外部验证(CI 重跑、Review 提交),说明状态
|
||
|
||
### 5.4 防虚假报告
|
||
|
||
Agent 可能写了 action_report 但没真做。缓解机制:
|
||
|
||
1. **后续事件链自然暴露**:CI 不会通过、Reviewer 不会收到 Review、部署不会成功
|
||
2. **action_report 可审计**:庞统可以查看 action_report 内容和实际 Gitea 状态是否一致
|
||
3. **验证目标定位**:verify 的首要目标是防止 Agent"没看到/忽略了"(占 90% 的失败场景),不是防止恶意行为(<10%)
|
||
|
||
---
|
||
|
||
## §6. 场景 steps 定义
|
||
|
||
### 6.1 完整场景对照表
|
||
|
||
| 场景 | action_type | 走向 | steps | 说明 |
|
||
|------|------------|------|-------|------|
|
||
| Review APPROVED → PR 作者 | review_result | toolchain | 2 步 | 合并 PR + 提交 report |
|
||
| Review REQUEST_CHANGES → PR 作者 | review_result | toolchain | 4 步 | 修改代码 + push + 等 Review + report |
|
||
| Review 请求 → reviewer | review_request | toolchain | 4 步 | 读 diff + 审查 + 提交 Review + report |
|
||
| Review 有新提交 → reviewer | review_updated | toolchain | 4 步 | 读 diff + 检查修改 + 提交 Review + report |
|
||
| Review 评论 → PR 作者 | review_comment | toolchain | 3 步 | 查看评论 + 响应(修改/回复)+ report |
|
||
| CI 失败 → PR 作者 | ci_failure | toolchain | 4 步 | 查 CI 日志 + 修测试 + push + report |
|
||
| Issue 指派 → 开发者 | issue_assigned | toolchain | 6 步 | 创建分支 + 编码 + push + CI + PR + report |
|
||
| 部署失败 → 运维 | deploy_failure | toolchain | 4 步 | 查日志 + 排查 + 修+重部署 + report |
|
||
| @mention → 被@者 | mention | toolchain | 按 guidance | 按 mention 模板的 response_guidance + report |
|
||
| PR 合并 → PR 作者 | review_merged | toolchain | 0 步 | 纯通知,走 _send_toolchain_task(steps 为空,verify 始终通过) |
|
||
|
||
**D17-2: 所有 toolchain 场景走 ToolchainHandler**
|
||
|
||
### 6.2 各场景 steps 详细定义
|
||
|
||
#### Review APPROVED → PR 作者
|
||
|
||
```
|
||
event_type: review_result
|
||
action_type: review_result
|
||
steps:
|
||
1. 合并 PR(Gitea API: POST /repos/{repo}/pulls/{pr_number}/merge)
|
||
2. 提交 action report(POST .../comments, comment_type=action_report)
|
||
context:
|
||
pr_number, repo, pr_title, result=APPROVED, reviewer, review_body
|
||
```
|
||
|
||
#### Review REQUEST_CHANGES → PR 作者
|
||
|
||
```
|
||
event_type: review_result
|
||
action_type: review_result
|
||
steps:
|
||
1. 按审查意见逐条修改代码
|
||
2. push 到原分支 → CI 自动跑
|
||
3. CI 通过后等重新 Review
|
||
4. 提交 action report
|
||
context:
|
||
pr_number, repo, pr_title, result=REQUEST_CHANGES, reviewer, review_body
|
||
```
|
||
|
||
#### Review 请求 → reviewer
|
||
|
||
```
|
||
event_type: review_request
|
||
action_type: review_request
|
||
steps:
|
||
1. 读取 PR diff(Gitea API: GET /repos/{repo}/pulls/{pr_number}.diff)
|
||
2. 按审查清单审查(参考 code-review Skill)
|
||
3. 提交 Review(Gitea API: POST /repos/{repo}/pulls/{pr_number}/reviews)— APPROVE 或 REQUEST_CHANGES
|
||
4. 提交 action report
|
||
context:
|
||
pr_number, repo, pr_title, pr_author, branch, risk_level, changed_files
|
||
```
|
||
|
||
#### Review 有新提交 → reviewer
|
||
|
||
```
|
||
event_type: review_updated
|
||
action_type: review_updated
|
||
steps:
|
||
1. 读取 PR diff(Gitea API: GET /repos/{repo}/pulls/{pr_number}.diff)
|
||
2. 重点检查上次 Review 意见的修改部分
|
||
3. 提交 Review(Gitea API: POST /repos/{repo}/pulls/{pr_number}/reviews)
|
||
4. 提交 action report
|
||
context:
|
||
pr_number, repo, pr_title, pr_author, new_sha, reviewer
|
||
```
|
||
|
||
#### CI 失败 → PR 作者
|
||
|
||
```
|
||
event_type: ci_failure
|
||
action_type: ci_failure
|
||
steps:
|
||
1. 查看完整 CI 日志(PR 页面或 Gitea Actions 页面)
|
||
2. 修复失败的测试
|
||
3. push → CI 自动重跑
|
||
4. 提交 action report
|
||
context:
|
||
pr_number, repo, branch, error_summary
|
||
```
|
||
|
||
#### Issue 指派 → 开发者
|
||
|
||
```
|
||
event_type: issue_assigned
|
||
action_type: issue_assigned
|
||
steps:
|
||
1. 创建分支 fix/{issue_number}-{brief}
|
||
2. 编码 + 写 UT
|
||
3. push → 等 CI
|
||
4. CI 通过后创建 PR(Gitea API: POST /repos/{repo}/pulls)
|
||
5. 等 Review
|
||
6. 提交 action report
|
||
context:
|
||
issue_number, repo, issue_title, labels, issue_body, brief
|
||
```
|
||
|
||
#### 部署失败 → 运维
|
||
|
||
```
|
||
event_type: deploy_failure
|
||
action_type: deploy_failure
|
||
steps:
|
||
1. 检查 deploy 日志
|
||
2. 排查失败原因
|
||
3. 修复并重新部署
|
||
4. 提交 action report
|
||
context:
|
||
repo, commit_sha, reason
|
||
```
|
||
|
||
#### @mention → 被@者
|
||
|
||
```
|
||
event_type: mention
|
||
action_type: mention
|
||
steps:
|
||
1. 按 mention 模板中的 response_guidance 执行
|
||
2. 提交 action report
|
||
context:
|
||
source_type, source_url, commenter, content_snippet, intent_hint, response_guidance
|
||
```
|
||
|
||
#### PR 合并 → PR 作者
|
||
|
||
```
|
||
event_type: review_merged
|
||
action_type: review_merged
|
||
steps: [] # 无步骤,纯通知
|
||
verify: 始终通过(inform 语义,无需 action_report)
|
||
context:
|
||
pr_number, repo, pr_title, pr_author, merged_by
|
||
```
|
||
|
||
**特殊处理**:review_merged 的 verify_completion 始终返回 `VerifyResult(True)`。这是唯一的纯通知场景,Agent 只需阅读即可。
|
||
|
||
### 6.3 PR 合并通知为何也走 ToolchainHandler
|
||
|
||
**设计原则**:toolchain 和 Mail 完全分离。所有工具链事件(包括纯通知)都走 ToolchainHandler + _toolchain DB。
|
||
|
||
**为什么 PR 合并通知不走 _mail**:
|
||
- toolchain 事件的完整生命周期应在同一个 DB(_toolchain)中追溯
|
||
- 前端展示统一(Toolchain Tab),不需要跨 _mail 和 _toolchain 两个 Tab 查看同一类事件
|
||
- Mail 只服务 Agent 间点对点通信(inform / request),不服务工具链事件
|
||
|
||
**实现差异**:review_merged 的 verify_completion 始终通过(`VerifyResult(True)`),不需要 action_report。这是 ToolchainHandler 内部的语义区分,不影响 MailHandler。
|
||
|
||
**spawn 说明**:review_merged 仍会触发 spawn(Agent 只需阅读通知),verify auto-pass 后标 done。未来可优化为 ticker 直接 auto-done 跳过 spawn。
|
||
|
||
---
|
||
|
||
## §7. _send_toolchain_task 函数设计
|
||
|
||
### 7.1 函数定义
|
||
|
||
新增 `_send_toolchain_task` 函数(`src/api/toolchain_routes.py`),与 `_send_mail` 并列。两个函数各司其职:
|
||
|
||
| 函数 | 用途 | project_id | task_type | DB |
|
||
|------|------|-----------|-----------|-----|
|
||
| `_send_mail` | Agent 间点对点通信(inform / request) | `_mail` | `mail` | `_mail/blackboard.db` |
|
||
| `_send_toolchain_task` | 工具链动作事件(需 Agent 执行步骤) | `_toolchain` | `toolchain` | `_toolchain/blackboard.db` |
|
||
|
||
```python
|
||
def _toolchain_db_path() -> Path:
|
||
"""获取 Toolchain 数据库路径,确保目录存在。"""
|
||
root = get_data_root()
|
||
db = root / "_toolchain" / "blackboard.db"
|
||
db.parent.mkdir(parents=True, exist_ok=True)
|
||
init_db(db)
|
||
return db
|
||
|
||
|
||
def _send_toolchain_task(
|
||
to_agent: str,
|
||
title: str,
|
||
description: str,
|
||
event_type: str,
|
||
action_type: str,
|
||
steps: list[str],
|
||
context_data: dict | None = None,
|
||
source: str = "webhook",
|
||
) -> str:
|
||
"""创建 Toolchain Task 并写入 _toolchain DB。
|
||
|
||
Args:
|
||
to_agent: 收件人 Agent ID
|
||
title: 任务标题
|
||
description: 任务描述(模板渲染后的事件信息)
|
||
event_type: 事件类型(review_result / ci_failure / ...)
|
||
action_type: 动作分类(用于步骤选择和日志统计)
|
||
steps: 结构化编号步骤列表
|
||
context_data: 事件上下文数据(PR 号、仓库名等)
|
||
source: 来源标识
|
||
|
||
Returns:
|
||
创建的 Task ID
|
||
"""
|
||
if to_agent not in AGENT_IDS:
|
||
logger.warning("Unknown agent: %s, skipping toolchain task", to_agent)
|
||
return ""
|
||
|
||
task_id = f"tc-{int(datetime.now().timestamp() * 1000)}"
|
||
must_hives = json.dumps({
|
||
"event_type": event_type,
|
||
"action_type": action_type,
|
||
"steps": steps,
|
||
"context": context_data or {},
|
||
"from": "system",
|
||
"source": source,
|
||
}, ensure_ascii=False)
|
||
|
||
task = Task(
|
||
id=task_id,
|
||
title=title,
|
||
description=description,
|
||
assignee=to_agent,
|
||
assigned_by="system",
|
||
must_haves=must_hives,
|
||
task_type="toolchain",
|
||
status="pending",
|
||
)
|
||
bb = Blackboard(_toolchain_db_path())
|
||
bb.create_task(task)
|
||
logger.info(
|
||
"Toolchain task sent: %s → %s [%s] action_type=%s",
|
||
title[:40], to_agent, task_id, action_type,
|
||
)
|
||
return task_id
|
||
```
|
||
|
||
### 7.2 各 handler 调用改造
|
||
|
||
`toolchain_routes.py` 中各 handler 从调用 `_send_mail` 改为调用 `_send_toolchain_task`。
|
||
|
||
以 `_handle_pr_opened` 为例(改造后):
|
||
|
||
```python
|
||
async def _handle_pr_opened(payload: Dict[str, Any]) -> None:
|
||
"""PR opened → 通知 simayi-challenger(走 ToolchainHandler)。"""
|
||
pr = payload.get("pull_request")
|
||
repo = _repo_fullname(payload)
|
||
pr_number = pr.get("number", 0)
|
||
pr_title = pr.get("title", "")
|
||
# ... 获取文件列表、风险级别(现有逻辑不变)
|
||
|
||
text = render_template("review_request", {...})
|
||
|
||
title = f"Review 请求: {pr_title} ({repo}#{pr_number})"
|
||
_send_toolchain_task(
|
||
to_agent="simayi-challenger",
|
||
title=title,
|
||
description=text,
|
||
event_type="review_request",
|
||
action_type="review_request",
|
||
steps=[
|
||
f"读取 PR diff(Gitea API: GET /repos/{repo}/pulls/{pr_number}.diff)",
|
||
"按审查清单审查(参考 code-review Skill)",
|
||
f"提交 Review(Gitea API: POST /repos/{repo}/pulls/{pr_number}/reviews)— APPROVE 或 REQUEST_CHANGES",
|
||
f"提交 action report(POST http://localhost:8083/api/projects/_toolchain/tasks/<task_id>/comments,comment_type=action_report)",
|
||
],
|
||
context_data={
|
||
"pr_number": pr_number,
|
||
"repo": repo,
|
||
"pr_title": pr_title,
|
||
"pr_author": pr_author,
|
||
"branch": branch,
|
||
"risk_level": risk_level,
|
||
},
|
||
)
|
||
```
|
||
|
||
### 7.3 handler 改造对照表
|
||
|
||
| handler 函数 | 新 action_type | 新调用 |
|
||
|-------------|---------------|--------|
|
||
| `_handle_pr_opened` | review_request | `_send_toolchain_task(...)` |
|
||
| `_handle_pull_request_review` (APPROVED/REQUEST_CHANGES) | review_result | `_send_toolchain_task(...)` |
|
||
| `_handle_pr_synchronize` | review_updated | `_send_toolchain_task(...)` |
|
||
| `_handle_pull_request_review` (COMMENTED) | review_comment | `_send_toolchain_task(...)` |
|
||
| `_handle_issue_comment` (CI failure) | ci_failure | `_send_toolchain_task(...)` |
|
||
| `_handle_issues` (assigned) | issue_assigned | `_send_toolchain_task(...)` |
|
||
| `_handle_pr_closed` (merged) | review_merged | `_send_toolchain_task(...)`(纯通知,steps 为空,verify 始终通过) |
|
||
| `_send_deploy_failure_mail` | deploy_failure | `_send_toolchain_task(...)` |
|
||
| `_send_mention_mails` | mention | `_send_toolchain_task(...)` |
|
||
|
||
### 7.4 _send_mail 不参与任何 toolchain 事件
|
||
|
||
`_send_mail` 函数只服务一个场景:**Agent 间点对点通信**(inform / request)。
|
||
|
||
**toolchain 事件完全不经过 Mail**:
|
||
- 事件投递:`_send_toolchain_task`(不是 `_send_mail`)
|
||
- 失败处理:Gitea PR comment / Gitea Issue / `_send_toolchain_task`(三分路)
|
||
- PR 合并通知:`_send_toolchain_task`(review_merged,steps 为空)
|
||
|
||
Mail 和 toolchain 是两套完全独立的系统,各自有独立的 DB、Handler、PromptSection。
|
||
|
||
---
|
||
|
||
## §8. spawner / PromptContext 改动
|
||
|
||
### 8.1 PromptContext 新增字段
|
||
|
||
```python
|
||
@dataclass
|
||
class PromptContext:
|
||
# ... 现有字段不变 ...
|
||
|
||
# toolchain 专用(增强)
|
||
event_type: str = ""
|
||
event_data: Dict = field(default_factory=dict)
|
||
action_type: str = "" # 新增:动作分类
|
||
action_steps: list = field(default_factory=list) # 新增:结构化步骤列表
|
||
```
|
||
|
||
### 8.2 spawner 解析 must_hives 增强
|
||
|
||
`spawner.py` 中 handler 路径的 PromptContext 构造,需要从 must_hives JSON 中提取 action 字段:
|
||
|
||
```python
|
||
handler = TaskTypeRegistry.get_by_project(project_id)
|
||
if handler:
|
||
meta = json.loads(must_haves) if must_haves else {}
|
||
from_agent = meta.get("from", "")
|
||
mail_type = meta.get("performative", meta.get("type", ""))
|
||
# 注:toolchain task 的 mail_type 为空(不走 MailHandler),保留字段兼容 MailHandler
|
||
|
||
# 新增:toolchain 字段提取
|
||
event_type = meta.get("event_type", "")
|
||
event_data = meta.get("context", {})
|
||
action_type = meta.get("action_type", "")
|
||
action_steps = meta.get("steps", [])
|
||
|
||
ctx = PromptContext(
|
||
task_id=task_id, title=title, description=description or "",
|
||
must_haves=must_haves or "", project_id=project_id,
|
||
agent_id=agent_id, role=spawn_type,
|
||
spawn_type=spawn_type,
|
||
from_agent=from_agent, mail_type=mail_type,
|
||
event_type=event_type, event_data=event_data,
|
||
action_type=action_type, action_steps=action_steps,
|
||
)
|
||
return handler.build_prompt(ctx)
|
||
```
|
||
|
||
---
|
||
|
||
## §9. DB 隔离设计
|
||
|
||
### 9.1 两套独立 DB
|
||
|
||
**D17-5: _mail 和 _toolchain DB 隔离**(§14 原设计)
|
||
|
||
```
|
||
~/.sanguo_projects/sanguo_moziplus_v2/data/
|
||
├── _mail/
|
||
│ └── blackboard.db # MailHandler 管理
|
||
├── _toolchain/
|
||
│ └── blackboard.db # ToolchainHandler 管理
|
||
└── projects/
|
||
└── ...
|
||
```
|
||
|
||
隔离理由:
|
||
1. §14 L41 明确:`_toolchain` 有独立 DB,和 `_mail` 隔离
|
||
2. 不同 task_type 的 task 互不干扰
|
||
3. 前端展示独立(Toolchain Tab vs 飞鸽传书 Tab)
|
||
4. 数据量可控(toolchain 事件多但每个 task 生命周期短)
|
||
|
||
### 9.2 comments 表 CHECK 约束
|
||
|
||
**D17-3: comments 表 CHECK 约束处理**
|
||
|
||
`_toolchain/blackboard.db` 的 comments 表需要支持 `action_report` 类型的 comment。
|
||
|
||
现有 CHECK 约束(`db.py`):
|
||
```sql
|
||
CHECK (comment_type IN (
|
||
'general','handoff','observation','review',
|
||
'rebuttal','rebuttal_response','debate_argument',
|
||
'debate_rebuttal','debate_judgment'
|
||
))
|
||
```
|
||
|
||
**方案 A(推荐)**:去掉 CHECK 约束。CHECK 在 SQLite 中仅文档作用,应用层已做校验。去掉后未来新增 comment_type 不需要 migration。
|
||
|
||
**方案 B**:新增 `action_report` 到 CHECK 约束枚举。需要 migration(SQLite 重建表)。
|
||
|
||
推荐方案 A——直接去掉 CHECK,在应用层(ToolchainApiSection + comments API)校验 comment_type 合法性。
|
||
|
||
### 9.3 ticker 扫描
|
||
|
||
ticker 需要扫描 `_toolchain` 虚拟项目。当前 ticker 通过 `TaskTypeRegistry.virtual_projects()` 自动发现已注册的虚拟项目,ToolchainHandler 已注册 `virtual_project="_toolchain"`,无需额外改动。
|
||
|
||
---
|
||
|
||
## §10. 影响范围
|
||
|
||
涉及的文件(开发目录 `~/.openclaw/sanguo_projects/sanguo_moziplus_v2/`):
|
||
|
||
| 文件 | 改动类型 | 说明 |
|
||
|------|---------|------|
|
||
| `src/daemon/toolchain_handler.py` | 修改 | ToolchainContextSection 加 steps 渲染 + action_hint;ToolchainApiSection 改为 action_report 指引;ToolchainConstraintsSection 加 Red Flags;verify_completion 改用 action_report |
|
||
| `src/api/toolchain_routes.py` | 修改 | 新增 `_toolchain_db_path()` + `_send_toolchain_task()`;所有 handler(含 PR merged)改为调用 `_send_toolchain_task` |
|
||
| `src/daemon/spawner.py` | 修改 | handler 路径 PromptContext 构造时提取 `action_type`、`action_steps` 字段 |
|
||
| `src/daemon/prompt_composer.py` | 修改 | PromptContext 新增 `action_type`、`action_steps` 字段 |
|
||
| `src/blackboard/db.py` | 修改 | comments 表 CHECK 约束处理(去掉 CHECK 或加 action_report) |
|
||
|
||
### 改动量估算
|
||
|
||
| 文件 | 改动量 | 风险 |
|
||
|------|--------|------|
|
||
| `src/daemon/toolchain_handler.py` | ~120 行 | 中(核心逻辑变化 + on_failure 三分路) |
|
||
| `src/api/toolchain_routes.py` | ~120 行 | 中(新增函数 + 8 个 handler 改造) |
|
||
| `src/daemon/spawner.py` | ~8 行 | 低(纯新增字段提取) |
|
||
| `src/daemon/prompt_composer.py` | ~3 行 | 低(dataclass 新增字段) |
|
||
| `src/blackboard/db.py` | ~5 行 | 低(CHECK 约束处理) |
|
||
| **总计** | **~256 行** | |
|
||
|
||
---
|
||
|
||
## §11. 向后兼容
|
||
|
||
### 11.1 Mail 系统不受影响
|
||
|
||
| 场景 | 影响 |
|
||
|------|------|
|
||
| Agent 间手动发 inform Mail | ✅ 无影响 |
|
||
| Agent 间手动发 request Mail | ✅ 无影响 |
|
||
| MailHandler 的 verify / on_failure | ✅ 无影响 |
|
||
| `_send_mail` 函数 | ✅ 保留不变(只服务 Agent 间通信,不服务任何 toolchain 事件) |
|
||
|
||
### 11.2 _mail DB 中已有的 toolchain task
|
||
|
||
改造前创建的 toolchain task 存在于 `_mail/blackboard.db` 中(task_type=mail, type=inform)。改造后:
|
||
|
||
- 这些旧 task 继续由 MailHandler 管理(inform 始终通过验证)
|
||
- 不需要 migration——旧 task 自然 done / 过期清理
|
||
- 新 task 创建在 `_toolchain/blackboard.db` 中
|
||
|
||
### 11.3 ToolchainHandler 的 fallback verify
|
||
|
||
改造后 verify_completion 保留了三层 fallback:
|
||
1. action_report comment(首选)
|
||
2. output(fallback)
|
||
3. 有实质内容的 comment(fallback)
|
||
|
||
这意味着即使 Agent 初期不习惯提交 action_report,只要有 output 或实质 comment 仍能通过验证。平滑过渡。
|
||
|
||
### 11.4 PromptContext 新增字段
|
||
|
||
`action_type` 和 `action_steps` 使用 `field(default_factory=list/str)`,不传时为空/[]。现有 PromptContext 构造不受影响。
|
||
|
||
### 11.5 comments 表 CHECK 约束
|
||
|
||
如果选择"去掉 CHECK"方案,对现有数据无影响——现有 comment_type 值在应用层仍被校验。如果选择"加 action_report"方案,需要 migration。
|
||
|
||
---
|
||
|
||
## §12. 设计决策记录
|
||
|
||
### D17-1: verify 采用 action_report comment 机制
|
||
|
||
**决策**:verify_completion 优先检查 `comment_type='action_report'` 的 comment 是否存在,替代现有"任意 comment ≥20 字符"逻辑。保留 output 和实质 comment 作为 fallback。
|
||
|
||
**讨论的替代方案**:
|
||
- A(外部状态检查):太复杂,每个 action_type 需要不同检查逻辑,耦合 Gitea API
|
||
- B(始终通过):等于 inform,失去意义
|
||
- C(只查 action_report,无 fallback):改造初期过于激进
|
||
|
||
**理由**:action_report comment 机制最简单且与现有架构一致。保留 fallback 确保平滑过渡。Agent 如果写了 report 但没执行,后续事件链(CI 不会通过、Reviewer 不会收到 Review)会自然暴露问题。
|
||
|
||
### D17-2: 所有 toolchain 场景走 ToolchainHandler
|
||
|
||
**决策**:全部 10 种 toolchain 场景走 ToolchainHandler(`_send_toolchain_task`),包括 PR 合并通知(review_merged)。Mail 不服务任何 toolchain 事件。
|
||
|
||
**理由**:
|
||
- toolchain 事件的完整生命周期应在同一个 DB(_toolchain)中追溯
|
||
- 前端展示统一(Toolchain Tab),不需要跨 _mail 和 _toolchain 两个 Tab
|
||
- Mail 只服务 Agent 间点对点通信(inform / request),不服务工具链事件
|
||
- review_merged 的 verify_completion 始终通过,不需要 action_report
|
||
|
||
### D17-3: comments 表 CHECK 约束处理
|
||
|
||
**决策**:推荐去掉 comments 表的 comment_type CHECK 约束,在应用层校验。或新增 action_report 到 CHECK 枚举。
|
||
|
||
**理由**:SQLite CHECK 约束修改需要重建表(CREATE → COPY → DROP → RENAME),migration 成本高。CHECK 仅文档作用,去掉不影响功能。
|
||
|
||
### D17-4: 推翻 §16.0 D1"不做第三种 task 类型"
|
||
|
||
**决策**:推翻 D1。toolchain 事件不再走 MailHandler(mail + inform),改走 ToolchainHandler(toolchain)。
|
||
|
||
**理由**:
|
||
- D1 基于权宜方案——当时 ToolchainHandler 还没接线
|
||
- §14 早已设计 ToolchainHandler 作为独立 task type,有自己的 DB、PromptSection、verify 逻辑
|
||
- 不强约束总是断链——主公明确要求 L2 引擎层必须是强约束
|
||
- MailHandler 的 inform 语义("已阅即可")和 toolchain 事件的期望行为("必须执行步骤")根本矛盾
|
||
- ToolchainHandler 不需要 Mail 的回复机制(request),也不应该被 inform 的"已阅即可"语义覆盖
|
||
|
||
### D17-5: _mail 和 _toolchain DB 隔离
|
||
|
||
**决策**:toolchain task 写入 `_toolchain/blackboard.db`,不写入 `_mail/blackboard.db`。
|
||
|
||
**理由**:
|
||
- §14 L41 原设计
|
||
- 不同 task_type 的 task 互不干扰
|
||
- 数据生命周期不同(toolchain task 短生命周期,mail 可能需要长期保留线程)
|
||
- 前端展示独立
|
||
|
||
### D17-6: action_report 作为唯一的新 comment_type
|
||
|
||
**决策**:只引入 `action_report` 一个新 comment_type,不为每种 action_type 定义不同的 comment_type。
|
||
|
||
**理由**:
|
||
- 统一简化了 verify 逻辑(只查一种 type)
|
||
- action_type 的区分在 must_hives JSON 中已有
|
||
- comment body 内容可以自由描述具体执行了什么
|
||
|
||
### D17-7: ToolchainApiSection 移除"手动标 done"指引
|
||
|
||
**决策**:ToolchainApiSection 不再指示 Agent 手动标 done,改为指示提交 action_report。done 由 verify_completion 通过后自动触发。
|
||
|
||
**理由**:
|
||
- Agent 手动标 done 和 verify_completion 的 done 可能冲突
|
||
- action_report + verify 是更可靠的完成路径
|
||
- 减少 Agent 需要执行的 API 操作(从"标 done + 提交产出"简化为"提交 action_report")
|
||
|
||
---
|
||
|
||
## §13. 实施计划
|
||
|
||
### Step 1:基础设施(prompt_composer + spawner + db)
|
||
|
||
| 子步骤 | 文件 | 内容 | 风险 |
|
||
|--------|------|------|------|
|
||
| 1a | `prompt_composer.py` | PromptContext 新增 `action_type`、`action_steps` 字段 | 极低 |
|
||
| 1b | `spawner.py` | handler 路径提取 `action_type`、`action_steps` | 极低 |
|
||
| 1c | `db.py` | comments 表 CHECK 约束处理 | 低 |
|
||
|
||
### Step 2:ToolchainHandler 强化
|
||
|
||
| 子步骤 | 文件 | 内容 | 风险 |
|
||
|--------|------|------|------|
|
||
| 2a | `toolchain_handler.py` | ToolchainContextSection 加 steps 渲染 + action_hint | 低 |
|
||
| 2b | `toolchain_handler.py` | ToolchainApiSection 改为 action_report 指引 | 低 |
|
||
| 2c | `toolchain_handler.py` | ToolchainConstraintsSection 加 Red Flags 表 | 低 |
|
||
| 2d | `toolchain_handler.py` | verify_completion 改用 action_report(保留 fallback) | 中 |
|
||
| 2e | `toolchain_handler.py` | on_failure 三分路重写(业务→PR comment / 系统→Gitea Issue / 基础设施→toolchain task) | 中 |
|
||
|
||
### Step 3:toolchain_routes 改造
|
||
|
||
| 子步骤 | 文件 | 内容 | 风险 |
|
||
|--------|------|------|------|
|
||
| 3a | `toolchain_routes.py` | 新增 `_toolchain_db_path()` + `_send_toolchain_task()` | 低 |
|
||
| 3b | `toolchain_routes.py` | 所有 handler(含 PR merged)改为调用 `_send_toolchain_task` | 中 |
|
||
|
||
### Step 4:测试 + 验证
|
||
|
||
| 子步骤 | 内容 |
|
||
|--------|------|
|
||
| 4a | 单元测试:ToolchainContextSection steps 渲染 |
|
||
| 4b | 单元测试:verify_completion action_report 检查 + fallback |
|
||
| 4c | 单元测试:_send_toolchain_task 写入 _toolchain DB |
|
||
| 4d | 集成测试:webhook → toolchain task → Agent → action_report → done |
|
||
| 4e | 回归测试:_mail 路径不受影响(inform/request 不变) |
|
||
| 4f | 回归测试:PR merged 走 _send_toolchain_task(review_merged,verify 始终通过) |
|
||
|
||
---
|
||
|
||
## §14. 风险评估
|
||
|
||
| 风险 | 概率 | 影响 | 缓解措施 |
|
||
|------|------|------|----------|
|
||
| Agent 不提交 action_report | 中 | 高 | Prompt 强约束 + Red Flag 表 + verify 失败 → on_failure 三分路(PR comment @assignee / Gitea Issue @pangtong / toolchain task @jiangwei)+ fallback(output/comment) |
|
||
| Agent 提交虚假 action_report | 低 | 中 | 后续事件链自然暴露(CI 不通过、Reviewer 收不到 Review) |
|
||
| Agent 混淆 toolchain 和 mail 语义 | 低 | 低 | ToolchainContextSection 明确告知"这是需要执行动作的事件" |
|
||
| _toolchain DB 未初始化 | 低 | 中 | `_toolchain_db_path()` 中调用 `init_db()` 确保目录和表存在 |
|
||
| ticker 不扫描 _toolchain | 低 | 中 | TaskTypeRegistry.virtual_projects() 已自动发现 |
|
||
| handler 改造遗漏 | 中 | 低 | 逐个 handler 审查 + 集成测试覆盖 |
|
||
| steps 内容不完整或不准确 | 中 | 低 | 代码审查 + 从 §13 §15.5 已有模板提取 steps |
|
||
|
||
---
|
||
|
||
## §15. 优秀实践参考
|
||
|
||
### 15.1 §13 §15.5 流程强约束模板
|
||
|
||
§13 §15.5 已定义 6 个强约束模板,每个包含编号步骤、Gitea API 调用指令、时限要求。本设计在此基础上:
|
||
- 将步骤从模板纯文本提取到 must_hives JSON 的 `steps` 字段(结构化、可编程化)
|
||
- 通过 ToolchainHandler 的 PromptSection 强约束确保 Agent 知道必须执行
|
||
- 用 action report(执行凭证)替代邮件回复(更适合自动化验证)
|
||
|
||
### 15.2 Superpowers: Red Flags 表
|
||
|
||
Superpowers 使用 Red Flags 表防止 Agent self-rationalization。本设计在 ToolchainConstraintsSection 中增加 Red Flag 示例(如"这个通知看看就行了"→ ❌ 错!),防止 Agent 将 action 降级为 inform 处理。
|
||
|
||
### 15.3 §14 Handler 架构
|
||
|
||
§14 定义了 TaskTypeRegistry + Handler 架构,ToolchainHandler 已实现并注册。本设计是"给 ToolchainHandler 接线 + 强化约束"——不是新建一套系统,而是让已有的系统按设计意图运转。
|
||
|
||
### 15.4 Hermes: "Keep calling tools until complete AND verified"
|
||
|
||
Hermes 的验证理念:执行和验证不可分割。本设计中 verify_completion 的 action_report 检查就是这个理念的体现——不是检查 Agent"说了什么",而是检查 Agent"产出了什么执行凭证"。
|
||
|
||
---
|
||
|
||
## §16. 未来演进
|
||
|
||
### 16.1 外部状态验证(增强)
|
||
|
||
未来可选择性增加某些 action_type 的外部状态验证作为补充:
|
||
- `review_request`:检查 PR 是否有新的 Review
|
||
- `ci_failure`:检查 PR 是否有新 push
|
||
- `issue_assigned`:检查是否有关联 PR 创建
|
||
|
||
这是可选增强,在 action_report 之上叠加更精确的验证。
|
||
|
||
### 16.2 steps 动态化
|
||
|
||
当前 steps 在 `_send_toolchain_task` 调用时硬编码。未来可以根据事件内容动态生成 steps(如根据 CI 失败的具体测试文件给出修复建议)。
|
||
|
||
### 16.3 超时检测
|
||
|
||
参考 §15.4 的超时处置机制:
|
||
- toolchain task 创建后 N 小时内无 action_report → ticker 重发提醒
|
||
- 超时严重时 spawn 庞统介入
|
||
|
||
当前由 verify_completion 的 fail → on_failure → notify 机制处理。
|
||
|
||
---
|
||
|
||
## §17. 审查检查清单
|
||
|
||
- [ ] §1 问题陈述是否准确(ToolchainHandler 未接线,toolchain 事件走了 MailHandler inform)
|
||
- [ ] §2 三层强约束设计是否完整(输入/执行/输出)
|
||
- [ ] §3 输入约束:must_hives JSON 结构 + ToolchainContextSection 渲染增强
|
||
- [ ] §4 执行约束:Red Flags 表设计是否覆盖常见 self-rationalization 模式
|
||
- [ ] §5 输出约束:action_report verify 机制 + fallback 设计
|
||
- [ ] §6 场景 steps 定义是否完整(9 种 action 场景 + 1 种纯通知场景 review_merged)
|
||
- [ ] §7 _send_toolchain_task 函数设计是否正确
|
||
- [ ] §8 PromptContext / spawner 改动是否和 §14 架构一致
|
||
- [ ] §9 DB 隔离是否符合 §14 原设计
|
||
- [ ] §10 影响范围是否完整
|
||
- [ ] §11 向后兼容是否充分
|
||
- [ ] §12 设计决策 D17-1 ~ D17-7 是否合理
|
||
- [ ] §13 实施计划是否可行(4 步渐进)
|