mcpField
C
cloud

cloud

github.com/assistant-ui云与 DevOps295.1k 次安装1 天前更新
代码仓库

关于 cloud

cloud 是 assistant-ui 的托管服务,为 React 聊天界面提供线程持久化、消息历史、标题生成、反馈和文件上传。它通过 AssistantCloud 客户端连接 assistant-ui runtime,也支持 LangGraph Cloud 后端的线程管理。

主要功能

  1. 01持久化线程与消息历史
  2. 02自动生成线程标题
  3. 03保存消息反馈
  4. 04支持文件上传
  5. 05集成 assistant-ui runtime 与 LangGraph Cloud

适用场景

  1. 01保存聊天记录并在切换线程时加载
  2. 02为消息提供并记录正负反馈
  3. 03在聊天界面中支持文件上传
  4. 04通过 LangGraph Cloud 管理对话线程

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/assistant-ui/skills --skill cloud

安装后在 Claude Code 中输入/cloud确认已加载。

包含的文件

除 SKILL.md 外,安装时一起下载的参考资料和脚本。

references/
auth-integrations.md
authorization.md
custom-persistence.md
persistence.md

详细介绍

assistant-ui Cloud

请始终查阅 assistant-ui.com/llms.txt,以获取最新 API。

Assistant Cloud 是一项托管服务,可为任何 React 聊天 UI 添加线程持久化、消息历史记录、自动生成标题、消息反馈和文件上传功能。一个 AssistantCloud 客户端即可支持 assistant-ui runtime、AuiConfig 线程集成和 LangGraph Cloud。

目录

参考资料

安装

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

assistant-cloud 作为 @assistant-ui/react 的依赖项提供,后者会为浏览器代码重新导出 AssistantCloud。服务端代码(API 路由、令牌端点)若无需依赖 @assistant-ui/react,则可直接从 assistant-cloud 导入 AssistantCloud。

快速开始:useChatRuntime

来自 @assistant-ui/ai-sdk 的 useChatRuntime({ cloud }) 封装了 AI SDK 的 useChat 并添加持久化功能。它会在发送第一条消息时创建云端线程,在消息流式传输时保存消息,在收到首条回复后生成标题,通过 <ThreadList /> 在线程切换时加载历史记录,并针对已存储的消息提交反馈。

"use client";

import { useMemo } from "react";
import { AssistantCloud, AssistantRuntimeProvider } from "@assistant-ui/react";
import { useChatRuntime } from "@assistant-ui/ai-sdk";
import { Thread } from "@/components/assistant-ui/elements/thread.aui";
import { ThreadList } from "@/components/assistant-ui/elements/thread-list.aui";

export default function ChatPage() {
  const cloud = useMemo(
    () =>
      new AssistantCloud({
        baseUrl: process.env.NEXT_PUBLIC_ASSISTANT_BASE_URL!,
        anonymous: true,
      }),
    [],
  );

  const runtime = useChatRuntime({ cloud });

  return (
    <AssistantRuntimeProvider runtime={runtime}>
      <div className="grid h-dvh grid-cols-[250px_1fr] gap-x-2">
        <ThreadList />
        <Thread />
      </div>
    </AssistantRuntimeProvider>
  );
}

anonymous: true 适用于演示;生产环境的身份验证请参阅身份验证。useChatRuntime 还接受 adapters.history(一个 ThreadHistoryAdapter,必须实现 withFormat 才能与 AI SDK 结合使用)、adapters.feedback(设置 cloud 时默认为云端反馈适配器)、adapters.attachments、toCreateMessage、transport(默认为调用 /api/chat 的 AssistantChatTransport)以及 onResumeError。

AuiConfig 宿主:AISDKThreads

来自 @assistant-ui/ai-sdk 的 AISDKThreads({ cloud }) 是适用于非 AssistantRuntimeProvider 宿主(Vue 或手动构建的 AssistantClient)的 AuiConfig 等效方案。设置 cloud 后,线程列表会成为带有后台线程的 RemoteThreadList:每个访问过的线程在线程切换后仍会继续运行并保留自己的历史记录,新建的线程则会自动生成标题。

import { AuiConfig, AuiProvider } from "@assistant-ui/react";
import { AISDKThreads } from "@assistant-ui/ai-sdk";

const config = AuiConfig({
  threads: AISDKThreads({ cloud }),
});

从 Cloud AI SDK 迁移

