« Phase 21 README · Warmup · Deep Dive · Principal Deep Dive · Core Contributor · Staff Notes
Phase 21 — Hitchhiker's Guide
The compressed practitioner tour. Read the WARMUP for the mechanisms; this is the stuff you say in the meeting.
30-second mental model
The OpenAI Agents SDK is four primitives over one loop. The loop lives in Runner: call the
model → if it asked for tools, run them and feed results back → if it asked to hand off, switch the
active agent → else return the final output; max_turns guards it. Agents are declarative
bundles (instructions + tools + handoffs + guardrails + output_type). Tools are typed Python
functions (@function_tool derives the schema from the signature). Handoffs are
transfer_to_<agent> tools that switch the active agent. Guardrails are cheap tripwire checks
around the agent. Sessions are automatic cross-run memory. Understand the loop and the whole SDK
falls out.
The things to tattoo on your arm
| Thing | The one-liner |
|---|---|
| the loop | model → tools → feed back → repeat → final | max_turns |
@function_tool | schema from the signature; no default ⇒ required |
| trust boundary | model proposes a call; on_invoke_tool executes it |
| tool exception | fed back as an observation (recoverable) |
| unknown tool | ModelBehaviorError (structurally impossible) |
RunResult | final_output, new_items, last_agent |
| handoff | a transfer_to_<agent> tool that switches the active agent |
last_agent | who finished — the specialist after a handoff |
| handoff vs agent-as-tool | control transfers vs control returns |
| guardrail | GuardrailFunctionOutput(output_info, tripwire_triggered) |
| guardrail model | small / fast / cheap — it gates the expensive agent |
| session | pass session=; history in, new items out, automatically |
session_id | a tenant boundary, not just a chat key |
| durability | wrap the loop in Temporal → crash-safe, resumable |
Framework one-liners
- OpenAI Agents SDK =
Agent+Runner(the loop) + handoffs + guardrails + sessions; Python-first, few primitives, built-in tracing. - LangGraph = an explicit
StateGraph(nodes/edges/typed state + reducers, checkpoints, interrupts). Reach for it when you need to see and persist the control flow. - CrewAI = roles + tasks in a crew/process. Reach for it to prototype a role-playing team fast.
- All of them are
while not done: proposal = model(scratchpad); executewith different ergonomics — and they interoperate.
War stories
- The agent that "handed off" but kept answering. Someone used an agent-as-tool (wrapped
Runner.runin a@function_tool) expecting a handoff. Control kept returning to the orchestrator, so the specialist never owned the reply andlast_agentwas always the triage agent. One line — make it a real handoff — fixed the routing. Know which mechanism you're using. - The guardrail that doubled the bill. A team ran their input guardrail on the same big model as the agent "to be accurate." Every request now paid for two big-model calls. Swapping the guardrail to a tiny fast model cut cost back and lost nothing — the guardrail only needed a yes/no.
- The two agents that ping-ponged forever. Triage handed off to billing, billing handed back to
triage, repeat. No
max_turnsacross handoffs, so it burned turns until the timeout. The budget is a guard, and it must count across handoffs, not per agent. - The session that leaked across tenants.
session_idwas the conversation id but not scoped by user, so a shared id surfaced another customer's history.session_idis a security boundary (Phase 13), full stop. - The crash that cost $4. A 12-minute research agent died at minute 10 on a deploy; the in-memory
loop restarted from zero and re-paid for everything. Wrapping the
Runnerin Temporal made every turn a durable step — the restart resumed at minute 10.
Vocabulary
Agent (declarative bundle) · Runner (the loop) · @function_tool (schema from
signature) · on_invoke_tool (the executor) · RunResult (final_output / new_items /
last_agent) · max_turns (loop budget) · Handoff (transfer_to_<agent>, switches agent) ·
agent-as-tool (control returns) · on_handoff / input_filter (handoff knobs) ·
Guardrail / tripwire (tripwire_triggered) · Session (get/add/pop/clear) ·
output_type (structured output) · Tracing (spans) · durable execution (Temporal).
Beginner mistakes
- Thinking the framework runs your tools — it doesn't; the model proposes,
on_invoke_toolruns. - Confusing a handoff (control transfers) with an agent-as-tool (control returns).
- Running guardrails on the expensive model instead of a cheap fast one.
- Forgetting
max_turnscounts across handoffs, so agents can ping-pong. - Treating
session_idas a chat key rather than a tenant/security boundary. - Assuming the in-memory loop is durable — it isn't; long-running agents need Temporal.
- Reaching for the SDK (or LangGraph, or CrewAI) when the task is a workflow with one fuzzy step (Phase 00) — the most senior move is still "this shouldn't be an agent."