@paymanai/payman-typescript-ask-sdk 1.2.8 → 1.2.10
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.d.mts +56 -1
- package/dist/index.d.ts +56 -1
- package/dist/index.js +1078 -5
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +1075 -6
- package/dist/index.mjs.map +1 -1
- package/dist/index.native.js +1078 -5
- package/dist/index.native.js.map +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -474,8 +474,78 @@ function processStreamEvent(event, state) {
|
|
|
474
474
|
|
|
475
475
|
// src/utils/messageStateManager.ts
|
|
476
476
|
var FRIENDLY_ERROR_MESSAGE = "Oops, something went wrong. Please try again.";
|
|
477
|
+
function buildFormattedThinking(steps, allThinkingText) {
|
|
478
|
+
const parts = [];
|
|
479
|
+
const safeSteps = steps ?? [];
|
|
480
|
+
const cleanAll = allThinkingText.replace(/^\s+/, "");
|
|
481
|
+
if (cleanAll) {
|
|
482
|
+
const firstStepWithThinking = safeSteps.find(
|
|
483
|
+
(s) => s.thinkingText && s.thinkingText.trim()
|
|
484
|
+
);
|
|
485
|
+
if (!firstStepWithThinking) {
|
|
486
|
+
parts.push("**Preflight**");
|
|
487
|
+
parts.push(cleanAll);
|
|
488
|
+
} else {
|
|
489
|
+
const stepText = firstStepWithThinking.thinkingText.trim();
|
|
490
|
+
const idx = cleanAll.indexOf(stepText);
|
|
491
|
+
if (idx > 0) {
|
|
492
|
+
const orphaned = cleanAll.substring(0, idx).replace(/\s+$/, "");
|
|
493
|
+
if (orphaned) {
|
|
494
|
+
parts.push("**Preflight**");
|
|
495
|
+
parts.push(orphaned);
|
|
496
|
+
}
|
|
497
|
+
}
|
|
498
|
+
}
|
|
499
|
+
}
|
|
500
|
+
for (const step of safeSteps) {
|
|
501
|
+
switch (step.eventType) {
|
|
502
|
+
case "ORCHESTRATOR_THINKING":
|
|
503
|
+
parts.push("**Planning**");
|
|
504
|
+
if (step.message) parts.push(step.message);
|
|
505
|
+
break;
|
|
506
|
+
case "INTENT_STARTED": {
|
|
507
|
+
let label = step.message || "Processing";
|
|
508
|
+
const started = label.match(/^(.+?)\s+started$/i);
|
|
509
|
+
const progress = label.match(/^(.+?)\s+in progress$/i);
|
|
510
|
+
if (started) label = started[1];
|
|
511
|
+
else if (progress) label = progress[1];
|
|
512
|
+
parts.push(`**${label}**`);
|
|
513
|
+
if (step.thinkingText) parts.push(step.thinkingText);
|
|
514
|
+
break;
|
|
515
|
+
}
|
|
516
|
+
case "INTENT_PROGRESS": {
|
|
517
|
+
if (step.thinkingText) parts.push(step.thinkingText);
|
|
518
|
+
else if (step.message) parts.push(step.message);
|
|
519
|
+
break;
|
|
520
|
+
}
|
|
521
|
+
case "AGGREGATOR_THINKING":
|
|
522
|
+
parts.push("**Finalizing**");
|
|
523
|
+
if (step.message) parts.push(step.message);
|
|
524
|
+
break;
|
|
525
|
+
case "USER_ACTION_REQUIRED":
|
|
526
|
+
parts.push("**Verification Required**");
|
|
527
|
+
if (step.message) parts.push(step.message);
|
|
528
|
+
break;
|
|
529
|
+
case "USER_ACTION_SUCCESS":
|
|
530
|
+
parts.push(`\u2713 ${step.message || "Verification successful"}`);
|
|
531
|
+
break;
|
|
532
|
+
case "USER_ACTION_REJECTED":
|
|
533
|
+
parts.push(`\u2717 ${step.message || "Verification rejected"}`);
|
|
534
|
+
break;
|
|
535
|
+
case "USER_ACTION_EXPIRED":
|
|
536
|
+
parts.push(`\u2717 ${step.message || "Verification expired"}`);
|
|
537
|
+
break;
|
|
538
|
+
case "USER_ACTION_FAILED":
|
|
539
|
+
parts.push(`\u2717 ${step.message || "Verification failed"}`);
|
|
540
|
+
break;
|
|
541
|
+
}
|
|
542
|
+
}
|
|
543
|
+
return parts.length > 0 ? parts.join("\n") : allThinkingText;
|
|
544
|
+
}
|
|
477
545
|
function createStreamingMessageUpdate(state) {
|
|
478
546
|
const hasCompletedContent = state.accumulatedContent && state.finalData !== void 0;
|
|
547
|
+
const steps = state.hasError ? [] : [...state.steps];
|
|
548
|
+
const allThinking = state.hasError ? void 0 : state.allThinkingText;
|
|
479
549
|
return {
|
|
480
550
|
streamingContent: state.hasError ? FRIENDLY_ERROR_MESSAGE : hasCompletedContent ? state.accumulatedContent : "",
|
|
481
551
|
content: state.hasError ? FRIENDLY_ERROR_MESSAGE : "",
|
|
@@ -485,12 +555,13 @@ function createStreamingMessageUpdate(state) {
|
|
|
485
555
|
errorDetails: state.hasError ? state.errorMessage : void 0,
|
|
486
556
|
executionId: state.executionId,
|
|
487
557
|
sessionId: state.sessionId,
|
|
488
|
-
steps
|
|
558
|
+
steps,
|
|
489
559
|
currentExecutingStepId: state.hasError ? void 0 : state.currentExecutingStepId,
|
|
490
560
|
isCancelled: false,
|
|
491
561
|
userActionResult: state.userActionResult,
|
|
492
562
|
activeThinkingText: state.hasError ? void 0 : state.activeThinkingText,
|
|
493
|
-
allThinkingText:
|
|
563
|
+
allThinkingText: allThinking,
|
|
564
|
+
formattedThinkingText: state.hasError ? void 0 : buildFormattedThinking(steps, allThinking || "")
|
|
494
565
|
};
|
|
495
566
|
}
|
|
496
567
|
function createErrorMessageUpdate(error, state) {
|
|
@@ -514,6 +585,8 @@ function createErrorMessageUpdate(error, state) {
|
|
|
514
585
|
};
|
|
515
586
|
}
|
|
516
587
|
function createFinalMessage(streamingId, state) {
|
|
588
|
+
const steps = state.hasError ? [] : [...state.steps];
|
|
589
|
+
const allThinking = state.hasError ? void 0 : state.allThinkingText;
|
|
517
590
|
return {
|
|
518
591
|
id: streamingId,
|
|
519
592
|
sessionId: state.sessionId,
|
|
@@ -526,12 +599,14 @@ function createFinalMessage(streamingId, state) {
|
|
|
526
599
|
errorDetails: state.hasError ? state.errorMessage : void 0,
|
|
527
600
|
executionId: state.executionId,
|
|
528
601
|
tracingData: state.finalData,
|
|
529
|
-
steps
|
|
602
|
+
steps,
|
|
530
603
|
isCancelled: false,
|
|
531
604
|
currentExecutingStepId: void 0,
|
|
532
605
|
userActionResult: state.userActionResult,
|
|
533
606
|
activeThinkingText: void 0,
|
|
534
|
-
allThinkingText:
|
|
607
|
+
allThinkingText: allThinking,
|
|
608
|
+
formattedThinkingText: state.hasError ? void 0 : buildFormattedThinking(steps, allThinking || ""),
|
|
609
|
+
isResolvingImages: state.hasError ? void 0 : state.isResolvingImages
|
|
535
610
|
};
|
|
536
611
|
}
|
|
537
612
|
function createCancelledMessageUpdate(steps, currentMessage) {
|
|
@@ -585,6 +660,16 @@ function buildUserActionUrl(config, userActionId, action) {
|
|
|
585
660
|
const encodedUserActionId = encodeURIComponent(userActionId);
|
|
586
661
|
return `${config.api.baseUrl}${basePath}/user-action/${encodedUserActionId}/${action}`;
|
|
587
662
|
}
|
|
663
|
+
function buildResolveImagesUrl(config) {
|
|
664
|
+
if (config.api.resolveImagesEndpoint) {
|
|
665
|
+
return `${config.api.baseUrl}${config.api.resolveImagesEndpoint}`;
|
|
666
|
+
}
|
|
667
|
+
const streamEndpoint = config.api.streamEndpoint || "/api/workflows/ask/stream";
|
|
668
|
+
const [endpointPath] = streamEndpoint.split("?");
|
|
669
|
+
const normalizedEndpointPath = endpointPath.replace(/\/+$/, "");
|
|
670
|
+
const basePath = normalizedEndpointPath.endsWith("/stream") ? normalizedEndpointPath.slice(0, -"/stream".length) : normalizedEndpointPath;
|
|
671
|
+
return `${config.api.baseUrl}${basePath}/resolve-image-urls`;
|
|
672
|
+
}
|
|
588
673
|
function buildRequestHeaders(config) {
|
|
589
674
|
const headers = {
|
|
590
675
|
...config.api.headers
|
|
@@ -699,6 +784,58 @@ var activeStreamStore = {
|
|
|
699
784
|
streams.delete(key);
|
|
700
785
|
}
|
|
701
786
|
};
|
|
787
|
+
|
|
788
|
+
// src/utils/ragImageResolver.ts
|
|
789
|
+
var RAG_IMAGE_REGEX = /\/api\/rag\/chunks\/[^"'\s]+\/image/;
|
|
790
|
+
function hasRagImages(content) {
|
|
791
|
+
return RAG_IMAGE_REGEX.test(content);
|
|
792
|
+
}
|
|
793
|
+
async function waitForNextPaint(signal) {
|
|
794
|
+
if (signal?.aborted) return;
|
|
795
|
+
await new Promise((resolve) => {
|
|
796
|
+
let isSettled = false;
|
|
797
|
+
const finish = () => {
|
|
798
|
+
if (isSettled) return;
|
|
799
|
+
isSettled = true;
|
|
800
|
+
signal?.removeEventListener("abort", finish);
|
|
801
|
+
resolve();
|
|
802
|
+
};
|
|
803
|
+
signal?.addEventListener("abort", finish, { once: true });
|
|
804
|
+
if (typeof requestAnimationFrame === "function") {
|
|
805
|
+
requestAnimationFrame(() => {
|
|
806
|
+
setTimeout(finish, 0);
|
|
807
|
+
});
|
|
808
|
+
return;
|
|
809
|
+
}
|
|
810
|
+
setTimeout(finish, 0);
|
|
811
|
+
});
|
|
812
|
+
}
|
|
813
|
+
async function resolveRagImageUrls(config, content, signal) {
|
|
814
|
+
const url = buildResolveImagesUrl(config);
|
|
815
|
+
const baseHeaders = buildRequestHeaders(config);
|
|
816
|
+
const headers = { "Content-Type": "application/json", ...baseHeaders };
|
|
817
|
+
const response = await fetch(url, {
|
|
818
|
+
method: "POST",
|
|
819
|
+
headers,
|
|
820
|
+
body: JSON.stringify({ input: content }),
|
|
821
|
+
signal
|
|
822
|
+
});
|
|
823
|
+
if (!response.ok) {
|
|
824
|
+
const errorText = await response.text();
|
|
825
|
+
throw new Error(`HTTP ${response.status}: ${errorText}`);
|
|
826
|
+
}
|
|
827
|
+
const text = await response.text();
|
|
828
|
+
try {
|
|
829
|
+
const parsed = JSON.parse(text);
|
|
830
|
+
if (typeof parsed === "string") return parsed;
|
|
831
|
+
if (typeof parsed.output === "string") return parsed.output;
|
|
832
|
+
if (typeof parsed.result === "string") return parsed.result;
|
|
833
|
+
} catch {
|
|
834
|
+
}
|
|
835
|
+
return text;
|
|
836
|
+
}
|
|
837
|
+
|
|
838
|
+
// src/hooks/useStreamManager.ts
|
|
702
839
|
function useStreamManager(config, callbacks, setMessages, setIsWaitingForResponse) {
|
|
703
840
|
const abortControllerRef = react.useRef(null);
|
|
704
841
|
const configRef = react.useRef(config);
|
|
@@ -864,9 +1001,11 @@ function useStreamManager(config, callbacks, setMessages, setIsWaitingForRespons
|
|
|
864
1001
|
if (state.currentSessionId && state.currentSessionId !== sessionId) {
|
|
865
1002
|
callbacksRef.current.onSessionIdChange?.(state.currentSessionId);
|
|
866
1003
|
}
|
|
1004
|
+
const needsImageResolve = !state.hasError && !abortController.signal.aborted && hasRagImages(state.accumulatedContent);
|
|
867
1005
|
const finalMessage = createFinalMessage(streamingId, {
|
|
868
1006
|
...state,
|
|
869
|
-
sessionId: state.currentSessionId || sessionId
|
|
1007
|
+
sessionId: state.currentSessionId || sessionId,
|
|
1008
|
+
isResolvingImages: needsImageResolve
|
|
870
1009
|
});
|
|
871
1010
|
setMessages(
|
|
872
1011
|
(prev) => prev.map(
|
|
@@ -877,6 +1016,30 @@ function useStreamManager(config, callbacks, setMessages, setIsWaitingForRespons
|
|
|
877
1016
|
}
|
|
878
1017
|
});
|
|
879
1018
|
clearThrottle();
|
|
1019
|
+
const shouldResolveImages = !abortController.signal.aborted && !state.hasError && hasRagImages(state.accumulatedContent);
|
|
1020
|
+
if (shouldResolveImages) {
|
|
1021
|
+
await waitForNextPaint(abortController.signal);
|
|
1022
|
+
}
|
|
1023
|
+
if (shouldResolveImages && !abortController.signal.aborted) {
|
|
1024
|
+
try {
|
|
1025
|
+
const resolvedContent = await resolveRagImageUrls(
|
|
1026
|
+
currentConfig,
|
|
1027
|
+
state.accumulatedContent,
|
|
1028
|
+
abortController.signal
|
|
1029
|
+
);
|
|
1030
|
+
setMessages(
|
|
1031
|
+
(prev) => prev.map(
|
|
1032
|
+
(msg) => msg.id === streamingId ? { ...msg, content: resolvedContent, isResolvingImages: false } : msg
|
|
1033
|
+
)
|
|
1034
|
+
);
|
|
1035
|
+
} catch {
|
|
1036
|
+
setMessages(
|
|
1037
|
+
(prev) => prev.map(
|
|
1038
|
+
(msg) => msg.id === streamingId ? { ...msg, isResolvingImages: false } : msg
|
|
1039
|
+
)
|
|
1040
|
+
);
|
|
1041
|
+
}
|
|
1042
|
+
}
|
|
880
1043
|
return state.currentSessionId;
|
|
881
1044
|
} catch (error) {
|
|
882
1045
|
clearThrottle();
|
|
@@ -1208,6 +1371,912 @@ function useChat(config, callbacks = {}) {
|
|
|
1208
1371
|
resendOtp
|
|
1209
1372
|
};
|
|
1210
1373
|
}
|
|
1374
|
+
|
|
1375
|
+
// src/utils/v2EventProcessor.ts
|
|
1376
|
+
function getEventText(event, field) {
|
|
1377
|
+
const value = event[field];
|
|
1378
|
+
return typeof value === "string" ? value.trim() : "";
|
|
1379
|
+
}
|
|
1380
|
+
function shouldShowIntentHeader(event) {
|
|
1381
|
+
const workerName = getEventText(event, "workerName");
|
|
1382
|
+
const intentId = getEventText(event, "intentId");
|
|
1383
|
+
return Boolean(workerName && intentId && workerName === intentId);
|
|
1384
|
+
}
|
|
1385
|
+
function addThinkingHeader(state, header) {
|
|
1386
|
+
state.formattedThinkingText += (state.formattedThinkingText ? "\n" : "") + header;
|
|
1387
|
+
}
|
|
1388
|
+
function addThinkingDetail(state, detail) {
|
|
1389
|
+
const trimmed = detail.trim();
|
|
1390
|
+
if (!trimmed) return;
|
|
1391
|
+
state.formattedThinkingText += (state.formattedThinkingText ? "\n" : "") + trimmed;
|
|
1392
|
+
}
|
|
1393
|
+
function addThinkingLine(state, header, detail) {
|
|
1394
|
+
state.formattedThinkingText += (state.formattedThinkingText ? "\n" : "") + header + "\n" + detail;
|
|
1395
|
+
}
|
|
1396
|
+
function appendThinkingText(state, text) {
|
|
1397
|
+
state.formattedThinkingText += text;
|
|
1398
|
+
}
|
|
1399
|
+
function completeLastInProgressStep2(steps) {
|
|
1400
|
+
for (let i = steps.length - 1; i >= 0; i--) {
|
|
1401
|
+
if (steps[i].status === "in_progress") {
|
|
1402
|
+
steps[i].status = "completed";
|
|
1403
|
+
return;
|
|
1404
|
+
}
|
|
1405
|
+
}
|
|
1406
|
+
}
|
|
1407
|
+
function createInitialV2State() {
|
|
1408
|
+
return {
|
|
1409
|
+
formattedThinkingText: "",
|
|
1410
|
+
finalResponse: "",
|
|
1411
|
+
currentWorker: "",
|
|
1412
|
+
lastEventType: "",
|
|
1413
|
+
sessionId: void 0,
|
|
1414
|
+
executionId: void 0,
|
|
1415
|
+
hasError: false,
|
|
1416
|
+
errorMessage: "",
|
|
1417
|
+
userActionRequest: void 0,
|
|
1418
|
+
userActionPending: false,
|
|
1419
|
+
userActionResult: void 0,
|
|
1420
|
+
finalData: void 0,
|
|
1421
|
+
steps: [],
|
|
1422
|
+
stepCounter: 0,
|
|
1423
|
+
currentExecutingStepId: void 0
|
|
1424
|
+
};
|
|
1425
|
+
}
|
|
1426
|
+
function processStreamEventV2(event, state) {
|
|
1427
|
+
const eventType = event.eventType;
|
|
1428
|
+
if (typeof eventType === "string" && eventType.toUpperCase() === "KEEP_ALIVE") {
|
|
1429
|
+
if (event.executionId) state.executionId = event.executionId;
|
|
1430
|
+
if (event.sessionId) state.sessionId = event.sessionId;
|
|
1431
|
+
return state;
|
|
1432
|
+
}
|
|
1433
|
+
if (event.executionId) state.executionId = event.executionId;
|
|
1434
|
+
if (event.sessionId) state.sessionId = event.sessionId;
|
|
1435
|
+
const message = getEventMessage(event);
|
|
1436
|
+
switch (eventType) {
|
|
1437
|
+
case "WORKFLOW_STARTED":
|
|
1438
|
+
case "STARTED":
|
|
1439
|
+
state.lastEventType = eventType;
|
|
1440
|
+
break;
|
|
1441
|
+
case "INTENT_THINKING": {
|
|
1442
|
+
const worker = getEventText(event, "workerName") || "Worker";
|
|
1443
|
+
const msg = getEventText(event, "message") || "Thinking...";
|
|
1444
|
+
const showHeader = shouldShowIntentHeader(event);
|
|
1445
|
+
if (worker !== state.currentWorker) {
|
|
1446
|
+
state.currentWorker = worker;
|
|
1447
|
+
if (showHeader && msg && msg !== worker) {
|
|
1448
|
+
addThinkingLine(state, `**${worker}**`, msg);
|
|
1449
|
+
} else if (showHeader) {
|
|
1450
|
+
addThinkingHeader(state, `**${worker}**`);
|
|
1451
|
+
} else if (msg !== "Thinking...") {
|
|
1452
|
+
addThinkingDetail(state, msg);
|
|
1453
|
+
}
|
|
1454
|
+
} else if ((showHeader || msg !== "Thinking...")) {
|
|
1455
|
+
appendThinkingText(state, "\n" + msg);
|
|
1456
|
+
}
|
|
1457
|
+
const lastInProgress = [...state.steps].reverse().find((s) => s.status === "in_progress");
|
|
1458
|
+
if (lastInProgress) {
|
|
1459
|
+
lastInProgress.thinkingText = "";
|
|
1460
|
+
lastInProgress.isThinking = true;
|
|
1461
|
+
}
|
|
1462
|
+
state.lastEventType = "INTENT_THINKING";
|
|
1463
|
+
break;
|
|
1464
|
+
}
|
|
1465
|
+
case "INTENT_THINKING_CONT": {
|
|
1466
|
+
const msg = event.message || "";
|
|
1467
|
+
if (!msg) break;
|
|
1468
|
+
if (state.lastEventType === "INTENT_THINKING") {
|
|
1469
|
+
appendThinkingText(state, "\n" + msg);
|
|
1470
|
+
} else {
|
|
1471
|
+
appendThinkingText(state, msg);
|
|
1472
|
+
}
|
|
1473
|
+
const thinkingStep = [...state.steps].reverse().find((s) => s.isThinking);
|
|
1474
|
+
if (thinkingStep) {
|
|
1475
|
+
thinkingStep.thinkingText = (thinkingStep.thinkingText || "") + msg;
|
|
1476
|
+
}
|
|
1477
|
+
state.lastEventType = "INTENT_THINKING_CONT";
|
|
1478
|
+
break;
|
|
1479
|
+
}
|
|
1480
|
+
case "ORCHESTRATOR_THINKING": {
|
|
1481
|
+
addThinkingLine(state, "**Planning**", event.message || "Understanding your request...");
|
|
1482
|
+
const stepId = `step-${state.stepCounter++}`;
|
|
1483
|
+
state.steps.push({
|
|
1484
|
+
id: stepId,
|
|
1485
|
+
eventType,
|
|
1486
|
+
message,
|
|
1487
|
+
status: "in_progress",
|
|
1488
|
+
timestamp: Date.now(),
|
|
1489
|
+
elapsedMs: event.elapsedMs
|
|
1490
|
+
});
|
|
1491
|
+
state.currentExecutingStepId = stepId;
|
|
1492
|
+
state.lastEventType = eventType;
|
|
1493
|
+
break;
|
|
1494
|
+
}
|
|
1495
|
+
case "ORCHESTRATOR_COMPLETED": {
|
|
1496
|
+
appendThinkingText(state, "\n" + (event.message || "Planning complete"));
|
|
1497
|
+
const step = state.steps.find((s) => s.eventType === "ORCHESTRATOR_THINKING" && s.status === "in_progress");
|
|
1498
|
+
if (step) {
|
|
1499
|
+
step.status = "completed";
|
|
1500
|
+
if (event.elapsedMs) step.elapsedMs = event.elapsedMs;
|
|
1501
|
+
if (step.id === state.currentExecutingStepId) state.currentExecutingStepId = void 0;
|
|
1502
|
+
}
|
|
1503
|
+
state.lastEventType = eventType;
|
|
1504
|
+
break;
|
|
1505
|
+
}
|
|
1506
|
+
case "INTENT_STARTED": {
|
|
1507
|
+
const worker = getEventText(event, "workerName") || "Worker";
|
|
1508
|
+
const msg = getEventText(event, "message") || "Starting...";
|
|
1509
|
+
const showHeader = shouldShowIntentHeader(event);
|
|
1510
|
+
state.currentWorker = worker;
|
|
1511
|
+
if (showHeader && msg !== worker) {
|
|
1512
|
+
addThinkingLine(state, `**${worker}**`, msg);
|
|
1513
|
+
} else if (showHeader) {
|
|
1514
|
+
addThinkingHeader(state, `**${worker}**`);
|
|
1515
|
+
} else {
|
|
1516
|
+
addThinkingDetail(state, msg);
|
|
1517
|
+
}
|
|
1518
|
+
const thinkingStep = state.steps.find((s) => s.isThinking);
|
|
1519
|
+
if (thinkingStep) thinkingStep.isThinking = false;
|
|
1520
|
+
const stepId = `step-${state.stepCounter++}`;
|
|
1521
|
+
state.steps.push({
|
|
1522
|
+
id: stepId,
|
|
1523
|
+
eventType,
|
|
1524
|
+
message,
|
|
1525
|
+
status: "in_progress",
|
|
1526
|
+
timestamp: Date.now(),
|
|
1527
|
+
elapsedMs: event.elapsedMs
|
|
1528
|
+
});
|
|
1529
|
+
state.currentExecutingStepId = stepId;
|
|
1530
|
+
state.lastEventType = eventType;
|
|
1531
|
+
break;
|
|
1532
|
+
}
|
|
1533
|
+
case "INTENT_COMPLETED": {
|
|
1534
|
+
const intentStep = state.steps.find((s) => s.eventType === "INTENT_STARTED" && s.status === "in_progress");
|
|
1535
|
+
if (intentStep) {
|
|
1536
|
+
intentStep.status = "completed";
|
|
1537
|
+
intentStep.isThinking = false;
|
|
1538
|
+
if (event.elapsedMs) intentStep.elapsedMs = event.elapsedMs;
|
|
1539
|
+
if (intentStep.id === state.currentExecutingStepId) state.currentExecutingStepId = void 0;
|
|
1540
|
+
}
|
|
1541
|
+
state.lastEventType = eventType;
|
|
1542
|
+
break;
|
|
1543
|
+
}
|
|
1544
|
+
case "AGGREGATOR_THINKING": {
|
|
1545
|
+
addThinkingLine(state, "**Finalizing**", event.message || "Preparing response...");
|
|
1546
|
+
const stepId = `step-${state.stepCounter++}`;
|
|
1547
|
+
state.steps.push({
|
|
1548
|
+
id: stepId,
|
|
1549
|
+
eventType,
|
|
1550
|
+
message,
|
|
1551
|
+
status: "in_progress",
|
|
1552
|
+
timestamp: Date.now(),
|
|
1553
|
+
elapsedMs: event.elapsedMs
|
|
1554
|
+
});
|
|
1555
|
+
state.currentExecutingStepId = stepId;
|
|
1556
|
+
state.lastEventType = eventType;
|
|
1557
|
+
break;
|
|
1558
|
+
}
|
|
1559
|
+
case "AGGREGATOR_COMPLETED": {
|
|
1560
|
+
appendThinkingText(state, "\n" + (event.message || "Response ready"));
|
|
1561
|
+
const step = state.steps.find((s) => s.eventType === "AGGREGATOR_THINKING" && s.status === "in_progress");
|
|
1562
|
+
if (step) {
|
|
1563
|
+
step.status = "completed";
|
|
1564
|
+
if (event.elapsedMs) step.elapsedMs = event.elapsedMs;
|
|
1565
|
+
if (step.id === state.currentExecutingStepId) state.currentExecutingStepId = void 0;
|
|
1566
|
+
}
|
|
1567
|
+
state.lastEventType = eventType;
|
|
1568
|
+
break;
|
|
1569
|
+
}
|
|
1570
|
+
case "WORKFLOW_COMPLETED":
|
|
1571
|
+
case "COMPLETED": {
|
|
1572
|
+
let content = extractResponseContent(event.response);
|
|
1573
|
+
const trace = event.trace && typeof event.trace === "object" ? event.trace : null;
|
|
1574
|
+
if (!content && trace?.workflowMsg && typeof trace.workflowMsg === "string") {
|
|
1575
|
+
content = trace.workflowMsg;
|
|
1576
|
+
}
|
|
1577
|
+
if (!content && trace?.aggregator && typeof trace.aggregator === "object") {
|
|
1578
|
+
const agg = trace.aggregator;
|
|
1579
|
+
if (typeof agg.response === "string") content = agg.response;
|
|
1580
|
+
else content = extractResponseContent(agg.response);
|
|
1581
|
+
}
|
|
1582
|
+
if (content) {
|
|
1583
|
+
state.finalResponse = content;
|
|
1584
|
+
state.finalData = event.response ?? event.trace;
|
|
1585
|
+
state.hasError = false;
|
|
1586
|
+
state.errorMessage = "";
|
|
1587
|
+
} else {
|
|
1588
|
+
state.hasError = true;
|
|
1589
|
+
state.errorMessage = "WORKFLOW_FAILED";
|
|
1590
|
+
}
|
|
1591
|
+
state.steps.forEach((step) => {
|
|
1592
|
+
if (step.status === "in_progress") {
|
|
1593
|
+
step.status = "completed";
|
|
1594
|
+
step.isThinking = false;
|
|
1595
|
+
}
|
|
1596
|
+
});
|
|
1597
|
+
state.lastEventType = eventType;
|
|
1598
|
+
break;
|
|
1599
|
+
}
|
|
1600
|
+
case "USER_ACTION_REQUIRED": {
|
|
1601
|
+
completeLastInProgressStep2(state.steps);
|
|
1602
|
+
if (event.userActionRequest) {
|
|
1603
|
+
state.userActionRequest = {
|
|
1604
|
+
userActionId: event.userActionRequest.userActionId,
|
|
1605
|
+
userActionType: event.userActionRequest.userActionType,
|
|
1606
|
+
message: event.userActionRequest.message,
|
|
1607
|
+
requestedSchema: event.userActionRequest.requestedSchema,
|
|
1608
|
+
metadata: event.userActionRequest.metadata
|
|
1609
|
+
};
|
|
1610
|
+
}
|
|
1611
|
+
state.userActionPending = true;
|
|
1612
|
+
const req = event.userActionRequest;
|
|
1613
|
+
if (req) {
|
|
1614
|
+
addThinkingLine(state, "**Verification Required**", req.message || "Waiting for authorization...");
|
|
1615
|
+
}
|
|
1616
|
+
const stepId = `step-${state.stepCounter++}`;
|
|
1617
|
+
state.steps.push({
|
|
1618
|
+
id: stepId,
|
|
1619
|
+
eventType,
|
|
1620
|
+
message,
|
|
1621
|
+
status: "in_progress",
|
|
1622
|
+
timestamp: Date.now(),
|
|
1623
|
+
elapsedMs: event.elapsedMs
|
|
1624
|
+
});
|
|
1625
|
+
state.currentExecutingStepId = stepId;
|
|
1626
|
+
state.lastEventType = eventType;
|
|
1627
|
+
break;
|
|
1628
|
+
}
|
|
1629
|
+
case "USER_ACTION_SUCCESS": {
|
|
1630
|
+
appendThinkingText(state, "\n\u2713 " + (event.message || "Verification successful"));
|
|
1631
|
+
completeLastInProgressStep2(state.steps);
|
|
1632
|
+
state.userActionRequest = void 0;
|
|
1633
|
+
state.userActionPending = false;
|
|
1634
|
+
state.userActionResult = "approved";
|
|
1635
|
+
const stepId = `step-${state.stepCounter++}`;
|
|
1636
|
+
state.steps.push({
|
|
1637
|
+
id: stepId,
|
|
1638
|
+
eventType,
|
|
1639
|
+
message,
|
|
1640
|
+
status: "completed",
|
|
1641
|
+
timestamp: Date.now(),
|
|
1642
|
+
elapsedMs: event.elapsedMs
|
|
1643
|
+
});
|
|
1644
|
+
state.lastEventType = eventType;
|
|
1645
|
+
break;
|
|
1646
|
+
}
|
|
1647
|
+
case "USER_ACTION_INVALID": {
|
|
1648
|
+
completeLastInProgressStep2(state.steps);
|
|
1649
|
+
const errorStepId = `step-${state.stepCounter++}`;
|
|
1650
|
+
state.steps.push({
|
|
1651
|
+
id: errorStepId,
|
|
1652
|
+
eventType,
|
|
1653
|
+
message,
|
|
1654
|
+
status: "error",
|
|
1655
|
+
timestamp: Date.now(),
|
|
1656
|
+
elapsedMs: event.elapsedMs
|
|
1657
|
+
});
|
|
1658
|
+
const retryStepId = `step-${state.stepCounter++}`;
|
|
1659
|
+
state.steps.push({
|
|
1660
|
+
id: retryStepId,
|
|
1661
|
+
eventType: "USER_ACTION_REQUIRED",
|
|
1662
|
+
message: "Waiting for verification...",
|
|
1663
|
+
status: "in_progress",
|
|
1664
|
+
timestamp: Date.now()
|
|
1665
|
+
});
|
|
1666
|
+
state.currentExecutingStepId = retryStepId;
|
|
1667
|
+
state.lastEventType = eventType;
|
|
1668
|
+
break;
|
|
1669
|
+
}
|
|
1670
|
+
case "USER_ACTION_REJECTED": {
|
|
1671
|
+
appendThinkingText(state, "\n\u2717 " + (event.message || "Verification rejected"));
|
|
1672
|
+
completeLastInProgressStep2(state.steps);
|
|
1673
|
+
state.userActionRequest = void 0;
|
|
1674
|
+
state.userActionPending = false;
|
|
1675
|
+
state.userActionResult = "rejected";
|
|
1676
|
+
const stepId = `step-${state.stepCounter++}`;
|
|
1677
|
+
state.steps.push({
|
|
1678
|
+
id: stepId,
|
|
1679
|
+
eventType,
|
|
1680
|
+
message,
|
|
1681
|
+
status: "completed",
|
|
1682
|
+
timestamp: Date.now(),
|
|
1683
|
+
elapsedMs: event.elapsedMs
|
|
1684
|
+
});
|
|
1685
|
+
state.lastEventType = eventType;
|
|
1686
|
+
break;
|
|
1687
|
+
}
|
|
1688
|
+
case "USER_ACTION_EXPIRED": {
|
|
1689
|
+
appendThinkingText(state, "\n\u2717 " + (event.message || "Verification expired"));
|
|
1690
|
+
completeLastInProgressStep2(state.steps);
|
|
1691
|
+
state.userActionRequest = void 0;
|
|
1692
|
+
state.userActionPending = false;
|
|
1693
|
+
const stepId = `step-${state.stepCounter++}`;
|
|
1694
|
+
state.steps.push({
|
|
1695
|
+
id: stepId,
|
|
1696
|
+
eventType,
|
|
1697
|
+
message,
|
|
1698
|
+
status: "error",
|
|
1699
|
+
timestamp: Date.now(),
|
|
1700
|
+
elapsedMs: event.elapsedMs
|
|
1701
|
+
});
|
|
1702
|
+
state.lastEventType = eventType;
|
|
1703
|
+
break;
|
|
1704
|
+
}
|
|
1705
|
+
case "USER_ACTION_RESENT": {
|
|
1706
|
+
const stepId = `step-${state.stepCounter++}`;
|
|
1707
|
+
state.steps.push({
|
|
1708
|
+
id: stepId,
|
|
1709
|
+
eventType,
|
|
1710
|
+
message,
|
|
1711
|
+
status: "completed",
|
|
1712
|
+
timestamp: Date.now(),
|
|
1713
|
+
elapsedMs: event.elapsedMs
|
|
1714
|
+
});
|
|
1715
|
+
state.lastEventType = eventType;
|
|
1716
|
+
break;
|
|
1717
|
+
}
|
|
1718
|
+
case "USER_ACTION_FAILED": {
|
|
1719
|
+
appendThinkingText(state, "\n\u2717 " + (event.message || "Verification failed"));
|
|
1720
|
+
completeLastInProgressStep2(state.steps);
|
|
1721
|
+
state.userActionRequest = void 0;
|
|
1722
|
+
state.userActionPending = false;
|
|
1723
|
+
const stepId = `step-${state.stepCounter++}`;
|
|
1724
|
+
state.steps.push({
|
|
1725
|
+
id: stepId,
|
|
1726
|
+
eventType,
|
|
1727
|
+
message,
|
|
1728
|
+
status: "error",
|
|
1729
|
+
timestamp: Date.now(),
|
|
1730
|
+
elapsedMs: event.elapsedMs
|
|
1731
|
+
});
|
|
1732
|
+
state.lastEventType = eventType;
|
|
1733
|
+
break;
|
|
1734
|
+
}
|
|
1735
|
+
case "WORKFLOW_ERROR":
|
|
1736
|
+
case "ERROR":
|
|
1737
|
+
state.hasError = true;
|
|
1738
|
+
state.errorMessage = event.errorMessage || event.message || "Workflow error";
|
|
1739
|
+
state.lastEventType = eventType;
|
|
1740
|
+
break;
|
|
1741
|
+
case "INTENT_ERROR": {
|
|
1742
|
+
state.errorMessage = message || event.errorMessage || "An error occurred";
|
|
1743
|
+
const intentStep = state.steps.find((s) => s.eventType === "INTENT_STARTED" && s.status === "in_progress");
|
|
1744
|
+
if (intentStep) {
|
|
1745
|
+
intentStep.status = "error";
|
|
1746
|
+
intentStep.isThinking = false;
|
|
1747
|
+
}
|
|
1748
|
+
state.lastEventType = eventType;
|
|
1749
|
+
break;
|
|
1750
|
+
}
|
|
1751
|
+
default:
|
|
1752
|
+
state.lastEventType = eventType;
|
|
1753
|
+
break;
|
|
1754
|
+
}
|
|
1755
|
+
return state;
|
|
1756
|
+
}
|
|
1757
|
+
|
|
1758
|
+
// src/hooks/useStreamManagerV2.ts
|
|
1759
|
+
var FRIENDLY_ERROR_MESSAGE2 = "Oops, something went wrong. Please try again.";
|
|
1760
|
+
function useStreamManagerV2(config, callbacks, setMessages, setIsWaitingForResponse) {
|
|
1761
|
+
const abortControllerRef = react.useRef(null);
|
|
1762
|
+
const configRef = react.useRef(config);
|
|
1763
|
+
configRef.current = config;
|
|
1764
|
+
const callbacksRef = react.useRef(callbacks);
|
|
1765
|
+
callbacksRef.current = callbacks;
|
|
1766
|
+
const startStream = react.useCallback(
|
|
1767
|
+
async (userMessage, streamingId, sessionId, externalAbortController) => {
|
|
1768
|
+
abortControllerRef.current?.abort();
|
|
1769
|
+
const abortController = externalAbortController ?? new AbortController();
|
|
1770
|
+
abortControllerRef.current = abortController;
|
|
1771
|
+
const state = createInitialV2State();
|
|
1772
|
+
const updateMessage = (update) => {
|
|
1773
|
+
if (abortController.signal.aborted) return;
|
|
1774
|
+
setMessages(
|
|
1775
|
+
(prev) => prev.map(
|
|
1776
|
+
(msg) => msg.id === streamingId ? { ...msg, ...update } : msg
|
|
1777
|
+
)
|
|
1778
|
+
);
|
|
1779
|
+
};
|
|
1780
|
+
const currentConfig = configRef.current;
|
|
1781
|
+
const requestBody = buildRequestBody(currentConfig, userMessage, sessionId);
|
|
1782
|
+
const url = buildStreamingUrl(currentConfig);
|
|
1783
|
+
const headers = buildRequestHeaders(currentConfig);
|
|
1784
|
+
try {
|
|
1785
|
+
await streamWorkflowEvents(url, requestBody, headers, {
|
|
1786
|
+
signal: abortController.signal,
|
|
1787
|
+
onEvent: (event) => {
|
|
1788
|
+
if (abortController.signal.aborted) return;
|
|
1789
|
+
if (typeof event.eventType === "string" && event.eventType.toUpperCase() === "KEEP_ALIVE") {
|
|
1790
|
+
if (event.executionId) state.executionId = event.executionId;
|
|
1791
|
+
if (event.sessionId) state.sessionId = event.sessionId;
|
|
1792
|
+
return;
|
|
1793
|
+
}
|
|
1794
|
+
processStreamEventV2(event, state);
|
|
1795
|
+
const eventType = event.eventType;
|
|
1796
|
+
if (eventType === "USER_ACTION_REQUIRED" && state.userActionRequest) {
|
|
1797
|
+
callbacksRef.current.onUserActionRequired?.(state.userActionRequest);
|
|
1798
|
+
} else if (eventType.startsWith("USER_ACTION_") && eventType !== "USER_ACTION_REQUIRED") {
|
|
1799
|
+
const msg = event.message?.trim() || event.errorMessage?.trim() || getEventMessage(event);
|
|
1800
|
+
callbacksRef.current.onUserActionEvent?.(eventType, msg);
|
|
1801
|
+
}
|
|
1802
|
+
const activeStep = state.steps.find((s) => s.id === state.currentExecutingStepId);
|
|
1803
|
+
const lastInProgressStep = [...state.steps].reverse().find((s) => s.status === "in_progress");
|
|
1804
|
+
const currentMessage = activeStep?.message || lastInProgressStep?.message || getEventMessage(event);
|
|
1805
|
+
if (state.hasError) {
|
|
1806
|
+
updateMessage({
|
|
1807
|
+
streamingContent: FRIENDLY_ERROR_MESSAGE2,
|
|
1808
|
+
content: FRIENDLY_ERROR_MESSAGE2,
|
|
1809
|
+
streamProgress: "error",
|
|
1810
|
+
isError: true,
|
|
1811
|
+
errorDetails: state.errorMessage,
|
|
1812
|
+
formattedThinkingText: state.formattedThinkingText || void 0,
|
|
1813
|
+
steps: [...state.steps],
|
|
1814
|
+
currentExecutingStepId: void 0,
|
|
1815
|
+
executionId: state.executionId,
|
|
1816
|
+
sessionId: state.sessionId
|
|
1817
|
+
});
|
|
1818
|
+
} else {
|
|
1819
|
+
updateMessage({
|
|
1820
|
+
streamingContent: "",
|
|
1821
|
+
content: "",
|
|
1822
|
+
currentMessage,
|
|
1823
|
+
streamProgress: "processing",
|
|
1824
|
+
isError: false,
|
|
1825
|
+
formattedThinkingText: state.formattedThinkingText || void 0,
|
|
1826
|
+
steps: [...state.steps],
|
|
1827
|
+
currentExecutingStepId: state.currentExecutingStepId,
|
|
1828
|
+
executionId: state.executionId,
|
|
1829
|
+
sessionId: state.sessionId,
|
|
1830
|
+
userActionResult: state.userActionResult,
|
|
1831
|
+
isCancelled: false
|
|
1832
|
+
});
|
|
1833
|
+
}
|
|
1834
|
+
},
|
|
1835
|
+
onError: (error) => {
|
|
1836
|
+
setIsWaitingForResponse(false);
|
|
1837
|
+
if (error.name !== "AbortError") {
|
|
1838
|
+
callbacksRef.current.onError?.(error);
|
|
1839
|
+
}
|
|
1840
|
+
if (state.userActionPending) {
|
|
1841
|
+
state.userActionPending = false;
|
|
1842
|
+
state.userActionRequest = void 0;
|
|
1843
|
+
callbacksRef.current.onUserActionEvent?.(
|
|
1844
|
+
"USER_ACTION_FAILED",
|
|
1845
|
+
"Connection lost. Please try again."
|
|
1846
|
+
);
|
|
1847
|
+
}
|
|
1848
|
+
const isAborted = error.name === "AbortError";
|
|
1849
|
+
setMessages(
|
|
1850
|
+
(prev) => prev.map(
|
|
1851
|
+
(msg) => msg.id === streamingId ? {
|
|
1852
|
+
...msg,
|
|
1853
|
+
isStreaming: false,
|
|
1854
|
+
streamProgress: isAborted ? "processing" : "error",
|
|
1855
|
+
isError: !isAborted,
|
|
1856
|
+
isCancelled: isAborted,
|
|
1857
|
+
errorDetails: isAborted ? void 0 : error.message,
|
|
1858
|
+
content: isAborted ? state.finalResponse || "" : state.finalResponse || FRIENDLY_ERROR_MESSAGE2,
|
|
1859
|
+
currentMessage: isAborted ? "Thinking..." : void 0,
|
|
1860
|
+
formattedThinkingText: state.formattedThinkingText || void 0,
|
|
1861
|
+
steps: [...state.steps].map((step) => {
|
|
1862
|
+
if (step.status === "in_progress" && isAborted) {
|
|
1863
|
+
return { ...step, status: "pending" };
|
|
1864
|
+
}
|
|
1865
|
+
return step;
|
|
1866
|
+
}),
|
|
1867
|
+
currentExecutingStepId: void 0
|
|
1868
|
+
} : msg
|
|
1869
|
+
)
|
|
1870
|
+
);
|
|
1871
|
+
},
|
|
1872
|
+
onComplete: () => {
|
|
1873
|
+
setIsWaitingForResponse(false);
|
|
1874
|
+
if (state.userActionPending) {
|
|
1875
|
+
state.userActionPending = false;
|
|
1876
|
+
state.userActionRequest = void 0;
|
|
1877
|
+
callbacksRef.current.onUserActionEvent?.(
|
|
1878
|
+
"USER_ACTION_FAILED",
|
|
1879
|
+
"Verification could not be completed."
|
|
1880
|
+
);
|
|
1881
|
+
}
|
|
1882
|
+
if (state.sessionId && state.sessionId !== sessionId) {
|
|
1883
|
+
callbacksRef.current.onSessionIdChange?.(state.sessionId);
|
|
1884
|
+
}
|
|
1885
|
+
const needsImageResolve = !state.hasError && !abortController.signal.aborted && hasRagImages(state.finalResponse);
|
|
1886
|
+
const finalMessage = {
|
|
1887
|
+
id: streamingId,
|
|
1888
|
+
sessionId: state.sessionId || sessionId,
|
|
1889
|
+
role: "assistant",
|
|
1890
|
+
content: state.hasError ? FRIENDLY_ERROR_MESSAGE2 : state.finalResponse || "",
|
|
1891
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
1892
|
+
isStreaming: false,
|
|
1893
|
+
streamProgress: state.hasError ? "error" : "completed",
|
|
1894
|
+
isError: state.hasError,
|
|
1895
|
+
errorDetails: state.hasError ? state.errorMessage : void 0,
|
|
1896
|
+
executionId: state.executionId,
|
|
1897
|
+
tracingData: state.finalData,
|
|
1898
|
+
steps: state.hasError ? [] : [...state.steps],
|
|
1899
|
+
isCancelled: false,
|
|
1900
|
+
currentExecutingStepId: void 0,
|
|
1901
|
+
userActionResult: state.userActionResult,
|
|
1902
|
+
formattedThinkingText: state.hasError ? void 0 : state.formattedThinkingText || void 0,
|
|
1903
|
+
isResolvingImages: needsImageResolve
|
|
1904
|
+
};
|
|
1905
|
+
setMessages(
|
|
1906
|
+
(prev) => prev.map(
|
|
1907
|
+
(msg) => msg.id === streamingId ? finalMessage : msg
|
|
1908
|
+
)
|
|
1909
|
+
);
|
|
1910
|
+
callbacksRef.current.onStreamComplete?.(finalMessage);
|
|
1911
|
+
}
|
|
1912
|
+
});
|
|
1913
|
+
const shouldResolveImages = !abortController.signal.aborted && !state.hasError && hasRagImages(state.finalResponse);
|
|
1914
|
+
if (shouldResolveImages) {
|
|
1915
|
+
await waitForNextPaint(abortController.signal);
|
|
1916
|
+
}
|
|
1917
|
+
if (shouldResolveImages && !abortController.signal.aborted) {
|
|
1918
|
+
try {
|
|
1919
|
+
const resolvedContent = await resolveRagImageUrls(
|
|
1920
|
+
currentConfig,
|
|
1921
|
+
state.finalResponse,
|
|
1922
|
+
abortController.signal
|
|
1923
|
+
);
|
|
1924
|
+
setMessages(
|
|
1925
|
+
(prev) => prev.map(
|
|
1926
|
+
(msg) => msg.id === streamingId ? { ...msg, content: resolvedContent, isResolvingImages: false } : msg
|
|
1927
|
+
)
|
|
1928
|
+
);
|
|
1929
|
+
} catch {
|
|
1930
|
+
setMessages(
|
|
1931
|
+
(prev) => prev.map(
|
|
1932
|
+
(msg) => msg.id === streamingId ? { ...msg, isResolvingImages: false } : msg
|
|
1933
|
+
)
|
|
1934
|
+
);
|
|
1935
|
+
}
|
|
1936
|
+
}
|
|
1937
|
+
return state.sessionId;
|
|
1938
|
+
} catch (error) {
|
|
1939
|
+
setIsWaitingForResponse(false);
|
|
1940
|
+
if (error.name !== "AbortError") {
|
|
1941
|
+
callbacksRef.current.onError?.(error);
|
|
1942
|
+
}
|
|
1943
|
+
if (state.userActionPending) {
|
|
1944
|
+
state.userActionPending = false;
|
|
1945
|
+
state.userActionRequest = void 0;
|
|
1946
|
+
callbacksRef.current.onUserActionEvent?.(
|
|
1947
|
+
"USER_ACTION_FAILED",
|
|
1948
|
+
"Connection lost. Please try again."
|
|
1949
|
+
);
|
|
1950
|
+
}
|
|
1951
|
+
const isAborted = error.name === "AbortError";
|
|
1952
|
+
setMessages(
|
|
1953
|
+
(prev) => prev.map(
|
|
1954
|
+
(msg) => msg.id === streamingId ? {
|
|
1955
|
+
...msg,
|
|
1956
|
+
isStreaming: false,
|
|
1957
|
+
streamProgress: isAborted ? "processing" : "error",
|
|
1958
|
+
isError: !isAborted,
|
|
1959
|
+
isCancelled: isAborted,
|
|
1960
|
+
errorDetails: isAborted ? void 0 : error.message,
|
|
1961
|
+
content: isAborted ? state.finalResponse || "" : state.finalResponse || FRIENDLY_ERROR_MESSAGE2,
|
|
1962
|
+
formattedThinkingText: state.formattedThinkingText || void 0,
|
|
1963
|
+
steps: [...state.steps].map((step) => {
|
|
1964
|
+
if (step.status === "in_progress" && isAborted) {
|
|
1965
|
+
return { ...step, status: "pending" };
|
|
1966
|
+
}
|
|
1967
|
+
return step;
|
|
1968
|
+
}),
|
|
1969
|
+
currentExecutingStepId: void 0
|
|
1970
|
+
} : msg
|
|
1971
|
+
)
|
|
1972
|
+
);
|
|
1973
|
+
return state.sessionId;
|
|
1974
|
+
}
|
|
1975
|
+
},
|
|
1976
|
+
[setMessages, setIsWaitingForResponse]
|
|
1977
|
+
);
|
|
1978
|
+
const cancelStream = react.useCallback(() => {
|
|
1979
|
+
abortControllerRef.current?.abort();
|
|
1980
|
+
}, []);
|
|
1981
|
+
return {
|
|
1982
|
+
startStream,
|
|
1983
|
+
cancelStream,
|
|
1984
|
+
abortControllerRef
|
|
1985
|
+
};
|
|
1986
|
+
}
|
|
1987
|
+
|
|
1988
|
+
// src/hooks/useChatV2.ts
|
|
1989
|
+
function useChatV2(config, callbacks = {}) {
|
|
1990
|
+
const [messages, setMessages] = react.useState(() => {
|
|
1991
|
+
if (config.userId) return chatStore.get(config.userId);
|
|
1992
|
+
return config.initialMessages ?? [];
|
|
1993
|
+
});
|
|
1994
|
+
const [isWaitingForResponse, setIsWaitingForResponse] = react.useState(false);
|
|
1995
|
+
const sessionIdRef = react.useRef(
|
|
1996
|
+
config.userId ? chatStore.get(config.userId).find((m) => m.sessionId)?.sessionId ?? config.initialSessionId ?? void 0 : config.initialSessionId ?? void 0
|
|
1997
|
+
);
|
|
1998
|
+
const prevUserIdRef = react.useRef(config.userId);
|
|
1999
|
+
const callbacksRef = react.useRef(callbacks);
|
|
2000
|
+
callbacksRef.current = callbacks;
|
|
2001
|
+
const configRef = react.useRef(config);
|
|
2002
|
+
configRef.current = config;
|
|
2003
|
+
const messagesRef = react.useRef(messages);
|
|
2004
|
+
messagesRef.current = messages;
|
|
2005
|
+
const storeAwareSetMessages = react.useCallback(
|
|
2006
|
+
(updater) => {
|
|
2007
|
+
const { userId } = configRef.current;
|
|
2008
|
+
if (userId && activeStreamStore.has(userId)) {
|
|
2009
|
+
activeStreamStore.applyMessages(userId, updater);
|
|
2010
|
+
}
|
|
2011
|
+
setMessages(updater);
|
|
2012
|
+
},
|
|
2013
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
2014
|
+
[]
|
|
2015
|
+
);
|
|
2016
|
+
const storeAwareSetIsWaiting = react.useCallback(
|
|
2017
|
+
(waiting) => {
|
|
2018
|
+
const { userId } = configRef.current;
|
|
2019
|
+
if (userId && activeStreamStore.has(userId)) {
|
|
2020
|
+
activeStreamStore.setWaiting(userId, waiting);
|
|
2021
|
+
}
|
|
2022
|
+
setIsWaitingForResponse(waiting);
|
|
2023
|
+
},
|
|
2024
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
2025
|
+
[]
|
|
2026
|
+
);
|
|
2027
|
+
const [userActionState, setUserActionState] = react.useState({
|
|
2028
|
+
request: null,
|
|
2029
|
+
result: null,
|
|
2030
|
+
clearOtpTrigger: 0
|
|
2031
|
+
});
|
|
2032
|
+
const userActionStateRef = react.useRef(userActionState);
|
|
2033
|
+
userActionStateRef.current = userActionState;
|
|
2034
|
+
const wrappedCallbacks = react.useMemo(() => ({
|
|
2035
|
+
...callbacksRef.current,
|
|
2036
|
+
onMessageSent: (message) => callbacksRef.current.onMessageSent?.(message),
|
|
2037
|
+
onStreamStart: () => callbacksRef.current.onStreamStart?.(),
|
|
2038
|
+
onStreamComplete: (message) => callbacksRef.current.onStreamComplete?.(message),
|
|
2039
|
+
onError: (error) => callbacksRef.current.onError?.(error),
|
|
2040
|
+
onExecutionTraceClick: (data) => callbacksRef.current.onExecutionTraceClick?.(data),
|
|
2041
|
+
onSessionIdChange: (sessionId) => callbacksRef.current.onSessionIdChange?.(sessionId),
|
|
2042
|
+
onUserActionRequired: (request) => {
|
|
2043
|
+
setUserActionState((prev) => ({ ...prev, request, result: null }));
|
|
2044
|
+
callbacksRef.current.onUserActionRequired?.(request);
|
|
2045
|
+
},
|
|
2046
|
+
onUserActionEvent: (eventType, message) => {
|
|
2047
|
+
switch (eventType) {
|
|
2048
|
+
case "USER_ACTION_SUCCESS":
|
|
2049
|
+
setUserActionState((prev) => ({ ...prev, request: null, result: "approved" }));
|
|
2050
|
+
break;
|
|
2051
|
+
case "USER_ACTION_REJECTED":
|
|
2052
|
+
setUserActionState((prev) => ({ ...prev, request: null, result: "rejected" }));
|
|
2053
|
+
break;
|
|
2054
|
+
case "USER_ACTION_EXPIRED":
|
|
2055
|
+
case "USER_ACTION_FAILED":
|
|
2056
|
+
setUserActionState((prev) => ({ ...prev, request: null }));
|
|
2057
|
+
break;
|
|
2058
|
+
case "USER_ACTION_INVALID":
|
|
2059
|
+
setUserActionState((prev) => ({ ...prev, clearOtpTrigger: prev.clearOtpTrigger + 1 }));
|
|
2060
|
+
break;
|
|
2061
|
+
}
|
|
2062
|
+
callbacksRef.current.onUserActionEvent?.(eventType, message);
|
|
2063
|
+
}
|
|
2064
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
2065
|
+
}), []);
|
|
2066
|
+
const { startStream, cancelStream: cancelStreamManager, abortControllerRef } = useStreamManagerV2(
|
|
2067
|
+
config,
|
|
2068
|
+
wrappedCallbacks,
|
|
2069
|
+
storeAwareSetMessages,
|
|
2070
|
+
storeAwareSetIsWaiting
|
|
2071
|
+
);
|
|
2072
|
+
const sendMessage = react.useCallback(
|
|
2073
|
+
async (userMessage) => {
|
|
2074
|
+
if (!userMessage.trim()) return;
|
|
2075
|
+
if (!sessionIdRef.current && configRef.current.autoGenerateSessionId !== false) {
|
|
2076
|
+
sessionIdRef.current = generateId();
|
|
2077
|
+
callbacksRef.current.onSessionIdChange?.(sessionIdRef.current);
|
|
2078
|
+
}
|
|
2079
|
+
const userMessageId = `user-${Date.now()}`;
|
|
2080
|
+
const userMsg = {
|
|
2081
|
+
id: userMessageId,
|
|
2082
|
+
sessionId: sessionIdRef.current,
|
|
2083
|
+
role: "user",
|
|
2084
|
+
content: userMessage,
|
|
2085
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString()
|
|
2086
|
+
};
|
|
2087
|
+
setMessages((prev) => [...prev, userMsg]);
|
|
2088
|
+
callbacksRef.current.onMessageSent?.(userMessage);
|
|
2089
|
+
setIsWaitingForResponse(true);
|
|
2090
|
+
callbacksRef.current.onStreamStart?.();
|
|
2091
|
+
const streamingId = `assistant-${Date.now()}`;
|
|
2092
|
+
const streamingMsg = {
|
|
2093
|
+
id: streamingId,
|
|
2094
|
+
sessionId: sessionIdRef.current,
|
|
2095
|
+
role: "assistant",
|
|
2096
|
+
content: "",
|
|
2097
|
+
streamingContent: "",
|
|
2098
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
2099
|
+
isStreaming: true,
|
|
2100
|
+
streamProgress: "started",
|
|
2101
|
+
steps: [],
|
|
2102
|
+
currentExecutingStepId: void 0,
|
|
2103
|
+
isCancelled: false,
|
|
2104
|
+
currentMessage: void 0
|
|
2105
|
+
};
|
|
2106
|
+
setMessages((prev) => [...prev, streamingMsg]);
|
|
2107
|
+
const abortController = new AbortController();
|
|
2108
|
+
const { userId } = configRef.current;
|
|
2109
|
+
if (userId) {
|
|
2110
|
+
const initialMessages = [...messagesRef.current, userMsg, streamingMsg];
|
|
2111
|
+
activeStreamStore.start(userId, abortController, initialMessages);
|
|
2112
|
+
}
|
|
2113
|
+
const newSessionId = await startStream(
|
|
2114
|
+
userMessage,
|
|
2115
|
+
streamingId,
|
|
2116
|
+
sessionIdRef.current,
|
|
2117
|
+
abortController
|
|
2118
|
+
);
|
|
2119
|
+
if (userId) {
|
|
2120
|
+
activeStreamStore.complete(userId);
|
|
2121
|
+
}
|
|
2122
|
+
if (!abortController.signal.aborted && newSessionId && newSessionId !== sessionIdRef.current) {
|
|
2123
|
+
sessionIdRef.current = newSessionId;
|
|
2124
|
+
}
|
|
2125
|
+
},
|
|
2126
|
+
[startStream]
|
|
2127
|
+
);
|
|
2128
|
+
const clearMessages = react.useCallback(() => {
|
|
2129
|
+
if (configRef.current.userId) {
|
|
2130
|
+
chatStore.delete(configRef.current.userId);
|
|
2131
|
+
}
|
|
2132
|
+
setMessages([]);
|
|
2133
|
+
}, []);
|
|
2134
|
+
const prependMessages = react.useCallback((msgs) => {
|
|
2135
|
+
setMessages((prev) => [...msgs, ...prev]);
|
|
2136
|
+
}, []);
|
|
2137
|
+
const cancelStream = react.useCallback(() => {
|
|
2138
|
+
if (configRef.current.userId) {
|
|
2139
|
+
activeStreamStore.abort(configRef.current.userId);
|
|
2140
|
+
}
|
|
2141
|
+
cancelStreamManager();
|
|
2142
|
+
setIsWaitingForResponse(false);
|
|
2143
|
+
setUserActionState((prev) => ({ ...prev, request: null, result: null }));
|
|
2144
|
+
setMessages(
|
|
2145
|
+
(prev) => prev.map((msg) => {
|
|
2146
|
+
if (msg.isStreaming) {
|
|
2147
|
+
return {
|
|
2148
|
+
...msg,
|
|
2149
|
+
...createCancelledMessageUpdate(
|
|
2150
|
+
msg.steps || [],
|
|
2151
|
+
msg.currentMessage
|
|
2152
|
+
)
|
|
2153
|
+
};
|
|
2154
|
+
}
|
|
2155
|
+
return msg;
|
|
2156
|
+
})
|
|
2157
|
+
);
|
|
2158
|
+
}, [cancelStreamManager]);
|
|
2159
|
+
const resetSession = react.useCallback(() => {
|
|
2160
|
+
if (configRef.current.userId) {
|
|
2161
|
+
activeStreamStore.abort(configRef.current.userId);
|
|
2162
|
+
chatStore.delete(configRef.current.userId);
|
|
2163
|
+
}
|
|
2164
|
+
setMessages([]);
|
|
2165
|
+
sessionIdRef.current = void 0;
|
|
2166
|
+
abortControllerRef.current?.abort();
|
|
2167
|
+
setIsWaitingForResponse(false);
|
|
2168
|
+
setUserActionState({ request: null, result: null, clearOtpTrigger: 0 });
|
|
2169
|
+
}, []);
|
|
2170
|
+
const getSessionId = react.useCallback(() => {
|
|
2171
|
+
return sessionIdRef.current;
|
|
2172
|
+
}, []);
|
|
2173
|
+
const getMessages = react.useCallback(() => {
|
|
2174
|
+
return messages;
|
|
2175
|
+
}, [messages]);
|
|
2176
|
+
const approveUserAction = react.useCallback(
|
|
2177
|
+
async (otp) => {
|
|
2178
|
+
const request = userActionStateRef.current.request;
|
|
2179
|
+
if (!request) return;
|
|
2180
|
+
try {
|
|
2181
|
+
await submitUserAction(configRef.current, request.userActionId, { otp });
|
|
2182
|
+
} catch (error) {
|
|
2183
|
+
setUserActionState((prev) => ({
|
|
2184
|
+
...prev,
|
|
2185
|
+
clearOtpTrigger: prev.clearOtpTrigger + 1
|
|
2186
|
+
}));
|
|
2187
|
+
callbacksRef.current.onError?.(error);
|
|
2188
|
+
throw error;
|
|
2189
|
+
}
|
|
2190
|
+
},
|
|
2191
|
+
[]
|
|
2192
|
+
);
|
|
2193
|
+
const rejectUserAction = react.useCallback(async () => {
|
|
2194
|
+
const request = userActionStateRef.current.request;
|
|
2195
|
+
if (!request) return;
|
|
2196
|
+
try {
|
|
2197
|
+
setMessages((prev) => {
|
|
2198
|
+
let lastStreamingIdx = -1;
|
|
2199
|
+
for (let i = prev.length - 1; i >= 0; i--) {
|
|
2200
|
+
if (prev[i].role === "assistant" && prev[i].isStreaming) {
|
|
2201
|
+
lastStreamingIdx = i;
|
|
2202
|
+
break;
|
|
2203
|
+
}
|
|
2204
|
+
}
|
|
2205
|
+
if (lastStreamingIdx === -1) return prev;
|
|
2206
|
+
return prev.map(
|
|
2207
|
+
(msg, i) => i === lastStreamingIdx ? { ...msg, currentMessage: "Rejecting..." } : msg
|
|
2208
|
+
);
|
|
2209
|
+
});
|
|
2210
|
+
await cancelUserAction(configRef.current, request.userActionId);
|
|
2211
|
+
} catch (error) {
|
|
2212
|
+
callbacksRef.current.onError?.(error);
|
|
2213
|
+
throw error;
|
|
2214
|
+
}
|
|
2215
|
+
}, []);
|
|
2216
|
+
const resendOtp = react.useCallback(async () => {
|
|
2217
|
+
const request = userActionStateRef.current.request;
|
|
2218
|
+
if (!request) return;
|
|
2219
|
+
try {
|
|
2220
|
+
await resendUserAction(configRef.current, request.userActionId);
|
|
2221
|
+
} catch (error) {
|
|
2222
|
+
callbacksRef.current.onError?.(error);
|
|
2223
|
+
throw error;
|
|
2224
|
+
}
|
|
2225
|
+
}, []);
|
|
2226
|
+
react.useEffect(() => {
|
|
2227
|
+
const { userId } = config;
|
|
2228
|
+
if (!userId) return;
|
|
2229
|
+
const unsubscribe = activeStreamStore.subscribe(userId, (msgs, isWaiting) => {
|
|
2230
|
+
setMessages(msgs);
|
|
2231
|
+
setIsWaitingForResponse(isWaiting);
|
|
2232
|
+
});
|
|
2233
|
+
const active = activeStreamStore.get(userId);
|
|
2234
|
+
if (active) {
|
|
2235
|
+
setMessages(active.messages);
|
|
2236
|
+
setIsWaitingForResponse(active.isWaiting);
|
|
2237
|
+
}
|
|
2238
|
+
return unsubscribe;
|
|
2239
|
+
}, []);
|
|
2240
|
+
react.useEffect(() => {
|
|
2241
|
+
if (!config.userId) return;
|
|
2242
|
+
const toSave = messages.filter((m) => !m.isStreaming);
|
|
2243
|
+
if (toSave.length > 0) {
|
|
2244
|
+
chatStore.set(config.userId, toSave);
|
|
2245
|
+
}
|
|
2246
|
+
}, [messages, config.userId]);
|
|
2247
|
+
react.useEffect(() => {
|
|
2248
|
+
const prevUserId = prevUserIdRef.current;
|
|
2249
|
+
prevUserIdRef.current = config.userId;
|
|
2250
|
+
if (prevUserId === config.userId) return;
|
|
2251
|
+
if (prevUserId && !config.userId) {
|
|
2252
|
+
chatStore.delete(prevUserId);
|
|
2253
|
+
setMessages([]);
|
|
2254
|
+
sessionIdRef.current = void 0;
|
|
2255
|
+
setIsWaitingForResponse(false);
|
|
2256
|
+
setUserActionState({ request: null, result: null, clearOtpTrigger: 0 });
|
|
2257
|
+
} else if (config.userId) {
|
|
2258
|
+
const stored = chatStore.get(config.userId);
|
|
2259
|
+
setMessages(stored);
|
|
2260
|
+
sessionIdRef.current = stored.find((m) => m.sessionId)?.sessionId;
|
|
2261
|
+
}
|
|
2262
|
+
}, [config.userId]);
|
|
2263
|
+
return {
|
|
2264
|
+
messages,
|
|
2265
|
+
sendMessage,
|
|
2266
|
+
clearMessages,
|
|
2267
|
+
prependMessages,
|
|
2268
|
+
cancelStream,
|
|
2269
|
+
resetSession,
|
|
2270
|
+
getSessionId,
|
|
2271
|
+
getMessages,
|
|
2272
|
+
isWaitingForResponse,
|
|
2273
|
+
sessionId: sessionIdRef.current,
|
|
2274
|
+
userActionState,
|
|
2275
|
+
approveUserAction,
|
|
2276
|
+
rejectUserAction,
|
|
2277
|
+
resendOtp
|
|
2278
|
+
};
|
|
2279
|
+
}
|
|
1211
2280
|
function getSpeechRecognition() {
|
|
1212
2281
|
if (typeof window === "undefined") return null;
|
|
1213
2282
|
return window.SpeechRecognition || window.webkitSpeechRecognition || null;
|
|
@@ -1424,12 +2493,16 @@ function useVoice(config = {}, callbacks = {}) {
|
|
|
1424
2493
|
};
|
|
1425
2494
|
}
|
|
1426
2495
|
|
|
2496
|
+
exports.buildFormattedThinking = buildFormattedThinking;
|
|
1427
2497
|
exports.cancelUserAction = cancelUserAction;
|
|
2498
|
+
exports.createInitialV2State = createInitialV2State;
|
|
1428
2499
|
exports.generateId = generateId;
|
|
2500
|
+
exports.processStreamEventV2 = processStreamEventV2;
|
|
1429
2501
|
exports.resendUserAction = resendUserAction;
|
|
1430
2502
|
exports.streamWorkflowEvents = streamWorkflowEvents;
|
|
1431
2503
|
exports.submitUserAction = submitUserAction;
|
|
1432
2504
|
exports.useChat = useChat;
|
|
2505
|
+
exports.useChatV2 = useChatV2;
|
|
1433
2506
|
exports.useVoice = useVoice;
|
|
1434
2507
|
//# sourceMappingURL=index.js.map
|
|
1435
2508
|
//# sourceMappingURL=index.js.map
|