diff --git a/ui/src/App.tsx b/ui/src/App.tsx index 16fc4c0..9842f9d 100644 --- a/ui/src/App.tsx +++ b/ui/src/App.tsx @@ -13,7 +13,6 @@ import { SetupWizard } from './components/SetupWizard' import { AddFeatureForm } from './components/AddFeatureForm' import { FeatureModal } from './components/FeatureModal' import { DebugLogViewer, type TabType } from './components/DebugLogViewer' -import { AgentThought } from './components/AgentThought' import { AgentMissionControl } from './components/AgentMissionControl' import { CelebrationOverlay } from './components/CelebrationOverlay' import { AssistantFAB } from './components/AssistantFAB' @@ -390,6 +389,8 @@ function App() { total={progress.total} percentage={progress.percentage} isConnected={wsState.isConnected} + logs={wsState.activeAgents.length === 0 ? wsState.logs : undefined} + agentStatus={wsState.activeAgents.length === 0 ? wsState.agentStatus : undefined} /> {/* Agent Mission Control - shows orchestrator status and active agents in parallel mode */} @@ -400,13 +401,6 @@ function App() { getAgentLogs={wsState.getAgentLogs} /> - {/* Agent Thought - shows latest agent narrative (single agent mode) */} - {wsState.activeAgents.length === 0 && ( - - )} {/* Initializing Features State - show when agent is running but no features yet */} {features && diff --git a/ui/src/components/ProgressDashboard.tsx b/ui/src/components/ProgressDashboard.tsx index 7b935db..4a1865f 100644 --- a/ui/src/components/ProgressDashboard.tsx +++ b/ui/src/components/ProgressDashboard.tsx @@ -1,12 +1,40 @@ -import { Wifi, WifiOff } from 'lucide-react' +import { useMemo, useState, useEffect } from 'react' +import { Wifi, WifiOff, Brain, Sparkles } from 'lucide-react' import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card' import { Badge } from '@/components/ui/badge' +import type { AgentStatus } from '../lib/types' interface ProgressDashboardProps { passing: number total: number percentage: number isConnected: boolean + logs?: Array<{ line: string; timestamp: string }> + agentStatus?: AgentStatus +} + +const IDLE_TIMEOUT = 30000 + +function isAgentThought(line: string): boolean { + const trimmed = line.trim() + if (/^\[Tool:/.test(trimmed)) return false + if (/^\s*Input:\s*\{/.test(trimmed)) return false + if (/^\[(Done|Error)\]/.test(trimmed)) return false + if (/^Output:/.test(trimmed)) return false + if (/^[[{]/.test(trimmed)) return false + if (trimmed.length < 10) return false + if (/^[A-Za-z]:\\/.test(trimmed)) return false + if (/^\/[a-z]/.test(trimmed)) return false + return true +} + +function getLatestThought(logs: Array<{ line: string; timestamp: string }>): string | null { + for (let i = logs.length - 1; i >= 0; i--) { + if (isAgentThought(logs[i].line)) { + return logs[i].line.trim() + } + } + return null } export function ProgressDashboard({ @@ -14,67 +42,109 @@ export function ProgressDashboard({ total, percentage, isConnected, + logs = [], + agentStatus, }: ProgressDashboardProps) { + const thought = useMemo(() => getLatestThought(logs), [logs]) + const [displayedThought, setDisplayedThought] = useState(null) + const [textVisible, setTextVisible] = useState(true) + + const lastLogTimestamp = logs.length > 0 + ? new Date(logs[logs.length - 1].timestamp).getTime() + : 0 + + const showThought = useMemo(() => { + if (!thought) return false + if (agentStatus === 'running') return true + if (agentStatus === 'paused') { + return Date.now() - lastLogTimestamp < IDLE_TIMEOUT + } + return false + }, [thought, agentStatus, lastLogTimestamp]) + + useEffect(() => { + if (thought !== displayedThought && thought) { + setTextVisible(false) + const timeout = setTimeout(() => { + setDisplayedThought(thought) + setTextVisible(true) + }, 150) + return () => clearTimeout(timeout) + } + }, [thought, displayedThought]) + + const isRunning = agentStatus === 'running' + return ( - - - Progress - - - {isConnected ? ( - <> - - Live - - ) : ( - <> - - Offline - - )} - + +
+ + Progress + + + {isConnected ? ( + <> + + Live + + ) : ( + <> + + Offline + + )} + +
+
+ + {passing} + + / + + {total} + +
- - {/* Large Percentage */} -
- - - {percentage.toFixed(1)} - - - % - + +
+ {/* Progress Bar */} +
+
+
+ {/* Percentage */} + + {percentage.toFixed(1)}%
- {/* Progress Bar */} -
-
-
- - {/* Stats */} -
-
- - {passing} - - - Passing - -
-
/
-
- - {total} - - - Total - + {/* Agent Thought */} +
+
+
+ + {isRunning && ( + + )} +
+

+ {displayedThought?.replace(/:$/, '')} +