@assistant-ui/cloud-ai-sdk 已弃用。新代码请使用 @assistant-ui/ai-sdk 中 useChatRuntime 的 cloud 选项;对于 AuiConfig 宿主,请使用 AISDKThreads({ cloud })。迁移详情请参阅从 Cloud AI SDK 迁移。

LangGraph:useLangGraphRuntime

@assistant-ui/react-langgraph 中的 useLangGraphRuntime 除了 stream、create、load 和 delete,还接受 cloud,用于通过 LangGraph Cloud 后端管理云端会话。

"use client";

import { AssistantCloud, AssistantRuntimeProvider } from "@assistant-ui/react";
import { useLangGraphRuntime, type LangChainMessage } from "@assistant-ui/react-langgraph";
import { useMemo } from "react";
import { createThread, deleteThread, getThreadState, sendMessage } from "@/lib/chatApi";

export function MyRuntimeProvider({ children }: { children: React.ReactNode }) {
  const cloud = useMemo(
    () => new AssistantCloud({ baseUrl: process.env.NEXT_PUBLIC_ASSISTANT_BASE_URL!, anonymous: true }),
    [],
  );

  const runtime = useLangGraphRuntime({
    cloud,
    stream: async function* (messages, { initialize }) {
      const { externalId } = await initialize();
      if (!externalId) throw new Error("Thread not found");
      return sendMessage({ threadId: externalId, messages });
    },
    create: async () => ({ externalId: (await createThread()).thread_id }),
    load: async (externalId) => {
      const state = await getThreadState(externalId);
      return { messages: (state.values as { messages?: LangChainMessage[] }).messages ?? [] };
    },
    delete: async (externalId) => deleteThread(externalId),
  });

  return <AssistantRuntimeProvider runtime={runtime}>{children}</AssistantRuntimeProvider>;
}

create 返回 { externalId },即你后端的 LangGraph 会话 ID;load 返回该会话的消息(也可以选择返回中断);delete 接收 externalId,如果提供了该参数,便可在会话列表 UI 中删除会话。

消息反馈

在 useChatRuntime(或 AISDKThreads)上设置 cloud 时,运行时会接入默认的 FeedbackAdapter,自动调用 cloud.threads.messages.feedback,因此内置的点赞和点踩按钮会将反馈保存到对应消息,无需额外代码。直接调用方式如下:

const { feedback_id, type } = await cloud.threads.messages.feedback(threadId, messageId, {
  type: "positive", // or "negative"
});

身份验证

根据传入的字段,有以下三种构造方式:

// JWT (recommended for production; client-side)
const cloud = new AssistantCloud({
  baseUrl: process.env.NEXT_PUBLIC_ASSISTANT_BASE_URL!,
  authToken: async () => getAuthToken(), // returns a JWT, or null
});

// API key (server-side only; baseUrl defaults to https://backend.assistant-api.com)
const cloud = new AssistantCloud({
  apiKey: process.env.ASSISTANT_API_KEY!,
  userId: user.id,
  workspaceId: user.workspaceId,
});

// Anonymous (demos and prototypes; a new user per browser session)
const cloud = new AssistantCloud({
  baseUrl: process.env.NEXT_PUBLIC_ASSISTANT_BASE_URL!,
  anonymous: true,
});

授权范围限定在一个工作区内(通常为 userId、orgId_userId 或 projectId_userId)。你可以从 Assistant Cloud 控制面板配置直接提供商集成(Clerk、Auth0、Supabase、Firebase),也可以使用 API 密钥客户端在服务端签发令牌,并通过前端 authToken 回调所请求的端点返回该令牌。关于这两种方式的完整说明,请参阅 authorization.md;关于将 Cloud 与 Auth.js、Clerk 或 better-auth 的会话数据配合使用,请参阅 auth-integrations.md。

客户端 API

