@openuidev/react-headless
API reference for chat state, hooks, streaming adapters, and message types.
Use this package when you want headless chat state + streaming, with or without prebuilt UI.
Import
import {
ChatProvider,
fetchLLM,
restStorage,
useThread,
useThreadList,
openAIAdapter,
openAIResponsesAdapter,
openAIReadableStreamAdapter,
vercelAIAdapter,
agUIAdapter,
openAIMessageFormat,
openAIConversationMessageFormat,
vercelAIMessageFormat,
identityMessageFormat,
processStreamedMessage,
MessageProvider,
useMessage,
EventType,
type ArtifactCategory,
type ArtifactRendererConfig,
type ChatLLM,
type ChatStorage,
} from "@openuidev/react-headless";ChatProvider
Provides chat, thread, streaming, and optional artifact state to its children.
interface ChatProviderProps {
llm: ChatLLM;
storage?: ChatStorage;
artifactRenderers?: ReadonlyArray<ArtifactRendererConfig>;
artifactCategories?: ArtifactCategory[];
artifactAutoOpen?: boolean;
children: React.ReactNode;
}llm is required. It sends messages to your backend and specifies the adapter used to parse the
streaming response. Create one with fetchLLM() or implement the ChatLLM interface yourself.
const llm = fetchLLM({
url: "/api/chat",
streamAdapter: agUIAdapter(),
});
function App() {
return (
<ChatProvider llm={llm}>
<YourChatUI />
</ChatProvider>
);
}storage is optional. Without it, conversations are stored in memory and are cleared when the page
reloads. Use restStorage() for the built-in REST conventions, or provide your own ChatStorage
implementation:
const storage = restStorage({ baseUrl: "/api/threads" });
<ChatProvider llm={llm} storage={storage}>
<YourChatUI />
</ChatProvider>;useThread()
Thread-level state/actions used throughout chat docs.
function useThread(): ThreadState & ThreadActions;
function useThread<T>(selector: (state: ThreadState & ThreadActions) => T): T;Shape:
type ThreadState = {
messages: Message[];
isRunning: boolean;
isLoadingMessages: boolean;
threadError: Error | null;
};
type ThreadActions = {
processMessage: (message: CreateMessage) => Promise<void>;
appendMessages: (...messages: Message[]) => void;
updateMessage: (message: Message) => void;
setMessages: (messages: Message[]) => void;
deleteMessage: (messageId: string) => void;
cancelMessage: () => void;
};useThreadList()
Thread list state/actions for sidebars and history.
function useThreadList(): ThreadListState & ThreadListActions;
function useThreadList<T>(selector: (state: ThreadListState & ThreadListActions) => T): T;useMessage()
Access the current message inside a message component.
function useMessage(): { message: Message };Provided via MessageProvider / MessageContext.
Stream adapters
Adapters referenced in integration guides:
function openAIAdapter(): StreamProtocolAdapter; // OpenAI Chat Completions stream
function openAIResponsesAdapter(): StreamProtocolAdapter; // OpenAI Responses stream
function openAIReadableStreamAdapter(): StreamProtocolAdapter; // OpenAI ReadableStream
function vercelAIAdapter(): StreamProtocolAdapter; // Vercel AI SDK v6 UIMessage stream
function agUIAdapter(): StreamProtocolAdapter; // AG-UI protocol streamRelated type:
interface StreamProtocolAdapter {
parse(response: Response): AsyncIterable<AGUIEvent>;
}Message format adapters
Converters referenced in integration guides:
const openAIMessageFormat: MessageFormat; // Chat Completions format
const openAIConversationMessageFormat: MessageFormat; // Responses/Conversations item format
const vercelAIMessageFormat: MessageFormat; // Vercel AI SDK v6 UIMessage format
const identityMessageFormat: MessageFormat; // Pass-through (no conversion)Base type:
interface MessageFormat {
toApi(messages: Message[]): unknown;
fromApi(data: unknown): Message[];
}The Vercel AI SDK integration supports app-executed tools. Provider-executed tools
(providerExecuted: true) are rejected because AG-UI messages cannot preserve
their assistant-contained result semantics.
Message types
type Message =
| UserMessage
| AssistantMessage
| SystemMessage
| DeveloperMessage
| ToolMessage
| ActivityMessage
| ReasoningMessage;Key message shapes:
interface UserMessage {
role: "user";
id: string;
content: InputContent[];
}
interface AssistantMessage {
role: "assistant";
id: string;
content: string | null;
toolCalls?: ToolCall[];
}Streaming utilities
function processStreamedMessage(/* ... */): Promise<void>;Low-level utility for processing a streamed response outside of ChatProvider.