Skip to content

Routers

The purpose of a Network’s Router is to decide what Agent to call based off the current Network State.

A router is a function that gets called after each agent runs, which decides whether to:

  1. Call another agent (by returning an Agent)
  2. Stop the network’s execution loop (by returning undefined)

The routing function gets access to everything it needs to make this decision:

  • The Network object itself, including it’s State.
  • The stack of Agents to be called.
  • The number of times the Network has called Agents (the number of iterations).
  • The result from the previously called Agent in the Network’s execution loop.

For more information about the role of a Router in a Network, read about how Networks work.

Providing a custom Router to your Network can be achieved using 3 different patterns:

  • Writing a custom Code-based Router: Define a function that makes decisions based on the current State.
  • Creating a Routing Agent: Leverages LLM calls to decide which Agents should be called next based on the current State.
  • Writing a custom Hybrid Router: Mix code and agent-based routing to get the best of both worlds.

Custom Routers can be provided by defining a defaultRouter function returning either an instance of an Agent object or undefined.

import { createNetwork } from "@inngest/agent-kit";
// classifier and writer Agents definition...
const network = createNetwork({
agents: [classifier, writer],
router: ({ lastResult, callCount }) => {
// retrieve the last message from the output
const lastMessage = lastResult?.output[lastResult?.output.length - 1];
const content =
lastMessage?.type === "text" ? (lastMessage?.content as string) : "";
// First call: use the classifier
if (callCount === 0) {
return classifier;
}
// Second call: if it's a question, use the writer
if (callCount === 1 && content.includes("question")) {
return writer;
}
// Otherwise, we're done!
return undefined;
},
});

The defaultRouter function receives a number of arguments:

interface RouterArgs {
network: Network; // The entire network, including the state and history
stack: Agent[]; // Future agents to be called
callCount: number; // Number of times the Network has called agents
lastResult?: InferenceResult; // The the previously called Agent's result
}

The available arguments can be used to build the routing patterns described below.

  • Start simple with code-based routing for predictable behavior, then add agent-based routing for flexibility.
  • Remember that routers can access the network’s state
  • You can return agents that weren’t in the original network
  • The router runs after each agent call
  • Returning undefined stops the network’s execution loop

That’s it! Routing is what makes networks powerful - it lets you build workflows that can be as simple or complex as you need.

The simplest way to route is to write code that makes decisions. Here’s an example that routes between a classifier and a writer:

import { createNetwork } from "@inngest/agent-kit";
// classifier and writer Agents definition...
const network = createNetwork({
agents: [classifier, writer],
router: ({ lastResult, callCount }) => {
// retrieve the last message from the output
const lastMessage = lastResult?.output[lastResult?.output.length - 1];
const content =
lastMessage?.type === "text" ? (lastMessage?.content as string) : "";
// First call: use the classifier
if (callCount === 0) {
return classifier;
}
// Second call: if it's a question, use the writer
if (callCount === 1 && content.includes("question")) {
return writer;
}
// Otherwise, we're done!
return undefined;
},
});

Code-based routing is great when you want deterministic, predictable behavior. It’s also the fastest option since there’s no LLM calls involved.

Without a defaultRouter defined, the network will use the “Default Routing Agent” to decide which agent to call next. The “Default Routing Agent” is a Routing Agent provided by Agent Kit to handle the default routing logic.

You can create your own Routing Agent by using the createRoutingAgent helper function:

import { createRoutingAgent } from "@inngest/agent-kit";
const routingAgent = createRoutingAgent({
name: "Custom routing agent",
description: "Selects agents based on the current state and request",
lifecycle: {
onRoute: ({ result, network }) => {
// custom logic...
},
},
});
// classifier and writer Agents definition...
const network = createNetwork({
agents: [classifier, writer],
router: routingAgent,
});

Hybrid code and agent Routers (semi-supervised routing)

Section titled “Hybrid code and agent Routers (semi-supervised routing)”

And, of course, you can mix code and agent-based routing. Here’s an example that uses code for the first step, then lets an agent take over:

import { createNetwork, getDefaultRoutingAgent } from "@inngest/agent-kit";
// classifier and writer Agents definition...
const network = createNetwork({
agents: [classifier, writer],
router: ({ callCount }) => {
// Always start with the classifier
if (callCount === 0) {
return classifier;
}
// Then let the routing agent take over
return getDefaultRoutingAgent();
},
});

This gives you the best of both worlds:

  • Predictable first steps when you know what needs to happen
  • Flexibility when the path forward isn’t clear

The router is the brain of your network - it decides which agent to call next. You can use state to make smart routing decisions:

import { createNetwork } from '@inngest/agent-kit';
// mathAgent and contextAgent Agents definition...
const network = createNetwork({
agents: [mathAgent, contextAgent],
router: ({ network, lastResult }): Agent | undefined => {
// Check if we've solved the problem
const solution = network.state.data.solution;
if (solution) {
// We're done - return undefined to stop the network
return undefined;
}
// retrieve the last message from the output
const lastMessage = lastResult?.output[lastResult?.output.length - 1];
const content = lastMessage?.type === 'text' ? lastMessage?.content as string : '';
// Check the last result to decide what to do next
if (content.includes('need more context')) {
return contextAgent;
}
return mathAgent;
};
});