所有方法均已根据 src/cloud/** 验证。threadId/messageId 始终是第一个参数;列表端点使用 after 分页(它是游标,而不是偏移量)。

// Threads
const { threads } = await cloud.threads.list({ is_archived: false, limit: 50, after: cursor });
const thread = await cloud.threads.get(threadId);
const { thread_id } = await cloud.threads.create({ last_message_at: new Date(), title, external_id, metadata });
await cloud.threads.update(threadId, { title, last_message_at, metadata, is_archived });
await cloud.threads.delete(threadId);

// Messages (parent_id and format are required on create; update touches content only)
const { messages } = await cloud.threads.messages.list(threadId, { format: "ai-sdk/v6" });
const { message_id } = await cloud.threads.messages.create(threadId, { parent_id, format, content });
await cloud.threads.messages.update(threadId, messageId, { content });
await cloud.threads.messages.feedback(threadId, messageId, { type: "positive" });

// Files
const { signedUrl, publicUrl, expiresAt } = await cloud.files.generatePresignedUploadUrl({ filename });
await fetch(signedUrl, { method: "PUT", body: file });

// Runs, projects, auth
await cloud.runs.report(runReport); // telemetry sink; the runtime calls this for you
const { threads: projectThreads } = await cloud.projects.threads.list({ limit: 50, after: cursor }); // whole project, not one workspace
const { messages: projectMessages } = await cloud.projects.threads.messages.list(threadId, { limit: 50, after: cursor });
const { token } = await cloud.auth.tokens.create(); // server-side, API key mode
cloud.telemetry; // { enabled: boolean, beforeReport? }

cloud.threads.create 的 last_message_at 为必填项;创建和更新中的其他字段均为可选项。CloudThread 字段:id、title、last_message_at、created_at、updated_at、is_archived、external_id、metadata、project_id、workspace_id。CloudMessage 字段:id、parent_id、height、format、content、created_at、updated_at。对于客户端而言,content/format 是不透明的;useChatRuntime 和 AISDKThreads 会写入 format: "ai-sdk/v6",以及符合 AI SDK UIMessage 结构的 content。cloud.projects.threads.messages.list 支持 limit/after 分页,而 cloud.threads.messages.list 不支持。请求失败时会从 assistant-cloud 抛出 CloudAPIError(含 .status);响应格式错误时会抛出 CloudResponseError。完整详情、自动保存行为、遥测字段和错误处理,请参阅 persistence.md。

环境变量

NEXT_PUBLIC_ASSISTANT_BASE_URL=https://proj-[YOUR-ID].assistant-api.com  # client-side
ASSISTANT_API_KEY=your-api-key-here                                     # server-side only, never expose to the client

React Native 读取 EXPO_PUBLIC_ASSISTANT_BASE_URL;React Ink 读取 ASSISTANT_BASE_URL(不带 NEXT_PUBLIC_ 前缀,因为没有打包器将其暴露给浏览器)。

常见注意事项

线程未持久化

  • 必须将 cloud 传入 useChatRuntime 或 AISDKThreads;尚无消息的线程永远不会被创建。
  • 检查 authToken 是否意外解析为 null:此时任何实际请求都会在发往网络之前抛出普通的 Error("Authorization failed"),这与 CloudAPIError 401 不同。

云 API 返回 401 或“Authorization failed”

  • 确认 baseUrl 与项目的 Frontend API URL 完全一致(主机名后没有多余内容)。
  • 对于 JWT 模式,确认 authToken 在首次请求前已完成解析;对于 Clerk 模板,JWT 中的 aud 声明必须为 "assistant-ui"。

反馈按钮已渲染,但反馈未持久化

  • 只有在将 cloud 传入运行时后,默认反馈适配器才会接入;自定义 adapters.feedback 会完全覆盖默认适配器。

页面重新加载后,消息历史又以乱序显示

  • 不要手动编写消息行的 content;它必须与当前格式的 encode 生成的内容完全一致,否则重新加载时 decode 会失败。应通过运行时填充测试数据,而不是直接插入行。

从 @assistant-ui/react-ai-sdk 导入

  • 该软件包仅为固定在较旧版本的安装重新导出 @assistant-ui/ai-sdk。新代码请从 @assistant-ui/ai-sdk 导入 useChatRuntime 和 AssistantChatTransport。

匿名模式会丢失历史记录

  • 匿名模式会为每个浏览器会话创建一个新用户(无法跨设备同步);需要持久保存数据时,请切换到 JWT 或 API key 身份验证。

相关技能

  • thread-list -- <ThreadList /> 侧边栏 UI、线程 CRUD 选择器,以及用于完全可自托管(非云端)线程列表的 RemoteThreadListAdapter 契约
  • setup -- 安装 assistant-ui 并选择运行时钩子,包括 cloud 和 cloud-clerk CLI 模板
  • runtime -- 云端所实现的通用适配器契约(ThreadHistoryAdapter、FeedbackAdapter、AttachmentAdapter)

评论

支持 Markdown