From a503938d26d672b7e79ba34779545fc97ce2def5 Mon Sep 17 00:00:00 2001 From: cfdaily Date: Thu, 21 May 2026 13:17:49 +0800 Subject: [PATCH] auto-sync: 2026-05-21 13:17:49 --- docs/design/v3.0-router-refactor.md | 133 +++++++++++++++++++++++++++- 1 file changed, 129 insertions(+), 4 deletions(-) diff --git a/docs/design/v3.0-router-refactor.md b/docs/design/v3.0-router-refactor.md index b67d503..dbccb38 100644 --- a/docs/design/v3.0-router-refactor.md +++ b/docs/design/v3.0-router-refactor.md @@ -241,7 +241,132 @@ def _build_claim_prompt(self, agent_id, tasks, project_id): --- -## 5. 场景对比 +## 5. 广播认领完整生命周期 + +> 本节记录从任务创建到最终闭环的完整链路,包括所有已实现但此前未在设计文档中记录的机制。 + +### 5.1 完整流程图 + +``` +用户创建任务 → pending + ↓ +Ticker 检测到 pending 任务 + ↓ +有确定性路径?(retry/handoff/assignee/生命周期) + ├─ 是 → 直接 spawn 指定 Agent + └─ 否 → 进入广播认领 + ↓ + 广播前检查全局并发(counter.is_near_limit()) + → 接近上限?跳过本轮 + ↓ + 获取空闲 Agent 列表(从 config agents 列表取) + → 无空闲?log warning,不递增 retry_count,等下轮 + ↓ + spawn 所有空闲 Agent,传入 claim prompt + retry_count++(本轮广播计数) + ↓ + ┌─ 有人 claim → 正常执行流程 + └─ 无人 claim + ↓ + claimed 超时(5min)→ _check_timeouts 重置为 pending + retry_count 已递增 + ↓ + retry_count < 3?→ 下轮 Ticker 继续广播 + retry_count >= 3?→ escalate to 庞统 +``` + +### 5.2 retry_count 的三种递增场景 + +| 场景 | 触发位置 | retry_count++? | 说明 | +|------|----------|-----------------|------| +| 广播后无人认领 | `_broadcast_claim` L536 | ✅ 是 | 每轮广播递增,记录广播轮次 | +| claimed 超时回收 | `_check_timeouts` L724 | ✅ 是 | Agent 认领后未执行,视为失败 | +| 无空闲 Agent | `_broadcast_claim` L527 | ❌ 否 | 系统容量问题,不是任务问题 | + +### 5.3 超时阈值(与 working 状态一致) + +| 状态 | 超时 | 处理 | +|------|------|------| +| claimed | `claim_timeout_minutes = 5.0` | → pending(retry_count < 3)或 escalated(retry_count >= 3) | +| working | `default_task_timeout_minutes = 30.0` | → failed | + +超时后 retry_count >= 3 时的处理与 working 超时一致:标记 escalated,触发用户介入流程。 + +### 5.4 庞统兜底(delegate 模式) + +当任务进入以下状态时,Router 路由到 `FALLBACK_AGENT = "pangtong-fujunshi"`,mode="delegate": +- 广播 3 轮无人认领(retry_count >= 3) +- 确定性路由无法匹配(模糊场景) + +庞统收到的 delegate prompt 包含:任务信息 + 团队能力列表 + API 端点。庞统可以: +1. 直接分配给指定 Agent(通过 claim API) +2. 自己执行 +3. 判断任务不合理 → cancel + +### 5.5 用户介入链路(已完整实现) + +当任务 escalated 后,用户介入的完整链路: + +``` +Agent 超时/广播无人认领 + → Ticker 标记 status="escalated" + → SSE broker.publish_sync("task_updated", {...}) + → 前端 EventSource 实时收到事件 + → 通知中心推送 "{old_status} → escalated" + → 卡片红色高亮 + ⚠️ 图标 + → 用户点开 TaskModal + → 看到 escalated 按钮: + · ▶ 继续执行 (→ working) + · 🔄 重新分配 (→ pending, retry_count 重置) + · 🚫 取消 (→ cancelled) + ▸ 高级操作: + · (可扩展更多手动干预) + → 用户点击 → POST /tasks/{id}/status → SSE 推送 → 状态更新 +``` + +**已实现代码对应表:** + +| 环节 | 代码文件 | 具体实现 | +|------|----------|----------| +| 标记 escalated | `ticker.py` _check_timeouts / _broadcast_claim | _transition_status(conn, task_id, "escalated", ...) | +| SSE 推送 | `blackboard_routes.py` update_status | broker.publish_sync("task_updated", ...) | +| SSE 基础设施 | `sse.py` / `sse_routes.py` | SSEBroker + EventSource endpoint | +| 前端 SSE 监听 | `store.ts` startSSE() | addEventListener('task_updated', ...) | +| 前端通知中心 | `store.ts` _pushSseEvent() | 通知列表 + 未读计数 | +| escalated 按钮 | `TaskModal.tsx` PRIMARY_ACTIONS[escalated] | ▶ 继续执行 + 🔄 重新分配 | +| escalated 高级操作 | `TaskModal.tsx` ADVANCED_ACTIONS | 🚫 取消 | +| 状态转换 API | `blackboard_routes.py` POST /tasks/{id}/status | VALID_TRANSITIONS 校验 | +| 转换矩阵 | `db.py` VALID_TRANSITIONS | escalated → {working, pending, cancelled} | + +### 5.6 前端按钮完整矩阵 + +**PRIMARY_ACTIONS(主操作区,直接展示):** + +| 状态 | 按钮 | 目标状态 | 说明 | +|------|------|----------|------| +| pending | ⏳ 等待 Agent 自动认领... | — | 提示文字(待补取消按钮) | +| claimed | ⏳ Agent 已认领,即将开始... | — | 提示文字 | +| working | ⏸ 暂停任务 | paused | | +| review | 🔍 Agent 审查中... | — | 提示文字 | +| waiting_human | ✅ 确认完成 / 🔄 拒绝继续做 | done / working | | +| escalated | ▶ 继续执行 / 🔄 重新分配 | working / pending | | +| failed | 🔄 重试 | pending | | +| blocked | 🔓 解除阻塞 | pending | | +| paused | ▶ 继续执行 / 🚫 取消任务 | working / cancelled | | +| done | 📦 归档 | — | | +| cancelled | 📦 归档 | — | | + +**ADVANCED_ACTIONS(折叠在"▸ 高级操作"下):** + +| 状态 | 按钮 | 说明 | +|------|------|------| +| working | 🔍 手动提交审查 / 🚫 取消 | | +| review | ✅ 手动通过 / 🔄 打回重做 | | +| failed | 🚫 取消 | | + +--- + +## 6. 场景对比 | 场景 | 改前(独立 LLM 分配) | 改后(广播认领 + 确定性交接) | |------|---------------------|---------------------------| @@ -254,7 +379,7 @@ def _build_claim_prompt(self, agent_id, tasks, project_id): --- -## 6. 代码量 +## 7. 代码量 - **删**:~130 行(`LLMDriver` + routing config 初始化 + config.yaml routing 节) - **改**:~30 行(`Router.route()` 末尾 + `Dispatcher._build_spawn_message()` delegate 分支) @@ -263,7 +388,7 @@ def _build_claim_prompt(self, agent_id, tasks, project_id): --- -## 7. 风险与缓解 +## 8. 风险与缓解 | # | 风险 | 评估 | 缓解 | |---|------|------|------| @@ -275,7 +400,7 @@ def _build_claim_prompt(self, agent_id, tasks, project_id): --- -## 8. 实施步骤 +## 9. 实施步骤 1. `router.py`:删除 `LLMDriver` 类 + `AgentRouter` 去掉 `llm_driver` + `route()` 末尾改 delegate 2. `ticker.py`:新增 `_broadcast_claim` + `_build_claim_prompt`,修改 `_dispatch_pending` 增加 广播路径