@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.mjs CHANGED
@@ -11,6 +11,11 @@ var DiscoveryManager = class {
11
11
  watcher = null;
12
12
  onChange = null;
13
13
  pollInterval = null;
14
+ /**
15
+ * Cached executable path from last successful connection.json read.
16
+ * Persists even when Sanqian is not running, for use in auto-launch.
17
+ */
18
+ cachedExecutable = null;
14
19
  /**
15
20
  * Get the path to connection.json
16
21
  */
@@ -36,6 +41,9 @@ var DiscoveryManager = class {
36
41
  if (!info.port || !info.token || !info.pid) {
37
42
  return null;
38
43
  }
44
+ if (info.executable) {
45
+ this.cachedExecutable = info.executable;
46
+ }
39
47
  if (!this.isProcessRunning(info.pid)) {
40
48
  return null;
41
49
  }
@@ -197,9 +205,22 @@ var DiscoveryManager = class {
197
205
  /**
198
206
  * Launch Sanqian in hidden/tray mode
199
207
  * Returns true if launch was initiated successfully
208
+ *
209
+ * Priority for finding Sanqian executable:
210
+ * 1. customPath parameter (if provided)
211
+ * 2. Cached executable from connection.json (most reliable)
212
+ * 3. Search in standard installation locations (fallback)
200
213
  */
201
214
  launchSanqian(customPath) {
202
- const sanqianPath = this.findSanqianPath(customPath);
215
+ let sanqianPath = null;
216
+ if (customPath) {
217
+ sanqianPath = this.findSanqianPath(customPath);
218
+ } else if (this.cachedExecutable && existsSync(this.cachedExecutable)) {
219
+ sanqianPath = this.cachedExecutable;
220
+ console.log(`[SDK] Using cached executable: ${sanqianPath}`);
221
+ } else {
222
+ sanqianPath = this.findSanqianPath();
223
+ }
203
224
  if (!sanqianPath) {
204
225
  console.error("[SDK] Sanqian executable not found");
205
226
  return false;
@@ -212,7 +233,7 @@ var DiscoveryManager = class {
212
233
  "/Contents/MacOS/Sanqian",
213
234
  ""
214
235
  );
215
- spawn("open", ["-a", appPath, "--args", "--hidden"], {
236
+ spawn("open", ["-g", "-a", appPath, "--args", "--hidden"], {
216
237
  detached: true,
217
238
  stdio: "ignore"
218
239
  }).unref();
@@ -241,6 +262,172 @@ var DiscoveryManager = class {
241
262
  }
242
263
  };
243
264
 
265
+ // src/errors.ts
266
+ var SANQIAN_WEBSITE = "https://sanqian.io";
267
+ var SDKErrorCode = /* @__PURE__ */ ((SDKErrorCode2) => {
268
+ SDKErrorCode2["NOT_INSTALLED"] = "NOT_INSTALLED";
269
+ SDKErrorCode2["NOT_RUNNING"] = "NOT_RUNNING";
270
+ SDKErrorCode2["CONNECTION_TIMEOUT"] = "CONNECTION_TIMEOUT";
271
+ SDKErrorCode2["STARTUP_TIMEOUT"] = "STARTUP_TIMEOUT";
272
+ SDKErrorCode2["REGISTRATION_FAILED"] = "REGISTRATION_FAILED";
273
+ SDKErrorCode2["REQUEST_TIMEOUT"] = "REQUEST_TIMEOUT";
274
+ SDKErrorCode2["REQUEST_FAILED"] = "REQUEST_FAILED";
275
+ SDKErrorCode2["DISCONNECTED"] = "DISCONNECTED";
276
+ SDKErrorCode2["WEBSOCKET_ERROR"] = "WEBSOCKET_ERROR";
277
+ SDKErrorCode2["AGENT_NOT_FOUND"] = "AGENT_NOT_FOUND";
278
+ SDKErrorCode2["CONVERSATION_NOT_FOUND"] = "CONVERSATION_NOT_FOUND";
279
+ SDKErrorCode2["TOOL_NOT_FOUND"] = "TOOL_NOT_FOUND";
280
+ SDKErrorCode2["TOOL_EXECUTION_TIMEOUT"] = "TOOL_EXECUTION_TIMEOUT";
281
+ return SDKErrorCode2;
282
+ })(SDKErrorCode || {});
283
+ var ErrorMessages = {
284
+ ["NOT_INSTALLED" /* NOT_INSTALLED */]: {
285
+ en: `Sanqian is not installed on this computer.`,
286
+ zh: `Sanqian \u5C1A\u672A\u5B89\u88C5\u5728\u6B64\u7535\u8111\u4E0A\u3002`,
287
+ hint: {
288
+ en: `Please download and install Sanqian from ${SANQIAN_WEBSITE}`,
289
+ zh: `\u8BF7\u8BBF\u95EE ${SANQIAN_WEBSITE} \u4E0B\u8F7D\u5B89\u88C5 Sanqian`
290
+ }
291
+ },
292
+ ["NOT_RUNNING" /* NOT_RUNNING */]: {
293
+ en: `Sanqian is not running.`,
294
+ zh: `Sanqian \u672A\u5728\u8FD0\u884C\u3002`,
295
+ hint: {
296
+ en: `Please start Sanqian first, or enable autoLaunchSanqian option in SDK config.`,
297
+ zh: `\u8BF7\u5148\u542F\u52A8 Sanqian\uFF0C\u6216\u5728 SDK \u914D\u7F6E\u4E2D\u542F\u7528 autoLaunchSanqian \u9009\u9879\u3002`
298
+ }
299
+ },
300
+ ["CONNECTION_TIMEOUT" /* CONNECTION_TIMEOUT */]: {
301
+ en: `Failed to connect to Sanqian (connection timeout).`,
302
+ zh: `\u8FDE\u63A5 Sanqian \u5931\u8D25\uFF08\u8FDE\u63A5\u8D85\u65F6\uFF09\u3002`,
303
+ hint: {
304
+ en: `Please check if Sanqian is running properly. If the problem persists, try restarting Sanqian.`,
305
+ 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`
306
+ }
307
+ },
308
+ ["STARTUP_TIMEOUT" /* STARTUP_TIMEOUT */]: {
309
+ en: `Sanqian failed to start within 2 minutes.`,
310
+ zh: `Sanqian \u5728 2 \u5206\u949F\u5185\u672A\u80FD\u542F\u52A8\u3002`,
311
+ hint: {
312
+ en: `Please try starting Sanqian manually. If it fails to start, reinstall from ${SANQIAN_WEBSITE}`,
313
+ 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`
314
+ }
315
+ },
316
+ ["REGISTRATION_FAILED" /* REGISTRATION_FAILED */]: {
317
+ en: `Failed to register with Sanqian.`,
318
+ zh: `\u5411 Sanqian \u6CE8\u518C\u5931\u8D25\u3002`,
319
+ hint: {
320
+ en: `Please check your SDK configuration (appName, tools). If the problem persists, try restarting Sanqian.`,
321
+ zh: `\u8BF7\u68C0\u67E5 SDK \u914D\u7F6E\uFF08appName\u3001tools\uFF09\u3002\u5982\u95EE\u9898\u6301\u7EED\uFF0C\u8BF7\u5C1D\u8BD5\u91CD\u542F Sanqian\u3002`
322
+ }
323
+ },
324
+ ["REQUEST_TIMEOUT" /* REQUEST_TIMEOUT */]: {
325
+ en: `Request timed out.`,
326
+ zh: `\u8BF7\u6C42\u8D85\u65F6\u3002`,
327
+ hint: {
328
+ en: `The operation took too long. Please try again.`,
329
+ zh: `\u64CD\u4F5C\u8017\u65F6\u8FC7\u957F\uFF0C\u8BF7\u91CD\u8BD5\u3002`
330
+ }
331
+ },
332
+ ["REQUEST_FAILED" /* REQUEST_FAILED */]: {
333
+ en: `Request failed.`,
334
+ zh: `\u8BF7\u6C42\u5931\u8D25\u3002`,
335
+ hint: {
336
+ en: `Please check the error details and try again.`,
337
+ zh: `\u8BF7\u68C0\u67E5\u9519\u8BEF\u8BE6\u60C5\u540E\u91CD\u8BD5\u3002`
338
+ }
339
+ },
340
+ ["DISCONNECTED" /* DISCONNECTED */]: {
341
+ en: `Disconnected from Sanqian.`,
342
+ zh: `\u4E0E Sanqian \u7684\u8FDE\u63A5\u5DF2\u65AD\u5F00\u3002`,
343
+ hint: {
344
+ en: `The SDK will automatically reconnect. If problems persist, check if Sanqian is still running.`,
345
+ 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`
346
+ }
347
+ },
348
+ ["WEBSOCKET_ERROR" /* WEBSOCKET_ERROR */]: {
349
+ en: `WebSocket connection error.`,
350
+ zh: `WebSocket \u8FDE\u63A5\u9519\u8BEF\u3002`,
351
+ hint: {
352
+ en: `Please check your network and firewall settings. Sanqian uses local WebSocket on port shown in settings.`,
353
+ 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`
354
+ }
355
+ },
356
+ ["AGENT_NOT_FOUND" /* AGENT_NOT_FOUND */]: {
357
+ en: `Agent not found.`,
358
+ zh: `\u627E\u4E0D\u5230\u8BE5 Agent\u3002`,
359
+ hint: {
360
+ en: `Please check the agent ID. Use listAgents() to see available agents.`,
361
+ zh: `\u8BF7\u68C0\u67E5 Agent ID\u3002\u4F7F\u7528 listAgents() \u67E5\u770B\u53EF\u7528\u7684 Agent\u3002`
362
+ }
363
+ },
364
+ ["CONVERSATION_NOT_FOUND" /* CONVERSATION_NOT_FOUND */]: {
365
+ en: `Conversation not found.`,
366
+ zh: `\u627E\u4E0D\u5230\u8BE5\u5BF9\u8BDD\u3002`,
367
+ hint: {
368
+ en: `The conversation may have been deleted. Start a new conversation with startConversation().`,
369
+ zh: `\u8BE5\u5BF9\u8BDD\u53EF\u80FD\u5DF2\u88AB\u5220\u9664\u3002\u4F7F\u7528 startConversation() \u5F00\u59CB\u65B0\u5BF9\u8BDD\u3002`
370
+ }
371
+ },
372
+ ["TOOL_NOT_FOUND" /* TOOL_NOT_FOUND */]: {
373
+ en: `Tool not found.`,
374
+ zh: `\u627E\u4E0D\u5230\u8BE5\u5DE5\u5177\u3002`,
375
+ hint: {
376
+ en: `Please check that the tool is registered in your SDK config.`,
377
+ zh: `\u8BF7\u68C0\u67E5\u8BE5\u5DE5\u5177\u662F\u5426\u5DF2\u5728 SDK \u914D\u7F6E\u4E2D\u6CE8\u518C\u3002`
378
+ }
379
+ },
380
+ ["TOOL_EXECUTION_TIMEOUT" /* TOOL_EXECUTION_TIMEOUT */]: {
381
+ en: `Tool execution timed out.`,
382
+ zh: `\u5DE5\u5177\u6267\u884C\u8D85\u65F6\u3002`,
383
+ hint: {
384
+ en: `The tool took too long to execute. Consider increasing toolExecutionTimeout in SDK config.`,
385
+ zh: `\u5DE5\u5177\u6267\u884C\u65F6\u95F4\u8FC7\u957F\u3002\u53EF\u5728 SDK \u914D\u7F6E\u4E2D\u589E\u52A0 toolExecutionTimeout\u3002`
386
+ }
387
+ }
388
+ };
389
+ var SanqianSDKError = class extends Error {
390
+ code;
391
+ messageZh;
392
+ hint;
393
+ hintZh;
394
+ constructor(code, details) {
395
+ const msg = ErrorMessages[code];
396
+ const fullMessage = details ? `${msg.en} ${details}` : msg.en;
397
+ super(fullMessage);
398
+ this.name = "SanqianSDKError";
399
+ this.code = code;
400
+ this.messageZh = details ? `${msg.zh} ${details}` : msg.zh;
401
+ this.hint = msg.hint?.en;
402
+ this.hintZh = msg.hint?.zh;
403
+ }
404
+ /**
405
+ * Get full error message with hint (English)
406
+ */
407
+ getFullMessage() {
408
+ return this.hint ? `${this.message}
409
+ ${this.hint}` : this.message;
410
+ }
411
+ /**
412
+ * Get full error message with hint (Chinese)
413
+ */
414
+ getFullMessageZh() {
415
+ return this.hintZh ? `${this.messageZh}
416
+ ${this.hintZh}` : this.messageZh;
417
+ }
418
+ /**
419
+ * Get bilingual error message
420
+ */
421
+ getBilingualMessage() {
422
+ return `${this.getFullMessage()}
423
+
424
+ ${this.getFullMessageZh()}`;
425
+ }
426
+ };
427
+ function createSDKError(code, details) {
428
+ return new SanqianSDKError(code, details);
429
+ }
430
+
244
431
  // src/client.ts
245
432
  var SanqianSDK = class _SanqianSDK {
246
433
  config;
@@ -263,6 +450,8 @@ var SanqianSDK = class _SanqianSDK {
263
450
  heartbeatAckPending = false;
264
451
  missedHeartbeats = 0;
265
452
  static MAX_MISSED_HEARTBEATS = 2;
453
+ // Connection promise for deduplication (prevents multiple concurrent connect attempts)
454
+ connectingPromise = null;
266
455
  // Event listeners
267
456
  eventListeners = /* @__PURE__ */ new Map();
268
457
  constructor(config) {
@@ -288,40 +477,12 @@ var SanqianSDK = class _SanqianSDK {
288
477
  *
289
478
  * If autoLaunchSanqian is enabled and Sanqian is not running,
290
479
  * SDK will attempt to start it in hidden/tray mode.
480
+ *
481
+ * @throws Error if Sanqian executable cannot be found (when autoLaunchSanqian is enabled)
482
+ * @throws Error if connection times out after 2 minutes
291
483
  */
292
484
  async connect() {
293
- const info = this.discovery.read();
294
- if (!info) {
295
- if (this.config.autoLaunchSanqian) {
296
- console.log("[SDK] Sanqian not running, attempting to launch...");
297
- const launched = this.discovery.launchSanqian(this.config.sanqianPath);
298
- if (launched) {
299
- console.log("[SDK] Sanqian launch initiated, waiting for startup...");
300
- } else {
301
- console.warn("[SDK] Failed to launch Sanqian, will wait for manual start");
302
- }
303
- }
304
- return new Promise((resolve, reject) => {
305
- console.log("[SDK] Waiting for Sanqian...");
306
- const timeout = setTimeout(() => {
307
- this.discovery.stopWatching();
308
- reject(new Error("Sanqian connection timeout"));
309
- }, 6e4);
310
- this.discovery.startWatching(async (newInfo) => {
311
- if (newInfo) {
312
- clearTimeout(timeout);
313
- this.discovery.stopWatching();
314
- try {
315
- await this.connectWithInfo(newInfo);
316
- resolve();
317
- } catch (e) {
318
- reject(e);
319
- }
320
- }
321
- });
322
- });
323
- }
324
- await this.connectWithInfo(info);
485
+ return this.ensureReady();
325
486
  }
326
487
  /**
327
488
  * Connect with known connection info
@@ -333,7 +494,7 @@ var SanqianSDK = class _SanqianSDK {
333
494
  console.log(`[SDK] Connecting to ${url}`);
334
495
  this.ws = new WebSocket(url);
335
496
  const connectTimeout = setTimeout(() => {
336
- reject(new Error("WebSocket connection timeout"));
497
+ reject(createSDKError("CONNECTION_TIMEOUT" /* CONNECTION_TIMEOUT */));
337
498
  this.ws?.close();
338
499
  }, 1e4);
339
500
  this.ws.on("open", async () => {
@@ -414,7 +575,7 @@ var SanqianSDK = class _SanqianSDK {
414
575
  1e4
415
576
  );
416
577
  if (!response.success) {
417
- throw new Error(response.error || "Registration failed");
578
+ throw createSDKError("REGISTRATION_FAILED" /* REGISTRATION_FAILED */, response.error);
418
579
  }
419
580
  this.state.registering = false;
420
581
  this.state.registered = true;
@@ -546,7 +707,7 @@ var SanqianSDK = class _SanqianSDK {
546
707
  this.state.registered = false;
547
708
  this.emit("disconnected", reason);
548
709
  for (const [, pending] of this.pendingRequests) {
549
- pending.reject(new Error("Disconnected"));
710
+ pending.reject(createSDKError("DISCONNECTED" /* DISCONNECTED */));
550
711
  }
551
712
  this.pendingRequests.clear();
552
713
  this.scheduleReconnect();
@@ -638,7 +799,7 @@ var SanqianSDK = class _SanqianSDK {
638
799
  return new Promise((resolve, reject) => {
639
800
  const timer = setTimeout(() => {
640
801
  this.pendingRequests.delete(id);
641
- reject(new Error("Request timeout"));
802
+ reject(createSDKError("REQUEST_TIMEOUT" /* REQUEST_TIMEOUT */));
642
803
  }, timeout);
643
804
  this.pendingRequests.set(id, {
644
805
  resolve: (value) => {
@@ -675,57 +836,73 @@ var SanqianSDK = class _SanqianSDK {
675
836
  return this.state.connected && this.state.registered;
676
837
  }
677
838
  /**
678
- * Wait for connection to be established.
679
- * Used internally by chat() and chatStream() for auto-reconnect.
680
- * Relies on background scheduleReconnect() to do the actual reconnection.
839
+ * Ensure SDK is ready for API calls.
840
+ *
841
+ * This is the unified entry point for all API methods that require a connection.
842
+ * It handles:
843
+ * - Already connected: returns immediately
844
+ * - Connection in progress: waits for existing attempt (deduplication)
845
+ * - Not connected: initiates connection (with optional auto-launch)
846
+ *
847
+ * Design pattern: gRPC wait-for-ready + ClientFactory promise deduplication
848
+ *
849
+ * @throws Error if connection fails or times out
681
850
  */
682
- async waitForConnection(timeout = 3e4) {
851
+ async ensureReady() {
683
852
  if (this.isConnected()) {
684
853
  return;
685
854
  }
686
- console.log("[SDK] Not connected, waiting for reconnection...");
687
- return new Promise((resolve, reject) => {
688
- let resolved = false;
689
- const timer = setTimeout(() => {
690
- if (!resolved) {
691
- resolved = true;
692
- reject(new Error("Connection timeout. Please ensure Sanqian is running."));
693
- }
694
- }, timeout);
695
- this.once("registered", () => {
696
- if (!resolved) {
697
- resolved = true;
698
- clearTimeout(timer);
699
- resolve();
700
- }
701
- });
702
- if (this.isConnected()) {
703
- if (!resolved) {
704
- resolved = true;
705
- clearTimeout(timer);
706
- resolve();
855
+ if (this.connectingPromise) {
856
+ console.log("[SDK] Connection already in progress, waiting...");
857
+ return this.connectingPromise;
858
+ }
859
+ this.connectingPromise = this.doFullConnect();
860
+ try {
861
+ await this.connectingPromise;
862
+ } finally {
863
+ this.connectingPromise = null;
864
+ }
865
+ }
866
+ /**
867
+ * Internal: Perform full connection flow
868
+ * Handles launching Sanqian if needed, then connecting and registering.
869
+ *
870
+ * Note: This method is protected by connectingPromise deduplication in ensureReady(),
871
+ * so there's no need for additional launch-in-progress tracking within a single instance.
872
+ */
873
+ async doFullConnect() {
874
+ console.log("[SDK] Starting full connection flow...");
875
+ let info = this.discovery.read();
876
+ if (!info) {
877
+ if (this.config.autoLaunchSanqian) {
878
+ console.log("[SDK] Sanqian not running, attempting to launch...");
879
+ const launched = this.discovery.launchSanqian(this.config.sanqianPath);
880
+ if (!launched) {
881
+ throw createSDKError("NOT_INSTALLED" /* NOT_INSTALLED */);
707
882
  }
708
- return;
883
+ console.log("[SDK] Sanqian launch initiated, waiting for startup...");
884
+ info = await this.waitForSanqianStartup();
885
+ } else {
886
+ throw createSDKError("NOT_RUNNING" /* NOT_RUNNING */);
709
887
  }
710
- if (!this.reconnectTimer) {
711
- const info = this.discovery.read();
712
- if (!info && this.config.autoLaunchSanqian) {
713
- console.log("[SDK] Sanqian not running, attempting to launch...");
714
- const launched = this.discovery.launchSanqian(this.config.sanqianPath);
715
- if (launched) {
716
- this.scheduleReconnect();
717
- }
718
- } else if (!info) {
719
- if (!resolved) {
720
- resolved = true;
721
- clearTimeout(timer);
722
- reject(new Error("Sanqian is not running. Please start it manually."));
723
- }
724
- } else {
725
- this.scheduleReconnect();
726
- }
888
+ }
889
+ await this.connectWithInfo(info);
890
+ }
891
+ /**
892
+ * Wait for Sanqian to start and connection.json to become available
893
+ */
894
+ async waitForSanqianStartup(timeout = 12e4) {
895
+ const startTime = Date.now();
896
+ const pollInterval = 500;
897
+ while (Date.now() - startTime < timeout) {
898
+ const info = this.discovery.read();
899
+ if (info) {
900
+ console.log("[SDK] Sanqian started, connection info available");
901
+ return info;
727
902
  }
728
- });
903
+ await new Promise((resolve) => setTimeout(resolve, pollInterval));
904
+ }
905
+ throw createSDKError("STARTUP_TIMEOUT" /* STARTUP_TIMEOUT */);
729
906
  }
730
907
  /**
731
908
  * Update tool list dynamically
@@ -762,9 +939,7 @@ var SanqianSDK = class _SanqianSDK {
762
939
  * @returns Full agent info (or agent_id string for backward compatibility)
763
940
  */
764
941
  async createAgent(config) {
765
- if (!this.isConnected()) {
766
- throw new Error("Not connected to Sanqian");
767
- }
942
+ await this.ensureReady();
768
943
  const msgId = this.generateId();
769
944
  const message = {
770
945
  id: msgId,
@@ -773,7 +948,7 @@ var SanqianSDK = class _SanqianSDK {
773
948
  };
774
949
  const response = await this.sendAndWait(message, msgId, 1e4);
775
950
  if (!response.success) {
776
- throw new Error(response.error || "Failed to create agent");
951
+ throw createSDKError("AGENT_NOT_FOUND" /* AGENT_NOT_FOUND */, response.error);
777
952
  }
778
953
  if (response.agent) {
779
954
  return response.agent;
@@ -789,9 +964,7 @@ var SanqianSDK = class _SanqianSDK {
789
964
  * List all private agents owned by this app
790
965
  */
791
966
  async listAgents() {
792
- if (!this.isConnected()) {
793
- throw new Error("Not connected to Sanqian");
794
- }
967
+ await this.ensureReady();
795
968
  const msgId = this.generateId();
796
969
  const message = {
797
970
  id: msgId,
@@ -807,9 +980,7 @@ var SanqianSDK = class _SanqianSDK {
807
980
  * Delete a private agent
808
981
  */
809
982
  async deleteAgent(agentId) {
810
- if (!this.isConnected()) {
811
- throw new Error("Not connected to Sanqian");
812
- }
983
+ await this.ensureReady();
813
984
  const msgId = this.generateId();
814
985
  const message = {
815
986
  id: msgId,
@@ -818,7 +989,7 @@ var SanqianSDK = class _SanqianSDK {
818
989
  };
819
990
  const response = await this.sendAndWait(message, msgId, 1e4);
820
991
  if (!response.success) {
821
- throw new Error(response.error || "Failed to delete agent");
992
+ throw createSDKError("AGENT_NOT_FOUND" /* AGENT_NOT_FOUND */, response.error);
822
993
  }
823
994
  }
824
995
  /**
@@ -830,9 +1001,7 @@ var SanqianSDK = class _SanqianSDK {
830
1001
  * @returns Updated agent info
831
1002
  */
832
1003
  async updateAgent(agentId, updates) {
833
- if (!this.isConnected()) {
834
- throw new Error("Not connected to Sanqian");
835
- }
1004
+ await this.ensureReady();
836
1005
  const msgId = this.generateId();
837
1006
  const message = {
838
1007
  id: msgId,
@@ -842,7 +1011,7 @@ var SanqianSDK = class _SanqianSDK {
842
1011
  };
843
1012
  const response = await this.sendAndWait(message, msgId, 1e4);
844
1013
  if (!response.success || !response.agent) {
845
- throw new Error(response.error || "Failed to update agent");
1014
+ throw createSDKError("AGENT_NOT_FOUND" /* AGENT_NOT_FOUND */, response.error);
846
1015
  }
847
1016
  return response.agent;
848
1017
  }
@@ -853,9 +1022,7 @@ var SanqianSDK = class _SanqianSDK {
853
1022
  * List conversations for this app
854
1023
  */
855
1024
  async listConversations(options) {
856
- if (!this.isConnected()) {
857
- throw new Error("Not connected to Sanqian");
858
- }
1025
+ await this.ensureReady();
859
1026
  const msgId = this.generateId();
860
1027
  const message = {
861
1028
  id: msgId,
@@ -877,9 +1044,7 @@ var SanqianSDK = class _SanqianSDK {
877
1044
  * Get conversation details with messages
878
1045
  */
879
1046
  async getConversation(conversationId, options) {
880
- if (!this.isConnected()) {
881
- throw new Error("Not connected to Sanqian");
882
- }
1047
+ await this.ensureReady();
883
1048
  const msgId = this.generateId();
884
1049
  const message = {
885
1050
  id: msgId,
@@ -891,7 +1056,7 @@ var SanqianSDK = class _SanqianSDK {
891
1056
  };
892
1057
  const response = await this.sendAndWait(message, msgId, 1e4);
893
1058
  if (!response.success || !response.conversation) {
894
- throw new Error(response.error || "Failed to get conversation");
1059
+ throw createSDKError("CONVERSATION_NOT_FOUND" /* CONVERSATION_NOT_FOUND */, response.error);
895
1060
  }
896
1061
  return response.conversation;
897
1062
  }
@@ -899,9 +1064,7 @@ var SanqianSDK = class _SanqianSDK {
899
1064
  * Delete a conversation
900
1065
  */
901
1066
  async deleteConversation(conversationId) {
902
- if (!this.isConnected()) {
903
- throw new Error("Not connected to Sanqian");
904
- }
1067
+ await this.ensureReady();
905
1068
  const msgId = this.generateId();
906
1069
  const message = {
907
1070
  id: msgId,
@@ -910,7 +1073,7 @@ var SanqianSDK = class _SanqianSDK {
910
1073
  };
911
1074
  const response = await this.sendAndWait(message, msgId, 1e4);
912
1075
  if (!response.success) {
913
- throw new Error(response.error || "Failed to delete conversation");
1076
+ throw createSDKError("CONVERSATION_NOT_FOUND" /* CONVERSATION_NOT_FOUND */, response.error);
914
1077
  }
915
1078
  }
916
1079
  // ============================================
@@ -931,10 +1094,7 @@ var SanqianSDK = class _SanqianSDK {
931
1094
  * @returns Chat response with assistant message and conversation ID
932
1095
  */
933
1096
  async chat(agentId, messages, options) {
934
- if (!this.isConnected()) {
935
- console.log("[SDK] Not connected, attempting to reconnect...");
936
- await this.waitForConnection();
937
- }
1097
+ await this.ensureReady();
938
1098
  const msgId = this.generateId();
939
1099
  const message = {
940
1100
  id: msgId,
@@ -951,7 +1111,11 @@ var SanqianSDK = class _SanqianSDK {
951
1111
  };
952
1112
  const response = await this.sendAndWait(message, msgId, 6e5);
953
1113
  if (!response.success) {
954
- throw new Error(response.error || "Chat request failed");
1114
+ const errorLower = (response.error || "").toLowerCase();
1115
+ if (errorLower.includes("agent") && errorLower.includes("not found")) {
1116
+ throw createSDKError("AGENT_NOT_FOUND" /* AGENT_NOT_FOUND */, response.error);
1117
+ }
1118
+ throw createSDKError("REQUEST_FAILED" /* REQUEST_FAILED */, response.error);
955
1119
  }
956
1120
  return {
957
1121
  message: response.message,
@@ -973,10 +1137,7 @@ var SanqianSDK = class _SanqianSDK {
973
1137
  * @returns AsyncIterable of stream events
974
1138
  */
975
1139
  async *chatStream(agentId, messages, options) {
976
- if (!this.isConnected()) {
977
- console.log("[SDK] Not connected, attempting to reconnect...");
978
- await this.waitForConnection();
979
- }
1140
+ await this.ensureReady();
980
1141
  const msgId = this.generateId();
981
1142
  const message = {
982
1143
  id: msgId,
@@ -1102,7 +1263,7 @@ var SanqianSDK = class _SanqianSDK {
1102
1263
  }
1103
1264
  createTimeout(ms) {
1104
1265
  return new Promise((_, reject) => {
1105
- setTimeout(() => reject(new Error("Timeout")), ms);
1266
+ setTimeout(() => reject(createSDKError("TOOL_EXECUTION_TIMEOUT" /* TOOL_EXECUTION_TIMEOUT */)), ms);
1106
1267
  });
1107
1268
  }
1108
1269
  };
@@ -1185,6 +1346,11 @@ var Conversation = class {
1185
1346
  export {
1186
1347
  Conversation,
1187
1348
  DiscoveryManager,
1188
- SanqianSDK
1349
+ ErrorMessages,
1350
+ SANQIAN_WEBSITE,
1351
+ SDKErrorCode,
1352
+ SanqianSDK,
1353
+ SanqianSDKError,
1354
+ createSDKError
1189
1355
  };
1190
1356
  //# sourceMappingURL=index.mjs.map