[moz] docs(§22): v1.4 设计补足 — 6 个问题修复(基础设施排除/单spawn自主模式/迁移策略/TC数据源分流通透)
This commit is contained in:
@@ -1,9 +1,10 @@
|
||||
---
|
||||
title: "End-to-End Flow — 端到端任务流程设计"
|
||||
created: 2026-06-22
|
||||
version: v1.3
|
||||
version: v1.4
|
||||
status: draft
|
||||
changelog: v1.3 §22.6 重构为「所有 TC 流程第一步走 Discuss」+ §22.8 TC Round Review Gitea 适配设计
|
||||
changelog: v1.4 §22.6/§22.8 设计补足:基础设施排除、定向讨论简化为单spawn自主模式、迁移策略、TC数据源/round_count分流通透
|
||||
v1.3 §22.6 重构为「所有 TC 流程第一步走 Discuss」+ §22.8 TC Round Review Gitea 适配设计
|
||||
v1.2 §22.3/§22.4 更新 Phase 1 为 ✅ 已实现(PR #124)
|
||||
v1.1 补充轻量路径设计(§22.6)、数据流澄清(§22.7)、修正设计原则3、统一Phase编号、Phase 1标注
|
||||
v1.0 初版
|
||||
@@ -265,7 +266,7 @@ issue_assigned:
|
||||
|
||||
## §22.6 轻量路径设计(Direct Assignment)
|
||||
|
||||
> **核心原则:所有 TC 流程第一步都走 Discuss。**
|
||||
> **核心原则:所有 TC 流程第一步都走 Discuss(基础设施和 flow/direct 除外)。**
|
||||
> Discussion 不是可选项,而是 TC 流程的必经阶段——确保方案对齐、风险暴露后再进入 exec。
|
||||
> 区别只在于「谁参与讨论」。
|
||||
|
||||
@@ -274,14 +275,17 @@ issue_assigned:
|
||||
| 条件 | 讨论范围 | 流程 |
|
||||
|------|---------|------|
|
||||
| Issue 无 assignee + type/* label | **广播所有空闲 agent** | Phase 0 → 1(广播讨论)→ 2 → … |
|
||||
| Issue 有 assignee | **assignee + reviewer(司马懿)定向讨论** | Phase 0 → 1(定向讨论)→ 2 → … |
|
||||
| Issue 有 `flow/direct` label | **跳过讨论** | → Phase 2(唯一跳过 Discuss 的路径) |
|
||||
| Issue 有 assignee(非 infrastructure) | **assignee 自主定向讨论** | assignee 写方案 → @司马懿 review → 创建 sub Issue 进 exec |
|
||||
| Issue 有 `type/infrastructure` label | **跳过讨论** | → executor(运维排障,无需方案审查) |
|
||||
| Issue 有 `flow/direct` label | **跳过讨论** | → Phase 2(极小改动逃生舱) |
|
||||
|
||||
**设计原则**:
|
||||
1. 没有 `flow/direct` label → 必须走 Discuss,没有例外
|
||||
2. 有 assignee → assignee 自己写方案 + 司马懿 review 通过后才能进 exec
|
||||
3. 没有 assignee → 广播所有 agent 讨论,有 agent 认领后创建 sub Issue
|
||||
4. `flow/direct` 是唯一的逃生舱(明确不需要讨论的小改动)
|
||||
1. 基础设施 Issue(`type/infrastructure`)→ 直接到 executor(运维排障任务,不需要写方案+审查)
|
||||
2. `flow/direct` label → 直接到 executor(明确不需要讨论的小改动)
|
||||
3. 有 assignee(非 infrastructure)→ assignee 自主走「方案→review→exec」流程,daemon 不编排
|
||||
4. 没有 assignee → 广播所有 agent 讨论,有 agent 认领后创建 sub Issue
|
||||
|
||||
> **v1.4 补充**:v1.3 原设计将 infrastructure 也纳入 Discuss,但基础设施排障任务(Gitea 挂了、磁盘满等)不需要写实现方案和司马懿审查,应排除。
|
||||
|
||||
### 判断逻辑
|
||||
|
||||
@@ -292,20 +296,32 @@ parent Issue 创建
|
||||
└─ 无 assignee(默认)→ 广播 Discussion(所有空闲 agent)
|
||||
```
|
||||
|
||||
### 定向讨论流程(有 assignee)
|
||||
### 定向讨论流程(有 assignee,非 infrastructure)
|
||||
|
||||
> **v1.4 修正**:v1.3 原设计「ticker 同时 spawn assignee + 司马懿」过于复杂,需要 daemon 协调两个 agent 生命周期。
|
||||
> v1.4 简化为**单 spawn 自主模式**——daemon 只创建 discussion task 给 assignee,assignee 在一个 session 内自主完成全部流程。
|
||||
|
||||
```
|
||||
Issue assigned webhook
|
||||
→ daemon 创建 issue_discussion task(context_data 带 assignee)
|
||||
→ ticker dispatch:检测到 assignee 不为空
|
||||
→ 只 spawn assignee + simayi-challenger(不广播其他人)
|
||||
→ daemon 创建 issue_discussion task(assignee=该 agent,context_data 带 issue/repo)
|
||||
→ ticker dispatch:有 assignee → 确定性路由 spawn assignee 单人
|
||||
→ discussion prompt 引导 assignee:
|
||||
1. 在 Gitea Issue comment 写实现方案(技术选型、实现路径、影响范围)
|
||||
2. 等待司马懿 review 方案
|
||||
3. review 通过 → 创建 sub Issue assign 自己 → 进入 exec
|
||||
4. review 驳回 → 修改方案重新提交
|
||||
1. 读 Issue 全文,在 Gitea Issue comment 写实现方案(技术选型、实现路径、影响范围)
|
||||
2. @simayi-challenger 请求方案审查(利用现有 @mention 机制自动创建 review task)
|
||||
3. 等司马懿 review 结果(通过 @mention 回传)
|
||||
4. review 通过 → 创建 sub Issue(assign 自己)→ 进入 exec
|
||||
5. review 驳回 → 修改方案重新提交(重新 comment + @司马懿)
|
||||
```
|
||||
|
||||
**为什么不双 spawn**:
|
||||
1. assignee 写方案时间不确定,双 spawn 后司马懿可能干等
|
||||
2. 两阶段串行更简单,assignee 完成后 @mention 自动触发司马懿
|
||||
3. 和广播讨论一致——daemon 只创建初始 task,后续靠 agent 自主 + @mention
|
||||
|
||||
**与广播讨论的区别**:
|
||||
- 广播讨论:assignee=None → ticker 归入 broadcast_tasks → 广播所有空闲 agent
|
||||
- 定向讨论:assignee=该 agent → ticker 归入 deterministic_tasks → 确定性路由 spawn 单人
|
||||
|
||||
### 广播讨论流程(无 assignee)
|
||||
|
||||
```
|
||||
@@ -335,16 +351,38 @@ Discussion 进行中,如果所有 agent 都认为任务足够简单只涉及
|
||||
|
||||
庞统判断后创建 sub Issue 直接 assign → 该 agent 跳过讨论直接进入 Phase 2。
|
||||
|
||||
### 迁移策略
|
||||
|
||||
> **v1.4 补充**:v1.3 未说明现有 `issue_assigned` 路径如何处理。
|
||||
|
||||
**保留 `issue_assigned` 给 infrastructure / flow-direct,新增定向讨论路径**:
|
||||
|
||||
| 条件 | 旧路径(v1.2) | 新路径(v1.4) | 变化 |
|
||||
|------|----------------|----------------|------|
|
||||
| 有 assignee + 非 infrastructure | issue_assigned → executor | issue_discussion → discussion(定向) | **改** |
|
||||
| 有 assignee + `type/infrastructure` | issue_assigned → executor | issue_assigned → executor(不变) | 无 |
|
||||
| 有 `flow/direct` label | issue_assigned → executor | issue_assigned → executor(不变) | 无 |
|
||||
| 无 assignee + type/* label | issue_discussion → broadcast | issue_discussion → broadcast(不变) | 无 |
|
||||
|
||||
`_ACTION_HINTS` / YAML steps / `ToolchainContextSection` 中的 `issue_assigned` 相关逻辑**保留**(infrastructure/flow-direct 还用),新增 `issue_review_discussion` action_type。
|
||||
|
||||
### 实现方案
|
||||
|
||||
**toolchain_routes.py**:
|
||||
- `opened` 分支(无 assignee)→ discussion task(assignee=None)— 现有逻辑 ✅
|
||||
- `assigned` 分支改为:创建 discussion task(context_data 带 assignee)— **需要改动**
|
||||
- `flow/direct` 分支 → executor task — 现有逻辑 ✅
|
||||
- `assigned` 分支改造:
|
||||
- `is_infrastructure=True` → executor task(现有逻辑保留 ✅)
|
||||
- `has_flow_direct=True` → executor task(现有逻辑保留 ✅)
|
||||
- **其他** → discussion task(assignee=该 agent,context_data 带 issue/repo)— **需要改动**
|
||||
|
||||
**ticker.py `_broadcast_claim`**:
|
||||
- discussion task + `context.assignee` 有值 → 只 spawn assignee + simayi-challenger
|
||||
- discussion task + `context.assignee` 为空 → 广播所有空闲 agent(现有逻辑 ✅)
|
||||
**ticker.py**:
|
||||
- 定向讨论 task 有 assignee → `_dispatch_pending` 确定性路由直接 spawn assignee 单人
|
||||
- 广播讨论 task 无 assignee → `_broadcast_claim` 广播所有空闲 agent(现有逻辑 ✅)
|
||||
- `_broadcast_claim` 中的 action_type 判断逻辑保留(discussion task 走 `_build_discussion_prompt`)
|
||||
|
||||
**讨论 prompt 差异化**:
|
||||
- 定向讨论 prompt 额外指引:你是 assignee,需要写方案并主动 @司马懿 review
|
||||
- 广播讨论 prompt 保持现有模板(4 维度回应 + 自主认领)
|
||||
|
||||
**不影响**:mail / task 流程(它们不走 toolchain_routes.py)
|
||||
|
||||
@@ -417,23 +455,64 @@ task_state 表创建前,`_check_round_complete` 仍扫 `tasks.parent_task`。
|
||||
|
||||
> **设计原则:三个流程已通过 Handler 架构分离(§14)。TC Round Review 的改造通过 ToolchainHandler 分流,不影响黑板流程。**
|
||||
|
||||
### 问题
|
||||
### 问题(v1.4 修正:不只是 prompt 不同,数据查询链路也不同)
|
||||
|
||||
`_check_round_complete` 中调用 `self._build_review_prompt`(黑板 API 版本),对 TC 项目也用黑板 API。但 TC 项目的协作面在 Gitea,数据源不一致。
|
||||
`_check_round_complete` 中调用 `bb.get_subtasks_summary(parent_id)` / `bb.get_aggregate_outputs()` / `bb.get_round_comments()` 全部查黑板 DB。但 TC 的子任务信息在 `task_state` 表 + Gitea Issue/PR,**根本不在黑板 tasks/outputs/comments 表**。
|
||||
|
||||
### 分流方案
|
||||
因此 handler 分流不只是 prompt 层面,需要贯穿**数据查询 → prompt 构建 → round_count 递增**三个环节。
|
||||
|
||||
通过 Handler 架构分流,和 `_dispatch_reviews`(L1379 已有 `handler = get_by_project(); if handler: return []`)一样的模式:
|
||||
### TC 数据源 vs 黑板数据源对照
|
||||
|
||||
| 环节 | 黑板路径 | TC 路径 |
|
||||
|------|---------|---------|
|
||||
| 子任务状态 | `bb.get_subtasks_summary()` → tasks 表 | 新增 `get_tc_subtask_summary()` → task_state 表 |
|
||||
| 成果物 | `bb.get_aggregate_outputs()` → outputs 表 | 庞统自己读 Gitea API(PR/commit) |
|
||||
| 讨论历史 | `bb.get_round_comments()` → comments 表 | 庞统自己读 Gitea Issue comments |
|
||||
| round_count | `bb.increment_round_count()` → tasks.round_count | `UPDATE task_state SET round_count+1` |
|
||||
| parent status | tasks.status | task_state.status(需补充更新逻辑) |
|
||||
|
||||
### task_state.status 更新机制
|
||||
|
||||
> **v1.4 补充**:当前 `_ensure_task_state` 只做 `INSERT OR IGNORE`,status 初始为 `pending`,后续没有任何代码更新。需补充。
|
||||
|
||||
**更新来源**:Gitea Issue closed webhook → 更新 `task_state.status = 'done'`
|
||||
|
||||
```
|
||||
_handle_issues: action == "closed"
|
||||
→ UPDATE task_state SET status='done', updated_at=datetime('now')
|
||||
WHERE issue_number = ?
|
||||
```
|
||||
|
||||
后续如需更精细状态(failed/retry),通过 ToolchainHandler.post_complete 补充更新。
|
||||
|
||||
### 分流方案(全链路)
|
||||
|
||||
```
|
||||
_check_round_complete:
|
||||
handler = TaskTypeRegistry.get_by_project(project_id)
|
||||
if handler and handler.virtual_project == "_toolchain":
|
||||
# TC 路径:用 Gitea API 版 review prompt
|
||||
review_prompt = handler.build_round_review_prompt(parent_id, ...)
|
||||
is_tc = handler and handler.virtual_project == "_toolchain"
|
||||
|
||||
# 1. 数据查询分流
|
||||
if is_tc and parent_id in task_state_parents:
|
||||
summary = get_tc_subtask_summary(tc_db, int(parent_id))
|
||||
# 不查 outputs/comments — 庞统 spawn 后自己读 Gitea API
|
||||
else:
|
||||
# 黑板路径:原有逻辑不变
|
||||
review_prompt = self._build_review_prompt(parent_task, summary, ...)
|
||||
summary = bb.get_subtasks_summary(parent_id)
|
||||
outputs = bb.get_aggregate_outputs(parent_id)
|
||||
comments = bb.get_round_comments(parent_id)
|
||||
|
||||
# 2. prompt 构建分流
|
||||
if is_tc:
|
||||
review_prompt = handler.build_round_review_prompt(parent_id, summary, ...)
|
||||
else:
|
||||
review_prompt = self._build_review_prompt(parent_task, summary, outputs, comments, ...)
|
||||
|
||||
# 3. round_count 递增分流
|
||||
if spawned:
|
||||
if is_tc:
|
||||
UPDATE task_state SET round_count = round_count + 1 WHERE issue_number = ?
|
||||
else:
|
||||
bb.increment_round_count(parent_id)
|
||||
```
|
||||
|
||||
### BaseTaskHandler 接口扩展
|
||||
@@ -508,8 +587,49 @@ TC 版本的 Round Review prompt。核心区别:
|
||||
| 文件 | 改动 |
|
||||
|------|------|
|
||||
| `task_type_registry.py` | `BaseTaskHandler` 加 `build_round_review_prompt` 默认方法(raise NotImplementedError) |
|
||||
| `toolchain_handler.py` | `ToolchainHandler` override `build_round_review_prompt` → 返回 Gitea API 版 prompt |
|
||||
| `ticker.py` | `_check_round_complete` 中 handler 分流:有 handler 用 handler 方法,否则用 `_build_review_prompt` |
|
||||
| `toolchain_handler.py` | `ToolchainHandler` override `build_round_review_prompt` → 返回 Gitea API 版 prompt;新增 `get_tc_subtask_summary()` 静态方法 |
|
||||
| `ticker.py` | `_check_round_complete` 全链路分流:数据查询 + prompt 构建 + round_count 递增 |
|
||||
| `toolchain_routes.py` | `_handle_issues` closed 分支:更新 `task_state.status = 'done'` |
|
||||
|
||||
### get_tc_subtask_summary 方法设计
|
||||
|
||||
```python
|
||||
def get_tc_subtask_summary(tc_db: Path, parent_issue: int) -> Optional[dict]:
|
||||
"""TC 路径:从 task_state 表查子任务状态摘要"""
|
||||
conn = get_connection(tc_db)
|
||||
try:
|
||||
parent_row = conn.execute(
|
||||
"SELECT round_count FROM task_state WHERE issue_number = ?",
|
||||
(parent_issue,)
|
||||
).fetchone()
|
||||
if not parent_row:
|
||||
return None
|
||||
|
||||
rows = conn.execute(
|
||||
"SELECT status, COUNT(*) as cnt FROM task_state "
|
||||
"WHERE parent_issue = ? GROUP BY status",
|
||||
(parent_issue,)
|
||||
).fetchall()
|
||||
if not rows:
|
||||
return None
|
||||
|
||||
summary = {
|
||||
"parent_id": str(parent_issue),
|
||||
"parent_status": "done", # TC 路径 parent 是 Gitea Issue
|
||||
"round_count": parent_row["round_count"],
|
||||
"total": 0, "done": 0, "failed": 0, "cancelled": 0, "other": 0,
|
||||
}
|
||||
for row in rows:
|
||||
summary["total"] += row["cnt"]
|
||||
if row["status"] in ("done", "failed", "cancelled"):
|
||||
summary[row["status"]] += row["cnt"]
|
||||
else:
|
||||
summary["other"] += row["cnt"]
|
||||
summary["all_terminal"] = summary["other"] == 0 and summary["total"] > 0
|
||||
return summary
|
||||
finally:
|
||||
conn.close()
|
||||
```
|
||||
|
||||
### TaskState round_count 同步
|
||||
|
||||
|
||||
Reference in New Issue
Block a user