AI SDK by Vercel
Vercel AI SDK RSC Runtime
Overview
Integration with the Vercel AI SDK React Server Components. It allows streaming React components directly from the server.
Integrates with OpenAI, Anthropic, Mistral, Perplexity, AWS Bedrock, Azure, Google Gemini, Hugging Face, Fireworks, Cohere, LangChain, Replicate, Ollama, and more.
Example
Getting Started
Create a Next.JS project
npx create-next-app@latest my-app
cd my-app
Install Vercel AI SDK and @assistant-ui/react-ai-sdk
npm install @assistant-ui/react @assistant-ui/react-ai-sdk ai @ai-sdk/openai zod nanoid
Setup actions.tsx
@/app/actions.tsx
"use server";
import { createAI, getMutableAIState, streamUI } from "ai/rsc";
import { openai } from "@ai-sdk/openai";
import { ReactNode } from "react";
import { z } from "zod";
import { nanoid } from "nanoid";
export interface ServerMessage {
role: "user" | "assistant";
content: string;
}
export interface ClientMessage {
id: string;
role: "user" | "assistant";
display: ReactNode;
}
export async function continueConversation(
input: string,
): Promise<ClientMessage> {
"use server";
const history = getMutableAIState();
const result = await streamUI({
model: openai("gpt-3.5-turbo"),
messages: [...history.get(), { role: "user", content: input }],
text: ({ content, done }) => {
if (done) {
history.done((messages: ServerMessage[]) => [
...messages,
{ role: "assistant", content },
]);
}
return <div>{content}</div>;
},
tools: {
deploy: {
description: "Deploy repository to vercel",
parameters: z.object({
repositoryName: z
.string()
.describe("The name of the repository, example: vercel/ai-chatbot"),
}),
generate: async function* ({ repositoryName }) {
yield <div>Cloning repository {repositoryName}...</div>;
await new Promise((resolve) => setTimeout(resolve, 3000));
yield <div>Building repository {repositoryName}...</div>;
await new Promise((resolve) => setTimeout(resolve, 2000));
return <div>{repositoryName} deployed!</div>;
},
},
},
});
return {
id: nanoid(),
role: "assistant",
display: result.value,
};
}
export const AI = createAI<ServerMessage[], ClientMessage[]>({
actions: {
continueConversation,
},
initialAIState: [],
initialUIState: [],
});
Define a MyRuntimeProvider
component
@/app/MyRuntimeProvider.tsx
"use client";
import {
type AppendMessage,
AssistantRuntimeProvider,
} from "@assistant-ui/react";
import { useVercelRSCRuntime } from "@assistant-ui/react-ai-sdk";
import { useActions, useUIState } from "ai/rsc";
import { nanoid } from "nanoid";
import type { AI } from "./actions";
export function MyRuntimeProvider({
children,
}: Readonly<{
children: React.ReactNode;
}>) {
const { continueConversation } = useActions();
const [messages, setMessages] = useUIState<typeof AI>();
const onNew = async (m: AppendMessage) => {
if (m.content[0]?.type !== "text")
throw new Error("Only text messages are supported");
const input = m.content[0].text;
setMessages((currentConversation) => [
...currentConversation,
{ id: nanoid(), role: "user", display: input },
]);
const message = await continueConversation(input);
setMessages((currentConversation) => [...currentConversation, message]);
};
const runtime = useVercelRSCRuntime({ messages, onNew });
return (
<AssistantRuntimeProvider runtime={runtime}>
{children}
</AssistantRuntimeProvider>
);
}
Wrap your app in AI
and MyRuntimeProvider
@/app/layout.tsx
import { AI } from '@/app/actions';
import { MyRuntimeProvider } from '@/app/MyRuntimeProvider';
...
export default function RootLayout({
children,
}: Readonly<{
children: React.ReactNode;
}>) {
return (
<AI>
<MyRuntimeProvider>
<html lang="en">
<body className={inter.className}>
{children}
</body>
</html>
</MyRuntimeProvider>
</AI>
)
}
Set up RSCDisplay
Pass the RSCDisplay
component to your MessagePrimitive.Content
:
<MessagePrimitive.Content components={{ Text: RSCDisplay }} />
(if you are using react-ui: <Thread assistantMessage={{ components: { Text: RSCDisplay } }} />
)
Accessing AI SDK Messages
You can use the getExternalStoreMessages
utility to convert ThreadMessage
s back to your message format.
const MyAssistantMessage = () => {
const myMessage = useMessage((m) => getExternalStoreMessages(m)[0]);
// ...
};