@qfei-design/make-ai-assistant 0.2.12 → 0.2.14

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (41) hide show
  1. package/PUBLIC_API.md +20 -20
  2. package/README.md +19 -13
  3. package/capabilities.json +2 -1
  4. package/dist/client-protocol.d.ts +24 -0
  5. package/dist/client-types.d.ts +420 -0
  6. package/dist/client.cjs +2 -0
  7. package/dist/client.d.ts +18 -0
  8. package/dist/client.mjs +1154 -0
  9. package/dist/conversation-BpmWa2VL.cjs +1 -0
  10. package/dist/conversation-DuqMadaQ.js +888 -0
  11. package/dist/conversation-management-DZROhXyK.js +229 -0
  12. package/dist/conversation-management-f1y0yRvt.cjs +1 -0
  13. package/dist/core/conversation-management.d.ts +15 -5
  14. package/dist/core/conversation.d.ts +6 -5
  15. package/dist/index.cjs +1 -1
  16. package/dist/index.mjs +4 -4
  17. package/dist/make-app.cjs +1 -1
  18. package/dist/make-app.d.ts +8 -69
  19. package/dist/make-app.mjs +236 -703
  20. package/dist/make-console.cjs +1 -1
  21. package/dist/make-console.mjs +1 -1
  22. package/dist/react/conversation-controls.d.ts +1 -1
  23. package/dist/react/make-ai-assistant.d.ts +1 -2
  24. package/dist/react/use-attachments.d.ts +3 -1
  25. package/dist/react/use-conversation-manager.d.ts +3 -2
  26. package/dist/react.cjs +62 -4
  27. package/dist/react.mjs +3268 -1794
  28. package/dist/sse.cjs +1 -1
  29. package/dist/sse.mjs +1 -1
  30. package/dist/styles.css +625 -137
  31. package/docs/backend-contract.md +3 -7
  32. package/docs/make-app-integration.md +23 -68
  33. package/examples/make-app/main.tsx +1 -1
  34. package/examples/make-app/transport.ts +36 -146
  35. package/package.ai.json +9 -6
  36. package/package.json +11 -3
  37. package/recipes.json +4 -3
  38. package/dist/conversation-CZfbgCXd.js +0 -1111
  39. package/dist/conversation-Cvh-IVRV.cjs +0 -1
  40. package/dist/make-app/protocol.d.ts +0 -27
  41. package/dist/make-app/stream.d.ts +0 -20
package/PUBLIC_API.md CHANGED
@@ -5,7 +5,7 @@
5
5
  - `@qfei-design/make-ai-assistant`:headless Artifact、会话、模板注册和 transport 合同。
6
6
  - `@qfei-design/make-ai-assistant/react`:React 助手壳、ArtifactRenderer 和平台模板。
7
7
  - `@qfei-design/make-ai-assistant/sse`:基于 Fetch、ReadableStream 的浏览器/现代 Node SSE transport;公开声明不要求 TypeScript `DOM` lib。
8
- - `@qfei-design/make-ai-assistant/make-app`:Make App AI 语义协议 adapter;网络请求、认证和 EventSource 创建均由宿主注入。
8
+ - `@qfei-design/make-ai-assistant/make-app`:Make App v1 UI adapter;使用标准 Client,异步读取能力后返回 AssistantTransport。
9
9
  - `@qfei-design/make-ai-assistant/make-console`:Make Console Agent/Session/Run 语义协议 adapter;认证请求和 EventSource 创建由 Console 宿主注入。
10
10
  - `@qfei-design/make-ai-assistant/testing`:Mock transport 和通用 fixtures,仅用于开发、测试与 Gallery。
11
11
  - `@qfei-design/make-ai-assistant/styles.css`:助手壳与默认模板样式。
@@ -13,6 +13,8 @@
13
13
 
14
14
  禁止宿主从 `src`、`dist` 或包内部路径导入。
15
15
 
16
+ - `@qfei-design/make-ai-assistant/client`:无 React/DOM 类型依赖的 v1 HTTP/字节流客户端与 ApiError。
17
+
16
18
  ## Headless exports
17
19
 
18
20
  - `validateArtifact` / `parseArtifact`
@@ -40,18 +42,17 @@ Fetch SSE 实现时,从 `/sse` 入口导入 `createSseAssistantTransport`。
40
42
  - `MakeAiAssistant`:默认右下角浮动入口与右侧抽屉;支持受控开关、自定义 launcher,以及
41
43
  `brandName` 对默认“{品牌名} AI 助手”标题的覆盖。`title` 可覆盖完整标题;`assistantName` /
42
44
  `userName` / `userAvatarUrl` 可显示当前登录人的名称和头像;未传入时用户侧不显示身份信息。
43
- `subtitle` 用于显示宿主传入的当前对象(兼容移除旧接入中的“只读分析 ·”前缀);`privacyNotice`
44
- 会在对象右侧的问号 Tooltip 中展示,并根据图标与可用视口选择相邻方向,而非单独的广播行。头栏默认高度为 50px,可通过 `headerHeight` 或
45
+ `subtitle` `privacyNotice` 仅继续接受旧调用传入的值以保持类型兼容,不会参与渲染或发送到
46
+ transport;新宿主不应传入。头栏默认高度为 50px,可通过 `headerHeight` 或
45
47
  `--make-ai-header-height` 覆盖。内置浮动入口可通过 `launcherPosition` 设置为 `bottom-left`、
