super-agent-sdk 1.0.8 → 1.0.10
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 +253 -81
- package/dist/widget.cjs +152 -701
- package/dist/widget.d.ts +187 -10
- package/dist/widget.mjs +2120 -2084
- 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
|
|
|
@@ -142,9 +142,19 @@ export interface SuperAgentSDK {
|
|
|
142
142
|
getMessages(sessionId: string): Promise<UIMessage[]>;
|
|
143
143
|
getToken(): Promise<string>;
|
|
144
144
|
setToken(token: string): void;
|
|
145
|
-
feedback(
|
|
145
|
+
feedback(
|
|
146
|
+
messageId: string,
|
|
147
|
+
type: "like" | "dislike",
|
|
148
|
+
options?: { reason?: number; remark?: string },
|
|
149
|
+
): Promise<void>;
|
|
146
150
|
cancelFeedback(messageId: string): Promise<void>;
|
|
147
|
-
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>;
|
|
148
158
|
listSkills(): Promise<SkillInfo[]>;
|
|
149
159
|
stopGeneration(sessionId: string): Promise<void>;
|
|
150
160
|
}
|
|
@@ -176,7 +186,11 @@ export interface ChatOptions {
|
|
|
176
186
|
stream?: boolean; // 默认 true
|
|
177
187
|
onMessage?: (event: ChatEvent) => void;
|
|
178
188
|
onError?: (error: Error) => void;
|
|
179
|
-
onDone?: (result: {
|
|
189
|
+
onDone?: (result: {
|
|
190
|
+
sessionId: string;
|
|
191
|
+
content: string;
|
|
192
|
+
messageId?: string;
|
|
193
|
+
}) => void; // messageId:后端在 done 事件返回的消息标识(存在时 SDK Widget 用其启用消息反馈,若返回可据此判断该消息可 feedback)
|
|
180
194
|
signal?: AbortSignal;
|
|
181
195
|
}
|
|
182
196
|
```
|
|
@@ -315,7 +329,7 @@ await sdk.feedback(aiMsg.id, "like");
|
|
|
315
329
|
|
|
316
330
|
// 踩(可附原因 + 备注)
|
|
317
331
|
await sdk.feedback(aiMsg.id, "dislike", {
|
|
318
|
-
reason: 1,
|
|
332
|
+
reason: 1, // 1=事实错误 2=逻辑问题 3=不相关 4=信息过时 5=冗长啰嗦 6=难以理解
|
|
319
333
|
remark: "时间描述有误",
|
|
320
334
|
});
|
|
321
335
|
|
|
@@ -324,6 +338,7 @@ await sdk.cancelFeedback(aiMsg.id);
|
|
|
324
338
|
```
|
|
325
339
|
|
|
326
340
|
组件内置的点赞/踩按钮已自动调用 `feedback()`/`cancelFeedback()`:
|
|
341
|
+
|
|
327
342
|
- 点击已选中的按钮 → 取消(DELETE)
|
|
328
343
|
- 点击另一个按钮 → 切换(POST)
|
|
329
344
|
- 点踩时弹出原因选择面板(可选填原因 + 备注后提交)
|
|
@@ -360,17 +375,17 @@ SDK 方法 → 后端接口的完整映射:
|
|
|
360
375
|
|
|
361
376
|
> 除 `getToken()` 外,其余接口请求均携带 `X-App-Id` 与 `X-Token` 请求头进行鉴权。
|
|
362
377
|
|
|
363
|
-
| SDK 方法 | HTTP 请求
|
|
364
|
-
| --------------------- |
|
|
365
|
-
| `getToken()` | `POST {gateway}/v1/token`
|
|
366
|
-
| `createSession()` | `POST /chat/sessions`
|
|
367
|
-
| `chat()` | `POST /chat`
|
|
368
|
-
| `listConversations()` | `GET /chat/conversations`
|
|
369
|
-
| `feedback()` | `POST /chat/messages/{messageId}/feedback`
|
|
370
|
-
| `cancelFeedback()` | `DELETE /chat/messages/{messageId}/feedback` | 无 body
|
|
371
|
-
| `respondInterrupt()` | `POST /chat/interrupt/{interruptId}/respond` | `{ sessionId, action, value? }`
|
|
372
|
-
| `stopGeneration()` | `POST /chat/stop`
|
|
373
|
-
| `listSkills()` | `GET /chat/bots/{botId}/skills`
|
|
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 }]` |
|
|
374
389
|
|
|
375
390
|
---
|
|
376
391
|
|
|
@@ -396,8 +411,27 @@ export interface MountOptions {
|
|
|
396
411
|
suggestedPrompts?: string[];
|
|
397
412
|
title?: string; // 标题,默认 "AI Assistant"
|
|
398
413
|
sidebarDefaultOpen?: boolean; // fullpage 模式:侧边栏初始展开(默认 true)
|
|
399
|
-
avatar?: AvatarConfig; //
|
|
414
|
+
avatar?: AvatarConfig; // 自定义头像(AI 消息始终有内置默认头像;用户头像未配置则不显示)
|
|
400
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
|
+
action?: PanelAction; // 点击行为:整屏容器 / 外链(优先于 prompt)
|
|
434
|
+
onClick?: () => void; // 自定义点击行为(优先于 action / prompt)
|
|
401
435
|
}
|
|
402
436
|
|
|
403
437
|
export interface WidgetInstance {
|
|
@@ -432,16 +466,38 @@ widget.destroy(); // 卸载并移除 DOM
|
|
|
432
466
|
|
|
433
467
|
> 挂载后默认是收起状态,需调用 `widget.open()` 展开。
|
|
434
468
|
|
|
469
|
+
### 6.2 源码接入(monorepo alias)注意事项
|
|
470
|
+
|
|
471
|
+
Widget 内部使用 **Tailwind CSS**(utility 全部限定在 `[data-super-agent-widget]` 宿主选择器内、禁用 preflight,不影响宿主页样式)。分发包(`dist`)已内联全部样式;内置图片资产(Logo/图标/头像等)走 CDN 绝对路径(`src/widget/assets/index.ts` 的 `BASE_URL`),**npm 引入无需任何配置**(需能访问 CDN)。
|
|
472
|
+
|
|
473
|
+
若宿主工程通过 vite alias 直接引用 SDK **源码**(如本仓库 frontend 的做法),则 SDK 的样式会由宿主自己的 PostCSS/Tailwind 管线处理,需要满足:
|
|
474
|
+
|
|
475
|
+
1. 宿主 `tailwind.config` 的 `content` 包含 SDK 源码路径,否则 widget 的 utility 类不会生成:
|
|
476
|
+
|
|
477
|
+
```ts
|
|
478
|
+
// frontend/tailwind.config.ts
|
|
479
|
+
export default {
|
|
480
|
+
content: [
|
|
481
|
+
'./index.html',
|
|
482
|
+
'./src/**/*.{js,jsx,ts,tsx}',
|
|
483
|
+
'../sdk/src/**/*.{ts,tsx}', // SDK 源码
|
|
484
|
+
],
|
|
485
|
+
// ...
|
|
486
|
+
};
|
|
487
|
+
```
|
|
488
|
+
|
|
489
|
+
2. 无需在宿主 config 中镜像 SDK 的 `important: '[data-super-agent-widget]'`(那会把宿主自己的 utility 也锁进 widget 容器内);宿主管线生成的 utility 为普通类,widget DOM 照常命中,动画/自定义类由 SDK 自带的 `tailwind.css`(运行时注入)保证。
|
|
490
|
+
|
|
435
491
|
---
|
|
436
492
|
|
|
437
493
|
## 7. 展示模式
|
|
438
494
|
|
|
439
495
|
通过 `mode` 切换两种展示模式:
|
|
440
496
|
|
|
441
|
-
| 模式 | 说明
|
|
442
|
-
| ------------------ |
|
|
443
|
-
| `floating`(默认) |
|
|
444
|
-
| `fullpage` |
|
|
497
|
+
| 模式 | 说明 |
|
|
498
|
+
| ------------------ | ---------------------------------------------------------- |
|
|
499
|
+
| `floating`(默认) | 右下角 Logo 触发按钮 + 可拖拽/拉伸/最大化的浮窗聊天窗口 |
|
|
500
|
+
| `fullpage` | 整页布局,左侧会话栏(hr-for-help 风格)+ 右侧聊天区 |
|
|
445
501
|
|
|
446
502
|
```ts
|
|
447
503
|
mount("#chat-root", { sdk, mode: "fullpage" });
|
|
@@ -453,6 +509,21 @@ mount("#chat-root", { sdk, mode: "fullpage" });
|
|
|
453
509
|
mount("#chat-root", { sdk, mode: "fullpage", sidebarDefaultOpen: false });
|
|
454
510
|
```
|
|
455
511
|
|
|
512
|
+
### 7.1 浮窗模式(floating)交互
|
|
513
|
+
|
|
514
|
+
浮窗窗口对齐 hr-for-help 设计,开箱具备以下交互能力:
|
|
515
|
+
|
|
516
|
+
- **标题栏拖拽**:按住顶部导航栏移动窗口(视口内钳制,按钮区域不触发)
|
|
517
|
+
- **左侧拉伸调宽**:窗口左侧 6px 手柄拖拽(右缘稳定不动),宽度范围 360 ~ 800 px,拖超过 800 自动进入大窗
|
|
518
|
+
- **大窗/小窗切换**:header 右侧「大窗」按钮切换;大窗为底部弹出的近全屏 overlay(内容区 800px 居中),回小窗时宽度重置为默认值
|
|
519
|
+
- **内容自适应高度**:聊天内容增长时窗口自动变高(默认 648px,上限 95% 视口,超出后消息区滚动),回到首页恢复默认高度
|
|
520
|
+
- **内嵌会话侧边栏**:header「历史记录」按钮开合;小窗下侧边栏紧贴窗口左缘向外展开(无缝拼接为一个连续圆角窗口,主区位置不动);大窗模式自动展开(220px),大窗/小窗各自记住用户偏好
|
|
521
|
+
- **关闭即还原**:关闭窗口后几何状态(位置/宽度/大窗态/高度)全部重置
|
|
522
|
+
|
|
523
|
+
浮窗消息展示对齐 hr-for-help:AI 头像独占一行(无背景色,生成中切换动效头像)、气泡白底描边、用户气泡浅蓝右对齐;`fullpage` 模式保持横排头像 + 经典气泡,两者互不影响。
|
|
524
|
+
|
|
525
|
+
首页(无消息时)包含:居中 Logo(浮动动画)+ 流光渐变标题 + 能力清单 + 建议词 chips + 快速入口,内容通过 `capabilities` / `suggestedPrompts` / `quickLinks` / `logo` 配置(见 6.1;icon 可复用 `super-agent-sdk/widget` 导出的内置 `ASSETS`)。
|
|
526
|
+
|
|
456
527
|
---
|
|
457
528
|
|
|
458
529
|
## 8. 定制化
|
|
@@ -467,8 +538,8 @@ export interface ThemeConfig {
|
|
|
467
538
|
backgroundColor?: string; // 默认 #ffffff
|
|
468
539
|
fontFamily?: string; // 默认 system-ui, -apple-system, sans-serif
|
|
469
540
|
borderRadius?: number; // 默认 16 (px)
|
|
470
|
-
panelWidth?: number; //
|
|
471
|
-
panelHeight?: number; //
|
|
541
|
+
panelWidth?: number; // floating 初始宽度,默认 400 (px)
|
|
542
|
+
panelHeight?: number; // floating 初始高度,默认 648 (px)
|
|
472
543
|
zIndex?: number; // 默认 9999
|
|
473
544
|
}
|
|
474
545
|
```
|
|
@@ -481,8 +552,8 @@ export interface ThemeConfig {
|
|
|
481
552
|
| `--sa-bg` | `#ffffff` | `backgroundColor` |
|
|
482
553
|
| `--sa-font` | `system-ui, -apple-system, sans-serif` | `fontFamily` |
|
|
483
554
|
| `--sa-radius` | `16px` | `borderRadius` |
|
|
484
|
-
| `--sa-panel-width` | `
|
|
485
|
-
| `--sa-panel-height` | `
|
|
555
|
+
| `--sa-panel-width` | `400px` | `panelWidth` |
|
|
556
|
+
| `--sa-panel-height` | `648px` | `panelHeight` |
|
|
486
557
|
| `--sa-z-index` | `9999` | `zIndex` |
|
|
487
558
|
|
|
488
559
|
```ts
|
|
@@ -502,12 +573,12 @@ mount("#chat-root", {
|
|
|
502
573
|
|
|
503
574
|
### 8.2 头像定制
|
|
504
575
|
|
|
505
|
-
通过 `avatar`
|
|
576
|
+
通过 `avatar` 配置助手与用户的头像,支持图片 URL、emoji 或文本。以 `http(s)://`、`data:`、`blob:`、`/`、`./`、`../`、`//` 开头的字符串渲染为图片,其余作为 emoji/文本展示(无背景色):
|
|
506
577
|
|
|
507
578
|
```ts
|
|
508
579
|
export interface AvatarConfig {
|
|
509
|
-
assistant?: string; // URL、emoji
|
|
510
|
-
user?: string;
|
|
580
|
+
assistant?: string; // 图片 URL、emoji 或文本;默认 SDK 内置头像(生成中显示动效头像)
|
|
581
|
+
user?: string; // 图片 URL、emoji 或文本;未配置则不显示用户头像
|
|
511
582
|
}
|
|
512
583
|
```
|
|
513
584
|
|
|
@@ -515,7 +586,7 @@ export interface AvatarConfig {
|
|
|
515
586
|
mount("#chat-root", {
|
|
516
587
|
sdk,
|
|
517
588
|
avatar: {
|
|
518
|
-
assistant: "🤖",
|
|
589
|
+
assistant: "🤖", // 配置后覆盖内置默认头像
|
|
519
590
|
user: "https://cdn.example.com/user-avatar.png",
|
|
520
591
|
},
|
|
521
592
|
});
|
|
@@ -540,23 +611,26 @@ export interface Slots {
|
|
|
540
611
|
ErrorPart?: ComponentType<ErrorPartProps>;
|
|
541
612
|
InterruptCard?: ComponentType<InterruptCardProps>;
|
|
542
613
|
WelcomeScreen?: ComponentType<WelcomeScreenProps>;
|
|
614
|
+
/** 首屏底部业务定制容器 */
|
|
615
|
+
AppendContainer?: ComponentType<AppendContainerProps>;
|
|
543
616
|
}
|
|
544
617
|
```
|
|
545
618
|
|
|
546
|
-
| 插槽 | Props 接口 | 说明
|
|
547
|
-
| ---------------- | --------------------- |
|
|
548
|
-
| `Trigger` | `TriggerProps` | 悬浮触发按钮
|
|
549
|
-
| `Header` | `HeaderProps` | 面板标题栏
|
|
550
|
-
| `Message` | `MessageProps` | 单条消息容器(完整自定义消息渲染)
|
|
551
|
-
| `Composer` | `ComposerProps` | 输入框 / 发送栏
|
|
552
|
-
| `ActionBar` | `ActionBarProps` | 消息操作栏(复制 / 重试 / 反馈)
|
|
553
|
-
| `ThreadList` | `ThreadListProps` | 会话列表(浮窗模式覆盖层 / 全屏模式侧边栏)
|
|
554
|
-
| `ThinkingPart` | `ThinkingPartProps` | 思考过程块
|
|
555
|
-
| `TextPart` | `TextPartProps` | 文本块
|
|
556
|
-
| `ToolCallPart` | `ToolCallPartProps` | 工具调用卡片(可折叠 + 展开后复制参数)
|
|
619
|
+
| 插槽 | Props 接口 | 说明 |
|
|
620
|
+
| ---------------- | --------------------- | -------------------------------------------------------------------------------------------------- |
|
|
621
|
+
| `Trigger` | `TriggerProps` | 悬浮触发按钮 |
|
|
622
|
+
| `Header` | `HeaderProps` | 面板标题栏 |
|
|
623
|
+
| `Message` | `MessageProps` | 单条消息容器(完整自定义消息渲染) |
|
|
624
|
+
| `Composer` | `ComposerProps` | 输入框 / 发送栏 |
|
|
625
|
+
| `ActionBar` | `ActionBarProps` | 消息操作栏(复制 / 重试 / 反馈) |
|
|
626
|
+
| `ThreadList` | `ThreadListProps` | 会话列表(浮窗模式覆盖层 / 全屏模式侧边栏) |
|
|
627
|
+
| `ThinkingPart` | `ThinkingPartProps` | 思考过程块 |
|
|
628
|
+
| `TextPart` | `TextPartProps` | 文本块 |
|
|
629
|
+
| `ToolCallPart` | `ToolCallPartProps` | 工具调用卡片(可折叠 + 展开后复制参数) |
|
|
557
630
|
| `ToolResultPart` | `ToolResultPartProps` | 工具返回卡片(pre 滚动 + 复制;`renderMode==="html"` 时 DOMPurify 清洗后直接渲染,最高 60vh 滚动) |
|
|
558
|
-
| `ErrorPart` | `ErrorPartProps` | 错误提示块
|
|
559
|
-
| `WelcomeScreen` | `WelcomeScreenProps` | 空会话欢迎页
|
|
631
|
+
| `ErrorPart` | `ErrorPartProps` | 错误提示块 |
|
|
632
|
+
| `WelcomeScreen` | `WelcomeScreenProps` | 空会话欢迎页 |
|
|
633
|
+
| `AppendContainer`| `AppendContainerProps`| 首屏底部业务定制区,`openPanel(action)` 开整屏容器或外链(见下) |
|
|
560
634
|
|
|
561
635
|
#### Trigger
|
|
562
636
|
|
|
@@ -565,6 +639,7 @@ export interface TriggerProps {
|
|
|
565
639
|
isOpen: boolean;
|
|
566
640
|
onClick: () => void;
|
|
567
641
|
unreadCount?: number;
|
|
642
|
+
triggerLogo?: string; // 触发按钮 Logo(URL)
|
|
568
643
|
}
|
|
569
644
|
```
|
|
570
645
|
|
|
@@ -584,11 +659,21 @@ function MyTrigger({ isOpen, onClick, unreadCount }: TriggerProps) {
|
|
|
584
659
|
|
|
585
660
|
#### Header
|
|
586
661
|
|
|
662
|
+
floating 与 fullpage 模式均支持替换;`onToggleThreadList` 在 floating 下切换内嵌会话侧边栏、在 fullpage 下切换左侧边栏;开启 `artifactPreview` 后额外提供产物入口字段。
|
|
663
|
+
|
|
664
|
+
> 注:fullpage 内置 Header 只有标题与产物入口(无关闭按钮);需要关闭入口时通过自定义 Header 的 `onClose` 自行渲染。floating 内置 Header 含历史/回首页/大窗/关闭按钮。
|
|
665
|
+
|
|
587
666
|
```ts
|
|
588
667
|
export interface HeaderProps {
|
|
589
668
|
title: string;
|
|
590
669
|
onClose: () => void;
|
|
591
670
|
onToggleThreadList: () => void;
|
|
671
|
+
isMaximized?: boolean; // floating:大窗状态
|
|
672
|
+
onToggleMaximize?: () => void; // floating:大窗/小窗切换
|
|
673
|
+
showHome?: boolean; // floating:聊天态显示回到首页
|
|
674
|
+
onHome?: () => void; // floating:回到首页(新会话)
|
|
675
|
+
artifactCount?: number; // 会话产物数量(artifactPreview 开启时提供)
|
|
676
|
+
onToggleArtifactDrawer?: () => void; // 打开/关闭产物预览抽屉
|
|
592
677
|
}
|
|
593
678
|
```
|
|
594
679
|
|
|
@@ -733,7 +818,11 @@ export interface ActionBarProps {
|
|
|
733
818
|
message: UIMessage;
|
|
734
819
|
onCopy: () => void;
|
|
735
820
|
onRegenerate?: () => void;
|
|
736
|
-
onFeedback?: (
|
|
821
|
+
onFeedback?: (
|
|
822
|
+
messageId: string,
|
|
823
|
+
feedback: "like" | "dislike",
|
|
824
|
+
options?: { reason?: number; remark?: string },
|
|
825
|
+
) => void;
|
|
737
826
|
}
|
|
738
827
|
```
|
|
739
828
|
|
|
@@ -755,9 +844,9 @@ function MyActionBar({
|
|
|
755
844
|
}
|
|
756
845
|
```
|
|
757
846
|
|
|
758
|
-
#### ThreadList
|
|
847
|
+
#### ThreadList(浮窗内嵌会话侧边栏 + 全屏模式侧边栏)
|
|
759
848
|
|
|
760
|
-
在 `floating`
|
|
849
|
+
在 `floating` 模式下作为窗口内嵌侧边栏渲染(小窗 200px / 大窗 220px,随「历史记录」按钮开合);在 `fullpage` 模式下作为左侧侧边栏渲染(220px,可收起为图标栏)。
|
|
761
850
|
|
|
762
851
|
```ts
|
|
763
852
|
export interface ThreadListProps {
|
|
@@ -880,6 +969,86 @@ function MyErrorPart({ content, onRetry }: ErrorPartProps) {
|
|
|
880
969
|
}
|
|
881
970
|
```
|
|
882
971
|
|
|
972
|
+
#### AppendContainer(首屏业务定制 + 整屏容器)
|
|
973
|
+
|
|
974
|
+
首屏(无消息时)在 `WelcomeScreen` 之下预留一块业务定制区,浮窗与全屏模式共用;未配置则不产生任何 DOM。
|
|
975
|
+
用法就一句话:**点一下,`openPanel(action)`**——可视区始终在 chatPanel 内(`link` 除外)。
|
|
976
|
+
|
|
977
|
+
```ts
|
|
978
|
+
export type PanelContent = ComponentType<PageProps> | ReactElement; // 组件类型,或带参数的元素
|
|
979
|
+
export type PanelAction =
|
|
980
|
+
| { type: 'page'; component: PanelContent; title?: string } // 整屏容器
|
|
981
|
+
| { type: 'link'; url: string; target?: '_blank' | '_self' }; // 外链
|
|
982
|
+
|
|
983
|
+
export interface AppendContainerProps { openPanel: (action: PanelAction) => void }
|
|
984
|
+
export interface PageProps { close: () => void }
|
|
985
|
+
```
|
|
986
|
+
|
|
987
|
+
```tsx
|
|
988
|
+
function ReportPage({ close }: PageProps) {
|
|
989
|
+
return (
|
|
990
|
+
<div style={{ padding: 16 }}>
|
|
991
|
+
报告内容……
|
|
992
|
+
<button onClick={close}>返回</button>
|
|
993
|
+
</div>
|
|
994
|
+
);
|
|
995
|
+
}
|
|
996
|
+
|
|
997
|
+
function MyHomeBlock({ openPanel }: AppendContainerProps) {
|
|
998
|
+
return (
|
|
999
|
+
<>
|
|
1000
|
+
<button onClick={() => openPanel({ type: "page", component: ReportPage, title: "全景报告" })}>
|
|
1001
|
+
整屏容器
|
|
1002
|
+
</button>
|
|
1003
|
+
<button onClick={() => openPanel({ type: "link", url: "https://example.com" })}>
|
|
1004
|
+
新窗口外链
|
|
1005
|
+
</button>
|
|
1006
|
+
</>
|
|
1007
|
+
);
|
|
1008
|
+
}
|
|
1009
|
+
|
|
1010
|
+
mount("#app", { sdk, slots: { AppendContainer: MyHomeBlock } });
|
|
1011
|
+
```
|
|
1012
|
+
|
|
1013
|
+
要开「第 3 条记录」这类带参数的页面,直接给**元素**,SDK 用 `cloneElement` 补上 `close`:
|
|
1014
|
+
|
|
1015
|
+
```tsx
|
|
1016
|
+
// 元素形态下 close 声明为可选,才能写 <DetailPage id={3} />(运行时 SDK 必然注入)
|
|
1017
|
+
function DetailPage({ id, close }: { id: number; close?: () => void }) {
|
|
1018
|
+
return <button onClick={close}>详情 #{id} 返回</button>;
|
|
1019
|
+
}
|
|
1020
|
+
|
|
1021
|
+
openPanel({ type: "page", component: <DetailPage id={3} />, title: "详情 #3" });
|
|
1022
|
+
```
|
|
1023
|
+
|
|
1024
|
+
给组件类型(`component: DetailPage`)时 `close` 是必填 prop,同样由 SDK 注入。
|
|
1025
|
+
|
|
1026
|
+
连定制区都不想写?首屏「快速入口」吃同一个 `action`,纯配置即可接入(`title` 缺省用 `label`):
|
|
1027
|
+
|
|
1028
|
+
```tsx
|
|
1029
|
+
mount("#app", {
|
|
1030
|
+
sdk,
|
|
1031
|
+
quickLinks: [
|
|
1032
|
+
{ label: "全景报告", action: { type: "page", component: ReportPage } },
|
|
1033
|
+
{ label: "帮助文档", action: { type: "link", url: "https://example.com/help" } },
|
|
1034
|
+
],
|
|
1035
|
+
});
|
|
1036
|
+
```
|
|
1037
|
+
|
|
1038
|
+
点击优先级:`onClick > action > prompt`。
|
|
1039
|
+
|
|
1040
|
+
整屏容器行为:
|
|
1041
|
+
|
|
1042
|
+
| 项 | 表现 |
|
|
1043
|
+
| --- | --- |
|
|
1044
|
+
| 呈现 | 替换「内容区 + 输入区」,Header 保留(小窗仍可拖拽);`link` 走 `window.open`,不占状态 |
|
|
1045
|
+
| 标题栏 | 返回箭头 + `title`(可选);`Esc` 等价返回 |
|
|
1046
|
+
| 窗口几何 | 保持打开前窗态,小窗不自动升大窗;内容在容器内滚动(业务页不写滚动容器) |
|
|
1047
|
+
| 关闭 | 返回 / `close()` / `Esc`;关闭聊天面板时一并清掉 |
|
|
1048
|
+
| 栈 | 单层不叠栈,容器内部导航由业务组件自己管 |
|
|
1049
|
+
|
|
1050
|
+
注意:浮层组件渲染在 SDK 自己的 `createRoot` 树内,拿不到宿主的 React Context / Router。组件引用直接给,不需要注册表——类型即校验。
|
|
1051
|
+
|
|
883
1052
|
### 8.4 事件钩子(EventHooks)
|
|
884
1053
|
|
|
885
1054
|
通过 `hooks` 监听组件生命周期与交互事件:
|
|
@@ -1175,7 +1344,7 @@ const controller = sdk.chat({
|
|
|
1175
1344
|
message: "...",
|
|
1176
1345
|
stream: true,
|
|
1177
1346
|
onMessage: (event) => {
|
|
1178
|
-
if (event.type ===
|
|
1347
|
+
if (event.type === "stop") {
|
|
1179
1348
|
// 用户主动停止,event.content 为已生成的半截回复全文
|
|
1180
1349
|
console.log("已停止,半截回复:", event.content);
|
|
1181
1350
|
}
|
|
@@ -1270,14 +1439,14 @@ export type MessagePart =
|
|
|
1270
1439
|
};
|
|
1271
1440
|
```
|
|
1272
1441
|
|
|
1273
|
-
| type | 字段
|
|
1274
|
-
| ------------- |
|
|
1275
|
-
| `text` | `content`
|
|
1276
|
-
| `thinking` | `content`
|
|
1277
|
-
| `tool_call` | `toolName`, `toolCallId`, `args`
|
|
1278
|
-
| `tool_result` | `toolName`, `toolCallId`, `content`, `artifacts?`, `renderMode?`, `html?` | 工具返回结果
|
|
1279
|
-
| `error` | `content`
|
|
1280
|
-
| `interrupt` | `interrupt`, `resolved?`, `response?`
|
|
1442
|
+
| type | 字段 | 说明 |
|
|
1443
|
+
| ------------- | ------------------------------------------------------------------------- | ------------------------------- |
|
|
1444
|
+
| `text` | `content` | 文本 / Markdown 内容 |
|
|
1445
|
+
| `thinking` | `content` | 思考过程(reasoning) |
|
|
1446
|
+
| `tool_call` | `toolName`, `toolCallId`, `args` | 工具调用,`args` 为 JSON 字符串 |
|
|
1447
|
+
| `tool_result` | `toolName`, `toolCallId`, `content`, `artifacts?`, `renderMode?`, `html?` | 工具返回结果 |
|
|
1448
|
+
| `error` | `content` | 错误信息 |
|
|
1449
|
+
| `interrupt` | `interrupt`, `resolved?`, `response?` | 中断交互卡片(HITL) |
|
|
1281
1450
|
|
|
1282
1451
|
### 11.3 ChatEvent(流式事件)
|
|
1283
1452
|
|
|
@@ -1358,7 +1527,7 @@ mount("#chat", { sdk }).open();
|
|
|
1358
1527
|
mount("#chat", {
|
|
1359
1528
|
sdk,
|
|
1360
1529
|
slots: {
|
|
1361
|
-
InterruptCard: MyInterruptCard,
|
|
1530
|
+
InterruptCard: MyInterruptCard, // 自定义全部类型
|
|
1362
1531
|
},
|
|
1363
1532
|
});
|
|
1364
1533
|
```
|
|
@@ -1383,23 +1552,23 @@ sdk.chat({
|
|
|
1383
1552
|
|
|
1384
1553
|
### 12.6 interruptType 一览
|
|
1385
1554
|
|
|
1386
|
-
| interruptType | 交互
|
|
1387
|
-
|
|
1388
|
-
| `confirm`
|
|
1389
|
-
| `select`
|
|
1390
|
-
| `multiSelect` | 多选
|
|
1391
|
-
| `input`
|
|
1392
|
-
| `form`
|
|
1393
|
-
| `review`
|
|
1394
|
-
| `approve`
|
|
1395
|
-
| `upload`
|
|
1396
|
-
| `image`
|
|
1397
|
-
| `auth`
|
|
1398
|
-
| `captcha`
|
|
1399
|
-
| `decision`
|
|
1400
|
-
| `rating`
|
|
1401
|
-
| `date`
|
|
1402
|
-
| `location`
|
|
1555
|
+
| interruptType | 交互 | action | value 示例 |
|
|
1556
|
+
| ------------- | -------- | --------------------- | ----------------------- |
|
|
1557
|
+
| `confirm` | 二次确认 | `confirm` / `cancel` | — |
|
|
1558
|
+
| `select` | 单选 | `select` | `"flight_a"` |
|
|
1559
|
+
| `multiSelect` | 多选 | `submit` | `["name", "phone"]` |
|
|
1560
|
+
| `input` | 文本输入 | `submit` | `"123456"` |
|
|
1561
|
+
| `form` | 表单 | `submit` | `{ name: "张三" }` |
|
|
1562
|
+
| `review` | 内容审阅 | `approve` / `reject` | 修改后内容 |
|
|
1563
|
+
| `approve` | 审批流 | `approve` / `reject` | 驳回原因 |
|
|
1564
|
+
| `upload` | 文件上传 | `submit` | `{ fileId, fileName }` |
|
|
1565
|
+
| `image` | 图片选择 | `select` / `reject` | 图片索引 |
|
|
1566
|
+
| `auth` | 授权请求 | `authorized` / `skip` | — |
|
|
1567
|
+
| `captcha` | 人机验证 | `verified` | `"captcha_token"` |
|
|
1568
|
+
| `decision` | 流程分支 | `decide` | `"retry"` 等 |
|
|
1569
|
+
| `rating` | 评分 | `rate` | `4` |
|
|
1570
|
+
| `date` | 日期选择 | `submit` | `"2026-08-21T14:00:00"` |
|
|
1571
|
+
| `location` | 位置选择 | `submit` | `{ address, lat, lng }` |
|
|
1403
1572
|
|
|
1404
1573
|
> `form` 的字段定义见 `FormField`(`types.ts`):`type` 支持 `text` / `number` / `password` / `textarea` / `select` / `multiSelect` / `date`;`options` 支持字符串数组或 `{ value, label }` 数组。已回答的历史 interrupt 以禁用态回显用户答案。
|
|
1405
1574
|
|
|
@@ -1461,7 +1630,10 @@ interface UseChatReturn {
|
|
|
1461
1630
|
stop: () => void;
|
|
1462
1631
|
regenerate: () => void;
|
|
1463
1632
|
setMessages: (messages: UIMessage[]) => void;
|
|
1464
|
-
respondToInterrupt: (
|
|
1633
|
+
respondToInterrupt: (
|
|
1634
|
+
interruptId: string,
|
|
1635
|
+
response: InterruptResponse,
|
|
1636
|
+
) => void;
|
|
1465
1637
|
}
|
|
1466
1638
|
```
|
|
1467
1639
|
|