@trustgraph/client 1.2.1 → 1.3.1
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.cjs +1 -2
- package/dist/index.cjs.map +1 -1
- package/dist/index.esm.js +1 -2
- package/dist/index.esm.js.map +1 -1
- package/dist/models/Triple.d.ts +25 -10
- package/dist/models/Triple.d.ts.map +1 -1
- package/dist/models/messages.d.ts +11 -7
- package/dist/models/messages.d.ts.map +1 -1
- package/dist/socket/trustgraph-socket.d.ts +7 -7
- package/dist/socket/trustgraph-socket.d.ts.map +1 -1
- package/package.json +1 -1
- package/dist/api/authenticated-fetch.d.ts +0 -18
- package/dist/api/authenticated-fetch.d.ts.map +0 -1
- package/dist/api/trustgraph/SocketContext.d.ts +0 -2
- package/dist/api/trustgraph/SocketContext.d.ts.map +0 -1
- package/dist/api/trustgraph/SocketProvider.d.ts +0 -21
- package/dist/api/trustgraph/SocketProvider.d.ts.map +0 -1
- package/dist/api/trustgraph/Triple.d.ts +0 -17
- package/dist/api/trustgraph/Triple.d.ts.map +0 -1
- package/dist/api/trustgraph/messages.d.ts +0 -205
- package/dist/api/trustgraph/messages.d.ts.map +0 -1
- package/dist/api/trustgraph/service-call-multi.d.ts +0 -17
- package/dist/api/trustgraph/service-call-multi.d.ts.map +0 -1
- package/dist/api/trustgraph/service-call.d.ts +0 -57
- package/dist/api/trustgraph/service-call.d.ts.map +0 -1
- package/dist/api/trustgraph/socket.d.ts +0 -2
- package/dist/api/trustgraph/socket.d.ts.map +0 -1
- package/dist/api/trustgraph/trustgraph-socket.d.ts +0 -429
- package/dist/api/trustgraph/trustgraph-socket.d.ts.map +0 -1
- package/dist/index.js +0 -1375
- package/dist/index.js.map +0 -1
package/dist/index.js
DELETED
|
@@ -1,1375 +0,0 @@
|
|
|
1
|
-
'use strict';
|
|
2
|
-
|
|
3
|
-
// Constant defining the delay before attempting to reconnect a WebSocket
|
|
4
|
-
// (2 seconds)
|
|
5
|
-
const SOCKET_RECONNECTION_TIMEOUT$2 = 2000;
|
|
6
|
-
class ServiceCallMulti {
|
|
7
|
-
constructor(mid, msg, success, error, timeout, retries, socket, receiver) {
|
|
8
|
-
this.mid = mid;
|
|
9
|
-
this.msg = msg;
|
|
10
|
-
this.success = success;
|
|
11
|
-
this.error = error;
|
|
12
|
-
this.timeout = timeout;
|
|
13
|
-
this.retries = retries;
|
|
14
|
-
this.socket = socket;
|
|
15
|
-
this.complete = false;
|
|
16
|
-
this.receiver = receiver;
|
|
17
|
-
}
|
|
18
|
-
start() {
|
|
19
|
-
this.socket.inflight[this.mid] = this;
|
|
20
|
-
this.attempt();
|
|
21
|
-
}
|
|
22
|
-
onReceived(resp) {
|
|
23
|
-
if (this.complete == true)
|
|
24
|
-
console.log(this.mid, "should not happen, request is already complete");
|
|
25
|
-
const fin = this.receiver(resp);
|
|
26
|
-
if (fin) {
|
|
27
|
-
this.complete = true;
|
|
28
|
-
// console.log("Received for", this.mid);
|
|
29
|
-
clearTimeout(this.timeoutId);
|
|
30
|
-
this.timeoutId = undefined;
|
|
31
|
-
delete this.socket.inflight[this.mid];
|
|
32
|
-
this.success(resp);
|
|
33
|
-
}
|
|
34
|
-
}
|
|
35
|
-
onTimeout() {
|
|
36
|
-
if (this.complete == true)
|
|
37
|
-
console.log(this.mid, "timeout should not happen, request is already complete");
|
|
38
|
-
console.log("Request", this.mid, "timed out");
|
|
39
|
-
clearTimeout(this.timeoutId);
|
|
40
|
-
this.attempt();
|
|
41
|
-
}
|
|
42
|
-
attempt() {
|
|
43
|
-
// console.log("attempt:", this.mid);
|
|
44
|
-
if (this.complete == true)
|
|
45
|
-
console.log(this.mid, "attempt should not be called, request is already complete");
|
|
46
|
-
this.retries--;
|
|
47
|
-
if (this.retries < 0) {
|
|
48
|
-
console.log("Request", this.mid, "ran out of retries");
|
|
49
|
-
clearTimeout(this.timeoutId);
|
|
50
|
-
delete this.socket.inflight[this.mid];
|
|
51
|
-
this.error("Ran out of retries");
|
|
52
|
-
return; // Exit early - no more attempts
|
|
53
|
-
}
|
|
54
|
-
// Check if WebSocket connection is available and ready
|
|
55
|
-
if (this.socket.ws && this.socket.ws.readyState === WebSocket.OPEN) {
|
|
56
|
-
try {
|
|
57
|
-
this.socket.ws.send(JSON.stringify(this.msg));
|
|
58
|
-
this.timeoutId = setTimeout(this.onTimeout.bind(this), this.timeout);
|
|
59
|
-
return;
|
|
60
|
-
}
|
|
61
|
-
catch (e) {
|
|
62
|
-
console.log("Error:", e);
|
|
63
|
-
console.log("Message send failure, retry...");
|
|
64
|
-
// Calculate backoff delay with jitter
|
|
65
|
-
const backoffDelay = Math.min(SOCKET_RECONNECTION_TIMEOUT$2 * Math.pow(2, 3 - this.retries) +
|
|
66
|
-
Math.random() * 1000, 30000);
|
|
67
|
-
this.timeoutId = setTimeout(this.attempt.bind(this), backoffDelay);
|
|
68
|
-
console.log("Reopen...");
|
|
69
|
-
// Attempt to reopen the WebSocket connection
|
|
70
|
-
this.socket.reopen();
|
|
71
|
-
}
|
|
72
|
-
}
|
|
73
|
-
else {
|
|
74
|
-
// No WebSocket connection available or not ready
|
|
75
|
-
// Check if socket is connecting
|
|
76
|
-
if (this.socket.ws &&
|
|
77
|
-
this.socket.ws.readyState === WebSocket.CONNECTING) {
|
|
78
|
-
// Wait a bit longer for connection to establish
|
|
79
|
-
setTimeout(this.attempt.bind(this), 500);
|
|
80
|
-
}
|
|
81
|
-
else {
|
|
82
|
-
// Socket is closed or closing, trigger reopen
|
|
83
|
-
console.log("Socket not ready, reopening...");
|
|
84
|
-
this.socket.reopen();
|
|
85
|
-
// Calculate backoff delay
|
|
86
|
-
const backoffDelay = Math.min(SOCKET_RECONNECTION_TIMEOUT$2 * Math.pow(2, 3 - this.retries) +
|
|
87
|
-
Math.random() * 1000, 30000);
|
|
88
|
-
setTimeout(this.attempt.bind(this), backoffDelay);
|
|
89
|
-
}
|
|
90
|
-
}
|
|
91
|
-
}
|
|
92
|
-
}
|
|
93
|
-
|
|
94
|
-
// Constant defining the delay before attempting to reconnect a WebSocket
|
|
95
|
-
// (2 seconds)
|
|
96
|
-
const SOCKET_RECONNECTION_TIMEOUT$1 = 2000;
|
|
97
|
-
/**
|
|
98
|
-
* ServiceCall represents a single request/response cycle over a WebSocket
|
|
99
|
-
* connection with built-in retry logic, timeout handling, and completion
|
|
100
|
-
* tracking.
|
|
101
|
-
*
|
|
102
|
-
* This class manages the lifecycle of a service call including:
|
|
103
|
-
* - Sending the initial request
|
|
104
|
-
* - Handling timeouts and retries
|
|
105
|
-
* - Managing completion state
|
|
106
|
-
* - Cleaning up resources
|
|
107
|
-
*/
|
|
108
|
-
class ServiceCall {
|
|
109
|
-
constructor(mid, // Message ID - unique identifier for this request
|
|
110
|
-
msg, // The actual message/request to send
|
|
111
|
-
success, // Callback function called on
|
|
112
|
-
// successful response
|
|
113
|
-
error, // Callback function called on error/failure
|
|
114
|
-
timeout, // Timeout duration in milliseconds
|
|
115
|
-
retries, // Number of retry attempts allowed
|
|
116
|
-
socket) {
|
|
117
|
-
this.mid = mid;
|
|
118
|
-
this.msg = msg;
|
|
119
|
-
this.success = success;
|
|
120
|
-
this.error = error;
|
|
121
|
-
this.timeout = timeout;
|
|
122
|
-
this.retries = retries;
|
|
123
|
-
this.socket = socket;
|
|
124
|
-
this.complete = false; // Track if this request has completed
|
|
125
|
-
}
|
|
126
|
-
/**
|
|
127
|
-
* Initiates the service call by registering it with the socket's inflight
|
|
128
|
-
* requests and making the first attempt to send the message
|
|
129
|
-
*/
|
|
130
|
-
start() {
|
|
131
|
-
// Register this request as "in-flight" so responses can be matched to it
|
|
132
|
-
this.socket.inflight[this.mid] = this;
|
|
133
|
-
// Make the first attempt to send the message
|
|
134
|
-
this.attempt();
|
|
135
|
-
}
|
|
136
|
-
/**
|
|
137
|
-
* Called when a response is received for this request
|
|
138
|
-
* Handles cleanup and calls the success or error callback based on response
|
|
139
|
-
*
|
|
140
|
-
* @param resp - The response object received from the server
|
|
141
|
-
*/
|
|
142
|
-
onReceived(resp) {
|
|
143
|
-
// Defensive check - this shouldn't happen but log if it does
|
|
144
|
-
if (this.complete == true)
|
|
145
|
-
console.log(this.mid, "should not happen, request is already complete");
|
|
146
|
-
// Mark as complete to prevent duplicate processing
|
|
147
|
-
this.complete = true;
|
|
148
|
-
// Clean up timeout timer
|
|
149
|
-
clearTimeout(this.timeoutId);
|
|
150
|
-
this.timeoutId = undefined;
|
|
151
|
-
// Remove from inflight requests tracker
|
|
152
|
-
delete this.socket.inflight[this.mid];
|
|
153
|
-
// Check if the response contains an error (error can be directly in resp or nested under response)
|
|
154
|
-
let errorToHandle = null;
|
|
155
|
-
// Check for direct error in response
|
|
156
|
-
if (resp && typeof resp === "object" && "error" in resp) {
|
|
157
|
-
errorToHandle = resp.error;
|
|
158
|
-
}
|
|
159
|
-
// Check for nested error under response property
|
|
160
|
-
else if (resp && typeof resp === "object" && "response" in resp) {
|
|
161
|
-
const response = resp.response;
|
|
162
|
-
if (response && typeof response === "object" && "error" in response) {
|
|
163
|
-
errorToHandle = response.error;
|
|
164
|
-
}
|
|
165
|
-
}
|
|
166
|
-
if (errorToHandle) {
|
|
167
|
-
// Response contains an error - call error callback
|
|
168
|
-
const errorObj = errorToHandle;
|
|
169
|
-
const errorMessage = (typeof errorObj.message === "string" ? errorObj.message : null) ||
|
|
170
|
-
(typeof errorObj.type === "string" ? errorObj.type : null) ||
|
|
171
|
-
"Unknown error";
|
|
172
|
-
console.log("ServiceCall: API error detected in response:", errorMessage, "Full error:", errorToHandle);
|
|
173
|
-
this.error(new Error(errorMessage));
|
|
174
|
-
return;
|
|
175
|
-
}
|
|
176
|
-
// Call success callback with the response
|
|
177
|
-
this.success(resp);
|
|
178
|
-
}
|
|
179
|
-
/**
|
|
180
|
-
* Called when the request times out
|
|
181
|
-
* Triggers another attempt if retries are available
|
|
182
|
-
*/
|
|
183
|
-
onTimeout() {
|
|
184
|
-
// Defensive check - this shouldn't happen but log if it does
|
|
185
|
-
if (this.complete == true)
|
|
186
|
-
console.log(this.mid, "timeout should not happen, request is already complete");
|
|
187
|
-
console.log("Request", this.mid, "timed out");
|
|
188
|
-
// Clear the current timeout
|
|
189
|
-
clearTimeout(this.timeoutId);
|
|
190
|
-
// Try again (this will check retry count)
|
|
191
|
-
this.attempt();
|
|
192
|
-
}
|
|
193
|
-
/**
|
|
194
|
-
* Calculates exponential backoff delay with jitter
|
|
195
|
-
* @returns backoff delay in milliseconds
|
|
196
|
-
*/
|
|
197
|
-
calculateBackoff() {
|
|
198
|
-
return Math.min(SOCKET_RECONNECTION_TIMEOUT$1 * Math.pow(2, 3 - this.retries) +
|
|
199
|
-
Math.random() * 1000, 30000);
|
|
200
|
-
}
|
|
201
|
-
/**
|
|
202
|
-
* Core retry logic - attempts to send the message over the WebSocket
|
|
203
|
-
* Handles retries and waits for BaseApi to handle reconnection
|
|
204
|
-
*/
|
|
205
|
-
attempt() {
|
|
206
|
-
// Defensive check - this shouldn't be called on completed requests
|
|
207
|
-
if (this.complete == true)
|
|
208
|
-
console.log(this.mid, "attempt should not be called, request is already complete");
|
|
209
|
-
// Decrement retry counter
|
|
210
|
-
this.retries--;
|
|
211
|
-
// Check if we've exhausted all retries
|
|
212
|
-
if (this.retries < 0) {
|
|
213
|
-
console.log("Request", this.mid, "ran out of retries");
|
|
214
|
-
// Clean up and call error callback
|
|
215
|
-
clearTimeout(this.timeoutId);
|
|
216
|
-
delete this.socket.inflight[this.mid];
|
|
217
|
-
this.error("Ran out of retries");
|
|
218
|
-
return; // Exit early - no more attempts
|
|
219
|
-
}
|
|
220
|
-
// Check if WebSocket connection is available and ready
|
|
221
|
-
if (this.socket.ws && this.socket.ws.readyState === WebSocket.OPEN) {
|
|
222
|
-
try {
|
|
223
|
-
// Attempt to send the message as JSON
|
|
224
|
-
this.socket.ws.send(JSON.stringify(this.msg));
|
|
225
|
-
// Set up timeout for this attempt
|
|
226
|
-
this.timeoutId = setTimeout(this.onTimeout.bind(this), this.timeout);
|
|
227
|
-
return; // Success - message sent, waiting for response or timeout
|
|
228
|
-
}
|
|
229
|
-
catch (e) {
|
|
230
|
-
// Handle send failure - wait for BaseApi to handle reconnection
|
|
231
|
-
console.log("Error:", e);
|
|
232
|
-
console.log("Message send failure, waiting for socket reconnection...");
|
|
233
|
-
// Schedule retry with backoff - let BaseApi handle the reconnection
|
|
234
|
-
this.timeoutId = setTimeout(this.attempt.bind(this), this.calculateBackoff());
|
|
235
|
-
}
|
|
236
|
-
}
|
|
237
|
-
else {
|
|
238
|
-
// No WebSocket connection available or not ready
|
|
239
|
-
// Let BaseApi handle reconnection, just wait and retry
|
|
240
|
-
console.log("Request", this.mid, "waiting for socket reconnection...");
|
|
241
|
-
// Use consistent backoff for all waiting scenarios
|
|
242
|
-
setTimeout(this.attempt.bind(this), this.calculateBackoff());
|
|
243
|
-
}
|
|
244
|
-
}
|
|
245
|
-
}
|
|
246
|
-
|
|
247
|
-
// Configuration constants
|
|
248
|
-
const SOCKET_RECONNECTION_TIMEOUT = 2000; // 2 seconds between reconnection
|
|
249
|
-
// attempts
|
|
250
|
-
const SOCKET_URL = "/api/socket"; // WebSocket endpoint path
|
|
251
|
-
/**
|
|
252
|
-
* Generates a random message ID using cryptographically secure random values
|
|
253
|
-
* @param length - Number of random characters to generate
|
|
254
|
-
* @returns Random string of specified length
|
|
255
|
-
*/
|
|
256
|
-
function makeid(length) {
|
|
257
|
-
const array = new Uint32Array(length);
|
|
258
|
-
crypto.getRandomValues(array);
|
|
259
|
-
const characters = "abcdefghijklmnopqrstuvwxyz1234567890";
|
|
260
|
-
return array.reduce((acc, current) => acc + characters[current % characters.length], "");
|
|
261
|
-
}
|
|
262
|
-
class BaseApi {
|
|
263
|
-
constructor(user, token) {
|
|
264
|
-
this.inflight = {}; // Track active requests by
|
|
265
|
-
// message ID
|
|
266
|
-
this.reconnectAttempts = 0; // Track reconnection attempts
|
|
267
|
-
this.maxReconnectAttempts = 10; // Maximum reconnection attempts
|
|
268
|
-
this.reconnectionState = "idle"; // Connection state
|
|
269
|
-
// Connection state tracking for UI
|
|
270
|
-
this.connectionStateListeners = [];
|
|
271
|
-
this.tag = makeid(16); // Generate unique client tag
|
|
272
|
-
this.id = 1; // Start message ID counter
|
|
273
|
-
this.token = token; // Store authentication token
|
|
274
|
-
this.user = user; // Store user identifier
|
|
275
|
-
console.log("SOCKET: opening socket...", token ? "with auth" : "without auth", "user:", user);
|
|
276
|
-
this.openSocket(); // Establish WebSocket connection
|
|
277
|
-
console.log("SOCKET: socket opened");
|
|
278
|
-
}
|
|
279
|
-
/**
|
|
280
|
-
* Subscribe to connection state changes for UI updates
|
|
281
|
-
*/
|
|
282
|
-
onConnectionStateChange(listener) {
|
|
283
|
-
this.connectionStateListeners.push(listener);
|
|
284
|
-
// Immediately send current state
|
|
285
|
-
listener(this.getConnectionState());
|
|
286
|
-
// Return unsubscribe function
|
|
287
|
-
return () => {
|
|
288
|
-
const index = this.connectionStateListeners.indexOf(listener);
|
|
289
|
-
if (index > -1) {
|
|
290
|
-
this.connectionStateListeners.splice(index, 1);
|
|
291
|
-
}
|
|
292
|
-
};
|
|
293
|
-
}
|
|
294
|
-
/**
|
|
295
|
-
* Get current connection state
|
|
296
|
-
*/
|
|
297
|
-
getConnectionState() {
|
|
298
|
-
const hasApiKey = !!this.token;
|
|
299
|
-
// Determine status based on WebSocket state and reconnection state
|
|
300
|
-
let status;
|
|
301
|
-
if (!this.ws || this.ws.readyState === WebSocket.CLOSED) {
|
|
302
|
-
if (this.reconnectionState === "failed") {
|
|
303
|
-
status = "failed";
|
|
304
|
-
}
|
|
305
|
-
else if (this.reconnectionState === "reconnecting") {
|
|
306
|
-
status = "reconnecting";
|
|
307
|
-
}
|
|
308
|
-
else {
|
|
309
|
-
status = "connecting";
|
|
310
|
-
}
|
|
311
|
-
}
|
|
312
|
-
else if (this.ws.readyState === WebSocket.CONNECTING) {
|
|
313
|
-
status = "connecting";
|
|
314
|
-
}
|
|
315
|
-
else if (this.ws.readyState === WebSocket.OPEN) {
|
|
316
|
-
status = hasApiKey ? "authenticated" : "unauthenticated";
|
|
317
|
-
}
|
|
318
|
-
else {
|
|
319
|
-
status = "connecting";
|
|
320
|
-
}
|
|
321
|
-
const state = {
|
|
322
|
-
status,
|
|
323
|
-
hasApiKey,
|
|
324
|
-
lastError: this.lastError,
|
|
325
|
-
};
|
|
326
|
-
// Add reconnection details if applicable
|
|
327
|
-
if (status === "reconnecting") {
|
|
328
|
-
state.reconnectAttempt = this.reconnectAttempts;
|
|
329
|
-
state.maxAttempts = this.maxReconnectAttempts;
|
|
330
|
-
}
|
|
331
|
-
return state;
|
|
332
|
-
}
|
|
333
|
-
/**
|
|
334
|
-
* Notify all listeners of connection state changes
|
|
335
|
-
*/
|
|
336
|
-
notifyStateChange() {
|
|
337
|
-
const state = this.getConnectionState();
|
|
338
|
-
this.connectionStateListeners.forEach((listener) => {
|
|
339
|
-
try {
|
|
340
|
-
listener(state);
|
|
341
|
-
}
|
|
342
|
-
catch (error) {
|
|
343
|
-
console.error("Error in connection state listener:", error);
|
|
344
|
-
}
|
|
345
|
-
});
|
|
346
|
-
}
|
|
347
|
-
/**
|
|
348
|
-
* Establishes WebSocket connection and sets up event handlers
|
|
349
|
-
*/
|
|
350
|
-
openSocket() {
|
|
351
|
-
// Don't create multiple connections
|
|
352
|
-
if (this.ws &&
|
|
353
|
-
(this.ws.readyState === WebSocket.CONNECTING ||
|
|
354
|
-
this.ws.readyState === WebSocket.OPEN)) {
|
|
355
|
-
return;
|
|
356
|
-
}
|
|
357
|
-
// Clean up old socket if exists
|
|
358
|
-
if (this.ws) {
|
|
359
|
-
this.ws.removeEventListener("message", this.onMessage);
|
|
360
|
-
this.ws.removeEventListener("close", this.onClose);
|
|
361
|
-
this.ws.removeEventListener("open", this.onOpen);
|
|
362
|
-
this.ws.removeEventListener("error", this.onError);
|
|
363
|
-
this.ws = undefined;
|
|
364
|
-
}
|
|
365
|
-
try {
|
|
366
|
-
// Build WebSocket URL with optional token parameter
|
|
367
|
-
const wsUrl = this.token
|
|
368
|
-
? `${SOCKET_URL}?token=${this.token}`
|
|
369
|
-
: SOCKET_URL;
|
|
370
|
-
console.log("SOCKET: connecting to", wsUrl.replace(/token=[^&]*/, "token=***"));
|
|
371
|
-
this.ws = new WebSocket(wsUrl);
|
|
372
|
-
}
|
|
373
|
-
catch (e) {
|
|
374
|
-
console.error("[socket creation error]", e);
|
|
375
|
-
this.scheduleReconnect();
|
|
376
|
-
return;
|
|
377
|
-
}
|
|
378
|
-
// Bind event handlers to maintain proper 'this' context
|
|
379
|
-
this.onMessage = this.onMessage.bind(this);
|
|
380
|
-
this.onClose = this.onClose.bind(this);
|
|
381
|
-
this.onOpen = this.onOpen.bind(this);
|
|
382
|
-
this.onError = this.onError.bind(this);
|
|
383
|
-
// Attach event listeners
|
|
384
|
-
this.ws.addEventListener("message", this.onMessage);
|
|
385
|
-
this.ws.addEventListener("close", this.onClose);
|
|
386
|
-
this.ws.addEventListener("open", this.onOpen);
|
|
387
|
-
this.ws.addEventListener("error", this.onError);
|
|
388
|
-
}
|
|
389
|
-
// Handle incoming messages from server
|
|
390
|
-
onMessage(message) {
|
|
391
|
-
if (!message.data)
|
|
392
|
-
return;
|
|
393
|
-
try {
|
|
394
|
-
const obj = JSON.parse(message.data);
|
|
395
|
-
// Skip messages without ID (can't route them)
|
|
396
|
-
if (!obj.id)
|
|
397
|
-
return;
|
|
398
|
-
// Route response to the corresponding inflight request
|
|
399
|
-
if (this.inflight[obj.id]) {
|
|
400
|
-
this.inflight[obj.id].onReceived(obj.response);
|
|
401
|
-
}
|
|
402
|
-
}
|
|
403
|
-
catch (e) {
|
|
404
|
-
console.error("[socket message parse error]", e);
|
|
405
|
-
}
|
|
406
|
-
}
|
|
407
|
-
// Handle connection closure - automatically attempt reconnection
|
|
408
|
-
onClose(event) {
|
|
409
|
-
console.log("[socket close]", event.code, event.reason);
|
|
410
|
-
this.lastError = `Connection closed: ${event.reason || "Unknown reason"}`;
|
|
411
|
-
this.ws = undefined;
|
|
412
|
-
this.notifyStateChange();
|
|
413
|
-
this.scheduleReconnect();
|
|
414
|
-
}
|
|
415
|
-
// Handle successful connection
|
|
416
|
-
onOpen() {
|
|
417
|
-
console.log("[socket open]");
|
|
418
|
-
this.reconnectAttempts = 0; // Reset reconnection attempts on success
|
|
419
|
-
this.reconnectionState = "idle"; // Reset connection state
|
|
420
|
-
this.lastError = undefined; // Clear any previous errors
|
|
421
|
-
// Clear any pending reconnect timer
|
|
422
|
-
if (this.reconnectTimer) {
|
|
423
|
-
clearTimeout(this.reconnectTimer);
|
|
424
|
-
this.reconnectTimer = undefined;
|
|
425
|
-
}
|
|
426
|
-
// Notify UI of successful connection
|
|
427
|
-
this.notifyStateChange();
|
|
428
|
-
}
|
|
429
|
-
// Handle socket errors
|
|
430
|
-
onError(event) {
|
|
431
|
-
console.error("[socket error]", event);
|
|
432
|
-
this.lastError = "Connection error occurred";
|
|
433
|
-
this.notifyStateChange();
|
|
434
|
-
}
|
|
435
|
-
/**
|
|
436
|
-
* Schedules a reconnection attempt with exponential backoff
|
|
437
|
-
*/
|
|
438
|
-
scheduleReconnect() {
|
|
439
|
-
// Prevent concurrent reconnection attempts
|
|
440
|
-
if (this.reconnectionState === "reconnecting") {
|
|
441
|
-
console.log("[socket] Reconnection already in progress, skipping");
|
|
442
|
-
return;
|
|
443
|
-
}
|
|
444
|
-
// Don't schedule if already scheduled
|
|
445
|
-
if (this.reconnectTimer)
|
|
446
|
-
return;
|
|
447
|
-
this.reconnectionState = "reconnecting";
|
|
448
|
-
this.reconnectAttempts++;
|
|
449
|
-
this.notifyStateChange(); // Notify UI of reconnection attempt
|
|
450
|
-
if (this.reconnectAttempts > this.maxReconnectAttempts) {
|
|
451
|
-
console.error("[socket] Max reconnection attempts reached");
|
|
452
|
-
this.reconnectionState = "failed";
|
|
453
|
-
this.lastError = "Max reconnection attempts exceeded";
|
|
454
|
-
this.notifyStateChange();
|
|
455
|
-
// Notify all pending requests of the failure
|
|
456
|
-
for (const mid in this.inflight) {
|
|
457
|
-
this.inflight[mid].error(new Error("WebSocket connection failed"));
|
|
458
|
-
}
|
|
459
|
-
return;
|
|
460
|
-
}
|
|
461
|
-
// Calculate exponential backoff with jitter
|
|
462
|
-
const backoffDelay = Math.min(SOCKET_RECONNECTION_TIMEOUT * Math.pow(2, this.reconnectAttempts - 1) +
|
|
463
|
-
Math.random() * 1000, 30000);
|
|
464
|
-
console.log(`[socket] Reconnecting in ${backoffDelay}ms (attempt ${this.reconnectAttempts}/${this.maxReconnectAttempts})`);
|
|
465
|
-
this.reconnectTimer = setTimeout(() => {
|
|
466
|
-
this.reconnectTimer = undefined;
|
|
467
|
-
this.reopen();
|
|
468
|
-
}, backoffDelay);
|
|
469
|
-
}
|
|
470
|
-
/**
|
|
471
|
-
* Reopens the WebSocket connection (used after connection failures)
|
|
472
|
-
*/
|
|
473
|
-
reopen() {
|
|
474
|
-
console.log("[socket reopen]");
|
|
475
|
-
// Check if we're already connected or connecting
|
|
476
|
-
if (this.ws &&
|
|
477
|
-
(this.ws.readyState === WebSocket.OPEN ||
|
|
478
|
-
this.ws.readyState === WebSocket.CONNECTING)) {
|
|
479
|
-
return;
|
|
480
|
-
}
|
|
481
|
-
this.openSocket();
|
|
482
|
-
}
|
|
483
|
-
/**
|
|
484
|
-
* Closes the WebSocket connection and cleans up
|
|
485
|
-
*/
|
|
486
|
-
close() {
|
|
487
|
-
// Clear reconnection timer
|
|
488
|
-
if (this.reconnectTimer) {
|
|
489
|
-
clearTimeout(this.reconnectTimer);
|
|
490
|
-
this.reconnectTimer = undefined;
|
|
491
|
-
}
|
|
492
|
-
// Clean up WebSocket
|
|
493
|
-
if (this.ws) {
|
|
494
|
-
// Remove event listeners to prevent memory leaks
|
|
495
|
-
this.ws.removeEventListener("message", this.onMessage);
|
|
496
|
-
this.ws.removeEventListener("close", this.onClose);
|
|
497
|
-
this.ws.removeEventListener("open", this.onOpen);
|
|
498
|
-
this.ws.removeEventListener("error", this.onError);
|
|
499
|
-
this.ws.close();
|
|
500
|
-
this.ws = undefined;
|
|
501
|
-
}
|
|
502
|
-
// Clear any remaining inflight requests
|
|
503
|
-
for (const mid in this.inflight) {
|
|
504
|
-
this.inflight[mid].error(new Error("Socket closed"));
|
|
505
|
-
}
|
|
506
|
-
this.inflight = {};
|
|
507
|
-
}
|
|
508
|
-
/**
|
|
509
|
-
* Generates the next unique message ID for requests
|
|
510
|
-
* Format: {clientTag}-{incrementingNumber}
|
|
511
|
-
*/
|
|
512
|
-
getNextId() {
|
|
513
|
-
const mid = this.tag + "-" + this.id.toString();
|
|
514
|
-
this.id++;
|
|
515
|
-
return mid;
|
|
516
|
-
}
|
|
517
|
-
/**
|
|
518
|
-
* Core method for making service requests over WebSocket
|
|
519
|
-
* @param service - Name of the service to call
|
|
520
|
-
* @param request - Request payload
|
|
521
|
-
* @param timeout - Request timeout in milliseconds (default: 10000)
|
|
522
|
-
* @param retries - Number of retry attempts (default: 3)
|
|
523
|
-
* @param flow - Optional flow identifier
|
|
524
|
-
* @returns Promise resolving to the service response
|
|
525
|
-
*/
|
|
526
|
-
makeRequest(service, request, timeout, retries, flow) {
|
|
527
|
-
const mid = this.getNextId();
|
|
528
|
-
// Set default values
|
|
529
|
-
if (timeout == undefined)
|
|
530
|
-
timeout = 10000;
|
|
531
|
-
if (retries == undefined)
|
|
532
|
-
retries = 3;
|
|
533
|
-
// Construct the request message
|
|
534
|
-
const msg = {
|
|
535
|
-
id: mid,
|
|
536
|
-
service: service,
|
|
537
|
-
request: request,
|
|
538
|
-
};
|
|
539
|
-
// Add flow identifier if provided
|
|
540
|
-
if (flow)
|
|
541
|
-
msg.flow = flow;
|
|
542
|
-
// Return a Promise that will be resolved/rejected by the ServiceCall
|
|
543
|
-
return new Promise((resolve, reject) => {
|
|
544
|
-
const call = new ServiceCall(mid, msg, resolve, reject, timeout, retries, this);
|
|
545
|
-
call.start();
|
|
546
|
-
// Commented out debug logging: console.log("-->", msg);
|
|
547
|
-
}).then((obj) => {
|
|
548
|
-
// Commented out success logging: console.log("Success for", mid);
|
|
549
|
-
return obj;
|
|
550
|
-
});
|
|
551
|
-
}
|
|
552
|
-
/**
|
|
553
|
-
* Makes a request that can receive multiple responses (streaming)
|
|
554
|
-
* Used for operations that return data in chunks
|
|
555
|
-
*/
|
|
556
|
-
makeRequestMulti(service, request, receiver, // Callback to handle each response chunk
|
|
557
|
-
timeout, retries, flow) {
|
|
558
|
-
const mid = this.getNextId();
|
|
559
|
-
// Set defaults
|
|
560
|
-
if (timeout == undefined)
|
|
561
|
-
timeout = 10000;
|
|
562
|
-
if (retries == undefined)
|
|
563
|
-
retries = 3;
|
|
564
|
-
// Construct request message
|
|
565
|
-
const msg = {
|
|
566
|
-
id: mid,
|
|
567
|
-
service: service,
|
|
568
|
-
request: request,
|
|
569
|
-
};
|
|
570
|
-
if (flow)
|
|
571
|
-
msg.flow = flow;
|
|
572
|
-
return new Promise((resolve, reject) => {
|
|
573
|
-
const call = new ServiceCallMulti(mid, msg, resolve, reject, timeout, retries, this, // eslint-disable-line @typescript-eslint/no-explicit-any
|
|
574
|
-
receiver);
|
|
575
|
-
call.start();
|
|
576
|
-
}).then((obj) => {
|
|
577
|
-
return obj;
|
|
578
|
-
});
|
|
579
|
-
}
|
|
580
|
-
/**
|
|
581
|
-
* Convenience method for making flow-specific requests
|
|
582
|
-
* Defaults to "default" flow if none specified
|
|
583
|
-
*/
|
|
584
|
-
makeFlowRequest(service, request, timeout, retries, flow) {
|
|
585
|
-
if (!flow)
|
|
586
|
-
flow = "default";
|
|
587
|
-
return this.makeRequest(service, request, timeout, retries, flow);
|
|
588
|
-
}
|
|
589
|
-
// Factory methods for creating specialized API instances
|
|
590
|
-
librarian() {
|
|
591
|
-
return new LibrarianApi(this);
|
|
592
|
-
}
|
|
593
|
-
flows() {
|
|
594
|
-
return new FlowsApi(this);
|
|
595
|
-
}
|
|
596
|
-
flow(id) {
|
|
597
|
-
return new FlowApi(this, id);
|
|
598
|
-
}
|
|
599
|
-
knowledge() {
|
|
600
|
-
return new KnowledgeApi(this);
|
|
601
|
-
}
|
|
602
|
-
config() {
|
|
603
|
-
return new ConfigApi(this);
|
|
604
|
-
}
|
|
605
|
-
collectionManagement() {
|
|
606
|
-
return new CollectionManagementApi(this);
|
|
607
|
-
}
|
|
608
|
-
}
|
|
609
|
-
/**
|
|
610
|
-
* LibrarianApi - Manages document storage and retrieval
|
|
611
|
-
* Handles document lifecycle including upload, processing, and removal
|
|
612
|
-
*/
|
|
613
|
-
class LibrarianApi {
|
|
614
|
-
constructor(api) {
|
|
615
|
-
this.api = api;
|
|
616
|
-
}
|
|
617
|
-
/**
|
|
618
|
-
* Retrieves list of all documents in the system
|
|
619
|
-
*/
|
|
620
|
-
getDocuments() {
|
|
621
|
-
return this.api
|
|
622
|
-
.makeRequest("librarian", {
|
|
623
|
-
operation: "list-documents",
|
|
624
|
-
user: "trustgraph",
|
|
625
|
-
}, 60000)
|
|
626
|
-
.then((r) => r["document-metadatas"]);
|
|
627
|
-
}
|
|
628
|
-
/**
|
|
629
|
-
* Retrieves list of documents currently being processed
|
|
630
|
-
*/
|
|
631
|
-
getProcessing() {
|
|
632
|
-
return this.api
|
|
633
|
-
.makeRequest("librarian", {
|
|
634
|
-
operation: "list-processing",
|
|
635
|
-
user: "trustgraph",
|
|
636
|
-
}, 60000)
|
|
637
|
-
.then((r) => r["processing-metadata"]);
|
|
638
|
-
}
|
|
639
|
-
/**
|
|
640
|
-
* Uploads a document to the library with full metadata
|
|
641
|
-
* @param document - Base64-encoded document content
|
|
642
|
-
* @param id - Optional document identifier
|
|
643
|
-
* @param metadata - Optional metadata as triples
|
|
644
|
-
* @param mimeType - Document MIME type
|
|
645
|
-
* @param title - Document title
|
|
646
|
-
* @param comments - Additional comments
|
|
647
|
-
* @param tags - Document tags for categorization
|
|
648
|
-
* @param user - User identifier
|
|
649
|
-
*/
|
|
650
|
-
loadDocument(document, // base64-encoded doc
|
|
651
|
-
mimeType, title, comments, tags, user, id, metadata) {
|
|
652
|
-
return this.api.makeRequest("librarian", {
|
|
653
|
-
operation: "add-document",
|
|
654
|
-
"document-metadata": {
|
|
655
|
-
id: id,
|
|
656
|
-
time: Math.floor(Date.now() / 1000), // Unix timestamp
|
|
657
|
-
kind: mimeType,
|
|
658
|
-
title: title,
|
|
659
|
-
comments: comments,
|
|
660
|
-
metadata: metadata,
|
|
661
|
-
user: user ? user : "trustgraph",
|
|
662
|
-
tags: tags,
|
|
663
|
-
},
|
|
664
|
-
content: document,
|
|
665
|
-
}, 30000);
|
|
666
|
-
}
|
|
667
|
-
/**
|
|
668
|
-
* Removes a document from the library
|
|
669
|
-
*/
|
|
670
|
-
removeDocument(id, collection) {
|
|
671
|
-
return this.api.makeRequest("librarian", {
|
|
672
|
-
operation: "remove-document",
|
|
673
|
-
"document-id": id,
|
|
674
|
-
user: this.api.user,
|
|
675
|
-
collection: collection || "default",
|
|
676
|
-
}, 30000);
|
|
677
|
-
}
|
|
678
|
-
/**
|
|
679
|
-
* Adds a document to the processing queue
|
|
680
|
-
* @param id - Processing job identifier
|
|
681
|
-
* @param doc_id - Document to process
|
|
682
|
-
* @param flow - Processing flow to use
|
|
683
|
-
* @param user - User identifier
|
|
684
|
-
* @param collection - Collection to add processed data to
|
|
685
|
-
* @param tags - Tags for the processing job
|
|
686
|
-
*/
|
|
687
|
-
addProcessing(id, doc_id, flow, user, collection, tags) {
|
|
688
|
-
return this.api.makeRequest("librarian", {
|
|
689
|
-
operation: "add-processing",
|
|
690
|
-
"processing-metadata": {
|
|
691
|
-
id: id,
|
|
692
|
-
"document-id": doc_id,
|
|
693
|
-
time: Math.floor(Date.now() / 1000),
|
|
694
|
-
flow: flow,
|
|
695
|
-
user: user ? user : "trustgraph",
|
|
696
|
-
collection: collection ? collection : "default",
|
|
697
|
-
tags: tags ? tags : [],
|
|
698
|
-
},
|
|
699
|
-
}, 30000);
|
|
700
|
-
}
|
|
701
|
-
}
|
|
702
|
-
/**
|
|
703
|
-
* FlowsApi - Manages processing flows and configuration
|
|
704
|
-
* Flows define how documents and data are processed through the system
|
|
705
|
-
*/
|
|
706
|
-
class FlowsApi {
|
|
707
|
-
constructor(api) {
|
|
708
|
-
this.api = api;
|
|
709
|
-
}
|
|
710
|
-
/**
|
|
711
|
-
* Retrieves list of available flows
|
|
712
|
-
*/
|
|
713
|
-
getFlows() {
|
|
714
|
-
return this.api
|
|
715
|
-
.makeRequest("flow", {
|
|
716
|
-
operation: "list-flows",
|
|
717
|
-
}, 60000)
|
|
718
|
-
.then((r) => r["flow-ids"] || []);
|
|
719
|
-
}
|
|
720
|
-
/**
|
|
721
|
-
* Retrieves definition of a specific flow
|
|
722
|
-
*/
|
|
723
|
-
getFlow(id) {
|
|
724
|
-
return this.api
|
|
725
|
-
.makeRequest("flow", {
|
|
726
|
-
operation: "get-flow",
|
|
727
|
-
"flow-id": id,
|
|
728
|
-
}, 60000)
|
|
729
|
-
.then((r) => JSON.parse(r.flow || "{}")); // Parse JSON flow definition
|
|
730
|
-
}
|
|
731
|
-
// Configuration management methods
|
|
732
|
-
/**
|
|
733
|
-
* Retrieves all configuration settings
|
|
734
|
-
*/
|
|
735
|
-
getConfigAll() {
|
|
736
|
-
return this.api.makeRequest("config", {
|
|
737
|
-
operation: "config",
|
|
738
|
-
}, 60000);
|
|
739
|
-
}
|
|
740
|
-
/**
|
|
741
|
-
* Retrieves specific configuration values by key
|
|
742
|
-
*/
|
|
743
|
-
getConfig(keys) {
|
|
744
|
-
return this.api.makeRequest("config", {
|
|
745
|
-
operation: "get",
|
|
746
|
-
keys: keys,
|
|
747
|
-
}, 60000);
|
|
748
|
-
}
|
|
749
|
-
/**
|
|
750
|
-
* Updates configuration values
|
|
751
|
-
*/
|
|
752
|
-
putConfig(values) {
|
|
753
|
-
return this.api.makeRequest("config", {
|
|
754
|
-
operation: "put",
|
|
755
|
-
values: values,
|
|
756
|
-
}, 60000);
|
|
757
|
-
}
|
|
758
|
-
/**
|
|
759
|
-
* Deletes configuration entries
|
|
760
|
-
*/
|
|
761
|
-
deleteConfig(keys) {
|
|
762
|
-
return this.api.makeRequest("config", {
|
|
763
|
-
operation: "delete",
|
|
764
|
-
keys: keys,
|
|
765
|
-
}, 30000);
|
|
766
|
-
}
|
|
767
|
-
// Prompt management - specialized config operations for AI prompts
|
|
768
|
-
/**
|
|
769
|
-
* Retrieves list of available prompt templates
|
|
770
|
-
*/
|
|
771
|
-
getPrompts() {
|
|
772
|
-
return this.getConfigAll().then((r) => {
|
|
773
|
-
const config = r;
|
|
774
|
-
return JSON.parse(config.config.prompt["template-index"]);
|
|
775
|
-
});
|
|
776
|
-
}
|
|
777
|
-
/**
|
|
778
|
-
* Retrieves a specific prompt template
|
|
779
|
-
*/
|
|
780
|
-
getPrompt(id) {
|
|
781
|
-
return this.getConfigAll().then((r) => {
|
|
782
|
-
const config = r;
|
|
783
|
-
return JSON.parse(config.config.prompt[`template.${id}`]);
|
|
784
|
-
});
|
|
785
|
-
}
|
|
786
|
-
/**
|
|
787
|
-
* Retrieves the system prompt configuration
|
|
788
|
-
*/
|
|
789
|
-
getSystemPrompt() {
|
|
790
|
-
return this.getConfigAll().then((r) => {
|
|
791
|
-
const config = r;
|
|
792
|
-
return JSON.parse(config.config.prompt.system);
|
|
793
|
-
});
|
|
794
|
-
}
|
|
795
|
-
// Flow class management - templates for creating flows
|
|
796
|
-
/**
|
|
797
|
-
* Retrieves list of available flow classes (templates)
|
|
798
|
-
*/
|
|
799
|
-
getFlowClasses() {
|
|
800
|
-
return this.api
|
|
801
|
-
.makeRequest("flow", {
|
|
802
|
-
operation: "list-classes",
|
|
803
|
-
}, 60000)
|
|
804
|
-
.then((r) => r["class-names"]);
|
|
805
|
-
}
|
|
806
|
-
/**
|
|
807
|
-
* Retrieves definition of a specific flow class
|
|
808
|
-
*/
|
|
809
|
-
getFlowClass(name) {
|
|
810
|
-
return this.api
|
|
811
|
-
.makeRequest("flow", {
|
|
812
|
-
operation: "get-class",
|
|
813
|
-
"class-name": name,
|
|
814
|
-
}, 60000)
|
|
815
|
-
.then((r) => JSON.parse(r["class-definition"] || "{}"));
|
|
816
|
-
}
|
|
817
|
-
/**
|
|
818
|
-
* Deletes a flow class
|
|
819
|
-
*/
|
|
820
|
-
deleteFlowClass(name) {
|
|
821
|
-
return this.api.makeRequest("flow", {
|
|
822
|
-
operation: "delete-class",
|
|
823
|
-
"class-name": name,
|
|
824
|
-
}, 30000);
|
|
825
|
-
}
|
|
826
|
-
// Flow lifecycle management
|
|
827
|
-
/**
|
|
828
|
-
* Starts a new flow instance
|
|
829
|
-
*/
|
|
830
|
-
startFlow(id, class_name, description, parameters) {
|
|
831
|
-
const request = {
|
|
832
|
-
operation: "start-flow",
|
|
833
|
-
"flow-id": id,
|
|
834
|
-
"class-name": class_name,
|
|
835
|
-
description: description,
|
|
836
|
-
};
|
|
837
|
-
// Only include parameters if provided and not empty
|
|
838
|
-
if (parameters && Object.keys(parameters).length > 0) {
|
|
839
|
-
request.parameters = parameters;
|
|
840
|
-
}
|
|
841
|
-
return this.api
|
|
842
|
-
.makeRequest("flow", request, 30000)
|
|
843
|
-
.then((response) => {
|
|
844
|
-
if (response.error) {
|
|
845
|
-
let errorMessage = "Flow start failed";
|
|
846
|
-
if (typeof response.error === "object" &&
|
|
847
|
-
response.error &&
|
|
848
|
-
"message" in response.error) {
|
|
849
|
-
errorMessage =
|
|
850
|
-
response.error.message || errorMessage;
|
|
851
|
-
}
|
|
852
|
-
else if (typeof response.error === "string") {
|
|
853
|
-
errorMessage = response.error;
|
|
854
|
-
}
|
|
855
|
-
throw new Error(errorMessage);
|
|
856
|
-
}
|
|
857
|
-
return response;
|
|
858
|
-
});
|
|
859
|
-
}
|
|
860
|
-
/**
|
|
861
|
-
* Stops a running flow instance
|
|
862
|
-
*/
|
|
863
|
-
stopFlow(id) {
|
|
864
|
-
return this.api.makeRequest("flow", {
|
|
865
|
-
operation: "stop-flow",
|
|
866
|
-
"flow-id": id,
|
|
867
|
-
}, 30000);
|
|
868
|
-
}
|
|
869
|
-
}
|
|
870
|
-
/**
|
|
871
|
-
* FlowApi - Interface for interacting with a specific flow instance
|
|
872
|
-
* Provides flow-specific versions of core AI/ML operations
|
|
873
|
-
*/
|
|
874
|
-
class FlowApi {
|
|
875
|
-
constructor(api, flowId) {
|
|
876
|
-
this.api = api;
|
|
877
|
-
this.flowId = flowId; // All requests will be routed through this flow
|
|
878
|
-
}
|
|
879
|
-
/**
|
|
880
|
-
* Performs text completion using AI models within this flow
|
|
881
|
-
*/
|
|
882
|
-
textCompletion(system, text) {
|
|
883
|
-
return this.api
|
|
884
|
-
.makeRequest("text-completion", {
|
|
885
|
-
system: system, // System prompt/instructions
|
|
886
|
-
prompt: text, // User prompt
|
|
887
|
-
}, 30000, undefined, // Use default retries
|
|
888
|
-
this.flowId)
|
|
889
|
-
.then((r) => r.response);
|
|
890
|
-
}
|
|
891
|
-
/**
|
|
892
|
-
* Performs Graph RAG (Retrieval Augmented Generation) query
|
|
893
|
-
*/
|
|
894
|
-
graphRag(text, options, collection) {
|
|
895
|
-
return this.api
|
|
896
|
-
.makeRequest("graph-rag", {
|
|
897
|
-
query: text,
|
|
898
|
-
user: this.api.user,
|
|
899
|
-
collection: collection || "default",
|
|
900
|
-
"entity-limit": options?.entityLimit,
|
|
901
|
-
"triple-limit": options?.tripleLimit,
|
|
902
|
-
"max-subgraph-size": options?.maxSubgraphSize,
|
|
903
|
-
"max-path-length": options?.pathLength,
|
|
904
|
-
}, 60000, // Longer timeout for complex graph operations
|
|
905
|
-
undefined, this.flowId)
|
|
906
|
-
.then((r) => r.response);
|
|
907
|
-
}
|
|
908
|
-
/**
|
|
909
|
-
* Performs Document RAG (Retrieval Augmented Generation) query
|
|
910
|
-
*/
|
|
911
|
-
documentRag(text, docLimit, collection) {
|
|
912
|
-
return this.api
|
|
913
|
-
.makeRequest("document-rag", {
|
|
914
|
-
query: text,
|
|
915
|
-
user: this.api.user,
|
|
916
|
-
collection: collection || "default",
|
|
917
|
-
"doc-limit": docLimit || 20,
|
|
918
|
-
}, 60000, // Longer timeout for document operations
|
|
919
|
-
undefined, this.flowId)
|
|
920
|
-
.then((r) => r.response);
|
|
921
|
-
}
|
|
922
|
-
/**
|
|
923
|
-
* Interacts with an AI agent that provides streaming responses
|
|
924
|
-
*/
|
|
925
|
-
agent(question, think, // Called when agent is thinking
|
|
926
|
-
observe, // Called when agent observes something
|
|
927
|
-
answer, // Called when agent provides answer
|
|
928
|
-
error) {
|
|
929
|
-
// Create a receiver function to handle streaming responses
|
|
930
|
-
const receiver = (response) => {
|
|
931
|
-
console.log("Agent response received:", response);
|
|
932
|
-
const resp = response;
|
|
933
|
-
// Check for backend errors
|
|
934
|
-
if (resp.error) {
|
|
935
|
-
const errorObj = resp.error;
|
|
936
|
-
const errorMessage = (typeof errorObj.message === "string" ? errorObj.message : null) ||
|
|
937
|
-
"Unknown agent error";
|
|
938
|
-
error(`Agent error: ${errorMessage}`);
|
|
939
|
-
return true; // End streaming on error
|
|
940
|
-
}
|
|
941
|
-
// Handle different response types
|
|
942
|
-
if (typeof resp.thought === "string")
|
|
943
|
-
think(resp.thought);
|
|
944
|
-
if (typeof resp.observation === "string")
|
|
945
|
-
observe(resp.observation);
|
|
946
|
-
if (typeof resp.answer === "string") {
|
|
947
|
-
answer(resp.answer);
|
|
948
|
-
return true; // End streaming when final answer is received
|
|
949
|
-
}
|
|
950
|
-
return false; // Continue streaming
|
|
951
|
-
};
|
|
952
|
-
// Use the existing makeRequestMulti infrastructure
|
|
953
|
-
return this.api
|
|
954
|
-
.makeRequestMulti("agent", {
|
|
955
|
-
question: question,
|
|
956
|
-
user: this.api.user,
|
|
957
|
-
}, receiver, 120000, // 120 second timeout
|
|
958
|
-
2, // 2 retries
|
|
959
|
-
this.flowId)
|
|
960
|
-
.catch((err) => {
|
|
961
|
-
// Handle any errors from makeRequestMulti
|
|
962
|
-
const errorMessage = err instanceof Error
|
|
963
|
-
? err.message
|
|
964
|
-
: err?.toString() || "Unknown error";
|
|
965
|
-
error(`Agent request failed: ${errorMessage}`);
|
|
966
|
-
});
|
|
967
|
-
}
|
|
968
|
-
/**
|
|
969
|
-
* Generates embeddings for text within this flow
|
|
970
|
-
*/
|
|
971
|
-
embeddings(text) {
|
|
972
|
-
return this.api
|
|
973
|
-
.makeRequest("embeddings", {
|
|
974
|
-
text: text,
|
|
975
|
-
}, 30000, undefined, this.flowId)
|
|
976
|
-
.then((r) => r.vectors);
|
|
977
|
-
}
|
|
978
|
-
/**
|
|
979
|
-
* Queries the knowledge graph using embedding vectors
|
|
980
|
-
*/
|
|
981
|
-
graphEmbeddingsQuery(vecs, limit, collection) {
|
|
982
|
-
return this.api
|
|
983
|
-
.makeRequest("graph-embeddings", {
|
|
984
|
-
vectors: vecs,
|
|
985
|
-
limit: limit ? limit : 20, // Default to 20 results
|
|
986
|
-
user: this.api.user,
|
|
987
|
-
collection: collection || "default",
|
|
988
|
-
}, 30000, undefined, this.flowId)
|
|
989
|
-
.then((r) => r.entities);
|
|
990
|
-
}
|
|
991
|
-
/**
|
|
992
|
-
* Queries knowledge graph triples (subject-predicate-object relationships)
|
|
993
|
-
* All parameters are optional - omitted parameters act as wildcards
|
|
994
|
-
*/
|
|
995
|
-
triplesQuery(s, p, o, limit, collection) {
|
|
996
|
-
return this.api
|
|
997
|
-
.makeRequest("triples", {
|
|
998
|
-
s: s, // Subject
|
|
999
|
-
p: p, // Predicate
|
|
1000
|
-
o: o, // Object
|
|
1001
|
-
limit: limit ? limit : 20,
|
|
1002
|
-
user: this.api.user,
|
|
1003
|
-
collection: collection || "default",
|
|
1004
|
-
}, 30000, undefined, this.flowId)
|
|
1005
|
-
.then((r) => r.response);
|
|
1006
|
-
}
|
|
1007
|
-
/**
|
|
1008
|
-
* Loads a document into this flow for processing
|
|
1009
|
-
*/
|
|
1010
|
-
loadDocument(document, // base64-encoded document
|
|
1011
|
-
id, metadata) {
|
|
1012
|
-
return this.api.makeRequest("document-load", {
|
|
1013
|
-
id: id,
|
|
1014
|
-
metadata: metadata,
|
|
1015
|
-
data: document,
|
|
1016
|
-
}, 30000, undefined, this.flowId);
|
|
1017
|
-
}
|
|
1018
|
-
/**
|
|
1019
|
-
* Loads plain text into this flow for processing
|
|
1020
|
-
*/
|
|
1021
|
-
loadText(text, // Text content
|
|
1022
|
-
id, metadata, charset) {
|
|
1023
|
-
return this.api.makeRequest("text-load", {
|
|
1024
|
-
id: id,
|
|
1025
|
-
metadata: metadata,
|
|
1026
|
-
text: text,
|
|
1027
|
-
charset: charset,
|
|
1028
|
-
}, 30000, undefined, this.flowId);
|
|
1029
|
-
}
|
|
1030
|
-
/**
|
|
1031
|
-
* Executes a GraphQL query against structured data objects
|
|
1032
|
-
*/
|
|
1033
|
-
objectsQuery(query, collection, variables, operationName) {
|
|
1034
|
-
return this.api
|
|
1035
|
-
.makeRequest("objects", {
|
|
1036
|
-
query: query,
|
|
1037
|
-
user: this.api.user,
|
|
1038
|
-
collection: collection || "default",
|
|
1039
|
-
variables: variables,
|
|
1040
|
-
operation_name: operationName,
|
|
1041
|
-
}, 30000, undefined, this.flowId)
|
|
1042
|
-
.then((r) => {
|
|
1043
|
-
// Return the GraphQL response structure directly
|
|
1044
|
-
const result = {};
|
|
1045
|
-
if (r.data !== undefined)
|
|
1046
|
-
result.data = r.data;
|
|
1047
|
-
if (r.errors)
|
|
1048
|
-
result.errors = r.errors;
|
|
1049
|
-
if (r.extensions)
|
|
1050
|
-
result.extensions = r.extensions;
|
|
1051
|
-
return result;
|
|
1052
|
-
});
|
|
1053
|
-
}
|
|
1054
|
-
/**
|
|
1055
|
-
* Converts a natural language question to a GraphQL query
|
|
1056
|
-
*/
|
|
1057
|
-
nlpQuery(question, maxResults) {
|
|
1058
|
-
return this.api
|
|
1059
|
-
.makeRequest("nlp-query", {
|
|
1060
|
-
question: question,
|
|
1061
|
-
max_results: maxResults || 100,
|
|
1062
|
-
}, 30000, undefined, this.flowId)
|
|
1063
|
-
.then((r) => r);
|
|
1064
|
-
}
|
|
1065
|
-
/**
|
|
1066
|
-
* Executes a natural language question against structured data
|
|
1067
|
-
* Combines NLP query conversion and GraphQL execution
|
|
1068
|
-
*/
|
|
1069
|
-
structuredQuery(question, collection) {
|
|
1070
|
-
return this.api
|
|
1071
|
-
.makeRequest("structured-query", {
|
|
1072
|
-
question: question,
|
|
1073
|
-
user: this.api.user,
|
|
1074
|
-
collection: collection || "default",
|
|
1075
|
-
}, 30000, undefined, this.flowId)
|
|
1076
|
-
.then((r) => {
|
|
1077
|
-
// Return the response structure directly
|
|
1078
|
-
const result = {};
|
|
1079
|
-
if (r.data !== undefined)
|
|
1080
|
-
result.data = r.data;
|
|
1081
|
-
if (r.errors)
|
|
1082
|
-
result.errors = r.errors;
|
|
1083
|
-
return result;
|
|
1084
|
-
});
|
|
1085
|
-
}
|
|
1086
|
-
}
|
|
1087
|
-
/**
|
|
1088
|
-
* ConfigApi - Dedicated configuration management interface
|
|
1089
|
-
* Handles system configuration, prompts, and token cost tracking
|
|
1090
|
-
*/
|
|
1091
|
-
class ConfigApi {
|
|
1092
|
-
constructor(api) {
|
|
1093
|
-
this.api = api;
|
|
1094
|
-
}
|
|
1095
|
-
/**
|
|
1096
|
-
* Retrieves complete configuration
|
|
1097
|
-
*/
|
|
1098
|
-
getConfigAll() {
|
|
1099
|
-
return this.api.makeRequest("config", {
|
|
1100
|
-
operation: "config",
|
|
1101
|
-
}, 60000);
|
|
1102
|
-
}
|
|
1103
|
-
/**
|
|
1104
|
-
* Retrieves specific configuration entries
|
|
1105
|
-
*/
|
|
1106
|
-
getConfig(keys) {
|
|
1107
|
-
return this.api.makeRequest("config", {
|
|
1108
|
-
operation: "get",
|
|
1109
|
-
keys: keys,
|
|
1110
|
-
}, 60000);
|
|
1111
|
-
}
|
|
1112
|
-
/**
|
|
1113
|
-
* Updates configuration values
|
|
1114
|
-
*/
|
|
1115
|
-
putConfig(values) {
|
|
1116
|
-
return this.api.makeRequest("config", {
|
|
1117
|
-
operation: "put",
|
|
1118
|
-
values: values,
|
|
1119
|
-
}, 60000);
|
|
1120
|
-
}
|
|
1121
|
-
/**
|
|
1122
|
-
* Deletes configuration entries
|
|
1123
|
-
*/
|
|
1124
|
-
deleteConfig(keys) {
|
|
1125
|
-
return this.api.makeRequest("config", {
|
|
1126
|
-
operation: "delete",
|
|
1127
|
-
keys: keys,
|
|
1128
|
-
}, 30000);
|
|
1129
|
-
}
|
|
1130
|
-
// Specialized prompt management methods
|
|
1131
|
-
/**
|
|
1132
|
-
* Retrieves available prompt templates
|
|
1133
|
-
*/
|
|
1134
|
-
getPrompts() {
|
|
1135
|
-
return this.getConfigAll().then((r) => {
|
|
1136
|
-
const config = r;
|
|
1137
|
-
return JSON.parse(config.config.prompt["template-index"]);
|
|
1138
|
-
});
|
|
1139
|
-
}
|
|
1140
|
-
/**
|
|
1141
|
-
* Retrieves a specific prompt template
|
|
1142
|
-
*/
|
|
1143
|
-
getPrompt(id) {
|
|
1144
|
-
return this.getConfigAll().then((r) => {
|
|
1145
|
-
const config = r;
|
|
1146
|
-
return JSON.parse(config.config.prompt[`template.${id}`]);
|
|
1147
|
-
});
|
|
1148
|
-
}
|
|
1149
|
-
/**
|
|
1150
|
-
* Retrieves system prompt configuration
|
|
1151
|
-
*/
|
|
1152
|
-
getSystemPrompt() {
|
|
1153
|
-
return this.getConfigAll().then((r) => {
|
|
1154
|
-
const config = r;
|
|
1155
|
-
return JSON.parse(config.config.prompt.system);
|
|
1156
|
-
});
|
|
1157
|
-
}
|
|
1158
|
-
/**
|
|
1159
|
-
* Lists available configuration types
|
|
1160
|
-
*/
|
|
1161
|
-
list(type) {
|
|
1162
|
-
return this.api
|
|
1163
|
-
.makeRequest("config", {
|
|
1164
|
-
operation: "list",
|
|
1165
|
-
type: type,
|
|
1166
|
-
}, 60000)
|
|
1167
|
-
.then((r) => r);
|
|
1168
|
-
}
|
|
1169
|
-
/**
|
|
1170
|
-
* Retrieves all key/values for a specific type
|
|
1171
|
-
*/
|
|
1172
|
-
getValues(type) {
|
|
1173
|
-
return this.api
|
|
1174
|
-
.makeRequest("config", {
|
|
1175
|
-
operation: "getvalues",
|
|
1176
|
-
type: type,
|
|
1177
|
-
}, 60000)
|
|
1178
|
-
.then((r) => r.values);
|
|
1179
|
-
}
|
|
1180
|
-
/**
|
|
1181
|
-
* Retrieves token cost information for different AI models
|
|
1182
|
-
* Useful for cost tracking and optimization
|
|
1183
|
-
*/
|
|
1184
|
-
getTokenCosts() {
|
|
1185
|
-
return this.api
|
|
1186
|
-
.makeRequest("config", {
|
|
1187
|
-
operation: "getvalues",
|
|
1188
|
-
type: "token-costs",
|
|
1189
|
-
}, 60000)
|
|
1190
|
-
.then((r) => {
|
|
1191
|
-
// Parse JSON values and restructure data
|
|
1192
|
-
const response = r;
|
|
1193
|
-
return (response.values || []).map((x) => {
|
|
1194
|
-
const item = x;
|
|
1195
|
-
return { key: item.key, value: JSON.parse(item.value) };
|
|
1196
|
-
});
|
|
1197
|
-
})
|
|
1198
|
-
.then((r) =>
|
|
1199
|
-
// Transform to more usable format
|
|
1200
|
-
r.map((x) => {
|
|
1201
|
-
const item = x;
|
|
1202
|
-
const value = item.value;
|
|
1203
|
-
return {
|
|
1204
|
-
model: item.key,
|
|
1205
|
-
input_price: value.input_price, // Cost per input token
|
|
1206
|
-
output_price: value.output_price, // Cost per output token
|
|
1207
|
-
};
|
|
1208
|
-
}));
|
|
1209
|
-
}
|
|
1210
|
-
}
|
|
1211
|
-
/**
|
|
1212
|
-
* KnowledgeApi - Manages knowledge graph cores and data
|
|
1213
|
-
* Knowledge cores appear to be collections of processed knowledge graph data
|
|
1214
|
-
*/
|
|
1215
|
-
class KnowledgeApi {
|
|
1216
|
-
constructor(api) {
|
|
1217
|
-
this.api = api;
|
|
1218
|
-
}
|
|
1219
|
-
/**
|
|
1220
|
-
* Retrieves list of available knowledge graph cores
|
|
1221
|
-
*/
|
|
1222
|
-
getKnowledgeCores() {
|
|
1223
|
-
return this.api
|
|
1224
|
-
.makeRequest("knowledge", {
|
|
1225
|
-
operation: "list-kg-cores",
|
|
1226
|
-
user: "trustgraph",
|
|
1227
|
-
}, 60000)
|
|
1228
|
-
.then((r) => r.ids);
|
|
1229
|
-
}
|
|
1230
|
-
/**
|
|
1231
|
-
* Deletes a knowledge graph core
|
|
1232
|
-
*/
|
|
1233
|
-
deleteKgCore(id, collection) {
|
|
1234
|
-
return this.api.makeRequest("knowledge", {
|
|
1235
|
-
operation: "delete-kg-core",
|
|
1236
|
-
id: id,
|
|
1237
|
-
user: this.api.user,
|
|
1238
|
-
collection: collection || "default",
|
|
1239
|
-
}, 30000);
|
|
1240
|
-
}
|
|
1241
|
-
/**
|
|
1242
|
-
* Deletes a knowledge graph core
|
|
1243
|
-
*/
|
|
1244
|
-
loadKgCore(id, flow, collection) {
|
|
1245
|
-
return this.api.makeRequest("knowledge", {
|
|
1246
|
-
operation: "load-kg-core",
|
|
1247
|
-
id: id,
|
|
1248
|
-
flow: flow,
|
|
1249
|
-
user: this.api.user,
|
|
1250
|
-
collection: collection || "default",
|
|
1251
|
-
}, 30000);
|
|
1252
|
-
}
|
|
1253
|
-
/**
|
|
1254
|
-
* Retrieves a knowledge graph core with streaming data
|
|
1255
|
-
* Uses multi-request pattern for large datasets
|
|
1256
|
-
* @param receiver - Callback function to handle streaming data chunks
|
|
1257
|
-
*/
|
|
1258
|
-
getKgCore(id, collection, receiver) {
|
|
1259
|
-
// Wrapper to handle end-of-stream detection
|
|
1260
|
-
const recv = (msg) => {
|
|
1261
|
-
const response = msg;
|
|
1262
|
-
if (response.eos) {
|
|
1263
|
-
// End of stream - notify receiver and signal completion
|
|
1264
|
-
receiver(msg, true);
|
|
1265
|
-
return true;
|
|
1266
|
-
}
|
|
1267
|
-
else {
|
|
1268
|
-
// Regular message - continue streaming
|
|
1269
|
-
receiver(msg, false);
|
|
1270
|
-
return false;
|
|
1271
|
-
}
|
|
1272
|
-
};
|
|
1273
|
-
return this.api.makeRequestMulti("knowledge", {
|
|
1274
|
-
operation: "get-kg-core",
|
|
1275
|
-
id: id,
|
|
1276
|
-
user: this.api.user,
|
|
1277
|
-
collection: collection || "default",
|
|
1278
|
-
}, recv, // Stream handler
|
|
1279
|
-
30000);
|
|
1280
|
-
}
|
|
1281
|
-
}
|
|
1282
|
-
/**
|
|
1283
|
-
* CollectionManagementApi - Manages collections for organizing documents
|
|
1284
|
-
* Provides operations for listing, creating, updating, and deleting collections
|
|
1285
|
-
*/
|
|
1286
|
-
class CollectionManagementApi {
|
|
1287
|
-
constructor(api) {
|
|
1288
|
-
this.api = api;
|
|
1289
|
-
}
|
|
1290
|
-
/**
|
|
1291
|
-
* Lists all collections for a user with optional tag filtering
|
|
1292
|
-
* @param user - User identifier
|
|
1293
|
-
* @param tagFilter - Optional array of tags to filter collections
|
|
1294
|
-
* @returns Promise resolving to array of collection metadata
|
|
1295
|
-
*/
|
|
1296
|
-
listCollections(user, tagFilter) {
|
|
1297
|
-
const request = {
|
|
1298
|
-
operation: "list-collections",
|
|
1299
|
-
user,
|
|
1300
|
-
};
|
|
1301
|
-
if (tagFilter && tagFilter.length > 0) {
|
|
1302
|
-
request.tag_filter = tagFilter;
|
|
1303
|
-
}
|
|
1304
|
-
return this.api
|
|
1305
|
-
.makeRequest("collection-management", request, 30000)
|
|
1306
|
-
.then((r) => r.collections || []);
|
|
1307
|
-
}
|
|
1308
|
-
/**
|
|
1309
|
-
* Creates or updates a collection
|
|
1310
|
-
* @param user - User identifier
|
|
1311
|
-
* @param collection - Collection ID (unique identifier)
|
|
1312
|
-
* @param name - Display name for the collection
|
|
1313
|
-
* @param description - Description of the collection
|
|
1314
|
-
* @param tags - Array of tags for categorization
|
|
1315
|
-
* @returns Promise resolving to updated collection metadata
|
|
1316
|
-
*/
|
|
1317
|
-
updateCollection(user, collection, name, description, tags) {
|
|
1318
|
-
const request = {
|
|
1319
|
-
operation: "update-collection",
|
|
1320
|
-
user,
|
|
1321
|
-
collection,
|
|
1322
|
-
};
|
|
1323
|
-
if (name !== undefined) {
|
|
1324
|
-
request.name = name;
|
|
1325
|
-
}
|
|
1326
|
-
if (description !== undefined) {
|
|
1327
|
-
request.description = description;
|
|
1328
|
-
}
|
|
1329
|
-
if (tags !== undefined) {
|
|
1330
|
-
request.tags = tags;
|
|
1331
|
-
}
|
|
1332
|
-
return this.api
|
|
1333
|
-
.makeRequest("collection-management", request, 30000)
|
|
1334
|
-
.then((r) => {
|
|
1335
|
-
if (r.collections &&
|
|
1336
|
-
Array.isArray(r.collections) &&
|
|
1337
|
-
r.collections.length > 0) {
|
|
1338
|
-
return r.collections[0];
|
|
1339
|
-
}
|
|
1340
|
-
throw new Error("Failed to update collection");
|
|
1341
|
-
});
|
|
1342
|
-
}
|
|
1343
|
-
/**
|
|
1344
|
-
* Deletes a collection and all its data
|
|
1345
|
-
* @param user - User identifier
|
|
1346
|
-
* @param collection - Collection ID to delete
|
|
1347
|
-
* @returns Promise resolving when deletion is complete
|
|
1348
|
-
*/
|
|
1349
|
-
deleteCollection(user, collection) {
|
|
1350
|
-
return this.api.makeRequest("collection-management", {
|
|
1351
|
-
operation: "delete-collection",
|
|
1352
|
-
user,
|
|
1353
|
-
collection,
|
|
1354
|
-
}, 30000);
|
|
1355
|
-
}
|
|
1356
|
-
}
|
|
1357
|
-
/**
|
|
1358
|
-
* Factory function to create a new TrustGraph WebSocket connection
|
|
1359
|
-
* This is the main entry point for using the TrustGraph API
|
|
1360
|
-
* @param user - User identifier for API requests
|
|
1361
|
-
* @param token - Optional authentication token for secure connections
|
|
1362
|
-
*/
|
|
1363
|
-
const createTrustGraphSocket = (user, token) => {
|
|
1364
|
-
return new BaseApi(user, token);
|
|
1365
|
-
};
|
|
1366
|
-
|
|
1367
|
-
exports.BaseApi = BaseApi;
|
|
1368
|
-
exports.CollectionManagementApi = CollectionManagementApi;
|
|
1369
|
-
exports.ConfigApi = ConfigApi;
|
|
1370
|
-
exports.FlowApi = FlowApi;
|
|
1371
|
-
exports.FlowsApi = FlowsApi;
|
|
1372
|
-
exports.KnowledgeApi = KnowledgeApi;
|
|
1373
|
-
exports.LibrarianApi = LibrarianApi;
|
|
1374
|
-
exports.createTrustGraphSocket = createTrustGraphSocket;
|
|
1375
|
-
//# sourceMappingURL=index.js.map
|