@chat-adapter/web

中文文档
4.44.0发布于 2026/11/02MITTypeScriptES Module构建来源已验证近 30 天下载 8.1万

Chat SDK的网络适配器——浏览器在AI SDK或AG-UI(TanStack AI)流协议上的聊天UI

中文使用文档
文档目录25 节
  1. 安装
  2. 带CLI的脚手架
  3. 快开始
  4. 服务器
  5. 客户端
  6. 认证
  7. 线索
  8. 流线
  9. 信件持续性
  10. 框架帮助者
  11. 配置
  12. 特征
  13. 通讯
  14. 丰富内容
  15. 对话
  16. 信件历史
  17. v1 范围
  18. 解决问题
  19. 每个请求返回401
  20. 每个请求返回 400 “无效用户 ID ”
  21. useChat 在每次渲染时重现状态
  22. thread.messages 为空
  23. 请求退回 400 “信件的最后一项必须是用户信件”
  24. AI 编码代理
  25. 许可证

Web adapter for Chat SDK

@chat-adapter/web (英语)

npm 软件包 : @chat-adapter/web

Agent Stack MIT License

网络适配器 聊天SDK。让一个聊天-sdk bot与Slack, Teams, Discord 等同时为浏览器聊天UI服务——相同 bot.onDirectMessage(...) 每个平台的操作员起火.

适配器说 AI SDK UI 消息流协议 默认情况下,因此React,Vue,和Svelte AI SDK客户端对服务器端点工作. 设定 protocol: "ag-ui" 说话 乌干达 相反,因为 谭斯塔克AI 和其他AG-UI客户端。 服务器对两个客户端SDK都没有运行时间依赖.

联合国 聊天-sdk.dev/适应者/官方/网络 指南: vercel.com/kb/chat-sdk (英语)

安装

pnpm add @chat-adapter/web

然后安装匹配您的用户界面的客户端软件包 :

客户端软件包从protocol
AI SDK + React / Next.js (英语)ai, (中文(简体) ), @ai-sdk/react@chat-adapter/web/react"ai-sdk" (默认)
AI SDK + Vue / 努克特ai, (中文(简体) ), @ai-sdk/vue@chat-adapter/web/vue"ai-sdk" (默认)
AI SDK + Svelte / Svelte Kit 软件ai, (中文(简体) ), @ai-sdk/svelte@chat-adapter/web/svelte"ai-sdk" (默认)
谭斯塔克AI@tanstack/ai-react (或另一个 TanStack AI 框架包)@tanstack/ai-react"ag-ui"

带CLI的脚手架

要使用Web适配器预选的新浏览器聊天程序 :

npx create-chat-sdk@latest my-bot --adapter web memory

访问 适配器目录 见其他官方和供应商官方适配器.

快开始

服务器

// lib/bot.ts
import { Chat } from "chat";
import { createWebAdapter } from "@chat-adapter/web";
import { createMemoryState } from "@chat-adapter/state-memory";

export const bot = new Chat({
  userName: "mybot",
  adapters: {
    web: createWebAdapter({
      userName: "mybot",
      getUser: (req) => ({ id: getUserIdFromCookie(req) }),
    }),
  },
  state: createMemoryState(),
});

bot.onDirectMessage(async (thread, message) => {
  await thread.post(`You said: ${message.text}`);
});
// app/api/chat/route.ts
import { after } from "next/server";
import { bot } from "@/lib/bot";

export async function POST(request: Request): Promise<Response> {
  return bot.webhooks.web(request, {
    waitUntil: (task) => after(() => task),
  });
}

客户端

反应

// app/chat/page.tsx
"use client";
import { useChat } from "@chat-adapter/web/react";

export default function ChatPage() {
  const { messages, sendMessage, status, stop } = useChat();
  // Render with `ai-elements` (<Conversation>, <Message>, <PromptInput>)
  // or your own components — `messages`, `sendMessage`, `status` are the
  // standard `@ai-sdk/react` API.
}

