Skip to content
Blog

Handoff Design: Passing State and Control Between Agents

A deep dive into agent handoff patterns — how to pass state and control between agents cleanly, with SDK implementations and failure mode analysis.

Published on September 9, 2026

AI Assistant

Handoff Design: Passing State and Control Between Agents

The handoff is the hardest part of multi-agent systems. The agent that understands billing hands off to the agent that handles refunds — and somehow, critical context gets lost. The customer repeats themselves. The refund agent doesn’t know what billing already verified. The user experience falls apart.

Why Handoffs Fail

Most agent frameworks expose “start” and “kill” as first-class controls. Pause, resume, and cancel are afterthoughts. Without a proper interruption and handoff surface, autonomous loops produce a binary “let it finish or lose everything” experience that destroys user trust.

Three Handoff Patterns

Sequential Handoff

Agent A completes its task, packages results, and passes a structured packet to Agent B. Simple, predictable, but creates latency when Agent B needs Agent A’s intermediate reasoning.

Agent A (billing) → HandoffPacket → Agent B (refund)

Shared-Context Handoff

Both agents read from a shared state store. Agent A writes its findings; Agent B picks up where A left off without waiting for a full handoff.

# Shared context via state store
context = {
    "customer_id": "cust_123",
    "billing_verified": True,
    "refund_amount": 50.00,
    "reason": "duplicate_charge"
}

Supervisor-Routed Handoff

A supervisor agent decides which specialist should handle each step, maintaining full context and routing dynamically.

The Handoff Contract

What to pass in a handoff:

FieldPurpose
context_summaryWhat was done, what remains
customer_stateVerified facts, pending items
decision_trailWhy specific actions were taken
tool_cachePre-fetched data for the next agent
provenanceWhich agent produced each piece of info

What NOT to pass:

  • Raw conversation history (noise)
  • Internal reasoning traces (confuse the next agent)
  • Credentials or secrets

OpenAI Agents SDK Implementation

from agents import Agent, handoff

billing_agent = Agent(
    name="billing_specialist",
    instructions="Verify billing issues and resolve payment problems.",
)

refund_agent = Agent(
    name="refund_specialist",
    instructions="Process refunds based on verified billing information.",
)

triage_agent = Agent(
    name="triage",
    instructions="Route customers to the right specialist.",
    handoffs=[billing_agent, refund_agent],
)

Input Filtering for Handoffs

Control what context travels with the handoff:

from agents import handoff, HandoffInputFilter

class BillingToRefundFilter(HandoffInputFilter):
    def filter(self, input_data):
        # Only pass verified facts, not raw messages
        return {
            "customer_id": input_data.get("customer_id"),
            "billing_verified": input_data.get("billing_verified"),
            "refund_amount": input_data.get("refund_amount"),
        }

handoff(
    agent=refund_agent,
    input_type=RefundRequest,
    input_filter=BillingToRefundFilter(),
)

Common Failure Modes

Context Bleed — Agent B sees Agent A’s internal reasoning and gets confused about what’s been communicated to the user.

State Staleness — Agent B acts on data that Agent A modified after the handoff packet was created.

Circular Delegation — Agent A hands to Agent B, which hands back to Agent A, creating an infinite loop.

Lost Tool Results — Agent A fetched data with a tool call, but the result doesn’t travel with the handoff.

Premature Handoff — Triage agent routes too early before the specialist has enough context to help.

Framework Comparison

FrameworkHandoff PrimitiveContext Passing
OpenAI Agents SDKhandoff() + input_filterRunState serialization
LangGraphCommand.PARENT + subgraphsCheckpointer state
PydanticAIAgent delegationTyped context objects
CrewAIProcess orchestrationShared task context

When Handoffs Are the Wrong Tool

Not every handoff is necessary. Consider:

  • Tool use instead — If the agent just needs data from another system, use a tool call, not a handoff
  • Sub-agent instead — If the sub-task is well-defined and returns a result, use Agent.as_tool()
  • Single agent with tools — If one agent can handle everything with the right tools, avoid the handoff complexity

The Takeaway

Handoffs are necessary when different agents own different parts of a workflow, but they’re expensive in context and complexity. Use them sparingly, define a clear contract for what travels, and always test the “user repeated themselves” scenario.

💡 Start with handoff() in the OpenAI Agents SDK and input_filter to control what context crosses agent boundaries.