Skip to main content
Many agent systems need a router that decides which specialist agent should handle a request. Restate makes these routing decisions durable: if the process crashes after the LLM picks an agent but before that agent responds, recovery skips the routing step and resumes the agent call.

How it works

  1. A router agent receives the request
  2. An LLM decides which specialist to delegate to (persisted as a durable step)
  3. The specialist agent processes the request
  4. The router returns the result
Routing decisions, agent calls, and results are all recorded in the journal.

Example: routing to specialist agents

Define specialist agents within the same process. The LLM picks the right one, and Restate ensures the decision sticks.
With the Vercel AI, specialist agents are exposed as tools. The LLM decides which tool to call, and Restate durably persists the routing decision.
multi-agent.ts
async function runEligibilityAgent(model: LanguageModel, claim: InsuranceClaim){
  const { text } = await generateText({
    model,
    system:
        "Decide whether the following claim is eligible for reimbursement." +
        "Respond with eligible if it's a medical claim, and not eligible otherwise.",
    prompt: JSON.stringify(claim),
  });
  return text;
}

async function runFraudAgent(model: LanguageModel, claim: InsuranceClaim){
  const { text } = await generateText({
    model,
    system:
        "Decide whether the claim is fraudulent." +
        "Always respond with low risk, medium risk, or high risk.",
    prompt: JSON.stringify(claim),
  });
  return text;
}

const run = async (ctx: restate.Context, claim: ClaimInput) => {
  const model = wrapLanguageModel({
    model: openai("gpt-5.4"),
    middleware: durableCalls(ctx, { maxRetryAttempts: 3 }),
  });

  const { text } = await generateText({
    model,
    prompt: `Claim: ${JSON.stringify(claim)}`,
    system:
      "Analyze the insurance claim and use your tools to decide whether to approve.",
    tools: {
      analyzeEligibility: tool({
        description: "Analyze claim eligibility.",
        inputSchema: InsuranceClaimSchema,
        execute: async (claim: InsuranceClaim) => runEligibilityAgent(model, claim),
      }),
      analyzeFraud: tool({
        description: "Analyze probability of fraud.",
        inputSchema: InsuranceClaimSchema,
        execute: async (claim: InsuranceClaim) => runFraudAgent(model, claim),
      }),
    },
    stopWhen: [stepCountIs(10)],
    providerOptions: { openai: { parallelToolCalls: false } },
  });

  return text;
};
Install Restate and launch it:
npm install --global @restatedev/restate-server@latest @restatedev/restate@latest
restate-server
Get the example:
restate example typescript-vercel-ai-tour-of-agents && cd typescript-vercel-ai-tour-of-agents
npm install
Export your OpenAI API key and run the agent:
export OPENAI_API_KEY=sk-...
npx tsx ./src/multi-agent.ts
Register the agents with Restate:
restate deployments register http://localhost:9080 --force --yes # dev only: overrides previous registrations
Start a request for a claim that needs to be analyzed by multiple agents:
curl localhost:8080/restate/call/MultiAgentClaimApproval/run --json '{
    "date":"2024-10-01",
    "category":"orthopedic",
    "reason":"hospital bill for a broken leg",
    "amount":3000,
    "placeOfService":"General Hospital"
}'
In the UI, in the LLM responses, you can see that the agent called the sub-agents via tools.

Handing off to remote agents

When agents need to scale independently, run on different platforms, or be developed by different teams, you can deploy them as separate Restate services. Restate makes cross-service calls look like local function calls while providing end-to-end durability and failure recovery. See the guide on calling remote agents implementation guide for full examples of remote agent routing.