Curriculum/Agent Architectures
Handoff Is a First-Class Stop
Unknown, unsafe, or over-budget work goes to a human or another system with a packet, not a shrug.
Handoff is not a crash. It is a stop with a packet:
- Why (unknown intent, policy, budget, parse fail, thrash, circuit, banned click)
- What you tried (trace ids, tool names)
- Frozen args if a tool was pending
- What the human should do next (one form, not a novel)
Why, what you tried, any frozen args. A shrug is how tickets die.
Handoff is a packetThe user-facing message is short. The operator packet is complete. A shrug (“ask a human”) is how tickets die. The model’s chain of thought as the ticket body is how tickets become unread novels. A new infinite agent as the destination is how you recurse the furnace.
Unknown, unsafe, or over-budget work goes to a human or another system with a packet. Wire handoff to the same queue as HITL. Waiting_human has a pending tool. Handoff may not. Same inbox. Same run_id.
Why is an enum
Use a small set: unknown_intent, policy, budget, parse_fail, thrash, circuit_open, banned_click, guard_failed. The router’s unknown kind is unknown_intent. Amount over cap is policy. Operators filter. Models writing a paragraph why is extra; keep the enum as the field that matters.
Do not use crash in the user message. The user is not blocked on a stack trace. They are waiting on a person. The live box’s user_msg says that. “crash” in the user string is a test that should be false.
Tried
List what you tried: router, search, search (thrash will also fire). Trace ids beat dumping rows into the ticket. The packet points at the movie. The operator opens the trace. If tried is empty, you handed off before the loop — still valid for unknown_intent at the router.
Pending freeze
If a tool was pending (HITL-ish policy handoff), include frozen args. Deny/approve can proceed. If there is no pending tool, pending is None. Do not invent a refund to attach. Do not drop a real freeze because the why was budget.
Next action is a form
“Refund 40 on 99, approve or deny” is a next action. “Please look into this” is a shrug. One form. Buttons. Not “write the next ReAct thought.” HITL lesson again. Handoff without a form still needs a why and a tried so the human can make a form.
Destinations
Default destination: human queue. Next track: another specialist, still with a packet, still with a stop. Do not start a second unbounded loop as the handoff. Packet in, specialist runs with its own budget, packet out. If you cannot name the destination, it is humans.
Do not handoff to computer use as a promotion. Do not handoff to exec. Do not handoff to “be clever.”
First-class in stop
should_stop already returned handoff. Honor it. Persist the packet on the job. Wake_when is human:queue. The loop is done until a person (or a later specialist) resumes. That is success of control, not success of the user goal. Do not mark the user goal done.
Packet shape, user copy, and resume
A packet is JSON you can store: stop, why, tried, pending, run_id, step, user_msg, maybe next_form (fields the human should fill). tried is a short list of names or step ids, not the full TRACE array. Link the trace. Pending is the freeze object or null. If you embed the live args dict, you failed freeze-payload again — copy.
User copy is one or two sentences: a person will take this; you are not blocked on the model. No stack traces. No “the AI crashed.” No chain of thought. Operators get why plus tried plus a button.
Resume from handoff is not always execute. Unknown_intent resume might be a human-typed kind (billing) that re-enters the router with a human decision, not a model guess. Policy resume might be deny (stop) or approve (HITL path). Budget resume might be “raise cap” by an operator flag — that flag is a product choice, not the model asking for one more search. Default: do not raise caps from the packet without a person.
Do not chain handoff to a new agent with no budget. Do not chain to computer use. Do not chain to exec. Next track’s specialist destination still receives this packet and still stops. If the destination cannot honor stop, it is not a destination.
Handoff is how the router’s poem path, the breaker’s open circuit, the thrash cap, and the banned Pay cell all leave the loop honestly.
The packet is a stop you can count. Traces get stop: handoff plus why. Support gets the short user_msg. Billing ops gets the form. If any of those three documents is missing, you will either leak thoughts to customers or starve operators. Build the three from one function, like the live box, and persist it on the job row next to wake_when.
Common mistakes
- User message says crash.
- Thought dump as the ticket.
- No why enum.
- Dropping frozen args.
- Destination = new infinite agent.
- Shrug with no tried.
Run to execute this in your browser. Nothing is sent to a server.
Unknown intent hands off with no pending tool. Policy handoff keeps frozen refund args. The user message does not say “crash.” The last print is False. tried is copied so later mutation of the caller’s list does not rewrite the packet — same instinct as freeze.
Stop is the string handoff, a first-class reason next to success and budget. Count it in traces.
How agents use this
Wire handoff to the same queue as HITL. Multiagent (next track) is another destination: another specialist, still with a packet, still with a stop.
When-not-to-agent is next: sometimes you should not have started this loop. Handoff is how you leave a loop you should not finish. Not starting is cheaper.
Check your understanding