@paymanai/payman-ask-sdk 1.2.3 → 1.2.5

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.
@@ -1,234 +1,580 @@
1
1
  'use strict';
2
2
 
3
3
  var paymanTypescriptAskSdk = require('@paymanai/payman-typescript-ask-sdk');
4
- var React4 = require('react');
4
+ var React = require('react');
5
5
  var reactNative = require('react-native');
6
6
  var lucideReactNative = require('lucide-react-native');
7
7
  var jsxRuntime = require('react/jsx-runtime');
8
- var Animated = require('react-native-reanimated');
8
+ var Animated2 = require('react-native-reanimated');
9
9
  var Markdown = require('react-native-markdown-display');
10
10
  var clsx = require('clsx');
11
11
  var tailwindMerge = require('tailwind-merge');
12
12
 
13
13
  function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
14
14
 
15
- var React4__default = /*#__PURE__*/_interopDefault(React4);
16
- var Animated__default = /*#__PURE__*/_interopDefault(Animated);
15
+ var React__default = /*#__PURE__*/_interopDefault(React);
16
+ var Animated2__default = /*#__PURE__*/_interopDefault(Animated2);
17
17
  var Markdown__default = /*#__PURE__*/_interopDefault(Markdown);
18
18
 
19
19
  // src/components/PaymanChat/index.native.tsx
20
- var PaymanChatContext = React4.createContext(void 0);
20
+ var PaymanChatContext = React.createContext(void 0);
21
21
  function usePaymanChat() {
22
- const context = React4.useContext(PaymanChatContext);
22
+ const context = React.useContext(PaymanChatContext);
23
23
  if (!context) {
24
24
  throw new Error("usePaymanChat must be used within a PaymanChat component");
25
25
  }
26
26
  return context;
27
27
  }
28
+ if (reactNative.Platform.OS === "android" && reactNative.UIManager.setLayoutAnimationEnabledExperimental) {
29
+ reactNative.UIManager.setLayoutAnimationEnabledExperimental(true);
30
+ }
31
+ var VOICE_DOT_COUNT = 24;
32
+ var VOICE_DOT_MIN_H = 5;
33
+ var VOICE_DOT_MAX_H = 14;
34
+ var SPEECH_ACTIVITY_MS = 1400;
35
+ var VOICE_THEME_COLOR = "#00858d";
36
+ var VOICE_THEME_RGBA = "rgba(0, 133, 141, 0.6)";
37
+ var VOICE_THEME_RGBA_LIGHT = "rgba(0, 133, 141, 0.2)";
38
+ var VOICE_BAR_BG = "#f0f9f9";
39
+ var VOICE_BAR_BORDER = "rgba(0, 133, 141, 0.35)";
40
+ var VoiceWaveformBar = React.memo(
41
+ ({
42
+ index,
43
+ isActive,
44
+ barColor
45
+ }) => {
46
+ const height = React.useRef(new reactNative.Animated.Value(VOICE_DOT_MIN_H)).current;
47
+ React.useEffect(() => {
48
+ if (isActive) {
49
+ const delay = index * 25;
50
+ const duration = 180 + index % 3 * 40;
51
+ const animation = reactNative.Animated.loop(
52
+ reactNative.Animated.sequence([
53
+ reactNative.Animated.timing(height, {
54
+ toValue: VOICE_DOT_MAX_H,
55
+ duration,
56
+ delay,
57
+ easing: reactNative.Easing.inOut(reactNative.Easing.ease),
58
+ useNativeDriver: false
59
+ }),
60
+ reactNative.Animated.timing(height, {
61
+ toValue: VOICE_DOT_MIN_H,
62
+ duration,
63
+ easing: reactNative.Easing.inOut(reactNative.Easing.ease),
64
+ useNativeDriver: false
65
+ })
66
+ ])
67
+ );
68
+ animation.start();
69
+ return () => animation.stop();
70
+ } else {
71
+ reactNative.Animated.timing(height, {
72
+ toValue: VOICE_DOT_MIN_H,
73
+ duration: 200,
74
+ useNativeDriver: false
75
+ }).start();
76
+ }
77
+ }, [isActive, index, height]);
78
+ return /* @__PURE__ */ jsxRuntime.jsx(
79
+ reactNative.Animated.View,
80
+ {
81
+ style: [
82
+ s.voiceDotBase,
83
+ {
84
+ height,
85
+ backgroundColor: barColor
86
+ }
87
+ ]
88
+ }
89
+ );
90
+ }
91
+ );
92
+ VoiceWaveformBar.displayName = "VoiceWaveformBar";
93
+ function formatDuration(seconds) {
94
+ const m = Math.floor(seconds / 60);
95
+ const s9 = seconds % 60;
96
+ return `${m}:${s9.toString().padStart(2, "0")}`;
97
+ }
28
98
  function ChatInput({
29
99
  value,
30
100
  onChange,
31
101
  onSend,
32
102
  onPause,
33
103
  disabled = false,
34
- placeholder = "Type your message...",
104
+ placeholder = "Chat with Claude",
35
105
  isWaitingForResponse = false,
36
106
  hasSelectedSession = true,
37
107
  isSessionParamsConfigured = true,
38
108
  onClick,
39
109
  inputStyle = "rounded",
40
110
  layout = "full-width",
41
- className,
42
111
  enableVoice = false,
43
112
  onVoicePress,
44
- voiceAvailable = false
113
+ voiceAvailable = false,
114
+ isRecording = false,
115
+ recordingDurationSeconds = 0,
116
+ onConfirmRecording,
117
+ onCancelRecording,
118
+ transcribedText
45
119
  }) {
46
120
  const isInputDisabled = disabled || isWaitingForResponse;
47
121
  const showPauseButton = isWaitingForResponse && onPause;
48
122
  const showVoiceButton = enableVoice && onVoicePress != null;
49
123
  const isVoiceButtonDisabled = isWaitingForResponse || !voiceAvailable || !isSessionParamsConfigured;
50
- const getPlaceholder = () => {
51
- if (!hasSelectedSession) {
52
- return "Select a version to start chatting";
124
+ const canSend = !isInputDisabled && value.trim().length > 0;
125
+ const showVoiceBar = enableVoice && isRecording && onConfirmRecording != null && onCancelRecording != null;
126
+ const [isUserSpeaking, setIsUserSpeaking] = React.useState(false);
127
+ const speechTimeoutRef = React.useRef(null);
128
+ const prevTranscriptRef = React.useRef("");
129
+ React.useEffect(() => {
130
+ if (!showVoiceBar) {
131
+ setIsUserSpeaking(false);
132
+ prevTranscriptRef.current = "";
133
+ if (speechTimeoutRef.current) {
134
+ clearTimeout(speechTimeoutRef.current);
135
+ speechTimeoutRef.current = null;
136
+ }
137
+ return;
53
138
  }
54
- if (!isSessionParamsConfigured) {
55
- return "Configure User ID and User Label in Session Params";
139
+ const current = transcribedText ?? "";
140
+ const changed = current !== prevTranscriptRef.current;
141
+ prevTranscriptRef.current = current;
142
+ if (changed) {
143
+ setIsUserSpeaking(true);
144
+ if (speechTimeoutRef.current) clearTimeout(speechTimeoutRef.current);
145
+ speechTimeoutRef.current = setTimeout(() => {
146
+ speechTimeoutRef.current = null;
147
+ setIsUserSpeaking(false);
148
+ }, SPEECH_ACTIVITY_MS);
149
+ }
150
+ return () => {
151
+ if (speechTimeoutRef.current) {
152
+ clearTimeout(speechTimeoutRef.current);
153
+ speechTimeoutRef.current = null;
154
+ }
155
+ };
156
+ }, [showVoiceBar, transcribedText]);
157
+ const animOpacity = React.useRef(new reactNative.Animated.Value(1)).current;
158
+ const animScale = React.useRef(new reactNative.Animated.Value(1)).current;
159
+ const inputRef = React.useRef(null);
160
+ React.useEffect(() => {
161
+ if (showVoiceBar) {
162
+ reactNative.LayoutAnimation.configureNext(
163
+ reactNative.LayoutAnimation.create(200, "easeInEaseOut", "opacity")
164
+ );
165
+ animOpacity.setValue(0.92);
166
+ animScale.setValue(0.98);
167
+ reactNative.Animated.parallel([
168
+ reactNative.Animated.timing(animOpacity, {
169
+ toValue: 1,
170
+ duration: 200,
171
+ useNativeDriver: true
172
+ }),
173
+ reactNative.Animated.spring(animScale, {
174
+ toValue: 1,
175
+ useNativeDriver: true,
176
+ speed: 12,
177
+ bounciness: 4
178
+ })
179
+ ]).start();
180
+ } else {
181
+ reactNative.LayoutAnimation.configureNext(
182
+ reactNative.LayoutAnimation.create(220, "easeInEaseOut", "opacity")
183
+ );
184
+ animOpacity.setValue(1);
185
+ animScale.setValue(1);
56
186
  }
187
+ }, [showVoiceBar, animOpacity, animScale]);
188
+ const getPlaceholder = () => {
189
+ if (!hasSelectedSession) return "Select a version to start chatting";
190
+ if (!isSessionParamsConfigured)
191
+ return "Configure User ID and User Label in Session Params";
57
192
  return placeholder;
58
193
  };
194
+ const handleSubmit = () => {
195
+ if (canSend) onSend();
196
+ };
197
+ const handleConfirmRecording = () => {
198
+ reactNative.LayoutAnimation.configureNext(
199
+ reactNative.LayoutAnimation.create(220, "easeOut", "opacity")
200
+ );
201
+ onConfirmRecording?.();
202
+ };
203
+ const handleCancelRecording = () => {
204
+ reactNative.LayoutAnimation.configureNext(
205
+ reactNative.LayoutAnimation.create(200, "easeIn", "opacity")
206
+ );
207
+ onCancelRecording?.();
208
+ };
59
209
  return /* @__PURE__ */ jsxRuntime.jsx(
60
210
  reactNative.View,
61
211
  {
62
212
  style: [
63
- styles.container,
64
- layout === "centered" && styles.containerCentered
213
+ s.outerBar,
214
+ layout === "centered" && s.outerBarCentered,
215
+ showVoiceBar && s.outerBarVoiceMargin
65
216
  ],
66
- children: /* @__PURE__ */ jsxRuntime.jsx(reactNative.View, { style: styles.wrapper, children: /* @__PURE__ */ jsxRuntime.jsxs(
67
- reactNative.View,
68
- {
69
- style: [
70
- styles.inputContainer,
71
- inputStyle === "rounded" && styles.inputRounded
72
- ],
73
- children: [
74
- /* @__PURE__ */ jsxRuntime.jsx(
75
- reactNative.TextInput,
76
- {
77
- value,
78
- onChangeText: onChange,
79
- onPress: onClick,
80
- editable: !isInputDisabled,
81
- placeholder: getPlaceholder(),
82
- placeholderTextColor: "#999",
83
- multiline: true,
84
- style: [styles.input, isInputDisabled && styles.inputDisabled],
85
- returnKeyType: "default",
86
- blurOnSubmit: false
87
- }
88
- ),
89
- /* @__PURE__ */ jsxRuntime.jsxs(reactNative.View, { style: styles.actionsRow, children: [
90
- showVoiceButton && /* @__PURE__ */ jsxRuntime.jsx(reactNative.View, { style: styles.voiceButton, children: /* @__PURE__ */ jsxRuntime.jsx(
91
- reactNative.Pressable,
92
- {
93
- onPress: onVoicePress,
94
- disabled: isVoiceButtonDisabled,
95
- style: ({ pressed }) => [
96
- styles.iconButton,
97
- pressed && styles.buttonPressed,
98
- isVoiceButtonDisabled && styles.buttonDisabled
99
- ],
100
- children: /* @__PURE__ */ jsxRuntime.jsx(lucideReactNative.Mic, { size: 20, color: "#000000" })
101
- }
102
- ) }),
103
- showPauseButton ? /* @__PURE__ */ jsxRuntime.jsx(reactNative.View, { style: styles.button, children: /* @__PURE__ */ jsxRuntime.jsx(
104
- reactNative.Pressable,
217
+ children: /* @__PURE__ */ jsxRuntime.jsxs(reactNative.View, { style: s.column, children: [
218
+ /* @__PURE__ */ jsxRuntime.jsxs(reactNative.View, { style: [s.inputWrap, showVoiceBar && s.inputWrapRelative], children: [
219
+ /* @__PURE__ */ jsxRuntime.jsx(
220
+ reactNative.TextInput,
221
+ {
222
+ ref: inputRef,
223
+ value,
224
+ onChangeText: onChange,
225
+ onPress: onClick,
226
+ editable: !isInputDisabled,
227
+ placeholder: getPlaceholder(),
228
+ placeholderTextColor: "#9CA3AF",
229
+ multiline: true,
230
+ style: [
231
+ s.input,
232
+ isInputDisabled && s.inputDisabled,
233
+ showVoiceBar && s.inputHiddenKeepFocus
234
+ ],
235
+ returnKeyType: "default",
236
+ blurOnSubmit: false,
237
+ onSubmitEditing: handleSubmit
238
+ }
239
+ ),
240
+ showVoiceBar && /* @__PURE__ */ jsxRuntime.jsx(
241
+ reactNative.Animated.View,
242
+ {
243
+ pointerEvents: "box-none",
244
+ style: [
245
+ s.voiceBarContainer,
105
246
  {
106
- onPress: onPause,
107
- style: ({ pressed }) => [
108
- styles.iconButton,
109
- pressed && styles.buttonPressed
110
- ],
111
- children: /* @__PURE__ */ jsxRuntime.jsx(lucideReactNative.Pause, { size: 16, color: "#FFFFFF" })
247
+ opacity: animOpacity,
248
+ transform: [{ scale: animScale }]
112
249
  }
113
- ) }) : /* @__PURE__ */ jsxRuntime.jsx(
114
- reactNative.View,
115
- {
116
- style: [
117
- styles.button,
118
- (isInputDisabled || !value.trim()) && styles.buttonDisabled
119
- ],
120
- children: /* @__PURE__ */ jsxRuntime.jsx(
121
- reactNative.Pressable,
250
+ ],
251
+ children: /* @__PURE__ */ jsxRuntime.jsxs(reactNative.View, { style: s.voiceBar, children: [
252
+ /* @__PURE__ */ jsxRuntime.jsx(
253
+ reactNative.Pressable,
254
+ {
255
+ onPress: handleCancelRecording,
256
+ style: ({ pressed }) => [
257
+ s.voiceBarCancelBtn,
258
+ pressed && s.btnPressed
259
+ ],
260
+ accessibilityLabel: "Cancel recording",
261
+ children: /* @__PURE__ */ jsxRuntime.jsx(lucideReactNative.X, { size: 20, color: VOICE_THEME_COLOR, strokeWidth: 2.5 })
262
+ }
263
+ ),
264
+ /* @__PURE__ */ jsxRuntime.jsxs(reactNative.View, { style: s.voiceBarCenter, children: [
265
+ /* @__PURE__ */ jsxRuntime.jsx(reactNative.View, { style: s.voiceBarDots, children: Array.from({ length: VOICE_DOT_COUNT }).map((_, i) => /* @__PURE__ */ jsxRuntime.jsx(
266
+ VoiceWaveformBar,
122
267
  {
123
- onPress: onSend,
124
- disabled: isInputDisabled || !value.trim(),
125
- style: ({ pressed }) => [
126
- styles.iconButton,
127
- pressed && styles.buttonPressed
128
- ],
129
- children: /* @__PURE__ */ jsxRuntime.jsx(lucideReactNative.Send, { size: 16, color: "#FFFFFF" })
130
- }
131
- )
132
- }
133
- )
134
- ] })
135
- ]
136
- }
137
- ) })
268
+ index: i,
269
+ isActive: isUserSpeaking,
270
+ barColor: VOICE_THEME_RGBA
271
+ },
272
+ i
273
+ )) }),
274
+ /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: s.voiceBarTimer, children: formatDuration(recordingDurationSeconds) })
275
+ ] }),
276
+ /* @__PURE__ */ jsxRuntime.jsx(
277
+ reactNative.Pressable,
278
+ {
279
+ onPress: handleConfirmRecording,
280
+ style: ({ pressed }) => [
281
+ s.voiceBarConfirmBtn,
282
+ pressed && s.btnPressed
283
+ ],
284
+ accessibilityLabel: "Confirm and send recording",
285
+ children: /* @__PURE__ */ jsxRuntime.jsx(lucideReactNative.Check, { size: 22, color: VOICE_THEME_COLOR, strokeWidth: 2.5 })
286
+ }
287
+ )
288
+ ] })
289
+ }
290
+ )
291
+ ] }),
292
+ !showVoiceBar && /* @__PURE__ */ jsxRuntime.jsx(reactNative.View, { style: s.actionsRow, children: /* @__PURE__ */ jsxRuntime.jsxs(reactNative.View, { style: s.rightActions, children: [
293
+ showVoiceButton && /* @__PURE__ */ jsxRuntime.jsx(
294
+ reactNative.Pressable,
295
+ {
296
+ onPress: onVoicePress,
297
+ disabled: isVoiceButtonDisabled,
298
+ style: ({ pressed }) => [
299
+ s.iconBtn,
300
+ pressed && s.btnPressed,
301
+ isVoiceButtonDisabled && s.btnDisabled
302
+ ],
303
+ accessibilityLabel: "Voice input",
304
+ children: /* @__PURE__ */ jsxRuntime.jsx(reactNative.View, { style: s.iconBtnInner, children: /* @__PURE__ */ jsxRuntime.jsx(lucideReactNative.Mic, { size: 22, color: "#6B7280", strokeWidth: 2 }) })
305
+ }
306
+ ),
307
+ showPauseButton ? /* @__PURE__ */ jsxRuntime.jsx(
308
+ reactNative.Pressable,
309
+ {
310
+ onPress: onPause,
311
+ style: ({ pressed }) => [
312
+ s.sendBtn,
313
+ pressed && s.btnPressed
314
+ ],
315
+ children: /* @__PURE__ */ jsxRuntime.jsx(reactNative.View, { style: s.sendBtnInner, children: /* @__PURE__ */ jsxRuntime.jsx(lucideReactNative.Pause, { size: 18, color: "#FFFFFF" }) })
316
+ }
317
+ ) : /* @__PURE__ */ jsxRuntime.jsx(
318
+ reactNative.Pressable,
319
+ {
320
+ onPress: onSend,
321
+ disabled: !canSend,
322
+ style: ({ pressed }) => [
323
+ s.sendBtn,
324
+ !canSend && s.btnDisabled,
325
+ pressed && s.btnPressed
326
+ ],
327
+ children: /* @__PURE__ */ jsxRuntime.jsx(reactNative.View, { style: s.sendBtnInner, children: /* @__PURE__ */ jsxRuntime.jsx(lucideReactNative.Send, { size: 18, color: "#FFFFFF" }) })
328
+ }
329
+ )
330
+ ] }) })
331
+ ] })
138
332
  }
139
333
  );
140
334
  }