阴道

<!-- components/Chat.vue -->
<script setup lang="ts">
import { useChat } from "@chat-adapter/web/vue";

const chat = useChat({ api: "/api/chat" });
</script>

<template>
  <div v-for="msg in chat.messages" :key="msg.id">
    <template
      v-for="(part, index) in msg.parts"
      :key="`${msg.id}-${part.type}-${index}`"
    >
      <p v-if="part.type === 'text'">{{ part.text }}</p>
    </template>
  </div>
</template>

丝绒

<!-- Chat.svelte -->
<script lang="ts">
  import { useChat } from "@chat-adapter/web/svelte";

  const chat = useChat({ api: "/api/chat" });
</script>

{#each chat.messages as msg (msg.id)}
  {#each msg.parts as part, index (`${msg.id}-${part.type}-${index}`)}
    {#if part.type === "text"}<p>{part.text}</p>{/if}
  {/each}
{/each}

谭斯塔克AI

设定 protocol: "ag-ui" 在适配器上,然后点 TanStack AI的 useChat 在路线上 fetchServerSentEvents数字 :

createWebAdapter({
  userName: "mybot",
  getUser: (req) => ({ id: getUserIdFromCookie(req) }),
  protocol: "ag-ui",
});
// app/chat/page.tsx
"use client";
import { fetchServerSentEvents, useChat } from "@tanstack/ai-react";

export default function ChatPage() {
  const { messages, sendMessage, isLoading, stop } = useChat({
    connection: fetchServerSentEvents("/api/chat"),
    threadId: "support-1",
  });
  // Text parts carry their text in `part.content`.
}

threadId 成为聊天- sdk 线条 id 中的对话 id 。 每个 thread.post 调用作为自己的助理消息到达,处理器错误以一个 RUN_ERROR 活动.

认证

getUser 这是 安全边界 用于网络适配器。 与Slack/Teams不同的是,平台在每一个webhook上签名,web请求直接来自浏览器——您必须亲自识别呼叫者. 正在返回 null 导致适配器以 HTTP 401 响应,没有处理器运行.

插入您的应用程序已经使用的内容 :

// NextAuth
createWebAdapter({
  userName: "mybot",
  getUser: async (req) => {
    const session = await getServerSession(authOptions);
    if (!session?.user) return null;
    return { id: session.user.id, name: session.user.name };
  },
});

// Clerk
createWebAdapter({
  userName: "mybot",
  getUser: async (req) => {
    const { userId, sessionClaims } = await auth();
    if (!userId) return null;
    return { id: userId, name: sessionClaims?.name as string | undefined };
  },
});

// Custom session cookie
createWebAdapter({
  userName: "mybot",
  getUser: async (req) => {
    const sessionId = req.headers.get("cookie")?.match(/session=([^;]+)/)?.[1];
    if (!sessionId) return null;
    const user = await db.users.findBySession(sessionId);
    return user ? { id: user.id, name: user.name } : null;
  },
});

若为 getUser 扔出,适配器返回401并记录出错。 在错误消息中不要包括敏感数据——它没有被浮出客户端,而是被登录.

决心 user.id 嵌入到聊天- sdk 线索 id (参见 线索 页:1 包含的用户代号 : 与 HTTP 400 一同被拒绝,因为他们会破坏往返 decodeThreadId。如果您的认证提供者以冒号(例如. provider:sub 要求) getUser ——以基数64-编码为例.

线索

默认情况下,每个 useChat 一个聊天- sdk 线索的对话地图 :

web:{user.id}:{conversationId}

conversationId 这是 id 字段 AI SDK 的使用 Chat 在其请求正文中发送,或 threadId 字段为 protocol: "ag-ui"。如果客户提供(useChat({ id: "support-chat" })),它通过再装入来再使用;否则每个请求都会生成新鲜的ID. 一个不是字符串的对话ID,或者包含 :,用HTTP 400拒绝.

channel.messages 财务报告和审定财务报表 thread.messages 在网络上是等同的——频道 id 是线索 id. 这样可以避免交会出血 persistMessageHistory 被启用,而同一用户有多个使用Chat 对话框打开.

覆盖( 例如, 每个用户一个线程, 不分对话) :

createWebAdapter({
  userName: "mybot",
  getUser: (req) => /* ... */,
  threadIdFor: ({ user }) => `web:${user.id}:default`,
});

编码/解码辅助器在适配器上被曝光:

adapter.encodeThreadId({ userId: "u1", conversationId: "abc" });
// → "web:u1:abc"
adapter.decodeThreadId("web:u1:abc");
// → { userId: "u1", conversationId: "abc" }

流线

thread.post 接受一个 AsyncIterable<string | StreamChunk> 并直接将 Dertas 泵入SSE 响应机体——没有编辑回路,没有限制速率. Handlers可以使用任何模型库. 例如,用AI SDK的 streamText数字 :

import { streamText } from "ai";
// Bring your own model from any AI SDK provider
// (@ai-sdk/openai, @ai-sdk/anthropic, @ai-sdk/google, ...).

bot.onDirectMessage(async (thread, message) => {
  const result = streamText({
    model: myModel,
    prompt: message.text,
  });
  await thread.post(result.textStream);
});

适配者的荣誉 request.signal,所以打电话 stop() 从客户端的短路中取出服务器上的转发器. task_update 财务报告和审定财务报表 plan_update StreamChunk电线上没有原生的v1代表,被悄悄地抛出.

信件持续性

persistMessageHistory 默认为 true。Web没有平台侧历史 API,所以是聊天 sdk 处理器通过前一个回合查看的唯一方法 thread.messages 编号 : channel.messages 是通过配置的状态适配器消息历史缓存。 准备吧 false 只有在您的操作者不需要前轮 :

createWebAdapter({
  userName: "mybot",
  getUser: (req) => /* ... */,
  persistMessageHistory: false,
});

客户端在每个请求上重新发送整个对话,但适配器不从中读取历史. 浏览器控制请求主体 messages[] 数组,因此适配器只消耗最新的用户消息,并从中去除工具部件. 最后一个条目必须是用户消息;一个以助手或工具消息结尾的正文,如客户端工具结果被HTTP 400拒绝. 再次发送相同的用户消息( S)regenerate() 或重新装入)再次运行处理器,而不是作为重复被丢弃,历史保存了更早的回覆并存储了重复的信件第二次.

message.raw 输入 WebMessage部分字段 type 为: unknown与 "ai-sdk" 形状匹配 AI SDK UIMessage这样你就可以投出 message.raw as UIMessage。 。 。 .

框架帮助者

@chat-adapter/web/react 输出薄薄的包装 @ai-sdk/react是因为 useChat 预配置为 DefaultChatTransport数字 :

import { useChat } from "@chat-adapter/web/react";

const { messages, sendMessage, status, stop, regenerate } = useChat({
  api: "/api/chat",        // default
  threadId: "support-1",   // becomes useChat's `id` and the request body's `id`
});
选项说明
apiWeb适配器路由的API端点. 默认为 /api/chat。 。 。 .
threadId聊天- sdk 线程 id — 请求体的表面 id 这样服务器就可以获得聊天-sdk线程 id. 大力推荐. 倒计时 id 从 ChatInit。 。 。 .
experimental_throttleThrottle在ms中等待聊天消息和数据更新.
resume是否恢复当前聊天生成流 .
退缩所有其他选项都通过 @ai-sdk/react是因为 useChat。 。 。 .

用于高级配置(海关运输、响应拦截器等) @ai-sdk/react是因为 useChat 直接——包装上没有什么神奇.

@chat-adapter/web/vue 出口a useChat 返回 Vue 反应的工厂 Chat 实例 @ai-sdk/vue数字 :

<script setup lang="ts">
import { useChat } from "@chat-adapter/web/vue";

const chat = useChat({ api: "/api/chat", threadId: "support-1" });
</script>

<template>
  <div v-for="msg in chat.messages" :key="msg.id">
    <template
      v-for="(part, index) in msg.parts"
      :key="`${msg.id}-${part.type}-${index}`"
    >
      <p v-if="part.type === 'text'">{{ part.text }}</p>
    </template>
  </div>
</template>

@chat-adapter/web/svelte 出口a useChat 返回 Svelte 反应的工厂 Chat 实例 @ai-sdk/svelte数字 :

<script lang="ts">
  import { useChat } from "@chat-adapter/web/svelte";

  const chat = useChat({ api: "/api/chat", threadId: "support-1" });
</script>

{#each chat.messages as msg (msg.id)}
  {#each msg.parts as part, index (`${msg.id}-${part.type}-${index}`)}
    {#if part.type === "text"}<p>{part.text}</p>{/if}
  {/each}
{/each}

与反应助手不同,Vue和Svelte返回 Chat 直接出现。 访问 chat.messages, (中文(简体) ), chat.sendMessage(), (中文(简体) ), chat.status,以及 chat.stop() 而不是去结构化.

配置

选项需求说明
userName对Bot用户名. 聊天 sdk 要求的提及检测( S)@username)并种子助理消息的机器人身份.
getUser对(request: Request) => WebUser | null | Promise<WebUser | null>。从输入的 HTTP 请求中解析用户。 正在返回 null 生产出 HTTP 401.
protocol没有"ai-sdk" (违约)或 "ag-ui". 请求和流式答复的无线电协议。 使用 "ag-ui" 给TanStack AI和其他AG-UI客户端.
persistMessageHistory没有在配置的状态适配器中坚持发送消息历史 。 默认 : true。 。 。 .
threadIdFor没有从已解析的用户和使用Chat 对话 id 中获取聊天- sdk 线索 id 。 默认 : web:{user.id}:{conversationId}。 。 。 .
logger没有锁定实例( 默认为 ConsoleLogger("info")) (中文(简体) ).

特征

通讯

特性支助
邮件对
编辑信件没有(每个助理转弯都是新鲜的回音)
删除信件没有
文件上传否(推迟到v2)
流线原生( SSE: AI SDK UI 消息流或 AG- UI)
已排定的消息没有

丰富内容

特性支助
卡片格式只在v1(卡/JSX被推迟到v2)中下标
按钮没有
表格是(全球增长机制降标)
模块没有

对话

特性支助
提及N/A(每个网络消息路由作为管理器)
添加反应没有
删除反应没有
打字指标不适用(使用Chat生成a) status (来自SSE反应本身)
模式对.. isDM: true 每个线程

信件历史

特性支助
获取信件Via 状态适配器缓存( 无平台 API)
获取单个消息没有
获取线索信息是(合成)
获取频道消息通过状态适配器缓存
列表线索没有
后频道消息没有

v1 范围

在: 文本 + 标记下, 本地流线, DM 风格的路由, 持续的信息历史, 中止通过 request.signal。 。 。 .

退出( 推迟至 v2 ): 卡/JSX渲染,反应,模式,文件上传,编辑/删除,多塔布主动推.

解决问题

每个请求返回401

  • getUser 正在返回 null 或掷出. 在其中添加一个日志以确认请求实际包含您期望的会话 .
  • 饼干没有被转发——检查一下 useChat 被挂载在与 /api/chat (或您的运输通过证书).

每个请求返回 400 “无效用户 ID ”

  • 身份证归来 getUser 包含一个 : 字符,将损坏线条编号的回转。 将内部的标识规范化 getUser (例如, id.replace(/:/g, "_") 或基础64-编码它.

useChat 在每次渲染时重现状态

  • 别走 id: undefined 改为 useChat- 内部的包裹守卫 - 但是如果你打电话 @ai-sdk/react是因为 useChat 直接删除 id 而不是通过 undefined。 。 。 .

thread.messages 为空

  • persistMessageHistory 实值 false 没有任何平台-侧面的历史可以倒退。 准备吧 true (默认). 适配器从不通过请求体 messages[] 因此,状态适配器是先前转弯的唯一来源.

请求退回 400 “信件的最后一项必须是用户信件”

  • 适配器只处理新用户转动. 客户端工具结果和自动重新提交(例如, useChat是因为 sendAutomaticallyWhen)发送一个以助手或工具消息结尾的正文,不支持.

AI 编码代理

如果您使用OpenAI Codex, Claude Code, 或 Cursor 等AI编码代理, 在写入代码前安装 Chat SDK 技能, 使其了解 SDK API, 适配器模式, 以及项目常规 .

npx skills add vercel/chat

技术参考文献 node_modules/chat/docs,加上已发布的软件包中的适配器指南和启动模板.

您也可以安装 Vercel 插件 包括Chat SDK技术与专家代理、代理斜线指令

npx plugins add vercel/vercel-plugin

插件是可选的;单是技能就足以用Chat SDK来构建.

关于可代理阅读的文件,见 聊天- sdk.dev/llms.txt (页数索引)或 聊天- sdk.dev/llms- full.txt (全文).

许可证

麻省理工学院

版本与发布记录

@chat-adapter/web 共发布 20 个版本,首次发布于 2026/05/08;过去 12 个月发布了 20 个版本。最新版本附带 npm provenance 构建来源证明,可追溯到公开的 CI 构建记录。

版本发布日期距今
4.44.0latest2026/11/026 天前
4.43.02026/10/1921 天前
4.42.02026/10/1425 天前
4.41.12026/09/291 个月前
4.41.02026/09/181 个月前
4.40.02026/09/052 个月前

关于 @chat-adapter/web 的常见问题

@chat-adapter/web 是什么?

Chat SDK的网络适配器——浏览器在AI SDK或AG-UI(TanStack AI)流协议上的聊天UI

如何安装 @chat-adapter/web?

在项目目录运行 npm install @chat-adapter/web,或使用 pnpm add / yarn add / bun add。

@chat-adapter/web 支持 TypeScript 吗?

支持。包内自带 TypeScript 类型声明(package.json 声明了 types 入口),安装后即可获得类型提示,无需再安装 @types 包。

@chat-adapter/web 支持 ESM 还是 CommonJS?

以 ES Module 形式发布,推荐使用 import 引入。在 CommonJS 项目中,Node.js 20.19+ / 22.12+ 可以直接 require() 不含顶层 await 的 ES Module,更早的版本需要改用动态 import()。

@chat-adapter/web 需要什么版本的 Node.js?

package.json 的 engines 字段要求 Node.js >=20。版本不符时 npm 默认只给出警告,开启 engine-strict 后会拒绝安装。

@chat-adapter/web 可以商用吗?

@chat-adapter/web 使用 MIT 许可。宽松许可:允许商业使用、修改和再分发,通常只需在分发时保留原版权与许可声明。以上为概括,不构成法律意见,请以许可原文为准。

@chat-adapter/web 的下载量有多少?

根据 npm 官方下载统计,@chat-adapter/web 在 2026/10/10 – 2026/11/08 这 30 天内被下载 81,011 次,日均约 2,700 次。下载量会把 CI 构建、镜像同步和作为其他包依赖的安装一并计入,适合横向比较热度,不能直接等同于使用人数。

@chat-adapter/web 还在维护吗?

最新版本 4.44.0 发布于 2026/11/02(6 天前);至今共发布 20 个版本,其中过去 12 个月发布了 20 个;首次发布于 2026/05/08。发布频率只是参考信号:功能稳定的工具可能很少需要更新,建议结合源码仓库的 issue 和提交记录判断。