# @coveo/thermidor 中文文档

规范地址：https://npmcn.com/package/%40coveo/thermidor/

版本：0\.9\.0
npm 元数据更新时间：2026-11-10T16:31:04.348Z
中文译文更新时间：2026-11-14T07:57:59.924Z
软件包许可：Apache-2\.0

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

原始 npm 页面：https://www.npmjs.com/package/%40coveo/thermidor
原文对照：https://npmcn.com/package/%40coveo/thermidor/?lang=original
源码仓库：https://github.com/coveo/ui-kit

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

- 包体积（解压后）：196 kB，45 个文件
- 模块格式：ES Module
- TypeScript 类型：包内自带
- Node.js 要求：^22\.11\.0 \|\| ^24\.11\.0
- 运行依赖：1 个
- peer 依赖：zod 3\.25\.76 \|\| ^4
- 首次发布：2026-06-25T14:35:11.476Z
- 最新版本发布：2026-11-10T16:31:03.875Z
- 近 30 天下载量：2116（2026-10-11 至 2026-11-09，npm 官方下载统计）
- 已发布版本数：15（近 12 个月 15 个）

## 中文简介

用于搜索和谈话体验的统一、框架不可知头引擎的实验软件包

## 安装

```sh
npm install @coveo/thermidor
```

也可以使用：`pnpm add @coveo/thermidor`、`yarn add @coveo/thermidor`、`bun add @coveo/thermidor`

## README

# 库维奥热电站

`@coveo/thermidor` 是一个实验性,框架不可知的客户端 一个单一,状态,意图的路径 **统一反向终点**它暴露了一个工厂 `createSession(config)` ——这个返回 a `Session`: 一个简单的可观测列表 `Turn`s 从服务器发送事件(SSE)流中折叠出,外加一个单一的动作发送出入口直接接通了渲染器.

包裹是私人的,实验性的,只消耗在这个单体内(由 `samples/thermidor/demo-schema-react`) (中文(简体) ).

> 有一个 **没有引擎,没有接口层,没有Redux/RTK,没有每个端点外观**旧订正中提及这些层面已过时.

## 这个想法

