@paymanai/payman-ask-sdk 1.0.4 → 1.1.0

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
@@ -165,7 +165,6 @@ function AgentMessage({
165
165
  agentName = "Assistant",
166
166
  showAvatar = false,
167
167
  layout = "full-width",
168
- showTimestamp = false,
169
168
  showExecutionSteps = false,
170
169
  showStreamingDot = false,
171
170
  streamingStepsText,
@@ -218,6 +217,13 @@ function AgentMessage({
218
217
  "min-w-0 flex flex-col",
219
218
  layout === "centered" ? "max-w-[85%]" : showAvatar ? "max-w-[85%]" : "max-w-[80%]"
220
219
  ), children: [
220
+ message.userActionResult && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "mb-2", children: message.userActionResult === "approved" ? /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "inline-flex items-center gap-1 px-2 py-1 text-xs font-medium rounded-full bg-green-100 text-green-700", children: [
221
+ /* @__PURE__ */ jsxRuntime.jsx(lucideReact.CheckCircle2, { className: "w-3 h-3" }),
222
+ " OTP Verified"
223
+ ] }) : /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "inline-flex items-center gap-1 px-2 py-1 text-xs font-medium rounded-full bg-red-100 text-red-700", children: [
224
+ /* @__PURE__ */ jsxRuntime.jsx(lucideReact.XCircle, { className: "w-3 h-3" }),
225
+ " Rejected"
226
+ ] }) }),
221
227
  /* @__PURE__ */ jsxRuntime.jsxs(
222
228
  "div",
223
229
  {
@@ -325,7 +331,7 @@ function AgentMessage({
325
331
  layout === "centered" ? "text-neutral-500 hover:bg-neutral-50" : "text-muted-foreground hover:bg-muted/70"
326
332
  ),
327
333
  children: [
328
- /* @__PURE__ */ jsxRuntime.jsx("span", { children: getCompletedStepsText(isStepsExpanded) }),
334
+ /* @__PURE__ */ jsxRuntime.jsx("span", { children: getCompletedStepsText(!!isStepsExpanded) }),
329
335
  isStepsExpanded ? /* @__PURE__ */ jsxRuntime.jsx(lucideReact.ChevronUp, { className: "h-3 w-3" }) : /* @__PURE__ */ jsxRuntime.jsx(lucideReact.ChevronDown, { className: "h-3 w-3" })
330
336
  ]
331
337
  }
@@ -345,7 +351,7 @@ function AgentMessage({
345
351
  step.status === "pending" && isCancelled && /* @__PURE__ */ jsxRuntime.jsx(lucideReact.XCircle, { className: "h-3 w-3 text-muted-foreground shrink-0 mt-0.5" }),
346
352
  step.status === "pending" && !isCancelled && /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Loader2, { className: "h-3 w-3 text-primary animate-spin shrink-0 mt-0.5" }),
347
353
  step.status === "in_progress" && !isCurrentlyExecuting && /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Loader2, { className: "h-3 w-3 text-primary animate-spin shrink-0 mt-0.5" }),
348
- step.status === "completed" && /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Check, { className: "h-3 w-3 text-primary shrink-0 mt-0.5" }),
354
+ step.status === "completed" && /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Check, { className: cn("h-3 w-3 shrink-0 mt-0.5", step.eventType === "USER_ACTION_SUCCESS" ? "text-green-600" : "text-primary") }),
349
355
  step.status === "error" && /* @__PURE__ */ jsxRuntime.jsx(lucideReact.X, { className: "h-3 w-3 text-destructive shrink-0 mt-0.5" }),
350
356
  /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex-1 min-w-0", children: [
