Skip to content

Lazy Agent Instantiation

Plugins should be "safe to load" regardless of the user's environment. You should defer the instantiation of heavy objects—especially LLM agents that require API keys—until they are actually needed.

If you instantiate an agent in the tool's __init__, it might fail if the user hasn't configured an API key or model for that tool. This prevents the entire toolkit from starting or listing other tools.

Pattern: Private Property Instantiation

Instantiate your agents lazily inside the execute method or via a private property.

from aifred_tk.core.llm import build_agent_from_settings, AgentRunner

class MyTool(Tool):
    def __init__(self, settings: Dynaconf):
        self._settings = settings
        self._agent: AgentRunner[MyResultModel] | None = None

    def _get_agent(self) -> AgentRunner[MyResultModel]:
        if self._agent is None:
            # This will fail if no LLM is configured for this tool, 
            # but only when the tool is actually RUN.
            self._agent = build_agent_from_settings(
                self.tool_id, 
                self._settings,
                output_type=MyResultModel,
                system_prompt=MY_SYSTEM_PROMPT
            )
        return self._agent

    def execute(self, args: ToolArgs) -> ToolResult:
        # Agent is built only when the tool is executed
        agent = self._get_agent()
        # ...

This ensures that aifred-tk can still start and list all available tools even if one plugin is misconfigured.