diff --git a/pipeline_service/agent_loop_v2.py b/pipeline_service/agent_loop_v2.py index 0831014..02bf067 100644 --- a/pipeline_service/agent_loop_v2.py +++ b/pipeline_service/agent_loop_v2.py @@ -684,6 +684,8 @@ class AgentExecutor: # ── 通用工具集(Hermes CLI 能力子集)── "read_file": self._t_read_file, "load_skill": self._t_load_skill, + "list_packs": self._t_list_packs, + "install_pack": self._t_install_pack, "write_file": self._t_write_file, "list_files": self._t_list_files, "search_files": self._t_search_files, @@ -868,6 +870,37 @@ class AgentExecutor: return f"FAIL: 技能 '{name}' 不存在。可用技能: {names}" return merged[name].to_prompt_block() + async def _t_list_packs(self, sor, p, pid): + try: + from pipeline_core.skill_pack import list_packs + packs = list_packs() + if not packs: + return "(无可安装的技能集)" + lines = ["可安装的技能集:"] + for pk in packs: + lines.append(f" - {pk['name']}: {pk.get('title', '')}({pk.get('skill_count', 0)} 个技能)") + return "\n".join(lines) + except Exception as e: + return f"ERROR: {str(e)[:300]}" + + async def _t_install_pack(self, sor, p, pid): + pack = (p.get("pack") or "").strip() + if not pack: + return "FAIL: 需要技能集名(先用 list_packs 查看可用的技能集名)" + try: + from pipeline_core.skill_pack import install_pack + base_dir = self._skill_loader.base_dir if self._skill_loader else "" + org_id = self.org_id or "0" + r = install_pack(pack, base_dir, org_id) + if r.get("success"): + if self._skill_loader: + self._skill_loader.reload() + installed = r.get("installed", []) + return f"OK: 已安装技能集 {pack}({len(installed)} 个技能)" + return f"FAIL: {r.get('error', '未知错误')}" + except Exception as e: + return f"ERROR: {str(e)[:300]}" + async def _t_write_file(self, sor, p, pid): path = p.get("path", "") content = p.get("content", "") diff --git a/pipeline_service/slash_commands.py b/pipeline_service/slash_commands.py index 378561b..5a58379 100644 --- a/pipeline_service/slash_commands.py +++ b/pipeline_service/slash_commands.py @@ -75,8 +75,10 @@ async def _h_skills(args, ctx): ) if not merged: return "暂无可用技能" - lines = ["可用技能:"] - for name, s in merged.items(): + # 限数量:只列前 20 个(按 scope + 名字排序),提示总数,避免 216 个全倒出来 + items = sorted(merged.items(), key=lambda kv: (kv[1].scope, kv[0])) + lines = [f"可用技能(共 {len(items)} 个,仅列前 20,按需用 load_skill 加载正文):"] + for name, s in items[:20]: lines.append(f" - [{s.scope}] {name} — {s.description[:100]}") return "\n".join(lines)