auto-sync: 2026-06-07 11:18:00
This commit is contained in:
@@ -1506,7 +1506,7 @@ daemon Webhook 模块中维护此映射表。
|
||||
| D2 | 提示词独立模板文件 | 模板和代码分离,改文案不改代码,可审查可扩展 |
|
||||
| D3 | 中枢是 daemon 内模块 | 要访问 Blackboard 创建 Task,共享进程。用独立路由模块(`toolchain_routes.py`)保持职责清晰 |
|
||||
| D4 | 同步处理 | 事件处理很轻(解析+模板填充+创建Task),远在 Gitea 5秒超时内。复杂事件未来用 asyncio.create_task |
|
||||
| D5 | Agent ID = Gitea 用户名 | 设计目标一致,代码里留 `to_agent_id()` 函数兜底,实际直用。待姜维确认各 Agent 在 Gitea 上的注册用户名 |
|
||||
| D5 | Agent ID ≠ Gitea 用户名,需要映射表 | Gitea 注册用户名是短名(zhangfei),Agent ID 是长名(zhangfei-dev)。§4.4 的 `to_agent_id()` 内建 `GIT_TO_AGENT` 映射字典(见 §15.7) |
|
||||
| D6 | CI/部署通知也走事件中枢 | 统一入口,不走 workflow 直接调 Mail API。CI workflow 写 PR comment → Gitea 触发 issue_comment Webhook → 中枢处理 |
|
||||
|
||||
---
|
||||
@@ -1522,6 +1522,7 @@ daemon Webhook 模块中维护此映射表。
|
||||
- 不是消息队列
|
||||
- 不是 Agent 间通信通道(Agent 间协作走 Mail,不经过中枢)
|
||||
- 不是编排引擎(任务编排由 dispatcher + spawner 负责)
|
||||
- 不负责 Agent 回复 Mail 后的流程驱动(由 daemon ticker 的回复驱动机制负责,见 §15.4)
|
||||
|
||||
### 1.3 两条线
|
||||
|
||||
@@ -1577,7 +1578,7 @@ daemon 内部 ───────┘ │ 5. 创建 Mail │
|
||||
| `pull_request_review` submitted | Gitea Webhook | PR 作者 | `review_result.md` | PR号、审查结论、评论、审查者 |
|
||||
| `issues` assigned | Gitea Webhook | 被指派人 | `issue_assigned.md` | Issue号、标题、标签、描述、分支名建议 |
|
||||
| `issue_comment` (CI失败) | CI workflow → Webhook | PR 作者 | `ci_failure.md` | PR号、分支、失败步骤、错误摘要 |
|
||||
| `issue_comment` (部署成功) | Deploy workflow → Webhook | 庞统 | `deploy_success.md` | 仓库、版本、commit |
|
||||
| ~~部署成功~~ | ~~不需要通知~~ | ~~流程自动闭环~~ | ~~—~~ | ~~Gitea Issue 自动关闭~~ |
|
||||
| `issue_comment` (部署失败) | Deploy workflow → Webhook | 庞统 + 姜维 | `deploy_failure.md` | 仓库、失败原因、已回滚版本 |
|
||||
|
||||
### 2.3 事件过滤规则
|
||||
@@ -1589,7 +1590,7 @@ daemon 内部 ───────┘ │ 5. 创建 Mail │
|
||||
| 只处理白名单内的事件类型 | 未知的忽略 + 日志 |
|
||||
| issue_comment 需判断来源 | 只处理 CI/deploy workflow 写的评论(按特定前缀匹配,如 `[CI]`、`[Deploy]`) |
|
||||
| PR 作者/审查者必须是已知 Agent | 未知的忽略 + 日志 |
|
||||
| 幂等:同一事件不重复创建 Mail | 按 `{event_type}-{payload_id}` 去重 |
|
||||
| 幂等:同一事件不重复创建 Mail | 按 `{x_gitea_event}-{x_gitea_delivery}` 去重(delivery ID 来自 `X-Gitea-Delivery` header) |
|
||||
|
||||
---
|
||||
|
||||
@@ -1603,7 +1604,6 @@ templates/toolchain/
|
||||
├── review_result.md # Review submitted → PR 作者
|
||||
├── issue_assigned.md # Issue assigned → 开发者
|
||||
├── ci_failure.md # CI 失败 → PR 作者
|
||||
├── deploy_success.md # 部署成功 → 庞统
|
||||
└── deploy_failure.md # 部署失败 → 庞统+姜维
|
||||
```
|
||||
|
||||
@@ -1625,9 +1625,9 @@ PR: http://192.168.2.154:3000/{repo}/pulls/{pr_number}
|
||||
{file_list}
|
||||
|
||||
流程:
|
||||
1. 读取 PR diff(Gitea API: GET /repos/{repo_owner}/{repo}/pulls/{pr_number}.diff)
|
||||
1. 读取 PR diff(Gitea API: GET /repos/{repo}/pulls/{pr_number}.diff)
|
||||
2. 按审查清单审查(参考 code-review Skill)
|
||||
3. 提交 Review(Gitea API: POST /repos/{repo_owner}/{repo}/pulls/{pr_number}/reviews)
|
||||
3. 提交 Review(Gitea API: POST /repos/{repo}/pulls/{pr_number}/reviews)
|
||||
4. 提交后改动者会自动收到通知
|
||||
|
||||
完成后回复此 Mail 确认。
|
||||
@@ -1650,13 +1650,16 @@ PR: http://192.168.2.154:3000/{repo}/pulls/{pr_number}
|
||||
按改动文件路径匹配规则:
|
||||
|
||||
```python
|
||||
HIGH_PATTERNS = ["**/spawner*", "**/ticker*", "**/dispatcher*",
|
||||
from pathlib import PurePath
|
||||
|
||||
# 高风险文件路径模式(使用 pathlib.PurePath.match,支持 ** 递归)
|
||||
HIGH_PATTERNS = ["**/spawner*", "**/ticker*", "**/dispatcher*",
|
||||
"**/router*", "**/guardrails*", "**/strategy*", "**/risk*"]
|
||||
|
||||
def calc_risk_level(changed_files: list[str]) -> str:
|
||||
for f in changed_files:
|
||||
for pattern in HIGH_PATTERNS:
|
||||
if fnmatch(f, pattern):
|
||||
if PurePath(f).match(pattern):
|
||||
return "high"
|
||||
return "standard"
|
||||
```
|
||||
@@ -1719,7 +1722,7 @@ async def handle_gitea_webhook(
|
||||
|
||||
event = json.loads(body)
|
||||
|
||||
# 2. 幂等检查
|
||||
# 2. 幂等检查(delivery ID = X-Gitea-Delivery header,Gitea 全局唯一)
|
||||
event_key = f"{x_gitea_event}-{x_gitea_delivery}"
|
||||
if is_duplicate(event_key):
|
||||
return {"status": "duplicate"}
|
||||
@@ -1744,7 +1747,14 @@ async def handle_gitea_webhook(
|
||||
每个事件类型一个处理函数,职责:解析 payload → 选模板 → 填充 → 创建 Mail Task。
|
||||
|
||||
```python
|
||||
async def handle_pr_opened(engine: TemplateEngine, event: dict) -> str:
|
||||
async def handle_pull_request(engine: TemplateEngine, event: dict) -> str:
|
||||
"""pull_request 事件分发:只处理 opened,忽略 synchronized/closed/reopened"""
|
||||
if event.get("action") != "opened":
|
||||
return None
|
||||
return await _handle_pr_opened(engine, event)
|
||||
|
||||
|
||||
async def _handle_pr_opened(engine: TemplateEngine, event: dict) -> str:
|
||||
"""PR opened → Review 请求给司马懿"""
|
||||
pr = event["pull_request"]
|
||||
|
||||
@@ -1816,17 +1826,18 @@ async def handle_issue_comment(engine: TemplateEngine, event: dict) -> str:
|
||||
|
||||
if comment_body.startswith("[CI]"):
|
||||
return await handle_ci_comment(engine, event)
|
||||
elif comment_body.startswith("[Deploy]"):
|
||||
elif comment_body.startswith("[Deploy"):
|
||||
return await handle_deploy_comment(engine, event)
|
||||
|
||||
return None # 非 CI/部署评论不处理
|
||||
|
||||
|
||||
# HANDLERS 注册表
|
||||
# pull_request 和 issues 只处理特定 action,在函数内部过滤
|
||||
HANDLERS = {
|
||||
"pull_request": handle_pr_event, # 根据 action 分发
|
||||
"pull_request": handle_pull_request, # 内部只处理 opened,忽略其他 action
|
||||
"pull_request_review": handle_review_submitted,
|
||||
"issues": handle_issue_event, # 根据 action 分发
|
||||
"issues": handle_issues, # 内部只处理 assigned,忽略其他 action
|
||||
"issue_comment": handle_issue_comment,
|
||||
}
|
||||
```
|
||||
@@ -1834,9 +1845,19 @@ HANDLERS = {
|
||||
### 4.4 共用函数
|
||||
|
||||
```python
|
||||
# Git 用户名 → Agent ID 映射(与 §15.7 一致)
|
||||
GIT_TO_AGENT = {
|
||||
"pangtong": "pangtong-fujunshi",
|
||||
"zhangfei": "zhangfei-dev",
|
||||
"simayi": "simayi-challenger",
|
||||
"guanyu": "guanyu-dev",
|
||||
"zhaoyun": "zhaoyun-data",
|
||||
"jiangwei": "jiangwei-infra",
|
||||
}
|
||||
|
||||
def to_agent_id(gitea_username: str) -> str:
|
||||
"""Gitea 用户名 → Agent ID。当前设计目标一致,直用。"""
|
||||
return gitea_username
|
||||
"""Gitea 用户名 → Agent ID(通过映射表)"""
|
||||
return GIT_TO_AGENT.get(gitea_username, gitea_username)
|
||||
|
||||
def create_mail_task(to: str, title: str, text: str, meta: dict) -> str:
|
||||
"""创建 Mail Task(from=system, type=inform)
|
||||
@@ -1846,7 +1867,10 @@ def create_mail_task(to: str, title: str, text: str, meta: dict) -> str:
|
||||
...
|
||||
|
||||
def is_duplicate(event_key: str) -> bool:
|
||||
"""幂等检查:同一事件不重复创建 Mail"""
|
||||
"""幂等检查:同一事件不重复创建 Mail
|
||||
存储在 SQLite events 表,daemon 重启后仍有效。
|
||||
保留最近 7 天记录,ticker 定期清理过期记录。
|
||||
"""
|
||||
...
|
||||
|
||||
def calc_risk_level(files: list[str]) -> str:
|
||||
@@ -1962,7 +1986,7 @@ CI workflow 失败时写 PR comment,触发 issue_comment Webhook:
|
||||
|
||||
| # | 项 | 负责人 | 说明 |
|
||||
|---|------|--------|------|
|
||||
| 1 | 各 Agent 在 Gitea 上的注册用户名是否和 Agent ID 一致 | 姜维 | 决定是否需要映射表 |
|
||||
| 1 | ~~各 Agent 在 Gitea 上的注册用户名是否和 Agent ID 一致~~ | ~~姜维~~ | **已确认不一致**(zhangfei ≠ zhangfei-dev),已使用映射表 |
|
||||
| 2 | Gitea Webhook 是否已配置 secret | 姜维 | 当前已配未启用 |
|
||||
| 3 | CI workflow 是否已有写 PR comment 的 step | — | 当前 CI workflow 可能没有 |
|
||||
| 4 | `from=system` 走 HTTP API 还是只走内部函数 | — | mail_routes.py 当前只在内部函数支持 system |
|
||||
@@ -1978,7 +2002,7 @@ CI workflow 失败时写 PR comment,触发 issue_comment Webhook:
|
||||
| 2 | `toolchain_templates.py` 模板引擎 | 无 |
|
||||
| 3 | 6 个模板文件 | 步骤 2 |
|
||||
| 4 | 4 个事件处理器(PR/Review/Issue/Comment) | 步骤 1+3 |
|
||||
| 5 | 幂等检查(内存缓存或 SQLite 记录) | 步骤 1 |
|
||||
| 5 | 幂等检查(SQLite events 表,保留 7 天) | 步骤 1 |
|
||||
| 6 | `create_mail_task` 共用函数(从 mail_routes.py 提取) | 无 |
|
||||
| 7 | CI/Deploy workflow 加 comment step | 步骤 1+4 |
|
||||
| 8 | Gitea Webhook 启用 + 测试 | 姜维 |
|
||||
|
||||
Reference in New Issue
Block a user