Skip to main content
This page provides a quick reference for commonly used AFK imports and constructor signatures. For the full field-by-field reference, see the Configuration Reference. For module-level documentation, see the Module Reference.

Quick import map

TaskImportFrom
Define an agentfrom afk.agents import Agentafk.agents
Configure safety limitsfrom afk.agents import FailSafeConfigafk.agents
Set up policy enginefrom afk.agents import PolicyEngine, PolicyRuleafk.agents
Run an agentfrom afk.core import Runnerafk.core
Configure the runnerfrom afk.core import RunnerConfigafk.core
Debug a runfrom afk.debugger import Debugger, DebuggerConfigafk.debugger
Define a toolfrom afk.tools import toolafk.tools
Tool context accessfrom afk.tools import ToolContextafk.tools
Tool hooksfrom afk.tools import prehook, posthook, middlewareafk.tools
Build an LLM clientfrom afk.llms import LLMBuilderafk.llms
Run evalsfrom afk.evals import run_suiteafk.evals
Define eval casesfrom afk.evals.models import EvalCase, EvalBudgetafk.evals.models
A2A clientfrom afk.a2a import A2AClientafk.a2a
MCP serverfrom afk.mcp import MCPServerafk.mcp
Task queuefrom afk.queues import TaskQueue, TaskItemafk.queues

Architecture overview

The framework is built on three core pillars that interact at runtime:
  1. Agent (afk.agents.Agent) — The definition. It holds the static configuration: “Who am I?” (instructions, name), “What can I do?” (tools, subagents), and “How safe am I?” (fail-safe limits). Agents are stateless definitions that can be reused across many runs.
  2. Runner (afk.core.Runner) — The engine. It orchestrates the dynamic execution: managing the event loop, maintaining conversation state in memory, executing tools, handling failures, and dispatching events to telemetry. Runners are stateful (holding connections to memory/telemetry) but re-entrant.
  3. Runtime (afk.llms, afk.tools) — The capabilities. The underlying machinery that powers the agent: LLM clients handling provider I/O, and the tool registry managing safe execution of Python functions.

Execution model

The Runner supports three execution modes for different use cases. All modes use the same underlying event loop and guarantee the same consistency models.

1. Synchronous (run_sync)

Blocks the calling thread until the run is complete. Best for scripts, cron jobs, and simple CLI tools.
  • Concurrency: Internal tasks (like tool execution) still run on the asyncio event loop, but the entry point is blocking.
  • Return: Returns the final AgentResult only after the run reaches a terminal state (completed, failed).

2. Asynchronous (await run)

Returns an awaitable coroutine. Best for backend API handlers (FastAPI, Django Async) and high-concurrency workloads.
  • Concurrency: Non-blocking. Allows thousands of concurrent agent runs in a single process.
  • Return: Returns AgentResult upon completion.

3. Streaming (await run_stream)

Returns an async iterator of AgentStreamEvents. Best for real-time UIs (chatbots, IDE integrations).
  • Feedback: Emits events immediately as they happen (token delta, tool start, tool end).
  • Control: Allows the consumer to abort the run by cancelling the stream consumption.

Most common pattern

from afk.agents import Agent, FailSafeConfig
from afk.tools import tool
from afk.core import Runner, RunnerConfig
from pydantic import BaseModel

Constructor signatures

Agent

from afk.agents import Agent

agent = Agent(
    *,
    model: str | LLM,                                    # Required — model name or client
    name: str | None = None,                             # Agent identity
    instructions: str | callable | None = None,          # System prompt
    instruction_file: str | Path | None = None,          # Prompt file path
    tools: list | None = None,                           # Tool list
    subagents: list[Agent] | None = None,                # Specialist subagents
    context_defaults: dict | None = None,                # Default run context
    fail_safe: FailSafeConfig | None = None,             # Limits and failure policies
    max_steps: int = 20,                                 # Max loop iterations
    policy_engine: PolicyEngine | None = None,           # Deterministic policy rules
    model_resolver: callable | None = None,              # Custom model resolver
    skills: list[str] | None = None,                     # Skill names to load
    mcp_servers: list | None = None,                     # External MCP server refs
)
Only model is required. See the Configuration Reference for the full list of 25+ fields with defaults.

Runner

from afk.core import Runner

runner = Runner(
    *,
    memory_store: MemoryStore | None = None,             # Memory backend
    interaction_provider: InteractionProvider | None = None,  # HITL provider
    policy_engine: PolicyEngine | None = None,           # Shared policy engine
    telemetry: str | TelemetrySink | None = None,        # "console" | "otel" | "json"
    telemetry_config: dict | None = None,                # Backend config
    config: RunnerConfig | None = None,                  # Runner configuration
)

