Back to Ai

DirectChatTransport

content/docs/07-reference/02-ai-sdk-ui/50-direct-chat-transport.mdx

2.1.108.5 KB
Original Source

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.

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