By Sagar Shankaran, Founder of CallSphere
Learn how to share sessions across multiple AI agents in the OpenAI Agents SDK for context continuity, handoff-aware patterns, and building multi-agent support systems.
Key takeaways
In multi-agent systems, different agents specialize in different tasks. A triage agent routes requests, a billing agent handles payment issues, and a technical support agent solves product problems. When a user is handed off from one agent to another, the receiving agent needs to know what happened before — what the user said, what was tried, and what the outcome was.
Without shared sessions, each agent starts blind. The user has to repeat their problem, and the agent has no context about prior attempts. This creates a frustrating experience and wastes both time and tokens.
The simplest form of session sharing is using the same session_id when running different agents. Since sessions are stored by ID, any agent that references the same ID sees the same history.
flowchart LR
INPUT(["User intent"])
PARSE["Parse plus<br/>classify"]
PLAN["Plan and tool<br/>selection"]
AGENT["Agent loop<br/>LLM plus tools"]
GUARD{"Guardrails<br/>and policy"}
EXEC["Execute and<br/>verify result"]
OBS[("Trace and metrics")]
OUT(["Outcome plus<br/>next action"])
INPUT --> PARSE --> PLAN --> AGENT --> GUARD
GUARD -->|Pass| EXEC --> OUT
GUARD -->|Fail| AGENT
AGENT --> OBS
style AGENT fill:#4f46e5,stroke:#4338ca,color:#fff
style GUARD fill:#f59e0b,stroke:#d97706,color:#1f2937
style OBS fill:#ede9fe,stroke:#7c3aed,color:#1e1b4b
style OUT fill:#059669,stroke:#047857,color:#fff
from agents import Agent, Runner
from agents.extensions.sessions import SQLiteSession
session = SQLiteSession(db_path="./shared_sessions.db")
# Two specialized agents
greeter = Agent(
name="Greeter",
instructions="You warmly greet users and ask how you can help today.",
)
helper = Agent(
name="Helper",
instructions="""You are a knowledgeable assistant. You can see the full
conversation history including what the Greeter discussed with the user.
Continue naturally from where the conversation left off.""",
)
async def demo():
sid = "user-session-001"
# Greeter handles the initial interaction
result = await Runner.run(
greeter, "Hi there!", session=session, session_id=sid
)
print(f"Greeter: {result.final_output}")
# User responds
result = await Runner.run(
greeter, "I need help with my billing.", session=session, session_id=sid
)
print(f"Greeter: {result.final_output}")
# Handoff to Helper — same session_id, sees full history
result = await Runner.run(
helper,
"I was transferred here for billing help.",
session=session,
session_id=sid,
)
print(f"Helper: {result.final_output}")
# Helper sees the greeting exchange and knows the user needs billing help
The Helper agent sees the entire conversation with the Greeter because they share the same session ID.
Hear it before you finish reading
Talk to a live CallSphere AI voice agent in your browser — 60 seconds, no signup.
For context continuity to work well, agents need clear instructions about how to interpret shared history. The history will contain turns from different agents, and each agent should understand its role in the sequence.
triage_agent = Agent(
name="TriageAgent",
instructions="""You are the triage agent. Your job is to understand the
user's problem and categorize it. Ask clarifying questions if needed.
When you have enough context, indicate the category clearly:
- BILLING for payment and subscription issues
- TECHNICAL for product bugs and how-to questions
- ACCOUNT for login, password, and profile issues""",
)
billing_agent = Agent(
name="BillingAgent",
instructions="""You are the billing specialist. The conversation history
may contain messages from the TriageAgent who categorized this as a
billing issue. Review the full history to understand the user's problem
without asking them to repeat information. Resolve billing issues
directly using the tools available to you.""",
)
technical_agent = Agent(
name="TechnicalAgent",
instructions="""You are the technical support specialist. Review the full
conversation history — the TriageAgent has already gathered initial
context. Pick up where they left off and solve the technical issue.
Never ask the user to repeat information that is already in the history.""",
)
async def handle_support_request(session_id: str, message: str, current_agent: str):
"""Route to the appropriate agent while maintaining session continuity."""
agents = {
"triage": triage_agent,
"billing": billing_agent,
"technical": technical_agent,
}
agent = agents[current_agent]
result = await Runner.run(
agent, message, session=session, session_id=session_id
)
# Check if triage agent wants to hand off
output = result.final_output.upper()
if current_agent == "triage":
if "BILLING" in output:
return result.final_output, "billing"
elif "TECHNICAL" in output:
return result.final_output, "technical"
return result.final_output, current_agent
The OpenAI Agents SDK has built-in handoff support. When combining handoffs with shared sessions, the receiving agent automatically gets the full context.
from agents import Agent, Runner, handoff
billing_agent = Agent(
name="BillingAgent",
instructions="Handle billing inquiries. You have full conversation context.",
)
technical_agent = Agent(
name="TechnicalAgent",
instructions="Handle technical issues. You have full conversation context.",
)
triage_agent = Agent(
name="TriageAgent",
instructions="""Understand the user's issue and hand off to the right specialist.
Use the transfer_to_billing or transfer_to_technical tools.""",
handoffs=[
handoff(billing_agent, tool_name="transfer_to_billing",
tool_description="Transfer to billing for payment issues"),
handoff(technical_agent, tool_name="transfer_to_technical",
tool_description="Transfer to technical for product issues"),
],
)
async def support_flow(session_id: str, message: str):
result = await Runner.run(
triage_agent,
message,
session=session,
session_id=session_id,
)
# If a handoff occurred, result.last_agent is the target agent
print(f"Handled by: {result.last_agent.name}")
print(f"Response: {result.final_output}")
return result
When a handoff occurs, the target agent receives the full session history including all turns with the triage agent. The transition is seamless.
Here is a complete multi-agent support system with session sharing, handoffs, and escalation:
Still reading? Stop comparing — try CallSphere live.
CallSphere ships complete AI voice agents per industry — 14 tools for healthcare, 10 agents for real estate, 4 specialists for salons. See how it actually handles a call before you book a demo.
import asyncio
from agents import Agent, Runner, handoff
from agents.extensions.sessions import SQLiteSession, SessionSettings
session = SQLiteSession(db_path="./support_system.db")
settings = SessionSettings(limit=50)
# Level 1: Automated support
l1_billing = Agent(
name="L1Billing",
instructions="""You handle routine billing questions: checking balances,
explaining charges, updating payment methods. If the issue requires
a refund over $50 or involves a disputed charge, escalate to L2.""",
handoffs=[], # Will be set after L2 is defined
)
l1_technical = Agent(
name="L1Technical",
instructions="""You handle common technical issues: password resets,
basic troubleshooting, feature explanations. If the issue requires
backend investigation or is a confirmed bug, escalate to L2.""",
handoffs=[],
)
# Level 2: Senior support (has more tools and authority)
l2_support = Agent(
name="L2Support",
instructions="""You are a senior support agent. You handle escalated issues
that L1 agents cannot resolve. Review the FULL conversation history to
understand what has already been tried. Never ask the user to repeat
steps that are documented in the history.
You can issue refunds, file bug reports, and make account changes.
If you cannot resolve the issue, create a ticket for engineering.""",
)
# Configure handoffs after all agents are defined
l1_billing.handoffs = [
handoff(l2_support, tool_name="escalate_to_senior",
tool_description="Escalate to senior support for complex billing issues"),
]
l1_technical.handoffs = [
handoff(l2_support, tool_name="escalate_to_senior",
tool_description="Escalate to senior support for complex technical issues"),
]
# Triage agent
triage = Agent(
name="Triage",
instructions="""Greet the user and understand their issue.
Route to billing for payment/subscription issues.
Route to technical for product/feature issues.""",
handoffs=[
handoff(l1_billing, tool_name="route_to_billing",
tool_description="Route to billing support"),
handoff(l1_technical, tool_name="route_to_technical",
tool_description="Route to technical support"),
],
)
async def support_conversation():
sid = "ticket-2026-0314-001"
messages = [
"Hi, I was charged twice for my subscription this month.",
"Yes, I can see two charges of $29.99 on March 1st and March 3rd.",
"I'd like a refund for the duplicate charge.",
"The amount is $29.99 — can you process that?",
]
current_agent = triage
for msg in messages:
print(f"\nUser: {msg}")
result = await Runner.run(
current_agent, msg, session=session,
session_id=sid, session_settings=settings,
)
current_agent = result.last_agent
print(f"{current_agent.name}: {result.final_output}")
asyncio.run(support_conversation())
session_id.SessionSettings(limit=50) prevents unbounded history growth.Do not create separate sessions per agent. If each agent gets its own session_id, context is lost during handoffs. Always use one session_id per user conversation, regardless of how many agents participate.
Do not include agent-specific state in the session. Sessions store conversation items (user messages and assistant responses). If you need agent-specific metadata (internal routing decisions, confidence scores), store that in a separate data store keyed by session_id.
Do not assume history ordering. In concurrent multi-agent systems, items might be added by different agents simultaneously. Design your session backend to handle concurrent writes safely, and rely on item_order rather than timestamps.
Sources:

