Skip to main content

Documentation Index

Fetch the complete documentation index at: https://afk.arpan.sh/llms.txt

Use this file to discover all available pages before exploring further.

This tutorial expands the quickstart into the core workflow used by most AFK applications. Each section introduces one concept and keeps the code small enough to copy into a single file.

1. Agent + runner

from afk.agents import Agent
from afk.core import Runner

agent = Agent(
    name="tutor",
    model="gpt-4.1-mini",
    instructions="Explain programming concepts in plain language.",
)

runner = Runner()
result = runner.run_sync(agent, user_message="What is recursion?")

print(result.final_text)
print(result.run_id)
Key point: an agent is declarative. The runner owns execution.

2. Typed tools

from pydantic import BaseModel

from afk.agents import Agent
from afk.core import Runner
from afk.tools import tool


class LookupArgs(BaseModel):
    topic: str
    max_results: int = 3


@tool(args_model=LookupArgs, name="search_docs", description="Search docs by topic.")
def search_docs(args: LookupArgs) -> dict:
    return {
        "results": [
            {"title": f"Guide: {args.topic}", "score": 0.95},
            {"title": f"FAQ: {args.topic}", "score": 0.82},
        ][: args.max_results]
    }


agent = Agent(
    name="research-tutor",
    model="gpt-4.1-mini",
    instructions="Search docs before answering user questions.",
    tools=[search_docs],
)

result = Runner().run_sync(
    agent,
    user_message="How do I handle errors in Python?",
)

print(result.final_text)
print(result.tool_executions)
Key point: tool arguments are validated before your function runs.

3. Streaming

Use streaming when a UI or CLI should show progress before the final result is ready.
import asyncio

from afk.agents import Agent
from afk.core import Runner


agent = Agent(
    name="streamer",
    model="gpt-4.1-mini",
    instructions="Explain topics clearly.",
)


async def main() -> None:
    handle = await Runner().run_stream(
        agent,
        user_message="Explain Python decorators in three bullets.",
    )

    async for event in handle:
        if event.type == "text_delta":
            print(event.text_delta, end="", flush=True)
        elif event.type == "completed":
            print(f"\n\nstate={event.result.state}")


asyncio.run(main())
Key point: run_stream() returns an AgentStreamHandle. Consume it to receive text, tool lifecycle events, errors, and the terminal result.

4. Memory continuity

Pass the same thread_id to keep conversation context attached to a thread.
import asyncio

from afk.agents import Agent
from afk.core import Runner


agent = Agent(
    name="memory-tutor",
    model="gpt-4.1-mini",
    instructions="Remember the user's earlier questions in this thread.",
)


async def main() -> None:
    runner = Runner()
    thread_id = "student-session-42"

    first = await runner.run(
        agent,
        user_message="What are Python decorators?",
        thread_id=thread_id,
    )
    second = await runner.run(
        agent,
        user_message="Give me a short example using that idea.",
        thread_id=thread_id,
    )

    print(first.final_text)
    print(second.final_text)


asyncio.run(main())
Key point: thread continuity is explicit. Use the same thread_id for related turns.

5. Safety limits

Production agents need hard limits even when prompts and tools are well designed.
from afk.agents import Agent, FailSafeConfig
from afk.core import Runner, RunnerConfig

agent = Agent(
    name="bounded-agent",
    model="gpt-4.1-mini",
    instructions="Help users, but stop if the task becomes too large.",
    fail_safe=FailSafeConfig(
        max_steps=8,
        max_llm_calls=12,
        max_tool_calls=20,
        max_wall_time_s=45.0,
        max_total_cost_usd=0.25,
    ),
)

runner = Runner(
    config=RunnerConfig(
        sanitize_tool_output=True,
        tool_output_max_chars=8_000,
    ),
)

result = runner.run_sync(agent, user_message="Summarize the tradeoffs of caching.")
print(result.final_text)
Key point: limits are part of the agent contract. Set them before shipping.

Agents

Agent fields, prompt resolution, subagents, skills, and MCP tools.

Tools

Tool schemas, context, hooks, middleware, sandboxing, and output limits.

Streaming

Event types, stream handles, cancellation, and UI patterns.

Production Readiness

Evals, telemetry, security controls, queues, and deployment.