@elqnt/chat 1.0.9 → 1.0.12
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/hooks/use-websocket-chat-admin.js +367 -8
- package/dist/hooks/use-websocket-chat-admin.js.map +1 -1
- package/dist/hooks/use-websocket-chat-admin.mjs +367 -8
- package/dist/hooks/use-websocket-chat-admin.mjs.map +1 -1
- package/dist/hooks/use-websocket-chat-base.d.mts +13 -2
- package/dist/hooks/use-websocket-chat-base.d.ts +13 -2
- package/dist/hooks/use-websocket-chat-base.js +367 -8
- package/dist/hooks/use-websocket-chat-base.js.map +1 -1
- package/dist/hooks/use-websocket-chat-base.mjs +367 -8
- package/dist/hooks/use-websocket-chat-base.mjs.map +1 -1
- package/dist/hooks/use-websocket-chat-customer.js +367 -8
- package/dist/hooks/use-websocket-chat-customer.js.map +1 -1
- package/dist/hooks/use-websocket-chat-customer.mjs +367 -8
- package/dist/hooks/use-websocket-chat-customer.mjs.map +1 -1
- package/dist/index.d.mts +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +367 -8
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +367 -8
- package/dist/index.mjs.map +1 -1
- package/dist/models/index.d.mts +1 -1
- package/dist/models/index.d.ts +1 -1
- package/dist/models/index.js.map +1 -1
- package/dist/models/index.mjs.map +1 -1
- package/package.json +1 -1
|
@@ -22,6 +22,7 @@ var DEFAULT_QUEUE_CONFIG = {
|
|
|
22
22
|
};
|
|
23
23
|
var DEFAULT_HEARTBEAT_INTERVAL = 3e4;
|
|
24
24
|
var DEFAULT_HEARTBEAT_TIMEOUT = 5e3;
|
|
25
|
+
var DEFAULT_TRANSPORT = "websocket";
|
|
25
26
|
function isChatEvent(data) {
|
|
26
27
|
return data && typeof data === "object" && (typeof data.type === "string" || data.message);
|
|
27
28
|
}
|
|
@@ -36,7 +37,8 @@ var useWebSocketChatBase = ({
|
|
|
36
37
|
debug = false,
|
|
37
38
|
logger = createDefaultLogger(debug),
|
|
38
39
|
heartbeatInterval = DEFAULT_HEARTBEAT_INTERVAL,
|
|
39
|
-
heartbeatTimeout = DEFAULT_HEARTBEAT_TIMEOUT
|
|
40
|
+
heartbeatTimeout = DEFAULT_HEARTBEAT_TIMEOUT,
|
|
41
|
+
transport = DEFAULT_TRANSPORT
|
|
40
42
|
}) => {
|
|
41
43
|
const [connectionState, setConnectionState] = useState("disconnected");
|
|
42
44
|
const [error, setError] = useState(void 0);
|
|
@@ -46,9 +48,15 @@ var useWebSocketChatBase = ({
|
|
|
46
48
|
messagesSent: 0,
|
|
47
49
|
messagesReceived: 0,
|
|
48
50
|
messagesQueued: 0,
|
|
49
|
-
reconnectCount: 0
|
|
51
|
+
reconnectCount: 0,
|
|
52
|
+
transportType: transport
|
|
50
53
|
});
|
|
51
54
|
const wsRef = useRef(void 0);
|
|
55
|
+
const sseRef = useRef(void 0);
|
|
56
|
+
const transportRef = useRef(transport);
|
|
57
|
+
useEffect(() => {
|
|
58
|
+
transportRef.current = transport;
|
|
59
|
+
}, [transport]);
|
|
52
60
|
const reconnectTimeoutRef = useRef(void 0);
|
|
53
61
|
const retryCountRef = useRef(0);
|
|
54
62
|
const messageQueueRef = useRef([]);
|
|
@@ -178,6 +186,10 @@ var useWebSocketChatBase = ({
|
|
|
178
186
|
wsRef.current.close(1e3, "Cleanup");
|
|
179
187
|
}
|
|
180
188
|
wsRef.current = void 0;
|
|
189
|
+
if (sseRef.current) {
|
|
190
|
+
sseRef.current.close();
|
|
191
|
+
sseRef.current = void 0;
|
|
192
|
+
}
|
|
181
193
|
if (reconnectTimeoutRef.current) {
|
|
182
194
|
clearTimeout(reconnectTimeoutRef.current);
|
|
183
195
|
reconnectTimeoutRef.current = void 0;
|
|
@@ -195,6 +207,35 @@ var useWebSocketChatBase = ({
|
|
|
195
207
|
});
|
|
196
208
|
loadChatRetryMapRef.current.clear();
|
|
197
209
|
}, [stopHeartbeat]);
|
|
210
|
+
const getRestApiUrl = useCallback((endpoint) => {
|
|
211
|
+
const httpUrl = serverBaseUrl.replace(/^wss:/, "https:").replace(/^ws:/, "http:");
|
|
212
|
+
return `${httpUrl}/${endpoint}`;
|
|
213
|
+
}, [serverBaseUrl]);
|
|
214
|
+
const sendRestMessage = useCallback(
|
|
215
|
+
async (endpoint, body) => {
|
|
216
|
+
const url = getRestApiUrl(endpoint);
|
|
217
|
+
logger.debug(`SSE REST API call: POST ${endpoint}`, body);
|
|
218
|
+
try {
|
|
219
|
+
const response = await fetch(url, {
|
|
220
|
+
method: "POST",
|
|
221
|
+
headers: {
|
|
222
|
+
"Content-Type": "application/json"
|
|
223
|
+
},
|
|
224
|
+
body: JSON.stringify(body)
|
|
225
|
+
});
|
|
226
|
+
if (!response.ok) {
|
|
227
|
+
const errorText = await response.text();
|
|
228
|
+
throw new Error(`REST API error: ${response.status} - ${errorText}`);
|
|
229
|
+
}
|
|
230
|
+
const data = await response.json();
|
|
231
|
+
return data;
|
|
232
|
+
} catch (error2) {
|
|
233
|
+
logger.error(`SSE REST API error for ${endpoint}:`, error2);
|
|
234
|
+
throw error2;
|
|
235
|
+
}
|
|
236
|
+
},
|
|
237
|
+
[getRestApiUrl, logger]
|
|
238
|
+
);
|
|
198
239
|
const connect = useCallback(
|
|
199
240
|
async (userId) => {
|
|
200
241
|
if (!mountedRef.current) {
|
|
@@ -212,7 +253,11 @@ var useWebSocketChatBase = ({
|
|
|
212
253
|
return Promise.reject(error2);
|
|
213
254
|
}
|
|
214
255
|
if (wsRef.current?.readyState === WebSocket.OPEN) {
|
|
215
|
-
logger.debug("Already connected");
|
|
256
|
+
logger.debug("Already connected (WebSocket)");
|
|
257
|
+
return Promise.resolve();
|
|
258
|
+
}
|
|
259
|
+
if (sseRef.current?.readyState === EventSource.OPEN) {
|
|
260
|
+
logger.debug("Already connected (SSE)");
|
|
216
261
|
return Promise.resolve();
|
|
217
262
|
}
|
|
218
263
|
if (connectionState === "connecting" || connectionState === "reconnecting") {
|
|
@@ -238,8 +283,169 @@ var useWebSocketChatBase = ({
|
|
|
238
283
|
intentionalDisconnectRef.current = false;
|
|
239
284
|
return new Promise((resolve, reject) => {
|
|
240
285
|
try {
|
|
241
|
-
const wsUrl = `${serverBaseUrl}?orgId=${orgId}&userId=${userId}&clientType=${clientType}&product=${product}`;
|
|
242
286
|
const connectionStartTime = Date.now();
|
|
287
|
+
logger.info(`\u{1F504} Connecting with transport: ${transportRef.current}`);
|
|
288
|
+
if (transportRef.current === "sse") {
|
|
289
|
+
const sseUrl = getRestApiUrl(`stream?orgId=${orgId}&userId=${userId}&clientType=${clientType}&chatId=${currentChatKeyRef.current || ""}`);
|
|
290
|
+
logger.debug("Connecting to SSE:", sseUrl);
|
|
291
|
+
console.log(`\u23F3 Initiating SSE connection to ${sseUrl}...`);
|
|
292
|
+
const eventSource = new EventSource(sseUrl);
|
|
293
|
+
eventSource.onopen = () => {
|
|
294
|
+
if (!mountedRef.current) {
|
|
295
|
+
eventSource.close();
|
|
296
|
+
reject(new Error("Component unmounted"));
|
|
297
|
+
return;
|
|
298
|
+
}
|
|
299
|
+
const connectionTimeMs = Date.now() - connectionStartTime;
|
|
300
|
+
const connectionTimeSec = (connectionTimeMs / 1e3).toFixed(2);
|
|
301
|
+
logger.info("\u2705 SSE connected", {
|
|
302
|
+
userId,
|
|
303
|
+
retryCount: retryCountRef.current,
|
|
304
|
+
connectionTime: `${connectionTimeSec}s (${connectionTimeMs}ms)`
|
|
305
|
+
});
|
|
306
|
+
console.log(`\u{1F50C} SSE connection established in ${connectionTimeSec} seconds`);
|
|
307
|
+
setConnectionState("connected");
|
|
308
|
+
setError(void 0);
|
|
309
|
+
const wasReconnecting = retryCountRef.current > 0;
|
|
310
|
+
retryCountRef.current = 0;
|
|
311
|
+
updateMetrics({
|
|
312
|
+
connectedAt: Date.now(),
|
|
313
|
+
latency: connectionTimeMs,
|
|
314
|
+
transportType: "sse",
|
|
315
|
+
reconnectCount: wasReconnecting ? metrics.reconnectCount + 1 : metrics.reconnectCount
|
|
316
|
+
});
|
|
317
|
+
currentUserIdRef.current = userId;
|
|
318
|
+
if (currentChatKeyRef.current) {
|
|
319
|
+
logger.info("Loading chat after SSE reconnection:", currentChatKeyRef.current);
|
|
320
|
+
sendRestMessage("load", {
|
|
321
|
+
orgId,
|
|
322
|
+
chatKey: currentChatKeyRef.current,
|
|
323
|
+
userId
|
|
324
|
+
}).then((response) => {
|
|
325
|
+
if (response.success && response.data?.chat) {
|
|
326
|
+
const chatEvent = {
|
|
327
|
+
type: "load_chat_response",
|
|
328
|
+
orgId,
|
|
329
|
+
chatKey: currentChatKeyRef.current,
|
|
330
|
+
userId,
|
|
331
|
+
timestamp: Date.now(),
|
|
332
|
+
data: response.data
|
|
333
|
+
};
|
|
334
|
+
emit("load_chat_response", chatEvent);
|
|
335
|
+
if (onMessageRef.current) {
|
|
336
|
+
onMessageRef.current(chatEvent);
|
|
337
|
+
}
|
|
338
|
+
}
|
|
339
|
+
}).catch((err) => {
|
|
340
|
+
logger.error("Failed to load chat after SSE reconnection:", err);
|
|
341
|
+
});
|
|
342
|
+
}
|
|
343
|
+
emit("connected", { userId, wasReconnecting, transport: "sse" });
|
|
344
|
+
resolve();
|
|
345
|
+
};
|
|
346
|
+
const handleSSEMessage = (event) => {
|
|
347
|
+
if (!mountedRef.current) return;
|
|
348
|
+
try {
|
|
349
|
+
const data = JSON.parse(event.data);
|
|
350
|
+
if (!isChatEvent(data)) {
|
|
351
|
+
logger.warn("Received invalid SSE message format:", data);
|
|
352
|
+
return;
|
|
353
|
+
}
|
|
354
|
+
const chatEvent = data;
|
|
355
|
+
logger.debug("SSE message received:", chatEvent.type);
|
|
356
|
+
updateMetrics({
|
|
357
|
+
messagesReceived: metrics.messagesReceived + 1,
|
|
358
|
+
lastMessageAt: Date.now()
|
|
359
|
+
});
|
|
360
|
+
switch (chatEvent.type) {
|
|
361
|
+
case "new_chat_created":
|
|
362
|
+
const newChatKey = chatEvent.data?.chatKey;
|
|
363
|
+
if (newChatKey) {
|
|
364
|
+
logger.info("New chat created with key:", newChatKey);
|
|
365
|
+
currentChatKeyRef.current = newChatKey;
|
|
366
|
+
if (chatCreationPromiseRef.current) {
|
|
367
|
+
chatCreationPromiseRef.current.resolve(newChatKey);
|
|
368
|
+
chatCreationPromiseRef.current = null;
|
|
369
|
+
}
|
|
370
|
+
}
|
|
371
|
+
break;
|
|
372
|
+
case "load_chat_response":
|
|
373
|
+
const chat = chatEvent.data?.chat;
|
|
374
|
+
if (chat && chat.key) {
|
|
375
|
+
logger.info("Chat loaded with key:", chat.key);
|
|
376
|
+
currentChatKeyRef.current = chat.key;
|
|
377
|
+
}
|
|
378
|
+
break;
|
|
379
|
+
case "chat_ended":
|
|
380
|
+
logger.info("Chat ended, clearing key");
|
|
381
|
+
currentChatKeyRef.current = void 0;
|
|
382
|
+
break;
|
|
383
|
+
}
|
|
384
|
+
emit(chatEvent.type || "message", chatEvent);
|
|
385
|
+
if (onMessageRef.current) {
|
|
386
|
+
onMessageRef.current(chatEvent);
|
|
387
|
+
}
|
|
388
|
+
} catch (error2) {
|
|
389
|
+
logger.error("Failed to parse SSE message:", error2);
|
|
390
|
+
}
|
|
391
|
+
};
|
|
392
|
+
eventSource.addEventListener("message", handleSSEMessage);
|
|
393
|
+
eventSource.addEventListener("reconnected", handleSSEMessage);
|
|
394
|
+
eventSource.addEventListener("typing", handleSSEMessage);
|
|
395
|
+
eventSource.addEventListener("stopped_typing", handleSSEMessage);
|
|
396
|
+
eventSource.addEventListener("waiting", handleSSEMessage);
|
|
397
|
+
eventSource.addEventListener("waiting_for_agent", handleSSEMessage);
|
|
398
|
+
eventSource.addEventListener("human_agent_joined", handleSSEMessage);
|
|
399
|
+
eventSource.addEventListener("human_agent_left", handleSSEMessage);
|
|
400
|
+
eventSource.addEventListener("chat_ended", handleSSEMessage);
|
|
401
|
+
eventSource.addEventListener("chat_updated", handleSSEMessage);
|
|
402
|
+
eventSource.addEventListener("load_chat_response", handleSSEMessage);
|
|
403
|
+
eventSource.addEventListener("new_chat_created", handleSSEMessage);
|
|
404
|
+
eventSource.addEventListener("error", handleSSEMessage);
|
|
405
|
+
eventSource.addEventListener("show_csat_survey", handleSSEMessage);
|
|
406
|
+
eventSource.addEventListener("csat_response", handleSSEMessage);
|
|
407
|
+
eventSource.addEventListener("user_suggested_actions", handleSSEMessage);
|
|
408
|
+
eventSource.addEventListener("agent_execution_started", handleSSEMessage);
|
|
409
|
+
eventSource.addEventListener("agent_execution_ended", handleSSEMessage);
|
|
410
|
+
eventSource.addEventListener("agent_context_update", handleSSEMessage);
|
|
411
|
+
eventSource.addEventListener("plan_pending_approval", handleSSEMessage);
|
|
412
|
+
eventSource.addEventListener("step_started", handleSSEMessage);
|
|
413
|
+
eventSource.addEventListener("step_completed", handleSSEMessage);
|
|
414
|
+
eventSource.addEventListener("step_failed", handleSSEMessage);
|
|
415
|
+
eventSource.addEventListener("plan_completed", handleSSEMessage);
|
|
416
|
+
eventSource.addEventListener("skills_changed", handleSSEMessage);
|
|
417
|
+
eventSource.addEventListener("summary_update", handleSSEMessage);
|
|
418
|
+
eventSource.onerror = (error2) => {
|
|
419
|
+
logger.error("SSE error:", error2);
|
|
420
|
+
if (!mountedRef.current) return;
|
|
421
|
+
if (eventSource.readyState === EventSource.CLOSED) {
|
|
422
|
+
const sseError = {
|
|
423
|
+
code: "CONNECTION_FAILED",
|
|
424
|
+
message: "SSE connection failed",
|
|
425
|
+
retryable: true,
|
|
426
|
+
timestamp: Date.now()
|
|
427
|
+
};
|
|
428
|
+
setError(sseError);
|
|
429
|
+
updateMetrics({ lastError: sseError });
|
|
430
|
+
setConnectionState("disconnected");
|
|
431
|
+
emit("disconnected", { reason: "SSE error" });
|
|
432
|
+
if (!intentionalDisconnectRef.current && mountedRef.current) {
|
|
433
|
+
const retryInterval = calculateRetryInterval(retryCountRef.current);
|
|
434
|
+
retryCountRef.current++;
|
|
435
|
+
logger.info(`SSE reconnecting in ${retryInterval}ms (attempt ${retryCountRef.current})`);
|
|
436
|
+
if (reconnectTimeoutRef.current) {
|
|
437
|
+
clearTimeout(reconnectTimeoutRef.current);
|
|
438
|
+
}
|
|
439
|
+
reconnectTimeoutRef.current = setTimeout(() => {
|
|
440
|
+
connect(userId);
|
|
441
|
+
}, retryInterval);
|
|
442
|
+
}
|
|
443
|
+
}
|
|
444
|
+
};
|
|
445
|
+
sseRef.current = eventSource;
|
|
446
|
+
return;
|
|
447
|
+
}
|
|
448
|
+
const wsUrl = `${serverBaseUrl}?orgId=${orgId}&userId=${userId}&clientType=${clientType}&product=${product}`;
|
|
243
449
|
logger.debug("Connecting to WebSocket:", wsUrl);
|
|
244
450
|
console.log(`\u23F3 Initiating WebSocket connection to ${serverBaseUrl}...`);
|
|
245
451
|
const ws = new WebSocket(wsUrl);
|
|
@@ -511,7 +717,7 @@ var useWebSocketChatBase = ({
|
|
|
511
717
|
);
|
|
512
718
|
const sendMessage = useCallback(
|
|
513
719
|
(event, overrideUserId) => {
|
|
514
|
-
return new Promise((resolve, reject) => {
|
|
720
|
+
return new Promise(async (resolve, reject) => {
|
|
515
721
|
if (!mountedRef.current) {
|
|
516
722
|
reject(new Error("Component not mounted"));
|
|
517
723
|
return;
|
|
@@ -520,8 +726,161 @@ var useWebSocketChatBase = ({
|
|
|
520
726
|
...event,
|
|
521
727
|
timestamp: Date.now()
|
|
522
728
|
};
|
|
523
|
-
const messageId = `${fullEvent.type}_${fullEvent.timestamp}_${Math.random()}`;
|
|
524
729
|
logger.debug("Sending message:", fullEvent.type);
|
|
730
|
+
if (transportRef.current === "sse") {
|
|
731
|
+
if (!sseRef.current || sseRef.current.readyState !== EventSource.OPEN) {
|
|
732
|
+
logger.debug("SSE not connected, attempting to connect");
|
|
733
|
+
if (connectionState === "disconnected" && overrideUserId) {
|
|
734
|
+
try {
|
|
735
|
+
await connect(overrideUserId);
|
|
736
|
+
} catch (error2) {
|
|
737
|
+
reject(error2);
|
|
738
|
+
return;
|
|
739
|
+
}
|
|
740
|
+
} else {
|
|
741
|
+
reject(new Error("SSE not connected"));
|
|
742
|
+
return;
|
|
743
|
+
}
|
|
744
|
+
}
|
|
745
|
+
try {
|
|
746
|
+
switch (fullEvent.type) {
|
|
747
|
+
case "message":
|
|
748
|
+
await sendRestMessage("send", {
|
|
749
|
+
orgId: fullEvent.orgId,
|
|
750
|
+
chatKey: fullEvent.chatKey || currentChatKeyRef.current,
|
|
751
|
+
userId: fullEvent.userId,
|
|
752
|
+
message: fullEvent.message
|
|
753
|
+
});
|
|
754
|
+
break;
|
|
755
|
+
case "typing":
|
|
756
|
+
await sendRestMessage("typing", {
|
|
757
|
+
orgId: fullEvent.orgId,
|
|
758
|
+
chatKey: fullEvent.chatKey || currentChatKeyRef.current,
|
|
759
|
+
userId: fullEvent.userId,
|
|
760
|
+
typing: true
|
|
761
|
+
});
|
|
762
|
+
break;
|
|
763
|
+
case "stopped_typing":
|
|
764
|
+
await sendRestMessage("typing", {
|
|
765
|
+
orgId: fullEvent.orgId,
|
|
766
|
+
chatKey: fullEvent.chatKey || currentChatKeyRef.current,
|
|
767
|
+
userId: fullEvent.userId,
|
|
768
|
+
typing: false
|
|
769
|
+
});
|
|
770
|
+
break;
|
|
771
|
+
case "load_chat":
|
|
772
|
+
const loadResponse = await sendRestMessage("load", {
|
|
773
|
+
orgId: fullEvent.orgId,
|
|
774
|
+
chatKey: fullEvent.chatKey,
|
|
775
|
+
userId: fullEvent.userId
|
|
776
|
+
});
|
|
777
|
+
if (loadResponse.success && loadResponse.data?.chat) {
|
|
778
|
+
currentChatKeyRef.current = loadResponse.data.chat.key;
|
|
779
|
+
const chatEvent = {
|
|
780
|
+
type: "load_chat_response",
|
|
781
|
+
orgId: fullEvent.orgId,
|
|
782
|
+
chatKey: loadResponse.data.chat.key,
|
|
783
|
+
userId: fullEvent.userId,
|
|
784
|
+
timestamp: Date.now(),
|
|
785
|
+
data: loadResponse.data
|
|
786
|
+
};
|
|
787
|
+
emit("load_chat_response", chatEvent);
|
|
788
|
+
if (onMessageRef.current) {
|
|
789
|
+
onMessageRef.current(chatEvent);
|
|
790
|
+
}
|
|
791
|
+
}
|
|
792
|
+
break;
|
|
793
|
+
case "new_chat":
|
|
794
|
+
const createResponse = await sendRestMessage("create", {
|
|
795
|
+
orgId: fullEvent.orgId,
|
|
796
|
+
userId: fullEvent.userId,
|
|
797
|
+
metadata: fullEvent.data
|
|
798
|
+
});
|
|
799
|
+
if (createResponse.success && createResponse.data?.chatKey) {
|
|
800
|
+
currentChatKeyRef.current = createResponse.data.chatKey;
|
|
801
|
+
const newChatEvent = {
|
|
802
|
+
type: "new_chat_created",
|
|
803
|
+
orgId: fullEvent.orgId,
|
|
804
|
+
chatKey: createResponse.data.chatKey,
|
|
805
|
+
userId: fullEvent.userId,
|
|
806
|
+
timestamp: Date.now(),
|
|
807
|
+
data: { chatKey: createResponse.data.chatKey }
|
|
808
|
+
};
|
|
809
|
+
emit("new_chat_created", newChatEvent);
|
|
810
|
+
if (onMessageRef.current) {
|
|
811
|
+
onMessageRef.current(newChatEvent);
|
|
812
|
+
}
|
|
813
|
+
if (chatCreationPromiseRef.current) {
|
|
814
|
+
chatCreationPromiseRef.current.resolve(createResponse.data.chatKey);
|
|
815
|
+
chatCreationPromiseRef.current = null;
|
|
816
|
+
}
|
|
817
|
+
}
|
|
818
|
+
break;
|
|
819
|
+
case "end_chat":
|
|
820
|
+
await sendRestMessage("end", {
|
|
821
|
+
orgId: fullEvent.orgId,
|
|
822
|
+
chatKey: fullEvent.chatKey || currentChatKeyRef.current,
|
|
823
|
+
userId: fullEvent.userId,
|
|
824
|
+
data: fullEvent.data
|
|
825
|
+
});
|
|
826
|
+
break;
|
|
827
|
+
case "human_agent_join":
|
|
828
|
+
await sendRestMessage("agent-join", {
|
|
829
|
+
orgId: fullEvent.orgId,
|
|
830
|
+
chatKey: fullEvent.chatKey || currentChatKeyRef.current,
|
|
831
|
+
user: fullEvent.data?.user
|
|
832
|
+
});
|
|
833
|
+
break;
|
|
834
|
+
case "human_agent_leave":
|
|
835
|
+
await sendRestMessage("agent-leave", {
|
|
836
|
+
orgId: fullEvent.orgId,
|
|
837
|
+
chatKey: fullEvent.chatKey || currentChatKeyRef.current,
|
|
838
|
+
user: fullEvent.data?.user
|
|
839
|
+
});
|
|
840
|
+
break;
|
|
841
|
+
// Event types that use the generic /event endpoint
|
|
842
|
+
case "load_agent_context":
|
|
843
|
+
case "skill_activate":
|
|
844
|
+
case "skill_deactivate":
|
|
845
|
+
case "sync_metadata":
|
|
846
|
+
case "plan_approved":
|
|
847
|
+
case "plan_rejected":
|
|
848
|
+
await sendRestMessage("event", {
|
|
849
|
+
type: fullEvent.type,
|
|
850
|
+
orgId: fullEvent.orgId,
|
|
851
|
+
chatKey: fullEvent.chatKey || currentChatKeyRef.current,
|
|
852
|
+
userId: fullEvent.userId,
|
|
853
|
+
data: fullEvent.data
|
|
854
|
+
});
|
|
855
|
+
break;
|
|
856
|
+
default:
|
|
857
|
+
logger.warn("Sending unrecognized event type via generic endpoint:", fullEvent.type);
|
|
858
|
+
await sendRestMessage("event", {
|
|
859
|
+
type: fullEvent.type,
|
|
860
|
+
orgId: fullEvent.orgId,
|
|
861
|
+
chatKey: fullEvent.chatKey || currentChatKeyRef.current,
|
|
862
|
+
userId: fullEvent.userId,
|
|
863
|
+
data: fullEvent.data
|
|
864
|
+
});
|
|
865
|
+
break;
|
|
866
|
+
}
|
|
867
|
+
updateMetrics({ messagesSent: metrics.messagesSent + 1 });
|
|
868
|
+
logger.debug("SSE REST message sent successfully");
|
|
869
|
+
resolve();
|
|
870
|
+
} catch (error2) {
|
|
871
|
+
logger.error("Failed to send SSE REST message:", error2);
|
|
872
|
+
const sendError = {
|
|
873
|
+
code: "SEND_FAILED",
|
|
874
|
+
message: error2 instanceof Error ? error2.message : "Failed to send message",
|
|
875
|
+
retryable: true,
|
|
876
|
+
timestamp: Date.now()
|
|
877
|
+
};
|
|
878
|
+
setError(sendError);
|
|
879
|
+
updateMetrics({ lastError: sendError });
|
|
880
|
+
reject(sendError);
|
|
881
|
+
}
|
|
882
|
+
return;
|
|
883
|
+
}
|
|
525
884
|
if (!wsRef.current || wsRef.current.readyState !== WebSocket.OPEN) {
|
|
526
885
|
if (addToQueue(fullEvent)) {
|
|
527
886
|
logger.debug("Message queued, attempting to connect");
|
|
@@ -558,7 +917,7 @@ var useWebSocketChatBase = ({
|
|
|
558
917
|
}
|
|
559
918
|
});
|
|
560
919
|
},
|
|
561
|
-
[connectionState, connect, addToQueue, logger, metrics, updateMetrics]
|
|
920
|
+
[connectionState, connect, addToQueue, logger, metrics, updateMetrics, sendRestMessage, emit]
|
|
562
921
|
);
|
|
563
922
|
const startNewChat = useCallback(
|
|
564
923
|
(userId, data) => {
|
|
@@ -596,7 +955,7 @@ var useWebSocketChatBase = ({
|
|
|
596
955
|
);
|
|
597
956
|
const disconnect = useCallback(
|
|
598
957
|
(intentional = true) => {
|
|
599
|
-
logger.info("Disconnecting
|
|
958
|
+
logger.info("Disconnecting", { intentional, transport: transportRef.current });
|
|
600
959
|
intentionalDisconnectRef.current = intentional;
|
|
601
960
|
cleanup();
|
|
602
961
|
setConnectionState("disconnected");
|