UNPKG

@tanstack/ai

Version:

Type-safe TypeScript AI SDK for streaming chat, tool calling, agents, structured outputs, and multimodal generation.

90 lines (89 loc) • 3.76 kB
import { boolean, choice } from '../../evaluate/index.js'; import { InferSchemaType, SchemaInput } from '../../../types.js'; import { DefinedAgent } from './define-agent.js'; import { SubagentOrder, SubagentRouterPick } from './spawn.js'; export interface SubagentRouteOptions<TAgents extends ReadonlyArray<DefinedAgent>> { /** * Question text for every agent. The key is the agent name. * Omit this and each question uses that agent's description. */ when?: { [K in TAgents[number]['name']]: string; }; /** * Agents that run after the other selected agents. The lead group starts * together. The `then` agents then run one after another in list order, and * each reads the text so far. Used only when the router picks at least one * agent from each group. Otherwise `pick` returns `{ names, order }`. */ then?: ReadonlyArray<TAgents[number]['name']>; } type RouteQuestions<TAgents extends ReadonlyArray<DefinedAgent>> = { [K in TAgents[number]['name']]: ReturnType<typeof boolean>; } & { order: ReturnType<typeof choice<{ parallel: string; sequence: string; }>>; }; type RouteAnswers<TAgents extends ReadonlyArray<DefinedAgent>> = { [K in TAgents[number]['name']]: { value: boolean; }; } & { order: { value: SubagentOrder; }; }; /** The name and the `inputSchema` of an agent that has one. Else `never`. */ type InputNeed<TAgent> = TAgent extends { name: infer TName; inputSchema?: infer TSchema; } ? TSchema extends SchemaInput ? { name: TName; inputSchema: TSchema; } : never : never; /** One input for each agent with an `inputSchema`, typed from that schema. */ type RouteInputs<TAgents extends ReadonlyArray<DefinedAgent>> = { [TNeed in InputNeed<TAgents[number]> as TNeed['name']]?: InferSchemaType<TNeed['inputSchema']>; }; interface RoutePickOptions<TAgents extends ReadonlyArray<DefinedAgent>> { /** * The input of each picked agent that has an `inputSchema`. The key is the * agent name. `needsInput` lists the agents that need one. An input for an * agent that is not picked is not used. */ inputs?: RouteInputs<TAgents>; } /** * Build `decide()` questions for a subagent router. * * One yes/no question per agent, plus an `order` choice. * `pick` returns `main`, one name, `{ names, order }`, or `{ steps }`. * Names follow the `agents` array order. * `{ names, order }` overrides `subagents.order` for that turn. * `then`: agents that run after the other selected agents. The lead group * starts together. The `then` agents then run one after another in list * order, and each reads the text so far. Used only when the router picks at * least one agent from each group. Otherwise `pick` returns `{ names, order }`. * * An agent with `inputSchema` needs input. `needsInput(result)` lists the * picked agents that need it, with their schemas. Make each input, then pass * them as `pick(result, { inputs })`. Each name with an input becomes * `{ name, input }`. `pick` throws when a picked agent with a schema has no * input. * * @example * ```ts * const route = subagentRoute(agents) * const result = await decide({ adapter, state, questions: route.questions }) * const inputs = { pricer: { sku: 'A-1' } } * return route.pick(result, { inputs }) * ``` */ export declare function subagentRoute<const TAgents extends ReadonlyArray<DefinedAgent>>(agents: TAgents, options?: SubagentRouteOptions<TAgents>): { questions: RouteQuestions<TAgents>; pick: (result: RouteAnswers<TAgents>, pickOptions?: RoutePickOptions<TAgents>) => SubagentRouterPick; needsInput: (result: RouteAnswers<TAgents>) => Array<InputNeed<TAgents[number]>>; }; export {};