Handoffs
Handoffs allow an agent to transfer control of a conversation to another agent. This is fundamental for building multi-agent systems where specialized agents handle different parts of a complex workflow.
The Go SDK provides a type-safe, declarative API for configuring handoffs that matches the capabilities of the Python SDK.
Basic Usage
The simplest way to create a handoff is to use handoff.New() with a target agent. This automatically generates a tool that, when called by the model, transfers control to that agent.
import (
"github.com/MitulShah1/openai-agents-go/handoff"
"github.com/MitulShah1/openai-agents-go"
)
// Create agents
triageAgent := agents.NewAgent("Triage")
supportAgent := agents.NewAgent("Support")
// Create a handoff tool
// By default, this creates a tool named "transfer_to_support"
transferToSupport := handoff.New(supportAgent).ToTool()
// Register the tool with the source agent
triageAgent.Tools = []tools.Tool{transferToSupport}
Configuration Options
The handoff.New() function accepts functional options to customize behavior.
Custom Tool Name and Description
You can override the automatically generated tool name and description to better guide the model on when to use the handoff.
transfer := handoff.New(
billingAgent,
handoff.WithToolName("escalate_payment_issue"),
handoff.WithDescription("Use this when the user has a problem with a credit card charge."),
).ToTool()
Input Filtering
Input filters allow you to inspect or modify the conversation state before the handoff occurs. This is useful for redacting sensitive data, adding context variables, or validation.
filter := func(ctx context.Context, data handoff.InputData) (handoff.InputData, error) {
// Add a context variable for the next agent
data.ContextVars["referring_agent"] = "triage"
return data, nil
}
transfer := handoff.New(
salesAgent,
handoff.WithInputFilter(filter),
).ToTool()
History Nesting (Summarization)
By default, the entire conversation history is passed to the next agent. For long conversations, this can consume many tokens. History nesting summarizes the conversation history into a single message for the next agent.
transfer := handoff.New(
archiveAgent,
handoff.WithHistoryNesting(true), // Content will be summarized
).ToTool()
Dynamic Enablement
You can control when a handoff is available using a predicate function. This is evaluated at runtime.
// Only allow handoff during business hours
predicate := func(ctx context.Context, agent *agents.Agent, vars agents.ContextVariables) (bool, error) {
hour := time.Now().Hour()
return hour >= 9 && hour < 17, nil
}
transfer := handoff.New(
liveAgent,
handoff.WithEnabledPredicate(predicate),
).ToTool()
Advanced Patterns
Context Variables
Handoffs preserve ContextVariables. Any variables set by previous agents are available to the target agent.
// In Agent A
ctxVars["customer_id"] = "123"
// ... handoff to Agent B ...
// In Agent B
id := ctxVars["customer_id"] // "123"
Multi-Hop Handoffs
Agents can hand off to other agents that can, in turn, hand off again. The SDK manages the call stack and history automatically.
API Reference
See the GoDoc for the full API reference.