@trustgraph/client 1.7.2 → 2.0.3
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/auth/auth-api.d.ts +26 -0
- package/dist/auth/auth-api.d.ts.map +1 -0
- package/dist/index.cjs +345 -64
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.esm.js +340 -64
- package/dist/index.esm.js.map +1 -1
- package/dist/models/messages.d.ts +31 -2
- package/dist/models/messages.d.ts.map +1 -1
- package/dist/models/namespaces.d.ts +2 -1
- package/dist/models/namespaces.d.ts.map +1 -1
- package/dist/socket/service-call-multi.d.ts +3 -1
- package/dist/socket/service-call-multi.d.ts.map +1 -1
- package/dist/socket/service-call.d.ts +1 -0
- package/dist/socket/service-call.d.ts.map +1 -1
- package/dist/socket/trustgraph-socket.d.ts +58 -14
- package/dist/socket/trustgraph-socket.d.ts.map +1 -1
- package/package.json +6 -6
package/dist/index.esm.js
CHANGED
|
@@ -8,7 +8,8 @@ const TG_QUERY = TG + "query";
|
|
|
8
8
|
const TG_EDGE_COUNT = TG + "edgeCount";
|
|
9
9
|
const TG_SELECTED_EDGE = TG + "selectedEdge";
|
|
10
10
|
const TG_EDGE = TG + "edge";
|
|
11
|
-
const
|
|
11
|
+
const TG_CONCEPT = TG + "concept";
|
|
12
|
+
const TG_SCORE = TG + "score";
|
|
12
13
|
const TG_CONTENT = TG + "content";
|
|
13
14
|
const TG_REIFIES = TG + "reifies";
|
|
14
15
|
const TG_DOCUMENT = TG + "document";
|
|
@@ -74,18 +75,17 @@ class ServiceCallMulti {
|
|
|
74
75
|
}
|
|
75
76
|
}
|
|
76
77
|
/**
|
|
77
|
-
* Called when socket
|
|
78
|
+
* Called when socket reconnects. Streaming requests cannot be resumed
|
|
79
|
+
* after a disconnect — the backend state is gone — so fail immediately.
|
|
78
80
|
*/
|
|
79
81
|
retryNow() {
|
|
80
82
|
if (this.complete)
|
|
81
83
|
return;
|
|
82
|
-
// Clear any pending backoff timer
|
|
83
84
|
clearTimeout(this.timeoutId);
|
|
84
85
|
this.timeoutId = undefined;
|
|
85
|
-
|
|
86
|
-
this.
|
|
87
|
-
|
|
88
|
-
this.attempt();
|
|
86
|
+
this.complete = true;
|
|
87
|
+
delete this.socket.inflight[this.mid];
|
|
88
|
+
this.error("Connection lost during streaming request");
|
|
89
89
|
}
|
|
90
90
|
onTimeout() {
|
|
91
91
|
if (this.complete == true)
|
|
@@ -106,8 +106,11 @@ class ServiceCallMulti {
|
|
|
106
106
|
this.error("Ran out of retries");
|
|
107
107
|
return; // Exit early - no more attempts
|
|
108
108
|
}
|
|
109
|
-
// Check if WebSocket connection is available and
|
|
110
|
-
|
|
109
|
+
// Check if WebSocket connection is available, open, and authenticated.
|
|
110
|
+
const authReady = this.socket.isAuthReady?.() ?? true;
|
|
111
|
+
if (this.socket.ws &&
|
|
112
|
+
this.socket.ws.readyState === WebSocket.OPEN &&
|
|
113
|
+
authReady) {
|
|
111
114
|
try {
|
|
112
115
|
this.socket.ws.send(JSON.stringify(this.msg));
|
|
113
116
|
this.timeoutId = setTimeout(this.onTimeout.bind(this), this.timeout);
|
|
@@ -289,8 +292,14 @@ class ServiceCall {
|
|
|
289
292
|
this.error("Ran out of retries");
|
|
290
293
|
return; // Exit early - no more attempts
|
|
291
294
|
}
|
|
292
|
-
// Check if WebSocket connection is available and
|
|
293
|
-
|
|
295
|
+
// Check if WebSocket connection is available, open, and authenticated.
|
|
296
|
+
// The IAM gateway rejects all non-auth frames until the first-frame
|
|
297
|
+
// auth handshake has completed, so sends gated only on readyState
|
|
298
|
+
// would race the auth response.
|
|
299
|
+
const authReady = this.socket.isAuthReady?.() ?? true;
|
|
300
|
+
if (this.socket.ws &&
|
|
301
|
+
this.socket.ws.readyState === WebSocket.OPEN &&
|
|
302
|
+
authReady) {
|
|
294
303
|
try {
|
|
295
304
|
// Attempt to send the message as JSON
|
|
296
305
|
this.socket.ws.send(JSON.stringify(this.msg));
|
|
@@ -319,12 +328,23 @@ class ServiceCall {
|
|
|
319
328
|
// Configuration constants
|
|
320
329
|
const SOCKET_RECONNECTION_TIMEOUT = 2000; // 2 seconds between reconnection
|
|
321
330
|
// attempts
|
|
322
|
-
const SOCKET_URL = "/api/socket"; // WebSocket endpoint path
|
|
331
|
+
const SOCKET_URL = "/api/v1/socket"; // WebSocket endpoint path
|
|
323
332
|
/**
|
|
324
333
|
* Generates a random message ID using cryptographically secure random values
|
|
325
334
|
* @param length - Number of random characters to generate
|
|
326
335
|
* @returns Random string of specified length
|
|
327
336
|
*/
|
|
337
|
+
// Normalise the top-level `error` field from a WebSocket response frame.
|
|
338
|
+
// The gateway may send it as a plain string *or* as an object with a
|
|
339
|
+
// `message` field; callers always want a string.
|
|
340
|
+
function errorToString(err) {
|
|
341
|
+
if (typeof err === "string")
|
|
342
|
+
return err;
|
|
343
|
+
if (err && typeof err === "object" && "message" in err) {
|
|
344
|
+
return String(err.message);
|
|
345
|
+
}
|
|
346
|
+
return String(err);
|
|
347
|
+
}
|
|
328
348
|
function makeid(length) {
|
|
329
349
|
const array = new Uint32Array(length);
|
|
330
350
|
crypto.getRandomValues(array);
|
|
@@ -332,23 +352,46 @@ function makeid(length) {
|
|
|
332
352
|
return array.reduce((acc, current) => acc + characters[current % characters.length], "");
|
|
333
353
|
}
|
|
334
354
|
class BaseApi {
|
|
335
|
-
constructor(
|
|
355
|
+
constructor(token, socketUrl) {
|
|
356
|
+
// Legacy honour-system field. The gateway now derives identity from the
|
|
357
|
+
// authenticated token; this is retained as an empty string so the
|
|
358
|
+
// existing request-builder code paths that read `api.user` keep
|
|
359
|
+
// compiling. It will be removed when the request payloads are cleaned
|
|
360
|
+
// up.
|
|
361
|
+
this.user = "";
|
|
362
|
+
// Active workspace for outbound requests. Sent as the envelope
|
|
363
|
+
// `workspace` field (sibling of `flow`); the gateway reconciles it
|
|
364
|
+
// against the authenticated identity and, when empty, defaults to
|
|
365
|
+
// the token's bound workspace. Kept in sync with the active
|
|
366
|
+
// workspace by the state layer.
|
|
367
|
+
this.workspace = "";
|
|
336
368
|
this.inflight = {}; // Track active requests by
|
|
337
369
|
// message ID
|
|
338
370
|
this.reconnectAttempts = 0; // Track reconnection attempts
|
|
339
371
|
this.maxReconnectAttempts = 10; // Maximum reconnection attempts
|
|
340
372
|
this.reconnectionState = "idle"; // Connection state
|
|
373
|
+
// Auth-handshake state for the current socket. Reset on each open.
|
|
374
|
+
this.authState = "pending";
|
|
341
375
|
// Connection state tracking for UI
|
|
342
376
|
this.connectionStateListeners = [];
|
|
343
377
|
this.tag = makeid(16); // Generate unique client tag
|
|
344
378
|
this.id = 1; // Start message ID counter
|
|
345
|
-
this.token = token;
|
|
346
|
-
this.user = user; // Store user identifier
|
|
379
|
+
this.token = token;
|
|
347
380
|
this.socketUrl = socketUrl || SOCKET_URL; // Use provided URL or default
|
|
348
|
-
console.log("SOCKET: opening socket..."
|
|
381
|
+
console.log("SOCKET: opening socket...");
|
|
349
382
|
this.openSocket(); // Establish WebSocket connection
|
|
350
383
|
console.log("SOCKET: socket opened");
|
|
351
384
|
}
|
|
385
|
+
/**
|
|
386
|
+
* True once the WebSocket is OPEN and the first-frame auth handshake
|
|
387
|
+
* has been accepted by the gateway. ServiceCall consults this before
|
|
388
|
+
* sending request frames.
|
|
389
|
+
*/
|
|
390
|
+
isAuthReady() {
|
|
391
|
+
return (!!this.ws &&
|
|
392
|
+
this.ws.readyState === WebSocket.OPEN &&
|
|
393
|
+
this.authState === "ok");
|
|
394
|
+
}
|
|
352
395
|
/**
|
|
353
396
|
* Subscribe to connection state changes for UI updates
|
|
354
397
|
*/
|
|
@@ -369,7 +412,8 @@ class BaseApi {
|
|
|
369
412
|
*/
|
|
370
413
|
getConnectionState() {
|
|
371
414
|
const hasApiKey = !!this.token;
|
|
372
|
-
// Determine status based on WebSocket state
|
|
415
|
+
// Determine status based on WebSocket state, auth handshake state, and
|
|
416
|
+
// reconnection state.
|
|
373
417
|
let status;
|
|
374
418
|
if (!this.ws || this.ws.readyState === WebSocket.CLOSED) {
|
|
375
419
|
if (this.reconnectionState === "failed") {
|
|
@@ -386,7 +430,12 @@ class BaseApi {
|
|
|
386
430
|
status = "connecting";
|
|
387
431
|
}
|
|
388
432
|
else if (this.ws.readyState === WebSocket.OPEN) {
|
|
389
|
-
|
|
433
|
+
if (this.authState === "ok")
|
|
434
|
+
status = "authenticated";
|
|
435
|
+
else if (this.authState === "failed")
|
|
436
|
+
status = "auth-failed";
|
|
437
|
+
else
|
|
438
|
+
status = "authenticating";
|
|
390
439
|
}
|
|
391
440
|
else {
|
|
392
441
|
status = "connecting";
|
|
@@ -435,13 +484,12 @@ class BaseApi {
|
|
|
435
484
|
this.ws.removeEventListener("error", this.onError);
|
|
436
485
|
this.ws = undefined;
|
|
437
486
|
}
|
|
487
|
+
// Reset the auth handshake state for the new connection. The token
|
|
488
|
+
// is sent as the first frame after onOpen, never on the URL.
|
|
489
|
+
this.authState = "pending";
|
|
438
490
|
try {
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
? `${this.socketUrl}?token=${this.token}`
|
|
442
|
-
: this.socketUrl;
|
|
443
|
-
console.log("SOCKET: connecting to", wsUrl.replace(/token=[^&]*/, "token=***"));
|
|
444
|
-
this.ws = new WebSocket(wsUrl);
|
|
491
|
+
console.log("SOCKET: connecting to", this.socketUrl);
|
|
492
|
+
this.ws = new WebSocket(this.socketUrl);
|
|
445
493
|
}
|
|
446
494
|
catch (e) {
|
|
447
495
|
console.error("[socket creation error]", e);
|
|
@@ -465,6 +513,34 @@ class BaseApi {
|
|
|
465
513
|
return;
|
|
466
514
|
try {
|
|
467
515
|
const obj = JSON.parse(message.data);
|
|
516
|
+
// Auth handshake frames are addressed by `type`, not by request id.
|
|
517
|
+
if (obj.type === "auth-ok") {
|
|
518
|
+
console.log("[socket] auth-ok", obj.default_workspace ?? "");
|
|
519
|
+
this.authState = "ok";
|
|
520
|
+
this.lastError = undefined;
|
|
521
|
+
this.notifyStateChange();
|
|
522
|
+
// Auth complete — release any requests that were waiting for the
|
|
523
|
+
// socket to become usable.
|
|
524
|
+
for (const mid in this.inflight) {
|
|
525
|
+
this.inflight[mid].retryNow();
|
|
526
|
+
}
|
|
527
|
+
return;
|
|
528
|
+
}
|
|
529
|
+
if (obj.type === "auth-failed") {
|
|
530
|
+
console.warn("[socket] auth-failed", obj.error);
|
|
531
|
+
this.authState = "failed";
|
|
532
|
+
this.lastError = obj.error || "auth failure";
|
|
533
|
+
this.notifyStateChange();
|
|
534
|
+
// Per the IAM spec the server keeps the socket open so the client
|
|
535
|
+
// can re-authenticate without reconnecting. Don't auto-close.
|
|
536
|
+
// Surface the failure to any inflight requests so they don't sit
|
|
537
|
+
// forever — callers should clear the token and reauth.
|
|
538
|
+
for (const mid in this.inflight) {
|
|
539
|
+
this.inflight[mid].error(new Error("auth failure"));
|
|
540
|
+
}
|
|
541
|
+
this.inflight = {};
|
|
542
|
+
return;
|
|
543
|
+
}
|
|
468
544
|
// Skip messages without ID (can't route them)
|
|
469
545
|
if (!obj.id)
|
|
470
546
|
return;
|
|
@@ -497,12 +573,19 @@ class BaseApi {
|
|
|
497
573
|
clearTimeout(this.reconnectTimer);
|
|
498
574
|
this.reconnectTimer = undefined;
|
|
499
575
|
}
|
|
500
|
-
//
|
|
501
|
-
|
|
502
|
-
//
|
|
503
|
-
|
|
504
|
-
|
|
576
|
+
// Send the auth frame as the first message. The server rejects all
|
|
577
|
+
// non-auth messages until it sends back auth-ok, so we hold off
|
|
578
|
+
// releasing inflight requests here — that happens in onMessage when
|
|
579
|
+
// auth-ok arrives.
|
|
580
|
+
this.authState = "pending";
|
|
581
|
+
try {
|
|
582
|
+
this.ws?.send(JSON.stringify({ type: "auth", token: this.token }));
|
|
505
583
|
}
|
|
584
|
+
catch (e) {
|
|
585
|
+
console.error("[socket] failed to send auth frame", e);
|
|
586
|
+
}
|
|
587
|
+
// Notify UI that we're now in the authenticating phase.
|
|
588
|
+
this.notifyStateChange();
|
|
506
589
|
}
|
|
507
590
|
// Handle socket errors
|
|
508
591
|
onError(event) {
|
|
@@ -605,7 +688,7 @@ class BaseApi {
|
|
|
605
688
|
const mid = this.getNextId();
|
|
606
689
|
// Set default values
|
|
607
690
|
if (timeout == undefined)
|
|
608
|
-
timeout =
|
|
691
|
+
timeout = 30000;
|
|
609
692
|
if (retries == undefined)
|
|
610
693
|
retries = 3;
|
|
611
694
|
// Construct the request message
|
|
@@ -617,6 +700,10 @@ class BaseApi {
|
|
|
617
700
|
// Add flow identifier if provided
|
|
618
701
|
if (flow)
|
|
619
702
|
msg.flow = flow;
|
|
703
|
+
// Stamp the active workspace onto the envelope. When empty the
|
|
704
|
+
// gateway falls back to the token's bound workspace.
|
|
705
|
+
if (this.workspace)
|
|
706
|
+
msg.workspace = this.workspace;
|
|
620
707
|
// Return a Promise that will be resolved/rejected by the ServiceCall
|
|
621
708
|
return new Promise((resolve, reject) => {
|
|
622
709
|
const call = new ServiceCall(mid, msg, resolve, reject, timeout, retries, this);
|
|
@@ -636,7 +723,7 @@ class BaseApi {
|
|
|
636
723
|
const mid = this.getNextId();
|
|
637
724
|
// Set defaults
|
|
638
725
|
if (timeout == undefined)
|
|
639
|
-
timeout =
|
|
726
|
+
timeout = 30000;
|
|
640
727
|
if (retries == undefined)
|
|
641
728
|
retries = 3;
|
|
642
729
|
// Construct request message
|
|
@@ -647,6 +734,8 @@ class BaseApi {
|
|
|
647
734
|
};
|
|
648
735
|
if (flow)
|
|
649
736
|
msg.flow = flow;
|
|
737
|
+
if (this.workspace)
|
|
738
|
+
msg.workspace = this.workspace;
|
|
650
739
|
return new Promise((resolve, reject) => {
|
|
651
740
|
const call = new ServiceCallMulti(mid, msg, resolve, reject, timeout, retries, this, // eslint-disable-line @typescript-eslint/no-explicit-any
|
|
652
741
|
receiver);
|
|
@@ -683,6 +772,49 @@ class BaseApi {
|
|
|
683
772
|
collectionManagement() {
|
|
684
773
|
return new CollectionManagementApi(this);
|
|
685
774
|
}
|
|
775
|
+
iam() {
|
|
776
|
+
return new IamApi(this);
|
|
777
|
+
}
|
|
778
|
+
}
|
|
779
|
+
/**
|
|
780
|
+
* IamApi - Identity and workspace discovery over the authenticated
|
|
781
|
+
* socket. IAM is the one surface that lives outside workspace tenancy;
|
|
782
|
+
* these calls run as the `iam` service and the gateway injects the
|
|
783
|
+
* caller's identity from the connection's token.
|
|
784
|
+
*/
|
|
785
|
+
class IamApi {
|
|
786
|
+
constructor(api) {
|
|
787
|
+
this.api = api;
|
|
788
|
+
}
|
|
789
|
+
// The caller's own user record, including their home workspace.
|
|
790
|
+
whoami() {
|
|
791
|
+
return this.api
|
|
792
|
+
.makeRequest("iam", { operation: "whoami" })
|
|
793
|
+
.then((r) => {
|
|
794
|
+
const user = r.user ?? {};
|
|
795
|
+
return {
|
|
796
|
+
id: String(user.id ?? ""),
|
|
797
|
+
username: String(user.username ?? ""),
|
|
798
|
+
name: String(user.name ?? ""),
|
|
799
|
+
email: String(user.email ?? ""),
|
|
800
|
+
default_workspace: String(user.default_workspace ?? ""),
|
|
801
|
+
roles: Array.isArray(user.roles) ? user.roles : [],
|
|
802
|
+
enabled: !!user.enabled,
|
|
803
|
+
};
|
|
804
|
+
});
|
|
805
|
+
}
|
|
806
|
+
// The workspaces the caller has access to (one for an ordinary user,
|
|
807
|
+
// all for an admin — driven entirely by what the gateway returns).
|
|
808
|
+
listMyWorkspaces() {
|
|
809
|
+
return this.api
|
|
810
|
+
.makeRequest("iam", { operation: "list-my-workspaces" })
|
|
811
|
+
.then((r) => (r.workspaces ?? []).map((w) => ({
|
|
812
|
+
id: String(w.id ?? ""),
|
|
813
|
+
name: String(w.name ?? ""),
|
|
814
|
+
enabled: !!w.enabled,
|
|
815
|
+
created: String(w.created ?? ""),
|
|
816
|
+
})));
|
|
817
|
+
}
|
|
686
818
|
}
|
|
687
819
|
/**
|
|
688
820
|
* LibrarianApi - Manages document storage and retrieval
|
|
@@ -921,7 +1053,7 @@ class LibrarianApi {
|
|
|
921
1053
|
const msg = message;
|
|
922
1054
|
// Check for top-level error
|
|
923
1055
|
if (msg.error) {
|
|
924
|
-
onError(msg.error);
|
|
1056
|
+
onError(errorToString(msg.error));
|
|
925
1057
|
return true;
|
|
926
1058
|
}
|
|
927
1059
|
const resp = msg.response;
|
|
@@ -1007,17 +1139,30 @@ class FlowsApi {
|
|
|
1007
1139
|
deleteConfig(keys) {
|
|
1008
1140
|
return this.api.makeRequest("config", {
|
|
1009
1141
|
operation: "delete",
|
|
1010
|
-
keys: keys,
|
|
1142
|
+
keys: [keys],
|
|
1011
1143
|
}, 30000);
|
|
1012
1144
|
}
|
|
1145
|
+
/**
|
|
1146
|
+
* Lists available configuration keys for a given type
|
|
1147
|
+
*/
|
|
1148
|
+
list(type) {
|
|
1149
|
+
return this.api
|
|
1150
|
+
.makeRequest("config", {
|
|
1151
|
+
operation: "list",
|
|
1152
|
+
type: type,
|
|
1153
|
+
}, 60000)
|
|
1154
|
+
.then((r) => r);
|
|
1155
|
+
}
|
|
1013
1156
|
// Prompt management - specialized config operations for AI prompts
|
|
1014
1157
|
/**
|
|
1015
|
-
* Retrieves list of available prompt
|
|
1158
|
+
* Retrieves list of available prompt template IDs
|
|
1016
1159
|
*/
|
|
1017
1160
|
getPrompts() {
|
|
1018
|
-
return this.
|
|
1019
|
-
const
|
|
1020
|
-
return
|
|
1161
|
+
return this.list("prompt").then((r) => {
|
|
1162
|
+
const keys = r?.directory || [];
|
|
1163
|
+
return keys
|
|
1164
|
+
.filter((k) => k.startsWith("template."))
|
|
1165
|
+
.map((k) => k.slice("template.".length));
|
|
1021
1166
|
});
|
|
1022
1167
|
}
|
|
1023
1168
|
/**
|
|
@@ -1174,17 +1319,19 @@ class FlowApi {
|
|
|
1174
1319
|
const msg = message;
|
|
1175
1320
|
// Check for top-level error
|
|
1176
1321
|
if (msg.error) {
|
|
1177
|
-
error(msg.error);
|
|
1322
|
+
error(errorToString(msg.error));
|
|
1178
1323
|
return true;
|
|
1179
1324
|
}
|
|
1180
1325
|
const resp = msg.response || {};
|
|
1326
|
+
// Prefer message_type, fall back to chunk_type for older backends
|
|
1327
|
+
const msgType = resp.message_type || resp.chunk_type;
|
|
1181
1328
|
// Check for errors in response
|
|
1182
|
-
if (
|
|
1329
|
+
if (msgType === "error" || resp.error) {
|
|
1183
1330
|
error(resp.error?.message || "Unknown agent error");
|
|
1184
1331
|
return true; // End streaming on error
|
|
1185
1332
|
}
|
|
1186
|
-
// Handle explainability events
|
|
1187
|
-
if (
|
|
1333
|
+
// Handle explainability events
|
|
1334
|
+
if (msgType === "explain" && resp.explain_id && resp.explain_graph) {
|
|
1188
1335
|
onExplain?.({
|
|
1189
1336
|
explainId: resp.explain_id,
|
|
1190
1337
|
explainGraph: resp.explain_graph,
|
|
@@ -1192,7 +1339,7 @@ class FlowApi {
|
|
|
1192
1339
|
});
|
|
1193
1340
|
return false;
|
|
1194
1341
|
}
|
|
1195
|
-
// Handle streaming chunks by
|
|
1342
|
+
// Handle streaming chunks by message type
|
|
1196
1343
|
const content = resp.content || "";
|
|
1197
1344
|
const messageId = resp.message_id;
|
|
1198
1345
|
const messageComplete = !!resp.end_of_message;
|
|
@@ -1201,7 +1348,7 @@ class FlowApi {
|
|
|
1201
1348
|
const metadata = dialogComplete && (resp.in_token || resp.out_token || resp.model)
|
|
1202
1349
|
? { in_token: resp.in_token, out_token: resp.out_token, model: resp.model }
|
|
1203
1350
|
: undefined;
|
|
1204
|
-
switch (
|
|
1351
|
+
switch (msgType) {
|
|
1205
1352
|
case "thought":
|
|
1206
1353
|
think(content, messageComplete, messageId, metadata);
|
|
1207
1354
|
break;
|
|
@@ -1225,7 +1372,7 @@ class FlowApi {
|
|
|
1225
1372
|
user: this.api.user,
|
|
1226
1373
|
collection: collection || "default",
|
|
1227
1374
|
streaming: true, // Always use streaming mode
|
|
1228
|
-
}, receiver,
|
|
1375
|
+
}, receiver, 180000, 1, this.flowId)
|
|
1229
1376
|
.catch((err) => {
|
|
1230
1377
|
const errorMessage = err instanceof Error ? err.message : err?.toString() || "Unknown error";
|
|
1231
1378
|
error(`Agent request failed: ${errorMessage}`);
|
|
@@ -1245,7 +1392,7 @@ class FlowApi {
|
|
|
1245
1392
|
const msg = message;
|
|
1246
1393
|
// Check for top-level error
|
|
1247
1394
|
if (msg.error) {
|
|
1248
|
-
onError(msg.error);
|
|
1395
|
+
onError(errorToString(msg.error));
|
|
1249
1396
|
return true;
|
|
1250
1397
|
}
|
|
1251
1398
|
const resp = (msg.response || {});
|
|
@@ -1283,7 +1430,7 @@ class FlowApi {
|
|
|
1283
1430
|
"max-subgraph-size": options?.maxSubgraphSize,
|
|
1284
1431
|
"max-path-length": options?.pathLength,
|
|
1285
1432
|
streaming: true,
|
|
1286
|
-
}, recv,
|
|
1433
|
+
}, recv, 180000, 1, this.flowId);
|
|
1287
1434
|
}
|
|
1288
1435
|
/**
|
|
1289
1436
|
* Performs Document RAG query with streaming response
|
|
@@ -1298,7 +1445,7 @@ class FlowApi {
|
|
|
1298
1445
|
const msg = message;
|
|
1299
1446
|
// Check for top-level error
|
|
1300
1447
|
if (msg.error) {
|
|
1301
|
-
onError(msg.error);
|
|
1448
|
+
onError(errorToString(msg.error));
|
|
1302
1449
|
return true;
|
|
1303
1450
|
}
|
|
1304
1451
|
const resp = (msg.response || {});
|
|
@@ -1331,7 +1478,7 @@ class FlowApi {
|
|
|
1331
1478
|
collection: collection || "default",
|
|
1332
1479
|
"doc-limit": docLimit,
|
|
1333
1480
|
streaming: true,
|
|
1334
|
-
}, recv,
|
|
1481
|
+
}, recv, 180000, 1, this.flowId);
|
|
1335
1482
|
}
|
|
1336
1483
|
/**
|
|
1337
1484
|
* Performs text completion with streaming response
|
|
@@ -1345,7 +1492,7 @@ class FlowApi {
|
|
|
1345
1492
|
const msg = message;
|
|
1346
1493
|
// Check for top-level error
|
|
1347
1494
|
if (msg.error) {
|
|
1348
|
-
onError(msg.error);
|
|
1495
|
+
onError(errorToString(msg.error));
|
|
1349
1496
|
return true;
|
|
1350
1497
|
}
|
|
1351
1498
|
const resp = (msg.response || {});
|
|
@@ -1382,7 +1529,7 @@ class FlowApi {
|
|
|
1382
1529
|
const msg = message;
|
|
1383
1530
|
// Check for top-level error
|
|
1384
1531
|
if (msg.error) {
|
|
1385
|
-
onError(msg.error);
|
|
1532
|
+
onError(errorToString(msg.error));
|
|
1386
1533
|
return true;
|
|
1387
1534
|
}
|
|
1388
1535
|
const resp = (msg.response || {});
|
|
@@ -1403,7 +1550,7 @@ class FlowApi {
|
|
|
1403
1550
|
};
|
|
1404
1551
|
this.api.makeRequestMulti("prompt", {
|
|
1405
1552
|
id: id,
|
|
1406
|
-
|
|
1553
|
+
variables: terms,
|
|
1407
1554
|
streaming: true,
|
|
1408
1555
|
}, recv, 30000, undefined, this.flowId);
|
|
1409
1556
|
}
|
|
@@ -1448,6 +1595,75 @@ class FlowApi {
|
|
|
1448
1595
|
}, 30000, undefined, this.flowId)
|
|
1449
1596
|
.then((r) => r.response);
|
|
1450
1597
|
}
|
|
1598
|
+
sparqlQuery(query, collection, limit, batchSize) {
|
|
1599
|
+
const columns = [];
|
|
1600
|
+
const rows = [];
|
|
1601
|
+
let queryType = "select";
|
|
1602
|
+
let askResult;
|
|
1603
|
+
let triples;
|
|
1604
|
+
let sparqlError = null;
|
|
1605
|
+
const termToString = (val) => {
|
|
1606
|
+
if (!val)
|
|
1607
|
+
return "";
|
|
1608
|
+
if (val.t === "i")
|
|
1609
|
+
return val.i;
|
|
1610
|
+
if (val.t === "l")
|
|
1611
|
+
return val.v;
|
|
1612
|
+
return "";
|
|
1613
|
+
};
|
|
1614
|
+
return this.api
|
|
1615
|
+
.makeRequestMulti("sparql", {
|
|
1616
|
+
query,
|
|
1617
|
+
collection: collection || "default",
|
|
1618
|
+
limit: limit ?? 10000,
|
|
1619
|
+
streaming: true,
|
|
1620
|
+
"batch-size": batchSize ?? 50,
|
|
1621
|
+
}, (resp) => {
|
|
1622
|
+
const msg = resp;
|
|
1623
|
+
const batch = msg.response;
|
|
1624
|
+
const isComplete = msg.complete === true;
|
|
1625
|
+
if (!batch)
|
|
1626
|
+
return isComplete;
|
|
1627
|
+
if (batch.error) {
|
|
1628
|
+
sparqlError = typeof batch.error === "string"
|
|
1629
|
+
? batch.error
|
|
1630
|
+
: batch.error.message || "SPARQL query error";
|
|
1631
|
+
return true;
|
|
1632
|
+
}
|
|
1633
|
+
queryType = batch["query-type"] || queryType;
|
|
1634
|
+
if (queryType === "ask") {
|
|
1635
|
+
askResult = batch["ask-result"];
|
|
1636
|
+
return true;
|
|
1637
|
+
}
|
|
1638
|
+
if (queryType === "construct" || queryType === "describe") {
|
|
1639
|
+
triples = batch.triples || [];
|
|
1640
|
+
return true;
|
|
1641
|
+
}
|
|
1642
|
+
if (batch.variables && columns.length === 0) {
|
|
1643
|
+
columns.push(...batch.variables);
|
|
1644
|
+
}
|
|
1645
|
+
if (batch.bindings) {
|
|
1646
|
+
for (const binding of batch.bindings) {
|
|
1647
|
+
const row = {};
|
|
1648
|
+
for (let i = 0; i < columns.length; i++) {
|
|
1649
|
+
row[columns[i]] = termToString(binding.values[i] ?? null);
|
|
1650
|
+
}
|
|
1651
|
+
rows.push(row);
|
|
1652
|
+
}
|
|
1653
|
+
}
|
|
1654
|
+
return isComplete;
|
|
1655
|
+
}, 60000, undefined, this.flowId)
|
|
1656
|
+
.then(() => {
|
|
1657
|
+
if (sparqlError)
|
|
1658
|
+
throw new Error(sparqlError);
|
|
1659
|
+
return { queryType, columns, rows, askResult, triples };
|
|
1660
|
+
})
|
|
1661
|
+
.catch((err) => {
|
|
1662
|
+
if (err instanceof Error)
|
|
1663
|
+
throw err;
|
|
1664
|
+
throw new Error(typeof err === "string" ? err : JSON.stringify(err));
|
|
1665
|
+
});
|
|
1666
|
+
}
|
|
1451
1667
|
/**
|
|
1452
1668
|
* Loads a document into this flow for processing
|
|
1453
1669
|
*/
|
|
@@ -1596,17 +1812,19 @@ class ConfigApi {
|
|
|
1596
1812
|
deleteConfig(keys) {
|
|
1597
1813
|
return this.api.makeRequest("config", {
|
|
1598
1814
|
operation: "delete",
|
|
1599
|
-
keys: keys,
|
|
1815
|
+
keys: [keys],
|
|
1600
1816
|
}, 30000);
|
|
1601
1817
|
}
|
|
1602
1818
|
// Specialized prompt management methods
|
|
1603
1819
|
/**
|
|
1604
|
-
* Retrieves available prompt
|
|
1820
|
+
* Retrieves available prompt template IDs
|
|
1605
1821
|
*/
|
|
1606
1822
|
getPrompts() {
|
|
1607
|
-
return this.
|
|
1608
|
-
const
|
|
1609
|
-
return
|
|
1823
|
+
return this.list("prompt").then((r) => {
|
|
1824
|
+
const keys = r?.directory || [];
|
|
1825
|
+
return keys
|
|
1826
|
+
.filter((k) => k.startsWith("template."))
|
|
1827
|
+
.map((k) => k.slice("template.".length));
|
|
1610
1828
|
});
|
|
1611
1829
|
}
|
|
1612
1830
|
/**
|
|
@@ -1824,15 +2042,73 @@ class CollectionManagementApi {
|
|
|
1824
2042
|
}
|
|
1825
2043
|
}
|
|
1826
2044
|
/**
|
|
1827
|
-
* Factory function to create a new TrustGraph WebSocket connection
|
|
1828
|
-
*
|
|
1829
|
-
*
|
|
1830
|
-
*
|
|
1831
|
-
* @param
|
|
2045
|
+
* Factory function to create a new TrustGraph WebSocket connection.
|
|
2046
|
+
* The token (JWT or API key) is sent as the first frame after connect;
|
|
2047
|
+
* the gateway derives the user identity and workspace from it.
|
|
2048
|
+
*
|
|
2049
|
+
* @param token - Bearer token (JWT from /auth/login or an API key)
|
|
2050
|
+
* @param socketUrl - Optional WebSocket URL (defaults to /api/v1/socket
|
|
2051
|
+
* for browser, provide full URL for Node.js)
|
|
1832
2052
|
*/
|
|
1833
|
-
const createTrustGraphSocket = (
|
|
1834
|
-
return new BaseApi(
|
|
2053
|
+
const createTrustGraphSocket = (token, socketUrl) => {
|
|
2054
|
+
return new BaseApi(token, socketUrl);
|
|
1835
2055
|
};
|
|
1836
2056
|
|
|
1837
|
-
|
|
2057
|
+
// HTTP auth client for the TrustGraph IAM gateway endpoints.
|
|
2058
|
+
//
|
|
2059
|
+
// These endpoints run before the WebSocket exists, so they use plain
|
|
2060
|
+
// fetch rather than the socket transport.
|
|
2061
|
+
const DEFAULT_BOOTSTRAP_STATUS_URL = "/api/v1/auth/bootstrap-status";
|
|
2062
|
+
const DEFAULT_LOGIN_URL = "/api/v1/auth/login";
|
|
2063
|
+
class AuthError extends Error {
|
|
2064
|
+
constructor(message, status) {
|
|
2065
|
+
super(message);
|
|
2066
|
+
this.name = "AuthError";
|
|
2067
|
+
this.status = status;
|
|
2068
|
+
}
|
|
2069
|
+
}
|
|
2070
|
+
class AuthApi {
|
|
2071
|
+
constructor(options = {}) {
|
|
2072
|
+
this.bootstrapStatusUrl =
|
|
2073
|
+
options.bootstrapStatusUrl ?? DEFAULT_BOOTSTRAP_STATUS_URL;
|
|
2074
|
+
this.loginUrl = options.loginUrl ?? DEFAULT_LOGIN_URL;
|
|
2075
|
+
this.fetchImpl = options.fetchImpl ?? fetch.bind(globalThis);
|
|
2076
|
+
}
|
|
2077
|
+
async bootstrapStatus() {
|
|
2078
|
+
const resp = await this.fetchImpl(this.bootstrapStatusUrl, {
|
|
2079
|
+
method: "POST",
|
|
2080
|
+
headers: { "Content-Type": "application/json" },
|
|
2081
|
+
body: "{}",
|
|
2082
|
+
});
|
|
2083
|
+
if (!resp.ok) {
|
|
2084
|
+
throw new AuthError(`bootstrap-status failed: ${resp.status}`, resp.status);
|
|
2085
|
+
}
|
|
2086
|
+
const body = await resp.json();
|
|
2087
|
+
return { bootstrapAvailable: !!body.bootstrap_available };
|
|
2088
|
+
}
|
|
2089
|
+
async login(username, password, default_workspace) {
|
|
2090
|
+
const payload = { username, password };
|
|
2091
|
+
if (default_workspace)
|
|
2092
|
+
payload.default_workspace = default_workspace;
|
|
2093
|
+
const resp = await this.fetchImpl(this.loginUrl, {
|
|
2094
|
+
method: "POST",
|
|
2095
|
+
headers: { "Content-Type": "application/json" },
|
|
2096
|
+
body: JSON.stringify(payload),
|
|
2097
|
+
});
|
|
2098
|
+
if (resp.status === 401) {
|
|
2099
|
+
throw new AuthError("auth failure", 401);
|
|
2100
|
+
}
|
|
2101
|
+
if (!resp.ok) {
|
|
2102
|
+
throw new AuthError(`login failed: ${resp.status}`, resp.status);
|
|
2103
|
+
}
|
|
2104
|
+
const body = await resp.json();
|
|
2105
|
+
if (!body.jwt) {
|
|
2106
|
+
throw new AuthError("login response missing jwt");
|
|
2107
|
+
}
|
|
2108
|
+
return { jwt: body.jwt, jwtExpires: body.jwt_expires ?? "" };
|
|
2109
|
+
}
|
|
2110
|
+
}
|
|
2111
|
+
const createAuthApi = (options) => new AuthApi(options);
|
|
2112
|
+
|
|
2113
|
+
export { AuthApi, AuthError, BaseApi, CollectionManagementApi, ConfigApi, FlowApi, FlowsApi, IamApi, KnowledgeApi, LibrarianApi, PROV, PROV_ACTIVITY, PROV_ENTITY, PROV_STARTED_AT_TIME, PROV_WAS_DERIVED_FROM, PROV_WAS_GENERATED_BY, RDF, RDFS, RDFS_LABEL, RDF_TYPE, SCHEMA, SCHEMA_AUTHOR, SCHEMA_DESCRIPTION, SCHEMA_KEYWORDS, SCHEMA_NAME, SKOS, SKOS_DEFINITION, TG, TG_CONCEPT, TG_CONTENT, TG_DOCUMENT, TG_EDGE, TG_EDGE_COUNT, TG_QUERY, TG_REIFIES, TG_SCORE, TG_SELECTED_EDGE, createAuthApi, createTrustGraphSocket };
|
|
1838
2114
|
//# sourceMappingURL=index.esm.js.map
|