@paymanai/payman-ask-sdk 2.0.0 → 2.0.2

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
@@ -6,7 +6,7 @@ import { twMerge } from 'tailwind-merge';
6
6
  import * as Sentry from '@sentry/react';
7
7
  import { AnimatePresence, motion } from 'framer-motion';
8
8
  import { jsxs, jsx, Fragment } from 'react/jsx-runtime';
9
- import { ArrowDown, Pencil, X, RotateCcw, Plus, ImagePlus, Paperclip, Mic, ArrowUp, Check, AlertCircle, Copy, WifiOff, SearchCode, ShieldCheck, Loader2, PanelBottomOpen, Download, ChevronRight, PanelLeftClose, PanelLeftOpen, ImageOff, Eye, MessageSquare, Menu, MessageCircle, ChevronDown } from 'lucide-react';
9
+ import { ArrowDown, Pencil, X, RotateCcw, Plus, ImagePlus, Paperclip, Mic, ArrowUp, Check, AlertCircle, Copy, WifiOff, SearchCode, ShieldCheck, PanelBottomOpen, Download, Loader2, ChevronRight, PanelLeftClose, PanelLeftOpen, ImageOff, Eye, MessageSquare, Menu, MessageCircle, ChevronDown } from 'lucide-react';
10
10
  import { createPortal } from 'react-dom';
11
11
  import ReactMarkdown from 'react-markdown';
12
12
  import remarkGfm from 'remark-gfm';
@@ -458,7 +458,6 @@ function MarkdownImageV2({
458
458
  setIsLoaded(false);
459
459
  setHasError(false);
460
460
  setRetryCount(0);
461
- setIsVisible(false);
462
461
  }, [src]);