46
48
  `bottom-right`、`top-left`、`top-right`、`left-center` 或 `right-center`;默认值为 `bottom-right`。
47
49
  自定义 `launcher` 自行负责位置。标准位置只读取对应锚点的
48
50
  `--make-ai-launcher-left`、`--make-ai-launcher-right`、`--make-ai-launcher-top` 或
49
51
  `--make-ai-launcher-bottom` 变量;窄屏使用对应的 `--make-ai-launcher-mobile-*` 变量,另一侧始终为
50
52
  `auto`。
51
- 桌面端抽屉可从左边缘 12px 热区向左拖宽,初始计算宽度(默认 480px,或宿主的
52
- `--make-ai-drawer-width`)同时作为拖拽下限;热区激活时展示 2px 主题色提示线,宿主可通过
53
- `--make-ai-drawer-resize-line` 覆盖其颜色;手柄支持左右方向键微调。不大于 560px 的视口保持全宽,
54
- 不提供宽度调整。
53
+ 桌面端抽屉默认 560px,宿主可通过 `--make-ai-drawer-width` 覆盖固定宽度;包内最大宽度规则为
54
+ `min(1024px, 72vw)`,但不会压缩固定宽度,可通过 `maxDrawerWidth` 传入像素值设置明确上限。抽屉不提供左侧拖拽或键盘宽度调整;
55
+ 标题栏右侧“新建对话”左侧提供全屏/退出全屏按钮,全屏只作用于组件抽屉布局。不大于 560px 的视口保持全宽。
55
56
  面板按自身容器宽度适配:达到 560px 时扩展内容区间距和阅读宽度,达到 760px 时 Markdown 表格
56
57
  优先按可用宽度分列并换行;宿主可使用 `--make-ai-panel-gutter-wide` 覆盖扩展状态内边距。
57
58
  首次打开后关闭抽屉只隐藏 Drawer,不卸载 `AssistantPanel`,不会中断正在进行的生成。
@@ -59,8 +60,8 @@ Fetch SSE 实现时,从 `/sse` 入口导入 `createSseAssistantTransport`。
59
60
  省略 `suggestions` 时显示包内默认推荐问题,传入 `[]` 时隐藏推荐问题。
60
61
  - `AssistantPanel`:不带 Drawer 的嵌入式会话面板;支持 `brandName`、`title`、`assistantName` /
61
62
  `subtitle` / `userName` / `userAvatarUrl` / `privacyNotice` / `headerHeight`。默认品牌为“Make”,
62
- 默认显示“AI 助手”;用户侧默认不展示名称或头像,宿主提示默认不展示。这些字段只参与本地 React
63
- 渲染,不会进入 transport 请求。嵌入式面板包含图标化复制回答、可选安全重新生成、图标化回到最新消息、
63
+ 默认显示“AI 助手”;用户侧默认不展示名称或头像。`subtitle` 与 `privacyNotice` 不参与渲染;
64
+ 其余展示字段只参与本地 React 渲染,不会进入 transport 请求。嵌入式面板包含图标化复制、喜欢/不喜欢、可选安全重新生成、图标化回到最新消息、
64
65
  仅在生成中显示的处理步骤、错误重试、键盘提交与 reduced-motion 处理。
65
66
  - `ArtifactRenderer`:注册表驱动的单 Artifact 渲染器。
66
67
  - `createPlatformArtifactRegistry`
@@ -84,7 +85,8 @@ Promise rejection。`onActionError` 自身同步抛错或返回 rejected Promise
84
85
  不会污染宿主的全局未处理异常。
85
86
 
86
87
  成功回答的复制操作以图标按钮展示,悬浮或聚焦时显示“复制”提示,保留“复制回答”的无障碍名称,
87
- 只复制该 assistant message 的文本内容;复制失败只在本地 UI 反馈并记录不含回答正文的错误类型。AI 回答正文会按标题、
88
+ 只复制该 assistant message 的文本内容;持久 assistant message 的反馈操作同样使用图标按钮,悬浮或聚焦时显示
89
+ “喜欢”或“不喜欢”提示,并保留可读的无障碍名称。复制失败只在本地 UI 反馈并记录不含回答正文的错误类型。AI 回答正文会按标题、
88
90
  段落、列表、强调、反引号代码片段和 Markdown 表格行做轻量结构化展示;该渲染不执行 HTML、JSX、
89
91
  CSS 或 JavaScript。对话排版默认分为四级:标题和用户问题为 14px、AI 正文与结构化结果数据为
90
92
  13px、身份/状态/操作等辅助信息为 12px、来源/时间/复制反馈等非关键注释为 11px。宿主可通过
@@ -173,19 +175,13 @@ UI 会拒绝孤立、迟到、重复或跨 run 混入的事件,避免静默丢
173
175
 
174
176
  ## Make App transport
175
177
 
