@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.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
|
-
|
|
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
|
-
|
|
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(
|
|
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
|
|
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(
|
|
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(
|
|
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
|
-
*
|
|
679
|
-
*
|
|
680
|
-
*
|
|
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
|
|
851
|
+
async ensureReady() {
|
|
683
852
|
if (this.isConnected()) {
|
|
684
853
|
return;
|
|
685
854
|
}
|
|
686
|
-
|
|
687
|
-
|
|
688
|
-
|
|
689
|
-
|
|
690
|
-
|
|
691
|
-
|
|
692
|
-
|
|
693
|
-
|
|
694
|
-
|
|
695
|
-
|
|
696
|
-
|
|
697
|
-
|
|
698
|
-
|
|
699
|
-
|
|
700
|
-
|
|
701
|
-
|
|
702
|
-
|
|
703
|
-
|
|
704
|
-
|
|
705
|
-
|
|
706
|
-
|
|
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
|
-
|
|
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
|
-
|
|
711
|
-
|
|
712
|
-
|
|
713
|
-
|
|
714
|
-
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
|
|
718
|
-
|
|
719
|
-
|
|
720
|
-
|
|
721
|
-
|
|
722
|
-
|
|
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
|
-
|
|
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
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|
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
|
-
|
|
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
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|
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
|
-
|
|
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
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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(
|
|
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
|
-
|
|
1349
|
+
ErrorMessages,
|
|
1350
|
+
SANQIAN_WEBSITE,
|
|
1351
|
+
SDKErrorCode,
|
|
1352
|
+
SanqianSDK,
|
|
1353
|
+
SanqianSDKError,
|
|
1354
|
+
createSDKError
|
|
1189
1355
|
};
|
|
1190
1356
|
//# sourceMappingURL=index.mjs.map
|