[moz] docs(§21): v1.1 §11b Issue opened 无 assignee 处理设计 #112
@@ -1,9 +1,10 @@
|
||||
---
|
||||
title: "Unified Toolchain Design — 统一工具链工作流设计"
|
||||
created: 2026-06-20
|
||||
version: v1.0 draft
|
||||
version: v1.1 draft
|
||||
status: draft
|
||||
changelog: v1.0 初版
|
||||
changelog: v1.1 补充 §11b Issue opened 无 assignee 处理 + 修正 §13.1 触发路径
|
||||
v1.0 初版
|
||||
---
|
||||
|
||||
# Unified Toolchain Design
|
||||
@@ -569,6 +570,125 @@ issue_closed 走 auto-pass(和 review_merged 一样),纯通知不需要 ag
|
||||
|
||||
---
|
||||
|
||||
## §11b. Issue opened 无 assignee 处理
|
||||
|
||||
### 11b.1 问题
|
||||
|
||||
`_handle_issues` 的 `action == "opened"` 分支只处理"部署失败"关键词和 @mention。无 assignee 的普通 Issue(如庞统创建的 parent Issue)被静默忽略,无法触发 discussion 流程。
|
||||
|
||||
### 11b.2 设计
|
||||
|
||||
`_handle_issues` 的 `opened` 分支新增无 assignee 处理路径:
|
||||
|
||||
```
|
||||
Gitea Issue 创建(无 assignee, 有 type/* label)
|
||||
→ webhook: issues/opened
|
||||
→ _handle_issues:
|
||||
action == "opened"
|
||||
→ 非"部署失败"
|
||||
→ 无 assignee + 有 type/* label
|
||||
→ 创建 toolchain task(assignee=None, action_type=issue_discussion)
|
||||
→ ticker 扫到 pending task
|
||||
→ router.route: assignee=None → 不走快速路径 4 → delegate 庞统
|
||||
→ 庞统收到 discussion prompt(spawner._build_discussion_prompt)
|
||||
→ 庞统在 Issue 上 comment 发起讨论,引导其他 agent 参与
|
||||
```
|
||||
|
||||
### 11b.3 `_send_toolchain_task` 改动
|
||||
|
||||
`to_agent` 参数允许 `None`:
|
||||
|
||||
```python
|
||||
def _send_toolchain_task(
|
||||
to_agent: str | None, # None = 无指派,待路由
|
||||
...
|
||||
) -> str:
|
||||
# None 不校验 AGENT_IDS(非 None 时仍然校验)
|
||||
if to_agent is not None and to_agent not in AGENT_IDS:
|
||||
logger.warning("Unknown agent: %s, skipping toolchain task", to_agent)
|
||||
return ""
|
||||
|
||||
task = Task(
|
||||
...
|
||||
assignee=to_agent, # None → 待路由
|
||||
...
|
||||
)
|
||||
```
|
||||
|
||||
### 11b.4 `_handle_issues` opened 分支改动
|
||||
|
||||
```python
|
||||
elif action == "opened":
|
||||
if "部署失败" in issue_title:
|
||||
# 部署失败处理(不变)
|
||||
...
|
||||
elif not (issue.get("assignees") or issue.get("assignee")):
|
||||
# §11b: 无 assignee 的普通 Issue
|
||||
labels_list = [lbl.get("name", "")
|
||||
for lbl in (issue.get("labels") or [])]
|
||||
has_type_label = any(lbl.lower().startswith("type/") for lbl in labels_list)
|
||||
if not has_type_label:
|
||||
return # 无 type label 不处理(避免噪音)
|
||||
|
||||
title = f"Issue 讨论: {issue_title} ({repo}#{issue_number})"
|
||||
_send_toolchain_task(
|
||||
to_agent=None, # 无指派 → router delegate 庞统
|
||||
title=title,
|
||||
description=f"## Issue 需要讨论\n\n{issue.get('body', '(无描述)')}",
|
||||
event_type="issue_discussion",
|
||||
action_type="issue_discussion",
|
||||
steps=[], # discussion 不需要结构化步骤
|
||||
context_data={
|
||||
"issue_number": issue_number,
|
||||
"repo": repo,
|
||||
"issue_title": issue_title,
|
||||
"issue_body": issue.get("body", ""),
|
||||
},
|
||||
)
|
||||
return
|
||||
|
||||
# @mention 检查(不变)
|
||||
...
|
||||
```
|
||||
|
||||
### 11b.5 ToolchainHandler verify 改动
|
||||
|
||||
`issue_discussion` 走 auto-pass(纯触发,不需要 agent 执行步骤):
|
||||
|
||||
```python
|
||||
if meta.get("action_type") == "issue_discussion":
|
||||
return VerifyResult(True, "discussion_passthrough",
|
||||
"issue_discussion auto-pass")
|
||||
```
|
||||
|
||||
### 11b.6 为什么用 delegate 而非 broadcast?
|
||||
|
||||
现有 ticker 有两种调度路径:
|
||||
- **deterministic**:有 assignee → 直接 spawn 给该 agent
|
||||
- **broadcast**:无 assignee → 所有空闲 agent 收到 claim prompt
|
||||
|
||||
无 assignee 的 Issue 如果走 broadcast,每个 agent 收到的是 claim prompt(认领 task),不是 discussion prompt(讨论 Issue)。而 §13.2 设计的 discussion prompt 才是正确行为——agent 应该讨论 Issue 内容,自主决定是否参与,而不是竞争认领一个 task。
|
||||
|
||||
**delegate 庞统**是更合理的路径:
|
||||
- 庞统收到 task → 读取 Issue body → 按副军师职责发起讨论
|
||||
- 庞统在 Issue 上 comment 引导其他 agent 参与
|
||||
- 其他 agent 看到 @mention 后自主创建 sub Issue
|
||||
|
||||
如果未来需要多 agent 并行讨论,可以在 ticker 中新增 discussion broadcast 路径(spawn_type=discussion)。但 MVP 阶段 delegate 庞统已足够。
|
||||
|
||||
### 11b.7 涉及改动
|
||||
|
||||
| 文件 | 改动 |
|
||||
|------|------|
|
||||
| `src/api/toolchain_routes.py` `_send_toolchain_task` | `to_agent` 允许 None |
|
||||
| `src/api/toolchain_routes.py` `_handle_issues` | opened 分支加无 assignee 路径 |
|
||||
| `src/daemon/toolchain_handler.py` `verify_completion` | issue_discussion auto-pass |
|
||||
| `src/daemon/toolchain_handler.py` `_ACTION_HINTS` | 新增 issue_discussion |
|
||||
| `src/daemon/toolchain_handler.py` `EVENT_LABELS_ZH` | 新增 issue_discussion |
|
||||
| `tests/` | 新增 issue_discussion 测试 |
|
||||
|
||||
---
|
||||
|
||||
## §12. AI Native 能力完整性(v2 补充)
|
||||
|
||||
> 本节确保 Gitea 替代黑板后,PRD-v3.0 的 AI native 能力不降级。
|
||||
@@ -606,12 +726,17 @@ issue_closed 走 auto-pass(和 review_merged 一样),纯通知不需要 ag
|
||||
庞统创建 parent Issue(无 assignee)后,触发 discussion:
|
||||
|
||||
```
|
||||
庞统创建 parent Issue → webhook: issues/assigned(或 ticker 发现 pending 无 assignee)
|
||||
→ daemon 检测:无 assignee = 广播讨论
|
||||
→ ticker 广播 spawn 所有 agent(spawn_type=discussion)
|
||||
→ 每个 agent 收到 DISCUSSION_PROMPT_TEMPLATE
|
||||
庞统创建 parent Issue(无 assignee)
|
||||
→ Gitea webhook: issues/opened(注意:不是 assigned,无 assignee 的 Issue 只触发 opened)
|
||||
→ _handle_issues opened 分支检测:无 assignee + 有 type/* label
|
||||
→ 创建 toolchain task(assignee=None, action_type=issue_discussion)
|
||||
→ ticker 扫到 pending task → router delegate 庞统
|
||||
→ 庞统收到 discussion prompt → 在 Issue 上 comment 发起讨论
|
||||
→ 其他 agent 看到讨论 → 自主创建 sub Issue 认领
|
||||
```
|
||||
|
||||
**关键修正(v1.1)**:原设计写 "webhook: issues/assigned",实际 Gitea 对无 assignee 的 Issue 只发 `issues/opened` 事件。`_handle_issues` 的 `opened` 分支需要新增无 assignee 处理路径(见 §11b)。
|
||||
|
||||
### 13.2 Discussion Prompt 设计(v3 重构)
|
||||
|
||||
**设计参考**:Edict(角色驱动主动发言)+ APM(自包含 Task Prompt)+ PAV 循环(输入/输出/验证)。
|
||||
|
||||
Reference in New Issue
Block a user