176
- `/make-app` 导出 `createMakeAppAssistantTransport`、`MakeAppAssistantTransportOptions`、`MakeAppAssistantScope`、`MakeAppAssistantEventSourceFactory` 及相关结构类型。完整回调与接线示例见 [当前 Make App 合同](docs/make-app-integration.md)。
177
-
178
- 宿主注入 resolveScope、会话/SSE/上传语义回调及可选的 readContent:listAgents、createChat、listChats、getChat、updateChat、deleteChat、loadHistory、sendMessage、getResponse、cancelResponse、setFeedback、startUpload、getUpload、uploadPart、completeUpload、eventSourceFactory。JSON 回调返回裸对象,204 返回 void;宿主能够无损读取二进制时再提供 readContent,并返回 Uint8Array。
179
-
180
- `resolveScope(context)` 返回 appKey、agentId 和随登录身份变化的 identityKey。包只用于作用域绑定与缓存失效,服务器仍独立鉴权。每个异步回调接受 AbortSignal;包不提供部署 URL、不读 Cookie、不导入认证 SDK。
178
+ `/client` 导出 createMakeAgentClient、ApiError、Client AuthenticatedTransport 等平台中立类型。固定 apiVersion=v1,basePath 默认 /api/make/app/ai。详细方法、错误、预算和幂等责任见 [稳定客户端合同](docs/make-app-integration.md)。
181
179
 
182
- `AssistantTransport` 原地增加 listAgents、listConversations、create/get/update/deleteConversation、get/cancelResponse、setFeedback、上传/内容方法与 watchResponse。方法在通用 interface 上可选,Make App adapter 实现全部。loadConversation options 可传 threadId/cursor,返回 nextCursor/hasMore;分页读取不会隐式创建 Chat。
180
+ `/make-app` 导出异步 createMakeAppAssistantTransport({ client, agentId, historyLimit?, signal? }),通过能力发现后返回 AssistantTransport。宿主只注入一个正式认证 HTTP 传输、App/身份和 Agent;身份变化时调用 client.dispose() 并重建实例。
183
181
 
184
- 输入 message 可携带 parts;响应事件增加 response.accepted/state/output_item.added/output_text.delta/output_item.done/snapshot/reconciled/terminal。每个 Run、item part 的身份独立,持久助手 messageId 用于反馈。`AssistantConversationState.responses` 保存响应集合;输入可以合并到同一 Run,不按调用次数伪造 Turn
182
+ 标准 SDK 将新增响应元数据安全投影;未知事件保留名称/游标,未知内容块保留 originalKind/textFallback,不执行未知动作。输入仍严格验证。v1 的 cursor 为不透明字符串,ResponseSnapshot 必含 terminal 和 snapshotRevision。框架中立的 AssistantTransport 仍允许 Console/测试适配器的本地序号,但 Make App v1 不接受数字 cursor
185
183
 
186
- features 增加 conversationManagement、feedback、attachments、modelInputKinds。Make App 的 newConversation/remoteCancellation 和 attachments 为 true,regeneration 为 false;modelInputKinds 是宿主对模型输入的声明,附件的实际接受与拒绝由服务端处理。未注入 readContent transport 不暴露该方法,React UI 也不展示无效的下载/预览按钮。historyLimit 范围 1—200;maxEventCharacters 默认 1,000,000;重连由 adapter 单独负责。完整快照属于覆盖,不能当新 delta。
187
-
188
- 根入口导出 AssistantContentPart、AssistantMedia、AssistantChat、AssistantChatPage、AssistantAgent、AssistantFeedback、AssistantUpload、AssistantResponseSnapshot、AssistantResponseEvent 等类型,仍无 React/DOM File 依赖。文件读取与 Object URL 留在 React/宿主边界。
184
+ Chat.titlePending 缺失按 false;摘要完成通过同一 Client 的详情刷新立即反映到会话列表。SSE 只更新响应视图,反馈使用历史中真正的 messageId,关闭订阅不会远程取消运行。
189
185
 
190
186
  ## Make Console transport
191
187
 
@@ -233,3 +229,7 @@ Artifact 的 `action.target` 只是 JSON 意图。宿主必须根据当前权限
233
229
  - 未注册模板安全降级;
234
230
  - `presentation.template` 不会触发代码加载;
235
231
  - 新模板不得复用已有 id。
232
+
233
+ ## 自动标题更新
234
+
235
+ AssistantChat 必须包含 titlePending: boolean。首条长消息摘要排队或生成时为 true,完成、失败或手工命名后为 false。消息受理后读取一次会话详情;列表或当前会话存在待摘要状态时,每秒通过已认证 getConversation 回调刷新对应详情,按 revision 合并。正文终态不停止标题检查;摘要完成即停止,作用域切换、删除或卸载会取消请求。迟到的较低 revision 详情或列表不会覆盖新标题。
package/README.md CHANGED
@@ -5,9 +5,11 @@
5
5
  ## Install
6
6
 
7
7
  ```bash
8
- pnpm add @qfei-design/make-ai-assistant@^0.2.0
8
+ pnpm add --save-exact @qfei-design/make-ai-assistant@VERSION
9
9
  ```
10
10
 
11
+ VERSION 替换为完成本地验收的发布版本,提交 lockfile 固定制品。
12
+
11
13
  ## Quick start
12
14
 
