Session Handoff

Category: Architecture

Problem

Conversations often need to transfer between agents — a tier-1 bot escalates to a human agent, a general assistant hands off to a specialist, or a user switches devices mid-conversation. Without proper handoff, the receiving agent starts without context, frustrating users.

Architecture

Use Dakera's session API to capture the full context of the outgoing session, then make it available to the incoming agent. The handoff pattern stores a structured summary at session end and provides it as bootstrap context for the new session.

Flow

Implementation

from dakera import Dakera

client = Dakera(base_url="http://localhost:3300", api_key="dk-...")

# --- Source Agent (Bot) ---

# During conversation, store key information
session = client.sessions.start(
    namespace="user-dave",
    metadata={"agent": "tier1-bot", "channel": "chat"}
)

client.memory.store(
    content="User reports billing discrepancy: charged $299 but plan is $199/mo",
    namespace="user-dave",
    metadata={"session_id": session["session_id"], "type": "issue", "importance": 0.9}
)

client.memory.store(
    content="User has been a customer since 2024. Account ID: ACC-4521.",
    namespace="user-dave",
    metadata={"session_id": session["session_id"], "type": "context", "importance": 0.8}
)

# Handoff triggered — store handoff summary
client.memory.store(
    content="HANDOFF SUMMARY: Customer ACC-4521 (since 2024) reports $100 billing overcharge. "
            "Verified plan is $199/mo but last invoice shows $299. "
            "Customer tone: frustrated but polite. Needs refund or explanation.",
    namespace="user-dave",
    metadata={
        "session_id": session["session_id"],
        "type": "handoff",
        "from_agent": "tier1-bot",
        "to_agent": "billing-specialist",
        "importance": 1.0
    }
)

# End source session
client.sessions.end(session_id=session["session_id"])

# --- Target Agent (Billing Specialist) ---

# Start new session
new_session = client.sessions.start(
    namespace="user-dave",
    metadata={"agent": "billing-specialist", "channel": "chat"}
)

# Recall handoff context
handoff = client.memory.recall(
    query="handoff summary billing issue",
    namespace="user-dave",
    top_k=3
)

# Target agent now has full context:
# - The billing discrepancy ($299 vs $199)
# - Account details (ACC-4521, customer since 2024)
# - Customer sentiment (frustrated but polite)
# - What action is needed (refund or explanation)

Inter-Agent Handoff (Specialist Routing)

import { Dakera } from 'dakera';

const client = new Dakera({
  baseUrl: 'http://localhost:3300',
  apiKey: 'dk-...'
});

async function handoffToSpecialist(
  userId: string,
  currentSessionId: string,
  targetAgent: string,
  reason: string
) {
  // Store structured handoff
  await client.memory.store({
    content: `HANDOFF to ${targetAgent}: ${reason}`,
    namespace: `user-${userId}`,
    metadata: {
      session_id: currentSessionId,
      type: 'handoff',
      to_agent: targetAgent,
      importance: 1.0
    }
  });

  // End current session
  await client.sessions.end({ sessionId: currentSessionId });

  // Start new session for target agent
  const newSession = await client.sessions.start({
    namespace: `user-${userId}`,
    metadata: { agent: targetAgent }
  });

  // Bootstrap target agent with relevant context
  const context = await client.memory.recall({
    query: `handoff ${targetAgent}`,
    namespace: `user-${userId}`,
    topK: 5
  });

  return { session: newSession, context: context.results };
}

When to Use This Pattern

Key Considerations