141
- var styles = reactNative.StyleSheet.create({
142
- container: {
143
- padding: 16,
144
- width: "100%"
145
- },
146
- containerCentered: {
147
- alignItems: "center"
335
+ var s = reactNative.StyleSheet.create({
336
+ outerBar: {
337
+ width: "100%",
338
+ backgroundColor: "#f1f5f9",
339
+ borderTopWidth: 1,
340
+ borderTopColor: "rgba(0,0,0,0.08)",
341
+ paddingTop: 12,
342
+ paddingBottom: reactNative.Platform.OS === "ios" ? 28 : 12,
343
+ paddingHorizontal: 12,
344
+ borderTopLeftRadius: 20,
345
+ borderTopRightRadius: 20
148
346
  },
149
- wrapper: {
150
- position: "relative",
347
+ outerBarCentered: { alignItems: "center" },
348
+ column: {
349
+ maxWidth: 672,
151
350
  width: "100%",
152
- maxWidth: 672
351
+ alignSelf: "center",
352
+ gap: 10
153
353
  },
154
- inputContainer: {
354
+ actionsRow: {
155
355
  flexDirection: "row",
156
- alignItems: "flex-end",
157
- backgroundColor: "#F5F5F5",
158
- borderWidth: 1,
159
- borderColor: "#E5E5E5",
160
- borderRadius: 12,
356
+ justifyContent: "flex-end",
357
+ alignItems: "center",
358
+ marginBottom: 10
359
+ },
360
+ iconBtn: {
361
+ width: 36,
362
+ height: 36,
363
+ justifyContent: "center",
364
+ alignItems: "center",
365
+ borderRadius: 18,
161
366
  overflow: "hidden"
162
367
  },
163
- inputRounded: {
164
- borderRadius: 24
368
+ iconBtnInner: {
369
+ width: 36,
370
+ height: 36,
371
+ justifyContent: "center",
372
+ alignItems: "center",
373
+ backgroundColor: "rgba(0,0,0,0.1)",
374
+ borderRadius: 18
165
375
  },
166
- input: {
167
- flex: 1,
168
- minHeight: 48,
169
- maxHeight: 200,
170
- paddingTop: 12,
171
- paddingBottom: 12,
172
- paddingLeft: 16,
173
- paddingRight: 8,
174
- fontSize: 14,
175
- color: "#000",
176
- lineHeight: 20
376
+ inputWrap: {
377
+ width: "100%",
378
+ minHeight: 56,
379
+ justifyContent: "center",
380
+ paddingHorizontal: 4
177
381
  },
178
- inputDisabled: {
179
- opacity: 0.5
382
+ inputWrapRelative: {
383
+ position: "relative"
180
384
  },
181
- actionsRow: {
385
+ inputHiddenKeepFocus: {
386
+ position: "absolute",
387
+ left: 0,
388
+ right: 0,
389
+ top: 0,
390
+ opacity: 0,
391
+ zIndex: 0
392
+ },
393
+ input: {
394
+ minHeight: 56,
395
+ maxHeight: 140,
396
+ paddingVertical: 16,
397
+ paddingHorizontal: 16,
398
+ fontSize: 16,
399
+ color: "#1F2937",
400
+ lineHeight: 22
401
+ },
402
+ inputDisabled: { opacity: 0.5 },
403
+ rightActions: {
182
404
  flexDirection: "row",
183
405
  alignItems: "center",
184
- marginRight: 8,
185
- marginBottom: 8,
186
- gap: 4
406
+ gap: 6
187
407
  },
188
- button: {
189
- width: 32,
190
- height: 32,
191
- borderRadius: 16,
192
- backgroundColor: "#007AFF",
408
+ sendBtn: {
409
+ width: 36,
410
+ height: 36,
411
+ borderRadius: 18,
412
+ overflow: "hidden",
193
413
  justifyContent: "center",
194
414
  alignItems: "center"
195
415
  },
196
- iconButton: {
197
- width: "100%",
198
- height: "100%",
416
+ sendBtnInner: {
417
+ width: 36,
418
+ height: 36,
419
+ borderRadius: 18,
420
+ backgroundColor: "#00858d",
199
421
  justifyContent: "center",
200
422
  alignItems: "center"
201
423
  },
202
- buttonDisabled: {
203
- opacity: 0.5
424
+ btnDisabled: { opacity: 0.35 },
425
+ btnPressed: { opacity: 0.7 },
426
+ outerBarVoiceMargin: {
427
+ paddingBottom: reactNative.Platform.OS === "ios" ? 36 : 20
428
+ },
429
+ // Voice bar (replaces input when recording) – theme #00858d
430
+ voiceBarContainer: {
431
+ position: "absolute",
432
+ left: 0,
433
+ right: 0,
434
+ top: 0,
435
+ bottom: 0,
436
+ justifyContent: "center",
437
+ zIndex: 1
204
438
  },
205
- buttonPressed: {
206
- opacity: 0.8
439
+ voiceBar: {
440
+ flexDirection: "row",
441
+ alignItems: "center",
442
+ justifyContent: "space-between",
443
+ backgroundColor: VOICE_BAR_BG,
444
+ borderWidth: 1,
445
+ borderColor: VOICE_BAR_BORDER,
446
+ borderRadius: 28,
447
+ minHeight: 56,
448
+ paddingHorizontal: 12,
449
+ paddingVertical: 10,
450
+ gap: 12
207
451
  },
208
- voiceButton: {
209
- width: 32,
210
- height: 32,
211
- justifyContent: "center",
212
- alignItems: "center"
452
+ voiceBarCancelBtn: {
453
+ width: 40,
454
+ height: 40,
455
+ borderRadius: 20,
456
+ backgroundColor: VOICE_THEME_RGBA_LIGHT,
457
+ alignItems: "center",
458
+ justifyContent: "center"
459
+ },
460
+ voiceBarCenter: {
461
+ flex: 1,
462
+ flexDirection: "row",
463
+ alignItems: "center",
464
+ justifyContent: "space-between",
465
+ gap: 10,
466
+ marginLeft: 8
467
+ },
468
+ voiceBarDots: {
469
+ flex: 1,
470
+ flexDirection: "row",
471
+ alignItems: "center",
472
+ justifyContent: "space-between",
473
+ gap: 4
474
+ },
475
+ voiceDotBase: {
476
+ width: 4,
477
+ borderRadius: 2
478
+ },
479
+ voiceDot: {
480
+ width: 4,
481
+ height: 6,
482
+ borderRadius: 2,
483
+ backgroundColor: VOICE_THEME_RGBA
484
+ },
485
+ voiceDotActive: {
486
+ height: 12,
487
+ backgroundColor: VOICE_THEME_COLOR
488
+ },
489
+ voiceBarTimer: {
490
+ fontSize: 15,
491
+ fontWeight: "600",
492
+ color: VOICE_THEME_COLOR,
493
+ minWidth: 36,
494
+ textAlign: "right"
495
+ },
496
+ voiceBarConfirmBtn: {
497
+ width: 40,
498
+ height: 40,
499
+ borderRadius: 20,
500
+ backgroundColor: "#FFFFFF",
501
+ borderWidth: 1,
502
+ borderColor: VOICE_THEME_COLOR,
503
+ alignItems: "center",
504
+ justifyContent: "center"
213
505
  }
214
506
  });
215
- function AnimatedLoader({ size = 16, color = "#007AFF" }) {
216
- const rotation = Animated.useSharedValue(0);
217
- React4__default.default.useEffect(() => {
218
- rotation.value = Animated.withRepeat(
219
- Animated.withTiming(360, {
220
- duration: 1e3,
221
- easing: Animated.Easing.linear
222
- }),
507
+ function AnimatedLoader({
508
+ size = 14,
509
+ color = "#00858d"
510
+ }) {
511
+ const rotation = Animated2.useSharedValue(0);
512
+ React__default.default.useEffect(() => {
513
+ rotation.value = Animated2.withRepeat(
514
+ Animated2.withTiming(360, { duration: 1e3, easing: Animated2.Easing.linear }),
223
515
  -1
224
516
  );
225
517
  }, [rotation]);
226
- const animatedStyle = Animated.useAnimatedStyle(() => {
227
- return {
228
- transform: [{ rotate: `${rotation.value}deg` }]
229
- };
518
+ const style = Animated2.useAnimatedStyle(() => ({
519
+ transform: [{ rotate: `${rotation.value}deg` }]
520
+ }));
521
+ return /* @__PURE__ */ jsxRuntime.jsx(Animated2__default.default.View, { style, children: /* @__PURE__ */ jsxRuntime.jsx(lucideReactNative.Loader2, { size, color }) });
522
+ }
523
+ function ShimmerText({
524
+ children,
525
+ style: textStyle
526
+ }) {
527
+ const progress = Animated2.useSharedValue(0);
528
+ React__default.default.useEffect(() => {
529
+ progress.value = Animated2.withRepeat(
530
+ Animated2.withTiming(1, { duration: 3500, easing: Animated2.Easing.linear }),
531
+ -1,
532
+ false
533
+ );
534
+ }, [progress]);
535
+ const animatedStyle = Animated2.useAnimatedStyle(() => {
536
+ const color = Animated2.interpolateColor(
537
+ progress.value,
538
+ [0, 0.35, 0.5, 0.65, 1],
539
+ ["#9CA3AF", "#9CA3AF", "#00858d", "#9CA3AF", "#9CA3AF"]
540
+ );
541
+ return { color };
230
542
  });
231
- return /* @__PURE__ */ jsxRuntime.jsx(Animated__default.default.View, { style: animatedStyle, children: /* @__PURE__ */ jsxRuntime.jsx(lucideReactNative.Loader2, { size, color }) });
543
+ return /* @__PURE__ */ jsxRuntime.jsx(Animated2__default.default.Text, { style: [textStyle, animatedStyle, { fontWeight: "600" }], children });
544
+ }
545
+ function ThoughtProcessLabel({ style }) {
546
+ const opacity = Animated2.useSharedValue(1);
547
+ React__default.default.useEffect(() => {
548
+ opacity.value = Animated2.withRepeat(
549
+ Animated2.withTiming(0.5, { duration: 800, easing: Animated2.Easing.inOut(Animated2.Easing.ease) }),
550
+ -1,
551
+ true
552
+ );
553
+ }, [opacity]);
554
+ const animatedStyle = Animated2.useAnimatedStyle(() => ({ opacity: opacity.value }));
555
+ return /* @__PURE__ */ jsxRuntime.jsx(Animated2__default.default.Text, { style: [style, animatedStyle], children: "Thought Process" });
556
+ }
557
+ function ThinkingBlock({ text }) {
558
+ const [isOpen, setIsOpen] = React.useState(false);
559
+ const hasContent = typeof text === "string" && text.trim().length > 0;
560
+ if (!hasContent) return null;
561
+ return /* @__PURE__ */ jsxRuntime.jsxs(reactNative.View, { style: ts.thinkingWrap, children: [
562
+ /* @__PURE__ */ jsxRuntime.jsxs(
563
+ reactNative.Pressable,
564
+ {
565
+ onPress: () => setIsOpen((prev) => !prev),
566
+ style: ts.thinkingToggle,
567
+ accessibilityRole: "button",
568
+ accessibilityState: { expanded: isOpen },
569
+ accessibilityLabel: isOpen ? "Collapse thought process" : "Expand thought process",
570
+ children: [
571
+ /* @__PURE__ */ jsxRuntime.jsx(reactNative.View, { style: { transform: [{ rotate: isOpen ? "180deg" : "0deg" }] }, children: /* @__PURE__ */ jsxRuntime.jsx(lucideReactNative.ChevronDown, { size: 10, color: "rgba(156,163,175,0.5)" }) }),
572
+ /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: ts.thinkingToggleText, children: "Thought process" })
573
+ ]
574
+ }
575
+ ),
576
+ isOpen && /* @__PURE__ */ jsxRuntime.jsx(reactNative.View, { style: ts.thinkingContent, children: /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: ts.thinkingContentText, children: text }) })
577
+ ] });
232
578
  }
233
579
  function AgentMessage({
234
580
  message,
@@ -250,501 +596,447 @@ function AgentMessage({
250
596
  const isError = message.isError ?? (message.streamProgress === "error" || !!message.errorDetails);
251
597
  const isCancelled = message.isCancelled ?? false;
252
598
  const currentExecutingStepId = message.currentExecutingStepId;
253
- const [isStepsExpanded, setIsStepsExpanded] = React4.useState(
599
+ const [isStepsExpanded, setIsStepsExpanded] = React.useState(
254
600
  isStreaming && hasSteps
255
601
  );
256
- React4.useEffect(() => {
257
- if (isStreaming && hasSteps) {
258
- setIsStepsExpanded(true);
259
- }
602
+ const wasStreamingRef = React.useRef(isStreaming);
603
+ React.useEffect(() => {
604
+ if (isStreaming && hasSteps) setIsStepsExpanded(true);
605
+ if (wasStreamingRef.current && !isStreaming) setIsStepsExpanded(false);
606
+ wasStreamingRef.current = isStreaming;
260
607
  }, [isStreaming, hasSteps]);
261
608
  const totalElapsedMs = hasSteps ? message.steps.reduce((sum, step) => sum + (step.elapsedMs || 0), 0) : 0;
262
609
  const currentMessage = message.currentMessage;
263
610
  const rawContent = message.streamingContent || message.content || "";
264
611
  const content = rawContent.replace(/\\n/g, "\n");
265
- const getStreamingStepsText = (expanded) => {
266
- const defaultText = `${expanded ? "Hide" : "View"} progress ({count} ${message.steps.length === 1 ? "step" : "steps"})`;
267
- const text = streamingStepsText || defaultText;
268
- const prefix = expanded ? "Hide" : "View";
269
- return text.replace("{count}", message.steps.length.toString()).replace(/^(View|Hide)/, prefix);
270
- };
271
- const getCompletedStepsText = (expanded) => {
272
- if (completedStepsText) {
273
- const result = completedStepsText.replace("{count}", message.steps.length.toString()).replace("{time}", (totalElapsedMs / 1e3).toFixed(1));
274
- return result;
275
- }
276
- const prefix = expanded ? "Hide" : "View";
277
- const stepWord = message.steps.length === 1 ? "step" : "steps";
278
- return `${prefix} execution steps (${message.steps.length} ${stepWord})`;
279
- };
280
- const AnimatedView = animated ? Animated__default.default.View : reactNative.View;
281
- const animatedProps = animated ? { entering: Animated.FadeInDown.duration(200), layout: Animated.Layout } : {};
282
- const messageContent = /* @__PURE__ */ jsxRuntime.jsxs(reactNative.View, { style: styles2.container, children: [
283
- showAvatar && /* @__PURE__ */ jsxRuntime.jsx(reactNative.View, { style: styles2.avatarContainer, children: isStreaming && showStreamingDot ? (
284
- // Animated dot indicator while streaming
285
- /* @__PURE__ */ jsxRuntime.jsx(reactNative.View, { style: styles2.dotContainer, children: /* @__PURE__ */ jsxRuntime.jsx(reactNative.View, { style: [styles2.dot, styles2.dotPulse] }) })
286
- ) : (
287
- // Avatar after completion
288
- /* @__PURE__ */ jsxRuntime.jsx(reactNative.View, { style: styles2.avatar, children: /* @__PURE__ */ jsxRuntime.jsx(lucideReactNative.Bot, { size: 16, color: "#666" }) })
289
- ) }),
290
- /* @__PURE__ */ jsxRuntime.jsxs(
291
- reactNative.View,
292
- {
293
- style: [
294
- styles2.messageContainer,
295
- layout === "centered" && styles2.messageContainerCentered
296
- ],
297
- children: [
298
- message.userActionResult && /* @__PURE__ */ jsxRuntime.jsx(reactNative.View, { style: styles2.badgeContainer, children: message.userActionResult === "approved" ? /* @__PURE__ */ jsxRuntime.jsxs(reactNative.View, { style: [styles2.badge, styles2.badgeApproved], children: [
299
- /* @__PURE__ */ jsxRuntime.jsx(lucideReactNative.CheckCircle2, { size: 12, color: "#15803d" }),
300
- /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: styles2.badgeApprovedText, children: "OTP Verified" })
301
- ] }) : /* @__PURE__ */ jsxRuntime.jsxs(reactNative.View, { style: [styles2.badge, styles2.badgeRejected], children: [
302
- /* @__PURE__ */ jsxRuntime.jsx(lucideReactNative.XCircle, { size: 12, color: "#b91c1c" }),
303
- /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: styles2.badgeRejectedText, children: "Rejected" })
304
- ] }) }),
305
- /* @__PURE__ */ jsxRuntime.jsxs(
306
- reactNative.View,
307
- {
308
- style: [
309
- styles2.bubble,
310
- layout === "centered" && styles2.bubbleCentered,
311
- hasSteps && styles2.bubbleWithSteps,
312
- isStreaming && styles2.bubbleStreaming,
313
- isError && styles2.bubbleError
314
- ],
315
- children: [
316
- showAgentName && /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: styles2.agentName, children: agentName }),
317
- /* @__PURE__ */ jsxRuntime.jsx(reactNative.View, { style: styles2.contentContainer, children: isStreaming && !content ? !showAvatar ? /* @__PURE__ */ jsxRuntime.jsxs(reactNative.View, { style: styles2.thinkingContainer, children: [
318
- /* @__PURE__ */ jsxRuntime.jsx(AnimatedLoader, { size: 16, color: "#007AFF" }),
319
- /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: styles2.thinkingText, children: currentMessage || "Thinking..." })
320
- ] }) : /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: styles2.thinkingText, children: currentMessage || "Thinking..." }) : isCancelled && !content ? !showAvatar ? /* @__PURE__ */ jsxRuntime.jsxs(reactNative.View, { style: styles2.thinkingContainer, children: [
321
- /* @__PURE__ */ jsxRuntime.jsx(lucideReactNative.X, { size: 16, color: "#666" }),
322
- /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: styles2.thinkingText, children: currentMessage || "The request was stopped." })
323
- ] }) : /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: styles2.thinkingText, children: currentMessage || "The request was stopped." }) : /* @__PURE__ */ jsxRuntime.jsx(
324
- Markdown__default.default,
325
- {
326
- style: isError ? markdownErrorStyles : markdownStyles,
327
- children: content || (isStreaming ? "Thinking..." : isCancelled ? "The request was stopped." : isError ? "Oops, something went wrong. Please try again." : "")
328
- }
329
- ) })
330
- ]
331
- }
332
- ),
333
- showExecutionSteps && hasSteps && !isStreaming && !isError && /* @__PURE__ */ jsxRuntime.jsxs(
334
- reactNative.View,
335
- {
336
- style: [
337
- styles2.stepsContainer,
338
- layout === "centered" && styles2.stepsContainerCentered
339
- ],
340
- children: [
341
- /* @__PURE__ */ jsxRuntime.jsxs(
342
- reactNative.Pressable,
343
- {
344
- onPress: () => setIsStepsExpanded(!isStepsExpanded),
345
- style: styles2.stepsButton,
346
- children: [
347
- /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: styles2.stepsButtonText, children: getCompletedStepsText(!!isStepsExpanded) }),
348
- isStepsExpanded ? /* @__PURE__ */ jsxRuntime.jsx(lucideReactNative.ChevronUp, { size: 12, color: "#666" }) : /* @__PURE__ */ jsxRuntime.jsx(lucideReactNative.ChevronDown, { size: 12, color: "#666" })
349
- ]
350
- }
351
- ),
352
- isStepsExpanded && /* @__PURE__ */ jsxRuntime.jsx(
353
- Animated__default.default.View,
354
- {
355
- entering: animated ? Animated.FadeIn.duration(200) : void 0,
356
- exiting: animated ? Animated.FadeOut.duration(200) : void 0,
357
- style: styles2.stepsList,
358
- children: message.steps.map((step, index) => {
359
- const isCurrentlyExecuting = step.id === currentExecutingStepId && step.status === "in_progress" && isStreaming && !isCancelled;
360
- return /* @__PURE__ */ jsxRuntime.jsxs(
361
- Animated__default.default.View,
362
- {
363
- entering: animated ? Animated.FadeInUp.duration(300).delay(index * 50) : void 0,
364
- layout: animated ? Animated.Layout.springify() : void 0,
365
- style: styles2.stepItem,
366
- children: [
367
- isCurrentlyExecuting && /* @__PURE__ */ jsxRuntime.jsx(AnimatedLoader, { size: 12, color: "#007AFF" }),
368
- step.status === "pending" && isCancelled && /* @__PURE__ */ jsxRuntime.jsx(lucideReactNative.XCircle, { size: 12, color: "#666" }),
369
- step.status === "pending" && !isCancelled && /* @__PURE__ */ jsxRuntime.jsx(AnimatedLoader, { size: 12, color: "#007AFF" }),
370
- step.status === "in_progress" && !isCurrentlyExecuting && /* @__PURE__ */ jsxRuntime.jsx(AnimatedLoader, { size: 12, color: "#007AFF" }),
371
- step.status === "completed" && /* @__PURE__ */ jsxRuntime.jsx(
372
- lucideReactNative.Check,
373
- {
374
- size: 12,
375
- color: step.eventType === "USER_ACTION_SUCCESS" ? "#16a34a" : "#007AFF"
376
- }
377
- ),
378
- step.status === "error" && /* @__PURE__ */ jsxRuntime.jsx(lucideReactNative.X, { size: 12, color: "#FF3B30" }),
379
- /* @__PURE__ */ jsxRuntime.jsxs(reactNative.View, { style: styles2.stepContent, children: [
380
- /* @__PURE__ */ jsxRuntime.jsx(
381
- reactNative.Text,
382
- {
383
- style: [
384
- styles2.stepText,
385
- step.status === "error" && styles2.stepTextError,
386
- step.eventType === "USER_ACTION_SUCCESS" && styles2.stepTextSuccess
387
- ],
388
- children: step.message
389
- }
390
- ),
391
- step.elapsedMs && /* @__PURE__ */ jsxRuntime.jsxs(reactNative.Text, { style: styles2.stepTime, children: [
392
- "(",
393
- (step.elapsedMs / 1e3).toFixed(1),
394
- "s)"
395
- ] })
396
- ] })
397
- ]
398
- },
399
- step.id
400
- );
401
- })
402
- }
403
- )
404
- ]
405
- }
406
- ),
407
- hasSteps && isStreaming && /* @__PURE__ */ jsxRuntime.jsxs(
408
- reactNative.View,
409
- {
410
- style: [
411
- styles2.stepsContainer,
412
- styles2.stepsContainerStreaming,
413
- layout === "centered" && styles2.stepsContainerCentered
414
- ],
415
- children: [
416
- /* @__PURE__ */ jsxRuntime.jsxs(
417
- reactNative.Pressable,
418
- {
419
- onPress: () => setIsStepsExpanded(!isStepsExpanded),
420
- style: styles2.stepsButton,
421
- children: [
422
- /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: styles2.stepsButtonText, children: getStreamingStepsText(!!isStepsExpanded) }),
423
- isStepsExpanded ? /* @__PURE__ */ jsxRuntime.jsx(lucideReactNative.ChevronUp, { size: 12, color: "#666" }) : /* @__PURE__ */ jsxRuntime.jsx(lucideReactNative.ChevronDown, { size: 12, color: "#666" })
424
- ]
425
- }
426
- ),
427
- isStepsExpanded && /* @__PURE__ */ jsxRuntime.jsx(
428
- Animated__default.default.View,
429
- {
430
- entering: animated ? Animated.FadeIn.duration(200) : void 0,
431
- exiting: animated ? Animated.FadeOut.duration(200) : void 0,
432
- style: styles2.stepsList,
433
- children: message.steps.map((step, index) => {
434
- const isCurrentlyExecuting = step.id === currentExecutingStepId && step.status === "in_progress" && isStreaming && !isCancelled;
435
- return /* @__PURE__ */ jsxRuntime.jsxs(
436
- Animated__default.default.View,
437
- {
438
- entering: animated ? Animated.FadeInUp.duration(300).delay(index * 50) : void 0,
439
- layout: animated ? Animated.Layout.springify() : void 0,
440
- style: styles2.stepItem,
441
- children: [
442
- isCurrentlyExecuting && /* @__PURE__ */ jsxRuntime.jsx(AnimatedLoader, { size: 12, color: "#007AFF" }),
443
- step.status === "pending" && isCancelled && /* @__PURE__ */ jsxRuntime.jsx(lucideReactNative.XCircle, { size: 12, color: "#666" }),
444
- step.status === "pending" && !isCancelled && /* @__PURE__ */ jsxRuntime.jsx(AnimatedLoader, { size: 12, color: "#007AFF" }),
445
- step.status === "in_progress" && !isCurrentlyExecuting && /* @__PURE__ */ jsxRuntime.jsx(AnimatedLoader, { size: 12, color: "#007AFF" }),
446
- step.status === "completed" && /* @__PURE__ */ jsxRuntime.jsx(
447
- lucideReactNative.Check,
448
- {
449
- size: 12,
450
- color: step.eventType === "USER_ACTION_SUCCESS" ? "#16a34a" : "#007AFF"
451
- }
452
- ),
453
- step.status === "error" && /* @__PURE__ */ jsxRuntime.jsx(lucideReactNative.X, { size: 12, color: "#FF3B30" }),
454
- /* @__PURE__ */ jsxRuntime.jsxs(reactNative.View, { style: styles2.stepContent, children: [
455
- /* @__PURE__ */ jsxRuntime.jsx(
456
- reactNative.Text,
457
- {
458
- style: [
459
- styles2.stepText,
460
- step.status === "error" && styles2.stepTextError,
461
- step.eventType === "USER_ACTION_SUCCESS" && styles2.stepTextSuccess
462
- ],
463
- children: step.message
464
- }
465
- ),
466
- step.elapsedMs && /* @__PURE__ */ jsxRuntime.jsxs(reactNative.Text, { style: styles2.stepTime, children: [
467
- "(",
468
- (step.elapsedMs / 1e3).toFixed(1),
469
- "s)"
470
- ] })
471
- ] })
472
- ]
473
- },
474
- step.id
475
- );
476
- })
477
- }
478
- )
479
- ]
480
- }
481
- )
482
- ]
483
- }
612
+ const activeThinkingText = message.activeThinkingText;
613
+ const allThinkingText = message.allThinkingText;
614
+ const currentStep = React.useMemo(
615
+ () => message.steps?.find(
616
+ (s9) => s9.id === currentExecutingStepId && s9.status === "in_progress"
484
617
  ),
485
- hasTraceData && onExecutionTraceClick && /* @__PURE__ */ jsxRuntime.jsx(
486
- reactNative.Pressable,
487
- {
488
- onPress: () => onExecutionTraceClick({
489
- message,
490
- tracingData: message.tracingData,
491
- executionId: message.executionId
492
- }),
493
- style: [
494
- styles2.traceButton,
495
- message.userActionResult ? styles2.traceButtonWithBadge : void 0
496
- ],
497
- children: /* @__PURE__ */ jsxRuntime.jsx(lucideReactNative.Binoculars, { size: 16, color: "#007AFF" })
618
+ [message.steps, currentExecutingStepId]
619
+ );
620
+ const getStepsLabel = React.useCallback(
621
+ (streaming) => {
622
+ const count = message.steps.length;
623
+ const stepWord = count === 1 ? "step" : "steps";
624
+ if (streaming) {
625
+ if (streamingStepsText)
626
+ return streamingStepsText.replace("{count}", count.toString());
627
+ return `${count} ${stepWord} in progress`;
628
+ }
629
+ if (completedStepsText) {
630
+ return completedStepsText.replace("{count}", count.toString()).replace("{time}", (totalElapsedMs / 1e3).toFixed(1));
498
631
  }
499
- )
632
+ return `${count} ${stepWord} completed`;
633
+ },
634
+ [message.steps, streamingStepsText, completedStepsText, totalElapsedMs]
635
+ );
636
+ const renderStepIcon = (step, isCurrentlyExecuting) => {
637
+ const W = s2.iconWrap;
638
+ if (isCurrentlyExecuting)
639
+ return /* @__PURE__ */ jsxRuntime.jsx(reactNative.View, { style: W, children: /* @__PURE__ */ jsxRuntime.jsx(AnimatedLoader, { size: 13, color: "#00858d" }) });
640
+ if (step.status === "pending" && isCancelled)
641
+ return /* @__PURE__ */ jsxRuntime.jsx(reactNative.View, { style: W, children: /* @__PURE__ */ jsxRuntime.jsx(reactNative.View, { style: s2.dotMuted }) });
642
+ if (step.status === "pending" || step.status === "in_progress")
643
+ return /* @__PURE__ */ jsxRuntime.jsx(reactNative.View, { style: W, children: /* @__PURE__ */ jsxRuntime.jsx(AnimatedLoader, { size: 13, color: "rgba(0,133,141,0.4)" }) });
644
+ if (step.status === "completed")
645
+ return /* @__PURE__ */ jsxRuntime.jsx(reactNative.View, { style: W, children: /* @__PURE__ */ jsxRuntime.jsx(
646
+ lucideReactNative.Check,
647
+ {
648
+ size: 13,
649
+ color: step.eventType === "USER_ACTION_SUCCESS" ? "#10B981" : "rgba(0,133,141,0.7)"
650
+ }
651
+ ) });
652
+ if (step.status === "error")
653
+ return /* @__PURE__ */ jsxRuntime.jsx(reactNative.View, { style: W, children: /* @__PURE__ */ jsxRuntime.jsx(lucideReactNative.X, { size: 13, color: "#EF4444" }) });
654
+ return /* @__PURE__ */ jsxRuntime.jsx(reactNative.View, { style: W, children: /* @__PURE__ */ jsxRuntime.jsx(reactNative.View, { style: s2.dotMuted }) });
655
+ };
656
+ const showSteps = showExecutionSteps && hasSteps && !isStreaming && !isError;
657
+ const handleStepsToggle = React.useCallback(() => {
658
+ setIsStepsExpanded((prev) => !prev);
659
+ }, []);
660
+ const AnimatedView = animated ? Animated2__default.default.View : reactNative.View;
661
+ const animatedProps = animated ? { entering: Animated2.FadeInDown.duration(200), layout: Animated2.Layout } : {};
662
+ const messageContent = /* @__PURE__ */ jsxRuntime.jsxs(reactNative.View, { style: s2.outerWrap, children: [
663
+ /* @__PURE__ */ jsxRuntime.jsxs(reactNative.View, { style: s2.row, children: [
664
+ showAvatar && /* @__PURE__ */ jsxRuntime.jsx(reactNative.View, { style: s2.avatarWrap, children: isStreaming && showStreamingDot ? /* @__PURE__ */ jsxRuntime.jsx(reactNative.View, { style: s2.dotContainer, children: /* @__PURE__ */ jsxRuntime.jsx(reactNative.View, { style: s2.streamDot }) }) : /* @__PURE__ */ jsxRuntime.jsx(reactNative.View, { style: s2.avatar, children: /* @__PURE__ */ jsxRuntime.jsx(lucideReactNative.Sparkles, { size: 14, color: "#9CA3AF" }) }) }),
665
+ /* @__PURE__ */ jsxRuntime.jsxs(
666
+ reactNative.View,
667
+ {
668
+ style: [s2.bubbleCol, layout === "centered" && s2.bubbleColCentered],
669
+ children: [
670
+ message.userActionResult && /* @__PURE__ */ jsxRuntime.jsx(reactNative.View, { style: s2.badgeWrap, children: message.userActionResult === "approved" ? /* @__PURE__ */ jsxRuntime.jsxs(reactNative.View, { style: [s2.badge, s2.badgeApproved], children: [
671
+ /* @__PURE__ */ jsxRuntime.jsx(lucideReactNative.Check, { size: 10, color: "#15803D" }),
672
+ /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: s2.badgeApprovedText, children: "Verified" })
673
+ ] }) : /* @__PURE__ */ jsxRuntime.jsxs(reactNative.View, { style: [s2.badge, s2.badgeRejected], children: [
674
+ /* @__PURE__ */ jsxRuntime.jsx(lucideReactNative.X, { size: 10, color: "#B91C1C" }),
675
+ /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: s2.badgeRejectedText, children: "Rejected" })
676
+ ] }) }),
677
+ /* @__PURE__ */ jsxRuntime.jsxs(
678
+ reactNative.View,
679
+ {
680
+ style: [
681
+ s2.bubble,
682
+ layout === "centered" ? s2.bubbleCentered : s2.bubbleDefault,
683
+ isError && s2.bubbleError
684
+ ],
685
+ children: [
686
+ showAgentName && (isStreaming && !content ? /* @__PURE__ */ jsxRuntime.jsx(ThoughtProcessLabel, { style: s2.agentName }) : /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: s2.agentName, children: agentName })),
687
+ /* @__PURE__ */ jsxRuntime.jsx(reactNative.View, { children: isStreaming && !content ? (
688
+ // One active item at a time, by event order: thinking stream OR current step with loading (same bullet UI as dropdown)
689
+ activeThinkingText ? /* @__PURE__ */ jsxRuntime.jsxs(reactNative.View, { style: s2.stepRow, children: [
690
+ /* @__PURE__ */ jsxRuntime.jsx(reactNative.View, { style: { marginTop: 1 }, children: /* @__PURE__ */ jsxRuntime.jsx(reactNative.View, { style: s2.iconWrap, children: /* @__PURE__ */ jsxRuntime.jsx(AnimatedLoader, { size: 13, color: "rgba(0,133,141,0.7)" }) }) }),
691
+ /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: [s2.bubbleBodyText, s2.thinkingTextFlex], children: activeThinkingText })
692
+ ] }) : currentStep ? /* @__PURE__ */ jsxRuntime.jsxs(reactNative.View, { style: s2.stepRow, children: [
693
+ /* @__PURE__ */ jsxRuntime.jsx(reactNative.View, { style: { marginTop: 1 }, children: renderStepIcon(currentStep, true) }),
694
+ /* @__PURE__ */ jsxRuntime.jsx(ShimmerText, { style: s2.bubbleBodyText, children: currentStep.message })
695
+ ] }) : /* @__PURE__ */ jsxRuntime.jsxs(reactNative.View, { style: s2.thinkingRow, children: [
696
+ !showAvatar && /* @__PURE__ */ jsxRuntime.jsx(AnimatedLoader, { size: 15, color: "rgba(0,133,141,0.7)" }),
697
+ /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: s2.bubbleBodyText, children: currentMessage || "Thinking..." })
698
+ ] })
699
+ ) : isCancelled && !content ? /* @__PURE__ */ jsxRuntime.jsxs(reactNative.View, { style: s2.thinkingRow, children: [
700
+ /* @__PURE__ */ jsxRuntime.jsx(lucideReactNative.X, { size: 15, color: "#9CA3AF" }),
701
+ /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: [s2.bubbleBodyText, { fontStyle: "italic" }], children: currentMessage || "Request was stopped." })
702
+ ] }) : /* @__PURE__ */ jsxRuntime.jsx(
703
+ Markdown__default.default,
704
+ {
705
+ style: isError ? markdownErrorStyles : markdownStyles,
706
+ children: content || (isStreaming ? "Thinking..." : isCancelled ? "Request was stopped." : isError ? "Something went wrong. Please try again." : "")
707
+ }
708
+ ) })
709
+ ]
710
+ }
711
+ )
712
+ ]
713
+ }
714
+ ),
715
+ hasTraceData && onExecutionTraceClick && /* @__PURE__ */ jsxRuntime.jsx(
716
+ reactNative.Pressable,
717
+ {
718
+ onPress: () => onExecutionTraceClick({
719
+ message,
720
+ tracingData: message.tracingData,
721
+ executionId: message.executionId
722
+ }),
723
+ style: [s2.traceBtn, message.userActionResult && s2.traceBtnOffset],
724
+ children: /* @__PURE__ */ jsxRuntime.jsx(lucideReactNative.Binoculars, { size: 15, color: "#9CA3AF" })
725
+ }
726
+ )
727
+ ] }),
728
+ showSteps && /* @__PURE__ */ jsxRuntime.jsxs(reactNative.View, { style: [s2.stepsOuter, showAvatar && s2.stepsIndented], children: [
729
+ /* @__PURE__ */ jsxRuntime.jsxs(reactNative.Pressable, { onPress: handleStepsToggle, style: s2.stepsToggle, children: [
730
+ /* @__PURE__ */ jsxRuntime.jsx(
731
+ reactNative.View,
732
+ {
733
+ style: {
734
+ transform: [{ rotate: isStepsExpanded ? "90deg" : "0deg" }]
735
+ },
736
+ children: /* @__PURE__ */ jsxRuntime.jsx(lucideReactNative.ChevronRight, { size: 12, color: "rgba(156,163,175,0.6)" })
737
+ }
738
+ ),
739
+ /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: s2.stepsToggleText, children: getStepsLabel(false) })
740
+ ] }),
741
+ isStepsExpanded && hasSteps && /* @__PURE__ */ jsxRuntime.jsxs(
742
+ Animated2__default.default.View,
743
+ {
744
+ entering: animated ? Animated2.FadeIn.duration(200) : void 0,
745
+ exiting: animated ? Animated2.FadeOut.duration(150) : void 0,
746
+ children: [
747
+ !isStreaming && allThinkingText?.trim() ? /* @__PURE__ */ jsxRuntime.jsx(ThinkingBlock, { text: allThinkingText }) : null,
748
+ /* @__PURE__ */ jsxRuntime.jsx(reactNative.View, { style: s2.stepsList, children: message.steps.map((step) => {
749
+ const isExec = step.id === currentExecutingStepId && step.status === "in_progress" && isStreaming && !isCancelled;
750
+ const hasTime = step.elapsedMs != null && step.elapsedMs > 0;
751
+ return /* @__PURE__ */ jsxRuntime.jsxs(reactNative.View, { style: s2.stepItem, children: [
752
+ /* @__PURE__ */ jsxRuntime.jsxs(reactNative.View, { style: s2.stepRow, children: [
753
+ /* @__PURE__ */ jsxRuntime.jsx(reactNative.View, { style: { marginTop: 1 }, children: renderStepIcon(step, isExec) }),
754
+ isExec ? /* @__PURE__ */ jsxRuntime.jsx(ShimmerText, { style: s2.stepText, children: step.message }) : /* @__PURE__ */ jsxRuntime.jsx(
755
+ reactNative.Text,
756
+ {
757
+ style: [
758
+ s2.stepText,
759
+ step.status === "completed" && s2.stepTextMuted,
760
+ step.status === "error" && s2.stepTextError,
761
+ step.eventType === "USER_ACTION_SUCCESS" && s2.stepTextSuccess,
762
+ step.status === "pending" && s2.stepTextPending,
763
+ step.status === "in_progress" && !isExec && s2.stepTextInProgress
764
+ ],
765
+ children: step.message
766
+ }
767
+ )
768
+ ] }),
769
+ hasTime && /* @__PURE__ */ jsxRuntime.jsx(reactNative.View, { style: s2.timeBadgeWrap, children: /* @__PURE__ */ jsxRuntime.jsxs(reactNative.View, { style: s2.timeBadge, children: [
770
+ /* @__PURE__ */ jsxRuntime.jsx(lucideReactNative.Clock, { size: 8, color: "rgba(156,163,175,0.6)" }),
771
+ /* @__PURE__ */ jsxRuntime.jsxs(reactNative.Text, { style: s2.timeBadgeText, children: [
772
+ (step.elapsedMs / 1e3).toFixed(1),
773
+ "s"
774
+ ] })
775
+ ] }) })
776
+ ] }, step.id);
777
+ }) })
778
+ ]
779
+ }
780
+ )
781
+ ] })
500
782
  ] });