13
15
  ```tsx
@@ -93,12 +95,12 @@ const hostTheme: MakeAiTheme = {
93
95
  宿主 `--make-color-primary` > 包内默认值。`background` 会控制内容区基础背景;`surface`、`text` 等其余中性色字段为兼容保留,
94
96
  不会改变内置默认样式;它们仍会写入 `renderContext.themeStyle`,供自定义 Artifact 模板自行使用。
95
97
 
96
- 桌面端抽屉默认宽度为 480px,且该初始宽度是用户拖拽时的最小宽度。最大宽度默认是 `min(1024px, 72vw)`,宿主可通过 `maxDrawerWidth` 传入像素值覆盖;小于最小宽度的配置会回退至最小宽度。鼠标移至抽屉左边缘的 12px 热区时才会显示 2px 主题色拖拽提示线(可通过 `--make-ai-drawer-resize-line` 覆盖),可向左拖宽;获得焦点后也可用左、右方向键以 16px 调整宽度。不大于 560px 的视口保持全宽展示,不显示拖拽手柄。
98
+ 桌面端抽屉默认宽度为 560px,宿主仍可通过 `--make-ai-drawer-width` 覆盖固定宽度。包内最大宽度规则为 `min(1024px, 72vw)`,但不会压缩默认或宿主指定的固定宽度;宿主可通过 `maxDrawerWidth` 传入像素值设置明确上限。抽屉不再提供左侧拖拽或键盘调整宽度;标题栏右侧“新建对话”左侧提供全屏/退出全屏按钮,全屏只作用于本组件的抽屉布局,不调用浏览器原生全屏。不大于 560px 的视口保持全宽展示。
97
99
 
98
100
  面板使用容器查询而非页面视口响应宽度:回答区、结构化结果、代码块和 Markdown 表格会随抽屉可用宽度扩展;达到 760px 时,表格优先按可用宽度分列并换行,长段落和列表仍限制在 96ch 内以保障阅读性。窄容器中的 Markdown 表格保留横向滚动保护,并使用细窄的中性灰滚动条。宿主可通过 `--make-ai-panel-gutter-wide` 覆盖扩展抽屉的内边距。
99
101
 
100
102
  成功的 AI 回答会显示仅含图标的复制按钮,鼠标悬浮或键盘聚焦时显示“复制”提示,按钮保留
101
- “复制回答”的无障碍名称;复制只处理该回答的文本内容,失败时会在本地 UI 内提示,不会把回答正文写入日志。AI 回答正文会按标题、
103
+ “复制回答”的无障碍名称;持久回答的喜欢/不喜欢也使用同样的图标交互,并分别显示“喜欢”与“不喜欢”提示。复制只处理该回答的文本内容,失败时会在本地 UI 内提示,不会把回答正文写入日志。AI 回答正文会按标题、
102
104
  段落、列表、强调、代码片段和 Markdown 表格行做轻量结构化展示,不执行 HTML,也不引入 Markdown
103
105
  运行时依赖。对话排版默认分为四级:标题和用户问题为 14px、AI 正文与结构化结果数据为 13px、身份/状态/操作等辅助信息为
104
106
  12px、来源/时间/复制反馈等非关键注释为 11px。宿主可通过
@@ -192,23 +194,23 @@ const assistantTransport = createSseAssistantTransport({
192
194
  });
193
195
  ```
194
196
 
195
- Make App 使用专用 adapter 与当前唯一公开契约:
197
+ 客户端入口为 `@qfei-design/make-ai-assistant/client`。App 宿主提供正式认证 HTTP 传输,标准客户端统一管理 18 项接口、固定 `/v1` 路径、响应解码、分页、重试、字节上传与 SSE。`/make-app` 把客户端结果映射到已有助手 UI 状态机。
196
198
 
197
199
  ```ts
200
+ import { createMakeAgentClient } from "@qfei-design/make-ai-assistant/client";
198
201
  import { createMakeAppAssistantTransport } from "@qfei-design/make-ai-assistant/make-app";
199
202
 
200
- const assistantTransport = createMakeAppAssistantTransport({
201
- ...makeAppAiClient,
202
- resolveScope: () => ({ appKey, agentId, identityKey }),
203
- modelInputKinds: ["text"],
203
+ const client = createMakeAgentClient({
204
+ apiVersion: "v1",
205
+ scope: { appKey, identityKey },
206
+ transport: authenticatedTransport,
204
207
  });
208
+ const assistantTransport = await createMakeAppAssistantTransport({ client, agentId });
209
+ // 将 assistantTransport 传入 AssistantPanel / MakeAiAssistant。
210
+ // App、用户或租户改变时,取消旧连接并 client.dispose(),重新创建实例。
205
211
  ```
206
212
 
