# @cubos/agent-sdk-react 中文文档

规范地址：https://npmcn.com/package/%40cubos/agent-sdk-react/

版本：0\.0\.1174337
npm 元数据更新时间：2026-11-07T11:20:20.205Z
中文译文更新时间：2026-11-11T04:30:30.112Z
软件包许可：SEE LICENSE IN LICENSE

本文由上游 README 翻译，可能存在偏差，请结合原文核对 API、命令与配置。版权与许可归原作者所有。

原始 npm 页面：https://www.npmjs.com/package/%40cubos/agent-sdk-react
原文对照：https://npmcn.com/package/%40cubos/agent-sdk-react/?lang=original

## 关键信息（来自 npm 元数据）

- 包体积（解压后）：175 kB，11 个文件
- 模块格式：ES Module
- TypeScript 类型：包内自带
- 运行依赖：0 个
- peer 依赖：react \>=18，@cubos/agent-sdk 0\.0\.x
- 首次发布：2026-09-08T15:04:52.472Z
- 最新版本发布：2026-11-07T11:20:19.989Z
- 近 30 天下载量：11118（2026-10-11 至 2026-11-09，npm 官方下载统计）
- 已发布版本数：113（近 12 个月 113 个）

## 中文简介

Cubos代理对话的无头回放钩子 API. 没有DOM——在React Industrial工作.

## 安装

```sh
npm install @cubos/agent-sdk-react
```

也可以使用：`pnpm add @cubos/agent-sdk-react`、`yarn add @cubos/agent-sdk-react`、`bun add @cubos/agent-sdk-react`

## README

# @cubos/代理服务器

Cubos代理对话的无头回放钩子 API.

**没有DOM.** 套件不做,不进口 `react-dom`,所以一样 钩子驱动一个网络应用程序, React Introduct, 或者其他任何内容 React运行. 测试中 如果一个浏览器全局或一个 `<div>` 潜入.

```sh
npm install @cubos/agent-sdk @cubos/agent-sdk-react
```

## 整个事情

```tsx
import { AgentProvider, useConversation } from "@cubos/agent-sdk-react";

function App() {
  return (
    <AgentProvider
      baseUrl="https://agent.acme.com"
      getToken={async () => (await fetch("/api/agent-token").then((r) => r.json())).token}
    >
      <Chat />
    </AgentProvider>
  );
}

function Chat() {
  const [id, setId] = useState<string | null>(null);
  const { messages, send, activity } = useConversation(id, {
    agentSlug: "support",
    onCreated: (conversation) => setId(conversation.id),
  });

  return (
    <>
      {messages.map((m) => (
        <div key={m.id} data-role={m.role}>
          {m.content}
        </div>
      ))}
      {(activity.isProcessing || activity.hasPendingTurn) && <Typing />}
      <Composer onSubmit={send} />
    </>
  );
}
```

`getToken` 必须返回 **短寿命最终用户代号**,在服务器上刻出. Api key是全租户,绝对不能联系客户端. SDK又问了一遍 `forceRefresh` 401之后,所以过期 为你处理.

## 两个钩子,你拿着中间的ID

没有钩子拥有"什么对话是开放的"。 那是你的应用程序 状态 —— 以上示例中的组件状态, 真实的路由参数 ——和 把它从包中排除出去是应该的 `/c/:id` 工作不同步 任何东西.

```tsx
const [selectedId, setSelectedId] = useState<string | null>(null);

const list = useConversationList();
const conversation = useConversation(selectedId, {
  agentSlug: "support",
  onCreated: (created) => setSelectedId(created.id),
});
```

唯一值得了解的行为是: **第一次对话是创建的 消息,而不是用户点击"新聊天"时.** 否则,每一个被抛弃的空白 列表中留下了一行空行 . `send` 调查两起案子,所以你的UI从来没有 特例"还没有谈话" 刚刚通过 `null` 直至 `onCreated` 火灾。 已经在屏幕上的信息 幸存的交接.

双钩相通,相向相通,故名相分: `list.hasMore` 编号 : `list.loadMore` 走开 **对话框列表**· ; `conversation.hasOlder` 编号 : `conversation.loadOlder` 走开 **打开 对话的历史**。 。 。 .

