@yushaw/sanqian-sdk 0.2.0 → 0.2.2

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/dist/index.js CHANGED
@@ -32,7 +32,12 @@ var index_exports = {};
32
32
  __export(index_exports, {
33
33
  Conversation: () => Conversation,
34
34
  DiscoveryManager: () => DiscoveryManager,
35
- SanqianSDK: () => SanqianSDK
35
+ ErrorMessages: () => ErrorMessages,
36
+ SANQIAN_WEBSITE: () => SANQIAN_WEBSITE,
37
+ SDKErrorCode: () => SDKErrorCode,
38
+ SanqianSDK: () => SanqianSDK,
39
+ SanqianSDKError: () => SanqianSDKError,
40
+ createSDKError: () => createSDKError
36
41
  });
37
42
  module.exports = __toCommonJS(index_exports);
38
43
 
@@ -49,6 +54,11 @@ var DiscoveryManager = class {
49
54
  watcher = null;
50
55
  onChange = null;
51
56
  pollInterval = null;
57
+ /**
58
+ * Cached executable path from last successful connection.json read.
59
+ * Persists even when Sanqian is not running, for use in auto-launch.
60
+ */
61
+ cachedExecutable = null;
52
62
  /**
53
63
  * Get the path to connection.json
54
64
  */
@@ -74,6 +84,9 @@ var DiscoveryManager = class {
74
84
  if (!info.port || !info.token || !info.pid) {
75
85
  return null;
76
86
  }
87
+ if (info.executable) {
88
+ this.cachedExecutable = info.executable;
89
+ }
77
90
  if (!this.isProcessRunning(info.pid)) {
78
91
  return null;
79
92
  }
@@ -235,9 +248,22 @@ var DiscoveryManager = class {
235
248
  /**
236
249
  * Launch Sanqian in hidden/tray mode
237
250
  * Returns true if launch was initiated successfully
251
+ *
252
+ * Priority for finding Sanqian executable:
253
+ * 1. customPath parameter (if provided)
254
+ * 2. Cached executable from connection.json (most reliable)
255
+ * 3. Search in standard installation locations (fallback)
238
256
  */
239
257
  launchSanqian(customPath) {
240
- const sanqianPath = this.findSanqianPath(customPath);
258
+ let sanqianPath = null;
259
+ if (customPath) {
260
+ sanqianPath = this.findSanqianPath(customPath);
261
+ } else if (this.cachedExecutable && (0, import_fs.existsSync)(this.cachedExecutable)) {
262
+ sanqianPath = this.cachedExecutable;
263
+ console.log(`[SDK] Using cached executable: ${sanqianPath}`);
264
+ } else {
265
+ sanqianPath = this.findSanqianPath();
266
+ }
241
267
  if (!sanqianPath) {
242
268
  console.error("[SDK] Sanqian executable not found");
243
269
  return false;
@@ -250,7 +276,7 @@ var DiscoveryManager = class {
250
276
  "/Contents/MacOS/Sanqian",
251
277
  ""
252
278
  );
253
- (0, import_child_process.spawn)("open", ["-a", appPath, "--args", "--hidden"], {
279
+ (0, import_child_process.spawn)("open", ["-g", "-a", appPath, "--args", "--hidden"], {
254
280
  detached: true,
255
281
  stdio: "ignore"
256
282
  }).unref();
@@ -279,6 +305,172 @@ var DiscoveryManager = class {
279
305
  }
280
306
  };
281
307
 
308
+ // src/errors.ts
309
+ var SANQIAN_WEBSITE = "https://sanqian.io";
310
+ var SDKErrorCode = /* @__PURE__ */ ((SDKErrorCode2) => {
311
+ SDKErrorCode2["NOT_INSTALLED"] = "NOT_INSTALLED";
312
+ SDKErrorCode2["NOT_RUNNING"] = "NOT_RUNNING";
313
+ SDKErrorCode2["CONNECTION_TIMEOUT"] = "CONNECTION_TIMEOUT";
314
+ SDKErrorCode2["STARTUP_TIMEOUT"] = "STARTUP_TIMEOUT";
315
+ SDKErrorCode2["REGISTRATION_FAILED"] = "REGISTRATION_FAILED";
316
+ SDKErrorCode2["REQUEST_TIMEOUT"] = "REQUEST_TIMEOUT";
317
+ SDKErrorCode2["REQUEST_FAILED"] = "REQUEST_FAILED";
318
+ SDKErrorCode2["DISCONNECTED"] = "DISCONNECTED";
319
+ SDKErrorCode2["WEBSOCKET_ERROR"] = "WEBSOCKET_ERROR";
320
+ SDKErrorCode2["AGENT_NOT_FOUND"] = "AGENT_NOT_FOUND";
321
+ SDKErrorCode2["CONVERSATION_NOT_FOUND"] = "CONVERSATION_NOT_FOUND";
322
+ SDKErrorCode2["TOOL_NOT_FOUND"] = "TOOL_NOT_FOUND";
323
+ SDKErrorCode2["TOOL_EXECUTION_TIMEOUT"] = "TOOL_EXECUTION_TIMEOUT";
324
+ return SDKErrorCode2;
325
+ })(SDKErrorCode || {});
326
+ var ErrorMessages = {
327
+ ["NOT_INSTALLED" /* NOT_INSTALLED */]: {
328
+ en: `Sanqian is not installed on this computer.`,
329
+ zh: `Sanqian \u5C1A\u672A\u5B89\u88C5\u5728\u6B64\u7535\u8111\u4E0A\u3002`,
330
+ hint: {
331
+ en: `Please download and install Sanqian from ${SANQIAN_WEBSITE}`,
332
+ zh: `\u8BF7\u8BBF\u95EE ${SANQIAN_WEBSITE} \u4E0B\u8F7D\u5B89\u88C5 Sanqian`
333
+ }
334
+ },
335
+ ["NOT_RUNNING" /* NOT_RUNNING */]: {
336
+ en: `Sanqian is not running.`,
337
+ zh: `Sanqian \u672A\u5728\u8FD0\u884C\u3002`,
338
+ hint: {
339
+ en: `Please start Sanqian first, or enable autoLaunchSanqian option in SDK config.`,
340
+ zh: `\u8BF7\u5148\u542F\u52A8 Sanqian\uFF0C\u6216\u5728 SDK \u914D\u7F6E\u4E2D\u542F\u7528 autoLaunchSanqian \u9009\u9879\u3002`
341
+ }
342
+ },
343
+ ["CONNECTION_TIMEOUT" /* CONNECTION_TIMEOUT */]: {
344
+ en: `Failed to connect to Sanqian (connection timeout).`,
345
+ zh: `\u8FDE\u63A5 Sanqian \u5931\u8D25\uFF08\u8FDE\u63A5\u8D85\u65F6\uFF09\u3002`,
346
+ hint: {
347
+ en: `Please check if Sanqian is running properly. If the problem persists, try restarting Sanqian.`,
348
+ zh: `\u8BF7\u68C0\u67E5 Sanqian \u662F\u5426\u6B63\u5E38\u8FD0\u884C\u3002\u5982\u95EE\u9898\u6301\u7EED\uFF0C\u8BF7\u5C1D\u8BD5\u91CD\u542F Sanqian\u3002`
349
+ }
350
+ },
351
+ ["STARTUP_TIMEOUT" /* STARTUP_TIMEOUT */]: {
352
+ en: `Sanqian failed to start within 2 minutes.`,
353
+ zh: `Sanqian \u5728 2 \u5206\u949F\u5185\u672A\u80FD\u542F\u52A8\u3002`,
354
+ hint: {
355
+ en: `Please try starting Sanqian manually. If it fails to start, reinstall from ${SANQIAN_WEBSITE}`,
356
+ zh: `\u8BF7\u5C1D\u8BD5\u624B\u52A8\u542F\u52A8 Sanqian\u3002\u5982\u4ECD\u65E0\u6CD5\u542F\u52A8\uFF0C\u8BF7\u4ECE ${SANQIAN_WEBSITE} \u91CD\u65B0\u5B89\u88C5\u3002`
357
+ }
358
+ },
359
+ ["REGISTRATION_FAILED" /* REGISTRATION_FAILED */]: {
360
+ en: `Failed to register with Sanqian.`,
361
+ zh: `\u5411 Sanqian \u6CE8\u518C\u5931\u8D25\u3002`,
362
+ hint: {
363
+ en: `Please check your SDK configuration (appName, tools). If the problem persists, try restarting Sanqian.`,
364
+ zh: `\u8BF7\u68C0\u67E5 SDK \u914D\u7F6E\uFF08appName\u3001tools\uFF09\u3002\u5982\u95EE\u9898\u6301\u7EED\uFF0C\u8BF7\u5C1D\u8BD5\u91CD\u542F Sanqian\u3002`
365
+ }
366
+ },
367
+ ["REQUEST_TIMEOUT" /* REQUEST_TIMEOUT */]: {
368
+ en: `Request timed out.`,
369
+ zh: `\u8BF7\u6C42\u8D85\u65F6\u3002`,
370
+ hint: {
371
+ en: `The operation took too long. Please try again.`,
372
+ zh: `\u64CD\u4F5C\u8017\u65F6\u8FC7\u957F\uFF0C\u8BF7\u91CD\u8BD5\u3002`
373
+ }
374
+ },
375
+ ["REQUEST_FAILED" /* REQUEST_FAILED */]: {
376
+ en: `Request failed.`,
377
+ zh: `\u8BF7\u6C42\u5931\u8D25\u3002`,
378
+ hint: {
379
+ en: `Please check the error details and try again.`,
380
+ zh: `\u8BF7\u68C0\u67E5\u9519\u8BEF\u8BE6\u60C5\u540E\u91CD\u8BD5\u3002`
381
+ }
382
+ },
383
+ ["DISCONNECTED" /* DISCONNECTED */]: {
384
+ en: `Disconnected from Sanqian.`,
385
+ zh: `\u4E0E Sanqian \u7684\u8FDE\u63A5\u5DF2\u65AD\u5F00\u3002`,
386
+ hint: {
387
+ en: `The SDK will automatically reconnect. If problems persist, check if Sanqian is still running.`,
388
+ zh: `SDK \u4F1A\u81EA\u52A8\u91CD\u8FDE\u3002\u5982\u95EE\u9898\u6301\u7EED\uFF0C\u8BF7\u68C0\u67E5 Sanqian \u662F\u5426\u4ECD\u5728\u8FD0\u884C\u3002`
389
+ }
390
+ },
391
+ ["WEBSOCKET_ERROR" /* WEBSOCKET_ERROR */]: {
392
+ en: `WebSocket connection error.`,
393
+ zh: `WebSocket \u8FDE\u63A5\u9519\u8BEF\u3002`,
394
+ hint: {
395
+ en: `Please check your network and firewall settings. Sanqian uses local WebSocket on port shown in settings.`,
396
+ zh: `\u8BF7\u68C0\u67E5\u7F51\u7EDC\u548C\u9632\u706B\u5899\u8BBE\u7F6E\u3002Sanqian \u4F7F\u7528\u672C\u5730 WebSocket\uFF0C\u7AEF\u53E3\u53EF\u5728\u8BBE\u7F6E\u4E2D\u67E5\u770B\u3002`
397
+ }
398
+ },
399
+ ["AGENT_NOT_FOUND" /* AGENT_NOT_FOUND */]: {
400
+ en: `Agent not found.`,
401
+ zh: `\u627E\u4E0D\u5230\u8BE5 Agent\u3002`,
402
+ hint: {
403
+ en: `Please check the agent ID. Use listAgents() to see available agents.`,
404
+ zh: `\u8BF7\u68C0\u67E5 Agent ID\u3002\u4F7F\u7528 listAgents() \u67E5\u770B\u53EF\u7528\u7684 Agent\u3002`
405
+ }
406
+ },
407
+ ["CONVERSATION_NOT_FOUND" /* CONVERSATION_NOT_FOUND */]: {
408
+ en: `Conversation not found.`,
409
+ zh: `\u627E\u4E0D\u5230\u8BE5\u5BF9\u8BDD\u3002`,
410
+ hint: {
411
+ en: `The conversation may have been deleted. Start a new conversation with startConversation().`,
412
+ zh: `\u8BE5\u5BF9\u8BDD\u53EF\u80FD\u5DF2\u88AB\u5220\u9664\u3002\u4F7F\u7528 startConversation() \u5F00\u59CB\u65B0\u5BF9\u8BDD\u3002`
413
+ }
414
+ },
415
+ ["TOOL_NOT_FOUND" /* TOOL_NOT_FOUND */]: {
416
+ en: `Tool not found.`,
417
+ zh: `\u627E\u4E0D\u5230\u8BE5\u5DE5\u5177\u3002`,
418
+ hint: {
419
+ en: `Please check that the tool is registered in your SDK config.`,
420
+ zh: `\u8BF7\u68C0\u67E5\u8BE5\u5DE5\u5177\u662F\u5426\u5DF2\u5728 SDK \u914D\u7F6E\u4E2D\u6CE8\u518C\u3002`
421
+ }
422
+ },
423
+ ["TOOL_EXECUTION_TIMEOUT" /* TOOL_EXECUTION_TIMEOUT */]: {
424
+ en: `Tool execution timed out.`,
425
+ zh: `\u5DE5\u5177\u6267\u884C\u8D85\u65F6\u3002`,
426
+ hint: {
427
+ en: `The tool took too long to execute. Consider increasing toolExecutionTimeout in SDK config.`,
428
+ zh: `\u5DE5\u5177\u6267\u884C\u65F6\u95F4\u8FC7\u957F\u3002\u53EF\u5728 SDK \u914D\u7F6E\u4E2D\u589E\u52A0 toolExecutionTimeout\u3002`
429
+ }
430
+ }
431
+ };
432
+ var SanqianSDKError = class extends Error {
433
+ code;
434
+ messageZh;
435
+ hint;
436
+ hintZh;
437
+ constructor(code, details) {
438
+ const msg = ErrorMessages[code];
439
+ const fullMessage = details ? `${msg.en} ${details}` : msg.en;
440
+ super(fullMessage);
441
+ this.name = "SanqianSDKError";
442
+ this.code = code;
443
+ this.messageZh = details ? `${msg.zh} ${details}` : msg.zh;
444
+ this.hint = msg.hint?.en;
445
+ this.hintZh = msg.hint?.zh;
446
+ }
447
+ /**
448
+ * Get full error message with hint (English)
449
+ */
450
+ getFullMessage() {
451
+ return this.hint ? `${this.message}
452
+ ${this.hint}` : this.message;
453
+ }
454
+ /**
455
+ * Get full error message with hint (Chinese)
456
+ */
457
+ getFullMessageZh() {
458
+ return this.hintZh ? `${this.messageZh}
459
+ ${this.hintZh}` : this.messageZh;
460
+ }
461
+ /**
462
+ * Get bilingual error message
463
+ */
464
+ getBilingualMessage() {
465
+ return `${this.getFullMessage()}
466
+
467
+ ${this.getFullMessageZh()}`;
468
+ }
469
+ };
470
+ function createSDKError(code, details) {
471
+ return new SanqianSDKError(code, details);
472
+ }
473
+
282
474
  // src/client.ts
283
475
  var SanqianSDK = class _SanqianSDK {
284
476
  config;
@@ -301,6 +493,8 @@ var SanqianSDK = class _SanqianSDK {
301
493
  heartbeatAckPending = false;
302
494
  missedHeartbeats = 0;
303
495
  static MAX_MISSED_HEARTBEATS = 2;
496
+ // Connection promise for deduplication (prevents multiple concurrent connect attempts)
497
+ connectingPromise = null;
304
498
  // Event listeners
305
499
  eventListeners = /* @__PURE__ */ new Map();
306
500
  constructor(config) {
@@ -326,40 +520,12 @@ var SanqianSDK = class _SanqianSDK {
326
520
  *
327
521
  * If autoLaunchSanqian is enabled and Sanqian is not running,
328
522
  * SDK will attempt to start it in hidden/tray mode.
523
+ *
524
+ * @throws Error if Sanqian executable cannot be found (when autoLaunchSanqian is enabled)
525
+ * @throws Error if connection times out after 2 minutes
329
526
  */
330
527
  async connect() {
331
- const info = this.discovery.read();
332
- if (!info) {
333
- if (this.config.autoLaunchSanqian) {
334
- console.log("[SDK] Sanqian not running, attempting to launch...");
335
- const launched = this.discovery.launchSanqian(this.config.sanqianPath);
336
- if (launched) {
337
- console.log("[SDK] Sanqian launch initiated, waiting for startup...");
338
- } else {
339
- console.warn("[SDK] Failed to launch Sanqian, will wait for manual start");
340
- }
341
- }
342
- return new Promise((resolve, reject) => {
343
- console.log("[SDK] Waiting for Sanqian...");
344
- const timeout = setTimeout(() => {
345
- this.discovery.stopWatching();
346
- reject(new Error("Sanqian connection timeout"));
347
- }, 6e4);
348
- this.discovery.startWatching(async (newInfo) => {
349
- if (newInfo) {
350
- clearTimeout(timeout);
351
- this.discovery.stopWatching();
352
- try {
353
- await this.connectWithInfo(newInfo);
354
- resolve();
355
- } catch (e) {
356
- reject(e);
357
- }
358
- }
359
- });
360
- });
361
- }
362
- await this.connectWithInfo(info);
528
+ return this.ensureReady();
363
529
  }
364
530
  /**
365
531
  * Connect with known connection info
@@ -371,7 +537,7 @@ var SanqianSDK = class _SanqianSDK {
371
537
  console.log(`[SDK] Connecting to ${url}`);
372
538
  this.ws = new import_ws.default(url);
373
539
  const connectTimeout = setTimeout(() => {
374
- reject(new Error("WebSocket connection timeout"));
540
+ reject(createSDKError("CONNECTION_TIMEOUT" /* CONNECTION_TIMEOUT */));
375
541
  this.ws?.close();
376
542
  }, 1e4);
377
543
  this.ws.on("open", async () => {
@@ -452,7 +618,7 @@ var SanqianSDK = class _SanqianSDK {
452
618
  1e4
453
619
  );
454
620
  if (!response.success) {
455
- throw new Error(response.error || "Registration failed");
621
+ throw createSDKError("REGISTRATION_FAILED" /* REGISTRATION_FAILED */, response.error);
456
622
  }
457
623
  this.state.registering = false;
458
624
  this.state.registered = true;
@@ -584,7 +750,7 @@ var SanqianSDK = class _SanqianSDK {
584
750
  this.state.registered = false;
585
751
  this.emit("disconnected", reason);
586
752
  for (const [, pending] of this.pendingRequests) {
587
- pending.reject(new Error("Disconnected"));
753
+ pending.reject(createSDKError("DISCONNECTED" /* DISCONNECTED */));
588
754
  }
589
755
  this.pendingRequests.clear();
590
756
  this.scheduleReconnect();
@@ -676,7 +842,7 @@ var SanqianSDK = class _SanqianSDK {
676
842
  return new Promise((resolve, reject) => {
677
843
  const timer = setTimeout(() => {
678
844
  this.pendingRequests.delete(id);
679
- reject(new Error("Request timeout"));
845
+ reject(createSDKError("REQUEST_TIMEOUT" /* REQUEST_TIMEOUT */));
680
846
  }, timeout);
681
847
  this.pendingRequests.set(id, {
682
848
  resolve: (value) => {
@@ -713,57 +879,73 @@ var SanqianSDK = class _SanqianSDK {
713
879
  return this.state.connected && this.state.registered;
714
880
  }
715
881
  /**
716
- * Wait for connection to be established.
717
- * Used internally by chat() and chatStream() for auto-reconnect.
718
- * Relies on background scheduleReconnect() to do the actual reconnection.
882
+ * Ensure SDK is ready for API calls.
883
+ *
884
+ * This is the unified entry point for all API methods that require a connection.
885
+ * It handles:
886
+ * - Already connected: returns immediately
887
+ * - Connection in progress: waits for existing attempt (deduplication)
888
+ * - Not connected: initiates connection (with optional auto-launch)
889
+ *
890
+ * Design pattern: gRPC wait-for-ready + ClientFactory promise deduplication
891
+ *
892
+ * @throws Error if connection fails or times out
719
893
  */
720
- async waitForConnection(timeout = 3e4) {
894
+ async ensureReady() {
721
895
  if (this.isConnected()) {
722
896
  return;
723
897
  }
724
- console.log("[SDK] Not connected, waiting for reconnection...");
725
- return new Promise((resolve, reject) => {
726
- let resolved = false;
727
- const timer = setTimeout(() => {
728
- if (!resolved) {
729
- resolved = true;
730
- reject(new Error("Connection timeout. Please ensure Sanqian is running."));
731
- }
732
- }, timeout);
733
- this.once("registered", () => {
734
- if (!resolved) {
735
- resolved = true;
736
- clearTimeout(timer);
737
- resolve();
738
- }
739
- });
740
- if (this.isConnected()) {
741
- if (!resolved) {
742
- resolved = true;
743
- clearTimeout(timer);
744
- resolve();
898
+ if (this.connectingPromise) {
899
+ console.log("[SDK] Connection already in progress, waiting...");
900
+ return this.connectingPromise;
901
+ }
902
+ this.connectingPromise = this.doFullConnect();
903
+ try {
904
+ await this.connectingPromise;
905
+ } finally {
906
+ this.connectingPromise = null;
907
+ }
908
+ }
909
+ /**
910
+ * Internal: Perform full connection flow
911
+ * Handles launching Sanqian if needed, then connecting and registering.
912
+ *
913
+ * Note: This method is protected by connectingPromise deduplication in ensureReady(),
914
+ * so there's no need for additional launch-in-progress tracking within a single instance.
915
+ */
916
+ async doFullConnect() {
917
+ console.log("[SDK] Starting full connection flow...");
918
+ let info = this.discovery.read();
919
+ if (!info) {
920
+ if (this.config.autoLaunchSanqian) {
921
+ console.log("[SDK] Sanqian not running, attempting to launch...");
922
+ const launched = this.discovery.launchSanqian(this.config.sanqianPath);
923
+ if (!launched) {
924
+ throw createSDKError("NOT_INSTALLED" /* NOT_INSTALLED */);
745
925
  }
746
- return;
926
+ console.log("[SDK] Sanqian launch initiated, waiting for startup...");
927
+ info = await this.waitForSanqianStartup();
928
+ } else {
929
+ throw createSDKError("NOT_RUNNING" /* NOT_RUNNING */);
747
930
  }
748
- if (!this.reconnectTimer) {
749
- const info = this.discovery.read();
750
- if (!info && this.config.autoLaunchSanqian) {
751
- console.log("[SDK] Sanqian not running, attempting to launch...");
752
- const launched = this.discovery.launchSanqian(this.config.sanqianPath);
753
- if (launched) {
754
- this.scheduleReconnect();
755
- }
756
- } else if (!info) {
757
- if (!resolved) {
758
- resolved = true;
759
- clearTimeout(timer);
760
- reject(new Error("Sanqian is not running. Please start it manually."));
761
- }
762
- } else {
763
- this.scheduleReconnect();
764
- }
931
+ }
932
+ await this.connectWithInfo(info);
933
+ }
934
+ /**
935
+ * Wait for Sanqian to start and connection.json to become available
936
+ */
937
+ async waitForSanqianStartup(timeout = 12e4) {
938
+ const startTime = Date.now();
939
+ const pollInterval = 500;
940
+ while (Date.now() - startTime < timeout) {
941
+ const info = this.discovery.read();
942
+ if (info) {
943
+ console.log("[SDK] Sanqian started, connection info available");
944
+ return info;
765
945
  }
766
- });
946
+ await new Promise((resolve) => setTimeout(resolve, pollInterval));
947
+ }
948
+ throw createSDKError("STARTUP_TIMEOUT" /* STARTUP_TIMEOUT */);
767
949
  }
768
950
  /**
769
951
  * Update tool list dynamically
@@ -800,9 +982,7 @@ var SanqianSDK = class _SanqianSDK {
800
982
  * @returns Full agent info (or agent_id string for backward compatibility)
801
983
  */
802
984
  async createAgent(config) {
803
- if (!this.isConnected()) {
804
- throw new Error("Not connected to Sanqian");
805
- }
985
+ await this.ensureReady();
806
986
  const msgId = this.generateId();
807
987
  const message = {
808
988
  id: msgId,
@@ -811,7 +991,7 @@ var SanqianSDK = class _SanqianSDK {
811
991
  };
812
992
  const response = await this.sendAndWait(message, msgId, 1e4);
813
993
  if (!response.success) {
814
- throw new Error(response.error || "Failed to create agent");
994
+ throw createSDKError("AGENT_NOT_FOUND" /* AGENT_NOT_FOUND */, response.error);
815
995
  }
816
996
  if (response.agent) {
817
997
  return response.agent;
@@ -827,9 +1007,7 @@ var SanqianSDK = class _SanqianSDK {
827
1007
  * List all private agents owned by this app
828
1008
  */
829
1009
  async listAgents() {
830
- if (!this.isConnected()) {
831
- throw new Error("Not connected to Sanqian");
832
- }
1010
+ await this.ensureReady();
833
1011
  const msgId = this.generateId();
834
1012
  const message = {
835
1013
  id: msgId,
@@ -845,9 +1023,7 @@ var SanqianSDK = class _SanqianSDK {
845
1023
  * Delete a private agent
846
1024
  */
847
1025
  async deleteAgent(agentId) {
848
- if (!this.isConnected()) {
849
- throw new Error("Not connected to Sanqian");
850
- }
1026
+ await this.ensureReady();
851
1027
  const msgId = this.generateId();
852
1028
  const message = {
853
1029
  id: msgId,
@@ -856,7 +1032,7 @@ var SanqianSDK = class _SanqianSDK {
856
1032
  };
857
1033
  const response = await this.sendAndWait(message, msgId, 1e4);
858
1034
  if (!response.success) {
859
- throw new Error(response.error || "Failed to delete agent");
1035
+ throw createSDKError("AGENT_NOT_FOUND" /* AGENT_NOT_FOUND */, response.error);
860
1036
  }
861
1037
  }
862
1038
  /**
@@ -868,9 +1044,7 @@ var SanqianSDK = class _SanqianSDK {
868
1044
  * @returns Updated agent info
869
1045
  */
870
1046
  async updateAgent(agentId, updates) {
871
- if (!this.isConnected()) {
872
- throw new Error("Not connected to Sanqian");
873
- }
1047
+ await this.ensureReady();
874
1048
  const msgId = this.generateId();
875
1049
  const message = {
876
1050
  id: msgId,
@@ -880,7 +1054,7 @@ var SanqianSDK = class _SanqianSDK {
880
1054
  };
881
1055
  const response = await this.sendAndWait(message, msgId, 1e4);
882
1056
  if (!response.success || !response.agent) {
883
- throw new Error(response.error || "Failed to update agent");
1057
+ throw createSDKError("AGENT_NOT_FOUND" /* AGENT_NOT_FOUND */, response.error);
884
1058
  }
885
1059
  return response.agent;
886
1060
  }
@@ -891,9 +1065,7 @@ var SanqianSDK = class _SanqianSDK {
891
1065
  * List conversations for this app
892
1066
  */
893
1067
  async listConversations(options) {
894
- if (!this.isConnected()) {
895
- throw new Error("Not connected to Sanqian");
896
- }
1068
+ await this.ensureReady();
897
1069
  const msgId = this.generateId();
898
1070
  const message = {
899
1071
  id: msgId,
@@ -915,9 +1087,7 @@ var SanqianSDK = class _SanqianSDK {
915
1087
  * Get conversation details with messages
916
1088
  */
917
1089
  async getConversation(conversationId, options) {
918
- if (!this.isConnected()) {
919
- throw new Error("Not connected to Sanqian");
920
- }
1090
+ await this.ensureReady();
921
1091
  const msgId = this.generateId();
922
1092
  const message = {
923
1093
  id: msgId,
@@ -929,7 +1099,7 @@ var SanqianSDK = class _SanqianSDK {
929
1099
  };
930
1100
  const response = await this.sendAndWait(message, msgId, 1e4);
931
1101
  if (!response.success || !response.conversation) {
932
- throw new Error(response.error || "Failed to get conversation");
1102
+ throw createSDKError("CONVERSATION_NOT_FOUND" /* CONVERSATION_NOT_FOUND */, response.error);
933
1103
  }
934
1104
  return response.conversation;
935
1105
  }
@@ -937,9 +1107,7 @@ var SanqianSDK = class _SanqianSDK {
937
1107
  * Delete a conversation
938
1108
  */
939
1109
  async deleteConversation(conversationId) {
940
- if (!this.isConnected()) {
941
- throw new Error("Not connected to Sanqian");
942
- }
1110
+ await this.ensureReady();
943
1111
  const msgId = this.generateId();
944
1112
  const message = {
945
1113
  id: msgId,
@@ -948,7 +1116,7 @@ var SanqianSDK = class _SanqianSDK {
948
1116
  };
949
1117
  const response = await this.sendAndWait(message, msgId, 1e4);
950
1118
  if (!response.success) {
951
- throw new Error(response.error || "Failed to delete conversation");
1119
+ throw createSDKError("CONVERSATION_NOT_FOUND" /* CONVERSATION_NOT_FOUND */, response.error);
952
1120
  }
953
1121
  }
954
1122
  // ============================================
@@ -969,10 +1137,7 @@ var SanqianSDK = class _SanqianSDK {
969
1137
  * @returns Chat response with assistant message and conversation ID
970
1138
  */
971
1139
  async chat(agentId, messages, options) {
972
- if (!this.isConnected()) {
973
- console.log("[SDK] Not connected, attempting to reconnect...");
974
- await this.waitForConnection();
975
- }
1140
+ await this.ensureReady();
976
1141
  const msgId = this.generateId();
977
1142
  const message = {
978
1143
  id: msgId,
@@ -989,7 +1154,11 @@ var SanqianSDK = class _SanqianSDK {
989
1154
  };
990
1155
  const response = await this.sendAndWait(message, msgId, 6e5);
991
1156
  if (!response.success) {
992
- throw new Error(response.error || "Chat request failed");
1157
+ const errorLower = (response.error || "").toLowerCase();
1158
+ if (errorLower.includes("agent") && errorLower.includes("not found")) {
1159
+ throw createSDKError("AGENT_NOT_FOUND" /* AGENT_NOT_FOUND */, response.error);
1160
+ }
1161
+ throw createSDKError("REQUEST_FAILED" /* REQUEST_FAILED */, response.error);
993
1162
  }
994
1163
  return {
995
1164
  message: response.message,
@@ -1011,10 +1180,7 @@ var SanqianSDK = class _SanqianSDK {
1011
1180
  * @returns AsyncIterable of stream events
1012
1181
  */
1013
1182
  async *chatStream(agentId, messages, options) {
1014
- if (!this.isConnected()) {
1015
- console.log("[SDK] Not connected, attempting to reconnect...");
1016
- await this.waitForConnection();
1017
- }
1183
+ await this.ensureReady();
1018
1184
  const msgId = this.generateId();
1019
1185
  const message = {
1020
1186
  id: msgId,
@@ -1140,7 +1306,7 @@ var SanqianSDK = class _SanqianSDK {
1140
1306
  }
1141
1307
  createTimeout(ms) {
1142
1308
  return new Promise((_, reject) => {
1143
- setTimeout(() => reject(new Error("Timeout")), ms);
1309
+ setTimeout(() => reject(createSDKError("TOOL_EXECUTION_TIMEOUT" /* TOOL_EXECUTION_TIMEOUT */)), ms);
1144
1310
  });
1145
1311
  }
1146
1312
  };
@@ -1224,6 +1390,11 @@ var Conversation = class {
1224
1390
  0 && (module.exports = {
1225
1391
  Conversation,
1226
1392
  DiscoveryManager,
1227
- SanqianSDK
1393
+ ErrorMessages,
1394
+ SANQIAN_WEBSITE,
1395
+ SDKErrorCode,
1396
+ SanqianSDK,
1397
+ SanqianSDKError,
1398
+ createSDKError
1228
1399
  });
1229
1400
  //# sourceMappingURL=index.js.map