workflows/route

Source: src/workflows/route.ts

route: 1 → 1. A classifier agent picks who should do the work.

pickDestination

function

export function pickDestination(output: string, destinations: readonly Agent[]): Agent | undefined { /* … */ }

Reads a destination out of whatever the classifier actually wrote.

The input here is a language model, not a caller, so this is lenient on purpose - and only here. It tries, in order: the whole answer as a name, the last non-empty line, then the first name mentioned anywhere. Matching is on whole words, so coder never matches inside decoder.

Ambiguity is refused rather than guessed: an answer naming two destinations on its last line resolves to nothing, and the caller sees what was said.

route

function

export async function route(options: RouteOptions): Promise<RouteResult> { /* … */ }

Classifies a task, then hands it to the destination that was picked.

The classifier reads the destinations’ descriptions - the field pi already makes mandatory - so routing needs no second vocabulary to maintain. Write a description that says when to pick that agent and routing works; write a vague one and no parser will save it.

An unroutable task is a Result, not a throw. A classifier that answers with prose, or names an agent that does not exist, is a model failure like any other: with a fallback the work still happens, without one the caller gets ok: false and the classifier’s actual answer to look at. What never happens is a silent pick of the first destination.

RouteOptions

type

export type RouteOptions = WorkflowOptions & {
	/** The agent that classifies. It sees the destinations, never the work. */
	router: Agent;
	/** Where the task may go. Their `description` is what the classifier reads. */
	destinations: Agent[];
	/** The work to route. The classifier is asked about it; only the destination does it. */
	input: string;
	/** Taken when the classifier names nothing recognisable. */
	fallback?: Agent;
	/** Overrides how the classifier's answer is read. See {@link pickDestination}. */
	parse?: (output: string, destinations: readonly Agent[]) => Agent | undefined;
	/** Overrides the question put to the classifier. See {@link routingPrompt}. */
	format?: (input: string, destinations: readonly Agent[]) => string;
};

The classifier, the agents it may pick from, and what to do when it picks nobody.

RouteResult

type

export type RouteResult = WorkflowResult & {
	/** Who was chosen, or `undefined` when nothing was. */
	destination?: Agent;
	/** The classifier's own turn, kept even when the routing failed. */
	routing: Result;
};

The destination’s result, plus who was picked and how.

routingPrompt

function

export function routingPrompt(input: string, destinations: readonly Agent[]): string { /* … */ }

The question put to the classifier: the destinations, then the task.

It asks for the name alone. That is a hint, not a contract - {@link pickDestination} is what actually makes the answer usable.