@yushaw/sanqian-sdk 0.3.18 → 0.3.19

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.
@@ -261,6 +261,14 @@ interface ChatResponse {
261
261
  total_tokens: number;
262
262
  };
263
263
  }
264
+ /** Mention/load item types for dynamic capability/context activation */
265
+ type LoadItemType = "tool" | "skill" | "subagent" | "context";
266
+ type LoadItemAction = "load" | "unload";
267
+ interface LoadItem {
268
+ type: LoadItemType;
269
+ id: string;
270
+ action?: LoadItemAction;
271
+ }
264
272
  interface ChatStreamEvent {
265
273
  type: "start" | "text" | "thinking" | "tool_call" | "tool_args_chunk" | "tool_args" | "tool_result" | "done" | "error" | "interrupt" | "cancelled";
266
274
  /** Text content (for "text" and "thinking" events) */
@@ -289,7 +297,7 @@ interface ChatStreamEvent {
289
297
  interrupt_type?: HitlInterruptType;
290
298
  /** Interrupt payload (for "interrupt" event) - HITL */
291
299
  interrupt_payload?: HitlInterruptPayload;
292
- /** Run ID (for "interrupt" event) - needed to send HITL response */
300
+ /** Run ID (for "start"/"interrupt"/"cancelled" events) */
293
301
  run_id?: string;
294
302
  }
295
303
  /**
@@ -741,9 +749,14 @@ declare class SanqianSDK {
741
749
  private sessionResources;
742
750
  private contextProviders;
743
751
  private runIdToMsgId;
744
- private pendingStreamMsgId;
752
+ private pendingStreamRequests;
753
+ private pendingCancelMsgIds;
754
+ private static readonly VALID_SECURITY_LEVELS;
745
755
  private log;
746
756
  private warn;
757
+ private normalizeRequestedSecurityLevel;
758
+ private sendRunCancel;
759
+ private requestStreamCancel;
747
760
  constructor(config: SDKConfig);
748
761
  /**
749
762
  * Build WebSocket URL from connection info
@@ -824,11 +837,7 @@ declare class SanqianSDK {
824
837
  autoDiscoverSubagents?: boolean;
825
838
  persistHistory?: boolean;
826
839
  filePaths?: string[];
827
- loadItems?: Array<{
828
- type: string;
829
- id: string;
830
- action?: string;
831
- }>;
840
+ loadItems?: LoadItem[];
832
841
  mentionedTools?: string[];
833
842
  }): Promise<ChatResponse>;
834
843
  chatStream(agentId: string, messages: ChatMessage[], options?: {
@@ -842,12 +851,9 @@ declare class SanqianSDK {
842
851
  attachedResources?: string[];
843
852
  sessionResources?: string[];
844
853
  filePaths?: string[];
845
- loadItems?: Array<{
846
- type: string;
847
- id: string;
848
- action?: string;
849
- }>;
854
+ loadItems?: LoadItem[];
850
855
  mentionedTools?: string[];
856
+ signal?: AbortSignal;
851
857
  }): AsyncGenerator<ChatStreamEvent>;
852
858
  /**
853
859
  * Send HITL (Human-in-the-Loop) response to resume after interrupt
@@ -972,6 +978,7 @@ declare const SANQIAN_WEBSITE = "https://sanqian.io";
972
978
  * Error codes for SDK errors
973
979
  */
974
980
  declare enum SDKErrorCode {
981
+ INVALID_CONFIG = "INVALID_CONFIG",
975
982
  NOT_INSTALLED = "NOT_INSTALLED",
976
983
  NOT_RUNNING = "NOT_RUNNING",
977
984
  CONNECTION_TIMEOUT = "CONNECTION_TIMEOUT",
@@ -1024,4 +1031,4 @@ declare class SanqianSDKError extends Error {
1024
1031
  */
1025
1032
  declare function createSDKError(code: SDKErrorCode, details?: string): SanqianSDKError;
1026
1033
 
1027
- export { type AgentCapability, type AgentConfig, type AgentInfo, type AgentUpdateConfig, type Capability, type CapabilitySearchResult, type CapabilityType, type ChatMessage, type ChatRequest, type ChatResponse, type ChatStreamEvent, type ConnectionInfo, type ConnectionState, type ContextData, type ContextListItem, type ContextProvider, Conversation, type ConversationDetail, type ConversationInfo, type ConversationMessage, type EmbeddingConfigResult, ErrorMessages, type HitlInterruptPayload, type HitlInterruptType, type HitlResponse, type HitlRiskLevel, type JSONSchema, type JSONSchemaProperty, type ListCapabilitiesOptions, type RemoteToolDefinition, type RerankConfigResult, SANQIAN_WEBSITE, type SDKConfig, SDKErrorCode, type SDKEventName, type SDKEvents, SanqianSDK, SanqianSDKError, type SearchCapabilitiesOptions, type SessionResource, type SkillCapability, type StoredSessionResource, type ToolCall, type ToolCapability, type ToolDefinition, createSDKError };
1034
+ export { type AgentCapability, type AgentConfig, type AgentInfo, type AgentUpdateConfig, type Capability, type CapabilitySearchResult, type CapabilityType, type ChatMessage, type ChatRequest, type ChatResponse, type ChatStreamEvent, type ConnectionInfo, type ConnectionState, type ContextData, type ContextListItem, type ContextProvider, Conversation, type ConversationDetail, type ConversationInfo, type ConversationMessage, type EmbeddingConfigResult, ErrorMessages, type HitlInterruptPayload, type HitlInterruptType, type HitlResponse, type HitlRiskLevel, type JSONSchema, type JSONSchemaProperty, type ListCapabilitiesOptions, type LoadItem, type LoadItemAction, type LoadItemType, type RemoteToolDefinition, type RerankConfigResult, SANQIAN_WEBSITE, type SDKConfig, SDKErrorCode, type SDKEventName, type SDKEvents, SanqianSDK, SanqianSDKError, type SearchCapabilitiesOptions, type SessionResource, type SkillCapability, type StoredSessionResource, type ToolCall, type ToolCapability, type ToolDefinition, createSDKError };
@@ -261,6 +261,14 @@ interface ChatResponse {
261
261
  total_tokens: number;
262
262
  };
263
263
  }
264
+ /** Mention/load item types for dynamic capability/context activation */
265
+ type LoadItemType = "tool" | "skill" | "subagent" | "context";
266
+ type LoadItemAction = "load" | "unload";
267
+ interface LoadItem {
268
+ type: LoadItemType;
269
+ id: string;
270
+ action?: LoadItemAction;
271
+ }
264
272
  interface ChatStreamEvent {
265
273
  type: "start" | "text" | "thinking" | "tool_call" | "tool_args_chunk" | "tool_args" | "tool_result" | "done" | "error" | "interrupt" | "cancelled";
266
274
  /** Text content (for "text" and "thinking" events) */
@@ -289,7 +297,7 @@ interface ChatStreamEvent {
289
297
  interrupt_type?: HitlInterruptType;
290
298
  /** Interrupt payload (for "interrupt" event) - HITL */
291
299
  interrupt_payload?: HitlInterruptPayload;
292
- /** Run ID (for "interrupt" event) - needed to send HITL response */
300
+ /** Run ID (for "start"/"interrupt"/"cancelled" events) */
293
301
  run_id?: string;
294
302
  }
295
303
  /**
@@ -741,9 +749,14 @@ declare class SanqianSDK {
741
749
  private sessionResources;
742
750
  private contextProviders;
743
751
  private runIdToMsgId;
744
- private pendingStreamMsgId;
752
+ private pendingStreamRequests;
753
+ private pendingCancelMsgIds;
754
+ private static readonly VALID_SECURITY_LEVELS;
745
755
  private log;
746
756
  private warn;
757
+ private normalizeRequestedSecurityLevel;
758
+ private sendRunCancel;
759
+ private requestStreamCancel;
747
760
  constructor(config: SDKConfig);
748
761
  /**
749
762
  * Build WebSocket URL from connection info
@@ -824,11 +837,7 @@ declare class SanqianSDK {
824
837
  autoDiscoverSubagents?: boolean;
825
838
  persistHistory?: boolean;
826
839
  filePaths?: string[];
827
- loadItems?: Array<{
828
- type: string;
829
- id: string;
830
- action?: string;
831
- }>;
840
+ loadItems?: LoadItem[];
832
841
  mentionedTools?: string[];
833
842
  }): Promise<ChatResponse>;
834
843
  chatStream(agentId: string, messages: ChatMessage[], options?: {
@@ -842,12 +851,9 @@ declare class SanqianSDK {
842
851
  attachedResources?: string[];
843
852
  sessionResources?: string[];
844
853
  filePaths?: string[];
845
- loadItems?: Array<{
846
- type: string;
847
- id: string;
848
- action?: string;
849
- }>;
854
+ loadItems?: LoadItem[];
850
855
  mentionedTools?: string[];
856
+ signal?: AbortSignal;
851
857
  }): AsyncGenerator<ChatStreamEvent>;
852
858
  /**
853
859
  * Send HITL (Human-in-the-Loop) response to resume after interrupt
@@ -972,6 +978,7 @@ declare const SANQIAN_WEBSITE = "https://sanqian.io";
972
978
  * Error codes for SDK errors
973
979
  */
974
980
  declare enum SDKErrorCode {
981
+ INVALID_CONFIG = "INVALID_CONFIG",
975
982
  NOT_INSTALLED = "NOT_INSTALLED",
976
983
  NOT_RUNNING = "NOT_RUNNING",
977
984
  CONNECTION_TIMEOUT = "CONNECTION_TIMEOUT",
@@ -1024,4 +1031,4 @@ declare class SanqianSDKError extends Error {
1024
1031
  */
1025
1032
  declare function createSDKError(code: SDKErrorCode, details?: string): SanqianSDKError;
1026
1033
 
1027
- export { type AgentCapability, type AgentConfig, type AgentInfo, type AgentUpdateConfig, type Capability, type CapabilitySearchResult, type CapabilityType, type ChatMessage, type ChatRequest, type ChatResponse, type ChatStreamEvent, type ConnectionInfo, type ConnectionState, type ContextData, type ContextListItem, type ContextProvider, Conversation, type ConversationDetail, type ConversationInfo, type ConversationMessage, type EmbeddingConfigResult, ErrorMessages, type HitlInterruptPayload, type HitlInterruptType, type HitlResponse, type HitlRiskLevel, type JSONSchema, type JSONSchemaProperty, type ListCapabilitiesOptions, type RemoteToolDefinition, type RerankConfigResult, SANQIAN_WEBSITE, type SDKConfig, SDKErrorCode, type SDKEventName, type SDKEvents, SanqianSDK, SanqianSDKError, type SearchCapabilitiesOptions, type SessionResource, type SkillCapability, type StoredSessionResource, type ToolCall, type ToolCapability, type ToolDefinition, createSDKError };
1034
+ export { type AgentCapability, type AgentConfig, type AgentInfo, type AgentUpdateConfig, type Capability, type CapabilitySearchResult, type CapabilityType, type ChatMessage, type ChatRequest, type ChatResponse, type ChatStreamEvent, type ConnectionInfo, type ConnectionState, type ContextData, type ContextListItem, type ContextProvider, Conversation, type ConversationDetail, type ConversationInfo, type ConversationMessage, type EmbeddingConfigResult, ErrorMessages, type HitlInterruptPayload, type HitlInterruptType, type HitlResponse, type HitlRiskLevel, type JSONSchema, type JSONSchemaProperty, type ListCapabilitiesOptions, type LoadItem, type LoadItemAction, type LoadItemType, type RemoteToolDefinition, type RerankConfigResult, SANQIAN_WEBSITE, type SDKConfig, SDKErrorCode, type SDKEventName, type SDKEvents, SanqianSDK, SanqianSDKError, type SearchCapabilitiesOptions, type SessionResource, type SkillCapability, type StoredSessionResource, type ToolCall, type ToolCapability, type ToolDefinition, createSDKError };
@@ -33,6 +33,7 @@ module.exports = __toCommonJS(index_browser_exports);
33
33
  // src/errors.ts
34
34
  var SANQIAN_WEBSITE = "https://sanqian.io";
35
35
  var SDKErrorCode = /* @__PURE__ */ ((SDKErrorCode2) => {
36
+ SDKErrorCode2["INVALID_CONFIG"] = "INVALID_CONFIG";
36
37
  SDKErrorCode2["NOT_INSTALLED"] = "NOT_INSTALLED";
37
38
  SDKErrorCode2["NOT_RUNNING"] = "NOT_RUNNING";
38
39
  SDKErrorCode2["CONNECTION_TIMEOUT"] = "CONNECTION_TIMEOUT";
@@ -49,6 +50,14 @@ var SDKErrorCode = /* @__PURE__ */ ((SDKErrorCode2) => {
49
50
  return SDKErrorCode2;
50
51
  })(SDKErrorCode || {});
51
52
  var ErrorMessages = {
53
+ ["INVALID_CONFIG" /* INVALID_CONFIG */]: {
54
+ en: `SDK configuration is invalid.`,
55
+ zh: `SDK \u914D\u7F6E\u65E0\u6548\u3002`,
56
+ hint: {
57
+ en: `Please check required fields and option values in your SDK config.`,
58
+ zh: `\u8BF7\u68C0\u67E5 SDK \u914D\u7F6E\u4E2D\u7684\u5FC5\u586B\u5B57\u6BB5\u548C\u9009\u9879\u53D6\u503C\u3002`
59
+ }
60
+ },
52
61
  ["NOT_INSTALLED" /* NOT_INSTALLED */]: {
53
62
  en: `Sanqian is not installed on this computer.`,
54
63
  zh: `Sanqian \u5C1A\u672A\u5B89\u88C5\u5728\u6B64\u7535\u8111\u4E0A\u3002`,
@@ -229,8 +238,15 @@ var SanqianSDK = class _SanqianSDK {
229
238
  contextProviders = /* @__PURE__ */ new Map();
230
239
  // Map run_id -> msgId for routing backend messages to correct handler
231
240
  runIdToMsgId = /* @__PURE__ */ new Map();
232
- // Track the most recent pending msgId (for start message routing)
233
- pendingStreamMsgId = null;
241
+ // Queue pending stream requests for backend-native "start" routing (which has no msgId)
242
+ pendingStreamRequests = [];
243
+ // Streams requested to cancel before run_id is available
244
+ pendingCancelMsgIds = /* @__PURE__ */ new Set();
245
+ static VALID_SECURITY_LEVELS = /* @__PURE__ */ new Set([
246
+ "standard",
247
+ "elevated",
248
+ "unrestricted"
249
+ ]);
234
250
  // ============================================
235
251
  // Debug Logging
236
252
  // ============================================
@@ -244,6 +260,34 @@ var SanqianSDK = class _SanqianSDK {
244
260
  console.warn("[SDK]", ...args);
245
261
  }
246
262
  }
263
+ normalizeRequestedSecurityLevel(level) {
264
+ if (level === void 0 || level === null) {
265
+ return void 0;
266
+ }
267
+ if (typeof level === "string" && _SanqianSDK.VALID_SECURITY_LEVELS.has(level)) {
268
+ return level;
269
+ }
270
+ throw createSDKError(
271
+ "INVALID_CONFIG" /* INVALID_CONFIG */,
272
+ "requestedSecurityLevel must be one of: standard, elevated, unrestricted"
273
+ );
274
+ }
275
+ sendRunCancel(runId) {
276
+ const message = {
277
+ type: "cancel",
278
+ run_id: runId
279
+ };
280
+ this.send(message);
281
+ this.log(`Sent cancel for run ${runId}`);
282
+ }
283
+ requestStreamCancel(msgId, runId) {
284
+ if (runId) {
285
+ this.pendingCancelMsgIds.delete(msgId);
286
+ this.sendRunCancel(runId);
287
+ return;
288
+ }
289
+ this.pendingCancelMsgIds.add(msgId);
290
+ }
247
291
  constructor(config) {
248
292
  if (!config.connectionInfo) {
249
293
  throw new SanqianSDKError(
@@ -251,6 +295,9 @@ var SanqianSDK = class _SanqianSDK {
251
295
  "Browser build requires connectionInfo in config. Use the Node.js build for auto-discovery, or provide connectionInfo manually."
252
296
  );
253
297
  }
298
+ const requestedSecurityLevel = this.normalizeRequestedSecurityLevel(
299
+ config.requestedSecurityLevel
300
+ );
254
301
  this.config = {
255
302
  reconnectInterval: 5e3,
256
303
  heartbeatInterval: 3e4,
@@ -258,7 +305,8 @@ var SanqianSDK = class _SanqianSDK {
258
305
  debug: false,
259
306
  autoLaunchSanqian: false,
260
307
  // Not supported in browser
261
- ...config
308
+ ...config,
309
+ requestedSecurityLevel
262
310
  };
263
311
  for (const tool of config.tools) {
264
312
  this.toolHandlers.set(tool.name, tool.handler);
@@ -537,18 +585,36 @@ var SanqianSDK = class _SanqianSDK {
537
585
  this.warn("Received start message without run_id");
538
586
  return;
539
587
  }
540
- if (this.pendingStreamMsgId) {
541
- this.runIdToMsgId.set(runId, this.pendingStreamMsgId);
542
- const handler = this.streamHandlers.get(this.pendingStreamMsgId);
543
- if (handler) {
544
- handler.onEvent({
545
- type: "start",
546
- run_id: runId,
547
- conversationId: message.payload?.session_id || ""
548
- });
549
- }
550
- } else {
588
+ const sessionId = message.payload?.session_id;
589
+ let pendingIndex = -1;
590
+ if (sessionId) {
591
+ pendingIndex = this.pendingStreamRequests.findIndex((item) => item.conversationId === sessionId);
592
+ }
593
+ if (pendingIndex < 0) {
594
+ pendingIndex = 0;
595
+ }
596
+ const pending = this.pendingStreamRequests[pendingIndex];
597
+ if (!pending) {
551
598
  this.warn("Received start message but no pending stream handler");
599
+ return;
600
+ }
601
+ this.pendingStreamRequests.splice(pendingIndex, 1);
602
+ const pendingMsgId = pending.msgId;
603
+ this.runIdToMsgId.set(runId, pendingMsgId);
604
+ const handler = this.streamHandlers.get(pendingMsgId);
605
+ if (handler) {
606
+ handler.onEvent({
607
+ type: "start",
608
+ run_id: runId,
609
+ conversationId: message.payload?.session_id || ""
610
+ });
611
+ }
612
+ if (this.pendingCancelMsgIds.has(pendingMsgId)) {
613
+ try {
614
+ this.requestStreamCancel(pendingMsgId, runId);
615
+ } catch (e) {
616
+ this.warn("Failed to send queued cancel for run", runId, e);
617
+ }
552
618
  }
553
619
  }
554
620
  handleBackendStream(message) {
@@ -696,6 +762,14 @@ var SanqianSDK = class _SanqianSDK {
696
762
  pending.reject(createSDKError("DISCONNECTED" /* DISCONNECTED */));
697
763
  }
698
764
  this.pendingRequests.clear();
765
+ const disconnectError = createSDKError("DISCONNECTED" /* DISCONNECTED */, reason);
766
+ for (const [, handler] of this.streamHandlers) {
767
+ handler.onError(disconnectError);
768
+ }
769
+ this.streamHandlers.clear();
770
+ this.runIdToMsgId.clear();
771
+ this.pendingStreamRequests = [];
772
+ this.pendingCancelMsgIds.clear();
699
773
  if (reason === "Client disconnect") {
700
774
  this.log("Client disconnected intentionally, skipping auto-reconnect");
701
775
  return;
@@ -1144,9 +1218,39 @@ var SanqianSDK = class _SanqianSDK {
1144
1218
  let done = false;
1145
1219
  let error = null;
1146
1220
  let resolveNext = null;
1221
+ let activeRunId;
1222
+ if (options?.signal?.aborted) {
1223
+ throw createSDKError(
1224
+ "REQUEST_FAILED" /* REQUEST_FAILED */,
1225
+ "Chat stream aborted before request was sent"
1226
+ );
1227
+ }
1228
+ const handleAbort = () => {
1229
+ try {
1230
+ this.requestStreamCancel(msgId, activeRunId);
1231
+ } catch (e) {
1232
+ error = e instanceof Error ? e : new Error(String(e));
1233
+ resolveNext?.();
1234
+ }
1235
+ };
1236
+ options?.signal?.addEventListener("abort", handleAbort, { once: true });
1147
1237
  this.streamHandlers.set(msgId, {
1148
1238
  onEvent: (event) => {
1149
1239
  eventQueue.push(event);
1240
+ if (event.type === "start") {
1241
+ activeRunId = event.run_id;
1242
+ this.pendingStreamRequests = this.pendingStreamRequests.filter((item) => item.msgId !== msgId);
1243
+ if (this.pendingCancelMsgIds.has(msgId)) {
1244
+ try {
1245
+ this.requestStreamCancel(msgId, activeRunId);
1246
+ } catch (e) {
1247
+ error = e instanceof Error ? e : new Error(String(e));
1248
+ }
1249
+ }
1250
+ }
1251
+ if (event.type === "cancelled") {
1252
+ done = true;
1253
+ }
1150
1254
  resolveNext?.();
1151
1255
  },
1152
1256
  onDone: (response) => {
@@ -1164,7 +1268,10 @@ var SanqianSDK = class _SanqianSDK {
1164
1268
  }
1165
1269
  });
1166
1270
  try {
1167
- this.pendingStreamMsgId = msgId;
1271
+ this.pendingStreamRequests.push({
1272
+ msgId,
1273
+ conversationId: options?.conversationId
1274
+ });
1168
1275
  this.send(message);
1169
1276
  while (!done && !error) {
1170
1277
  if (eventQueue.length > 0) {
@@ -1183,12 +1290,13 @@ var SanqianSDK = class _SanqianSDK {
1183
1290
  throw error;
1184
1291
  }
1185
1292
  } finally {
1293
+ options?.signal?.removeEventListener("abort", handleAbort);
1186
1294
  this.streamHandlers.delete(msgId);
1187
- this.pendingStreamMsgId = null;
1295
+ this.pendingStreamRequests = this.pendingStreamRequests.filter((item) => item.msgId !== msgId);
1296
+ this.pendingCancelMsgIds.delete(msgId);
1188
1297
  for (const [runId, id] of this.runIdToMsgId) {
1189
1298
  if (id === msgId) {
1190
1299
  this.runIdToMsgId.delete(runId);
1191
- break;
1192
1300
  }
1193
1301
  }
1194
1302
  }
@@ -1222,12 +1330,7 @@ var SanqianSDK = class _SanqianSDK {
1222
1330
  if (!this.state.connected) {
1223
1331
  throw createSDKError("DISCONNECTED" /* DISCONNECTED */, "Not connected to Sanqian");
1224
1332
  }
1225
- const message = {
1226
- type: "cancel",
1227
- run_id: runId
1228
- };
1229
- this.send(message);
1230
- this.log(`Sent cancel for run ${runId}`);
1333
+ this.sendRunCancel(runId);
1231
1334
  }
1232
1335
  startConversation(agentId) {
1233
1336
  return new Conversation(this, agentId);