From 0ef3dec4db956cc539328f650458065f2d92aad8 Mon Sep 17 00:00:00 2001 From: ymq Date: Wed, 2 Sep 2026 12:00:39 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20create=5Ftask=E5=8A=A0=E4=BA=A7?= =?UTF-8?q?=E7=BA=BF=E8=A7=92=E8=89=B2=E5=AE=88=E5=8D=AB(=E8=A7=92?= =?UTF-8?q?=E8=89=B2=E5=BF=85=E9=A1=BB=E5=B1=9E=E5=BD=93=E5=89=8D=E4=BA=A7?= =?UTF-8?q?=E7=BA=BF=E8=A7=92=E8=89=B2=E9=9B=86=E5=90=A6=E5=88=99=E6=8B=92?= =?UTF-8?q?=E7=BB=9D+=E8=BF=94=E5=9B=9E=E5=8F=AF=E7=94=A8=E8=A7=92?= =?UTF-8?q?=E8=89=B2=E6=B8=85=E5=8D=95);=20=E6=96=B0=E5=A2=9Elist=5Froles?= =?UTF-8?q?=E5=85=B1=E4=BA=AB=E5=B7=A5=E5=85=B7(=E5=90=84=E4=BA=A7?= =?UTF-8?q?=E7=BA=BF=E8=87=AA=E5=8A=A8=E7=BB=A7=E6=89=BF);=20=E5=B7=A5?= =?UTF-8?q?=E5=85=B7=E6=8F=8F=E8=BF=B0=E5=8E=BB=E6=8E=89=E7=A1=AC=E7=BC=96?= =?UTF-8?q?=E7=A0=81=E5=BC=80=E5=8F=91=E8=A7=92=E8=89=B2=E5=90=8D=E2=80=94?= =?UTF-8?q?=E2=80=94=E6=A0=B9=E6=B2=BB=E6=8A=95=E6=A0=87=E4=BA=A7=E7=BA=BF?= =?UTF-8?q?PM=E7=94=A8requirement/design/develop=E5=BB=BA=E7=AB=A0?= =?UTF-8?q?=E8=8A=82=E4=BB=BB=E5=8A=A1=E7=9A=84=E6=AD=BB=E5=BE=AA=E7=8E=AF?= =?UTF-8?q?(2026-09-02)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- pipeline_service/sdlc_ability.py | 43 ++++++++++++++++++++++++++++-- pipeline_service/shared_ability.py | 2 +- 2 files changed, 42 insertions(+), 3 deletions(-) diff --git a/pipeline_service/sdlc_ability.py b/pipeline_service/sdlc_ability.py index ece5a72..102e7b9 100644 --- a/pipeline_service/sdlc_ability.py +++ b/pipeline_service/sdlc_ability.py @@ -29,15 +29,22 @@ from pipeline_core import ( SDL_TOOLS = [ ToolDefinition( name="create_task", - description="创建开发任务,分配给角色agent执行", + description="创建任务,分配给角色agent执行。角色必须属于当前产线(不同产线角色集不同)," + "不确定有哪些角色时先调 list_roles 查看,禁止凭记忆用其他产线的角色名", parameters={ "title": "任务标题", - "role": "目标角色(requirement/design/develop/test/deploy)", + "role": "目标角色(必须是当前产线的角色,用 list_roles 查看)", "description": "任务详细描述", "iteration_id": "归属迭代(可选,默认当前迭代)", }, category="task", ), + ToolDefinition( + name="list_roles", + description="列出当前产线的全部角色(角色名/职责/别名)。建任务前用它确认当前产线有哪些可用角色", + parameters={}, + category="task", + ), ToolDefinition( name="list_tasks", description="查看当前项目的任务列表", @@ -326,6 +333,22 @@ SDL_ROLES = [ # ── handler 独立函数(签名统一 async def handler(sor, params, ctx) -> str) ── +async def _h_list_roles(sor, p, ctx): + """列出当前产线的全部角色(名称/职责/别名)。""" + from pipeline_core import list_roles as _list_roles + cur_pipeline = ctx.get("pipeline_id", "") + if not cur_pipeline: + return "无产线上下文(请先进入某产线的项目)" + specs = _list_roles(cur_pipeline) + if not specs: + return "产线「%s」未注册角色集" % cur_pipeline + lines = [] + for s in specs: + aliases = "(别名: %s)" % "/".join(s.aliases) if getattr(s, "aliases", None) else "" + lines.append("- %s:%s%s" % (s.name, s.description, aliases)) + return "当前产线「%s」共 %d 个角色:\n" % (cur_pipeline, len(specs)) + "\n".join(lines) + + async def _h_create_task(sor, p, ctx): pid = ctx.get("project_id", "") if not pid: @@ -344,6 +367,21 @@ async def _h_create_task(sor, p, ctx): from .agent_loop import _normalize_role role = _normalize_role(role) + # 产线角色守卫:角色必须属于当前产线的角色集,否则拒绝创建。 + # 背景:共享 create_task 被多产线复用,PM 曾按工具描述里硬编码的开发角色名 + # (requirement/design/develop)在投标产线里建章节任务 → 角色无人认领、任务死循环。 + # 校验用 pipeline_core 注册表按当前产线查角色;能力包未注册时放行(逃逸阀,不阻塞)。 + from pipeline_core import get_role_spec, list_roles as _list_roles + cur_pipeline = ctx.get("pipeline_id", "") + if cur_pipeline and _list_roles(cur_pipeline): + spec = get_role_spec(cur_pipeline, role) + if not spec: + avail = "、".join("%s(%s)" % (s.name, s.description) for s in _list_roles(cur_pipeline)) + return ("⚠️ 拒绝创建:角色「%s」不属于当前产线「%s」。当前产线可用角色:%s。" + "请改用上述角色重新创建(可用 list_roles 随时查看)。" + % (role, cur_pipeline, avail)) + role = spec.name # 归一到注册表规范名(比裸名拼接更可靠) + tid = getID() # 迭代归属:显式指定 > 当前迭代(该 project 最新创建的迭代)。 # 「当前迭代」概念:新建迭代后当前迭代即新建的那个,任务默认归到它。 @@ -1784,6 +1822,7 @@ async def _h_verify_env(sor, p, ctx): SDL_HANDLERS = { "create_task": _h_create_task, + "list_roles": _h_list_roles, "list_tasks": _h_list_tasks, "task_detail": _h_task_detail, "reset_task_retry": _h_reset_task_retry, diff --git a/pipeline_service/shared_ability.py b/pipeline_service/shared_ability.py index 7cc8da5..4b0dbc0 100644 --- a/pipeline_service/shared_ability.py +++ b/pipeline_service/shared_ability.py @@ -20,7 +20,7 @@ logger = logging.getLogger("pipeline.shared_ability") # sd_test_* / sd_deploy_envs 的 SDLC 专属工具都不在此列。 _GENERIC_TOOL_NAMES = [ # 任务 - "create_task", "list_tasks", "task_detail", "reset_task_retry", + "create_task", "list_roles", "list_tasks", "task_detail", "reset_task_retry", "approve_task", "complete_task", "cancel_task", # agent 运行 / 诊断 "start_agents", "diagnose_project", "check_progress",