@elqnt/chat 3.0.2 → 3.1.0
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/README.md +27 -0
- package/dist/api/index.d.mts +53 -2
- package/dist/api/index.d.ts +53 -2
- package/dist/api/index.js +79 -9
- package/dist/api/index.js.map +1 -1
- package/dist/api/index.mjs +65 -9
- package/dist/api/index.mjs.map +1 -1
- package/dist/hooks/index.d.mts +134 -2
- package/dist/hooks/index.d.ts +134 -2
- package/dist/hooks/index.js +713 -8
- package/dist/hooks/index.js.map +1 -1
- package/dist/hooks/index.mjs +706 -7
- package/dist/hooks/index.mjs.map +1 -1
- package/dist/index.d.mts +6 -3
- package/dist/index.d.ts +6 -3
- package/dist/index.js +722 -8
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +712 -7
- package/dist/index.mjs.map +1 -1
- package/dist/models/index.d.mts +78 -3
- package/dist/models/index.d.ts +78 -3
- package/dist/models/index.js +9 -0
- package/dist/models/index.js.map +1 -1
- package/dist/models/index.mjs +6 -0
- package/dist/models/index.mjs.map +1 -1
- package/dist/transport/index.js +2 -1
- package/dist/transport/index.js.map +1 -1
- package/dist/transport/index.mjs +2 -1
- package/dist/transport/index.mjs.map +1 -1
- package/package.json +5 -5
package/dist/hooks/index.mjs
CHANGED
|
@@ -232,6 +232,383 @@ function createSSETransport(options = {}) {
|
|
|
232
232
|
state = "disconnected";
|
|
233
233
|
retryCount = 0;
|
|
234
234
|
},
|
|
235
|
+
async send(event) {
|
|
236
|
+
if (!config) {
|
|
237
|
+
throw new Error("Transport not connected");
|
|
238
|
+
}
|
|
239
|
+
switch (event.type) {
|
|
240
|
+
case "message":
|
|
241
|
+
await sendRest("send", {
|
|
242
|
+
orgId: event.orgId,
|
|
243
|
+
chatKey: event.chatKey,
|
|
244
|
+
userId: event.userId,
|
|
245
|
+
message: event.message,
|
|
246
|
+
...event.data ? { data: event.data } : {}
|
|
247
|
+
});
|
|
248
|
+
break;
|
|
249
|
+
case "typing":
|
|
250
|
+
await sendRest("typing", {
|
|
251
|
+
orgId: event.orgId,
|
|
252
|
+
chatKey: event.chatKey,
|
|
253
|
+
userId: event.userId,
|
|
254
|
+
typing: true
|
|
255
|
+
});
|
|
256
|
+
break;
|
|
257
|
+
case "stopped_typing":
|
|
258
|
+
await sendRest("typing", {
|
|
259
|
+
orgId: event.orgId,
|
|
260
|
+
chatKey: event.chatKey,
|
|
261
|
+
userId: event.userId,
|
|
262
|
+
typing: false
|
|
263
|
+
});
|
|
264
|
+
break;
|
|
265
|
+
case "load_chat":
|
|
266
|
+
await sendRest("load", {
|
|
267
|
+
orgId: event.orgId,
|
|
268
|
+
chatKey: event.chatKey,
|
|
269
|
+
userId: event.userId
|
|
270
|
+
});
|
|
271
|
+
break;
|
|
272
|
+
case "new_chat":
|
|
273
|
+
await sendRest("create", {
|
|
274
|
+
orgId: event.orgId,
|
|
275
|
+
userId: event.userId,
|
|
276
|
+
metadata: event.data
|
|
277
|
+
});
|
|
278
|
+
break;
|
|
279
|
+
case "end_chat":
|
|
280
|
+
await sendRest("end", {
|
|
281
|
+
orgId: event.orgId,
|
|
282
|
+
chatKey: event.chatKey,
|
|
283
|
+
userId: event.userId,
|
|
284
|
+
data: event.data
|
|
285
|
+
});
|
|
286
|
+
break;
|
|
287
|
+
default:
|
|
288
|
+
await sendRest("event", {
|
|
289
|
+
type: event.type,
|
|
290
|
+
orgId: event.orgId,
|
|
291
|
+
chatKey: event.chatKey,
|
|
292
|
+
userId: event.userId,
|
|
293
|
+
data: event.data
|
|
294
|
+
});
|
|
295
|
+
}
|
|
296
|
+
metrics.messagesSent++;
|
|
297
|
+
},
|
|
298
|
+
async sendMessage(message) {
|
|
299
|
+
if (!config) {
|
|
300
|
+
throw new Error("Transport not connected");
|
|
301
|
+
}
|
|
302
|
+
await sendRest("send", {
|
|
303
|
+
orgId: config.orgId,
|
|
304
|
+
chatKey: config.chatKey,
|
|
305
|
+
userId: config.userId,
|
|
306
|
+
message
|
|
307
|
+
});
|
|
308
|
+
metrics.messagesSent++;
|
|
309
|
+
},
|
|
310
|
+
async createChat(options2) {
|
|
311
|
+
if (!config) {
|
|
312
|
+
throw new Error("Transport not connected");
|
|
313
|
+
}
|
|
314
|
+
const response = await sendRest("create", {
|
|
315
|
+
orgId: options2.orgId,
|
|
316
|
+
userId: options2.userId,
|
|
317
|
+
metadata: options2.metadata
|
|
318
|
+
});
|
|
319
|
+
if (!response?.chatKey) {
|
|
320
|
+
throw new Error("Failed to create chat: no chatKey returned");
|
|
321
|
+
}
|
|
322
|
+
return { chatKey: response.chatKey };
|
|
323
|
+
},
|
|
324
|
+
async loadChatData(options2) {
|
|
325
|
+
if (!config) {
|
|
326
|
+
throw new Error("Transport not connected");
|
|
327
|
+
}
|
|
328
|
+
const response = await sendRest("load", {
|
|
329
|
+
orgId: options2.orgId,
|
|
330
|
+
chatKey: options2.chatKey,
|
|
331
|
+
userId: options2.userId
|
|
332
|
+
});
|
|
333
|
+
if (!response?.chat) {
|
|
334
|
+
throw new Error("Failed to load chat: no chat data returned");
|
|
335
|
+
}
|
|
336
|
+
return {
|
|
337
|
+
chat: response.chat,
|
|
338
|
+
agentId: response.agentId
|
|
339
|
+
};
|
|
340
|
+
},
|
|
341
|
+
onMessage(handler) {
|
|
342
|
+
globalHandlers.add(handler);
|
|
343
|
+
return () => globalHandlers.delete(handler);
|
|
344
|
+
},
|
|
345
|
+
on(eventType, handler) {
|
|
346
|
+
if (!typeHandlers.has(eventType)) {
|
|
347
|
+
typeHandlers.set(eventType, /* @__PURE__ */ new Set());
|
|
348
|
+
}
|
|
349
|
+
typeHandlers.get(eventType).add(handler);
|
|
350
|
+
return () => {
|
|
351
|
+
const handlers = typeHandlers.get(eventType);
|
|
352
|
+
if (handlers) {
|
|
353
|
+
handlers.delete(handler);
|
|
354
|
+
if (handlers.size === 0) {
|
|
355
|
+
typeHandlers.delete(eventType);
|
|
356
|
+
}
|
|
357
|
+
}
|
|
358
|
+
};
|
|
359
|
+
},
|
|
360
|
+
getState() {
|
|
361
|
+
return state;
|
|
362
|
+
},
|
|
363
|
+
getMetrics() {
|
|
364
|
+
return { ...metrics };
|
|
365
|
+
},
|
|
366
|
+
getError() {
|
|
367
|
+
return error;
|
|
368
|
+
},
|
|
369
|
+
clearError() {
|
|
370
|
+
error = void 0;
|
|
371
|
+
}
|
|
372
|
+
};
|
|
373
|
+
return transport;
|
|
374
|
+
}
|
|
375
|
+
|
|
376
|
+
// transport/sse-fetch.ts
|
|
377
|
+
function createFetchSSETransport(options = {}) {
|
|
378
|
+
const {
|
|
379
|
+
retryConfig = DEFAULT_RETRY_CONFIG,
|
|
380
|
+
debug = false,
|
|
381
|
+
logger = createLogger(debug),
|
|
382
|
+
customFetch = fetch
|
|
383
|
+
} = options;
|
|
384
|
+
let abortController;
|
|
385
|
+
let config;
|
|
386
|
+
let state = "disconnected";
|
|
387
|
+
let error;
|
|
388
|
+
let retryCount = 0;
|
|
389
|
+
let reconnectTimeout;
|
|
390
|
+
let intentionalDisconnect = false;
|
|
391
|
+
const metrics = {
|
|
392
|
+
latency: 0,
|
|
393
|
+
messagesSent: 0,
|
|
394
|
+
messagesReceived: 0,
|
|
395
|
+
messagesQueued: 0,
|
|
396
|
+
reconnectCount: 0,
|
|
397
|
+
transportType: "sse-fetch"
|
|
398
|
+
};
|
|
399
|
+
const globalHandlers = /* @__PURE__ */ new Set();
|
|
400
|
+
const typeHandlers = /* @__PURE__ */ new Map();
|
|
401
|
+
function emit(event) {
|
|
402
|
+
metrics.messagesReceived++;
|
|
403
|
+
metrics.lastMessageAt = Date.now();
|
|
404
|
+
globalHandlers.forEach((handler) => {
|
|
405
|
+
try {
|
|
406
|
+
handler(event);
|
|
407
|
+
} catch (err) {
|
|
408
|
+
logger.error("Error in message handler:", err);
|
|
409
|
+
}
|
|
410
|
+
});
|
|
411
|
+
const handlers = typeHandlers.get(event.type);
|
|
412
|
+
if (handlers) {
|
|
413
|
+
handlers.forEach((handler) => {
|
|
414
|
+
try {
|
|
415
|
+
handler(event);
|
|
416
|
+
} catch (err) {
|
|
417
|
+
logger.error(`Error in ${event.type} handler:`, err);
|
|
418
|
+
}
|
|
419
|
+
});
|
|
420
|
+
}
|
|
421
|
+
}
|
|
422
|
+
async function sendRest(endpoint, body) {
|
|
423
|
+
if (!config) {
|
|
424
|
+
throw new Error("Transport not connected");
|
|
425
|
+
}
|
|
426
|
+
const url = `${config.baseUrl}/${endpoint}`;
|
|
427
|
+
logger.debug(`POST ${endpoint}`, body);
|
|
428
|
+
const response = await customFetch(url, {
|
|
429
|
+
method: "POST",
|
|
430
|
+
headers: { "Content-Type": "application/json" },
|
|
431
|
+
body: JSON.stringify(body)
|
|
432
|
+
});
|
|
433
|
+
if (!response.ok) {
|
|
434
|
+
const errorText = await response.text();
|
|
435
|
+
throw new Error(`API error: ${response.status} - ${errorText}`);
|
|
436
|
+
}
|
|
437
|
+
const json = await response.json();
|
|
438
|
+
if (json && typeof json === "object" && "data" in json) {
|
|
439
|
+
return json.data;
|
|
440
|
+
}
|
|
441
|
+
return json;
|
|
442
|
+
}
|
|
443
|
+
function parseSSEChunk(chunk) {
|
|
444
|
+
const events = [];
|
|
445
|
+
const lines = chunk.split("\n");
|
|
446
|
+
let eventType = "message";
|
|
447
|
+
let data = "";
|
|
448
|
+
for (const line of lines) {
|
|
449
|
+
if (line.startsWith("event:")) {
|
|
450
|
+
eventType = line.slice(6).trim();
|
|
451
|
+
} else if (line.startsWith("data:")) {
|
|
452
|
+
data = line.slice(5).trim();
|
|
453
|
+
} else if (line === "" && data) {
|
|
454
|
+
try {
|
|
455
|
+
const parsed = JSON.parse(data);
|
|
456
|
+
events.push(parsed);
|
|
457
|
+
} catch {
|
|
458
|
+
logger.warn("Failed to parse SSE data:", data);
|
|
459
|
+
}
|
|
460
|
+
eventType = "message";
|
|
461
|
+
data = "";
|
|
462
|
+
}
|
|
463
|
+
}
|
|
464
|
+
return events;
|
|
465
|
+
}
|
|
466
|
+
async function startStream(cfg) {
|
|
467
|
+
const url = `${cfg.baseUrl}/stream?orgId=${cfg.orgId}&userId=${cfg.userId}&clientType=${cfg.clientType}${cfg.chatKey ? `&chatId=${cfg.chatKey}` : ""}`;
|
|
468
|
+
logger.debug("Connecting to:", url);
|
|
469
|
+
abortController = new AbortController();
|
|
470
|
+
const response = await customFetch(url, {
|
|
471
|
+
method: "GET",
|
|
472
|
+
headers: {
|
|
473
|
+
Accept: "text/event-stream",
|
|
474
|
+
"Cache-Control": "no-cache"
|
|
475
|
+
},
|
|
476
|
+
signal: abortController.signal
|
|
477
|
+
});
|
|
478
|
+
if (!response.ok) {
|
|
479
|
+
throw new Error(`Stream connection failed: ${response.status}`);
|
|
480
|
+
}
|
|
481
|
+
if (!response.body) {
|
|
482
|
+
throw new Error("Response body is null - ReadableStream not supported");
|
|
483
|
+
}
|
|
484
|
+
const reader = response.body.getReader();
|
|
485
|
+
const decoder = new TextDecoder();
|
|
486
|
+
let buffer = "";
|
|
487
|
+
const readStream = async () => {
|
|
488
|
+
try {
|
|
489
|
+
while (true) {
|
|
490
|
+
const { done, value } = await reader.read();
|
|
491
|
+
if (done) {
|
|
492
|
+
logger.info("Stream ended");
|
|
493
|
+
break;
|
|
494
|
+
}
|
|
495
|
+
buffer += decoder.decode(value, { stream: true });
|
|
496
|
+
const lastNewline = buffer.lastIndexOf("\n\n");
|
|
497
|
+
if (lastNewline !== -1) {
|
|
498
|
+
const complete = buffer.slice(0, lastNewline + 2);
|
|
499
|
+
buffer = buffer.slice(lastNewline + 2);
|
|
500
|
+
const events = parseSSEChunk(complete);
|
|
501
|
+
events.forEach(emit);
|
|
502
|
+
}
|
|
503
|
+
}
|
|
504
|
+
} catch (err) {
|
|
505
|
+
if (err.name === "AbortError") {
|
|
506
|
+
logger.debug("Stream aborted");
|
|
507
|
+
return;
|
|
508
|
+
}
|
|
509
|
+
logger.error("Stream error:", err);
|
|
510
|
+
throw err;
|
|
511
|
+
}
|
|
512
|
+
if (!intentionalDisconnect) {
|
|
513
|
+
state = "disconnected";
|
|
514
|
+
scheduleReconnect();
|
|
515
|
+
}
|
|
516
|
+
};
|
|
517
|
+
readStream().catch((err) => {
|
|
518
|
+
if (!intentionalDisconnect) {
|
|
519
|
+
error = {
|
|
520
|
+
code: "CONNECTION_FAILED",
|
|
521
|
+
message: err.message,
|
|
522
|
+
retryable: true,
|
|
523
|
+
timestamp: Date.now(),
|
|
524
|
+
originalError: err
|
|
525
|
+
};
|
|
526
|
+
metrics.lastError = error;
|
|
527
|
+
state = "disconnected";
|
|
528
|
+
scheduleReconnect();
|
|
529
|
+
}
|
|
530
|
+
});
|
|
531
|
+
}
|
|
532
|
+
function scheduleReconnect() {
|
|
533
|
+
if (intentionalDisconnect || !config) return;
|
|
534
|
+
const maxRetries = retryConfig.maxRetries ?? DEFAULT_RETRY_CONFIG.maxRetries;
|
|
535
|
+
if (retryCount >= maxRetries) {
|
|
536
|
+
logger.error(`Max retries (${maxRetries}) exceeded`);
|
|
537
|
+
error = {
|
|
538
|
+
code: "CONNECTION_FAILED",
|
|
539
|
+
message: `Max retries (${maxRetries}) exceeded`,
|
|
540
|
+
retryable: false,
|
|
541
|
+
timestamp: Date.now()
|
|
542
|
+
};
|
|
543
|
+
return;
|
|
544
|
+
}
|
|
545
|
+
const interval = calculateRetryInterval(retryCount, retryConfig);
|
|
546
|
+
retryCount++;
|
|
547
|
+
metrics.reconnectCount++;
|
|
548
|
+
logger.info(`Reconnecting in ${interval}ms (attempt ${retryCount})`);
|
|
549
|
+
state = "reconnecting";
|
|
550
|
+
reconnectTimeout = setTimeout(() => {
|
|
551
|
+
if (config) {
|
|
552
|
+
transport.connect(config).catch((err) => {
|
|
553
|
+
logger.error("Reconnect failed:", err);
|
|
554
|
+
});
|
|
555
|
+
}
|
|
556
|
+
}, interval);
|
|
557
|
+
}
|
|
558
|
+
const transport = {
|
|
559
|
+
async connect(cfg) {
|
|
560
|
+
config = cfg;
|
|
561
|
+
intentionalDisconnect = false;
|
|
562
|
+
if (abortController) {
|
|
563
|
+
abortController.abort();
|
|
564
|
+
abortController = void 0;
|
|
565
|
+
}
|
|
566
|
+
if (reconnectTimeout) {
|
|
567
|
+
clearTimeout(reconnectTimeout);
|
|
568
|
+
reconnectTimeout = void 0;
|
|
569
|
+
}
|
|
570
|
+
state = retryCount > 0 ? "reconnecting" : "connecting";
|
|
571
|
+
const connectionStart = Date.now();
|
|
572
|
+
try {
|
|
573
|
+
await startStream(cfg);
|
|
574
|
+
const connectionTime = Date.now() - connectionStart;
|
|
575
|
+
logger.info(`Connected in ${connectionTime}ms`);
|
|
576
|
+
state = "connected";
|
|
577
|
+
error = void 0;
|
|
578
|
+
retryCount = 0;
|
|
579
|
+
metrics.connectedAt = Date.now();
|
|
580
|
+
metrics.latency = connectionTime;
|
|
581
|
+
} catch (err) {
|
|
582
|
+
const connectError = {
|
|
583
|
+
code: "CONNECTION_FAILED",
|
|
584
|
+
message: err.message,
|
|
585
|
+
retryable: true,
|
|
586
|
+
timestamp: Date.now(),
|
|
587
|
+
originalError: err
|
|
588
|
+
};
|
|
589
|
+
error = connectError;
|
|
590
|
+
metrics.lastError = connectError;
|
|
591
|
+
state = "disconnected";
|
|
592
|
+
if (!intentionalDisconnect) {
|
|
593
|
+
scheduleReconnect();
|
|
594
|
+
}
|
|
595
|
+
throw connectError;
|
|
596
|
+
}
|
|
597
|
+
},
|
|
598
|
+
disconnect(intentional = true) {
|
|
599
|
+
logger.info("Disconnecting", { intentional });
|
|
600
|
+
intentionalDisconnect = intentional;
|
|
601
|
+
if (reconnectTimeout) {
|
|
602
|
+
clearTimeout(reconnectTimeout);
|
|
603
|
+
reconnectTimeout = void 0;
|
|
604
|
+
}
|
|
605
|
+
if (abortController) {
|
|
606
|
+
abortController.abort();
|
|
607
|
+
abortController = void 0;
|
|
608
|
+
}
|
|
609
|
+
state = "disconnected";
|
|
610
|
+
retryCount = 0;
|
|
611
|
+
},
|
|
235
612
|
async send(event) {
|
|
236
613
|
if (!config) {
|
|
237
614
|
throw new Error("Transport not connected");
|
|
@@ -374,6 +751,16 @@ function createSSETransport(options = {}) {
|
|
|
374
751
|
|
|
375
752
|
// hooks/use-chat.ts
|
|
376
753
|
function getDefaultTransport(type, debug) {
|
|
754
|
+
if (type === "sse-fetch") {
|
|
755
|
+
return createFetchSSETransport({ debug });
|
|
756
|
+
}
|
|
757
|
+
if (type === "sse") {
|
|
758
|
+
return createSSETransport({ debug });
|
|
759
|
+
}
|
|
760
|
+
const isReactNative = typeof navigator !== "undefined" && navigator.product === "ReactNative";
|
|
761
|
+
if (isReactNative || typeof EventSource === "undefined") {
|
|
762
|
+
return createFetchSSETransport({ debug });
|
|
763
|
+
}
|
|
377
764
|
return createSSETransport({ debug });
|
|
378
765
|
}
|
|
379
766
|
function useChat(options) {
|
|
@@ -484,6 +871,7 @@ function useChat(options) {
|
|
|
484
871
|
throw err;
|
|
485
872
|
}
|
|
486
873
|
setConnectionState("connecting");
|
|
874
|
+
onConnectionChange?.("connecting");
|
|
487
875
|
try {
|
|
488
876
|
const unsubscribe = transport.onMessage(handleEvent);
|
|
489
877
|
await transport.connect({
|
|
@@ -502,6 +890,7 @@ function useChat(options) {
|
|
|
502
890
|
} catch (err) {
|
|
503
891
|
const transportError = err;
|
|
504
892
|
setConnectionState("disconnected");
|
|
893
|
+
onConnectionChange?.("disconnected");
|
|
505
894
|
setError(transportError);
|
|
506
895
|
onErrorRef.current?.(transportError);
|
|
507
896
|
throw err;
|
|
@@ -531,7 +920,7 @@ function useChat(options) {
|
|
|
531
920
|
},
|
|
532
921
|
[orgId, userId]
|
|
533
922
|
);
|
|
534
|
-
const
|
|
923
|
+
const loadChat2 = useCallback(
|
|
535
924
|
async (key) => {
|
|
536
925
|
const transport = transportRef.current;
|
|
537
926
|
if (!transport) {
|
|
@@ -584,7 +973,7 @@ function useChat(options) {
|
|
|
584
973
|
},
|
|
585
974
|
[orgId, chatKey, userId]
|
|
586
975
|
);
|
|
587
|
-
const
|
|
976
|
+
const endChat2 = useCallback(
|
|
588
977
|
async (reason) => {
|
|
589
978
|
const transport = transportRef.current;
|
|
590
979
|
if (!transport) {
|
|
@@ -606,7 +995,7 @@ function useChat(options) {
|
|
|
606
995
|
},
|
|
607
996
|
[orgId, chatKey, userId]
|
|
608
997
|
);
|
|
609
|
-
const
|
|
998
|
+
const sendEvent2 = useCallback(
|
|
610
999
|
async (event) => {
|
|
611
1000
|
const transport = transportRef.current;
|
|
612
1001
|
if (!transport) {
|
|
@@ -691,10 +1080,10 @@ function useChat(options) {
|
|
|
691
1080
|
isConnected,
|
|
692
1081
|
// Chat operations
|
|
693
1082
|
startChat,
|
|
694
|
-
loadChat,
|
|
1083
|
+
loadChat: loadChat2,
|
|
695
1084
|
sendMessage,
|
|
696
|
-
sendEvent,
|
|
697
|
-
endChat,
|
|
1085
|
+
sendEvent: sendEvent2,
|
|
1086
|
+
endChat: endChat2,
|
|
698
1087
|
// Typing
|
|
699
1088
|
startTyping,
|
|
700
1089
|
stopTyping,
|
|
@@ -709,7 +1098,317 @@ function useChat(options) {
|
|
|
709
1098
|
clearError
|
|
710
1099
|
};
|
|
711
1100
|
}
|
|
1101
|
+
|
|
1102
|
+
// hooks/use-chat-history.ts
|
|
1103
|
+
import { useMemo } from "react";
|
|
1104
|
+
|
|
1105
|
+
// api/index.ts
|
|
1106
|
+
import { browserApiRequest as browserApiRequest2 } from "@elqnt/api-client/browser";
|
|
1107
|
+
|
|
1108
|
+
// api/memory.ts
|
|
1109
|
+
import { browserApiRequest } from "@elqnt/api-client/browser";
|
|
1110
|
+
var patchProfileApi = (patch, o) => browserApiRequest("/api/v1/memory/profile", { method: "PATCH", body: patch, ...o });
|
|
1111
|
+
var replaceProfileApi = (p, o) => browserApiRequest("/api/v1/memory/profile", { method: "PUT", body: p, ...o });
|
|
1112
|
+
var clearProfileApi = (o) => browserApiRequest("/api/v1/memory/profile", { method: "DELETE", ...o });
|
|
1113
|
+
var deleteContactApi = (name, o) => browserApiRequest(`/api/v1/memory/profile/contacts/${encodeURIComponent(name)}`, { method: "DELETE", ...o });
|
|
1114
|
+
var deleteNoteApi = (index, o) => browserApiRequest(`/api/v1/memory/profile/notes/${index}`, { method: "DELETE", ...o });
|
|
1115
|
+
var clearSummaryApi = (chatKey, o) => browserApiRequest(`/api/v1/chats/${chatKey}/summary`, { method: "DELETE", ...o });
|
|
1116
|
+
var regenerateSummaryApi = (chatKey, o) => browserApiRequest(`/api/v1/chats/${chatKey}/summary/regenerate`, { method: "POST", ...o });
|
|
1117
|
+
|
|
1118
|
+
// api/index.ts
|
|
1119
|
+
async function getChatHistoryApi(options) {
|
|
1120
|
+
return browserApiRequest2("/api/v1/chats", {
|
|
1121
|
+
method: "POST",
|
|
1122
|
+
body: {
|
|
1123
|
+
limit: options.limit || 15,
|
|
1124
|
+
offset: options.offset || 0,
|
|
1125
|
+
...options.skipCache ? { skipCache: true } : {}
|
|
1126
|
+
},
|
|
1127
|
+
...options
|
|
1128
|
+
});
|
|
1129
|
+
}
|
|
1130
|
+
async function getChatApi(chatKey, options) {
|
|
1131
|
+
return browserApiRequest2(`/api/v1/chats/${chatKey}`, {
|
|
1132
|
+
method: "GET",
|
|
1133
|
+
...options
|
|
1134
|
+
});
|
|
1135
|
+
}
|
|
1136
|
+
async function updateChatApi(chatKey, updates, options) {
|
|
1137
|
+
return browserApiRequest2(`/api/v1/chats/${chatKey}`, {
|
|
1138
|
+
method: "PATCH",
|
|
1139
|
+
body: updates,
|
|
1140
|
+
...options
|
|
1141
|
+
});
|
|
1142
|
+
}
|
|
1143
|
+
async function deleteChatApi(chatKey, options) {
|
|
1144
|
+
return browserApiRequest2(`/api/v1/chats/${chatKey}`, {
|
|
1145
|
+
method: "DELETE",
|
|
1146
|
+
...options
|
|
1147
|
+
});
|
|
1148
|
+
}
|
|
1149
|
+
async function getActiveChatsCountApi(options) {
|
|
1150
|
+
return browserApiRequest2("/api/v1/chats/active/count", {
|
|
1151
|
+
method: "GET",
|
|
1152
|
+
...options
|
|
1153
|
+
});
|
|
1154
|
+
}
|
|
1155
|
+
async function getActiveChatsApi(options) {
|
|
1156
|
+
const params = new URLSearchParams();
|
|
1157
|
+
if (options.pastHours) params.set("pastHours", String(options.pastHours));
|
|
1158
|
+
const queryString = params.toString();
|
|
1159
|
+
return browserApiRequest2(`/api/v1/chats/active${queryString ? `?${queryString}` : ""}`, {
|
|
1160
|
+
method: "GET",
|
|
1161
|
+
...options
|
|
1162
|
+
});
|
|
1163
|
+
}
|
|
1164
|
+
async function getWaitingChatsCountApi(options) {
|
|
1165
|
+
return browserApiRequest2("/api/v1/chats/waiting/count", {
|
|
1166
|
+
method: "GET",
|
|
1167
|
+
...options
|
|
1168
|
+
});
|
|
1169
|
+
}
|
|
1170
|
+
async function getChatsByUserApi(userEmail, options) {
|
|
1171
|
+
return browserApiRequest2(`/api/v1/chats/user/${encodeURIComponent(userEmail)}`, {
|
|
1172
|
+
method: "GET",
|
|
1173
|
+
...options
|
|
1174
|
+
});
|
|
1175
|
+
}
|
|
1176
|
+
async function listQueuesApi(options) {
|
|
1177
|
+
return browserApiRequest2("/api/v1/queues", {
|
|
1178
|
+
method: "GET",
|
|
1179
|
+
...options
|
|
1180
|
+
});
|
|
1181
|
+
}
|
|
1182
|
+
async function getOnlineSessionsApi(options) {
|
|
1183
|
+
return browserApiRequest2("/api/v1/agents/sessions/online", {
|
|
1184
|
+
method: "GET",
|
|
1185
|
+
...options
|
|
1186
|
+
});
|
|
1187
|
+
}
|
|
1188
|
+
async function getAgentSessionApi(agentId, options) {
|
|
1189
|
+
return browserApiRequest2(`/api/v1/agents/sessions/${agentId}`, {
|
|
1190
|
+
method: "GET",
|
|
1191
|
+
...options
|
|
1192
|
+
});
|
|
1193
|
+
}
|
|
1194
|
+
|
|
1195
|
+
// hooks/use-chat-history.ts
|
|
1196
|
+
import { useApiAsync } from "@elqnt/api-client/hooks";
|
|
1197
|
+
|
|
1198
|
+
// hooks/use-options-ref.ts
|
|
1199
|
+
import { useRef as useRef2, useEffect as useEffect2 } from "react";
|
|
1200
|
+
function useOptionsRef(options) {
|
|
1201
|
+
const optionsRef = useRef2(options);
|
|
1202
|
+
useEffect2(() => {
|
|
1203
|
+
optionsRef.current = options;
|
|
1204
|
+
}, [options]);
|
|
1205
|
+
return optionsRef;
|
|
1206
|
+
}
|
|
1207
|
+
|
|
1208
|
+
// hooks/use-chat-history.ts
|
|
1209
|
+
function useChatHistory(options) {
|
|
1210
|
+
const optionsRef = useOptionsRef(options);
|
|
1211
|
+
const { execute: getChatHistory, loading: listLoading, error: listError } = useApiAsync(
|
|
1212
|
+
(params) => getChatHistoryApi({ ...optionsRef.current, ...params }),
|
|
1213
|
+
(data) => ({
|
|
1214
|
+
chats: data.chats,
|
|
1215
|
+
total: data.total,
|
|
1216
|
+
hasMore: data.hasMore
|
|
1217
|
+
}),
|
|
1218
|
+
{ chats: [], total: 0, hasMore: false }
|
|
1219
|
+
);
|
|
1220
|
+
const { execute: getChat, loading: getLoading, error: getError } = useApiAsync(
|
|
1221
|
+
(chatKey) => getChatApi(chatKey, optionsRef.current),
|
|
1222
|
+
(data) => data.chat || null,
|
|
1223
|
+
null
|
|
1224
|
+
);
|
|
1225
|
+
const { execute: updateChat, loading: updateLoading, error: updateError } = useApiAsync(
|
|
1226
|
+
(chatKey, updates) => updateChatApi(chatKey, updates, optionsRef.current),
|
|
1227
|
+
(data) => !!data.chatKey,
|
|
1228
|
+
false
|
|
1229
|
+
);
|
|
1230
|
+
const { execute: deleteChat, loading: deleteLoading, error: deleteError } = useApiAsync(
|
|
1231
|
+
(chatKey) => deleteChatApi(chatKey, optionsRef.current),
|
|
1232
|
+
(data) => data.success,
|
|
1233
|
+
false
|
|
1234
|
+
);
|
|
1235
|
+
const { execute: getChatsByUser, loading: userChatsLoading, error: userChatsError } = useApiAsync(
|
|
1236
|
+
(userEmail) => getChatsByUserApi(userEmail, optionsRef.current),
|
|
1237
|
+
(data) => data.chats,
|
|
1238
|
+
[]
|
|
1239
|
+
);
|
|
1240
|
+
const loading = listLoading || getLoading || updateLoading || deleteLoading || userChatsLoading;
|
|
1241
|
+
const error = listError || getError || updateError || deleteError || userChatsError;
|
|
1242
|
+
return useMemo(
|
|
1243
|
+
() => ({
|
|
1244
|
+
loading,
|
|
1245
|
+
error,
|
|
1246
|
+
getChatHistory,
|
|
1247
|
+
getChat,
|
|
1248
|
+
updateChat,
|
|
1249
|
+
deleteChat,
|
|
1250
|
+
getChatsByUser
|
|
1251
|
+
}),
|
|
1252
|
+
[loading, error, getChatHistory, getChat, updateChat, deleteChat, getChatsByUser]
|
|
1253
|
+
);
|
|
1254
|
+
}
|
|
1255
|
+
|
|
1256
|
+
// hooks/use-chat-monitoring.ts
|
|
1257
|
+
import { useMemo as useMemo2 } from "react";
|
|
1258
|
+
import { useApiAsync as useApiAsync2 } from "@elqnt/api-client/hooks";
|
|
1259
|
+
function useChatMonitoring(options) {
|
|
1260
|
+
const optionsRef = useOptionsRef(options);
|
|
1261
|
+
const { execute: getActiveChats, loading: activeLoading, error: activeError } = useApiAsync2(
|
|
1262
|
+
(pastHours) => getActiveChatsApi({ ...optionsRef.current, pastHours }),
|
|
1263
|
+
(data) => data.chats,
|
|
1264
|
+
[]
|
|
1265
|
+
);
|
|
1266
|
+
const { execute: getActiveChatsCount, loading: activeCountLoading, error: activeCountError } = useApiAsync2(
|
|
1267
|
+
() => getActiveChatsCountApi(optionsRef.current),
|
|
1268
|
+
(data) => data.count,
|
|
1269
|
+
0
|
|
1270
|
+
);
|
|
1271
|
+
const { execute: getWaitingChatsCount, loading: waitingCountLoading, error: waitingCountError } = useApiAsync2(
|
|
1272
|
+
() => getWaitingChatsCountApi(optionsRef.current),
|
|
1273
|
+
(data) => data.count,
|
|
1274
|
+
0
|
|
1275
|
+
);
|
|
1276
|
+
const { execute: listQueues, loading: queuesLoading, error: queuesError } = useApiAsync2(
|
|
1277
|
+
() => listQueuesApi(optionsRef.current),
|
|
1278
|
+
(data) => data.queues,
|
|
1279
|
+
[]
|
|
1280
|
+
);
|
|
1281
|
+
const loading = activeLoading || activeCountLoading || waitingCountLoading || queuesLoading;
|
|
1282
|
+
const error = activeError || activeCountError || waitingCountError || queuesError;
|
|
1283
|
+
return useMemo2(
|
|
1284
|
+
() => ({
|
|
1285
|
+
loading,
|
|
1286
|
+
error,
|
|
1287
|
+
getActiveChats,
|
|
1288
|
+
getActiveChatsCount,
|
|
1289
|
+
getWaitingChatsCount,
|
|
1290
|
+
listQueues
|
|
1291
|
+
}),
|
|
1292
|
+
[loading, error, getActiveChats, getActiveChatsCount, getWaitingChatsCount, listQueues]
|
|
1293
|
+
);
|
|
1294
|
+
}
|
|
1295
|
+
|
|
1296
|
+
// hooks/use-human-agent-sessions.ts
|
|
1297
|
+
import { useMemo as useMemo3 } from "react";
|
|
1298
|
+
import { useApiAsync as useApiAsync3 } from "@elqnt/api-client/hooks";
|
|
1299
|
+
function useHumanAgentSessions(options) {
|
|
1300
|
+
const optionsRef = useOptionsRef(options);
|
|
1301
|
+
const { execute: getOnlineSessions, loading: onlineLoading, error: onlineError } = useApiAsync3(
|
|
1302
|
+
() => getOnlineSessionsApi(optionsRef.current),
|
|
1303
|
+
(data) => data.sessions,
|
|
1304
|
+
[]
|
|
1305
|
+
);
|
|
1306
|
+
const { execute: getAgentSession, loading: sessionLoading, error: sessionError } = useApiAsync3(
|
|
1307
|
+
(agentId) => getAgentSessionApi(agentId, optionsRef.current),
|
|
1308
|
+
(data) => data.session || null,
|
|
1309
|
+
null
|
|
1310
|
+
);
|
|
1311
|
+
const loading = onlineLoading || sessionLoading;
|
|
1312
|
+
const error = onlineError || sessionError;
|
|
1313
|
+
return useMemo3(
|
|
1314
|
+
() => ({
|
|
1315
|
+
loading,
|
|
1316
|
+
error,
|
|
1317
|
+
getOnlineSessions,
|
|
1318
|
+
getAgentSession
|
|
1319
|
+
}),
|
|
1320
|
+
[loading, error, getOnlineSessions, getAgentSession]
|
|
1321
|
+
);
|
|
1322
|
+
}
|
|
1323
|
+
|
|
1324
|
+
// hooks/use-memory.ts
|
|
1325
|
+
import { useCallback as useCallback2, useRef as useRef3, useState as useState2 } from "react";
|
|
1326
|
+
function useMemory(options, initialProfile = null) {
|
|
1327
|
+
const [profile, setProfile] = useState2(initialProfile);
|
|
1328
|
+
const [loading, setLoading] = useState2(false);
|
|
1329
|
+
const requestCountRef = useRef3(0);
|
|
1330
|
+
const runProfileMutation = useCallback2(
|
|
1331
|
+
async (fn) => {
|
|
1332
|
+
requestCountRef.current += 1;
|
|
1333
|
+
setLoading(true);
|
|
1334
|
+
try {
|
|
1335
|
+
const response = await fn();
|
|
1336
|
+
if (!response.error && response.data) {
|
|
1337
|
+
setProfile(response.data);
|
|
1338
|
+
return response.data;
|
|
1339
|
+
}
|
|
1340
|
+
return null;
|
|
1341
|
+
} catch {
|
|
1342
|
+
return null;
|
|
1343
|
+
} finally {
|
|
1344
|
+
requestCountRef.current -= 1;
|
|
1345
|
+
if (requestCountRef.current === 0) {
|
|
1346
|
+
setLoading(false);
|
|
1347
|
+
}
|
|
1348
|
+
}
|
|
1349
|
+
},
|
|
1350
|
+
[]
|
|
1351
|
+
);
|
|
1352
|
+
const optionsRef = useRef3(options);
|
|
1353
|
+
optionsRef.current = options;
|
|
1354
|
+
const patchProfile = useCallback2(
|
|
1355
|
+
(patch) => runProfileMutation(() => patchProfileApi(patch, optionsRef.current)),
|
|
1356
|
+
[runProfileMutation]
|
|
1357
|
+
);
|
|
1358
|
+
const replaceProfile = useCallback2(
|
|
1359
|
+
(p) => runProfileMutation(() => replaceProfileApi(p, optionsRef.current)),
|
|
1360
|
+
[runProfileMutation]
|
|
1361
|
+
);
|
|
1362
|
+
const clearProfile = useCallback2(
|
|
1363
|
+
() => runProfileMutation(() => clearProfileApi(optionsRef.current)),
|
|
1364
|
+
[runProfileMutation]
|
|
1365
|
+
);
|
|
1366
|
+
const deleteContact = useCallback2(
|
|
1367
|
+
(name) => runProfileMutation(() => deleteContactApi(name, optionsRef.current)),
|
|
1368
|
+
[runProfileMutation]
|
|
1369
|
+
);
|
|
1370
|
+
const deleteNote = useCallback2(
|
|
1371
|
+
(index) => runProfileMutation(() => deleteNoteApi(index, optionsRef.current)),
|
|
1372
|
+
[runProfileMutation]
|
|
1373
|
+
);
|
|
1374
|
+
const clearSummary = useCallback2(
|
|
1375
|
+
async (chatKey) => {
|
|
1376
|
+
await clearSummaryApi(chatKey, optionsRef.current);
|
|
1377
|
+
},
|
|
1378
|
+
[]
|
|
1379
|
+
);
|
|
1380
|
+
const regenerateSummary = useCallback2(
|
|
1381
|
+
async (chatKey) => {
|
|
1382
|
+
const response = await regenerateSummaryApi(chatKey, optionsRef.current);
|
|
1383
|
+
if (!response.error && response.data) {
|
|
1384
|
+
return response.data;
|
|
1385
|
+
}
|
|
1386
|
+
return null;
|
|
1387
|
+
},
|
|
1388
|
+
[]
|
|
1389
|
+
);
|
|
1390
|
+
return {
|
|
1391
|
+
profile,
|
|
1392
|
+
loading,
|
|
1393
|
+
patchProfile,
|
|
1394
|
+
replaceProfile,
|
|
1395
|
+
clearProfile,
|
|
1396
|
+
deleteContact,
|
|
1397
|
+
deleteNote,
|
|
1398
|
+
clearSummary,
|
|
1399
|
+
regenerateSummary
|
|
1400
|
+
};
|
|
1401
|
+
}
|
|
1402
|
+
|
|
1403
|
+
// hooks/index.ts
|
|
1404
|
+
import { useApiAsync as useApiAsync4 } from "@elqnt/api-client/hooks";
|
|
712
1405
|
export {
|
|
713
|
-
|
|
1406
|
+
useApiAsync4 as useApiAsync,
|
|
1407
|
+
useChat,
|
|
1408
|
+
useChatHistory,
|
|
1409
|
+
useChatMonitoring,
|
|
1410
|
+
useHumanAgentSessions,
|
|
1411
|
+
useMemory,
|
|
1412
|
+
useOptionsRef
|
|
714
1413
|
};
|
|
715
1414
|
//# sourceMappingURL=index.mjs.map
|