服务器串流图定义 [A2UI (英语)](https://github.com/google/A2UI) 组件; 客户端生成服务器发送的内容。 瑟米多的工作是将消费者的输入传递到端点,将流出的结果折叠成可观察到的转折列表——它不会在折叠后产生任何用例行为. 合同计划,端点URL,以及环境背景都是由消费者注入的,所以一个单一的软件包构建服务于公共,内部(私人-注册计划)和代理部署.

组件状态旅行 **内入** 通过 A2-UI 数据模型: 服务器发送 `updateDataModel` 业务 `/state/<id>`,而被冻结的渲染器通过A2-UI Data Binding(`{ path: <JSON Pointer> }`)与该数据模型相对. 制作者是“哑巴”:他们得到解析状态 `props` 从不给控制器水分 也不加入快照 A2-UI是唯一支持的状态源. 此内置模型取代了早先的远程控制器 / AG- UI `StateSnapshot` 设计.

## 公众表面

```typescript
import {createSession} from '@coveo/thermidor';
import {ComponentContractsSchema} from '@coveo/thermidor-schema';

const session = createSession({
  organizationId: 'my-org',
  accessToken: 'xx-token',
  agentConfigurationId: '00000000-0000-0000-0000-000000000000', // the configured agent that answers the session
  trackingId: 'my-tracking-id',
  contracts: ComponentContractsSchema, // injected Zod discriminated union (Zod 3 or 4)
  navigatorContextProvider: () => getNavigatorContext(), // required; includes language, country, currency
  commerceContextProvider: () => ({cart: getCart()}),
});

session.subscribe(() => render(session.getSnapshot()));

await session.dispatchAction({name: 'submitPrompt', payload: {prompt: 'show me running shoes'}});
```

`createSession(config)` 返回 a `Session` 完全暴露:

| 成员 | 目的 |
| --- | --- |
| `contracts` | 本次会话中注入的合同计划(只读)可以验证. |
| `turns` | 仅读可观察列表 `Turn`s从溪来折叠(最初为空). |
| `initialization` | 运行 `initialize` a. 会议开幕的行动,或 `undefined`。见 [会议开幕](https://npmcn.com/package/%40coveo/thermidor/#readme-opening-the-session)。 。 。 . |
| `surfaces` | 会话的每个活表面,按创建顺序排列,由谁运行创建. |
| `a2uiMessages` | 会话的整个渲染器流,为A2-UI v0.9形状. 它只会增长:将每个新消息反馈给一个渲染器一次. |
| `state` | 每个活地表的验证数据模型,由地表id键入. |
| `actionError` | 最后一个失败的组件动作( X)`ActionError`数字 : `message`, (中文(简体) ), `component`, (中文(简体) ), `name`, (中文(简体) ), `surfaceId`, (中文(简体) ), `sourceComponentId`),或 `undefined`。 。 。 . |
| `request` | 发出的请求,或 `undefined` 当闲置。 见 [一次一个请求](https://npmcn.com/package/%40coveo/thermidor/#readme-one-request-at-a-time)。 。 。 . |
| `subscribe(listener)` | 记录每次更改转折列表、初始化、, `actionError` 或者说 `request`。 。 。 . |
| `getSnapshot()` | `turns`, (中文(简体) ), `initialization`, (中文(简体) ), `surfaces`, (中文(简体) ), `a2uiMessages`, (中文(简体) ), `state`, (中文(简体) ), `request` 财务报告和审定财务报表 `actionError` 作为永恒的 `SessionSnapshot`,更改时替换. |
| `dispatchAction(message)` | 提示的单个切入点( Q)`submitPrompt`和组件动作,直接作为渲染器的 `onAction`。 。 。 . |
| `cancel()` | 停止活动流 . |
| `retry(turnId)` | 在错误时重新提交上个回合的输入:它的快取,或打开它的动作. |
| `serialize()` | 将笔录序列化为已版本 `SerializedSession`。 。 。 . |

`subscribe` 财务报告和审定财务报表 `getSnapshot` 不依赖 `this`,所以它们可以通过引用来传递给任何通过引用来比较快照的商店,比如React's `useSyncExternalStore(session.subscribe, session.getSnapshot)`。软件包本身取决于任何框架.

混凝土 `contracts` 类型 `createSession` 呼叫站点线索未断 `Session`,因此组件类型、动作名称和有效载荷在呼叫地点保持完全打入(否) `string`,没有 `never`,没有 `unknown`) (中文(简体) ).

## 会议开幕

1\. 会议开幕: `createSession` 发送一个 `initialize` 返回后动作一个微任务,所以在同一任务中订阅的听众会看到它开始。 它没有表面或源部件,因为还没有部件。 当它飞行时, `session.request` 实值 `{kind: 'initialize'}`它穿过 [单一请求规则](https://npmcn.com/package/%40coveo/thermidor/#readme-one-request-at-a-time) 和冲突再试,并采用会话编号 从它的运行,像一个提示。 制作人以会话外壳作为普通表面回答,如它的搜索框.

运行记录为 `session.initialization` (单位:千美元)`activities`, (中文(简体) ), `status`, (中文(简体) ), `error`从不作为转弯。 失败 `initialize` 未重审 : `initialization.status` 变成 `'error'`,第一个提示仍然打开会话. `cancel()` 停止它的任何请求。 恢复的会话从不发送,也没有创建会话 `initialize: false`,用于测试或用于在渲染时创建会话的服务器.

## 调度行动

`session.dispatchAction` 是消费者的单一行动入口。 它接受两种信息.

### 提交提示

在 A2-UI 构成外输入的即时键, 如集成器的搜索框中, 是 a `SubmitPromptAction`数字 :

```typescript
session.dispatchAction({name: 'submitPrompt', payload: {prompt: 'show me running shoes'}});
```

它打开了一个新的流转方向 记录了转弯时的提示 `input.prompt`,然后将其输入到反向端点。 它不需要变换组件或主动转弯,因此它也开启了会话的第一个转弯. 当另一个请求在逃时,它会等待它(参见: [一次一个请求](https://npmcn.com/package/%40coveo/thermidor/#readme-one-request-at-a-time)),以及 `retry(turnId)` 重新开出一圈.

### 构成部分行动

组件动作是标准 A2-UI 客户端到服务器消息( Name`A2uiClientMessage`被冻结的制造器将手伸到其 `onAction` 处理器,所以它有线 没有适配器:

```typescript
<A2UIProvider catalog={catalog} onAction={session.dispatchAction}>{/* … */}</A2UIProvider>
```

鉴于一个消息, `dispatchAction` 打开它 `userAction`,从会话的活出地表取回调度部件的区别性物质,无论由哪个运行产生,对照组件内部注入的合同验证动作有效载荷,并在成功时将动作定位到反向终点.

制作方宣布为打开转盘的动作,如后续芯片或搜索选项,作为对话的新转盘被回答,如提示. 制片人用表面宣布,在AG-UI中 `metadata` 简况`metadata.turnOpeningActions`,通过表面的ID),所以消费者宣布无所事事,而转弯会一经hopper取出动作就打开. 这样的行动开启了一个新的接踵而至的转折 `input.action` 记录它(组件、动作名称、地表代号、源节点和有效载荷),然后转弯成为活转。 转弯时的表面 一直没有接受动作 它不需要主动转弯,所以在外壳上打开的转弯动作打开会话的第一个转弯. 任何其他动作只更新表面:其表面快照用活转来记录,或用 `session.initialization` 在第一个转弯之前.

没错 **火灾和遗忘**: 回归的承诺总是解决,而永不拒绝,所以消费者不需要 `.catch`。一个没有 `userAction`,没有 `sourceComponentId`,一个解析为无组件的节点,或者一个内部验证失败被丢弃,只发出一个 dev-exected 警告,而什么也没有发出.

### 一次一个请求

瑟米多每次发送一个请求, `initialize`,激励和构成行动相同,但 [并行行动](https://npmcn.com/package/%40coveo/thermidor/#readme-concurrent-and-cached-actions) 制片人会宣布。 请求中发出的命令,是被扣留的;任何警告,都不被发出来;命令中发出的警告,是无效的。 每个 `dispatchAction` 承诺一旦结束就会解决.

-   `session.request` 正在发送的请求( e)`{kind: 'initialize'}`, (中文(简体) ), `{kind: 'prompt', turnId}` 或者说 `{kind: 'action', component, name, surfaceId, sourceComponentId, turnId?}`,没有 `turnId` 在第一个回合之前),或 `undefined` 当闲置。 一个动作的运行计数, 包括后续。 同步读取,或者通过 `subscribe`,以锁定或淡化接口,并延迟发送,直到会话自由. `component` 是发送节点的区别者,所以消费者可以按其自己的行动清单,如按部件和行动名称,按与下列单位签订的合同键入的使其表面能够使用的动作清单 `ComponentActionNames`。 。 。 .
-   `cancel()` 在飞行中停止请求,但 `session.request` 等它没有受伤 以后再做一些微小任务 之后就发出来 `cancel()` 被扣留。 等着 `request` 改为 `undefined`,通过 `subscribe`在发送下一个之前.

### 同步和缓存动作

生产者可以在回合之外回答一些行动,例如针对突出建议即时产品. 在AG -UI中公布它们与地表 `metadata` 在宣布开启动作时

```json
"metadata": {
  "concurrentActions": {"<surfaceId>": {"fetchInstantProducts": {"cache": {"ttlMs": 60000}}}}
}
```

每项同时进行的行动可以包括: `cache` 政策、答案的寿命;没有答案,答案就得不到重复。 最新宣布的表面胜出,空入则撤销. 渲染器只发送:它没有缓存,没有重试和等待自由会话.

-   无论飞行中的请求如何,同时发出一个行动,从不设定 `session.request`即时或 `cancel()` 不制止它,它将被扣留,直到会议有它的迹象.
-   只应用从节点发送的最新消息 。 飞行中一个更古老的请求被中止,除非动作被缓存:然后它运行到最后,所以它的答案被缓存,一个带有同一种有效载荷的调度会加入它而不是发送另一个.
-   在宣布的寿命内再次以相同有效载荷发送的缓存动作,从会话缓存中解答而无所寄出. 缓存保存了最后100个答案,活在记忆中,从未被序列化.
-   它的答案可能只更新会话已经持有的节点的数据模型;其他任何东西,如新的表面或组件,都会被丢去并附带一个 dev-leven的警告,答案是: `metadata` 未读。 它的书写范围 `session.a2uiMessages` 财务报告和审定财务报表 `session.state`,但是没有运行记录它们:后来录制的写到同一路径的文字代替它们, `session.serialize()` 离开它们,一个恢复的会话会显示该州最后记录的左跑,所以渲染器再次问起.
-   它的失败,包括一个被拒绝的请求,是一个虔诚的警告. 没有 `session.actionError` 更改不运行 .

### 乐观价值

为了显示一个手势的预期值,直到会话解答为止,显示从手势被发出到其发出承诺决定为止的价值,然后让位于制作者的价值. 一个返回它的渲染器 `onAction` 处理者的承诺 从自己的派遣手 回来 `session.dispatchAction` 答应我,等待造物师的指令就够了 热子不依赖于UI框架,因此任何状态机制都有效. 与反应 `useOptimistic`例如,等待发送的过渡会持续那么长:

```tsx
const [values, addOptimisticValues] = useOptimistic(producerValues);

startTransition(async () => {
  addOptimisticValues(values.map((v) => (v.value === 'Nike' ? {...v, state: 'selected'} : v)));
  await renderer.dispatchAction({event: {name: 'toggleSelect', context: {value: 'Nike'}}});
});
```

乐观值让位于制作方的手势一结束,无论结果如何,所以一个失败或被扣留的手势不需要回滚. 热力学从不计算预期值:整数是.

### 货币冲突

当“网关”仍然忙于处理关于届会的另一个请求时,它拒绝新的请求(`409`, (中文(简体) ), `AGENT:ACTION_IN_FLIGHT`) (中文(简体) ). 热电站自动重试最多可达30秒,而一个恢复的冲突却无所表现. 如果它放弃了:

-   a 一个 **动作** 不打开一转而不改变任何转折,从而释放出乐观的持有 `session.actionError` (一) 报告情况,直至发出下一个行动或提示;
-   a 一个 **打开转弯的动作** 套装 `session.actionError` 轮到他 `error`,可用 `retry(turnId)` 这是最后的转折;
-   (单位:千美元) **提示**轮到 `error`,可用 `retry(turnId)` 而这是最后的转折.

## 转动/回转模式

每个转一对 `input` 及其流出 `response`数字 :

```typescript
interface Turn {
  id: string;
  input: {prompt?: string; action?: TurnAction}; // the prompt, or the action that opened the turn
  response: TurnResponse;
  status: 'streaming' | 'complete' | 'error';
  error?: string; // present iff status === 'error'
}

interface TurnResponse {
  activities: Activity[]; // raw snapshot log, latest snapshot per messageId, defaults to []
  surfaces: DiscoveredSurface[]; // the live surfaces this turn created
  agent?: {messages: AgentMessage[]; reasoningSteps: ReasoningStep[]}; // present only when the router invoked an agent
}
```

`activities` 路由中立,而且始终存在. `agent` 仅当路由器为转弯而引用代理人时才会出现。 消费者读取 `turn.input.prompt`, (中文(简体) ), `turn.response.surfaces` (在哪里画转弯的块)和 `turn.response.agent?.messages` 编号 : `turn.response.agent?.reasoningSteps`。 。 。 .

### 会话范围表面

地表活在会话中,而不是创造它们的转弯. 会话来源于一个命令的活动日志:初始化的活动,然后每个转弯. 水面从它的 `createSurface` 直至 `deleteSurface`以运行者为准 `createSurface` 对于活的id取代了表面, 所以一个生产者薄荷一个新的id 对于每一个新的表面.

-   `session.surfaces` 按创建顺序列出每个活表面;一个表面,代理删除它,一个再创建移动到结尾。 每个转弯 `response.surfaces` 列出生成的活表面; 找到一个没有生成的, 如外壳, 由其 `rootComponentType`。只有在创建它的运行流出时才列出加载占位符:当其转动或初始化流出时,或者当飞行流中的请求进入该运行而未发现其已留下时;留下的代理人(取消运行、出错、恢复会话)之一离开列表,所以消费者为列出的每个表面画出一个骨架 `isLoading` 别动.
-   `session.a2uiMessages` 按照到达顺序是整个会话的渲染流。 它只生长,所以一个单一的渲染器每个新消息都会被喂入一次. a 之前,一个 `createSurface` 代替活表面,它携带一个 `deleteSurface` 因为它没有在表面做活的手术, 因为造物者拒绝两者。 它之所以存在,是因为Agent Gateways exits A2-UI v1.0,而每个可用的渲染器消耗v0.9:热电压降低消费者代表的流(已记录的临时债务,见下文).
-   `session.state` 是每个活地表的验证数据模型,由地表id键入,以所写的运行为准,上面有同时动作的答案.
-   一个动作解决了整个会话的活表面的源组件,所以更早运行的表面会不断接受动作. 它的运行只更新了表面:它的表面快照用活转来记录,或者在一转前进行初始化,它永远不会改变一转或初始化的状态或反应. 当它失败,不管终点拒绝它,它会流出 `RUN_ERROR`,其流结束没有终端事件或请求无法构建, `session.actionError` 识别此动作( e)`message`, (中文(简体) ), `component`, (中文(简体) ), `name`, (中文(简体) ), `surfaceId`, (中文(简体) ), `sourceComponentId`),因此消费者可以显示它来自的街区旁边的故障.

每个 `DiscoveredSurface` 携带 `surfaceId`, (中文(简体) ), `rootComponentType`,以及 `isLoading`,这是 `true` 当表层的数据模型宣布时 `isLoading: true` (用于 `rootComponentType`) (中文(简体) ).

## 验证和显示值

-   **客户端验证保留,透明.** 注射时 `contracts` schema仍然是唯一的验证来源,但消费者从未运行Zod并写出任何适配器胶. 入境 `updateDataModel` 行动在应用到 `session.state`,与每个活地表面的组件相对抗;出站动作有效载荷在POST之前的私人发送路径被验证. 两种边界都生活在核心内. `session.a2uiMessages` 来源于生源流,所以渲染器仍然收到一个操作,验证从 `session.state`,且组件状态由 `createSurface.dataModel`,它永远不会被验证.
-   **显示值格式是代理生成的.** 渲染器显示它通过其 `{ path }` 绑定; Thermidor 不重塑显示的值.

## 注射计划、终点和上下文

-   **合同计划a** 由消费者注入的Zod受歧视工会`contracts`)是组件状态和动作负载验证的唯一来源。 通过结构打字接缝(`ContractsSchema` 编号 : `ComponentContractSchema` 编号 : `ParsableSchema`)只读出公共 Zod API,因此它宣布不依赖任何特定的计划包. 它宣布 `zod` 作为跨两大类的同伴依赖关系`3.25.76 || ^4`),所以验证通过单一共享 `zod` 实例通过注入的图解。 由Zod 3制造出制造器的消费者注入了Zod 3图案,例如: `@coveo/thermidor-schema/zod3`。 。 。 .
-   **终点** 何时 `endpoint` 提供客户邮递服务。 如果缺席,就解决了 `https://{orgId}.org.coveo.com` 并附加固定的逆向路径 `/api/preview/organizations/{orgId}/agents/commerce/agui/converse`。 。 。 .
-   **上下文提供者** —— 说 `navigatorContextProvider` (所需)和 `commerceContextProvider` 是每个请求读取的同步函数。 导航器上下文包含请求的 `language`, (中文(简体) ), `country` 财务报告和审定财务报表 `currency`。上下文从不存储在会话上,也从不序列化.

## 序列化

`session.serialize()` 生成一个版本 `SerializedSession` (整数) `version >= 1`),不同于运行时间 `Turn` 类型。 传回去吧 `sessionToRestore` 内 `createSession` 继续谈话 开始,转弯和会话记录 `state` 表面和成形器流从未存在过 `activities` 在恢复时); 转弯或初始化在中游持续; 降级为 `error` 与 `'Stream was interrupted'`保留它持有的东西.