## 无限历史,活现

`useConversation` 打开一页历史并点出实时流 那页的结尾,所以一年来的对话 需要开一页 并且每次重新连接都要花费一页.

```tsx
const { messages, hasOlder, isLoadingOlder, loadOlder } = useConversation(id);

// Whatever your list uses to notice the top: a scroll handler, an
// IntersectionObserver on a sentinel, FlatList's onEndReached inverted.
const onReachedTop = () => {
  if (hasOlder && !isLoadingOlder) void loadOlder();
};
```

两个细节 为你处理,一个不是:

-   **道口无隙.** 溪流从页面光标恢复 服务器在启动前重放所有经过它的东西, 因此发送信件时 页面在飞行中到达 而不是消失.
-   **秩序稳定.** 页面、活框和你自己的乐观信息 由 id 合并,按顺序排序, 所以一个页面登陆 中转不能洗 记录.
-   **螺旋锚是你的.** 将列表向上增加,而 滚动偏移保留, 它读作跳跃 。 记录 `scrollHeight` 在此之前 电话 `loadOlder` ,然后在布局效果中添加差异——或者,在 网络,请 `useTranscriptAnchor` 从 `@cubos/agent-sdk-react-dom`,哪个 正好是这个加上了寻呼触发器.

重新打开用户已经访问过的对话 基础 SDK 缓存已装入对话框( 默认为内存) 和这些钩子 打开它,在留言到达时录音,然后恢复 缓存光标的流出,所以没有重放。 配置或替换 关于客户端的(`cache`, (中文(简体) ), `cacheMessageLimit`);见 `@cubos/agent-sdk` 读取.

`loadOlder` 决定它实际添加了多少信息。 历史页 以 **事件**,而不是通过信息,一个答复后面的工具呼叫可以填补一个 所以钩子一直呼唤 直到你没有 已经占领了土地, 一个呼叫总是 一个明显的后退一步。 读取 `0` 合并 `hasOlder`数字 : `false` 是谈话的开始, `true` (rare-扫描击中了它的页盖)表示再次呼叫.

## 代理回复中的组件

给钩子一张地图 **渲染器** 加减 **组件库** 此屏幕 可绘制,且该剂可在回复中使用这些组件:

```tsx
const { messages, renderMessage } = useConversation(id, {
  components: {
    Choices: (props) => <Choices {...props} onPick={send} />,
  },
  componentLibraries: ["support-widgets"],
  renderMarkdown: (text) => <Markdown>{text}</Markdown>,
});

// In your bubble. Null means the message has no blocks — every user message —
// so that is where your own rendering of `content` goes.
{
  renderMessage(message) ?? message.content;
}
```

这两个部分有不同的主人,这是有意的。 经纪人是什么 _告诉_ 关于一个组件——它的总结,每个道具的含义,JSON Schema, 实例——生活在一个组件库中,操作员的作者在 管理API,因为这些词 进入模型的背景逐字。 什麽 _绘图_ 这是你的。 您选择您拥有的屏幕所应用的库 打开; 钩子可以让他们在对话中, 在创建时聊天 从这里开始,从一个 `PUT` 当列表更改时.

服务器拒绝任何被启用的库无法解析的组件,并且 在信件被写入前 一个造型师从来没有看到它没有要求的形状. 无渲染器绘图的标签 没有,钩子记录了一个警告 它命名,因为这是一个无声的空白 回复。 反之亦然 **保存组件的渲染器无 继续提供图书馆服务**,因为这就是画 旧消息在 记录.

`renderMarkdown` 将散文画入组件周围。 没有它,减分 制作纯文本: 此软件包没有解析器, 您的应用程序已经 一个.

## 客户端工具: 代理机在您的应用程序中调用功能

```tsx
useConversation(id, {
  clientTools: {
    get_browser_context: {
      description: "Timezone, locale and local time, as this browser reports them.",
      inputSchema: { type: "object", properties: {} },
      readOnlyHint: true,
      handler: () => ({ timezone: Intl.DateTimeFormat().resolvedOptions().timeZone }),
    },
  },
  onClientToolError: (err) => console.error(err),
});
```

