Merge PR #107
Deploy / ci (push) Failing after 11m50s
Deploy / deploy (push) Has been skipped
Deploy / notify-deploy-failure (push) Successful in 0s
Deploy / notify-deploy-success (push) Successful in 0s

This commit was merged in pull request #107.
This commit is contained in:
2026-06-20 15:46:20 +00:00
6 changed files with 104 additions and 18 deletions
+1 -1
View File
@@ -2,7 +2,7 @@ name: 实现任务
about: 按设计文档实现功能
title: "[moz] impl: "
labels:
- type/feature
- type/feat
body:
- type: textarea
id: description
+1 -1
View File
@@ -6,7 +6,7 @@
# issue_assigned(按 Issue label 分 6 路 + infrastructure
# ---------------------------------------------------------------------------
issue_assigned:
feature:
feat:
steps:
- "理解需求(Issue body)→ 如有不明确在 Issue comment 追问"
- "git checkout main && git pull origin main"
+63 -9
View File
@@ -1025,14 +1025,38 @@ async def _handle_issues(payload: Dict[str, Any]) -> None:
},
)
else:
title = f"Issue 指派: {issue_title} ({repo}#{issue_number})"
_send_toolchain_task(
to_agent=assignee,
title=title,
description=text,
event_type="issue_assigned",
action_type="issue_assigned",
steps=[
# §21 §5 按 type/* label 解析 business_type
business_type = "feat" # default
for lbl in labels_list:
lbl_lower = lbl.lower()
if "bug" in lbl_lower:
business_type = "bug"
elif "impl" in lbl_lower:
business_type = "impl"
elif "feat" in lbl_lower:
business_type = "feat"
elif "docs" in lbl_lower or "documentation" in lbl_lower:
business_type = "docs"
elif "refactor" in lbl_lower:
business_type = "refactor"
elif "test" in lbl_lower:
business_type = "test"
# §21 §4 从 YAML 模板获取 stepsfallback 到硬编码)
from src.daemon.toolchain_templates import get_steps
yaml_steps = get_steps("issue_assigned", business_type)
if yaml_steps:
# 渲染占位符
rendered_steps = []
for s in yaml_steps:
s = s.replace("{issue_number}", str(issue_number))
s = s.replace("{brief}", brief)
s = s.replace("{title}", issue_title[:30])
rendered_steps.append(s)
steps_to_use = rendered_steps
else:
# fallback: 硬编码 steps(向后兼容)
steps_to_use = [
f"在开发目录执行 git 操作:\n a. git checkout main && git pull origin main\n b. git checkout -b fix/{issue_number}-{brief}",
"编码 + 写 UT",
"文档同步:如果本次改动涉及设计变更或接口变更,在同一分支更新 docs/design/ 对应文档。如无需更新,在 action report 中说明「文档无需更新」",
@@ -1040,7 +1064,16 @@ async def _handle_issues(payload: Dict[str, Any]) -> None:
f"CI 通过后创建 PRGitea API: POST /repos/{repo}/pullshead: fix/{issue_number}-{brief}, base: main)— PR body 必须含 Closes #{issue_number}",
"等 Review",
"提交 action reportPOST http://localhost:8083/api/projects/_toolchain/tasks/<task_id>/commentscomment_type=action_report)— 报告中必须说明文档是否需要更新及处理结果",
],
]
title = f"Issue 指派: {issue_title} ({repo}#{issue_number})"
_send_toolchain_task(
to_agent=assignee,
title=title,
description=text,
event_type="issue_assigned",
action_type="issue_assigned",
steps=steps_to_use,
context_data={
"issue_number": issue_number,
"repo": repo,
@@ -1048,9 +1081,30 @@ async def _handle_issues(payload: Dict[str, Any]) -> None:
"labels": labels,
"issue_body": issue_body or "(无描述)",
"brief": brief,
"business_type": business_type,
},
)
elif action == "closed":
# §21 §11 Issue closed 纯通知(auto-pass
assignee_login = ""
issue_assignees = issue.get("assignees") or []
if issue_assignees:
assignee_login = issue_assignees[-1].get("login", "")
if not assignee_login or assignee_login not in AGENT_IDS:
logger.debug("Issue closed but no valid assignee, skipping")
return
title = f"Issue 已关闭: {issue_title} ({repo}#{issue_number})"
_send_toolchain_task(
to_agent=assignee_login,
title=title,
description=f"## Issue 已关闭\n\n**{repo}#{issue_number}**: {issue_title}\n\nIssue 已被关闭。",
event_type="issue_closed",
action_type="issue_closed",
steps=[], # 纯通知,无步骤
context_data={"repo": repo, "issue_number": issue_number},
)
elif action == "opened":
if "部署失败" in issue_title:
# 从 Issue body 提取 commit hashGitea deploy workflow 格式)
+32 -6
View File
@@ -103,9 +103,9 @@ SPAWN_PROMPT_TEMPLATE = """{identity_section}
"""
DISCUSSION_PROMPT_TEMPLATE = """你被 spawn 来参与黑板讨论。这是一个 v2.9 四相循环的讨论环节。
DISCUSSION_PROMPT_TEMPLATE = """你被 spawn 来参与讨论。这是一个四相循环的讨论环节。
## 你的任务
## 讨论主题
{goal_snapshot}
@@ -113,14 +113,38 @@ DISCUSSION_PROMPT_TEMPLATE = """你被 spawn 来参与黑板讨论。这是一
{constraints}
## 你是谁
{agent_identity}
## 你必须做什么
读完需求后在黑板 comment 回应必须不是可选
1.定位这个需求和你有什么关系你的专业能力能贡献什么
2.建议你对实现方案有什么建议技术选型数据来源实现路径
3.认领如果你需要参与创建 sub task 并在 parent task comment 注册
- 创建 sub task: POST http://{api_host}:{api_port}/api/projects/{project_id}/tasks
body: {{"title": "...", "description": "...", "task_type": "...", "parent_task": "{task_id}", "must_haves": "{{\"capability\": \"...\"}}"}}
- 创建后在 parent task comment: "[你的角色名] 我创建了 sub: 任务名,我负责 简述"
4.风险如果你发现风险不合理的假设或遗漏的环节直接提出
每个 agent 必须 comment即使你认为和自己无关也要说明原因这证明你读过并思考过了
## Comment 格式
你的 comment 必须以角色名开头让其他人知道你是谁
[角色名] 你的观点
[张飞] 我来负责策略编码 vnpy CtaTemplate 实现
[关羽] 这个策略需要风控连亏 3 天应暂停
[赵云] 数据已就绪2024-08 缺失已补齐
## 黑板 API
你可以随时:
- 读黑板:GET http://{api_host}:{api_port}/api/projects/{project_id}/tasks/{task_id}?expand=all( commentsoutputs)
- 读黑板:GET http://{api_host}:{api_port}/api/projects/{project_id}/tasks/{task_id}?expand=all
- comment:POST http://{api_host}:{api_port}/api/projects/{project_id}/tasks/{task_id}/comments
body: {{"author": "{agent_id}", "body": "内容(@agent-id 自动路由)"}}
body: {{"author": "{agent_id}", "body": "内容"}}
- 创建 sub task:POST http://{api_host}:{api_port}/api/projects/{project_id}/tasks
body: {{"title": "...", "description": "...", "task_type": "...", "parent_task": "{task_id}", "must_haves": "{{\"capability\": \"...\"}}"}}
- 认领任务:POST http://{api_host}:{api_port}/api/projects/{project_id}/tasks/{{sub_task_id}}/claim
## 行为准则
@@ -387,12 +411,14 @@ curl -X POST http://{self.api_host}:{self.api_port}/api/projects/{project_id}/ta
goal_snapshot = description or title
constraints = must_haves or "(无特殊约束)"
agent_identity = self._inject_agent_identity(agent_id)
return DISCUSSION_PROMPT_TEMPLATE.format(
goal_snapshot=goal_snapshot,
constraints=constraints,
project_id=project_id,
task_id=task_id,
agent_id=agent_id,
agent_identity=agent_identity,
api_host=self.api_host,
api_port=self.api_port,
)
+5
View File
@@ -331,6 +331,11 @@ class ToolchainHandler(BaseTaskHandler):
return VerifyResult(True, "merged_passthrough",
"review_merged auto-pass")
# 特殊处理:issue_closed 始终通过(纯通知, §21 §11)
if meta.get("action_type") == "issue_closed":
return VerifyResult(True, "issue_closed_passthrough",
"issue_closed auto-pass")
# 1. 优先检查 action_report comment
report_row = conn.execute(
"SELECT id FROM comments WHERE task_id=? "
+2 -1
View File
@@ -87,7 +87,8 @@ def render_template(name: str, variables: Dict[str, str]) -> str:
def clear_cache() -> None:
"""清空模板缓存(用于测试或热更新)"""
_template_cache.clear()
_steps_cache.clear()
global _steps_cache
_steps_cache = None # 重置为 None,强制下次 reload
# ---------------------------------------------------------------------------