62 lines
2.3 KiB
Python
62 lines
2.3 KiB
Python
"""load_skill 工具: agent 主动加载某个 skill 的完整 SKILL.md。
|
|
|
|
这是渐进披露的中间层 (Activation): 启动时只看到 name+description,
|
|
认为自己要做某类任务时,调 load_skill 拿到完整指引。
|
|
"""
|
|
from __future__ import annotations
|
|
|
|
from pathlib import Path
|
|
from typing import Optional
|
|
|
|
from core.skills import SkillRegistry
|
|
|
|
from .base import Tool
|
|
|
|
|
|
class LoadSkillTool(Tool):
|
|
name = "load_skill"
|
|
description = (
|
|
"Load full instructions for a skill. Call this when the current task matches "
|
|
"a skill's domain (e.g. writing PPT, coding, research proposal). "
|
|
"Returns the SKILL.md body, which may reference further files in skills/<name>/references."
|
|
)
|
|
parameters = {
|
|
"type": "object",
|
|
"properties": {
|
|
"name": {
|
|
"type": "string",
|
|
"description": "Skill name as listed in the system prompt's discovery block",
|
|
}
|
|
},
|
|
"required": ["name"],
|
|
}
|
|
|
|
def __init__(
|
|
self,
|
|
registry: SkillRegistry,
|
|
base_dir: Optional[Path] = None,
|
|
user_root: Optional[Path] = None,
|
|
container_skills_dir: Optional[str] = None,
|
|
) -> None:
|
|
super().__init__(base_dir, user_root=user_root)
|
|
self.registry = registry
|
|
# docker backend 下,fs / shell / run_python 都在容器里跑,host skills/ bind
|
|
# mount 到 /sandbox/skills:ro(pool.py)。header 里的 dir 要给容器内可用路径
|
|
# —— 否则 LLM 拿 host 绝对路径(`/home/.../skills/<name>`)去 read references
|
|
# 时容器看不见,抓瞎报 file not found。POSIX 串(容器恒为 Linux),与 host OS 无关。
|
|
# None = host backend,保持 skill.skill_dir 原 host 绝对路径。
|
|
self.container_skills_dir = container_skills_dir
|
|
|
|
def execute(self, name: str) -> str:
|
|
skill = self.registry.get(name)
|
|
if skill is None:
|
|
available = ", ".join(self.registry.skills.keys()) or "(none)"
|
|
return f"[Error] skill '{name}' not found. Available: {available}"
|
|
body = skill.full_content()
|
|
if self.container_skills_dir is not None:
|
|
dir_str = f"{self.container_skills_dir.rstrip('/')}/{skill.name}"
|
|
else:
|
|
dir_str = str(skill.skill_dir)
|
|
header = f"[skill={skill.name}, dir={dir_str}]\n"
|
|
return header + body
|