UNPKG

@tanstack/ai

Version:

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

125 lines (124 loc) • 5.87 kB
import { EventType, Interrupt, ModelMessage, RunAgentResumeItem, StreamChunk, TokenUsage, Tool, UIMessage } from '../../../types.js'; import { SpecTokenUsage } from '../../../utilities/ag-ui-usage.js'; import { DefinedAgent, SubagentRunContext } from './define-agent.js'; import { ChatMiddleware } from '../middleware/types.js'; import { SubagentTurn } from './turn.js'; export declare const SUBAGENT_STARTED = EventType.SUBAGENT_STARTED; export declare const SUBAGENT_FINISHED = EventType.SUBAGENT_FINISHED; export declare const SUBAGENT_ERROR = EventType.SUBAGENT_ERROR; export type SubagentOrder = 'parallel' | 'sequence'; export interface SubagentRouterPlan { names: ReadonlyArray<string>; /** Overrides `subagents.order` for this turn. */ order?: SubagentOrder; } export interface SubagentStep { names: ReadonlyArray<string>; /** Overrides `subagents.order` for this step. */ order?: SubagentOrder; } export interface SubagentStepsPlan { steps: ReadonlyArray<SubagentStep>; } export type SubagentRouterPick = 'main' | string | ReadonlyArray<string> | SubagentRouterPlan | SubagentStepsPlan; export interface SubagentsBag<TAgents extends ReadonlyArray<DefinedAgent> = ReadonlyArray<DefinedAgent>> { agents: TAgents; router?: (ctx: { messages: SubagentRunContext['messages']; agents: NoInfer<TAgents>; abortSignal?: AbortSignal; }) => SubagentRouterPick | Promise<SubagentRouterPick>; strategy?: 'exclusive' | 'handoff'; /** * How a router list runs. `parallel` starts every name together. * `sequence` runs each name after the previous one finishes, and passes * that child's text to the next child. */ order?: 'parallel' | 'sequence'; sandbox?: 'own' | 'inherit'; } /** What the children of one parent run left behind for the parent terminal. */ export interface SubagentSink { interrupts: Array<Interrupt>; /** One AG-UI entry per child model call. */ usage: Array<SpecTokenUsage>; /** Summed full usage of the children, including cost. */ total?: TokenUsage; } export declare function createSubagentSink(): SubagentSink; /** One child to start, or a suspended child to continue. */ export interface SpawnEntry { name: string; resume?: { subagentRunId: string; /** The child's own messages from the interrupted run. */ messages: Array<UIMessage | ModelMessage>; entries: Array<RunAgentResumeItem>; /** Text the child wrote before it stopped. */ text: string; }; } interface SpawnContext { messages: SubagentRunContext['messages']; abortSignal?: AbortSignal; threadId: string; /** The parent chat run. */ parentRunId: string; /** The interrupted parent run, on a resume. */ interruptedRunId?: string; } export declare function createSubagentId(): string; /** * Bind child interrupts to the parent run. The client resumes the parent run, * so each binding must name that run. The resumed child then validates with * the parent's interrupted run id. */ export declare function rebindInterrupts(interrupts: ReadonlyArray<Interrupt>, runId: string): Array<Interrupt>; export declare function normalizeRouterPick(pick: SubagentRouterPick, agents: ReadonlyArray<DefinedAgent>): { steps: ReadonlyArray<SubagentStep>; }; /** Add a finished child run's usage to the sink. */ export declare function collectUsage(sink: SubagentSink, finished?: StreamChunk): void; /** A parent run's last chunk: it completed, or it failed. */ type ParentTerminal = Extract<StreamChunk, { type: 'RUN_FINISHED' | 'RUN_ERROR'; }>; /** * Put the children's usage on a parent terminal. `usage[]` keeps one entry per * model call. `metadata.tanstack.usage` holds the summed cost and the other * TanStack fields, so `fromSpecTokenUsage` reads the full total. Empties the * sink, so the next parent terminal does not count it again. * * `RUN_ERROR` is accepted too: a turn that failed still spent whatever its * children spent. Such a chunk carries no usage of its own, so `runUsage` and * `fullUsage` return empty for it and the children's total stands alone. */ export declare function withChildUsage(chunk: ParentTerminal, sink: SubagentSink): ParentTerminal; export declare function spawnAgentStream(agent: DefinedAgent, ctx: SubagentRunContext, sink?: SubagentSink, parentToolCallId?: string): AsyncIterable<StreamChunk>; export declare function spawnNamedAgents(entries: ReadonlyArray<SpawnEntry>, bag: SubagentsBag, ctx: SpawnContext, sink?: SubagentSink): AsyncGenerator<import('../../..').AGUIEvent, void, any>; /** * Text of the named direct children, in `names` order. Text from nested * children stays out: their chunks carry their own id. */ export declare function collectNamedText(chunks: Array<StreamChunk>, names: ReadonlyArray<string>): string; /** * Record the parent messages when the model calls a subagent tool, so the * child reads the conversation as it is at that call. */ export declare function subagentCallMessages(names: ReadonlySet<string>): { middleware: ChatMiddleware<unknown, never>; messagesFor: (toolCallId: string | undefined) => ModelMessage<string | import('../../..').ContentPart<unknown, unknown, unknown, unknown, unknown>[] | null>[] | undefined; }; export declare function createSyntheticSubagentTools(bag: SubagentsBag, parent: { /** Messages the parent run started with. Used when no call was recorded. */ messages: SubagentRunContext['messages']; /** The parent messages at a tool call. See subagentCallMessages. */ messagesFor?: (toolCallId: string | undefined) => SubagentRunContext['messages'] | undefined; threadId: string; runId: string; interruptedRunId?: string; abortSignal?: AbortSignal; turn?: SubagentTurn; sink: SubagentSink; }): Array<Tool>; export {};