UNPKG

ai

Version:

AI SDK by Vercel - build apps like ChatGPT, Claude, Gemini, and more with a single interface for any model using the Vercel AI Gateway or go direct to OpenAI, Anthropic, Google, or any other model provider.

334 lines (287 loc) 8.78 kB
--- title: DirectChatTransport description: API Reference for the DirectChatTransport class. --- # `DirectChatTransport` A transport that directly communicates with an [Agent](/docs/reference/ai-sdk-core/agent) in-process, without going through HTTP. This is useful for: - Server-side rendering scenarios - Testing without network - Single-process applications Unlike `DefaultChatTransport` which sends HTTP requests to an API endpoint, `DirectChatTransport` invokes the agent's `stream()` method directly and converts the result to a UI message stream. ```tsx import { useChat } from '@ai-sdk/react'; import { DirectChatTransport, ToolLoopAgent } from 'ai'; __PROVIDER_IMPORT__; const agent = new ToolLoopAgent({ model: __MODEL__, instructions: 'You are a helpful assistant.', }); export default function Chat() { const { messages, sendMessage, status } = useChat({ transport: new DirectChatTransport({ agent }), }); // ... render chat UI } ``` ## Import <Snippet text={`import { DirectChatTransport } from "ai"`} prompt={false} /> ## Constructor ### Parameters <PropertiesTable content={[ { name: 'agent', type: 'Agent', isRequired: true, description: 'The Agent instance to use for generating responses. The agent will be called with `stream()` for each message.', }, { name: 'options', type: 'CALL_OPTIONS', isOptional: true, description: 'Options to pass to the agent when calling it. These are agent-specific options defined when creating the agent.', }, { name: 'originalMessages', type: 'UIMessage[]', isOptional: true, description: 'The original messages. If provided, persistence mode is assumed, and a message ID is provided for the response message.', }, { name: 'generateMessageId', type: 'IdGenerator', isOptional: true, description: 'Generate a message ID for the response message. If not provided, no message ID will be set for the response message.', }, { name: 'messageMetadata', type: '(options: { part: TextStreamPart }) => METADATA | undefined', isOptional: true, description: 'Extracts message metadata that will be sent to the client. Called on `start` and `finish` events.', }, { name: 'sendReasoning', type: 'boolean', isOptional: true, description: 'Send reasoning parts to the client. Defaults to true.', }, { name: 'sendSources', type: 'boolean', isOptional: true, description: 'Send source parts to the client. Defaults to false.', }, { name: 'sendFinish', type: 'boolean', isOptional: true, description: 'Send the finish event to the client. Set to false if you are using additional streamText calls that send additional data. Defaults to true.', }, { name: 'sendStart', type: 'boolean', isOptional: true, description: 'Send the message start event to the client. Set to false if you are using additional streamText calls and the message start event has already been sent. Defaults to true.', }, { name: 'onError', type: '(error: unknown) => string', isOptional: true, description: "Process an error, e.g. to log it. Defaults to `() => 'An error occurred.'`. Return the error message to include in the data stream.", }, ]} /> ## Methods ### `sendMessages()` Sends messages to the agent and returns a streaming response. This method validates and converts UI messages to model messages, calls the agent's `stream()` method, and returns the result as a UI message stream. ```ts const stream = await transport.sendMessages({ chatId: 'chat-123', trigger: 'submit-message', messages: [...], abortSignal: controller.signal, }); ``` <PropertiesTable content={[ { name: 'chatId', type: 'string', description: 'Unique identifier for the chat session.', }, { name: 'trigger', type: "'submit-message' | 'regenerate-message'", description: 'The type of message submission - either new message or regeneration.', }, { name: 'messageId', type: 'string | undefined', description: 'ID of the message to regenerate, or undefined for new messages.', }, { name: 'messages', type: 'UIMessage[]', description: 'Array of UI messages representing the conversation history.', }, { name: 'abortSignal', type: 'AbortSignal | undefined', description: 'Signal to abort the request if needed.', }, { name: 'headers', type: 'Record<string, string> | Headers', isOptional: true, description: 'Additional headers (ignored by DirectChatTransport).', }, { name: 'body', type: 'object', isOptional: true, description: 'Additional body properties (ignored by DirectChatTransport).', }, { name: 'metadata', type: 'unknown', isOptional: true, description: 'Custom metadata (ignored by DirectChatTransport).', }, ]} /> #### Returns Returns a `Promise<ReadableStream<UIMessageChunk>>` - a stream of UI message chunks that can be processed by the chat UI. ### `reconnectToStream()` Direct transport does not support reconnection since there is no persistent server-side stream to reconnect to. #### Returns Always returns `Promise<null>`. ## Examples ### Basic Usage ```tsx import { useChat } from '@ai-sdk/react'; import { DirectChatTransport, ToolLoopAgent } from 'ai'; import { openai } from '@ai-sdk/openai'; const agent = new ToolLoopAgent({ model: openai('gpt-4o'), instructions: 'You are a helpful assistant.', }); export default function Chat() { const { messages, sendMessage, status } = useChat({ transport: new DirectChatTransport({ agent }), }); return ( <div> {messages.map(message => ( <div key={message.id}> {message.role === 'user' ? 'User: ' : 'AI: '} {message.parts.map((part, index) => part.type === 'text' ? <span key={index}>{part.text}</span> : null, )} </div> ))} <button onClick={() => sendMessage({ text: 'Hello!' })}>Send</button> </div> ); } ``` ### With Agent Tools ```tsx import { useChat } from '@ai-sdk/react'; import { DirectChatTransport, ToolLoopAgent, tool } from 'ai'; import { openai } from '@ai-sdk/openai'; import { z } from 'zod'; const weatherTool = tool({ description: 'Get the current weather', parameters: z.object({ location: z.string().describe('The city and state'), }), execute: async ({ location }) => { return `The weather in ${location} is sunny and 72°F.`; }, }); const agent = new ToolLoopAgent({ model: openai('gpt-4o'), instructions: 'You are a helpful assistant with access to weather data.', tools: { weather: weatherTool }, }); export default function Chat() { const { messages, sendMessage } = useChat({ transport: new DirectChatTransport({ agent }), }); // ... render chat UI with tool results } ``` ### With Custom Agent Options ```tsx import { useChat } from '@ai-sdk/react'; import { DirectChatTransport, ToolLoopAgent } from 'ai'; import { openai } from '@ai-sdk/openai'; const agent = new ToolLoopAgent<{ userId: string }>({ model: openai('gpt-4o'), prepareCall: ({ options, ...rest }) => ({ ...rest, providerOptions: { openai: { user: options.userId }, }, }), }); export default function Chat({ userId }: { userId: string }) { const { messages, sendMessage } = useChat({ transport: new DirectChatTransport({ agent, options: { userId }, }), }); // ... render chat UI } ``` ### With Reasoning ```tsx import { useChat } from '@ai-sdk/react'; import { DirectChatTransport, ToolLoopAgent } from 'ai'; import { openai } from '@ai-sdk/openai'; const agent = new ToolLoopAgent({ model: openai('o1-preview'), }); export default function Chat() { const { messages, sendMessage } = useChat({ transport: new DirectChatTransport({ agent, sendReasoning: true, }), }); return ( <div> {messages.map(message => ( <div key={message.id}> {message.parts.map((part, index) => { if (part.type === 'text') { return <p key={index}>{part.text}</p>; } if (part.type === 'reasoning') { return ( <pre key={index} style={{ opacity: 0.6 }}> {part.text} </pre> ); } return null; })} </div> ))} </div> ); } ```