@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.d.mts +104 -5
- package/dist/index.d.ts +104 -5
- package/dist/index.js +291 -120
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +285 -119
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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(
|
|
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
|
|
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(
|
|
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(
|
|
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
|
-
*
|
|
717
|
-
*
|
|
718
|
-
*
|
|
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
|
|
894
|
+
async ensureReady() {
|
|
721
895
|
if (this.isConnected()) {
|
|
722
896
|
return;
|
|
723
897
|
}
|
|
724
|
-
|
|
725
|
-
|
|
726
|
-
|
|
727
|
-
|
|
728
|
-
|
|
729
|
-
|
|
730
|
-
|
|
731
|
-
|
|
732
|
-
|
|
733
|
-
|
|
734
|
-
|
|
735
|
-
|
|
736
|
-
|
|
737
|
-
|
|
738
|
-
|
|
739
|
-
|
|
740
|
-
|
|
741
|
-
|
|
742
|
-
|
|
743
|
-
|
|
744
|
-
|
|
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
|
-
|
|
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
|
-
|
|
749
|
-
|
|
750
|
-
|
|
751
|
-
|
|
752
|
-
|
|
753
|
-
|
|
754
|
-
|
|
755
|
-
|
|
756
|
-
|
|
757
|
-
|
|
758
|
-
|
|
759
|
-
|
|
760
|
-
|
|
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
|
-
|
|
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
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|
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
|
-
|
|
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
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|
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
|
-
|
|
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
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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(
|
|
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
|
-
|
|
1393
|
+
ErrorMessages,
|
|
1394
|
+
SANQIAN_WEBSITE,
|
|
1395
|
+
SDKErrorCode,
|
|
1396
|
+
SanqianSDK,
|
|
1397
|
+
SanqianSDKError,
|
|
1398
|
+
createSDKError
|
|
1228
1399
|
});
|
|
1229
1400
|
//# sourceMappingURL=index.js.map
|