@alia.onl/sdk 10.1.1 → 11.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (66) hide show
  1. package/CHANGELOG.md +67 -0
  2. package/README.md +24 -0
  3. package/package.json +4 -6
  4. package/src/components/AliaAvatar.tsx +66 -0
  5. package/src/components/AliaChatContent.tsx +236 -112
  6. package/src/components/AliaChatHeader.tsx +118 -0
  7. package/src/components/AliaChatMessageList.tsx +197 -260
  8. package/src/components/AliaChatScreen.tsx +23 -24
  9. package/src/components/AliaChatSheet.tsx +70 -316
  10. package/src/components/AliaWelcomeMessage.tsx +47 -50
  11. package/src/components/AmbientField.tsx +577 -0
  12. package/src/components/IdentityMark.tsx +10 -2
  13. package/src/components/Markdown.tsx +116 -40
  14. package/src/components/PlanPreviewCard.tsx +71 -55
  15. package/src/components/QuestionCard.tsx +62 -0
  16. package/src/components/ThinkingBlock.tsx +47 -0
  17. package/src/components/VoiceModeIcon.tsx +10 -0
  18. package/src/components/voice/VoiceControls.tsx +22 -73
  19. package/src/components/voice/VoiceSession.tsx +2 -1
  20. package/src/hooks/useAliaChat.ts +22 -15
  21. package/src/hooks/useAmbientWave.ts +35 -5
  22. package/src/hooks/useSoundEffects.ts +14 -11
  23. package/src/hooks/useSpeechToText.ts +9 -2
  24. package/src/hooks/useTTS.ts +163 -156
  25. package/src/hooks/useVoiceRoom.ts +228 -170
  26. package/src/index.ts +26 -6
  27. package/src/lib/catalogue.ts +17 -4
  28. package/src/lib/chat-stream.ts +25 -7
  29. package/src/lib/chat-transport.ts +2 -1
  30. package/src/lib/citations.ts +63 -0
  31. package/src/lib/content-utils.ts +3 -2
  32. package/src/lib/image-data-url.ts +15 -0
  33. package/src/lib/keyboard.tsx +1 -1
  34. package/src/lib/labels.tsx +81 -0
  35. package/src/lib/questions.ts +78 -0
  36. package/src/lib/speech-recognition.native.ts +15 -4
  37. package/src/lib/speech-recognition.ts +27 -7
  38. package/src/lib/task-labels.ts +67 -0
  39. package/src/lib/tool-call-status.ts +28 -0
  40. package/src/lib/tool-registry.ts +14 -14
  41. package/src/lib/voice-text.ts +12 -6
  42. package/src/lib/voice-turn.ts +4 -1
  43. package/src/lib/work-log-copy.ts +61 -0
  44. package/src/lib/work-log.ts +378 -0
  45. package/src/tools.ts +18 -0
  46. package/src/types.ts +5 -2
  47. package/src/voice.ts +12 -4
  48. package/src/components/Reasoning.tsx +0 -152
  49. package/src/components/ResearchProgressCard.tsx +0 -159
  50. package/src/components/ThinkingIndicator.tsx +0 -98
  51. package/src/components/ui/button.tsx +0 -104
  52. package/src/components/ui/chat-text-input.tsx +0 -184
  53. package/src/components/ui/dropdown-menu.tsx +0 -2
  54. package/src/components/ui/dropdown-menu.web.tsx +0 -383
  55. package/src/components/ui/prompt-input/actions.tsx +0 -28
  56. package/src/components/ui/prompt-input/add-menu.tsx +0 -83
  57. package/src/components/ui/prompt-input/attachments.tsx +0 -181
  58. package/src/components/ui/prompt-input/autocomplete.tsx +0 -168
  59. package/src/components/ui/prompt-input/context.tsx +0 -71
  60. package/src/components/ui/prompt-input/mic-button.tsx +0 -53
  61. package/src/components/ui/prompt-input/prompt-input.tsx +0 -279
  62. package/src/components/ui/prompt-input/submit-button.tsx +0 -50
  63. package/src/components/ui/prompt-input/textarea.tsx +0 -80
  64. package/src/components/ui/text.tsx +0 -29
  65. package/src/components/voice/AudioWaveVisualizer.tsx +0 -444
  66. package/src/components/voice/VoiceOverlay.tsx +0 -75
