Claude Agent

tool_runner

Expose tools through a focused agent for safe, direct tool execution.

LLM Mart · 0 points · 16 views 0 listing impressions 0 install-command copies

What vetted this — trust report

Download evalstate-fast-agent-docs_docs_agents_tool_runner.md-9be5169.zip · 1 KB
Part of evalstate/fast-agent — 11 skills

Install

skills CLI npx skills add https://github.com/evalstate/fast-agent/tree/main/docs/docs/agents/tool_runner.md
Git git clone https://github.com/evalstate/fast-agent.git

The skills CLI installs just this skill, for any of its supported agents. Git is the plain clone.

Files (fast-agent)
  • tool_runner.md 3.7 KB
    ---
    social:
      title: Tool Runner
      tagline: Expose tools through a focused agent for safe, direct tool execution.
      description: Expose tools through a focused agent for safe, direct tool execution.
      alt: fast-agent social card — Tool Runner
    ---
    
    # Tool Runner
    
    Tool Runner is the internal loop that powers tool calling for `ToolAgent` and MCP agents. It:
    - Sends messages to the LLM.
    - Detects tool requests.
    - Executes tools.
    - Feeds tool results back into the loop until the assistant is done.
    
    ## Hooks (optional)
    
    You can attach lightweight hooks to the Tool Runner without changing the core agent protocol.
    Implement the `ToolRunnerHookCapable` capability and expose a `tool_runner_hooks` property.
    
    Available hook points:
    - `before_llm_call`
    - `after_llm_call`
    - `before_tool_call`
    - `after_tool_call`
    - `after_turn_complete`
    
    `after_llm_call` runs after every assistant response from the model, including
    intermediate responses that request tools. `before_tool_call` and
    `after_tool_call` wrap each tool-execution step. `after_turn_complete` runs once
    at the end of the whole user turn, after any model/tool/model loop has finished,
    and receives the final message for that turn.
    
    ### Built-in hooks
    
    fast-agent ships several `after_turn_complete` hooks built on this mechanism,
    applied automatically and gated by config:
    
    - **Auto-compaction** — summarizes older history when context usage crosses
      `compaction.threshold`. See [Compaction](../guides/compaction.md).
    - **History trimming** — `trim_tool_history: true` on an agent collapses a
      multi-call tool loop to its last call, result, and final response.
    - **Session-history persistence** — saves the conversation after each turn when
      `session_history` is enabled.
    
    These coexist with any hooks you attach: built-ins run in a fixed order
    (custom/trim → compact → session save) so a custom `after_turn_complete` hook
    still fires.
    
    ## Minimal example
    
    ```python
    import asyncio
    
    from fast_agent import FastAgent
    from fast_agent.agents.agent_types import AgentConfig
    from fast_agent.agents.tool_agent import ToolAgent
    from fast_agent.agents.tool_runner import ToolRunnerHooks
    from fast_agent.context import Context
    from fast_agent.interfaces import ToolRunnerHookCapable
    from fast_agent.types import PromptMessageExtended
    
    
    def get_video_call_transcript(video_id: str) -> str:
        return "Assistant: Hi, how can I assist you today?\n\nCustomer: Hi, I wanted to ask you about last invoice I received..."
    
    
    class HookedToolAgent(ToolAgent, ToolRunnerHookCapable):
        def __init__(self, config: AgentConfig, context: Context | None = None):
            super().__init__(config, [get_video_call_transcript], context)
            self._hooks = ToolRunnerHooks(
                before_llm_call=self._add_style_hint,
                after_tool_call=self._log_tool_result,
            )
    
        @property
        def tool_runner_hooks(self) -> ToolRunnerHooks | None:
            return self._hooks
    
        async def _add_style_hint(self, runner, messages: list[PromptMessageExtended]) -> None:
            if runner.iteration == 0:
                runner.append_messages("Keep the answer to one short sentence.")
    
        async def _log_tool_result(self, runner, message: PromptMessageExtended) -> None:
            if message.tool_results:
                tool_names = ", ".join(message.tool_results.keys())
                print(f"[hook] tool results received: {tool_names}")
    
    
    fast = FastAgent("Example Tool Use Application (Hooks)")
    
    
    @fast.custom(HookedToolAgent)
    async def main() -> None:
        async with fast.run() as agent:
            await agent.default.generate("What is the topic of the video call no.1234?")
    
    
    if __name__ == "__main__":
        asyncio.run(main())
    ```
    
    The full runnable example lives in the repo at:
    `examples/tool-runner-hooks/tool_runner_hooks.py`
    

Comments (0)

Sign in to join the conversation.

No comments yet.

Reviews (0)

No reviews yet.

Related