代理称, **转会暂停**你的管家跑来跑去 轮到 带着你回来的回来 处理器会随失败而发出答案 而不是离开代理 等待期限.

这对你来说有两件事 很容易用手做错

-   **一道溪来,不是两道.** 跑步者已经骑着车钩了 持有 -- -- a `client_tool_call` 框架推动它,每一次重联,所以 连接下行时发出的电话被接上而不是留到 过期。 在钩子外做这个意味着 第二次SSE 连接每 对话,针对一个服务器,该服务器会限制用户可持有多少个.
-   **初转正前所宣说.** 在空白板块上宣布工具 与创造对话的相同呼吸,所以代理已经可以到达 他们在初次答复时.

租赁 续约 慢处理器运行 重试结果 POST是SDK的基地,是SDK的基地 `serveClientTools`; 钩子只决定何时开始 并停下来.

## 水面 水面

| 钩子 | 它给你什么 |
| --- | --- |
| `useConversationList(opts)` | 现场名单,加 `archive`, (中文(简体) ), `loadMore` |
| `useConversation(id | null, opts)` | 信件、 待办事宜、活动、, `send`, (中文(简体) ), `sendAudio`, (中文(简体) ), `sendImages`, (中文(简体) ), `loadOlder`, (中文(简体) ), `renderMessage` |
| `useIdentity()` | 何人的行为,以及它可能使用的代理人 |
| `useAgentClient()` | 基础 `AgentClient`,对于任何没有包裹 |

`useConversation(null)` 有效且不打开连接——即空白 在谈话被选中之前先排队.

名单和谈话都是 **现场直播**: 钩子装入一页 历史中,请遵循该页结尾处的SSE流,然后从 准确的一点一滴。 民意调查 无效调查.

### 当溪水不活

投放是普通的, SDK 处理它: 它与回放重接, 重放 光标不会漏掉任何东西, 如果旧光标过期, 薄荷会重新表示 {\\fn华文楷体\\fs20\\bord1\\shad1\\1cHE0E0E0\\2cH000000}被活活活活的溪流所活活了 {\\fn华文楷体\\fs20\\bord1\\shad1\\1cHE0E0E0\\2cH000000}被活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活 连接 _无声_ - 一个电话 离开背景, 代理挂断了 由监视器在~30s内重新打开,因为服务器发送一个 每15秒和连续2次失手 都意味着插座不见了.

SDK无法修复的, 它报告. `useConversation` 返回 :

| 外地 | 含义 |
| --- | --- |
| `isStreamLive` | 现在连接。 第一次连接之前和一次空投与其再连接之间都是虚假的——谨慎的"重接..."提示,绝不出错 |
| `streamError` | 订阅 **死了,不会回来**: 令牌被拒绝两次, 对话已去, 或者服务器拒绝流 |

`streamError` 无法自行推断 因此,特工就再也不回答问题了,所以请表明这一点。 没有恢复 从它自动: 重挂起钩( 或更改) `conversationId` 转回 重新订阅. `useConversationList` 自己报告同样的事情 `streamError`。 。 。 .

## 信件

```ts
interface Message {
  id: string;
  role: "user" | "agent";
  content: string;
  attachments: Array<{
    id: string;
    kind: "image" | "audio";
    mimeType: string;
    bytes: number;
    label: string | null;
  }>;
  seq: number;
  at: string;
}
```

媒体挂断 `attachments`,以及 `content` 是随它而来的文字 图像标题,语音音符的转录. **两者都可以空出**这样 提交 `attachments` 即使当 `content` 是空白的.

语音信息是一体的 `Message` 携带剪辑 _财务报告和审定财务报表_ 页:1 复制, 在代理的 STT 模型完成前是空的 —— 您的提示 使玩家具有“trantext”状态.

字节来自 `useAgentClient().fetchAttachment(conversationId, message.id, attachment.id)`作为 `Blob` 而不是 URL: 信使在信头中行走, 所以 a 一个 `<img src>` 指向航道时,会到达未经认证。 把它包起来 平台,并在视图消失时发布.

发送图像是该图像的镜像 :

