@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.native.js
CHANGED
|
@@ -500,8 +500,78 @@ function processStreamEvent(event, state) {
|
|
|
500
500
|
|
|
501
501
|
// src/utils/messageStateManager.ts
|
|
502
502
|
var FRIENDLY_ERROR_MESSAGE = "Oops, something went wrong. Please try again.";
|
|
503
|
+
function buildFormattedThinking(steps, allThinkingText) {
|
|
504
|
+
const parts = [];
|
|
505
|
+
const safeSteps = steps ?? [];
|
|
506
|
+
const cleanAll = allThinkingText.replace(/^\s+/, "");
|
|
507
|
+
if (cleanAll) {
|
|
508
|
+
const firstStepWithThinking = safeSteps.find(
|
|
509
|
+
(s) => s.thinkingText && s.thinkingText.trim()
|
|
510
|
+
);
|
|
511
|
+
if (!firstStepWithThinking) {
|
|
512
|
+
parts.push("**Preflight**");
|
|
513
|
+
parts.push(cleanAll);
|
|
514
|
+
} else {
|
|
515
|
+
const stepText = firstStepWithThinking.thinkingText.trim();
|
|
516
|
+
const idx = cleanAll.indexOf(stepText);
|
|
517
|
+
if (idx > 0) {
|
|
518
|
+
const orphaned = cleanAll.substring(0, idx).replace(/\s+$/, "");
|
|
519
|
+
if (orphaned) {
|
|
520
|
+
parts.push("**Preflight**");
|
|
521
|
+
parts.push(orphaned);
|
|
522
|
+
}
|
|
523
|
+
}
|
|
524
|
+
}
|
|
525
|
+
}
|
|
526
|
+
for (const step of safeSteps) {
|
|
527
|
+
switch (step.eventType) {
|
|
528
|
+
case "ORCHESTRATOR_THINKING":
|
|
529
|
+
parts.push("**Planning**");
|
|
530
|
+
if (step.message) parts.push(step.message);
|
|
531
|
+
break;
|
|
532
|
+
case "INTENT_STARTED": {
|
|
533
|
+
let label = step.message || "Processing";
|
|
534
|
+
const started = label.match(/^(.+?)\s+started$/i);
|
|
535
|
+
const progress = label.match(/^(.+?)\s+in progress$/i);
|
|
536
|
+
if (started) label = started[1];
|
|
537
|
+
else if (progress) label = progress[1];
|
|
538
|
+
parts.push(`**${label}**`);
|
|
539
|
+
if (step.thinkingText) parts.push(step.thinkingText);
|
|
540
|
+
break;
|
|
541
|
+
}
|
|
542
|
+
case "INTENT_PROGRESS": {
|
|
543
|
+
if (step.thinkingText) parts.push(step.thinkingText);
|
|
544
|
+
else if (step.message) parts.push(step.message);
|
|
545
|
+
break;
|
|
546
|
+
}
|
|
547
|
+
case "AGGREGATOR_THINKING":
|
|
548
|
+
parts.push("**Finalizing**");
|
|
549
|
+
if (step.message) parts.push(step.message);
|
|
550
|
+
break;
|
|
551
|
+
case "USER_ACTION_REQUIRED":
|
|
552
|
+
parts.push("**Verification Required**");
|
|
553
|
+
if (step.message) parts.push(step.message);
|
|
554
|
+
break;
|
|
555
|
+
case "USER_ACTION_SUCCESS":
|
|
556
|
+
parts.push(`\u2713 ${step.message || "Verification successful"}`);
|
|
557
|
+
break;
|
|
558
|
+
case "USER_ACTION_REJECTED":
|
|
559
|
+
parts.push(`\u2717 ${step.message || "Verification rejected"}`);
|
|
560
|
+
break;
|
|
561
|
+
case "USER_ACTION_EXPIRED":
|
|
562
|
+
parts.push(`\u2717 ${step.message || "Verification expired"}`);
|
|
563
|
+
break;
|
|
564
|
+
case "USER_ACTION_FAILED":
|
|
565
|
+
parts.push(`\u2717 ${step.message || "Verification failed"}`);
|
|
566
|
+
break;
|
|
567
|
+
}
|
|
568
|
+
}
|
|
569
|
+
return parts.length > 0 ? parts.join("\n") : allThinkingText;
|
|
570
|
+
}
|
|
503
571
|
function createStreamingMessageUpdate(state) {
|
|
504
572
|
const hasCompletedContent = state.accumulatedContent && state.finalData !== void 0;
|
|
573
|
+
const steps = state.hasError ? [] : [...state.steps];
|
|
574
|
+
const allThinking = state.hasError ? void 0 : state.allThinkingText;
|
|
505
575
|
return {
|
|
506
576
|
streamingContent: state.hasError ? FRIENDLY_ERROR_MESSAGE : hasCompletedContent ? state.accumulatedContent : "",
|
|
507
577
|
content: state.hasError ? FRIENDLY_ERROR_MESSAGE : "",
|
|
@@ -511,12 +581,13 @@ function createStreamingMessageUpdate(state) {
|
|
|
511
581
|
errorDetails: state.hasError ? state.errorMessage : void 0,
|
|
512
582
|
executionId: state.executionId,
|
|
513
583
|
sessionId: state.sessionId,
|
|
514
|
-
steps
|
|
584
|
+
steps,
|
|
515
585
|
currentExecutingStepId: state.hasError ? void 0 : state.currentExecutingStepId,
|
|
516
586
|
isCancelled: false,
|
|
517
587
|
userActionResult: state.userActionResult,
|
|
518
588
|
activeThinkingText: state.hasError ? void 0 : state.activeThinkingText,
|
|
519
|
-
allThinkingText:
|
|
589
|
+
allThinkingText: allThinking,
|
|
590
|
+
formattedThinkingText: state.hasError ? void 0 : buildFormattedThinking(steps, allThinking || "")
|
|
520
591
|
};
|
|
521
592
|
}
|
|
522
593
|
function createErrorMessageUpdate(error, state) {
|
|
@@ -540,6 +611,8 @@ function createErrorMessageUpdate(error, state) {
|
|
|
540
611
|
};
|
|
541
612
|
}
|
|
542
613
|
function createFinalMessage(streamingId, state) {
|
|
614
|
+
const steps = state.hasError ? [] : [...state.steps];
|
|
615
|
+
const allThinking = state.hasError ? void 0 : state.allThinkingText;
|
|
543
616
|
return {
|
|
544
617
|
id: streamingId,
|
|
545
618
|
sessionId: state.sessionId,
|
|
@@ -552,12 +625,14 @@ function createFinalMessage(streamingId, state) {
|
|
|
552
625
|
errorDetails: state.hasError ? state.errorMessage : void 0,
|
|
553
626
|
executionId: state.executionId,
|
|
554
627
|
tracingData: state.finalData,
|
|
555
|
-
steps
|
|
628
|
+
steps,
|
|
556
629
|
isCancelled: false,
|
|
557
630
|
currentExecutingStepId: void 0,
|
|
558
631
|
userActionResult: state.userActionResult,
|
|
559
632
|
activeThinkingText: void 0,
|
|
560
|
-
allThinkingText:
|
|
633
|
+
allThinkingText: allThinking,
|
|
634
|
+
formattedThinkingText: state.hasError ? void 0 : buildFormattedThinking(steps, allThinking || ""),
|
|
635
|
+
isResolvingImages: state.hasError ? void 0 : state.isResolvingImages
|
|
561
636
|
};
|
|
562
637
|
}
|
|
563
638
|
function createCancelledMessageUpdate(steps, currentMessage) {
|
|
@@ -611,6 +686,16 @@ function buildUserActionUrl(config, userActionId, action) {
|
|
|
611
686
|
const encodedUserActionId = encodeURIComponent(userActionId);
|
|
612
687
|
return `${config.api.baseUrl}${basePath}/user-action/${encodedUserActionId}/${action}`;
|
|
613
688
|
}
|
|
689
|
+
function buildResolveImagesUrl(config) {
|
|
690
|
+
if (config.api.resolveImagesEndpoint) {
|
|
691
|
+
return `${config.api.baseUrl}${config.api.resolveImagesEndpoint}`;
|
|
692
|
+
}
|
|
693
|
+
const streamEndpoint = config.api.streamEndpoint || "/api/workflows/ask/stream";
|
|
694
|
+
const [endpointPath] = streamEndpoint.split("?");
|
|
695
|
+
const normalizedEndpointPath = endpointPath.replace(/\/+$/, "");
|
|
696
|
+
const basePath = normalizedEndpointPath.endsWith("/stream") ? normalizedEndpointPath.slice(0, -"/stream".length) : normalizedEndpointPath;
|
|
697
|
+
return `${config.api.baseUrl}${basePath}/resolve-image-urls`;
|
|
698
|
+
}
|
|
614
699
|
function buildRequestHeaders(config) {
|
|
615
700
|
const headers = {
|
|
616
701
|
...config.api.headers
|
|
@@ -729,6 +814,58 @@ var activeStreamStore = {
|
|
|
729
814
|
streams.delete(key);
|
|
730
815
|
}
|
|
731
816
|
};
|
|
817
|
+
|
|
818
|
+
// src/utils/ragImageResolver.ts
|
|
819
|
+
var RAG_IMAGE_REGEX = /\/api\/rag\/chunks\/[^"'\s]+\/image/;
|
|
820
|
+
function hasRagImages(content) {
|
|
821
|
+
return RAG_IMAGE_REGEX.test(content);
|
|
822
|
+
}
|
|
823
|
+
async function waitForNextPaint(signal) {
|
|
824
|
+
if (signal?.aborted) return;
|
|
825
|
+
await new Promise((resolve) => {
|
|
826
|
+
let isSettled = false;
|
|
827
|
+
const finish = () => {
|
|
828
|
+
if (isSettled) return;
|
|
829
|
+
isSettled = true;
|
|
830
|
+
signal?.removeEventListener("abort", finish);
|
|
831
|
+
resolve();
|
|
832
|
+
};
|
|
833
|
+
signal?.addEventListener("abort", finish, { once: true });
|
|
834
|
+
if (typeof requestAnimationFrame === "function") {
|
|
835
|
+
requestAnimationFrame(() => {
|
|
836
|
+
setTimeout(finish, 0);
|
|
837
|
+
});
|
|
838
|
+
return;
|
|
839
|
+
}
|
|
840
|
+
setTimeout(finish, 0);
|
|
841
|
+
});
|
|
842
|
+
}
|
|
843
|
+
async function resolveRagImageUrls(config, content, signal) {
|
|
844
|
+
const url = buildResolveImagesUrl(config);
|
|
845
|
+
const baseHeaders = buildRequestHeaders(config);
|
|
846
|
+
const headers = { "Content-Type": "application/json", ...baseHeaders };
|
|
847
|
+
const response = await fetch(url, {
|
|
848
|
+
method: "POST",
|
|
849
|
+
headers,
|
|
850
|
+
body: JSON.stringify({ input: content }),
|
|
851
|
+
signal
|
|
852
|
+
});
|
|
853
|
+
if (!response.ok) {
|
|
854
|
+
const errorText = await response.text();
|
|
855
|
+
throw new Error(`HTTP ${response.status}: ${errorText}`);
|
|
856
|
+
}
|
|
857
|
+
const text = await response.text();
|
|
858
|
+
try {
|
|
859
|
+
const parsed = JSON.parse(text);
|
|
860
|
+
if (typeof parsed === "string") return parsed;
|
|
861
|
+
if (typeof parsed.output === "string") return parsed.output;
|
|
862
|
+
if (typeof parsed.result === "string") return parsed.result;
|
|
863
|
+
} catch {
|
|
864
|
+
}
|
|
865
|
+
return text;
|
|
866
|
+
}
|
|
867
|
+
|
|
868
|
+
// src/hooks/useStreamManager.ts
|
|
732
869
|
function useStreamManager(config, callbacks, setMessages, setIsWaitingForResponse) {
|
|
733
870
|
const abortControllerRef = react.useRef(null);
|
|
734
871
|
const configRef = react.useRef(config);
|
|
@@ -894,9 +1031,11 @@ function useStreamManager(config, callbacks, setMessages, setIsWaitingForRespons
|
|
|
894
1031
|
if (state.currentSessionId && state.currentSessionId !== sessionId) {
|
|
895
1032
|
callbacksRef.current.onSessionIdChange?.(state.currentSessionId);
|
|
896
1033
|
}
|
|
1034
|
+
const needsImageResolve = !state.hasError && !abortController.signal.aborted && hasRagImages(state.accumulatedContent);
|
|
897
1035
|
const finalMessage = createFinalMessage(streamingId, {
|
|
898
1036
|
...state,
|
|
899
|
-
sessionId: state.currentSessionId || sessionId
|
|
1037
|
+
sessionId: state.currentSessionId || sessionId,
|
|
1038
|
+
isResolvingImages: needsImageResolve
|
|
900
1039
|
});
|
|
901
1040
|
setMessages(
|
|
902
1041
|
(prev) => prev.map(
|
|
@@ -907,6 +1046,30 @@ function useStreamManager(config, callbacks, setMessages, setIsWaitingForRespons
|
|
|
907
1046
|
}
|
|
908
1047
|
});
|
|
909
1048
|
clearThrottle();
|
|
1049
|
+
const shouldResolveImages = !abortController.signal.aborted && !state.hasError && hasRagImages(state.accumulatedContent);
|
|
1050
|
+
if (shouldResolveImages) {
|
|
1051
|
+
await waitForNextPaint(abortController.signal);
|
|
1052
|
+
}
|
|
1053
|
+
if (shouldResolveImages && !abortController.signal.aborted) {
|
|
1054
|
+
try {
|
|
1055
|
+
const resolvedContent = await resolveRagImageUrls(
|
|
1056
|
+
currentConfig,
|
|
1057
|
+
state.accumulatedContent,
|
|
1058
|
+
abortController.signal
|
|
1059
|
+
);
|
|
1060
|
+
setMessages(
|
|
1061
|
+
(prev) => prev.map(
|
|
1062
|
+
(msg) => msg.id === streamingId ? { ...msg, content: resolvedContent, isResolvingImages: false } : msg
|
|
1063
|
+
)
|
|
1064
|
+
);
|
|
1065
|
+
} catch {
|
|
1066
|
+
setMessages(
|
|
1067
|
+
(prev) => prev.map(
|
|
1068
|
+
(msg) => msg.id === streamingId ? { ...msg, isResolvingImages: false } : msg
|
|
1069
|
+
)
|
|
1070
|
+
);
|
|
1071
|
+
}
|
|
1072
|
+
}
|
|
910
1073
|
return state.currentSessionId;
|
|
911
1074
|
} catch (error) {
|
|
912
1075
|
clearThrottle();
|
|
@@ -1238,6 +1401,912 @@ function useChat(config, callbacks = {}) {
|
|
|
1238
1401
|
resendOtp
|
|
1239
1402
|
};
|
|
1240
1403
|
}
|
|
1404
|
+
|
|
1405
|
+
// src/utils/v2EventProcessor.ts
|
|
1406
|
+
function getEventText(event, field) {
|
|
1407
|
+
const value = event[field];
|
|
1408
|
+
return typeof value === "string" ? value.trim() : "";
|
|
1409
|
+
}
|
|
1410
|
+
function shouldShowIntentHeader(event) {
|
|
1411
|
+
const workerName = getEventText(event, "workerName");
|
|
1412
|
+
const intentId = getEventText(event, "intentId");
|
|
1413
|
+
return Boolean(workerName && intentId && workerName === intentId);
|
|
1414
|
+
}
|
|
1415
|
+
function addThinkingHeader(state, header) {
|
|
1416
|
+
state.formattedThinkingText += (state.formattedThinkingText ? "\n" : "") + header;
|
|
1417
|
+
}
|
|
1418
|
+
function addThinkingDetail(state, detail) {
|
|
1419
|
+
const trimmed = detail.trim();
|
|
1420
|
+
if (!trimmed) return;
|
|
1421
|
+
state.formattedThinkingText += (state.formattedThinkingText ? "\n" : "") + trimmed;
|
|
1422
|
+
}
|
|
1423
|
+
function addThinkingLine(state, header, detail) {
|
|
1424
|
+
state.formattedThinkingText += (state.formattedThinkingText ? "\n" : "") + header + "\n" + detail;
|
|
1425
|
+
}
|
|
1426
|
+
function appendThinkingText(state, text) {
|
|
1427
|
+
state.formattedThinkingText += text;
|
|
1428
|
+
}
|
|
1429
|
+
function completeLastInProgressStep2(steps) {
|
|
1430
|
+
for (let i = steps.length - 1; i >= 0; i--) {
|
|
1431
|
+
if (steps[i].status === "in_progress") {
|
|
1432
|
+
steps[i].status = "completed";
|
|
1433
|
+
return;
|
|
1434
|
+
}
|
|
1435
|
+
}
|
|
1436
|
+
}
|
|
1437
|
+
function createInitialV2State() {
|
|
1438
|
+
return {
|
|
1439
|
+
formattedThinkingText: "",
|
|
1440
|
+
finalResponse: "",
|
|
1441
|
+
currentWorker: "",
|
|
1442
|
+
lastEventType: "",
|
|
1443
|
+
sessionId: void 0,
|
|
1444
|
+
executionId: void 0,
|
|
1445
|
+
hasError: false,
|
|
1446
|
+
errorMessage: "",
|
|
1447
|
+
userActionRequest: void 0,
|
|
1448
|
+
userActionPending: false,
|
|
1449
|
+
userActionResult: void 0,
|
|
1450
|
+
finalData: void 0,
|
|
1451
|
+
steps: [],
|
|
1452
|
+
stepCounter: 0,
|
|
1453
|
+
currentExecutingStepId: void 0
|
|
1454
|
+
};
|
|
1455
|
+
}
|
|
1456
|
+
function processStreamEventV2(event, state) {
|
|
1457
|
+
const eventType = event.eventType;
|
|
1458
|
+
if (typeof eventType === "string" && eventType.toUpperCase() === "KEEP_ALIVE") {
|
|
1459
|
+
if (event.executionId) state.executionId = event.executionId;
|
|
1460
|
+
if (event.sessionId) state.sessionId = event.sessionId;
|
|
1461
|
+
return state;
|
|
1462
|
+
}
|
|
1463
|
+
if (event.executionId) state.executionId = event.executionId;
|
|
1464
|
+
if (event.sessionId) state.sessionId = event.sessionId;
|
|
1465
|
+
const message = getEventMessage(event);
|
|
1466
|
+
switch (eventType) {
|
|
1467
|
+
case "WORKFLOW_STARTED":
|
|
1468
|
+
case "STARTED":
|
|
1469
|
+
state.lastEventType = eventType;
|
|
1470
|
+
break;
|
|
1471
|
+
case "INTENT_THINKING": {
|
|
1472
|
+
const worker = getEventText(event, "workerName") || "Worker";
|
|
1473
|
+
const msg = getEventText(event, "message") || "Thinking...";
|
|
1474
|
+
const showHeader = shouldShowIntentHeader(event);
|
|
1475
|
+
if (worker !== state.currentWorker) {
|
|
1476
|
+
state.currentWorker = worker;
|
|
1477
|
+
if (showHeader && msg && msg !== worker) {
|
|
1478
|
+
addThinkingLine(state, `**${worker}**`, msg);
|
|
1479
|
+
} else if (showHeader) {
|
|
1480
|
+
addThinkingHeader(state, `**${worker}**`);
|
|
1481
|
+
} else if (msg !== "Thinking...") {
|
|
1482
|
+
addThinkingDetail(state, msg);
|
|
1483
|
+
}
|
|
1484
|
+
} else if ((showHeader || msg !== "Thinking...")) {
|
|
1485
|
+
appendThinkingText(state, "\n" + msg);
|
|
1486
|
+
}
|
|
1487
|
+
const lastInProgress = [...state.steps].reverse().find((s) => s.status === "in_progress");
|
|
1488
|
+
if (lastInProgress) {
|
|
1489
|
+
lastInProgress.thinkingText = "";
|
|
1490
|
+
lastInProgress.isThinking = true;
|
|
1491
|
+
}
|
|
1492
|
+
state.lastEventType = "INTENT_THINKING";
|
|
1493
|
+
break;
|
|
1494
|
+
}
|
|
1495
|
+
case "INTENT_THINKING_CONT": {
|
|
1496
|
+
const msg = event.message || "";
|
|
1497
|
+
if (!msg) break;
|
|
1498
|
+
if (state.lastEventType === "INTENT_THINKING") {
|
|
1499
|
+
appendThinkingText(state, "\n" + msg);
|
|
1500
|
+
} else {
|
|
1501
|
+
appendThinkingText(state, msg);
|
|
1502
|
+
}
|
|
1503
|
+
const thinkingStep = [...state.steps].reverse().find((s) => s.isThinking);
|
|
1504
|
+
if (thinkingStep) {
|
|
1505
|
+
thinkingStep.thinkingText = (thinkingStep.thinkingText || "") + msg;
|
|
1506
|
+
}
|
|
1507
|
+
state.lastEventType = "INTENT_THINKING_CONT";
|
|
1508
|
+
break;
|
|
1509
|
+
}
|
|
1510
|
+
case "ORCHESTRATOR_THINKING": {
|
|
1511
|
+
addThinkingLine(state, "**Planning**", event.message || "Understanding your request...");
|
|
1512
|
+
const stepId = `step-${state.stepCounter++}`;
|
|
1513
|
+
state.steps.push({
|
|
1514
|
+
id: stepId,
|
|
1515
|
+
eventType,
|
|
1516
|
+
message,
|
|
1517
|
+
status: "in_progress",
|
|
1518
|
+
timestamp: Date.now(),
|
|
1519
|
+
elapsedMs: event.elapsedMs
|
|
1520
|
+
});
|
|
1521
|
+
state.currentExecutingStepId = stepId;
|
|
1522
|
+
state.lastEventType = eventType;
|
|
1523
|
+
break;
|
|
1524
|
+
}
|
|
1525
|
+
case "ORCHESTRATOR_COMPLETED": {
|
|
1526
|
+
appendThinkingText(state, "\n" + (event.message || "Planning complete"));
|
|
1527
|
+
const step = state.steps.find((s) => s.eventType === "ORCHESTRATOR_THINKING" && s.status === "in_progress");
|
|
1528
|
+
if (step) {
|
|
1529
|
+
step.status = "completed";
|
|
1530
|
+
if (event.elapsedMs) step.elapsedMs = event.elapsedMs;
|
|
1531
|
+
if (step.id === state.currentExecutingStepId) state.currentExecutingStepId = void 0;
|
|
1532
|
+
}
|
|
1533
|
+
state.lastEventType = eventType;
|
|
1534
|
+
break;
|
|
1535
|
+
}
|
|
1536
|
+
case "INTENT_STARTED": {
|
|
1537
|
+
const worker = getEventText(event, "workerName") || "Worker";
|
|
1538
|
+
const msg = getEventText(event, "message") || "Starting...";
|
|
1539
|
+
const showHeader = shouldShowIntentHeader(event);
|
|
1540
|
+
state.currentWorker = worker;
|
|
1541
|
+
if (showHeader && msg !== worker) {
|
|
1542
|
+
addThinkingLine(state, `**${worker}**`, msg);
|
|
1543
|
+
} else if (showHeader) {
|
|
1544
|
+
addThinkingHeader(state, `**${worker}**`);
|
|
1545
|
+
} else {
|
|
1546
|
+
addThinkingDetail(state, msg);
|
|
1547
|
+
}
|
|
1548
|
+
const thinkingStep = state.steps.find((s) => s.isThinking);
|
|
1549
|
+
if (thinkingStep) thinkingStep.isThinking = false;
|
|
1550
|
+
const stepId = `step-${state.stepCounter++}`;
|
|
1551
|
+
state.steps.push({
|
|
1552
|
+
id: stepId,
|
|
1553
|
+
eventType,
|
|
1554
|
+
message,
|
|
1555
|
+
status: "in_progress",
|
|
1556
|
+
timestamp: Date.now(),
|
|
1557
|
+
elapsedMs: event.elapsedMs
|
|
1558
|
+
});
|
|
1559
|
+
state.currentExecutingStepId = stepId;
|
|
1560
|
+
state.lastEventType = eventType;
|
|
1561
|
+
break;
|
|
1562
|
+
}
|
|
1563
|
+
case "INTENT_COMPLETED": {
|
|
1564
|
+
const intentStep = state.steps.find((s) => s.eventType === "INTENT_STARTED" && s.status === "in_progress");
|
|
1565
|
+
if (intentStep) {
|
|
1566
|
+
intentStep.status = "completed";
|
|
1567
|
+
intentStep.isThinking = false;
|
|
1568
|
+
if (event.elapsedMs) intentStep.elapsedMs = event.elapsedMs;
|
|
1569
|
+
if (intentStep.id === state.currentExecutingStepId) state.currentExecutingStepId = void 0;
|
|
1570
|
+
}
|
|
1571
|
+
state.lastEventType = eventType;
|
|
1572
|
+
break;
|
|
1573
|
+
}
|
|
1574
|
+
case "AGGREGATOR_THINKING": {
|
|
1575
|
+
addThinkingLine(state, "**Finalizing**", event.message || "Preparing response...");
|
|
1576
|
+
const stepId = `step-${state.stepCounter++}`;
|
|
1577
|
+
state.steps.push({
|
|
1578
|
+
id: stepId,
|
|
1579
|
+
eventType,
|
|
1580
|
+
message,
|
|
1581
|
+
status: "in_progress",
|
|
1582
|
+
timestamp: Date.now(),
|
|
1583
|
+
elapsedMs: event.elapsedMs
|
|
1584
|
+
});
|
|
1585
|
+
state.currentExecutingStepId = stepId;
|
|
1586
|
+
state.lastEventType = eventType;
|
|
1587
|
+
break;
|
|
1588
|
+
}
|
|
1589
|
+
case "AGGREGATOR_COMPLETED": {
|
|
1590
|
+
appendThinkingText(state, "\n" + (event.message || "Response ready"));
|
|
1591
|
+
const step = state.steps.find((s) => s.eventType === "AGGREGATOR_THINKING" && s.status === "in_progress");
|
|
1592
|
+
if (step) {
|
|
1593
|
+
step.status = "completed";
|
|
1594
|
+
if (event.elapsedMs) step.elapsedMs = event.elapsedMs;
|
|
1595
|
+
if (step.id === state.currentExecutingStepId) state.currentExecutingStepId = void 0;
|
|
1596
|
+
}
|
|
1597
|
+
state.lastEventType = eventType;
|
|
1598
|
+
break;
|
|
1599
|
+
}
|
|
1600
|
+
case "WORKFLOW_COMPLETED":
|
|
1601
|
+
case "COMPLETED": {
|
|
1602
|
+
let content = extractResponseContent(event.response);
|
|
1603
|
+
const trace = event.trace && typeof event.trace === "object" ? event.trace : null;
|
|
1604
|
+
if (!content && trace?.workflowMsg && typeof trace.workflowMsg === "string") {
|
|
1605
|
+
content = trace.workflowMsg;
|
|
1606
|
+
}
|
|
1607
|
+
if (!content && trace?.aggregator && typeof trace.aggregator === "object") {
|
|
1608
|
+
const agg = trace.aggregator;
|
|
1609
|
+
if (typeof agg.response === "string") content = agg.response;
|
|
1610
|
+
else content = extractResponseContent(agg.response);
|
|
1611
|
+
}
|
|
1612
|
+
if (content) {
|
|
1613
|
+
state.finalResponse = content;
|
|
1614
|
+
state.finalData = event.response ?? event.trace;
|
|
1615
|
+
state.hasError = false;
|
|
1616
|
+
state.errorMessage = "";
|
|
1617
|
+
} else {
|
|
1618
|
+
state.hasError = true;
|
|
1619
|
+
state.errorMessage = "WORKFLOW_FAILED";
|
|
1620
|
+
}
|
|
1621
|
+
state.steps.forEach((step) => {
|
|
1622
|
+
if (step.status === "in_progress") {
|
|
1623
|
+
step.status = "completed";
|
|
1624
|
+
step.isThinking = false;
|
|
1625
|
+
}
|
|
1626
|
+
});
|
|
1627
|
+
state.lastEventType = eventType;
|
|
1628
|
+
break;
|
|
1629
|
+
}
|
|
1630
|
+
case "USER_ACTION_REQUIRED": {
|
|
1631
|
+
completeLastInProgressStep2(state.steps);
|
|
1632
|
+
if (event.userActionRequest) {
|
|
1633
|
+
state.userActionRequest = {
|
|
1634
|
+
userActionId: event.userActionRequest.userActionId,
|
|
1635
|
+
userActionType: event.userActionRequest.userActionType,
|
|
1636
|
+
message: event.userActionRequest.message,
|
|
1637
|
+
requestedSchema: event.userActionRequest.requestedSchema,
|
|
1638
|
+
metadata: event.userActionRequest.metadata
|
|
1639
|
+
};
|
|
1640
|
+
}
|
|
1641
|
+
state.userActionPending = true;
|
|
1642
|
+
const req = event.userActionRequest;
|
|
1643
|
+
if (req) {
|
|
1644
|
+
addThinkingLine(state, "**Verification Required**", req.message || "Waiting for authorization...");
|
|
1645
|
+
}
|
|
1646
|
+
const stepId = `step-${state.stepCounter++}`;
|
|
1647
|
+
state.steps.push({
|
|
1648
|
+
id: stepId,
|
|
1649
|
+
eventType,
|
|
1650
|
+
message,
|
|
1651
|
+
status: "in_progress",
|
|
1652
|
+
timestamp: Date.now(),
|
|
1653
|
+
elapsedMs: event.elapsedMs
|
|
1654
|
+
});
|
|
1655
|
+
state.currentExecutingStepId = stepId;
|
|
1656
|
+
state.lastEventType = eventType;
|
|
1657
|
+
break;
|
|
1658
|
+
}
|
|
1659
|
+
case "USER_ACTION_SUCCESS": {
|
|
1660
|
+
appendThinkingText(state, "\n\u2713 " + (event.message || "Verification successful"));
|
|
1661
|
+
completeLastInProgressStep2(state.steps);
|
|
1662
|
+
state.userActionRequest = void 0;
|
|
1663
|
+
state.userActionPending = false;
|
|
1664
|
+
state.userActionResult = "approved";
|
|
1665
|
+
const stepId = `step-${state.stepCounter++}`;
|
|
1666
|
+
state.steps.push({
|
|
1667
|
+
id: stepId,
|
|
1668
|
+
eventType,
|
|
1669
|
+
message,
|
|
1670
|
+
status: "completed",
|
|
1671
|
+
timestamp: Date.now(),
|
|
1672
|
+
elapsedMs: event.elapsedMs
|
|
1673
|
+
});
|
|
1674
|
+
state.lastEventType = eventType;
|
|
1675
|
+
break;
|
|
1676
|
+
}
|
|
1677
|
+
case "USER_ACTION_INVALID": {
|
|
1678
|
+
completeLastInProgressStep2(state.steps);
|
|
1679
|
+
const errorStepId = `step-${state.stepCounter++}`;
|
|
1680
|
+
state.steps.push({
|
|
1681
|
+
id: errorStepId,
|
|
1682
|
+
eventType,
|
|
1683
|
+
message,
|
|
1684
|
+
status: "error",
|
|
1685
|
+
timestamp: Date.now(),
|
|
1686
|
+
elapsedMs: event.elapsedMs
|
|
1687
|
+
});
|
|
1688
|
+
const retryStepId = `step-${state.stepCounter++}`;
|
|
1689
|
+
state.steps.push({
|
|
1690
|
+
id: retryStepId,
|
|
1691
|
+
eventType: "USER_ACTION_REQUIRED",
|
|
1692
|
+
message: "Waiting for verification...",
|
|
1693
|
+
status: "in_progress",
|
|
1694
|
+
timestamp: Date.now()
|
|
1695
|
+
});
|
|
1696
|
+
state.currentExecutingStepId = retryStepId;
|
|
1697
|
+
state.lastEventType = eventType;
|
|
1698
|
+
break;
|
|
1699
|
+
}
|
|
1700
|
+
case "USER_ACTION_REJECTED": {
|
|
1701
|
+
appendThinkingText(state, "\n\u2717 " + (event.message || "Verification rejected"));
|
|
1702
|
+
completeLastInProgressStep2(state.steps);
|
|
1703
|
+
state.userActionRequest = void 0;
|
|
1704
|
+
state.userActionPending = false;
|
|
1705
|
+
state.userActionResult = "rejected";
|
|
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_EXPIRED": {
|
|
1719
|
+
appendThinkingText(state, "\n\u2717 " + (event.message || "Verification expired"));
|
|
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 "USER_ACTION_RESENT": {
|
|
1736
|
+
const stepId = `step-${state.stepCounter++}`;
|
|
1737
|
+
state.steps.push({
|
|
1738
|
+
id: stepId,
|
|
1739
|
+
eventType,
|
|
1740
|
+
message,
|
|
1741
|
+
status: "completed",
|
|
1742
|
+
timestamp: Date.now(),
|
|
1743
|
+
elapsedMs: event.elapsedMs
|
|
1744
|
+
});
|
|
1745
|
+
state.lastEventType = eventType;
|
|
1746
|
+
break;
|
|
1747
|
+
}
|
|
1748
|
+
case "USER_ACTION_FAILED": {
|
|
1749
|
+
appendThinkingText(state, "\n\u2717 " + (event.message || "Verification failed"));
|
|
1750
|
+
completeLastInProgressStep2(state.steps);
|
|
1751
|
+
state.userActionRequest = void 0;
|
|
1752
|
+
state.userActionPending = false;
|
|
1753
|
+
const stepId = `step-${state.stepCounter++}`;
|
|
1754
|
+
state.steps.push({
|
|
1755
|
+
id: stepId,
|
|
1756
|
+
eventType,
|
|
1757
|
+
message,
|
|
1758
|
+
status: "error",
|
|
1759
|
+
timestamp: Date.now(),
|
|
1760
|
+
elapsedMs: event.elapsedMs
|
|
1761
|
+
});
|
|
1762
|
+
state.lastEventType = eventType;
|
|
1763
|
+
break;
|
|
1764
|
+
}
|
|
1765
|
+
case "WORKFLOW_ERROR":
|
|
1766
|
+
case "ERROR":
|
|
1767
|
+
state.hasError = true;
|
|
1768
|
+
state.errorMessage = event.errorMessage || event.message || "Workflow error";
|
|
1769
|
+
state.lastEventType = eventType;
|
|
1770
|
+
break;
|
|
1771
|
+
case "INTENT_ERROR": {
|
|
1772
|
+
state.errorMessage = message || event.errorMessage || "An error occurred";
|
|
1773
|
+
const intentStep = state.steps.find((s) => s.eventType === "INTENT_STARTED" && s.status === "in_progress");
|
|
1774
|
+
if (intentStep) {
|
|
1775
|
+
intentStep.status = "error";
|
|
1776
|
+
intentStep.isThinking = false;
|
|
1777
|
+
}
|
|
1778
|
+
state.lastEventType = eventType;
|
|
1779
|
+
break;
|
|
1780
|
+
}
|
|
1781
|
+
default:
|
|
1782
|
+
state.lastEventType = eventType;
|
|
1783
|
+
break;
|
|
1784
|
+
}
|
|
1785
|
+
return state;
|
|
1786
|
+
}
|
|
1787
|
+
|
|
1788
|
+
// src/hooks/useStreamManagerV2.ts
|
|
1789
|
+
var FRIENDLY_ERROR_MESSAGE2 = "Oops, something went wrong. Please try again.";
|
|
1790
|
+
function useStreamManagerV2(config, callbacks, setMessages, setIsWaitingForResponse) {
|
|
1791
|
+
const abortControllerRef = react.useRef(null);
|
|
1792
|
+
const configRef = react.useRef(config);
|
|
1793
|
+
configRef.current = config;
|
|
1794
|
+
const callbacksRef = react.useRef(callbacks);
|
|
1795
|
+
callbacksRef.current = callbacks;
|
|
1796
|
+
const startStream = react.useCallback(
|
|
1797
|
+
async (userMessage, streamingId, sessionId, externalAbortController) => {
|
|
1798
|
+
abortControllerRef.current?.abort();
|
|
1799
|
+
const abortController = externalAbortController ?? new AbortController();
|
|
1800
|
+
abortControllerRef.current = abortController;
|
|
1801
|
+
const state = createInitialV2State();
|
|
1802
|
+
const updateMessage = (update) => {
|
|
1803
|
+
if (abortController.signal.aborted) return;
|
|
1804
|
+
setMessages(
|
|
1805
|
+
(prev) => prev.map(
|
|
1806
|
+
(msg) => msg.id === streamingId ? { ...msg, ...update } : msg
|
|
1807
|
+
)
|
|
1808
|
+
);
|
|
1809
|
+
};
|
|
1810
|
+
const currentConfig = configRef.current;
|
|
1811
|
+
const requestBody = buildRequestBody(currentConfig, userMessage, sessionId);
|
|
1812
|
+
const url = buildStreamingUrl(currentConfig);
|
|
1813
|
+
const headers = buildRequestHeaders(currentConfig);
|
|
1814
|
+
try {
|
|
1815
|
+
await streamWorkflowEvents(url, requestBody, headers, {
|
|
1816
|
+
signal: abortController.signal,
|
|
1817
|
+
onEvent: (event) => {
|
|
1818
|
+
if (abortController.signal.aborted) return;
|
|
1819
|
+
if (typeof event.eventType === "string" && event.eventType.toUpperCase() === "KEEP_ALIVE") {
|
|
1820
|
+
if (event.executionId) state.executionId = event.executionId;
|
|
1821
|
+
if (event.sessionId) state.sessionId = event.sessionId;
|
|
1822
|
+
return;
|
|
1823
|
+
}
|
|
1824
|
+
processStreamEventV2(event, state);
|
|
1825
|
+
const eventType = event.eventType;
|
|
1826
|
+
if (eventType === "USER_ACTION_REQUIRED" && state.userActionRequest) {
|
|
1827
|
+
callbacksRef.current.onUserActionRequired?.(state.userActionRequest);
|
|
1828
|
+
} else if (eventType.startsWith("USER_ACTION_") && eventType !== "USER_ACTION_REQUIRED") {
|
|
1829
|
+
const msg = event.message?.trim() || event.errorMessage?.trim() || getEventMessage(event);
|
|
1830
|
+
callbacksRef.current.onUserActionEvent?.(eventType, msg);
|
|
1831
|
+
}
|
|
1832
|
+
const activeStep = state.steps.find((s) => s.id === state.currentExecutingStepId);
|
|
1833
|
+
const lastInProgressStep = [...state.steps].reverse().find((s) => s.status === "in_progress");
|
|
1834
|
+
const currentMessage = activeStep?.message || lastInProgressStep?.message || getEventMessage(event);
|
|
1835
|
+
if (state.hasError) {
|
|
1836
|
+
updateMessage({
|
|
1837
|
+
streamingContent: FRIENDLY_ERROR_MESSAGE2,
|
|
1838
|
+
content: FRIENDLY_ERROR_MESSAGE2,
|
|
1839
|
+
streamProgress: "error",
|
|
1840
|
+
isError: true,
|
|
1841
|
+
errorDetails: state.errorMessage,
|
|
1842
|
+
formattedThinkingText: state.formattedThinkingText || void 0,
|
|
1843
|
+
steps: [...state.steps],
|
|
1844
|
+
currentExecutingStepId: void 0,
|
|
1845
|
+
executionId: state.executionId,
|
|
1846
|
+
sessionId: state.sessionId
|
|
1847
|
+
});
|
|
1848
|
+
} else {
|
|
1849
|
+
updateMessage({
|
|
1850
|
+
streamingContent: "",
|
|
1851
|
+
content: "",
|
|
1852
|
+
currentMessage,
|
|
1853
|
+
streamProgress: "processing",
|
|
1854
|
+
isError: false,
|
|
1855
|
+
formattedThinkingText: state.formattedThinkingText || void 0,
|
|
1856
|
+
steps: [...state.steps],
|
|
1857
|
+
currentExecutingStepId: state.currentExecutingStepId,
|
|
1858
|
+
executionId: state.executionId,
|
|
1859
|
+
sessionId: state.sessionId,
|
|
1860
|
+
userActionResult: state.userActionResult,
|
|
1861
|
+
isCancelled: false
|
|
1862
|
+
});
|
|
1863
|
+
}
|
|
1864
|
+
},
|
|
1865
|
+
onError: (error) => {
|
|
1866
|
+
setIsWaitingForResponse(false);
|
|
1867
|
+
if (error.name !== "AbortError") {
|
|
1868
|
+
callbacksRef.current.onError?.(error);
|
|
1869
|
+
}
|
|
1870
|
+
if (state.userActionPending) {
|
|
1871
|
+
state.userActionPending = false;
|
|
1872
|
+
state.userActionRequest = void 0;
|
|
1873
|
+
callbacksRef.current.onUserActionEvent?.(
|
|
1874
|
+
"USER_ACTION_FAILED",
|
|
1875
|
+
"Connection lost. Please try again."
|
|
1876
|
+
);
|
|
1877
|
+
}
|
|
1878
|
+
const isAborted = error.name === "AbortError";
|
|
1879
|
+
setMessages(
|
|
1880
|
+
(prev) => prev.map(
|
|
1881
|
+
(msg) => msg.id === streamingId ? {
|
|
1882
|
+
...msg,
|
|
1883
|
+
isStreaming: false,
|
|
1884
|
+
streamProgress: isAborted ? "processing" : "error",
|
|
1885
|
+
isError: !isAborted,
|
|
1886
|
+
isCancelled: isAborted,
|
|
1887
|
+
errorDetails: isAborted ? void 0 : error.message,
|
|
1888
|
+
content: isAborted ? state.finalResponse || "" : state.finalResponse || FRIENDLY_ERROR_MESSAGE2,
|
|
1889
|
+
currentMessage: isAborted ? "Thinking..." : void 0,
|
|
1890
|
+
formattedThinkingText: state.formattedThinkingText || void 0,
|
|
1891
|
+
steps: [...state.steps].map((step) => {
|
|
1892
|
+
if (step.status === "in_progress" && isAborted) {
|
|
1893
|
+
return { ...step, status: "pending" };
|
|
1894
|
+
}
|
|
1895
|
+
return step;
|
|
1896
|
+
}),
|
|
1897
|
+
currentExecutingStepId: void 0
|
|
1898
|
+
} : msg
|
|
1899
|
+
)
|
|
1900
|
+
);
|
|
1901
|
+
},
|
|
1902
|
+
onComplete: () => {
|
|
1903
|
+
setIsWaitingForResponse(false);
|
|
1904
|
+
if (state.userActionPending) {
|
|
1905
|
+
state.userActionPending = false;
|
|
1906
|
+
state.userActionRequest = void 0;
|
|
1907
|
+
callbacksRef.current.onUserActionEvent?.(
|
|
1908
|
+
"USER_ACTION_FAILED",
|
|
1909
|
+
"Verification could not be completed."
|
|
1910
|
+
);
|
|
1911
|
+
}
|
|
1912
|
+
if (state.sessionId && state.sessionId !== sessionId) {
|
|
1913
|
+
callbacksRef.current.onSessionIdChange?.(state.sessionId);
|
|
1914
|
+
}
|
|
1915
|
+
const needsImageResolve = !state.hasError && !abortController.signal.aborted && hasRagImages(state.finalResponse);
|
|
1916
|
+
const finalMessage = {
|
|
1917
|
+
id: streamingId,
|
|
1918
|
+
sessionId: state.sessionId || sessionId,
|
|
1919
|
+
role: "assistant",
|
|
1920
|
+
content: state.hasError ? FRIENDLY_ERROR_MESSAGE2 : state.finalResponse || "",
|
|
1921
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
1922
|
+
isStreaming: false,
|
|
1923
|
+
streamProgress: state.hasError ? "error" : "completed",
|
|
1924
|
+
isError: state.hasError,
|
|
1925
|
+
errorDetails: state.hasError ? state.errorMessage : void 0,
|
|
1926
|
+
executionId: state.executionId,
|
|
1927
|
+
tracingData: state.finalData,
|
|
1928
|
+
steps: state.hasError ? [] : [...state.steps],
|
|
1929
|
+
isCancelled: false,
|
|
1930
|
+
currentExecutingStepId: void 0,
|
|
1931
|
+
userActionResult: state.userActionResult,
|
|
1932
|
+
formattedThinkingText: state.hasError ? void 0 : state.formattedThinkingText || void 0,
|
|
1933
|
+
isResolvingImages: needsImageResolve
|
|
1934
|
+
};
|
|
1935
|
+
setMessages(
|
|
1936
|
+
(prev) => prev.map(
|
|
1937
|
+
(msg) => msg.id === streamingId ? finalMessage : msg
|
|
1938
|
+
)
|
|
1939
|
+
);
|
|
1940
|
+
callbacksRef.current.onStreamComplete?.(finalMessage);
|
|
1941
|
+
}
|
|
1942
|
+
});
|
|
1943
|
+
const shouldResolveImages = !abortController.signal.aborted && !state.hasError && hasRagImages(state.finalResponse);
|
|
1944
|
+
if (shouldResolveImages) {
|
|
1945
|
+
await waitForNextPaint(abortController.signal);
|
|
1946
|
+
}
|
|
1947
|
+
if (shouldResolveImages && !abortController.signal.aborted) {
|
|
1948
|
+
try {
|
|
1949
|
+
const resolvedContent = await resolveRagImageUrls(
|
|
1950
|
+
currentConfig,
|
|
1951
|
+
state.finalResponse,
|
|
1952
|
+
abortController.signal
|
|
1953
|
+
);
|
|
1954
|
+
setMessages(
|
|
1955
|
+
(prev) => prev.map(
|
|
1956
|
+
(msg) => msg.id === streamingId ? { ...msg, content: resolvedContent, isResolvingImages: false } : msg
|
|
1957
|
+
)
|
|
1958
|
+
);
|
|
1959
|
+
} catch {
|
|
1960
|
+
setMessages(
|
|
1961
|
+
(prev) => prev.map(
|
|
1962
|
+
(msg) => msg.id === streamingId ? { ...msg, isResolvingImages: false } : msg
|
|
1963
|
+
)
|
|
1964
|
+
);
|
|
1965
|
+
}
|
|
1966
|
+
}
|
|
1967
|
+
return state.sessionId;
|
|
1968
|
+
} catch (error) {
|
|
1969
|
+
setIsWaitingForResponse(false);
|
|
1970
|
+
if (error.name !== "AbortError") {
|
|
1971
|
+
callbacksRef.current.onError?.(error);
|
|
1972
|
+
}
|
|
1973
|
+
if (state.userActionPending) {
|
|
1974
|
+
state.userActionPending = false;
|
|
1975
|
+
state.userActionRequest = void 0;
|
|
1976
|
+
callbacksRef.current.onUserActionEvent?.(
|
|
1977
|
+
"USER_ACTION_FAILED",
|
|
1978
|
+
"Connection lost. Please try again."
|
|
1979
|
+
);
|
|
1980
|
+
}
|
|
1981
|
+
const isAborted = error.name === "AbortError";
|
|
1982
|
+
setMessages(
|
|
1983
|
+
(prev) => prev.map(
|
|
1984
|
+
(msg) => msg.id === streamingId ? {
|
|
1985
|
+
...msg,
|
|
1986
|
+
isStreaming: false,
|
|
1987
|
+
streamProgress: isAborted ? "processing" : "error",
|
|
1988
|
+
isError: !isAborted,
|
|
1989
|
+
isCancelled: isAborted,
|
|
1990
|
+
errorDetails: isAborted ? void 0 : error.message,
|
|
1991
|
+
content: isAborted ? state.finalResponse || "" : state.finalResponse || FRIENDLY_ERROR_MESSAGE2,
|
|
1992
|
+
formattedThinkingText: state.formattedThinkingText || void 0,
|
|
1993
|
+
steps: [...state.steps].map((step) => {
|
|
1994
|
+
if (step.status === "in_progress" && isAborted) {
|
|
1995
|
+
return { ...step, status: "pending" };
|
|
1996
|
+
}
|
|
1997
|
+
return step;
|
|
1998
|
+
}),
|
|
1999
|
+
currentExecutingStepId: void 0
|
|
2000
|
+
} : msg
|
|
2001
|
+
)
|
|
2002
|
+
);
|
|
2003
|
+
return state.sessionId;
|
|
2004
|
+
}
|
|
2005
|
+
},
|
|
2006
|
+
[setMessages, setIsWaitingForResponse]
|
|
2007
|
+
);
|
|
2008
|
+
const cancelStream = react.useCallback(() => {
|
|
2009
|
+
abortControllerRef.current?.abort();
|
|
2010
|
+
}, []);
|
|
2011
|
+
return {
|
|
2012
|
+
startStream,
|
|
2013
|
+
cancelStream,
|
|
2014
|
+
abortControllerRef
|
|
2015
|
+
};
|
|
2016
|
+
}
|
|
2017
|
+
|
|
2018
|
+
// src/hooks/useChatV2.ts
|
|
2019
|
+
function useChatV2(config, callbacks = {}) {
|
|
2020
|
+
const [messages, setMessages] = react.useState(() => {
|
|
2021
|
+
if (config.userId) return chatStore.get(config.userId);
|
|
2022
|
+
return config.initialMessages ?? [];
|
|
2023
|
+
});
|
|
2024
|
+
const [isWaitingForResponse, setIsWaitingForResponse] = react.useState(false);
|
|
2025
|
+
const sessionIdRef = react.useRef(
|
|
2026
|
+
config.userId ? chatStore.get(config.userId).find((m) => m.sessionId)?.sessionId ?? config.initialSessionId ?? void 0 : config.initialSessionId ?? void 0
|
|
2027
|
+
);
|
|
2028
|
+
const prevUserIdRef = react.useRef(config.userId);
|
|
2029
|
+
const callbacksRef = react.useRef(callbacks);
|
|
2030
|
+
callbacksRef.current = callbacks;
|
|
2031
|
+
const configRef = react.useRef(config);
|
|
2032
|
+
configRef.current = config;
|
|
2033
|
+
const messagesRef = react.useRef(messages);
|
|
2034
|
+
messagesRef.current = messages;
|
|
2035
|
+
const storeAwareSetMessages = react.useCallback(
|
|
2036
|
+
(updater) => {
|
|
2037
|
+
const { userId } = configRef.current;
|
|
2038
|
+
if (userId && activeStreamStore.has(userId)) {
|
|
2039
|
+
activeStreamStore.applyMessages(userId, updater);
|
|
2040
|
+
}
|
|
2041
|
+
setMessages(updater);
|
|
2042
|
+
},
|
|
2043
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
2044
|
+
[]
|
|
2045
|
+
);
|
|
2046
|
+
const storeAwareSetIsWaiting = react.useCallback(
|
|
2047
|
+
(waiting) => {
|
|
2048
|
+
const { userId } = configRef.current;
|
|
2049
|
+
if (userId && activeStreamStore.has(userId)) {
|
|
2050
|
+
activeStreamStore.setWaiting(userId, waiting);
|
|
2051
|
+
}
|
|
2052
|
+
setIsWaitingForResponse(waiting);
|
|
2053
|
+
},
|
|
2054
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
2055
|
+
[]
|
|
2056
|
+
);
|
|
2057
|
+
const [userActionState, setUserActionState] = react.useState({
|
|
2058
|
+
request: null,
|
|
2059
|
+
result: null,
|
|
2060
|
+
clearOtpTrigger: 0
|
|
2061
|
+
});
|
|
2062
|
+
const userActionStateRef = react.useRef(userActionState);
|
|
2063
|
+
userActionStateRef.current = userActionState;
|
|
2064
|
+
const wrappedCallbacks = react.useMemo(() => ({
|
|
2065
|
+
...callbacksRef.current,
|
|
2066
|
+
onMessageSent: (message) => callbacksRef.current.onMessageSent?.(message),
|
|
2067
|
+
onStreamStart: () => callbacksRef.current.onStreamStart?.(),
|
|
2068
|
+
onStreamComplete: (message) => callbacksRef.current.onStreamComplete?.(message),
|
|
2069
|
+
onError: (error) => callbacksRef.current.onError?.(error),
|
|
2070
|
+
onExecutionTraceClick: (data) => callbacksRef.current.onExecutionTraceClick?.(data),
|
|
2071
|
+
onSessionIdChange: (sessionId) => callbacksRef.current.onSessionIdChange?.(sessionId),
|
|
2072
|
+
onUserActionRequired: (request) => {
|
|
2073
|
+
setUserActionState((prev) => ({ ...prev, request, result: null }));
|
|
2074
|
+
callbacksRef.current.onUserActionRequired?.(request);
|
|
2075
|
+
},
|
|
2076
|
+
onUserActionEvent: (eventType, message) => {
|
|
2077
|
+
switch (eventType) {
|
|
2078
|
+
case "USER_ACTION_SUCCESS":
|
|
2079
|
+
setUserActionState((prev) => ({ ...prev, request: null, result: "approved" }));
|
|
2080
|
+
break;
|
|
2081
|
+
case "USER_ACTION_REJECTED":
|
|
2082
|
+
setUserActionState((prev) => ({ ...prev, request: null, result: "rejected" }));
|
|
2083
|
+
break;
|
|
2084
|
+
case "USER_ACTION_EXPIRED":
|
|
2085
|
+
case "USER_ACTION_FAILED":
|
|
2086
|
+
setUserActionState((prev) => ({ ...prev, request: null }));
|
|
2087
|
+
break;
|
|
2088
|
+
case "USER_ACTION_INVALID":
|
|
2089
|
+
setUserActionState((prev) => ({ ...prev, clearOtpTrigger: prev.clearOtpTrigger + 1 }));
|
|
2090
|
+
break;
|
|
2091
|
+
}
|
|
2092
|
+
callbacksRef.current.onUserActionEvent?.(eventType, message);
|
|
2093
|
+
}
|
|
2094
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
2095
|
+
}), []);
|
|
2096
|
+
const { startStream, cancelStream: cancelStreamManager, abortControllerRef } = useStreamManagerV2(
|
|
2097
|
+
config,
|
|
2098
|
+
wrappedCallbacks,
|
|
2099
|
+
storeAwareSetMessages,
|
|
2100
|
+
storeAwareSetIsWaiting
|
|
2101
|
+
);
|
|
2102
|
+
const sendMessage = react.useCallback(
|
|
2103
|
+
async (userMessage) => {
|
|
2104
|
+
if (!userMessage.trim()) return;
|
|
2105
|
+
if (!sessionIdRef.current && configRef.current.autoGenerateSessionId !== false) {
|
|
2106
|
+
sessionIdRef.current = generateId();
|
|
2107
|
+
callbacksRef.current.onSessionIdChange?.(sessionIdRef.current);
|
|
2108
|
+
}
|
|
2109
|
+
const userMessageId = `user-${Date.now()}`;
|
|
2110
|
+
const userMsg = {
|
|
2111
|
+
id: userMessageId,
|
|
2112
|
+
sessionId: sessionIdRef.current,
|
|
2113
|
+
role: "user",
|
|
2114
|
+
content: userMessage,
|
|
2115
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString()
|
|
2116
|
+
};
|
|
2117
|
+
setMessages((prev) => [...prev, userMsg]);
|
|
2118
|
+
callbacksRef.current.onMessageSent?.(userMessage);
|
|
2119
|
+
setIsWaitingForResponse(true);
|
|
2120
|
+
callbacksRef.current.onStreamStart?.();
|
|
2121
|
+
const streamingId = `assistant-${Date.now()}`;
|
|
2122
|
+
const streamingMsg = {
|
|
2123
|
+
id: streamingId,
|
|
2124
|
+
sessionId: sessionIdRef.current,
|
|
2125
|
+
role: "assistant",
|
|
2126
|
+
content: "",
|
|
2127
|
+
streamingContent: "",
|
|
2128
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
2129
|
+
isStreaming: true,
|
|
2130
|
+
streamProgress: "started",
|
|
2131
|
+
steps: [],
|
|
2132
|
+
currentExecutingStepId: void 0,
|
|
2133
|
+
isCancelled: false,
|
|
2134
|
+
currentMessage: void 0
|
|
2135
|
+
};
|
|
2136
|
+
setMessages((prev) => [...prev, streamingMsg]);
|
|
2137
|
+
const abortController = new AbortController();
|
|
2138
|
+
const { userId } = configRef.current;
|
|
2139
|
+
if (userId) {
|
|
2140
|
+
const initialMessages = [...messagesRef.current, userMsg, streamingMsg];
|
|
2141
|
+
activeStreamStore.start(userId, abortController, initialMessages);
|
|
2142
|
+
}
|
|
2143
|
+
const newSessionId = await startStream(
|
|
2144
|
+
userMessage,
|
|
2145
|
+
streamingId,
|
|
2146
|
+
sessionIdRef.current,
|
|
2147
|
+
abortController
|
|
2148
|
+
);
|
|
2149
|
+
if (userId) {
|
|
2150
|
+
activeStreamStore.complete(userId);
|
|
2151
|
+
}
|
|
2152
|
+
if (!abortController.signal.aborted && newSessionId && newSessionId !== sessionIdRef.current) {
|
|
2153
|
+
sessionIdRef.current = newSessionId;
|
|
2154
|
+
}
|
|
2155
|
+
},
|
|
2156
|
+
[startStream]
|
|
2157
|
+
);
|
|
2158
|
+
const clearMessages = react.useCallback(() => {
|
|
2159
|
+
if (configRef.current.userId) {
|
|
2160
|
+
chatStore.delete(configRef.current.userId);
|
|
2161
|
+
}
|
|
2162
|
+
setMessages([]);
|
|
2163
|
+
}, []);
|
|
2164
|
+
const prependMessages = react.useCallback((msgs) => {
|
|
2165
|
+
setMessages((prev) => [...msgs, ...prev]);
|
|
2166
|
+
}, []);
|
|
2167
|
+
const cancelStream = react.useCallback(() => {
|
|
2168
|
+
if (configRef.current.userId) {
|
|
2169
|
+
activeStreamStore.abort(configRef.current.userId);
|
|
2170
|
+
}
|
|
2171
|
+
cancelStreamManager();
|
|
2172
|
+
setIsWaitingForResponse(false);
|
|
2173
|
+
setUserActionState((prev) => ({ ...prev, request: null, result: null }));
|
|
2174
|
+
setMessages(
|
|
2175
|
+
(prev) => prev.map((msg) => {
|
|
2176
|
+
if (msg.isStreaming) {
|
|
2177
|
+
return {
|
|
2178
|
+
...msg,
|
|
2179
|
+
...createCancelledMessageUpdate(
|
|
2180
|
+
msg.steps || [],
|
|
2181
|
+
msg.currentMessage
|
|
2182
|
+
)
|
|
2183
|
+
};
|
|
2184
|
+
}
|
|
2185
|
+
return msg;
|
|
2186
|
+
})
|
|
2187
|
+
);
|
|
2188
|
+
}, [cancelStreamManager]);
|
|
2189
|
+
const resetSession = react.useCallback(() => {
|
|
2190
|
+
if (configRef.current.userId) {
|
|
2191
|
+
activeStreamStore.abort(configRef.current.userId);
|
|
2192
|
+
chatStore.delete(configRef.current.userId);
|
|
2193
|
+
}
|
|
2194
|
+
setMessages([]);
|
|
2195
|
+
sessionIdRef.current = void 0;
|
|
2196
|
+
abortControllerRef.current?.abort();
|
|
2197
|
+
setIsWaitingForResponse(false);
|
|
2198
|
+
setUserActionState({ request: null, result: null, clearOtpTrigger: 0 });
|
|
2199
|
+
}, []);
|
|
2200
|
+
const getSessionId = react.useCallback(() => {
|
|
2201
|
+
return sessionIdRef.current;
|
|
2202
|
+
}, []);
|
|
2203
|
+
const getMessages = react.useCallback(() => {
|
|
2204
|
+
return messages;
|
|
2205
|
+
}, [messages]);
|
|
2206
|
+
const approveUserAction = react.useCallback(
|
|
2207
|
+
async (otp) => {
|
|
2208
|
+
const request = userActionStateRef.current.request;
|
|
2209
|
+
if (!request) return;
|
|
2210
|
+
try {
|
|
2211
|
+
await submitUserAction(configRef.current, request.userActionId, { otp });
|
|
2212
|
+
} catch (error) {
|
|
2213
|
+
setUserActionState((prev) => ({
|
|
2214
|
+
...prev,
|
|
2215
|
+
clearOtpTrigger: prev.clearOtpTrigger + 1
|
|
2216
|
+
}));
|
|
2217
|
+
callbacksRef.current.onError?.(error);
|
|
2218
|
+
throw error;
|
|
2219
|
+
}
|
|
2220
|
+
},
|
|
2221
|
+
[]
|
|
2222
|
+
);
|
|
2223
|
+
const rejectUserAction = react.useCallback(async () => {
|
|
2224
|
+
const request = userActionStateRef.current.request;
|
|
2225
|
+
if (!request) return;
|
|
2226
|
+
try {
|
|
2227
|
+
setMessages((prev) => {
|
|
2228
|
+
let lastStreamingIdx = -1;
|
|
2229
|
+
for (let i = prev.length - 1; i >= 0; i--) {
|
|
2230
|
+
if (prev[i].role === "assistant" && prev[i].isStreaming) {
|
|
2231
|
+
lastStreamingIdx = i;
|
|
2232
|
+
break;
|
|
2233
|
+
}
|
|
2234
|
+
}
|
|
2235
|
+
if (lastStreamingIdx === -1) return prev;
|
|
2236
|
+
return prev.map(
|
|
2237
|
+
(msg, i) => i === lastStreamingIdx ? { ...msg, currentMessage: "Rejecting..." } : msg
|
|
2238
|
+
);
|
|
2239
|
+
});
|
|
2240
|
+
await cancelUserAction(configRef.current, request.userActionId);
|
|
2241
|
+
} catch (error) {
|
|
2242
|
+
callbacksRef.current.onError?.(error);
|
|
2243
|
+
throw error;
|
|
2244
|
+
}
|
|
2245
|
+
}, []);
|
|
2246
|
+
const resendOtp = react.useCallback(async () => {
|
|
2247
|
+
const request = userActionStateRef.current.request;
|
|
2248
|
+
if (!request) return;
|
|
2249
|
+
try {
|
|
2250
|
+
await resendUserAction(configRef.current, request.userActionId);
|
|
2251
|
+
} catch (error) {
|
|
2252
|
+
callbacksRef.current.onError?.(error);
|
|
2253
|
+
throw error;
|
|
2254
|
+
}
|
|
2255
|
+
}, []);
|
|
2256
|
+
react.useEffect(() => {
|
|
2257
|
+
const { userId } = config;
|
|
2258
|
+
if (!userId) return;
|
|
2259
|
+
const unsubscribe = activeStreamStore.subscribe(userId, (msgs, isWaiting) => {
|
|
2260
|
+
setMessages(msgs);
|
|
2261
|
+
setIsWaitingForResponse(isWaiting);
|
|
2262
|
+
});
|
|
2263
|
+
const active = activeStreamStore.get(userId);
|
|
2264
|
+
if (active) {
|
|
2265
|
+
setMessages(active.messages);
|
|
2266
|
+
setIsWaitingForResponse(active.isWaiting);
|
|
2267
|
+
}
|
|
2268
|
+
return unsubscribe;
|
|
2269
|
+
}, []);
|
|
2270
|
+
react.useEffect(() => {
|
|
2271
|
+
if (!config.userId) return;
|
|
2272
|
+
const toSave = messages.filter((m) => !m.isStreaming);
|
|
2273
|
+
if (toSave.length > 0) {
|
|
2274
|
+
chatStore.set(config.userId, toSave);
|
|
2275
|
+
}
|
|
2276
|
+
}, [messages, config.userId]);
|
|
2277
|
+
react.useEffect(() => {
|
|
2278
|
+
const prevUserId = prevUserIdRef.current;
|
|
2279
|
+
prevUserIdRef.current = config.userId;
|
|
2280
|
+
if (prevUserId === config.userId) return;
|
|
2281
|
+
if (prevUserId && !config.userId) {
|
|
2282
|
+
chatStore.delete(prevUserId);
|
|
2283
|
+
setMessages([]);
|
|
2284
|
+
sessionIdRef.current = void 0;
|
|
2285
|
+
setIsWaitingForResponse(false);
|
|
2286
|
+
setUserActionState({ request: null, result: null, clearOtpTrigger: 0 });
|
|
2287
|
+
} else if (config.userId) {
|
|
2288
|
+
const stored = chatStore.get(config.userId);
|
|
2289
|
+
setMessages(stored);
|
|
2290
|
+
sessionIdRef.current = stored.find((m) => m.sessionId)?.sessionId;
|
|
2291
|
+
}
|
|
2292
|
+
}, [config.userId]);
|
|
2293
|
+
return {
|
|
2294
|
+
messages,
|
|
2295
|
+
sendMessage,
|
|
2296
|
+
clearMessages,
|
|
2297
|
+
prependMessages,
|
|
2298
|
+
cancelStream,
|
|
2299
|
+
resetSession,
|
|
2300
|
+
getSessionId,
|
|
2301
|
+
getMessages,
|
|
2302
|
+
isWaitingForResponse,
|
|
2303
|
+
sessionId: sessionIdRef.current,
|
|
2304
|
+
userActionState,
|
|
2305
|
+
approveUserAction,
|
|
2306
|
+
rejectUserAction,
|
|
2307
|
+
resendOtp
|
|
2308
|
+
};
|
|
2309
|
+
}
|
|
1241
2310
|
function useVoice() {
|
|
1242
2311
|
const [voiceState, setVoiceState] = react.useState("idle");
|
|
1243
2312
|
const [transcribedText, setTranscribedText] = react.useState("");
|
|
@@ -1354,12 +2423,16 @@ function useVoice() {
|
|
|
1354
2423
|
};
|
|
1355
2424
|
}
|
|
1356
2425
|
|
|
2426
|
+
exports.buildFormattedThinking = buildFormattedThinking;
|
|
1357
2427
|
exports.cancelUserAction = cancelUserAction;
|
|
2428
|
+
exports.createInitialV2State = createInitialV2State;
|
|
1358
2429
|
exports.generateId = generateId;
|
|
2430
|
+
exports.processStreamEventV2 = processStreamEventV2;
|
|
1359
2431
|
exports.resendUserAction = resendUserAction;
|
|
1360
2432
|
exports.streamWorkflowEvents = streamWorkflowEvents;
|
|
1361
2433
|
exports.submitUserAction = submitUserAction;
|
|
1362
2434
|
exports.useChat = useChat;
|
|
2435
|
+
exports.useChatV2 = useChatV2;
|
|
1363
2436
|
exports.useVoice = useVoice;
|
|
1364
2437
|
//# sourceMappingURL=index.native.js.map
|
|
1365
2438
|
//# sourceMappingURL=index.native.js.map
|