207
- `makeAppAiClient` 实现 Agent/Chat 管理、分页历史、消息、响应快照、独立取消、反馈、上传和 EventSource,并可在宿主具备无损二进制认证读取能力时注入原件读取。完整类型与示例见 [Make App 接入说明](docs/make-app-integration.md)[宿主示例](examples/make-app/main.tsx)。网络与认证由宿主注入,identityKey 随当前用户/租户变化。
208
-
209
- 内置面板支持持久会话列表、新建、改名、置顶/删除、反馈与附件队列。历史 cursor=-1 从最早事件正向分页,空可见页仍可能存在后续事件。首次加载不隐式建会话,用户新建或主动发送才创建。item/part 增量、完整文本覆盖、快照恢复和持久 messageId 对账由包统一处理。
210
-
211
- 停止显示“停止中”,直到服务端确认终态;中断订阅不取消后台 Run。当前 Make App 不提供重新生成语义,也不传 context/capabilities 或伪造 Artifact。附件入口固定为“上传文件或图片”;modelInputKinds 仅描述宿主模型能力,服务端根据消息 parts 决定是否接受媒体类型。单条消息文本最多 8 KiB UTF-8,最多 32 个 parts。
213
+ `AuthenticatedTransport.request` 只执行一次已认证 I/O,返回 status、headers AsyncIterable<Uint8Array>。`retryOwner: "sdk"` 由 SDK 按幂等语义做有限重试;`retryOwner: "transport"` 不叠加 SDK 重试。宿主沿正式 auth.api 处理登录、401/403 Cookie,SSE/二进制成功体不经过 JSON 或 text() 缓冲。SDK 不读取 Token、Cookie、LocalStorage 或 Provider key。
212
214
 
213
215
  Make Console 可以使用独立 adapter:
214
216
 
