logoassistant-ui
Vercel AI SDK

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

RSC Example App

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

On this page

Edit on Github