diff --git a/pipeline_service/agent_loop.py b/pipeline_service/agent_loop.py index abb4d7a..6f849f9 100644 --- a/pipeline_service/agent_loop.py +++ b/pipeline_service/agent_loop.py @@ -383,6 +383,8 @@ __QNA__ 工作空间:__WORKSPACE__ 产出要求:__ROLE_SPECIFIC__ +__ROLE_SKILLS__ + ## 工具 你可以使用以下工具完成工作: __TOOLS__ @@ -1086,6 +1088,44 @@ async def _build_fallback_deliverable(workspace_dir, written_files, repos_dir, r } +async def _build_role_skills_block(sor, project_id, role, org_id=""): + """为角色 agent 构建技能注入块。 + + 角色专属技能(scope=role,即 pipelines/{pid}/roles/{role}/)全量注入正文—— + 角色 agent 无 load_skill 工具,且角色技能数量少、是角色必须遵守的领域规范。 + 其余 scope(项目/产线/机构/通用)注入目录层(名字+描述),按优先级降序排列, + 优先级(同名覆盖,高→低):项目 > 角色 > 产线 > 机构 > 通用(SCOPE_PRIORITY 已定义)。 + 返回注入 system prompt 的文本,无技能或失败时返回空串。 + """ + try: + pid = await _resolve_pipeline_id(project_id) + from pipeline_core.skill_loader import get_skill_loader, SCOPE_PRIORITY + from pipeline_core.skill_pack import ensure_org_skills + from .workspace import get_workspace_base + ws_base = await get_workspace_base(sor) + skills_dir = ensure_org_skills(ws_base, org_id or '0') + loader = get_skill_loader(skills_dir) + merged = loader.get_merged(pipeline_id=pid, role=role, + project_id=project_id, org_id=org_id or '0') + if not merged: + return "" + blocks = [] + role_skills = [s for s in merged.values() if getattr(s, 'scope', '') == 'role'] + for s in role_skills: + blocks.append(s.to_prompt_block()) + others = sorted([s for s in merged.values() if getattr(s, 'scope', '') != 'role'], + key=lambda s: -SCOPE_PRIORITY.get(getattr(s, 'scope', ''), 0)) + if others: + lines = ["## 可用技能(目录,优先级 项目>机构>通用)"] + for s in others[:30]: + lines.append(f"- [{getattr(s, 'scope', '')}] {s.name}: {(s.description or '')[:100]}") + blocks.append("\n".join(lines)) + return "\n\n".join(blocks) + except Exception as e: + logger.warning(f"role skills load failed: {e}") + return "" + + async def role_agent_run(project_id, role, agent_id=None, model_name=None): role, _role_specific, _ = await _resolve_role(project_id, role) if role == 'pm': @@ -1123,12 +1163,16 @@ async def role_agent_run(project_id, role, agent_id=None, model_name=None): qna_section = await _build_qna_section(sor, task_id, role, agent_id) tools_text = json.dumps(AGENT_TOOLS, ensure_ascii=False) + # 注入角色技能(角色专属技能全量 + 其余 scope 目录层,优先级 项目>机构>通用) + role_skills = await _build_role_skills_block(sor, project_id, role, org_id) + system = (AGENT_SYSTEM_PROMPT .replace('__ROLE__', role) .replace('__TITLE__', title) .replace('__QNA__', qna_section) .replace('__WORKSPACE__', workspace_dir) .replace('__ROLE_SPECIFIC__', role_specific) + .replace('__ROLE_SKILLS__', role_skills) .replace('__TOOLS__', tools_text)) msgs = [{"role": "system", "content": system}]