Compare commits
15 Commits
e89bd51d7c
...
v2.1.0-rc
| Author | SHA1 | Date | |
|---|---|---|---|
| 027ae59d40 | |||
| 12f6ac3b1f | |||
| 623942bd15 | |||
| 280435119e | |||
| 65eb7d6a99 | |||
| f4c995270c | |||
| 4a154f8e1a | |||
| 735b8c4fed | |||
| 2e2edd2b00 | |||
| b384433c80 | |||
| dceddeff45 | |||
| 31028a7e6f | |||
| 6a73d6d6c7 | |||
| 576cd96b43 | |||
| 48c2b8ea3d |
@@ -51,7 +51,7 @@ jobs:
|
|||||||
rm -rf /tmp/ci-venv-test
|
rm -rf /tmp/ci-venv-test
|
||||||
python3 -m venv /tmp/ci-venv-test
|
python3 -m venv /tmp/ci-venv-test
|
||||||
/tmp/ci-venv-test/bin/pip install --quiet --upgrade pip
|
/tmp/ci-venv-test/bin/pip install --quiet --upgrade pip
|
||||||
/tmp/ci-venv-test/bin/pip install --quiet --no-cache-dir 'fastapi' 'pydantic<2' pyyaml uvicorn requests pytest pytest-asyncio httpx
|
/tmp/ci-venv-test/bin/pip install --quiet 'fastapi' 'pydantic<2' pyyaml uvicorn requests pytest pytest-asyncio httpx
|
||||||
|
|
||||||
- name: Debug environment
|
- name: Debug environment
|
||||||
run: |
|
run: |
|
||||||
|
|||||||
@@ -35,3 +35,4 @@ inbox/*.jsonl
|
|||||||
|
|
||||||
# E2E test data
|
# E2E test data
|
||||||
data/e2e-*/
|
data/e2e-*/
|
||||||
|
data/_mail/
|
||||||
|
|||||||
@@ -473,7 +473,550 @@ L2 重组后的 section 列表:
|
|||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## §11. 不做的事
|
## §11. Issue closed 事件处理
|
||||||
|
|
||||||
|
### 11.1 问题
|
||||||
|
|
||||||
|
当前 `_handle_issues` 只处理 `action == "assigned"`,不处理 `action == "closed"`。Issue 被关闭时:
|
||||||
|
- daemon 不感知(webhook `issues/closed` 被忽略)
|
||||||
|
- 创建者 / 关注者收不到通知
|
||||||
|
- 如果该 Issue 对应一个活跃的 task,daemon 不知道 Issue 已关闭
|
||||||
|
|
||||||
|
### 11.2 设计
|
||||||
|
|
||||||
|
`_handle_issues` 增加 `action == "closed"` 分支:
|
||||||
|
|
||||||
|
**谁被通知**:Issue 创建者(`issue.user.login`)。
|
||||||
|
|
||||||
|
**通知内容**(通过 toolchain task 发给创建者):
|
||||||
|
- Issue 标题 + 编号
|
||||||
|
- 关闭者(`payload.sender.login`)
|
||||||
|
- 关闭时间
|
||||||
|
- Issue 上最后一个 comment 的摘要(修复说明)
|
||||||
|
|
||||||
|
**通知类型**:纯通知(event_type=issue_closed,verify auto-pass,和 review_merged 一样)。
|
||||||
|
|
||||||
|
**特殊情况**:
|
||||||
|
- 如果关闭者是创建者自己(自己关自己创建的),不通知(避免自环)
|
||||||
|
- 如果 Issue 没有创建者信息或创建者不是已知 agent,跳过
|
||||||
|
|
||||||
|
### 11.3 实现伪代码
|
||||||
|
|
||||||
|
```python
|
||||||
|
# _handle_issues 中新增
|
||||||
|
if action == "closed":
|
||||||
|
issue_creator = issue.get("user", {}).get("login", "")
|
||||||
|
closed_by = payload.get("sender", {}).get("login", "")
|
||||||
|
|
||||||
|
# 自己关自己创建的,不通知
|
||||||
|
if issue_creator == closed_by:
|
||||||
|
return
|
||||||
|
|
||||||
|
# 只通知已注册的 agent
|
||||||
|
if issue_creator not in AGENT_IDS:
|
||||||
|
return
|
||||||
|
|
||||||
|
# 读取最后一个 comment 作为修复摘要
|
||||||
|
comments = issue.get("comments", 0)
|
||||||
|
last_comment_summary = "(无 comment)"
|
||||||
|
# 可选:调 Gitea API 读最后一个 comment
|
||||||
|
|
||||||
|
title = f"Issue 已关闭: {issue_title} ({repo}#{issue_number})"
|
||||||
|
description = f"Issue {repo}#{issue_number} 已被 {closed_by} 关闭。\n\n{last_comment_summary}"
|
||||||
|
|
||||||
|
_send_toolchain_task(
|
||||||
|
to_agent=issue_creator,
|
||||||
|
title=title,
|
||||||
|
description=description,
|
||||||
|
event_type="issue_closed",
|
||||||
|
action_type="issue_closed",
|
||||||
|
steps=[], # 纯通知,无步骤
|
||||||
|
context_data={
|
||||||
|
"issue_number": issue_number,
|
||||||
|
"repo": repo,
|
||||||
|
"issue_title": issue_title,
|
||||||
|
"closed_by": closed_by,
|
||||||
|
},
|
||||||
|
)
|
||||||
|
```
|
||||||
|
|
||||||
|
### 11.4 _ACTION_HINTS 新增
|
||||||
|
|
||||||
|
```python
|
||||||
|
"issue_closed": "你创建的 Issue 已被关闭。这是一条纯通知,阅读即可。",
|
||||||
|
```
|
||||||
|
|
||||||
|
### 11.5 EVENT_LABELS_ZH 新增
|
||||||
|
|
||||||
|
```python
|
||||||
|
"issue_closed": "Issue 已关闭",
|
||||||
|
```
|
||||||
|
|
||||||
|
### 11.6 verify_completion
|
||||||
|
|
||||||
|
issue_closed 走 auto-pass(和 review_merged 一样),纯通知不需要 agent 动作。
|
||||||
|
|
||||||
|
### 11.7 涉及改动
|
||||||
|
|
||||||
|
| 文件 | 改动 |
|
||||||
|
|------|------|
|
||||||
|
| `src/api/toolchain_routes.py` `_handle_issues` | 新增 `action == "closed"` 分支 |
|
||||||
|
| `src/daemon/toolchain_handler.py` `_ACTION_HINTS` | 新增 issue_closed |
|
||||||
|
| `src/daemon/toolchain_handler.py` `EVENT_LABELS_ZH` | 新增 issue_closed |
|
||||||
|
| `src/daemon/toolchain_handler.py` `verify_completion` | issue_closed auto-pass |
|
||||||
|
| `templates/toolchain/issue_closed.md` | 新建通知模板 |
|
||||||
|
| `tests/` | 新增 closed 事件测试 |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## §12. AI Native 能力完整性(v2 补充)
|
||||||
|
|
||||||
|
> 本节确保 Gitea 替代黑板后,PRD-v3.0 的 AI native 能力不降级。
|
||||||
|
> 对照 §01 四相循环实现 + spawner.py / ticker.py / operations.py 的实际代码逐项检查。
|
||||||
|
|
||||||
|
### 12.1 完整能力对照表
|
||||||
|
|
||||||
|
| # | AI native 能力 | 黑板实现 | Gitea Issue 对应 | 保留? | §21 补充 |
|
||||||
|
|---|-------------|---------|-----------------|-------|---------|
|
||||||
|
| 1 | **Discussion 讨论** | spawner DISCUSSION_PROMPT_TEMPLATE + spawn_type=discussion + ticker 广播 | parent Issue 创建后 ticker 广播 spawn discussion prompt;Issue comment 是讨论空间 | ✅ | §13 |
|
||||||
|
| 2 | **Agent 自建 sub** | agent POST /tasks {parent_task, must_haves} | agent POST Gitea /issues {title: "[repo][sub][parent #N] ..."} + assign 自己 | ✅ | §14 |
|
||||||
|
| 3 | **@mention 通知** | comment mentions 字段 → mention_queue → ticker 扫描 → spawn 被@者 | Gitea Issue/PR comment @ → webhook issue_comment → daemon 解析 @ → spawn | ✅ | §15 |
|
||||||
|
| 4 | **Round review** | _check_round_complete → parent sub 全终态 → spawn 庞统三问 | daemon 扫 task_state parent 下所有 sub 终态 → spawn 庞统 review | ✅ | §16 |
|
||||||
|
| 5 | **Retry 上下文** | retry_count 字段 + _build_retry_context | task_state.retry_count + retry prompt(不变) | ✅ | 不需额外 |
|
||||||
|
| 6 | **Handoff comment** | comment_type=handoff + ≥50 字符 | Issue/PR comment(无 type 区分,但 Boids 行为准则约束 agent 写实质内容) | ✅ | §17 |
|
||||||
|
| 7 | **Outputs 产出物** | outputs 表 {agent, type, content_path, summary} | 分支 commit(代码/文档)+ Issue comment(摘要) | ✅ | 不需额外 |
|
||||||
|
| 8 | **Depends_on 前序** | tasks.depends_on 字段 + PriorOutputsSection | Issue body `Depends: #N` + daemon 解析注入 | ✅ | §17 |
|
||||||
|
| 9 | **Boids 行为准则** | DISCUSSION_PROMPT 中的 4 条准则 | discussion prompt 不变(Boids 准则在 prompt 中,与存储介质无关) | ✅ | §13 |
|
||||||
|
| 10 | **Agent 自主涌现** | 无 assignee 的 parent task → ticker 广播 → agent 自主讨论/创建 sub | 无 assignee 的 parent Issue → ticker 广播 discussion → agent 自建 sub Issue | ✅ | §13/§14 |
|
||||||
|
| 11 | **Guardrail 安全红线** | dispatcher check_task → violations → block | 不变(guardrail 查 task_state,不依赖黑板) | ✅ | 不需额外 |
|
||||||
|
| 12 | **Classify outcome** | spawner _classify_outcome → done/failed/pending | 不变(classify 逻辑在 daemon 内部) | ✅ | 不需额外 |
|
||||||
|
| 13 | **Rebuttal** | review.py submit_rebuttal → @mention assignee + 回到 working | PR Review REQUEST_CHANGES → webhook → daemon 通知 agent | ✅ | 不需额外 |
|
||||||
|
| 14 | **Checkpoints** | checkpoint_routes.py → approve/reject | PR Review(代码/方案审查统一走 PR Review) | ✅ | 不需额外 |
|
||||||
|
|
||||||
|
### 12.2 结论
|
||||||
|
|
||||||
|
**14 项 AI native 能力全部可保留。** 其中需要补充设计的是 5 项(§13-§17),其余沿用现有 daemon 逻辑不变。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## §13. Discussion 能力保留
|
||||||
|
|
||||||
|
### 13.1 设计
|
||||||
|
|
||||||
|
庞统创建 parent Issue(无 assignee)后,触发 discussion:
|
||||||
|
|
||||||
|
```
|
||||||
|
庞统创建 parent Issue → webhook: issues/assigned(或 ticker 发现 pending 无 assignee)
|
||||||
|
→ daemon 检测:无 assignee = 广播讨论
|
||||||
|
→ ticker 广播 spawn 所有 agent(spawn_type=discussion)
|
||||||
|
→ 每个 agent 收到 DISCUSSION_PROMPT_TEMPLATE
|
||||||
|
```
|
||||||
|
|
||||||
|
### 13.2 Discussion Prompt 设计(v3 重构)
|
||||||
|
|
||||||
|
**设计参考**:Edict(角色驱动主动发言)+ APM(自包含 Task Prompt)+ PAV 循环(输入/输出/验证)。
|
||||||
|
|
||||||
|
当前问题:DISCUSSION_PROMPT 只列了"你可以做什么",没引导 agent 思考"我和这个需求什么关系"。agent 读完和自己没关系就忽略了。
|
||||||
|
|
||||||
|
重构后 discussion prompt:
|
||||||
|
|
||||||
|
```
|
||||||
|
你被 spawn 来参与 Gitea Issue 讨论。这是一个四相循环的讨论环节。
|
||||||
|
|
||||||
|
## 讨论主题
|
||||||
|
{parent Issue body 全文}
|
||||||
|
|
||||||
|
## 你是谁
|
||||||
|
你是 {agent_id}({display_name}),你的角色是 {role},你的专业能力是 {capabilities}。
|
||||||
|
(如:你是 zhangfei-dev(张飞 翼德),角色是编码先锋,能力是编码/脚本/实现)
|
||||||
|
|
||||||
|
## 你必须做什么
|
||||||
|
|
||||||
|
读完需求后,在 Issue 上 comment 回应(必须,不是可选):
|
||||||
|
|
||||||
|
1.【定位】这个需求和你有什么关系?你的专业能力能贡献什么?
|
||||||
|
2.【建议】你对实现方案有什么建议?(技术选型、数据来源、实现路径)
|
||||||
|
3.【认领】如果你需要参与,创建 sub Issue 并在 parent Issue comment 注册:
|
||||||
|
- 创建 sub Issue:POST /repos/{repo}/issues
|
||||||
|
title: "[repo][sub][parent #{N}] 任务名"
|
||||||
|
body: "Parent: #{N}\nDepends: #M (如果有前序依赖)\n## 任务\n..."
|
||||||
|
assignees: ["{你的 agent_id}"]
|
||||||
|
- 创建后在 parent Issue comment:"[{你的角色名}] 我创建了 sub #{M}: {任务名},我负责 {简述}"
|
||||||
|
4.【风险】如果你发现风险、不合理的假设、或遗漏的环节,直接提出
|
||||||
|
|
||||||
|
⚠️ 每个 agent 必须 comment。即使你认为和自己无关,也要说明原因——这证明你读过并思考过了。不 comment 的 agent 会被视为未参与讨论。
|
||||||
|
|
||||||
|
## Comment 格式
|
||||||
|
你的 comment 必须以角色名开头,让其他人知道你是谁:
|
||||||
|
[{角色名}] {你的观点}
|
||||||
|
例:[张飞] 我来负责策略编码,用 vnpy CtaTemplate 实现。
|
||||||
|
例:[关羽] 这个策略需要风控,连亏 3 天应暂停。
|
||||||
|
例:[赵云] 数据已就绪,2024-08 缺失已补齐。
|
||||||
|
例:[姜维] 我与此需求无直接关系,但建议关注回测滑点设置。
|
||||||
|
|
||||||
|
## API(Gitea)
|
||||||
|
- 读 Issue 详情+comments:GET /repos/{repo}/issues/{N}
|
||||||
|
- 写 comment:POST /repos/{repo}/issues/{N}/comments
|
||||||
|
- 创建 sub Issue:POST /repos/{repo}/issues
|
||||||
|
|
||||||
|
## 行为准则
|
||||||
|
1. 你是自主的。读 Issue、思考、行动,不要等指令。
|
||||||
|
2. 不重复别人的工作。动手前先读 Issue comments 看谁在做什么(Separation)。
|
||||||
|
3. 保持方向对齐。你的产出方向和 parent goal 对齐,不确定时 @pangtong-fujunshi(Alignment)。
|
||||||
|
4. 产出可共享。产出写入 Issue comment,让其他人能看到你的成果(Cohesion)。
|
||||||
|
5. 不越界。安全红线不要碰,超出能力的 @ 庞统升级(Boundary)。
|
||||||
|
6. 随时讨论。执行过程中需要协作时 @ 对应 Agent,讨论是灵活的不是固定阶段的。
|
||||||
|
```
|
||||||
|
|
||||||
|
**与现有实现差异**:
|
||||||
|
1. 新增"你是谁"段——agent 知道自己的角色和能力,有定位感
|
||||||
|
2. 新增"你必须做什么"——4 条必须回应的维度,不是可选
|
||||||
|
3. 新增 comment 格式——以角色名开头,其他人知道是谁在说
|
||||||
|
4. 新增"创建 sub 后在 parent comment 注册"——parent Issue comment 流自然包含所有 agent 的表态和分工
|
||||||
|
5. 底线约束:不 comment = 未参与——强制每个 agent 思考和表态
|
||||||
|
|
||||||
|
**输入/输出/验证标准**(PAV 循环):
|
||||||
|
| 阶段 | 输入 | 输出 | 验证 |
|
||||||
|
|------|------|------|------|
|
||||||
|
| Discussion | parent Issue body(goal)| 每个 agent 的 comment(定位+建议+认领+风险)| 所有被 spawn 的 agent 都 comment 了 |
|
||||||
|
|
||||||
|
### 13.3 庞统初始引导
|
||||||
|
|
||||||
|
庞统创建 parent Issue 时,可以在 Issue body 中 @ 特定 agent 引导认领:
|
||||||
|
|
||||||
|
```
|
||||||
|
Issue body:
|
||||||
|
## 任务
|
||||||
|
做一个双均线量化策略...
|
||||||
|
|
||||||
|
## 建议分工
|
||||||
|
@zhangfei-dev 你来认领策略编码
|
||||||
|
@zhaoyun-data 你来认领数据准备
|
||||||
|
```
|
||||||
|
|
||||||
|
但庞统不需要知道全部——关羽可能发现需要风控,自己创建 sub 去做。司马懿可能发现需要测试,自己创建 sub。**这是涌现,不是分配。**
|
||||||
|
|
||||||
|
### 13.4 Parent Issue 中的 sub 注册
|
||||||
|
|
||||||
|
agent 创建 sub Issue 后,**自己在 parent Issue 上 comment 注册**(不需要 daemon 做):
|
||||||
|
|
||||||
|
```
|
||||||
|
[张飞] 我创建了 sub #101: 策略编码,我来负责实现。
|
||||||
|
技术方案:用 vnpy CtaTemplate,金叉买入死叉卖出。
|
||||||
|
```
|
||||||
|
|
||||||
|
Gitea 的 Issue reference 功能会自动在 parent Issue timeline 显示 "Referenced by #N"。
|
||||||
|
agent 的 comment + Gitea 自动引用 = parent Issue 中有完整的 sub 注册信息。
|
||||||
|
|
||||||
|
### 13.5 分支创建时机
|
||||||
|
|
||||||
|
| 阶段 | 谁创建分支? | 分支名 |
|
||||||
|
|------|-----------|-------|
|
||||||
|
| Discussion(Phase 3) | ❌ 不创建分支 | — |
|
||||||
|
| Executor(Phase 4) | agent 收到 executor prompt 后自己创建 | `{type}/{sub_issue_number}-{brief}`(type 按 Issue 类型:fix/feat/impl/docs/refactor/test) |
|
||||||
|
|
||||||
|
**executor prompt 的 steps 中明确指定分支名**:
|
||||||
|
```
|
||||||
|
git checkout -b fix/{issue_number}-{brief}
|
||||||
|
```
|
||||||
|
|
||||||
|
多分支并行场景(每个 sub Issue number 不同,分支名不同,不冲突):
|
||||||
|
```
|
||||||
|
张飞 sub #101 → 分支 fix/101-dual-ma-strategy
|
||||||
|
关羽 sub #102 → 分支 fix/102-risk-control
|
||||||
|
司马懿 sub #103 → 分支 fix/103-strategy-test
|
||||||
|
```
|
||||||
|
|
||||||
|
### 13.6 L2 输入输出约束(PAV 循环)
|
||||||
|
|
||||||
|
每种 prompt 都有明确的输入/输出/验证标准:
|
||||||
|
|
||||||
|
| prompt 类型 | 输入 | 输出 | 验证 |
|
||||||
|
|------------|------|------|------|
|
||||||
|
| Discussion | parent Issue body(goal)| 每个 agent comment(定位+建议+认领+风险)| 所有 spawn 的 agent 都 comment 了 |
|
||||||
|
| Executor | sub Issue body + parent Issue body + 所有 comments | [Action Report](分支+PR+改动+CI)| PR 创建 + CI 通过 |
|
||||||
|
| Review(司马懿)| PR diff + sub Issue body + parent goal | Review verdict(APPROVE/REQUEST_CHANGES)| Review API 提交 |
|
||||||
|
| Round Review(庞统)| parent Issue body + 所有 sub outputs + 所有 comments | 三问评估(goal 一致性/成果覆盖/下一步)| GOAL_ACHIEVED 或新轮 sub |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## §14. Agent 自建 sub Issue 模式
|
||||||
|
|
||||||
|
### 14.1 设计
|
||||||
|
|
||||||
|
替代当前的 claim 竞争模式。每个 agent 自己创建 sub Issue + assign 自己。
|
||||||
|
|
||||||
|
**标题格式**:
|
||||||
|
```
|
||||||
|
[quant][sub][parent #100] 策略编码
|
||||||
|
```
|
||||||
|
- `[quant]` — 项目代号
|
||||||
|
- `[sub]` — 标记为 sub Issue
|
||||||
|
- `[parent #100]` — parent Issue 编号(Gitea 自动渲染 #100 为链接)
|
||||||
|
- 后面是人类可读的任务描述
|
||||||
|
|
||||||
|
**Sub Issue body**:
|
||||||
|
```markdown
|
||||||
|
Parent: #100
|
||||||
|
|
||||||
|
## 任务
|
||||||
|
从 parent Issue 继承的具体任务描述
|
||||||
|
|
||||||
|
## 验收标准
|
||||||
|
...
|
||||||
|
```
|
||||||
|
|
||||||
|
Gitea 的 Issue reference 功能会自动在 parent Issue #100 上显示 "Referenced by #101"。
|
||||||
|
|
||||||
|
### 14.2 不需要 claim 竞争
|
||||||
|
|
||||||
|
当前黑板的 claim 模式(CAS 原子操作)是为了防止两个 agent 认领同一个 task。
|
||||||
|
|
||||||
|
在 Gitea Issue 模式下,每个 agent 创建自己的 sub Issue——**不存在竞争**。各创建各的,各 assign 各的。
|
||||||
|
|
||||||
|
**重复不怕**:如果关羽和张飞创建了内容重叠的 sub Issue,庞统在 round review 时引导两人统一看法。这不是错误,是讨论的契机。**不做严谨工作流,做 AI 生态。**
|
||||||
|
|
||||||
|
### 14.3 daemon 内部 parent/sub 映射
|
||||||
|
|
||||||
|
daemon 维护 parent/sub 层级(用于 round review 检测):
|
||||||
|
|
||||||
|
```sql
|
||||||
|
-- task_state 表(§20 设计)
|
||||||
|
CREATE TABLE task_state (
|
||||||
|
issue_number INTEGER,
|
||||||
|
repo TEXT,
|
||||||
|
parent_issue INTEGER, -- 新增:parent Issue 编号
|
||||||
|
status TEXT DEFAULT 'pending',
|
||||||
|
...
|
||||||
|
);
|
||||||
|
```
|
||||||
|
|
||||||
|
daemon 监听 Issue 创建 webhook → 解析标题中的 `[parent #N]` → 记录 parent_issue。
|
||||||
|
|
||||||
|
⚠️ **需同步更新 §20 task_state DDL** 新增 `parent_issue INTEGER` 列。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## §14b. 分支与 PR 生命周期管理
|
||||||
|
|
||||||
|
> 解决分支、PR、Issue 之间的割裂问题,统一定义完整生命周期。
|
||||||
|
|
||||||
|
### 14b.1 Sub Issue 的分支/PR 生命周期
|
||||||
|
|
||||||
|
```
|
||||||
|
① 创建 Sub Issue
|
||||||
|
Agent 在 discussion 阶段创建 sub Issue(assign 自己)
|
||||||
|
→ 分支:还不存在
|
||||||
|
→ daemon task_state: status=pending, parent_issue=N
|
||||||
|
|
||||||
|
② 分支创建(executor 阶段)
|
||||||
|
Agent 收到 executor prompt → git checkout -b {type}/{sub_issue_number}-{brief}
|
||||||
|
→ 分支名从 sub Issue number 派生,一一对应
|
||||||
|
→ daemon task_state: status=working(通过 dispatch 触发)
|
||||||
|
|
||||||
|
③ 编码
|
||||||
|
Agent 在分支上编码 → commit → push
|
||||||
|
→ 分支远程存在,Gitea 可见
|
||||||
|
|
||||||
|
④ PR 创建
|
||||||
|
Agent 创建 PR(head: {type}/{sub_issue_number}-{brief} → base: main)
|
||||||
|
PR body 必须包含:
|
||||||
|
- `Closes #{sub_issue_number}`(让 Gitea merge 时自动关 sub Issue)
|
||||||
|
- `Parent: #{parent_issue_number}`(关联到 parent)
|
||||||
|
- 改动说明(改了什么、为什么)
|
||||||
|
→ webhook: pull_request/opened → daemon task_state: status=review
|
||||||
|
|
||||||
|
⑤ CI
|
||||||
|
PR 创建 → CI 自动触发(lint + test + frontend)
|
||||||
|
→ 通过:等 Review
|
||||||
|
→ 失败:toolchain handler 创建 ci_failure task → agent 修复 → push 到同分支 → CI 重跑
|
||||||
|
|
||||||
|
⑥ Review
|
||||||
|
司马懿收到 Review 请求 → 读 PR diff → 提交 Review(Review API)
|
||||||
|
→ APPROVED:通知 agent 合并
|
||||||
|
→ REQUEST_CHANGES:通知 agent 修改
|
||||||
|
|
||||||
|
⑦ 修改(如果有)
|
||||||
|
Agent 在同分支上修改 → commit → push
|
||||||
|
→ PR 自动更新(不新建 PR)
|
||||||
|
→ CI 重跑 → 司马懿重新 Review
|
||||||
|
→ 循环回到 ⑥
|
||||||
|
|
||||||
|
⑧ Merge
|
||||||
|
Agent 或 Reviewer merge PR
|
||||||
|
→ Gitea 自动关闭 sub Issue(因为 PR body 有 Closes #N)
|
||||||
|
→ webhook: pull_request/closed(merged=true)
|
||||||
|
→ daemon 终态信号:task_state status=done
|
||||||
|
|
||||||
|
⑨ 分支清理
|
||||||
|
Gitea 配置自动删除已合并分支(推荐)
|
||||||
|
Issue 保持 closed 状态(完整历史保留)
|
||||||
|
```
|
||||||
|
|
||||||
|
### 14b.2 Parent Issue 的生命周期
|
||||||
|
|
||||||
|
```
|
||||||
|
① 创建(庞统)
|
||||||
|
庞统创建 parent Issue(无 assignee)
|
||||||
|
→ 触发 discussion 广播
|
||||||
|
→ parent Issue 不创建分支(parent 是讨论和编排层)
|
||||||
|
|
||||||
|
② Discussion
|
||||||
|
Agents 讨论、创建 sub Issues、在 parent comment 注册
|
||||||
|
|
||||||
|
③ 执行
|
||||||
|
所有 sub Issues 走 §14b.1 生命周期
|
||||||
|
|
||||||
|
④ Round Review
|
||||||
|
所有 sub Issues 终态 → 庞统三问
|
||||||
|
→ GOAL_ACHIEVED → 庞统关闭 parent Issue
|
||||||
|
→ 需要新轮 → 庞统创建新 sub Issues → 回到 ③
|
||||||
|
|
||||||
|
⑤ 关闭
|
||||||
|
庞统关闭 parent Issue
|
||||||
|
→ webhook: issues/closed → daemon 终态
|
||||||
|
```
|
||||||
|
|
||||||
|
### 14b.3 核心规则
|
||||||
|
|
||||||
|
| 规则 | 定义 | 原因 |
|
||||||
|
|------|------|------|
|
||||||
|
| 分支 : sub Issue = 1:1 | 每个 sub Issue 一个分支 | 分支名从 Issue number 派生 |
|
||||||
|
| 分支 : PR = 1:1 | 每个分支一个 PR | Review 驳回不新建 PR,push 到同分支更新 |
|
||||||
|
| sub Issue : PR = 1:1 | 一个 sub Issue 一个 PR | 简单场景。复杂 sub 按需拆多个 sub Issue |
|
||||||
|
| PR body 必须含 Closes #N | N = sub Issue 编号 | merge 后自动关 Issue |
|
||||||
|
| PR body 必须含 Parent #M | M = parent Issue 编号 | 关联到 parent,方便追溯 |
|
||||||
|
| parent Issue 不创建分支 | parent 是讨论编排层 | 代码产出在 sub Issue 的分支 |
|
||||||
|
| discussion 不碰 git | 只读 Issue + comment + 创建 sub | 避免讨论阶段产生无意义 commit |
|
||||||
|
| 分支名格式 | {type}/{sub_issue_number}-{brief} | 按 Issue 类型:fix/feat/impl/docs/refactor/test |
|
||||||
|
| merge 后自动删分支 | Gitea 配置 | 避免分支堆积 |
|
||||||
|
|
||||||
|
### 14b.4 多分支并行场景
|
||||||
|
|
||||||
|
一个 parent Issue 下多个 sub Issue 同时执行:
|
||||||
|
|
||||||
|
```
|
||||||
|
parent Issue #100(双均线策略)
|
||||||
|
├── sub #101 策略编码 → 分支 feat/101-dual-ma → PR #104
|
||||||
|
│ └── CI 跑 + Review → merge → Closes #101
|
||||||
|
├── sub #102 风控规则 → 分支 feat/102-risk-control → PR #105
|
||||||
|
│ └── CI 跑 + Review → merge → Closes #102
|
||||||
|
└── sub #103 策略测试 → 分支 test/103-strategy-test → PR #106
|
||||||
|
└── CI 跑 + Review → merge → Closes #103
|
||||||
|
|
||||||
|
所有 sub 终态 → 庞统 round review → parent Issue #100 关闭
|
||||||
|
```
|
||||||
|
|
||||||
|
每个 sub Issue 的分支、PR、CI、Review 独立流转,互不干扰。
|
||||||
|
|
||||||
|
### 14b.5 PR body 模板
|
||||||
|
|
||||||
|
```markdown
|
||||||
|
Closes #{sub_issue_number}
|
||||||
|
Parent: #{parent_issue_number}
|
||||||
|
|
||||||
|
## 改动说明
|
||||||
|
<改了什么、为什么>
|
||||||
|
|
||||||
|
## 验证
|
||||||
|
- [ ] CI 通过(lint + test)
|
||||||
|
- [ ] 本地测试通过(如有)
|
||||||
|
|
||||||
|
## 改动文件
|
||||||
|
- `src/xxx.py`: <改了什么>
|
||||||
|
- `tests/test_xxx.py`: <新增什么测试>
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## §15. @mention 通知迁移
|
||||||
|
|
||||||
|
### 15.1 当前实现
|
||||||
|
|
||||||
|
```
|
||||||
|
agent 写 comment → mentions 字段 → mention_queue 表 → ticker 扫描 → spawn 被@者
|
||||||
|
```
|
||||||
|
|
||||||
|
### 15.2 Gitea 迁移
|
||||||
|
|
||||||
|
```
|
||||||
|
agent 写 Issue/PR comment → webhook: issue_comment/created → daemon 解析 @ → spawn 被@者
|
||||||
|
```
|
||||||
|
|
||||||
|
**mention_queue 表保留**,但数据来源改为 webhook payload。daemon 收到 issue_comment webhook 后:
|
||||||
|
1. 正则提取 comment body 中的 `@(
|
||||||
|
[-
|
||||||
|
]*)`
|
||||||
|
2. 写入 mention_queue
|
||||||
|
3. ticker 消费 mention_queue → spawn 被@者
|
||||||
|
|
||||||
|
复用现有 mention_utils.py 的 extract_mentions 逻辑(§25 已实现)。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## §16. Round Review 迁移
|
||||||
|
|
||||||
|
### 16.1 当前实现
|
||||||
|
|
||||||
|
ticker._check_round_complete:
|
||||||
|
1. 扫描所有 parent task
|
||||||
|
2. 检查 sub task 是否全部终态
|
||||||
|
3. spawn 庞统 review(三问框架)
|
||||||
|
|
||||||
|
### 16.2 Gitea 迁移
|
||||||
|
|
||||||
|
ticker._check_round_complete 改为:
|
||||||
|
1. 扫描 task_state 中 parent_issue IS NOT NULL(替代原 `SELECT DISTINCT parent_task FROM tasks`,语义不变——都是找有子任务的 parent)
|
||||||
|
2. 找到所有 parent_issue 相同的 sub Issue
|
||||||
|
3. 检查 sub Issue 是否全部终态(通过 task_state.status)
|
||||||
|
4. 全部终态 → spawn 庞统 review
|
||||||
|
|
||||||
|
**庞统三问 prompt 不变**:
|
||||||
|
```
|
||||||
|
1. Goal 还清晰吗?(是否有 goal drift)
|
||||||
|
2. 成果物覆盖 goal 了吗?(逐条检查验收标准)
|
||||||
|
3. 下一轮需要做什么?(创建新 sub / 标记完成 / 调整方向)
|
||||||
|
```
|
||||||
|
|
||||||
|
庞统通过 Gitea API 读 parent Issue body(goal)+ 所有 sub Issue 的 comments/outputs → 做评估。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## §17. 无缝接续机制完整迁移
|
||||||
|
|
||||||
|
### 17.1 handoff comment
|
||||||
|
|
||||||
|
当前:comment_type=handoff + ≥50 字符
|
||||||
|
|
||||||
|
Gitea:所有 Issue/PR comment 都是天然的 handoff。Boids 行为准则约束 agent 写实质内容。不强制 ≥50 字符——用 Boids 准则引导比硬阈值更 AI native。
|
||||||
|
|
||||||
|
### 17.2 depends_on 前序引用
|
||||||
|
|
||||||
|
当前:tasks.depends_on 字段 + PriorOutputsSection
|
||||||
|
|
||||||
|
Gitea:Issue body 中 `Depends: #N`。daemon 解析 → 读前序 Issue 的 comments(含 Action Report)→ 注入 prompt。
|
||||||
|
|
||||||
|
### 17.3 retry 上下文
|
||||||
|
|
||||||
|
current:retry_count 字段 + _build_retry_context
|
||||||
|
|
||||||
|
Gitea:task_state.retry_count(不变,daemon 内部)。retry prompt 中加入前序 Issue/PR 链接供 agent 参考。
|
||||||
|
|
||||||
|
### 17.4 状态转换流转
|
||||||
|
|
||||||
|
agent 完成后的状态转换(working → review → done)全部由 daemon 内部管理。agent 不需要手动 POST status。daemon 通过以下信号自动感知:
|
||||||
|
|
||||||
|
| 信号 | 来源 | 触发 |
|
||||||
|
|------|------|------|
|
||||||
|
| agent 创建 sub Issue | webhook: issues/opened | sub status=pending → dispatch |
|
||||||
|
| agent 创建 PR | webhook: pull_request/opened | sub status → review |
|
||||||
|
| PR Review 提交 | webhook: pull_request_review | review 结果 → done 或 back to working |
|
||||||
|
| PR merge | webhook: pull_request/closed(merged) | sub status → done + Issue auto-close |
|
||||||
|
| agent Issue comment | webhook: issue_comment/created | 检查是否为 Action Report → 终态检测 |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## §18. 不做的事
|
||||||
|
|
||||||
| 不做 | 理由 |
|
| 不做 | 理由 |
|
||||||
|------|------|
|
|------|------|
|
||||||
|
|||||||
@@ -650,9 +650,10 @@ async def _handle_pull_request_review(payload: Dict[str, Any]) -> None:
|
|||||||
else: # REQUEST_CHANGES
|
else: # REQUEST_CHANGES
|
||||||
tc_steps = [
|
tc_steps = [
|
||||||
"按审查意见逐条修改代码",
|
"按审查意见逐条修改代码",
|
||||||
|
"文档同步:如审查涉及设计/接口变更,同步更新 docs/design/ 对应文档",
|
||||||
"push 到原分支 → CI 自动跑",
|
"push 到原分支 → CI 自动跑",
|
||||||
"CI 通过后等重新 Review",
|
"CI 通过后等重新 Review",
|
||||||
"提交 action report(POST http://localhost:8083/api/projects/_toolchain/tasks/<task_id>/comments,comment_type=action_report)",
|
"提交 action report(POST http://localhost:8083/api/projects/_toolchain/tasks/<task_id>/comments,comment_type=action_report)— 报告中必须说明文档是否需要更新及处理结果",
|
||||||
]
|
]
|
||||||
_send_toolchain_task(
|
_send_toolchain_task(
|
||||||
to_agent=pr_author,
|
to_agent=pr_author,
|
||||||
@@ -1034,10 +1035,11 @@ async def _handle_issues(payload: Dict[str, Any]) -> None:
|
|||||||
steps=[
|
steps=[
|
||||||
f"在开发目录执行 git 操作:\n a. git checkout main && git pull origin main\n b. git checkout -b fix/{issue_number}-{brief}",
|
f"在开发目录执行 git 操作:\n a. git checkout main && git pull origin main\n b. git checkout -b fix/{issue_number}-{brief}",
|
||||||
"编码 + 写 UT",
|
"编码 + 写 UT",
|
||||||
|
"文档同步:如果本次改动涉及设计变更或接口变更,在同一分支更新 docs/design/ 对应文档。如无需更新,在 action report 中说明「文档无需更新」",
|
||||||
f"git add -A && git commit -m \"[moz] fix: {issue_title[:30]}\" && git push origin fix/{issue_number}-{brief}",
|
f"git add -A && git commit -m \"[moz] fix: {issue_title[:30]}\" && git push origin fix/{issue_number}-{brief}",
|
||||||
f"CI 通过后创建 PR(Gitea API: POST /repos/{repo}/pulls,head: fix/{issue_number}-{brief}, base: main)",
|
f"CI 通过后创建 PR(Gitea API: POST /repos/{repo}/pulls,head: fix/{issue_number}-{brief}, base: main)— PR body 必须含 Closes #{issue_number}",
|
||||||
"等 Review",
|
"等 Review",
|
||||||
"提交 action report(POST http://localhost:8083/api/projects/_toolchain/tasks/<task_id>/comments,comment_type=action_report)",
|
"提交 action report(POST http://localhost:8083/api/projects/_toolchain/tasks/<task_id>/comments,comment_type=action_report)— 报告中必须说明文档是否需要更新及处理结果",
|
||||||
],
|
],
|
||||||
context_data={
|
context_data={
|
||||||
"issue_number": issue_number,
|
"issue_number": issue_number,
|
||||||
@@ -1153,7 +1155,8 @@ async def _handle_issue_comment(payload: Dict[str, Any]) -> None:
|
|||||||
steps=[
|
steps=[
|
||||||
"查看完整 CI 日志(PR 页面或 Gitea Actions 页面)",
|
"查看完整 CI 日志(PR 页面或 Gitea Actions 页面)",
|
||||||
"根据 CI 日志判断失败原因类型:\n a. 代码问题(lint/test 失败)→ 修复失败的测试 → push 到原分支 → CI 自动重跑\n b. 基础设施问题(runner 环境/Python/venv/Gitea/网络故障)→ 在该仓库创建 Issue 指派 jiangwei-infra(见下方「需要创建 Issue 时」),label 必须包含 type/infrastructure",
|
"根据 CI 日志判断失败原因类型:\n a. 代码问题(lint/test 失败)→ 修复失败的测试 → push 到原分支 → CI 自动重跑\n b. 基础设施问题(runner 环境/Python/venv/Gitea/网络故障)→ 在该仓库创建 Issue 指派 jiangwei-infra(见下方「需要创建 Issue 时」),label 必须包含 type/infrastructure",
|
||||||
"提交 action report(POST http://localhost:8083/api/projects/_toolchain/tasks/<task_id>/comments,comment_type=action_report)— 报告中说明判断的原因类型和执行的操作",
|
"文档同步:如修复涉及设计/接口变更,同步更新 docs/design/ 对应文档",
|
||||||
|
"提交 action report(POST http://localhost:8083/api/projects/_toolchain/tasks/<task_id>/comments,comment_type=action_report)— 报告中说明判断的原因类型和执行的操作,以及文档是否需要更新",
|
||||||
],
|
],
|
||||||
context_data={
|
context_data={
|
||||||
"pr_number": issue_number,
|
"pr_number": issue_number,
|
||||||
|
|||||||
@@ -152,6 +152,7 @@ class BootstrapBuilder:
|
|||||||
constraints.extend([
|
constraints.extend([
|
||||||
"- 审查结果必须明确 pass/fail",
|
"- 审查结果必须明确 pass/fail",
|
||||||
"- 评审意见须附证据(文件:行号)",
|
"- 评审意见须附证据(文件:行号)",
|
||||||
|
"- 需求-设计-编码一致性:PR 改动是否和 Issue/设计文档描述一致?如改了实现但 docs/design 未同步更新,在 Review 中指出",
|
||||||
])
|
])
|
||||||
elif role == "planner":
|
elif role == "planner":
|
||||||
constraints.extend([
|
constraints.extend([
|
||||||
|
|||||||
@@ -186,10 +186,11 @@ class DeliveryChecklistSection:
|
|||||||
priority: int = 55 # CONSTRAINTS(50) 和 EXTENSION(60) 之间
|
priority: int = 55 # CONSTRAINTS(50) 和 EXTENSION(60) 之间
|
||||||
|
|
||||||
CHECKLIST_TEXT = (
|
CHECKLIST_TEXT = (
|
||||||
"## 交付检查\n"
|
"## 交付检查(强制)\n"
|
||||||
"完成代码改动前确认:\n"
|
"⚠️ 这是必须执行的步骤,不是提醒。代码改动完成后,以下检查每一项都要有明确结论:\n"
|
||||||
"- 改了实现 → docs/design/ 对应设计文档是否需要更新\n"
|
"- 改了实现 → docs/design/ 对应设计文档是否需要更新?需要则在同一 PR 中更新\n"
|
||||||
"- 改了实现 → tests/ 是否有对应测试脚本需要更新\n"
|
"- 改了实现 → tests/ 是否有对应测试脚本需要更新?需要则在同一 PR 中更新\n"
|
||||||
|
"- action report 中必须逐项说明上述检查结果(如「文档无需更新」「测试已补充」)\n"
|
||||||
"- 所有成果物变更通过 PR 流程:PR review 把关设计合理性,CI 把关代码质量,CD 把关部署正确性\n"
|
"- 所有成果物变更通过 PR 流程:PR review 把关设计合理性,CI 把关代码质量,CD 把关部署正确性\n"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|||||||
@@ -513,7 +513,7 @@ class Ticker:
|
|||||||
|
|
||||||
### 三问
|
### 三问
|
||||||
1. Goal 还清晰吗?(是否有 goal drift)
|
1. Goal 还清晰吗?(是否有 goal drift)
|
||||||
2. 成果物覆盖 goal 了吗?(逐条检查验收标准)
|
2. 成果物覆盖 goal 了吗?(逐条检查验收标准 + 确认 docs/design 是否同步更新)
|
||||||
3. 下一轮需要做什么?(创建新 sub tasks / 标记完成 / 调整方向)
|
3. 下一轮需要做什么?(创建新 sub tasks / 标记完成 / 调整方向)
|
||||||
|
|
||||||
### 失败处理
|
### 失败处理
|
||||||
|
|||||||
@@ -166,6 +166,19 @@ class ToolchainApiSection:
|
|||||||
"",
|
"",
|
||||||
"⚠️ 不要使用 Mail API(飞鸽传书)。所有协作通过 Gitea 留痕。",
|
"⚠️ 不要使用 Mail API(飞鸽传书)。所有协作通过 Gitea 留痕。",
|
||||||
"",
|
"",
|
||||||
|
"### 提交 PR Review",
|
||||||
|
"",
|
||||||
|
"如果步骤中要求提交 Review(审查 PR):",
|
||||||
|
"```bash",
|
||||||
|
f'curl -s -X POST "{_GITEA_BASE}/repos/{{repo}}/pulls/{{pr_number}}/reviews" \\',
|
||||||
|
' -H "Authorization: token <your-token>" \\',
|
||||||
|
' -H "Content-Type: application/json" \\',
|
||||||
|
' -d \'{"event": "approved", "body": "审查结论"}\'',
|
||||||
|
"```",
|
||||||
|
"",
|
||||||
|
"event 可选:approved(通过)/ request_changes(驳回)",
|
||||||
|
"⚠️ 必须用 Review API 提交,不要在 PR comment 中写 Review。",
|
||||||
|
"",
|
||||||
"### 需要创建 Issue 时",
|
"### 需要创建 Issue 时",
|
||||||
"",
|
"",
|
||||||
"如果步骤中要求创建 Issue 指派他人(如 jiangwei-infra):",
|
"如果步骤中要求创建 Issue 指派他人(如 jiangwei-infra):",
|
||||||
@@ -235,6 +248,11 @@ class ToolchainConstraintsSection:
|
|||||||
'- 不要使用 Mail API(飞鸽传书)发送消息',
|
'- 不要使用 Mail API(飞鸽传书)发送消息',
|
||||||
'- 你的所有操作都在 toolchain 流程内,通过 Gitea 留痕',
|
'- 你的所有操作都在 toolchain 流程内,通过 Gitea 留痕',
|
||||||
"",
|
"",
|
||||||
|
"### 6. 文档同步(涉及代码改动时)",
|
||||||
|
'- 改了实现 → 检查 docs/design/ 对应设计文档是否需要更新',
|
||||||
|
'- 改了实现 → 检查 tests/ 是否有对应测试脚本需要更新',
|
||||||
|
'- action report 中必须说明文档是否需要更新及处理结果(如「文档无需更新」)',
|
||||||
|
"",
|
||||||
"### Red Flags(如果脑海中出现以下想法,说明你错了)",
|
"### Red Flags(如果脑海中出现以下想法,说明你错了)",
|
||||||
"",
|
"",
|
||||||
'| Agent 想法 | Red Flag 驳回 |',
|
'| Agent 想法 | Red Flag 驳回 |',
|
||||||
@@ -246,6 +264,7 @@ class ToolchainConstraintsSection:
|
|||||||
'| “步骤太多了,选几个做就行” | ❌ 错!必须逐条执行,不可跳过 |',
|
'| “步骤太多了,选几个做就行” | ❌ 错!必须逐条执行,不可跳过 |',
|
||||||
'| “这个步骤不适用于当前情况” | ❌ 如果确实不适用,在 action report 中说明原因,但其他步骤必须执行 |',
|
'| “这个步骤不适用于当前情况” | ❌ 如果确实不适用,在 action report 中说明原因,但其他步骤必须执行 |',
|
||||||
'| “CI/部署失败不是我代码的问题,我什么也不用做” | ❌ 错!即使是基础设施问题,你也必须创建 Issue 指派 jiangwei-infra(body 含错误来源链接 + 日志 + 判断依据),并在 action report 中说明。不能只报告“不是我的问题”就完事 |',
|
'| “CI/部署失败不是我代码的问题,我什么也不用做” | ❌ 错!即使是基础设施问题,你也必须创建 Issue 指派 jiangwei-infra(body 含错误来源链接 + 日志 + 判断依据),并在 action report 中说明。不能只报告“不是我的问题”就完事 |',
|
||||||
|
'| "文档以后再说" | ❌ 错!文档同步和代码改动在同一 PR 中完成,action report 中必须说明文档处理情况 |',
|
||||||
"",
|
"",
|
||||||
]
|
]
|
||||||
return "\n".join(lines)
|
return "\n".join(lines)
|
||||||
|
|||||||
Reference in New Issue
Block a user