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