DirectChatTransport

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

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.

import { useChat } from '@ai-sdk/react';
import { DirectChatTransport, ToolLoopAgent } from 'ai';
const agent = new ToolLoopAgent({
model: "anthropic/claude-sonnet-4.5",
instructions: 'You are a helpful assistant.',
});
export default function Chat() {
const { messages, sendMessage, status } = useChat({
transport: new DirectChatTransport({ agent }),
});
// ... render chat UI
}

Import

import { DirectChatTransport } from "ai"

Constructor

Parameters

agent:

Agent

options?:

CALL_OPTIONS

originalMessages?:

UIMessage[]

generateMessageId?:

IdGenerator

messageMetadata?:

(options: { part: TextStreamPart }) => METADATA | undefined

sendReasoning?:

boolean

sendSources?:

boolean

sendFinish?:

boolean

sendStart?:

boolean

onError?:

(error: unknown) => string

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.

const stream = await transport.sendMessages({
chatId: 'chat-123',
trigger: 'submit-message',
messages: [...],
abortSignal: controller.signal,
});

chatId:

string

trigger:

'submit-message' | 'regenerate-message'

messageId:

string | undefined

messages:

UIMessage[]

abortSignal:

AbortSignal | undefined

headers?:

Record<string, string> | Headers

body?:

object

metadata?:

unknown

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

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

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

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

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>
);
}