@apteva/apteva-kit 0.1.11 → 0.1.12
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.js +8 -8
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +8 -8
- package/dist/index.mjs.map +1 -1
- package/dist/styles.css +1 -1
- package/package.json +1 -1
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["/Users/marcoschwartz/Documents/code/frontends/apteva/apteva-kit/dist/index.js","../src/components/Chat/Chat.tsx","../src/components/Chat/MessageList.tsx","../src/utils/cn.ts","../src/utils/mock-data.ts","../src/components/Widgets/Widgets.tsx","../src/components/Widgets/widget-library/Card.tsx","../src/components/Widgets/widget-library/List.tsx","../src/components/Widgets/widget-library/Button.tsx","../src/components/Widgets/WidgetRenderer.tsx","../src/components/Chat/MarkdownContent.tsx","../src/components/Chat/ToolCall.tsx","../src/components/Chat/Message.tsx","../src/components/Chat/Composer.tsx","../src/lib/apteva-client.ts","../src/components/Command/Command.tsx","../src/components/Prompt/Prompt.tsx","../src/components/Stream/Stream.tsx","../src/components/Threads/ThreadList.tsx","../src/components/Threads/ThreadItem.tsx","../src/components/Threads/Threads.tsx","../src/utils/theme-script.ts"],"names":["jsxs","jsx","useRef","threadId","useState","Fragment","result","error"],"mappings":"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","file":"/Users/marcoschwartz/Documents/code/frontends/apteva/apteva-kit/dist/index.js","sourcesContent":[null,"import { useState, useEffect } from 'react';\nimport { ChatProps } from '../../types/components';\nimport { Message as MessageType } from '../../types/messages';\nimport { MessageList } from './MessageList';\nimport { Composer } from './Composer';\nimport { cn, generateMockResponse } from '../../utils';\nimport { aptevaClient } from '../../lib/apteva-client';\nimport { Widget } from '../../types/widgets';\n\nexport function Chat({\n agentId,\n threadId,\n initialMessages = [],\n context,\n apiUrl,\n apiKey,\n useMock = false,\n onThreadChange,\n onMessageSent,\n onAction,\n onFileUpload,\n placeholder = 'Type a message...',\n showHeader = true,\n headerTitle = 'Chat',\n className,\n}: ChatProps) {\n const [messages, setMessages] = useState<MessageType[]>(initialMessages);\n const [isLoading, setIsLoading] = useState(false);\n const [currentThreadId, setCurrentThreadId] = useState<string | null>(threadId || null);\n\n // Configure API client if props provided\n useEffect(() => {\n if (apiUrl || apiKey) {\n aptevaClient.configure({\n ...(apiUrl && { apiUrl }),\n ...(apiKey && { apiKey }),\n });\n }\n }, [apiUrl, apiKey]);\n\n useEffect(() => {\n // Load messages when threadId changes\n if (threadId) {\n // In real implementation, fetch messages from API\n console.log('Loading thread:', threadId);\n onThreadChange?.(threadId);\n }\n }, [threadId, onThreadChange]);\n\n const handleSendMessage = async (text: string) => {\n // Add user message\n const userMessage: MessageType = {\n id: `msg-${Date.now()}`,\n role: 'user',\n content: text,\n timestamp: new Date(),\n };\n\n setMessages((prev) => [...prev, userMessage]);\n onMessageSent?.(userMessage);\n\n setIsLoading(true);\n\n try {\n if (useMock) {\n // MOCK MODE\n const response = await generateMockResponse(1000);\n setMessages((prev) => [...prev, response]);\n } else {\n // REAL API MODE\n // Content segments: array of { type: 'text' | 'tool', content/tool data }\n let contentSegments: Array<{ type: 'text'; content: string } | { type: 'tool'; id: string; name: string; result?: any }> = [];\n let currentTextBuffer = '';\n let accumulatedWidgets: Widget[] = [];\n let responseThreadId = currentThreadId;\n let toolInputBuffer = '';\n\n const updateMessage = () => {\n // Build content with tool markers embedded\n const segments = [...contentSegments];\n if (currentTextBuffer) {\n // Add current text buffer if exists\n const lastSegment = segments[segments.length - 1];\n if (lastSegment && lastSegment.type === 'text') {\n lastSegment.content = currentTextBuffer;\n } else {\n segments.push({ type: 'text', content: currentTextBuffer });\n }\n }\n\n setMessages((prev) => {\n const lastMessage = prev[prev.length - 1];\n if (lastMessage && lastMessage.role === 'assistant') {\n return [\n ...prev.slice(0, -1),\n {\n ...lastMessage,\n content: currentTextBuffer,\n widgets: accumulatedWidgets.length > 0 ? accumulatedWidgets : undefined,\n metadata: {\n ...lastMessage.metadata,\n content_segments: segments,\n },\n }\n ];\n } else {\n return [\n ...prev,\n {\n id: `msg-${Date.now()}-streaming`,\n role: 'assistant' as const,\n content: currentTextBuffer,\n widgets: accumulatedWidgets.length > 0 ? accumulatedWidgets : undefined,\n timestamp: new Date(),\n metadata: {\n content_segments: segments,\n },\n }\n ];\n }\n });\n };\n\n await aptevaClient.chatStream(\n {\n agent_id: agentId,\n message: text,\n stream: true,\n ...(currentThreadId && { thread_id: currentThreadId }),\n ...(context && { system: context }),\n },\n (chunk) => {\n // Handle different chunk types based on SSE event types\n switch (chunk.type) {\n case 'start':\n // Stream initialization\n break;\n\n case 'thread_id':\n // Thread identifier\n if (chunk.thread_id) {\n responseThreadId = chunk.thread_id;\n if (!currentThreadId) {\n setCurrentThreadId(chunk.thread_id);\n onThreadChange?.(chunk.thread_id);\n }\n }\n break;\n\n case 'content':\n case 'token':\n // Text content chunk\n if (chunk.content) {\n currentTextBuffer += chunk.content;\n updateMessage();\n }\n break;\n\n case 'tool_call':\n // Tool invocation announced\n if (chunk.tool_id && chunk.tool_name) {\n // Save current text as a segment\n if (currentTextBuffer) {\n contentSegments.push({ type: 'text', content: currentTextBuffer });\n currentTextBuffer = '';\n }\n // Add tool segment (initially running)\n contentSegments.push({\n type: 'tool',\n id: chunk.tool_id,\n name: chunk.tool_name,\n });\n toolInputBuffer = '';\n updateMessage();\n }\n break;\n\n case 'tool_input_delta':\n // Tool arguments streaming (accumulate JSON chunks)\n if (chunk.tool_id && chunk.content) {\n toolInputBuffer += chunk.content;\n }\n break;\n\n case 'tool_use':\n // Tool execution starting (input is complete)\n toolInputBuffer = '';\n break;\n\n case 'tool_result':\n // Tool execution completed\n if (chunk.tool_id) {\n // Find and update the tool segment\n const toolSegment = contentSegments.find(\n (s) => s.type === 'tool' && s.id === chunk.tool_id\n ) as { type: 'tool'; id: string; name: string; result?: any } | undefined;\n if (toolSegment) {\n toolSegment.result = chunk.content;\n }\n updateMessage();\n }\n break;\n\n case 'widget':\n // Widget from response\n if (chunk.widget) {\n accumulatedWidgets.push(chunk.widget);\n updateMessage();\n }\n break;\n\n case 'stop':\n // Intermediate stop (after tool execution, before next turn)\n break;\n\n case 'complete':\n // Stream complete\n break;\n\n case 'error':\n // Error occurred\n throw new Error(chunk.message || 'Stream error');\n\n default:\n // Unknown chunk type - silently ignore\n break;\n }\n },\n (threadId) => {\n // On complete\n // Save any remaining text\n if (currentTextBuffer) {\n const lastSegment = contentSegments[contentSegments.length - 1];\n if (lastSegment && lastSegment.type === 'text') {\n lastSegment.content = currentTextBuffer;\n } else {\n contentSegments.push({ type: 'text', content: currentTextBuffer });\n }\n }\n\n // Finalize the assistant message\n setMessages((prev) => {\n const lastMessage = prev[prev.length - 1];\n if (lastMessage && lastMessage.role === 'assistant') {\n return [\n ...prev.slice(0, -1),\n {\n ...lastMessage,\n id: `msg-${Date.now()}`,\n content: currentTextBuffer || 'Response received',\n widgets: accumulatedWidgets.length > 0 ? accumulatedWidgets : undefined,\n metadata: {\n thread_id: threadId,\n content_segments: contentSegments,\n },\n }\n ];\n }\n return prev;\n });\n\n if (threadId && threadId !== currentThreadId) {\n setCurrentThreadId(threadId);\n onThreadChange?.(threadId);\n }\n\n // Stop loading indicator\n setIsLoading(false);\n },\n (error) => {\n // On error\n\n // Add error message\n const errorMessage: MessageType = {\n id: `msg-${Date.now()}-error`,\n role: 'assistant',\n content: `Error: ${error.message}`,\n timestamp: new Date(),\n metadata: { error: true },\n };\n\n setMessages((prev) => {\n // Remove incomplete streaming message if exists\n const lastMessage = prev[prev.length - 1];\n if (lastMessage && lastMessage.id.includes('streaming')) {\n return [...prev.slice(0, -1), errorMessage];\n }\n return [...prev, errorMessage];\n });\n\n // Stop loading indicator\n setIsLoading(false);\n }\n );\n }\n } catch (error) {\n console.error('Chat error:', error);\n\n // Add error message\n const errorMessage: MessageType = {\n id: `msg-${Date.now()}-error`,\n role: 'assistant',\n content: error instanceof Error ? `Error: ${error.message}` : 'An error occurred',\n timestamp: new Date(),\n metadata: { error: true },\n };\n\n setMessages((prev) => [...prev, errorMessage]);\n } finally {\n setIsLoading(false);\n }\n };\n\n return (\n <div className={cn('flex flex-col h-full bg-white dark:bg-gray-900', className)}>\n {showHeader && (\n <div className=\"px-4 py-3 bg-white dark:bg-gray-900\">\n <h2 className=\"!text-lg font-semibold !text-gray-900 dark:!text-white\">{headerTitle}</h2>\n </div>\n )}\n\n <MessageList messages={messages} onAction={onAction} />\n\n {isLoading && (\n <div className=\"px-4 py-2 !text-sm !text-gray-500 dark:!text-gray-400 italic\">AI is thinking...</div>\n )}\n\n <Composer onSendMessage={handleSendMessage} placeholder={placeholder} disabled={isLoading} onFileUpload={onFileUpload} />\n </div>\n );\n}\n","import { useEffect, useRef } from 'react';\nimport { Message as MessageType } from '../../types/messages';\nimport { Message } from './Message';\nimport { ActionEvent } from '../../types/actions';\n\ninterface MessageListProps {\n messages: MessageType[];\n onAction?: (action: ActionEvent) => void;\n}\n\nexport function MessageList({ messages, onAction }: MessageListProps) {\n const listRef = useRef<HTMLDivElement>(null);\n\n useEffect(() => {\n // Auto-scroll to bottom when new messages arrive\n if (listRef.current) {\n listRef.current.scrollTop = listRef.current.scrollHeight;\n }\n }, [messages]);\n\n return (\n <div ref={listRef} className=\"flex-1 overflow-y-auto px-4 py-4 space-y-3 apteva-scrollbar-hidden\">\n {messages.length === 0 ? (\n <div className=\"flex items-center justify-center h-full !text-gray-500 dark:!text-gray-400\">\n <div className=\"text-center space-y-2\">\n <div className=\"text-4xl\">💬</div>\n <p>No messages yet. Start a conversation!</p>\n </div>\n </div>\n ) : (\n messages.map((message) => <Message key={message.id} message={message} onAction={onAction} />)\n )}\n </div>\n );\n}\n","import { clsx, type ClassValue } from 'clsx';\nimport { twMerge } from 'tailwind-merge';\n\nexport function cn(...inputs: ClassValue[]) {\n return twMerge(clsx(inputs));\n}\n","import { Message, Thread } from '../types/messages';\nimport { Widget } from '../types/widgets';\n\nexport const mockMessages: Message[] = [\n {\n id: 'msg-1',\n role: 'assistant',\n content: 'Hello! I\\'m your AI assistant. How can I help you today?',\n timestamp: new Date(Date.now() - 3600000),\n },\n {\n id: 'msg-2',\n role: 'user',\n content: 'I want to plan a trip to Europe',\n timestamp: new Date(Date.now() - 3500000),\n },\n {\n id: 'msg-3',\n role: 'assistant',\n content: 'Great choice! Europe has amazing destinations. What\\'s your budget and how many days do you have?',\n timestamp: new Date(Date.now() - 3400000),\n },\n {\n id: 'msg-4',\n role: 'user',\n content: 'Around $2000 for 5 days',\n timestamp: new Date(Date.now() - 3300000),\n },\n {\n id: 'msg-5',\n role: 'assistant',\n content: 'Perfect! I found some great destinations that fit your budget:',\n widgets: [\n {\n type: 'list',\n id: 'destinations-1',\n props: {\n items: [\n {\n id: 'paris',\n title: 'Paris, France',\n subtitle: '5 days • $1,850',\n description: 'The City of Light with iconic landmarks',\n metadata: { city: 'Paris', country: 'France', lat: 48.8566, lng: 2.3522, price: 1850, days: 5 },\n },\n {\n id: 'rome',\n title: 'Rome, Italy',\n subtitle: '5 days • $1,650',\n description: 'Ancient history meets modern culture',\n metadata: { city: 'Rome', country: 'Italy', lat: 41.9028, lng: 12.4964, price: 1650, days: 5 },\n },\n {\n id: 'barcelona',\n title: 'Barcelona, Spain',\n subtitle: '5 days • $1,450',\n description: 'Beautiful beaches and Gaudí architecture',\n metadata: { city: 'Barcelona', country: 'Spain', lat: 41.3851, lng: 2.1734, price: 1450, days: 5 },\n },\n ],\n },\n actions: [\n {\n type: 'select_destination',\n label: 'Select',\n handler: 'client',\n payload: {},\n },\n {\n type: 'view_details',\n label: 'Details',\n handler: 'server',\n payload: {},\n },\n ],\n },\n ],\n timestamp: new Date(Date.now() - 3200000),\n },\n];\n\nexport const mockThreads: Thread[] = [\n {\n id: 'thread-1',\n title: 'Trip to Europe',\n preview: 'Planning a 5-day trip...',\n createdAt: new Date(Date.now() - 86400000),\n updatedAt: new Date(Date.now() - 3600000),\n messageCount: 12,\n },\n {\n id: 'thread-2',\n title: 'Restaurant Recommendations',\n preview: 'Looking for good places...',\n createdAt: new Date(Date.now() - 172800000),\n updatedAt: new Date(Date.now() - 86400000),\n messageCount: 8,\n },\n {\n id: 'thread-3',\n title: 'Budget Planning',\n preview: 'Help with monthly budget',\n createdAt: new Date(Date.now() - 259200000),\n updatedAt: new Date(Date.now() - 172800000),\n messageCount: 15,\n },\n];\n\nexport const mockWidgets: Widget[] = [\n {\n type: 'card',\n id: 'card-1',\n props: {\n title: 'Paris, France',\n description: '5-day adventure in the City of Light',\n image: 'https://images.unsplash.com/photo-1502602898657-3e91760cbb34',\n footer: 'Total: $1,850',\n },\n actions: [\n {\n type: 'book_trip',\n label: 'Book Now',\n handler: 'client',\n payload: { tripId: 'trip-paris' },\n },\n ],\n },\n {\n type: 'card',\n id: 'card-2',\n props: {\n title: 'Rome, Italy',\n description: 'Explore ancient wonders',\n image: 'https://images.unsplash.com/photo-1552832230-c0197dd311b5',\n footer: 'Total: $1,650',\n },\n actions: [\n {\n type: 'book_trip',\n label: 'Book Now',\n handler: 'client',\n payload: { tripId: 'trip-rome' },\n },\n ],\n },\n];\n\nexport function generateMockResponse(delay: number = 1000): Promise<Message> {\n return new Promise((resolve) => {\n setTimeout(() => {\n resolve({\n id: `msg-${Date.now()}`,\n role: 'assistant',\n content: 'This is a mock response. In production, this would come from your AI agent API.',\n timestamp: new Date(),\n });\n }, delay);\n });\n}\n\nexport function generateMockStreamingResponse(\n text: string,\n onChunk: (chunk: string) => void,\n typingSpeed: number = 30\n): Promise<void> {\n return new Promise((resolve) => {\n const words = text.split(' ');\n let currentIndex = 0;\n\n const interval = setInterval(() => {\n if (currentIndex < words.length) {\n onChunk(words[currentIndex] + ' ');\n currentIndex++;\n } else {\n clearInterval(interval);\n resolve();\n }\n }, typingSpeed);\n });\n}\n\n// Generate mock plan based on command content\nexport function generateMockPlan(command: string): string {\n const lowerCommand = command.toLowerCase();\n\n if (lowerCommand.includes('analyze') || lowerCommand.includes('analysis')) {\n return `**Plan:**\\n\\n1. Fetch data from the analytics database\\n2. Apply filters and aggregations\\n3. Calculate key metrics and trends\\n4. Generate visualization data\\n5. Compile insights and recommendations`;\n }\n\n if (lowerCommand.includes('sales') || lowerCommand.includes('revenue')) {\n return `**Plan:**\\n\\n1. Query sales records for the specified period\\n2. Calculate total revenue and growth rates\\n3. Break down performance by product category\\n4. Analyze regional distribution\\n5. Present findings in charts and summary`;\n }\n\n if (lowerCommand.includes('report') || lowerCommand.includes('summary')) {\n return `**Plan:**\\n\\n1. Gather data from all relevant sources\\n2. Aggregate metrics across categories\\n3. Identify key trends and anomalies\\n4. Generate executive summary\\n5. Create detailed breakdowns with visualizations`;\n }\n\n if (lowerCommand.includes('customer') || lowerCommand.includes('user')) {\n return `**Plan:**\\n\\n1. Pull customer data from CRM\\n2. Calculate engagement metrics\\n3. Segment users by behavior patterns\\n4. Analyze satisfaction scores\\n5. Generate customer insights report`;\n }\n\n if (lowerCommand.includes('task') || lowerCommand.includes('todo') || lowerCommand.includes('work') || lowerCommand.includes('completed')) {\n return `**Plan:**\\n\\n1. Retrieve task records from the database\\n2. Filter by status and date range\\n3. Organize by priority and category\\n4. Calculate completion metrics\\n5. Display in interactive list format`;\n }\n\n // Default plan\n return `**Plan:**\\n\\n1. Parse and understand the command requirements\\n2. Gather necessary data from available sources\\n3. Process and analyze the information\\n4. Format results for optimal presentation\\n5. Return response with any relevant visualizations`;\n}\n\n// Generate mock command response based on command content\nexport function generateMockCommandResponse(command: string): string {\n const lowerCommand = command.toLowerCase();\n\n if (lowerCommand.includes('analyze') || lowerCommand.includes('analysis')) {\n return `Analysis complete for \"${command}\". Found 247 records with an average value of $1,234. The data shows a 23% increase compared to last quarter. Key insights: Revenue is up, customer satisfaction improved by 15%, and operational costs decreased by 8%.`;\n }\n\n if (lowerCommand.includes('sales') || lowerCommand.includes('revenue')) {\n return `Sales data processed: Q4 2024 revenue reached $2.4M, representing 18% growth year-over-year. Top performing products: Enterprise Plan (+45%), Pro Plan (+32%), Basic Plan (+12%). Regional breakdown: North America (52%), Europe (31%), APAC (17%).`;\n }\n\n if (lowerCommand.includes('report') || lowerCommand.includes('summary')) {\n return `Report generated successfully. Executive Summary: Overall performance exceeded targets by 12%. Marketing ROI improved to 3.2x, customer acquisition cost reduced by 18%, and lifetime value increased by 24%. Detailed breakdown available in attached widgets.`;\n }\n\n if (lowerCommand.includes('data') || lowerCommand.includes('metrics')) {\n return `Data metrics retrieved: 1,847 active users, 12,394 sessions this month, 94.2% uptime, average response time 127ms. Performance is within acceptable parameters. No critical issues detected.`;\n }\n\n if (lowerCommand.includes('customer') || lowerCommand.includes('user')) {\n return `Customer analysis complete: 523 new customers this month, 89% retention rate, average satisfaction score 4.6/5. Top feedback themes: excellent support (87%), easy to use (72%), good value (68%). 3 support tickets pending review.`;\n }\n\n // Default response\n return `This is a mock response showing how your agent would process and respond to commands. The actual response would be generated by your AI agent based on real data and context.`;\n}\n\n// Generate mock command response with widgets\nexport function generateMockCommandWithWidgets(command: string): { message: string; widgets: Widget[]; action?: { type: string; payload: any } } {\n const message = generateMockCommandResponse(command);\n const lowerCommand = command.toLowerCase();\n\n let widgets: Widget[] = [];\n let action: { type: string; payload: any } | undefined;\n\n // Add relevant widgets based on command type\n if (lowerCommand.includes('sales') || lowerCommand.includes('revenue') || lowerCommand.includes('analyze')) {\n widgets.push({\n type: 'card',\n id: `widget-${Date.now()}-1`,\n props: {\n title: 'Q4 2024 Performance',\n description: 'Revenue: $2.4M (+18% YoY)',\n footer: 'Updated: ' + new Date().toLocaleDateString(),\n },\n actions: [\n {\n type: 'view_details',\n label: 'View Details',\n handler: 'client',\n payload: { reportId: 'q4-2024' },\n },\n ],\n });\n }\n\n if (lowerCommand.includes('customer') || lowerCommand.includes('user')) {\n widgets.push({\n type: 'list',\n id: `widget-${Date.now()}-2`,\n props: {\n items: [\n {\n id: 'metric-1',\n title: 'Active Users',\n subtitle: '1,847 users',\n description: '+12% from last month',\n },\n {\n id: 'metric-2',\n title: 'Retention Rate',\n subtitle: '89%',\n description: 'Above industry average',\n },\n {\n id: 'metric-3',\n title: 'Satisfaction Score',\n subtitle: '4.6/5',\n description: 'Based on 234 reviews',\n },\n ],\n },\n });\n }\n\n // Add task widget for task-related commands\n if (lowerCommand.includes('task') || lowerCommand.includes('todo') || lowerCommand.includes('work') || lowerCommand.includes('completed')) {\n widgets.push({\n type: 'list',\n id: `widget-${Date.now()}-tasks`,\n props: {\n items: [\n {\n id: 'task-1',\n title: 'Implement user authentication',\n subtitle: 'Created just now',\n description: 'Added OAuth 2.0 support with Google and GitHub providers',\n backgroundColor: 'rgba(59, 130, 246, 0.15)',\n metadata: {\n status: 'created',\n priority: 'high',\n tags: ['backend', 'security']\n }\n },\n {\n id: 'task-2',\n title: 'Update API documentation',\n subtitle: 'Modified 2 minutes ago',\n description: 'Changed endpoint descriptions and added new examples',\n backgroundColor: 'rgba(234, 179, 8, 0.15)',\n metadata: {\n status: 'modified',\n priority: 'medium',\n tags: ['docs']\n }\n },\n {\n id: 'task-3',\n title: 'Fix login redirect bug',\n subtitle: 'Completed 5 minutes ago',\n description: 'Users now properly redirected after successful login',\n backgroundColor: 'rgba(34, 197, 94, 0.15)',\n metadata: {\n status: 'completed',\n priority: 'urgent',\n tags: ['bugfix', 'auth']\n }\n }\n ],\n },\n actions: [\n {\n type: 'view_task',\n label: 'View',\n handler: 'client',\n payload: {}\n },\n {\n type: 'undo',\n label: 'Undo',\n handler: 'server',\n payload: {}\n }\n ]\n });\n\n // Agent also wants to update the database after showing tasks\n action = {\n type: 'update_database',\n payload: {\n table: 'tasks',\n operation: 'mark_as_viewed',\n taskIds: ['task-1', 'task-2', 'task-3'],\n timestamp: new Date().toISOString()\n }\n };\n }\n\n // Add agent action for analysis commands\n if (lowerCommand.includes('analyze') || lowerCommand.includes('analysis')) {\n action = {\n type: 'send_notification',\n payload: {\n recipient: 'team@company.com',\n subject: 'Analysis Complete',\n message: 'Your requested analysis has been completed and is ready for review.'\n }\n };\n }\n\n return { message, widgets, action };\n}\n\n// Simulate streaming command response\nexport function generateMockCommandStream(\n command: string,\n onChunk: (chunk: { type: 'token' | 'widget' | 'complete'; content?: string; widget?: Widget }) => void,\n onComplete: (threadId: string) => void,\n onError: (error: Error) => void,\n typingSpeed: number = 30\n): void {\n const { message, widgets } = generateMockCommandWithWidgets(command);\n const words = message.split(' ');\n let currentIndex = 0;\n\n const interval = setInterval(() => {\n try {\n if (currentIndex < words.length) {\n onChunk({ type: 'token', content: words[currentIndex] + ' ' });\n currentIndex++;\n } else {\n clearInterval(interval);\n\n // Send widgets after text is complete\n widgets.forEach(widget => {\n onChunk({ type: 'widget', widget });\n });\n\n // Signal completion\n const threadId = `mock_thread_${Date.now()}`;\n onChunk({ type: 'complete' });\n onComplete(threadId);\n }\n } catch (error) {\n clearInterval(interval);\n onError(error instanceof Error ? error : new Error('Mock streaming error'));\n }\n }, typingSpeed);\n}\n","import { useEffect } from 'react';\nimport { WidgetsProps } from '../../types/components';\nimport { WidgetRenderer } from './WidgetRenderer';\nimport { cn } from '../../utils';\n\nexport function Widgets({\n widgets,\n onAction,\n onWidgetMount,\n layout = 'stack',\n spacing = 'normal',\n columns = 3,\n className,\n}: WidgetsProps) {\n useEffect(() => {\n widgets.forEach((widget) => {\n onWidgetMount?.(widget.id);\n });\n }, [widgets, onWidgetMount]);\n\n const layoutClasses = {\n stack: 'flex flex-col',\n grid: `grid grid-cols-1 md:grid-cols-${columns}`,\n masonry: 'columns-1 md:columns-2 lg:columns-3',\n };\n\n const spacingClasses = {\n tight: 'gap-2',\n normal: 'gap-4',\n loose: 'gap-6',\n };\n\n return (\n <div className={cn(layoutClasses[layout], spacingClasses[spacing], className)}>\n {widgets.map((widget) => (\n <WidgetRenderer key={widget.id} widget={widget} onAction={onAction} />\n ))}\n </div>\n );\n}\n","// No direct imports needed 'react';\nimport { CardWidget } from '../../../types/widgets';\nimport { ActionEvent } from '../../../types/actions';\n\ninterface CardProps {\n widget: CardWidget;\n onAction?: (action: ActionEvent) => void;\n}\n\nexport function Card({ widget, onAction }: CardProps) {\n const { title, description, image, footer } = widget.props;\n\n return (\n <div className=\"border border-gray-200 dark:border-gray-700 rounded-xl bg-white dark:bg-gray-900 overflow-hidden\">\n {image && <img src={image} alt={title} className=\"w-full h-48 object-cover\" />}\n\n <div className=\"p-4\">\n <h3 className=\"!text-lg font-semibold !text-gray-900 dark:!text-white\">{title}</h3>\n {description && <p className=\"!text-gray-600 dark:!text-gray-400 mt-2\">{description}</p>}\n </div>\n\n {(footer || (widget.actions && widget.actions.length > 0)) && (\n <div className=\"border-t border-gray-200 dark:border-gray-700 p-4 flex justify-between items-center\">\n {footer && <span className=\"!text-sm !text-gray-600 dark:!text-gray-400\">{footer}</span>}\n\n {widget.actions && widget.actions.length > 0 && (\n <div className=\"flex gap-2\">\n {widget.actions.map((action, idx) => (\n <button\n key={idx}\n onClick={() =>\n onAction?.({\n type: action.type,\n payload: action.payload,\n widgetId: widget.id,\n timestamp: new Date(),\n })\n }\n className=\"px-3 py-1.5 !text-sm rounded-lg font-medium transition-colors bg-blue-500 !text-white hover:bg-blue-600\"\n >\n {action.label}\n </button>\n ))}\n </div>\n )}\n </div>\n )}\n </div>\n );\n}\n","// No direct imports needed 'react';\nimport { ListWidget } from '../../../types/widgets';\nimport { ActionEvent } from '../../../types/actions';\n\ninterface ListProps {\n widget: ListWidget;\n onAction?: (action: ActionEvent) => void;\n}\n\nexport function List({ widget, onAction }: ListProps) {\n const { items } = widget.props;\n\n return (\n <div className=\"border border-gray-200 dark:border-gray-700 rounded-xl bg-white dark:bg-gray-900 overflow-hidden\">\n {items.map((item, index) => (\n <div\n key={item.id}\n className={`flex items-center p-4 transition-colors ${\n index !== items.length - 1 ? 'border-b border-gray-200 dark:border-gray-700' : ''\n } ${!item.backgroundColor ? 'hover:bg-gray-50 dark:hover:bg-gray-800' : ''}`}\n style={item.backgroundColor ? { backgroundColor: item.backgroundColor } : undefined}\n >\n {item.image && <img src={item.image} alt={item.title} className=\"w-16 h-16 rounded object-cover\" />}\n\n <div className={`flex-1 ${item.image ? 'ml-4' : ''}`}>\n <h4 className=\"font-semibold !text-gray-900 dark:!text-white\">{item.title}</h4>\n {item.subtitle && <p className=\"!text-sm !text-gray-600 dark:!text-gray-400\">{item.subtitle}</p>}\n {item.description && (\n <p className=\"!text-xs !text-gray-500 dark:!text-gray-500 mt-1\">{item.description}</p>\n )}\n </div>\n\n {widget.actions && widget.actions.length > 0 && (\n <div className=\"flex gap-2\">\n {widget.actions.map((action, idx) => (\n <button\n key={idx}\n onClick={() =>\n onAction?.({\n type: action.type,\n payload: item.metadata || item,\n widgetId: widget.id,\n timestamp: new Date(),\n })\n }\n className=\"px-3 py-1.5 !text-sm rounded-lg font-medium transition-colors bg-blue-500 !text-white hover:bg-blue-600\"\n >\n {action.label}\n </button>\n ))}\n </div>\n )}\n </div>\n ))}\n </div>\n );\n}\n","// No direct imports needed 'react';\nimport { ButtonWidget } from '../../../types/widgets';\nimport { ActionEvent } from '../../../types/actions';\nimport { cn } from '../../../utils';\n\ninterface ButtonProps {\n widget: ButtonWidget;\n onAction?: (action: ActionEvent) => void;\n}\n\nexport function Button({ widget, onAction }: ButtonProps) {\n const { label, variant = 'primary', disabled = false } = widget.props;\n\n const variantClasses = {\n primary: 'bg-blue-500 !text-white hover:bg-blue-600',\n secondary: 'bg-gray-500 !text-white hover:bg-gray-600',\n outline: 'border-2 border-blue-500 !text-blue-500 hover:bg-blue-50 dark:hover:bg-blue-900',\n ghost: '!text-blue-500 hover:bg-blue-50 dark:hover:bg-blue-900',\n };\n\n return (\n <button\n onClick={() =>\n widget.actions?.[0] &&\n onAction?.({\n type: widget.actions[0].type,\n payload: widget.actions[0].payload,\n widgetId: widget.id,\n timestamp: new Date(),\n })\n }\n disabled={disabled}\n className={cn('px-4 py-2 rounded-lg font-medium transition-colors', variantClasses[variant], {\n 'opacity-50 cursor-not-allowed': disabled,\n })}\n >\n {label}\n </button>\n );\n}\n","// No direct imports needed 'react';\nimport { Widget } from '../../types/widgets';\nimport { ActionEvent } from '../../types/actions';\nimport { Card, List, Button } from './widget-library';\n\ninterface WidgetRendererProps {\n widget: Widget;\n onAction?: (action: ActionEvent) => void;\n}\n\nexport function WidgetRenderer({ widget, onAction }: WidgetRendererProps) {\n switch (widget.type) {\n case 'card':\n return <Card widget={widget as any} onAction={onAction} />;\n case 'list':\n return <List widget={widget as any} onAction={onAction} />;\n case 'button':\n return <Button widget={widget as any} onAction={onAction} />;\n default:\n return (\n <div className=\"p-4 border border-yellow-300 bg-yellow-50 rounded-lg\">\n <p className=\"text-sm text-yellow-800\">Unknown widget type: {widget.type}</p>\n <pre className=\"text-xs mt-2 overflow-auto\">{JSON.stringify(widget, null, 2)}</pre>\n </div>\n );\n }\n}\n","import React from 'react';\n\ninterface MarkdownContentProps {\n content: string;\n className?: string;\n}\n\nfunction parseInlineMarkdown(text: string, keyPrefix: string = ''): React.ReactNode[] {\n const result: React.ReactNode[] = [];\n // Match **bold** or __bold__\n const boldRegex = /(\\*\\*|__)(.+?)\\1/g;\n\n let lastIndex = 0;\n let match;\n let key = 0;\n\n while ((match = boldRegex.exec(text)) !== null) {\n // Add text before the match\n if (match.index > lastIndex) {\n result.push(text.slice(lastIndex, match.index));\n }\n // Add bold text\n result.push(<strong key={`${keyPrefix}b${key++}`}>{match[2]}</strong>);\n lastIndex = match.index + match[0].length;\n }\n\n // Add remaining text\n if (lastIndex < text.length) {\n result.push(text.slice(lastIndex));\n }\n\n return result.length > 0 ? result : [text];\n}\n\nfunction parseMarkdown(content: string): React.ReactNode[] {\n const lines = content.split('\\n');\n const result: React.ReactNode[] = [];\n let key = 0;\n let i = 0;\n\n while (i < lines.length) {\n const line = lines[i];\n\n // Check for headings (## or ###)\n const h2Match = line.match(/^##\\s+(.*)$/);\n if (h2Match) {\n result.push(\n <h2 key={`h2${key++}`} className=\"apteva-md-h2\">\n {parseInlineMarkdown(h2Match[1], `${key}`)}\n </h2>\n );\n i++;\n continue;\n }\n\n const h3Match = line.match(/^###\\s+(.*)$/);\n if (h3Match) {\n result.push(\n <h3 key={`h3${key++}`} className=\"apteva-md-h3\">\n {parseInlineMarkdown(h3Match[1], `${key}`)}\n </h3>\n );\n i++;\n continue;\n }\n\n // Check for unordered list item (-, *, +)\n const ulMatch = line.match(/^(\\s*)([-*+])\\s+(.*)$/);\n if (ulMatch) {\n const listItems: React.ReactNode[] = [];\n const indent = ulMatch[1].length;\n\n while (i < lines.length) {\n const itemMatch = lines[i].match(/^(\\s*)([-*+])\\s+(.*)$/);\n if (itemMatch && itemMatch[1].length === indent) {\n listItems.push(\n <li key={`li${key++}`} className=\"apteva-md-li\">{parseInlineMarkdown(itemMatch[3], `${key}`)}</li>\n );\n i++;\n } else {\n break;\n }\n }\n\n result.push(\n <ul key={`ul${key++}`} className=\"apteva-md-ul\">\n {listItems}\n </ul>\n );\n continue;\n }\n\n // Check for ordered list item (1., 2., etc.)\n const olMatch = line.match(/^(\\s*)(\\d+)\\.\\s+(.*)$/);\n if (olMatch) {\n const listItems: React.ReactNode[] = [];\n const indent = olMatch[1].length;\n\n while (i < lines.length) {\n const itemMatch = lines[i].match(/^(\\s*)(\\d+)\\.\\s+(.*)$/);\n if (itemMatch && itemMatch[1].length === indent) {\n listItems.push(\n <li key={`li${key++}`} className=\"apteva-md-li\">{parseInlineMarkdown(itemMatch[3], `${key}`)}</li>\n );\n i++;\n } else {\n break;\n }\n }\n\n result.push(\n <ol key={`ol${key++}`} className=\"apteva-md-ol\">\n {listItems}\n </ol>\n );\n continue;\n }\n\n // Regular line - parse inline markdown and preserve line breaks\n if (line === '') {\n result.push(<br key={`br${key++}`} />);\n } else {\n result.push(\n <span key={`p${key++}`}>\n {parseInlineMarkdown(line, `${key}`)}\n {i < lines.length - 1 ? '\\n' : ''}\n </span>\n );\n }\n i++;\n }\n\n return result;\n}\n\nexport function MarkdownContent({ content, className = '' }: MarkdownContentProps) {\n return (\n <div className={`apteva-md ${className}`}>\n {parseMarkdown(content)}\n </div>\n );\n}\n","import React from 'react';\n\ninterface ToolCallProps {\n name: string;\n status: 'running' | 'completed' | 'error';\n}\n\nexport function ToolCall({ name, status }: ToolCallProps) {\n return (\n <div className=\"flex items-center gap-2 py-2 px-3 my-2 rounded-lg bg-gray-100 dark:bg-gray-800 border border-gray-200 dark:border-gray-700 text-sm\">\n {status === 'running' && (\n <div className=\"w-2 h-2 rounded-full bg-blue-500 animate-pulse\" />\n )}\n {status === 'completed' && (\n <div className=\"w-2 h-2 rounded-full bg-green-500\" />\n )}\n {status === 'error' && (\n <div className=\"w-2 h-2 rounded-full bg-red-500\" />\n )}\n <span className=\"text-gray-700 dark:text-gray-300 font-mono\">\n {name}\n </span>\n {status === 'running' && (\n <span className=\"text-gray-500 dark:text-gray-400 ml-auto\">Running...</span>\n )}\n {status === 'completed' && (\n <span className=\"text-green-600 dark:text-green-400 ml-auto\">Completed</span>\n )}\n {status === 'error' && (\n <span className=\"text-red-600 dark:text-red-400 ml-auto\">Error</span>\n )}\n </div>\n );\n}\n","// No direct imports needed 'react';\nimport { Message as MessageType } from '../../types/messages';\nimport { cn } from '../../utils';\nimport { Widgets } from '../Widgets';\nimport { ActionEvent } from '../../types/actions';\nimport { MarkdownContent } from './MarkdownContent';\nimport { ToolCall } from './ToolCall';\n\ntype ContentSegment =\n | { type: 'text'; content: string }\n | { type: 'tool'; id: string; name: string; result?: any };\n\ninterface MessageProps {\n message: MessageType;\n onAction?: (action: ActionEvent) => void;\n}\n\nexport function Message({ message, onAction }: MessageProps) {\n const isUser = message.role === 'user';\n const contentSegments = message.metadata?.content_segments as ContentSegment[] | undefined;\n\n // Render content with inline tool calls\n const renderContent = () => {\n if (isUser) {\n return <div className=\"whitespace-pre-wrap !text-sm leading-relaxed\">{message.content}</div>;\n }\n\n // If we have content segments, render them in order\n if (contentSegments && contentSegments.length > 0) {\n return (\n <div>\n {contentSegments.map((segment, index) => {\n if (segment.type === 'text') {\n return segment.content ? (\n <MarkdownContent key={`text-${index}`} content={segment.content} />\n ) : null;\n } else if (segment.type === 'tool') {\n return (\n <div key={segment.id} className=\"my-2\">\n <ToolCall\n name={segment.name}\n status={segment.result !== undefined ? 'completed' : 'running'}\n />\n </div>\n );\n }\n return null;\n })}\n </div>\n );\n }\n\n // Fallback to just content\n return <MarkdownContent content={message.content} />;\n };\n\n return (\n <div\n className={cn(\n 'max-w-[80%]',\n isUser\n ? 'px-4 py-2.5 rounded-xl bg-gray-100 dark:bg-gray-800 !text-gray-900 dark:!text-gray-100 ml-auto'\n : '!text-gray-900 dark:!text-gray-100'\n )}\n >\n {renderContent()}\n\n {message.widgets && message.widgets.length > 0 && (\n <div className={cn(isUser ? 'mt-3' : 'mt-2')}>\n <Widgets widgets={message.widgets} onAction={onAction} layout=\"stack\" />\n </div>\n )}\n\n <div className={cn('!text-xs opacity-70', isUser ? 'mt-1.5 !text-gray-500 dark:!text-gray-400' : 'mt-1 !text-gray-500 dark:!text-gray-400')} suppressHydrationWarning>\n {message.timestamp.toLocaleTimeString([], { hour: '2-digit', minute: '2-digit' })}\n </div>\n </div>\n );\n}\n","import { useState, KeyboardEvent, useRef } from 'react';\n\ninterface ComposerProps {\n onSendMessage: (text: string) => void;\n placeholder?: string;\n disabled?: boolean;\n onFileUpload?: (files: FileList) => void;\n}\n\nexport function Composer({ onSendMessage, placeholder = 'Type a message...', disabled = false, onFileUpload }: ComposerProps) {\n const [text, setText] = useState('');\n const [showMenu, setShowMenu] = useState(false);\n const textareaRef = useRef<HTMLTextAreaElement>(null);\n const fileInputRef = useRef<HTMLInputElement>(null);\n\n const handleKeyDown = (e: KeyboardEvent<HTMLTextAreaElement>) => {\n if (e.key === 'Enter' && !e.shiftKey) {\n e.preventDefault();\n handleSend();\n }\n };\n\n const handleSend = () => {\n if (text.trim() && !disabled) {\n onSendMessage(text.trim());\n setText('');\n // Reset textarea height\n if (textareaRef.current) {\n textareaRef.current.style.height = 'auto';\n }\n }\n };\n\n const handleChange = (e: React.ChangeEvent<HTMLTextAreaElement>) => {\n setText(e.target.value);\n // Auto-resize textarea\n e.target.style.height = 'auto';\n e.target.style.height = `${e.target.scrollHeight}px`;\n };\n\n const handleFileSelect = (e: React.ChangeEvent<HTMLInputElement>) => {\n if (e.target.files && e.target.files.length > 0) {\n onFileUpload?.(e.target.files);\n setShowMenu(false);\n }\n };\n\n return (\n <div className=\"px-4 py-3 bg-white dark:bg-gray-900 relative\">\n {/* Menu Popup */}\n {showMenu && (\n <>\n <div className=\"fixed inset-0 z-10\" onClick={() => setShowMenu(false)} />\n <div className=\"absolute bottom-full left-4 mb-2 bg-gray-800 dark:bg-gray-700 rounded-xl shadow-lg overflow-hidden z-20 min-w-[240px]\">\n <button\n onClick={() => fileInputRef.current?.click()}\n className=\"w-full flex items-center gap-3 px-4 py-3 hover:bg-gray-700 dark:hover:bg-gray-600 transition-colors !text-white text-left\"\n >\n <svg width=\"20\" height=\"20\" viewBox=\"0 0 20 20\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\n <path d=\"M10.5 3.5L5.5 8.5C4.67157 9.32843 4.67157 10.6716 5.5 11.5C6.32843 12.3284 7.67157 12.3284 8.5 11.5L14.5 5.5C15.8807 4.11929 15.8807 1.88071 14.5 0.5C13.1193 -0.880711 10.8807 -0.880711 9.5 0.5L3.5 6.5C1.56846 8.43154 1.56846 11.5685 3.5 13.5C5.43154 15.4315 8.56846 15.4315 10.5 13.5L15.5 8.5\" stroke=\"currentColor\" strokeWidth=\"1.5\" strokeLinecap=\"round\" strokeLinejoin=\"round\" transform=\"translate(2, 3)\"/>\n </svg>\n <span className=\"!text-sm font-medium\">Add photos & files</span>\n </button>\n </div>\n </>\n )}\n\n <div className=\"relative border-2 border-gray-300 dark:border-gray-700 rounded-xl bg-white dark:bg-gray-900 transition-all duration-300 flex items-center px-3 py-2 gap-3\">\n <button\n onClick={() => setShowMenu(!showMenu)}\n className=\"w-8 h-8 rounded-lg flex items-center justify-center transition-all flex-shrink-0 !text-gray-700 dark:!text-gray-300 hover:bg-gray-100 dark:hover:bg-gray-800\"\n title=\"More options\"\n >\n <svg width=\"20\" height=\"20\" viewBox=\"0 0 20 20\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\n <path d=\"M10 5v10M5 10h10\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\"/>\n </svg>\n </button>\n\n <textarea\n ref={textareaRef}\n value={text}\n onChange={handleChange}\n onKeyDown={handleKeyDown}\n placeholder={placeholder}\n disabled={disabled}\n className=\"flex-1 resize-none bg-transparent border-none focus:outline-none !text-gray-900 dark:!text-gray-100 placeholder-gray-400 dark:placeholder-gray-500 py-1 disabled:opacity-50 disabled:cursor-not-allowed\"\n rows={1}\n style={{ maxHeight: '120px' }}\n />\n\n <button\n onClick={handleSend}\n disabled={!text.trim() || disabled}\n className=\"w-8 h-8 rounded-lg flex items-center justify-center font-bold transition-all flex-shrink-0 border border-gray-300 dark:border-gray-600 bg-white dark:bg-gray-800 !text-gray-700 dark:!text-gray-300 hover:bg-gray-50 dark:hover:bg-gray-700 disabled:opacity-30 disabled:cursor-not-allowed !text-lg\"\n title=\"Send message\"\n >\n <svg width=\"16\" height=\"16\" viewBox=\"0 0 16 16\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\n <path d=\"M8 3L8 13M8 3L4 7M8 3L12 7\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\"/>\n </svg>\n </button>\n </div>\n\n {/* Hidden file input */}\n <input\n ref={fileInputRef}\n type=\"file\"\n multiple\n onChange={handleFileSelect}\n className=\"hidden\"\n accept=\"image/*,application/pdf,.doc,.docx,.txt\"\n />\n </div>\n );\n}\n","export interface AptevaClientConfig {\n apiUrl?: string;\n apiKey?: string;\n}\n\nexport interface ChatMessage {\n role: 'user' | 'assistant' | 'system';\n content: string;\n}\n\nexport interface ChatRequest {\n agent_id: string;\n message: string | Array<{\n type: 'text' | 'image' | 'document';\n text?: string;\n source?: {\n type: 'base64';\n media_type: string;\n data: string;\n };\n }>;\n thread_id?: string;\n stream?: boolean;\n system?: string;\n}\n\nexport interface ChatResponse {\n message: string;\n thread_id: string;\n widgets?: any[];\n}\n\nexport interface StreamChunk {\n type: 'start' | 'thread_id' | 'content' | 'token' | 'tool_call' | 'tool_input_delta' | 'tool_use' | 'tool_result' | 'stop' | 'widget' | 'complete' | 'done' | 'error';\n content?: string;\n widget?: any;\n thread_id?: string;\n tool_id?: string;\n tool_name?: string;\n error?: string;\n message?: string;\n}\n\n// Default configuration\nconst DEFAULT_API_URL = 'http://localhost:3000/agents';\nconst DEFAULT_API_KEY = 'agt_894abd5966bc9f1e9f8f17f2a6f6b5e0';\n\nclass AptevaClient {\n private config: Required<AptevaClientConfig>;\n\n constructor() {\n this.config = {\n apiUrl: DEFAULT_API_URL,\n apiKey: DEFAULT_API_KEY,\n };\n }\n\n /**\n * Update client configuration (optional - users can override defaults)\n */\n configure(config: AptevaClientConfig) {\n if (config.apiUrl) this.config.apiUrl = config.apiUrl;\n if (config.apiKey) this.config.apiKey = config.apiKey;\n }\n\n /**\n * Get current configuration\n */\n getConfig(): AptevaClientConfig {\n return { ...this.config };\n }\n\n /**\n * Send a chat message to an agent\n */\n async chat(request: ChatRequest): Promise<ChatResponse> {\n try {\n console.log('[AptevaClient] Chat request:', {\n agent_id: request.agent_id,\n message: typeof request.message === 'string' ? request.message.substring(0, 100) + '...' : '[multi-part message]',\n system: request.system,\n stream: request.stream,\n });\n\n const response = await fetch(`${this.config.apiUrl}/chat`, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n 'X-API-Key': this.config.apiKey,\n },\n body: JSON.stringify(request),\n });\n\n if (!response.ok) {\n const error = await response.json().catch(() => ({ error: 'Request failed' }));\n throw new Error(error.error || `Request failed with status ${response.status}`);\n }\n\n const data = await response.json();\n\n // Map API response format to expected format\n // API returns: { response, thread_id, success, model, trace_id }\n // We expect: { message, thread_id, widgets }\n return {\n message: data.response || data.message || '',\n thread_id: data.thread_id,\n widgets: data.widgets,\n };\n } catch (error) {\n console.error('Chat API error:', error);\n throw error;\n }\n }\n\n /**\n * Send a chat message with streaming response\n */\n async chatStream(\n request: ChatRequest,\n onChunk: (chunk: StreamChunk) => void,\n onComplete?: (threadId: string) => void,\n onError?: (error: Error) => void\n ): Promise<void> {\n try {\n console.log('[AptevaClient] Chat stream request:', {\n agent_id: request.agent_id,\n message: typeof request.message === 'string' ? request.message.substring(0, 100) + '...' : '[multi-part message]',\n system: request.system,\n stream: request.stream,\n });\n\n const response = await fetch(`${this.config.apiUrl}/chat`, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n 'X-API-Key': this.config.apiKey,\n 'Accept': 'text/event-stream',\n },\n body: JSON.stringify({\n ...request,\n stream: true,\n }),\n });\n\n if (!response.ok) {\n const error = await response.json().catch(() => ({ error: 'Request failed' }));\n throw new Error(error.error || `Request failed with status ${response.status}`);\n }\n\n const reader = response.body?.getReader();\n if (!reader) {\n throw new Error('Response body is not readable');\n }\n\n const decoder = new TextDecoder();\n let buffer = '';\n let threadId = '';\n\n while (true) {\n const { done, value } = await reader.read();\n if (done) break;\n\n buffer += decoder.decode(value, { stream: true });\n const lines = buffer.split('\\n');\n buffer = lines.pop() || '';\n\n for (const line of lines) {\n if (!line.trim() || line.startsWith(':')) continue;\n\n if (line.startsWith('data: ')) {\n const data = line.slice(6);\n\n if (data === '[DONE]') {\n onComplete?.(threadId);\n return;\n }\n\n try {\n const chunk = JSON.parse(data);\n\n // Store thread_id if present in chunk\n if (chunk.thread_id) {\n threadId = chunk.thread_id;\n }\n\n // Pass through ALL chunk types to the handler\n onChunk(chunk);\n\n } catch (e) {\n console.warn('[AptevaClient] Failed to parse SSE data:', data);\n }\n }\n }\n }\n\n onComplete?.(threadId);\n } catch (error) {\n const err = error instanceof Error ? error : new Error('Unknown error');\n onError?.(err);\n throw err;\n }\n }\n\n /**\n * Create a new thread\n */\n async createThread(agentId: string, metadata?: Record<string, any>): Promise<string> {\n const response = await fetch(`${this.config.apiUrl}/agents/${agentId}/threads`, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n 'X-API-Key': this.config.apiKey,\n },\n body: JSON.stringify({ metadata }),\n });\n\n if (!response.ok) {\n const error = await response.json().catch(() => ({ error: 'Request failed' }));\n throw new Error(error.error || `Request failed with status ${response.status}`);\n }\n\n const data = await response.json();\n return data.thread_id;\n }\n\n /**\n * Get thread messages\n */\n async getThreadMessages(threadId: string): Promise<ChatMessage[]> {\n const response = await fetch(`${this.config.apiUrl}/threads/${threadId}/messages`, {\n method: 'GET',\n headers: {\n 'X-API-Key': this.config.apiKey,\n },\n });\n\n if (!response.ok) {\n const error = await response.json().catch(() => ({ error: 'Request failed' }));\n throw new Error(error.error || `Request failed with status ${response.status}`);\n }\n\n const data = await response.json();\n return data.messages;\n }\n}\n\n// Export singleton instance\nexport const aptevaClient = new AptevaClient();\n\n// Export class for custom instances\nexport { AptevaClient };\n","import React, { useState, useEffect } from 'react';\nimport { CommandProps, CommandResult } from '../../types/components';\nimport { cn, generateMockCommandWithWidgets, generateMockCommandStream, generateMockPlan } from '../../utils';\nimport { aptevaClient } from '../../lib/apteva-client';\nimport { WidgetRenderer } from '../Widgets/WidgetRenderer';\n\nexport function Command({\n agentId,\n command: initialCommand,\n context,\n autoExecute = false,\n allowInput = true,\n placeholder = 'Enter your command...',\n submitButtonText = 'Execute',\n variant = 'default',\n useMock = false,\n planMode = false,\n onPlanModeChange,\n enableFileUpload = true,\n onStart,\n onProgress,\n onChunk,\n onComplete,\n onError,\n onFileUpload,\n onAction,\n loadingText = 'Processing...',\n showProgress = true,\n enableStreaming = false,\n resultRenderer,\n className,\n}: CommandProps) {\n const [state, setState] = useState<'idle' | 'loading' | 'success' | 'error' | 'plan-pending'>('idle');\n const [result, setResult] = useState<CommandResult | null>(null);\n const [error, setError] = useState<Error | null>(null);\n const [progress, setProgress] = useState(0);\n const [command, setCommand] = useState(initialCommand || '');\n const [streamedContent, setStreamedContent] = useState('');\n const [plan, setPlan] = useState<string>('');\n const [pendingCommand, setPendingCommand] = useState<string>('');\n const [showPlanDetails, setShowPlanDetails] = useState(false);\n const [uploadedFiles, setUploadedFiles] = useState<Array<{ type: 'image' | 'document'; data: string; mediaType: string; preview?: string; name: string }>>([]);\n const [showSettingsMenu, setShowSettingsMenu] = useState(false);\n const [internalPlanMode, setInternalPlanMode] = useState(planMode);\n const fileInputRef = React.useRef<HTMLInputElement>(null);\n\n useEffect(() => {\n if (autoExecute && state === 'idle' && command) {\n executeCommand();\n }\n }, [autoExecute]);\n\n // Sync internal plan mode with prop when prop changes\n useEffect(() => {\n setInternalPlanMode(planMode);\n }, [planMode]);\n\n // Close settings menu when clicking outside\n useEffect(() => {\n const handleClickOutside = (event: MouseEvent) => {\n const target = event.target as HTMLElement;\n if (showSettingsMenu && !target.closest('.settings-menu-container')) {\n setShowSettingsMenu(false);\n }\n };\n\n document.addEventListener('mousedown', handleClickOutside);\n return () => document.removeEventListener('mousedown', handleClickOutside);\n }, [showSettingsMenu]);\n\n const executeCommand = async (commandOverride?: string) => {\n const currentCommand = commandOverride || command;\n\n if (!currentCommand.trim()) {\n setError(new Error('Please enter a command'));\n setState('error');\n return;\n }\n\n // Plan mode: show plan first\n if (internalPlanMode && state !== 'plan-pending') {\n setState('loading');\n setError(null);\n setCommand(''); // Clear input\n\n // Generate plan (mock or real)\n if (useMock) {\n setTimeout(() => {\n const mockPlan = generateMockPlan(currentCommand);\n setPlan(mockPlan);\n setPendingCommand(currentCommand);\n setState('plan-pending');\n }, 800);\n } else {\n // Real API plan generation\n try {\n // Build message - multi-part if files are uploaded\n let messageContent: any;\n\n if (uploadedFiles.length > 0) {\n messageContent = [\n {\n type: 'text',\n text: currentCommand,\n },\n ...uploadedFiles.map(file => ({\n type: file.type,\n source: {\n type: 'base64',\n media_type: file.mediaType,\n data: file.data,\n },\n })),\n ];\n } else {\n messageContent = currentCommand;\n }\n\n // System instruction for planning only\n let systemMessage = context || '';\n const planningInstruction = `CRITICAL PLANNING MODE - READ CAREFULLY:\n\nYou are ONLY creating a plan. You are NOT executing anything.\n\nYOUR TASK: Write a numbered list of steps describing what WOULD be done.\nDO NOT: Execute any actions, make API calls, access databases, modify data, or perform any operations.\nDO NOT: Ask questions or clarifications. Make reasonable assumptions.\nDO: Describe the steps as \"Step 1: Would search database...\", \"Step 2: Would analyze results...\", etc.\nDO: Use default values or best practices if details are missing.\n\nFORMAT REQUIRED:\n1. [First action that would be taken]\n2. [Second action that would be taken]\n3. [Third action that would be taken]\n...\n\nIMPORTANT: This is COMMAND MODE - figure things out yourself. Make intelligent assumptions based on context. ONLY ask questions if something is absolutely impossible to proceed without (e.g., missing required credentials). Otherwise, use sensible defaults and proceed with the plan.\n\nREMEMBER: This is ONLY a plan. The user will approve it, THEN it will be executed. Right now you are just describing what would happen - NOT doing it.`;\n\n\n systemMessage = systemMessage\n ? `${systemMessage}\\n\\n${planningInstruction}`\n : planningInstruction;\n\n aptevaClient.chat({\n agent_id: agentId,\n message: messageContent,\n stream: false,\n system: systemMessage,\n }).then((response) => {\n setPlan(response.message);\n setPendingCommand(currentCommand);\n setState('plan-pending');\n }).catch((err) => {\n const error = err instanceof Error ? err : new Error('Failed to generate plan');\n setError(error);\n setState('error');\n onError?.(error);\n });\n } catch (err) {\n const error = err instanceof Error ? err : new Error('Failed to generate plan');\n setError(error);\n setState('error');\n onError?.(error);\n }\n }\n return;\n }\n\n setState('loading');\n setError(null);\n setProgress(0);\n setStreamedContent('');\n setCommand(''); // Clear input for next command\n setUploadedFiles([]); // Clear uploaded files after sending\n onStart?.();\n\n try {\n if (useMock) {\n // MOCK MODE\n if (enableStreaming) {\n // Mock streaming\n let accumulatedContent = '';\n\n generateMockCommandStream(\n currentCommand,\n (chunk) => {\n if (chunk.type === 'token' && chunk.content) {\n accumulatedContent += chunk.content;\n setStreamedContent(accumulatedContent);\n onChunk?.(chunk.content);\n\n // Estimate progress based on content length\n const estimatedProgress = Math.min(Math.round(accumulatedContent.length / 10), 90);\n setProgress(estimatedProgress);\n onProgress?.(estimatedProgress);\n } else if (chunk.type === 'widget' && chunk.widget) {\n // Handle widgets in streamed response\n const widget = chunk.widget;\n setResult((prev) => ({\n success: true,\n data: prev?.data || {},\n widgets: [...(prev?.widgets || []), widget],\n message: accumulatedContent || 'Command executed successfully',\n }));\n }\n },\n (threadId) => {\n // On complete\n const result: CommandResult = {\n success: true,\n data: {\n summary: accumulatedContent,\n thread_id: threadId,\n agentId,\n context,\n timestamp: new Date().toISOString(),\n },\n message: accumulatedContent || 'Command executed successfully',\n };\n\n setResult(result);\n setState('success');\n setProgress(100);\n onComplete?.(result);\n },\n (error) => {\n // On error\n setError(error);\n setState('error');\n onError?.(error);\n }\n );\n } else {\n // Mock non-streaming\n const progressInterval = setInterval(() => {\n setProgress((prev) => {\n const next = Math.min(prev + 10, 90);\n onProgress?.(next);\n return next;\n });\n }, 200);\n\n // Simulate network delay\n await new Promise(resolve => setTimeout(resolve, 1500));\n\n clearInterval(progressInterval);\n\n const mockResponse = generateMockCommandWithWidgets(currentCommand);\n\n const result: CommandResult = {\n success: true,\n data: {\n summary: mockResponse.message,\n thread_id: `mock_thread_${Date.now()}`,\n agentId,\n context,\n timestamp: new Date().toISOString(),\n action: mockResponse.action, // Include agent action intent\n },\n widgets: mockResponse.widgets,\n message: mockResponse.message,\n };\n\n setResult(result);\n setState('success');\n setProgress(100);\n onComplete?.(result);\n }\n } else {\n // REAL API MODE\n if (enableStreaming) {\n // Real streaming API call\n let accumulatedContent = '';\n\n // Build message - multi-part if files are uploaded\n let messageContent: any;\n\n if (uploadedFiles.length > 0) {\n // Multi-part message with text and images\n messageContent = [\n {\n type: 'text',\n text: currentCommand,\n },\n ...uploadedFiles.map(file => ({\n type: file.type, // 'image' or 'document'\n source: {\n type: 'base64',\n media_type: file.mediaType,\n data: file.data,\n },\n })),\n ];\n } else {\n // Simple text message\n messageContent = currentCommand;\n }\n\n // Build system message - add command execution instruction\n let systemMessage = context || '';\n\n // Always include command mode instruction for brevity\n let commandInstruction: string;\n if (isCompact) {\n // Compact mode - extremely terse\n commandInstruction = 'CRITICAL COMMAND MODE: Maximum 10 words per response. Execute immediately, make intelligent assumptions, use defaults when needed. NO questions unless absolutely critical (missing required credentials). State action or result ONLY. Examples: \"Searching database for matching records...\" or \"Found 3 user records in database\" or \"Task completed successfully\". NO greetings, NO explanations, NO clarification requests. Just execute and report.';\n } else {\n // Default mode - still very brief\n commandInstruction = 'CRITICAL COMMAND MODE: Maximum 10 words per response. Execute the command immediately. Make reasonable assumptions based on context. Use sensible defaults for missing details. DO NOT ask questions unless something is truly impossible without user input (e.g., missing required password). State what you\\'re doing or the result. Examples: \"Analyzing customer data from last quarter...\" or \"Created 5 new database entries successfully\" or \"Search complete: found 12 matching results\". NO greetings, NO filler words, NO clarification requests. Action/result only.';\n }\n\n systemMessage = systemMessage\n ? `${systemMessage}\\n\\n${commandInstruction}`\n : commandInstruction;\n\n await aptevaClient.chatStream(\n {\n agent_id: agentId,\n message: messageContent,\n stream: true,\n ...(systemMessage && { system: systemMessage }),\n },\n (chunk) => {\n if (chunk.type === 'token' && chunk.content) {\n accumulatedContent += chunk.content;\n setStreamedContent(accumulatedContent);\n onChunk?.(chunk.content);\n\n // Estimate progress based on content length (rough approximation)\n const estimatedProgress = Math.min(Math.round(accumulatedContent.length / 10), 90);\n setProgress(estimatedProgress);\n onProgress?.(estimatedProgress);\n } else if (chunk.type === 'widget' && chunk.widget) {\n // Handle widgets in streamed response\n const widget = chunk.widget;\n setResult((prev) => ({\n success: true,\n data: prev?.data || {},\n widgets: [...(prev?.widgets || []), widget],\n message: accumulatedContent || 'Command executed successfully',\n }));\n }\n },\n (threadId) => {\n // On complete\n const result: CommandResult = {\n success: true,\n data: {\n summary: accumulatedContent,\n thread_id: threadId,\n agentId,\n context,\n timestamp: new Date().toISOString(),\n },\n message: accumulatedContent || 'Command executed successfully',\n };\n\n setResult(result);\n setState('success');\n setProgress(100);\n onComplete?.(result);\n },\n (error) => {\n // On error\n const err = error instanceof Error ? error : new Error('Unknown error');\n setError(err);\n setState('error');\n onError?.(err);\n }\n );\n } else {\n // Non-streaming API call\n const progressInterval = setInterval(() => {\n setProgress((prev) => {\n const next = Math.min(prev + 10, 90);\n onProgress?.(next);\n return next;\n });\n }, 200);\n\n // Build message - multi-part if files are uploaded\n let messageContent: any;\n\n if (uploadedFiles.length > 0) {\n // Multi-part message with text and images\n messageContent = [\n {\n type: 'text',\n text: currentCommand,\n },\n ...uploadedFiles.map(file => ({\n type: file.type, // 'image' or 'document'\n source: {\n type: 'base64',\n media_type: file.mediaType,\n data: file.data,\n },\n })),\n ];\n } else {\n // Simple text message\n messageContent = currentCommand;\n }\n\n // Build system message - add command execution instruction\n let systemMessage = context || '';\n\n // Always include command mode instruction for brevity\n let commandInstruction: string;\n if (isCompact) {\n // Compact mode - extremely terse\n commandInstruction = 'CRITICAL COMMAND MODE: Maximum 10 words per response. Execute immediately, make intelligent assumptions, use defaults when needed. NO questions unless absolutely critical (missing required credentials). State action or result ONLY. Examples: \"Searching database for matching records...\" or \"Found 3 user records in database\" or \"Task completed successfully\". NO greetings, NO explanations, NO clarification requests. Just execute and report.';\n } else {\n // Default mode - still very brief\n commandInstruction = 'CRITICAL COMMAND MODE: Maximum 10 words per response. Execute the command immediately. Make reasonable assumptions based on context. Use sensible defaults for missing details. DO NOT ask questions unless something is truly impossible without user input (e.g., missing required password). State what you\\'re doing or the result. Examples: \"Analyzing customer data from last quarter...\" or \"Created 5 new database entries successfully\" or \"Search complete: found 12 matching results\". NO greetings, NO filler words, NO clarification requests. Action/result only.';\n }\n\n systemMessage = systemMessage\n ? `${systemMessage}\\n\\n${commandInstruction}`\n : commandInstruction;\n\n const response = await aptevaClient.chat({\n agent_id: agentId,\n message: messageContent,\n stream: false,\n ...(systemMessage && { system: systemMessage }),\n });\n\n clearInterval(progressInterval);\n\n const result: CommandResult = {\n success: true,\n data: {\n summary: response.message,\n thread_id: response.thread_id,\n agentId,\n context,\n timestamp: new Date().toISOString(),\n },\n widgets: response.widgets,\n message: response.message,\n };\n\n setResult(result);\n setState('success');\n setProgress(100);\n onComplete?.(result);\n }\n }\n } catch (err) {\n const error = err instanceof Error ? err : new Error('Unknown error');\n setError(error);\n setState('error');\n onError?.(error);\n }\n };\n\n const resetCommand = () => {\n setState('idle');\n setResult(null);\n setError(null);\n setProgress(0);\n setCommand('');\n setPlan('');\n setPendingCommand('');\n setShowPlanDetails(false);\n setUploadedFiles([]);\n };\n\n const approvePlan = () => {\n // Execute the plan after approval\n // Send the plan to the agent with \"execute this now\" instruction\n setShowPlanDetails(false);\n const planToExecute = plan;\n setPlan('');\n setPendingCommand('');\n\n // Execute with the plan as the command\n const executionMessage = `Execute this plan now:\\n\\n${planToExecute}`;\n executeCommand(executionMessage);\n };\n\n const rejectPlan = () => {\n // Reset to idle and restore the command for editing\n setCommand(pendingCommand);\n setPlan('');\n setPendingCommand('');\n setShowPlanDetails(false);\n setState('idle');\n };\n\n const handleFileSelect = async (e: React.ChangeEvent<HTMLInputElement>) => {\n if (e.target.files && e.target.files.length > 0) {\n onFileUpload?.(e.target.files);\n\n // Convert files to base64 for API\n const files: Array<{ type: 'image' | 'document'; data: string; mediaType: string; preview?: string; name: string }> = [];\n\n for (let i = 0; i < e.target.files.length; i++) {\n const file = e.target.files[i];\n\n const reader = new FileReader();\n\n await new Promise<void>((resolve) => {\n reader.onload = (event) => {\n if (event.target?.result) {\n const fullDataUrl = event.target.result as string;\n const base64Data = fullDataUrl.split(',')[1]; // Remove data:...;base64, prefix\n\n if (file.type.startsWith('image/')) {\n // Images with preview\n files.push({\n type: 'image',\n data: base64Data,\n mediaType: file.type,\n preview: fullDataUrl, // Keep full data URL for preview\n name: file.name,\n });\n } else if (file.type === 'application/pdf' || file.type.startsWith('application/')) {\n // Documents (PDF, etc.) without preview\n files.push({\n type: 'document',\n data: base64Data,\n mediaType: file.type,\n name: file.name,\n });\n }\n }\n resolve();\n };\n reader.readAsDataURL(file);\n });\n }\n\n setUploadedFiles(prev => [...prev, ...files]); // Append to existing files\n }\n };\n\n const removeFile = (index: number) => {\n setUploadedFiles(prev => prev.filter((_, i) => i !== index));\n };\n\n const isCompact = variant === 'compact';\n\n return (\n <div\n className={cn(\n 'relative border-2 rounded-xl bg-white dark:bg-gray-900 transition-all duration-300 flex flex-col',\n state === 'loading' && 'animate-pulse-border',\n state === 'idle' && 'border-gray-300 dark:border-gray-700',\n state === 'loading' && 'border-blue-500',\n state === 'plan-pending' && 'border-blue-400',\n state === 'success' && 'border-green-500',\n state === 'error' && 'border-red-500',\n className\n )}\n style={{ minHeight: isCompact ? 'auto' : '180px' }}\n >\n {/* Input/Display Area */}\n <div className={cn('flex-1 flex', isCompact ? 'flex-row items-center p-3 gap-3' : 'flex-col p-4')}>\n {state === 'idle' && allowInput && !isCompact && (\n <>\n <textarea\n value={command}\n onChange={(e) => setCommand(e.target.value)}\n onKeyDown={(e) => {\n if (e.key === 'Enter' && (e.metaKey || e.ctrlKey)) {\n e.preventDefault();\n executeCommand();\n }\n }}\n placeholder={placeholder}\n className=\"flex-1 w-full resize-none bg-transparent border-none focus:outline-none !text-gray-900 dark:!text-gray-100 placeholder-gray-400 dark:placeholder-gray-500\"\n rows={6}\n />\n {/* File Previews - Non-Compact */}\n {uploadedFiles.length > 0 && (\n <div className=\"flex flex-wrap gap-2 mt-2\">\n {uploadedFiles.map((file, index) => (\n <div key={index} className=\"relative group\">\n {file.type === 'image' ? (\n <img\n src={file.preview}\n alt={file.name}\n className=\"w-20 h-20 object-cover rounded-lg border-2 border-gray-300 dark:border-gray-600\"\n />\n ) : (\n <div className=\"w-20 h-20 flex flex-col items-center justify-center rounded-lg border-2 border-gray-300 dark:border-gray-600 bg-gray-50 dark:bg-gray-800\">\n <svg className=\"w-8 h-8 text-gray-500 dark:text-gray-400\" fill=\"currentColor\" viewBox=\"0 0 20 20\">\n <path fillRule=\"evenodd\" d=\"M4 4a2 2 0 012-2h4.586A2 2 0 0112 2.586L15.414 6A2 2 0 0116 7.414V16a2 2 0 01-2 2H6a2 2 0 01-2-2V4zm2 6a1 1 0 011-1h6a1 1 0 110 2H7a1 1 0 01-1-1zm1 3a1 1 0 100 2h6a1 1 0 100-2H7z\" clipRule=\"evenodd\" />\n </svg>\n <span className=\"text-[8px] text-gray-500 dark:text-gray-400 mt-1 px-1 truncate max-w-full\">\n {file.name.length > 12 ? file.name.slice(0, 12) + '...' : file.name}\n </span>\n </div>\n )}\n <button\n onClick={() => removeFile(index)}\n className=\"absolute -top-2 -right-2 w-6 h-6 bg-red-500 hover:bg-red-600 text-white rounded-full flex items-center justify-center opacity-0 group-hover:opacity-100 transition-opacity\"\n title={`Remove ${file.type}`}\n >\n <svg className=\"w-4 h-4\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\">\n <path strokeLinecap=\"round\" strokeLinejoin=\"round\" strokeWidth={2} d=\"M6 18L18 6M6 6l12 12\" />\n </svg>\n </button>\n </div>\n ))}\n </div>\n )}\n </>\n )}\n\n {state === 'idle' && allowInput && isCompact && (\n <>\n <div className=\"flex items-center gap-0.5 flex-shrink-0\">\n {enableFileUpload && (\n <button\n onClick={() => fileInputRef.current?.click()}\n className=\"w-8 h-8 rounded-lg flex items-center justify-center transition-all flex-shrink-0 !text-gray-500 dark:!text-gray-500 hover:bg-gray-100 dark:hover:bg-gray-800\"\n title=\"Attach file\"\n >\n <svg width=\"16\" height=\"16\" viewBox=\"0 0 16 16\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\n <path d=\"M8.4 2.8L4.4 6.8C3.736 7.464 3.736 8.536 4.4 9.2C5.064 9.864 6.136 9.864 6.8 9.2L11.6 4.4C12.704 3.296 12.704 1.504 11.6 0.4C10.496 -0.704 8.704 -0.704 7.6 0.4L2.8 5.2C1.256 6.744 1.256 9.256 2.8 10.8C4.344 12.344 6.856 12.344 8.4 10.8L12.4 6.8\" stroke=\"currentColor\" strokeWidth=\"1.2\" strokeLinecap=\"round\" strokeLinejoin=\"round\" transform=\"translate(1.6, 2.4)\"/>\n </svg>\n </button>\n )}\n {planMode && (\n <div className=\"relative settings-menu-container\">\n <button\n onClick={() => setShowSettingsMenu(!showSettingsMenu)}\n className={cn(\n \"w-8 h-8 rounded-lg flex items-center justify-center transition-all flex-shrink-0 hover:bg-gray-100 dark:hover:bg-gray-800\",\n internalPlanMode ? \"!text-blue-600 dark:!text-blue-400\" : \"!text-gray-500 dark:!text-gray-500\"\n )}\n title=\"Settings\"\n >\n <svg width=\"14\" height=\"14\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\">\n <line x1=\"4\" y1=\"21\" x2=\"4\" y2=\"14\"></line>\n <line x1=\"4\" y1=\"10\" x2=\"4\" y2=\"3\"></line>\n <line x1=\"12\" y1=\"21\" x2=\"12\" y2=\"12\"></line>\n <line x1=\"12\" y1=\"8\" x2=\"12\" y2=\"3\"></line>\n <line x1=\"20\" y1=\"21\" x2=\"20\" y2=\"16\"></line>\n <line x1=\"20\" y1=\"12\" x2=\"20\" y2=\"3\"></line>\n <line x1=\"1\" y1=\"14\" x2=\"7\" y2=\"14\"></line>\n <line x1=\"9\" y1=\"8\" x2=\"15\" y2=\"8\"></line>\n <line x1=\"17\" y1=\"16\" x2=\"23\" y2=\"16\"></line>\n </svg>\n </button>\n {showSettingsMenu && (\n <div className=\"absolute top-10 left-0 z-50 w-56 bg-white dark:bg-gray-800 border border-gray-200 dark:border-gray-700 rounded-lg shadow-lg p-2.5 settings-menu-container\">\n <label className=\"flex items-center justify-between cursor-pointer group\">\n <div className=\"flex items-center gap-2\">\n <svg className=\"w-3.5 h-3.5 text-gray-500 dark:text-gray-400\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\">\n <path strokeLinecap=\"round\" strokeLinejoin=\"round\" strokeWidth={2} d=\"M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-3 7h3m-3 4h3m-6-4h.01M9 16h.01\" />\n </svg>\n <div>\n <div className=\"text-xs font-medium text-gray-700 dark:text-gray-300\">Plan Mode</div>\n <div className=\"text-[10px] text-gray-500 dark:text-gray-400\">Review first</div>\n </div>\n </div>\n <button\n onClick={(e) => {\n e.stopPropagation();\n setInternalPlanMode(!internalPlanMode);\n }}\n className={cn(\n \"relative inline-flex h-4 w-8 items-center rounded-full transition-colors\",\n internalPlanMode ? \"bg-blue-600\" : \"bg-gray-300 dark:bg-gray-600\"\n )}\n type=\"button\"\n >\n <span\n className={cn(\n \"inline-block h-3 w-3 transform rounded-full bg-white transition-transform\",\n internalPlanMode ? \"translate-x-4.5\" : \"translate-x-0.5\"\n )}\n />\n </button>\n </label>\n </div>\n )}\n </div>\n )}\n </div>\n {/* File Previews - Compact */}\n {uploadedFiles.length > 0 && (\n <div className=\"flex gap-1 flex-shrink-0\">\n {uploadedFiles.map((file, index) => (\n <div key={index} className=\"relative group\">\n {file.type === 'image' ? (\n <img\n src={file.preview}\n alt={file.name}\n className=\"w-8 h-8 object-cover rounded border border-gray-300 dark:border-gray-600\"\n />\n ) : (\n <div className=\"w-8 h-8 flex items-center justify-center rounded border border-gray-300 dark:border-gray-600 bg-gray-50 dark:bg-gray-800\" title={file.name}>\n <svg className=\"w-4 h-4 text-gray-500 dark:text-gray-400\" fill=\"currentColor\" viewBox=\"0 0 20 20\">\n <path fillRule=\"evenodd\" d=\"M4 4a2 2 0 012-2h4.586A2 2 0 0112 2.586L15.414 6A2 2 0 0116 7.414V16a2 2 0 01-2 2H6a2 2 0 01-2-2V4zm2 6a1 1 0 011-1h6a1 1 0 110 2H7a1 1 0 01-1-1zm1 3a1 1 0 100 2h6a1 1 0 100-2H7z\" clipRule=\"evenodd\" />\n </svg>\n </div>\n )}\n <button\n onClick={() => removeFile(index)}\n className=\"absolute -top-1 -right-1 w-4 h-4 bg-red-500 hover:bg-red-600 text-white rounded-full flex items-center justify-center opacity-0 group-hover:opacity-100 transition-opacity\"\n title=\"Remove\"\n >\n <svg className=\"w-2.5 h-2.5\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\" strokeWidth={3}>\n <path strokeLinecap=\"round\" strokeLinejoin=\"round\" d=\"M6 18L18 6M6 6l12 12\" />\n </svg>\n </button>\n </div>\n ))}\n </div>\n )}\n <input\n type=\"text\"\n value={command}\n onChange={(e) => setCommand(e.target.value)}\n onKeyDown={(e) => {\n if (e.key === 'Enter') {\n e.preventDefault();\n executeCommand();\n }\n }}\n placeholder={placeholder}\n className=\"flex-1 bg-transparent border-none focus:outline-none !text-gray-900 dark:!text-gray-100 placeholder-gray-400 dark:placeholder-gray-500 py-1\"\n />\n <button\n onClick={() => executeCommand()}\n disabled={!command.trim()}\n className={cn(\n 'w-8 h-8 rounded-lg flex items-center justify-center font-bold transition-all flex-shrink-0',\n 'border border-gray-300 dark:border-gray-600',\n 'bg-white dark:bg-gray-800',\n '!text-gray-700 dark:!text-gray-300',\n 'hover:bg-gray-50 dark:hover:bg-gray-700',\n 'disabled:opacity-30 disabled:cursor-not-allowed',\n '!text-lg',\n !command.trim() && 'border-gray-200 dark:border-gray-700 !text-gray-400 dark:!text-gray-600'\n )}\n title=\"Execute\"\n >\n <svg width=\"16\" height=\"16\" viewBox=\"0 0 16 16\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\n <path d=\"M8 3L8 13M8 3L4 7M8 3L12 7\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\"/>\n </svg>\n </button>\n </>\n )}\n\n {state === 'loading' && !isCompact && (\n <div className=\"flex-1 flex flex-col items-center justify-center space-y-4 py-8\">\n <div className=\"w-6 h-6 border-2 border-gray-300 border-t-blue-500 rounded-full animate-spin\"></div>\n <div className=\"text-gray-600 dark:text-gray-400 text-sm text-center max-w-md\">\n {enableStreaming && streamedContent ? streamedContent : loadingText}\n </div>\n {showProgress && (\n <div className=\"w-full max-w-sm\">\n <div className=\"w-full bg-gray-200 dark:bg-gray-700 rounded-full h-1.5\">\n <div\n className=\"bg-blue-500 h-1.5 rounded-full transition-all duration-300\"\n style={{ width: `${progress}%` }}\n />\n </div>\n <p className=\"text-xs text-gray-500 mt-2 text-center\">{progress}%</p>\n </div>\n )}\n </div>\n )}\n\n {state === 'loading' && isCompact && (\n <>\n <div className=\"flex-1 flex items-center gap-3 py-1\">\n <div className=\"w-4 h-4 border-2 border-gray-300 border-t-blue-500 rounded-full animate-spin\"></div>\n <div className=\"text-gray-600 dark:text-gray-400 text-sm truncate\">\n {enableStreaming && streamedContent ? streamedContent : loadingText}\n </div>\n </div>\n <button\n disabled\n className={cn(\n 'w-8 h-8 rounded-lg flex items-center justify-center font-bold transition-all flex-shrink-0',\n 'border border-gray-200 dark:border-gray-700',\n 'bg-white dark:bg-gray-800',\n '!text-gray-400 dark:!text-gray-600',\n '!text-lg',\n 'opacity-30 cursor-not-allowed'\n )}\n >\n <svg width=\"16\" height=\"16\" viewBox=\"0 0 16 16\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\n <path d=\"M8 3L8 13M8 3L4 7M8 3L12 7\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\"/>\n </svg>\n </button>\n </>\n )}\n\n {state === 'plan-pending' && !isCompact && (\n <div className=\"flex-1 flex flex-col\">\n <div className=\"mb-4 p-4 bg-blue-50 dark:bg-blue-900/20 border border-blue-200 dark:border-blue-800 rounded-lg\">\n <div className=\"flex items-start gap-2 mb-3\">\n <svg className=\"w-5 h-5 text-blue-600 dark:text-blue-400 mt-0.5 flex-shrink-0\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\">\n <path strokeLinecap=\"round\" strokeLinejoin=\"round\" strokeWidth={2} d=\"M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-3 7h3m-3 4h3m-6-4h.01M9 16h.01\" />\n </svg>\n <div className=\"flex-1\">\n <h3 className=\"text-sm font-semibold text-blue-800 dark:text-blue-300 mb-1\">Proposed Plan</h3>\n <div className=\"text-blue-700 dark:text-blue-300 text-sm whitespace-pre-line leading-relaxed\">\n {plan}\n </div>\n </div>\n </div>\n <div className=\"flex gap-2 mt-4\">\n <button\n onClick={approvePlan}\n className=\"flex-1 px-4 py-2 bg-blue-600 text-white rounded-lg hover:bg-blue-700 transition-colors text-sm font-medium\"\n >\n Approve & Execute\n </button>\n <button\n onClick={rejectPlan}\n className=\"flex-1 px-4 py-2 bg-gray-200 dark:bg-gray-700 text-gray-700 dark:text-gray-300 rounded-lg hover:bg-gray-300 dark:hover:bg-gray-600 transition-colors text-sm font-medium\"\n >\n Modify\n </button>\n </div>\n </div>\n </div>\n )}\n\n {state === 'plan-pending' && isCompact && (\n <>\n <button\n onClick={() => setShowPlanDetails(true)}\n className=\"flex-1 flex items-center gap-2 px-3 py-2 bg-blue-50 dark:bg-blue-900/30 hover:bg-blue-100 dark:hover:bg-blue-900/40 border border-blue-200 dark:border-blue-800 rounded-lg transition-colors\"\n >\n <svg className=\"w-4 h-4 text-blue-600 dark:text-blue-400 flex-shrink-0\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\">\n <path strokeLinecap=\"round\" strokeLinejoin=\"round\" strokeWidth={2} d=\"M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-3 7h3m-3 4h3m-6-4h.01M9 16h.01\" />\n </svg>\n <span className=\"text-sm font-medium text-blue-700 dark:text-blue-300 truncate flex-1\">View Execution Plan</span>\n </button>\n <div className=\"flex gap-2 flex-shrink-0\">\n <button\n onClick={approvePlan}\n className=\"px-3 py-1.5 bg-blue-600 text-white rounded-lg hover:bg-blue-700 transition-colors text-xs font-medium\"\n >\n Approve\n </button>\n <button\n onClick={rejectPlan}\n className=\"px-3 py-1.5 bg-gray-200 dark:bg-gray-700 text-gray-700 dark:text-gray-300 rounded-lg hover:bg-gray-300 dark:hover:bg-gray-600 transition-colors text-xs font-medium\"\n >\n Modify\n </button>\n </div>\n </>\n )}\n\n {state === 'error' && (\n <div className=\"flex-1 flex flex-col\">\n <div className=\"mb-4 p-3 bg-red-50 dark:bg-red-900/20 border border-red-200 dark:border-red-800 rounded-lg\">\n <div className=\"flex items-start gap-2\">\n <svg className=\"w-5 h-5 text-red-600 mt-0.5 flex-shrink-0\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\">\n <path strokeLinecap=\"round\" strokeLinejoin=\"round\" strokeWidth={2} d=\"M12 8v4m0 4h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z\" />\n </svg>\n <div>\n <h3 className=\"text-sm font-semibold text-red-800 dark:text-red-400\">Error</h3>\n <p className=\"text-red-700 dark:text-red-300 text-sm mt-1\">{error?.message}</p>\n </div>\n </div>\n </div>\n {allowInput && (\n <textarea\n value={command}\n onChange={(e) => setCommand(e.target.value)}\n onKeyDown={(e) => {\n if (e.key === 'Enter' && (e.metaKey || e.ctrlKey)) {\n e.preventDefault();\n executeCommand();\n }\n }}\n placeholder={placeholder}\n className=\"flex-1 w-full resize-none bg-transparent border-none focus:outline-none text-gray-900 dark:text-white placeholder-gray-400\"\n rows={4}\n />\n )}\n </div>\n )}\n\n {state === 'success' && result && !isCompact && (\n <div className=\"flex-1 overflow-auto\">\n {resultRenderer ? (\n resultRenderer(result.data)\n ) : (\n <div className=\"space-y-4\">\n <div className=\"flex items-start gap-3 p-3 bg-green-50 dark:bg-green-900/20 border border-green-200 dark:border-green-800 rounded-lg\">\n <svg className=\"w-5 h-5 text-green-600 mt-0.5 flex-shrink-0\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\">\n <path strokeLinecap=\"round\" strokeLinejoin=\"round\" strokeWidth={2} d=\"M9 12l2 2 4-4m6 2a9 9 0 11-18 0 9 9 0 0118 0z\" />\n </svg>\n <div className=\"flex-1\">\n <h3 className=\"text-sm font-semibold text-green-800 dark:text-green-400 mb-1\">Success</h3>\n <p className=\"text-green-700 dark:text-green-300 text-sm\">Command executed successfully</p>\n </div>\n </div>\n {result.data?.summary && (\n <div className=\"text-gray-700 dark:text-gray-300 text-sm leading-relaxed whitespace-pre-line\">\n {result.data.summary}\n </div>\n )}\n {result.widgets && result.widgets.length > 0 && (\n <div className=\"space-y-3\">\n {result.widgets.map((widget) => (\n <WidgetRenderer\n key={widget.id}\n widget={widget}\n onAction={onAction}\n />\n ))}\n </div>\n )}\n </div>\n )}\n </div>\n )}\n\n {state === 'success' && result && isCompact && (\n <>\n <div\n className=\"flex-1 flex items-center gap-2 py-1 cursor-text min-w-0\"\n onClick={() => {\n setState('idle');\n setResult(null);\n }}\n >\n <svg className=\"w-4 h-4 text-green-600 flex-shrink-0\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\">\n <path strokeLinecap=\"round\" strokeLinejoin=\"round\" strokeWidth={2} d=\"M9 12l2 2 4-4m6 2a9 9 0 11-18 0 9 9 0 0118 0z\" />\n </svg>\n <div className=\"text-green-700 dark:text-green-300 text-sm truncate flex-1 min-w-0\">\n {resultRenderer ? resultRenderer(result.data) : (result.message || 'Command executed successfully')}\n </div>\n </div>\n <button\n onClick={() => {\n setState('idle');\n setResult(null);\n }}\n className={cn(\n 'w-8 h-8 rounded-lg flex items-center justify-center font-bold transition-all flex-shrink-0',\n 'border border-gray-300 dark:border-gray-600',\n 'bg-white dark:bg-gray-800',\n '!text-gray-700 dark:!text-gray-300',\n 'hover:bg-gray-50 dark:hover:bg-gray-700',\n '!text-lg'\n )}\n title=\"New command\"\n >\n <svg width=\"16\" height=\"16\" viewBox=\"0 0 16 16\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\n <path d=\"M8 3L8 13M8 3L4 7M8 3L12 7\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\"/>\n </svg>\n </button>\n </>\n )}\n </div>\n\n {/* Bottom Action Bar - Only show for default variant when not in compact mode */}\n {!isCompact && (\n <div className=\"p-3 flex items-center justify-between gap-2\">\n {/* Left side - Attachment and Settings buttons */}\n <div className=\"flex items-center gap-1\">\n {state === 'idle' && allowInput && (\n <>\n {enableFileUpload && (\n <button\n onClick={() => fileInputRef.current?.click()}\n className=\"w-8 h-8 rounded-lg flex items-center justify-center transition-all flex-shrink-0 !text-gray-500 dark:!text-gray-500 hover:bg-gray-100 dark:hover:bg-gray-800\"\n title=\"Attach file\"\n >\n <svg width=\"16\" height=\"16\" viewBox=\"0 0 16 16\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\n <path d=\"M8.4 2.8L4.4 6.8C3.736 7.464 3.736 8.536 4.4 9.2C5.064 9.864 6.136 9.864 6.8 9.2L11.6 4.4C12.704 3.296 12.704 1.504 11.6 0.4C10.496 -0.704 8.704 -0.704 7.6 0.4L2.8 5.2C1.256 6.744 1.256 9.256 2.8 10.8C4.344 12.344 6.856 12.344 8.4 10.8L12.4 6.8\" stroke=\"currentColor\" strokeWidth=\"1.2\" strokeLinecap=\"round\" strokeLinejoin=\"round\" transform=\"translate(1.6, 2.4)\"/>\n </svg>\n </button>\n )}\n {planMode && (\n <div className=\"relative settings-menu-container\">\n <button\n onClick={() => setShowSettingsMenu(!showSettingsMenu)}\n className={cn(\n \"w-8 h-8 rounded-lg flex items-center justify-center transition-all flex-shrink-0 hover:bg-gray-100 dark:hover:bg-gray-800\",\n internalPlanMode ? \"!text-blue-600 dark:!text-blue-400\" : \"!text-gray-500 dark:!text-gray-500\"\n )}\n title=\"Settings\"\n >\n <svg width=\"16\" height=\"16\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\">\n <line x1=\"4\" y1=\"21\" x2=\"4\" y2=\"14\"></line>\n <line x1=\"4\" y1=\"10\" x2=\"4\" y2=\"3\"></line>\n <line x1=\"12\" y1=\"21\" x2=\"12\" y2=\"12\"></line>\n <line x1=\"12\" y1=\"8\" x2=\"12\" y2=\"3\"></line>\n <line x1=\"20\" y1=\"21\" x2=\"20\" y2=\"16\"></line>\n <line x1=\"20\" y1=\"12\" x2=\"20\" y2=\"3\"></line>\n <line x1=\"1\" y1=\"14\" x2=\"7\" y2=\"14\"></line>\n <line x1=\"9\" y1=\"8\" x2=\"15\" y2=\"8\"></line>\n <line x1=\"17\" y1=\"16\" x2=\"23\" y2=\"16\"></line>\n </svg>\n </button>\n {showSettingsMenu && (\n <div className=\"absolute top-10 left-0 z-50 w-64 bg-white dark:bg-gray-800 border border-gray-200 dark:border-gray-700 rounded-lg shadow-lg p-3 settings-menu-container\">\n <label className=\"flex items-center justify-between cursor-pointer group\">\n <div className=\"flex items-center gap-2\">\n <svg className=\"w-4 h-4 text-gray-500 dark:text-gray-400\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\">\n <path strokeLinecap=\"round\" strokeLinejoin=\"round\" strokeWidth={2} d=\"M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-3 7h3m-3 4h3m-6-4h.01M9 16h.01\" />\n </svg>\n <div>\n <div className=\"text-sm font-medium text-gray-700 dark:text-gray-300\">Plan Mode</div>\n <div className=\"text-xs text-gray-500 dark:text-gray-400\">Review before executing</div>\n </div>\n </div>\n <button\n onClick={(e) => {\n e.stopPropagation();\n setInternalPlanMode(!internalPlanMode);\n }}\n className={cn(\n \"relative inline-flex h-5 w-9 items-center rounded-full transition-colors\",\n internalPlanMode ? \"bg-blue-600\" : \"bg-gray-300 dark:bg-gray-600\"\n )}\n type=\"button\"\n >\n <span\n className={cn(\n \"inline-block h-3.5 w-3.5 transform rounded-full bg-white transition-transform\",\n internalPlanMode ? \"translate-x-5\" : \"translate-x-0.5\"\n )}\n />\n </button>\n </label>\n </div>\n )}\n </div>\n )}\n </>\n )}\n </div>\n\n {/* Spacer when no attachment button */}\n {!(state === 'idle' && allowInput) && <div />}\n\n {/* Right side - Action buttons */}\n <div className=\"flex items-center gap-2\">\n {(state === 'success' || state === 'error') && allowInput && (\n <button\n onClick={resetCommand}\n className=\"px-3 py-1.5 text-sm text-gray-600 dark:text-gray-400 hover:text-gray-900 dark:hover:text-white transition-colors\"\n >\n Reset\n </button>\n )}\n\n {(state === 'idle' || state === 'error') && (\n <button\n onClick={() => executeCommand()}\n disabled={!command.trim()}\n className={cn(\n 'w-8 h-8 rounded-lg flex items-center justify-center font-bold transition-all',\n 'border border-gray-300 dark:border-gray-600',\n 'bg-white dark:bg-gray-800',\n '!text-gray-700 dark:!text-gray-300',\n 'hover:bg-gray-50 dark:hover:bg-gray-700',\n 'disabled:opacity-30 disabled:cursor-not-allowed',\n '!text-lg',\n !command.trim() && 'border-gray-200 dark:border-gray-700 !text-gray-400 dark:!text-gray-600'\n )}\n title={state === 'error' ? 'Retry' : 'Execute'}\n >\n {state === 'error' ? (\n <svg width=\"16\" height=\"16\" viewBox=\"0 0 16 16\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\n <path d=\"M13 8C13 10.7614 10.7614 13 8 13C5.23858 13 3 10.7614 3 8C3 5.23858 5.23858 3 8 3C9.65685 3 11.1257 3.82818 12 5.09091M12 3V5.09091M12 5.09091H9.81818\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\"/>\n </svg>\n ) : (\n <svg width=\"16\" height=\"16\" viewBox=\"0 0 16 16\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\n <path d=\"M8 3L8 13M8 3L4 7M8 3L12 7\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\"/>\n </svg>\n )}\n </button>\n )}\n </div>\n </div>\n )}\n\n {/* Plan Modal - Only for compact mode */}\n {showPlanDetails && isCompact && state === 'plan-pending' && (\n <div className=\"fixed inset-0 bg-black/50 flex items-center justify-center z-50 p-4\" onClick={() => setShowPlanDetails(false)}>\n <div className=\"bg-white dark:bg-gray-900 rounded-2xl shadow-2xl max-w-2xl w-full max-h-[80vh] overflow-hidden\" onClick={(e) => e.stopPropagation()}>\n {/* Modal Header */}\n <div className=\"flex items-center justify-between p-6 border-b border-gray-200 dark:border-gray-700\">\n <div className=\"flex items-center gap-3\">\n <svg className=\"w-6 h-6 text-blue-600 dark:text-blue-400\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\">\n <path strokeLinecap=\"round\" strokeLinejoin=\"round\" strokeWidth={2} d=\"M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-3 7h3m-3 4h3m-6-4h.01M9 16h.01\" />\n </svg>\n <h2 className=\"text-xl font-semibold text-gray-900 dark:text-white\">Proposed Execution Plan</h2>\n </div>\n <button\n onClick={() => setShowPlanDetails(false)}\n className=\"text-gray-400 hover:text-gray-600 dark:hover:text-gray-300 transition-colors\"\n >\n <svg className=\"w-6 h-6\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\">\n <path strokeLinecap=\"round\" strokeLinejoin=\"round\" strokeWidth={2} d=\"M6 18L18 6M6 6l12 12\" />\n </svg>\n </button>\n </div>\n\n {/* Modal Content */}\n <div className=\"p-6 overflow-y-auto max-h-[calc(80vh-180px)]\">\n <div className=\"prose prose-sm dark:prose-invert max-w-none\">\n <div className=\"text-gray-700 dark:text-gray-300 whitespace-pre-line leading-relaxed\">\n {plan}\n </div>\n </div>\n </div>\n\n {/* Modal Footer */}\n <div className=\"flex items-center justify-end gap-3 p-6 border-t border-gray-200 dark:border-gray-700 bg-gray-50 dark:bg-gray-800/50\">\n <button\n onClick={rejectPlan}\n className=\"px-6 py-2.5 bg-gray-200 dark:bg-gray-700 text-gray-700 dark:text-gray-300 rounded-lg hover:bg-gray-300 dark:hover:bg-gray-600 transition-colors font-medium\"\n >\n Modify Command\n </button>\n <button\n onClick={approvePlan}\n className=\"px-6 py-2.5 bg-blue-600 text-white rounded-lg hover:bg-blue-700 transition-colors font-medium\"\n >\n Approve & Execute\n </button>\n </div>\n </div>\n </div>\n )}\n\n {/* Hidden file input */}\n <input\n ref={fileInputRef}\n type=\"file\"\n multiple\n onChange={handleFileSelect}\n className=\"hidden\"\n accept=\"image/*,application/pdf,.doc,.docx,.txt\"\n />\n\n <style dangerouslySetInnerHTML={{\n __html: `\n @keyframes pulse-border {\n 0%, 100% {\n border-color: rgb(59, 130, 246);\n }\n 50% {\n border-color: rgb(147, 197, 253);\n }\n }\n .animate-pulse-border {\n animation: pulse-border 2s ease-in-out infinite;\n }\n `\n }} />\n </div>\n );\n}\n","import { useState, KeyboardEvent } from 'react';\nimport { PromptProps } from '../../types/components';\nimport { cn } from '../../utils';\nimport { aptevaClient } from '../../lib/apteva-client';\n\nexport function Prompt({\n agentId,\n placeholder = 'Enter your prompt...',\n initialValue = '',\n useMock = true,\n submitOn = 'button',\n debounceMs = 0,\n minLength = 0,\n maxLength,\n onSubmit,\n onResult,\n onChange,\n variant = 'inline',\n showSuggestions = false,\n className,\n}: PromptProps) {\n const [value, setValue] = useState(initialValue);\n const [isLoading, setIsLoading] = useState(false);\n const [suggestions] = useState(['Plan a trip', 'Write a description', 'Analyze data']);\n\n const handleChange = (e: React.ChangeEvent<HTMLInputElement>) => {\n const newValue = e.target.value;\n if (!maxLength || newValue.length <= maxLength) {\n setValue(newValue);\n onChange?.(newValue);\n }\n };\n\n const handleSubmit = async () => {\n if (value.length < minLength) return;\n\n onSubmit?.(value);\n setIsLoading(true);\n\n try {\n if (useMock) {\n // MOCK MODE\n await new Promise((resolve) => setTimeout(resolve, 1500));\n const mockResult = `Enhanced version: ${value} [AI-generated content]`;\n onResult?.(mockResult);\n setValue('');\n } else {\n // REAL API MODE\n const response = await aptevaClient.chat({\n agent_id: agentId,\n message: value,\n });\n onResult?.(response.message);\n setValue('');\n }\n } catch (error) {\n console.error('Error processing prompt:', error);\n } finally {\n setIsLoading(false);\n }\n };\n\n const handleKeyDown = (e: KeyboardEvent<HTMLInputElement>) => {\n if (submitOn === 'enter' && e.key === 'Enter' && !e.shiftKey) {\n e.preventDefault();\n handleSubmit();\n }\n };\n\n const handleBlur = () => {\n if (submitOn === 'blur' && value.trim()) {\n handleSubmit();\n }\n };\n\n return (\n <div className={cn('space-y-2', className)}>\n <div className=\"flex gap-2\">\n <input\n type=\"text\"\n value={value}\n onChange={handleChange}\n onKeyDown={handleKeyDown}\n onBlur={handleBlur}\n placeholder={placeholder}\n disabled={isLoading}\n className=\"flex-1 px-4 py-2 border border-gray-300 rounded-lg focus:outline-none focus:ring-2 focus:ring-apteva-500 dark:bg-gray-800 dark:border-gray-600 dark:text-white\"\n />\n\n {submitOn === 'button' && (\n <button\n onClick={handleSubmit}\n disabled={isLoading || value.length < minLength}\n className=\"px-6 py-2 bg-apteva-500 text-white rounded-lg hover:bg-apteva-600 disabled:opacity-50 disabled:cursor-not-allowed transition-colors font-medium\"\n >\n {isLoading ? 'Processing...' : 'Generate'}\n </button>\n )}\n </div>\n\n {maxLength && (\n <p className=\"text-xs text-gray-500\">\n {value.length} / {maxLength} characters\n </p>\n )}\n\n {showSuggestions && !value && (\n <div className=\"flex flex-wrap gap-2\">\n {suggestions.map((suggestion, idx) => (\n <button\n key={idx}\n onClick={() => setValue(suggestion)}\n className=\"px-3 py-1 text-sm bg-gray-100 hover:bg-gray-200 text-gray-700 rounded-full transition-colors\"\n >\n {suggestion}\n </button>\n ))}\n </div>\n )}\n\n {isLoading && (\n <div className=\"flex items-center gap-2 text-sm text-gray-500\">\n <div className=\"w-4 h-4 border-2 border-apteva-500 border-t-transparent rounded-full animate-spin\" />\n <span>AI is processing your request...</span>\n </div>\n )}\n </div>\n );\n}\n","import { useState, useEffect } from 'react';\nimport { StreamProps } from '../../types/components';\nimport { cn, generateMockStreamingResponse } from '../../utils';\nimport { aptevaClient } from '../../lib/apteva-client';\n\nexport function Stream({\n agentId,\n prompt,\n context,\n autoStart = false,\n useMock = true,\n onStart,\n onChunk,\n onComplete,\n onError,\n variant = 'prose',\n showCursor = true,\n typingSpeed = 30,\n className,\n}: StreamProps) {\n const [text, setText] = useState('');\n const [isStreaming, setIsStreaming] = useState(false);\n const [isComplete, setIsComplete] = useState(false);\n\n useEffect(() => {\n if (autoStart && !isStreaming && !isComplete) {\n startStreaming();\n }\n }, [autoStart]);\n\n const startStreaming = async () => {\n setIsStreaming(true);\n onStart?.();\n\n try {\n if (useMock) {\n // MOCK MODE\n const mockText =\n 'This is a simulated streaming response from the AI agent. ' +\n 'In a real implementation, this would stream data from your backend API. ' +\n 'The text appears word by word to simulate the streaming effect. ' +\n 'You can customize the typing speed and styling based on your needs.';\n\n await generateMockStreamingResponse(\n mockText,\n (chunk) => {\n setText((prev) => prev + chunk);\n onChunk?.(chunk);\n },\n typingSpeed\n );\n\n setIsComplete(true);\n setIsStreaming(false);\n onComplete?.(text + mockText);\n } else {\n // REAL API MODE\n let accumulatedText = '';\n\n await aptevaClient.chatStream(\n {\n agent_id: agentId,\n message: prompt,\n stream: true,\n },\n (chunk) => {\n if (chunk.type === 'token' && chunk.content) {\n accumulatedText += chunk.content;\n setText(accumulatedText);\n onChunk?.(chunk.content);\n }\n },\n () => {\n // On complete\n setIsComplete(true);\n setIsStreaming(false);\n onComplete?.(accumulatedText);\n },\n (error) => {\n // On error\n const err = error instanceof Error ? error : new Error('Streaming error');\n onError?.(err);\n setIsStreaming(false);\n }\n );\n }\n } catch (error) {\n const err = error instanceof Error ? error : new Error('Streaming error');\n onError?.(err);\n setIsStreaming(false);\n }\n };\n\n const variantClasses = {\n prose: 'prose prose-sm max-w-none dark:prose-invert',\n code: 'font-mono text-sm bg-gray-900 text-green-400 p-4 rounded-lg',\n plain: 'text-gray-900 dark:text-gray-100',\n };\n\n if (!isStreaming && !isComplete) {\n return (\n <div className={cn('p-4', className)}>\n <button\n onClick={startStreaming}\n className=\"px-6 py-3 bg-apteva-500 text-white rounded-lg hover:bg-apteva-600 transition-colors font-medium\"\n >\n Start Streaming\n </button>\n </div>\n );\n }\n\n return (\n <div className={cn(variantClasses[variant], className)}>\n {text}\n {isStreaming && showCursor && <span className=\"apteva-stream-cursor\" />}\n </div>\n );\n}\n","import { useState } from 'react';\nimport { Thread } from '../../types/messages';\nimport { ThreadItem } from './ThreadItem';\n\ninterface ThreadListProps {\n threads: Thread[];\n currentThreadId?: string;\n onThreadSelect?: (threadId: string) => void;\n onThreadDelete?: (threadId: string) => void;\n showSearch?: boolean;\n groupBy?: 'date' | 'agent' | 'none';\n}\n\nexport function ThreadList({\n threads,\n currentThreadId,\n onThreadSelect,\n onThreadDelete,\n showSearch = false,\n groupBy = 'none',\n}: ThreadListProps) {\n const [searchQuery, setSearchQuery] = useState('');\n\n const filteredThreads = threads.filter(\n (thread) =>\n thread.title.toLowerCase().includes(searchQuery.toLowerCase()) ||\n thread.preview?.toLowerCase().includes(searchQuery.toLowerCase())\n );\n\n const groupedThreads = groupBy === 'date' ? groupThreadsByDate(filteredThreads) : { All: filteredThreads };\n\n return (\n <div className=\"flex flex-col h-full\">\n {showSearch && (\n <div className=\"p-3 border-b border-gray-200 dark:border-gray-700\">\n <input\n type=\"text\"\n placeholder=\"Search conversations...\"\n value={searchQuery}\n onChange={(e) => setSearchQuery(e.target.value)}\n className=\"w-full px-3 py-2 text-sm border border-gray-300 rounded-lg focus:outline-none focus:ring-2 focus:ring-apteva-500 dark:bg-gray-800 dark:border-gray-600 dark:text-white\"\n />\n </div>\n )}\n\n <div className=\"flex-1 overflow-y-auto\">\n {Object.entries(groupedThreads).map(([group, groupThreads]) => (\n <div key={group}>\n {groupBy !== 'none' && (\n <div className=\"px-3 py-2 text-xs font-semibold text-gray-500 uppercase\">{group}</div>\n )}\n {groupThreads.map((thread) => (\n <ThreadItem\n key={thread.id}\n thread={thread}\n isActive={thread.id === currentThreadId}\n onSelect={() => onThreadSelect?.(thread.id)}\n onDelete={() => onThreadDelete?.(thread.id)}\n />\n ))}\n </div>\n ))}\n\n {filteredThreads.length === 0 && (\n <div className=\"p-8 text-center text-gray-500\">\n <div className=\"text-4xl mb-2\">💬</div>\n <p>No conversations found</p>\n </div>\n )}\n </div>\n </div>\n );\n}\n\nfunction groupThreadsByDate(threads: Thread[]): Record<string, Thread[]> {\n const now = new Date();\n const today = new Date(now.getFullYear(), now.getMonth(), now.getDate());\n const yesterday = new Date(today);\n yesterday.setDate(yesterday.getDate() - 1);\n const lastWeek = new Date(today);\n lastWeek.setDate(lastWeek.getDate() - 7);\n\n return threads.reduce(\n (groups, thread) => {\n const threadDate = new Date(thread.updatedAt);\n let group = 'Older';\n\n if (threadDate >= today) {\n group = 'Today';\n } else if (threadDate >= yesterday) {\n group = 'Yesterday';\n } else if (threadDate >= lastWeek) {\n group = 'Last 7 Days';\n }\n\n if (!groups[group]) groups[group] = [];\n groups[group].push(thread);\n return groups;\n },\n {} as Record<string, Thread[]>\n );\n}\n","// No direct imports needed 'react';\nimport { Thread } from '../../types/messages';\nimport { cn } from '../../utils';\n\ninterface ThreadItemProps {\n thread: Thread;\n isActive?: boolean;\n onSelect?: () => void;\n onDelete?: () => void;\n}\n\nexport function ThreadItem({ thread, isActive = false, onSelect, onDelete }: ThreadItemProps) {\n return (\n <div\n className={cn('apteva-thread-item', {\n 'apteva-thread-item-active': isActive,\n })}\n onClick={onSelect}\n >\n <div className=\"flex-1 min-w-0\">\n <h4 className=\"font-semibold text-gray-900 dark:text-white truncate\">{thread.title}</h4>\n {thread.preview && <p className=\"text-sm text-gray-600 dark:text-gray-400 truncate\">{thread.preview}</p>}\n <div className=\"flex items-center gap-2 mt-1 text-xs text-gray-500\">\n <span>{thread.messageCount} messages</span>\n <span>•</span>\n <span>{formatRelativeTime(thread.updatedAt)}</span>\n </div>\n </div>\n\n {onDelete && (\n <button\n onClick={(e) => {\n e.stopPropagation();\n onDelete();\n }}\n className=\"p-2 text-gray-400 hover:text-red-500 hover:bg-red-50 rounded transition-colors\"\n title=\"Delete thread\"\n >\n 🗑️\n </button>\n )}\n </div>\n );\n}\n\nfunction formatRelativeTime(date: Date): string {\n const now = new Date();\n const diff = now.getTime() - date.getTime();\n const minutes = Math.floor(diff / 60000);\n const hours = Math.floor(diff / 3600000);\n const days = Math.floor(diff / 86400000);\n\n if (minutes < 1) return 'Just now';\n if (minutes < 60) return `${minutes}m ago`;\n if (hours < 24) return `${hours}h ago`;\n if (days < 7) return `${days}d ago`;\n return date.toLocaleDateString();\n}\n","// No direct imports needed 'react';\nimport { ThreadsProps } from '../../types/components';\nimport { ThreadList } from './ThreadList';\nimport { cn } from '../../utils';\n\nexport function Threads({\n threads,\n currentThreadId,\n onThreadSelect,\n onThreadDelete,\n onNewThread,\n variant = 'sidebar',\n showSearch = false,\n showNewButton = true,\n groupBy = 'none',\n className,\n}: ThreadsProps) {\n const variantClasses = {\n sidebar: 'h-full border-r border-gray-200 dark:border-gray-700 bg-white dark:bg-gray-900',\n dropdown: 'absolute top-full left-0 right-0 mt-2 bg-white dark:bg-gray-800 rounded-lg shadow-lg border border-gray-200 dark:border-gray-700 max-h-96 overflow-hidden',\n tabs: 'flex gap-2 border-b border-gray-200 dark:border-gray-700 overflow-x-auto',\n };\n\n if (variant === 'tabs') {\n return (\n <div className={cn(variantClasses[variant], className)}>\n {threads.slice(0, 5).map((thread) => (\n <button\n key={thread.id}\n onClick={() => onThreadSelect?.(thread.id)}\n className={cn(\n 'px-4 py-2 whitespace-nowrap font-medium transition-colors',\n thread.id === currentThreadId\n ? 'border-b-2 border-apteva-500 text-apteva-500'\n : 'text-gray-600 hover:text-gray-900'\n )}\n >\n {thread.title}\n </button>\n ))}\n {showNewButton && onNewThread && (\n <button\n onClick={onNewThread}\n className=\"px-4 py-2 text-gray-600 hover:text-apteva-500 transition-colors font-medium\"\n >\n + New\n </button>\n )}\n </div>\n );\n }\n\n return (\n <div className={cn(variantClasses[variant], 'flex flex-col', className)}>\n {showNewButton && onNewThread && (\n <div className=\"p-3 border-b border-gray-200 dark:border-gray-700\">\n <button\n onClick={onNewThread}\n className=\"w-full px-4 py-2 bg-apteva-500 text-white rounded-lg hover:bg-apteva-600 transition-colors font-medium\"\n >\n + New Conversation\n </button>\n </div>\n )}\n\n <ThreadList\n threads={threads}\n currentThreadId={currentThreadId}\n onThreadSelect={onThreadSelect}\n onThreadDelete={onThreadDelete}\n showSearch={showSearch}\n groupBy={groupBy}\n />\n </div>\n );\n}\n","/**\n * Theme initialization script that runs before React hydration\n * This prevents flickering by setting the theme before the page renders\n * Must be inlined in the HTML <head> as a blocking script\n */\n\nexport const themeScript = `\n(function() {\n try {\n // Get system preference\n const isDark = window.matchMedia('(prefers-color-scheme: dark)').matches;\n const colorMode = isDark ? 'dark' : 'light';\n\n // Set attributes before render\n document.documentElement.setAttribute('data-color-mode', colorMode);\n\n // Add dark class for Tailwind\n if (isDark) {\n document.documentElement.classList.add('dark');\n }\n } catch (e) {\n console.error('Failed to initialize theme:', e);\n }\n})();\n`;\n\nexport function getThemeScript() {\n return themeScript;\n}\n"]}
|
|
1
|
+
{"version":3,"sources":["/Users/marcoschwartz/Documents/code/frontends/apteva/apteva-kit/dist/index.js","../src/components/Chat/Chat.tsx","../src/components/Chat/MessageList.tsx","../src/utils/cn.ts","../src/utils/mock-data.ts","../src/components/Widgets/Widgets.tsx","../src/components/Widgets/widget-library/Card.tsx","../src/components/Widgets/widget-library/List.tsx","../src/components/Widgets/widget-library/Button.tsx","../src/components/Widgets/WidgetRenderer.tsx","../src/components/Chat/MarkdownContent.tsx","../src/components/Chat/ToolCall.tsx","../src/components/Chat/Message.tsx","../src/components/Chat/Composer.tsx","../src/lib/apteva-client.ts","../src/components/Command/Command.tsx","../src/components/Prompt/Prompt.tsx","../src/components/Stream/Stream.tsx","../src/components/Threads/ThreadList.tsx","../src/components/Threads/ThreadItem.tsx","../src/components/Threads/Threads.tsx","../src/utils/theme-script.ts"],"names":["jsxs","jsx","useRef","threadId","useState","Fragment","result","error"],"mappings":"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","file":"/Users/marcoschwartz/Documents/code/frontends/apteva/apteva-kit/dist/index.js","sourcesContent":[null,"import { useState, useEffect } from 'react';\nimport { ChatProps } from '../../types/components';\nimport { Message as MessageType } from '../../types/messages';\nimport { MessageList } from './MessageList';\nimport { Composer } from './Composer';\nimport { cn, generateMockResponse } from '../../utils';\nimport { aptevaClient } from '../../lib/apteva-client';\nimport { Widget } from '../../types/widgets';\n\nexport function Chat({\n agentId,\n threadId,\n initialMessages = [],\n context,\n apiUrl,\n apiKey,\n useMock = false,\n onThreadChange,\n onMessageSent,\n onAction,\n onFileUpload,\n placeholder = 'Type a message...',\n showHeader = true,\n headerTitle = 'Chat',\n className,\n}: ChatProps) {\n const [messages, setMessages] = useState<MessageType[]>(initialMessages);\n const [isLoading, setIsLoading] = useState(false);\n const [currentThreadId, setCurrentThreadId] = useState<string | null>(threadId || null);\n\n // Configure API client if props provided\n useEffect(() => {\n if (apiUrl || apiKey) {\n aptevaClient.configure({\n ...(apiUrl && { apiUrl }),\n ...(apiKey && { apiKey }),\n });\n }\n }, [apiUrl, apiKey]);\n\n useEffect(() => {\n // Load messages when threadId changes\n if (threadId) {\n // In real implementation, fetch messages from API\n console.log('Loading thread:', threadId);\n onThreadChange?.(threadId);\n }\n }, [threadId, onThreadChange]);\n\n const handleSendMessage = async (text: string) => {\n // Add user message\n const userMessage: MessageType = {\n id: `msg-${Date.now()}`,\n role: 'user',\n content: text,\n timestamp: new Date(),\n };\n\n setMessages((prev) => [...prev, userMessage]);\n onMessageSent?.(userMessage);\n\n setIsLoading(true);\n\n try {\n if (useMock) {\n // MOCK MODE\n const response = await generateMockResponse(1000);\n setMessages((prev) => [...prev, response]);\n } else {\n // REAL API MODE\n // Content segments: array of { type: 'text' | 'tool', content/tool data }\n let contentSegments: Array<{ type: 'text'; content: string } | { type: 'tool'; id: string; name: string; result?: any }> = [];\n let currentTextBuffer = '';\n let accumulatedWidgets: Widget[] = [];\n let responseThreadId = currentThreadId;\n let toolInputBuffer = '';\n\n const updateMessage = () => {\n // Build content with tool markers embedded\n const segments = [...contentSegments];\n if (currentTextBuffer) {\n // Add current text buffer if exists\n const lastSegment = segments[segments.length - 1];\n if (lastSegment && lastSegment.type === 'text') {\n lastSegment.content = currentTextBuffer;\n } else {\n segments.push({ type: 'text', content: currentTextBuffer });\n }\n }\n\n setMessages((prev) => {\n const lastMessage = prev[prev.length - 1];\n if (lastMessage && lastMessage.role === 'assistant') {\n return [\n ...prev.slice(0, -1),\n {\n ...lastMessage,\n content: currentTextBuffer,\n widgets: accumulatedWidgets.length > 0 ? accumulatedWidgets : undefined,\n metadata: {\n ...lastMessage.metadata,\n content_segments: segments,\n },\n }\n ];\n } else {\n return [\n ...prev,\n {\n id: `msg-${Date.now()}-streaming`,\n role: 'assistant' as const,\n content: currentTextBuffer,\n widgets: accumulatedWidgets.length > 0 ? accumulatedWidgets : undefined,\n timestamp: new Date(),\n metadata: {\n content_segments: segments,\n },\n }\n ];\n }\n });\n };\n\n await aptevaClient.chatStream(\n {\n agent_id: agentId,\n message: text,\n stream: true,\n ...(currentThreadId && { thread_id: currentThreadId }),\n ...(context && { system: context }),\n },\n (chunk) => {\n // Handle different chunk types based on SSE event types\n switch (chunk.type) {\n case 'start':\n // Stream initialization\n break;\n\n case 'thread_id':\n // Thread identifier\n if (chunk.thread_id) {\n responseThreadId = chunk.thread_id;\n if (!currentThreadId) {\n setCurrentThreadId(chunk.thread_id);\n onThreadChange?.(chunk.thread_id);\n }\n }\n break;\n\n case 'content':\n case 'token':\n // Text content chunk\n if (chunk.content) {\n currentTextBuffer += chunk.content;\n updateMessage();\n }\n break;\n\n case 'tool_call':\n // Tool invocation announced\n if (chunk.tool_id && chunk.tool_name) {\n // Save current text as a segment\n if (currentTextBuffer) {\n contentSegments.push({ type: 'text', content: currentTextBuffer });\n currentTextBuffer = '';\n }\n // Add tool segment (initially running)\n contentSegments.push({\n type: 'tool',\n id: chunk.tool_id,\n name: chunk.tool_name,\n });\n toolInputBuffer = '';\n updateMessage();\n }\n break;\n\n case 'tool_input_delta':\n // Tool arguments streaming (accumulate JSON chunks)\n if (chunk.tool_id && chunk.content) {\n toolInputBuffer += chunk.content;\n }\n break;\n\n case 'tool_use':\n // Tool execution starting (input is complete)\n toolInputBuffer = '';\n break;\n\n case 'tool_result':\n // Tool execution completed\n if (chunk.tool_id) {\n // Find and update the tool segment\n const toolSegment = contentSegments.find(\n (s) => s.type === 'tool' && s.id === chunk.tool_id\n ) as { type: 'tool'; id: string; name: string; result?: any } | undefined;\n if (toolSegment) {\n toolSegment.result = chunk.content;\n }\n updateMessage();\n }\n break;\n\n case 'widget':\n // Widget from response\n if (chunk.widget) {\n accumulatedWidgets.push(chunk.widget);\n updateMessage();\n }\n break;\n\n case 'stop':\n // Intermediate stop (after tool execution, before next turn)\n break;\n\n case 'complete':\n // Stream complete\n break;\n\n case 'error':\n // Error occurred\n throw new Error(chunk.message || 'Stream error');\n\n default:\n // Unknown chunk type - silently ignore\n break;\n }\n },\n (threadId) => {\n // On complete\n // Save any remaining text\n if (currentTextBuffer) {\n const lastSegment = contentSegments[contentSegments.length - 1];\n if (lastSegment && lastSegment.type === 'text') {\n lastSegment.content = currentTextBuffer;\n } else {\n contentSegments.push({ type: 'text', content: currentTextBuffer });\n }\n }\n\n // Finalize the assistant message\n setMessages((prev) => {\n const lastMessage = prev[prev.length - 1];\n if (lastMessage && lastMessage.role === 'assistant') {\n return [\n ...prev.slice(0, -1),\n {\n ...lastMessage,\n id: `msg-${Date.now()}`,\n content: currentTextBuffer || 'Response received',\n widgets: accumulatedWidgets.length > 0 ? accumulatedWidgets : undefined,\n metadata: {\n thread_id: threadId,\n content_segments: contentSegments,\n },\n }\n ];\n }\n return prev;\n });\n\n if (threadId && threadId !== currentThreadId) {\n setCurrentThreadId(threadId);\n onThreadChange?.(threadId);\n }\n\n // Stop loading indicator\n setIsLoading(false);\n },\n (error) => {\n // On error\n\n // Add error message\n const errorMessage: MessageType = {\n id: `msg-${Date.now()}-error`,\n role: 'assistant',\n content: `Error: ${error.message}`,\n timestamp: new Date(),\n metadata: { error: true },\n };\n\n setMessages((prev) => {\n // Remove incomplete streaming message if exists\n const lastMessage = prev[prev.length - 1];\n if (lastMessage && lastMessage.id.includes('streaming')) {\n return [...prev.slice(0, -1), errorMessage];\n }\n return [...prev, errorMessage];\n });\n\n // Stop loading indicator\n setIsLoading(false);\n }\n );\n }\n } catch (error) {\n console.error('Chat error:', error);\n\n // Add error message\n const errorMessage: MessageType = {\n id: `msg-${Date.now()}-error`,\n role: 'assistant',\n content: error instanceof Error ? `Error: ${error.message}` : 'An error occurred',\n timestamp: new Date(),\n metadata: { error: true },\n };\n\n setMessages((prev) => [...prev, errorMessage]);\n } finally {\n setIsLoading(false);\n }\n };\n\n return (\n <div className={cn('flex flex-col h-full bg-white dark:bg-gray-900', className)}>\n {showHeader && (\n <div className=\"px-4 py-3 bg-white dark:bg-gray-900\">\n <h2 className=\"!text-lg font-semibold !text-gray-900 dark:!text-white\">{headerTitle}</h2>\n </div>\n )}\n\n <MessageList messages={messages} onAction={onAction} />\n\n {isLoading && (\n <div className=\"px-4 py-2 !text-sm !text-gray-500 dark:!text-gray-400 italic\">AI is thinking...</div>\n )}\n\n <Composer onSendMessage={handleSendMessage} placeholder={placeholder} disabled={isLoading} onFileUpload={onFileUpload} />\n </div>\n );\n}\n","import { useEffect, useRef } from 'react';\nimport { Message as MessageType } from '../../types/messages';\nimport { Message } from './Message';\nimport { ActionEvent } from '../../types/actions';\n\ninterface MessageListProps {\n messages: MessageType[];\n onAction?: (action: ActionEvent) => void;\n}\n\nexport function MessageList({ messages, onAction }: MessageListProps) {\n const listRef = useRef<HTMLDivElement>(null);\n\n useEffect(() => {\n // Auto-scroll to bottom when new messages arrive\n if (listRef.current) {\n listRef.current.scrollTop = listRef.current.scrollHeight;\n }\n }, [messages]);\n\n return (\n <div ref={listRef} className=\"flex-1 overflow-y-auto px-4 py-4 space-y-3 apteva-scrollbar-hidden\">\n {messages.length === 0 ? (\n <div className=\"flex items-center justify-center h-full !text-gray-500 dark:!text-gray-400\">\n <div className=\"text-center space-y-2\">\n <div className=\"text-4xl\">💬</div>\n <p>No messages yet. Start a conversation!</p>\n </div>\n </div>\n ) : (\n messages.map((message) => <Message key={message.id} message={message} onAction={onAction} />)\n )}\n </div>\n );\n}\n","import { clsx, type ClassValue } from 'clsx';\nimport { twMerge } from 'tailwind-merge';\n\nexport function cn(...inputs: ClassValue[]) {\n return twMerge(clsx(inputs));\n}\n","import { Message, Thread } from '../types/messages';\nimport { Widget } from '../types/widgets';\n\nexport const mockMessages: Message[] = [\n {\n id: 'msg-1',\n role: 'assistant',\n content: 'Hello! I\\'m your AI assistant. How can I help you today?',\n timestamp: new Date(Date.now() - 3600000),\n },\n {\n id: 'msg-2',\n role: 'user',\n content: 'I want to plan a trip to Europe',\n timestamp: new Date(Date.now() - 3500000),\n },\n {\n id: 'msg-3',\n role: 'assistant',\n content: 'Great choice! Europe has amazing destinations. What\\'s your budget and how many days do you have?',\n timestamp: new Date(Date.now() - 3400000),\n },\n {\n id: 'msg-4',\n role: 'user',\n content: 'Around $2000 for 5 days',\n timestamp: new Date(Date.now() - 3300000),\n },\n {\n id: 'msg-5',\n role: 'assistant',\n content: 'Perfect! I found some great destinations that fit your budget:',\n widgets: [\n {\n type: 'list',\n id: 'destinations-1',\n props: {\n items: [\n {\n id: 'paris',\n title: 'Paris, France',\n subtitle: '5 days • $1,850',\n description: 'The City of Light with iconic landmarks',\n metadata: { city: 'Paris', country: 'France', lat: 48.8566, lng: 2.3522, price: 1850, days: 5 },\n },\n {\n id: 'rome',\n title: 'Rome, Italy',\n subtitle: '5 days • $1,650',\n description: 'Ancient history meets modern culture',\n metadata: { city: 'Rome', country: 'Italy', lat: 41.9028, lng: 12.4964, price: 1650, days: 5 },\n },\n {\n id: 'barcelona',\n title: 'Barcelona, Spain',\n subtitle: '5 days • $1,450',\n description: 'Beautiful beaches and Gaudí architecture',\n metadata: { city: 'Barcelona', country: 'Spain', lat: 41.3851, lng: 2.1734, price: 1450, days: 5 },\n },\n ],\n },\n actions: [\n {\n type: 'select_destination',\n label: 'Select',\n handler: 'client',\n payload: {},\n },\n {\n type: 'view_details',\n label: 'Details',\n handler: 'server',\n payload: {},\n },\n ],\n },\n ],\n timestamp: new Date(Date.now() - 3200000),\n },\n];\n\nexport const mockThreads: Thread[] = [\n {\n id: 'thread-1',\n title: 'Trip to Europe',\n preview: 'Planning a 5-day trip...',\n createdAt: new Date(Date.now() - 86400000),\n updatedAt: new Date(Date.now() - 3600000),\n messageCount: 12,\n },\n {\n id: 'thread-2',\n title: 'Restaurant Recommendations',\n preview: 'Looking for good places...',\n createdAt: new Date(Date.now() - 172800000),\n updatedAt: new Date(Date.now() - 86400000),\n messageCount: 8,\n },\n {\n id: 'thread-3',\n title: 'Budget Planning',\n preview: 'Help with monthly budget',\n createdAt: new Date(Date.now() - 259200000),\n updatedAt: new Date(Date.now() - 172800000),\n messageCount: 15,\n },\n];\n\nexport const mockWidgets: Widget[] = [\n {\n type: 'card',\n id: 'card-1',\n props: {\n title: 'Paris, France',\n description: '5-day adventure in the City of Light',\n image: 'https://images.unsplash.com/photo-1502602898657-3e91760cbb34',\n footer: 'Total: $1,850',\n },\n actions: [\n {\n type: 'book_trip',\n label: 'Book Now',\n handler: 'client',\n payload: { tripId: 'trip-paris' },\n },\n ],\n },\n {\n type: 'card',\n id: 'card-2',\n props: {\n title: 'Rome, Italy',\n description: 'Explore ancient wonders',\n image: 'https://images.unsplash.com/photo-1552832230-c0197dd311b5',\n footer: 'Total: $1,650',\n },\n actions: [\n {\n type: 'book_trip',\n label: 'Book Now',\n handler: 'client',\n payload: { tripId: 'trip-rome' },\n },\n ],\n },\n];\n\nexport function generateMockResponse(delay: number = 1000): Promise<Message> {\n return new Promise((resolve) => {\n setTimeout(() => {\n resolve({\n id: `msg-${Date.now()}`,\n role: 'assistant',\n content: 'This is a mock response. In production, this would come from your AI agent API.',\n timestamp: new Date(),\n });\n }, delay);\n });\n}\n\nexport function generateMockStreamingResponse(\n text: string,\n onChunk: (chunk: string) => void,\n typingSpeed: number = 30\n): Promise<void> {\n return new Promise((resolve) => {\n const words = text.split(' ');\n let currentIndex = 0;\n\n const interval = setInterval(() => {\n if (currentIndex < words.length) {\n onChunk(words[currentIndex] + ' ');\n currentIndex++;\n } else {\n clearInterval(interval);\n resolve();\n }\n }, typingSpeed);\n });\n}\n\n// Generate mock plan based on command content\nexport function generateMockPlan(command: string): string {\n const lowerCommand = command.toLowerCase();\n\n if (lowerCommand.includes('analyze') || lowerCommand.includes('analysis')) {\n return `**Plan:**\\n\\n1. Fetch data from the analytics database\\n2. Apply filters and aggregations\\n3. Calculate key metrics and trends\\n4. Generate visualization data\\n5. Compile insights and recommendations`;\n }\n\n if (lowerCommand.includes('sales') || lowerCommand.includes('revenue')) {\n return `**Plan:**\\n\\n1. Query sales records for the specified period\\n2. Calculate total revenue and growth rates\\n3. Break down performance by product category\\n4. Analyze regional distribution\\n5. Present findings in charts and summary`;\n }\n\n if (lowerCommand.includes('report') || lowerCommand.includes('summary')) {\n return `**Plan:**\\n\\n1. Gather data from all relevant sources\\n2. Aggregate metrics across categories\\n3. Identify key trends and anomalies\\n4. Generate executive summary\\n5. Create detailed breakdowns with visualizations`;\n }\n\n if (lowerCommand.includes('customer') || lowerCommand.includes('user')) {\n return `**Plan:**\\n\\n1. Pull customer data from CRM\\n2. Calculate engagement metrics\\n3. Segment users by behavior patterns\\n4. Analyze satisfaction scores\\n5. Generate customer insights report`;\n }\n\n if (lowerCommand.includes('task') || lowerCommand.includes('todo') || lowerCommand.includes('work') || lowerCommand.includes('completed')) {\n return `**Plan:**\\n\\n1. Retrieve task records from the database\\n2. Filter by status and date range\\n3. Organize by priority and category\\n4. Calculate completion metrics\\n5. Display in interactive list format`;\n }\n\n // Default plan\n return `**Plan:**\\n\\n1. Parse and understand the command requirements\\n2. Gather necessary data from available sources\\n3. Process and analyze the information\\n4. Format results for optimal presentation\\n5. Return response with any relevant visualizations`;\n}\n\n// Generate mock command response based on command content\nexport function generateMockCommandResponse(command: string): string {\n const lowerCommand = command.toLowerCase();\n\n if (lowerCommand.includes('analyze') || lowerCommand.includes('analysis')) {\n return `Analysis complete for \"${command}\". Found 247 records with an average value of $1,234. The data shows a 23% increase compared to last quarter. Key insights: Revenue is up, customer satisfaction improved by 15%, and operational costs decreased by 8%.`;\n }\n\n if (lowerCommand.includes('sales') || lowerCommand.includes('revenue')) {\n return `Sales data processed: Q4 2024 revenue reached $2.4M, representing 18% growth year-over-year. Top performing products: Enterprise Plan (+45%), Pro Plan (+32%), Basic Plan (+12%). Regional breakdown: North America (52%), Europe (31%), APAC (17%).`;\n }\n\n if (lowerCommand.includes('report') || lowerCommand.includes('summary')) {\n return `Report generated successfully. Executive Summary: Overall performance exceeded targets by 12%. Marketing ROI improved to 3.2x, customer acquisition cost reduced by 18%, and lifetime value increased by 24%. Detailed breakdown available in attached widgets.`;\n }\n\n if (lowerCommand.includes('data') || lowerCommand.includes('metrics')) {\n return `Data metrics retrieved: 1,847 active users, 12,394 sessions this month, 94.2% uptime, average response time 127ms. Performance is within acceptable parameters. No critical issues detected.`;\n }\n\n if (lowerCommand.includes('customer') || lowerCommand.includes('user')) {\n return `Customer analysis complete: 523 new customers this month, 89% retention rate, average satisfaction score 4.6/5. Top feedback themes: excellent support (87%), easy to use (72%), good value (68%). 3 support tickets pending review.`;\n }\n\n // Default response\n return `This is a mock response showing how your agent would process and respond to commands. The actual response would be generated by your AI agent based on real data and context.`;\n}\n\n// Generate mock command response with widgets\nexport function generateMockCommandWithWidgets(command: string): { message: string; widgets: Widget[]; action?: { type: string; payload: any } } {\n const message = generateMockCommandResponse(command);\n const lowerCommand = command.toLowerCase();\n\n let widgets: Widget[] = [];\n let action: { type: string; payload: any } | undefined;\n\n // Add relevant widgets based on command type\n if (lowerCommand.includes('sales') || lowerCommand.includes('revenue') || lowerCommand.includes('analyze')) {\n widgets.push({\n type: 'card',\n id: `widget-${Date.now()}-1`,\n props: {\n title: 'Q4 2024 Performance',\n description: 'Revenue: $2.4M (+18% YoY)',\n footer: 'Updated: ' + new Date().toLocaleDateString(),\n },\n actions: [\n {\n type: 'view_details',\n label: 'View Details',\n handler: 'client',\n payload: { reportId: 'q4-2024' },\n },\n ],\n });\n }\n\n if (lowerCommand.includes('customer') || lowerCommand.includes('user')) {\n widgets.push({\n type: 'list',\n id: `widget-${Date.now()}-2`,\n props: {\n items: [\n {\n id: 'metric-1',\n title: 'Active Users',\n subtitle: '1,847 users',\n description: '+12% from last month',\n },\n {\n id: 'metric-2',\n title: 'Retention Rate',\n subtitle: '89%',\n description: 'Above industry average',\n },\n {\n id: 'metric-3',\n title: 'Satisfaction Score',\n subtitle: '4.6/5',\n description: 'Based on 234 reviews',\n },\n ],\n },\n });\n }\n\n // Add task widget for task-related commands\n if (lowerCommand.includes('task') || lowerCommand.includes('todo') || lowerCommand.includes('work') || lowerCommand.includes('completed')) {\n widgets.push({\n type: 'list',\n id: `widget-${Date.now()}-tasks`,\n props: {\n items: [\n {\n id: 'task-1',\n title: 'Implement user authentication',\n subtitle: 'Created just now',\n description: 'Added OAuth 2.0 support with Google and GitHub providers',\n backgroundColor: 'rgba(59, 130, 246, 0.15)',\n metadata: {\n status: 'created',\n priority: 'high',\n tags: ['backend', 'security']\n }\n },\n {\n id: 'task-2',\n title: 'Update API documentation',\n subtitle: 'Modified 2 minutes ago',\n description: 'Changed endpoint descriptions and added new examples',\n backgroundColor: 'rgba(234, 179, 8, 0.15)',\n metadata: {\n status: 'modified',\n priority: 'medium',\n tags: ['docs']\n }\n },\n {\n id: 'task-3',\n title: 'Fix login redirect bug',\n subtitle: 'Completed 5 minutes ago',\n description: 'Users now properly redirected after successful login',\n backgroundColor: 'rgba(34, 197, 94, 0.15)',\n metadata: {\n status: 'completed',\n priority: 'urgent',\n tags: ['bugfix', 'auth']\n }\n }\n ],\n },\n actions: [\n {\n type: 'view_task',\n label: 'View',\n handler: 'client',\n payload: {}\n },\n {\n type: 'undo',\n label: 'Undo',\n handler: 'server',\n payload: {}\n }\n ]\n });\n\n // Agent also wants to update the database after showing tasks\n action = {\n type: 'update_database',\n payload: {\n table: 'tasks',\n operation: 'mark_as_viewed',\n taskIds: ['task-1', 'task-2', 'task-3'],\n timestamp: new Date().toISOString()\n }\n };\n }\n\n // Add agent action for analysis commands\n if (lowerCommand.includes('analyze') || lowerCommand.includes('analysis')) {\n action = {\n type: 'send_notification',\n payload: {\n recipient: 'team@company.com',\n subject: 'Analysis Complete',\n message: 'Your requested analysis has been completed and is ready for review.'\n }\n };\n }\n\n return { message, widgets, action };\n}\n\n// Simulate streaming command response\nexport function generateMockCommandStream(\n command: string,\n onChunk: (chunk: { type: 'token' | 'widget' | 'complete'; content?: string; widget?: Widget }) => void,\n onComplete: (threadId: string) => void,\n onError: (error: Error) => void,\n typingSpeed: number = 30\n): void {\n const { message, widgets } = generateMockCommandWithWidgets(command);\n const words = message.split(' ');\n let currentIndex = 0;\n\n const interval = setInterval(() => {\n try {\n if (currentIndex < words.length) {\n onChunk({ type: 'token', content: words[currentIndex] + ' ' });\n currentIndex++;\n } else {\n clearInterval(interval);\n\n // Send widgets after text is complete\n widgets.forEach(widget => {\n onChunk({ type: 'widget', widget });\n });\n\n // Signal completion\n const threadId = `mock_thread_${Date.now()}`;\n onChunk({ type: 'complete' });\n onComplete(threadId);\n }\n } catch (error) {\n clearInterval(interval);\n onError(error instanceof Error ? error : new Error('Mock streaming error'));\n }\n }, typingSpeed);\n}\n","import { useEffect } from 'react';\nimport { WidgetsProps } from '../../types/components';\nimport { WidgetRenderer } from './WidgetRenderer';\nimport { cn } from '../../utils';\n\nexport function Widgets({\n widgets,\n onAction,\n onWidgetMount,\n layout = 'stack',\n spacing = 'normal',\n columns = 3,\n className,\n}: WidgetsProps) {\n useEffect(() => {\n widgets.forEach((widget) => {\n onWidgetMount?.(widget.id);\n });\n }, [widgets, onWidgetMount]);\n\n const layoutClasses = {\n stack: 'flex flex-col',\n grid: `grid grid-cols-1 md:grid-cols-${columns}`,\n masonry: 'columns-1 md:columns-2 lg:columns-3',\n };\n\n const spacingClasses = {\n tight: 'gap-2',\n normal: 'gap-4',\n loose: 'gap-6',\n };\n\n return (\n <div className={cn(layoutClasses[layout], spacingClasses[spacing], className)}>\n {widgets.map((widget) => (\n <WidgetRenderer key={widget.id} widget={widget} onAction={onAction} />\n ))}\n </div>\n );\n}\n","// No direct imports needed 'react';\nimport { CardWidget } from '../../../types/widgets';\nimport { ActionEvent } from '../../../types/actions';\n\ninterface CardProps {\n widget: CardWidget;\n onAction?: (action: ActionEvent) => void;\n}\n\nexport function Card({ widget, onAction }: CardProps) {\n const { title, description, image, footer } = widget.props;\n\n return (\n <div className=\"border border-gray-200 dark:border-gray-700 rounded-xl bg-white dark:bg-gray-900 overflow-hidden\">\n {image && <img src={image} alt={title} className=\"w-full h-48 object-cover\" />}\n\n <div className=\"p-4\">\n <h3 className=\"!text-lg font-semibold !text-gray-900 dark:!text-white\">{title}</h3>\n {description && <p className=\"!text-gray-600 dark:!text-gray-400 mt-2\">{description}</p>}\n </div>\n\n {(footer || (widget.actions && widget.actions.length > 0)) && (\n <div className=\"border-t border-gray-200 dark:border-gray-700 p-4 flex justify-between items-center\">\n {footer && <span className=\"!text-sm !text-gray-600 dark:!text-gray-400\">{footer}</span>}\n\n {widget.actions && widget.actions.length > 0 && (\n <div className=\"flex gap-2\">\n {widget.actions.map((action, idx) => (\n <button\n key={idx}\n onClick={() =>\n onAction?.({\n type: action.type,\n payload: action.payload,\n widgetId: widget.id,\n timestamp: new Date(),\n })\n }\n className=\"px-3 py-1.5 !text-sm rounded-lg font-medium transition-colors bg-blue-500 !text-white hover:bg-blue-600\"\n >\n {action.label}\n </button>\n ))}\n </div>\n )}\n </div>\n )}\n </div>\n );\n}\n","// No direct imports needed 'react';\nimport { ListWidget } from '../../../types/widgets';\nimport { ActionEvent } from '../../../types/actions';\n\ninterface ListProps {\n widget: ListWidget;\n onAction?: (action: ActionEvent) => void;\n}\n\nexport function List({ widget, onAction }: ListProps) {\n const { items } = widget.props;\n\n return (\n <div className=\"border border-gray-200 dark:border-gray-700 rounded-xl bg-white dark:bg-gray-900 overflow-hidden\">\n {items.map((item, index) => (\n <div\n key={item.id}\n className={`flex items-center p-4 transition-colors ${\n index !== items.length - 1 ? 'border-b border-gray-200 dark:border-gray-700' : ''\n } ${!item.backgroundColor ? 'hover:bg-gray-50 dark:hover:bg-gray-800' : ''}`}\n style={item.backgroundColor ? { backgroundColor: item.backgroundColor } : undefined}\n >\n {item.image && <img src={item.image} alt={item.title} className=\"w-16 h-16 rounded object-cover\" />}\n\n <div className={`flex-1 ${item.image ? 'ml-4' : ''}`}>\n <h4 className=\"font-semibold !text-gray-900 dark:!text-white\">{item.title}</h4>\n {item.subtitle && <p className=\"!text-sm !text-gray-600 dark:!text-gray-400\">{item.subtitle}</p>}\n {item.description && (\n <p className=\"!text-xs !text-gray-500 dark:!text-gray-500 mt-1\">{item.description}</p>\n )}\n </div>\n\n {widget.actions && widget.actions.length > 0 && (\n <div className=\"flex gap-2\">\n {widget.actions.map((action, idx) => (\n <button\n key={idx}\n onClick={() =>\n onAction?.({\n type: action.type,\n payload: item.metadata || item,\n widgetId: widget.id,\n timestamp: new Date(),\n })\n }\n className=\"px-3 py-1.5 !text-sm rounded-lg font-medium transition-colors bg-blue-500 !text-white hover:bg-blue-600\"\n >\n {action.label}\n </button>\n ))}\n </div>\n )}\n </div>\n ))}\n </div>\n );\n}\n","// No direct imports needed 'react';\nimport { ButtonWidget } from '../../../types/widgets';\nimport { ActionEvent } from '../../../types/actions';\nimport { cn } from '../../../utils';\n\ninterface ButtonProps {\n widget: ButtonWidget;\n onAction?: (action: ActionEvent) => void;\n}\n\nexport function Button({ widget, onAction }: ButtonProps) {\n const { label, variant = 'primary', disabled = false } = widget.props;\n\n const variantClasses = {\n primary: 'bg-blue-500 !text-white hover:bg-blue-600',\n secondary: 'bg-gray-500 !text-white hover:bg-gray-600',\n outline: 'border-2 border-blue-500 !text-blue-500 hover:bg-blue-50 dark:hover:bg-blue-900',\n ghost: '!text-blue-500 hover:bg-blue-50 dark:hover:bg-blue-900',\n };\n\n return (\n <button\n onClick={() =>\n widget.actions?.[0] &&\n onAction?.({\n type: widget.actions[0].type,\n payload: widget.actions[0].payload,\n widgetId: widget.id,\n timestamp: new Date(),\n })\n }\n disabled={disabled}\n className={cn('px-4 py-2 rounded-lg font-medium transition-colors', variantClasses[variant], {\n 'opacity-50 cursor-not-allowed': disabled,\n })}\n >\n {label}\n </button>\n );\n}\n","// No direct imports needed 'react';\nimport { Widget } from '../../types/widgets';\nimport { ActionEvent } from '../../types/actions';\nimport { Card, List, Button } from './widget-library';\n\ninterface WidgetRendererProps {\n widget: Widget;\n onAction?: (action: ActionEvent) => void;\n}\n\nexport function WidgetRenderer({ widget, onAction }: WidgetRendererProps) {\n switch (widget.type) {\n case 'card':\n return <Card widget={widget as any} onAction={onAction} />;\n case 'list':\n return <List widget={widget as any} onAction={onAction} />;\n case 'button':\n return <Button widget={widget as any} onAction={onAction} />;\n default:\n return (\n <div className=\"p-4 border border-yellow-300 bg-yellow-50 rounded-lg\">\n <p className=\"text-sm text-yellow-800\">Unknown widget type: {widget.type}</p>\n <pre className=\"text-xs mt-2 overflow-auto\">{JSON.stringify(widget, null, 2)}</pre>\n </div>\n );\n }\n}\n","import React from 'react';\n\ninterface MarkdownContentProps {\n content: string;\n className?: string;\n}\n\nfunction parseInlineMarkdown(text: string, keyPrefix: string = ''): React.ReactNode[] {\n const result: React.ReactNode[] = [];\n // Match **bold** or __bold__\n const boldRegex = /(\\*\\*|__)(.+?)\\1/g;\n\n let lastIndex = 0;\n let match;\n let key = 0;\n\n while ((match = boldRegex.exec(text)) !== null) {\n // Add text before the match\n if (match.index > lastIndex) {\n result.push(text.slice(lastIndex, match.index));\n }\n // Add bold text\n result.push(<strong key={`${keyPrefix}b${key++}`}>{match[2]}</strong>);\n lastIndex = match.index + match[0].length;\n }\n\n // Add remaining text\n if (lastIndex < text.length) {\n result.push(text.slice(lastIndex));\n }\n\n return result.length > 0 ? result : [text];\n}\n\nfunction parseMarkdown(content: string): React.ReactNode[] {\n const lines = content.split('\\n');\n const result: React.ReactNode[] = [];\n let key = 0;\n let i = 0;\n\n while (i < lines.length) {\n const line = lines[i];\n\n // Check for headings (## or ###)\n const h2Match = line.match(/^##\\s+(.*)$/);\n if (h2Match) {\n result.push(\n <h2 key={`h2${key++}`} className=\"apteva-md-h2\">\n {parseInlineMarkdown(h2Match[1], `${key}`)}\n </h2>\n );\n i++;\n continue;\n }\n\n const h3Match = line.match(/^###\\s+(.*)$/);\n if (h3Match) {\n result.push(\n <h3 key={`h3${key++}`} className=\"apteva-md-h3\">\n {parseInlineMarkdown(h3Match[1], `${key}`)}\n </h3>\n );\n i++;\n continue;\n }\n\n // Check for unordered list item (-, *, +)\n const ulMatch = line.match(/^(\\s*)([-*+])\\s+(.*)$/);\n if (ulMatch) {\n const listItems: React.ReactNode[] = [];\n const indent = ulMatch[1].length;\n\n while (i < lines.length) {\n const itemMatch = lines[i].match(/^(\\s*)([-*+])\\s+(.*)$/);\n if (itemMatch && itemMatch[1].length === indent) {\n listItems.push(\n <li key={`li${key++}`} className=\"apteva-md-li\">{parseInlineMarkdown(itemMatch[3], `${key}`)}</li>\n );\n i++;\n } else {\n break;\n }\n }\n\n result.push(\n <ul key={`ul${key++}`} className=\"apteva-md-ul\">\n {listItems}\n </ul>\n );\n continue;\n }\n\n // Check for ordered list item (1., 2., etc.)\n const olMatch = line.match(/^(\\s*)(\\d+)\\.\\s+(.*)$/);\n if (olMatch) {\n const listItems: React.ReactNode[] = [];\n const indent = olMatch[1].length;\n\n while (i < lines.length) {\n const itemMatch = lines[i].match(/^(\\s*)(\\d+)\\.\\s+(.*)$/);\n if (itemMatch && itemMatch[1].length === indent) {\n listItems.push(\n <li key={`li${key++}`} className=\"apteva-md-li\">{parseInlineMarkdown(itemMatch[3], `${key}`)}</li>\n );\n i++;\n } else {\n break;\n }\n }\n\n result.push(\n <ol key={`ol${key++}`} className=\"apteva-md-ol\">\n {listItems}\n </ol>\n );\n continue;\n }\n\n // Regular line - parse inline markdown and preserve line breaks\n if (line === '') {\n result.push(<br key={`br${key++}`} />);\n } else {\n result.push(\n <span key={`p${key++}`}>\n {parseInlineMarkdown(line, `${key}`)}\n {i < lines.length - 1 ? '\\n' : ''}\n </span>\n );\n }\n i++;\n }\n\n return result;\n}\n\nexport function MarkdownContent({ content, className = '' }: MarkdownContentProps) {\n return (\n <div className={`apteva-md ${className}`}>\n {parseMarkdown(content)}\n </div>\n );\n}\n","interface ToolCallProps {\n name: string;\n status: 'running' | 'completed' | 'error';\n}\n\nexport function ToolCall({ name, status }: ToolCallProps) {\n return (\n <div className=\"apteva-tool-call\">\n {status === 'running' && (\n <div className=\"apteva-tool-call-dot apteva-tool-call-dot-running\" />\n )}\n {status === 'completed' && (\n <div className=\"apteva-tool-call-dot apteva-tool-call-dot-completed\" />\n )}\n {status === 'error' && (\n <div className=\"apteva-tool-call-dot apteva-tool-call-dot-error\" />\n )}\n <span className=\"apteva-tool-call-name\">\n {name}\n </span>\n {status === 'running' && (\n <span className=\"apteva-tool-call-status\">Running...</span>\n )}\n {status === 'completed' && (\n <span className=\"apteva-tool-call-status apteva-tool-call-status-completed\">Completed</span>\n )}\n {status === 'error' && (\n <span className=\"apteva-tool-call-status apteva-tool-call-status-error\">Error</span>\n )}\n </div>\n );\n}\n","// No direct imports needed 'react';\nimport { Message as MessageType } from '../../types/messages';\nimport { cn } from '../../utils';\nimport { Widgets } from '../Widgets';\nimport { ActionEvent } from '../../types/actions';\nimport { MarkdownContent } from './MarkdownContent';\nimport { ToolCall } from './ToolCall';\n\ntype ContentSegment =\n | { type: 'text'; content: string }\n | { type: 'tool'; id: string; name: string; result?: any };\n\ninterface MessageProps {\n message: MessageType;\n onAction?: (action: ActionEvent) => void;\n}\n\nexport function Message({ message, onAction }: MessageProps) {\n const isUser = message.role === 'user';\n const contentSegments = message.metadata?.content_segments as ContentSegment[] | undefined;\n\n // Render content with inline tool calls\n const renderContent = () => {\n if (isUser) {\n return <div className=\"whitespace-pre-wrap !text-sm leading-relaxed\">{message.content}</div>;\n }\n\n // If we have content segments, render them in order\n if (contentSegments && contentSegments.length > 0) {\n return (\n <div>\n {contentSegments.map((segment, index) => {\n if (segment.type === 'text') {\n return segment.content ? (\n <MarkdownContent key={`text-${index}`} content={segment.content} />\n ) : null;\n } else if (segment.type === 'tool') {\n return (\n <div key={segment.id} className=\"my-2\">\n <ToolCall\n name={segment.name}\n status={segment.result !== undefined ? 'completed' : 'running'}\n />\n </div>\n );\n }\n return null;\n })}\n </div>\n );\n }\n\n // Fallback to just content\n return <MarkdownContent content={message.content} />;\n };\n\n return (\n <div\n className={cn(\n 'max-w-[80%]',\n isUser\n ? 'px-4 py-2.5 rounded-xl bg-gray-100 dark:bg-gray-800 !text-gray-900 dark:!text-gray-100 ml-auto'\n : '!text-gray-900 dark:!text-gray-100'\n )}\n >\n {renderContent()}\n\n {message.widgets && message.widgets.length > 0 && (\n <div className={cn(isUser ? 'mt-3' : 'mt-2')}>\n <Widgets widgets={message.widgets} onAction={onAction} layout=\"stack\" />\n </div>\n )}\n\n <div className={cn('!text-xs opacity-70', isUser ? 'mt-1.5 !text-gray-500 dark:!text-gray-400' : 'mt-1 !text-gray-500 dark:!text-gray-400')} suppressHydrationWarning>\n {message.timestamp.toLocaleTimeString([], { hour: '2-digit', minute: '2-digit' })}\n </div>\n </div>\n );\n}\n","import { useState, KeyboardEvent, useRef } from 'react';\n\ninterface ComposerProps {\n onSendMessage: (text: string) => void;\n placeholder?: string;\n disabled?: boolean;\n onFileUpload?: (files: FileList) => void;\n}\n\nexport function Composer({ onSendMessage, placeholder = 'Type a message...', disabled = false, onFileUpload }: ComposerProps) {\n const [text, setText] = useState('');\n const [showMenu, setShowMenu] = useState(false);\n const textareaRef = useRef<HTMLTextAreaElement>(null);\n const fileInputRef = useRef<HTMLInputElement>(null);\n\n const handleKeyDown = (e: KeyboardEvent<HTMLTextAreaElement>) => {\n if (e.key === 'Enter' && !e.shiftKey) {\n e.preventDefault();\n handleSend();\n }\n };\n\n const handleSend = () => {\n if (text.trim() && !disabled) {\n onSendMessage(text.trim());\n setText('');\n // Reset textarea height\n if (textareaRef.current) {\n textareaRef.current.style.height = 'auto';\n }\n }\n };\n\n const handleChange = (e: React.ChangeEvent<HTMLTextAreaElement>) => {\n setText(e.target.value);\n // Auto-resize textarea\n e.target.style.height = 'auto';\n e.target.style.height = `${e.target.scrollHeight}px`;\n };\n\n const handleFileSelect = (e: React.ChangeEvent<HTMLInputElement>) => {\n if (e.target.files && e.target.files.length > 0) {\n onFileUpload?.(e.target.files);\n setShowMenu(false);\n }\n };\n\n return (\n <div className=\"px-4 py-3 bg-white dark:bg-gray-900 relative\">\n {/* Menu Popup */}\n {showMenu && (\n <>\n <div className=\"fixed inset-0 z-10\" onClick={() => setShowMenu(false)} />\n <div className=\"absolute bottom-full left-4 mb-2 bg-gray-800 dark:bg-gray-700 rounded-xl shadow-lg overflow-hidden z-20 min-w-[240px]\">\n <button\n onClick={() => fileInputRef.current?.click()}\n className=\"w-full flex items-center gap-3 px-4 py-3 hover:bg-gray-700 dark:hover:bg-gray-600 transition-colors !text-white text-left\"\n >\n <svg width=\"20\" height=\"20\" viewBox=\"0 0 20 20\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\n <path d=\"M10.5 3.5L5.5 8.5C4.67157 9.32843 4.67157 10.6716 5.5 11.5C6.32843 12.3284 7.67157 12.3284 8.5 11.5L14.5 5.5C15.8807 4.11929 15.8807 1.88071 14.5 0.5C13.1193 -0.880711 10.8807 -0.880711 9.5 0.5L3.5 6.5C1.56846 8.43154 1.56846 11.5685 3.5 13.5C5.43154 15.4315 8.56846 15.4315 10.5 13.5L15.5 8.5\" stroke=\"currentColor\" strokeWidth=\"1.5\" strokeLinecap=\"round\" strokeLinejoin=\"round\" transform=\"translate(2, 3)\"/>\n </svg>\n <span className=\"!text-sm font-medium\">Add photos & files</span>\n </button>\n </div>\n </>\n )}\n\n <div className=\"relative border-2 border-gray-300 dark:border-gray-700 rounded-xl bg-white dark:bg-gray-900 transition-all duration-300 flex items-center px-3 py-2 gap-3\">\n <button\n onClick={() => setShowMenu(!showMenu)}\n className=\"w-8 h-8 rounded-lg flex items-center justify-center transition-all flex-shrink-0 !text-gray-700 dark:!text-gray-300 hover:bg-gray-100 dark:hover:bg-gray-800\"\n title=\"More options\"\n >\n <svg width=\"20\" height=\"20\" viewBox=\"0 0 20 20\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\n <path d=\"M10 5v10M5 10h10\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\"/>\n </svg>\n </button>\n\n <textarea\n ref={textareaRef}\n value={text}\n onChange={handleChange}\n onKeyDown={handleKeyDown}\n placeholder={placeholder}\n disabled={disabled}\n className=\"flex-1 resize-none bg-transparent border-none focus:outline-none !text-gray-900 dark:!text-gray-100 placeholder-gray-400 dark:placeholder-gray-500 py-1 disabled:opacity-50 disabled:cursor-not-allowed\"\n rows={1}\n style={{ maxHeight: '120px' }}\n />\n\n <button\n onClick={handleSend}\n disabled={!text.trim() || disabled}\n className=\"w-8 h-8 rounded-lg flex items-center justify-center font-bold transition-all flex-shrink-0 border border-gray-300 dark:border-gray-600 bg-white dark:bg-gray-800 !text-gray-700 dark:!text-gray-300 hover:bg-gray-50 dark:hover:bg-gray-700 disabled:opacity-30 disabled:cursor-not-allowed !text-lg\"\n title=\"Send message\"\n >\n <svg width=\"16\" height=\"16\" viewBox=\"0 0 16 16\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\n <path d=\"M8 3L8 13M8 3L4 7M8 3L12 7\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\"/>\n </svg>\n </button>\n </div>\n\n {/* Hidden file input */}\n <input\n ref={fileInputRef}\n type=\"file\"\n multiple\n onChange={handleFileSelect}\n className=\"hidden\"\n accept=\"image/*,application/pdf,.doc,.docx,.txt\"\n />\n </div>\n );\n}\n","export interface AptevaClientConfig {\n apiUrl?: string;\n apiKey?: string;\n}\n\nexport interface ChatMessage {\n role: 'user' | 'assistant' | 'system';\n content: string;\n}\n\nexport interface ChatRequest {\n agent_id: string;\n message: string | Array<{\n type: 'text' | 'image' | 'document';\n text?: string;\n source?: {\n type: 'base64';\n media_type: string;\n data: string;\n };\n }>;\n thread_id?: string;\n stream?: boolean;\n system?: string;\n}\n\nexport interface ChatResponse {\n message: string;\n thread_id: string;\n widgets?: any[];\n}\n\nexport interface StreamChunk {\n type: 'start' | 'thread_id' | 'content' | 'token' | 'tool_call' | 'tool_input_delta' | 'tool_use' | 'tool_result' | 'stop' | 'widget' | 'complete' | 'done' | 'error';\n content?: string;\n widget?: any;\n thread_id?: string;\n tool_id?: string;\n tool_name?: string;\n error?: string;\n message?: string;\n}\n\n// Default configuration\nconst DEFAULT_API_URL = 'http://localhost:3000/agents';\nconst DEFAULT_API_KEY = 'agt_894abd5966bc9f1e9f8f17f2a6f6b5e0';\n\nclass AptevaClient {\n private config: Required<AptevaClientConfig>;\n\n constructor() {\n this.config = {\n apiUrl: DEFAULT_API_URL,\n apiKey: DEFAULT_API_KEY,\n };\n }\n\n /**\n * Update client configuration (optional - users can override defaults)\n */\n configure(config: AptevaClientConfig) {\n if (config.apiUrl) this.config.apiUrl = config.apiUrl;\n if (config.apiKey) this.config.apiKey = config.apiKey;\n }\n\n /**\n * Get current configuration\n */\n getConfig(): AptevaClientConfig {\n return { ...this.config };\n }\n\n /**\n * Send a chat message to an agent\n */\n async chat(request: ChatRequest): Promise<ChatResponse> {\n try {\n console.log('[AptevaClient] Chat request:', {\n agent_id: request.agent_id,\n message: typeof request.message === 'string' ? request.message.substring(0, 100) + '...' : '[multi-part message]',\n system: request.system,\n stream: request.stream,\n });\n\n const response = await fetch(`${this.config.apiUrl}/chat`, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n 'X-API-Key': this.config.apiKey,\n },\n body: JSON.stringify(request),\n });\n\n if (!response.ok) {\n const error = await response.json().catch(() => ({ error: 'Request failed' }));\n throw new Error(error.error || `Request failed with status ${response.status}`);\n }\n\n const data = await response.json();\n\n // Map API response format to expected format\n // API returns: { response, thread_id, success, model, trace_id }\n // We expect: { message, thread_id, widgets }\n return {\n message: data.response || data.message || '',\n thread_id: data.thread_id,\n widgets: data.widgets,\n };\n } catch (error) {\n console.error('Chat API error:', error);\n throw error;\n }\n }\n\n /**\n * Send a chat message with streaming response\n */\n async chatStream(\n request: ChatRequest,\n onChunk: (chunk: StreamChunk) => void,\n onComplete?: (threadId: string) => void,\n onError?: (error: Error) => void\n ): Promise<void> {\n try {\n console.log('[AptevaClient] Chat stream request:', {\n agent_id: request.agent_id,\n message: typeof request.message === 'string' ? request.message.substring(0, 100) + '...' : '[multi-part message]',\n system: request.system,\n stream: request.stream,\n });\n\n const response = await fetch(`${this.config.apiUrl}/chat`, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n 'X-API-Key': this.config.apiKey,\n 'Accept': 'text/event-stream',\n },\n body: JSON.stringify({\n ...request,\n stream: true,\n }),\n });\n\n if (!response.ok) {\n const error = await response.json().catch(() => ({ error: 'Request failed' }));\n throw new Error(error.error || `Request failed with status ${response.status}`);\n }\n\n const reader = response.body?.getReader();\n if (!reader) {\n throw new Error('Response body is not readable');\n }\n\n const decoder = new TextDecoder();\n let buffer = '';\n let threadId = '';\n\n while (true) {\n const { done, value } = await reader.read();\n if (done) break;\n\n buffer += decoder.decode(value, { stream: true });\n const lines = buffer.split('\\n');\n buffer = lines.pop() || '';\n\n for (const line of lines) {\n if (!line.trim() || line.startsWith(':')) continue;\n\n if (line.startsWith('data: ')) {\n const data = line.slice(6);\n\n if (data === '[DONE]') {\n onComplete?.(threadId);\n return;\n }\n\n try {\n const chunk = JSON.parse(data);\n\n // Store thread_id if present in chunk\n if (chunk.thread_id) {\n threadId = chunk.thread_id;\n }\n\n // Pass through ALL chunk types to the handler\n onChunk(chunk);\n\n } catch (e) {\n console.warn('[AptevaClient] Failed to parse SSE data:', data);\n }\n }\n }\n }\n\n onComplete?.(threadId);\n } catch (error) {\n const err = error instanceof Error ? error : new Error('Unknown error');\n onError?.(err);\n throw err;\n }\n }\n\n /**\n * Create a new thread\n */\n async createThread(agentId: string, metadata?: Record<string, any>): Promise<string> {\n const response = await fetch(`${this.config.apiUrl}/agents/${agentId}/threads`, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n 'X-API-Key': this.config.apiKey,\n },\n body: JSON.stringify({ metadata }),\n });\n\n if (!response.ok) {\n const error = await response.json().catch(() => ({ error: 'Request failed' }));\n throw new Error(error.error || `Request failed with status ${response.status}`);\n }\n\n const data = await response.json();\n return data.thread_id;\n }\n\n /**\n * Get thread messages\n */\n async getThreadMessages(threadId: string): Promise<ChatMessage[]> {\n const response = await fetch(`${this.config.apiUrl}/threads/${threadId}/messages`, {\n method: 'GET',\n headers: {\n 'X-API-Key': this.config.apiKey,\n },\n });\n\n if (!response.ok) {\n const error = await response.json().catch(() => ({ error: 'Request failed' }));\n throw new Error(error.error || `Request failed with status ${response.status}`);\n }\n\n const data = await response.json();\n return data.messages;\n }\n}\n\n// Export singleton instance\nexport const aptevaClient = new AptevaClient();\n\n// Export class for custom instances\nexport { AptevaClient };\n","import React, { useState, useEffect } from 'react';\nimport { CommandProps, CommandResult } from '../../types/components';\nimport { cn, generateMockCommandWithWidgets, generateMockCommandStream, generateMockPlan } from '../../utils';\nimport { aptevaClient } from '../../lib/apteva-client';\nimport { WidgetRenderer } from '../Widgets/WidgetRenderer';\n\nexport function Command({\n agentId,\n command: initialCommand,\n context,\n autoExecute = false,\n allowInput = true,\n placeholder = 'Enter your command...',\n submitButtonText = 'Execute',\n variant = 'default',\n useMock = false,\n planMode = false,\n onPlanModeChange,\n enableFileUpload = true,\n onStart,\n onProgress,\n onChunk,\n onComplete,\n onError,\n onFileUpload,\n onAction,\n loadingText = 'Processing...',\n showProgress = true,\n enableStreaming = false,\n resultRenderer,\n className,\n}: CommandProps) {\n const [state, setState] = useState<'idle' | 'loading' | 'success' | 'error' | 'plan-pending'>('idle');\n const [result, setResult] = useState<CommandResult | null>(null);\n const [error, setError] = useState<Error | null>(null);\n const [progress, setProgress] = useState(0);\n const [command, setCommand] = useState(initialCommand || '');\n const [streamedContent, setStreamedContent] = useState('');\n const [plan, setPlan] = useState<string>('');\n const [pendingCommand, setPendingCommand] = useState<string>('');\n const [showPlanDetails, setShowPlanDetails] = useState(false);\n const [uploadedFiles, setUploadedFiles] = useState<Array<{ type: 'image' | 'document'; data: string; mediaType: string; preview?: string; name: string }>>([]);\n const [showSettingsMenu, setShowSettingsMenu] = useState(false);\n const [internalPlanMode, setInternalPlanMode] = useState(planMode);\n const fileInputRef = React.useRef<HTMLInputElement>(null);\n\n useEffect(() => {\n if (autoExecute && state === 'idle' && command) {\n executeCommand();\n }\n }, [autoExecute]);\n\n // Sync internal plan mode with prop when prop changes\n useEffect(() => {\n setInternalPlanMode(planMode);\n }, [planMode]);\n\n // Close settings menu when clicking outside\n useEffect(() => {\n const handleClickOutside = (event: MouseEvent) => {\n const target = event.target as HTMLElement;\n if (showSettingsMenu && !target.closest('.settings-menu-container')) {\n setShowSettingsMenu(false);\n }\n };\n\n document.addEventListener('mousedown', handleClickOutside);\n return () => document.removeEventListener('mousedown', handleClickOutside);\n }, [showSettingsMenu]);\n\n const executeCommand = async (commandOverride?: string) => {\n const currentCommand = commandOverride || command;\n\n if (!currentCommand.trim()) {\n setError(new Error('Please enter a command'));\n setState('error');\n return;\n }\n\n // Plan mode: show plan first\n if (internalPlanMode && state !== 'plan-pending') {\n setState('loading');\n setError(null);\n setCommand(''); // Clear input\n\n // Generate plan (mock or real)\n if (useMock) {\n setTimeout(() => {\n const mockPlan = generateMockPlan(currentCommand);\n setPlan(mockPlan);\n setPendingCommand(currentCommand);\n setState('plan-pending');\n }, 800);\n } else {\n // Real API plan generation\n try {\n // Build message - multi-part if files are uploaded\n let messageContent: any;\n\n if (uploadedFiles.length > 0) {\n messageContent = [\n {\n type: 'text',\n text: currentCommand,\n },\n ...uploadedFiles.map(file => ({\n type: file.type,\n source: {\n type: 'base64',\n media_type: file.mediaType,\n data: file.data,\n },\n })),\n ];\n } else {\n messageContent = currentCommand;\n }\n\n // System instruction for planning only\n let systemMessage = context || '';\n const planningInstruction = `CRITICAL PLANNING MODE - READ CAREFULLY:\n\nYou are ONLY creating a plan. You are NOT executing anything.\n\nYOUR TASK: Write a numbered list of steps describing what WOULD be done.\nDO NOT: Execute any actions, make API calls, access databases, modify data, or perform any operations.\nDO NOT: Ask questions or clarifications. Make reasonable assumptions.\nDO: Describe the steps as \"Step 1: Would search database...\", \"Step 2: Would analyze results...\", etc.\nDO: Use default values or best practices if details are missing.\n\nFORMAT REQUIRED:\n1. [First action that would be taken]\n2. [Second action that would be taken]\n3. [Third action that would be taken]\n...\n\nIMPORTANT: This is COMMAND MODE - figure things out yourself. Make intelligent assumptions based on context. ONLY ask questions if something is absolutely impossible to proceed without (e.g., missing required credentials). Otherwise, use sensible defaults and proceed with the plan.\n\nREMEMBER: This is ONLY a plan. The user will approve it, THEN it will be executed. Right now you are just describing what would happen - NOT doing it.`;\n\n\n systemMessage = systemMessage\n ? `${systemMessage}\\n\\n${planningInstruction}`\n : planningInstruction;\n\n aptevaClient.chat({\n agent_id: agentId,\n message: messageContent,\n stream: false,\n system: systemMessage,\n }).then((response) => {\n setPlan(response.message);\n setPendingCommand(currentCommand);\n setState('plan-pending');\n }).catch((err) => {\n const error = err instanceof Error ? err : new Error('Failed to generate plan');\n setError(error);\n setState('error');\n onError?.(error);\n });\n } catch (err) {\n const error = err instanceof Error ? err : new Error('Failed to generate plan');\n setError(error);\n setState('error');\n onError?.(error);\n }\n }\n return;\n }\n\n setState('loading');\n setError(null);\n setProgress(0);\n setStreamedContent('');\n setCommand(''); // Clear input for next command\n setUploadedFiles([]); // Clear uploaded files after sending\n onStart?.();\n\n try {\n if (useMock) {\n // MOCK MODE\n if (enableStreaming) {\n // Mock streaming\n let accumulatedContent = '';\n\n generateMockCommandStream(\n currentCommand,\n (chunk) => {\n if (chunk.type === 'token' && chunk.content) {\n accumulatedContent += chunk.content;\n setStreamedContent(accumulatedContent);\n onChunk?.(chunk.content);\n\n // Estimate progress based on content length\n const estimatedProgress = Math.min(Math.round(accumulatedContent.length / 10), 90);\n setProgress(estimatedProgress);\n onProgress?.(estimatedProgress);\n } else if (chunk.type === 'widget' && chunk.widget) {\n // Handle widgets in streamed response\n const widget = chunk.widget;\n setResult((prev) => ({\n success: true,\n data: prev?.data || {},\n widgets: [...(prev?.widgets || []), widget],\n message: accumulatedContent || 'Command executed successfully',\n }));\n }\n },\n (threadId) => {\n // On complete\n const result: CommandResult = {\n success: true,\n data: {\n summary: accumulatedContent,\n thread_id: threadId,\n agentId,\n context,\n timestamp: new Date().toISOString(),\n },\n message: accumulatedContent || 'Command executed successfully',\n };\n\n setResult(result);\n setState('success');\n setProgress(100);\n onComplete?.(result);\n },\n (error) => {\n // On error\n setError(error);\n setState('error');\n onError?.(error);\n }\n );\n } else {\n // Mock non-streaming\n const progressInterval = setInterval(() => {\n setProgress((prev) => {\n const next = Math.min(prev + 10, 90);\n onProgress?.(next);\n return next;\n });\n }, 200);\n\n // Simulate network delay\n await new Promise(resolve => setTimeout(resolve, 1500));\n\n clearInterval(progressInterval);\n\n const mockResponse = generateMockCommandWithWidgets(currentCommand);\n\n const result: CommandResult = {\n success: true,\n data: {\n summary: mockResponse.message,\n thread_id: `mock_thread_${Date.now()}`,\n agentId,\n context,\n timestamp: new Date().toISOString(),\n action: mockResponse.action, // Include agent action intent\n },\n widgets: mockResponse.widgets,\n message: mockResponse.message,\n };\n\n setResult(result);\n setState('success');\n setProgress(100);\n onComplete?.(result);\n }\n } else {\n // REAL API MODE\n if (enableStreaming) {\n // Real streaming API call\n let accumulatedContent = '';\n\n // Build message - multi-part if files are uploaded\n let messageContent: any;\n\n if (uploadedFiles.length > 0) {\n // Multi-part message with text and images\n messageContent = [\n {\n type: 'text',\n text: currentCommand,\n },\n ...uploadedFiles.map(file => ({\n type: file.type, // 'image' or 'document'\n source: {\n type: 'base64',\n media_type: file.mediaType,\n data: file.data,\n },\n })),\n ];\n } else {\n // Simple text message\n messageContent = currentCommand;\n }\n\n // Build system message - add command execution instruction\n let systemMessage = context || '';\n\n // Always include command mode instruction for brevity\n let commandInstruction: string;\n if (isCompact) {\n // Compact mode - extremely terse\n commandInstruction = 'CRITICAL COMMAND MODE: Maximum 10 words per response. Execute immediately, make intelligent assumptions, use defaults when needed. NO questions unless absolutely critical (missing required credentials). State action or result ONLY. Examples: \"Searching database for matching records...\" or \"Found 3 user records in database\" or \"Task completed successfully\". NO greetings, NO explanations, NO clarification requests. Just execute and report.';\n } else {\n // Default mode - still very brief\n commandInstruction = 'CRITICAL COMMAND MODE: Maximum 10 words per response. Execute the command immediately. Make reasonable assumptions based on context. Use sensible defaults for missing details. DO NOT ask questions unless something is truly impossible without user input (e.g., missing required password). State what you\\'re doing or the result. Examples: \"Analyzing customer data from last quarter...\" or \"Created 5 new database entries successfully\" or \"Search complete: found 12 matching results\". NO greetings, NO filler words, NO clarification requests. Action/result only.';\n }\n\n systemMessage = systemMessage\n ? `${systemMessage}\\n\\n${commandInstruction}`\n : commandInstruction;\n\n await aptevaClient.chatStream(\n {\n agent_id: agentId,\n message: messageContent,\n stream: true,\n ...(systemMessage && { system: systemMessage }),\n },\n (chunk) => {\n if (chunk.type === 'token' && chunk.content) {\n accumulatedContent += chunk.content;\n setStreamedContent(accumulatedContent);\n onChunk?.(chunk.content);\n\n // Estimate progress based on content length (rough approximation)\n const estimatedProgress = Math.min(Math.round(accumulatedContent.length / 10), 90);\n setProgress(estimatedProgress);\n onProgress?.(estimatedProgress);\n } else if (chunk.type === 'widget' && chunk.widget) {\n // Handle widgets in streamed response\n const widget = chunk.widget;\n setResult((prev) => ({\n success: true,\n data: prev?.data || {},\n widgets: [...(prev?.widgets || []), widget],\n message: accumulatedContent || 'Command executed successfully',\n }));\n }\n },\n (threadId) => {\n // On complete\n const result: CommandResult = {\n success: true,\n data: {\n summary: accumulatedContent,\n thread_id: threadId,\n agentId,\n context,\n timestamp: new Date().toISOString(),\n },\n message: accumulatedContent || 'Command executed successfully',\n };\n\n setResult(result);\n setState('success');\n setProgress(100);\n onComplete?.(result);\n },\n (error) => {\n // On error\n const err = error instanceof Error ? error : new Error('Unknown error');\n setError(err);\n setState('error');\n onError?.(err);\n }\n );\n } else {\n // Non-streaming API call\n const progressInterval = setInterval(() => {\n setProgress((prev) => {\n const next = Math.min(prev + 10, 90);\n onProgress?.(next);\n return next;\n });\n }, 200);\n\n // Build message - multi-part if files are uploaded\n let messageContent: any;\n\n if (uploadedFiles.length > 0) {\n // Multi-part message with text and images\n messageContent = [\n {\n type: 'text',\n text: currentCommand,\n },\n ...uploadedFiles.map(file => ({\n type: file.type, // 'image' or 'document'\n source: {\n type: 'base64',\n media_type: file.mediaType,\n data: file.data,\n },\n })),\n ];\n } else {\n // Simple text message\n messageContent = currentCommand;\n }\n\n // Build system message - add command execution instruction\n let systemMessage = context || '';\n\n // Always include command mode instruction for brevity\n let commandInstruction: string;\n if (isCompact) {\n // Compact mode - extremely terse\n commandInstruction = 'CRITICAL COMMAND MODE: Maximum 10 words per response. Execute immediately, make intelligent assumptions, use defaults when needed. NO questions unless absolutely critical (missing required credentials). State action or result ONLY. Examples: \"Searching database for matching records...\" or \"Found 3 user records in database\" or \"Task completed successfully\". NO greetings, NO explanations, NO clarification requests. Just execute and report.';\n } else {\n // Default mode - still very brief\n commandInstruction = 'CRITICAL COMMAND MODE: Maximum 10 words per response. Execute the command immediately. Make reasonable assumptions based on context. Use sensible defaults for missing details. DO NOT ask questions unless something is truly impossible without user input (e.g., missing required password). State what you\\'re doing or the result. Examples: \"Analyzing customer data from last quarter...\" or \"Created 5 new database entries successfully\" or \"Search complete: found 12 matching results\". NO greetings, NO filler words, NO clarification requests. Action/result only.';\n }\n\n systemMessage = systemMessage\n ? `${systemMessage}\\n\\n${commandInstruction}`\n : commandInstruction;\n\n const response = await aptevaClient.chat({\n agent_id: agentId,\n message: messageContent,\n stream: false,\n ...(systemMessage && { system: systemMessage }),\n });\n\n clearInterval(progressInterval);\n\n const result: CommandResult = {\n success: true,\n data: {\n summary: response.message,\n thread_id: response.thread_id,\n agentId,\n context,\n timestamp: new Date().toISOString(),\n },\n widgets: response.widgets,\n message: response.message,\n };\n\n setResult(result);\n setState('success');\n setProgress(100);\n onComplete?.(result);\n }\n }\n } catch (err) {\n const error = err instanceof Error ? err : new Error('Unknown error');\n setError(error);\n setState('error');\n onError?.(error);\n }\n };\n\n const resetCommand = () => {\n setState('idle');\n setResult(null);\n setError(null);\n setProgress(0);\n setCommand('');\n setPlan('');\n setPendingCommand('');\n setShowPlanDetails(false);\n setUploadedFiles([]);\n };\n\n const approvePlan = () => {\n // Execute the plan after approval\n // Send the plan to the agent with \"execute this now\" instruction\n setShowPlanDetails(false);\n const planToExecute = plan;\n setPlan('');\n setPendingCommand('');\n\n // Execute with the plan as the command\n const executionMessage = `Execute this plan now:\\n\\n${planToExecute}`;\n executeCommand(executionMessage);\n };\n\n const rejectPlan = () => {\n // Reset to idle and restore the command for editing\n setCommand(pendingCommand);\n setPlan('');\n setPendingCommand('');\n setShowPlanDetails(false);\n setState('idle');\n };\n\n const handleFileSelect = async (e: React.ChangeEvent<HTMLInputElement>) => {\n if (e.target.files && e.target.files.length > 0) {\n onFileUpload?.(e.target.files);\n\n // Convert files to base64 for API\n const files: Array<{ type: 'image' | 'document'; data: string; mediaType: string; preview?: string; name: string }> = [];\n\n for (let i = 0; i < e.target.files.length; i++) {\n const file = e.target.files[i];\n\n const reader = new FileReader();\n\n await new Promise<void>((resolve) => {\n reader.onload = (event) => {\n if (event.target?.result) {\n const fullDataUrl = event.target.result as string;\n const base64Data = fullDataUrl.split(',')[1]; // Remove data:...;base64, prefix\n\n if (file.type.startsWith('image/')) {\n // Images with preview\n files.push({\n type: 'image',\n data: base64Data,\n mediaType: file.type,\n preview: fullDataUrl, // Keep full data URL for preview\n name: file.name,\n });\n } else if (file.type === 'application/pdf' || file.type.startsWith('application/')) {\n // Documents (PDF, etc.) without preview\n files.push({\n type: 'document',\n data: base64Data,\n mediaType: file.type,\n name: file.name,\n });\n }\n }\n resolve();\n };\n reader.readAsDataURL(file);\n });\n }\n\n setUploadedFiles(prev => [...prev, ...files]); // Append to existing files\n }\n };\n\n const removeFile = (index: number) => {\n setUploadedFiles(prev => prev.filter((_, i) => i !== index));\n };\n\n const isCompact = variant === 'compact';\n\n return (\n <div\n className={cn(\n 'relative border-2 rounded-xl bg-white dark:bg-gray-900 transition-all duration-300 flex flex-col',\n state === 'loading' && 'animate-pulse-border',\n state === 'idle' && 'border-gray-300 dark:border-gray-700',\n state === 'loading' && 'border-blue-500',\n state === 'plan-pending' && 'border-blue-400',\n state === 'success' && 'border-green-500',\n state === 'error' && 'border-red-500',\n className\n )}\n style={{ minHeight: isCompact ? 'auto' : '180px' }}\n >\n {/* Input/Display Area */}\n <div className={cn('flex-1 flex', isCompact ? 'flex-row items-center p-3 gap-3' : 'flex-col p-4')}>\n {state === 'idle' && allowInput && !isCompact && (\n <>\n <textarea\n value={command}\n onChange={(e) => setCommand(e.target.value)}\n onKeyDown={(e) => {\n if (e.key === 'Enter' && (e.metaKey || e.ctrlKey)) {\n e.preventDefault();\n executeCommand();\n }\n }}\n placeholder={placeholder}\n className=\"flex-1 w-full resize-none bg-transparent border-none focus:outline-none !text-gray-900 dark:!text-gray-100 placeholder-gray-400 dark:placeholder-gray-500\"\n rows={6}\n />\n {/* File Previews - Non-Compact */}\n {uploadedFiles.length > 0 && (\n <div className=\"flex flex-wrap gap-2 mt-2\">\n {uploadedFiles.map((file, index) => (\n <div key={index} className=\"relative group\">\n {file.type === 'image' ? (\n <img\n src={file.preview}\n alt={file.name}\n className=\"w-20 h-20 object-cover rounded-lg border-2 border-gray-300 dark:border-gray-600\"\n />\n ) : (\n <div className=\"w-20 h-20 flex flex-col items-center justify-center rounded-lg border-2 border-gray-300 dark:border-gray-600 bg-gray-50 dark:bg-gray-800\">\n <svg className=\"w-8 h-8 text-gray-500 dark:text-gray-400\" fill=\"currentColor\" viewBox=\"0 0 20 20\">\n <path fillRule=\"evenodd\" d=\"M4 4a2 2 0 012-2h4.586A2 2 0 0112 2.586L15.414 6A2 2 0 0116 7.414V16a2 2 0 01-2 2H6a2 2 0 01-2-2V4zm2 6a1 1 0 011-1h6a1 1 0 110 2H7a1 1 0 01-1-1zm1 3a1 1 0 100 2h6a1 1 0 100-2H7z\" clipRule=\"evenodd\" />\n </svg>\n <span className=\"text-[8px] text-gray-500 dark:text-gray-400 mt-1 px-1 truncate max-w-full\">\n {file.name.length > 12 ? file.name.slice(0, 12) + '...' : file.name}\n </span>\n </div>\n )}\n <button\n onClick={() => removeFile(index)}\n className=\"absolute -top-2 -right-2 w-6 h-6 bg-red-500 hover:bg-red-600 text-white rounded-full flex items-center justify-center opacity-0 group-hover:opacity-100 transition-opacity\"\n title={`Remove ${file.type}`}\n >\n <svg className=\"w-4 h-4\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\">\n <path strokeLinecap=\"round\" strokeLinejoin=\"round\" strokeWidth={2} d=\"M6 18L18 6M6 6l12 12\" />\n </svg>\n </button>\n </div>\n ))}\n </div>\n )}\n </>\n )}\n\n {state === 'idle' && allowInput && isCompact && (\n <>\n <div className=\"flex items-center gap-0.5 flex-shrink-0\">\n {enableFileUpload && (\n <button\n onClick={() => fileInputRef.current?.click()}\n className=\"w-8 h-8 rounded-lg flex items-center justify-center transition-all flex-shrink-0 !text-gray-500 dark:!text-gray-500 hover:bg-gray-100 dark:hover:bg-gray-800\"\n title=\"Attach file\"\n >\n <svg width=\"16\" height=\"16\" viewBox=\"0 0 16 16\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\n <path d=\"M8.4 2.8L4.4 6.8C3.736 7.464 3.736 8.536 4.4 9.2C5.064 9.864 6.136 9.864 6.8 9.2L11.6 4.4C12.704 3.296 12.704 1.504 11.6 0.4C10.496 -0.704 8.704 -0.704 7.6 0.4L2.8 5.2C1.256 6.744 1.256 9.256 2.8 10.8C4.344 12.344 6.856 12.344 8.4 10.8L12.4 6.8\" stroke=\"currentColor\" strokeWidth=\"1.2\" strokeLinecap=\"round\" strokeLinejoin=\"round\" transform=\"translate(1.6, 2.4)\"/>\n </svg>\n </button>\n )}\n {planMode && (\n <div className=\"relative settings-menu-container\">\n <button\n onClick={() => setShowSettingsMenu(!showSettingsMenu)}\n className={cn(\n \"w-8 h-8 rounded-lg flex items-center justify-center transition-all flex-shrink-0 hover:bg-gray-100 dark:hover:bg-gray-800\",\n internalPlanMode ? \"!text-blue-600 dark:!text-blue-400\" : \"!text-gray-500 dark:!text-gray-500\"\n )}\n title=\"Settings\"\n >\n <svg width=\"14\" height=\"14\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\">\n <line x1=\"4\" y1=\"21\" x2=\"4\" y2=\"14\"></line>\n <line x1=\"4\" y1=\"10\" x2=\"4\" y2=\"3\"></line>\n <line x1=\"12\" y1=\"21\" x2=\"12\" y2=\"12\"></line>\n <line x1=\"12\" y1=\"8\" x2=\"12\" y2=\"3\"></line>\n <line x1=\"20\" y1=\"21\" x2=\"20\" y2=\"16\"></line>\n <line x1=\"20\" y1=\"12\" x2=\"20\" y2=\"3\"></line>\n <line x1=\"1\" y1=\"14\" x2=\"7\" y2=\"14\"></line>\n <line x1=\"9\" y1=\"8\" x2=\"15\" y2=\"8\"></line>\n <line x1=\"17\" y1=\"16\" x2=\"23\" y2=\"16\"></line>\n </svg>\n </button>\n {showSettingsMenu && (\n <div className=\"absolute top-10 left-0 z-50 w-56 bg-white dark:bg-gray-800 border border-gray-200 dark:border-gray-700 rounded-lg shadow-lg p-2.5 settings-menu-container\">\n <label className=\"flex items-center justify-between cursor-pointer group\">\n <div className=\"flex items-center gap-2\">\n <svg className=\"w-3.5 h-3.5 text-gray-500 dark:text-gray-400\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\">\n <path strokeLinecap=\"round\" strokeLinejoin=\"round\" strokeWidth={2} d=\"M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-3 7h3m-3 4h3m-6-4h.01M9 16h.01\" />\n </svg>\n <div>\n <div className=\"text-xs font-medium text-gray-700 dark:text-gray-300\">Plan Mode</div>\n <div className=\"text-[10px] text-gray-500 dark:text-gray-400\">Review first</div>\n </div>\n </div>\n <button\n onClick={(e) => {\n e.stopPropagation();\n setInternalPlanMode(!internalPlanMode);\n }}\n className={cn(\n \"relative inline-flex h-4 w-8 items-center rounded-full transition-colors\",\n internalPlanMode ? \"bg-blue-600\" : \"bg-gray-300 dark:bg-gray-600\"\n )}\n type=\"button\"\n >\n <span\n className={cn(\n \"inline-block h-3 w-3 transform rounded-full bg-white transition-transform\",\n internalPlanMode ? \"translate-x-4.5\" : \"translate-x-0.5\"\n )}\n />\n </button>\n </label>\n </div>\n )}\n </div>\n )}\n </div>\n {/* File Previews - Compact */}\n {uploadedFiles.length > 0 && (\n <div className=\"flex gap-1 flex-shrink-0\">\n {uploadedFiles.map((file, index) => (\n <div key={index} className=\"relative group\">\n {file.type === 'image' ? (\n <img\n src={file.preview}\n alt={file.name}\n className=\"w-8 h-8 object-cover rounded border border-gray-300 dark:border-gray-600\"\n />\n ) : (\n <div className=\"w-8 h-8 flex items-center justify-center rounded border border-gray-300 dark:border-gray-600 bg-gray-50 dark:bg-gray-800\" title={file.name}>\n <svg className=\"w-4 h-4 text-gray-500 dark:text-gray-400\" fill=\"currentColor\" viewBox=\"0 0 20 20\">\n <path fillRule=\"evenodd\" d=\"M4 4a2 2 0 012-2h4.586A2 2 0 0112 2.586L15.414 6A2 2 0 0116 7.414V16a2 2 0 01-2 2H6a2 2 0 01-2-2V4zm2 6a1 1 0 011-1h6a1 1 0 110 2H7a1 1 0 01-1-1zm1 3a1 1 0 100 2h6a1 1 0 100-2H7z\" clipRule=\"evenodd\" />\n </svg>\n </div>\n )}\n <button\n onClick={() => removeFile(index)}\n className=\"absolute -top-1 -right-1 w-4 h-4 bg-red-500 hover:bg-red-600 text-white rounded-full flex items-center justify-center opacity-0 group-hover:opacity-100 transition-opacity\"\n title=\"Remove\"\n >\n <svg className=\"w-2.5 h-2.5\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\" strokeWidth={3}>\n <path strokeLinecap=\"round\" strokeLinejoin=\"round\" d=\"M6 18L18 6M6 6l12 12\" />\n </svg>\n </button>\n </div>\n ))}\n </div>\n )}\n <input\n type=\"text\"\n value={command}\n onChange={(e) => setCommand(e.target.value)}\n onKeyDown={(e) => {\n if (e.key === 'Enter') {\n e.preventDefault();\n executeCommand();\n }\n }}\n placeholder={placeholder}\n className=\"flex-1 bg-transparent border-none focus:outline-none !text-gray-900 dark:!text-gray-100 placeholder-gray-400 dark:placeholder-gray-500 py-1\"\n />\n <button\n onClick={() => executeCommand()}\n disabled={!command.trim()}\n className={cn(\n 'w-8 h-8 rounded-lg flex items-center justify-center font-bold transition-all flex-shrink-0',\n 'border border-gray-300 dark:border-gray-600',\n 'bg-white dark:bg-gray-800',\n '!text-gray-700 dark:!text-gray-300',\n 'hover:bg-gray-50 dark:hover:bg-gray-700',\n 'disabled:opacity-30 disabled:cursor-not-allowed',\n '!text-lg',\n !command.trim() && 'border-gray-200 dark:border-gray-700 !text-gray-400 dark:!text-gray-600'\n )}\n title=\"Execute\"\n >\n <svg width=\"16\" height=\"16\" viewBox=\"0 0 16 16\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\n <path d=\"M8 3L8 13M8 3L4 7M8 3L12 7\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\"/>\n </svg>\n </button>\n </>\n )}\n\n {state === 'loading' && !isCompact && (\n <div className=\"flex-1 flex flex-col items-center justify-center space-y-4 py-8\">\n <div className=\"w-6 h-6 border-2 border-gray-300 border-t-blue-500 rounded-full animate-spin\"></div>\n <div className=\"text-gray-600 dark:text-gray-400 text-sm text-center max-w-md\">\n {enableStreaming && streamedContent ? streamedContent : loadingText}\n </div>\n {showProgress && (\n <div className=\"w-full max-w-sm\">\n <div className=\"w-full bg-gray-200 dark:bg-gray-700 rounded-full h-1.5\">\n <div\n className=\"bg-blue-500 h-1.5 rounded-full transition-all duration-300\"\n style={{ width: `${progress}%` }}\n />\n </div>\n <p className=\"text-xs text-gray-500 mt-2 text-center\">{progress}%</p>\n </div>\n )}\n </div>\n )}\n\n {state === 'loading' && isCompact && (\n <>\n <div className=\"flex-1 flex items-center gap-3 py-1\">\n <div className=\"w-4 h-4 border-2 border-gray-300 border-t-blue-500 rounded-full animate-spin\"></div>\n <div className=\"text-gray-600 dark:text-gray-400 text-sm truncate\">\n {enableStreaming && streamedContent ? streamedContent : loadingText}\n </div>\n </div>\n <button\n disabled\n className={cn(\n 'w-8 h-8 rounded-lg flex items-center justify-center font-bold transition-all flex-shrink-0',\n 'border border-gray-200 dark:border-gray-700',\n 'bg-white dark:bg-gray-800',\n '!text-gray-400 dark:!text-gray-600',\n '!text-lg',\n 'opacity-30 cursor-not-allowed'\n )}\n >\n <svg width=\"16\" height=\"16\" viewBox=\"0 0 16 16\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\n <path d=\"M8 3L8 13M8 3L4 7M8 3L12 7\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\"/>\n </svg>\n </button>\n </>\n )}\n\n {state === 'plan-pending' && !isCompact && (\n <div className=\"flex-1 flex flex-col\">\n <div className=\"mb-4 p-4 bg-blue-50 dark:bg-blue-900/20 border border-blue-200 dark:border-blue-800 rounded-lg\">\n <div className=\"flex items-start gap-2 mb-3\">\n <svg className=\"w-5 h-5 text-blue-600 dark:text-blue-400 mt-0.5 flex-shrink-0\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\">\n <path strokeLinecap=\"round\" strokeLinejoin=\"round\" strokeWidth={2} d=\"M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-3 7h3m-3 4h3m-6-4h.01M9 16h.01\" />\n </svg>\n <div className=\"flex-1\">\n <h3 className=\"text-sm font-semibold text-blue-800 dark:text-blue-300 mb-1\">Proposed Plan</h3>\n <div className=\"text-blue-700 dark:text-blue-300 text-sm whitespace-pre-line leading-relaxed\">\n {plan}\n </div>\n </div>\n </div>\n <div className=\"flex gap-2 mt-4\">\n <button\n onClick={approvePlan}\n className=\"flex-1 px-4 py-2 bg-blue-600 text-white rounded-lg hover:bg-blue-700 transition-colors text-sm font-medium\"\n >\n Approve & Execute\n </button>\n <button\n onClick={rejectPlan}\n className=\"flex-1 px-4 py-2 bg-gray-200 dark:bg-gray-700 text-gray-700 dark:text-gray-300 rounded-lg hover:bg-gray-300 dark:hover:bg-gray-600 transition-colors text-sm font-medium\"\n >\n Modify\n </button>\n </div>\n </div>\n </div>\n )}\n\n {state === 'plan-pending' && isCompact && (\n <>\n <button\n onClick={() => setShowPlanDetails(true)}\n className=\"flex-1 flex items-center gap-2 px-3 py-2 bg-blue-50 dark:bg-blue-900/30 hover:bg-blue-100 dark:hover:bg-blue-900/40 border border-blue-200 dark:border-blue-800 rounded-lg transition-colors\"\n >\n <svg className=\"w-4 h-4 text-blue-600 dark:text-blue-400 flex-shrink-0\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\">\n <path strokeLinecap=\"round\" strokeLinejoin=\"round\" strokeWidth={2} d=\"M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-3 7h3m-3 4h3m-6-4h.01M9 16h.01\" />\n </svg>\n <span className=\"text-sm font-medium text-blue-700 dark:text-blue-300 truncate flex-1\">View Execution Plan</span>\n </button>\n <div className=\"flex gap-2 flex-shrink-0\">\n <button\n onClick={approvePlan}\n className=\"px-3 py-1.5 bg-blue-600 text-white rounded-lg hover:bg-blue-700 transition-colors text-xs font-medium\"\n >\n Approve\n </button>\n <button\n onClick={rejectPlan}\n className=\"px-3 py-1.5 bg-gray-200 dark:bg-gray-700 text-gray-700 dark:text-gray-300 rounded-lg hover:bg-gray-300 dark:hover:bg-gray-600 transition-colors text-xs font-medium\"\n >\n Modify\n </button>\n </div>\n </>\n )}\n\n {state === 'error' && (\n <div className=\"flex-1 flex flex-col\">\n <div className=\"mb-4 p-3 bg-red-50 dark:bg-red-900/20 border border-red-200 dark:border-red-800 rounded-lg\">\n <div className=\"flex items-start gap-2\">\n <svg className=\"w-5 h-5 text-red-600 mt-0.5 flex-shrink-0\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\">\n <path strokeLinecap=\"round\" strokeLinejoin=\"round\" strokeWidth={2} d=\"M12 8v4m0 4h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z\" />\n </svg>\n <div>\n <h3 className=\"text-sm font-semibold text-red-800 dark:text-red-400\">Error</h3>\n <p className=\"text-red-700 dark:text-red-300 text-sm mt-1\">{error?.message}</p>\n </div>\n </div>\n </div>\n {allowInput && (\n <textarea\n value={command}\n onChange={(e) => setCommand(e.target.value)}\n onKeyDown={(e) => {\n if (e.key === 'Enter' && (e.metaKey || e.ctrlKey)) {\n e.preventDefault();\n executeCommand();\n }\n }}\n placeholder={placeholder}\n className=\"flex-1 w-full resize-none bg-transparent border-none focus:outline-none text-gray-900 dark:text-white placeholder-gray-400\"\n rows={4}\n />\n )}\n </div>\n )}\n\n {state === 'success' && result && !isCompact && (\n <div className=\"flex-1 overflow-auto\">\n {resultRenderer ? (\n resultRenderer(result.data)\n ) : (\n <div className=\"space-y-4\">\n <div className=\"flex items-start gap-3 p-3 bg-green-50 dark:bg-green-900/20 border border-green-200 dark:border-green-800 rounded-lg\">\n <svg className=\"w-5 h-5 text-green-600 mt-0.5 flex-shrink-0\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\">\n <path strokeLinecap=\"round\" strokeLinejoin=\"round\" strokeWidth={2} d=\"M9 12l2 2 4-4m6 2a9 9 0 11-18 0 9 9 0 0118 0z\" />\n </svg>\n <div className=\"flex-1\">\n <h3 className=\"text-sm font-semibold text-green-800 dark:text-green-400 mb-1\">Success</h3>\n <p className=\"text-green-700 dark:text-green-300 text-sm\">Command executed successfully</p>\n </div>\n </div>\n {result.data?.summary && (\n <div className=\"text-gray-700 dark:text-gray-300 text-sm leading-relaxed whitespace-pre-line\">\n {result.data.summary}\n </div>\n )}\n {result.widgets && result.widgets.length > 0 && (\n <div className=\"space-y-3\">\n {result.widgets.map((widget) => (\n <WidgetRenderer\n key={widget.id}\n widget={widget}\n onAction={onAction}\n />\n ))}\n </div>\n )}\n </div>\n )}\n </div>\n )}\n\n {state === 'success' && result && isCompact && (\n <>\n <div\n className=\"flex-1 flex items-center gap-2 py-1 cursor-text min-w-0\"\n onClick={() => {\n setState('idle');\n setResult(null);\n }}\n >\n <svg className=\"w-4 h-4 text-green-600 flex-shrink-0\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\">\n <path strokeLinecap=\"round\" strokeLinejoin=\"round\" strokeWidth={2} d=\"M9 12l2 2 4-4m6 2a9 9 0 11-18 0 9 9 0 0118 0z\" />\n </svg>\n <div className=\"text-green-700 dark:text-green-300 text-sm truncate flex-1 min-w-0\">\n {resultRenderer ? resultRenderer(result.data) : (result.message || 'Command executed successfully')}\n </div>\n </div>\n <button\n onClick={() => {\n setState('idle');\n setResult(null);\n }}\n className={cn(\n 'w-8 h-8 rounded-lg flex items-center justify-center font-bold transition-all flex-shrink-0',\n 'border border-gray-300 dark:border-gray-600',\n 'bg-white dark:bg-gray-800',\n '!text-gray-700 dark:!text-gray-300',\n 'hover:bg-gray-50 dark:hover:bg-gray-700',\n '!text-lg'\n )}\n title=\"New command\"\n >\n <svg width=\"16\" height=\"16\" viewBox=\"0 0 16 16\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\n <path d=\"M8 3L8 13M8 3L4 7M8 3L12 7\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\"/>\n </svg>\n </button>\n </>\n )}\n </div>\n\n {/* Bottom Action Bar - Only show for default variant when not in compact mode */}\n {!isCompact && (\n <div className=\"p-3 flex items-center justify-between gap-2\">\n {/* Left side - Attachment and Settings buttons */}\n <div className=\"flex items-center gap-1\">\n {state === 'idle' && allowInput && (\n <>\n {enableFileUpload && (\n <button\n onClick={() => fileInputRef.current?.click()}\n className=\"w-8 h-8 rounded-lg flex items-center justify-center transition-all flex-shrink-0 !text-gray-500 dark:!text-gray-500 hover:bg-gray-100 dark:hover:bg-gray-800\"\n title=\"Attach file\"\n >\n <svg width=\"16\" height=\"16\" viewBox=\"0 0 16 16\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\n <path d=\"M8.4 2.8L4.4 6.8C3.736 7.464 3.736 8.536 4.4 9.2C5.064 9.864 6.136 9.864 6.8 9.2L11.6 4.4C12.704 3.296 12.704 1.504 11.6 0.4C10.496 -0.704 8.704 -0.704 7.6 0.4L2.8 5.2C1.256 6.744 1.256 9.256 2.8 10.8C4.344 12.344 6.856 12.344 8.4 10.8L12.4 6.8\" stroke=\"currentColor\" strokeWidth=\"1.2\" strokeLinecap=\"round\" strokeLinejoin=\"round\" transform=\"translate(1.6, 2.4)\"/>\n </svg>\n </button>\n )}\n {planMode && (\n <div className=\"relative settings-menu-container\">\n <button\n onClick={() => setShowSettingsMenu(!showSettingsMenu)}\n className={cn(\n \"w-8 h-8 rounded-lg flex items-center justify-center transition-all flex-shrink-0 hover:bg-gray-100 dark:hover:bg-gray-800\",\n internalPlanMode ? \"!text-blue-600 dark:!text-blue-400\" : \"!text-gray-500 dark:!text-gray-500\"\n )}\n title=\"Settings\"\n >\n <svg width=\"16\" height=\"16\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\">\n <line x1=\"4\" y1=\"21\" x2=\"4\" y2=\"14\"></line>\n <line x1=\"4\" y1=\"10\" x2=\"4\" y2=\"3\"></line>\n <line x1=\"12\" y1=\"21\" x2=\"12\" y2=\"12\"></line>\n <line x1=\"12\" y1=\"8\" x2=\"12\" y2=\"3\"></line>\n <line x1=\"20\" y1=\"21\" x2=\"20\" y2=\"16\"></line>\n <line x1=\"20\" y1=\"12\" x2=\"20\" y2=\"3\"></line>\n <line x1=\"1\" y1=\"14\" x2=\"7\" y2=\"14\"></line>\n <line x1=\"9\" y1=\"8\" x2=\"15\" y2=\"8\"></line>\n <line x1=\"17\" y1=\"16\" x2=\"23\" y2=\"16\"></line>\n </svg>\n </button>\n {showSettingsMenu && (\n <div className=\"absolute top-10 left-0 z-50 w-64 bg-white dark:bg-gray-800 border border-gray-200 dark:border-gray-700 rounded-lg shadow-lg p-3 settings-menu-container\">\n <label className=\"flex items-center justify-between cursor-pointer group\">\n <div className=\"flex items-center gap-2\">\n <svg className=\"w-4 h-4 text-gray-500 dark:text-gray-400\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\">\n <path strokeLinecap=\"round\" strokeLinejoin=\"round\" strokeWidth={2} d=\"M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-3 7h3m-3 4h3m-6-4h.01M9 16h.01\" />\n </svg>\n <div>\n <div className=\"text-sm font-medium text-gray-700 dark:text-gray-300\">Plan Mode</div>\n <div className=\"text-xs text-gray-500 dark:text-gray-400\">Review before executing</div>\n </div>\n </div>\n <button\n onClick={(e) => {\n e.stopPropagation();\n setInternalPlanMode(!internalPlanMode);\n }}\n className={cn(\n \"relative inline-flex h-5 w-9 items-center rounded-full transition-colors\",\n internalPlanMode ? \"bg-blue-600\" : \"bg-gray-300 dark:bg-gray-600\"\n )}\n type=\"button\"\n >\n <span\n className={cn(\n \"inline-block h-3.5 w-3.5 transform rounded-full bg-white transition-transform\",\n internalPlanMode ? \"translate-x-5\" : \"translate-x-0.5\"\n )}\n />\n </button>\n </label>\n </div>\n )}\n </div>\n )}\n </>\n )}\n </div>\n\n {/* Spacer when no attachment button */}\n {!(state === 'idle' && allowInput) && <div />}\n\n {/* Right side - Action buttons */}\n <div className=\"flex items-center gap-2\">\n {(state === 'success' || state === 'error') && allowInput && (\n <button\n onClick={resetCommand}\n className=\"px-3 py-1.5 text-sm text-gray-600 dark:text-gray-400 hover:text-gray-900 dark:hover:text-white transition-colors\"\n >\n Reset\n </button>\n )}\n\n {(state === 'idle' || state === 'error') && (\n <button\n onClick={() => executeCommand()}\n disabled={!command.trim()}\n className={cn(\n 'w-8 h-8 rounded-lg flex items-center justify-center font-bold transition-all',\n 'border border-gray-300 dark:border-gray-600',\n 'bg-white dark:bg-gray-800',\n '!text-gray-700 dark:!text-gray-300',\n 'hover:bg-gray-50 dark:hover:bg-gray-700',\n 'disabled:opacity-30 disabled:cursor-not-allowed',\n '!text-lg',\n !command.trim() && 'border-gray-200 dark:border-gray-700 !text-gray-400 dark:!text-gray-600'\n )}\n title={state === 'error' ? 'Retry' : 'Execute'}\n >\n {state === 'error' ? (\n <svg width=\"16\" height=\"16\" viewBox=\"0 0 16 16\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\n <path d=\"M13 8C13 10.7614 10.7614 13 8 13C5.23858 13 3 10.7614 3 8C3 5.23858 5.23858 3 8 3C9.65685 3 11.1257 3.82818 12 5.09091M12 3V5.09091M12 5.09091H9.81818\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\"/>\n </svg>\n ) : (\n <svg width=\"16\" height=\"16\" viewBox=\"0 0 16 16\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\n <path d=\"M8 3L8 13M8 3L4 7M8 3L12 7\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\"/>\n </svg>\n )}\n </button>\n )}\n </div>\n </div>\n )}\n\n {/* Plan Modal - Only for compact mode */}\n {showPlanDetails && isCompact && state === 'plan-pending' && (\n <div className=\"fixed inset-0 bg-black/50 flex items-center justify-center z-50 p-4\" onClick={() => setShowPlanDetails(false)}>\n <div className=\"bg-white dark:bg-gray-900 rounded-2xl shadow-2xl max-w-2xl w-full max-h-[80vh] overflow-hidden\" onClick={(e) => e.stopPropagation()}>\n {/* Modal Header */}\n <div className=\"flex items-center justify-between p-6 border-b border-gray-200 dark:border-gray-700\">\n <div className=\"flex items-center gap-3\">\n <svg className=\"w-6 h-6 text-blue-600 dark:text-blue-400\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\">\n <path strokeLinecap=\"round\" strokeLinejoin=\"round\" strokeWidth={2} d=\"M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-3 7h3m-3 4h3m-6-4h.01M9 16h.01\" />\n </svg>\n <h2 className=\"text-xl font-semibold text-gray-900 dark:text-white\">Proposed Execution Plan</h2>\n </div>\n <button\n onClick={() => setShowPlanDetails(false)}\n className=\"text-gray-400 hover:text-gray-600 dark:hover:text-gray-300 transition-colors\"\n >\n <svg className=\"w-6 h-6\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\">\n <path strokeLinecap=\"round\" strokeLinejoin=\"round\" strokeWidth={2} d=\"M6 18L18 6M6 6l12 12\" />\n </svg>\n </button>\n </div>\n\n {/* Modal Content */}\n <div className=\"p-6 overflow-y-auto max-h-[calc(80vh-180px)]\">\n <div className=\"prose prose-sm dark:prose-invert max-w-none\">\n <div className=\"text-gray-700 dark:text-gray-300 whitespace-pre-line leading-relaxed\">\n {plan}\n </div>\n </div>\n </div>\n\n {/* Modal Footer */}\n <div className=\"flex items-center justify-end gap-3 p-6 border-t border-gray-200 dark:border-gray-700 bg-gray-50 dark:bg-gray-800/50\">\n <button\n onClick={rejectPlan}\n className=\"px-6 py-2.5 bg-gray-200 dark:bg-gray-700 text-gray-700 dark:text-gray-300 rounded-lg hover:bg-gray-300 dark:hover:bg-gray-600 transition-colors font-medium\"\n >\n Modify Command\n </button>\n <button\n onClick={approvePlan}\n className=\"px-6 py-2.5 bg-blue-600 text-white rounded-lg hover:bg-blue-700 transition-colors font-medium\"\n >\n Approve & Execute\n </button>\n </div>\n </div>\n </div>\n )}\n\n {/* Hidden file input */}\n <input\n ref={fileInputRef}\n type=\"file\"\n multiple\n onChange={handleFileSelect}\n className=\"hidden\"\n accept=\"image/*,application/pdf,.doc,.docx,.txt\"\n />\n\n <style dangerouslySetInnerHTML={{\n __html: `\n @keyframes pulse-border {\n 0%, 100% {\n border-color: rgb(59, 130, 246);\n }\n 50% {\n border-color: rgb(147, 197, 253);\n }\n }\n .animate-pulse-border {\n animation: pulse-border 2s ease-in-out infinite;\n }\n `\n }} />\n </div>\n );\n}\n","import { useState, KeyboardEvent } from 'react';\nimport { PromptProps } from '../../types/components';\nimport { cn } from '../../utils';\nimport { aptevaClient } from '../../lib/apteva-client';\n\nexport function Prompt({\n agentId,\n placeholder = 'Enter your prompt...',\n initialValue = '',\n useMock = true,\n submitOn = 'button',\n debounceMs = 0,\n minLength = 0,\n maxLength,\n onSubmit,\n onResult,\n onChange,\n variant = 'inline',\n showSuggestions = false,\n className,\n}: PromptProps) {\n const [value, setValue] = useState(initialValue);\n const [isLoading, setIsLoading] = useState(false);\n const [suggestions] = useState(['Plan a trip', 'Write a description', 'Analyze data']);\n\n const handleChange = (e: React.ChangeEvent<HTMLInputElement>) => {\n const newValue = e.target.value;\n if (!maxLength || newValue.length <= maxLength) {\n setValue(newValue);\n onChange?.(newValue);\n }\n };\n\n const handleSubmit = async () => {\n if (value.length < minLength) return;\n\n onSubmit?.(value);\n setIsLoading(true);\n\n try {\n if (useMock) {\n // MOCK MODE\n await new Promise((resolve) => setTimeout(resolve, 1500));\n const mockResult = `Enhanced version: ${value} [AI-generated content]`;\n onResult?.(mockResult);\n setValue('');\n } else {\n // REAL API MODE\n const response = await aptevaClient.chat({\n agent_id: agentId,\n message: value,\n });\n onResult?.(response.message);\n setValue('');\n }\n } catch (error) {\n console.error('Error processing prompt:', error);\n } finally {\n setIsLoading(false);\n }\n };\n\n const handleKeyDown = (e: KeyboardEvent<HTMLInputElement>) => {\n if (submitOn === 'enter' && e.key === 'Enter' && !e.shiftKey) {\n e.preventDefault();\n handleSubmit();\n }\n };\n\n const handleBlur = () => {\n if (submitOn === 'blur' && value.trim()) {\n handleSubmit();\n }\n };\n\n return (\n <div className={cn('space-y-2', className)}>\n <div className=\"flex gap-2\">\n <input\n type=\"text\"\n value={value}\n onChange={handleChange}\n onKeyDown={handleKeyDown}\n onBlur={handleBlur}\n placeholder={placeholder}\n disabled={isLoading}\n className=\"flex-1 px-4 py-2 border border-gray-300 rounded-lg focus:outline-none focus:ring-2 focus:ring-apteva-500 dark:bg-gray-800 dark:border-gray-600 dark:text-white\"\n />\n\n {submitOn === 'button' && (\n <button\n onClick={handleSubmit}\n disabled={isLoading || value.length < minLength}\n className=\"px-6 py-2 bg-apteva-500 text-white rounded-lg hover:bg-apteva-600 disabled:opacity-50 disabled:cursor-not-allowed transition-colors font-medium\"\n >\n {isLoading ? 'Processing...' : 'Generate'}\n </button>\n )}\n </div>\n\n {maxLength && (\n <p className=\"text-xs text-gray-500\">\n {value.length} / {maxLength} characters\n </p>\n )}\n\n {showSuggestions && !value && (\n <div className=\"flex flex-wrap gap-2\">\n {suggestions.map((suggestion, idx) => (\n <button\n key={idx}\n onClick={() => setValue(suggestion)}\n className=\"px-3 py-1 text-sm bg-gray-100 hover:bg-gray-200 text-gray-700 rounded-full transition-colors\"\n >\n {suggestion}\n </button>\n ))}\n </div>\n )}\n\n {isLoading && (\n <div className=\"flex items-center gap-2 text-sm text-gray-500\">\n <div className=\"w-4 h-4 border-2 border-apteva-500 border-t-transparent rounded-full animate-spin\" />\n <span>AI is processing your request...</span>\n </div>\n )}\n </div>\n );\n}\n","import { useState, useEffect } from 'react';\nimport { StreamProps } from '../../types/components';\nimport { cn, generateMockStreamingResponse } from '../../utils';\nimport { aptevaClient } from '../../lib/apteva-client';\n\nexport function Stream({\n agentId,\n prompt,\n context,\n autoStart = false,\n useMock = true,\n onStart,\n onChunk,\n onComplete,\n onError,\n variant = 'prose',\n showCursor = true,\n typingSpeed = 30,\n className,\n}: StreamProps) {\n const [text, setText] = useState('');\n const [isStreaming, setIsStreaming] = useState(false);\n const [isComplete, setIsComplete] = useState(false);\n\n useEffect(() => {\n if (autoStart && !isStreaming && !isComplete) {\n startStreaming();\n }\n }, [autoStart]);\n\n const startStreaming = async () => {\n setIsStreaming(true);\n onStart?.();\n\n try {\n if (useMock) {\n // MOCK MODE\n const mockText =\n 'This is a simulated streaming response from the AI agent. ' +\n 'In a real implementation, this would stream data from your backend API. ' +\n 'The text appears word by word to simulate the streaming effect. ' +\n 'You can customize the typing speed and styling based on your needs.';\n\n await generateMockStreamingResponse(\n mockText,\n (chunk) => {\n setText((prev) => prev + chunk);\n onChunk?.(chunk);\n },\n typingSpeed\n );\n\n setIsComplete(true);\n setIsStreaming(false);\n onComplete?.(text + mockText);\n } else {\n // REAL API MODE\n let accumulatedText = '';\n\n await aptevaClient.chatStream(\n {\n agent_id: agentId,\n message: prompt,\n stream: true,\n },\n (chunk) => {\n if (chunk.type === 'token' && chunk.content) {\n accumulatedText += chunk.content;\n setText(accumulatedText);\n onChunk?.(chunk.content);\n }\n },\n () => {\n // On complete\n setIsComplete(true);\n setIsStreaming(false);\n onComplete?.(accumulatedText);\n },\n (error) => {\n // On error\n const err = error instanceof Error ? error : new Error('Streaming error');\n onError?.(err);\n setIsStreaming(false);\n }\n );\n }\n } catch (error) {\n const err = error instanceof Error ? error : new Error('Streaming error');\n onError?.(err);\n setIsStreaming(false);\n }\n };\n\n const variantClasses = {\n prose: 'prose prose-sm max-w-none dark:prose-invert',\n code: 'font-mono text-sm bg-gray-900 text-green-400 p-4 rounded-lg',\n plain: 'text-gray-900 dark:text-gray-100',\n };\n\n if (!isStreaming && !isComplete) {\n return (\n <div className={cn('p-4', className)}>\n <button\n onClick={startStreaming}\n className=\"px-6 py-3 bg-apteva-500 text-white rounded-lg hover:bg-apteva-600 transition-colors font-medium\"\n >\n Start Streaming\n </button>\n </div>\n );\n }\n\n return (\n <div className={cn(variantClasses[variant], className)}>\n {text}\n {isStreaming && showCursor && <span className=\"apteva-stream-cursor\" />}\n </div>\n );\n}\n","import { useState } from 'react';\nimport { Thread } from '../../types/messages';\nimport { ThreadItem } from './ThreadItem';\n\ninterface ThreadListProps {\n threads: Thread[];\n currentThreadId?: string;\n onThreadSelect?: (threadId: string) => void;\n onThreadDelete?: (threadId: string) => void;\n showSearch?: boolean;\n groupBy?: 'date' | 'agent' | 'none';\n}\n\nexport function ThreadList({\n threads,\n currentThreadId,\n onThreadSelect,\n onThreadDelete,\n showSearch = false,\n groupBy = 'none',\n}: ThreadListProps) {\n const [searchQuery, setSearchQuery] = useState('');\n\n const filteredThreads = threads.filter(\n (thread) =>\n thread.title.toLowerCase().includes(searchQuery.toLowerCase()) ||\n thread.preview?.toLowerCase().includes(searchQuery.toLowerCase())\n );\n\n const groupedThreads = groupBy === 'date' ? groupThreadsByDate(filteredThreads) : { All: filteredThreads };\n\n return (\n <div className=\"flex flex-col h-full\">\n {showSearch && (\n <div className=\"p-3 border-b border-gray-200 dark:border-gray-700\">\n <input\n type=\"text\"\n placeholder=\"Search conversations...\"\n value={searchQuery}\n onChange={(e) => setSearchQuery(e.target.value)}\n className=\"w-full px-3 py-2 text-sm border border-gray-300 rounded-lg focus:outline-none focus:ring-2 focus:ring-apteva-500 dark:bg-gray-800 dark:border-gray-600 dark:text-white\"\n />\n </div>\n )}\n\n <div className=\"flex-1 overflow-y-auto\">\n {Object.entries(groupedThreads).map(([group, groupThreads]) => (\n <div key={group}>\n {groupBy !== 'none' && (\n <div className=\"px-3 py-2 text-xs font-semibold text-gray-500 uppercase\">{group}</div>\n )}\n {groupThreads.map((thread) => (\n <ThreadItem\n key={thread.id}\n thread={thread}\n isActive={thread.id === currentThreadId}\n onSelect={() => onThreadSelect?.(thread.id)}\n onDelete={() => onThreadDelete?.(thread.id)}\n />\n ))}\n </div>\n ))}\n\n {filteredThreads.length === 0 && (\n <div className=\"p-8 text-center text-gray-500\">\n <div className=\"text-4xl mb-2\">💬</div>\n <p>No conversations found</p>\n </div>\n )}\n </div>\n </div>\n );\n}\n\nfunction groupThreadsByDate(threads: Thread[]): Record<string, Thread[]> {\n const now = new Date();\n const today = new Date(now.getFullYear(), now.getMonth(), now.getDate());\n const yesterday = new Date(today);\n yesterday.setDate(yesterday.getDate() - 1);\n const lastWeek = new Date(today);\n lastWeek.setDate(lastWeek.getDate() - 7);\n\n return threads.reduce(\n (groups, thread) => {\n const threadDate = new Date(thread.updatedAt);\n let group = 'Older';\n\n if (threadDate >= today) {\n group = 'Today';\n } else if (threadDate >= yesterday) {\n group = 'Yesterday';\n } else if (threadDate >= lastWeek) {\n group = 'Last 7 Days';\n }\n\n if (!groups[group]) groups[group] = [];\n groups[group].push(thread);\n return groups;\n },\n {} as Record<string, Thread[]>\n );\n}\n","// No direct imports needed 'react';\nimport { Thread } from '../../types/messages';\nimport { cn } from '../../utils';\n\ninterface ThreadItemProps {\n thread: Thread;\n isActive?: boolean;\n onSelect?: () => void;\n onDelete?: () => void;\n}\n\nexport function ThreadItem({ thread, isActive = false, onSelect, onDelete }: ThreadItemProps) {\n return (\n <div\n className={cn('apteva-thread-item', {\n 'apteva-thread-item-active': isActive,\n })}\n onClick={onSelect}\n >\n <div className=\"flex-1 min-w-0\">\n <h4 className=\"font-semibold text-gray-900 dark:text-white truncate\">{thread.title}</h4>\n {thread.preview && <p className=\"text-sm text-gray-600 dark:text-gray-400 truncate\">{thread.preview}</p>}\n <div className=\"flex items-center gap-2 mt-1 text-xs text-gray-500\">\n <span>{thread.messageCount} messages</span>\n <span>•</span>\n <span>{formatRelativeTime(thread.updatedAt)}</span>\n </div>\n </div>\n\n {onDelete && (\n <button\n onClick={(e) => {\n e.stopPropagation();\n onDelete();\n }}\n className=\"p-2 text-gray-400 hover:text-red-500 hover:bg-red-50 rounded transition-colors\"\n title=\"Delete thread\"\n >\n 🗑️\n </button>\n )}\n </div>\n );\n}\n\nfunction formatRelativeTime(date: Date): string {\n const now = new Date();\n const diff = now.getTime() - date.getTime();\n const minutes = Math.floor(diff / 60000);\n const hours = Math.floor(diff / 3600000);\n const days = Math.floor(diff / 86400000);\n\n if (minutes < 1) return 'Just now';\n if (minutes < 60) return `${minutes}m ago`;\n if (hours < 24) return `${hours}h ago`;\n if (days < 7) return `${days}d ago`;\n return date.toLocaleDateString();\n}\n","// No direct imports needed 'react';\nimport { ThreadsProps } from '../../types/components';\nimport { ThreadList } from './ThreadList';\nimport { cn } from '../../utils';\n\nexport function Threads({\n threads,\n currentThreadId,\n onThreadSelect,\n onThreadDelete,\n onNewThread,\n variant = 'sidebar',\n showSearch = false,\n showNewButton = true,\n groupBy = 'none',\n className,\n}: ThreadsProps) {\n const variantClasses = {\n sidebar: 'h-full border-r border-gray-200 dark:border-gray-700 bg-white dark:bg-gray-900',\n dropdown: 'absolute top-full left-0 right-0 mt-2 bg-white dark:bg-gray-800 rounded-lg shadow-lg border border-gray-200 dark:border-gray-700 max-h-96 overflow-hidden',\n tabs: 'flex gap-2 border-b border-gray-200 dark:border-gray-700 overflow-x-auto',\n };\n\n if (variant === 'tabs') {\n return (\n <div className={cn(variantClasses[variant], className)}>\n {threads.slice(0, 5).map((thread) => (\n <button\n key={thread.id}\n onClick={() => onThreadSelect?.(thread.id)}\n className={cn(\n 'px-4 py-2 whitespace-nowrap font-medium transition-colors',\n thread.id === currentThreadId\n ? 'border-b-2 border-apteva-500 text-apteva-500'\n : 'text-gray-600 hover:text-gray-900'\n )}\n >\n {thread.title}\n </button>\n ))}\n {showNewButton && onNewThread && (\n <button\n onClick={onNewThread}\n className=\"px-4 py-2 text-gray-600 hover:text-apteva-500 transition-colors font-medium\"\n >\n + New\n </button>\n )}\n </div>\n );\n }\n\n return (\n <div className={cn(variantClasses[variant], 'flex flex-col', className)}>\n {showNewButton && onNewThread && (\n <div className=\"p-3 border-b border-gray-200 dark:border-gray-700\">\n <button\n onClick={onNewThread}\n className=\"w-full px-4 py-2 bg-apteva-500 text-white rounded-lg hover:bg-apteva-600 transition-colors font-medium\"\n >\n + New Conversation\n </button>\n </div>\n )}\n\n <ThreadList\n threads={threads}\n currentThreadId={currentThreadId}\n onThreadSelect={onThreadSelect}\n onThreadDelete={onThreadDelete}\n showSearch={showSearch}\n groupBy={groupBy}\n />\n </div>\n );\n}\n","/**\n * Theme initialization script that runs before React hydration\n * This prevents flickering by setting the theme before the page renders\n * Must be inlined in the HTML <head> as a blocking script\n */\n\nexport const themeScript = `\n(function() {\n try {\n // Get system preference\n const isDark = window.matchMedia('(prefers-color-scheme: dark)').matches;\n const colorMode = isDark ? 'dark' : 'light';\n\n // Set attributes before render\n document.documentElement.setAttribute('data-color-mode', colorMode);\n\n // Add dark class for Tailwind\n if (isDark) {\n document.documentElement.classList.add('dark');\n }\n } catch (e) {\n console.error('Failed to initialize theme:', e);\n }\n})();\n`;\n\nexport function getThemeScript() {\n return themeScript;\n}\n"]}
|