@contentgrowth/llm-service 0.8.4 → 0.8.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 +1 @@
1
- {"version":3,"sources":["../../../../src/ui/react/components/ChatBubble.tsx","../../../../src/ui/react/components/MessageBubble.tsx","../../../../src/ui/react/context/ChatConfigContext.tsx","../../../../src/ui/react/components/ChatHeader.tsx","../../../../src/ui/react/components/ChatInputArea.tsx","../../../../src/ui/react/hooks/useSpeechRecognition.ts","../../../../src/ui/react/hooks/useAudioRecorder.ts","../../../../src/ui/react/hooks/useProactiveResize.ts","../../../../src/ui/react/components/ChatMessageList.tsx","../../../../src/ui/react/components/interactive/ConfirmInteraction.tsx","../../../../src/ui/react/components/interactive/SelectInteraction.tsx","../../../../src/ui/react/components/interactive/FormInteraction.tsx","../../../../src/ui/react/components/interactive/PresentInteraction.tsx","../../../../src/ui/react/components/interactive/InteractiveMessageHandler.tsx","../../../../src/ui/react/components/ConnectionStatus.tsx","../../../../src/ui/react/components/Spinner.tsx","../../../../src/ui/react/services/whisper-client.ts","../../../../src/ui/react/utils/voice-utils.ts"],"sourcesContent":["'use client';\n\nimport React from 'react';\n\ninterface ChatBubbleProps {\n onClick: () => void;\n}\n\nexport function ChatBubble({ onClick }: ChatBubbleProps) {\n return (\n <button\n onClick={onClick}\n className=\"bg-blue-500 hover:bg-blue-600 text-white rounded-full w-12 h-12 flex items-center justify-center shadow-lg animate-pulse\"\n aria-label=\"Open chat assistant\"\n >\n <svg xmlns=\"http://www.w3.org/2000/svg\" className=\"h-6 w-6\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\">\n <path strokeLinecap=\"round\" strokeLinejoin=\"round\" strokeWidth={2} d=\"M8 10h.01M12 10h.01M16 10h.01M9 16H5a2 2 0 01-2-2V6a2 2 0 012-2h14a2 2 0 012 2v8a2 2 0 01-2 2h-5l-5 5v-5z\" />\n </svg>\n </button>\n );\n}\n","'use client';\n\nimport React from 'react';\nimport ReactMarkdown from 'react-markdown';\nimport remarkGfm from 'remark-gfm';\nimport { SparklesIcon } from '@heroicons/react/24/solid';\nimport { ChatMessage } from '../types/chat';\nimport { useChatConfig } from '../context/ChatConfigContext';\n\nexport interface MessageBubbleProps {\n message: ChatMessage;\n isUser: boolean;\n userAvatarUrl?: string; // Optional user avatar URL\n onViewChanges?: (diff: { oldContent: string; newContent: string }) => void;\n}\n\nexport const MessageBubble: React.FC<MessageBubbleProps> = ({\n message,\n isUser,\n userAvatarUrl,\n onViewChanges\n}) => {\n const { user } = useChatConfig();\n const finalAvatarUrl = userAvatarUrl || user?.avatarUrl;\n const isSystem = message.role === 'system';\n\n if (isSystem) {\n return (\n <div className=\"text-center my-4\">\n <span className=\"text-xs text-gray-500 italic bg-gray-100 px-3 py-1 rounded-full\">\n {message.content}\n {message.diff && onViewChanges && (\n <button\n onClick={() => onViewChanges(message.diff!)}\n className=\"ml-2 font-semibold text-blue-600 hover:underline focus:outline-none\"\n >\n View Changes\n </button>\n )}\n </span>\n </div>\n );\n }\n\n return (\n <div className={`flex items-start gap-3 my-4 ${isUser ? 'justify-end' : 'justify-start'}`}>\n {/* Assistant Avatar */}\n {!isUser && (\n <div className=\"flex-shrink-0 h-8 w-8 rounded-full bg-blue-500 flex items-center justify-center text-white\">\n <SparklesIcon className=\"h-5 w-5\" />\n </div>\n )}\n\n {/* Content Bubble */}\n <div\n className={`max-w-[85%] px-4 py-3 rounded-2xl shadow-sm overflow-hidden ${isUser\n ? 'bg-blue-500 text-white rounded-br-none'\n : 'bg-gray-100 text-gray-800 rounded-bl-none'\n }`}>\n <div className={`text-sm ${!isUser ? 'prose prose-sm max-w-none' : ''}`}>\n {isUser ? (\n <p className=\"whitespace-pre-wrap\">{message.content}</p>\n ) : (\n <ReactMarkdown\n remarkPlugins={[remarkGfm]}\n components={{\n p: ({ node, ...props }) => <p className=\"mb-2 last:mb-0\" {...props} />,\n ul: ({ node, ...props }) => <ul className=\"list-disc ml-4 mb-2\" {...props} />,\n ol: ({ node, ...props }) => <ol className=\"list-decimal ml-4 mb-2\" {...props} />,\n li: ({ node, ...props }) => <li className=\"mb-0.5\" {...props} />,\n a: ({ node, ...props }) => <a className=\"text-blue-600 hover:underline\" {...props} />,\n code: ({ node, ...props }) => <code className=\"bg-gray-200 rounded px-1 py-0.5 text-xs font-mono\" {...props} />\n }}\n >\n {message.content}\n </ReactMarkdown>\n )}\n </div>\n {message.role === 'assistant' && message.diff && onViewChanges && (\n <button\n onClick={() => onViewChanges(message.diff!)}\n className=\"mt-2 text-sm text-blue-500 hover:underline block\"\n >\n View Changes\n </button>\n )}\n {message.actionResult && message.actionResult.type === 'link' && (\n <div className=\"mt-2 pt-2 border-t border-gray-300\">\n <a\n href={message.actionResult.url}\n target={message.actionResult.target || '_blank'}\n rel=\"noopener noreferrer\"\n onClick={(e) => {\n if (message.actionResult?.target && message.actionResult.target !== '_blank') {\n e.preventDefault();\n window.open(message.actionResult.url, message.actionResult.target);\n }\n }}\n className={`inline-flex items-center gap-1 text-sm font-medium hover:underline ${isUser\n ? 'text-blue-100 hover:text-white'\n : 'text-blue-600 hover:text-blue-800'\n }`}\n >\n {message.actionResult.label}\n <svg className=\"w-3.5 h-3.5\" fill=\"none\" stroke=\"currentColor\" viewBox=\"0 0 24 24\">\n <path strokeLinecap=\"round\" strokeLinejoin=\"round\" strokeWidth={2} d=\"M10 6H6a2 2 0 00-2 2v10a2 2 0 002 2h10a2 2 0 002-2v-4M14 4h6m0 0v6m0-6L10 14\" />\n </svg>\n </a>\n </div>\n )}\n </div>\n\n {/* User Avatar */}\n {isUser && (\n <div className=\"flex-shrink-0 h-8 w-8 rounded-full bg-gray-200 overflow-hidden flex items-center justify-center text-gray-500\">\n {finalAvatarUrl ? (\n <img\n className=\"h-full w-full object-cover\"\n src={finalAvatarUrl}\n alt=\"User\"\n onError={(e) => {\n // Hide image and show fallback icon if load fails involves state, \n // but for a simple component we can just hide it or let the parent handle it.\n // For now, let's just render the icon if no url, \n // preventing the broken image icon requires state or a different approach (like standard Radix Avatar).\n // A simple hack: set src to a transparent pixel or hide display.\n (e.target as HTMLImageElement).style.display = 'none';\n (e.target as HTMLImageElement).parentElement?.classList.remove('bg-gray-200'); // Clean up?\n // Actually, better to just render the fallback SVG behind it?\n // Let's try separate conditional structure.\n }}\n />\n ) : (\n <svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 24 24\" fill=\"currentColor\" className=\"w-5 h-5\">\n <path fillRule=\"evenodd\" d=\"M7.5 6a4.5 4.5 0 1 1 9 0 4.5 4.5 0 0 1-9 0ZM3.751 20.105a8.25 8.25 0 0 1 16.498 0 .75.75 0 0 1-.437.695A18.683 18.683 0 0 1 12 22.5c-2.786 0-5.433-.608-7.812-1.7a.75.75 0 0 1-.437-.695Z\" clipRule=\"evenodd\" />\n </svg>\n )}\n </div>\n )}\n </div>\n );\n};\n","import React, { createContext, useContext, ReactNode } from 'react';\nimport { VoiceConfig } from '../types/chat';\n\nexport interface ChatConfig {\n user?: {\n avatarUrl?: string;\n name?: string;\n };\n voice?: {\n enabled: boolean;\n config?: VoiceConfig;\n };\n}\n\nconst ChatConfigContext = createContext<ChatConfig>({});\n\nexport const ChatConfigProvider: React.FC<{\n config: ChatConfig;\n children: ReactNode;\n}> = ({ config, children }) => {\n return (\n <ChatConfigContext.Provider value={config}>\n {children}\n </ChatConfigContext.Provider>\n );\n};\n\nexport const useChatConfig = () => useContext(ChatConfigContext);\n","'use client';\n\nimport React from 'react';\nimport { ChatTask } from '../types/chat';\n\ninterface ChatHeaderProps {\n contextTitle: string;\n currentTask: ChatTask | null;\n onClose: () => void;\n}\n\nexport function ChatHeader({\n contextTitle,\n currentTask,\n onClose\n}: ChatHeaderProps) {\n return (\n <div className=\"bg-blue-500 text-white px-4 py-4 flex justify-between items-center\">\n <h3 className=\"font-medium text-lg\">\n {currentTask\n ? `DoveText Virtual Assistant (${currentTask.currentStep}/${currentTask.steps})`\n : `DoveText Virtual Assistant (${contextTitle})`}\n </h3>\n <button\n onClick={onClose}\n className=\"bg-blue-600 hover:bg-blue-700 text-white rounded-full p-1.5 flex items-center justify-center transition-colors cursor-pointer\"\n aria-label=\"Close chat\"\n >\n <svg xmlns=\"http://www.w3.org/2000/svg\" className=\"h-5 w-5\" viewBox=\"0 0 20 20\" fill=\"currentColor\">\n <path fillRule=\"evenodd\" d=\"M4.293 4.293a1 1 0 011.414 0L10 8.586l4.293-4.293a1 1 0 111.414 1.414L11.414 10l4.293 4.293a1 1 0 01-1.414 1.414L10 11.414l-4.293 4.293a1 1 0 01-1.414-1.414L8.586 10 4.293 5.707a1 1 0 010-1.414z\" clipRule=\"evenodd\" />\n </svg>\n </button>\n </div>\n );\n}\n","'use client';\n\nimport React, { useState, useRef, FormEvent, useImperativeHandle, forwardRef, useEffect } from 'react';\nimport { ArrowUpCircleIcon, MicrophoneIcon, StopIcon, PaperAirplaneIcon } from '@heroicons/react/24/outline';\nimport { ChatMessage, ChatTask, VoiceConfig } from '../types/chat';\nimport { InteractiveFunction } from '../types/interactive';\nimport { useSpeechRecognition } from '../hooks/useSpeechRecognition';\nimport { useAudioRecorder } from '../hooks/useAudioRecorder';\nimport { useProactiveResize } from '../hooks/useProactiveResize';\nimport { useChatConfig } from '../context/ChatConfigContext';\n\n// VoiceConfig imported from types/chat\n\ninterface ChatInputAreaProps {\n onSubmit: (message: string) => void;\n isSending: boolean;\n showInputForm: boolean;\n currentTask: ChatTask | null;\n lastInteractiveMessage?: ChatMessage | null;\n voiceConfig?: VoiceConfig;\n onStop?: () => void;\n hintText?: string;\n placeholder?: string;\n // Controlled props\n value?: string;\n onChange?: (e: React.ChangeEvent<HTMLTextAreaElement>) => void;\n}\n\n// Define the handle type for the forwarded ref\nexport interface ChatInputAreaHandle {\n focus: () => void;\n setValue: (value: string) => void;\n}\n\nexport const ChatInputArea = forwardRef<ChatInputAreaHandle, ChatInputAreaProps>(({\n onSubmit,\n isSending,\n showInputForm,\n currentTask,\n lastInteractiveMessage,\n voiceConfig: propVoiceConfig, // Rename to distinguish from context\n onStop,\n hintText,\n placeholder,\n value,\n onChange\n}, ref) => {\n const [internalMessage, setInternalMessage] = useState('');\n const [isVoiceActive, setIsVoiceActive] = useState(false);\n const [inputMode, setInputMode] = useState<'text' | 'voice'>('text');\n const textareaRef = useRef<HTMLTextAreaElement>(null);\n const measurementRef = useRef<HTMLSpanElement>(null);\n\n // Determine if controlled or uncontrolled\n const isControlled = value !== undefined;\n const message = isControlled ? value : internalMessage;\n\n // Get global config\n const { voice: globalVoice } = useChatConfig();\n\n // Determine effective voice config\n // If global says disabled, then no voice. \n // If global says enabled, use props config OR global config.\n const isVoiceEnabled = globalVoice?.enabled ?? (!!propVoiceConfig);\n const voiceConfig = isVoiceEnabled ? (propVoiceConfig || globalVoice?.config) : undefined;\n\n\n // Helper to fire onChange for non-user-input sources (voice, setValue) if controlled\n const triggerChange = (newValue: string) => {\n if (isControlled && onChange && textareaRef.current) {\n const syntheticEvent = {\n target: { value: newValue },\n currentTarget: { value: newValue }\n } as React.ChangeEvent<HTMLTextAreaElement>;\n onChange(syntheticEvent);\n } else {\n setInternalMessage(newValue);\n }\n };\n\n // Apply auto-resize\n const isInputDisabled = currentTask?.complete ||\n (lastInteractiveMessage?.interactive &&\n ((lastInteractiveMessage?.interactiveData?.function === 'form' && !lastInteractiveMessage?.isResponseSubmitted) ||\n (lastInteractiveMessage?.interactiveData?.function === 'confirm' && !lastInteractiveMessage?.isResponseSubmitted)));\n\n useProactiveResize(textareaRef, measurementRef, message, isInputDisabled || isVoiceActive || inputMode === 'voice');\n\n // Voice Hooks\n const nativeSpeech = useSpeechRecognition((text) => {\n // If native, we typically append text.\n // For \"Hold to Talk\", we might want to just set it or append.\n // Let's stick to append.\n triggerChange(message + (message ? ' ' : '') + text);\n }, () => {\n setIsVoiceActive(false);\n voiceConfig?.onVoiceEnd?.();\n }, voiceConfig?.language);\n\n const customRecorder = useAudioRecorder(async (blob) => {\n setIsVoiceActive(false);\n voiceConfig?.onVoiceEnd?.();\n if (voiceConfig?.onAudioCapture) {\n try {\n const text = await voiceConfig.onAudioCapture(blob);\n if (text) triggerChange(message + (message ? ' ' : '') + text);\n } catch (e) {\n console.error('Audio capture failed', e);\n }\n }\n });\n\n // Expose the focus and setValue method to parent components\n useImperativeHandle(ref, () => ({\n focus: () => {\n textareaRef.current?.focus();\n },\n setValue: (newValue: string) => {\n triggerChange(newValue);\n }\n }));\n\n const handleSubmit = (e?: FormEvent) => {\n if (e) e.preventDefault();\n\n if (!message.trim()) {\n setTimeout(() => textareaRef.current?.focus(), 0);\n return;\n }\n\n const currentMessage = message;\n triggerChange(''); // Clear input\n setTimeout(() => textareaRef.current?.focus(), 0);\n onSubmit(currentMessage);\n };\n\n const handleKeyDown = (e: React.KeyboardEvent<HTMLTextAreaElement>) => {\n if (e.key === 'Enter' && !e.shiftKey && !e.metaKey && !e.altKey) {\n e.preventDefault();\n handleSubmit();\n }\n };\n\n const startRecording = async () => {\n if (isVoiceActive) return;\n setIsVoiceActive(true);\n voiceConfig?.onVoiceStart?.();\n\n if (voiceConfig?.mode === 'native') {\n if (!nativeSpeech.isSupported) {\n alert('Speech recognition is not supported in this browser.');\n setIsVoiceActive(false);\n return;\n }\n nativeSpeech.start();\n } else {\n await customRecorder.start();\n }\n };\n\n const stopRecording = () => {\n if (!isVoiceActive) return;\n if (voiceConfig?.mode === 'native') {\n nativeSpeech.stop();\n } else {\n customRecorder.stop();\n }\n // setIsVoiceActive(false) is handled by callbacks\n };\n\n // Determine placeholder text based on interactive state\n const getPlaceholder = () => {\n if (placeholder) return placeholder;\n if (isVoiceActive) return 'Listening...';\n if (currentTask?.complete) {\n return 'Task completed!';\n }\n\n if (lastInteractiveMessage?.interactive && lastInteractiveMessage?.interactiveData && !lastInteractiveMessage?.isResponseSubmitted) {\n const interactiveType = lastInteractiveMessage.interactiveData.function as InteractiveFunction;\n\n switch (interactiveType) {\n case 'chat':\n return 'Type your response...';\n case 'confirm':\n return 'Select Yes or No, or type your response...';\n case 'select':\n return 'Choose an option or type your response...';\n case 'form':\n return 'Fill out the form...';\n default:\n return 'Type your response...';\n }\n }\n\n return currentTask ? 'Continue your conversation...' : 'Ask me anything...';\n };\n\n const inputHint = (!isInputDisabled && !lastInteractiveMessage?.interactive) ? null :\n (lastInteractiveMessage?.interactiveData?.function === 'form' ? 'Please provide information by completing above form' : null);\n\n if (!showInputForm) {\n return null;\n }\n\n return (\n <div className=\"flex flex-col w-full\">\n <div className=\"flex items-center gap-2\">\n {/* Voice/Keyboard Toggle */}\n {voiceConfig && (\n <button\n type=\"button\"\n onClick={() => {\n // If switching from voice, ensure recording is stopped\n if (inputMode === 'voice' && isVoiceActive) {\n stopRecording();\n }\n setInputMode(prev => prev === 'text' ? 'voice' : 'text');\n }}\n className=\"mb-1 p-2 text-gray-500 hover:text-gray-700 hover:bg-gray-100 rounded-full transition-colors flex-shrink-0 border border-gray-300 bg-white\"\n title={inputMode === 'text' ? \"Switch to Voice\" : \"Switch to Keyboard\"}\n >\n {inputMode === 'text' ? (\n // Voice Icon (Waveform)\n <svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 24 24\" fill=\"currentColor\" className=\"w-5 h-5 text-gray-600\">\n <path d=\"M11.25 4.532A.75.75 0 0 1 12 5.25v13.5a.75.75 0 0 1-1.5 0V5.25a.75.75 0 0 1 .75-.718ZM7.5 8.25a.75.75 0 0 1 .75.75v5.25a.75.75 0 0 1-1.5 0V9a.75.75 0 0 1 .75-.75Zm9 0a.75.75 0 0 1 .75.75v5.25a.75.75 0 0 1-1.5 0V9a.75.75 0 0 1 .75-.75ZM3.75 10.5a.75.75 0 0 1 .75.75v1.5a.75.75 0 0 1-1.5 0v-1.5a.75.75 0 0 1 .75-.75Zm16.5 0a.75.75 0 0 1 .75.75v1.5a.75.75 0 0 1-1.5 0v-1.5a.75.75 0 0 1 .75-.75Z\" />\n </svg>\n ) : (\n // Keyboard Icon (Filled)\n <svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 24 24\" fill=\"currentColor\" className=\"w-5 h-5 text-gray-600\">\n <path fillRule=\"evenodd\" d=\"M3 6a3 3 0 0 1 3-3h12a3 3 0 0 1 3 3v12a3 3 0 0 1-3 3H6a3 3 0 0 1-3-3V6Zm4.5 3a.75.75 0 0 1 .75-.75h1.5a.75.75 0 0 1 .75.75v1.5a.75.75 0 0 1-.75.75h-1.5a.75.75 0 0 1-.75-.75V9Zm6 0a.75.75 0 0 1 .75-.75h1.5a.75.75 0 0 1 .75.75v1.5a.75.75 0 0 1-.75.75h-1.5a.75.75 0 0 1-.75-.75V9Zm6 0a.75.75 0 0 1 .75-.75h1.5a.75.75 0 0 1 .75.75v1.5a.75.75 0 0 1-.75.75h-1.5a.75.75 0 0 1-.75-.75V9Zm-12 4.5a.75.75 0 0 1 .75-.75h1.5a.75.75 0 0 1 .75.75v1.5a.75.75 0 0 1-.75.75h-1.5a.75.75 0 0 1-.75-.75v-1.5Zm6 0a.75.75 0 0 1 .75-.75h6.75a.75.75 0 0 1 .75.75v1.5a.75.75 0 0 1-.75.75h-6.75a.75.75 0 0 1-.75-.75v-1.5Z\" clipRule=\"evenodd\" />\n </svg>\n )}\n </button>\n )}\n\n <div className=\"flex-1 flex items-center border border-gray-300 rounded-lg overflow-hidden focus-within:ring-2 focus-within:ring-blue-500 focus-within:border-blue-500 bg-white min-h-[42px] mb-1\">\n {/* Text Input Mode */}\n {inputMode === 'text' && (\n <>\n {/* Hidden span for proactive width measurement */}\n <span\n ref={measurementRef}\n className=\"absolute invisible whitespace-pre-wrap p-0 m-0 text-gray-700 leading-6\"\n style={{ fontSize: '1rem' }}\n />\n <textarea\n ref={textareaRef}\n value={message}\n onChange={(e) => {\n if (isControlled && onChange) {\n onChange(e);\n } else {\n setInternalMessage(e.target.value);\n }\n }}\n onKeyDown={handleKeyDown}\n placeholder={getPlaceholder()}\n disabled={isInputDisabled || isVoiceActive}\n rows={1}\n className={`flex-grow px-4 py-2 outline-none text-gray-700 placeholder-gray-500 disabled:bg-gray-100 resize-none leading-6 w-full ${isInputDisabled ? 'cursor-not-allowed' : ''}`}\n />\n </>\n )}\n\n {/* Voice Input Mode */}\n {inputMode === 'voice' && (\n <div className=\"flex-grow flex justify-center items-center p-1\">\n <button\n type=\"button\"\n onMouseDown={startRecording}\n onMouseUp={stopRecording}\n onTouchStart={startRecording}\n onTouchEnd={stopRecording}\n disabled={isInputDisabled}\n className={`flex-grow py-2 text-center font-medium rounded-md transition-colors select-none ${isVoiceActive\n ? 'bg-blue-100 text-blue-700'\n : 'bg-gray-50 text-gray-700 hover:bg-gray-100'\n }`}\n >\n {isVoiceActive ? 'Release to Send' : 'Hold to Talk'}\n </button>\n </div>\n )}\n\n {/* Send / Stop Button - Only show in text mode or if sending */}\n {(inputMode === 'text' || isSending) && (\n <div className=\"relative mx-2 flex-shrink-0\">\n {/* Spinner Overlay matching legacy ChatInput */}\n {isSending && (\n <div className=\"absolute -inset-1\">\n <svg\n className=\"animate-spin h-full w-full text-blue-500 opacity-75\"\n xmlns=\"http://www.w3.org/2000/svg\"\n fill=\"none\"\n viewBox=\"0 0 24 24\"\n >\n <circle\n className=\"opacity-25\"\n cx=\"12\"\n cy=\"12\"\n r=\"10\"\n stroke=\"currentColor\"\n strokeWidth=\"4\"\n ></circle>\n <path\n className=\"opacity-75\"\n fill=\"currentColor\"\n d=\"M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z\"\n ></path>\n </svg>\n </div>\n )}\n\n <button\n type=\"button\"\n onClick={(e) => {\n if (isSending && onStop) {\n e.preventDefault();\n onStop();\n } else {\n handleSubmit();\n }\n }}\n disabled={currentTask?.complete || (isSending && !onStop) || isInputDisabled || isVoiceActive}\n className={`relative z-10 text-white rounded-full p-2 transition-colors duration-200 disabled:bg-gray-400 disabled:cursor-not-allowed ${isSending && onStop\n ? 'bg-red-500 hover:bg-red-600'\n : 'bg-blue-600 hover:bg-blue-700'\n }`}\n title={isSending && onStop ? \"Stop generating\" : \"Send message\"}\n >\n {isSending ? (\n onStop ? (\n <StopIcon className=\"h-5 w-5\" />\n ) : (\n // AND we show the overlay spinner outside?\n // Actually `ChatInput.tsx` lines 117-140 are `isLoading && (...)`. It is always shown when loading.\n // So we have a spinner ring AROUND the button (absolute -inset-1).\n // AND potentially a spinner INSIDE the button if no onStop?\n // In my case, I will stick to:\n // If onStop: Show StopIcon. Button is Red.\n // If !onStop: Show Spinner inside? Or just let the outer ring do the work?\n // Legacy `Spinner` component usage inside button suggests double spinner if we are not careful.\n // But usually `onStop` is provided for streaming.\n // If I look at the screenshot, it shows a RED button (with stop icon) and a BLUE ring around it.\n // That matches: Red button (bg-red-500) + Blue Spinner Ring (text-blue-500).\n // So I will replicate that structure.\n <StopIcon className=\"h-5 w-5\" /> // Default fallback if sending without onStop? No, if !onStop, we might just show spinner.\n )\n ) : (\n <PaperAirplaneIcon className=\"h-5 w-5\" />\n )}\n </button>\n </div>\n )}\n </div>\n </div>\n\n {inputHint && (\n <div className=\"text-sm text-red-500 bg-red-50 py-1 px-4 rounded-lg mt-1\">\n {inputHint}\n </div>\n )}\n\n {(hintText && inputMode === 'text') && (\n <p className=\"text-xs text-gray-500 ml-12 mb-2 mt-1\">\n {hintText}\n </p>\n )}\n </div>\n );\n});\n\nChatInputArea.displayName = 'ChatInputArea';\n","import { useState, useEffect, useCallback, useRef } from 'react';\n\nexport interface SpeechRecognitionHook {\n isListening: boolean;\n transcript: string;\n start: () => void;\n stop: () => void;\n resetTranscript: () => void;\n isSupported: boolean;\n error: string | null;\n}\n\ninterface SpeechRecognitionEvent {\n results: {\n [index: number]: {\n [index: number]: {\n transcript: string;\n };\n isFinal: boolean;\n };\n length: number;\n };\n}\n\ninterface SpeechRecognitionErrorEvent {\n error: string;\n}\n\nexport const useSpeechRecognition = (\n onResult?: (text: string, isFinal: boolean) => void,\n onEnd?: () => void,\n language: string = 'en-US'\n): SpeechRecognitionHook => {\n const [isListening, setIsListening] = useState(false);\n const [transcript, setTranscript] = useState('');\n const [error, setError] = useState<string | null>(null);\n const [isSupported, setIsSupported] = useState(false);\n\n const recognitionRef = useRef<any>(null);\n\n useEffect(() => {\n if (typeof window !== 'undefined') {\n const SpeechRecognition = (window as any).SpeechRecognition || (window as any).webkitSpeechRecognition;\n if (SpeechRecognition) {\n setIsSupported(true);\n const recognition = new SpeechRecognition();\n recognition.continuous = true;\n recognition.interimResults = true;\n recognition.lang = language;\n\n recognition.onstart = () => {\n setIsListening(true);\n setError(null);\n };\n\n recognition.onend = () => {\n setIsListening(false);\n if (onEnd) onEnd();\n };\n\n recognition.onresult = (event: SpeechRecognitionEvent) => {\n let interimTranscript = '';\n let finalTranscript = '';\n\n for (let i = event.results.length - 1; i < event.results.length; ++i) {\n const result = event.results[i];\n if (result.isFinal) {\n finalTranscript += result[0].transcript;\n if (onResult) onResult(finalTranscript, true);\n } else {\n interimTranscript += result[0].transcript;\n if (onResult) onResult(interimTranscript, false);\n }\n }\n\n // We mainly rely on onResult callback for real-time updates\n // But keep local state just in case\n setTranscript(prev => prev + finalTranscript);\n };\n\n recognition.onerror = (event: SpeechRecognitionErrorEvent) => {\n // Dev mode fallback: Simulate speech if permission is denied\n if (event.error === 'not-allowed' && process.env.NODE_ENV === 'development') {\n console.warn('Speech recognition blocked. Simulating input for development...');\n setError(null);\n setIsListening(true);\n\n // Simulate a delay then result\n setTimeout(() => {\n const mockText = \"This is a simulated voice input for testing.\";\n setTranscript(prev => prev + (prev ? ' ' : '') + mockText);\n if (onResult) onResult(mockText, true);\n\n setIsListening(false);\n if (onEnd) onEnd();\n }, 1000);\n return;\n }\n\n console.error('Speech recognition error', event.error);\n setError(event.error);\n setIsListening(false);\n };\n\n recognitionRef.current = recognition;\n }\n }\n\n return () => {\n if (recognitionRef.current) {\n recognitionRef.current.stop();\n }\n };\n }, [onResult, onEnd]);\n\n const start = useCallback(() => {\n if (recognitionRef.current && !isListening) {\n try {\n setTranscript('');\n recognitionRef.current.start();\n } catch (e) {\n console.error('Failed to start speech recognition:', e);\n }\n }\n }, [isListening]);\n\n const stop = useCallback(() => {\n if (recognitionRef.current && isListening) {\n recognitionRef.current.stop();\n }\n }, [isListening]);\n\n const resetTranscript = useCallback(() => {\n setTranscript('');\n }, []);\n\n return {\n isListening,\n transcript,\n start,\n stop,\n resetTranscript,\n isSupported,\n error\n };\n};\n","import { useState, useRef, useCallback } from 'react';\n\nexport interface AudioRecorderHook {\n isRecording: boolean;\n start: () => Promise<void>;\n stop: () => void;\n blob: Blob | null;\n error: string | null;\n}\n\nexport const useAudioRecorder = (\n onStop?: (blob: Blob) => void\n): AudioRecorderHook => {\n const [isRecording, setIsRecording] = useState(false);\n const [blob, setBlob] = useState<Blob | null>(null);\n const [error, setError] = useState<string | null>(null);\n\n const mediaRecorderRef = useRef<MediaRecorder | null>(null);\n const chunksRef = useRef<Blob[]>([]);\n\n const start = useCallback(async () => {\n try {\n const stream = await navigator.mediaDevices.getUserMedia({ audio: true });\n const mediaRecorder = new MediaRecorder(stream);\n\n mediaRecorderRef.current = mediaRecorder;\n chunksRef.current = [];\n\n mediaRecorder.ondataavailable = (e) => {\n if (e.data.size > 0) {\n chunksRef.current.push(e.data);\n }\n };\n\n mediaRecorder.onstop = () => {\n const audioBlob = new Blob(chunksRef.current, { type: 'audio/webm' });\n setBlob(audioBlob);\n setIsRecording(false);\n if (onStop) onStop(audioBlob);\n\n // Stop all tracks\n stream.getTracks().forEach(track => track.stop());\n };\n\n mediaRecorder.start();\n setIsRecording(true);\n setError(null);\n } catch (e: any) {\n console.error('Failed to start audio recording:', e);\n setError(e.message || 'Microphone access denied');\n }\n }, [onStop]);\n\n const stop = useCallback(() => {\n if (mediaRecorderRef.current && mediaRecorderRef.current.state !== 'inactive') {\n mediaRecorderRef.current.stop();\n }\n }, []);\n\n return {\n isRecording,\n start,\n stop,\n blob,\n error\n };\n};\n","import { RefObject, useEffect } from 'react';\n\n/**\n * A hook that proactively resizes a textarea based on the content of a hidden measurement element.\n * This avoids the flickering often seen with standard \"height: auto\" approaches by measuring\n * the content in a hidden span first, then applying the height to the textarea.\n */\nexport function useProactiveResize(\n textareaRef: RefObject<HTMLTextAreaElement>,\n measurementRef: RefObject<HTMLSpanElement>,\n value: string,\n disabled: boolean\n) {\n useEffect(() => {\n if (!textareaRef.current || !measurementRef.current) return;\n\n // Copy styles from textarea to measurement span to ensure accurate sizing\n const styles = window.getComputedStyle(textareaRef.current);\n measurementRef.current.style.width = styles.width;\n measurementRef.current.style.font = styles.font; // Shorthand for font-style, font-variant, font-weight, font-size, line-height, font-family\n measurementRef.current.style.padding = styles.padding;\n measurementRef.current.style.border = styles.border;\n measurementRef.current.style.boxSizing = styles.boxSizing;\n measurementRef.current.style.whiteSpace = 'pre-wrap'; // Important for matching textarea behavior\n measurementRef.current.style.visibility = 'hidden';\n measurementRef.current.style.position = 'absolute';\n measurementRef.current.style.pointerEvents = 'none';\n\n // Set content to measurement span\n // Append a zero-width space to ensure empty lines are counted\n measurementRef.current.textContent = value + '\\u200B';\n\n // Calculate height\n const scrollHeight = measurementRef.current.offsetHeight;\n\n // Apply height to textarea\n // We add a small buffer (e.g., 2px) to prevent scrollbars from appearing due to sub-pixel rendering differences\n // But direct assignment is usually best.\n // Also respect min-height if set in CSS (typically handled by browser, but we set style.height)\n textareaRef.current.style.height = `${scrollHeight}px`;\n\n }, [value, disabled, textareaRef, measurementRef]);\n}\n","'use client';\n\nimport React, { useEffect, useRef } from 'react';\nimport { ChatMessage, ChatTask } from '../types/chat';\nimport InteractiveMessageHandler from './interactive/InteractiveMessageHandler';\nimport { InformationCircleIcon } from '@heroicons/react/24/outline';\nimport { MessageBubble } from './MessageBubble';\n\n// Define the props for the ChatMessageList component\ninterface ChatMessageListProps {\n chatHistory: ChatMessage[];\n isProcessing: boolean;\n processingHint: string;\n currentTask: ChatTask | null;\n getContextExample: () => string;\n onInteractiveResponse?: (messageId: string | number, response: any) => void;\n}\n\n/**\n * ChatMessageList component displays the chat messages and handles scrolling\n * Features:\n * - Displays user and system messages with different styling\n * - Shows a typing indicator when the system is processing\n * - Displays a welcome message when the chat is empty\n * - Auto-scrolls to the bottom when new messages arrive\n * - Handles interactive messages with different UI components\n */\nexport const ChatMessageList: React.FC<ChatMessageListProps> = ({\n chatHistory,\n isProcessing,\n processingHint,\n currentTask,\n getContextExample,\n onInteractiveResponse\n}) => {\n // Reference to the chat container for auto-scrolling\n const chatContainerRef = useRef<HTMLDivElement>(null);\n // Reference to the last message for scrolling into view\n const lastMessageRef = useRef<HTMLDivElement>(null);\n // Reference to the processing indicator\n const processingIndicatorRef = useRef<HTMLDivElement>(null);\n\n // Scroll to the bottom when chat history or processing state changes\n useEffect(() => {\n // If there's a processing indicator, scroll to it\n if (isProcessing && processingIndicatorRef.current) {\n processingIndicatorRef.current.scrollIntoView({ behavior: 'smooth' });\n return;\n }\n\n // If there's a last message, scroll to it\n if (lastMessageRef.current) {\n lastMessageRef.current.scrollIntoView({ behavior: 'smooth' });\n } else if (chatContainerRef.current) {\n // Fallback to scrolling the container\n chatContainerRef.current.scrollTop = chatContainerRef.current.scrollHeight;\n }\n }, [chatHistory, isProcessing]);\n\n // Handle interactive message responses\n const handleInteractiveResponse = (messageId: string | number, response: any) => {\n if (onInteractiveResponse) {\n onInteractiveResponse(messageId, response);\n }\n };\n\n return (\n <div\n ref={chatContainerRef}\n className=\"flex-1 overflow-y-auto p-4 space-y-4 bg-gray-50\"\n >\n {/* Welcome message when chat is empty */}\n {chatHistory.length === 0 && !isProcessing && (\n <div className=\"text-center py-8\">\n <h3 className=\"text-lg font-medium text-gray-700 mb-2\">How can I help you today?</h3>\n <p className=\"text-sm text-gray-500 mb-4\">\n Try asking me something like {getContextExample()}\n </p>\n </div>\n )}\n\n {/* Display chat messages */}\n {chatHistory.map((message, index) => {\n // Determine if this is the last message\n const isLastMessage = index === chatHistory.length - 1;\n const isUser = message.role === 'user';\n const isError = message.role === 'error';\n\n return (\n <div\n key={message.id || `message-${index}`}\n ref={isLastMessage ? lastMessageRef : undefined}\n className={`flex flex-col w-full ${isUser ? 'items-end' : 'items-start'}`}\n >\n {/* Timestamp display */}\n <div className=\"text-xs text-gray-400 mb-1 px-1\">\n {message.timestamp\n ? `${isUser ? 'Sent' : 'Received'} at ${new Date(message.timestamp).toLocaleString()}`\n : ''}\n </div>\n\n {/* Message Content */}\n <div className=\"w-full\">\n {message.interactive && message.interactiveData ? (\n <div className={`max-w-[85%] ${isUser ? 'ml-auto' : 'mr-auto'}`}>\n <InteractiveMessageHandler\n message={message.interactiveData}\n onResponse={(response: any) => {\n const messageId = message.id || `interactive-${index}-${Date.now()}`;\n message.responseValue = response;\n handleInteractiveResponse(messageId, response);\n }}\n isResponseSubmitted={!!message.isResponseSubmitted}\n parentMessage={message}\n />\n </div>\n ) : (\n <MessageBubble\n message={message}\n isUser={isUser}\n />\n )}\n </div>\n\n {isUser && message.interactive && (\n <div className=\"flex items-center mt-1 space-x-1 text-xs text-gray-500 italic\">\n <InformationCircleIcon className=\"h-3 w-3 text-blue-400\" />\n <span>\n {message.request === 'form' && 'Response to form submission'}\n {message.request === 'select' && 'Response to selection prompt'}\n {message.request === 'confirm' && 'Response to confirmation prompt'}\n </span>\n </div>\n )}\n </div>\n );\n })}\n\n {/* Show typing indicator when processing */}\n {isProcessing && (\n <div\n ref={processingIndicatorRef}\n className=\"flex justify-start\"\n >\n <div className=\"bg-white text-gray-800 border border-gray-200 rounded-lg px-4 py-2 max-w-[85%]\">\n <div className=\"flex items-center\">\n <span className=\"text-sm\">{processingHint}</span>\n <span className=\"ml-2 flex space-x-1\">\n <span className=\"h-2 w-2 bg-gray-400 rounded-full animate-bounce\" style={{ animationDelay: '0ms' }}></span>\n <span className=\"h-2 w-2 bg-gray-400 rounded-full animate-bounce\" style={{ animationDelay: '150ms' }}></span>\n <span className=\"h-2 w-2 bg-gray-400 rounded-full animate-bounce\" style={{ animationDelay: '300ms' }}></span>\n </span>\n </div>\n </div>\n </div>\n )}\n\n {/* Show task progress if available */}\n {currentTask && !currentTask.complete && (\n <div className=\"mt-4 bg-blue-50 border border-blue-100 rounded-lg p-3\">\n <div className=\"text-sm text-blue-800 mb-1\">\n Task in progress: Step {currentTask.currentStep} of {currentTask.steps}\n </div>\n <div className=\"w-full bg-blue-200 rounded-full h-2\">\n <div\n className=\"bg-blue-500 h-2 rounded-full\"\n style={{ width: `${(currentTask.currentStep / currentTask.steps) * 100}%` }}\n ></div>\n </div>\n </div>\n )}\n </div>\n );\n};\n\nexport default ChatMessageList;\n","'use client';\n\nimport React, { useState } from 'react';\nimport { ConfirmInteractionParams } from '../../types/interactive';\n\ninterface ConfirmInteractionProps {\n parameters: Record<string, any>;\n onResponse: (response: boolean) => void;\n isResponseSubmitted: boolean;\n}\n\n/**\n * Component for handling confirm (yes/no) interactions\n */\nconst ConfirmInteraction: React.FC<ConfirmInteractionProps> = ({\n parameters,\n onResponse,\n isResponseSubmitted\n}) => {\n const [selectedOption, setSelectedOption] = useState<string | null>(null);\n const params = parameters as ConfirmInteractionParams;\n\n // Extract parameters\n const { yesPrompt, noPrompt } = params;\n\n console.log('[ConfirmInteraction] Parameters:', params);\n\n const handleOptionClick = (value: boolean, buttonText: string) => {\n if (isResponseSubmitted) return;\n\n // Use the button text (yesPrompt/noPrompt) as the selected option\n setSelectedOption(buttonText);\n onResponse(value);\n };\n\n return (\n <div className=\"mt-2 mb-4\">\n <div className=\"flex space-x-2\">\n <button\n onClick={() => handleOptionClick(true, yesPrompt)}\n disabled={isResponseSubmitted}\n className={`px-4 py-2 rounded-md text-sm transition-colors ${isResponseSubmitted\n ? selectedOption === yesPrompt\n ? 'bg-blue-500 text-white' // Selected and submitted\n : 'bg-gray-200 text-gray-500 cursor-not-allowed' // Not selected and submitted\n : 'bg-blue-100 text-blue-700 hover:bg-blue-200'}`}\n >\n {yesPrompt}\n </button>\n <button\n onClick={() => handleOptionClick(false, noPrompt)}\n disabled={isResponseSubmitted}\n className={`px-4 py-2 rounded-md text-sm transition-colors ${isResponseSubmitted\n ? selectedOption === noPrompt\n ? 'bg-blue-500 text-white' // Selected and submitted\n : 'bg-gray-200 text-gray-500 cursor-not-allowed' // Not selected and submitted\n : 'bg-gray-100 text-gray-700 hover:bg-gray-200'}`}\n >\n {noPrompt}\n </button>\n </div>\n </div>\n );\n};\n\nexport default ConfirmInteraction;\n","'use client';\n\nimport React, { useState, useEffect } from 'react';\nimport { SelectInteractionParams } from '../../types/interactive';\n\ninterface SelectInteractionProps {\n parameters: Record<string, any>;\n onResponse: (response: string) => void;\n isResponseSubmitted: boolean;\n message?: any;\n}\n\n/**\n * Component for handling select interactions (choosing from multiple options)\n */\nconst SelectInteraction: React.FC<SelectInteractionProps> = ({\n parameters,\n onResponse,\n isResponseSubmitted,\n message\n}) => {\n const [selectedOption, setSelectedOption] = useState<string | null>(null);\n const [customOption, setCustomOption] = useState<string | null>(null);\n const params = parameters as SelectInteractionParams;\n\n const { question, options, placeholder } = params;\n\n // Effect to check if there's a responseValue to use\n useEffect(() => {\n if (isResponseSubmitted && message?.responseValue) {\n const responseValueStr = String(message.responseValue);\n setSelectedOption(responseValueStr);\n\n // Check if it's a custom option\n if (!options.includes(responseValueStr)) {\n setCustomOption(responseValueStr);\n }\n }\n }, [isResponseSubmitted, message, options]);\n\n const handleOptionClick = (option: string) => {\n if (isResponseSubmitted) return;\n\n setSelectedOption(option);\n setCustomOption(null); // Clear any custom option when selecting a predefined one\n onResponse(option);\n };\n\n return (\n <div className=\"mt-2 mb-4\">\n <div className=\"flex flex-wrap gap-2\">\n {options.map((option, index) => (\n <button\n key={index}\n onClick={() => handleOptionClick(option)}\n disabled={isResponseSubmitted}\n className={`px-4 py-2 rounded-md text-sm transition-colors ${isResponseSubmitted\n ? selectedOption === option\n ? 'bg-blue-500 text-white' // Selected and submitted\n : 'bg-gray-200 text-gray-500 cursor-not-allowed' // Not selected and submitted\n : 'bg-blue-100 text-blue-700 hover:bg-blue-200'}`}\n >\n {option}\n </button>\n ))}\n </div>\n\n {/* Show custom option message if applicable */}\n {customOption && isResponseSubmitted && (\n <div className=\"mt-2 text-sm text-amber-600 bg-amber-50 p-2 rounded\">\n User provided custom option: <span className=\"font-semibold\">\"{customOption}\"</span>\n </div>\n )}\n </div>\n );\n};\n\nexport default SelectInteraction;\n","'use client';\n\nimport React, { useState, useEffect, useRef } from 'react';\nimport { FormInteractionParams, FormField } from '../../types/interactive';\nimport { ChevronDownIcon, ChevronUpIcon } from 'lucide-react';\n\ninterface FormInteractionProps {\n parameters: Record<string, any>;\n onResponse: (response: Record<string, any>) => void;\n isResponseSubmitted: boolean;\n submittedValues?: Record<string, any>;\n}\n\n/**\n * Component for handling form interactions (collecting structured data)\n */\nconst FormInteraction: React.FC<FormInteractionProps> = ({\n parameters,\n onResponse,\n isResponseSubmitted,\n submittedValues\n}) => {\n const [isModalOpen, setIsModalOpen] = useState(false);\n const [formValues, setFormValues] = useState<Record<string, any>>({});\n const [isExpanded, setIsExpanded] = useState(false);\n const [parsedFields, setParsedFields] = useState<FormField[]>([]);\n const formButtonsRef = useRef<HTMLDivElement>(null);\n\n // Parse parameters to handle both array and object-based fields\n const parseParameters = () => {\n const { prompt, description, submitText = 'Submit', cancelText = 'Cancel' } = parameters;\n\n // Handle fields that might come as an array of stringified JSON\n let fieldsArray: FormField[] = [];\n\n if (parameters.fields) {\n // If fields is an array, parse each item if it's a string\n if (Array.isArray(parameters.fields)) {\n fieldsArray = parameters.fields.map(field => {\n if (typeof field === 'string') {\n try {\n const fieldData = JSON.parse(field);\n\n const name = fieldData.name;\n\n return {\n name,\n label: fieldData.label || name,\n type: fieldData.type || 'string',\n required: fieldData.required || false,\n options: fieldData.options || [],\n placeholder: fieldData.description || fieldData.label || name,\n defaultValue: fieldData.defaultValue\n } as FormField;\n } catch (error) {\n console.error(`Error parsing field:`, error);\n return null;\n }\n }\n return field;\n }).filter((field): field is FormField => field !== null);\n }\n // If fields is an object with stringified JSON values\n else if (typeof parameters.fields === 'object') {\n fieldsArray = Object.entries(parameters.fields).map(([name, fieldDataStr]) => {\n let fieldData: Record<string, any> = {};\n\n // Try to parse the stringified JSON\n try {\n if (typeof fieldDataStr === 'string') {\n fieldData = JSON.parse(fieldDataStr);\n } else {\n fieldData = fieldDataStr as Record<string, any>;\n }\n } catch (error) {\n console.error(`Error parsing field data for ${name}:`, error);\n }\n\n return {\n name,\n label: fieldData.label || name,\n type: fieldData.type || 'string',\n required: fieldData.required || false,\n options: fieldData.options || [],\n placeholder: fieldData.description || fieldData.label || name,\n defaultValue: fieldData.defaultValue\n } as FormField;\n });\n\n console.log('Field arrays: ', fieldsArray)\n }\n }\n\n return {\n title: prompt || 'Please fill out this form',\n description,\n fields: fieldsArray,\n submitText,\n cancelText\n };\n };\n\n const params = parseParameters();\n\n // Initialize form values with default values\n useEffect(() => {\n const processedParams = parseParameters();\n setParsedFields(processedParams.fields);\n\n const initialValues: Record<string, any> = {};\n processedParams.fields.forEach(field => {\n if (field.defaultValue !== undefined) {\n initialValues[field.name] = field.defaultValue;\n } else if (field.type === 'checkbox') {\n initialValues[field.name] = false;\n } else {\n initialValues[field.name] = '';\n }\n });\n setFormValues(initialValues);\n\n // Automatically open the modal when the component mounts\n if (!isResponseSubmitted) {\n setIsModalOpen(true);\n }\n }, [parameters, isResponseSubmitted]);\n\n // Effect to scroll form buttons into view when modal is opened\n useEffect(() => {\n if (isModalOpen && formButtonsRef.current) {\n setTimeout(() => {\n formButtonsRef.current?.scrollIntoView({ behavior: 'smooth', block: 'center' });\n }, 100); // Small delay to ensure form is rendered\n }\n }, [isModalOpen]);\n\n const handleInputChange = (field: FormField, value: any) => {\n setFormValues(prev => ({\n ...prev,\n [field.name]: value\n }));\n };\n\n const handleSubmit = (e: React.FormEvent) => {\n e.preventDefault();\n onResponse(formValues);\n setIsModalOpen(false);\n };\n\n const handleCancel = () => {\n onResponse({});\n setIsModalOpen(false);\n };\n\n const renderField = (field: FormField) => {\n const { name, label, type, required, options, placeholder } = field;\n\n switch (type) {\n case 'string':\n case 'email':\n case 'number':\n case 'password':\n return (\n <div className=\"mb-4 flex items-center space-x-4\" key={name}>\n <label htmlFor={name} className=\"text-sm font-medium text-gray-700 min-w-[120px]\">\n {label}{required && <span className=\"text-red-500\">*</span>}\n </label>\n <input\n type={type === 'string' ? 'text' : type}\n id={name}\n name={name}\n value={formValues[name] || ''}\n onChange={(e) => handleInputChange(field, e.target.value)}\n placeholder={placeholder}\n required={required}\n disabled={isResponseSubmitted}\n className=\"flex-1 px-3 py-2 border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-blue-500\"\n />\n </div>\n );\n\n case 'textarea':\n return (\n <div className=\"mb-4 flex items-start space-x-4\" key={name}>\n <label htmlFor={name} className=\"text-sm font-medium text-gray-700 min-w-[120px] pt-2\">\n {label}{required && <span className=\"text-red-500\">*</span>}\n </label>\n <textarea\n id={name}\n name={name}\n value={formValues[name] || ''}\n onChange={(e) => handleInputChange(field, e.target.value)}\n placeholder={placeholder}\n required={required}\n disabled={isResponseSubmitted}\n rows={4}\n className=\"flex-1 px-3 py-2 border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-blue-500\"\n />\n </div>\n );\n\n case 'select':\n return (\n <div className=\"mb-4 flex items-center space-x-4\" key={name}>\n <label htmlFor={name} className=\"text-sm font-medium text-gray-700 min-w-[120px]\">\n {label}{required && <span className=\"text-red-500\">*</span>}\n </label>\n <select\n id={name}\n name={name}\n value={formValues[name] || ''}\n onChange={(e) => handleInputChange(field, e.target.value)}\n required={required}\n disabled={isResponseSubmitted}\n className=\"flex-1 px-3 py-2 border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-blue-500\"\n >\n <option value=\"\" disabled>{placeholder || 'Select an option'}</option>\n {options?.map((option, index) => (\n <option key={index} value={option}>{option}</option>\n ))}\n </select>\n </div>\n );\n\n case 'checkbox':\n return (\n <div className=\"mb-4 flex items-center space-x-4\" key={name}>\n <div className=\"min-w-[120px]\" />\n <div className=\"flex items-center\">\n <input\n type=\"checkbox\"\n id={name}\n name={name}\n checked={!!formValues[name]}\n onChange={(e) => handleInputChange(field, e.target.checked)}\n required={required}\n disabled={isResponseSubmitted}\n className=\"h-4 w-4 text-blue-600 border-gray-300 rounded focus:ring-blue-500\"\n />\n <label htmlFor={name} className=\"ml-2 text-sm text-gray-700\">\n {label}{required && <span className=\"text-red-500\">*</span>}\n </label>\n </div>\n </div>\n );\n\n case 'radio':\n return (\n <div className=\"mb-4 flex space-x-4\" key={name}>\n <div className=\"text-sm font-medium text-gray-700 min-w-[120px] pt-2\">\n {label}{required && <span className=\"text-red-500\">*</span>}\n </div>\n <div className=\"flex-1 space-y-2\">\n {options?.map((option, index) => (\n <div key={index} className=\"flex items-center\">\n <input\n id={`${name}-${index}`}\n name={name}\n type=\"radio\"\n value={option}\n checked={formValues[name] === option}\n onChange={() => handleInputChange(field, option)}\n required={required}\n disabled={isResponseSubmitted}\n className=\"h-4 w-4 text-blue-600 border-gray-300 focus:ring-blue-500\"\n />\n <label htmlFor={`${name}-${index}`} className=\"ml-2 text-sm text-gray-700\">\n {option}\n </label>\n </div>\n ))}\n </div>\n </div>\n );\n\n default:\n return null;\n }\n };\n\n if (isResponseSubmitted) {\n // For submitted forms, show a summary of the responses\n return (\n <div className=\"mt-2 bg-gray-50 p-3 rounded-md border border-gray-200\">\n <div className=\"flex justify-between items-center cursor-pointer\" onClick={() => setIsExpanded(!isExpanded)}>\n <span className=\"font-medium text-gray-700\">{isExpanded ? 'Hide' : 'Show'} Form Responses</span>\n {isExpanded ?\n <ChevronUpIcon className=\"h-5 w-5 text-gray-500\" /> :\n <ChevronDownIcon className=\"h-5 w-5 text-gray-500\" />\n }\n </div>\n\n {isExpanded && (\n <div className=\"mt-2 space-y-2\">\n {parsedFields.map((field) => (\n <div key={field.name} className=\"flex\">\n <span className=\"text-sm font-medium text-gray-600 mr-2\">{field.label}:</span>\n <span className=\"text-sm text-gray-800\">\n {typeof submittedValues?.[field.name] === 'boolean'\n ? (submittedValues[field.name] ? 'Yes' : 'No')\n : submittedValues?.[field.name] || 'Not provided'}\n </span>\n </div>\n ))}\n </div>\n )}\n </div>\n );\n }\n\n // For new forms, show the modal\n return (\n <div className=\"mt-2\">\n {isModalOpen && (\n <div className=\"p-4\">\n <form onSubmit={handleSubmit} className=\"mt-4\">\n {parsedFields.map(field => renderField(field))}\n\n <div ref={formButtonsRef} className=\"flex justify-end mt-4 space-x-2\">\n <button\n type=\"button\"\n onClick={handleCancel}\n disabled={isResponseSubmitted}\n className=\"px-4 py-2 text-sm font-medium text-gray-700 bg-gray-100 border border-gray-300 rounded-md hover:bg-gray-200 focus:outline-none focus:ring-2 focus:ring-blue-500\"\n >\n {params.cancelText}\n </button>\n <button\n type=\"submit\"\n disabled={isResponseSubmitted}\n className=\"px-4 py-2 text-sm font-medium text-white bg-blue-600 rounded-md hover:bg-blue-700 focus:outline-none focus:ring-2 focus:ring-blue-500\"\n >\n {params.submitText}\n </button>\n </div>\n </form>\n </div>\n )}\n </div>\n );\n};\n\nexport default FormInteraction;\n","'use client';\n\nimport React from 'react';\nimport { PresentInteractionParams } from '../../types/interactive';\n\n// Try to import ReactMarkdown, but provide a fallback if it's not available\nlet ReactMarkdown: any;\ntry {\n // Dynamic import for ReactMarkdown\n ReactMarkdown = require('react-markdown');\n} catch (error) {\n // Fallback if ReactMarkdown is not available\n ReactMarkdown = ({ children }: { children: string }) => (\n <div className=\"whitespace-pre-wrap\">{children}</div>\n );\n}\n\ninterface PresentInteractionProps {\n parameters: Record<string, any>;\n}\n\n/**\n * Component for handling present interactions (displaying information)\n */\nconst PresentInteraction: React.FC<PresentInteractionProps> = ({\n parameters\n}) => {\n const params = parameters as PresentInteractionParams;\n const { title, content, format = 'text', level = 'info' } = params;\n\n // Define styles based on level\n const getLevelStyles = () => {\n switch (level) {\n case 'error':\n return {\n container: 'bg-red-50 border-red-100',\n title: 'text-red-800',\n content: 'text-red-700'\n };\n case 'warn':\n case 'warning':\n return {\n container: 'bg-amber-50 border-amber-100',\n title: 'text-amber-800',\n content: 'text-amber-700'\n };\n case 'success':\n return {\n container: 'bg-green-50 border-green-100',\n title: 'text-green-800',\n content: 'text-green-700'\n };\n case 'info':\n default:\n return {\n container: 'bg-blue-50 border-blue-100',\n title: 'text-blue-800',\n content: 'text-blue-700'\n };\n }\n };\n\n const styles = getLevelStyles();\n\n return (\n <div className={`mt-2 mb-4 p-4 ${styles.container} border rounded-md`}>\n {title && (\n <div className={`font-medium ${styles.title} mb-2`}>{title}</div>\n )}\n <div className={`text-sm ${styles.content}`}>\n {format === 'markdown' ? (\n <ReactMarkdown className=\"prose prose-sm max-w-none\">\n {content}\n </ReactMarkdown>\n ) : format === 'html' ? (\n <div dangerouslySetInnerHTML={{ __html: content }} />\n ) : (\n <div className=\"whitespace-pre-wrap\">{content}</div>\n )}\n </div>\n </div>\n );\n};\n\nexport default PresentInteraction;\n","'use client';\n\nimport React from 'react';\nimport { InteractiveMessage } from '../../types/interactive';\nimport ConfirmInteraction from './ConfirmInteraction';\nimport SelectInteraction from './SelectInteraction';\nimport FormInteraction from './FormInteraction';\nimport PresentInteraction from './PresentInteraction';\n\ninterface InteractiveMessageHandlerProps {\n message: InteractiveMessage;\n onResponse: (response: any) => void;\n isResponseSubmitted: boolean;\n parentMessage?: any; // Add reference to the parent ChatMessage\n}\n\n/**\n * Component that handles rendering different types of interactive messages\n * based on the function type (chat, confirm, select, form, present)\n */\nconst InteractiveMessageHandler: React.FC<InteractiveMessageHandlerProps> = ({\n message,\n onResponse,\n isResponseSubmitted,\n parentMessage\n}) => {\n const { function: functionType, parameters } = message;\n\n // Extract submitted response from parent message if available\n const submittedResponse = parentMessage?.responseValue;\n\n // Render the appropriate interaction component based on the function type\n switch (functionType) {\n case 'confirm':\n return (\n <ConfirmInteraction\n parameters={parameters}\n onResponse={onResponse}\n isResponseSubmitted={isResponseSubmitted}\n />\n );\n\n case 'select':\n return (\n <SelectInteraction\n parameters={parameters}\n onResponse={onResponse}\n isResponseSubmitted={isResponseSubmitted}\n message={parentMessage}\n />\n );\n\n case 'form':\n return (\n <FormInteraction\n parameters={parameters}\n onResponse={onResponse}\n isResponseSubmitted={isResponseSubmitted}\n submittedValues={submittedResponse}\n />\n );\n\n case 'present':\n return (\n <PresentInteraction\n parameters={parameters}\n />\n );\n\n case 'chat':\n // Chat is handled by the main input form, so we don't need a special component\n return null;\n\n default:\n console.warn(`Unknown interactive function type: ${functionType}`);\n return null;\n }\n};\n\nexport default InteractiveMessageHandler;\n","'use client';\n\nimport React from 'react';\nimport { Wifi, WifiOff, RefreshCw } from 'lucide-react';\n\ninterface ConnectionStatusProps {\n connectionStatus: 'connected' | 'disconnected' | 'reconnecting';\n onReconnect: () => void;\n}\n\nexport const ConnectionStatus: React.FC<ConnectionStatusProps> = ({\n connectionStatus,\n onReconnect\n}) => {\n return (\n <div className=\"bg-amber-100 connection-status flex items-center justify-between px-4 py-1 text-xs\">\n <div className=\"text-gray-700 font-medium\">\n You are talking with your personal Content Strategist\n </div>\n {connectionStatus === 'connected' && (\n <div className=\"flex items-center text-green-600\">\n <Wifi className=\"w-3 h-3 mr-1\" />\n <span>Connected</span>\n </div>\n )}\n {connectionStatus === 'reconnecting' && (\n <div className=\"flex items-center text-amber-600\">\n <RefreshCw className=\"w-3 h-3 mr-1 animate-spin\" />\n <span>Reconnecting...</span>\n </div>\n )}\n {connectionStatus === 'disconnected' && (\n <div className=\"flex items-center gap-2\">\n <div className=\"text-red-600 flex items-center\">\n <WifiOff className=\"w-3 h-3 mr-1\" />\n <span>Disconnected</span>\n </div>\n <button\n onClick={onReconnect}\n className=\"text-blue-600 hover:text-blue-800 flex items-center\"\n >\n <RefreshCw className=\"w-3 h-3 mr-1\" />\n <span>Reconnect</span>\n </button>\n </div>\n )}\n </div>\n );\n}\n","import React from 'react';\n\ninterface SpinnerProps {\n size?: 'sm' | 'md' | 'lg' | 'xl';\n className?: string;\n color?: string;\n}\n\nexport const Spinner: React.FC<SpinnerProps> = ({\n size = 'md',\n className = '',\n color = 'text-blue-600'\n}) => {\n const sizeClasses = {\n sm: 'h-4 w-4',\n md: 'h-6 w-6',\n lg: 'h-8 w-8',\n xl: 'h-12 w-12'\n };\n\n return (\n <svg\n className={`animate-spin ${sizeClasses[size]} ${color} ${className}`}\n xmlns=\"http://www.w3.org/2000/svg\"\n fill=\"none\"\n viewBox=\"0 0 24 24\"\n >\n <circle\n className=\"opacity-25\"\n cx=\"12\"\n cy=\"12\"\n r=\"10\"\n stroke=\"currentColor\"\n strokeWidth=\"4\"\n />\n <path\n className=\"opacity-75\"\n fill=\"currentColor\"\n d=\"M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z\"\n />\n </svg>\n );\n};\n","/**\n * Lightweight client for sending audio to a backend transcription endpoint.\n * This keeps the API key secret on the server.\n */\n\nexport interface TranscriptionConfig {\n endpoint: string;\n language?: string;\n // No headers needed if using standard fetch or cookies\n // Add custom headers support if needed for token auth\n headers?: Record<string, string>;\n}\n\nexport interface TranscriptionResult {\n text: string;\n error?: string;\n}\n\n/**\n * Transcribe audio blob by sending it to the configured backend endpoint.\n */\nexport async function transcribeAudio(\n audioBlob: Blob,\n config: TranscriptionConfig\n): Promise<string> {\n const formData = new FormData();\n formData.append('audio', audioBlob, 'recording.webm');\n\n if (config.language) {\n formData.append('language', config.language);\n }\n\n try {\n const response = await fetch(config.endpoint, {\n method: 'POST',\n body: formData,\n headers: config.headers || {},\n credentials: 'same-origin', // Ensure cookies are sent for same-domain requests\n });\n\n if (!response.ok) {\n const errorText = await response.text();\n throw new Error(`Transcription failed (${response.status}): ${errorText}`);\n }\n\n const data = await response.json();\n return data.text;\n } catch (error: any) {\n console.error('Transcription client error:', error);\n throw error;\n }\n}\n","import { VoiceConfig } from '../types/chat';\nimport { TranscriptionConfig, transcribeAudio } from '../services/whisper-client';\n\n/**\n * Helper to create a VoiceConfig that uses the backend Whisper transcription service.\n * \n * @param config - Configuration for the transcription endpoint\n * @param callbacks - Optional callbacks for voice events\n * @returns VoiceConfig ready to be used in ChatInputArea\n */\nexport function createWhisperVoiceConfig(\n config: TranscriptionConfig,\n callbacks?: {\n onVoiceStart?: () => void;\n onVoiceEnd?: () => void;\n }\n): VoiceConfig {\n return {\n mode: 'custom',\n onVoiceStart: callbacks?.onVoiceStart,\n onVoiceEnd: callbacks?.onVoiceEnd,\n /**\n * The core handler: takes the recorded blob and sends it to the server.\n */\n onAudioCapture: async (blob: Blob) => {\n return await transcribeAudio(blob, config);\n }\n };\n}\n"],"mappings":"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","names":["jsx","jsx","jsx","jsxs","useState","useRef","useState","useRef","useCallback","useEffect","jsx","jsxs","useState","useRef","_a","useEffect","useRef","useState","jsx","jsxs","useState","useEffect","jsx","jsxs","useState","useEffect","useRef","jsx","jsxs","jsx","jsxs","ReactMarkdown","jsx","jsx","jsxs","useRef","useEffect","jsx","jsxs","jsx","jsxs"]}
1
+ {"version":3,"sources":["../../../../src/ui/react/components/ChatBubble.tsx","../../../../src/ui/react/components/MessageBubble.tsx","../../../../src/ui/react/context/ChatConfigContext.tsx","../../../../src/ui/react/components/ChatHeader.tsx","../../../../src/ui/react/components/ChatInputArea.tsx","../../../../src/ui/react/hooks/useSpeechRecognition.ts","../../../../src/ui/react/hooks/useAudioRecorder.ts","../../../../src/ui/react/hooks/useProactiveResize.ts","../../../../src/ui/react/components/ChatMessageList.tsx","../../../../src/ui/react/components/interactive/ConfirmInteraction.tsx","../../../../src/ui/react/components/interactive/SelectInteraction.tsx","../../../../src/ui/react/components/interactive/FormInteraction.tsx","../../../../src/ui/react/components/interactive/PresentInteraction.tsx","../../../../src/ui/react/components/interactive/InteractiveMessageHandler.tsx","../../../../src/ui/react/components/ConnectionStatus.tsx","../../../../src/ui/react/components/Spinner.tsx","../../../../src/ui/react/services/whisper-client.ts","../../../../src/ui/react/utils/voice-utils.ts"],"sourcesContent":["'use client';\n\nimport React from 'react';\n\ninterface ChatBubbleProps {\n onClick: () => void;\n}\n\nexport function ChatBubble({ onClick }: ChatBubbleProps) {\n return (\n <button\n onClick={onClick}\n className=\"bg-blue-500 hover:bg-blue-600 text-white rounded-full w-12 h-12 flex items-center justify-center shadow-lg animate-pulse\"\n aria-label=\"Open chat assistant\"\n >\n <svg xmlns=\"http://www.w3.org/2000/svg\" className=\"h-6 w-6\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\">\n <path strokeLinecap=\"round\" strokeLinejoin=\"round\" strokeWidth={2} d=\"M8 10h.01M12 10h.01M16 10h.01M9 16H5a2 2 0 01-2-2V6a2 2 0 012-2h14a2 2 0 012 2v8a2 2 0 01-2 2h-5l-5 5v-5z\" />\n </svg>\n </button>\n );\n}\n","'use client';\n\nimport React from 'react';\nimport ReactMarkdown from 'react-markdown';\nimport remarkGfm from 'remark-gfm';\nimport { SparklesIcon } from '@heroicons/react/24/solid';\nimport { ChatMessage } from '../types/chat';\nimport { useChatConfig } from '../context/ChatConfigContext';\n\nexport interface MessageBubbleProps {\n message: ChatMessage;\n isUser: boolean;\n userAvatarUrl?: string; // Optional user avatar URL\n onViewChanges?: (diff: { oldContent: string; newContent: string }) => void;\n}\n\nexport const MessageBubble: React.FC<MessageBubbleProps> = ({\n message,\n isUser,\n userAvatarUrl,\n onViewChanges\n}) => {\n const { user } = useChatConfig();\n const finalAvatarUrl = userAvatarUrl || user?.avatarUrl;\n const isSystem = message.role === 'system';\n\n if (isSystem) {\n return (\n <div className=\"text-center my-4\">\n <span className=\"text-xs text-gray-500 italic bg-gray-100 px-3 py-1 rounded-full\">\n {message.content}\n {message.diff && onViewChanges && (\n <button\n onClick={() => onViewChanges(message.diff!)}\n className=\"ml-2 font-semibold text-blue-600 hover:underline focus:outline-none\"\n >\n View Changes\n </button>\n )}\n </span>\n </div>\n );\n }\n\n return (\n <div className={`flex items-start gap-3 my-4 ${isUser ? 'justify-end' : 'justify-start'}`}>\n {/* Assistant Avatar */}\n {!isUser && (\n <div className=\"flex-shrink-0 h-8 w-8 rounded-full bg-blue-500 flex items-center justify-center text-white\">\n <SparklesIcon className=\"h-5 w-5\" />\n </div>\n )}\n\n {/* Content Bubble */}\n <div\n className={`max-w-[85%] px-4 py-3 rounded-2xl shadow-sm overflow-hidden ${isUser\n ? 'bg-blue-500 text-white rounded-br-none'\n : 'bg-gray-100 text-gray-800 rounded-bl-none'\n }`}>\n <div className={`text-sm ${!isUser ? 'prose prose-sm max-w-none' : ''}`}>\n {isUser ? (\n <p className=\"whitespace-pre-wrap\">{message.content}</p>\n ) : (\n <ReactMarkdown\n remarkPlugins={[remarkGfm]}\n components={{\n p: ({ node, ...props }) => <p className=\"mb-2 last:mb-0\" {...props} />,\n ul: ({ node, ...props }) => <ul className=\"list-disc ml-4 mb-2\" {...props} />,\n ol: ({ node, ...props }) => <ol className=\"list-decimal ml-4 mb-2\" {...props} />,\n li: ({ node, ...props }) => <li className=\"mb-0.5\" {...props} />,\n a: ({ node, ...props }) => <a className=\"text-blue-600 hover:underline\" {...props} />,\n code: ({ node, ...props }) => <code className=\"bg-gray-200 rounded px-1 py-0.5 text-xs font-mono\" {...props} />\n }}\n >\n {message.content}\n </ReactMarkdown>\n )}\n </div>\n {message.role === 'assistant' && message.diff && onViewChanges && (\n <button\n onClick={() => onViewChanges(message.diff!)}\n className=\"mt-2 text-sm text-blue-500 hover:underline block\"\n >\n View Changes\n </button>\n )}\n {message.actionResult && message.actionResult.type === 'link' && (\n <div className=\"mt-2 pt-2 border-t border-gray-300\">\n <a\n href={message.actionResult.url}\n target={message.actionResult.target || '_blank'}\n rel=\"noopener noreferrer\"\n onClick={(e) => {\n if (message.actionResult?.target && message.actionResult.target !== '_blank') {\n e.preventDefault();\n window.open(message.actionResult.url, message.actionResult.target);\n }\n }}\n className={`inline-flex items-center gap-1 text-sm font-medium hover:underline ${isUser\n ? 'text-blue-100 hover:text-white'\n : 'text-blue-600 hover:text-blue-800'\n }`}\n >\n {message.actionResult.label}\n <svg className=\"w-3.5 h-3.5\" fill=\"none\" stroke=\"currentColor\" viewBox=\"0 0 24 24\">\n <path strokeLinecap=\"round\" strokeLinejoin=\"round\" strokeWidth={2} d=\"M10 6H6a2 2 0 00-2 2v10a2 2 0 002 2h10a2 2 0 002-2v-4M14 4h6m0 0v6m0-6L10 14\" />\n </svg>\n </a>\n </div>\n )}\n </div>\n\n {/* User Avatar */}\n {isUser && (\n <div className=\"flex-shrink-0 h-8 w-8 rounded-full bg-gray-200 overflow-hidden flex items-center justify-center text-gray-500\">\n {finalAvatarUrl ? (\n <img\n className=\"h-full w-full object-cover\"\n src={finalAvatarUrl}\n alt=\"User\"\n onError={(e) => {\n // Hide image and show fallback icon if load fails involves state, \n // but for a simple component we can just hide it or let the parent handle it.\n // For now, let's just render the icon if no url, \n // preventing the broken image icon requires state or a different approach (like standard Radix Avatar).\n // A simple hack: set src to a transparent pixel or hide display.\n (e.target as HTMLImageElement).style.display = 'none';\n (e.target as HTMLImageElement).parentElement?.classList.remove('bg-gray-200'); // Clean up?\n // Actually, better to just render the fallback SVG behind it?\n // Let's try separate conditional structure.\n }}\n />\n ) : (\n <svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 24 24\" fill=\"currentColor\" className=\"w-5 h-5\">\n <path fillRule=\"evenodd\" d=\"M7.5 6a4.5 4.5 0 1 1 9 0 4.5 4.5 0 0 1-9 0ZM3.751 20.105a8.25 8.25 0 0 1 16.498 0 .75.75 0 0 1-.437.695A18.683 18.683 0 0 1 12 22.5c-2.786 0-5.433-.608-7.812-1.7a.75.75 0 0 1-.437-.695Z\" clipRule=\"evenodd\" />\n </svg>\n )}\n </div>\n )}\n </div>\n );\n};\n","import React, { createContext, useContext, ReactNode } from 'react';\nimport { VoiceConfig } from '../types/chat';\n\nexport interface ChatConfig {\n user?: {\n avatarUrl?: string;\n name?: string;\n };\n voice?: {\n enabled: boolean;\n config?: VoiceConfig;\n };\n}\n\nconst ChatConfigContext = createContext<ChatConfig>({});\n\nexport const ChatConfigProvider: React.FC<{\n config: ChatConfig;\n children: ReactNode;\n}> = ({ config, children }) => {\n return (\n <ChatConfigContext.Provider value={config}>\n {children}\n </ChatConfigContext.Provider>\n );\n};\n\nexport const useChatConfig = () => useContext(ChatConfigContext);\n","'use client';\n\nimport React from 'react';\nimport { ChatTask } from '../types/chat';\n\ninterface ChatHeaderProps {\n contextTitle: string;\n currentTask: ChatTask | null;\n onClose: () => void;\n}\n\nexport function ChatHeader({\n contextTitle,\n currentTask,\n onClose\n}: ChatHeaderProps) {\n return (\n <div className=\"bg-blue-500 text-white px-4 py-4 flex justify-between items-center\">\n <h3 className=\"font-medium text-lg\">\n {currentTask\n ? `DoveText Virtual Assistant (${currentTask.currentStep}/${currentTask.steps})`\n : `DoveText Virtual Assistant (${contextTitle})`}\n </h3>\n <button\n onClick={onClose}\n className=\"bg-blue-600 hover:bg-blue-700 text-white rounded-full p-1.5 flex items-center justify-center transition-colors cursor-pointer\"\n aria-label=\"Close chat\"\n >\n <svg xmlns=\"http://www.w3.org/2000/svg\" className=\"h-5 w-5\" viewBox=\"0 0 20 20\" fill=\"currentColor\">\n <path fillRule=\"evenodd\" d=\"M4.293 4.293a1 1 0 011.414 0L10 8.586l4.293-4.293a1 1 0 111.414 1.414L11.414 10l4.293 4.293a1 1 0 01-1.414 1.414L10 11.414l-4.293 4.293a1 1 0 01-1.414-1.414L8.586 10 4.293 5.707a1 1 0 010-1.414z\" clipRule=\"evenodd\" />\n </svg>\n </button>\n </div>\n );\n}\n","'use client';\n\nimport React, { useState, useRef, FormEvent, useImperativeHandle, forwardRef, useEffect } from 'react';\nimport { ArrowUpCircleIcon, MicrophoneIcon, StopIcon, PaperAirplaneIcon } from '@heroicons/react/24/outline';\nimport { ChatMessage, ChatTask, VoiceConfig } from '../types/chat';\nimport { InteractiveFunction } from '../types/interactive';\nimport { useSpeechRecognition } from '../hooks/useSpeechRecognition';\nimport { useAudioRecorder } from '../hooks/useAudioRecorder';\nimport { useProactiveResize } from '../hooks/useProactiveResize';\nimport { useChatConfig } from '../context/ChatConfigContext';\n\n// VoiceConfig imported from types/chat\n\ninterface ChatInputAreaProps {\n onSubmit: (message: string) => void;\n isSending: boolean;\n showInputForm: boolean;\n currentTask: ChatTask | null;\n lastInteractiveMessage?: ChatMessage | null;\n voiceConfig?: VoiceConfig;\n onStop?: () => void;\n hintText?: string;\n placeholder?: string;\n // Controlled props\n value?: string;\n onChange?: (e: React.ChangeEvent<HTMLTextAreaElement>) => void;\n defaultInputMode?: 'text' | 'voice';\n}\n\n// Define the handle type for the forwarded ref\nexport interface ChatInputAreaHandle {\n focus: () => void;\n setValue: (value: string) => void;\n}\n\nexport const ChatInputArea = forwardRef<ChatInputAreaHandle, ChatInputAreaProps>(({\n onSubmit,\n isSending,\n showInputForm,\n currentTask,\n lastInteractiveMessage,\n voiceConfig: propVoiceConfig, // Rename to distinguish from context\n onStop,\n hintText,\n placeholder,\n value,\n onChange,\n defaultInputMode = 'text'\n}, ref) => {\n const [internalMessage, setInternalMessage] = useState('');\n const [voiceTrigger, setVoiceTrigger] = useState<'click' | 'space' | null>(null);\n const [inputMode, setInputMode] = useState<'text' | 'voice'>(defaultInputMode);\n const [isFocused, setIsFocused] = useState(false);\n\n const textareaRef = useRef<HTMLTextAreaElement>(null);\n const measurementRef = useRef<HTMLSpanElement>(null);\n const voiceContainerRef = useRef<HTMLDivElement>(null);\n\n // Auto-focus container when switching to voice mode to enable immediate Space-to-Talk\n useEffect(() => {\n if (inputMode === 'voice') {\n voiceContainerRef.current?.focus();\n }\n }, [inputMode]);\n\n // Determine if controlled or uncontrolled\n const isControlled = value !== undefined;\n const message = isControlled ? value : internalMessage;\n\n // Get global config\n const { voice: globalVoice } = useChatConfig();\n\n // Determine effective voice config\n // If global says disabled, then no voice. \n // If global says enabled, use props config OR global config.\n const isVoiceEnabled = globalVoice?.enabled ?? (!!propVoiceConfig);\n const voiceConfig = isVoiceEnabled ? (propVoiceConfig || globalVoice?.config) : undefined;\n\n\n // Helper to fire onChange for non-user-input sources (voice, setValue) if controlled\n const triggerChange = (newValue: string) => {\n if (isControlled && onChange && textareaRef.current) {\n const syntheticEvent = {\n target: { value: newValue },\n currentTarget: { value: newValue }\n } as React.ChangeEvent<HTMLTextAreaElement>;\n onChange(syntheticEvent);\n } else {\n setInternalMessage(newValue);\n }\n };\n\n // Apply auto-resize\n const isInputDisabled = currentTask?.complete ||\n (lastInteractiveMessage?.interactive &&\n ((lastInteractiveMessage?.interactiveData?.function === 'form' && !lastInteractiveMessage?.isResponseSubmitted) ||\n (lastInteractiveMessage?.interactiveData?.function === 'confirm' && !lastInteractiveMessage?.isResponseSubmitted)));\n\n useProactiveResize(textareaRef, measurementRef, message, isInputDisabled || !!voiceTrigger || inputMode === 'voice');\n\n // Spacebar to talk logic\n // Spacebar to talk logic\n const handleVoiceKeyDown = (e: React.KeyboardEvent) => {\n if (inputMode !== 'voice' || isInputDisabled) return;\n\n if (e.code !== 'Space') return;\n\n // Check if user is typing in an input\n const activeElement = document.activeElement;\n const isInputActive = activeElement && (\n activeElement.tagName === 'INPUT' ||\n activeElement.tagName === 'TEXTAREA' ||\n (activeElement instanceof HTMLElement && activeElement.isContentEditable)\n );\n\n if (isInputActive) return;\n\n // Always prevent default scrolling when in voice mode (and not in a text input)\n // This applies to initial press AND repeats (hold)\n e.preventDefault();\n e.stopPropagation();\n\n // If we are in 'click' mode, ignore space interaction\n if (voiceTrigger === 'click') return;\n\n // Start 'Hold-to-Talk' only on initial press (not repeat) and if not already active\n if (!e.repeat && !voiceTrigger) {\n startRecording('space');\n }\n };\n\n const handleVoiceKeyUp = (e: React.KeyboardEvent) => {\n if (inputMode !== 'voice' || isInputDisabled) return;\n\n // Only stop if we were holding space\n if (e.code === 'Space') {\n if (voiceTrigger === 'space') {\n e.preventDefault();\n stopRecording();\n }\n }\n };\n\n // Voice Hooks\n const nativeSpeech = useSpeechRecognition((text) => {\n // If native, we typically append text.\n // For \"Hold to Talk\", we might want to just set it or append.\n // Let's stick to append.\n triggerChange(message + (message ? ' ' : '') + text);\n }, () => {\n setVoiceTrigger(null);\n voiceConfig?.onVoiceEnd?.();\n }, voiceConfig?.language);\n\n const customRecorder = useAudioRecorder(async (blob) => {\n setVoiceTrigger(null);\n voiceConfig?.onVoiceEnd?.();\n if (voiceConfig?.onAudioCapture) {\n try {\n const text = await voiceConfig.onAudioCapture(blob);\n if (text) triggerChange(message + (message ? ' ' : '') + text);\n } catch (e) {\n console.error('Audio capture failed', e);\n }\n }\n });\n\n // Expose the focus and setValue method to parent components\n // Expose the focus and setValue method to parent components\n useImperativeHandle(ref, () => ({\n focus: () => {\n if (inputMode === 'voice') {\n voiceContainerRef.current?.focus();\n } else {\n textareaRef.current?.focus();\n }\n },\n setValue: (newValue: string) => {\n triggerChange(newValue);\n }\n }));\n\n const handleSubmit = (e?: FormEvent) => {\n if (e) e.preventDefault();\n\n if (!message.trim()) {\n setTimeout(() => textareaRef.current?.focus(), 0);\n return;\n }\n\n const currentMessage = message;\n triggerChange(''); // Clear input\n setTimeout(() => textareaRef.current?.focus(), 0);\n onSubmit(currentMessage);\n };\n\n const handleKeyDown = (e: React.KeyboardEvent<HTMLTextAreaElement>) => {\n if (e.key === 'Enter' && !e.shiftKey && !e.metaKey && !e.altKey) {\n e.preventDefault();\n handleSubmit();\n }\n };\n\n const startRecording = async (trigger: 'click' | 'space') => {\n if (voiceTrigger) return;\n setVoiceTrigger(trigger);\n voiceConfig?.onVoiceStart?.();\n\n if (voiceConfig?.mode === 'native') {\n if (!nativeSpeech.isSupported) {\n alert('Speech recognition is not supported in this browser.');\n setVoiceTrigger(null);\n return;\n }\n nativeSpeech.start();\n } else {\n await customRecorder.start();\n }\n };\n\n const stopRecording = () => {\n if (!voiceTrigger) return;\n if (voiceConfig?.mode === 'native') {\n nativeSpeech.stop();\n } else {\n customRecorder.stop();\n }\n // setVoiceTrigger(null) is handled by callbacks\n };\n\n // Determine placeholder text based on interactive state\n const getPlaceholder = () => {\n if (placeholder) return placeholder;\n if (voiceTrigger) return 'Listening...';\n if (currentTask?.complete) {\n return 'Task completed!';\n }\n\n if (lastInteractiveMessage?.interactive && lastInteractiveMessage?.interactiveData && !lastInteractiveMessage?.isResponseSubmitted) {\n const interactiveType = lastInteractiveMessage.interactiveData.function as InteractiveFunction;\n\n switch (interactiveType) {\n case 'chat':\n return 'Type your response...';\n case 'confirm':\n return 'Select Yes or No, or type your response...';\n case 'select':\n return 'Choose an option or type your response...';\n case 'form':\n return 'Fill out the form...';\n default:\n return 'Type your response...';\n }\n }\n\n return currentTask ? 'Continue your conversation...' : 'Ask me anything...';\n };\n\n const inputHint = (!isInputDisabled && !lastInteractiveMessage?.interactive) ? null :\n (lastInteractiveMessage?.interactiveData?.function === 'form' ? 'Please provide information by completing above form' : null);\n\n if (!showInputForm) {\n return null;\n }\n\n return (\n <div className=\"flex flex-col w-full\">\n <div className=\"flex items-center gap-2\">\n {/* Voice/Keyboard Toggle */}\n {voiceConfig && (\n <button\n type=\"button\"\n onClick={() => {\n // If switching from voice, ensure recording is stopped\n if (inputMode === 'voice' && voiceTrigger) {\n stopRecording();\n }\n setInputMode(prev => prev === 'text' ? 'voice' : 'text');\n }}\n className=\"mb-1 p-2 text-gray-500 hover:text-gray-700 hover:bg-gray-100 rounded-full transition-colors flex-shrink-0 border border-gray-300 bg-white\"\n title={inputMode === 'text' ? \"Switch to Voice\" : \"Switch to Keyboard\"}\n >\n {inputMode === 'text' ? (\n // Voice Icon (Waveform)\n <svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 24 24\" fill=\"currentColor\" className=\"w-5 h-5 text-gray-600\">\n <path d=\"M11.25 4.532A.75.75 0 0 1 12 5.25v13.5a.75.75 0 0 1-1.5 0V5.25a.75.75 0 0 1 .75-.718ZM7.5 8.25a.75.75 0 0 1 .75.75v5.25a.75.75 0 0 1-1.5 0V9a.75.75 0 0 1 .75-.75Zm9 0a.75.75 0 0 1 .75.75v5.25a.75.75 0 0 1-1.5 0V9a.75.75 0 0 1 .75-.75ZM3.75 10.5a.75.75 0 0 1 .75.75v1.5a.75.75 0 0 1-1.5 0v-1.5a.75.75 0 0 1 .75-.75Zm16.5 0a.75.75 0 0 1 .75.75v1.5a.75.75 0 0 1-1.5 0v-1.5a.75.75 0 0 1 .75-.75Z\" />\n </svg>\n ) : (\n // Keyboard Icon (Filled)\n <svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 24 24\" fill=\"currentColor\" className=\"w-5 h-5 text-gray-600\">\n <path fillRule=\"evenodd\" d=\"M3 6a3 3 0 0 1 3-3h12a3 3 0 0 1 3 3v12a3 3 0 0 1-3 3H6a3 3 0 0 1-3-3V6Zm4.5 3a.75.75 0 0 1 .75-.75h1.5a.75.75 0 0 1 .75.75v1.5a.75.75 0 0 1-.75.75h-1.5a.75.75 0 0 1-.75-.75V9Zm6 0a.75.75 0 0 1 .75-.75h1.5a.75.75 0 0 1 .75.75v1.5a.75.75 0 0 1-.75.75h-1.5a.75.75 0 0 1-.75-.75V9Zm6 0a.75.75 0 0 1 .75-.75h1.5a.75.75 0 0 1 .75.75v1.5a.75.75 0 0 1-.75.75h-1.5a.75.75 0 0 1-.75-.75V9Zm-12 4.5a.75.75 0 0 1 .75-.75h1.5a.75.75 0 0 1 .75.75v1.5a.75.75 0 0 1-.75.75h-1.5a.75.75 0 0 1-.75-.75v-1.5Zm6 0a.75.75 0 0 1 .75-.75h6.75a.75.75 0 0 1 .75.75v1.5a.75.75 0 0 1-.75.75h-6.75a.75.75 0 0 1-.75-.75v-1.5Z\" clipRule=\"evenodd\" />\n </svg>\n )}\n </button>\n )}\n\n <div\n ref={voiceContainerRef}\n tabIndex={inputMode === 'voice' ? 0 : -1}\n onKeyDown={handleVoiceKeyDown}\n onKeyUp={handleVoiceKeyUp}\n onFocus={() => setIsFocused(true)}\n onBlur={() => setIsFocused(false)}\n className=\"flex-1 flex items-center border border-gray-300 rounded-lg overflow-hidden outline-none focus-within:ring-2 focus-within:ring-blue-500 focus-within:border-blue-500 bg-white min-h-[42px] mb-1\"\n >\n {/* Text Input Mode */}\n {inputMode === 'text' && (\n <>\n {/* Hidden span for proactive width measurement */}\n <span\n ref={measurementRef}\n className=\"absolute invisible whitespace-pre-wrap p-0 m-0 text-gray-700 leading-6\"\n style={{ fontSize: '1rem' }}\n />\n <textarea\n ref={textareaRef}\n value={message}\n onChange={(e) => {\n if (isControlled && onChange) {\n onChange(e);\n } else {\n setInternalMessage(e.target.value);\n }\n }}\n onKeyDown={handleKeyDown}\n placeholder={getPlaceholder()}\n disabled={isInputDisabled || !!voiceTrigger}\n rows={1}\n className={`flex-grow px-4 py-2 outline-none text-gray-700 placeholder-gray-500 disabled:bg-gray-100 resize-none leading-6 w-full ${isInputDisabled ? 'cursor-not-allowed' : ''}`}\n />\n </>\n )}\n\n {/* Voice Input Mode */}\n {inputMode === 'voice' && (\n <div className=\"flex-grow flex flex-col justify-center items-center p-1 relative\">\n <button\n type=\"button\"\n onClick={() => {\n if (voiceTrigger === 'click') {\n stopRecording();\n } else if (!voiceTrigger) {\n startRecording('click');\n }\n }}\n disabled={isInputDisabled || voiceTrigger === 'space'}\n className={`w-full py-2 text-center font-medium rounded-md transition-all select-none flex items-center justify-center gap-2 ${voiceTrigger\n ? 'bg-red-50 text-red-600 animate-pulse border border-red-200'\n : 'bg-gray-50 text-gray-700 hover:bg-gray-100'\n } ${voiceTrigger === 'space' ? 'opacity-90 cursor-default' : ''}`}\n >\n {voiceTrigger ? (\n <>\n <div className=\"w-2 h-2 rounded-full bg-red-500 animate-ping mr-2\" />\n <span>Listening... {voiceTrigger === 'space' ? '(Release Space to send)' : 'Tap to send'}</span>\n </>\n ) : (\n <span>Tap to Talk</span>\n )}\n </button>\n </div>\n )}\n\n {/* Send / Stop Button - Only show in text mode or if sending */}\n {(inputMode === 'text' || isSending) && (\n <div className=\"relative mx-2 flex-shrink-0\">\n {/* Spinner Overlay matching legacy ChatInput */}\n {isSending && (\n <div className=\"absolute -inset-1\">\n <svg\n className=\"animate-spin h-full w-full text-blue-500 opacity-75\"\n xmlns=\"http://www.w3.org/2000/svg\"\n fill=\"none\"\n viewBox=\"0 0 24 24\"\n >\n <circle\n className=\"opacity-25\"\n cx=\"12\"\n cy=\"12\"\n r=\"10\"\n stroke=\"currentColor\"\n strokeWidth=\"4\"\n ></circle>\n <path\n className=\"opacity-75\"\n fill=\"currentColor\"\n d=\"M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z\"\n ></path>\n </svg>\n </div>\n )}\n\n <button\n type=\"button\"\n onClick={(e) => {\n if (isSending && onStop) {\n e.preventDefault();\n onStop();\n } else {\n handleSubmit();\n }\n }}\n disabled={currentTask?.complete || (isSending && !onStop) || isInputDisabled || !!voiceTrigger}\n className={`relative z-10 text-white rounded-full p-2 transition-colors duration-200 disabled:bg-gray-400 disabled:cursor-not-allowed ${isSending && onStop\n ? 'bg-red-500 hover:bg-red-600'\n : 'bg-blue-600 hover:bg-blue-700'\n }`}\n title={isSending && onStop ? \"Stop generating\" : \"Send message\"}\n >\n {isSending ? (\n onStop ? (\n <StopIcon className=\"h-5 w-5\" />\n ) : (\n // AND we show the overlay spinner outside?\n // Actually `ChatInput.tsx` lines 117-140 are `isLoading && (...)`. It is always shown when loading.\n // So we have a spinner ring AROUND the button (absolute -inset-1).\n // AND potentially a spinner INSIDE the button if no onStop?\n // In my case, I will stick to:\n // If onStop: Show StopIcon. Button is Red.\n // If !onStop: Show Spinner inside? Or just let the outer ring do the work?\n // Legacy `Spinner` component usage inside button suggests double spinner if we are not careful.\n // But usually `onStop` is provided for streaming.\n // If I look at the screenshot, it shows a RED button (with stop icon) and a BLUE ring around it.\n // That matches: Red button (bg-red-500) + Blue Spinner Ring (text-blue-500).\n // So I will replicate that structure.\n <StopIcon className=\"h-5 w-5\" /> // Default fallback if sending without onStop? No, if !onStop, we might just show spinner.\n )\n ) : (\n <PaperAirplaneIcon className=\"h-5 w-5\" />\n )}\n </button>\n </div>\n )}\n </div>\n </div>\n\n {inputHint && (\n <div className=\"text-sm text-red-500 bg-red-50 py-1 px-4 rounded-lg mt-1\">\n {inputHint}\n </div>\n )}\n\n {(hintText && inputMode === 'text') && (\n <p className=\"text-xs text-gray-500 ml-12 mb-2 mt-1\">\n {hintText}\n </p>\n )}\n\n {(inputMode === 'voice' && !voiceTrigger) && (\n <p\n className=\"text-[10px] text-gray-400 font-medium ml-12 text-center -mt-1 mb-1 cursor-pointer hover:text-gray-600 transition-colors\"\n onClick={() => voiceContainerRef.current?.focus()}\n >\n {isFocused\n ? \"Click to talk or hold space to talk\"\n : \"Tap to talk or click here to focus and push space to talk\"\n }\n </p>\n )}\n </div>\n );\n});\n\nChatInputArea.displayName = 'ChatInputArea';\n","import { useState, useEffect, useCallback, useRef } from 'react';\n\nexport interface SpeechRecognitionHook {\n isListening: boolean;\n transcript: string;\n start: () => void;\n stop: () => void;\n resetTranscript: () => void;\n isSupported: boolean;\n error: string | null;\n}\n\ninterface SpeechRecognitionEvent {\n results: {\n [index: number]: {\n [index: number]: {\n transcript: string;\n };\n isFinal: boolean;\n };\n length: number;\n };\n}\n\ninterface SpeechRecognitionErrorEvent {\n error: string;\n}\n\nexport const useSpeechRecognition = (\n onResult?: (text: string, isFinal: boolean) => void,\n onEnd?: () => void,\n language: string = 'en-US'\n): SpeechRecognitionHook => {\n const [isListening, setIsListening] = useState(false);\n const [transcript, setTranscript] = useState('');\n const [error, setError] = useState<string | null>(null);\n const [isSupported, setIsSupported] = useState(false);\n\n const recognitionRef = useRef<any>(null);\n const isSimulatingRef = useRef(false);\n const simulationTimeoutRef = useRef<any>(null);\n\n\n\n useEffect(() => {\n if (typeof window !== 'undefined') {\n const SpeechRecognition = (window as any).SpeechRecognition || (window as any).webkitSpeechRecognition;\n if (SpeechRecognition) {\n setIsSupported(true);\n const recognition = new SpeechRecognition();\n recognition.continuous = true;\n recognition.interimResults = true;\n recognition.lang = language;\n\n recognition.onstart = () => {\n setIsListening(true);\n setError(null);\n };\n\n recognition.onend = () => {\n if (isSimulatingRef.current) return;\n setIsListening(false);\n if (onEnd) onEnd();\n };\n\n\n recognition.onresult = (event: SpeechRecognitionEvent) => {\n let interimTranscript = '';\n let finalTranscript = '';\n\n for (let i = event.results.length - 1; i < event.results.length; ++i) {\n const result = event.results[i];\n if (result.isFinal) {\n finalTranscript += result[0].transcript;\n if (onResult) onResult(finalTranscript, true);\n } else {\n interimTranscript += result[0].transcript;\n if (onResult) onResult(interimTranscript, false);\n }\n }\n\n // We mainly rely on onResult callback for real-time updates\n // But keep local state just in case\n setTranscript(prev => prev + finalTranscript);\n };\n\n recognition.onerror = (event: SpeechRecognitionErrorEvent) => {\n // Dev mode fallback: Simulate speech if permission is denied\n if (event.error === 'not-allowed' && process.env.NODE_ENV === 'development') {\n console.warn('Speech recognition blocked. Simulating input for development...');\n isSimulatingRef.current = true;\n setError(null);\n setIsListening(true);\n\n // Simulate a delay then result\n simulationTimeoutRef.current = setTimeout(() => {\n const mockText = \"This is a simulated voice input for testing.\";\n setTranscript(prev => prev + (prev ? ' ' : '') + mockText);\n if (onResult) onResult(mockText, true);\n\n isSimulatingRef.current = false;\n setIsListening(false);\n if (onEnd) onEnd();\n simulationTimeoutRef.current = null;\n }, 3000);\n return;\n }\n\n\n console.error('Speech recognition error', event.error);\n setError(event.error);\n setIsListening(false);\n };\n\n recognitionRef.current = recognition;\n }\n }\n\n return () => {\n if (isSimulatingRef.current && simulationTimeoutRef.current) {\n clearTimeout(simulationTimeoutRef.current);\n simulationTimeoutRef.current = null;\n }\n recognitionRef.current.stop();\n }\n }, [onResult, onEnd, language]);\n\n const start = useCallback(() => {\n if (recognitionRef.current && !isListening) {\n try {\n setTranscript('');\n recognitionRef.current.start();\n } catch (e) {\n console.error('Failed to start speech recognition:', e);\n }\n }\n }, [isListening]);\n\n const stop = useCallback(() => {\n if (isSimulatingRef.current) {\n if (simulationTimeoutRef.current) {\n clearTimeout(simulationTimeoutRef.current);\n simulationTimeoutRef.current = null;\n }\n // If stopped manually during simulation, we can either cancel or complete.\n // Let's complete it so user sees something.\n const mockText = \"This is a simulated voice input for testing.\";\n setTranscript(prev => prev + (prev ? ' ' : '') + mockText);\n if (onResult) onResult(mockText, true);\n\n isSimulatingRef.current = false;\n setIsListening(false);\n if (onEnd) onEnd();\n return;\n }\n\n if (recognitionRef.current && isListening) {\n recognitionRef.current.stop();\n }\n }, [isListening, onResult, onEnd]);\n\n const resetTranscript = useCallback(() => {\n setTranscript('');\n }, []);\n\n return {\n isListening,\n transcript,\n start,\n stop,\n resetTranscript,\n isSupported,\n error\n };\n};\n","import { useState, useRef, useCallback } from 'react';\n\nexport interface AudioRecorderHook {\n isRecording: boolean;\n start: () => Promise<void>;\n stop: () => void;\n blob: Blob | null;\n error: string | null;\n}\n\nexport const useAudioRecorder = (\n onStop?: (blob: Blob) => void\n): AudioRecorderHook => {\n const [isRecording, setIsRecording] = useState(false);\n const [blob, setBlob] = useState<Blob | null>(null);\n const [error, setError] = useState<string | null>(null);\n\n const mediaRecorderRef = useRef<MediaRecorder | null>(null);\n const chunksRef = useRef<Blob[]>([]);\n\n const start = useCallback(async () => {\n try {\n const stream = await navigator.mediaDevices.getUserMedia({ audio: true });\n const mediaRecorder = new MediaRecorder(stream);\n\n mediaRecorderRef.current = mediaRecorder;\n chunksRef.current = [];\n\n mediaRecorder.ondataavailable = (e) => {\n if (e.data.size > 0) {\n chunksRef.current.push(e.data);\n }\n };\n\n mediaRecorder.onstop = () => {\n const audioBlob = new Blob(chunksRef.current, { type: 'audio/webm' });\n setBlob(audioBlob);\n setIsRecording(false);\n if (onStop) onStop(audioBlob);\n\n // Stop all tracks\n stream.getTracks().forEach(track => track.stop());\n };\n\n mediaRecorder.start();\n setIsRecording(true);\n setError(null);\n } catch (e: any) {\n console.error('Failed to start audio recording:', e);\n setError(e.message || 'Microphone access denied');\n }\n }, [onStop]);\n\n const stop = useCallback(() => {\n if (mediaRecorderRef.current && mediaRecorderRef.current.state !== 'inactive') {\n mediaRecorderRef.current.stop();\n }\n }, []);\n\n return {\n isRecording,\n start,\n stop,\n blob,\n error\n };\n};\n","import { RefObject, useEffect } from 'react';\n\n/**\n * A hook that proactively resizes a textarea based on the content of a hidden measurement element.\n * This avoids the flickering often seen with standard \"height: auto\" approaches by measuring\n * the content in a hidden span first, then applying the height to the textarea.\n */\nexport function useProactiveResize(\n textareaRef: RefObject<HTMLTextAreaElement>,\n measurementRef: RefObject<HTMLSpanElement>,\n value: string,\n disabled: boolean\n) {\n useEffect(() => {\n if (!textareaRef.current || !measurementRef.current) return;\n\n // Copy styles from textarea to measurement span to ensure accurate sizing\n const styles = window.getComputedStyle(textareaRef.current);\n measurementRef.current.style.width = styles.width;\n measurementRef.current.style.font = styles.font; // Shorthand for font-style, font-variant, font-weight, font-size, line-height, font-family\n measurementRef.current.style.padding = styles.padding;\n measurementRef.current.style.border = styles.border;\n measurementRef.current.style.boxSizing = styles.boxSizing;\n measurementRef.current.style.whiteSpace = 'pre-wrap'; // Important for matching textarea behavior\n measurementRef.current.style.visibility = 'hidden';\n measurementRef.current.style.position = 'absolute';\n measurementRef.current.style.pointerEvents = 'none';\n\n // Set content to measurement span\n // Append a zero-width space to ensure empty lines are counted\n measurementRef.current.textContent = value + '\\u200B';\n\n // Calculate height\n const scrollHeight = measurementRef.current.offsetHeight;\n\n // Apply height to textarea\n // We add a small buffer (e.g., 2px) to prevent scrollbars from appearing due to sub-pixel rendering differences\n // But direct assignment is usually best.\n // Also respect min-height if set in CSS (typically handled by browser, but we set style.height)\n textareaRef.current.style.height = `${scrollHeight}px`;\n\n }, [value, disabled, textareaRef, measurementRef]);\n}\n","'use client';\n\nimport React, { useEffect, useRef } from 'react';\nimport { ChatMessage, ChatTask } from '../types/chat';\nimport InteractiveMessageHandler from './interactive/InteractiveMessageHandler';\nimport { InformationCircleIcon } from '@heroicons/react/24/outline';\nimport { MessageBubble } from './MessageBubble';\n\n// Define the props for the ChatMessageList component\ninterface ChatMessageListProps {\n chatHistory: ChatMessage[];\n isProcessing: boolean;\n processingHint: string;\n currentTask: ChatTask | null;\n getContextExample: () => string;\n onInteractiveResponse?: (messageId: string | number, response: any) => void;\n}\n\n/**\n * ChatMessageList component displays the chat messages and handles scrolling\n * Features:\n * - Displays user and system messages with different styling\n * - Shows a typing indicator when the system is processing\n * - Displays a welcome message when the chat is empty\n * - Auto-scrolls to the bottom when new messages arrive\n * - Handles interactive messages with different UI components\n */\nexport const ChatMessageList: React.FC<ChatMessageListProps> = ({\n chatHistory,\n isProcessing,\n processingHint,\n currentTask,\n getContextExample,\n onInteractiveResponse\n}) => {\n // Reference to the chat container for auto-scrolling\n const chatContainerRef = useRef<HTMLDivElement>(null);\n // Reference to the last message for scrolling into view\n const lastMessageRef = useRef<HTMLDivElement>(null);\n // Reference to the processing indicator\n const processingIndicatorRef = useRef<HTMLDivElement>(null);\n\n // Scroll to the bottom when chat history or processing state changes\n useEffect(() => {\n // If there's a processing indicator, scroll to it\n if (isProcessing && processingIndicatorRef.current) {\n processingIndicatorRef.current.scrollIntoView({ behavior: 'smooth' });\n return;\n }\n\n // If there's a last message, scroll to it\n if (lastMessageRef.current) {\n lastMessageRef.current.scrollIntoView({ behavior: 'smooth' });\n } else if (chatContainerRef.current) {\n // Fallback to scrolling the container\n chatContainerRef.current.scrollTop = chatContainerRef.current.scrollHeight;\n }\n }, [chatHistory, isProcessing]);\n\n // Handle interactive message responses\n const handleInteractiveResponse = (messageId: string | number, response: any) => {\n if (onInteractiveResponse) {\n onInteractiveResponse(messageId, response);\n }\n };\n\n return (\n <div\n ref={chatContainerRef}\n className=\"flex-1 overflow-y-auto p-4 space-y-4 bg-gray-50\"\n >\n {/* Welcome message when chat is empty */}\n {chatHistory.length === 0 && !isProcessing && (\n <div className=\"text-center py-8\">\n <h3 className=\"text-lg font-medium text-gray-700 mb-2\">How can I help you today?</h3>\n <p className=\"text-sm text-gray-500 mb-4\">\n Try asking me something like {getContextExample()}\n </p>\n </div>\n )}\n\n {/* Display chat messages */}\n {chatHistory.map((message, index) => {\n // Determine if this is the last message\n const isLastMessage = index === chatHistory.length - 1;\n const isUser = message.role === 'user';\n const isError = message.role === 'error';\n\n return (\n <div\n key={message.id || `message-${index}`}\n ref={isLastMessage ? lastMessageRef : undefined}\n className={`flex flex-col w-full ${isUser ? 'items-end' : 'items-start'}`}\n >\n {/* Timestamp display */}\n <div className=\"text-xs text-gray-400 mb-1 px-1\">\n {message.timestamp\n ? `${isUser ? 'Sent' : 'Received'} at ${new Date(message.timestamp).toLocaleString()}`\n : ''}\n </div>\n\n {/* Message Content */}\n <div className=\"w-full\">\n {message.interactive && message.interactiveData ? (\n <div className={`max-w-[85%] ${isUser ? 'ml-auto' : 'mr-auto'}`}>\n <InteractiveMessageHandler\n message={message.interactiveData}\n onResponse={(response: any) => {\n const messageId = message.id || `interactive-${index}-${Date.now()}`;\n message.responseValue = response;\n handleInteractiveResponse(messageId, response);\n }}\n isResponseSubmitted={!!message.isResponseSubmitted}\n parentMessage={message}\n />\n </div>\n ) : (\n <MessageBubble\n message={message}\n isUser={isUser}\n />\n )}\n </div>\n\n {isUser && message.interactive && (\n <div className=\"flex items-center mt-1 space-x-1 text-xs text-gray-500 italic\">\n <InformationCircleIcon className=\"h-3 w-3 text-blue-400\" />\n <span>\n {message.request === 'form' && 'Response to form submission'}\n {message.request === 'select' && 'Response to selection prompt'}\n {message.request === 'confirm' && 'Response to confirmation prompt'}\n </span>\n </div>\n )}\n </div>\n );\n })}\n\n {/* Show typing indicator when processing */}\n {isProcessing && (\n <div\n ref={processingIndicatorRef}\n className=\"flex justify-start\"\n >\n <div className=\"bg-white text-gray-800 border border-gray-200 rounded-lg px-4 py-2 max-w-[85%]\">\n <div className=\"flex items-center\">\n <span className=\"text-sm\">{processingHint}</span>\n <span className=\"ml-2 flex space-x-1\">\n <span className=\"h-2 w-2 bg-gray-400 rounded-full animate-bounce\" style={{ animationDelay: '0ms' }}></span>\n <span className=\"h-2 w-2 bg-gray-400 rounded-full animate-bounce\" style={{ animationDelay: '150ms' }}></span>\n <span className=\"h-2 w-2 bg-gray-400 rounded-full animate-bounce\" style={{ animationDelay: '300ms' }}></span>\n </span>\n </div>\n </div>\n </div>\n )}\n\n {/* Show task progress if available */}\n {currentTask && !currentTask.complete && (\n <div className=\"mt-4 bg-blue-50 border border-blue-100 rounded-lg p-3\">\n <div className=\"text-sm text-blue-800 mb-1\">\n Task in progress: Step {currentTask.currentStep} of {currentTask.steps}\n </div>\n <div className=\"w-full bg-blue-200 rounded-full h-2\">\n <div\n className=\"bg-blue-500 h-2 rounded-full\"\n style={{ width: `${(currentTask.currentStep / currentTask.steps) * 100}%` }}\n ></div>\n </div>\n </div>\n )}\n </div>\n );\n};\n\nexport default ChatMessageList;\n","'use client';\n\nimport React, { useState } from 'react';\nimport { ConfirmInteractionParams } from '../../types/interactive';\n\ninterface ConfirmInteractionProps {\n parameters: Record<string, any>;\n onResponse: (response: boolean) => void;\n isResponseSubmitted: boolean;\n}\n\n/**\n * Component for handling confirm (yes/no) interactions\n */\nconst ConfirmInteraction: React.FC<ConfirmInteractionProps> = ({\n parameters,\n onResponse,\n isResponseSubmitted\n}) => {\n const [selectedOption, setSelectedOption] = useState<string | null>(null);\n const params = parameters as ConfirmInteractionParams;\n\n // Extract parameters\n const { yesPrompt, noPrompt } = params;\n\n console.log('[ConfirmInteraction] Parameters:', params);\n\n const handleOptionClick = (value: boolean, buttonText: string) => {\n if (isResponseSubmitted) return;\n\n // Use the button text (yesPrompt/noPrompt) as the selected option\n setSelectedOption(buttonText);\n onResponse(value);\n };\n\n return (\n <div className=\"mt-2 mb-4\">\n <div className=\"flex space-x-2\">\n <button\n onClick={() => handleOptionClick(true, yesPrompt)}\n disabled={isResponseSubmitted}\n className={`px-4 py-2 rounded-md text-sm transition-colors ${isResponseSubmitted\n ? selectedOption === yesPrompt\n ? 'bg-blue-500 text-white' // Selected and submitted\n : 'bg-gray-200 text-gray-500 cursor-not-allowed' // Not selected and submitted\n : 'bg-blue-100 text-blue-700 hover:bg-blue-200'}`}\n >\n {yesPrompt}\n </button>\n <button\n onClick={() => handleOptionClick(false, noPrompt)}\n disabled={isResponseSubmitted}\n className={`px-4 py-2 rounded-md text-sm transition-colors ${isResponseSubmitted\n ? selectedOption === noPrompt\n ? 'bg-blue-500 text-white' // Selected and submitted\n : 'bg-gray-200 text-gray-500 cursor-not-allowed' // Not selected and submitted\n : 'bg-gray-100 text-gray-700 hover:bg-gray-200'}`}\n >\n {noPrompt}\n </button>\n </div>\n </div>\n );\n};\n\nexport default ConfirmInteraction;\n","'use client';\n\nimport React, { useState, useEffect } from 'react';\nimport { SelectInteractionParams } from '../../types/interactive';\n\ninterface SelectInteractionProps {\n parameters: Record<string, any>;\n onResponse: (response: string) => void;\n isResponseSubmitted: boolean;\n message?: any;\n}\n\n/**\n * Component for handling select interactions (choosing from multiple options)\n */\nconst SelectInteraction: React.FC<SelectInteractionProps> = ({\n parameters,\n onResponse,\n isResponseSubmitted,\n message\n}) => {\n const [selectedOption, setSelectedOption] = useState<string | null>(null);\n const [customOption, setCustomOption] = useState<string | null>(null);\n const params = parameters as SelectInteractionParams;\n\n const { question, options, placeholder } = params;\n\n // Effect to check if there's a responseValue to use\n useEffect(() => {\n if (isResponseSubmitted && message?.responseValue) {\n const responseValueStr = String(message.responseValue);\n setSelectedOption(responseValueStr);\n\n // Check if it's a custom option\n if (!options.includes(responseValueStr)) {\n setCustomOption(responseValueStr);\n }\n }\n }, [isResponseSubmitted, message, options]);\n\n const handleOptionClick = (option: string) => {\n if (isResponseSubmitted) return;\n\n setSelectedOption(option);\n setCustomOption(null); // Clear any custom option when selecting a predefined one\n onResponse(option);\n };\n\n return (\n <div className=\"mt-2 mb-4\">\n <div className=\"flex flex-wrap gap-2\">\n {options.map((option, index) => (\n <button\n key={index}\n onClick={() => handleOptionClick(option)}\n disabled={isResponseSubmitted}\n className={`px-4 py-2 rounded-md text-sm transition-colors ${isResponseSubmitted\n ? selectedOption === option\n ? 'bg-blue-500 text-white' // Selected and submitted\n : 'bg-gray-200 text-gray-500 cursor-not-allowed' // Not selected and submitted\n : 'bg-blue-100 text-blue-700 hover:bg-blue-200'}`}\n >\n {option}\n </button>\n ))}\n </div>\n\n {/* Show custom option message if applicable */}\n {customOption && isResponseSubmitted && (\n <div className=\"mt-2 text-sm text-amber-600 bg-amber-50 p-2 rounded\">\n User provided custom option: <span className=\"font-semibold\">\"{customOption}\"</span>\n </div>\n )}\n </div>\n );\n};\n\nexport default SelectInteraction;\n","'use client';\n\nimport React, { useState, useEffect, useRef } from 'react';\nimport { FormInteractionParams, FormField } from '../../types/interactive';\nimport { ChevronDownIcon, ChevronUpIcon } from 'lucide-react';\n\ninterface FormInteractionProps {\n parameters: Record<string, any>;\n onResponse: (response: Record<string, any>) => void;\n isResponseSubmitted: boolean;\n submittedValues?: Record<string, any>;\n}\n\n/**\n * Component for handling form interactions (collecting structured data)\n */\nconst FormInteraction: React.FC<FormInteractionProps> = ({\n parameters,\n onResponse,\n isResponseSubmitted,\n submittedValues\n}) => {\n const [isModalOpen, setIsModalOpen] = useState(false);\n const [formValues, setFormValues] = useState<Record<string, any>>({});\n const [isExpanded, setIsExpanded] = useState(false);\n const [parsedFields, setParsedFields] = useState<FormField[]>([]);\n const formButtonsRef = useRef<HTMLDivElement>(null);\n\n // Parse parameters to handle both array and object-based fields\n const parseParameters = () => {\n const { prompt, description, submitText = 'Submit', cancelText = 'Cancel' } = parameters;\n\n // Handle fields that might come as an array of stringified JSON\n let fieldsArray: FormField[] = [];\n\n if (parameters.fields) {\n // If fields is an array, parse each item if it's a string\n if (Array.isArray(parameters.fields)) {\n fieldsArray = parameters.fields.map(field => {\n if (typeof field === 'string') {\n try {\n const fieldData = JSON.parse(field);\n\n const name = fieldData.name;\n\n return {\n name,\n label: fieldData.label || name,\n type: fieldData.type || 'string',\n required: fieldData.required || false,\n options: fieldData.options || [],\n placeholder: fieldData.description || fieldData.label || name,\n defaultValue: fieldData.defaultValue\n } as FormField;\n } catch (error) {\n console.error(`Error parsing field:`, error);\n return null;\n }\n }\n return field;\n }).filter((field): field is FormField => field !== null);\n }\n // If fields is an object with stringified JSON values\n else if (typeof parameters.fields === 'object') {\n fieldsArray = Object.entries(parameters.fields).map(([name, fieldDataStr]) => {\n let fieldData: Record<string, any> = {};\n\n // Try to parse the stringified JSON\n try {\n if (typeof fieldDataStr === 'string') {\n fieldData = JSON.parse(fieldDataStr);\n } else {\n fieldData = fieldDataStr as Record<string, any>;\n }\n } catch (error) {\n console.error(`Error parsing field data for ${name}:`, error);\n }\n\n return {\n name,\n label: fieldData.label || name,\n type: fieldData.type || 'string',\n required: fieldData.required || false,\n options: fieldData.options || [],\n placeholder: fieldData.description || fieldData.label || name,\n defaultValue: fieldData.defaultValue\n } as FormField;\n });\n\n console.log('Field arrays: ', fieldsArray)\n }\n }\n\n return {\n title: prompt || 'Please fill out this form',\n description,\n fields: fieldsArray,\n submitText,\n cancelText\n };\n };\n\n const params = parseParameters();\n\n // Initialize form values with default values\n useEffect(() => {\n const processedParams = parseParameters();\n setParsedFields(processedParams.fields);\n\n const initialValues: Record<string, any> = {};\n processedParams.fields.forEach(field => {\n if (field.defaultValue !== undefined) {\n initialValues[field.name] = field.defaultValue;\n } else if (field.type === 'checkbox') {\n initialValues[field.name] = false;\n } else {\n initialValues[field.name] = '';\n }\n });\n setFormValues(initialValues);\n\n // Automatically open the modal when the component mounts\n if (!isResponseSubmitted) {\n setIsModalOpen(true);\n }\n }, [parameters, isResponseSubmitted]);\n\n // Effect to scroll form buttons into view when modal is opened\n useEffect(() => {\n if (isModalOpen && formButtonsRef.current) {\n setTimeout(() => {\n formButtonsRef.current?.scrollIntoView({ behavior: 'smooth', block: 'center' });\n }, 100); // Small delay to ensure form is rendered\n }\n }, [isModalOpen]);\n\n const handleInputChange = (field: FormField, value: any) => {\n setFormValues(prev => ({\n ...prev,\n [field.name]: value\n }));\n };\n\n const handleSubmit = (e: React.FormEvent) => {\n e.preventDefault();\n onResponse(formValues);\n setIsModalOpen(false);\n };\n\n const handleCancel = () => {\n onResponse({});\n setIsModalOpen(false);\n };\n\n const renderField = (field: FormField) => {\n const { name, label, type, required, options, placeholder } = field;\n\n switch (type) {\n case 'string':\n case 'email':\n case 'number':\n case 'password':\n return (\n <div className=\"mb-4 flex items-center space-x-4\" key={name}>\n <label htmlFor={name} className=\"text-sm font-medium text-gray-700 min-w-[120px]\">\n {label}{required && <span className=\"text-red-500\">*</span>}\n </label>\n <input\n type={type === 'string' ? 'text' : type}\n id={name}\n name={name}\n value={formValues[name] || ''}\n onChange={(e) => handleInputChange(field, e.target.value)}\n placeholder={placeholder}\n required={required}\n disabled={isResponseSubmitted}\n className=\"flex-1 px-3 py-2 border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-blue-500\"\n />\n </div>\n );\n\n case 'textarea':\n return (\n <div className=\"mb-4 flex items-start space-x-4\" key={name}>\n <label htmlFor={name} className=\"text-sm font-medium text-gray-700 min-w-[120px] pt-2\">\n {label}{required && <span className=\"text-red-500\">*</span>}\n </label>\n <textarea\n id={name}\n name={name}\n value={formValues[name] || ''}\n onChange={(e) => handleInputChange(field, e.target.value)}\n placeholder={placeholder}\n required={required}\n disabled={isResponseSubmitted}\n rows={4}\n className=\"flex-1 px-3 py-2 border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-blue-500\"\n />\n </div>\n );\n\n case 'select':\n return (\n <div className=\"mb-4 flex items-center space-x-4\" key={name}>\n <label htmlFor={name} className=\"text-sm font-medium text-gray-700 min-w-[120px]\">\n {label}{required && <span className=\"text-red-500\">*</span>}\n </label>\n <select\n id={name}\n name={name}\n value={formValues[name] || ''}\n onChange={(e) => handleInputChange(field, e.target.value)}\n required={required}\n disabled={isResponseSubmitted}\n className=\"flex-1 px-3 py-2 border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-blue-500\"\n >\n <option value=\"\" disabled>{placeholder || 'Select an option'}</option>\n {options?.map((option, index) => (\n <option key={index} value={option}>{option}</option>\n ))}\n </select>\n </div>\n );\n\n case 'checkbox':\n return (\n <div className=\"mb-4 flex items-center space-x-4\" key={name}>\n <div className=\"min-w-[120px]\" />\n <div className=\"flex items-center\">\n <input\n type=\"checkbox\"\n id={name}\n name={name}\n checked={!!formValues[name]}\n onChange={(e) => handleInputChange(field, e.target.checked)}\n required={required}\n disabled={isResponseSubmitted}\n className=\"h-4 w-4 text-blue-600 border-gray-300 rounded focus:ring-blue-500\"\n />\n <label htmlFor={name} className=\"ml-2 text-sm text-gray-700\">\n {label}{required && <span className=\"text-red-500\">*</span>}\n </label>\n </div>\n </div>\n );\n\n case 'radio':\n return (\n <div className=\"mb-4 flex space-x-4\" key={name}>\n <div className=\"text-sm font-medium text-gray-700 min-w-[120px] pt-2\">\n {label}{required && <span className=\"text-red-500\">*</span>}\n </div>\n <div className=\"flex-1 space-y-2\">\n {options?.map((option, index) => (\n <div key={index} className=\"flex items-center\">\n <input\n id={`${name}-${index}`}\n name={name}\n type=\"radio\"\n value={option}\n checked={formValues[name] === option}\n onChange={() => handleInputChange(field, option)}\n required={required}\n disabled={isResponseSubmitted}\n className=\"h-4 w-4 text-blue-600 border-gray-300 focus:ring-blue-500\"\n />\n <label htmlFor={`${name}-${index}`} className=\"ml-2 text-sm text-gray-700\">\n {option}\n </label>\n </div>\n ))}\n </div>\n </div>\n );\n\n default:\n return null;\n }\n };\n\n if (isResponseSubmitted) {\n // For submitted forms, show a summary of the responses\n return (\n <div className=\"mt-2 bg-gray-50 p-3 rounded-md border border-gray-200\">\n <div className=\"flex justify-between items-center cursor-pointer\" onClick={() => setIsExpanded(!isExpanded)}>\n <span className=\"font-medium text-gray-700\">{isExpanded ? 'Hide' : 'Show'} Form Responses</span>\n {isExpanded ?\n <ChevronUpIcon className=\"h-5 w-5 text-gray-500\" /> :\n <ChevronDownIcon className=\"h-5 w-5 text-gray-500\" />\n }\n </div>\n\n {isExpanded && (\n <div className=\"mt-2 space-y-2\">\n {parsedFields.map((field) => (\n <div key={field.name} className=\"flex\">\n <span className=\"text-sm font-medium text-gray-600 mr-2\">{field.label}:</span>\n <span className=\"text-sm text-gray-800\">\n {typeof submittedValues?.[field.name] === 'boolean'\n ? (submittedValues[field.name] ? 'Yes' : 'No')\n : submittedValues?.[field.name] || 'Not provided'}\n </span>\n </div>\n ))}\n </div>\n )}\n </div>\n );\n }\n\n // For new forms, show the modal\n return (\n <div className=\"mt-2\">\n {isModalOpen && (\n <div className=\"p-4\">\n <form onSubmit={handleSubmit} className=\"mt-4\">\n {parsedFields.map(field => renderField(field))}\n\n <div ref={formButtonsRef} className=\"flex justify-end mt-4 space-x-2\">\n <button\n type=\"button\"\n onClick={handleCancel}\n disabled={isResponseSubmitted}\n className=\"px-4 py-2 text-sm font-medium text-gray-700 bg-gray-100 border border-gray-300 rounded-md hover:bg-gray-200 focus:outline-none focus:ring-2 focus:ring-blue-500\"\n >\n {params.cancelText}\n </button>\n <button\n type=\"submit\"\n disabled={isResponseSubmitted}\n className=\"px-4 py-2 text-sm font-medium text-white bg-blue-600 rounded-md hover:bg-blue-700 focus:outline-none focus:ring-2 focus:ring-blue-500\"\n >\n {params.submitText}\n </button>\n </div>\n </form>\n </div>\n )}\n </div>\n );\n};\n\nexport default FormInteraction;\n","'use client';\n\nimport React from 'react';\nimport { PresentInteractionParams } from '../../types/interactive';\n\n// Try to import ReactMarkdown, but provide a fallback if it's not available\nlet ReactMarkdown: any;\ntry {\n // Dynamic import for ReactMarkdown\n ReactMarkdown = require('react-markdown');\n} catch (error) {\n // Fallback if ReactMarkdown is not available\n ReactMarkdown = ({ children }: { children: string }) => (\n <div className=\"whitespace-pre-wrap\">{children}</div>\n );\n}\n\ninterface PresentInteractionProps {\n parameters: Record<string, any>;\n}\n\n/**\n * Component for handling present interactions (displaying information)\n */\nconst PresentInteraction: React.FC<PresentInteractionProps> = ({\n parameters\n}) => {\n const params = parameters as PresentInteractionParams;\n const { title, content, format = 'text', level = 'info' } = params;\n\n // Define styles based on level\n const getLevelStyles = () => {\n switch (level) {\n case 'error':\n return {\n container: 'bg-red-50 border-red-100',\n title: 'text-red-800',\n content: 'text-red-700'\n };\n case 'warn':\n case 'warning':\n return {\n container: 'bg-amber-50 border-amber-100',\n title: 'text-amber-800',\n content: 'text-amber-700'\n };\n case 'success':\n return {\n container: 'bg-green-50 border-green-100',\n title: 'text-green-800',\n content: 'text-green-700'\n };\n case 'info':\n default:\n return {\n container: 'bg-blue-50 border-blue-100',\n title: 'text-blue-800',\n content: 'text-blue-700'\n };\n }\n };\n\n const styles = getLevelStyles();\n\n return (\n <div className={`mt-2 mb-4 p-4 ${styles.container} border rounded-md`}>\n {title && (\n <div className={`font-medium ${styles.title} mb-2`}>{title}</div>\n )}\n <div className={`text-sm ${styles.content}`}>\n {format === 'markdown' ? (\n <ReactMarkdown className=\"prose prose-sm max-w-none\">\n {content}\n </ReactMarkdown>\n ) : format === 'html' ? (\n <div dangerouslySetInnerHTML={{ __html: content }} />\n ) : (\n <div className=\"whitespace-pre-wrap\">{content}</div>\n )}\n </div>\n </div>\n );\n};\n\nexport default PresentInteraction;\n","'use client';\n\nimport React from 'react';\nimport { InteractiveMessage } from '../../types/interactive';\nimport ConfirmInteraction from './ConfirmInteraction';\nimport SelectInteraction from './SelectInteraction';\nimport FormInteraction from './FormInteraction';\nimport PresentInteraction from './PresentInteraction';\n\ninterface InteractiveMessageHandlerProps {\n message: InteractiveMessage;\n onResponse: (response: any) => void;\n isResponseSubmitted: boolean;\n parentMessage?: any; // Add reference to the parent ChatMessage\n}\n\n/**\n * Component that handles rendering different types of interactive messages\n * based on the function type (chat, confirm, select, form, present)\n */\nconst InteractiveMessageHandler: React.FC<InteractiveMessageHandlerProps> = ({\n message,\n onResponse,\n isResponseSubmitted,\n parentMessage\n}) => {\n const { function: functionType, parameters } = message;\n\n // Extract submitted response from parent message if available\n const submittedResponse = parentMessage?.responseValue;\n\n // Render the appropriate interaction component based on the function type\n switch (functionType) {\n case 'confirm':\n return (\n <ConfirmInteraction\n parameters={parameters}\n onResponse={onResponse}\n isResponseSubmitted={isResponseSubmitted}\n />\n );\n\n case 'select':\n return (\n <SelectInteraction\n parameters={parameters}\n onResponse={onResponse}\n isResponseSubmitted={isResponseSubmitted}\n message={parentMessage}\n />\n );\n\n case 'form':\n return (\n <FormInteraction\n parameters={parameters}\n onResponse={onResponse}\n isResponseSubmitted={isResponseSubmitted}\n submittedValues={submittedResponse}\n />\n );\n\n case 'present':\n return (\n <PresentInteraction\n parameters={parameters}\n />\n );\n\n case 'chat':\n // Chat is handled by the main input form, so we don't need a special component\n return null;\n\n default:\n console.warn(`Unknown interactive function type: ${functionType}`);\n return null;\n }\n};\n\nexport default InteractiveMessageHandler;\n","'use client';\n\nimport React from 'react';\nimport { Wifi, WifiOff, RefreshCw } from 'lucide-react';\n\ninterface ConnectionStatusProps {\n connectionStatus: 'connected' | 'disconnected' | 'reconnecting';\n onReconnect: () => void;\n}\n\nexport const ConnectionStatus: React.FC<ConnectionStatusProps> = ({\n connectionStatus,\n onReconnect\n}) => {\n return (\n <div className=\"bg-amber-100 connection-status flex items-center justify-between px-4 py-1 text-xs\">\n <div className=\"text-gray-700 font-medium\">\n You are talking with your personal Content Strategist\n </div>\n {connectionStatus === 'connected' && (\n <div className=\"flex items-center text-green-600\">\n <Wifi className=\"w-3 h-3 mr-1\" />\n <span>Connected</span>\n </div>\n )}\n {connectionStatus === 'reconnecting' && (\n <div className=\"flex items-center text-amber-600\">\n <RefreshCw className=\"w-3 h-3 mr-1 animate-spin\" />\n <span>Reconnecting...</span>\n </div>\n )}\n {connectionStatus === 'disconnected' && (\n <div className=\"flex items-center gap-2\">\n <div className=\"text-red-600 flex items-center\">\n <WifiOff className=\"w-3 h-3 mr-1\" />\n <span>Disconnected</span>\n </div>\n <button\n onClick={onReconnect}\n className=\"text-blue-600 hover:text-blue-800 flex items-center\"\n >\n <RefreshCw className=\"w-3 h-3 mr-1\" />\n <span>Reconnect</span>\n </button>\n </div>\n )}\n </div>\n );\n}\n","import React from 'react';\n\ninterface SpinnerProps {\n size?: 'sm' | 'md' | 'lg' | 'xl';\n className?: string;\n color?: string;\n}\n\nexport const Spinner: React.FC<SpinnerProps> = ({\n size = 'md',\n className = '',\n color = 'text-blue-600'\n}) => {\n const sizeClasses = {\n sm: 'h-4 w-4',\n md: 'h-6 w-6',\n lg: 'h-8 w-8',\n xl: 'h-12 w-12'\n };\n\n return (\n <svg\n className={`animate-spin ${sizeClasses[size]} ${color} ${className}`}\n xmlns=\"http://www.w3.org/2000/svg\"\n fill=\"none\"\n viewBox=\"0 0 24 24\"\n >\n <circle\n className=\"opacity-25\"\n cx=\"12\"\n cy=\"12\"\n r=\"10\"\n stroke=\"currentColor\"\n strokeWidth=\"4\"\n />\n <path\n className=\"opacity-75\"\n fill=\"currentColor\"\n d=\"M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z\"\n />\n </svg>\n );\n};\n","/**\n * Lightweight client for sending audio to a backend transcription endpoint.\n * This keeps the API key secret on the server.\n */\n\nexport interface TranscriptionConfig {\n endpoint: string;\n language?: string;\n // No headers needed if using standard fetch or cookies\n // Add custom headers support if needed for token auth\n headers?: Record<string, string>;\n}\n\nexport interface TranscriptionResult {\n text: string;\n error?: string;\n}\n\n/**\n * Transcribe audio blob by sending it to the configured backend endpoint.\n */\nexport async function transcribeAudio(\n audioBlob: Blob,\n config: TranscriptionConfig\n): Promise<string> {\n const formData = new FormData();\n formData.append('audio', audioBlob, 'recording.webm');\n\n if (config.language) {\n formData.append('language', config.language);\n }\n\n try {\n const response = await fetch(config.endpoint, {\n method: 'POST',\n body: formData,\n headers: config.headers || {},\n credentials: 'same-origin', // Ensure cookies are sent for same-domain requests\n });\n\n if (!response.ok) {\n const errorText = await response.text();\n throw new Error(`Transcription failed (${response.status}): ${errorText}`);\n }\n\n const data = await response.json();\n return data.text;\n } catch (error: any) {\n console.error('Transcription client error:', error);\n throw error;\n }\n}\n","import { VoiceConfig } from '../types/chat';\nimport { TranscriptionConfig, transcribeAudio } from '../services/whisper-client';\n\n/**\n * Helper to create a VoiceConfig that uses the backend Whisper transcription service.\n * \n * @param config - Configuration for the transcription endpoint\n * @param callbacks - Optional callbacks for voice events\n * @returns VoiceConfig ready to be used in ChatInputArea\n */\nexport function createWhisperVoiceConfig(\n config: TranscriptionConfig,\n callbacks?: {\n onVoiceStart?: () => void;\n onVoiceEnd?: () => void;\n }\n): VoiceConfig {\n return {\n mode: 'custom',\n onVoiceStart: callbacks?.onVoiceStart,\n onVoiceEnd: callbacks?.onVoiceEnd,\n /**\n * The core handler: takes the recorded blob and sends it to the server.\n */\n onAudioCapture: async (blob: Blob) => {\n return await transcribeAudio(blob, config);\n }\n };\n}\n"],"mappings":"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","names":["jsx","jsx","jsx","jsxs","useState","useRef","useEffect","useState","useRef","useCallback","useEffect","jsx","jsxs","useState","useRef","useEffect","_a","_b","useEffect","useRef","useState","jsx","jsxs","useState","useEffect","jsx","jsxs","useState","useEffect","useRef","jsx","jsxs","jsx","jsxs","ReactMarkdown","jsx","jsx","jsxs","useRef","useEffect","jsx","jsxs","jsx","jsxs"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@contentgrowth/llm-service",
3
- "version": "0.8.4",
3
+ "version": "0.8.5",
4
4
  "description": "Unified LLM Service for Content Growth",
5
5
  "main": "./dist/index.js",
6
6
  "module": "./dist/index.mjs",