diff --git a/docs/design/17-toolchain-handler-enforcement.md b/docs/design/17-toolchain-handler-enforcement.md index 1c6e36f..4e18da2 100644 --- a/docs/design/17-toolchain-handler-enforcement.md +++ b/docs/design/17-toolchain-handler-enforcement.md @@ -353,13 +353,136 @@ def verify_completion(self, task_id: str, db_path: Path) -> VerifyResult: 保留 fallback 层次是为了平滑过渡:改造初期 Agent 可能还不习惯提交 action_report,fallback 避免"改造后所有 task 都 failed"的问题。 -### 5.2 on_failure 处理 +### 5.2 on_failure 分路处理 -verify 失败时的处理逻辑(现有逻辑保留): +**设计原则**:toolchain 事件全生命周期在 toolchain 流程内闭环,不走 Mail API。失败本身按错误类型分类,路由到不同的 Gitea 管理动作。 -1. 标 task 为 `failed` -2. 通过 Mail API 通知庞统(`_notify_via_mail_api`) -3. 通知内容包含:事件类型、事件详情、失败原因、Gitea 链接、行动指引 +#### 错误分类三分路 + +| 错误类型 | 例子 | 处理方式 | 管道 | +|---------|------|---------|------| +| **业务失败** | verify 不过(no action_report)、Agent 忽略步骤 | 在关联 PR/Issue 上创建 comment @原始 assignee | Gitea webhook → §25 @mention → toolchain task | +| **系统失败** | spawner crash、timeout、max_retries | 创建 Gitea Issue 指派 pangtong-fujunshi,body 包含错误详情 + task ID + 日志摘要 | Gitea webhook → issue_assigned → toolchain task | +| **基础设施失败** | Gitea API 不可用、网络不通 | `_send_toolchain_task` 直接创建 toolchain task 指派 jiangwei-infra | toolchain 内部直接创建 | + +三条路全在 toolchain 流程内,Mail 完全不参与。 + +#### 业务失败处理(PR/Issue comment @assignee) + +verify 失败时,在原始事件关联的 Gitea PR 或 Issue 上创建 comment,@原始 assignee: + +```python +def on_failure(self, task_id, agent_id, db_path, verify): + self._mark_task_status(db_path, task_id, "failed") + + # 读取事件上下文 + meta = self._read_task_meta(db_path, task_id) + failure_count = meta.get("failure_count", 0) + 1 + + # 分类路由 + if verify.reason in SYSTEM_ERROR_REASONS: + # 系统失败 → Gitea Issue 给庞统 + self._create_gitea_issue_for_system_error(task_id, meta, verify) + else: + # 业务失败 → PR/Issue comment @assignee + self._create_gitea_comment_for_business_failure(task_id, meta, verify, failure_count) +``` + +**PR/Issue comment 内容**: + +``` +@{assignee} 任务处理失败,需要你的支持 + +📋 原始事件:{event_type} +❌ 失败原因:{verify.reason} +📊 失败次数:第 {failure_count} 次 + +请检查并处理。完成后提交 action report。 +``` + +**为什么 @mention 而非新建 task**: +- @mention 通过 §25 webhook 自然触发新 toolchain task,不多建一条路 +- Gitea comment 自带完整 PR/Issue 上下文,Agent 收到时能理解全貌 +- 人也能在 Gitea 上看到失败记录,天然审计 + +**失败上限**:同一事件 failure_count ≥ 3 时,升级为系统失败(创建 Gitea Issue 给庞统),避免无限循环。 + +#### 系统失败处理(Gitea Issue 给庞统) + +spawner 错误(crash/timeout/max_retries)或业务失败连续 3 次,创建 Gitea Issue: + +```python +def _create_gitea_issue_for_system_error(self, task_id, meta, verify): + """创建 Gitea Issue 指派庞统排查""" + repo = meta.get("context", {}).get("repo", "sanguo/sanguo_moziplus_v2") + title = f"[toolchain] 系统错误排查: {meta.get('event_type', 'unknown')} ({task_id})" + body = ( + f"## 系统错误\n\n" + f"**Task ID**: {task_id}\n" + f"**事件类型**: {meta.get('event_type', 'unknown')}\n" + f"**失败原因**: {verify.reason}\n" + f"**证据**: {verify.evidence}\n" + f"**原始 assignee**: {meta.get('context', {}).get('assignee', 'unknown')}\n\n" + f"## 排查方向\n" + f"- 检查 spawner 日志\n" + f"- 确认 Agent 是否正常运行\n" + f"- 检查是否有系统性问题(API down / 配置错误 / 资源不足)\n" + ) + # Gitea API 创建 Issue,指派 pangtong-fujunshi + _create_gitea_issue(repo, title, body, assignee="pangtong-fujunshi") +``` + +**为什么用 Gitea Issue**: +- 系统问题需要排查和 tracking,Issue 有状态管理(open/closed) +- Issue body 包含完整错误详情,便于事后 troubleshooting +- 指派庞统后通过 issue_assigned webhook 自然触发 toolchain task + +#### 基础设施失败处理(toolchain task 给姜维) + +Gitea API 不可用或网络不通时,无法创建 PR comment 或 Issue。此时降级为直接创建 toolchain task: + +```python +def _create_infrastructure_task(self, task_id, meta, verify, error_detail): + """基础设施失败 → toolchain task 指派姜维""" + _send_toolchain_task( + to_agent="jiangwei-infra", + title=f"[基础设施] Gitea 不可用导致 on_failure 降级: {task_id}", + description=f"尝试处理 task {task_id} 失败时 Gitea API 不可用。\n错误: {error_detail}", + event_type="infrastructure_failure", + action_type="infrastructure_failure", + steps=[ + "检查 Gitea 服务状态(http://192.168.2.154:3000)", + "检查网络连通性", + "Gitea 恢复后检查原始 task 状态并补处理", + "提交 action report", + ], + context_data={ + "original_task_id": task_id, + "original_event_type": meta.get("event_type", ""), + "gitea_error": error_detail, + }, + ) +``` + +**为什么不走 Gitea**:Gitea 本身就是问题源,调 Gitea API 创建 Issue 会再次失败。直接在 _toolchain DB 内创建 task 是最后的降级手段。 + +#### 三分路总结 + +``` +on_failure + │ + ├─ 系统错误(crash/timeout/max_retries/连续3次业务失败)? + │ └─ Gitea API 可用? + │ ├─ YES → 创建 Issue @pangtong-fujunshi → webhook → toolchain task + │ └─ NO → _send_toolchain_task @jiangwei-infra(基础设施降级) + │ + └─ 业务错误(no action_report)? + └─ Gitea API 可用? + ├─ YES → PR/Issue comment @assignee → §25 webhook → toolchain task + └─ NO → _send_toolchain_task @jiangwei-infra(基础设施降级) +``` + +所有路径都在 toolchain 流程内闭环,Mail 不参与。 ### 5.3 action_report comment 格式 @@ -670,11 +793,13 @@ async def _handle_pr_opened(payload: Dict[str, Any]) -> None: | `_send_deploy_failure_mail` | deploy_failure | `_send_toolchain_task(...)` | | `_send_mention_mails` | mention | `_send_toolchain_task(...)` | -### 7.4 _send_mail 保留不变 +### 7.4 _send_mail 不参与 toolchain 失败处理 -`_send_mail` 函数完全保留不变,只服务两个场景: +`_send_mail` 函数只服务两个场景: 1. PR 合并通知(inform 纯通知) -2. ToolchainHandler on_failure 的 Mail 通知(通过 Mail API 发给庞统) +2. Agent 间点对点通信(inform / request) + +**toolchain on_failure 不调用 `_send_mail`**。失败处理三分路(PR comment / Gitea Issue / toolchain task)全在 toolchain 流程内闭环。 --- @@ -786,6 +911,7 @@ ticker 需要扫描 `_toolchain` 虚拟项目。当前 ticker 通过 `TaskTypeRe | `src/daemon/prompt_composer.py` | 修改 | PromptContext 新增 `action_type`、`action_steps` 字段 | | `src/blackboard/db.py` | 修改 | comments 表 CHECK 约束处理(去掉 CHECK 或加 action_report) | | `src/daemon/mail_notify.py` | 修改 | `_REASON_MAP` 新增 `no_action_report` reason | +| `src/daemon/toolchain_handler.py`(on_failure) | 修改 | on_failure 三分路重写(去掉 Mail API 调用,改为 Gitea API + _send_toolchain_task) | +~40 行 | ### 改动量估算 @@ -811,6 +937,7 @@ ticker 需要扫描 `_toolchain` 虚拟项目。当前 ticker 通过 `TaskTypeRe | Agent 间手动发 request Mail | ✅ 无影响 | | MailHandler 的 verify / on_failure | ✅ 无影响 | | `_send_mail` 函数 | ✅ 保留不变 | +| ToolchainHandler on_failure 改为 Gitea 管理(PR comment / Issue / toolchain task),不经过 Mail API | ✅ 无影响 | ### 11.2 _mail DB 中已有的 toolchain task @@ -905,6 +1032,21 @@ ticker 需要扫描 `_toolchain` 虚拟项目。当前 ticker 通过 `TaskTypeRe - action_report + verify 是更可靠的完成路径 - 减少 Agent 需要执行的 API 操作(从"标 done + 提交产出"简化为"提交 action_report") +### D17-8: on_failure 走 Gitea 管理,不走 Mail + +**决策**:toolchain 失败处理三分路——业务失败在 PR/Issue comment @assignee,系统失败创建 Gitea Issue @pangtong-fujunshi,基础设施失败创建 toolchain task @jiangwei-infra。三条路全在 toolchain 流程内,Mail 不参与。 + +**讨论的替代方案**: +- A(Mail API 通知庞统):跨系统,回溯需要在 _mail 和 _toolchain 两个 DB 之间跳 +- B(on_failure 直接创建新 _toolchain task):强约束语义不对,失败应该是协作求助而非又一个强制任务 +- C(只记日志 + 前端告警):system comment 没人主动看,等于没人管 + +**理由**: +- 错误分类后路由到不同处理方式,比统一通知更精准 +- Gitea Issue/PR comment 是天然的管理和审计工具,人也能看到 +- §25 @mention webhook 已有端到端集成,comment 创建后自然触发新 toolchain task,管道复用 +- Mail 只服务 Agent 间点对点通信和 PR 合并通知,职责清晰 + --- ## §13. 实施计划