From 4d81e02cf2392ef73c40887500a3f5433be8ff6d Mon Sep 17 00:00:00 2001 From: cfdaily Date: Sun, 7 Jun 2026 11:18:00 +0800 Subject: [PATCH] auto-sync: 2026-06-07 11:18:00 --- docs/design/13-toolchain-and-dev-workflow.md | 60 ++++++++++++++------ 1 file changed, 42 insertions(+), 18 deletions(-) diff --git a/docs/design/13-toolchain-and-dev-workflow.md b/docs/design/13-toolchain-and-dev-workflow.md index 98a8420..3ecfd1d 100644 --- a/docs/design/13-toolchain-and-dev-workflow.md +++ b/docs/design/13-toolchain-and-dev-workflow.md @@ -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 启用 + 测试 | 姜维 |