## 记录的临时债务和范围外的项目

以下是故意的 **尚未执行** 并记录为债务或延期工作:

-   **临时地表引出** —— 说 `surfaces` 是来自 `activities`,注释为临时;核心解释为否 `rootComponentType`;消费者阅读. 服务器发送打入的路由后, 它将被退役 .
-   **A2-UI v0.9 渲染器投影** —— 说 `session.a2uiMessages` 降级代理Gateway的v1.0流为今天的v0.9渲染器. 一旦 V1.0 有能力的渲染器存在,则在断裂变化中删除 .
-   **渲染器流绕过验证** - 输入操作,即中途验证从 `session.state` 仍然通过 `session.a2uiMessages`,组件的种子由 `createSurface.dataModel`,它永远不会被验证。 固定必须覆盖两条路.
-   **在渲染器边界上强制操作负载打字** - 变形手 `dispatchAction` 输入的动作信息很松散,因此,每个组件的动作打字由公约适用(消费者选择输入生成的 `XxxAction` 而不是在边界上执行。 如果软件包拥有约束性分辨率,则以后可以恢复.
-   **软件包重命名** ——被推迟为低价;一揽子措施仍然有效 `@coveo/thermidor`。 。 。 .

## 发展

```bash
pnpm --filter @coveo/thermidor build      # build project
pnpm --filter @coveo/thermidor test       # run unit + property tests
pnpm --filter @coveo/thermidor test:dts   # validate public API surface (incl. DX type test)
```

## 建筑

见 [架构指南](https://npmcn.com/package/%40coveo/thermidor/docs/architecture.md) 内部结构,以及 [`docs/internal/adr`](https://npmcn.com/package/%40coveo/thermidor/docs/internal/adr)。 。 。 .

## 常见问题

### @coveo/thermidor 是什么？

用于搜索和谈话体验的统一、框架不可知头引擎的实验软件包

### 如何安装 @coveo/thermidor？

在项目目录运行 npm install @coveo/thermidor，或使用 pnpm add / yarn add / bun add。它还需要宿主项目提供 peer 依赖：zod（3\.25\.76 \|\| ^4）。npm 7 及以上与 pnpm 8 及以上默认会自动安装必需的 peer 依赖，Yarn 需要手动安装。

### @coveo/thermidor 支持 TypeScript 吗？

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

### @coveo/thermidor 支持 ESM 还是 CommonJS？

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

### @coveo/thermidor 需要什么版本的 Node\.js？

package\.json 的 engines 字段要求 Node\.js ^22\.11\.0 \|\| ^24\.11\.0。版本不符时 npm 默认只给出警告，开启 engine-strict 后会拒绝安装。

### @coveo/thermidor 可以商用吗？

@coveo/thermidor 使用 Apache-2\.0 许可。宽松许可：允许商业使用、修改和再分发，并附带明确的专利授权；分发时需保留许可与 NOTICE 文件，修改过的文件要注明改动。以上为概括，不构成法律意见，请以许可原文为准。

### @coveo/thermidor 的下载量有多少？

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

### @coveo/thermidor 还在维护吗？

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

