super-agent-sdk 1.0.7 → 1.0.9
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.
- package/README.md +242 -93
- package/dist/index.cjs +3 -3
- package/dist/index.d.ts +7 -2
- package/dist/index.mjs +90 -85
- package/dist/widget.cjs +136 -666
- package/dist/widget.d.ts +126 -12
- package/dist/widget.mjs +2093 -2018
- package/package.json +4 -1
package/README.md
CHANGED
|
@@ -24,10 +24,10 @@ Super Agent Web SDK —— 为 `super-agent-service` 提供的一站式浏览器
|
|
|
24
24
|
|
|
25
25
|
`super-agent-sdk` 提供两个入口:
|
|
26
26
|
|
|
27
|
-
| 入口
|
|
28
|
-
|
|
|
29
|
-
| `super-agent-sdk` | 纯 JS API 调用层,封装鉴权、SSE 流式解析、会话与消息接口
|
|
30
|
-
| `super-agent-sdk/widget` | 可嵌入式 React 聊天组件
|
|
27
|
+
| 入口 | 说明 | 依赖 |
|
|
28
|
+
| ------------------------ | -------------------------------------------------------- | ---------- |
|
|
29
|
+
| `super-agent-sdk` | 纯 JS API 调用层,封装鉴权、SSE 流式解析、会话与消息接口 | 无 UI 依赖 |
|
|
30
|
+
| `super-agent-sdk/widget` | 可嵌入式 React 聊天组件 | React 18+ |
|
|
31
31
|
|
|
32
32
|
核心能力:
|
|
33
33
|
|
|
@@ -83,11 +83,11 @@ function createSuperAgent(config: SDKConfig): SuperAgentSDK;
|
|
|
83
83
|
|
|
84
84
|
```ts
|
|
85
85
|
export interface SDKConfig {
|
|
86
|
-
botId: number;
|
|
87
|
-
tokenGateway: string;
|
|
88
|
-
baseUrl?: string;
|
|
89
|
-
appId?: string;
|
|
90
|
-
token?: string;
|
|
86
|
+
botId: number; // Bot ID(必填)
|
|
87
|
+
tokenGateway: string; // Token 网关前缀(必填,不带 host),如 "/api/gateway";token URL = {origin}{tokenGateway}/v1/token
|
|
88
|
+
baseUrl?: string; // 业务接口前缀(可选,默认 "/api/agent/runtime/v1"),不带 host
|
|
89
|
+
appId?: string; // 可选,不传则从 token 接口响应自动获取
|
|
90
|
+
token?: string; // 可选,不传则自动调 token 接口获取
|
|
91
91
|
}
|
|
92
92
|
```
|
|
93
93
|
|
|
@@ -131,6 +131,7 @@ ready
|
|
|
131
131
|
|
|
132
132
|
```ts
|
|
133
133
|
export interface SuperAgentSDK {
|
|
134
|
+
readonly botId: number; // 当前 Bot ID
|
|
134
135
|
createSession(): Promise<string>;
|
|
135
136
|
chat(options: ChatOptions): AbortController;
|
|
136
137
|
listConversations(
|
|
@@ -141,9 +142,19 @@ export interface SuperAgentSDK {
|
|
|
141
142
|
getMessages(sessionId: string): Promise<UIMessage[]>;
|
|
142
143
|
getToken(): Promise<string>;
|
|
143
144
|
setToken(token: string): void;
|
|
144
|
-
feedback(
|
|
145
|
+
feedback(
|
|
146
|
+
messageId: string,
|
|
147
|
+
type: "like" | "dislike",
|
|
148
|
+
options?: { reason?: number; remark?: string },
|
|
149
|
+
): Promise<void>;
|
|
145
150
|
cancelFeedback(messageId: string): Promise<void>;
|
|
146
|
-
respondInterrupt(
|
|
151
|
+
respondInterrupt(
|
|
152
|
+
interruptId: string,
|
|
153
|
+
sessionId: string,
|
|
154
|
+
response: InterruptResponse,
|
|
155
|
+
onMessage?: (event: ChatEvent) => void,
|
|
156
|
+
onError?: (error: Error) => void,
|
|
157
|
+
): Promise<void>;
|
|
147
158
|
listSkills(): Promise<SkillInfo[]>;
|
|
148
159
|
stopGeneration(sessionId: string): Promise<void>;
|
|
149
160
|
}
|
|
@@ -175,7 +186,11 @@ export interface ChatOptions {
|
|
|
175
186
|
stream?: boolean; // 默认 true
|
|
176
187
|
onMessage?: (event: ChatEvent) => void;
|
|
177
188
|
onError?: (error: Error) => void;
|
|
178
|
-
onDone?: (result: {
|
|
189
|
+
onDone?: (result: {
|
|
190
|
+
sessionId: string;
|
|
191
|
+
content: string;
|
|
192
|
+
messageId?: string;
|
|
193
|
+
}) => void; // messageId:后端在 done 事件返回的消息标识(存在时 SDK Widget 用其启用消息反馈,若返回可据此判断该消息可 feedback)
|
|
179
194
|
signal?: AbortSignal;
|
|
180
195
|
}
|
|
181
196
|
```
|
|
@@ -303,41 +318,74 @@ sdk.setToken("<TOKEN>");
|
|
|
303
318
|
|
|
304
319
|
消息反馈(赞/踩)。调用 `sdk.feedback()` 发送 `POST /chat/messages/{messageId}/feedback`;调用 `sdk.cancelFeedback()` 发送 `DELETE` 取消反馈。
|
|
305
320
|
|
|
321
|
+
> **messageId 说明**:即消息历史返回的表主键 `id`(数字),不是 `messageId`(UUID)。纯 API 模式从 `getMessages()` 结果取 `UIMessage.id`。
|
|
322
|
+
|
|
306
323
|
```ts
|
|
324
|
+
const messages = await sdk.getMessages(sessionId);
|
|
325
|
+
const aiMsg = messages.findLast((m) => m.role === "assistant");
|
|
326
|
+
|
|
307
327
|
// 点赞
|
|
308
|
-
await sdk.feedback(
|
|
328
|
+
await sdk.feedback(aiMsg.id, "like");
|
|
309
329
|
|
|
310
330
|
// 踩(可附原因 + 备注)
|
|
311
|
-
await sdk.feedback(
|
|
312
|
-
reason: 1,
|
|
331
|
+
await sdk.feedback(aiMsg.id, "dislike", {
|
|
332
|
+
reason: 1, // 1=事实错误 2=逻辑问题 3=不相关 4=信息过时 5=冗长啰嗦 6=难以理解
|
|
313
333
|
remark: "时间描述有误",
|
|
314
334
|
});
|
|
315
335
|
|
|
316
336
|
// 取消反馈
|
|
317
|
-
await sdk.cancelFeedback(
|
|
337
|
+
await sdk.cancelFeedback(aiMsg.id);
|
|
318
338
|
```
|
|
319
339
|
|
|
320
340
|
组件内置的点赞/踩按钮已自动调用 `feedback()`/`cancelFeedback()`:
|
|
341
|
+
|
|
321
342
|
- 点击已选中的按钮 → 取消(DELETE)
|
|
322
343
|
- 点击另一个按钮 → 切换(POST)
|
|
323
344
|
- 点踩时弹出原因选择面板(可选填原因 + 备注后提交)
|
|
345
|
+
- 流式渲染期间消息尚无后端 ID(临时占位),此时点击反馈 SDK 会自动拉取一次历史消息解析真实 ID 再发送,业务方无感知
|
|
346
|
+
|
|
347
|
+
### 5.10 respondInterrupt()
|
|
348
|
+
|
|
349
|
+
响应中断事件(Human-in-the-Loop),后端继续推送后续 SSE 事件:
|
|
350
|
+
|
|
351
|
+
```ts
|
|
352
|
+
sdk.respondInterrupt(
|
|
353
|
+
interruptId: string,
|
|
354
|
+
sessionId: string,
|
|
355
|
+
response: InterruptResponse,
|
|
356
|
+
onMessage?: (event: ChatEvent) => void,
|
|
357
|
+
onError?: (error: Error) => void
|
|
358
|
+
): Promise<void>
|
|
359
|
+
```
|
|
360
|
+
|
|
361
|
+
Widget 内置中断卡片会自动调用此方法,纯 API 模式需手动处理(详见 [12. Human-in-the-Loop](#12-human-in-the-loop))。
|
|
362
|
+
|
|
363
|
+
### 5.11 listSkills()
|
|
324
364
|
|
|
325
|
-
|
|
365
|
+
获取当前 Bot 绑定的技能列表(用于 `/` 斜杠命令选择技能):
|
|
366
|
+
|
|
367
|
+
```ts
|
|
368
|
+
const skills: SkillInfo[] = await sdk.listSkills();
|
|
369
|
+
// [{ code: "web-searcher", name: "web-searcher", displayName: "网页搜索", description: "..." }]
|
|
370
|
+
```
|
|
371
|
+
|
|
372
|
+
### 5.12 后端接口对照
|
|
326
373
|
|
|
327
374
|
SDK 方法 → 后端接口的完整映射:
|
|
328
375
|
|
|
329
376
|
> 除 `getToken()` 外,其余接口请求均携带 `X-App-Id` 与 `X-Token` 请求头进行鉴权。
|
|
330
377
|
|
|
331
|
-
| SDK 方法 | HTTP 请求
|
|
332
|
-
| --------------------- |
|
|
333
|
-
| `getToken()` | `POST {gateway}/v1/token`
|
|
334
|
-
| `createSession()` | `POST /chat/sessions`
|
|
335
|
-
| `chat()` | `POST /chat`
|
|
336
|
-
| `listConversations()` | `GET /chat/conversations`
|
|
337
|
-
| `feedback()` | `POST /chat/messages/{messageId}/feedback`
|
|
338
|
-
| `cancelFeedback()` | `DELETE /chat/messages/{messageId}/feedback` | 无 body
|
|
339
|
-
| `
|
|
340
|
-
| `
|
|
378
|
+
| SDK 方法 | HTTP 请求 | 请求体 | 后端返回 |
|
|
379
|
+
| --------------------- | -------------------------------------------- | --------------------------------------- | ----------------------------------------------- |
|
|
380
|
+
| `getToken()` | `POST {gateway}/v1/token` | `{ botId }` | `{ token, appId }` |
|
|
381
|
+
| `createSession()` | `POST /chat/sessions` | `{ botId }` | `{ sessionId }` |
|
|
382
|
+
| `chat()` | `POST /chat` | `{ botId, sessionId, message, stream }` | SSE 流,`done`/`stop` 事件含 `sessionId` |
|
|
383
|
+
| `listConversations()` | `GET /chat/conversations` | 查询参数 `botId`、`page`、`size` | `{ items: [{ sessionId, botId, ... }], total }` |
|
|
384
|
+
| `feedback()` | `POST /chat/messages/{messageId}/feedback` | `{ type, reason?, remark? }` | `null` |
|
|
385
|
+
| `cancelFeedback()` | `DELETE /chat/messages/{messageId}/feedback` | 无 body | `null` |
|
|
386
|
+
| `respondInterrupt()` | `POST /chat/interrupt/{interruptId}/respond` | `{ sessionId, action, value? }` | SSE 流(后续事件) |
|
|
387
|
+
| `stopGeneration()` | `POST /chat/stop` | `{ sessionId }` | `{ stopped: "pending", sessionId }` |
|
|
388
|
+
| `listSkills()` | `GET /chat/bots/{botId}/skills` | — | `[{ code, name, displayName, description }]` |
|
|
341
389
|
|
|
342
390
|
---
|
|
343
391
|
|
|
@@ -363,7 +411,26 @@ export interface MountOptions {
|
|
|
363
411
|
suggestedPrompts?: string[];
|
|
364
412
|
title?: string; // 标题,默认 "AI Assistant"
|
|
365
413
|
sidebarDefaultOpen?: boolean; // fullpage 模式:侧边栏初始展开(默认 true)
|
|
366
|
-
avatar?: AvatarConfig; //
|
|
414
|
+
avatar?: AvatarConfig; // 自定义头像(AI 消息始终有内置默认头像;用户头像未配置则不显示)
|
|
415
|
+
artifactPreview?: boolean; // 产物预览总开关(html/pdf/docx 预览 + 下载 + 全屏),默认 false
|
|
416
|
+
capabilities?: CapabilityItem[]; // floating 首页:能力清单(icon + 标签 + 描述)
|
|
417
|
+
quickLinks?: QuickLinkItem[]; // floating 首页:快速入口
|
|
418
|
+
logo?: string; // floating 首页居中 Logo(URL),默认 SDK 内置 Logo
|
|
419
|
+
triggerLogo?: string; // floating 触发按钮 Logo(URL),默认 SDK 内置 Logo
|
|
420
|
+
showTimestamp?: boolean; // 显示消息时间戳,默认 false 不显示
|
|
421
|
+
}
|
|
422
|
+
|
|
423
|
+
export interface CapabilityItem {
|
|
424
|
+
icon?: string; // 图标 URL
|
|
425
|
+
label: string; // 能力名称
|
|
426
|
+
desc?: string; // 能力描述(超长自动省略)
|
|
427
|
+
}
|
|
428
|
+
|
|
429
|
+
export interface QuickLinkItem {
|
|
430
|
+
icon?: string; // 图标 URL
|
|
431
|
+
label: string; // 入口名称
|
|
432
|
+
prompt?: string; // 点击后发送的消息
|
|
433
|
+
onClick?: () => void; // 自定义点击行为(优先于 prompt)
|
|
367
434
|
}
|
|
368
435
|
|
|
369
436
|
export interface WidgetInstance {
|
|
@@ -398,16 +465,38 @@ widget.destroy(); // 卸载并移除 DOM
|
|
|
398
465
|
|
|
399
466
|
> 挂载后默认是收起状态,需调用 `widget.open()` 展开。
|
|
400
467
|
|
|
468
|
+
### 6.2 源码接入(monorepo alias)注意事项
|
|
469
|
+
|
|
470
|
+
Widget 内部使用 **Tailwind CSS**(utility 全部限定在 `[data-super-agent-widget]` 宿主选择器内、禁用 preflight,不影响宿主页样式)。分发包(`dist`)已内联全部样式;内置图片资产(Logo/图标/头像等)走 CDN 绝对路径(`src/widget/assets/index.ts` 的 `BASE_URL`),**npm 引入无需任何配置**(需能访问 CDN)。
|
|
471
|
+
|
|
472
|
+
若宿主工程通过 vite alias 直接引用 SDK **源码**(如本仓库 frontend 的做法),则 SDK 的样式会由宿主自己的 PostCSS/Tailwind 管线处理,需要满足:
|
|
473
|
+
|
|
474
|
+
1. 宿主 `tailwind.config` 的 `content` 包含 SDK 源码路径,否则 widget 的 utility 类不会生成:
|
|
475
|
+
|
|
476
|
+
```ts
|
|
477
|
+
// frontend/tailwind.config.ts
|
|
478
|
+
export default {
|
|
479
|
+
content: [
|
|
480
|
+
'./index.html',
|
|
481
|
+
'./src/**/*.{js,jsx,ts,tsx}',
|
|
482
|
+
'../sdk/src/**/*.{ts,tsx}', // SDK 源码
|
|
483
|
+
],
|
|
484
|
+
// ...
|
|
485
|
+
};
|
|
486
|
+
```
|
|
487
|
+
|
|
488
|
+
2. 无需在宿主 config 中镜像 SDK 的 `important: '[data-super-agent-widget]'`(那会把宿主自己的 utility 也锁进 widget 容器内);宿主管线生成的 utility 为普通类,widget DOM 照常命中,动画/自定义类由 SDK 自带的 `tailwind.css`(运行时注入)保证。
|
|
489
|
+
|
|
401
490
|
---
|
|
402
491
|
|
|
403
492
|
## 7. 展示模式
|
|
404
493
|
|
|
405
494
|
通过 `mode` 切换两种展示模式:
|
|
406
495
|
|
|
407
|
-
| 模式 | 说明
|
|
408
|
-
| ------------------ |
|
|
409
|
-
| `floating`(默认) |
|
|
410
|
-
| `fullpage` |
|
|
496
|
+
| 模式 | 说明 |
|
|
497
|
+
| ------------------ | ---------------------------------------------------------- |
|
|
498
|
+
| `floating`(默认) | 右下角 Logo 触发按钮 + 可拖拽/拉伸/最大化的浮窗聊天窗口 |
|
|
499
|
+
| `fullpage` | 整页布局,左侧会话栏(hr-for-help 风格)+ 右侧聊天区 |
|
|
411
500
|
|
|
412
501
|
```ts
|
|
413
502
|
mount("#chat-root", { sdk, mode: "fullpage" });
|
|
@@ -419,6 +508,21 @@ mount("#chat-root", { sdk, mode: "fullpage" });
|
|
|
419
508
|
mount("#chat-root", { sdk, mode: "fullpage", sidebarDefaultOpen: false });
|
|
420
509
|
```
|
|
421
510
|
|
|
511
|
+
### 7.1 浮窗模式(floating)交互
|
|
512
|
+
|
|
513
|
+
浮窗窗口对齐 hr-for-help 设计,开箱具备以下交互能力:
|
|
514
|
+
|
|
515
|
+
- **标题栏拖拽**:按住顶部导航栏移动窗口(视口内钳制,按钮区域不触发)
|
|
516
|
+
- **左右拉伸调宽**:窗口左右两侧 6px 手柄拖拽,宽度范围 360 ~ 800 px,拖超过 800 自动进入大窗
|
|
517
|
+
- **大窗/小窗切换**:header 右侧「大窗」按钮切换;大窗为底部弹出的近全屏 overlay(内容区 800px 居中),回小窗时宽度重置为默认值
|
|
518
|
+
- **内容自适应高度**:聊天内容增长时窗口自动变高(默认 648px,上限 95% 视口,超出后消息区滚动),回到首页恢复默认高度
|
|
519
|
+
- **内嵌会话侧边栏**:header「历史记录」按钮开合;小窗展开时窗口自动加宽 200px;大窗模式自动展开(220px),大窗/小窗各自记住用户偏好
|
|
520
|
+
- **关闭即还原**:关闭窗口后几何状态(位置/宽度/大窗态/高度)全部重置
|
|
521
|
+
|
|
522
|
+
浮窗消息展示对齐 hr-for-help:AI 头像独占一行(无背景色,生成中切换动效头像)、气泡白底描边、用户气泡浅蓝右对齐;`fullpage` 模式保持横排头像 + 经典气泡,两者互不影响。
|
|
523
|
+
|
|
524
|
+
首页(无消息时)包含:居中 Logo(浮动动画)+ 流光渐变标题 + 能力清单 + 建议词 chips + 快速入口,内容通过 `capabilities` / `suggestedPrompts` / `quickLinks` / `logo` 配置(见 6.1;icon 可复用 `super-agent-sdk/widget` 导出的内置 `ASSETS`)。
|
|
525
|
+
|
|
422
526
|
---
|
|
423
527
|
|
|
424
528
|
## 8. 定制化
|
|
@@ -433,8 +537,8 @@ export interface ThemeConfig {
|
|
|
433
537
|
backgroundColor?: string; // 默认 #ffffff
|
|
434
538
|
fontFamily?: string; // 默认 system-ui, -apple-system, sans-serif
|
|
435
539
|
borderRadius?: number; // 默认 16 (px)
|
|
436
|
-
panelWidth?: number; //
|
|
437
|
-
panelHeight?: number; //
|
|
540
|
+
panelWidth?: number; // floating 初始宽度,默认 400 (px)
|
|
541
|
+
panelHeight?: number; // floating 初始高度,默认 648 (px)
|
|
438
542
|
zIndex?: number; // 默认 9999
|
|
439
543
|
}
|
|
440
544
|
```
|
|
@@ -447,8 +551,8 @@ export interface ThemeConfig {
|
|
|
447
551
|
| `--sa-bg` | `#ffffff` | `backgroundColor` |
|
|
448
552
|
| `--sa-font` | `system-ui, -apple-system, sans-serif` | `fontFamily` |
|
|
449
553
|
| `--sa-radius` | `16px` | `borderRadius` |
|
|
450
|
-
| `--sa-panel-width` | `
|
|
451
|
-
| `--sa-panel-height` | `
|
|
554
|
+
| `--sa-panel-width` | `400px` | `panelWidth` |
|
|
555
|
+
| `--sa-panel-height` | `648px` | `panelHeight` |
|
|
452
556
|
| `--sa-z-index` | `9999` | `zIndex` |
|
|
453
557
|
|
|
454
558
|
```ts
|
|
@@ -468,12 +572,12 @@ mount("#chat-root", {
|
|
|
468
572
|
|
|
469
573
|
### 8.2 头像定制
|
|
470
574
|
|
|
471
|
-
通过 `avatar`
|
|
575
|
+
通过 `avatar` 配置助手与用户的头像,支持图片 URL、emoji 或文本。以 `http(s)://`、`data:`、`blob:`、`/`、`./`、`../`、`//` 开头的字符串渲染为图片,其余作为 emoji/文本展示(无背景色):
|
|
472
576
|
|
|
473
577
|
```ts
|
|
474
578
|
export interface AvatarConfig {
|
|
475
|
-
assistant?: string; // URL、emoji
|
|
476
|
-
user?: string;
|
|
579
|
+
assistant?: string; // 图片 URL、emoji 或文本;默认 SDK 内置头像(生成中显示动效头像)
|
|
580
|
+
user?: string; // 图片 URL、emoji 或文本;未配置则不显示用户头像
|
|
477
581
|
}
|
|
478
582
|
```
|
|
479
583
|
|
|
@@ -481,7 +585,7 @@ export interface AvatarConfig {
|
|
|
481
585
|
mount("#chat-root", {
|
|
482
586
|
sdk,
|
|
483
587
|
avatar: {
|
|
484
|
-
assistant: "🤖",
|
|
588
|
+
assistant: "🤖", // 配置后覆盖内置默认头像
|
|
485
589
|
user: "https://cdn.example.com/user-avatar.png",
|
|
486
590
|
},
|
|
487
591
|
});
|
|
@@ -504,24 +608,25 @@ export interface Slots {
|
|
|
504
608
|
ToolCallPart?: ComponentType<ToolCallPartProps>;
|
|
505
609
|
ToolResultPart?: ComponentType<ToolResultPartProps>;
|
|
506
610
|
ErrorPart?: ComponentType<ErrorPartProps>;
|
|
611
|
+
InterruptCard?: ComponentType<InterruptCardProps>;
|
|
507
612
|
WelcomeScreen?: ComponentType<WelcomeScreenProps>;
|
|
508
613
|
}
|
|
509
614
|
```
|
|
510
615
|
|
|
511
|
-
| 插槽 | Props 接口 | 说明
|
|
512
|
-
| ---------------- | --------------------- |
|
|
513
|
-
| `Trigger` | `TriggerProps` | 悬浮触发按钮
|
|
514
|
-
| `Header` | `HeaderProps` | 面板标题栏
|
|
515
|
-
| `Message` | `MessageProps` | 单条消息容器(完整自定义消息渲染)
|
|
516
|
-
| `Composer` | `ComposerProps` | 输入框 / 发送栏
|
|
517
|
-
| `ActionBar` | `ActionBarProps` | 消息操作栏(复制 / 重试 / 反馈)
|
|
518
|
-
| `ThreadList` | `ThreadListProps` | 会话列表(浮窗模式覆盖层 / 全屏模式侧边栏)
|
|
519
|
-
| `ThinkingPart` | `ThinkingPartProps` | 思考过程块
|
|
520
|
-
| `TextPart` | `TextPartProps` | 文本块
|
|
521
|
-
| `ToolCallPart` | `ToolCallPartProps` |
|
|
522
|
-
| `ToolResultPart` | `ToolResultPartProps` |
|
|
523
|
-
| `ErrorPart` | `ErrorPartProps` | 错误提示块
|
|
524
|
-
| `WelcomeScreen` | `WelcomeScreenProps` | 空会话欢迎页
|
|
616
|
+
| 插槽 | Props 接口 | 说明 |
|
|
617
|
+
| ---------------- | --------------------- | -------------------------------------------------------------------------------------------------- |
|
|
618
|
+
| `Trigger` | `TriggerProps` | 悬浮触发按钮 |
|
|
619
|
+
| `Header` | `HeaderProps` | 面板标题栏 |
|
|
620
|
+
| `Message` | `MessageProps` | 单条消息容器(完整自定义消息渲染) |
|
|
621
|
+
| `Composer` | `ComposerProps` | 输入框 / 发送栏 |
|
|
622
|
+
| `ActionBar` | `ActionBarProps` | 消息操作栏(复制 / 重试 / 反馈) |
|
|
623
|
+
| `ThreadList` | `ThreadListProps` | 会话列表(浮窗模式覆盖层 / 全屏模式侧边栏) |
|
|
624
|
+
| `ThinkingPart` | `ThinkingPartProps` | 思考过程块 |
|
|
625
|
+
| `TextPart` | `TextPartProps` | 文本块 |
|
|
626
|
+
| `ToolCallPart` | `ToolCallPartProps` | 工具调用卡片(可折叠 + 展开后复制参数) |
|
|
627
|
+
| `ToolResultPart` | `ToolResultPartProps` | 工具返回卡片(pre 滚动 + 复制;`renderMode==="html"` 时 DOMPurify 清洗后直接渲染,最高 60vh 滚动) |
|
|
628
|
+
| `ErrorPart` | `ErrorPartProps` | 错误提示块 |
|
|
629
|
+
| `WelcomeScreen` | `WelcomeScreenProps` | 空会话欢迎页 |
|
|
525
630
|
|
|
526
631
|
#### Trigger
|
|
527
632
|
|
|
@@ -530,6 +635,7 @@ export interface TriggerProps {
|
|
|
530
635
|
isOpen: boolean;
|
|
531
636
|
onClick: () => void;
|
|
532
637
|
unreadCount?: number;
|
|
638
|
+
triggerLogo?: string; // 触发按钮 Logo(URL)
|
|
533
639
|
}
|
|
534
640
|
```
|
|
535
641
|
|
|
@@ -549,11 +655,21 @@ function MyTrigger({ isOpen, onClick, unreadCount }: TriggerProps) {
|
|
|
549
655
|
|
|
550
656
|
#### Header
|
|
551
657
|
|
|
658
|
+
floating 与 fullpage 模式均支持替换;`onToggleThreadList` 在 floating 下切换内嵌会话侧边栏、在 fullpage 下切换左侧边栏;开启 `artifactPreview` 后额外提供产物入口字段。
|
|
659
|
+
|
|
660
|
+
> 注:fullpage 内置 Header 只有标题与产物入口(无关闭按钮);需要关闭入口时通过自定义 Header 的 `onClose` 自行渲染。floating 内置 Header 含历史/回首页/大窗/关闭按钮。
|
|
661
|
+
|
|
552
662
|
```ts
|
|
553
663
|
export interface HeaderProps {
|
|
554
664
|
title: string;
|
|
555
665
|
onClose: () => void;
|
|
556
666
|
onToggleThreadList: () => void;
|
|
667
|
+
isMaximized?: boolean; // floating:大窗状态
|
|
668
|
+
onToggleMaximize?: () => void; // floating:大窗/小窗切换
|
|
669
|
+
showHome?: boolean; // floating:聊天态显示回到首页
|
|
670
|
+
onHome?: () => void; // floating:回到首页(新会话)
|
|
671
|
+
artifactCount?: number; // 会话产物数量(artifactPreview 开启时提供)
|
|
672
|
+
onToggleArtifactDrawer?: () => void; // 打开/关闭产物预览抽屉
|
|
557
673
|
}
|
|
558
674
|
```
|
|
559
675
|
|
|
@@ -697,8 +813,12 @@ function MyComposer({ status, onSend, onStop }: ComposerProps) {
|
|
|
697
813
|
export interface ActionBarProps {
|
|
698
814
|
message: UIMessage;
|
|
699
815
|
onCopy: () => void;
|
|
700
|
-
onRegenerate
|
|
701
|
-
onFeedback?: (
|
|
816
|
+
onRegenerate?: () => void;
|
|
817
|
+
onFeedback?: (
|
|
818
|
+
messageId: string,
|
|
819
|
+
feedback: "like" | "dislike",
|
|
820
|
+
options?: { reason?: number; remark?: string },
|
|
821
|
+
) => void;
|
|
702
822
|
}
|
|
703
823
|
```
|
|
704
824
|
|
|
@@ -720,9 +840,9 @@ function MyActionBar({
|
|
|
720
840
|
}
|
|
721
841
|
```
|
|
722
842
|
|
|
723
|
-
#### ThreadList
|
|
843
|
+
#### ThreadList(浮窗内嵌会话侧边栏 + 全屏模式侧边栏)
|
|
724
844
|
|
|
725
|
-
在 `floating`
|
|
845
|
+
在 `floating` 模式下作为窗口内嵌侧边栏渲染(小窗 200px / 大窗 220px,随「历史记录」按钮开合);在 `fullpage` 模式下作为左侧侧边栏渲染(220px,可收起为图标栏)。
|
|
726
846
|
|
|
727
847
|
```ts
|
|
728
848
|
export interface ThreadListProps {
|
|
@@ -797,6 +917,10 @@ export interface ToolResultPartProps {
|
|
|
797
917
|
toolName: string;
|
|
798
918
|
toolCallId: string;
|
|
799
919
|
content: string;
|
|
920
|
+
artifacts?: Artifact[];
|
|
921
|
+
renderMode?: string;
|
|
922
|
+
html?: string;
|
|
923
|
+
artifactPreview?: boolean;
|
|
800
924
|
}
|
|
801
925
|
export interface ErrorPartProps {
|
|
802
926
|
content: string;
|
|
@@ -1113,7 +1237,7 @@ await sdk.deleteConversation(items[0].sessionId);
|
|
|
1113
1237
|
- **新建**:点击「新会话」清空当前消息,下次发送时自动调用 `createSession()` 创建新会话。
|
|
1114
1238
|
- **重命名**:`fullpage` 侧边栏或自定义 `ThreadList` 中调用 `renameConversation`。
|
|
1115
1239
|
- **删除**:悬停会话项后点击删除按钮。
|
|
1116
|
-
- **本地持久化**:最近一次活跃会话写入 `localStorage`,键为 `
|
|
1240
|
+
- **本地持久化**:最近一次活跃会话写入 `localStorage`,键为 `sa_active_conversation_{botId}`(按 Bot 隔离,切换 Bot 后互不串扰)。
|
|
1117
1241
|
|
|
1118
1242
|
---
|
|
1119
1243
|
|
|
@@ -1136,7 +1260,7 @@ const controller = sdk.chat({
|
|
|
1136
1260
|
message: "...",
|
|
1137
1261
|
stream: true,
|
|
1138
1262
|
onMessage: (event) => {
|
|
1139
|
-
if (event.type ===
|
|
1263
|
+
if (event.type === "stop") {
|
|
1140
1264
|
// 用户主动停止,event.content 为已生成的半截回复全文
|
|
1141
1265
|
console.log("已停止,半截回复:", event.content);
|
|
1142
1266
|
}
|
|
@@ -1185,7 +1309,7 @@ ac.abort();
|
|
|
1185
1309
|
|
|
1186
1310
|
页面刷新或组件重新挂载时,会话状态自动恢复:
|
|
1187
1311
|
|
|
1188
|
-
1. 挂载时从 `localStorage` 读取上次活跃会话 ID(键 `
|
|
1312
|
+
1. 挂载时从 `localStorage` 读取上次活跃会话 ID(键 `sa_active_conversation_{botId}`)。
|
|
1189
1313
|
2. 若该会话仍在列表中,自动调用 `getMessages` 拉取历史消息并渲染。
|
|
1190
1314
|
3. 若存储的会话已不存在(被删除),则自动清空并回退到「新会话」。
|
|
1191
1315
|
|
|
@@ -1218,17 +1342,27 @@ export type MessagePart =
|
|
|
1218
1342
|
toolName: string;
|
|
1219
1343
|
toolCallId: string;
|
|
1220
1344
|
content: string;
|
|
1345
|
+
artifacts?: Artifact[];
|
|
1346
|
+
renderMode?: string;
|
|
1347
|
+
html?: string;
|
|
1221
1348
|
}
|
|
1222
|
-
| { type: "error"; content: string }
|
|
1223
|
-
|
|
1224
|
-
|
|
1225
|
-
|
|
1226
|
-
|
|
1227
|
-
|
|
1228
|
-
|
|
1229
|
-
|
|
1230
|
-
|
|
1231
|
-
|
|
|
1349
|
+
| { type: "error"; content: string }
|
|
1350
|
+
| {
|
|
1351
|
+
type: "interrupt";
|
|
1352
|
+
interrupt: InterruptEvent;
|
|
1353
|
+
resolved?: boolean;
|
|
1354
|
+
response?: InterruptResponse;
|
|
1355
|
+
};
|
|
1356
|
+
```
|
|
1357
|
+
|
|
1358
|
+
| type | 字段 | 说明 |
|
|
1359
|
+
| ------------- | ------------------------------------------------------------------------- | ------------------------------- |
|
|
1360
|
+
| `text` | `content` | 文本 / Markdown 内容 |
|
|
1361
|
+
| `thinking` | `content` | 思考过程(reasoning) |
|
|
1362
|
+
| `tool_call` | `toolName`, `toolCallId`, `args` | 工具调用,`args` 为 JSON 字符串 |
|
|
1363
|
+
| `tool_result` | `toolName`, `toolCallId`, `content`, `artifacts?`, `renderMode?`, `html?` | 工具返回结果 |
|
|
1364
|
+
| `error` | `content` | 错误信息 |
|
|
1365
|
+
| `interrupt` | `interrupt`, `resolved?`, `response?` | 中断交互卡片(HITL) |
|
|
1232
1366
|
|
|
1233
1367
|
### 11.3 ChatEvent(流式事件)
|
|
1234
1368
|
|
|
@@ -1242,12 +1376,18 @@ export interface ChatEvent {
|
|
|
1242
1376
|
| "tool_result"
|
|
1243
1377
|
| "done"
|
|
1244
1378
|
| "stop"
|
|
1245
|
-
| "error"
|
|
1379
|
+
| "error"
|
|
1380
|
+
| "interrupt";
|
|
1246
1381
|
content: string;
|
|
1247
1382
|
toolName?: string;
|
|
1248
1383
|
toolCallId?: string;
|
|
1249
1384
|
args?: string; // JSON.stringify 后的字符串
|
|
1250
1385
|
sessionId?: string;
|
|
1386
|
+
messageId?: string; // done 事件携带后端消息标识(后端返回时该消息可反馈/feedback)
|
|
1387
|
+
interrupt?: InterruptEvent; // interrupt 事件携带中断详情
|
|
1388
|
+
artifacts?: Artifact[]; // tool_result 事件携带的结构化产物
|
|
1389
|
+
renderMode?: string; // "html" 时工具结果为富文本
|
|
1390
|
+
html?: string; // renderMode==="html" 时的 HTML 内容
|
|
1251
1391
|
}
|
|
1252
1392
|
```
|
|
1253
1393
|
|
|
@@ -1283,7 +1423,7 @@ Agent 执行中
|
|
|
1283
1423
|
### 12.3 响应中断
|
|
1284
1424
|
|
|
1285
1425
|
```ts
|
|
1286
|
-
await sdk.respondInterrupt(interruptId, {
|
|
1426
|
+
await sdk.respondInterrupt(interruptId, sessionId, {
|
|
1287
1427
|
action: "confirm",
|
|
1288
1428
|
});
|
|
1289
1429
|
```
|
|
@@ -1303,7 +1443,7 @@ mount("#chat", { sdk }).open();
|
|
|
1303
1443
|
mount("#chat", {
|
|
1304
1444
|
sdk,
|
|
1305
1445
|
slots: {
|
|
1306
|
-
InterruptCard: MyInterruptCard,
|
|
1446
|
+
InterruptCard: MyInterruptCard, // 自定义全部类型
|
|
1307
1447
|
},
|
|
1308
1448
|
});
|
|
1309
1449
|
```
|
|
@@ -1318,7 +1458,7 @@ sdk.chat({
|
|
|
1318
1458
|
if (e.type === "interrupt" && e.interrupt) {
|
|
1319
1459
|
// 自定义 UI 处理
|
|
1320
1460
|
const ok = window.confirm(e.interrupt.content);
|
|
1321
|
-
sdk.respondInterrupt(e.interrupt.interruptId, {
|
|
1461
|
+
sdk.respondInterrupt(e.interrupt.interruptId, sessionId, {
|
|
1322
1462
|
action: ok ? "confirm" : "cancel",
|
|
1323
1463
|
});
|
|
1324
1464
|
}
|
|
@@ -1328,23 +1468,25 @@ sdk.chat({
|
|
|
1328
1468
|
|
|
1329
1469
|
### 12.6 interruptType 一览
|
|
1330
1470
|
|
|
1331
|
-
| interruptType | 交互
|
|
1332
|
-
|
|
1333
|
-
| `confirm`
|
|
1334
|
-
| `select`
|
|
1335
|
-
| `multiSelect` | 多选
|
|
1336
|
-
| `input`
|
|
1337
|
-
| `form`
|
|
1338
|
-
| `review`
|
|
1339
|
-
| `approve`
|
|
1340
|
-
| `upload`
|
|
1341
|
-
| `image`
|
|
1342
|
-
| `auth`
|
|
1343
|
-
| `captcha`
|
|
1344
|
-
| `decision`
|
|
1345
|
-
| `rating`
|
|
1346
|
-
| `date`
|
|
1347
|
-
| `location`
|
|
1471
|
+
| interruptType | 交互 | action | value 示例 |
|
|
1472
|
+
| ------------- | -------- | --------------------- | ----------------------- |
|
|
1473
|
+
| `confirm` | 二次确认 | `confirm` / `cancel` | — |
|
|
1474
|
+
| `select` | 单选 | `select` | `"flight_a"` |
|
|
1475
|
+
| `multiSelect` | 多选 | `submit` | `["name", "phone"]` |
|
|
1476
|
+
| `input` | 文本输入 | `submit` | `"123456"` |
|
|
1477
|
+
| `form` | 表单 | `submit` | `{ name: "张三" }` |
|
|
1478
|
+
| `review` | 内容审阅 | `approve` / `reject` | 修改后内容 |
|
|
1479
|
+
| `approve` | 审批流 | `approve` / `reject` | 驳回原因 |
|
|
1480
|
+
| `upload` | 文件上传 | `submit` | `{ fileId, fileName }` |
|
|
1481
|
+
| `image` | 图片选择 | `select` / `reject` | 图片索引 |
|
|
1482
|
+
| `auth` | 授权请求 | `authorized` / `skip` | — |
|
|
1483
|
+
| `captcha` | 人机验证 | `verified` | `"captcha_token"` |
|
|
1484
|
+
| `decision` | 流程分支 | `decide` | `"retry"` 等 |
|
|
1485
|
+
| `rating` | 评分 | `rate` | `4` |
|
|
1486
|
+
| `date` | 日期选择 | `submit` | `"2026-08-21T14:00:00"` |
|
|
1487
|
+
| `location` | 位置选择 | `submit` | `{ address, lat, lng }` |
|
|
1488
|
+
|
|
1489
|
+
> `form` 的字段定义见 `FormField`(`types.ts`):`type` 支持 `text` / `number` / `password` / `textarea` / `select` / `multiSelect` / `date`;`options` 支持字符串数组或 `{ value, label }` 数组。已回答的历史 interrupt 以禁用态回显用户答案。
|
|
1348
1490
|
|
|
1349
1491
|
> 每个 `interruptType` 的完整字段定义见 [API 文档](./API.md) 与 [HITL 设计文档](../docs/superpowers/specs/2026-08-18-human-in-the-loop-design.md)。
|
|
1350
1492
|
|
|
@@ -1404,6 +1546,10 @@ interface UseChatReturn {
|
|
|
1404
1546
|
stop: () => void;
|
|
1405
1547
|
regenerate: () => void;
|
|
1406
1548
|
setMessages: (messages: UIMessage[]) => void;
|
|
1549
|
+
respondToInterrupt: (
|
|
1550
|
+
interruptId: string,
|
|
1551
|
+
response: InterruptResponse,
|
|
1552
|
+
) => void;
|
|
1407
1553
|
}
|
|
1408
1554
|
```
|
|
1409
1555
|
|
|
@@ -1415,15 +1561,18 @@ export function useConversations(
|
|
|
1415
1561
|
interface UseConversationsOptions {
|
|
1416
1562
|
sdk: SuperAgentSDK;
|
|
1417
1563
|
onConversationChange?: (sessionId: string) => void;
|
|
1564
|
+
enabled?: boolean; // 默认 true,false 时不自动加载
|
|
1418
1565
|
}
|
|
1419
1566
|
|
|
1420
1567
|
interface UseConversationsReturn {
|
|
1421
1568
|
conversations: Conversation[];
|
|
1422
1569
|
activeConversationId: string | null;
|
|
1423
1570
|
loading: boolean;
|
|
1571
|
+
hasMore: boolean;
|
|
1424
1572
|
loadConversations: () => Promise<void>;
|
|
1573
|
+
loadMore: () => Promise<void>;
|
|
1425
1574
|
switchConversation: (sessionId: string) => Promise<UIMessage[]>;
|
|
1426
|
-
newConversation: () => void
|
|
1575
|
+
newConversation: () => Promise<void>;
|
|
1427
1576
|
deleteConversation: (sessionId: string) => Promise<void>;
|
|
1428
1577
|
renameConversation: (sessionId: string, title: string) => Promise<void>;
|
|
1429
1578
|
setActiveConversationId: (id: string | null) => void;
|