@paymanai/payman-ask-sdk 1.2.16 → 1.2.18

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
@@ -1,10 +1,10 @@
1
1
  import { useChat, useVoice } from '@paymanai/payman-typescript-ask-sdk';
2
2
  export { cancelUserAction, generateId, resendUserAction, streamWorkflowEvents, submitUserAction, useChat, useVoice } from '@paymanai/payman-typescript-ask-sdk';
3
- import { createContext, forwardRef, useState, useRef, useMemo, useImperativeHandle, useEffect, useCallback, useLayoutEffect, useContext } from 'react';
3
+ import { AnimatePresence, motion } from 'framer-motion';
4
+ import { createContext, forwardRef, useState, useRef, useEffect, useMemo, useImperativeHandle, useCallback, useLayoutEffect, useContext } from 'react';
4
5
  import { clsx } from 'clsx';
5
6
  import { twMerge } from 'tailwind-merge';
6
- import { motion, AnimatePresence } from 'framer-motion';
7
- import { MessageCircle, ArrowDown, Square, Mic, ArrowUp, ShieldCheck, Loader2, X, Check, RefreshCw, User, Clock, Sparkles, Binoculars, ChevronDown, ChevronRight } from 'lucide-react';
7
+ import { Check, RotateCcw, Mic, ArrowUp, ArrowDown, ShieldCheck, Loader2, X, RefreshCw, User, Clock, Sparkles, Binoculars, ChevronDown, ChevronRight } from 'lucide-react';
8
8
  import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
9
9
  import ReactMarkdown from 'react-markdown';
10
10
  import remarkGfm from 'remark-gfm';
@@ -52,6 +52,7 @@ function formatElapsedTime(ms) {
52
52
  if (ms < 1e3) return `${ms}ms`;
53
53
  return `${(ms / 1e3).toFixed(1)}s`;
54
54
  }
