Skip to main content
Tools let agents take actions — query databases, call APIs, run calculations, write files, or anything you can express in Python. AFK handles schema generation, argument validation, policy gates, execution, and output sanitization.

Your first tool

That’s a complete tool. The @tool decorator generates the JSON schema from the Pydantic model, which the LLM uses to understand what arguments to pass.

How tool calling works

1

LLM decides to call a tool

Based on the user’s message and the tool schemas, the LLM emits a tool_call with the function name and arguments.
2

Validate arguments

AFK parses the arguments through the Pydantic model. Invalid arguments generate a validation error that’s sent back to the LLM for self-correction.
3

Check policy gate

If a PolicyEngine is attached, the tool call is checked against policy rules (allow, deny, or request_approval).
4

Execute the handler

The tool function runs with validated arguments. Pre/post hooks and middleware execute around the handler.
5

Sanitize output

The output is truncated to tool_output_max_chars, stripped of potential prompt injection vectors (if sanitize_tool_output=True), and formatted for the LLM.
6

Return to LLM

The sanitized result is appended to the conversation and the LLM generates its next response.

Tool patterns

Return a string or dict directly.

Deferred background tool calls

For long-running operations, a tool can return a deferred handle so the run can continue while work completes in the background.
When deferred:
  1. Runner emits tool_deferred.
  2. Agent continues with other work in the same run.
  3. Runner emits tool_background_resolved or tool_background_failed.
  4. Resolved tool output is injected back into conversation for next steps.
External workers can resolve tickets by writing:
  • bgtool:{run_id}:{ticket_id}:state
  • bgtool:{run_id}:latest
Status payload example:
This pattern is useful for coding agents that start a long build, continue writing docs, then consume build results once available. You can also use runner helpers instead of writing raw state keys:

Policy-gated tools

Use the PolicyEngine to gate sensitive tool calls:
Policy best practice: Gate all mutating tools with request_approval or deny by default. Only allow read-only tools without gates.

Hooks and middleware

AFK provides four extension points for tool execution: prehooks, posthooks, tool-level middleware, and registry-level middleware. Each has its own decorator.

Prehooks — transform args before execution

Prehooks run before the tool handler. They receive the tool’s arguments and must return a dict compatible with the tool’s args_model.
Posthooks run after the tool handler. They receive a dict {"output": <tool_output>, "tool_name": "<name>"} and should return a dict with the same shape.
Middleware wraps the entire tool execution. It receives call_next, the validated args, and optionally ctx.
Registry-level middleware applies to every tool in a ToolRegistry. Use for audit logging, rate limiting, or global policy enforcement.

Execution order

Common tools cookbook

Prebuilt tools

AFK ships with ready-to-use tools for common agent capabilities. These are in the afk.tools.prebuilts module.

Runtime tools

Filesystem tools scoped to a directory for safe agent exploration:
Runtime tools enforce directory-scoped access — the agent cannot read or list files outside the configured root_dir.

Skill tools

When an agent has skills configured, AFK generates four skill tools automatically: Skill tools are gated by a SkillToolPolicy that controls command allowlists, output limits, and shell operator restrictions:

Next steps

Streaming

Watch tool calls happen in real time.

Security Model

Policy gates, sandbox profiles, and tool allowlists.