Skip to content

UseSkillTool

Tools for Skills activation.

UseSkillTool

Bases: BaseTool

A dedicated tool for activating a skill.

Attributes:

Name Type Description
skills dict[str, Skill]

All discovered skills, keyed by name. Skills in explicit_only_skills are excluded from the enum but remain loadable if called directly via run_with_skill().

Source code in src/llm_agents_from_scratch/skills/tools.py
class UseSkillTool(BaseTool):
    """A dedicated tool for activating a skill.

    Attributes:
        skills (dict[str, Skill]): All discovered skills, keyed by name.
            Skills in ``explicit_only_skills`` are excluded from the enum
            but remain loadable if called directly via ``run_with_skill()``.
    """

    def __init__(
        self,
        skills: dict[str, Skill],
        explicit_only_skills: set[str] | None = None,
    ) -> None:
        """Initialize a UseSkillTool.

        Args:
            skills (dict[str, Skill]): All discovered skills, keyed by name.
            explicit_only_skills (set[str] | None): Skill names excluded from
                the model-visible catalog. They remain loadable via
                ``run_with_skill()``. Defaults to None.
        """
        self._skills = skills
        self._explicit_only_skills = explicit_only_skills or set()
        self._visible = [
            name for name in skills if name not in self._explicit_only_skills
        ]

    @property
    def name(self) -> str:
        """Name of skill activation tool."""
        return "from_scratch__use_skill"

    @property
    def description(self) -> str:
        """Description of the skill activation tool."""
        return (
            "Load and activate a skill by name, returning its full"
            " instructions. Only call this tool with a skill name from"
            " the <available_skills> catalog."
        )

    @property
    def parameters_json_schema(self) -> dict[str, Any]:
        """JSON schema for tool parameters.

        The ``name`` field is constrained to an enum of visible skill names
        (i.e. skills that have not set ``disable-model-invocation``).
        """
        return {
            "type": "object",
            "properties": {
                "name": {"type": "string", "enum": self._visible},
            },
            "required": ["name"],
        }

    def _build_skill_content(self, name: str) -> str:
        """Build the ``<skill_content>`` block for a skill.

        Args:
            name: The skill name to build content for.

        Returns:
            Formatted ``<skill_content>`` XML string.
        """
        skill = self._skills[name]
        resources = skill.resources
        skill_resources = (
            SKILL_RESOURCES_TEMPLATE.format(
                files="\n".join(
                    f"  <file>{r.as_posix()}</file>" for r in resources
                ),
            )
            if resources
            else ""
        )
        return ACTIVATION_CONTENT_TEMPLATE.format(
            name=skill.frontmatter.name,
            body=skill.read_body(),
            skill_dir=skill.location.parent.as_posix(),
            skill_resources=skill_resources,
        )

    def __call__(
        self,
        tool_call: ToolCall,
        *args: Any,
        **kwargs: Any,
    ) -> ToolCallResult:
        """Execute the skill activation tool.

        Args:
            tool_call (ToolCall): The ToolCall to execute.
            *args (Any): Additional positional arguments.
            **kwargs (Any): Additional keyword arguments.

        Returns:
            ToolCallResult: The activated skill's full content.
        """
        # Validate only that "name" is a present string, not the enum.
        # parameters_json_schema is narrower — it only enumerates visible
        # (non-explicit-only) skills as a hint to the model. Explicit-only
        # skills are absent from that enum but must still be activatable here.
        skill_name = tool_call.arguments.get("name")
        if not isinstance(skill_name, str):
            return ToolCallResult(
                tool_call_id=tool_call.id_,
                content=json.dumps(
                    {
                        "error_type": "ValueError",
                        "message": "'name' argument must be a string.",
                    },
                ),
                error=True,
            )
        if skill_name not in self._skills:
            return ToolCallResult(
                tool_call_id=tool_call.id_,
                content=json.dumps(
                    {
                        "error_type": "ValueError",
                        "message": f"Skill '{skill_name}' not found.",
                    },
                ),
                error=True,
            )
        content = self._build_skill_content(skill_name)

        return ToolCallResult(
            tool_call_id=tool_call.id_,
            content=content,
            error=False,
        )

name property

name

Name of skill activation tool.

description property

description

Description of the skill activation tool.

parameters_json_schema property

parameters_json_schema

JSON schema for tool parameters.

The name field is constrained to an enum of visible skill names (i.e. skills that have not set disable-model-invocation).

__init__

__init__(skills, explicit_only_skills=None)

Initialize a UseSkillTool.

Parameters:

Name Type Description Default
skills dict[str, Skill]

All discovered skills, keyed by name.

required
explicit_only_skills set[str] | None

Skill names excluded from the model-visible catalog. They remain loadable via run_with_skill(). Defaults to None.

None
Source code in src/llm_agents_from_scratch/skills/tools.py
def __init__(
    self,
    skills: dict[str, Skill],
    explicit_only_skills: set[str] | None = None,
) -> None:
    """Initialize a UseSkillTool.

    Args:
        skills (dict[str, Skill]): All discovered skills, keyed by name.
        explicit_only_skills (set[str] | None): Skill names excluded from
            the model-visible catalog. They remain loadable via
            ``run_with_skill()``. Defaults to None.
    """
    self._skills = skills
    self._explicit_only_skills = explicit_only_skills or set()
    self._visible = [
        name for name in skills if name not in self._explicit_only_skills
    ]

__call__

__call__(tool_call, *args, **kwargs)

Execute the skill activation tool.

Parameters:

Name Type Description Default
tool_call ToolCall

The ToolCall to execute.

required
*args Any

Additional positional arguments.

()
**kwargs Any

Additional keyword arguments.

{}

Returns:

Name Type Description
ToolCallResult ToolCallResult

The activated skill's full content.

Source code in src/llm_agents_from_scratch/skills/tools.py
def __call__(
    self,
    tool_call: ToolCall,
    *args: Any,
    **kwargs: Any,
) -> ToolCallResult:
    """Execute the skill activation tool.

    Args:
        tool_call (ToolCall): The ToolCall to execute.
        *args (Any): Additional positional arguments.
        **kwargs (Any): Additional keyword arguments.

    Returns:
        ToolCallResult: The activated skill's full content.
    """
    # Validate only that "name" is a present string, not the enum.
    # parameters_json_schema is narrower — it only enumerates visible
    # (non-explicit-only) skills as a hint to the model. Explicit-only
    # skills are absent from that enum but must still be activatable here.
    skill_name = tool_call.arguments.get("name")
    if not isinstance(skill_name, str):
        return ToolCallResult(
            tool_call_id=tool_call.id_,
            content=json.dumps(
                {
                    "error_type": "ValueError",
                    "message": "'name' argument must be a string.",
                },
            ),
            error=True,
        )
    if skill_name not in self._skills:
        return ToolCallResult(
            tool_call_id=tool_call.id_,
            content=json.dumps(
                {
                    "error_type": "ValueError",
                    "message": f"Skill '{skill_name}' not found.",
                },
            ),
            error=True,
        )
    content = self._build_skill_content(skill_name)

    return ToolCallResult(
        tool_call_id=tool_call.id_,
        content=content,
        error=False,
    )