feat: 接线feature工具到sdlc_ability(propose/list/approve/reject/verify 5工具+handler+ID前缀兜底)

This commit is contained in:
ymq 2026-08-17 07:31:19 +08:00
parent df6f5cce34
commit 4abe93a8f9

View File

@ -121,6 +121,36 @@ SDL_TOOLS = [
parameters={"title": "Bug标题", "description": "描述", "severity": "严重程度"},
category="task",
),
ToolDefinition(
name="propose_feature",
description="提出新功能/需求(用户提出新需求或需求拆解时用)",
parameters={"feature_name": "功能名称", "description": "功能描述", "iteration_id": "所属迭代(可选)", "priority": "优先级(P0/P1/P2/P3,默认P2)"},
category="feature",
),
ToolDefinition(
name="list_features",
description="查看当前项目功能列表",
parameters={"status": "按状态筛选(可选)"},
category="feature",
),
ToolDefinition(
name="approve_feature",
description="审批通过功能(需求评审通过)",
parameters={"feature_id": "功能ID"},
category="feature",
),
ToolDefinition(
name="reject_feature",
description="驳回功能(附意见)",
parameters={"feature_id": "功能ID", "comment": "驳回意见"},
category="feature",
),
ToolDefinition(
name="verify_feature",
description="验证功能(验收通过)",
parameters={"feature_id": "功能ID"},
category="feature",
),
]
@ -135,7 +165,8 @@ SDL_PROMPT = """你是「开发产线」的驾驶舱 agent负责软件项目
- 用户报告异常/故障 先用 diagnose_project 定位根因再用 task_detail 查详情
- 仓库管理 add_repo / list_repos / clone_repo
- 发现卡点任务卡死审核超时失败僵尸 claimed_by主动定位根因并推动修复
- 发现待回答问题> 0 或角色提问时加载 team-communication 技能按冒泡链处理list_questions 列问题 能答则 answer_question 不能答 escalate_question 沿冒泡路径转下一个处理方"""
- 发现待回答问题> 0 或角色提问时加载 team-communication 技能按冒泡链处理list_questions 列问题 能答则 answer_question 不能答 escalate_question 沿冒泡路径转下一个处理方
- 功能/需求管理 用户提新需求时 propose_feature查功能清单 list_features需求评审/验收时 approve_feature / reject_feature / verify_feature状态机规范见 feature 技能"""
# ── 产线角色集(可插拔,替代硬编码 ROLE_SPECIFICS/ROLE_ALIASES/ROLE_CHAIN ──
@ -602,6 +633,101 @@ async def _h_add_bug(sor, p, ctx):
return f"OK: 已提交Bug: {title}"
async def _resolve_feature_id(sor, fid):
"""功能 ID 前缀兜底精确匹配失败且入参≥6位时用 LIKE 前缀解析回完整 ID。"""
if not fid:
return ""
recs = await sor.sqlExe(
"SELECT id FROM sd_features WHERE id=${fid}$", {"fid": fid})
if recs:
return getattr(recs[0], "id", "")
if len(fid) >= 6:
recs = await sor.sqlExe(
"SELECT id FROM sd_features WHERE id LIKE ${prefix}$ LIMIT 1",
{"prefix": fid + "%"})
if recs:
return getattr(recs[0], "id", "")
return ""
async def _h_propose_feature(sor, p, ctx):
pid = ctx.get("project_id", "")
if not pid:
return "请先切换到项目"
name = (p.get("feature_name", "") or "").strip()
if not name:
return "需要功能名称"
from .feature_capability import propose_feature
ok, fid = await propose_feature(
project_id=pid,
feature_name=name,
description=p.get("description", "") or "",
iteration_id=p.get("iteration_id", "") or "",
priority=p.get("priority", "P2") or "P2",
created_by=ctx.get("user_id", "") or "",
who="agent.main_agent",
)
if not ok:
return f"ERROR: {fid}"
return f"OK: 已提出功能「{name}id={fid},状态 proposed"
async def _h_list_features(sor, p, ctx):
pid = ctx.get("project_id", "")
if not pid:
return "请先切换到项目"
status = (p.get("status", "") or "").strip()
sql = "SELECT id, feature_name, status, priority, iteration_id FROM sd_features WHERE project_id=${pid}$"
params = {"pid": pid}
if status:
sql += " AND status=${status}$"
params["status"] = status
sql += " ORDER BY created_at DESC LIMIT 30"
recs = await sor.sqlExe(sql, params)
if not recs:
return "暂无功能"
lines = []
for r in recs:
lines.append(
f"- [{getattr(r, 'status', '?')}][{getattr(r, 'priority', '') or ''}] "
f"{getattr(r, 'feature_name', '')} (id={getattr(r, 'id', '')})")
return "\n".join(lines)
async def _h_approve_feature(sor, p, ctx):
fid = (p.get("feature_id", "") or "").strip()
if not fid:
return "需要功能ID"
pid = ctx.get("project_id", "")
fid = await _resolve_feature_id(sor, fid) or fid
from .feature_capability import approve_feature
ok, msg = await approve_feature(fid, pid, who="agent.main_agent")
return f"OK: {msg}" if ok else f"ERROR: {msg}"
async def _h_reject_feature(sor, p, ctx):
fid = (p.get("feature_id", "") or "").strip()
if not fid:
return "需要功能ID"
pid = ctx.get("project_id", "")
fid = await _resolve_feature_id(sor, fid) or fid
from .feature_capability import reject_feature
ok, msg = await reject_feature(fid, pid, who="agent.main_agent",
comment=p.get("comment", "") or "")
return f"OK: {msg}" if ok else f"ERROR: {msg}"
async def _h_verify_feature(sor, p, ctx):
fid = (p.get("feature_id", "") or "").strip()
if not fid:
return "需要功能ID"
pid = ctx.get("project_id", "")
fid = await _resolve_feature_id(sor, fid) or fid
from .feature_capability import verify_feature
ok, msg = await verify_feature(fid, pid, who="agent.main_agent")
return f"OK: {msg}" if ok else f"ERROR: {msg}"
# ── 注册能力包 ──
SDL_HANDLERS = {
@ -620,6 +746,11 @@ SDL_HANDLERS = {
"clone_repo": _h_clone_repo,
"check_progress": _h_check_progress,
"add_bug": _h_add_bug,
"propose_feature": _h_propose_feature,
"list_features": _h_list_features,
"approve_feature": _h_approve_feature,
"reject_feature": _h_reject_feature,
"verify_feature": _h_verify_feature,
}