501
783
  return /* @__PURE__ */ jsxRuntime.jsx(AnimatedView, { ...animatedProps, children: messageContent });
502
784
  }
503
- var styles2 = reactNative.StyleSheet.create({
504
- container: {
785
+ var s2 = reactNative.StyleSheet.create({
786
+ outerWrap: { width: "100%" },
787
+ row: {
505
788
  flexDirection: "row",
506
- justifyContent: "flex-start",
507
789
  alignItems: "flex-start",
508
- width: "100%",
509
- gap: 16
510
- },
511
- avatarContainer: {
512
- width: 32,
513
- height: 32,
514
- marginTop: 2
790
+ gap: 10,
791
+ width: "100%"
515
792
  },
793
+ // Avatar
794
+ avatarWrap: { width: 28, height: 28, marginTop: 2 },
516
795
  dotContainer: {
517
- width: 32,
518
- height: 32,
796
+ width: 28,
797
+ height: 28,
519
798
  justifyContent: "center",
520
799
  alignItems: "center"
521
800
  },
522
- dot: {
801
+ streamDot: {
523
802
  width: 8,
524
803
  height: 8,
525
804
  borderRadius: 4,
526
- backgroundColor: "#007AFF"
527
- },
528
- dotPulse: {
805
+ backgroundColor: "#00858d",
529
806
  opacity: 0.75
530
807
  },
531
808
  avatar: {
532
- width: 32,
533
- height: 32,
534
- borderRadius: 16,
535
- backgroundColor: "#F5F5F5",
809
+ width: 28,
810
+ height: 28,
811
+ borderRadius: 14,
812
+ backgroundColor: "rgba(0,0,0,0.03)",
813
+ borderWidth: reactNative.StyleSheet.hairlineWidth,
814
+ borderColor: "rgba(0,0,0,0.08)",
536
815
  justifyContent: "center",
537
816
  alignItems: "center"
538
817
  },
539
- messageContainer: {
540
- minWidth: 0,
541
- flex: 1,
542
- maxWidth: "80%"
818
+ // Bubble column
819
+ bubbleCol: { minWidth: 0, maxWidth: "80%", flexShrink: 1 },
820
+ bubbleColCentered: { maxWidth: "85%" },
821
+ // Badge
822
+ badgeWrap: { marginBottom: 6 },
823
+ badge: {
824
+ flexDirection: "row",
825
+ alignItems: "center",
826
+ gap: 4,
827
+ paddingHorizontal: 8,
828
+ paddingVertical: 3,
829
+ borderRadius: 10,
830
+ alignSelf: "flex-start"
543
831
  },
544
- messageContainerCentered: {
545
- maxWidth: "85%"
832
+ badgeApproved: {
833
+ backgroundColor: "#DCFCE7",
834
+ borderWidth: reactNative.StyleSheet.hairlineWidth,
835
+ borderColor: "rgba(34,197,94,0.3)"
836
+ },
837
+ badgeApprovedText: { fontSize: 14, lineHeight: 21, fontWeight: "500", color: "#15803D" },
838
+ badgeRejected: {
839
+ backgroundColor: "#FEE2E2",
840
+ borderWidth: reactNative.StyleSheet.hairlineWidth,
841
+ borderColor: "rgba(239,68,68,0.3)"
546
842
  },
843
+ badgeRejectedText: { fontSize: 14, lineHeight: 21, fontWeight: "500", color: "#B91C1C" },
844
+ // Bubble
547
845
  bubble: {
548
846
  overflow: "hidden",
549
847
  width: "100%",
550
- padding: 12,
551
- backgroundColor: "#F5F5F5",
552
- borderRadius: 8
848
+ paddingHorizontal: 14,
849
+ paddingVertical: 10
850
+ },
851
+ bubbleDefault: {
852
+ backgroundColor: "rgba(0,0,0,0.04)",
853
+ borderRadius: 16,
854
+ borderTopLeftRadius: 4
553
855
  },
554
856
  bubbleCentered: {
555
857
  backgroundColor: "#FFFFFF",
556
858
  borderWidth: 1,
557
- borderColor: "#E5E5E5",
859
+ borderColor: "rgba(0,0,0,0.08)",
558
860
  borderRadius: 16,
559
861
  borderTopLeftRadius: 4
560
862
  },
561
- bubbleWithSteps: {
562
- borderBottomLeftRadius: 0,
563
- borderBottomRightRadius: 0
564
- },
565
- bubbleStreaming: {
566
- borderColor: "#D1D5DB"
567
- },
568
863
  bubbleError: {
569
- backgroundColor: "#FEE",
570
- borderColor: "#FCC"
864
+ backgroundColor: "rgba(239,68,68,0.05)",
865
+ borderWidth: 1,
866
+ borderColor: "rgba(239,68,68,0.15)"
571
867
  },
868
+ // Agent name (text-sm to match query)
572
869
  agentName: {
573
- fontSize: 12,
574
- fontWeight: "600",
575
- opacity: 0.6,
576
- marginBottom: 6
577
- },
578
- contentContainer: {
579
870
  fontSize: 14,
580
- lineHeight: 22
581
- },
582
- thinkingContainer: {
583
- flexDirection: "row",
584
- alignItems: "center",
585
- gap: 12
871
+ lineHeight: 21,
872
+ fontWeight: "600",
873
+ color: "rgba(0,0,0,0.35)",
874
+ marginBottom: 2
586
875
  },
587
- thinkingText: {
876
+ // All body text inside assistant bubble: same size as query (text-sm = 14px)
877
+ bubbleBodyText: {
588
878
  fontSize: 14,
589
- color: "#666"
590
- },
591
- stepsContainer: {
592
- overflow: "hidden",
593
- backgroundColor: "#F5F5F5",
594
- borderTopWidth: 1,
595
- borderTopColor: "rgba(0,0,0,0.1)",
596
- borderBottomLeftRadius: 8,
597
- borderBottomRightRadius: 8
598
- },
599
- stepsContainerCentered: {
600
- backgroundColor: "#FFFFFF",
601
- borderWidth: 1,
602
- borderTopWidth: 0,
603
- borderColor: "#E5E5E5",
604
- borderBottomLeftRadius: 16,
605
- borderBottomRightRadius: 16
879
+ lineHeight: 21,
880
+ color: "#9CA3AF",
881
+ flex: 1,
882
+ minWidth: 0
606
883
  },
607
- stepsContainerStreaming: {
608
- borderTopColor: "#D1D5DB"
884
+ // Thinking state
885
+ thinkingRow: { flexDirection: "row", alignItems: "center", gap: 8 },
886
+ thinkingText: { fontSize: 14, lineHeight: 21, color: "#9CA3AF" },
887
+ thinkingTextFlex: { flex: 1, minWidth: 0 },
888
+ // Trace button
889
+ traceBtn: {
890
+ padding: 7,
891
+ backgroundColor: "rgba(0,0,0,0.02)",
892
+ borderWidth: reactNative.StyleSheet.hairlineWidth,
893
+ borderColor: "rgba(0,0,0,0.08)",
894
+ borderRadius: 8,
895
+ marginTop: 2
609
896
  },
610
- stepsButton: {
611
- width: "100%",
612
- paddingHorizontal: 16,
613
- paddingVertical: 8,
614
- flexDirection: "row",
615
- justifyContent: "space-between",
897
+ traceBtnOffset: { marginTop: 30 },
898
+ // Steps section
899
+ stepsOuter: { marginTop: 6 },
900
+ stepsIndented: { marginLeft: 38 },
901
+ // 28 avatar + 10 gap
902
+ // Toggle
903
+ stepsToggle: { flexDirection: "row", alignItems: "center", gap: 5 },
904
+ stepsToggleText: { fontSize: 11, color: "rgba(156,163,175,0.65)" },
905
+ // Steps list
906
+ stepsList: { marginTop: 6 },
907
+ stepItem: { marginBottom: 6 },
908
+ stepRow: { flexDirection: "row", alignItems: "flex-start", gap: 5 },
909
+ iconWrap: {
910
+ width: 16,
911
+ height: 16,
912
+ justifyContent: "center",
616
913
  alignItems: "center"
617
914
  },
618
- stepsButtonText: {
619
- fontSize: 12,
620
- color: "#666"
621
- },
622
- stepsList: {
623
- paddingHorizontal: 16,
624
- paddingBottom: 12,
625
- paddingTop: 8,
626
- gap: 8,
627
- backgroundColor: "rgba(0,0,0,0.02)"
628
- },
629
- stepItem: {
630
- flexDirection: "row",
631
- alignItems: "flex-start",
632
- gap: 8
633
- },
634
- stepContent: {
635
- flex: 1,
636
- minWidth: 0
915
+ dotMuted: {
916
+ width: 5,
917
+ height: 5,
918
+ borderRadius: 3,
919
+ backgroundColor: "rgba(0,0,0,0.12)"
637
920
  },
638
921
  stepText: {
639
922
  fontSize: 12,
640
- color: "#666",
641
- flexWrap: "wrap"
642
- },
643
- stepTextError: {
644
- color: "#FF3B30"
645
- },
646
- stepTextSuccess: {
647
- color: "#16a34a"
648
- },
649
- stepTime: {
650
- fontSize: 10,
651
- opacity: 0.5,
652
- marginLeft: 6
653
- },
654
- traceButton: {
655
- marginTop: 2,
656
- padding: 8,
657
- backgroundColor: "rgba(255,255,255,0.05)",
658
- borderWidth: 1,
659
- borderColor: "rgba(255,255,255,0.2)",
660
- borderRadius: 8
661
- },
662
- traceButtonWithBadge: {
663
- marginTop: 32
664
- },
665
- badgeContainer: {
666
- marginBottom: 8
667
- },
668
- badge: {
923
+ lineHeight: 17,
924
+ flex: 1,
925
+ minWidth: 0,
926
+ color: "#374151"
927
+ },
928
+ stepTextMuted: { color: "#9CA3AF" },
929
+ stepTextError: { color: "#EF4444" },
930
+ stepTextSuccess: { color: "#10B981" },
931
+ stepTextPending: { color: "rgba(156,163,175,0.4)" },
932
+ stepTextInProgress: { color: "rgba(156,163,175,0.6)" },
933
+ // Time badge — aligned with text (pl = 16 icon + 5 gap = 21)
934
+ timeBadgeWrap: { paddingLeft: 21, marginTop: 3 },
935
+ timeBadge: {
669
936
  flexDirection: "row",
670
937
  alignItems: "center",
671
- gap: 4,
672
- paddingHorizontal: 8,
673
- paddingVertical: 4,
674
- borderRadius: 12,
938
+ gap: 3,
939
+ backgroundColor: "rgba(0,0,0,0.03)",
940
+ borderWidth: reactNative.StyleSheet.hairlineWidth,
941
+ borderColor: "rgba(0,0,0,0.06)",
942
+ borderRadius: 4,
943
+ paddingHorizontal: 5,
944
+ paddingVertical: 2,
675
945
  alignSelf: "flex-start"
676
946
  },
677
- badgeApproved: {
678
- backgroundColor: "#dcfce7"
679
- },
680
- badgeApprovedText: {
681
- fontSize: 12,
682
- fontWeight: "500",
683
- color: "#15803d"
947
+ timeBadgeText: {
948
+ fontSize: 9,
949
+ fontFamily: "monospace",
950
+ color: "rgba(156,163,175,0.6)"
951
+ }
952
+ });
953
+ var ts = reactNative.StyleSheet.create({
954
+ thinkingWrap: { marginTop: 4, marginBottom: 4 },
955
+ thinkingToggle: {
956
+ flexDirection: "row",
957
+ alignItems: "center",
958
+ gap: 3
684
959
  },
685
- badgeRejected: {
686
- backgroundColor: "#fee2e2"
960
+ thinkingToggleText: {
961
+ fontSize: 10,
962
+ color: "rgba(156,163,175,0.5)"
687
963
  },
688
- badgeRejectedText: {
689
- fontSize: 12,
690
- fontWeight: "500",
691
- color: "#b91c1c"
964
+ thinkingContent: {
965
+ marginTop: 4,
966
+ backgroundColor: "rgba(0,0,0,0.03)",
967
+ borderRadius: 6,
968
+ padding: 8
969
+ },
970
+ thinkingContentText: {
971
+ fontSize: 11,
972
+ lineHeight: 16,
973
+ color: "rgba(107,114,128,0.8)"
692
974
  }
693
975
  });
694
976
  var markdownStyles = {
695
- body: {
696
- fontSize: 14,
697
- lineHeight: 22,
698
- color: "#000"
699
- },
700
- paragraph: {
701
- marginBottom: 12,
702
- fontSize: 14,
703
- lineHeight: 22
704
- },
705
- strong: {
706
- fontWeight: "600"
707
- },
708
- em: {
709
- fontStyle: "italic"
710
- },
977
+ body: { fontSize: 14, lineHeight: 21, color: "#1F2937" },
978
+ paragraph: { marginBottom: 8, fontSize: 14, lineHeight: 21 },
979
+ strong: { fontWeight: "600" },
980
+ em: { fontStyle: "italic" },
711
981
  code_inline: {
712
- backgroundColor: "#F5F5F5",
713
- paddingHorizontal: 6,
982
+ backgroundColor: "rgba(0,0,0,0.04)",
983
+ paddingHorizontal: 5,
714
984
  paddingVertical: 2,
715
985
  borderRadius: 4,
716
986
  fontSize: 12,
717
987
  fontFamily: "monospace"
718
988
  },
719
989
  code_block: {
720
- backgroundColor: "#F5F5F5",
990
+ backgroundColor: "rgba(0,0,0,0.04)",
721
991
  padding: 12,
722
992
  borderRadius: 8,
723
993
  fontSize: 12,
724
994
  fontFamily: "monospace",
725
995
  marginVertical: 8
726
996
  },
727
- list_item: {
728
- fontSize: 14,
729
- lineHeight: 22
997
+ list_item: { fontSize: 14, lineHeight: 21 },
998
+ bullet_list: { marginBottom: 8 },
999
+ ordered_list: { marginBottom: 8 },
1000
+ heading1: {
1001
+ fontSize: 18,
1002
+ fontWeight: "600",
1003
+ marginBottom: 6,
1004
+ marginTop: 12,
1005
+ color: "#1F2937"
730
1006
  },
731
- bullet_list: {
732
- marginBottom: 12
1007
+ heading2: {
1008
+ fontSize: 16,
1009
+ fontWeight: "600",
1010
+ marginBottom: 6,
1011
+ marginTop: 10,
1012
+ color: "#1F2937"
733
1013
  },
734
- ordered_list: {
735
- marginBottom: 12
736
- }
1014
+ heading3: {
1015
+ fontSize: 14,
1016
+ fontWeight: "600",
1017
+ marginBottom: 4,
1018
+ marginTop: 8,
1019
+ color: "#1F2937"
1020
+ },
1021
+ blockquote: {
1022
+ borderLeftWidth: 3,
1023
+ borderLeftColor: "rgba(0,0,0,0.1)",
1024
+ paddingLeft: 12,
1025
+ marginVertical: 8,
1026
+ fontStyle: "italic",
1027
+ color: "#6B7280"
1028
+ },
1029
+ hr: {
1030
+ marginVertical: 16,
1031
+ borderBottomWidth: reactNative.StyleSheet.hairlineWidth,
1032
+ borderBottomColor: "rgba(0,0,0,0.1)"
1033
+ },
1034
+ link: { color: "#007AFF", textDecorationLine: "underline" }
737
1035
  };
738
1036
  var markdownErrorStyles = {
739
1037
  ...markdownStyles,
740
- body: {
741
- ...markdownStyles.body,
742
- color: "#FF3B30"
743
- },
744
- paragraph: {
745
- ...markdownStyles.paragraph,
746
- color: "#FF3B30"
747
- }
1038
+ body: { ...markdownStyles.body, color: "#EF4444" },
1039
+ paragraph: { ...markdownStyles.paragraph, color: "#EF4444" }
748
1040
  };
749
1041
  function cn(...inputs) {
750
1042
  return tailwindMerge.twMerge(clsx.clsx(inputs));
@@ -781,54 +1073,44 @@ function UserMessage({
781
1073
  animated = false,
782
1074
  showAvatar = false
783
1075
  }) {
784
- const AnimatedView = animated ? Animated__default.default.View : reactNative.View;
785
- const animatedProps = animated ? { entering: Animated.FadeInDown.duration(300) } : {};
786
- return /* @__PURE__ */ jsxRuntime.jsx(AnimatedView, { ...animatedProps, children: /* @__PURE__ */ jsxRuntime.jsxs(reactNative.View, { style: styles3.container, children: [
787
- /* @__PURE__ */ jsxRuntime.jsxs(reactNative.View, { style: styles3.messageContainer, children: [
788
- /* @__PURE__ */ jsxRuntime.jsx(reactNative.View, { style: styles3.bubble, children: /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: styles3.text, children: message.content }) }),
789
- /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: styles3.timestamp, children: formatDate(message.timestamp) })
1076
+ const AnimatedView = animated ? Animated2__default.default.View : reactNative.View;
1077
+ const animatedProps = animated ? { entering: Animated2.FadeInDown.duration(250) } : {};
1078
+ return /* @__PURE__ */ jsxRuntime.jsx(AnimatedView, { ...animatedProps, children: /* @__PURE__ */ jsxRuntime.jsxs(reactNative.View, { style: s3.container, children: [
1079
+ /* @__PURE__ */ jsxRuntime.jsxs(reactNative.View, { style: s3.messageCol, children: [
1080
+ /* @__PURE__ */ jsxRuntime.jsx(reactNative.View, { style: s3.bubble, children: /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: s3.text, children: message.content }) }),
1081
+ /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: s3.timestamp, children: formatDate(message.timestamp) })
790
1082
  ] }),
791
- showAvatar && /* @__PURE__ */ jsxRuntime.jsx(reactNative.View, { style: styles3.avatarContainer, children: /* @__PURE__ */ jsxRuntime.jsx(reactNative.View, { style: styles3.avatar, children: /* @__PURE__ */ jsxRuntime.jsx(lucideReactNative.User, { size: 16, color: "#007AFF" }) }) })
1083
+ showAvatar && /* @__PURE__ */ jsxRuntime.jsx(reactNative.View, { style: s3.avatarWrap, children: /* @__PURE__ */ jsxRuntime.jsx(reactNative.View, { style: s3.avatar, children: /* @__PURE__ */ jsxRuntime.jsx(lucideReactNative.User, { size: 13, color: "#FFFFFF" }) }) })
792
1084
  ] }) });
793
1085
  }
794
- var styles3 = reactNative.StyleSheet.create({
1086
+ var s3 = reactNative.StyleSheet.create({
795
1087
  container: {
796
1088
  flexDirection: "row",
797
1089
  justifyContent: "flex-end",
798
1090
  width: "100%",
799
- gap: 16
1091
+ gap: 10
800
1092
  },
801
- messageContainer: {
802
- maxWidth: "85%",
1093
+ messageCol: {
1094
+ maxWidth: "80%",
803
1095
  minWidth: 0,
804
1096
  flexDirection: "column",
805
1097
  alignItems: "flex-end"
806
1098
  },
807
- bubble: {
808
- borderRadius: 8,
809
- padding: 12,
810
- backgroundColor: "#007AFF"
811
- },
812
- text: {
813
- fontSize: 14,
814
- color: "#FFFFFF",
815
- lineHeight: 20
816
- },
817
- timestamp: {
818
- fontSize: 10,
819
- marginTop: 4,
820
- color: "#666"
821
- },
822
- avatarContainer: {
823
- width: 32,
824
- height: 32,
825
- marginTop: 2
826
- },
827
- avatar: {
828
- width: 32,
829
- height: 32,
1099
+ bubble: {
830
1100
  borderRadius: 16,
831
- backgroundColor: "rgba(0, 122, 255, 0.1)",
1101
+ borderBottomRightRadius: 4,
1102
+ paddingHorizontal: 14,
1103
+ paddingVertical: 10,
1104
+ backgroundColor: "#00858d"
1105
+ },
1106
+ text: { fontSize: 14, color: "#FFFFFF", lineHeight: 20 },
1107
+ timestamp: { fontSize: 10, marginTop: 3, color: "rgba(0,0,0,0.25)" },
1108
+ avatarWrap: { width: 28, height: 28, marginTop: 2 },
1109
+ avatar: {
1110
+ width: 28,
1111
+ height: 28,
1112
+ borderRadius: 14,
1113
+ backgroundColor: "#00858d",
832
1114
  justifyContent: "center",
833
1115
  alignItems: "center"
834
1116
  }
@@ -880,98 +1162,62 @@ function MessageRow({
880
1162
  function MessageRowSkeleton({
881
1163
  isRightAligned = false
882
1164
  }) {
883
- const opacity = Animated.useSharedValue(0.3);
884
- React4.useEffect(() => {
885
- opacity.value = Animated.withRepeat(
886
- Animated.withTiming(1, { duration: 1e3 }),
887
- -1,
888
- true
889
- );
1165
+ const opacity = Animated2.useSharedValue(0.3);
1166
+ React.useEffect(() => {
1167
+ opacity.value = Animated2.withRepeat(Animated2.withTiming(0.8, { duration: 1200 }), -1, true);
890
1168
  }, []);
891
- const animatedStyle = Animated.useAnimatedStyle(() => ({
892
- opacity: opacity.value
893
- }));
1169
+ const animatedStyle = Animated2.useAnimatedStyle(() => ({ opacity: opacity.value }));
894
1170
  return /* @__PURE__ */ jsxRuntime.jsx(
895
1171
  reactNative.View,
896
1172
  {
897
- style: [
898
- styles4.container,
899
- isRightAligned ? styles4.containerRight : styles4.containerLeft
900
- ],
1173
+ style: [s4.container, isRightAligned ? s4.containerRight : s4.containerLeft],
901
1174
  children: /* @__PURE__ */ jsxRuntime.jsxs(
902
1175
  reactNative.View,
903
1176
  {
904
- style: [
905
- styles4.content,
906
- isRightAligned ? styles4.contentRight : styles4.contentLeft
907
- ],
1177
+ style: [s4.content, isRightAligned ? s4.contentRight : s4.contentLeft],
908
1178
  children: [
909
1179
  /* @__PURE__ */ jsxRuntime.jsx(
910
- reactNative.View,
1180
+ Animated2__default.default.View,
911
1181
  {
912
1182
  style: [
913
- styles4.bubble,
914
- isRightAligned ? styles4.bubbleRight : styles4.bubbleLeft
1183
+ s4.bubble,
1184
+ isRightAligned ? s4.bubbleRight : s4.bubbleLeft,
1185
+ animatedStyle
915
1186
  ],
916
- children: /* @__PURE__ */ jsxRuntime.jsx(Animated__default.default.View, { style: animatedStyle, children: /* @__PURE__ */ jsxRuntime.jsxs(reactNative.View, { style: styles4.skeletonContainer, children: [
917
- /* @__PURE__ */ jsxRuntime.jsx(reactNative.View, { style: [styles4.skeletonLine, { width: "75%" }] }),
918
- /* @__PURE__ */ jsxRuntime.jsx(reactNative.View, { style: [styles4.skeletonLine, { width: "100%" }] }),
919
- /* @__PURE__ */ jsxRuntime.jsx(reactNative.View, { style: [styles4.skeletonLine, { width: "85%" }] })
920
- ] }) })
1187
+ children: /* @__PURE__ */ jsxRuntime.jsxs(reactNative.View, { style: s4.skeletonWrap, children: [
1188
+ /* @__PURE__ */ jsxRuntime.jsx(reactNative.View, { style: [s4.line, { width: "70%" }] }),
1189
+ /* @__PURE__ */ jsxRuntime.jsx(reactNative.View, { style: [s4.line, { width: "100%" }] }),
1190
+ /* @__PURE__ */ jsxRuntime.jsx(reactNative.View, { style: [s4.line, { width: "80%" }] })
1191
+ ] })
921
1192
  }
922
1193
  ),
923
- /* @__PURE__ */ jsxRuntime.jsx(Animated__default.default.View, { style: [styles4.timestamp, animatedStyle] })
1194
+ /* @__PURE__ */ jsxRuntime.jsx(Animated2__default.default.View, { style: [s4.timestamp, animatedStyle] })
924
1195
  ]
925
1196
  }
926
1197
  )
927
1198
  }
928
1199
  );
929
1200
  }
930
- var styles4 = reactNative.StyleSheet.create({
931
- container: {
932
- flexDirection: "row",
933
- width: "100%"
934
- },
935
- containerLeft: {
936
- justifyContent: "flex-start"
937
- },
938
- containerRight: {
939
- justifyContent: "flex-end"
940
- },
941
- content: {
942
- maxWidth: "80%",
943
- width: "100%"
944
- },
945
- contentLeft: {
946
- alignItems: "flex-start"
947
- },
948
- contentRight: {
949
- alignItems: "flex-end"
950
- },
951
- bubble: {
952
- borderRadius: 8,
953
- padding: 12,
954
- width: "100%"
955
- },
956
- bubbleLeft: {
957
- backgroundColor: "#F5F5F5"
958
- },
1201
+ var s4 = reactNative.StyleSheet.create({
1202
+ container: { flexDirection: "row", width: "100%" },
1203
+ containerLeft: { justifyContent: "flex-start" },
1204
+ containerRight: { justifyContent: "flex-end" },
1205
+ content: { maxWidth: "75%", width: "100%" },
1206
+ contentLeft: { alignItems: "flex-start" },
1207
+ contentRight: { alignItems: "flex-end" },
1208
+ bubble: { borderRadius: 16, padding: 14, width: "100%" },
1209
+ bubbleLeft: { backgroundColor: "rgba(0,0,0,0.04)", borderTopLeftRadius: 4 },
959
1210
  bubbleRight: {
960
- backgroundColor: "rgba(0, 122, 255, 0.2)"
961
- },
962
- skeletonContainer: {
963
- gap: 8
964
- },
965
- skeletonLine: {
966
- height: 12,
967
- backgroundColor: "rgba(0, 0, 0, 0.2)",
968
- borderRadius: 4
1211
+ backgroundColor: "rgba(0,122,255,0.08)",
1212
+ borderBottomRightRadius: 4
969
1213
  },
1214
+ skeletonWrap: { gap: 8 },
1215
+ line: { height: 10, backgroundColor: "rgba(0,0,0,0.08)", borderRadius: 5 },
970
1216
  timestamp: {
971
- height: 8,
972
- width: 64,
973
- backgroundColor: "rgba(0, 0, 0, 0.2)",
974
- borderRadius: 4,
1217
+ height: 6,
1218
+ width: 50,
1219
+ backgroundColor: "rgba(0,0,0,0.06)",
1220
+ borderRadius: 3,
975
1221
  marginTop: 4
976
1222
  }
977
1223
  });
@@ -996,8 +1242,8 @@ function MessageList({
996
1242
  onExecutionTraceClick,
997
1243
  className
998
1244
  }) {
999
- const flatListRef = React4.useRef(null);
1000
- React4.useEffect(() => {
1245
+ const flatListRef = React.useRef(null);
1246
+ React.useEffect(() => {
1001
1247
  if (messages.length > 0) {
1002
1248
  setTimeout(() => {
1003
1249
  flatListRef.current?.scrollToEnd({ animated: true });
@@ -1005,7 +1251,7 @@ function MessageList({
1005
1251
  }
1006
1252
  }, [messages.length]);
1007
1253
  if (isLoading) {
1008
- return /* @__PURE__ */ jsxRuntime.jsx(reactNative.View, { style: styles5.container, children: /* @__PURE__ */ jsxRuntime.jsx(reactNative.View, { style: styles5.content, children: Array.from({ length: 6 }).map((_, index) => /* @__PURE__ */ jsxRuntime.jsx(
1254
+ return /* @__PURE__ */ jsxRuntime.jsx(reactNative.View, { style: s5.container, children: /* @__PURE__ */ jsxRuntime.jsx(reactNative.View, { style: s5.skeletonContent, children: Array.from({ length: 5 }).map((_, index) => /* @__PURE__ */ jsxRuntime.jsx(
1009
1255
  MessageRowSkeleton,
1010
1256
  {
1011
1257
  isRightAligned: index % 3 === 0
@@ -1014,26 +1260,17 @@ function MessageList({
1014
1260
  )) }) });
1015
1261
  }
1016
1262
  if (messages.length === 0) {
1017
- return /* @__PURE__ */ jsxRuntime.jsx(reactNative.View, { style: styles5.emptyContainer, children: /* @__PURE__ */ jsxRuntime.jsxs(
1018
- Animated__default.default.View,
1019
- {
1020
- entering: Animated.FadeIn.duration(500),
1021
- style: styles5.emptyContent,
1022
- children: [
1023
- showEmptyStateIcon && /* @__PURE__ */ jsxRuntime.jsx(reactNative.View, { style: styles5.iconContainer, children: /* @__PURE__ */ jsxRuntime.jsx(lucideReactNative.Bot, { size: 24, color: "#999" }) }),
1024
- emptyStateText.split("\n").map((line, index) => /* @__PURE__ */ jsxRuntime.jsx(
1025
- reactNative.Text,
1026
- {
1027
- style: [
1028
- index === 0 ? layout === "centered" ? styles5.emptyTitle : styles5.emptyTitleDefault : styles5.emptySubtitle
1029
- ],
1030
- children: line
1031
- },
1032
- index
1033
- ))
1034
- ]
1035
- }
1036
- ) });
1263
+ return /* @__PURE__ */ jsxRuntime.jsx(reactNative.View, { style: s5.emptyContainer, children: /* @__PURE__ */ jsxRuntime.jsxs(Animated2__default.default.View, { entering: Animated2.FadeIn.duration(500), style: s5.emptyContent, children: [
1264
+ showEmptyStateIcon && /* @__PURE__ */ jsxRuntime.jsx(reactNative.View, { style: s5.iconContainer, children: /* @__PURE__ */ jsxRuntime.jsx(lucideReactNative.MessageCircle, { size: 24, color: "rgba(156,163,175,0.7)" }) }),
1265
+ emptyStateText.split("\n").map((line, index) => /* @__PURE__ */ jsxRuntime.jsx(
1266
+ reactNative.Text,
1267
+ {
1268
+ style: index === 0 ? s5.emptyTitle : s5.emptySubtitle,
1269
+ children: line
1270
+ },
1271
+ index
1272
+ ))
1273
+ ] }) });
1037
1274
  }
1038
1275
  return /* @__PURE__ */ jsxRuntime.jsx(
1039
1276
  reactNative.FlatList,
@@ -1060,341 +1297,56 @@ function MessageList({
1060
1297
  }
1061
1298
  ),
1062
1299
  contentContainerStyle: [
1063
- styles5.listContent,
1064
- layout === "centered" && styles5.listContentCentered
1300
+ s5.listContent,
1301
+ layout === "centered" && s5.listContentCentered
1065
1302
  ],
1066
- showsVerticalScrollIndicator: true
1303
+ showsVerticalScrollIndicator: false
1067
1304
  }
1068
1305
  );
1069
1306
  }
1070
- var styles5 = reactNative.StyleSheet.create({
1071
- container: {
1072
- flex: 1
1073
- },
1074
- content: {
1075
- padding: 16,
1076
- gap: 16
1077
- },
1307
+ var s5 = reactNative.StyleSheet.create({
1308
+ container: { flex: 1 },
1309
+ skeletonContent: { padding: 16, gap: 16 },
1078
1310
  emptyContainer: {
1079
1311
  flex: 1,
1080
1312
  justifyContent: "center",
1081
1313
  alignItems: "center",
1082
- padding: 16
1083
- },
1084
- emptyContent: {
1085
- alignItems: "center",
1086
- gap: 16
1314
+ padding: 24
1087
1315
  },
1316
+ emptyContent: { alignItems: "center", gap: 10, maxWidth: 280 },
1088
1317
  iconContainer: {
1089
- width: 48,
1090
- height: 48,
1318
+ width: 56,
1319
+ height: 56,
1320
+ borderRadius: 16,
1321
+ backgroundColor: "rgba(0,0,0,0.03)",
1322
+ borderWidth: reactNative.StyleSheet.hairlineWidth,
1323
+ borderColor: "rgba(0,0,0,0.06)",
1091
1324
  justifyContent: "center",
1092
- alignItems: "center"
1325
+ alignItems: "center",
1326
+ marginBottom: 4
1093
1327
  },
1094
1328
  emptyTitle: {
1095
- fontSize: 24,
1096
- fontWeight: "600",
1097
- color: "#007AFF",
1098
- textAlign: "center"
1099
- },
1100
- emptyTitleDefault: {
1101
- fontSize: 24,
1329
+ fontSize: 20,
1102
1330
  fontWeight: "600",
1103
- color: "#000",
1331
+ color: "#1F2937",
1104
1332
  textAlign: "center"
1105
1333
  },
1106
1334
  emptySubtitle: {
1107
1335
  fontSize: 14,
1108
- color: "#999",
1109
- textAlign: "center"
1110
- },
1111
- listContent: {
1112
- padding: 16,
1113
- gap: 16
1114
- },
1115
- listContentCentered: {
1116
- maxWidth: 672,
1117
- alignSelf: "center",
1118
- width: "100%"
1119
- }
1120
- });
1121
- var WaveformBar = React4.memo(
1122
- ({
1123
- delay,
1124
- isActive,
1125
- color
1126
- }) => {
1127
- const height = React4.useRef(new reactNative.Animated.Value(6)).current;
1128
- React4.useEffect(() => {
1129
- if (isActive) {
1130
- const animation = reactNative.Animated.loop(
1131
- reactNative.Animated.sequence([
1132
- reactNative.Animated.timing(height, {
1133
- toValue: 14 + Math.random() * 10,
1134
- duration: 300 + Math.random() * 50,
1135
- delay,
1136
- easing: reactNative.Easing.inOut(reactNative.Easing.ease),
1137
- useNativeDriver: false
1138
- }),
1139
- reactNative.Animated.timing(height, {
1140
- toValue: 6 + Math.random() * 4,
1141
- duration: 300 + Math.random() * 50,
1142
- easing: reactNative.Easing.inOut(reactNative.Easing.ease),
1143
- useNativeDriver: false
1144
- })
1145
- ])
1146
- );
1147
- animation.start();
1148
- return () => animation.stop();
1149
- } else {
1150
- reactNative.Animated.timing(height, {
1151
- toValue: 6,
1152
- duration: 300,
1153
- useNativeDriver: false
1154
- }).start();
1155
- }
1156
- }, [isActive, delay, height]);
1157
- return /* @__PURE__ */ jsxRuntime.jsx(
1158
- reactNative.Animated.View,
1159
- {
1160
- style: [styles6.waveformBar, { height, backgroundColor: color }]
1161
- }
1162
- );
1163
- }
1164
- );
1165
- WaveformBar.displayName = "WaveformBar";
1166
- var RollingText = React4.memo(({ text, color }) => {
1167
- const [lines, setLines] = React4__default.default.useState([]);
1168
- const [currentLineIndex, setCurrentLineIndex] = React4__default.default.useState(0);
1169
- const translateY = React4.useRef(new reactNative.Animated.Value(0)).current;
1170
- const opacity = React4.useRef(new reactNative.Animated.Value(1)).current;
1171
- React4.useEffect(() => {
1172
- if (!text) {
1173
- setLines([]);
1174
- setCurrentLineIndex(0);
1175
- return;
1176
- }
1177
- const words = text.split(" ");
1178
- const newLines = [];
1179
- let currentLine = "";
1180
- words.forEach((word) => {
1181
- const testLine = currentLine ? `${currentLine} ${word}` : word;
1182
- if (testLine.length > 35 && currentLine) {
1183
- newLines.push(currentLine);
1184
- currentLine = word;
1185
- } else {
1186
- currentLine = testLine;
1187
- }
1188
- });
1189
- if (currentLine) {
1190
- newLines.push(currentLine);
1191
- }
1192
- setLines(newLines);
1193
- if (newLines.length > 0) {
1194
- const newIndex = newLines.length - 1;
1195
- if (newIndex > currentLineIndex) {
1196
- reactNative.Animated.sequence([
1197
- reactNative.Animated.parallel([
1198
- reactNative.Animated.timing(translateY, {
1199
- toValue: -20,
1200
- duration: 150,
1201
- useNativeDriver: true
1202
- }),
1203
- reactNative.Animated.timing(opacity, {
1204
- toValue: 0,
1205
- duration: 150,
1206
- useNativeDriver: true
1207
- })
1208
- ]),
1209
- reactNative.Animated.timing(translateY, {
1210
- toValue: 20,
1211
- duration: 0,
1212
- useNativeDriver: true
1213
- }),
1214
- reactNative.Animated.parallel([
1215
- reactNative.Animated.timing(translateY, {
1216
- toValue: 0,
1217
- duration: 200,
1218
- easing: reactNative.Easing.out(reactNative.Easing.ease),
1219
- useNativeDriver: true
1220
- }),
1221
- reactNative.Animated.timing(opacity, {
1222
- toValue: 1,
1223
- duration: 200,
1224
- useNativeDriver: true
1225
- })
1226
- ])
1227
- ]).start();
1228
- setCurrentLineIndex(newIndex);
1229
- }
1230
- }
1231
- }, [text, currentLineIndex, translateY, opacity]);
1232
- const currentText = lines[currentLineIndex] || text;
1233
- return /* @__PURE__ */ jsxRuntime.jsx(
1234
- reactNative.Animated.Text,
1235
- {
1236
- style: [
1237
- styles6.transcribedText,
1238
- {
1239
- color,
1240
- opacity,
1241
- transform: [{ translateY }]
1242
- }
1243
- ],
1244
- numberOfLines: 1,
1245
- children: currentText
1246
- }
1247
- );
1248
- });
1249
- RollingText.displayName = "RollingText";
1250
- var VoiceOverlay = React4.memo(
1251
- ({
1252
- visible,
1253
- voiceState,
1254
- transcribedText,
1255
- onStopRecording
1256
- }) => {
1257
- const panelHeight = React4.useRef(new reactNative.Animated.Value(0)).current;
1258
- const contentOpacity = React4.useRef(new reactNative.Animated.Value(0)).current;
1259
- const isListening = voiceState === "listening";
1260
- const PANEL_CONTENT_HEIGHT = 180;
1261
- const bgColor = "rgba(250, 250, 252, 0.98)";
1262
- const textColor = "#000000";
1263
- const mutedColor = "#007AFF";
1264
- const primaryColor = "#007AFF";
1265
- React4.useEffect(() => {
1266
- if (visible) {
1267
- reactNative.Animated.sequence([
1268
- reactNative.Animated.timing(panelHeight, {
1269
- toValue: PANEL_CONTENT_HEIGHT,
1270
- duration: 300,
1271
- easing: reactNative.Easing.out(reactNative.Easing.cubic),
1272
- useNativeDriver: false
1273
- }),
1274
- reactNative.Animated.timing(contentOpacity, {
1275
- toValue: 1,
1276
- duration: 150,
1277
- useNativeDriver: true
1278
- })
1279
- ]).start();
1280
- } else {
1281
- reactNative.Animated.parallel([
1282
- reactNative.Animated.timing(contentOpacity, {
1283
- toValue: 0,
1284
- duration: 100,
1285
- useNativeDriver: true
1286
- }),
1287
- reactNative.Animated.timing(panelHeight, {
1288
- toValue: 0,
1289
- duration: 220,
1290
- easing: reactNative.Easing.in(reactNative.Easing.ease),
1291
- useNativeDriver: false
1292
- })
1293
- ]).start();
1294
- }
1295
- }, [visible, panelHeight, contentOpacity]);
1296
- if (!visible && panelHeight._value === 0) {
1297
- return null;
1298
- }
1299
- return /* @__PURE__ */ jsxRuntime.jsx(
1300
- reactNative.Animated.View,
1301
- {
1302
- style: [
1303
- styles6.panel,
1304
- {
1305
- height: panelHeight,
1306
- backgroundColor: bgColor
1307
- }
1308
- ],
1309
- children: /* @__PURE__ */ jsxRuntime.jsxs(reactNative.Animated.View, { style: [styles6.content, { opacity: contentOpacity }], children: [
1310
- /* @__PURE__ */ jsxRuntime.jsx(reactNative.View, { style: styles6.textContainer, children: transcribedText.length > 0 ? /* @__PURE__ */ jsxRuntime.jsx(RollingText, { text: transcribedText, color: textColor }) : /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: [styles6.placeholderText, { color: mutedColor }], children: "Listening..." }) }),
1311
- /* @__PURE__ */ jsxRuntime.jsxs(reactNative.View, { style: styles6.controlsContainer, children: [
1312
- /* @__PURE__ */ jsxRuntime.jsx(reactNative.View, { style: styles6.waveformContainer, children: [0, 1, 2, 3, 4].map((index) => /* @__PURE__ */ jsxRuntime.jsx(
1313
- WaveformBar,
1314
- {
1315
- delay: index * 20,
1316
- isActive: isListening,
1317
- color: primaryColor
1318
- },
1319
- index
1320
- )) }),
1321
- /* @__PURE__ */ jsxRuntime.jsx(reactNative.Pressable, { onPress: onStopRecording, style: styles6.micButton, children: /* @__PURE__ */ jsxRuntime.jsx(lucideReactNative.Mic, { size: 24, color: primaryColor, strokeWidth: 2 }) }),
1322
- /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: [styles6.hintText, { color: mutedColor }], children: "Tap to stop" })
1323
- ] })
1324
- ] })
1325
- }
1326
- );
1327
- }
1328
- );
1329
- VoiceOverlay.displayName = "VoiceOverlay";
1330
- var styles6 = reactNative.StyleSheet.create({
1331
- panel: {
1332
- overflow: "hidden",
1333
- borderTopLeftRadius: 20,
1334
- borderTopRightRadius: 20,
1335
- borderWidth: 1,
1336
- borderColor: "#E5E5E5"
1337
- },
1338
- content: {
1339
- flex: 1,
1340
- paddingHorizontal: 24,
1341
- paddingTop: 20
1342
- },
1343
- textContainer: {
1344
- height: 32,
1345
- justifyContent: "center",
1346
- marginBottom: 16,
1347
- overflow: "hidden"
1348
- },
1349
- transcribedText: {
1350
- fontSize: 18,
1351
- fontWeight: "500",
1352
- textAlign: "left"
1353
- },
1354
- placeholderText: {
1355
- fontSize: 15,
1356
- textAlign: "left",
1357
- fontWeight: "800"
1358
- },
1359
- controlsContainer: {
1360
- flex: 1,
1361
- alignItems: "center",
1362
- justifyContent: "flex-start"
1363
- },
1364
- waveformContainer: {
1365
- flexDirection: "row",
1366
- alignItems: "center",
1367
- justifyContent: "center",
1368
- gap: 5,
1369
- height: 28,
1370
- marginBottom: 16
1371
- },
1372
- waveformBar: {
1373
- width: 3,
1374
- borderRadius: 2
1375
- },
1376
- micButton: {
1377
- width: 56,
1378
- height: 56,
1379
- borderRadius: 28,
1380
- alignItems: "center",
1381
- justifyContent: "center",
1382
- backgroundColor: "#FFFFFF",
1383
- borderWidth: 1,
1384
- borderColor: "#E5E5E5"
1336
+ color: "#9CA3AF",
1337
+ textAlign: "center",
1338
+ lineHeight: 20
1385
1339
  },
1386
- hintText: {
1387
- fontSize: 12,
1388
- marginTop: 12
1389
- }
1340
+ listContent: { padding: 16, gap: 16 },
1341
+ listContentCentered: { maxWidth: 672, alignSelf: "center", width: "100%" }
1390
1342
  });
1391
1343
  var DEFAULT_MAX_LENGTH = 6;
1392
1344
  var MAX_SUPPORTED_LENGTH = 12;
1393
1345
  function OtpInput({ value, onChange, maxLength, disabled = false }) {
1394
- const inputRefs = React4.useRef([]);
1346
+ const inputRefs = React.useRef([]);
1395
1347
  const safeMaxLength = Number.isInteger(maxLength) && maxLength > 0 ? Math.min(maxLength, MAX_SUPPORTED_LENGTH) : DEFAULT_MAX_LENGTH;
1396
1348
  const digits = value.split("").concat(Array(safeMaxLength).fill("")).slice(0, safeMaxLength);
1397
- React4.useEffect(() => {
1349
+ React.useEffect(() => {
1398
1350
  if (!disabled) {
1399
1351
  inputRefs.current[0]?.focus();
1400
1352
  }
@@ -1438,7 +1390,7 @@ function OtpInput({ value, onChange, maxLength, disabled = false }) {
1438
1390
  }
1439
1391
  }
1440
1392
  };
1441
- return /* @__PURE__ */ jsxRuntime.jsx(reactNative.View, { style: styles7.container, children: digits.map((digit, i) => /* @__PURE__ */ jsxRuntime.jsx(
1393
+ return /* @__PURE__ */ jsxRuntime.jsx(reactNative.View, { style: s6.container, children: digits.map((digit, i) => /* @__PURE__ */ jsxRuntime.jsx(
1442
1394
  reactNative.TextInput,
1443
1395
  {
1444
1396
  ref: (el) => {
@@ -1451,33 +1403,27 @@ function OtpInput({ value, onChange, maxLength, disabled = false }) {
1451
1403
  onChangeText: (text) => handleChange(i, text),
1452
1404
  onKeyPress: ({ nativeEvent }) => handleKeyPress(i, nativeEvent.key),
1453
1405
  onFocus: () => inputRefs.current[i]?.setNativeProps({ selection: { start: 0, end: 1 } }),
1454
- style: [styles7.input, disabled && styles7.inputDisabled],
1406
+ style: [s6.input, disabled && s6.inputDisabled],
1455
1407
  accessibilityLabel: `Digit ${i + 1}`
1456
1408
  },
1457
1409
  i
1458
1410
  )) });
1459
1411
  }
1460
- var styles7 = reactNative.StyleSheet.create({
1461
- container: {
1462
- flexDirection: "row",
1463
- gap: 8,
1464
- justifyContent: "center"
1465
- },
1412
+ var s6 = reactNative.StyleSheet.create({
1413
+ container: { flexDirection: "row", gap: 8, justifyContent: "center" },
1466
1414
  input: {
1467
- width: 40,
1468
- height: 48,
1415
+ width: 42,
1416
+ height: 50,
1469
1417
  textAlign: "center",
1470
1418
  fontSize: 20,
1471
1419
  fontWeight: "600",
1472
1420
  borderWidth: 1,
1473
- borderColor: "#E5E5E5",
1474
- borderRadius: 8,
1475
- color: "#000"
1421
+ borderColor: "rgba(0,0,0,0.1)",
1422
+ borderRadius: 10,
1423
+ color: "#1F2937",
1424
+ backgroundColor: "#FFFFFF"
1476
1425
  },
1477
- inputDisabled: {
1478
- backgroundColor: "#F5F5F5",
1479
- opacity: 0.5
1480
- }
1426
+ inputDisabled: { backgroundColor: "rgba(0,0,0,0.03)", opacity: 0.5 }
1481
1427
  });
1482
1428
 
1483
1429
  // src/components/UserActionModal/constants.ts
@@ -1521,16 +1467,16 @@ function UserActionModal({
1521
1467
  onResend,
1522
1468
  clearOtpTrigger
1523
1469
  }) {
1524
- const [otp, setOtp] = React4.useState("");
1525
- const [actionType, setActionType] = React4.useState(null);
1526
- const [isSubmitting, setIsSubmitting] = React4.useState(false);
1527
- const [resendCooldownRemaining, setResendCooldownRemaining] = React4.useState(0);
1470
+ const [otp, setOtp] = React.useState("");
1471
+ const [actionType, setActionType] = React.useState(null);
1472
+ const [isSubmitting, setIsSubmitting] = React.useState(false);
1473
+ const [resendCooldownRemaining, setResendCooldownRemaining] = React.useState(0);
1528
1474
  const schema = getOtpSchemaFromRequest(userActionRequest?.requestedSchema);
1529
- const resetActionState = React4.useCallback(() => {
1475
+ const resetActionState = React.useCallback(() => {
1530
1476
  setIsSubmitting(false);
1531
1477
  setActionType(null);
1532
1478
  }, []);
1533
- React4.useEffect(() => {
1479
+ React.useEffect(() => {
1534
1480
  if (isOpen) {
1535
1481
  setResendCooldownRemaining(RESEND_OTP_COOLDOWN_SECONDS);
1536
1482
  } else {
@@ -1539,28 +1485,30 @@ function UserActionModal({
1539
1485
  setResendCooldownRemaining(0);
1540
1486
  }
1541
1487
  }, [isOpen, resetActionState]);
1542
- React4.useEffect(() => {
1488
+ React.useEffect(() => {
1543
1489
  if (resendCooldownRemaining <= 0) return;
1544
- const timer = setTimeout(() => {
1545
- setResendCooldownRemaining((prev) => prev - 1);
1546
- }, 1e3);
1490
+ const timer = setTimeout(
1491
+ () => setResendCooldownRemaining((prev) => prev - 1),
1492
+ 1e3
1493
+ );
1547
1494
  return () => clearTimeout(timer);
1548
1495
  }, [resendCooldownRemaining]);
1549
- React4.useEffect(() => {
1496
+ React.useEffect(() => {
1550
1497
  if (clearOtpTrigger > 0) {
1551
1498
  setOtp("");
1552
1499
  resetActionState();
1553
1500
  }
1554
1501
  }, [clearOtpTrigger, resetActionState]);
1555
- React4.useEffect(() => {
1502
+ React.useEffect(() => {
1556
1503
  if (!isOpen || !isSubmitting) return;
1557
1504
  if (actionType !== "approve" && actionType !== "reject") return;
1558
- const timeout = setTimeout(() => {
1559
- resetActionState();
1560
- }, ACTION_PENDING_TIMEOUT_MS);
1505
+ const timeout = setTimeout(
1506
+ () => resetActionState(),
1507
+ ACTION_PENDING_TIMEOUT_MS
1508
+ );
1561
1509
  return () => clearTimeout(timeout);
1562
1510
  }, [isOpen, isSubmitting, actionType, resetActionState]);
1563
- const handleApprove = React4.useCallback(async () => {
1511
+ const handleApprove = React.useCallback(async () => {
1564
1512
  if (otp.length !== schema.maxLength || !/^\d+$/.test(otp)) return;
1565
1513
  setIsSubmitting(true);
1566
1514
  setActionType("approve");
@@ -1570,7 +1518,7 @@ function UserActionModal({
1570
1518
  resetActionState();
1571
1519
  }
1572
1520
  }, [otp, schema.maxLength, onApprove, resetActionState]);
1573
- const handleReject = React4.useCallback(async () => {
1521
+ const handleReject = React.useCallback(async () => {
1574
1522
  setIsSubmitting(true);
1575
1523
  setActionType("reject");
1576
1524
  try {
@@ -1579,7 +1527,7 @@ function UserActionModal({
1579
1527
  resetActionState();
1580
1528
  }
1581
1529
  }, [onReject, resetActionState]);
1582
- const handleResend = React4.useCallback(async () => {
1530
+ const handleResend = React.useCallback(async () => {
1583
1531
  if (resendCooldownRemaining > 0) return;
1584
1532
  setIsSubmitting(true);
1585
1533
  setActionType("resend");
@@ -1608,10 +1556,10 @@ function UserActionModal({
1608
1556
  animationType: "fade",
1609
1557
  onRequestClose: () => {
1610
1558
  },
1611
- children: /* @__PURE__ */ jsxRuntime.jsx(reactNative.View, { style: styles8.backdrop, children: /* @__PURE__ */ jsxRuntime.jsxs(reactNative.View, { style: styles8.dialog, children: [
1612
- /* @__PURE__ */ jsxRuntime.jsx(reactNative.View, { style: styles8.titleContainer, children: /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: styles8.title, children: MODAL_CONTENT.TITLE }) }),
1613
- /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: styles8.description, children: userActionRequest.message }),
1614
- /* @__PURE__ */ jsxRuntime.jsx(reactNative.View, { style: styles8.otpContainer, children: /* @__PURE__ */ jsxRuntime.jsx(
1559
+ children: /* @__PURE__ */ jsxRuntime.jsx(reactNative.View, { style: s7.backdrop, children: /* @__PURE__ */ jsxRuntime.jsxs(reactNative.View, { style: s7.dialog, children: [
1560
+ /* @__PURE__ */ jsxRuntime.jsx(reactNative.View, { style: s7.titleWrap, children: /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: s7.title, children: MODAL_CONTENT.TITLE }) }),
1561
+ /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: s7.description, children: userActionRequest.message }),
1562
+ /* @__PURE__ */ jsxRuntime.jsx(reactNative.View, { style: s7.otpWrap, children: /* @__PURE__ */ jsxRuntime.jsx(
1615
1563
  OtpInput,
1616
1564
  {
1617
1565
  value: otp,
@@ -1620,21 +1568,28 @@ function UserActionModal({
1620
1568
  disabled: isSubmitting
1621
1569
  }
1622
1570
  ) }),
1623
- /* @__PURE__ */ jsxRuntime.jsxs(reactNative.View, { style: styles8.buttonsColumn, children: [
1624
- /* @__PURE__ */ jsxRuntime.jsxs(reactNative.View, { style: styles8.primaryButtonsRow, children: [
1571
+ /* @__PURE__ */ jsxRuntime.jsxs(reactNative.View, { style: s7.buttonsCol, children: [
1572
+ /* @__PURE__ */ jsxRuntime.jsxs(reactNative.View, { style: s7.primaryRow, children: [
1625
1573
  /* @__PURE__ */ jsxRuntime.jsxs(
1626
1574
  reactNative.Pressable,
1627
1575
  {
1628
1576
  onPress: handleReject,
1629
1577
  disabled: isSubmitting,
1630
1578
  style: ({ pressed }) => [
1631
- styles8.rejectButton,
1632
- isSubmitting && styles8.buttonDisabled,
1633
- pressed && styles8.rejectButtonPressed
1579
+ s7.rejectBtn,
1580
+ isSubmitting && s7.btnDisabled,
1581
+ pressed && { opacity: 0.7 }
1634
1582
  ],
1635
1583
  children: [
1636
- actionType === "reject" && /* @__PURE__ */ jsxRuntime.jsx(reactNative.ActivityIndicator, { size: "small", color: "#DC2626", style: styles8.spinner }),
1637
- /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: styles8.rejectButtonText, children: actionType === "reject" ? MODAL_CONTENT.LOADING_REJECT : BUTTON_LABELS.REJECT })
1584
+ actionType === "reject" && /* @__PURE__ */ jsxRuntime.jsx(
1585
+ reactNative.ActivityIndicator,
1586
+ {
1587
+ size: "small",
1588
+ color: "#DC2626",
1589
+ style: s7.spinner
1590
+ }
1591
+ ),
1592
+ /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: s7.rejectBtnText, children: actionType === "reject" ? MODAL_CONTENT.LOADING_REJECT : BUTTON_LABELS.REJECT })
1638
1593
  ]
1639
1594
  }
1640
1595
  ),
@@ -1644,13 +1599,20 @@ function UserActionModal({
1644
1599
  onPress: handleApprove,
1645
1600
  disabled: !isOtpValid || isSubmitting,
1646
1601
  style: ({ pressed }) => [
1647
- styles8.approveButton,
1648
- (!isOtpValid || isSubmitting) && styles8.buttonDisabled,
1649
- pressed && styles8.approveButtonPressed
1602
+ s7.approveBtn,
1603
+ (!isOtpValid || isSubmitting) && s7.btnDisabled,
1604
+ pressed && { opacity: 0.85 }
1650
1605
  ],
1651
1606
  children: [
1652
- actionType === "approve" && /* @__PURE__ */ jsxRuntime.jsx(reactNative.ActivityIndicator, { size: "small", color: "#FFF", style: styles8.spinner }),
1653
- /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: styles8.approveButtonText, children: actionType === "approve" ? MODAL_CONTENT.LOADING_APPROVE : BUTTON_LABELS.APPROVE })
1607
+ actionType === "approve" && /* @__PURE__ */ jsxRuntime.jsx(
1608
+ reactNative.ActivityIndicator,
1609
+ {
1610
+ size: "small",
1611
+ color: "#FFF",
1612
+ style: s7.spinner
1613
+ }
1614
+ ),
1615
+ /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: s7.approveBtnText, children: actionType === "approve" ? MODAL_CONTENT.LOADING_APPROVE : BUTTON_LABELS.APPROVE })
1654
1616
  ]
1655
1617
  }
1656
1618
  )
@@ -1661,13 +1623,20 @@ function UserActionModal({
1661
1623
  onPress: handleResend,
1662
1624
  disabled: isSubmitting || resendCooldownRemaining > 0,
1663
1625
  style: ({ pressed }) => [
1664
- styles8.resendButton,
1665
- (isSubmitting || resendCooldownRemaining > 0) && styles8.buttonDisabled,
1666
- pressed && styles8.resendButtonPressed
1626
+ s7.resendBtn,
1627
+ (isSubmitting || resendCooldownRemaining > 0) && s7.btnDisabled,
1628
+ pressed && { opacity: 0.7 }
1667
1629
  ],
1668
1630
  children: [
1669
- actionType === "resend" && /* @__PURE__ */ jsxRuntime.jsx(reactNative.ActivityIndicator, { size: "small", color: "#666", style: styles8.spinner }),
1670
- /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: styles8.resendButtonText, children: getResendLabel() })
1631
+ actionType === "resend" && /* @__PURE__ */ jsxRuntime.jsx(
1632
+ reactNative.ActivityIndicator,
1633
+ {
1634
+ size: "small",
1635
+ color: "#6B7280",
1636
+ style: s7.spinner
1637
+ }
1638
+ ),
1639
+ /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: s7.resendBtnText, children: getResendLabel() })
1671
1640
  ]
1672
1641
  }
1673
1642
  )
@@ -1676,105 +1645,65 @@ function UserActionModal({
1676
1645
  }
1677
1646
  );
1678
1647
  }
1679
- var styles8 = reactNative.StyleSheet.create({
1648
+ var s7 = reactNative.StyleSheet.create({
1680
1649
  backdrop: {
1681
1650
  flex: 1,
1682
- backgroundColor: "rgba(0, 0, 0, 0.5)",
1651
+ backgroundColor: "rgba(0,0,0,0.4)",
1683
1652
  justifyContent: "center",
1684
1653
  alignItems: "center"
1685
1654
  },
1686
1655
  dialog: {
1687
1656
  backgroundColor: "#FFF",
1688
- borderRadius: 12,
1657
+ borderRadius: 20,
1689
1658
  padding: 24,
1690
1659
  width: "90%",
1691
- maxWidth: 420
1692
- },
1693
- titleContainer: {
1694
- alignItems: "center",
1695
- marginBottom: 16
1696
- },
1697
- title: {
1698
- fontSize: 18,
1699
- fontWeight: "600",
1700
- color: "#000"
1660
+ maxWidth: 400
1701
1661
  },
1662
+ titleWrap: { alignItems: "center", marginBottom: 14 },
1663
+ title: { fontSize: 16, fontWeight: "600", color: "#1F2937" },
1702
1664
  description: {
1703
1665
  fontSize: 14,
1704
- color: "#666",
1666
+ lineHeight: 21,
1667
+ color: "#6B7280",
1705
1668
  textAlign: "center",
1706
- marginBottom: 24,
1707
- lineHeight: 21
1708
- },
1709
- otpContainer: {
1710
- marginBottom: 24
1669
+ marginBottom: 20
1711
1670
  },
1712
- buttonsColumn: {
1713
- gap: 10
1714
- },
1715
- primaryButtonsRow: {
1716
- flexDirection: "row",
1717
- gap: 8
1718
- },
1719
- resendButton: {
1720
- borderRadius: 8,
1721
- paddingVertical: 8,
1671
+ otpWrap: { marginBottom: 24 },
1672
+ buttonsCol: { gap: 10 },
1673
+ primaryRow: { flexDirection: "row", gap: 8 },
1674
+ rejectBtn: {
1675
+ flex: 1,
1676
+ borderRadius: 12,
1677
+ paddingVertical: 12,
1722
1678
  paddingHorizontal: 16,
1679
+ backgroundColor: "rgba(220,38,38,0.08)",
1723
1680
  flexDirection: "row",
1724
1681
  alignItems: "center",
1725
1682
  justifyContent: "center"
1726
1683
  },
1727
- resendButtonPressed: {
1728
- opacity: 0.7
1729
- },
1730
- resendButtonText: {
1731
- color: "#666",
1732
- fontSize: 12,
1733
- fontWeight: "500"
1734
- },
1735
- rejectButton: {
1684
+ rejectBtnText: { color: "#DC2626", fontSize: 14, fontWeight: "500" },
1685
+ approveBtn: {
1736
1686
  flex: 1,
1737
- borderRadius: 8,
1687
+ borderRadius: 12,
1738
1688
  paddingVertical: 12,
1739
1689
  paddingHorizontal: 16,
1740
- backgroundColor: "rgba(220, 38, 38, 0.1)",
1690
+ backgroundColor: "#007AFF",
1741
1691
  flexDirection: "row",
1742
1692
  alignItems: "center",
1743
1693
  justifyContent: "center"
1744
1694
  },
1745
- rejectButtonPressed: {
1746
- backgroundColor: "rgba(220, 38, 38, 0.2)"
1747
- },
1748
- rejectButtonText: {
1749
- color: "#DC2626",
1750
- fontSize: 14,
1751
- fontWeight: "500"
1752
- },
1753
- approveButton: {
1754
- flex: 1,
1755
- borderRadius: 8,
1756
- paddingVertical: 12,
1695
+ approveBtnText: { color: "#FFF", fontSize: 14, fontWeight: "600" },
1696
+ resendBtn: {
1697
+ borderRadius: 10,
1698
+ paddingVertical: 8,
1757
1699
  paddingHorizontal: 16,
1758
- backgroundColor: "#007AFF",
1759
1700
  flexDirection: "row",
1760
1701
  alignItems: "center",
1761
1702
  justifyContent: "center"
1762
1703
  },
1763
- approveButtonPressed: {
1764
- backgroundColor: "#0066D6",
1765
- opacity: 1
1766
- },
1767
- approveButtonText: {
1768
- color: "#FFF",
1769
- fontSize: 14,
1770
- fontWeight: "600"
1771
- },
1772
- buttonDisabled: {
1773
- opacity: 0.5
1774
- },
1775
- spinner: {
1776
- marginRight: 8
1777
- }
1704
+ resendBtnText: { color: "#6B7280", fontSize: 14, lineHeight: 21, fontWeight: "500" },
1705
+ btnDisabled: { opacity: 0.4 },
1706
+ spinner: { marginRight: 8 }
1778
1707
  });
1779
1708
  var DEFAULT_USER_ACTION_STATE = {
1780
1709
  request: null,
@@ -1789,9 +1718,11 @@ function PaymanChat({
1789
1718
  style,
1790
1719
  children
1791
1720
  }) {
1792
- const [inputValue, setInputValue] = React4.useState("");
1793
- const [voiceOverlayVisible, setVoiceOverlayVisible] = React4.useState(false);
1794
- const prevInputValueRef = React4.useRef(inputValue);
1721
+ const [inputValue, setInputValue] = React.useState("");
1722
+ const [recordingElapsedSeconds, setRecordingElapsedSeconds] = React.useState(0);
1723
+ const recordingStartRef = React.useRef(null);
1724
+ const recordingIntervalRef = React.useRef(null);
1725
+ const prevInputValueRef = React.useRef(inputValue);
1795
1726
  const chat = paymanTypescriptAskSdk.useChat(config, callbacks);
1796
1727
  const {
1797
1728
  messages,
@@ -1824,11 +1755,11 @@ function PaymanChat({
1824
1755
  {
1825
1756
  onError: (error) => {
1826
1757
  console.error("Voice error:", error);
1827
- setVoiceOverlayVisible(false);
1828
1758
  }
1829
1759
  }
1830
1760
  );
1831
- const contextValue = React4.useMemo(
1761
+ const isRecording = voiceState === "listening";
1762
+ const contextValue = React.useMemo(
1832
1763
  () => ({
1833
1764
  resetSession,
1834
1765
  clearMessages,
@@ -1871,23 +1802,47 @@ function PaymanChat({
1871
1802
  inputStyle = "rounded",
1872
1803
  enableVoice = false
1873
1804
  } = config;
1874
- const isSessionParamsConfigured = React4.useMemo(() => {
1805
+ const isSessionParamsConfigured = React.useMemo(() => {
1875
1806
  if (!sessionParams) return false;
1876
1807
  return !!(sessionParams.id?.trim() && sessionParams.name?.trim());
1877
1808
  }, [sessionParams?.id, sessionParams?.name]);
1878
- React4.useEffect(() => {
1809
+ React.useEffect(() => {
1810
+ if (isRecording) {
1811
+ recordingStartRef.current = Date.now();
1812
+ setRecordingElapsedSeconds(0);
1813
+ recordingIntervalRef.current = setInterval(() => {
1814
+ if (recordingStartRef.current != null) {
1815
+ setRecordingElapsedSeconds(
1816
+ Math.floor((Date.now() - recordingStartRef.current) / 1e3)
1817
+ );
1818
+ }
1819
+ }, 1e3);
1820
+ } else {
1821
+ recordingStartRef.current = null;
1822
+ if (recordingIntervalRef.current) {
1823
+ clearInterval(recordingIntervalRef.current);
1824
+ recordingIntervalRef.current = null;
1825
+ }
1826
+ setRecordingElapsedSeconds(0);
1827
+ }
1828
+ return () => {
1829
+ if (recordingIntervalRef.current) {
1830
+ clearInterval(recordingIntervalRef.current);
1831
+ recordingIntervalRef.current = null;
1832
+ }
1833
+ };
1834
+ }, [isRecording]);
1835
+ React.useEffect(() => {
1879
1836
  const wasEmpty = prevInputValueRef.current.trim() === "";
1880
1837
  const isEmpty = inputValue.trim() === "";
1881
1838
  prevInputValueRef.current = inputValue;
1882
1839
  if (!wasEmpty && isEmpty) {
1883
1840
  clearTranscript();
1884
1841
  stopRecording();
1885
- setVoiceOverlayVisible(false);
1886
1842
  }
1887
1843
  }, [inputValue, clearTranscript, stopRecording]);
1888
- const handleSend = React4.useCallback(() => {
1844
+ const handleSend = React.useCallback(() => {
1889
1845
  stopRecording();
1890
- setVoiceOverlayVisible(false);
1891
1846
  if (inputValue.trim() && !disableInput && isSessionParamsConfigured) {
1892
1847
  sendMessage(inputValue.trim());
1893
1848
  setInputValue("");
@@ -1900,35 +1855,34 @@ function PaymanChat({
1900
1855
  stopRecording
1901
1856
  ]);
1902
1857
  const isInputDisabled = isWaitingForResponse || !isSessionParamsConfigured || disableInput;
1903
- const handleVoicePress = React4.useCallback(async () => {
1858
+ const handleVoicePress = React.useCallback(async () => {
1904
1859
  if (!voiceAvailable) return;
1905
- setVoiceOverlayVisible(true);
1906
1860
  clearTranscript();
1907
1861
  await startRecording();
1908
1862
  }, [voiceAvailable, startRecording, clearTranscript]);
1909
- const handleStopRecording = React4.useCallback(() => {
1863
+ const handleConfirmRecording = React.useCallback(() => {
1910
1864
  stopRecording();
1911
- setVoiceOverlayVisible(false);
1912
- if (transcribedText.trim()) {
1913
- setInputValue(transcribedText);
1914
- }
1865
+ if (transcribedText.trim()) setInputValue(transcribedText);
1915
1866
  }, [stopRecording, transcribedText]);
1867
+ const handleCancelRecording = React.useCallback(() => {
1868
+ stopRecording();
1869
+ }, [stopRecording]);
1916
1870
  if (isChatDisabled) {
1917
1871
  if (disabledComponent) {
1918
- return /* @__PURE__ */ jsxRuntime.jsx(PaymanChatContext.Provider, { value: contextValue, children: /* @__PURE__ */ jsxRuntime.jsxs(reactNative.View, { style: [styles9.container, style], children: [
1872
+ return /* @__PURE__ */ jsxRuntime.jsx(PaymanChatContext.Provider, { value: contextValue, children: /* @__PURE__ */ jsxRuntime.jsxs(reactNative.View, { style: [s8.container, style], children: [
1919
1873
  children,
1920
1874
  disabledComponent
1921
1875
  ] }) });
1922
1876
  }
1923
- return /* @__PURE__ */ jsxRuntime.jsx(PaymanChatContext.Provider, { value: contextValue, children: /* @__PURE__ */ jsxRuntime.jsxs(reactNative.View, { style: [styles9.container, style], children: [
1877
+ return /* @__PURE__ */ jsxRuntime.jsx(PaymanChatContext.Provider, { value: contextValue, children: /* @__PURE__ */ jsxRuntime.jsxs(reactNative.View, { style: [s8.container, style], children: [
1924
1878
  children,
1925
- /* @__PURE__ */ jsxRuntime.jsx(reactNative.View, { style: styles9.disabledContainer, children: /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: styles9.disabledText, children: "Chat is currently disabled" }) })
1879
+ /* @__PURE__ */ jsxRuntime.jsx(reactNative.View, { style: s8.disabledWrap, children: /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: s8.disabledText, children: "Chat is currently disabled" }) })
1926
1880
  ] }) });
1927
1881
  }
1928
1882
  return /* @__PURE__ */ jsxRuntime.jsx(PaymanChatContext.Provider, { value: contextValue, children: /* @__PURE__ */ jsxRuntime.jsxs(
1929
1883
  reactNative.KeyboardAvoidingView,
1930
1884
  {
1931
- style: [styles9.container, style],
1885
+ style: [s8.container, style],
1932
1886
  behavior: reactNative.Platform.OS === "ios" ? "padding" : "height",
1933
1887
  keyboardVerticalOffset: reactNative.Platform.OS === "ios" ? 90 : 0,
1934
1888
  children: [
@@ -1956,36 +1910,30 @@ function PaymanChat({
1956
1910
  onExecutionTraceClick
1957
1911
  }
1958
1912
  ),
1959
- hasAskPermission && /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
1960
- /* @__PURE__ */ jsxRuntime.jsx(
1961
- ChatInput,
1962
- {
1963
- value: inputValue,
1964
- onChange: setInputValue,
1965
- onSend: handleSend,
1966
- onPause: cancelStream,
1967
- disabled: isInputDisabled,
1968
- placeholder,
1969
- isWaitingForResponse,
1970
- hasSelectedSession: true,
1971
- isSessionParamsConfigured,
1972
- inputStyle,
1973
- layout,
1974
- enableVoice,
1975
- onVoicePress: enableVoice ? handleVoicePress : void 0,
1976
- voiceAvailable: enableVoice && voiceAvailable
1977
- }
1978
- ),
1979
- enableVoice && /* @__PURE__ */ jsxRuntime.jsx(
1980
- VoiceOverlay,
1981
- {
1982
- visible: voiceOverlayVisible,
1983
- voiceState,
1984
- transcribedText,
1985
- onStopRecording: handleStopRecording
1986
- }
1987
- )
1988
- ] }),
1913
+ hasAskPermission && /* @__PURE__ */ jsxRuntime.jsx(
1914
+ ChatInput,
1915
+ {
1916
+ value: inputValue,
1917
+ onChange: setInputValue,
1918
+ onSend: handleSend,
1919
+ onPause: cancelStream,
1920
+ disabled: isInputDisabled,
1921
+ placeholder,
1922
+ isWaitingForResponse,
1923
+ hasSelectedSession: true,
1924
+ isSessionParamsConfigured,
1925
+ inputStyle,
1926
+ layout,
1927
+ enableVoice,
1928
+ onVoicePress: enableVoice ? handleVoicePress : void 0,
1929
+ voiceAvailable: enableVoice && voiceAvailable,
1930
+ isRecording: enableVoice && isRecording,
1931
+ recordingDurationSeconds: recordingElapsedSeconds,
1932
+ onConfirmRecording: enableVoice ? handleConfirmRecording : void 0,
1933
+ onCancelRecording: enableVoice ? handleCancelRecording : void 0,
1934
+ transcribedText: enableVoice && isRecording ? transcribedText : void 0
1935
+ }
1936
+ ),
1989
1937
  /* @__PURE__ */ jsxRuntime.jsx(
1990
1938
  UserActionModal,
1991
1939
  {
@@ -2001,26 +1949,22 @@ function PaymanChat({
2001
1949
  }
2002
1950
  ) });
2003
1951
  }
2004
- var styles9 = reactNative.StyleSheet.create({
1952
+ var s8 = reactNative.StyleSheet.create({
2005
1953
  container: {
2006
1954
  flex: 1,
2007
- backgroundColor: "#FFF",
2008
- borderWidth: 1,
2009
- borderColor: "#E5E5E5",
2010
- borderRadius: 8,
1955
+ backgroundColor: "#FFFFFF",
1956
+ borderWidth: reactNative.StyleSheet.hairlineWidth,
1957
+ borderColor: "rgba(0,0,0,0.08)",
1958
+ borderRadius: 16,
2011
1959
  overflow: "hidden"
2012
1960
  },
2013
- disabledContainer: {
1961
+ disabledWrap: {
2014
1962
  flex: 1,
2015
1963
  justifyContent: "center",
2016
1964
  alignItems: "center",
2017
1965
  padding: 16
2018
1966
  },
2019
- disabledText: {
2020
- fontSize: 14,
2021
- color: "#999",
2022
- textAlign: "center"
2023
- }
1967
+ disabledText: { fontSize: 14, color: "#9CA3AF", textAlign: "center" }
2024
1968
  });
2025
1969
 
2026
1970
  Object.defineProperty(exports, "cancelUserAction", {