@@ -259,3 +261,7 @@ pnpm build
259
261
  ```
260
262
 
261
263
  发布统一走 GitLab CI;不要从功能分支本地执行 npm publish。
264
+
265
+ ### 会话自动标题
266
+
267
+ Make App 的 Chat 包含 titlePending。首条长消息的摘要完成后,助手通过每秒一次的待摘要会话详情刷新自动更新列表,独立于正文流式完成时间;短标题和手工命名结束等待,旧 revision 不覆盖当前状态。详情刷新经过标准 client.chats.get 和正式认证传输,不增加登录或直连模型逻辑。
package/capabilities.json CHANGED
@@ -70,9 +70,10 @@
70
70
  "name": "Make App AI transport",
71
71
  "category": "integration",
72
72
  "status": "experimental",
73
- "summary": "宿主注入的多会话管理、反馈、附件与 item/part SSE、快照恢复和远程取消。",
73
+ "summary": "标准 v1 Client 支撑多会话、反馈、附件、SSE、单调快照与显式取消;宿主注入正式认证 HTTP 传输。",
74
74
  "docPath": "PUBLIC_API.md",
75
75
  "relatedExports": [
76
+ "@qfei-design/make-ai-assistant/client:createMakeAgentClient",
76
77
  "@qfei-design/make-ai-assistant/make-app:createMakeAppAssistantTransport",
77
78
  "AssistantTransport"
78
79
  ]
@@ -0,0 +1,24 @@
1
+ import type { AgentPage, Capabilities, Chat, ChatPage, Feedback, HistoryPage, Media, OutputPart, ResponseSnapshot, Upload } from "./client-types.js";
2
+ export declare const record: (value: unknown) => Record<string, unknown>;
3
+ export declare const id: (value: unknown) => string;
4
+ export declare const text: (value: unknown, maximum?: number, empty?: boolean) => string;
5
+ export declare const number: (value: unknown, minimum?: number, maximum?: number) => number;
6
+ export declare const boolean: (value: unknown) => boolean;
7
+ export declare const array: (value: unknown, maximum: number) => unknown[];
8
+ export declare function requestKeys(value: object, keys: readonly string[]): void;
9
+ export declare function uuid(value: unknown): string;
10
+ export declare function cursor(value: unknown, empty?: boolean): string;
11
+ export declare function pageFields(value: Record<string, unknown>): {
12
+ nextCursor: string;
13
+ hasMore: boolean;
14
+ };
15
+ export declare function readChat(raw: unknown, appKey: string, agentId?: string, chatId?: string): Chat;
16
+ export declare function readChatPage(raw: unknown, appKey: string, agentId: string): ChatPage;
17
+ export declare function readAgents(raw: unknown, appKey: string): AgentPage;
18
+ export declare function readMedia(raw: unknown): Media;
19
+ export declare function readParts(raw: unknown): OutputPart[];
20
+ export declare function readFeedback(raw: unknown): Feedback;
21
+ export declare function readHistory(raw: unknown): HistoryPage;
22
+ export declare function readSnapshot(raw: unknown, chatId: string, responseId: string): ResponseSnapshot;
23
+ export declare function readUpload(raw: unknown, expectedId?: string): Upload;
24
+ export declare function readCapabilities(raw: unknown, appKey: string, agentId: string): Capabilities;
@@ -0,0 +1,420 @@
1
+ /** v1 公共客户端类型;网络通过宿主认证传输,React 与业务动作留在上层。 */
2
+ export type ApiVersion = "v1";
3
+ export type Id = string;
4
+ export type Cursor = string;
5
+ export type OpenString<Known extends string> = Known | (string & {});
6
+ export interface AbortSignalLike {
7
+ readonly aborted: boolean;
8
+ readonly reason?: unknown;
9
+ addEventListener(type: "abort", listener: () => void, options?: {
10
+ once?: boolean;
11
+ }): void;
12
+ removeEventListener(type: "abort", listener: () => void): void;
13
+ }
14
+ export interface RetryOptions {
15
+ readonly maxAttempts?: number;
16
+ readonly maxDelayMs?: number;
17
+ }
18
+ export interface StreamOptions {
19
+ readonly connectTimeoutMs?: number;
20
+ readonly idleTimeoutMs?: number;
21
+ readonly maxDurationMs?: number;
22
+ }
23
+ export interface CallOptions {
24
+ readonly signal?: AbortSignalLike;
25
+ readonly timeoutMs?: number;
26
+ }
27
+ export interface Scope {
28
+ readonly appKey: Id;
29
+ readonly identityKey: string;
30
+ }
31
+ export interface HttpRequest {
32
+ readonly method: "GET" | "POST" | "PATCH" | "DELETE" | "PUT";
33
+ readonly path: string;
34
+ readonly headers: Readonly<Record<string, string>>;
35
+ readonly body?: Uint8Array;
36
+ }
37
+ export interface HttpResponse {
38
+ readonly status: number;
39
+ readonly headers: Readonly<Record<string, string>>;
40
+ readonly body?: AsyncIterable<Uint8Array>;
41
+ }
42
+ /** 由宿主正式认证适配器实现;不允许在浏览器 SDK 内读取 Token/Cookie。 */
43
+ export interface AuthenticatedTransport {
44
+ readonly retryOwner: "sdk" | "transport";
45
+ request(request: HttpRequest, options?: CallOptions): Promise<HttpResponse>;
46
+ }
47
+ export interface ClientOptions {
48
+ readonly apiVersion?: ApiVersion;
49
+ readonly basePath?: string;
50
+ readonly scope: Scope;
51
+ readonly transport: AuthenticatedTransport;
52
+ readonly retry?: RetryOptions;
53
+ readonly stream?: StreamOptions;
54
+ readonly timeoutMs?: number;
55
+ readonly maxJsonBytes?: number;
56
+ readonly maxEventBytes?: number;
57
+ readonly onDiagnostic?: (event: {
58
+ operation: string;
59
+ code?: string;
60
+ requestId?: string;
61
+ attempts?: number;
62
+ }) => void;
63
+ }
64
+ export interface PageOptions {
65
+ readonly cursor?: Cursor;
66
+ readonly limit?: number;
67
+ }
68
+ export interface IterateOptions extends CallOptions {
69
+ readonly maxPages: number;
70
+ readonly maxItems: number;
71
+ }
72
+ export interface Agent {
73
+ readonly agentId: Id;
74
+ readonly appKey: Id;
75
+ readonly name: string;
76
+ }
77
+ export interface AgentPage {
78
+ readonly agents: readonly Agent[];
79
+ readonly nextCursor: Cursor;
80
+ readonly hasMore: boolean;
81
+ }
82
+ export interface Chat {
83
+ readonly chatId: Id;
84
+ readonly appKey: Id;
85
+ readonly agentId: Id;
86
+ readonly title: string;
87
+ readonly status: "active" | "deleted";
88
+ readonly revision: number;
89
+ readonly pinned: boolean;
90
+ readonly pinnedAt?: string | null;
91
+ readonly createdAt: string;
92
+ readonly lastActivityAt: string;
93
+ readonly titlePending?: boolean;
94
+ }
95
+ export interface ChatPage {
96
+ readonly chats: readonly Chat[];
97
+ readonly nextCursor: Cursor;
98
+ readonly hasMore: boolean;
99
+ }
100
+ export interface CreateChatInput {
101
+ readonly agentId: Id;
102
+ readonly requestId: string;
103
+ readonly title?: string;
104
+ }
105
+ export type UpdateChatInput = {
106
+ readonly chatId: Id;
107
+ readonly expectedRevision: number;
108
+ } & ({
109
+ readonly title: string;
110
+ readonly pinned?: boolean;
111
+ } | {
112
+ readonly pinned: boolean;
113
+ readonly title?: string;
114
+ });
115
+ export interface Media {
116
+ readonly contentRef: Id;
117
+ readonly contentType: string;
118
+ readonly sizeBytes: number;
119
+ readonly digestSha256: string;
120
+ }
121
+ export type KnownMediaKind = "image" | "file" | "audio" | "video";
122
+ export type InputPart = {
123
+ readonly id: string;
124
+ readonly kind: "text";
125
+ readonly text: string;
126
+ } | {
127
+ readonly id: string;
128
+ readonly kind: KnownMediaKind;
129
+ readonly name?: string;
130
+ readonly media: Media;
131
+ };
132
+ export type OutputPart = {
133
+ readonly id?: Id;
134
+ readonly kind: "text";
135
+ readonly text: string;
136
+ } | {
137
+ readonly id?: Id;
138
+ readonly kind: KnownMediaKind;
139
+ readonly name?: string;
140
+ readonly media: Media;
141
+ } | {
142
+ readonly id?: Id;
143
+ readonly kind: "unknown";
144
+ readonly originalKind: string;
145
+ readonly textFallback?: string;
146
+ };
147
+ export type SendMessageInput = {
148
+ readonly chatId: Id;
149
+ readonly messageId: string;
150
+ } & ({
151
+ readonly text: string;
152
+ readonly parts?: never;
153
+ } | {
154
+ readonly parts: readonly InputPart[];
155
+ readonly text?: never;
156
+ });
157
+ export interface Accepted {
158
+ readonly chatId: Id;
159
+ readonly messageId: Id;
160
+ readonly responseId: Id;
161
+ readonly acceptedCursor?: Cursor;
162
+ }
163
+ export interface Feedback {
164
+ readonly id: Id;
165
+ readonly rating: "like" | "dislike" | "none";
166
+ readonly revision: number;
167
+ readonly reason?: string;
168
+ readonly comment?: string;
169
+ }
170
+ export interface FeedbackInput {
171
+ readonly chatId: Id;
172
+ readonly messageId: Id;
173
+ readonly requestId: string;
174
+ readonly rating: "like" | "dislike" | "none";
175
+ readonly reason?: string;
176
+ readonly comment?: string;
177
+ }
178
+ export interface StoredMessage {
179
+ readonly messageId: Id;
180
+ readonly role: "user" | "assistant";
181
+ readonly cursor: Cursor;
182
+ readonly createdAt: string;
183
+ readonly text: string;
184
+ readonly parts?: readonly OutputPart[];
185
+ readonly responseId?: Id;
186
+ readonly feedback?: Feedback;
187
+ }
188
+ export interface HistoryPage {
189
+ readonly messages: readonly StoredMessage[];
190
+ readonly nextCursor: Cursor;
191
+ readonly hasMore: boolean;
192
+ }
193
+ export interface OutputItem {
194
+ readonly itemId: Id;
195
+ readonly partId: Id;
196
+ readonly text: string;
197
+ readonly final: boolean;
198
+ readonly revision: number;
199
+ readonly parts?: readonly OutputPart[];
200
+ }
201
+ export type ResponseStatus = OpenString<"queued" | "dispatched" | "running" | "completed" | "failed" | "cancelled">;
202
+ export interface PublicError {
203
+ readonly code: string;
204
+ readonly message: string;
205
+ readonly requestId?: string;
206
+ readonly details?: readonly {
207
+ readonly code?: string;
208
+ readonly target?: string;
209
+ readonly message?: string;
210
+ }[];
211
+ }
212
+ export interface ResponseRef {
213
+ readonly chatId: Id;
214
+ readonly responseId: Id;
215
+ }
216
+ export interface ResponseSnapshot extends ResponseRef {
217
+ readonly status: ResponseStatus;
218
+ readonly terminal: boolean;
219
+ readonly snapshotRevision: number;
220
+ readonly items: readonly OutputItem[];
221
+ readonly cancelRequested?: boolean;
222
+ readonly error?: PublicError;
223
+ }
224
+ export type ResponseEvent = {
225
+ readonly kind: "subscribed";
226
+ readonly responseId: Id;
227
+ readonly cursor?: Cursor;
228
+ } | {
229
+ readonly kind: "state";
230
+ readonly responseId: Id;
231
+ readonly status: ResponseStatus;
232
+ readonly cursor?: Cursor;
233
+ } | {
234
+ readonly kind: "itemAdded";
235
+ readonly responseId: Id;
236
+ readonly itemId: Id;
237
+ readonly partId: Id;
238
+ readonly sequence: number;
239
+ readonly cursor?: Cursor;
240
+ } | {
241
+ readonly kind: "textDelta";
242
+ readonly responseId: Id;
243
+ readonly itemId: Id;
244
+ readonly partId: Id;
245
+ readonly sequence: number;
246
+ readonly delta: string;
247
+ readonly cursor?: Cursor;
248
+ } | {
249
+ readonly kind: "itemDone";
250
+ readonly responseId: Id;
251
+ readonly itemId: Id;
252
+ readonly partId: Id;
253
+ readonly sequence: number;
254
+ readonly text: string;
255
+ readonly final: boolean;
256
+ readonly cursor?: Cursor;
257
+ } | {
258
+ readonly kind: "reset";
259
+ readonly responseId: Id;
260
+ readonly reason: string;
261
+ readonly cursor?: Cursor;
262
+ } | {
263
+ readonly kind: "snapshot";
264
+ readonly snapshot: ResponseSnapshot;
265
+ readonly cursor?: Cursor;
266
+ } | {
267
+ readonly kind: "completed" | "failed" | "cancelled";
268
+ readonly responseId: Id;
269
+ readonly code?: string;
270
+ readonly cursor?: Cursor;
271
+ } | {
272
+ readonly kind: "unknown";
273
+ readonly responseId: Id;
274
+ readonly name: string;
275
+ readonly cursor?: Cursor;
276
+ };
277
+ export interface StartUploadInput {
278
+ readonly chatId: Id;
279
+ readonly fileId: string;
280
+ readonly name: string;
281
+ readonly contentType: string;
282
+ readonly sizeBytes: number;
283
+ readonly digestSha256?: string;
284
+ }
285
+ export interface ContentReference {
286
+ readonly kind: "reference";
287
+ readonly contentRef: Id;
288
+ readonly sizeBytes: number;
289
+ readonly digestSha256: string;
290
+ }
291
+ export interface Upload {
292
+ readonly id: Id;
293
+ readonly status: OpenString<"uploading" | "ready" | "expired" | "cancelled">;
294
+ readonly name: string;
295
+ readonly contentType: string;
296
+ readonly sizeBytes: number;
297
+ readonly partSize: number;
298
+ readonly completedParts: readonly number[];
299
+ readonly expiresAt?: string;
300
+ readonly content?: ContentReference;
301
+ }
302
+ export interface ReplayableBytes {
303
+ readonly sizeBytes: number;
304
+ read(offset: number, length: number, options?: CallOptions): Promise<Uint8Array>;
305
+ }
306
+ export interface ContentDownload {
307
+ readonly contentType?: string;
308
+ readonly contentLength?: number;
309
+ readonly body: AsyncIterable<Uint8Array>;
310
+ }
311
+ export interface Limits {
312
+ readonly maxInputTextBytes: number;
313
+ readonly maxMessageBytes: number;
314
+ readonly maxInputParts: number;
315
+ readonly maxUploadBytes: number;
316
+ readonly uploadPartBytes: number;
317
+ readonly maxConcurrentUploads: number;
318
+ readonly maxSseEventBytes: number;
319
+ }
320
+ export interface Capabilities {
321
+ readonly apiVersion: ApiVersion;
322
+ readonly appKey: Id;
323
+ readonly agentId: Id;
324
+ readonly features: readonly string[];
325
+ readonly modelInputKinds: readonly string[];
326
+ readonly limits: Limits;
327
+ readonly revision?: string;
328
+ }
329
+ export interface Client {
330
+ readonly scope: Scope;
331
+ readonly apiVersion: ApiVersion;
332
+ readonly capabilities: {
333
+ get(input: {
334
+ agentId: Id;
335
+ }, options?: CallOptions): Promise<Capabilities>;
336
+ };
337
+ readonly agents: {
338
+ list(page?: PageOptions, options?: CallOptions): Promise<AgentPage>;
339
+ };
340
+ readonly chats: {
341
+ create(input: CreateChatInput, options?: CallOptions): Promise<Chat>;
342
+ list(input: {
343
+ agentId: Id;
344
+ } & PageOptions, options?: CallOptions): Promise<ChatPage>;
345
+ get(input: {
346
+ chatId: Id;
347
+ }, options?: CallOptions): Promise<Chat>;
348
+ update(input: UpdateChatInput, options?: CallOptions): Promise<Chat>;
349
+ delete(input: {
350
+ chatId: Id;
351
+ expectedRevision: number;
352
+ }, options?: CallOptions): Promise<void>;
353
+ iterate(input: {
354
+ agentId: Id;
355
+ } & PageOptions, options: IterateOptions): AsyncIterable<Chat>;
356
+ };
357
+ readonly messages: {
358
+ send(input: SendMessageInput, options?: CallOptions): Promise<Accepted>;
359
+ list(input: {
360
+ chatId: Id;
361
+ } & PageOptions, options?: CallOptions): Promise<HistoryPage>;
362
+ iterate(input: {
363
+ chatId: Id;
364
+ } & PageOptions, options: IterateOptions): AsyncIterable<StoredMessage>;
365
+ sendAndWatch(input: SendMessageInput, options?: CallOptions): Promise<{
366
+ readonly accepted: Accepted;
367
+ readonly events: AsyncIterable<ResponseEvent>;
368
+ }>;
369
+ };
370
+ readonly responses: {
371
+ get(input: ResponseRef, options?: CallOptions): Promise<ResponseSnapshot>;
372
+ subscribe(input: ResponseRef & {
373
+ cursor?: Cursor;
374
+ }, options?: CallOptions): AsyncIterable<ResponseEvent>;
375
+ cancel(input: ResponseRef, options?: CallOptions): Promise<ResponseSnapshot>;
376
+ waitForTerminal(input: ResponseRef, options: CallOptions & {
377
+ timeoutMs: number;
378
+ pollIntervalMs?: number;
379
+ }): Promise<ResponseSnapshot>;
380
+ };
381
+ readonly feedback: {
382
+ set(input: FeedbackInput, options?: CallOptions): Promise<Feedback>;
383
+ };
384
+ readonly uploads: {
385
+ start(input: StartUploadInput, options?: CallOptions): Promise<Upload>;
386
+ get(input: {
387
+ chatId: Id;
388
+ uploadId: Id;
389
+ }, options?: CallOptions): Promise<Upload>;
390
+ putPart(input: {
391
+ chatId: Id;
392
+ uploadId: Id;
393
+ part: number;
394
+ bytes: Uint8Array;
395
+ }, options?: CallOptions): Promise<void>;
396
+ complete(input: {
397
+ chatId: Id;
398
+ uploadId: Id;
399
+ }, options?: CallOptions): Promise<Upload>;
400
+ uploadFile(input: Omit<StartUploadInput, "sizeBytes"> & {
401
+ source: ReplayableBytes;
402
+ }, options?: CallOptions & {
403
+ concurrency?: number;
404
+ onProgress?: (confirmedBytes: number) => void;
405
+ }): Promise<Upload>;
406
+ };
407
+ readonly content: {
408
+ read(input: {
409
+ chatId: Id;
410
+ contentRef: Id;
411
+ maxBytes: number;
412
+ }, options?: CallOptions): Promise<ContentDownload>;
413
+ };
414
+ /** 释放本地资源,不退出登录、不远程取消 Response。 */
415
+ dispose(): void;
416
+ }
417
+ /** 消费者可实现的小接口;扩展全量 Client 不应扩大这些接口的必需方法集。 */
418
+ export type ChatReader = Pick<Client["chats"], "list" | "get">;
419
+ export type MessageSender = Pick<Client["messages"], "send">;
420
+ export type ResponseReader = Pick<Client["responses"], "get" | "subscribe">;