Skip to content

SkillsToolkit

autogen.beta.tools.skills.local_skills.toolkit.SkillsToolkit #

SkillsToolkit(runtime=None, *, middleware=())

Bases: Toolkit

Client-side toolkit for agentskills.io-style local skills.

Packs a three-step progressive-disclosure pattern as a single toolkit so any provider can ship local skills without extra wiring:

  1. list_skills() — lightweight catalog (name + description).
  2. load_skill(name) — full SKILL.md instructions on demand.
  3. run_skill_script(name, script, args) — execute a script from the skill's scripts/ directory.

Default runtime scans ./.agents/skills and ~/.agents/skills::

SkillsToolkit()

Custom install directory::

SkillsToolkit(runtime=LocalRuntime("./skills"))

Extra read-only search paths::

SkillsToolkit(runtime=LocalRuntime("./skills", extra_paths=["./shared-skills"]))

Pick individual tools instead of the full toolkit::

skills = SkillsToolkit()
agent = Agent(
    "a",
    config=config,
    tools=[skills.list_skills(), skills.load_skill()],
)
Source code in autogen/beta/tools/skills/local_skills/toolkit.py
def __init__(
    self,
    runtime: SkillRuntime | str | os.PathLike[str] | None = None,
    *,
    middleware: Iterable[ToolMiddleware] = (),
) -> None:
    if runtime is not None:
        self._runtime: SkillRuntime = LocalRuntime.ensure_runtime(runtime)
    else:
        self._runtime = LocalRuntime()

    super().__init__(
        self.list_skills(),
        self.load_skill(),
        self.run_skill_script(),
        name="local_skills_toolkit",
        middleware=middleware,
    )

runtime property #

runtime

The underlying SkillRuntime used to discover and load skills.

name instance-attribute #

name = name or __name__

tools property #

tools

list_skills #

list_skills(*, name='list_skills', description='List available local skills with name and short description.', middleware=())
Source code in autogen/beta/tools/skills/local_skills/toolkit.py
def list_skills(
    self,
    *,
    name: str = "list_skills",
    description: str = "List available local skills with name and short description.",
    middleware: Iterable[ToolMiddleware] = (),
) -> FunctionTool:
    runtime = self._runtime

    @tool(name=name, description=description, middleware=middleware)
    def _list_skills() -> list[dict[str, str]]:
        return [{"name": m.name, "description": m.description} for m in runtime.discover()]

    return _list_skills

load_skill #

load_skill(*, name='load_skill', description='Load the full SKILL.md content for a specific skill.', middleware=())
Source code in autogen/beta/tools/skills/local_skills/toolkit.py
def load_skill(
    self,
    *,
    name: str = "load_skill",
    description: str = "Load the full SKILL.md content for a specific skill.",
    middleware: Iterable[ToolMiddleware] = (),
) -> FunctionTool:
    runtime = self._runtime

    @tool(name=name, description=description, middleware=middleware)
    def _load_skill(
        name: Annotated[str, Field(description="Skill name returned by list_skills.")],
    ) -> str:
        return runtime.load(name)

    return _load_skill

run_skill_script #

run_skill_script(*, name='run_skill_script', description="Run a script from a skill's scripts directory. Only .py and .sh scripts are supported.", middleware=())
Source code in autogen/beta/tools/skills/local_skills/toolkit.py
def run_skill_script(
    self,
    *,
    name: str = "run_skill_script",
    description: str = "Run a script from a skill's scripts directory. Only .py and .sh scripts are supported.",
    middleware: Iterable[ToolMiddleware] = (),
) -> FunctionTool:
    runtime = self._runtime

    @tool(name=name, description=description, middleware=middleware)
    def _run_skill_script(
        name: Annotated[
            str,
            Field(description="Skill name returned by list_skills."),
        ],
        script: Annotated[
            str,
            Field(description="Script filename inside scripts/, for example scaffold.py or build.sh."),
        ],
        args: Annotated[
            list[str] | None,
            Field(description="Optional script arguments passed as positional parameters."),
        ] = None,
    ) -> str:
        skill_dir = runtime.get_path(name)
        scripts_dir = skill_dir / "scripts"
        script_path = Path(script)
        if script_path.name != script:
            raise ValueError("script must be a filename inside the skill scripts directory")

        resolved_script = (scripts_dir / script_path.name).resolve()
        if not resolved_script.is_file() or not resolved_script.is_relative_to(scripts_dir.resolve()):
            raise FileNotFoundError(f"script {script!r} not found in {scripts_dir}")

        first_line = resolved_script.read_text(encoding="utf-8", errors="replace").split("\n", 1)[0]
        has_shebang = first_line.startswith("#!")

        if has_shebang:
            resolved_script.chmod(resolved_script.stat().st_mode | stat.S_IXUSR | stat.S_IXGRP | stat.S_IXOTH)
            command = [f"./{resolved_script.name}"]
        elif resolved_script.suffix.lower() == ".py":
            command = ["python3", f"./{resolved_script.name}"]
        elif resolved_script.suffix.lower() == ".sh":
            command = ["sh", f"./{resolved_script.name}"]
        else:
            resolved_script.chmod(resolved_script.stat().st_mode | stat.S_IXUSR | stat.S_IXGRP | stat.S_IXOTH)
            command = [f"./{resolved_script.name}"]

        if args:
            command.extend(args)

        env = runtime.shell(scripts_dir)
        return env.run(shlex.join(command))

    return _run_skill_script

set_provider #

set_provider(provider)
Source code in autogen/beta/tools/final/toolkit.py
def set_provider(self, provider: Provider) -> None:
    for t in self.tools:
        t.set_provider(provider)

schemas async #

schemas(context)
Source code in autogen/beta/tools/final/toolkit.py
async def schemas(self, context: "Context") -> Iterable[ToolSchema]:
    schemas: list[ToolSchema] = []
    for t in self.tools:
        schemas.extend(await t.schemas(context))
    return schemas

register #

register(stack, context, *, middleware=())
Source code in autogen/beta/tools/final/toolkit.py
def register(
    self,
    stack: "ExitStack | AsyncExitStack",
    context: "Context",
    *,
    middleware: Iterable["BaseMiddleware"] = (),
) -> None:
    for t in self.tools:
        t.register(stack, context, middleware=middleware)

tool #

tool(function: Callable[..., Any], *, name: str | None = None, description: str | None = None, schema: FunctionParameters | None = None, sync_to_thread: bool = True, middleware: Iterable[ToolMiddleware] = ()) -> FunctionTool
tool(function: None = None, *, name: str | None = None, description: str | None = None, schema: FunctionParameters | None = None, sync_to_thread: bool = True, middleware: Iterable[ToolMiddleware] = ()) -> Callable[[Callable[..., Any]], FunctionTool]
tool(function=None, *, name=None, description=None, schema=None, sync_to_thread=True, middleware=())
Source code in autogen/beta/tools/final/toolkit.py
def tool(
    self,
    function: Callable[..., Any] | None = None,
    *,
    name: str | None = None,
    description: str | None = None,
    schema: FunctionParameters | None = None,
    sync_to_thread: bool = True,
    middleware: Iterable[ToolMiddleware] = (),
) -> FunctionTool | Callable[[Callable[..., Any]], FunctionTool]:
    def make_tool(f: Callable[..., Any]) -> FunctionTool:
        t = tool(
            f,
            name=name,
            description=description,
            schema=schema,
            sync_to_thread=sync_to_thread,
            middleware=middleware,
        )
        self._add_tool(t)
        return t

    if function:
        return make_tool(function)

    return make_tool