tool_runner

The internal loop that lets a coding agent call tools, receive their results, and continue working until it has finished a turn. It also supports optional hooks before and after model calls, tool calls, and completed turns.

In plain words
What is it for?
Use it to run tool-based agents and attach actions such as logging, automatic context summarization, or other processing around tool calls and completed turns.
Why use it?
It coordinates the repeated model-and-tool steps that would otherwise need to be managed separately.

Agent

Install

Getting it into your agent

One page per mod, every tool's command on it. A separate URL per tool would split the same page into five that compete with each other.

agentmods
npx agentmods add agents/evalstate/fast-agent/tool_runner
Clone the repo
git clone --depth 1 https://github.com/evalstate/fast-agent
Per session 0 Only the description is in the session, so the agent can decide to use it. The body loads when it is invoked.
When invoked 848 The whole file, excluding the scripts and references it only reads on demand.
Security scan A 0 findings. Scan, not verified.
Origin original No closer match found in the catalogue.
Token cost

What it costs to keep this loaded

Counted locally with the o200k_base tokenizer, which is exact for GPT models; Claude uses its own tokenizer and its counts differ. Treat this as one consistent yardstick across the catalogue rather than a bill. Prices are per million input tokens.

ModelPer sessionOnce invoked
Fable 5 $0.00000 $0.00848
Opus 5 $0.00000 $0.00424
Sonnet 5 $0.00000 $0.00170
Haiku 4.5 $0.00000 $0.00085

Measured yesterday against content hash f3fb1087f977, method: parsed. Prices are Anthropic first-party input rates as of 2026-08-30, from the pricing page.

Security

Grade A, and why

tool_runner scanned grade A with 0 findings against 26 rules in 11 categories — prompt injection, anti-refusal, data exfiltration, privilege escalation, supply chain, agent snooping, system-prompt leakage, SSRF and excessive agency — measured yesterday.

A static scan of the body, not an audit. Every finding is printed with the line that produced it so you can judge whether it matters here. A mod is markdown that instructs an agent; that is exactly why what it instructs is worth reading.

Nothing flagged

None of the 26 patterns this scan looks for appear in this file: no shell pipes, no recursive deletes, no credential paths, no hidden text, no instruction-override or anti-refusal phrasing, no agent-config snooping. That is not a guarantee, it is the absence of the things that are checkable.

docs/docs/agents/tool_runner.md · 106 lines

How it starts

The opening of the file, as written. The whole thing — 106 lines — stays where its author put it; the contents beside it link to each section on GitHub.

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.
  • History trimmingtrim_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

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())

Read the full file on GitHub · 106 lines

Changes

What this file has done since we first saw it

Hashed on every crawl. A supply-chain change to an agent config is a question of when, not whether, so the history is kept rather than the latest state alone.

  1. yesterday First seen · 106 lines · 0 tokens per session scan A f3fb1087f977

Subscribe to this mod's changes

tool_runner is an agent published in the GitHub repository evalstate/fast-agent (3,904 stars, last pushed 2d ago), licensed Apache-2.0. It costs nothing until one of its globs matches a file; then it loads 848 tokens. A static security scan graded it A with 0 findings. No closer match exists in the catalogue, so it is treated as the original; first seen 2026-08-30.

Related

Other agents, from other repositories

agentlas-core-engine-meta-agent

Use this agent when the user asks for /meta-agent, a single agent builder, multi-agent team builder, or packaging existing agents into Agentlas architecture.

agentlas-ai/Agentlas-OS · 38 tokens

Explore

Fast read-only codebase & docs exploration. Returns structured findings, never raw file dumps.

BlackBeltTechnology/pi-agent-dashboard · 18 tokens

tech-lead

Technical lead agent – PR review/approval/merge, blocker resolution, and architecture/trade-off review aligned with Jira outcomes.

agents-universe/agents-universe · 25 tokens

unittest-generator

Use this agent when you need to create unit tests for your code in unittest.TestCase format, organized in a tests folder with concept-based subfolders. Examples: Context: User has just written a new authentication module and needs comprehensive unit tests. user: 'I just finished writing my user authentication…

Upsonic/Upsonic · 0 tokens

external-system-integration-expert

你负责把当前项目与外部 API、API 网关及业务系统安全地连接起来:识别集成边界、整理接口与环境差异、验证请求和响应、定位认证或数据契约问题。.

agents-universe/agents-universe · 33 tokens

DocScribe

Write docs/ prose for a completed change, in caveman style, per the repo's Documentation Update Protocol. Use after a change lands to update docs/architecture.md, docs/ .md, README, or docs/AGENTS.md — the Rule-6 delegation target (main agent must NOT edit docs/ directly). Self-contained — give it the diff + target…

BlackBeltTechnology/pi-agent-dashboard · 100 tokens