import { View, TextInput, Pressable, Text } from "react-native"; import { useState } from "react"; import { StyleSheet, useUnistyles } from "react-native-unistyles"; import { Mic, ArrowUp, AudioLines, Square, ChevronDown } from "lucide-react-native"; import { useSession } from "@/contexts/session-context"; import { useRealtime } from "@/contexts/realtime-context"; import { useAudioRecorder } from "@/hooks/use-audio-recorder"; import { ModeSelectorModal } from "./mode-selector-modal"; interface AgentInputAreaProps { agentId: string; } export function AgentInputArea({ agentId }: AgentInputAreaProps) { const { theme } = useUnistyles(); const { agents, ws, sendAgentMessage, sendAgentAudio, setAgentMode } = useSession(); const { isRealtimeMode, startRealtime } = useRealtime(); const audioRecorder = useAudioRecorder(); const [userInput, setUserInput] = useState(""); const [isRecording, setIsRecording] = useState(false); const [isProcessing, setIsProcessing] = useState(false); const [showModeSelector, setShowModeSelector] = useState(false); const agent = agents.get(agentId); // Hide when realtime is active - global footer takes over if (isRealtimeMode) { return null; } async function handleSendMessage() { if (!userInput.trim() || !ws.isConnected) return; const message = userInput.trim(); setUserInput(""); setIsProcessing(true); try { sendAgentMessage(agentId, message); } catch (error) { console.error("[AgentInput] Failed to send message:", error); } finally { setIsProcessing(false); } } async function handleVoicePress() { if (isRecording) { // Stop recording try { setIsRecording(false); const audioData = await audioRecorder.stop(); if (audioData) { setIsProcessing(true); console.log("[AgentInput] Audio recorded:", audioData.size, "bytes"); try { // Send audio to agent for transcription and processing await sendAgentAudio(agentId, audioData); console.log("[AgentInput] Audio sent to agent"); } catch (error) { console.error("[AgentInput] Failed to send audio:", error); } finally { setIsProcessing(false); } } } catch (error) { console.error("[AgentInput] Failed to stop recording:", error); setIsRecording(false); setIsProcessing(false); } } else { // Start recording try { await audioRecorder.start(); setIsRecording(true); } catch (error) { console.error("[AgentInput] Failed to start recording:", error); } } } function handleModeChange(modeId: string) { setAgentMode(agentId, modeId); } const hasText = userInput.trim().length > 0; return ( {/* Text input */} {/* Controls row */} {/* Mode badge - only show if agent has modes */} {agent && agent.availableModes && agent.availableModes.length > 0 && ( setShowModeSelector(true)} style={({ pressed }) => [ styles.modeBadge, pressed && styles.modeBadgePressed, ]} > {agent.availableModes?.find(m => m.id === agent.currentModeId)?.name || agent.currentModeId || 'default'} )} {/* Buttons */} {hasText ? ( // Send button when text is entered ) : ( // Voice and Realtime buttons when no text <> {/* Voice recording button */} {isRecording ? ( ) : ( )} {/* Realtime button */} )} {/* Mode selector modal */} setShowModeSelector(false)} /> ); } const styles = StyleSheet.create((theme) => ({ container: { padding: theme.spacing[4], gap: theme.spacing[3], }, textInput: { minHeight: 44, maxHeight: 120, paddingHorizontal: theme.spacing[4], paddingVertical: theme.spacing[3], backgroundColor: theme.colors.muted, borderRadius: theme.borderRadius.lg, color: theme.colors.foreground, fontSize: theme.fontSize.base, }, controlsRow: { flexDirection: "row", alignItems: "center", justifyContent: "space-between", gap: theme.spacing[2], }, modeBadge: { flexDirection: "row", alignItems: "center", gap: theme.spacing[2], paddingHorizontal: theme.spacing[3], paddingVertical: theme.spacing[2], backgroundColor: theme.colors.muted, borderRadius: theme.borderRadius.full, }, modeBadgePressed: { backgroundColor: theme.colors.accent, }, modeBadgeText: { color: theme.colors.mutedForeground, fontSize: theme.fontSize.xs, fontWeight: theme.fontWeight.semibold, textTransform: "capitalize", }, buttonRow: { flexDirection: "row", alignItems: "center", gap: theme.spacing[2], marginLeft: "auto", }, sendButton: { width: 40, height: 40, borderRadius: theme.borderRadius.full, backgroundColor: theme.colors.palette.blue[600], alignItems: "center", justifyContent: "center", }, voiceButton: { width: 40, height: 40, borderRadius: theme.borderRadius.full, backgroundColor: "transparent", alignItems: "center", justifyContent: "center", }, voiceButtonRecording: { backgroundColor: theme.colors.destructive, }, realtimeButton: { width: 40, height: 40, borderRadius: theme.borderRadius.full, backgroundColor: theme.colors.accentForeground, alignItems: "center", justifyContent: "center", }, buttonDisabled: { opacity: 0.5, }, }));