55
+ var AI_DISCLAIMER_TEXT = "AI can make mistakes. Please double-check responses.";
55
56
  function ChatInput({
56
57
  value,
57
58
  onChange,
@@ -67,20 +68,25 @@ function ChatInput({
67
68
  enableVoice = false,
68
69
  onVoicePress,
69
70
  voiceAvailable = false,
70
- isRecording = false
71
+ isRecording = false,
72
+ transcribedText = "",
73
+ onCancelRecording,
74
+ onConfirmRecording,
75
+ showResetSession = false,
76
+ onResetSession
71
77
  }) {
72
78
  const textareaRef = useRef(null);
73
79
  const containerRef = useRef(null);
74
80
  const prevWaitingRef = useRef(isWaitingForResponse);
81
+ const [recordingSeconds, setRecordingSeconds] = useState(0);
82
+ const recordingTimerRef = useRef(null);
83
+ const [isFocused, setIsFocused] = useState(false);
75
84
  useEffect(() => {
76
85
  if (textareaRef.current) {
77
86
  textareaRef.current.style.height = "auto";
78
87
  const scrollHeight = textareaRef.current.scrollHeight;
79
88
  const maxHeight = 160;
80
- textareaRef.current.style.height = `${Math.min(
81
- scrollHeight,
82
- maxHeight
83
- )}px`;
89
+ textareaRef.current.style.height = `${Math.min(scrollHeight, maxHeight)}px`;
84
90
  }
85
91
  }, [value]);
86
92
  useEffect(() => {
@@ -98,6 +104,25 @@ function ChatInput({
98
104
  });
99
105
  }
100
106
  }, [isWaitingForResponse]);
107
+ useEffect(() => {
108
+ if (isRecording) {
109
+ setRecordingSeconds(0);
110
+ recordingTimerRef.current = setInterval(() => {
111
+ setRecordingSeconds((s) => s + 1);
112
+ }, 1e3);
113
+ } else {
114
+ if (recordingTimerRef.current) {
115
+ clearInterval(recordingTimerRef.current);
116
+ recordingTimerRef.current = null;
117
+ }
118
+ setRecordingSeconds(0);
119
+ }
120
+ return () => {
121
+ if (recordingTimerRef.current) {
122
+ clearInterval(recordingTimerRef.current);
123
+ }
124
+ };
125
+ }, [isRecording]);
101
126
  const handleKeyDown = (e) => {
102
127
  if (e.key === "Enter" && !e.shiftKey) {
103
128
  e.preventDefault();
@@ -113,100 +138,180 @@ function ChatInput({
113
138
  if (!isSessionParamsConfigured) return "Configure session params to begin";
114
139
  return placeholder;
115
140
  };
141
+ const formatTime = useCallback((seconds) => {
142
+ const mins = Math.floor(seconds / 60);
143
+ const secs = seconds % 60;
144
+ return `${String(mins).padStart(2, "0")}:${String(secs).padStart(2, "0")}`;
145
+ }, []);
146
+ const handleCancel = () => {
147
+ if (onCancelRecording) {
148
+ onCancelRecording();
149
+ } else if (onVoicePress) {
150
+ onVoicePress();
151
+ }
152
+ };
153
+ const handleConfirm = () => {
154
+ if (onConfirmRecording) {
155
+ onConfirmRecording();
156
+ } else if (onVoicePress) {
157
+ onVoicePress();
158
+ }
159
+ };
116
160
  return /* @__PURE__ */ jsx(
117
161
  "div",
118
162
  {
119
163
  ref: containerRef,
120
- className: cn("flex-shrink-0 w-full", className),
121
- style: { flexShrink: 0 },
122
- children: /* @__PURE__ */ jsx("div", { className: "px-3 pb-3 pt-1.5 w-full", children: /* @__PURE__ */ jsx("div", { className: "relative w-full max-w-2xl mx-auto", children: /* @__PURE__ */ jsxs(
123
- motion.div,
124
- {
125
- initial: false,
126
- className: cn(
127
- "flex items-end overflow-hidden",
128
- "payman-chat-input"
129
- ),
130
- children: [
131
- /* @__PURE__ */ jsx(
132
- "textarea",
133
- {
134
- ref: textareaRef,
135
- value,
136
- onChange: (e) => onChange(e.target.value),
137
- onKeyDown: handleKeyDown,
138
- onClick,
139
- disabled: isInputDisabled,
140
- placeholder: getPlaceholder(),
141
- className: cn(
142
- "payman-chat-input-field",
143
- "focus:outline-none resize-none overflow-y-auto",
144
- "flex-1 min-w-0 py-3"
145
- ),
146
- style: {
147
- minHeight: "44px",
148
- maxHeight: "160px",
149
- paddingLeft: "18px",
150
- paddingRight: "8px"
151
- },
152
- rows: 1
153
- }
154
- ),
155
- /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-1 shrink-0 p-2", children: [
156
- showVoiceButton && /* @__PURE__ */ jsxs(
157
- "button",
158
- {
159
- type: "button",
160
- onClick: onVoicePress,
161
- disabled: isVoiceButtonDisabled,
162
- className: cn(
163
- "relative flex items-center justify-center",
164
- "w-8 h-8 rounded-full transition-all duration-200",
165
- "payman-chat-input-btn-voice",
166
- isRecording && "recording"
164
+ className: cn("payman-chat-input-wrapper", className),
165
+ children: /* @__PURE__ */ jsx("div", { className: "payman-chat-input-container", children: /* @__PURE__ */ jsxs("div", { className: "payman-chat-input-inner", children: [
166
+ /* @__PURE__ */ jsx(AnimatePresence, { mode: "wait", children: isRecording ? (
167
+ /* ======== Recording State ======== */
168
+ /* @__PURE__ */ jsxs(
169
+ motion.div,
170
+ {
171
+ initial: { opacity: 0, y: 6 },
172
+ animate: { opacity: 1, y: 0 },
173
+ exit: { opacity: 0, y: 6 },
174
+ transition: { duration: 0.25, ease: [0.25, 0.46, 0.45, 0.94] },
175
+ className: "payman-chat-input payman-chat-input--recording",
176
+ children: [
177
+ /* @__PURE__ */ jsx("div", { className: "payman-recording-transcript-area", children: /* @__PURE__ */ jsx(AnimatePresence, { mode: "wait", children: transcribedText ? /* @__PURE__ */ jsxs(
178
+ motion.p,
179
+ {
180
+ initial: { opacity: 0 },
181
+ animate: { opacity: 1 },
182
+ exit: { opacity: 0 },
183
+ transition: { duration: 0.15 },
184
+ className: "payman-recording-transcript-text",
185
+ children: [
186
+ transcribedText,
187
+ /* @__PURE__ */ jsx(
188
+ motion.span,
189
+ {
190
+ className: "payman-recording-cursor",
191
+ animate: { opacity: [1, 0] },
192
+ transition: { duration: 0.8, repeat: Infinity, repeatType: "reverse" }
193
+ }
194
+ )
195
+ ]
196
+ },
197
+ "text"
198
+ ) : /* @__PURE__ */ jsx(
199
+ motion.p,
200
+ {
201
+ initial: { opacity: 0 },
202
+ animate: { opacity: 0.5 },
203
+ className: "payman-recording-transcript-placeholder",
204
+ children: "Listening..."
205
+ },
206
+ "placeholder"
207
+ ) }) }),
208
+ /* @__PURE__ */ jsxs("div", { className: "payman-recording-bar", children: [
209
+ /* @__PURE__ */ jsx(
210
+ "button",
211
+ {
212
+ type: "button",
213
+ onClick: handleCancel,
214
+ className: "payman-recording-btn-cancel",
215
+ "aria-label": "Cancel recording",
216
+ children: "Cancel"
217
+ }
167
218
  ),
168
- "aria-label": isRecording ? "Stop recording" : "Voice input",
169
- children: [
170
- isRecording && /* @__PURE__ */ jsx(
171
- "span",
219
+ /* @__PURE__ */ jsxs("div", { className: "payman-recording-indicator", children: [
220
+ /* @__PURE__ */ jsx("span", { className: "payman-recording-dot" }),
221
+ /* @__PURE__ */ jsx("span", { className: "payman-recording-timer", children: formatTime(recordingSeconds) })
222
+ ] }),
223
+ /* @__PURE__ */ jsx(
224
+ "button",
225
+ {
226
+ type: "button",
227
+ onClick: handleConfirm,
228
+ className: "payman-recording-btn-confirm",
229
+ "aria-label": "Confirm recording",
230
+ children: /* @__PURE__ */ jsx(Check, { className: "w-4 h-4", strokeWidth: 2.5 })
231
+ }
232
+ )
233
+ ] })
234
+ ]
235
+ },
236
+ "recording"
237
+ )
238
+ ) : (
239
+ /* ======== Normal Input State ======== */
240
+ /* @__PURE__ */ jsxs(
241
+ motion.div,
242
+ {
243
+ initial: false,
244
+ animate: { opacity: 1, y: 0 },
245
+ exit: { opacity: 0, y: 6 },
246
+ transition: { duration: 0.2 },
247
+ className: cn(
248
+ "payman-chat-input",
249
+ isFocused && "payman-chat-input--focused"
250
+ ),
251
+ children: [
252
+ /* @__PURE__ */ jsx(
253
+ "textarea",
254
+ {
255
+ ref: textareaRef,
256
+ value,
257
+ onChange: (e) => onChange(e.target.value),
258
+ onKeyDown: handleKeyDown,
259
+ onFocus: () => setIsFocused(true),
260
+ onBlur: () => setIsFocused(false),
261
+ onClick,
262
+ disabled: isInputDisabled,
263
+ placeholder: getPlaceholder(),
264
+ className: "payman-chat-input-field",
265
+ rows: 1
266
+ }
267
+ ),
268
+ /* @__PURE__ */ jsxs("div", { className: "payman-chat-input-bottom", children: [
269
+ /* @__PURE__ */ jsx("div", { className: "payman-chat-input-actions-left", children: showResetSession && onResetSession && /* @__PURE__ */ jsxs(
270
+ "button",
271
+ {
272
+ type: "button",
273
+ onClick: onResetSession,
274
+ disabled: isWaitingForResponse,
275
+ className: "payman-chat-input-btn-reset",
276
+ "aria-label": "New Session",
277
+ children: [
278
+ /* @__PURE__ */ jsx(RotateCcw, { className: "w-3.5 h-3.5", strokeWidth: 2.5 }),
279
+ /* @__PURE__ */ jsx("span", { className: "payman-chat-input-btn-reset-tooltip", children: "New Session" })
280
+ ]
281
+ }
282
+ ) }),
283
+ /* @__PURE__ */ jsxs("div", { className: "payman-chat-input-actions", children: [
284
+ showVoiceButton && /* @__PURE__ */ jsx(
285
+ "button",
172
286
  {
173
- className: "absolute inset-0 rounded-full border-2 animate-ping opacity-40",
174
- style: {
175
- borderColor: "var(--payman-input-btn-voice-recording-ring)"
176
- }
287
+ type: "button",
288
+ onClick: onVoicePress,
289
+ disabled: isVoiceButtonDisabled,
290
+ className: "payman-chat-input-btn-voice",
291
+ "aria-label": "Voice input",
292
+ children: /* @__PURE__ */ jsx(Mic, { className: "w-[18px] h-[18px]" })
177
293
  }
178
294
  ),
179
- isRecording ? /* @__PURE__ */ jsx(
180
- Square,
295
+ /* @__PURE__ */ jsx(
296
+ "button",
181
297
  {
182
- className: "w-3 h-3 relative z-10",
183
- fill: "currentColor"
298
+ type: "button",
299
+ onClick: onSend,
300
+ disabled: !canSend,
301
+ className: "payman-chat-input-btn-send",
302
+ "aria-label": "Send message",
303
+ children: /* @__PURE__ */ jsx(ArrowUp, { className: "w-4 h-4", strokeWidth: 2.5 })
184
304
  }
185
- ) : /* @__PURE__ */ jsx(Mic, { className: "w-4 h-4" })
186
- ]
187
- }
188
- ),
189
- /* @__PURE__ */ jsx(
190
- "button",
191
- {
192
- type: "button",
193
- onClick: onSend,
194
- disabled: !canSend,
195
- className: cn(
196
- "flex items-center justify-center",
197
- "w-8 h-8 rounded-full",
198
- "payman-chat-input-btn-send",
199
- "hover:opacity-90 active:scale-95",
200
- "transition-all duration-150"
201
- ),
202
- "aria-label": "Send message",
203
- children: /* @__PURE__ */ jsx(ArrowUp, { className: "w-4 h-4", strokeWidth: 2.5 })
204
- }
205
- )
206
- ] })
207
- ]
208
- }
209
- ) }) })
305
+ )
306
+ ] })
307
+ ] })
308
+ ]
309
+ },
310
+ "input"
311
+ )
312
+ ) }),
313
+ /* @__PURE__ */ jsx("p", { className: "payman-chat-input-disclaimer", children: AI_DISCLAIMER_TEXT })
314
+ ] }) })
210
315
  }
211
316
  );
212
317
  }
@@ -773,6 +878,7 @@ function MessageList({
773
878
  isLoading = false,
774
879
  emptyStateText = "What can I help with?",
775
880
  showEmptyStateIcon = true,
881
+ emptyStateComponent,
776
882
  layout = "full-width",
777
883
  showTimestamps = false,
778
884
  stage = "DEV",
@@ -897,7 +1003,7 @@ function MessageList({
897
1003
  }
898
1004
  if (messages.length === 0) {
899
1005
  const lines = emptyStateText.split("\n").map((l) => l.trim()).filter(Boolean);
900
- return /* @__PURE__ */ jsx("div", { className: cn("payman-empty-root p-8", className), children: /* @__PURE__ */ jsxs(
1006
+ return /* @__PURE__ */ jsx("div", { className: cn("payman-empty-root", className), children: /* @__PURE__ */ jsxs(
901
1007
  motion.div,
902
1008
  {
903
1009
  initial: { opacity: 0, y: 20 },
@@ -905,17 +1011,17 @@ function MessageList({
905
1011
  transition: { duration: 0.5, ease: [0.25, 0.46, 0.45, 0.94] },
906
1012
  className: "payman-empty-content",
907
1013
  children: [
908
- showEmptyStateIcon && /* @__PURE__ */ jsx(
1014
+ emptyStateComponent && /* @__PURE__ */ jsx(
909
1015
  motion.div,
910
1016
  {
911
- initial: { scale: 0.85, opacity: 0 },
1017
+ initial: { scale: 0.9, opacity: 0 },
912
1018
  animate: { scale: 1, opacity: 1 },
913
- transition: { delay: 0.08, duration: 0.45, ease: [0.25, 0.46, 0.45, 0.94] },
914
- className: "payman-empty-icon-wrap",
915
- children: /* @__PURE__ */ jsx(MessageCircle, { className: "h-7 w-7 payman-empty-icon", strokeWidth: 1.5 })
1019
+ transition: { delay: 0.05, duration: 0.45, ease: [0.25, 0.46, 0.45, 0.94] },
1020
+ className: "payman-empty-custom-component",
1021
+ children: emptyStateComponent
916
1022
  }
917
1023
  ),
918
- /* @__PURE__ */ jsx("div", { className: "flex flex-col gap-1.5", children: lines.map((line, i) => /* @__PURE__ */ jsx(
1024
+ /* @__PURE__ */ jsx("div", { className: "payman-empty-text-group", children: lines.map((line, i) => /* @__PURE__ */ jsx(
919
1025
  motion.p,
920
1026
  {
921
1027
  initial: { opacity: 0, y: 6 },
@@ -1457,6 +1563,7 @@ var PaymanChat = forwardRef(function PaymanChat2({
1457
1563
  }, ref) {
1458
1564
  const [inputValue, setInputValue] = useState("");
1459
1565
  const prevInputValueRef = useRef(inputValue);
1566
+ const [hasEverSentMessage, setHasEverSentMessage] = useState(false);
1460
1567
  const chat = useChat(config, callbacks);
1461
1568
  const {
1462
1569
  messages,
@@ -1469,6 +1576,11 @@ var PaymanChat = forwardRef(function PaymanChat2({
1469
1576
  getSessionId,
1470
1577
  getMessages
1471
1578
  } = chat;
1579
+ useEffect(() => {
1580
+ if (messages.length > 0 && !hasEverSentMessage) {
1581
+ setHasEverSentMessage(true);
1582
+ }
1583
+ }, [messages.length, hasEverSentMessage]);
1472
1584
  const userActionState = chat.userActionState ?? DEFAULT_USER_ACTION_STATE;
1473
1585
  const approveUserAction = chat.approveUserAction ?? NOOP_ASYNC;
1474
1586
  const rejectUserAction = chat.rejectUserAction ?? NOOP_ASYNC;
@@ -1517,14 +1629,17 @@ var PaymanChat = forwardRef(function PaymanChat2({
1517
1629
  isWaitingForResponse
1518
1630
  ]
1519
1631
  );
1632
+ const { onExecutionTraceClick, onResetSession } = callbacks;
1520
1633
  useImperativeHandle(ref, () => ({
1521
- resetSession,
1634
+ resetSession: () => {
1635
+ resetSession();
1636
+ onResetSession?.();
1637
+ },
1522
1638
  clearMessages,
1523
1639
  cancelStream,
1524
1640
  getSessionId,
1525
1641
  getMessages
1526
- }), [resetSession, clearMessages, cancelStream, getSessionId, getMessages]);
1527
- const { onExecutionTraceClick } = callbacks;
1642
+ }), [resetSession, clearMessages, cancelStream, getSessionId, getMessages, onResetSession]);
1528
1643
  const {
1529
1644
  placeholder = "Type your message...",
1530
1645
  emptyStateText = "What can I help with?",
@@ -1546,7 +1661,9 @@ var PaymanChat = forwardRef(function PaymanChat2({
1546
1661
  animated = true,
1547
1662
  isChatDisabled = false,
1548
1663
  disabledComponent,
1549
- showEmptyStateIcon = true
1664
+ showEmptyStateIcon = true,
1665
+ emptyStateComponent,
1666
+ showResetSession = false
1550
1667
  } = config;
1551
1668
  const isSessionParamsConfigured = useMemo(() => {
1552
1669
  if (!sessionParams) return false;
@@ -1554,9 +1671,9 @@ var PaymanChat = forwardRef(function PaymanChat2({
1554
1671
  }, [sessionParams?.id, sessionParams?.name]);
1555
1672
  useEffect(() => {
1556
1673
  const wasEmpty = prevInputValueRef.current.trim() === "";
1557
- const isEmpty = inputValue.trim() === "";
1674
+ const isEmpty2 = inputValue.trim() === "";
1558
1675
  prevInputValueRef.current = inputValue;
1559
- if (!wasEmpty && isEmpty) {
1676
+ if (!wasEmpty && isEmpty2) {
1560
1677
  clearTranscript();
1561
1678
  if (isRecording) {
1562
1679
  stopRecording();
@@ -1572,14 +1689,23 @@ var PaymanChat = forwardRef(function PaymanChat2({
1572
1689
  setInputValue("");
1573
1690
  }
1574
1691
  };
1692
+ const handleCancelRecording = () => {
1693
+ stopRecording();
1694
+ clearTranscript();
1695
+ setInputValue("");
1696
+ };
1697
+ const handleConfirmRecording = () => {
1698
+ stopRecording();
1699
+ };
1575
1700
  const isInputDisabled = isWaitingForResponse || !isSessionParamsConfigured || disableInput;
1701
+ const isEmpty = messages.length === 0;
1576
1702
  if (isChatDisabled) {
1577
1703
  if (disabledComponent) {
1578
1704
  return /* @__PURE__ */ jsx(PaymanChatContext.Provider, { value: contextValue, children: /* @__PURE__ */ jsxs(
1579
1705
  "div",
1580
1706
  {
1581
1707
  className: cn(
1582
- "bg-card overflow-hidden flex flex-col flex-[4]",
1708
+ "bg-background overflow-hidden flex flex-col flex-[4]",
1583
1709
  className
1584
1710
  ),
1585
1711
  style,
@@ -1594,7 +1720,7 @@ var PaymanChat = forwardRef(function PaymanChat2({
1594
1720
  "div",
1595
1721
  {
1596
1722
  className: cn(
1597
- "bg-card overflow-hidden flex flex-col flex-[4]",
1723
+ "bg-background overflow-hidden flex flex-col flex-[4]",
1598
1724
  className
1599
1725
  ),
1600
1726
  style,
@@ -1605,62 +1731,138 @@ var PaymanChat = forwardRef(function PaymanChat2({
1605
1731
  }
1606
1732
  ) });
1607
1733
  }
1734
+ const inputElement = hasAskPermission && /* @__PURE__ */ jsx(
1735
+ ChatInput,
1736
+ {
1737
+ value: inputValue,
1738
+ onChange: setInputValue,
1739
+ onSend: handleSend,
1740
+ onPause: cancelStream,
1741
+ disabled: isInputDisabled,
1742
+ placeholder: isRecording ? "Listening..." : placeholder,
1743
+ isWaitingForResponse,
1744
+ hasSelectedSession: true,
1745
+ isSessionParamsConfigured,
1746
+ enableVoice: config.enableVoice === true,
1747
+ onVoicePress: isRecording ? stopRecording : startRecording,
1748
+ voiceAvailable: config.enableVoice === true && voiceAvailable,
1749
+ isRecording,
1750
+ transcribedText: inputValue,
1751
+ onCancelRecording: handleCancelRecording,
1752
+ onConfirmRecording: handleConfirmRecording,
1753
+ inputStyle,
1754
+ layout,
1755
+ showResetSession,
1756
+ onResetSession: () => {
1757
+ resetSession();
1758
+ onResetSession?.();
1759
+ }
1760
+ }
1761
+ );
1608
1762
  return /* @__PURE__ */ jsx(PaymanChatContext.Provider, { value: contextValue, children: /* @__PURE__ */ jsxs(
1609
1763
  "div",
1610
1764
  {
1611
1765
  className: cn(
1612
- "bg-card overflow-hidden flex flex-col flex-[4]",
1766
+ "bg-background overflow-hidden flex flex-col flex-[4]",
1613
1767
  className
1614
1768
  ),
1615
1769
  style,
1616
1770
  children: [
1617
1771
  children,
1618
- /* @__PURE__ */ jsx(
1619
- MessageList,
1620
- {
1621
- messages,
1622
- isLoading: false,
1623
- emptyStateText,
1624
- showEmptyStateIcon,
1625
- layout,
1626
- showTimestamps,
1627
- stage: config.stage || "DEV",
1628
- animated,
1629
- showAgentName,
1630
- agentName,
1631
- showAvatars,
1632
- showUserAvatar,
1633
- showAssistantAvatar,
1634
- showExecutionSteps,
1635
- showStreamingDot,
1636
- streamingStepsText,
1637
- completedStepsText,
1638
- onExecutionTraceClick,
1639
- onLoadMoreMessages,
1640
- isLoadingMoreMessages,
1641
- hasMoreMessages
1642
- }
1643
- ),
1644
- hasAskPermission && /* @__PURE__ */ jsx(
1645
- ChatInput,
1646
- {
1647
- value: inputValue,
1648
- onChange: setInputValue,
1649
- onSend: handleSend,
1650
- onPause: cancelStream,
1651
- disabled: isInputDisabled,
1652
- placeholder: isRecording ? "Listening..." : placeholder,
1653
- isWaitingForResponse,
1654
- hasSelectedSession: true,
1655
- isSessionParamsConfigured,
1656
- enableVoice: config.enableVoice === true,
1657
- onVoicePress: isRecording ? stopRecording : startRecording,
1658
- voiceAvailable: config.enableVoice === true && voiceAvailable,
1659
- isRecording,
1660
- inputStyle,
1661
- layout
1662
- }
1663
- ),
1772
+ /* @__PURE__ */ jsx(AnimatePresence, { mode: "wait", children: isEmpty && !hasEverSentMessage ? (
1773
+ /* ---- Centered empty state with input ---- */
1774
+ /* @__PURE__ */ jsx(
1775
+ motion.div,
1776
+ {
1777
+ initial: { opacity: 1 },
1778
+ exit: { opacity: 0 },
1779
+ transition: { duration: 0.3 },
1780
+ className: "payman-empty-centered-layout",
1781
+ children: /* @__PURE__ */ jsxs("div", { className: "payman-empty-centered-inner", children: [
1782
+ /* @__PURE__ */ jsx(
1783
+ MessageList,
1784
+ {
1785
+ messages,
1786
+ isLoading: false,
1787
+ emptyStateText,
1788
+ showEmptyStateIcon,
1789
+ emptyStateComponent,
1790
+ layout,
1791
+ showTimestamps,
1792
+ stage: config.stage || "DEV",
1793
+ animated,
1794
+ showAgentName,
1795
+ agentName,
1796
+ showAvatars,
1797
+ showUserAvatar,
1798
+ showAssistantAvatar,
1799
+ showExecutionSteps,
1800
+ showStreamingDot,
1801
+ streamingStepsText,
1802
+ completedStepsText,
1803
+ onExecutionTraceClick,
1804
+ onLoadMoreMessages,
1805
+ isLoadingMoreMessages,
1806
+ hasMoreMessages
1807
+ }
1808
+ ),
1809
+ /* @__PURE__ */ jsx(
1810
+ motion.div,
1811
+ {
1812
+ initial: { opacity: 0, y: 12 },
1813
+ animate: { opacity: 1, y: 0 },
1814
+ transition: { delay: 0.2, duration: 0.4, ease: [0.25, 0.46, 0.45, 0.94] },
1815
+ className: "payman-empty-centered-input",
1816
+ children: inputElement
1817
+ }
1818
+ )
1819
+ ] })
1820
+ },
1821
+ "empty-centered"
1822
+ )
1823
+ ) : (
1824
+ /* ---- Normal chat layout ---- */
1825
+ /* @__PURE__ */ jsxs(
1826
+ motion.div,
1827
+ {
1828
+ initial: hasEverSentMessage ? { opacity: 0 } : false,
1829
+ animate: { opacity: 1 },
1830
+ transition: { duration: 0.3 },
1831
+ className: "flex flex-col flex-1 min-h-0",
1832
+ children: [
1833
+ /* @__PURE__ */ jsx(
1834
+ MessageList,
1835
+ {
1836
+ messages,
1837
+ isLoading: false,
1838
+ emptyStateText,
1839
+ showEmptyStateIcon,
1840
+ emptyStateComponent,
1841
+ layout,
1842
+ showTimestamps,
1843
+ stage: config.stage || "DEV",
1844
+ animated,
1845
+ showAgentName,
1846
+ agentName,
1847
+ showAvatars,
1848
+ showUserAvatar,
1849
+ showAssistantAvatar,
1850
+ showExecutionSteps,
1851
+ showStreamingDot,
1852
+ streamingStepsText,
1853
+ completedStepsText,
1854
+ onExecutionTraceClick,
1855
+ onLoadMoreMessages,
1856
+ isLoadingMoreMessages,
1857
+ hasMoreMessages
1858
+ }
1859
+ ),
1860
+ inputElement
1861
+ ]
1862
+ },
1863
+ "chat-layout"
1864
+ )
1865
+ ) }),
1664
1866
  /* @__PURE__ */ jsx(
1665
1867
  UserActionModal,
1666
1868
  {