[moz] docs(§21): v1.1 §11b Issue opened 无 assignee 处理设计 #112

Merged
pangtong-fujunshi merged 1 commits from docs/21-issue-opened-no-assignee-design into main 2026-06-21 12:57:06 +00:00
+131 -6
View File
@@ -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 taskassignee=None, action_type=issue_discussion
→ ticker 扫到 pending task
→ router.route: assignee=None → 不走快速路径 4 → delegate 庞统
→ 庞统收到 discussion promptspawner._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 所有 agentspawn_type=discussion
每个 agent 收到 DISCUSSION_PROMPT_TEMPLATE
庞统创建 parent Issue无 assignee
Gitea webhook: issues/opened(注意:不是 assigned,无 assignee 的 Issue 只触发 opened
_handle_issues opened 分支检测:无 assignee + 有 type/* label
创建 toolchain taskassignee=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 循环(输入/输出/验证)。