```ts
// Up to 10 as ONE message, so the agent reasons over the set rather than
// spending a turn per picture. `caption` becomes the message's text.
await sendImages(
  [
    { image: receipt, label: "receipt" },
    { image: statement, label: "statement" },
  ],
  "which charge is duplicated?",
);
```

A 类 `label` 命名一个模型的图像, 它可以回答“ 收据 ” 而不是"第二个图像".

`send` 附加乐观,并与服务器的回声调和,滚动 如果发送失败, 乐观复制返回 。 一个信息谁 `id` 开始于 `optimistic:` 尚未确认.

## 渲染

这个包裹是故意运送任何部件和CSS的——这就是保持它的原因 运行在 React 运行的地方。 真正通用且确实需要的棋子 dOM,住在隔壁 [`@cubos/agent-sdk-react-dom`](https://npmcn.com/package/%40cubos/sdk-react-dom)数字 : `AgentMarkdown` 制作一个 代理回复(GFM,栅栏码,TeX)和样式本身.

```tsx
import { AgentMarkdown } from "@cubos/agent-sdk-react-dom";

useConversation(id, { renderMarkdown: (text) => <AgentMarkdown>{text}</AgentMarkdown> });
```

Chat UI proper——泡泡,作曲,对话列表——是产品不同之处 大部分, 和一组样式化的组件 对于它要么太僵硬 无法使用或者太 相会可作供养.

`renderMessage` 这是唯一的例外,它没有使自己的问题: __ 将散文交给 __ 马克倒置渲染器. `renderBlocks` 没有钩子的函数是相同的,因为 您已持有信件 .

完整的例子——信息泡沫,一个有图像的作曲家 附件和语音记录、代理服务器组件、客户端工具、 对话列表——参见"仪表盘" `packages/web/components/chats/` 输入 寄存器,它建立在这些钩子上. 它写在这些钩子的背面 并打算复制和改变,不是 已安装.

## 原生反应

取钩入地清净. 在底部SDK有两个警告:

-   **流来.** 实时更新使用 SSE over `fetch` 响应流。 反应 本地默认的网络不流响应机构; 您需要抓取 实际的多填充(`react-native-fetch-api` 与 `react-native-polyfill-globals`),作为 `fetch`。 。 。 .
-   **传媒.** `sendAudio` 财务报告和审定财务报表 `sendImages` 带 `Blob`s,和 `fetchAttachment` 手一个回来。 录音,取出一幅相片,然后把一个blob变成某种东西 可显示性都是针对特定平台的——使用平台提供的内容.

组件和客户工具不需要额外的设备 : `renderMessage` 构建元素 与 `createElement`,而处理器是一个函数。  `render` 是一个土著 和任何其他组件一样.

## 常见问题

### @cubos/agent-sdk-react 是什么？

Cubos代理对话的无头回放钩子 API\. 没有DOM——在React Industrial工作\.

### 如何安装 @cubos/agent-sdk-react？

在项目目录运行 npm install @cubos/agent-sdk-react，或使用 pnpm add / yarn add / bun add。它还需要宿主项目提供 peer 依赖：react（\>=18）、@cubos/agent-sdk（0\.0\.x）。npm 7 及以上与 pnpm 8 及以上默认会自动安装必需的 peer 依赖，Yarn 需要手动安装。

### @cubos/agent-sdk-react 支持 TypeScript 吗？

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

### @cubos/agent-sdk-react 支持 ESM 还是 CommonJS？

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

### @cubos/agent-sdk-react 可以商用吗？

@cubos/agent-sdk-react 使用 SEE LICENSE IN LICENSE 许可。许可条款写在包内的独立文件中，请阅读该文件确认可否商用。以上为概括，不构成法律意见，请以许可原文为准。

### @cubos/agent-sdk-react 的下载量有多少？

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

### @cubos/agent-sdk-react 还在维护吗？

最新版本 0\.0\.1174337 发布于 2026/11/07（3 天前）；至今共发布 113 个版本，其中过去 12 个月发布了 113 个；首次发布于 2026/09/08。发布频率只是参考信号：功能稳定的工具可能很少需要更新，建议结合源码仓库的 issue 和提交记录判断。