351
357
  /* @__PURE__ */ jsxRuntime.jsx(
@@ -353,7 +359,8 @@ function AgentMessage({
353
359
  {
354
360
  className: cn(
355
361
  "text-muted-foreground break-words",
356
- step.status === "error" && "text-destructive"
362
+ step.status === "error" && "text-destructive",
363
+ step.eventType === "USER_ACTION_SUCCESS" && "text-green-600"
357
364
  ),
358
365
  children: step.message
359
366
  }
@@ -382,7 +389,7 @@ function AgentMessage({
382
389
  layout === "centered" ? "text-neutral-500 hover:bg-neutral-50" : "text-muted-foreground hover:bg-muted/70"
383
390
  ),
384
391
  children: [
385
- /* @__PURE__ */ jsxRuntime.jsx("span", { children: getStreamingStepsText(isStepsExpanded) }),
392
+ /* @__PURE__ */ jsxRuntime.jsx("span", { children: getStreamingStepsText(!!isStepsExpanded) }),
386
393
  isStepsExpanded ? /* @__PURE__ */ jsxRuntime.jsx(lucideReact.ChevronUp, { className: "h-3 w-3" }) : /* @__PURE__ */ jsxRuntime.jsx(lucideReact.ChevronDown, { className: "h-3 w-3" })
387
394
  ]
388
395
  }
@@ -402,7 +409,7 @@ function AgentMessage({
402
409
  step.status === "pending" && isCancelled && /* @__PURE__ */ jsxRuntime.jsx(lucideReact.XCircle, { className: "h-3 w-3 text-muted-foreground shrink-0 mt-0.5" }),
403
410
  step.status === "pending" && !isCancelled && /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Loader2, { className: "h-3 w-3 text-primary animate-spin shrink-0 mt-0.5" }),
404
411
  step.status === "in_progress" && !isCurrentlyExecuting && /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Loader2, { className: "h-3 w-3 text-primary animate-spin shrink-0 mt-0.5" }),
405
- step.status === "completed" && /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Check, { className: "h-3 w-3 text-primary shrink-0 mt-0.5" }),
412
+ step.status === "completed" && /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Check, { className: cn("h-3 w-3 shrink-0 mt-0.5", step.eventType === "USER_ACTION_SUCCESS" ? "text-green-600" : "text-primary") }),
406
413
  step.status === "error" && /* @__PURE__ */ jsxRuntime.jsx(lucideReact.X, { className: "h-3 w-3 text-destructive shrink-0 mt-0.5" }),
407
414
  /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex-1 min-w-0", children: [
408
415
  /* @__PURE__ */ jsxRuntime.jsx(
@@ -410,7 +417,8 @@ function AgentMessage({
410
417
  {
411
418
  className: cn(
412
419
  "text-muted-foreground break-words",
413
- step.status === "error" && "text-destructive"
420
+ step.status === "error" && "text-destructive",
421
+ step.eventType === "USER_ACTION_SUCCESS" && "text-green-600"
414
422
  ),
415
423
  children: step.message
416
424
  }
@@ -435,7 +443,10 @@ function AgentMessage({
435
443
  tracingData: message.tracingData,
436
444
  executionId: message.executionId
437
445
  }),
438
- className: "mt-0.5 p-2 bg-white/5 border border-white/20 rounded-lg shadow-sm hover:bg-white/10 hover:border-highlight transition-colors duration-200 flex-shrink-0",
446
+ className: cn(
447
+ "p-2 bg-white/5 border border-white/20 rounded-lg shadow-sm hover:bg-white/10 hover:border-highlight transition-colors duration-200 flex-shrink-0",
448
+ message.userActionResult ? "mt-8" : "mt-0.5"
449
+ ),
439
450
  title: "View execution trace",
440
451
  "aria-label": "View execution trace",
441
452
  children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Binoculars, { className: "w-4 h-4 text-foreground" })
@@ -655,6 +666,466 @@ function MessageList({
655
666
  }
656
667
  );
657
668
  }
669
+ var DEFAULT_MAX_LENGTH = 6;
670
+ var MAX_SUPPORTED_LENGTH = 12;
671
+ var AUTO_FOCUS_DELAY_MS = 250;
672
+ function OtpInput({ value, onChange, maxLength, disabled = false }) {
673
+ const inputRefs = react.useRef([]);
674
+ const safeMaxLength = Number.isInteger(maxLength) && maxLength > 0 ? Math.min(maxLength, MAX_SUPPORTED_LENGTH) : DEFAULT_MAX_LENGTH;
675
+ const digits = value.split("").concat(Array(safeMaxLength).fill("")).slice(0, safeMaxLength);
676
+ react.useEffect(() => {
677
+ if (disabled) return;
678
+ const focusTimer = window.setTimeout(() => {
679
+ inputRefs.current[0]?.focus();
680
+ }, AUTO_FOCUS_DELAY_MS);
681
+ return () => window.clearTimeout(focusTimer);
682
+ }, [disabled]);
683
+ const focusInput = (index) => {
684
+ if (index >= 0 && index < safeMaxLength) {
685
+ inputRefs.current[index]?.focus();
686
+ }
687
+ };
688
+ const updateValue = (newDigits) => {
689
+ onChange(newDigits.join("").slice(0, safeMaxLength));
690
+ };
691
+ const handleChange = (index, char) => {
692
+ if (char && !/^\d$/.test(char)) return;
693
+ const newDigits = [...digits];
694
+ newDigits[index] = char;
695
+ updateValue(newDigits);
696
+ if (char && index < safeMaxLength - 1) {
697
+ focusInput(index + 1);
698
+ }
699
+ };
700
+ const handleKeyDown = (index, e) => {
701
+ if (e.key === "Enter") {
702
+ e.preventDefault();
703
+ return;
704
+ }
705
+ if (e.key === "Backspace") {
706
+ e.preventDefault();
707
+ if (digits[index]) {
708
+ const newDigits = [...digits];
709
+ newDigits[index] = "";
710
+ updateValue(newDigits);
711
+ } else if (index > 0) {
712
+ const newDigits = [...digits];
713
+ newDigits[index - 1] = "";
714
+ updateValue(newDigits);
715
+ focusInput(index - 1);
716
+ }
717
+ return;
718
+ }
719
+ if (e.key === "ArrowLeft") {
720
+ e.preventDefault();
721
+ focusInput(index - 1);
722
+ } else if (e.key === "ArrowRight") {
723
+ e.preventDefault();
724
+ focusInput(index + 1);
725
+ }
726
+ };
727
+ const handlePaste = (e) => {
728
+ e.preventDefault();
729
+ const pasted = e.clipboardData.getData("text").replace(/\D/g, "").slice(0, safeMaxLength);
730
+ if (!pasted) return;
731
+ const newDigits = pasted.split("").concat(Array(safeMaxLength).fill("")).slice(0, safeMaxLength);
732
+ updateValue(newDigits);
733
+ focusInput(Math.min(pasted.length, safeMaxLength - 1));
734
+ };
735
+ return /* @__PURE__ */ jsxRuntime.jsx("div", { style: { display: "flex", gap: "8px", justifyContent: "center" }, children: digits.map((digit, i) => /* @__PURE__ */ jsxRuntime.jsx(
736
+ "input",
737
+ {
738
+ ref: (el) => {
739
+ inputRefs.current[i] = el;
740
+ },
741
+ type: "text",
742
+ inputMode: "numeric",
743
+ maxLength: 1,
744
+ value: digit,
745
+ disabled,
746
+ onChange: (e) => handleChange(i, e.target.value.slice(-1)),
747
+ onKeyDown: (e) => handleKeyDown(i, e),
748
+ onPaste: handlePaste,
749
+ onFocus: (e) => e.target.select(),
750
+ "aria-label": `Digit ${i + 1}`,
751
+ style: {
752
+ width: "40px",
753
+ height: "48px",
754
+ textAlign: "center",
755
+ fontSize: "20px",
756
+ fontWeight: 600,
757
+ border: "1px solid var(--border, #E5E5E5)",
758
+ borderRadius: "8px",
759
+ outline: "none",
760
+ backgroundColor: disabled ? "var(--muted, #F5F5F5)" : "transparent",
761
+ color: "var(--foreground, #000)",
762
+ opacity: disabled ? 0.5 : 1
763
+ }
764
+ },
765
+ i
766
+ )) });
767
+ }
768
+
769
+ // src/components/UserActionModal/constants.ts
770
+ var BUTTON_LABELS = {
771
+ APPROVE: "Verify",
772
+ REJECT: "Reject",
773
+ RESEND: "Resend OTP"
774
+ };
775
+ var RESEND_OTP_COOLDOWN_SECONDS = 30;
776
+ var DEFAULT_OTP_MAX_LENGTH = 6;
777
+ var MIN_OTP_MAX_LENGTH = 1;
778
+ var MAX_OTP_MAX_LENGTH = 12;
779
+ var ACTION_PENDING_TIMEOUT_MS = 15e3;
780
+ var MODAL_CONTENT = {
781
+ TITLE: "Verification Required",
782
+ LOADING_APPROVE: "Verifying...",
783
+ LOADING_REJECT: "Rejecting...",
784
+ LOADING_RESEND: "Resending...",
785
+ RESEND_AVAILABLE_IN: "Resend OTP in"
786
+ };
787
+
788
+ // src/components/UserActionModal/utils.ts
789
+ function getOtpSchemaFromRequest(schema) {
790
+ const properties = schema?.properties;
791
+ const otp = properties?.otp;
792
+ const maxLengthRaw = otp?.maxLength;
793
+ const parsedMaxLength = Number.isInteger(maxLengthRaw) ? Number(maxLengthRaw) : DEFAULT_OTP_MAX_LENGTH;
794
+ const clampedMaxLength = Math.min(
795
+ MAX_OTP_MAX_LENGTH,
796
+ Math.max(MIN_OTP_MAX_LENGTH, parsedMaxLength)
797
+ );
798
+ return {
799
+ maxLength: clampedMaxLength
800
+ };
801
+ }
802
+ function UserActionModal({
803
+ isOpen,
804
+ userActionRequest,
805
+ onApprove,
806
+ onReject,
807
+ onResend,
808
+ clearOtpTrigger
809
+ }) {
810
+ const [otp, setOtp] = react.useState("");
811
+ const [actionType, setActionType] = react.useState(null);
812
+ const [isSubmitting, setIsSubmitting] = react.useState(false);
813
+ const [resendCooldownRemaining, setResendCooldownRemaining] = react.useState(0);
814
+ const dialogRef = react.useRef(null);
815
+ const previousFocusedRef = react.useRef(null);
816
+ const schema = getOtpSchemaFromRequest(userActionRequest?.requestedSchema);
817
+ const resetActionState = react.useCallback(() => {
818
+ setIsSubmitting(false);
819
+ setActionType(null);
820
+ }, []);
821
+ react.useEffect(() => {
822
+ if (isOpen) {
823
+ setResendCooldownRemaining(RESEND_OTP_COOLDOWN_SECONDS);
824
+ } else {
825
+ setOtp("");
826
+ resetActionState();
827
+ setResendCooldownRemaining(0);
828
+ }
829
+ }, [isOpen, resetActionState]);
830
+ react.useEffect(() => {
831
+ if (resendCooldownRemaining <= 0) return;
832
+ const timer = setTimeout(() => {
833
+ setResendCooldownRemaining((prev) => prev - 1);
834
+ }, 1e3);
835
+ return () => clearTimeout(timer);
836
+ }, [resendCooldownRemaining]);
837
+ react.useEffect(() => {
838
+ if (clearOtpTrigger > 0) {
839
+ setOtp("");
840
+ resetActionState();
841
+ }
842
+ }, [clearOtpTrigger, resetActionState]);
843
+ react.useEffect(() => {
844
+ if (!isOpen || !isSubmitting) return;
845
+ if (actionType !== "approve" && actionType !== "reject") return;
846
+ const timeout = setTimeout(() => {
847
+ resetActionState();
848
+ }, ACTION_PENDING_TIMEOUT_MS);
849
+ return () => clearTimeout(timeout);
850
+ }, [isOpen, isSubmitting, actionType, resetActionState]);
851
+ react.useEffect(() => {
852
+ if (!isOpen) return;
853
+ const dialog = dialogRef.current;
854
+ if (!dialog) return;
855
+ previousFocusedRef.current = document.activeElement;
856
+ const originalOverflow = document.body.style.overflow;
857
+ document.body.style.overflow = "hidden";
858
+ const getFocusableElements = () => Array.from(
859
+ dialog.querySelectorAll(
860
+ 'button, [href], input, select, textarea, [tabindex]:not([tabindex="-1"])'
861
+ )
862
+ ).filter((el) => !el.hasAttribute("disabled") && el.tabIndex !== -1);
863
+ const focusables = getFocusableElements();
864
+ (focusables[0] ?? dialog).focus();
865
+ const handleKeyDown = (event) => {
866
+ if (event.key === "Escape") {
867
+ event.preventDefault();
868
+ return;
869
+ }
870
+ if (event.key !== "Tab") return;
871
+ const currentFocusables = getFocusableElements();
872
+ if (currentFocusables.length === 0) {
873
+ event.preventDefault();
874
+ dialog.focus();
875
+ return;
876
+ }
877
+ const first = currentFocusables[0];
878
+ const last = currentFocusables[currentFocusables.length - 1];
879
+ const activeElement = document.activeElement;
880
+ const isInDialog = activeElement ? dialog.contains(activeElement) : false;
881
+ if (event.shiftKey) {
882
+ if (!isInDialog || activeElement === first) {
883
+ event.preventDefault();
884
+ last.focus();
885
+ }
886
+ return;
887
+ }
888
+ if (!isInDialog || activeElement === last) {
889
+ event.preventDefault();
890
+ first.focus();
891
+ }
892
+ };
893
+ document.addEventListener("keydown", handleKeyDown);
894
+ return () => {
895
+ document.removeEventListener("keydown", handleKeyDown);
896
+ document.body.style.overflow = originalOverflow;
897
+ previousFocusedRef.current?.focus();
898
+ };
899
+ }, [isOpen]);
900
+ const handleApprove = react.useCallback(async () => {
901
+ if (otp.length !== schema.maxLength || !/^\d+$/.test(otp)) return;
902
+ setIsSubmitting(true);
903
+ setActionType("approve");
904
+ try {
905
+ await onApprove(otp);
906
+ } catch {
907
+ resetActionState();
908
+ }
909
+ }, [otp, schema.maxLength, onApprove, resetActionState]);
910
+ const handleReject = react.useCallback(async () => {
911
+ setIsSubmitting(true);
912
+ setActionType("reject");
913
+ try {
914
+ await onReject();
915
+ } catch {
916
+ resetActionState();
917
+ }
918
+ }, [onReject, resetActionState]);
919
+ const handleResend = react.useCallback(async () => {
920
+ if (resendCooldownRemaining > 0) return;
921
+ setIsSubmitting(true);
922
+ setActionType("resend");
923
+ try {
924
+ await onResend();
925
+ setResendCooldownRemaining(RESEND_OTP_COOLDOWN_SECONDS);
926
+ } catch {
927
+ } finally {
928
+ setActionType(null);
929
+ setIsSubmitting(false);
930
+ }
931
+ }, [resendCooldownRemaining, onResend]);
932
+ if (!isOpen || !userActionRequest) return null;
933
+ const isOtpValid = otp.length === schema.maxLength && /^\d+$/.test(otp);
934
+ return /* @__PURE__ */ jsxRuntime.jsx(jsxRuntime.Fragment, { children: /* @__PURE__ */ jsxRuntime.jsx(
935
+ "div",
936
+ {
937
+ style: {
938
+ position: "fixed",
939
+ inset: 0,
940
+ backgroundColor: "rgba(0, 0, 0, 0.5)",
941
+ zIndex: 1e4,
942
+ display: "flex",
943
+ alignItems: "center",
944
+ justifyContent: "center"
945
+ },
946
+ children: /* @__PURE__ */ jsxRuntime.jsxs(
947
+ "div",
948
+ {
949
+ ref: dialogRef,
950
+ role: "dialog",
951
+ "aria-modal": "true",
952
+ style: {
953
+ backgroundColor: "var(--card, #FFFFFF)",
954
+ borderRadius: "12px",
955
+ padding: "24px",
956
+ width: "100%",
957
+ maxWidth: "420px",
958
+ margin: "0 16px",
959
+ boxShadow: "0 25px 50px -12px rgba(0, 0, 0, 0.25)"
960
+ },
961
+ tabIndex: -1,
962
+ children: [
963
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { style: { textAlign: "center", marginBottom: "16px" }, children: [
964
+ /* @__PURE__ */ jsxRuntime.jsx(
965
+ "div",
966
+ {
967
+ style: {
968
+ display: "inline-flex",
969
+ alignItems: "center",
970
+ justifyContent: "center",
971
+ width: "48px",
972
+ height: "48px",
973
+ borderRadius: "50%",
974
+ backgroundColor: "var(--muted, #F5F5F5)",
975
+ marginBottom: "12px"
976
+ },
977
+ children: /* @__PURE__ */ jsxRuntime.jsx(
978
+ lucideReact.ShieldCheck,
979
+ {
980
+ className: "text-primary",
981
+ style: { width: "24px", height: "24px" }
982
+ }
983
+ )
984
+ }
985
+ ),
986
+ /* @__PURE__ */ jsxRuntime.jsx(
987
+ "h2",
988
+ {
989
+ style: {
990
+ fontSize: "18px",
991
+ fontWeight: 600,
992
+ color: "var(--foreground, #000)",
993
+ margin: 0
994
+ },
995
+ children: MODAL_CONTENT.TITLE
996
+ }
997
+ )
998
+ ] }),
999
+ /* @__PURE__ */ jsxRuntime.jsx(
1000
+ "p",
1001
+ {
1002
+ style: {
1003
+ fontSize: "14px",
1004
+ color: "var(--muted-foreground, #666)",
1005
+ textAlign: "center",
1006
+ margin: "0 0 24px 0",
1007
+ lineHeight: 1.5
1008
+ },
1009
+ children: userActionRequest.message
1010
+ }
1011
+ ),
1012
+ /* @__PURE__ */ jsxRuntime.jsx("div", { style: { marginBottom: "24px" }, children: /* @__PURE__ */ jsxRuntime.jsx(
1013
+ OtpInput,
1014
+ {
1015
+ value: otp,
1016
+ onChange: setOtp,
1017
+ maxLength: schema.maxLength,
1018
+ disabled: isSubmitting
1019
+ }
1020
+ ) }),
1021
+ /* @__PURE__ */ jsxRuntime.jsxs(
1022
+ "div",
1023
+ {
1024
+ style: {
1025
+ display: "flex",
1026
+ flexDirection: "column",
1027
+ gap: "10px"
1028
+ },
1029
+ children: [
1030
+ /* @__PURE__ */ jsxRuntime.jsxs(
1031
+ "div",
1032
+ {
1033
+ style: {
1034
+ display: "flex",
1035
+ gap: "8px"
1036
+ },
1037
+ children: [
1038
+ /* @__PURE__ */ jsxRuntime.jsxs(
1039
+ "button",
1040
+ {
1041
+ onClick: handleReject,
1042
+ disabled: isSubmitting,
1043
+ className: cn(
1044
+ "py-2.5 px-4 rounded-lg text-sm font-medium transition-colors",
1045
+ "bg-destructive/10 text-destructive hover:bg-destructive/20 hover:text-destructive",
1046
+ "disabled:opacity-50 disabled:cursor-not-allowed"
1047
+ ),
1048
+ style: {
1049
+ flex: 1,
1050
+ display: "flex",
1051
+ alignItems: "center",
1052
+ justifyContent: "center",
1053
+ gap: "6px",
1054
+ whiteSpace: "nowrap",
1055
+ minWidth: 0
1056
+ },
1057
+ children: [
1058
+ actionType === "reject" && /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Loader2, { className: "w-4 h-4 animate-spin", style: { flexShrink: 0 } }),
1059
+ actionType === "reject" ? MODAL_CONTENT.LOADING_REJECT : BUTTON_LABELS.REJECT
1060
+ ]
1061
+ }
1062
+ ),
1063
+ /* @__PURE__ */ jsxRuntime.jsxs(
1064
+ "button",
1065
+ {
1066
+ onClick: handleApprove,
1067
+ disabled: !isOtpValid || isSubmitting,
1068
+ className: cn(
1069
+ "py-2.5 px-4 rounded-lg text-sm font-medium transition-colors",
1070
+ "bg-primary text-primary-foreground hover:bg-primary/90 active:bg-primary/80",
1071
+ "disabled:opacity-50 disabled:cursor-not-allowed"
1072
+ ),
1073
+ style: {
1074
+ flex: 1,
1075
+ display: "flex",
1076
+ alignItems: "center",
1077
+ justifyContent: "center",
1078
+ gap: "6px",
1079
+ whiteSpace: "nowrap",
1080
+ minWidth: 0
1081
+ },
1082
+ children: [
1083
+ actionType === "approve" && /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Loader2, { className: "w-4 h-4 animate-spin", style: { flexShrink: 0 } }),
1084
+ actionType === "approve" ? MODAL_CONTENT.LOADING_APPROVE : BUTTON_LABELS.APPROVE
1085
+ ]
1086
+ }
1087
+ )
1088
+ ]
1089
+ }
1090
+ ),
1091
+ /* @__PURE__ */ jsxRuntime.jsxs(
1092
+ "button",
1093
+ {
1094
+ onClick: handleResend,
1095
+ disabled: isSubmitting || resendCooldownRemaining > 0,
1096
+ className: cn(
1097
+ "py-2 px-4 rounded-lg text-xs font-medium transition-colors w-full",
1098
+ "text-muted-foreground hover:text-foreground",
1099
+ "disabled:opacity-50 disabled:cursor-not-allowed"
1100
+ ),
1101
+ style: {
1102
+ display: "flex",
1103
+ alignItems: "center",
1104
+ justifyContent: "center",
1105
+ gap: "6px",
1106
+ whiteSpace: "nowrap"
1107
+ },
1108
+ children: [
1109
+ actionType === "resend" && /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Loader2, { className: "w-3.5 h-3.5 animate-spin", style: { flexShrink: 0 } }),
1110
+ actionType === "resend" ? MODAL_CONTENT.LOADING_RESEND : resendCooldownRemaining > 0 ? `${MODAL_CONTENT.RESEND_AVAILABLE_IN} ${resendCooldownRemaining}s` : BUTTON_LABELS.RESEND
1111
+ ]
1112
+ }
1113
+ )
1114
+ ]
1115
+ }
1116
+ )
1117
+ ]
1118
+ }
1119
+ )
1120
+ }
1121
+ ) });
1122
+ }
1123
+ var DEFAULT_USER_ACTION_STATE = {
1124
+ request: null,
1125
+ clearOtpTrigger: 0
1126
+ };
1127
+ var NOOP_ASYNC = async () => {
1128
+ };
658
1129
  function PaymanChat({
659
1130
  config,
660
1131
  callbacks = {},
@@ -663,6 +1134,7 @@ function PaymanChat({
663
1134
  children
664
1135
  }) {
665
1136
  const [inputValue, setInputValue] = react.useState("");
1137
+ const chat = paymanTypescriptAskSdk.useChat(config, callbacks);
666
1138
  const {
667
1139
  messages,
668
1140
  sendMessage,
@@ -672,7 +1144,12 @@ function PaymanChat({
672
1144
  cancelStream,
673
1145
  getSessionId,
674
1146
  getMessages
675
- } = paymanTypescriptAskSdk.useChat(config, callbacks);
1147
+ } = chat;
1148
+ const userActionState = chat.userActionState ?? DEFAULT_USER_ACTION_STATE;
1149
+ const approveUserAction = chat.approveUserAction ?? NOOP_ASYNC;
1150
+ const rejectUserAction = chat.rejectUserAction ?? NOOP_ASYNC;
1151
+ const resendOtp = chat.resendOtp ?? NOOP_ASYNC;
1152
+ const isUserActionSupported = typeof chat.approveUserAction === "function" && typeof chat.rejectUserAction === "function" && typeof chat.resendOtp === "function";
676
1153
  const contextValue = react.useMemo(
677
1154
  () => ({
678
1155
  resetSession,
@@ -707,6 +1184,7 @@ function PaymanChat({
707
1184
  agentName = "Assistant",
708
1185
  showExecutionSteps = true,
709
1186
  showStreamingDot = true,
1187
+ inputStyle = "rounded",
710
1188
  layout = "full-width",
711
1189
  showTimestamps = false,
712
1190
  animated = true,
@@ -801,7 +1279,20 @@ function PaymanChat({
801
1279
  placeholder,
802
1280
  isWaitingForResponse,
803
1281
  hasSelectedSession: true,
804
- isSessionParamsConfigured
1282
+ isSessionParamsConfigured,
1283
+ inputStyle,
1284
+ layout
1285
+ }
1286
+ ),
1287
+ /* @__PURE__ */ jsxRuntime.jsx(
1288
+ UserActionModal,
1289
+ {
1290
+ isOpen: isUserActionSupported && userActionState.request !== null,
1291
+ userActionRequest: userActionState.request,
1292
+ onApprove: approveUserAction,
1293
+ onReject: rejectUserAction,
1294
+ onResend: resendOtp,
1295
+ clearOtpTrigger: userActionState.clearOtpTrigger
805
1296
  }
806
1297
  )
807
1298
  ]
@@ -809,14 +1300,26 @@ function PaymanChat({
809
1300
  ) });
810
1301
  }
811
1302
 
1303
+ Object.defineProperty(exports, "cancelUserAction", {
1304
+ enumerable: true,
1305
+ get: function () { return paymanTypescriptAskSdk.cancelUserAction; }
1306
+ });
812
1307
  Object.defineProperty(exports, "generateId", {
813
1308
  enumerable: true,
814
1309
  get: function () { return paymanTypescriptAskSdk.generateId; }
815
1310
  });
1311
+ Object.defineProperty(exports, "resendUserAction", {
1312
+ enumerable: true,
1313
+ get: function () { return paymanTypescriptAskSdk.resendUserAction; }
1314
+ });
816
1315
  Object.defineProperty(exports, "streamWorkflowEvents", {
817
1316
  enumerable: true,
818
1317
  get: function () { return paymanTypescriptAskSdk.streamWorkflowEvents; }
819
1318
  });
1319
+ Object.defineProperty(exports, "submitUserAction", {
1320
+ enumerable: true,
1321
+ get: function () { return paymanTypescriptAskSdk.submitUserAction; }
1322
+ });
820
1323
  Object.defineProperty(exports, "useChat", {
821
1324
  enumerable: true,
822
1325
  get: function () { return paymanTypescriptAskSdk.useChat; }