33 KiB
title: "End-to-End Flow — 端到端任务流程设计" created: 2026-06-22 version: v1.5 status: draft changelog: v1.5 采纳司马懿 S1-S4+P1-P3:判断逻辑补 infrastructure 分支、flow/discuss deprecated、定向讨论 fallback、task_state.status 完整生命周期、parent_status 查表不硬编码 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 初版
End-to-End Flow — 端到端任务流程设计
本文档描述一个任务从发起到结束的完整系统行为链路。 §21 各章节按功能点分章,本文档把它们串成一条端到端流程。 每个 Phase 标注:触发源、daemon 函数、prompt 来源、agent 行为、留痕位置。
§22.1 流程总览
Phase 0: 庞统创建 parent Issue(无 assignee, 有 type/* label)
↓ webhook: issues/opened
Phase 1: Discussion 广播(所有空闲 agent)
↓ agent 在 Gitea Issue comment 讨论 → 创建 sub Issue(assign 自己)
Phase 2: sub Issue assigned → executor 分派
↓ webhook: issues/assigned
Phase 3: 编码 + PR + CI
↓ webhook: pull_request/opened → CI 自动触发
↓ CI 通过 → 等 Review / CI 失败 → agent 修复 → 重跑
Phase 4: Review(司马懿)
↓ APPROVED → 通知 agent 合并 / REQUEST_CHANGES → agent 修改 → 回 Phase 3
Phase 5: Merge + sub Issue 自动关闭
↓ webhook: pull_request/closed(merged)
Phase 6: Round Review(庞统三问)
↓ GOAL_ACHIEVED → 关闭 parent / 需要新轮 → 创建新 sub → 回 Phase 2
Phase 7: parent Issue 关闭
↓ webhook: issues/closed
核心设计原则:
- 协作面是 Gitea(Issue/PR comment),不是黑板 DB
- 每个 Phase 有明确的前置条件和产出,前一步未完成则后续不触发
- webhook 和 ticker 协同——webhook 负责事件感知和 task 创建,ticker 负责广播调度(Phase 1)和聚合检测(Phase 6)
- agent 在 Gitea 留痕(Issue comment、PR、Review),黑板 DB 只存 daemon 内部状态
§22.2 阶段详解
Phase 0: parent Issue 创建
| 维度 | 内容 |
|---|---|
| 触发 | 庞统(或用户)在 Gitea 创建 parent Issue |
| 条件 | 无 assignee + 有 type/* label |
| daemon 函数 | _handle_issues(toolchain_routes.py),opened 分支 |
| daemon 行为 | 检测无 assignee + 有 type/* label → 创建 toolchain task(assignee=None, action_type=issue_discussion)写入 _toolchain DB |
| agent 行为 | 无(此阶段不 spawn agent) |
| 产出 | _toolchain DB 中一条 pending task |
webhook 流转:
Gitea: Issue created (no assignee, label type/feat)
→ webhook: issues/opened
→ daemon: _handle_issues → action="opened"
→ 非部署失败 + 无 assignee + 有 type/* label
→ _send_toolchain_task(to_agent=None, action_type="issue_discussion")
Phase 1: Discussion 广播
| 维度 | 内容 |
|---|---|
| 触发 | ticker 30s 扫到 Phase 0 创建的 pending task |
| daemon 函数 | ticker._dispatch_pending → dispatcher.decide → _broadcast_claim。action_type=issue_discussion 时调用 _build_discussion_prompt(Gitea API),否则用 _build_claim_prompt(黑板 API) |
| daemon 行为 | assignee=None → router 返回 mode=delegate → ticker 归入 broadcast_tasks → 广播给所有空闲 agent |
| prompt 来源(设计期望) | discussion prompt(§13.2):你是谁 + 你必须做什么(4 维度)+ Gitea API + Boids 行为准则 |
| agent 行为(设计期望) | 每个 agent 在 Gitea Issue comment(角色名开头,4 维度回应);需要参与的 agent 创建 sub Issue(Gitea API,assign 自己);在 parent Issue comment 注册 sub |
| 产出 | parent Issue 上有所有 agent 的讨论 comment;Gitea 上有若干 sub Issue |
discussion prompt 核心(§13.2):
你被 spawn 来参与 Gitea Issue 讨论。
## 讨论主题
{parent Issue body 全文}
## 你是谁
你是 {agent_id}({display_name}),角色是 {role},能力是 {capabilities}
## 你必须做什么(每个 agent 必须 comment)
1.【定位】这个需求和你有什么关系?
2.【建议】你对实现方案有什么建议?
3.【认领】如果你需要参与,创建 sub Issue 并在 parent comment 注册:
POST /repos/{repo}/issues
title: "[moz][sub][parent #{N}] 任务名"
body: "Parent: #{N}\nDepends: #M\n## 任务\n..."
assignees: ["{你的 agent_id}"]
4.【风险】如果发现风险或不合理假设,直接提出
## Comment 格式
[角色名] 你的观点
## API(Gitea)
- 读 Issue: GET /repos/{repo}/issues/{N}
- 写 comment: POST /repos/{repo}/issues/{N}/comments
- 创建 sub Issue: POST /repos/{repo}/issues
Phase 1 的结束条件:
- 所有被广播的 agent 都已 comment(或 NO_REPLY)
- 至少有一个 agent 创建了 sub Issue
- 如果没有任何 agent 创建 sub Issue → ticker 升级庞统(3 轮无 taker 机制)
Phase 2: sub Issue assigned → executor 分派
| 维度 | 内容 |
|---|---|
| 触发 | agent 在 Phase 1 创建 sub Issue 时 assign 自己 → Gitea 发 issues/assigned webhook |
| daemon 函数 | _handle_issues(toolchain_routes.py),assigned 分支 |
| daemon 行为 | 解析 type/* label → 确定 business_type → 从 toolchain-templates.yaml 获取 steps → 创建 toolchain task(action_type=issue_assigned)→ ticker dispatch |
| prompt 来源 | ToolchainHandler.build_prompt(通过 PromptComposer 拼装 sections) |
| agent 行为 | 建分支 {type}/{sub_issue_number}-{brief} → 编码 → 写测试 → 创建 PR(body 含 Closes #N + Parent #M) |
| 产出 | Gitea 上有 PR + 分支有代码 |
steps 来源(config/toolchain-templates.yaml):
issue_assigned:
feat:
steps:
- "理解需求(Issue body)"
- "git checkout -b feat/{issue_number}-{brief}"
- "编码 + 写 UT"
- "文档同步检查"
- "git push + 创建 PR(body 含 Closes #{issue_number})"
- "等 Review"
Phase 3: 编码 + PR + CI
| 维度 | 内容 |
|---|---|
| 触发 | agent 创建 PR → webhook pull_request/opened → CI 自动触发 |
| daemon 函数(PR opened) | _handle_pull_request → 创建 review_request task → 通知司马懿 |
| daemon 函数(CI) | CI 结果通过 Gitea comment 反馈 → _handle_issue_comment CI 路径 |
| CI 通过 | 等待 Review(Phase 5) |
| CI 失败 | 创建 ci_failure task → 通知 agent 修复 |
| agent prompt(CI 失败时) | ToolchainHandler.build_prompt,action_type=ci_failure,steps 含 CI 日志查看 + 根因判断 + 修复 |
| 产出 | CI 通过的 PR |
Phase 4: Review(司马懿)
| 维度 | 内容 |
|---|---|
| 触发 | review_request task 被 ticker dispatch 给司马懿 |
| daemon 函数 | ticker spawn 司马懿 → 司马懿通过 Review API 提交 verdict → webhook pull_request_review → _handle_pull_request_review |
| prompt 来源 | ToolchainHandler.build_prompt,action_type=review_request |
| Review APPROVED | 创建 review_result_approved task → 通知 agent 合并 |
| Review REQUEST_CHANGES | 创建 review_result_request_changes task → 通知 agent 修改 → agent push 同分支 → CI 重跑 → 回 Phase 3 |
| 产出 | Gitea Review 记录 |
Phase 5: Merge + sub Issue 关闭
| 维度 | 内容 |
|---|---|
| 触发 | agent merge PR |
| daemon 函数 | Gitea 自动关闭 sub Issue(PR body 含 Closes #N)→ webhook pull_request/closed(merged) → _handle_pull_request closed 分支 |
| daemon 行为 | 创建 review_merged task → 通知 agent(纯通知);ToolchainHandler verify: auto-pass |
| 产出 | sub Issue closed + 分支自动删除 |
Phase 6: Round Review(庞统三问)
| 维度 | 内容 |
|---|---|
| 触发 | daemon 检测 parent Issue 下所有 sub Issue 终态(done/closed) |
| daemon 函数 | ticker._check_round_complete 扫描 parent/sub 映射 → 所有 sub 终态 → spawn 庞统 |
| prompt 来源 | ticker._build_review_prompt(三问框架) |
| agent 行为 | 庞统通过 Gitea API 读 parent Issue body + 所有 sub Issue comments/outputs → 三问评估 |
| GOAL_ACHIEVED | 庞统关闭 parent Issue → Phase 7 |
| 需要新轮 | 庞统创建新 sub Issues → 回 Phase 2 |
| 产出 | parent Issue closed 或新一轮 sub Issues |
三问框架:
1. Goal 还清晰吗?(是否有 goal drift)
2. 成果物覆盖 goal 了吗?(逐条检查验收标准 + docs/design 同步确认)
3. 下一轮需要做什么?(创建新 sub / 标记完成 / 调整方向)
Phase 7: parent Issue 关闭
| 维度 | 内容 |
|---|---|
| 触发 | 庞统关闭 parent Issue |
| daemon 函数 | webhook issues/closed → _handle_issues closed 分支 |
| daemon 行为 | 创建 issue_closed task → 通知(纯通知,auto-pass) |
| 产出 | parent Issue closed,全流程结束 |
§22.3 Prompt 模板对照表
| Phase | prompt 用途 | 设计指定的模板来源 | 当前实际来源 | 一致? |
|---|---|---|---|---|
| 1 Discussion | 广播讨论 | discussion prompt(§13.2,Gitea API) | discussion prompt(_build_discussion_prompt,Gitea API) |
✅ |
| 2 Executor | 编码执行 | ToolchainHandler.build_prompt + YAML steps |
同设计 | ✅ |
| 3 CI 失败 | 修复 CI | ToolchainHandler.build_prompt ci_failure |
同设计 | ✅ |
| 4 Review | 审查 PR | ToolchainHandler.build_prompt review_request |
同设计 | ✅ |
| 5 Merge | 合并通知 | ToolchainHandler.build_prompt review_merged |
同设计 | ✅ |
| 6 Round Review | 庞统三问 | ticker._build_review_prompt |
同设计 | ✅ |
| 7 Issue closed | 关闭通知 | ToolchainHandler.build_prompt issue_closed |
同设计 | ✅ |
唯一偏差已修复:PR #124 将 ticker broadcast 改为根据 action_type 选择 discussion prompt(Gitea API)或 claim prompt(黑板 API)。
§22.4 当前实现差距
| Phase | 实现状态 | 差距描述 |
|---|---|---|
| 0 parent Issue 创建 | ✅ 已实现 | PR #113 _handle_issues opened 分支,无 assignee + type/* label → toolchain task |
| 1 Discussion 广播 | ✅ 已实现 | PR #124 修复:ticker _broadcast_claim 判断 action_type=issue_discussion → 调用 _build_discussion_prompt(Gitea API)。_build_discussion_prompt 从 must_haves.context 解析 repo / issue_number 注入模板 |
| 2 sub Issue → executor | ✅ 已实现 | assigned 路径 + YAML steps 已实现(PR #107),Phase 1 修复后 agent 会创建 sub Issue → 走到此阶段 |
| 3 PR + CI | ✅ 已实现 | toolchain handler 正常处理 PR opened + CI 失败 |
| 4 Review | ✅ 已实现 | Review 请求 + Review 结果通知正常 |
| 5 Merge + sub 关闭 | ✅ 已实现 | merge 通知正常。executor prompt(YAML steps)中已包含 Closes #{issue_number} |
| 6 Round Review | ✅ 已实现 | _check_round_complete 支持双源扫描:黑板 tasks.parent_task + toolchain task_state.parent_issue |
| 7 parent Issue 关闭 | ✅ 已实现 | PR #113 issue_closed auto-pass |
§22.5 差距优先级排序
| 优先级 | 差距 | 影响范围 | 修复建议 |
|---|---|---|---|
| P0 | Phase 1 discussion broadcast | ✅ 已完成(PR #124) | |
| P1 | Phase 5 PR body Closes #N | ✅ 已完成 | YAML steps 已包含 Closes #N,P0 修复后自然走通 |
| P2 | Phase 6 Round Review Gitea 适配 | ✅ 已完成 | _check_round_complete 双源扫描 task_state.parent_issue + tasks.parent_task |
关键结论:P0/P1/P2 全部完成。§22 端到端流程设计已全部实现。
§22.6 轻量路径设计(Direct Assignment)
核心原则:所有 TC 流程第一步都走 Discuss(基础设施和 flow/direct 除外)。 Discussion 不是可选项,而是 TC 流程的必经阶段——确保方案对齐、风险暴露后再进入 exec。 区别只在于「谁参与讨论」。
路径决策矩阵
| 条件 | 讨论范围 | 流程 |
|---|---|---|
| Issue 无 assignee + type/* label | 广播所有空闲 agent | Phase 0 → 1(广播讨论)→ 2 → … |
| Issue 有 assignee(非 infrastructure) | assignee 自主定向讨论 | assignee 写方案 → @司马懿 review → 创建 sub Issue 进 exec |
Issue 有 type/infrastructure label |
跳过讨论 | → executor(运维排障,无需方案审查) |
Issue 有 flow/direct label |
跳过讨论 | → Phase 2(极小改动逃生舱) |
设计原则:
- 基础设施 Issue(
type/infrastructure)→ 直接到 executor(运维排障任务,不需要写方案+审查) flow/directlabel → 直接到 executor(明确不需要讨论的小改动)- 有 assignee(非 infrastructure)→ assignee 自主走「方案→review→exec」流程,daemon 不编排
- 没有 assignee → 广播所有 agent 讨论,有 agent 认领后创建 sub Issue
v1.4 补充:v1.3 原设计将 infrastructure 也纳入 Discuss,但基础设施排障任务(Gitea 挂了、磁盘满等)不需要写实现方案和司马懿审查,应排除。
判断逻辑
parent Issue 创建
├─ 有 flow/direct label?→ Direct 路径(→ Phase 2,跳过讨论)
├─ 有 type/infrastructure label?→ Direct 路径(→ executor,运维排障)
├─ 有 assignee(非 infrastructure)?→ 定向 Discussion(assignee 自主模式)
└─ 无 assignee(默认)→ 广播 Discussion(所有空闲 agent)
定向讨论流程(有 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(assignee=该 agent,context_data 带 issue/repo)
→ ticker dispatch:有 assignee → 确定性路由 spawn assignee 单人
→ discussion prompt 引导 assignee:
1. 读 Issue 全文,在 Gitea Issue comment 写实现方案(技术选型、实现路径、影响范围)
2. @simayi-challenger 请求方案审查(利用现有 @mention 机制自动创建 review task)
3. 等司马懿 review 结果(通过 @mention 回传)
4. review 通过 → 创建 sub Issue(assign 自己)→ 进入 exec
5. review 驳回 → 修改方案重新提交(重新 comment + @司马懿)
为什么不双 spawn:
- assignee 写方案时间不确定,双 spawn 后司马懿可能干等
- 两阶段串行更简单,assignee 完成后 @mention 自动触发司马懿
- 和广播讨论一致——daemon 只创建初始 task,后续靠 agent 自主 + @mention
与广播讨论的区别:
- 广播讨论:assignee=None → ticker 归入 broadcast_tasks → 广播所有空闲 agent
- 定向讨论:assignee=该 agent → ticker 归入 deterministic_tasks → 确定性路由 spawn 单人
定向讨论 fallback(assignee 无响应)
v1.4 补充(司马懿 S4):广播讨论有「3 轮无 taker → 升级庞统」机制,定向讨论也需要 fallback。
单 spawn assignee 后,如果 assignee NO_REPLY 或 session 超时:
ticker 定期 check(复用现有 broadcast _broadcast_tracker 机制)
→ discussion task 仍 pending/working 且超过 3 轮 check 未终态
→ 升级庞统(escalated 状态)
→ 庞统判断:重新分配 / 转为广播讨论 / 直接关闭
复用现有 _broadcast_tracker 的 round_number >= 3 → escalated 逻辑,不引入新机制。
广播讨论流程(无 assignee)
Issue opened webhook
→ daemon 创建 issue_discussion task(assignee=None)
→ ticker broadcast:广播所有空闲 agent
→ discussion prompt 引导每个 agent:
1. 在 Gitea Issue comment 回应(定位/建议/认领/风险)
2. 需要参与的 agent 创建 sub Issue assign 自己
适用场景
| 路径 | 适用场景 | 示例 |
|---|---|---|
| 广播讨论 | 需求不明确、跨模块协作、涉及 3+ agent、无人认领 | 新功能设计、架构变更 |
| 定向讨论 | 需求明确但需要方案确认 | 有明确 assignee 的 Issue |
| Direct | 改 typo、改配置值等极小改动 | flow/direct label |
Discussion 路径中的降级
Discussion 进行中,如果所有 agent 都认为任务足够简单只涉及一个角色,任何 agent 可以在 comment 中建议:
@pangtong-fujunshi 建议直接指派 @agent-id,理由:...
庞统判断后创建 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。
flow/discusslabel deprecated:v1.2 曾设计flow/discusslabel(强制 Discussion 即使有 assignee),v1.4 废弃。所有有 assignee 的 Issue(非 infrastructure)默认走定向讨论,无需显式 label。Gitea 上flow/discusslabel(id=101)保留但不影响路由。
实现方案
toolchain_routes.py:
opened分支(无 assignee)→ discussion task(assignee=None)— 现有逻辑 ✅assigned分支改造:is_infrastructure=True→ executor task(现有逻辑保留 ✅)has_flow_direct=True→ executor task(现有逻辑保留 ✅)- 其他 → discussion task(assignee=该 agent,context_data 带 issue/repo)— 需要改动
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)
§22.7 数据流设计澄清
本文档涉及两个数据源(黑板 DB 和 Gitea Issue),parent/sub 映射的数据流必须明确。
当前状态 vs 设计目标
| 数据 | 当前存储 | §20/§21 设计目标 | 状态 |
|---|---|---|---|
| 协作面(title/body/comment) | Gitea Issue/PR(Phase 1 已修复) | Gitea Issue/PR | ✅ |
| parent/sub 映射 | task_state.parent_issue(已实现) + tasks.parent_task(兼容) |
task_state.parent_issue(新表) |
✅ |
| 执行状态 | toolchain DB tasks.status + task_state.status | task_state.status | ✅ |
| 成果物 | git commit + PR | git commit + PR | ✅ |
parent/sub Issue 映射数据流(设计)
Agent 在 Phase 1 创建 sub Issue:
POST /repos/{repo}/issues
title: "[moz][sub][parent #{N}] 任务名"
assignees: ["{agent_id}"]
↓
Gitea webhook: issues/opened (with assignee)
↓
daemon: _handle_issues → assigned 分支
→ 解析标题 [parent #{N}] → 提取 parent_issue_number
→ 写入 task_state (issue_number, parent_issue=N, status='pending')
↓
ticker: _check_round_complete
→ SELECT DISTINCT parent_issue FROM task_state WHERE parent_issue IS NOT NULL
→ 对每个 parent_issue: SELECT status FROM task_state WHERE parent_issue=?
→ 全部终态 → spawn 庞统 review
前置条件(已全部实现 ✅)
- task_state 表创建:已在 PR #125 中实现(
_init_task_state_table,CREATE IF NOT EXISTS)。 - parent_issue 解析:已实现(
_ensure_task_state,_handle_issuesassigned 分支解析[parent #N])。 - _check_round_complete 双源扫描:已实现(
task_state.parent_issue+tasks.parent_task)。
混合期处理
task_state 表创建前,_check_round_complete 仍扫 tasks.parent_task。两种数据可以共存:
- 黑板路径(Phase 1 断裂时):agent 通过黑板 API 认领 →
tasks.parent_task有值 - Gitea 路径(Phase 1 修复后):agent 创建 sub Issue →
task_state.parent_issue有值
_check_round_complete 需要同时扫两个源,直到黑板路径完全废弃。
各 Phase 数据读写汇总
| Phase | daemon 写 | daemon 读 | agent 读 | agent 写 |
|---|---|---|---|---|
| 0 | toolchain DB: task(pending, action_type=issue_discussion) | Gitea webhook payload | — | — |
| 1 | toolchain DB: broadcast log | toolchain DB: pending tasks | Gitea Issue body | Gitea Issue comment + sub Issue |
| 2 | toolchain DB: task(pending, action_type=issue_assigned) | Gitea webhook payload, toolchain-templates.yaml | Gitea Issue body | git branch + PR |
| 3 | toolchain DB: task(review_request/ci_failure) | Gitea webhook (PR opened, CI status) | Gitea PR + CI logs | git push (修复) |
| 4 | toolchain DB: task(review_result_*) | Gitea webhook (pull_request_review) | Gitea PR diff + files | Gitea Review API |
| 5 | toolchain DB: task(review_merged) | Gitea webhook (PR closed/merged) | — | — |
| 6 | task_state: round_count++ | task_state: parent_issue + sub status | Gitea parent Issue body + sub Issue comments | Gitea Issue comment(三问结论)+ 关闭/创建 Issue |
| 7 | toolchain DB: task(issue_closed) | Gitea webhook (issues/closed) | — | — |
§22.8 TC Round Review Gitea 适配
设计原则:三个流程已通过 Handler 架构分离(§14)。TC Round Review 的改造通过 ToolchainHandler 分流,不影响黑板流程。
问题(v1.4 修正:不只是 prompt 不同,数据查询链路也不同)
_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 递增三个环节。
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 补充(司马懿 S3):当前
_ensure_task_state只做INSERT OR IGNORE,status 初始为pending,后续没有任何代码更新。需补充。
状态生命周期:
| 状态 | 触发来源 | 更新位置 |
|---|---|---|
pending |
_ensure_task_state 初始插入 |
toolchain_routes.py assigned 分支 |
done |
Gitea Issue closed webhook | toolchain_routes.py closed 分支 |
failed |
executor task 验证失败且未重试 | toolchain_handler.py post_complete → _update_task_state_status() |
关键路径说明:
- sub Issue 创建 →
_ensure_task_state写入status='pending' - sub Issue 对应的 executor task 完成 → ToolchainHandler 通过 @mention 指引 agent 创建 PR(含
Closes #N)→ PR 合并时 Gitea 自动关闭 Issue → webhookissues/closed→ 更新status='done' - executor task 失败 →
ToolchainHandler.post_complete()中检测 verify 失败且 retry_count 达上限 → 调用_update_task_state_status(issue_number, 'failed')
post_complete 何时触发:spawner 完成 session 后(agent exit),ticker 在下个 tick 检测到 session 终态 → 调用 handler.post_complete(task_id, agent_id, outcome, db_path)。此时 handler 可以:
- 检查 verify 结果
- 如果 failed 且不可 retry → 查 task_state 找到对应 issue_number → 更新 status='failed'
新增方法:
# toolchain_handler.py
def _update_task_state_status(self, issue_number: int, status: str):
"""更新 task_state.status(executor 失败时调用)"""
tc_db = _toolchain_db_path()
conn = get_connection(tc_db)
try:
conn.execute(
"UPDATE task_state SET status=?, updated_at=datetime('now') "
"WHERE issue_number=?",
(status, issue_number)
)
conn.commit()
finally:
conn.close()
toolchain_routes.py closed 分支补充:
elif action == "closed":
# 更新 task_state status='done'
tc_db = _toolchain_db_path()
conn = get_connection(tc_db)
try:
conn.execute(
"UPDATE task_state SET status='done', updated_at=datetime('now') "
"WHERE issue_number=?",
(issue_number,)
)
conn.commit()
finally:
conn.close()
# ... 现有通知逻辑
注意:
get_tc_subtask_summary中的all_terminal只依赖done和failed两种终态。pending/working计入other,确保未完成的 sub 不会误触发 round review。
分流方案(全链路)
_check_round_complete:
handler = TaskTypeRegistry.get_by_project(project_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:
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 接口扩展
在 BaseTaskHandler(task_type_registry.py)中新增默认方法:
def build_round_review_prompt(self, parent_id: str, summary: dict,
outputs: list, comments: list,
round_num: int, **kwargs) -> str:
"""构建 Round Review prompt。默认 raise NotImplementedError。"""
raise NotImplementedError(
f"{self.task_type} handler does not support round review")
普通 task 和 mail 不调用此方法(走 ticker 原有 _build_review_prompt),只有 ToolchainHandler override。
ToolchainHandler.build_round_review_prompt
TC 版本的 Round Review prompt。核心区别:
| 维度 | 黑板版(原) | Gitea 版(新) |
|---|---|---|
| Goal 来源 | parent_task.description(黑板 DB) |
parent Issue body(庞统自己读 Gitea API) |
| 成果物 | bb.get_aggregate_outputs()(黑板 DB) |
PR / commit(庞统自己读 Gitea API) |
| 讨论历史 | bb.get_round_comments()(黑板 DB) |
Issue comments(庞统自己读 Gitea API) |
| 创建新 sub | POST localhost:8083/api/.../tasks(黑板 API) |
POST Gitea /repos/.../issues(Gitea API) |
| 关闭 parent | 更新黑板 status | PATCH Gitea /repos/.../issues/{N} |
prompt 设计:只给 Issue 编号和 repo,让庞统 spawn 后自己调 Gitea API 读详情。daemon 不做 Gitea API 调用。
## 庞统 TC Round Review(第 {round_num} 轮)
### Parent Issue
- Repo: {repo}
- Issue: #{parent_issue_number}
### 本轮 Sub Issue 状态
- 完成: {done}
- 失败: {failed}
- 总计: {total}
### 你必须做什么
1. 读 parent Issue: GET /repos/{repo}/issues/{parent_issue_number}
2. 读所有 sub Issue 的 comments 和 PR
3. 三问评估:
- Goal 还清晰吗?
- 成果物覆盖 goal 了吗?(逐条检查 + docs/design 同步)
- 下一轮需要做什么?
4. 决策:
- GOAL_ACHIEVED → 关闭 parent Issue
- 需要新轮 → 创建新 sub Issues
### Gitea API
- 读 Issue: GET /repos/{repo}/issues/{N}
- 读 comments: GET /repos/{repo}/issues/{N}/comments
- 创建 sub Issue: POST /repos/{repo}/issues
- 关闭 Issue: PATCH /repos/{repo}/issues/{N} (state=closed)
不影响黑板流程的保证
- Handler 分流:
_check_round_complete通过TaskTypeRegistry.get_by_project(project_id)判断。普通项目(无 handler)走_build_review_prompt(黑板版本不变) - 数据隔离:TC review 读
task_state表 + Gitea API;黑板 review 读tasks表 +outputs/comments表 - prompt 隔离:TC prompt 只含 Gitea API 指引;黑板 prompt 只含黑板 API 指引
- Handler 分流模式已在
_dispatch_reviews中验证可行:L1379if handler: return []用 Handler 分流跳过 handler 项目的 PR Review 流程,TC Round Review 采用相同模式
实现方案
| 文件 | 改动 |
|---|---|
task_type_registry.py |
BaseTaskHandler 加 build_round_review_prompt 默认方法(raise NotImplementedError) |
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 方法设计
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, status 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": parent_row["status"], # 从 task_state 读取实际状态
"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 同步
TC 路径的 round_count 存在 task_state 表中。_check_round_complete 需要在 spawn review 成功后递增:
if handler and handler.virtual_project == "_toolchain":
# TC 路径:递增 task_state.round_count
conn.execute("UPDATE task_state SET round_count = round_count + 1 WHERE issue_number = ?", ...)
else:
# 黑板路径:原有 bb.increment_round_count(parent_id)