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