Skip to main content
Imagine an agent that knows its limits. When it detects a user needs human support, or another specialist agent, it can gracefully hand off the chat instead of fumbling for an answer.

What You’ll Build

  • A Mastra agent that detects when to escalate.
  • A simple handoff action returning JSON with target user/system.
  • A deployable agent via Mastra’s API.
  • Integration into CometChat, so the chat seamlessly moves to a human.

Prerequisites

  • A Mastra project (npx create-mastra@latest my-mastra-app).
  • Node.js installed.
  • OpenAI API key in .env as OPENAI_API_KEY.
  • A CometChat app with users/roles defined (for live handoff).

Step 1

Define Handoff Action

src/tools/handoff-tool.ts:
import { createTool } from '@mastra/core/tools';
import { z } from 'zod';

export const handoffTool = createTool({
  id: 'handoff',
  description: 'Escalate chat to a specific human or system.',
  inputSchema: z.object({
    target: z.string().describe('User or system to handoff to, e.g., "swapnil" or "support-team"'),
    reason: z.string().describe('Reason for the handoff'),
  }),
  outputSchema: z.object({
    success: z.boolean(),
    message: z.string(),
  }),
  execute: async ({ context }) => {
    // Stub: in production, call CometChat API to reassign chat
    console.log(`Handing off to ${context.target} because ${context.reason}`);
    return { success: true, message: `Conversation handed off to ${context.target}` };
  },
});

Step 2

Create the Agent

src/agents/handoff-agent.ts:
import { openai } from '@ai-sdk/openai';
import { Agent } from '@mastra/core/agent';
import { handoffTool } from '../tools/handoff-tool';

export const handoffAgent = new Agent({
  name: 'Handoff Agent',
  instructions: `
You are a support triage bot. 
- If you cannot answer a question or detect the user needs a human, call the 'handoff' tool. 
- Provide the right target and reason.
- Otherwise, try to answer simply.
  `,
  model: openai('gpt-4o-mini'),
  tools: {
    'handoff': handoffTool,
  },
});

Step 3

Register the Agent in Mastra

src/mastra/index.ts:
import { Mastra } from '@mastra/core/mastra';
import { PinoLogger } from '@mastra/loggers';
import { LibSQLStore } from '@mastra/libsql';

import { handoffAgent } from '../agents/handoff-agent';

export const mastra = new Mastra({
  agents: { 'handoff': handoffAgent }, // API path: /api/agents/handoff/*
  storage: new LibSQLStore({ url: 'file:../mastra.db' }),
  logger: new PinoLogger({ name: 'Mastra', level: 'info' }),
});

Step 4

Run the Agent

rm -rf .mastra/output
npx mastra dev
You should see:
Mastra API running on port http://localhost:4111/api
Test it locally:
curl -X POST http://localhost:4111/api/agents/handoff/generate   -H "Content-Type: application/json"   -d '{"messages":[{"role":"user","content":"I need to speak with Swapnil about my billing issue"}]}'
Expected output:
{
  "success": true,
  "message": "Conversation handed off to Swapnil"
}

Step 5

Deploy & Connect

  • Deploy the API (/api/agents/handoff/generate) using Render, Railway, Vercel, or any host.
  • In CometChat Dashboard → AI Agents, create an agent with:
    • Provider: Mastra
    • Agent ID: handoff
    • Deployment URL: public endpoint from your host
Now users can say “I need human help” and the agent will call the handoff tool to route them.

Troubleshooting

  • Agent doesn’t escalate: Improve instructions with clear escalation rules.
  • Handoff not working: Ensure your tool executes CometChat’s API to transfer conversations.
  • Looping answers: Add a fallback to always call handoff after repeated failed answers.

Next Steps

  • Add logic to choose specific team members (billing, tech support).
  • Connect to external ticketing systems (Zendesk, Freshdesk).
  • Add a coordinator (relay) agent that can ask multiple humans/agents and return the answer.