463
462
  useEffect(() => {
464
463
  const el = sentinelRef.current;
@@ -482,7 +481,13 @@ function MarkdownImageV2({
482
481
  {
483
482
  className: cn("payman-v2-md-image", "payman-v2-md-image-resolving"),
484
483
  children: /* @__PURE__ */ jsxs("span", { className: "payman-v2-md-image-resolving-inner", children: [
485
- /* @__PURE__ */ jsx(Loader2, { className: "payman-v2-md-image-loading", "aria-hidden": true }),
484
+ /* @__PURE__ */ jsx(
485
+ Loader2,
486
+ {
487
+ style: { animation: "payman-v2-spin 0.7s linear infinite" },
488
+ "aria-hidden": true
489
+ }
490
+ ),
486
491
  /* @__PURE__ */ jsx("span", { children: "Loading image" }),
487
492
  /* @__PURE__ */ jsx("span", { children: "Reference image" })
488
493
  ] })
@@ -521,14 +526,14 @@ function MarkdownImageV2({
521
526
  "aria-busy": !isLoaded,
522
527
  style: {
523
528
  ...frameStyle,
524
- ...!isLoaded ? { minHeight: "10rem" } : {}
529
+ minHeight: isLoaded ? 0 : "10rem"
525
530
  },
526
531
  children: [
527
- !isLoaded && /* @__PURE__ */ jsxs("span", { className: "payman-v2-md-image-placeholder", children: [
532
+ !isLoaded && /* @__PURE__ */ jsxs("span", { className: "payman-v2-md-image-loading", children: [
528
533
  /* @__PURE__ */ jsx(
529
534
  Loader2,
530
535
  {
531
- className: "payman-v2-md-image-loading",
536
+ style: { animation: "payman-v2-spin 0.7s linear infinite" },
532
537
  "aria-hidden": true
533
538
  }
534
539
  ),
@@ -872,26 +877,29 @@ function parseThinkingContent(content) {
872
877
  }
873
878
  return out;
874
879
  }
880
+ function formatDuration(seconds) {
881
+ if (seconds < 60) return `${seconds}s`;
882
+ const m = Math.floor(seconds / 60);
883
+ const s = seconds % 60;
884
+ return s > 0 ? `${m}m ${s}s` : `${m}m`;
885
+ }
875
886
  function AnimatedSeconds({
876
887
  value,
877
888
  className,
878
889
  ariaLabel
879
890
  }) {
880
- return /* @__PURE__ */ jsxs("span", { className: cn("payman-v2-thinking-seconds", className), "aria-label": ariaLabel, children: [
881
- /* @__PURE__ */ jsx("span", { className: "payman-v2-thinking-seconds-track", "aria-hidden": "true", children: /* @__PURE__ */ jsx(AnimatePresence, { initial: false, children: /* @__PURE__ */ jsx(
882
- motion.span,
883
- {
884
- className: "payman-v2-thinking-seconds-value",
885
- initial: { opacity: 0, y: 6, filter: "blur(2px)" },
886
- animate: { opacity: 1, y: 0, filter: "blur(0px)" },
887
- exit: { opacity: 0, y: -6, filter: "blur(2px)" },
888
- transition: { duration: 0.2, ease: [0.22, 1, 0.36, 1] },
889
- children: value
890
- },
891
- value
892
- ) }) }),
893
- /* @__PURE__ */ jsx("span", { className: "payman-v2-thinking-seconds-suffix", "aria-hidden": "true", children: "s" })
894
- ] });
891
+ return /* @__PURE__ */ jsx("span", { className: cn("payman-v2-thinking-seconds", className), "aria-label": ariaLabel, children: /* @__PURE__ */ jsx("span", { className: "payman-v2-thinking-seconds-track", "aria-hidden": "true", children: /* @__PURE__ */ jsx(AnimatePresence, { initial: false, children: /* @__PURE__ */ jsx(
892
+ motion.span,
893
+ {
894
+ className: "payman-v2-thinking-seconds-value",
895
+ initial: { opacity: 0, y: 6, filter: "blur(2px)" },
896
+ animate: { opacity: 1, y: 0, filter: "blur(0px)" },
897
+ exit: { opacity: 0, y: -6, filter: "blur(2px)" },
898
+ transition: { duration: 0.2, ease: [0.22, 1, 0.36, 1] },
899
+ children: formatDuration(value)
900
+ },
901
+ value
902
+ ) }) }) });
895
903
  }
896
904
  function ThinkingBlockV2({
897
905
  content,
@@ -902,8 +910,14 @@ function ThinkingBlockV2({
902
910
  const [open, setOpen] = useState(true);
903
911
  const [cursorIdx, setCursorIdx] = useState(0);
904
912
  const [elapsedSec, setElapsedSec] = useState(
905
- () => startedAt ? Math.max(0, Math.floor((Date.now() - startedAt) / 1e3)) : 0
913
+ () => (
914
+ // Only seed from startedAt when actively streaming — otherwise (e.g.
915
+ // after a hot-reload on a completed message) Date.now()-startedAt would
916
+ // be the time since completion, not the actual thinking duration.
917
+ isStreaming && startedAt ? Math.max(0, Math.floor((Date.now() - startedAt) / 1e3)) : 0
918
+ )
906
919
  );
920
+ const elapsedSecRef = useRef(elapsedSec);
907
921
  const frozenSecRef = useRef(null);
908
922
  const prevStreaming = useRef(isStreaming);
909
923
  const parsed = useMemo(() => parseThinkingContent(content), [content]);
@@ -916,25 +930,25 @@ function ThinkingBlockV2({
916
930
  useEffect(() => {
917
931
  if (prevStreaming.current && !isStreaming) {
918
932
  setOpen(false);
919
- if (startedAt) {
920
- frozenSecRef.current = Math.max(
921
- 0,
922
- Math.floor((Date.now() - startedAt) / 1e3)
923
- );
924
- }
933
+ frozenSecRef.current = elapsedSecRef.current;
925
934
  }
926
935
  prevStreaming.current = isStreaming;
927
936
  }, [isStreaming, startedAt]);
928
937
  useEffect(() => {
929
938
  if (!isStreaming || !startedAt) return;
939
+ let active = true;
930
940
  const tick = () => {
931
- setElapsedSec(
932
- Math.max(0, Math.floor((Date.now() - startedAt) / 1e3))
933
- );
941
+ if (!active) return;
942
+ const val = Math.max(0, Math.floor((Date.now() - startedAt) / 1e3));
943
+ elapsedSecRef.current = val;
944
+ setElapsedSec(val);
934
945
  };
935
946
  tick();
936
947
  const id = window.setInterval(tick, 1e3);
937
- return () => window.clearInterval(id);
948
+ return () => {
949
+ active = false;
950
+ window.clearInterval(id);
951
+ };
938
952
  }, [isStreaming, startedAt]);
939
953
  useEffect(() => {
940
954
  if (!isStreaming || isFinalizingPhase) return;
@@ -945,10 +959,11 @@ function ThinkingBlockV2({
945
959
  }, [isStreaming, isFinalizingPhase]);
946
960
  const justStoppedSec = !isStreaming && prevStreaming.current && startedAt ? Math.max(0, Math.floor((Date.now() - startedAt) / 1e3)) : void 0;
947
961
  const finalSec = getMaxDuration(
948
- durationSec,
949
962
  frozenSecRef.current,
950
963
  justStoppedSec,
951
- !isStreaming ? elapsedSec : void 0
964
+ // Only fall back to durationSec when the timer never ran this session
965
+ // (i.e. the message was already complete when this component mounted).
966
+ frozenSecRef.current == null && !prevStreaming.current ? durationSec : void 0
952
967
  );
953
968
  const headerLabel = isStreaming ? /* @__PURE__ */ jsxs("span", { className: "payman-v2-thinking-header-label", children: [
954
969
  /* @__PURE__ */ jsx("span", { className: "payman-v2-thinking-shimmer", children: "Working on it\u2026" }),
@@ -956,11 +971,11 @@ function ThinkingBlockV2({
956
971
  AnimatedSeconds,
957
972
  {
958
973
  className: "payman-v2-thinking-timer",
959
- ariaLabel: `Elapsed ${elapsedSec} seconds`,
974
+ ariaLabel: `Elapsed ${formatDuration(elapsedSec)}`,
960
975
  value: elapsedSec
961
976
  }
962
977
  )
963
- ] }) : finalSec !== null && finalSec !== void 0 ? /* @__PURE__ */ jsxs("span", { className: "payman-v2-thinking-header-label", children: [
978
+ ] }) : finalSec != null && finalSec > 0 ? /* @__PURE__ */ jsxs("span", { className: "payman-v2-thinking-header-label", children: [
964
979
  /* @__PURE__ */ jsx("span", { children: "Thought for" }),
965
980
  /* @__PURE__ */ jsx(
966
981
  AnimatedSeconds,
@@ -969,7 +984,7 @@ function ThinkingBlockV2({
969
984
  "payman-v2-thinking-timer",
970
985
  "payman-v2-thinking-duration"
971
986
  ),
972
- ariaLabel: `Thought for ${finalSec} seconds`,
987
+ ariaLabel: `Thought for ${formatDuration(finalSec)}`,
973
988
  value: finalSec
974
989
  }
975
990
  )
@@ -1091,6 +1106,7 @@ function charDelay(char, speed) {
1091
1106
  return speed.punctuation[0] + Math.random() * speed.punctuation[1];
1092
1107
  return speed.normal[0] + Math.random() * speed.normal[1];
1093
1108
  }
1109
+ var MARKDOWN_IMAGE_REGEX = /^!\[[^\]]*\]\([^)]*\)/;
1094
1110
  var typingProgressCache = /* @__PURE__ */ new Map();
1095
1111
  function useTypingEffect(targetText, enabled, speed = RESPONSE_SPEED, initialDisplayedText, cacheKey) {
1096
1112
  const cached = cacheKey ? typingProgressCache.get(cacheKey) : void 0;
@@ -1128,6 +1144,11 @@ function useTypingEffect(targetText, enabled, speed = RESPONSE_SPEED, initialDis
1128
1144
  }
1129
1145
  return;
1130
1146
  }
1147
+ if (displayedRef.current && !targetRef.current.startsWith(displayedRef.current)) {
1148
+ displayedRef.current = "";
1149
+ setDisplayedText("");
1150
+ if (cacheKeyRef.current) typingProgressCache.delete(cacheKeyRef.current);
1151
+ }
1131
1152
  if (displayedRef.current.length === 0 && initialDisplayedRef.current && targetRef.current.startsWith(initialDisplayedRef.current)) {
1132
1153
  writeDisplayed(initialDisplayedRef.current);
1133
1154
  }
@@ -1138,8 +1159,41 @@ function useTypingEffect(targetText, enabled, speed = RESPONSE_SPEED, initialDis
1138
1159
  runningRef.current = false;
1139
1160
  return;
1140
1161
  }
1162
+ if (displayedRef.current && !targetRef.current.startsWith(displayedRef.current)) {
1163
+ let divergeAt = 0;
1164
+ const minLen = Math.min(displayedRef.current.length, targetRef.current.length);
1165
+ while (divergeAt < minLen && displayedRef.current[divergeAt] === targetRef.current[divergeAt]) {
1166
+ divergeAt++;
1167
+ }
1168
+ const imgStart = targetRef.current.slice(0, divergeAt).lastIndexOf("![");
1169
+ if (imgStart >= 0) {
1170
+ const newImgMatch = MARKDOWN_IMAGE_REGEX.exec(targetRef.current.slice(imgStart));
1171
+ const oldImgMatch = MARKDOWN_IMAGE_REGEX.exec(displayedRef.current.slice(imgStart));
1172
+ if (newImgMatch && oldImgMatch) {
1173
+ const oldImgEnd = imgStart + oldImgMatch[0].length;
1174
+ const newImgEnd = imgStart + newImgMatch[0].length;
1175
+ const newCursor = Math.min(
1176
+ Math.max(displayedRef.current.length + (newImgEnd - oldImgEnd), newImgEnd),
1177
+ targetRef.current.length
1178
+ );
1179
+ writeDisplayed(targetRef.current.slice(0, newCursor));
1180
+ timerRef.current = setTimeout(tick, 0);
1181
+ return;
1182
+ }
1183
+ }
1184
+ writeDisplayed(targetRef.current.slice(0, imgStart >= 0 ? imgStart : divergeAt));
1185
+ timerRef.current = setTimeout(tick, 0);
1186
+ return;
1187
+ }
1141
1188
  if (displayedRef.current.length < targetRef.current.length) {
1142
- const nextChar = targetRef.current[displayedRef.current.length];
1189
+ const remaining = targetRef.current.slice(displayedRef.current.length);
1190
+ const imgMatch = MARKDOWN_IMAGE_REGEX.exec(remaining);
1191
+ if (imgMatch) {
1192
+ writeDisplayed(displayedRef.current + imgMatch[0]);
1193
+ timerRef.current = setTimeout(tick, 0);
1194
+ return;
1195
+ }
1196
+ const nextChar = remaining[0];
1143
1197
  writeDisplayed(displayedRef.current + nextChar);
1144
1198
  const delay = charDelay(nextChar, speed);
1145
1199
  timerRef.current = setTimeout(tick, delay);
@@ -1379,7 +1433,7 @@ function AssistantMessageV2({
1379
1433
  {
1380
1434
  content: thinkingContent,
1381
1435
  isStreaming: isThinkingStreaming,
1382
- durationSec: thinkingDuration,
1436
+ durationSec: message.thinkingDurationSec ?? thinkingDuration,
1383
1437
  startedAt: requestStartedAt
1384
1438
  }
1385
1439
  ),
@@ -1538,6 +1592,7 @@ function VerificationCardV2({
1538
1592
  messageId,
1539
1593
  action,
1540
1594
  status,
1595
+ clearOtpTrigger = 0,
1541
1596
  onApprove,
1542
1597
  onReject,
1543
1598
  onResend
@@ -1545,33 +1600,41 @@ function VerificationCardV2({
1545
1600
  const [otp, setOtp] = useState("");
1546
1601
  const [otpErrored, setOtpErrored] = useState(false);
1547
1602
  const [resendSec, setResendSec] = useState(0);
1603
+ const [localPending, setLocalPending] = useState(false);
1548
1604
  const lastSubmittedRef = useRef(null);
1549
1605
  const resendTimerRef = useRef(void 0);
1550
1606
  useEffect(() => {
1551
- if (status !== "error") {
1552
- setOtpErrored(false);
1553
- return;
1554
- }
1607
+ if (clearOtpTrigger <= 0) return;
1555
1608
  setOtpErrored(true);
1556
1609
  const t = window.setTimeout(() => {
1557
1610
  setOtp("");
1558
1611
  setOtpErrored(false);
1612
+ setLocalPending(false);
1559
1613
  lastSubmittedRef.current = null;
1560
1614
  }, 600);
1561
1615
  return () => window.clearTimeout(t);
1562
- }, [status]);
1616
+ }, [clearOtpTrigger]);
1563
1617
  useEffect(() => {
1564
1618
  if (otp.length < OTP_LEN) {
1565
1619
  lastSubmittedRef.current = null;
1566
1620
  }
1567
1621
  }, [otp]);
1622
+ useEffect(() => {
1623
+ if (status !== "pending") {
1624
+ setLocalPending(false);
1625
+ }
1626
+ }, [status]);
1568
1627
  useEffect(() => {
1569
1628
  if (otp.length !== OTP_LEN || !/^\d+$/.test(otp) || status !== "pending") {
1570
1629
  return;
1571
1630
  }
1572
1631
  if (lastSubmittedRef.current === otp) return;
1573
1632
  lastSubmittedRef.current = otp;
1574
- void onApprove(messageId, otp);
1633
+ setLocalPending(true);
1634
+ void onApprove(messageId, otp).catch(() => {
1635
+ lastSubmittedRef.current = null;
1636
+ setLocalPending(false);
1637
+ });
1575
1638
  }, [messageId, onApprove, otp, status]);
1576
1639
  useEffect(() => {
1577
1640
  return () => {
@@ -1599,23 +1662,25 @@ function VerificationCardV2({
1599
1662
  }, 1e3);
1600
1663
  }, []);
1601
1664
  const handleResend = useCallback(async () => {
1602
- if (resendSec > 0 || status === "verifying") return;
1603
- await onResend(messageId);
1604
- startResendCooldown();
1605
- }, [messageId, onResend, resendSec, startResendCooldown, status]);
1665
+ if (resendSec > 0 || status === "verifying" || localPending) return;
1666
+ setLocalPending(true);
1667
+ try {
1668
+ await onResend(messageId);
1669
+ startResendCooldown();
1670
+ } finally {
1671
+ setLocalPending(false);
1672
+ }
1673
+ }, [localPending, messageId, onResend, resendSec, startResendCooldown, status]);
1606
1674
  const handleCancel = useCallback(async () => {
1607
- await onReject(messageId);
1608
- }, [messageId, onReject]);
1609
- useCallback(async () => {
1610
- if (otp.length !== OTP_LEN || !/^\d+$/.test(otp) || status !== "pending") {
1611
- return;
1675
+ if (status === "verifying" || localPending) return;
1676
+ setLocalPending(true);
1677
+ try {
1678
+ await onReject(messageId);
1679
+ } finally {
1680
+ setLocalPending(false);
1612
1681
  }
1613
- if (lastSubmittedRef.current === otp) return;
1614
- lastSubmittedRef.current = otp;
1615
- await onApprove(messageId, otp);
1616
- }, [messageId, onApprove, otp, status]);
1617
- const busy = status === "verifying";
1618
- status === "pending" && otp.length === OTP_LEN && /^\d+$/.test(otp);
1682
+ }, [localPending, messageId, onReject, status]);
1683
+ const busy = status === "verifying" || localPending;
1619
1684
  if (status === "approved" || status === "rejected") {
1620
1685
  return null;
1621
1686
  }
@@ -1627,61 +1692,53 @@ function VerificationCardV2({
1627
1692
  animate: { opacity: 1, y: 0 },
1628
1693
  transition: { type: "spring", stiffness: 320, damping: 28 },
1629
1694
  children: [
1630
- /* @__PURE__ */ jsxs("div", { className: "payman-v2-verification-card", children: [
1631
- /* @__PURE__ */ jsxs("div", { className: "payman-v2-verification-header", children: [
1632
- /* @__PURE__ */ jsxs("div", { className: "payman-v2-verification-header-row", children: [
1633
- /* @__PURE__ */ jsx(
1634
- ShieldCheck,
1635
- {
1636
- className: "payman-v2-verification-icon",
1637
- size: 18,
1638
- strokeWidth: 1.75,
1639
- "aria-hidden": true
1640
- }
1641
- ),
1642
- /* @__PURE__ */ jsx("p", { className: "payman-v2-verification-title", children: "Verify" }),
1643
- action.amount != null ? /* @__PURE__ */ jsx("span", { className: "payman-v2-verification-amount", children: action.amount }) : action.payeeName ? /* @__PURE__ */ jsx("span", { className: "payman-v2-verification-payee", children: action.payeeName }) : null
1644
- ] }),
1645
- /* @__PURE__ */ jsx("p", { className: "payman-v2-verification-description", children: "Enter the 6-digit code sent to your phone" }),
1646
- /* @__PURE__ */ jsx(
1647
- OtpInputV2,
1648
- {
1649
- value: otp,
1650
- onChange: setOtp,
1651
- maxLength: OTP_LEN,
1652
- disabled: busy,
1653
- error: otpErrored
1654
- }
1695
+ /* @__PURE__ */ jsxs(
1696
+ "div",
1697
+ {
1698
+ className: cn(
1699
+ "payman-v2-verification-card",
1700
+ busy && "payman-v2-verification-card-busy"
1655
1701
  ),
1656
- busy ? /* @__PURE__ */ jsxs("div", { className: "payman-v2-verification-submitting", children: [
1657
- /* @__PURE__ */ jsx(
1658
- motion.span,
1702
+ children: [
1703
+ /* @__PURE__ */ jsxs("div", { className: "payman-v2-verification-header", children: [
1704
+ /* @__PURE__ */ jsxs("div", { className: "payman-v2-verification-header-row", children: [
1705
+ /* @__PURE__ */ jsx(
1706
+ ShieldCheck,
1707
+ {
1708
+ className: "payman-v2-verification-icon",
1709
+ size: 18,
1710
+ strokeWidth: 1.75,
1711
+ "aria-hidden": true
1712
+ }
1713
+ ),
1714
+ /* @__PURE__ */ jsx("p", { className: "payman-v2-verification-title", children: "Verify" }),
1715
+ action.amount != null ? /* @__PURE__ */ jsx("span", { className: "payman-v2-verification-amount", children: action.amount }) : action.payeeName ? /* @__PURE__ */ jsx("span", { className: "payman-v2-verification-payee", children: action.payeeName }) : null
1716
+ ] }),
1717
+ /* @__PURE__ */ jsx("p", { className: "payman-v2-verification-description", children: "Enter the 6-digit code sent to your phone" }),
1718
+ /* @__PURE__ */ jsx(
1719
+ OtpInputV2,
1720
+ {
1721
+ value: otp,
1722
+ onChange: setOtp,
1723
+ maxLength: OTP_LEN,
1724
+ disabled: busy,
1725
+ error: otpErrored
1726
+ }
1727
+ )
1728
+ ] }),
1729
+ /* @__PURE__ */ jsx("div", { className: "payman-v2-verification-actions", children: /* @__PURE__ */ jsx(
1730
+ "button",
1659
1731
  {
1660
- "aria-hidden": true,
1661
- style: { display: "inline-flex" },
1662
- animate: { rotate: 360 },
1663
- transition: {
1664
- repeat: Infinity,
1665
- duration: 0.7,
1666
- ease: "linear"
1667
- },
1668
- children: /* @__PURE__ */ jsx(Loader2, { size: 14, strokeWidth: 2 })
1732
+ type: "button",
1733
+ className: "payman-v2-verification-cancel-btn",
1734
+ disabled: busy,
1735
+ onClick: () => void handleCancel(),
1736
+ children: "Cancel"
1669
1737
  }
1670
- ),
1671
- /* @__PURE__ */ jsx("span", { className: "payman-v2-verification-submitting-text", children: "Verifying..." })
1672
- ] }) : null
1673
- ] }),
1674
- /* @__PURE__ */ jsx("div", { className: "payman-v2-verification-actions", children: /* @__PURE__ */ jsx(
1675
- "button",
1676
- {
1677
- type: "button",
1678
- className: "payman-v2-verification-cancel-btn",
1679
- disabled: busy,
1680
- onClick: () => void handleCancel(),
1681
- children: "Cancel"
1682
- }
1683
- ) })
1684
- ] }),
1738
+ ) })
1739
+ ]
1740
+ }
1741
+ ),
1685
1742
  /* @__PURE__ */ jsx(
1686
1743
  "button",
1687
1744
  {
@@ -1874,6 +1931,7 @@ var MessageListV2 = forwardRef(
1874
1931
  messageId: userAction.messageId,
1875
1932
  action: userAction.action,
1876
1933
  status: userAction.status,
1934
+ clearOtpTrigger: userAction.clearOtpTrigger,
1877
1935
  onApprove: onApproveAction ?? (async () => {
1878
1936
  }),
1879
1937
  onReject: onRejectAction ?? (async () => {
@@ -3026,17 +3084,7 @@ function SessionList({
3026
3084
  [sessions, formattedNow]
3027
3085
  );
3028
3086
  if (!isReady) {
3029
- return /* @__PURE__ */ jsxs("div", { className: "payman-sidebar-notice", children: [
3030
- "Pass ",
3031
- /* @__PURE__ */ jsx(InlineCode, { children: "workflow.id" }),
3032
- " (or",
3033
- " ",
3034
- /* @__PURE__ */ jsx(InlineCode, { children: "workflow.name" }),
3035
- ") and",
3036
- " ",
3037
- /* @__PURE__ */ jsx(InlineCode, { children: "session.owner.id" }),
3038
- " in your chat config to view recent sessions."
3039
- ] });
3087
+ return /* @__PURE__ */ jsx("div", { className: "payman-sidebar-notice-shell", children: /* @__PURE__ */ jsx("div", { className: "payman-sidebar-notice", children: "Configure the chat settings." }) });
3040
3088
  }
3041
3089
  return /* @__PURE__ */ jsxs(
3042
3090
  "div",
@@ -3203,9 +3251,6 @@ function Spinner({ size = 12 }) {
3203
3251
  }
3204
3252
  );
3205
3253
  }
3206
- function InlineCode({ children }) {
3207
- return /* @__PURE__ */ jsx("code", { className: "payman-sidebar-inline-code", children });
3208
- }
3209
3254
  function groupSessionsByDate(sessions, now) {
3210
3255
  const groups = /* @__PURE__ */ new Map();
3211
3256
  const orderedGroups = [];
@@ -3682,6 +3727,14 @@ var PaymanChat = forwardRef(function PaymanChat2({
3682
3727
  }),
3683
3728
  [performResetSession, clearMessages, cancelStream, getSessionId, getMessages, loadSession]
3684
3729
  );
3730
+ const [v2VerificationPending, setV2VerificationPending] = useState(false);
3731
+ useEffect(() => {
3732
+ setV2VerificationPending(false);
3733
+ }, [
3734
+ userActionState.request?.userActionId,
3735
+ userActionState.clearOtpTrigger,
3736
+ userActionState.result
3737
+ ]);
3685
3738
  if (availability.state === "disabled") {
3686
3739
  return /* @__PURE__ */ jsx(PaymanChatContext.Provider, { value: contextValue, children: /* @__PURE__ */ jsxs(
3687
3740
  "div",
@@ -3704,7 +3757,8 @@ var PaymanChat = forwardRef(function PaymanChat2({
3704
3757
  if (!userActionState.request) return null;
3705
3758
  const req = userActionState.request;
3706
3759
  let status = "pending";
3707
- if (userActionState.result === "approved") status = "approved";
3760
+ if (v2VerificationPending) status = "verifying";
3761
+ else if (userActionState.result === "approved") status = "approved";
3708
3762
  else if (userActionState.result === "rejected") status = "rejected";
3709
3763
  return {
3710
3764
  messageId: `ua-${req.userActionId || Date.now()}`,
@@ -3714,9 +3768,15 @@ var PaymanChat = forwardRef(function PaymanChat2({
3714
3768
  amount: req.metadata?.amount,
3715
3769
  payeeName: req.metadata?.payeeName
3716
3770
  },
3717
- status
3771
+ status,
3772
+ clearOtpTrigger: userActionState.clearOtpTrigger
3718
3773
  };
3719
- }, [userActionState.request, userActionState.result]);
3774
+ }, [
3775
+ userActionState.request,
3776
+ userActionState.result,
3777
+ userActionState.clearOtpTrigger,
3778
+ v2VerificationPending
3779
+ ]);
3720
3780
  const hideV2SendDuringVerification = v2UserAction != null && v2UserAction.status !== "approved" && v2UserAction.status !== "rejected";
3721
3781
  const handleV2Send = (text) => {
3722
3782
  if (isRecording) stopRecording();
@@ -3852,7 +3912,8 @@ var PaymanChat = forwardRef(function PaymanChat2({
3852
3912
  alignItems: "center",
3853
3913
  justifyContent: "center",
3854
3914
  width: "100%",
3855
- minHeight: 0
3915
+ minHeight: 0,
3916
+ marginTop: "1.5rem"
3856
3917
  },
3857
3918
  children: /* @__PURE__ */ jsx(
3858
3919
  EmptyState2,
@@ -3878,10 +3939,22 @@ var PaymanChat = forwardRef(function PaymanChat2({
3878
3939
  retryDisabled: isWaitingForResponse,
3879
3940
  userAction: v2UserAction,
3880
3941
  onApproveAction: async (_id, otp) => {
3881
- await approveUserAction(otp);
3942
+ setV2VerificationPending(true);
3943
+ try {
3944
+ await approveUserAction(otp);
3945
+ } catch (error) {
3946
+ setV2VerificationPending(false);
3947
+ throw error;
3948
+ }
3882
3949
  },
3883
3950
  onRejectAction: async () => {
3884
- await rejectUserAction();
3951
+ setV2VerificationPending(true);
3952
+ try {
3953
+ await rejectUserAction();
3954
+ } catch (error) {
3955
+ setV2VerificationPending(false);
3956
+ throw error;
3957
+ }
3885
3958
  },
3886
3959
  onResendAction: async () => {
3887
3960
  await resendOtp();