Key Runner methods

  • run_sync(agent, ...) -> AgentResult Blocking execution. In memory-backend modes, this persists state to the DB at every step. In-memory mode is transient. Use for: Scripts, CLI tools, tests.
  • await run(agent, ...) -> AgentResult Async execution. This is the standard entry point for scalable applications. It handles the full agent loop: LLM calls -> Tool execution -> Policy checks -> Recursion. Use for: Web servers, queue workers, scalable backend services.
  • await run_stream(agent, ...) -> AgentStreamHandle Returns a handle exposing an async iterator of events. The stream yields events as they happen. You MUST consume the stream to drive execution forward. Use for: Chat interfaces, real-time feedback.
  • await list_background_tools(*, thread_id, run_id, include_resolved=False) -> list[dict] Lists persisted deferred tool tickets for a run. Use for: Long-running tool monitoring and external worker reconciliation.
  • await resolve_background_tool(*, thread_id, run_id, ticket_id, output=...) -> None Marks a deferred ticket as completed and stores output for runner polling. Use for: External worker completion callbacks.
  • await fail_background_tool(*, thread_id, run_id, ticket_id, error=...) -> None Marks a deferred ticket as failed with error details. Use for: External worker failure propagation.
  • await resume(agent, *, run_id, thread_id) -> AgentResult Re-hydrates a run from the database. It loads the full execution snapshot (messages, unexecuted tool calls) and continues exactly where it left off. Use for: Human-in-the-loop workflows (resume after approval), recovering from process crashes.
  • await compact_thread(*, thread_id) -> None Triggers memory compaction for a specific thread. This applies the configured RetentionPolicy to reduce token usage by summarizing history or discarding old messages. Use for: Long-running conversations where context window limits are a concern.

RunnerConfig

from afk.core import RunnerConfig

config = RunnerConfig(
    interaction_mode: str = "headless",                  # "headless" | "interactive" | "external"
    sanitize_tool_output: bool = True,                   # Strip injection vectors
    tool_output_max_chars: int = 12_000,                 # Output truncation limit
    approval_timeout_s: float = 300.0,                   # Approval timeout
    approval_fallback: str = "deny",                     # "allow" | "deny" | "defer"
)

FailSafeConfig

from afk.agents import FailSafeConfig

fail_safe = FailSafeConfig(
    max_steps: int = 20,                                 # Max run loop iterations
    max_llm_calls: int = 50,                             # Max LLM invocations
    max_tool_calls: int = 200,                           # Max tool invocations
    max_wall_time_s: float = 300.0,                      # Wall-clock timeout
    max_total_cost_usd: float | None = None,             # Cost ceiling
    llm_failure_policy: str = "retry_then_fail",         # LLM error strategy
    tool_failure_policy: str = "continue_with_error",    # Tool error strategy
    subagent_failure_policy: str = "continue",           # Subagent error strategy
    fallback_model_chain: list[str] = [],                # Fallback models
)
Always set max_total_cost_usd in production. Without it, a runaway agent loop can spend significant API credits in minutes.

@tool decorator

from afk.tools import tool

@tool(
    *,
    args_model: Type[BaseModel],                         # Required — Pydantic args model
    name: str | None = None,                             # Tool name (default: function name)
    description: str | None = None,                      # LLM-visible description
    timeout: float | None = None,                        # Execution timeout in seconds
    prehooks: list[PreHook] | None = None,               # Argument transform hooks
    posthooks: list[PostHook] | None = None,             # Output transform hooks
    middlewares: list[Middleware] | None = None,          # Execution wrappers
    raise_on_error: bool = False,                        # Raise vs return ToolResult
)

Core types

AgentResult

FieldTypeDescription
final_textstrThe agent’s final response
statestrTerminal state: completed, failed, degraded, cancelled, interrupted
run_idstrUnique run identifier
thread_idstrThread identifier for memory continuity
tool_executionslist[ToolExecutionRecord]All tool calls with name, success, output, latency, and agent provenance
subagent_executionslist[SubagentExecutionRecord]All subagent invocations
usage_aggregateUsageAggregateToken counts and cost estimates
state_snapshotdict[str, JSONValue]Final runtime counters/snapshot metadata

AgentStreamEvent

FieldTypeDescription
typestrEvent category (see Streaming)
text_deltastr | NoneIncremental text chunk
tool_namestr | NoneTool name for tool events
tool_call_idstr | NoneTool call identifier
tool_successbool | NoneWhether tool succeeded
tool_outputJSONValue | NoneTool output payload
tool_errorstr | NoneTool error message
stepint | NoneCurrent step index
statestr | NoneCurrent agent state
resultAgentResultTerminal result (for completed events)
errorstr | NoneError message (for error events)

Agents module

Core module

Tools module

LLM module

API stability

AFK follows semantic versioning. Public exports from afk.agents, afk.core, afk.tools, afk.llms, and afk.evals are considered stable and will not change without a major version bump. Internal modules (prefixed with _ or under afk.core.runner._internal) are not part of the public API and may change at any time.