super-agent-sdk 1.0.7 → 1.0.8

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 CHANGED
@@ -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(
@@ -143,7 +144,7 @@ export interface SuperAgentSDK {
143
144
  setToken(token: string): void;
144
145
  feedback(messageId: string, type: "like" | "dislike", options?: { reason?: number; remark?: string }): Promise<void>;
145
146
  cancelFeedback(messageId: string): Promise<void>;
146
- respondInterrupt(interruptId: string, sessionId: string, response: InterruptResponse): Promise<void>;
147
+ respondInterrupt(interruptId: string, sessionId: string, response: InterruptResponse, onMessage?: (event: ChatEvent) => void, onError?: (error: Error) => void): Promise<void>;
147
148
  listSkills(): Promise<SkillInfo[]>;
148
149
  stopGeneration(sessionId: string): Promise<void>;
149
150
  }
@@ -175,7 +176,7 @@ export interface ChatOptions {
175
176
  stream?: boolean; // 默认 true
176
177
  onMessage?: (event: ChatEvent) => void;
177
178
  onError?: (error: Error) => void;
178
- onDone?: (result: { sessionId: string; content: string }) => void;
179
+ onDone?: (result: { sessionId: string; content: string; messageId?: string }) => void; // messageId:后端在 done 事件返回的消息标识(存在时 SDK Widget 用其启用消息反馈,若返回可据此判断该消息可 feedback)
179
180
  signal?: AbortSignal;
180
181
  }
181
182
  ```
@@ -303,26 +304,57 @@ sdk.setToken("<TOKEN>");
303
304
 
304
305
  消息反馈(赞/踩)。调用 `sdk.feedback()` 发送 `POST /chat/messages/{messageId}/feedback`;调用 `sdk.cancelFeedback()` 发送 `DELETE` 取消反馈。
305
306
 
307
+ > **messageId 说明**:即消息历史返回的表主键 `id`(数字),不是 `messageId`(UUID)。纯 API 模式从 `getMessages()` 结果取 `UIMessage.id`。
308
+
306
309
  ```ts
310
+ const messages = await sdk.getMessages(sessionId);
311
+ const aiMsg = messages.findLast((m) => m.role === "assistant");
312
+
307
313
  // 点赞
308
- await sdk.feedback("msg_123", "like");
314
+ await sdk.feedback(aiMsg.id, "like");
309
315
 
310
316
  // 踩(可附原因 + 备注)
311
- await sdk.feedback("msg_123", "dislike", {
317
+ await sdk.feedback(aiMsg.id, "dislike", {
312
318
  reason: 1, // 1=事实错误 2=逻辑问题 3=不相关 4=信息过时 5=冗长啰嗦 6=难以理解
313
319
  remark: "时间描述有误",
314
320
  });
315
321
 
316
322
  // 取消反馈
317
- await sdk.cancelFeedback("msg_123");
323
+ await sdk.cancelFeedback(aiMsg.id);
318
324
  ```
319
325
 
320
326
  组件内置的点赞/踩按钮已自动调用 `feedback()`/`cancelFeedback()`:
321
327
  - 点击已选中的按钮 → 取消(DELETE)
322
328
  - 点击另一个按钮 → 切换(POST)
323
329
  - 点踩时弹出原因选择面板(可选填原因 + 备注后提交)
330
+ - 流式渲染期间消息尚无后端 ID(临时占位),此时点击反馈 SDK 会自动拉取一次历史消息解析真实 ID 再发送,业务方无感知
331
+
332
+ ### 5.10 respondInterrupt()
333
+
334
+ 响应中断事件(Human-in-the-Loop),后端继续推送后续 SSE 事件:
335
+
336
+ ```ts
337
+ sdk.respondInterrupt(
338
+ interruptId: string,
339
+ sessionId: string,
340
+ response: InterruptResponse,
341
+ onMessage?: (event: ChatEvent) => void,
342
+ onError?: (error: Error) => void
343
+ ): Promise<void>
344
+ ```
345
+
346
+ Widget 内置中断卡片会自动调用此方法,纯 API 模式需手动处理(详见 [12. Human-in-the-Loop](#12-human-in-the-loop))。
347
+
348
+ ### 5.11 listSkills()
324
349
 
325
- ### 5.10 后端接口对照
350
+ 获取当前 Bot 绑定的技能列表(用于 `/` 斜杠命令选择技能):
351
+
352
+ ```ts
353
+ const skills: SkillInfo[] = await sdk.listSkills();
354
+ // [{ code: "web-searcher", name: "web-searcher", displayName: "网页搜索", description: "..." }]
355
+ ```
356
+
357
+ ### 5.12 后端接口对照
326
358
 
327
359
  SDK 方法 → 后端接口的完整映射:
328
360
 
@@ -336,6 +368,7 @@ SDK 方法 → 后端接口的完整映射:
336
368
  | `listConversations()` | `GET /chat/conversations` | 查询参数 `botId`、`page`、`size` | `{ items: [{ sessionId, botId, ... }], total }` |
337
369
  | `feedback()` | `POST /chat/messages/{messageId}/feedback` | `{ type, reason?, remark? }` | `null` |
338
370
  | `cancelFeedback()` | `DELETE /chat/messages/{messageId}/feedback` | 无 body | `null` |
371
+ | `respondInterrupt()` | `POST /chat/interrupt/{interruptId}/respond` | `{ sessionId, action, value? }` | SSE 流(后续事件) |
339
372
  | `stopGeneration()` | `POST /chat/stop` | `{ sessionId }` | `{ stopped: "pending", sessionId }` |
340
373
  | `listSkills()` | `GET /chat/bots/{botId}/skills` | — | `[{ code, name, displayName, description }]` |
341
374
 
@@ -364,6 +397,7 @@ export interface MountOptions {
364
397
  title?: string; // 标题,默认 "AI Assistant"
365
398
  sidebarDefaultOpen?: boolean; // fullpage 模式:侧边栏初始展开(默认 true)
366
399
  avatar?: AvatarConfig; // 自定义头像
400
+ artifactPreview?: boolean; // 产物预览总开关(html/pdf/docx 预览 + 下载 + 全屏),默认 false
367
401
  }
368
402
 
369
403
  export interface WidgetInstance {
@@ -504,6 +538,7 @@ export interface Slots {
504
538
  ToolCallPart?: ComponentType<ToolCallPartProps>;
505
539
  ToolResultPart?: ComponentType<ToolResultPartProps>;
506
540
  ErrorPart?: ComponentType<ErrorPartProps>;
541
+ InterruptCard?: ComponentType<InterruptCardProps>;
507
542
  WelcomeScreen?: ComponentType<WelcomeScreenProps>;
508
543
  }
509
544
  ```
@@ -518,8 +553,8 @@ export interface Slots {
518
553
  | `ThreadList` | `ThreadListProps` | 会话列表(浮窗模式覆盖层 / 全屏模式侧边栏) |
519
554
  | `ThinkingPart` | `ThinkingPartProps` | 思考过程块 |
520
555
  | `TextPart` | `TextPartProps` | 文本块 |
521
- | `ToolCallPart` | `ToolCallPartProps` | 工具调用卡片 |
522
- | `ToolResultPart` | `ToolResultPartProps` | 工具返回卡片 |
556
+ | `ToolCallPart` | `ToolCallPartProps` | 工具调用卡片(可折叠 + 展开后复制参数) |
557
+ | `ToolResultPart` | `ToolResultPartProps` | 工具返回卡片(pre 滚动 + 复制;`renderMode==="html"` 时 DOMPurify 清洗后直接渲染,最高 60vh 滚动) |
523
558
  | `ErrorPart` | `ErrorPartProps` | 错误提示块 |
524
559
  | `WelcomeScreen` | `WelcomeScreenProps` | 空会话欢迎页 |
525
560
 
@@ -697,8 +732,8 @@ function MyComposer({ status, onSend, onStop }: ComposerProps) {
697
732
  export interface ActionBarProps {
698
733
  message: UIMessage;
699
734
  onCopy: () => void;
700
- onRegenerate: () => void;
701
- onFeedback?: (messageId: string, feedback: "like" | "dislike") => void;
735
+ onRegenerate?: () => void;
736
+ onFeedback?: (messageId: string, feedback: "like" | "dislike", options?: { reason?: number; remark?: string }) => void;
702
737
  }
703
738
  ```
704
739
 
@@ -797,6 +832,10 @@ export interface ToolResultPartProps {
797
832
  toolName: string;
798
833
  toolCallId: string;
799
834
  content: string;
835
+ artifacts?: Artifact[];
836
+ renderMode?: string;
837
+ html?: string;
838
+ artifactPreview?: boolean;
800
839
  }
801
840
  export interface ErrorPartProps {
802
841
  content: string;
@@ -1113,7 +1152,7 @@ await sdk.deleteConversation(items[0].sessionId);
1113
1152
  - **新建**:点击「新会话」清空当前消息,下次发送时自动调用 `createSession()` 创建新会话。
1114
1153
  - **重命名**:`fullpage` 侧边栏或自定义 `ThreadList` 中调用 `renameConversation`。
1115
1154
  - **删除**:悬停会话项后点击删除按钮。
1116
- - **本地持久化**:最近一次活跃会话写入 `localStorage`,键为 `sa_active_conversation`。
1155
+ - **本地持久化**:最近一次活跃会话写入 `localStorage`,键为 `sa_active_conversation_{botId}`(按 Bot 隔离,切换 Bot 后互不串扰)。
1117
1156
 
1118
1157
  ---
1119
1158
 
@@ -1185,7 +1224,7 @@ ac.abort();
1185
1224
 
1186
1225
  页面刷新或组件重新挂载时,会话状态自动恢复:
1187
1226
 
1188
- 1. 挂载时从 `localStorage` 读取上次活跃会话 ID(键 `sa_active_conversation`)。
1227
+ 1. 挂载时从 `localStorage` 读取上次活跃会话 ID(键 `sa_active_conversation_{botId}`)。
1189
1228
  2. 若该会话仍在列表中,自动调用 `getMessages` 拉取历史消息并渲染。
1190
1229
  3. 若存储的会话已不存在(被删除),则自动清空并回退到「新会话」。
1191
1230
 
@@ -1218,8 +1257,17 @@ export type MessagePart =
1218
1257
  toolName: string;
1219
1258
  toolCallId: string;
1220
1259
  content: string;
1260
+ artifacts?: Artifact[];
1261
+ renderMode?: string;
1262
+ html?: string;
1221
1263
  }
1222
- | { type: "error"; content: string };
1264
+ | { type: "error"; content: string }
1265
+ | {
1266
+ type: "interrupt";
1267
+ interrupt: InterruptEvent;
1268
+ resolved?: boolean;
1269
+ response?: InterruptResponse;
1270
+ };
1223
1271
  ```
1224
1272
 
1225
1273
  | type | 字段 | 说明 |
@@ -1227,8 +1275,9 @@ export type MessagePart =
1227
1275
  | `text` | `content` | 文本 / Markdown 内容 |
1228
1276
  | `thinking` | `content` | 思考过程(reasoning) |
1229
1277
  | `tool_call` | `toolName`, `toolCallId`, `args` | 工具调用,`args` 为 JSON 字符串 |
1230
- | `tool_result` | `toolName`, `toolCallId`, `content` | 工具返回结果 |
1278
+ | `tool_result` | `toolName`, `toolCallId`, `content`, `artifacts?`, `renderMode?`, `html?` | 工具返回结果 |
1231
1279
  | `error` | `content` | 错误信息 |
1280
+ | `interrupt` | `interrupt`, `resolved?`, `response?` | 中断交互卡片(HITL) |
1232
1281
 
1233
1282
  ### 11.3 ChatEvent(流式事件)
1234
1283
 
@@ -1242,12 +1291,18 @@ export interface ChatEvent {
1242
1291
  | "tool_result"
1243
1292
  | "done"
1244
1293
  | "stop"
1245
- | "error";
1294
+ | "error"
1295
+ | "interrupt";
1246
1296
  content: string;
1247
1297
  toolName?: string;
1248
1298
  toolCallId?: string;
1249
1299
  args?: string; // JSON.stringify 后的字符串
1250
1300
  sessionId?: string;
1301
+ messageId?: string; // done 事件携带后端消息标识(后端返回时该消息可反馈/feedback)
1302
+ interrupt?: InterruptEvent; // interrupt 事件携带中断详情
1303
+ artifacts?: Artifact[]; // tool_result 事件携带的结构化产物
1304
+ renderMode?: string; // "html" 时工具结果为富文本
1305
+ html?: string; // renderMode==="html" 时的 HTML 内容
1251
1306
  }
1252
1307
  ```
1253
1308
 
@@ -1283,7 +1338,7 @@ Agent 执行中
1283
1338
  ### 12.3 响应中断
1284
1339
 
1285
1340
  ```ts
1286
- await sdk.respondInterrupt(interruptId, {
1341
+ await sdk.respondInterrupt(interruptId, sessionId, {
1287
1342
  action: "confirm",
1288
1343
  });
1289
1344
  ```
@@ -1318,7 +1373,7 @@ sdk.chat({
1318
1373
  if (e.type === "interrupt" && e.interrupt) {
1319
1374
  // 自定义 UI 处理
1320
1375
  const ok = window.confirm(e.interrupt.content);
1321
- sdk.respondInterrupt(e.interrupt.interruptId, {
1376
+ sdk.respondInterrupt(e.interrupt.interruptId, sessionId, {
1322
1377
  action: ok ? "confirm" : "cancel",
1323
1378
  });
1324
1379
  }
@@ -1346,6 +1401,8 @@ sdk.chat({
1346
1401
  | `date` | 日期选择 | `submit` | `"2026-08-21T14:00:00"` |
1347
1402
  | `location` | 位置选择 | `submit` | `{ address, lat, lng }` |
1348
1403
 
1404
+ > `form` 的字段定义见 `FormField`(`types.ts`):`type` 支持 `text` / `number` / `password` / `textarea` / `select` / `multiSelect` / `date`;`options` 支持字符串数组或 `{ value, label }` 数组。已回答的历史 interrupt 以禁用态回显用户答案。
1405
+
1349
1406
  > 每个 `interruptType` 的完整字段定义见 [API 文档](./API.md) 与 [HITL 设计文档](../docs/superpowers/specs/2026-08-18-human-in-the-loop-design.md)。
1350
1407
 
1351
1408
  ---
@@ -1404,6 +1461,7 @@ interface UseChatReturn {
1404
1461
  stop: () => void;
1405
1462
  regenerate: () => void;
1406
1463
  setMessages: (messages: UIMessage[]) => void;
1464
+ respondToInterrupt: (interruptId: string, response: InterruptResponse) => void;
1407
1465
  }
1408
1466
  ```
1409
1467
 
@@ -1415,15 +1473,18 @@ export function useConversations(
1415
1473
  interface UseConversationsOptions {
1416
1474
  sdk: SuperAgentSDK;
1417
1475
  onConversationChange?: (sessionId: string) => void;
1476
+ enabled?: boolean; // 默认 true,false 时不自动加载
1418
1477
  }
1419
1478
 
1420
1479
  interface UseConversationsReturn {
1421
1480
  conversations: Conversation[];
1422
1481
  activeConversationId: string | null;
1423
1482
  loading: boolean;
1483
+ hasMore: boolean;
1424
1484
  loadConversations: () => Promise<void>;
1485
+ loadMore: () => Promise<void>;
1425
1486
  switchConversation: (sessionId: string) => Promise<UIMessage[]>;
1426
- newConversation: () => void;
1487
+ newConversation: () => Promise<void>;
1427
1488
  deleteConversation: (sessionId: string) => Promise<void>;
1428
1489
  renameConversation: (sessionId: string, title: string) => Promise<void>;
1429
1490
  setActiveConversationId: (id: string | null) => void;
package/dist/index.cjs CHANGED
@@ -1,5 +1,5 @@
1
- "use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});function u(r){if(Array.isArray(r))return r.map(e=>u(e));if(r&&typeof r=="object"&&r.constructor===Object){const e={};for(const[t,s]of Object.entries(r)){const o=t.replace(/_([a-z])/g,(n,a)=>a.toUpperCase());e[o]=u(s)}return e}return r}const I="/api/agent/runtime/v1";class w{constructor(e){this.refreshing=null;const t=e.baseUrl??I;this.baseUrl=t.replace(/\/$/,""),this.tokenGateway=e.tokenGateway.replace(/\/$/,""),this.appId=e.appId??"",this.token=e.token??"",this.botId=e.botId,this.isAbsoluteUrl=/^https?:\/\//.test(this.baseUrl),this.isAbsoluteGateway=/^https?:\/\//.test(this.tokenGateway)}getBotId(){return this.botId}getAppKey(){return this.appId}setToken(e){this.token=e}getOrigin(){return typeof window<"u"?window.location.origin:""}async fetchToken(){const t=`${this.isAbsoluteGateway?this.tokenGateway:`${this.getOrigin()}${this.tokenGateway}`}/v1/token`,s=await fetch(t,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({botId:this.botId})});if(!s.ok)throw new Error(`HTTP ${s.status}: ${s.statusText}`);const o=await s.json();if(o.code!=="200")throw new Error(o.message||`API error: ${o.code}`);const n=u(o.data);return this.token=n.token,n.appId&&!this.appId&&(this.appId=n.appId),n.token}headers(e){return{"Content-Type":"application/json","X-App-Id":this.appId,"X-Token":this.token,...e}}async handleTokenRefresh(){if(this.refreshing)return await this.refreshing,!0;try{return this.refreshing=(async()=>{await this.fetchToken()})(),await this.refreshing,!0}catch{return!1}finally{this.refreshing=null}}async request(e,t,s){if(!this.token&&!await this.handleTokenRefresh())throw new Error("SDK token not available: POST /token failed");let o=this.isAbsoluteUrl?`${this.baseUrl}${t}`:`${this.getOrigin()}${this.baseUrl}${t}`;if(s!=null&&s.params){const i=new URLSearchParams;for(const[d,l]of Object.entries(s.params))l!=null&&i.set(d,String(l));const c=i.toString();c&&(o+=`?${c}`)}const n=await fetch(o,{method:e,headers:this.headers(),body:s!=null&&s.body?JSON.stringify(s.body):void 0});if(n.status===401&&!(s!=null&&s.retry)&&await this.handleTokenRefresh())return this.request(e,t,{...s,retry:!0});if(!n.ok)throw new Error(`HTTP ${n.status}: ${n.statusText}`);const a=await n.json();if(a.code!=="200")throw new Error(a.message||`API error: ${a.code}`);return u(a.data)}get(e,t){return this.request("GET",e,{params:t})}post(e,t){return this.request("POST",e,{body:t})}patch(e,t){return this.request("PATCH",e,{body:t})}del(e){return this.request("DELETE",e)}async streamPost(e,t,s){if(!this.token&&!await this.handleTokenRefresh())throw new Error("SDK token not available: POST /token failed");const o=this.isAbsoluteUrl?`${this.baseUrl}${e}`:`${this.getOrigin()}${this.baseUrl}${e}`,n=await fetch(o,{method:"POST",headers:this.headers(),body:JSON.stringify(t),signal:s});return n.status===401&&await this.handleTokenRefresh()?fetch(o,{method:"POST",headers:this.headers(),body:JSON.stringify(t),signal:s}):n}}function y(r){const e=r.split(`
1
+ "use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});function u(r){if(Array.isArray(r))return r.map(e=>u(e));if(r&&typeof r=="object"&&r.constructor===Object){const e={};for(const[t,s]of Object.entries(r)){const o=t.replace(/_([a-z])/g,(a,n)=>n.toUpperCase());e[o]=u(s)}return e}return r}const I="/api/agent/runtime/v1";class w{constructor(e){this.refreshing=null;const t=e.baseUrl??I;this.baseUrl=t.replace(/\/$/,""),this.tokenGateway=e.tokenGateway.replace(/\/$/,""),this.appId=e.appId??"",this.token=e.token??"",this.botId=e.botId,this.isAbsoluteUrl=/^https?:\/\//.test(this.baseUrl),this.isAbsoluteGateway=/^https?:\/\//.test(this.tokenGateway)}getBotId(){return this.botId}getAppKey(){return this.appId}setToken(e){this.token=e}getOrigin(){return typeof window<"u"?window.location.origin:""}async fetchToken(){const t=`${this.isAbsoluteGateway?this.tokenGateway:`${this.getOrigin()}${this.tokenGateway}`}/v1/token`,s=await fetch(t,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({botId:this.botId})});if(!s.ok)throw new Error(`HTTP ${s.status}: ${s.statusText}`);const o=await s.json();if(o.code!=="200")throw new Error(o.message||`API error: ${o.code}`);const a=u(o.data);return this.token=a.token,a.appId&&!this.appId&&(this.appId=a.appId),a.token}headers(e){return{"Content-Type":"application/json","X-App-Id":this.appId,"X-Token":this.token,...e}}async handleTokenRefresh(){if(this.refreshing)return await this.refreshing,!0;try{return this.refreshing=(async()=>{await this.fetchToken()})(),await this.refreshing,!0}catch{return!1}finally{this.refreshing=null}}async request(e,t,s){if(!this.token&&!await this.handleTokenRefresh())throw new Error("SDK token not available: POST /token failed");let o=this.isAbsoluteUrl?`${this.baseUrl}${t}`:`${this.getOrigin()}${this.baseUrl}${t}`;if(s!=null&&s.params){const i=new URLSearchParams;for(const[d,l]of Object.entries(s.params))l!=null&&i.set(d,String(l));const c=i.toString();c&&(o+=`?${c}`)}const a=await fetch(o,{method:e,headers:this.headers(),body:s!=null&&s.body?JSON.stringify(s.body):void 0});if(a.status===401&&!(s!=null&&s.retry)&&await this.handleTokenRefresh())return this.request(e,t,{...s,retry:!0});if(!a.ok)throw new Error(`HTTP ${a.status}: ${a.statusText}`);const n=await a.json();if(n.code!=="200")throw new Error(n.message||`API error: ${n.code}`);return u(n.data)}get(e,t){return this.request("GET",e,{params:t})}post(e,t){return this.request("POST",e,{body:t})}patch(e,t){return this.request("PATCH",e,{body:t})}del(e){return this.request("DELETE",e)}async streamPost(e,t,s){if(!this.token&&!await this.handleTokenRefresh())throw new Error("SDK token not available: POST /token failed");const o=this.isAbsoluteUrl?`${this.baseUrl}${e}`:`${this.getOrigin()}${this.baseUrl}${e}`,a=await fetch(o,{method:"POST",headers:this.headers(),body:JSON.stringify(t),signal:s});return a.status===401&&await this.handleTokenRefresh()?fetch(o,{method:"POST",headers:this.headers(),body:JSON.stringify(t),signal:s}):a}}function y(r){const e=r.split(`
2
2
  `).map(s=>s.trim()).filter(s=>s.startsWith("data:")).map(s=>s.slice(5).trim());if(!e.length)return null;let t;try{t=JSON.parse(e.join(`
3
- `))}catch{return null}switch(t.type){case"user":return{type:"user",content:t.content??""};case"thinking":return{type:"thinking",content:t.content??""};case"ai":return{type:"ai",content:t.content??""};case"tool_call":return{type:"tool_call",content:t.name??"",toolName:t.name,toolCallId:t.id,args:typeof t.args=="string"?t.args:JSON.stringify(t.args??{})};case"tool_result":return{type:"tool_result",content:t.output??"",toolName:t.name,toolCallId:t.id,artifacts:Array.isArray(t.artifacts)?t.artifacts:void 0,renderMode:t.render_mode??t.renderMode,html:t.html};case"done":return{type:"done",content:t.content??"",sessionId:t.sessionId??t.session_id??"",messageId:t.messageId??t.message_id};case"stop":return{type:"stop",content:t.content??"",sessionId:t.sessionId??t.session_id??""};case"error":return{type:"error",content:t.message??"Unknown error"};case"interrupt":return{type:"interrupt",content:t.content??"",interrupt:{interruptId:t.interruptId??t.interrupt_id??"",interruptType:t.interruptType??t.interrupt_type??"confirm",content:t.content??"",options:t.options,placeholder:t.placeholder,inputType:t.inputType??t.input_type,maxLength:t.maxLength??t.max_length,required:t.required,fields:t.fields,metadata:t.metadata}};default:return null}}async function m(r,e,t){if(!r.body){t(new Error("Response body is null"));return}const s=r.body.getReader(),o=new TextDecoder;let n="";try{for(;;){const{value:a,done:i}=await s.read();if(i)break;n+=o.decode(a,{stream:!0});let c;for(;(c=n.indexOf(`
3
+ `))}catch{return null}switch(t.type){case"user":return{type:"user",content:t.content??""};case"thinking":return{type:"thinking",content:t.content??""};case"ai":return{type:"ai",content:t.content??""};case"tool_call":return{type:"tool_call",content:t.name??"",toolName:t.name,toolCallId:t.id,args:typeof t.args=="string"?t.args:JSON.stringify(t.args??{})};case"tool_result":return{type:"tool_result",content:t.output??"",toolName:t.name,toolCallId:t.id,artifacts:Array.isArray(t.artifacts)?t.artifacts:void 0,renderMode:t.render_mode??t.renderMode,html:t.html};case"done":return{type:"done",content:t.content??"",sessionId:t.sessionId??t.session_id??"",messageId:t.messageId??t.message_id};case"stop":return{type:"stop",content:t.content??"",sessionId:t.sessionId??t.session_id??"",messageId:t.messageId??t.message_id};case"error":return{type:"error",content:t.message??"Unknown error"};case"interrupt":return{type:"interrupt",content:t.content??"",interrupt:{interruptId:t.interruptId??t.interrupt_id??"",interruptType:t.interruptType??t.interrupt_type??"confirm",content:t.content??"",options:t.options,placeholder:t.placeholder,inputType:t.inputType??t.input_type,maxLength:t.maxLength??t.max_length,required:t.required,fields:t.fields,metadata:t.metadata}};default:return null}}async function m(r,e,t){if(!r.body){t(new Error("Response body is null"));return}const s=r.body.getReader(),o=new TextDecoder;let a="";try{for(;;){const{value:n,done:i}=await s.read();if(i)break;a+=o.decode(n,{stream:!0});let c;for(;(c=a.indexOf(`
4
4
 
5
- `))!==-1;){const d=n.slice(0,c);n=n.slice(c+2);const l=y(d);l&&e(l)}}if(n.trim()){const a=y(n);a&&e(a)}}catch(a){(a==null?void 0:a.name)!=="AbortError"&&t(a instanceof Error?a:new Error(String(a)))}finally{try{s.releaseLock()}catch{}}}function p(r,e){const t=new AbortController,s=e.signal?b(e.signal,t.signal):t.signal,o={botId:r.getBotId(),message:e.message,sessionId:e.sessionId,stream:e.stream!==!1};return o.stream?r.streamPost("/chat",o,s).then(n=>{var a;if(!n.ok){(a=e.onError)==null||a.call(e,new Error(`HTTP ${n.status}`));return}return m(n,i=>{var c,d,l,h,f,g;i.type==="done"&&i.sessionId?(c=e.onDone)==null||c.call(e,{sessionId:i.sessionId,content:i.content,messageId:i.messageId}):i.type==="done"?(d=e.onDone)==null||d.call(e,{sessionId:"",content:i.content,messageId:i.messageId}):i.type==="stop"?((l=e.onMessage)==null||l.call(e,i),(h=e.onDone)==null||h.call(e,{sessionId:i.sessionId??"",content:i.content})):i.type==="error"?(f=e.onError)==null||f.call(e,new Error(i.content)):(g=e.onMessage)==null||g.call(e,i)},i=>{var c;return(c=e.onError)==null?void 0:c.call(e,i)})}).catch(n=>{var a;(n==null?void 0:n.name)!=="AbortError"&&((a=e.onError)==null||a.call(e,n instanceof Error?n:new Error(String(n))))}):r.post("/chat",o).then(n=>{var a;(a=e.onDone)==null||a.call(e,{sessionId:n.sessionId,content:n.content??"",messageId:n.messageId})}).catch(n=>{var a;(a=e.onError)==null||a.call(e,n instanceof Error?n:new Error(String(n)))}),t}function b(r,e){const t=new AbortController,s=()=>t.abort();return r.addEventListener("abort",s,{once:!0}),e.addEventListener("abort",s,{once:!0}),(r.aborted||e.aborted)&&t.abort(),t.signal}async function k(r){return(await r.post("/chat/sessions",{botId:r.getBotId()})).sessionId}function T(r){return{sessionId:r.threadId??r.sessionId,botId:r.botId,title:r.title,createTime:r.createTime,updateTime:r.updateTime}}async function S(r,e){const t=await r.get("/chat/conversations",{botId:r.getBotId(),page:(e==null?void 0:e.page)??1,size:(e==null?void 0:e.size)??20});return{...t,items:t.items.map(T)}}async function $(r,e,t){await r.patch(`/chat/conversations/${e}`,{title:t})}async function A(r,e){await r.del(`/chat/conversations/${e}`)}async function C(r,e){const t=await r.get(`/chat/conversations/${e}/messages`);return O(t)}function O(r){const e=[...r].sort((a,i)=>(a.seq??0)-(i.seq??0)),t=new Map;for(const a of e)a.role==="tool"&&a.toolCallId&&t.set(a.toolCallId,a.content||"");const s=new Set,o=[],n=(a,i,c)=>{const d=o[o.length-1];(d==null?void 0:d.role)==="assistant"?(d.parts.push(...a),d.id=i):o.push({id:i,role:"assistant",parts:[...a],timestamp:c})};for(const a of e){if(a.role==="system")continue;const i=a.messageId??`msg_${a.id}`,c=new Date(a.createTime??"").getTime()||Date.now();if(a.role==="human"){o.push({id:i,role:"user",parts:[{type:"text",content:a.content??""}],timestamp:c});continue}if(a.role==="ai"){const d=P(a,t,s);d.length>0&&n(d,i,c);continue}if(a.role==="tool"){if(a.toolCallId&&s.has(a.toolCallId))continue;n([E(a)],i,c)}}return o}function P(r,e,t){const s=[];r.reasoning&&s.push({type:"thinking",content:r.reasoning}),r.content&&s.push({type:"text",content:r.content});for(const o of r.toolCalls??[])o.is_interrupt?(t.add(o.id),s.push(_(o,e))):s.push(v(o));return s}function _(r,e){const t=e.has(r.id),s=typeof r.args=="object"?r.args:{};return{type:"interrupt",interrupt:{interruptId:r.id??"",interruptType:s.interruptType??"input",content:s.content??"",options:s.options,placeholder:s.placeholder,inputType:s.inputType,maxLength:s.maxLength,required:s.required,fields:s.fields,metadata:s.metadata},resolved:t,response:t?{action:"submit",value:U(e.get(r.id))}:void 0}}function v(r){let e;try{e=typeof r.args=="string"?r.args:JSON.stringify(r.args??{})}catch{e=String(r.args??"{}")}return{type:"tool_call",toolName:r.name??"",toolCallId:r.id??"",args:e}}function E(r){var t,s,o;const e=Array.isArray(r.artifacts)?r.artifacts:void 0;return{type:"tool_result",toolName:r.toolName??"",toolCallId:r.toolCallId??"",content:r.content??"",artifacts:e,renderMode:((t=r.metadata)==null?void 0:t.renderMode)??((s=r.metadata)==null?void 0:s.render_mode),html:(o=r.metadata)==null?void 0:o.html}}function U(r){if(r!=null)try{return JSON.parse(r)}catch{return r}}async function x(r,e,t,s,o,n){const a=await r.streamPost(`/chat/interrupt/${e}/respond`,{sessionId:t,action:s.action,value:s.value});if(!a.ok){const i=new Error(`HTTP ${a.status}`);throw n==null||n(i),i}o&&await m(a,i=>{i.type==="error"?n==null||n(new Error(i.content)):o(i)},i=>n==null?void 0:n(i))}async function q(r){return r.get(`/chat/bots/${r.getBotId()}/skills`)}async function N(r,e){await r.post("/chat/stop",{sessionId:e})}function L(r){const e=new w(r);return{getToken:()=>e.fetchToken(),createSession:()=>k(e),chat:s=>p(e,s),listConversations:s=>S(e,s),renameConversation:(s,o)=>$(e,s,o),deleteConversation:s=>A(e,s),getMessages:s=>C(e,s),respondInterrupt:(s,o,n,a,i)=>x(e,s,o,n,a,i),setToken:s=>e.setToken(s),feedback:async(s,o,n)=>{const a={type:o};o==="dislike"&&((n==null?void 0:n.reason)!=null&&(a.reason=n.reason),n!=null&&n.remark&&(a.remark=n.remark)),await e.post(`/chat/messages/${s}/feedback`,a)},cancelFeedback:async s=>{await e.del(`/chat/messages/${s}/feedback`)},listSkills:()=>q(e),stopGeneration:s=>N(e,s)}}exports.createSuperAgent=L;
5
+ `))!==-1;){const d=a.slice(0,c);a=a.slice(c+2);const l=y(d);l&&e(l)}}if(a.trim()){const n=y(a);n&&e(n)}}catch(n){(n==null?void 0:n.name)!=="AbortError"&&t(n instanceof Error?n:new Error(String(n)))}finally{try{s.releaseLock()}catch{}}}function b(r,e){const t=new AbortController,s=e.signal?p(e.signal,t.signal):t.signal,o={botId:r.getBotId(),message:e.message,sessionId:e.sessionId,stream:e.stream!==!1};return o.stream?r.streamPost("/chat",o,s).then(a=>{var n;if(!a.ok){(n=e.onError)==null||n.call(e,new Error(`HTTP ${a.status}`));return}return m(a,i=>{var c,d,l,h,f,g;i.type==="done"&&i.sessionId?(c=e.onDone)==null||c.call(e,{sessionId:i.sessionId,content:i.content,messageId:i.messageId}):i.type==="done"?(d=e.onDone)==null||d.call(e,{sessionId:"",content:i.content,messageId:i.messageId}):i.type==="stop"?((l=e.onMessage)==null||l.call(e,i),(h=e.onDone)==null||h.call(e,{sessionId:i.sessionId??"",content:i.content,messageId:i.messageId})):i.type==="error"?(f=e.onError)==null||f.call(e,new Error(i.content)):(g=e.onMessage)==null||g.call(e,i)},i=>{var c;return(c=e.onError)==null?void 0:c.call(e,i)})}).catch(a=>{var n;(a==null?void 0:a.name)!=="AbortError"&&((n=e.onError)==null||n.call(e,a instanceof Error?a:new Error(String(a))))}):r.post("/chat",o).then(a=>{var n;(n=e.onDone)==null||n.call(e,{sessionId:a.sessionId,content:a.content??"",messageId:a.messageId})}).catch(a=>{var n;(n=e.onError)==null||n.call(e,a instanceof Error?a:new Error(String(a)))}),t}function p(r,e){const t=new AbortController,s=()=>t.abort();return r.addEventListener("abort",s,{once:!0}),e.addEventListener("abort",s,{once:!0}),(r.aborted||e.aborted)&&t.abort(),t.signal}async function T(r){return(await r.post("/chat/sessions",{botId:r.getBotId()})).sessionId}function k(r){return{sessionId:r.threadId??r.sessionId,botId:r.botId,title:r.title,createTime:r.createTime,updateTime:r.updateTime}}async function S(r,e){const t=await r.get("/chat/conversations",{botId:r.getBotId(),page:(e==null?void 0:e.page)??1,size:(e==null?void 0:e.size)??20});return{...t,items:t.items.map(k)}}async function $(r,e,t){await r.patch(`/chat/conversations/${e}`,{title:t})}async function A(r,e){await r.del(`/chat/conversations/${e}`)}async function C(r,e){const t=await r.get(`/chat/conversations/${e}/messages`);return O(t)}function O(r){const e=[...r].sort((n,i)=>{const c=new Date(n.createTime??0).getTime()||0,d=new Date(i.createTime??0).getTime()||0;return c!==d?c-d:(n.seq??0)-(i.seq??0)}),t=new Map;for(const n of e)n.role==="tool"&&n.toolCallId&&t.set(n.toolCallId,n.content||"");const s=new Set,o=[],a=(n,i,c)=>{const d=o[o.length-1];(d==null?void 0:d.role)==="assistant"?(d.parts.push(...n),d.id=i):o.push({id:i,role:"assistant",parts:[...n],timestamp:c})};for(const n of e){if(n.role==="system")continue;const i=String(n.id??n.messageId??`msg_${Date.now()}`),c=new Date(n.createTime??"").getTime()||Date.now();if(n.role==="human"){o.push({id:i,role:"user",parts:[{type:"text",content:n.content??""}],timestamp:c});continue}if(n.role==="ai"){const d=P(n,t,s);d.length>0&&a(d,i,c);continue}if(n.role==="tool"){if(n.toolCallId&&s.has(n.toolCallId))continue;a([v(n)],i,c)}}return o}function P(r,e,t){const s=[];r.reasoning&&s.push({type:"thinking",content:r.reasoning}),r.content&&s.push({type:"text",content:r.content});for(const o of r.toolCalls??[])o.is_interrupt?(t.add(o.id),s.push(_(o,e))):s.push(E(o));return s}function _(r,e){const t=e.has(r.id),s=typeof r.args=="object"?r.args:{};return{type:"interrupt",interrupt:{interruptId:r.id??"",interruptType:s.interruptType??"input",content:s.content??"",options:s.options,placeholder:s.placeholder,inputType:s.inputType,maxLength:s.maxLength,required:s.required,fields:s.fields,metadata:s.metadata},resolved:t,response:t?{action:"submit",value:U(e.get(r.id))}:void 0}}function E(r){let e;try{e=typeof r.args=="string"?r.args:JSON.stringify(r.args??{})}catch{e=String(r.args??"{}")}return{type:"tool_call",toolName:r.name??"",toolCallId:r.id??"",args:e}}function v(r){var t,s,o;const e=Array.isArray(r.artifacts)?r.artifacts:void 0;return{type:"tool_result",toolName:r.toolName??"",toolCallId:r.toolCallId??"",content:r.content??"",artifacts:e,renderMode:((t=r.metadata)==null?void 0:t.renderMode)??((s=r.metadata)==null?void 0:s.render_mode),html:(o=r.metadata)==null?void 0:o.html}}function U(r){if(r!=null)try{return JSON.parse(r)}catch{return r}}async function x(r,e,t,s,o,a){const n=await r.streamPost(`/chat/interrupt/${e}/respond`,{sessionId:t,action:s.action,value:s.value});if(!n.ok){const i=new Error(`HTTP ${n.status}`);throw a==null||a(i),i}o&&await m(n,i=>{i.type==="error"?a==null||a(new Error(i.content)):o(i)},i=>a==null?void 0:a(i))}async function D(r){return r.get(`/chat/bots/${r.getBotId()}/skills`)}async function q(r,e){await r.post("/chat/stop",{sessionId:e})}function N(r){const e=new w(r);return{botId:e.getBotId(),getToken:()=>e.fetchToken(),createSession:()=>T(e),chat:s=>b(e,s),listConversations:s=>S(e,s),renameConversation:(s,o)=>$(e,s,o),deleteConversation:s=>A(e,s),getMessages:s=>C(e,s),respondInterrupt:(s,o,a,n,i)=>x(e,s,o,a,n,i),setToken:s=>e.setToken(s),feedback:async(s,o,a)=>{const n={type:o};o==="dislike"&&((a==null?void 0:a.reason)!=null&&(n.reason=a.reason),a!=null&&a.remark&&(n.remark=a.remark)),await e.post(`/chat/messages/${s}/feedback`,n)},cancelFeedback:async s=>{await e.del(`/chat/messages/${s}/feedback`)},listSkills:()=>D(e),stopGeneration:s=>q(e,s)}}exports.createSuperAgent=N;
package/dist/index.d.ts CHANGED
@@ -55,11 +55,14 @@ export declare function createSuperAgent(config: SDKConfig): SuperAgentSDK;
55
55
  export declare interface FormField {
56
56
  name: string;
57
57
  label: string;
58
- type: 'text' | 'number' | 'password' | 'textarea' | 'select' | 'date';
58
+ type: 'text' | 'number' | 'password' | 'textarea' | 'select' | 'multiSelect' | 'date';
59
59
  required?: boolean;
60
60
  placeholder?: string;
61
61
  defaultValue?: any;
62
- options?: string[];
62
+ options?: (string | {
63
+ value: string;
64
+ label: string;
65
+ })[];
63
66
  }
64
67
 
65
68
  export declare interface InterruptEvent {
@@ -145,6 +148,8 @@ declare interface SkillInfo {
145
148
  }
146
149
 
147
150
  export declare interface SuperAgentSDK {
151
+ /** 当前 Bot ID(只读) */
152
+ readonly botId: number;
148
153
  /** 获取 token(调用 POST {tokenGateway}/v1/token),自动设置内部凭证 */
149
154
  getToken(): Promise<string>;
150
155
  /** 创建新会话,返回 sessionId */