Written by
Sagar Shankaran· Founder, CallSphere
LinkedInSagar Shankaran is the founder of CallSphere, where he builds production AI voice and chat agents deployed across healthcare, hospitality, real estate, and home services. He writes about agentic AI, LLM engineering, and shipping voice agents that handle real calls in production.
See how AI voice agents work for your industry. Live demo available -- no signup required.
OpenAI's Frontier platform makes model-native orchestration the default. What that means for agent builders, voice/chat buyers, and the build-vs-buy decision.
How to design a multi-agent system using MCP for tools and A2A for cross-vendor coordination, with a CallSphere voice agent as a participating node.
The 2026 desktop AI agent landscape — ServiceNow Project Arc, Anthropic Claude offerings, OpenAI agents, and Google Mariner. A buyer's map.
May 2026's biggest agent-architecture shift: planning, tool selection, and self-correction move inside the model. Framework code shrinks. Here is what changes.
A three-way comparison of Gemini Enterprise, Anthropic managed agents and OpenAI Frontier Platform after Cloud Next 2026 — strengths, gaps, buyer fit.
A2A is the open standard for agent-to-agent coordination. Here is how the Agent Card JSON works, how discovery happens, and what to publish.
© 2026 CallSphere Inc. All rights reserved.
Made within San Francisco