@@ -1,29 +0,0 @@
1
- import * as React from "react";
2
- import { Text as RNText, type TextProps as RNTextProps } from "react-native";
3
- import { cn } from "../../lib/utils";
4
-
5
- const TextClassContext = React.createContext<string | undefined>(undefined);
6
-
7
- export type TextProps = RNTextProps & {
8
- className?: string;
9
- };
10
-
11
- const Text = React.forwardRef<RNText, TextProps>(
12
- ({ className, ...props }, ref) => {
13
- const textClass = React.useContext(TextClassContext);
14
- return (
15
- <RNText
16
- className={cn(
17
- "text-base leading-7 text-foreground web:select-text font-sans",
18
- textClass,
19
- className
20
- )}
21
- ref={ref}
22
- {...props}
23
- />
24
- );
25
- }
26
- );
27
- Text.displayName = "Text";
28
-
29
- export { Text, TextClassContext };
@@ -1,444 +0,0 @@
1
- import React, { useEffect, useMemo } from 'react';
2
- import { View, Platform, useWindowDimensions, useColorScheme } from 'react-native';
3
- import Svg, { Path } from 'react-native-svg';
4
- import Animated, {
5
- useSharedValue,
6
- useAnimatedProps,
7
- useAnimatedStyle,
8
- withTiming,
9
- withRepeat,
10
- withSequence,
11
- Easing,
12
- type SharedValue,
13
- } from 'react-native-reanimated';
14
- import type { AgentState } from '../../types';
15
-
16
- const AnimatedPath = Animated.createAnimatedComponent(Path);
17
-
18
- /** Cross-platform blur: CSS string on web, RN array syntax on native */
19
- type BlurStyle =
20
- | { filter: string; WebkitFilter: string }
21
- | { filter: Array<{ blur: number }> };
22
-
23
- function blurStyle(radius: number): BlurStyle {
24
- return Platform.OS === 'web'
25
- ? { filter: `blur(${radius}px)`, WebkitFilter: `blur(${radius}px)` }
26
- : { filter: [{ blur: radius }] };
27
- }
28
-
29
- const GLOW_HEIGHT = 350;
30
- const NUM_POINTS = 8;
31
-
32
- // Ocean-style wave layers: fill from bottom to a surface level, crests undulate
33
- interface WaveLayerConfig {
34
- color: string;
35
- surfaceY: number; // surface level as % from top (50 = middle)
36
- waveHeight: number; // base crest height in px
37
- maxWaveBoost: number; // extra crest height from audio
38
- phaseOffset: number;
39
- speed: number; // ms for one full horizontal cycle
40
- blur: number;
41
- }
42
-
43
- const WAVE_LAYERS: WaveLayerConfig[] = [
44
- // Deepest layer - dark blue, highest surface (closest to top)
45
- {
46
- color: 'rgba(12, 74, 110, 0.8)',
47
- surfaceY: 35,
48
- waveHeight: 14,
49
- maxWaveBoost: 120,
50
- phaseOffset: 0,
51
- speed: 7000,
52
- blur: 30,
53
- },
54
- // Mid layer - ocean blue
55
- {
56
- color: 'rgba(14, 165, 233, 0.45)',
57
- surfaceY: 42,
58
- waveHeight: 16,
59
- maxWaveBoost: 140,
60
- phaseOffset: Math.PI * 0.8,
61
- speed: 5500,
62
- blur: 22,
63
- },
64
- // Front layer - bright cyan, lowest surface
65
- {
66
- color: 'rgba(56, 189, 248, 0.35)',
67
- surfaceY: 50,
68
- waveHeight: 20,
69
- maxWaveBoost: 150,
70
- phaseOffset: Math.PI * 1.5,
71
- speed: 4500,
72
- blur: 16,
73
- },
74
- // Accent layer - indigo/purple
75
- {
76
- color: 'rgba(99, 102, 241, 0.25)',
77
- surfaceY: 38,
78
- waveHeight: 12,
79
- maxWaveBoost: 100,
80
- phaseOffset: Math.PI * 0.3,
81
- speed: 8000,
82
- blur: 28,
83
- },
84
- ];
85
-
86
- // Background glow blobs for ambient color
87
- interface BlobConfig {
88
- color: string;
89
- baseWidth: number;
90
- baseHeight: number;
91
- x: number;
92
- y: number;
93
- blur: number;
94
- amplitudeScale: number;
95
- phaseSpeed: number;
96
- phaseDirection: 1 | -1;
97
- }
98
-
99
- const BLOBS: BlobConfig[] = [
100
- {
101
- color: '#0c4a6e',
102
- baseWidth: 320,
103
- baseHeight: 200,
104
- x: 50,
105
- y: 55,
106
- blur: 80,
107
- amplitudeScale: 1.0,
108
- phaseSpeed: 4000,
109
- phaseDirection: 1,
110
- },
111
- {
112
- color: '#0ea5e9',
113
- baseWidth: 220,
114
- baseHeight: 140,
115
- x: 38,
116
- y: 65,
117
- blur: 60,
118
- amplitudeScale: 1.2,
119
- phaseSpeed: 3500,
120
- phaseDirection: -1,
121
- },
122
- {
123
- color: '#6366f1',
124
- baseWidth: 180,
125
- baseHeight: 160,
126
- x: 70,
127
- y: 55,
128
- blur: 70,
129
- amplitudeScale: 0.7,
130
- phaseSpeed: 4500,
131
- phaseDirection: -1,
132
- },
133
- {
134
- color: '#a855f7',
135
- baseWidth: 130,
136
- baseHeight: 110,
137
- x: 78,
138
- y: 65,
139
- blur: 60,
140
- amplitudeScale: 0.5,
141
- phaseSpeed: 5500,
142
- phaseDirection: 1,
143
- },
144
- ];
145
-
146
- // Colors per agent state for waves — speaking blends blue + purple
147
- const WAVE_COLORS: Record<AgentState, WaveLayerConfig['color'][]> = {
148
- idle: [
149
- 'rgba(12, 74, 110, 0.8)',
150
- 'rgba(14, 165, 233, 0.45)',
151
- 'rgba(56, 189, 248, 0.35)',
152
- 'rgba(99, 102, 241, 0.25)',
153
- ],
154
- listening: [
155
- 'rgba(12, 74, 110, 0.8)',
156
- 'rgba(14, 165, 233, 0.45)',
157
- 'rgba(56, 189, 248, 0.35)',
158
- 'rgba(99, 102, 241, 0.25)',
159
- ],
160
- thinking: [
161
- 'rgba(120, 80, 20, 0.75)',
162
- 'rgba(234, 179, 8, 0.45)',
163
- 'rgba(251, 191, 36, 0.35)',
164
- 'rgba(253, 224, 71, 0.25)',
165
- ],
166
- speaking: [
167
- 'rgba(30, 40, 100, 0.8)',
168
- 'rgba(99, 102, 241, 0.5)',
169
- 'rgba(147, 51, 234, 0.4)',
170
- 'rgba(56, 189, 248, 0.3)',
171
- ],
172
- };
173
-
174
- const BLOB_COLORS: Record<AgentState, string[]> = {
175
- idle: ['#0c4a6e', '#0ea5e9', '#6366f1', '#a855f7'],
176
- listening: ['#0c4a6e', '#0ea5e9', '#6366f1', '#a855f7'],
177
- thinking: ['#92400e', '#eab308', '#f59e0b', '#fbbf24'],
178
- speaking: ['#1e2870', '#6366f1', '#9333ea', '#0ea5e9'],
179
- };
180
-
181
- // Derive wave & blob palettes from a hex color
182
- /** Parse a CSS color string (#rgb, #rrggbb, rgb(...), rgba(...)) to [r,g,b]; null if unrecognized. */
183
- function parseColor(input: string): [number, number, number] | null {
184
- const s = input.trim();
185
- if (s.startsWith('#')) {
186
- const h = s.slice(1);
187
- const expanded = h.length === 3 ? h[0] + h[0] + h[1] + h[1] + h[2] + h[2] : h;
188
- if (expanded.length !== 6) return null;
189
- const r = parseInt(expanded.slice(0, 2), 16);
190
- const g = parseInt(expanded.slice(2, 4), 16);
191
- const b = parseInt(expanded.slice(4, 6), 16);
192
- return Number.isNaN(r) || Number.isNaN(g) || Number.isNaN(b) ? null : [r, g, b];
193
- }
194
- // rgb()/rgba() — comma OR space separated (rgb(r, g, b) and modern rgb(r g b / a)); alpha ignored
195
- const match = s.match(/^rgba?\(\s*(\d+)[\s,]+(\d+)[\s,]+(\d+)/i);
196
- return match ? [Number(match[1]), Number(match[2]), Number(match[3])] : null;
197
- }
198
-
199
- function darken(rgb: [number, number, number], factor: number): [number, number, number] {
200
- return [Math.round(rgb[0] * factor), Math.round(rgb[1] * factor), Math.round(rgb[2] * factor)];
201
- }
202
-
203
- function lighten(rgb: [number, number, number], factor: number): [number, number, number] {
204
- return [
205
- Math.min(255, Math.round(rgb[0] + (255 - rgb[0]) * factor)),
206
- Math.min(255, Math.round(rgb[1] + (255 - rgb[1]) * factor)),
207
- Math.min(255, Math.round(rgb[2] + (255 - rgb[2]) * factor)),
208
- ];
209
- }
210
-
211
- function deriveWavePalette(color: string, isDark: boolean): { waves: string[]; blobs: string[] } | null {
212
- const rgb = parseColor(color);
213
- if (!rgb) return null;
214
- // Dark mode: lighter/brighter waves visible against dark bg
215
- // Light mode: darker waves visible against light bg
216
- const layer0 = isDark ? darken(rgb, 0.55) : darken(rgb, 0.3);
217
- const layer1 = isDark ? lighten(rgb, 0.15) : darken(rgb, 0.5);
218
- const layer2 = isDark ? lighten(rgb, 0.4) : darken(rgb, 0.15);
219
- const layer3 = isDark ? lighten(rgb, 0.6) : rgb;
220
- return {
221
- waves: [
222
- `rgba(${layer0[0]}, ${layer0[1]}, ${layer0[2]}, 0.8)`,
223
- `rgba(${layer1[0]}, ${layer1[1]}, ${layer1[2]}, 0.45)`,
224
- `rgba(${layer2[0]}, ${layer2[1]}, ${layer2[2]}, 0.35)`,
225
- `rgba(${layer3[0]}, ${layer3[1]}, ${layer3[2]}, 0.25)`,
226
- ],
227
- blobs: [
228
- `rgb(${layer0[0]}, ${layer0[1]}, ${layer0[2]})`,
229
- `rgb(${layer1[0]}, ${layer1[1]}, ${layer1[2]})`,
230
- `rgb(${layer2[0]}, ${layer2[1]}, ${layer2[2]})`,
231
- `rgb(${layer3[0]}, ${layer3[1]}, ${layer3[2]})`,
232
- ],
233
- };
234
- }
235
-
236
- interface AudioWaveVisualizerProps {
237
- waveAmplitude: SharedValue<number>;
238
- agentState: AgentState;
239
- isConnected?: boolean;
240
- /** Theme primary color hex — derives idle/listening wave palette */
241
- primaryColor?: string;
242
- /** Whether the app is in dark mode (affects wave brightness) */
243
- isDarkMode?: boolean;
244
- }
245
-
246
- export function AudioWaveVisualizer({
247
- waveAmplitude,
248
- agentState = 'idle',
249
- isConnected = true,
250
- primaryColor,
251
- isDarkMode,
252
- }: AudioWaveVisualizerProps) {
253
- const { width: screenWidth } = useWindowDimensions();
254
- const scheme = useColorScheme();
255
- const effectiveIsDark = isDarkMode ?? (scheme === 'dark');
256
- const state = WAVE_COLORS[agentState] ? agentState : 'idle';
257
-
258
- // Use theme-derived palette for idle/listening, keep hardcoded for thinking/speaking
259
- const themed = useMemo(
260
- () => (primaryColor ? deriveWavePalette(primaryColor, effectiveIsDark) : null),
261
- [primaryColor, effectiveIsDark],
262
- );
263
- const isThemed = (state === 'idle' || state === 'listening') && themed != null;
264
- const waveColors = isThemed ? themed.waves : WAVE_COLORS[state];
265
- const blobColors = isThemed ? themed.blobs : BLOB_COLORS[state];
266
-
267
- return (
268
- <View
269
- style={{
270
- width: screenWidth,
271
- height: GLOW_HEIGHT,
272
- position: 'relative',
273
- }}
274
- >
275
- {/* Background glow blobs */}
276
- {BLOBS.map((blob, i) => (
277
- <GlowBlob
278
- key={`blob-${i}`}
279
- blob={blob}
280
- color={blobColors[i]}
281
- waveAmplitude={waveAmplitude}
282
- isConnected={isConnected}
283
- screenWidth={screenWidth}
284
- />
285
- ))}
286
-
287
- {/* Ocean wave layers — filled from surface down to bottom, with blur */}
288
- {WAVE_LAYERS.map((layer, i) => (
289
- <OceanWave
290
- key={`wave-${i}`}
291
- layer={layer}
292
- color={waveColors[i]}
293
- waveAmplitude={waveAmplitude}
294
- isConnected={isConnected}
295
- screenWidth={screenWidth}
296
- />
297
- ))}
298
- </View>
299
- );
300
- }
301
-
302
- // Ocean wave: surface undulates horizontally, filled from surface to bottom
303
- function OceanWave({
304
- layer,
305
- color,
306
- waveAmplitude,
307
- isConnected,
308
- screenWidth,
309
- }: {
310
- layer: WaveLayerConfig;
311
- color: string;
312
- waveAmplitude: SharedValue<number>;
313
- isConnected: boolean;
314
- screenWidth: number;
315
- }) {
316
- const phase = useSharedValue(0);
317
-
318
- useEffect(() => {
319
- phase.value = 0;
320
- phase.value = withRepeat(
321
- withTiming(Math.PI * 2, { duration: layer.speed, easing: Easing.linear }),
322
- -1,
323
- false,
324
- );
325
- }, []);
326
-
327
- const animatedProps = useAnimatedProps(() => {
328
- const amp = waveAmplitude.value;
329
- // Surface Y position (fixed, doesn't move with audio)
330
- const surfaceY = (layer.surfaceY / 100) * GLOW_HEIGHT;
331
- // Wave crest height: base + audio boost
332
- const crestHeight = layer.waveHeight + amp * layer.maxWaveBoost;
333
- const currentPhase = phase.value + layer.phaseOffset;
334
- const segW = screenWidth / NUM_POINTS;
335
-
336
- // Start at bottom-left corner
337
- let d = `M 0 ${GLOW_HEIGHT}`;
338
-
339
- // Up to first surface point
340
- const firstY = surfaceY + Math.sin(currentPhase) * crestHeight;
341
- d += ` L 0 ${firstY}`;
342
-
343
- // Draw undulating surface across the width
344
- for (let i = 0; i < NUM_POINTS; i++) {
345
- const x1 = (i + 1) * segW;
346
- const y0 =
347
- surfaceY +
348
- Math.sin(currentPhase + (i / NUM_POINTS) * Math.PI * 2) * crestHeight;
349
- const y1 =
350
- surfaceY +
351
- Math.sin(currentPhase + ((i + 1) / NUM_POINTS) * Math.PI * 2) * crestHeight;
352
-
353
- const cp1x = i * segW + segW * 0.5;
354
- const cp2x = x1 - segW * 0.5;
355
-
356
- d += ` C ${cp1x} ${y0}, ${cp2x} ${y1}, ${x1} ${y1}`;
357
- }
358
-
359
- // Close: down to bottom-right, across to bottom-left
360
- d += ` L ${screenWidth} ${GLOW_HEIGHT} Z`;
361
-
362
- return { d };
363
- });
364
-
365
- return (
366
- <View
367
- style={{
368
- position: 'absolute',
369
- top: 0,
370
- left: 0,
371
- right: 0,
372
- bottom: 0,
373
- opacity: isConnected ? 1 : 0,
374
- ...blurStyle(layer.blur),
375
- pointerEvents: 'none',
376
- }}
377
- >
378
- <Svg width={screenWidth} height={GLOW_HEIGHT}>
379
- <AnimatedPath animatedProps={animatedProps} fill={color} />
380
- </Svg>
381
- </View>
382
- );
383
- }
384
-
385
- // Ambient glow blob
386
- function GlowBlob({
387
- blob,
388
- color,
389
- waveAmplitude,
390
- isConnected,
391
- screenWidth,
392
- }: {
393
- blob: BlobConfig;
394
- color: string;
395
- waveAmplitude: SharedValue<number>;
396
- isConnected: boolean;
397
- screenWidth: number;
398
- }) {
399
- const drift = useSharedValue(0);
400
-
401
- useEffect(() => {
402
- drift.value = 0;
403
- drift.value = withRepeat(
404
- withSequence(
405
- withTiming(1, {
406
- duration: blob.phaseSpeed,
407
- easing: Easing.bezier(0.37, 0, 0.63, 1),
408
- }),
409
- withTiming(0, {
410
- duration: blob.phaseSpeed,
411
- easing: Easing.bezier(0.37, 0, 0.63, 1),
412
- }),
413
- ),
414
- -1,
415
- false,
416
- );
417
- }, []);
418
-
419
- const animatedStyle = useAnimatedStyle(() => {
420
- const amp = waveAmplitude.value;
421
- const scale = 1 + amp * 0.3 * blob.amplitudeScale;
422
- const driftOffset = (drift.value - 0.5) * 20 * blob.phaseDirection;
423
- const opacity = isConnected ? 0.45 + amp * 0.35 * blob.amplitudeScale : 0;
424
-
425
- const w = blob.baseWidth * scale;
426
- const h = blob.baseHeight * scale;
427
- const left = (blob.x / 100) * screenWidth - w / 2 + driftOffset;
428
- const top = (blob.y / 100) * GLOW_HEIGHT - h / 2;
429
-
430
- return {
431
- position: 'absolute' as const,
432
- width: w,
433
- height: h,
434
- left,
435
- top,
436
- borderRadius: w / 2,
437
- backgroundColor: color,
438
- opacity,
439
- transform: [{ scale }],
440
- };
441
- });
442
-
443
- return <Animated.View style={[animatedStyle, blurStyle(blob.blur)]} />;
444
- }
@@ -1,75 +0,0 @@
1
- /**
2
- * Subtle wave overlay that renders the AudioWaveVisualizer behind the
3
- * conversation message list. Always mounted; `intensity` ramps the opacity
4
- * between a barely-there idle ambient and a prominent speaking state.
5
- */
6
-
7
- import Animated, {
8
- FadeIn,
9
- FadeOut,
10
- useSharedValue,
11
- useAnimatedReaction,
12
- useAnimatedStyle,
13
- withTiming,
14
- } from 'react-native-reanimated';
15
- import { AudioWaveVisualizer } from './AudioWaveVisualizer';
16
- import type { SharedValue } from 'react-native-reanimated';
17
- import type { AgentState } from '../../types';
18
-
19
- interface VoiceOverlayProps {
20
- waveAmplitude: SharedValue<number>;
21
- agentState: AgentState;
22
- /** Overlay opacity target (default 0.35); ramps over 500ms when it changes. */
23
- intensity?: number;
24
- isConnected?: boolean;
25
- primaryColor?: string;
26
- isDarkMode?: boolean;
27
- }
28
-
29
- export function VoiceOverlay({
30
- waveAmplitude,
31
- agentState,
32
- intensity = 0.35,
33
- isConnected = true,
34
- primaryColor,
35
- isDarkMode,
36
- }: VoiceOverlayProps) {
37
- // Imperative opacity ramp (web-safe): mapper-started style animations don't
38
- // tick on reanimated-web, so drive a shared value via useAnimatedReaction.
39
- const opacity = useSharedValue(intensity);
40
- useAnimatedReaction(
41
- () => intensity,
42
- (target, previous) => {
43
- if (target === previous) return;
44
- opacity.value = withTiming(target, { duration: 500 });
45
- },
46
- [intensity],
47
- );
48
- const animatedStyle = useAnimatedStyle(() => ({ opacity: opacity.value }));
49
-
50
- return (
51
- <Animated.View
52
- entering={FadeIn.duration(400)}
53
- exiting={FadeOut.duration(300)}
54
- style={{
55
- position: 'absolute',
56
- bottom: 0,
57
- left: 0,
58
- right: 0,
59
- height: 350,
60
- zIndex: 5,
61
- pointerEvents: 'none',
62
- }}
63
- >
64
- <Animated.View style={animatedStyle}>
65
- <AudioWaveVisualizer
66
- waveAmplitude={waveAmplitude}
67
- agentState={agentState}
68
- isConnected={isConnected}
69
- primaryColor={primaryColor}
70
- isDarkMode={isDarkMode}
71
- />
72
- </Animated.View>
73
- </Animated.View>
74
- );
75
- }