AI SDK

Add cloud persistence to your existing AI SDK app with a single hook.

Overview

The @assistant-ui/cloud-ai-sdk package provides a single hook that adds full message and thread persistence to any AI SDK application:

  • useCloudChat — wraps useChat with automatic cloud persistence and built-in thread management

This hook works with any React UI. You keep full control of your components.

Want pre-built UI components? See AI SDK + assistant-ui for the full integration with <Thread /> and <ThreadList />.

Prerequisites

You need an assistant-cloud account to follow this guide. Sign up here to get started.

Setup

Create a Cloud Project

Create a new project in the assistant-cloud dashboard and from the settings page, copy your Frontend API URL (https://proj-[ID].assistant-api.com).

Configure Environment Variables

.env.local
NEXT_PUBLIC_ASSISTANT_BASE_URL=https://proj-[YOUR-ID].assistant-api.com

Install Dependencies

npm install @assistant-ui/cloud-ai-sdk assistant-cloud @ai-sdk/react ai

Integrate

app/page.tsx
"use client";

import { useState } from "react";
import { useCloudChat } from "@assistant-ui/cloud-ai-sdk";

export default function Chat() {
  // Zero-config: auto-initializes anonymous cloud from env var with built-in threads.
  // For custom config, pass: { cloud, threads: useThreads(...), onSyncError }
  const { messages, sendMessage, threads } = useCloudChat();

  const [input, setInput] = useState("");
  const handleSubmit = () => {
    if (!input.trim()) return;
    sendMessage({ text: input });
    setInput("");
  };

  return (
    <div>
      {/* Thread list */}
      <ul>
        {threads.threads.map((t) => (
          <li key={t.id} onClick={() => threads.selectThread(t.id)}>
            {t.title || "New conversation"}
          </li>
        ))}
        <li onClick={() => threads.selectThread(null)}>New chat</li>
      </ul>

      {/* Chat messages */}
      <div>
        {messages.map((m) => (
          <div key={m.id}>
            {m.parts.map((p) => p.type === "text" && p.text)}
          </div>
        ))}
      </div>

      {/* Composer */}
      <form onSubmit={(e) => { e.preventDefault(); handleSubmit(); }}>
        <input value={input} onChange={(e) => setInput(e.target.value)} />
        <button type="submit">Send</button>
      </form>
    </div>
  );
}

That's it. Messages persist automatically as they complete, and switching threads loads the full history.

API Reference

useCloudChat(options?)

Wraps AI SDK's useChat with automatic cloud persistence and built-in thread management. Messages are persisted as they finish streaming. Thread creation is automatic on the first message — the hook will auto-create the thread, select it, refresh the thread list, and generate a title after the first response.

Configuration Modes

1. Zero-config — Set NEXT_PUBLIC_ASSISTANT_BASE_URL env var, call with no args:

const chat = useCloudChat();

2. Custom cloud instance — For authenticated users or custom configuration:

const cloud = new AssistantCloud({ baseUrl, authToken });
const chat = useCloudChat({ cloud });

3. External thread management — When threads need to be accessed from a separate component or you need custom thread options like includeArchived:

// In a context provider or parent component
const myThreads = useThreads({ cloud, includeArchived: true });

// Pass to useCloudChat - it will use your thread state
const chat = useCloudChat({ threads: myThreads });

Parameters

ParameterTypeDescription
options.cloudAssistantCloudCloud instance (optional — auto-creates anonymous instance from NEXT_PUBLIC_ASSISTANT_BASE_URL env var if not provided)
options.threadsUseThreadsResultExternal thread management from useThreads(). Use when you need thread operations in a separate component or custom thread options like includeArchived
options.onSyncError(error: Error) => voidCallback invoked when a sync error occurs

All other AI SDK useChat options are also accepted.

Returns: UseCloudChatResult

ValueTypeDescription
messagesUIMessage[]Chat messages (from AI SDK)
statusstringChat status: "ready", "submitted", "streaming", or "error"
sendMessage(message, options?) => Promise<void>Send a message (auto-creates thread if needed)
stop() => voidStop the current stream
threadsUseThreadsResultThread management (see below)

Plus all other properties from AI SDK's UseChatHelpers.

Thread management (threads):

ValueTypeDescription
threads.threadsCloudThread[]Active threads sorted by recency
threads.threadIdstring | nullCurrent thread ID (null for a new unsaved chat)
threads.selectThread(id: string | null) => voidSwitch threads or pass null for a new chat
threads.isLoadingbooleantrue during initial load or refresh
threads.errorError | nullLast error, if any
threads.refresh() => Promise<boolean>Re-fetch the thread list
threads.delete(id: string) => Promise<boolean>Delete a thread
threads.rename(id: string, title: string) => Promise<boolean>Rename a thread
threads.archive(id: string) => Promise<boolean>Archive a thread
threads.unarchive(id: string) => Promise<boolean>Unarchive a thread
threads.generateTitle(threadId: string) => Promise<string | null>Generate a title using AI

useThreads(options)

Thread list management for use with useCloudChat. Call this explicitly and pass to useCloudChat({ threads }) when you need access to thread operations outside the chat context (e.g., in a separate sidebar component).

const myThreads = useThreads({ cloud: myCloud });
const { messages, sendMessage } = useCloudChat({ threads: myThreads });

Parameters:

ParameterTypeDescription
options.cloudAssistantCloudCloud client instance
options.includeArchivedbooleanInclude archived threads (default: false)
options.enabledbooleanEnable thread fetching (default: true)

Returns: UseThreadsResult — same shape as threads from useCloudChat().

Authentication

The example above uses anonymous mode (browser session-based user ID) via the env var. For production apps with user accounts, pass an explicit cloud instance:

import { useAuth } from "@clerk/nextjs";
import { AssistantCloud } from "assistant-cloud";
import { useCloudChat } from "@assistant-ui/cloud-ai-sdk";

function Chat() {
  const { getToken } = useAuth();

  const cloud = useMemo(() => new AssistantCloud({
    baseUrl: process.env.NEXT_PUBLIC_ASSISTANT_BASE_URL!,
    authToken: async () => getToken({ template: "assistant-ui" }),
  }), [getToken]);

  const { messages, sendMessage, threads } = useCloudChat({ cloud });
  // ...
}

See the Cloud Authorization guide for other auth providers.

Next Steps