mirror of
https://github.com/leonvanzyl/autocoder.git
synced 2026-04-03 11:13:08 +00:00
feat: add concurrent agents with dependency system and delightful UI
Major feature implementation for parallel agent execution with dependency-aware scheduling and an engaging multi-agent UI experience. Backend Changes: - Add parallel_orchestrator.py for concurrent feature processing - Add api/dependency_resolver.py with cycle detection (Kahn's algorithm + DFS) - Add atomic feature_claim_next() with retry limit and exponential backoff - Fix circular dependency check arguments in 4 locations - Add AgentTracker class for parsing agent output and emitting updates - Add browser isolation with --isolated flag for Playwright MCP - Extend WebSocket protocol with agent_update messages and log attribution - Add WSAgentUpdateMessage schema with agent states and mascot names - Fix WSProgressMessage to include in_progress field New UI Components: - AgentMissionControl: Dashboard showing active agents with collapsible activity - AgentCard: Individual agent status with avatar and thought bubble - AgentAvatar: SVG mascots (Spark, Fizz, Octo, Hoot, Buzz) with animations - ActivityFeed: Recent activity stream with stable keys (no flickering) - CelebrationOverlay: Confetti animation with click/Escape dismiss - DependencyGraph: Interactive node graph visualization with dagre layout - DependencyBadge: Visual indicator for feature dependencies - ViewToggle: Switch between Kanban and Graph views - KeyboardShortcutsHelp: Help overlay accessible via ? key UI/UX Improvements: - Celebration queue system to handle rapid success messages - Accessibility attributes on AgentAvatar (role, aria-label, aria-live) - Collapsible Recent Activity section with persisted preference - Agent count display in header - Keyboard shortcut G to toggle Kanban/Graph view - Real-time thought bubbles and state animations Bug Fixes: - Fix circular dependency validation (swapped source/target arguments) - Add MAX_CLAIM_RETRIES=10 to prevent stack overflow under contention - Fix THOUGHT_PATTERNS to match actual [Tool: name] format - Fix ActivityFeed key prop to prevent re-renders on new items - Add featureId/agentIndex to log messages for proper attribution Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
99
ui/src/components/AgentCard.tsx
Normal file
99
ui/src/components/AgentCard.tsx
Normal file
@@ -0,0 +1,99 @@
|
||||
import { MessageCircle } from 'lucide-react'
|
||||
import { AgentAvatar } from './AgentAvatar'
|
||||
import type { ActiveAgent } from '../lib/types'
|
||||
|
||||
interface AgentCardProps {
|
||||
agent: ActiveAgent
|
||||
}
|
||||
|
||||
// Get a friendly state description
|
||||
function getStateText(state: ActiveAgent['state']): string {
|
||||
switch (state) {
|
||||
case 'idle':
|
||||
return 'Waiting...'
|
||||
case 'thinking':
|
||||
return 'Thinking...'
|
||||
case 'working':
|
||||
return 'Coding...'
|
||||
case 'testing':
|
||||
return 'Testing...'
|
||||
case 'success':
|
||||
return 'Done!'
|
||||
case 'error':
|
||||
return 'Hit an issue'
|
||||
case 'struggling':
|
||||
return 'Retrying...'
|
||||
default:
|
||||
return 'Working...'
|
||||
}
|
||||
}
|
||||
|
||||
// Get state color
|
||||
function getStateColor(state: ActiveAgent['state']): string {
|
||||
switch (state) {
|
||||
case 'success':
|
||||
return 'text-neo-done'
|
||||
case 'error':
|
||||
case 'struggling':
|
||||
return 'text-neo-danger'
|
||||
case 'working':
|
||||
case 'testing':
|
||||
return 'text-neo-progress'
|
||||
case 'thinking':
|
||||
return 'text-neo-pending'
|
||||
default:
|
||||
return 'text-neo-text-secondary'
|
||||
}
|
||||
}
|
||||
|
||||
export function AgentCard({ agent }: AgentCardProps) {
|
||||
const isActive = ['thinking', 'working', 'testing'].includes(agent.state)
|
||||
|
||||
return (
|
||||
<div
|
||||
className={`
|
||||
neo-card p-3 min-w-[180px] max-w-[220px]
|
||||
${isActive ? 'animate-pulse-neo' : ''}
|
||||
transition-all duration-300
|
||||
`}
|
||||
>
|
||||
{/* Header with avatar and name */}
|
||||
<div className="flex items-center gap-2 mb-2">
|
||||
<AgentAvatar name={agent.agentName} state={agent.state} size="sm" />
|
||||
<div className="flex-1 min-w-0">
|
||||
<div className="font-display font-bold text-sm truncate">
|
||||
{agent.agentName}
|
||||
</div>
|
||||
<div className={`text-xs ${getStateColor(agent.state)}`}>
|
||||
{getStateText(agent.state)}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Feature info */}
|
||||
<div className="mb-2">
|
||||
<div className="text-xs text-neo-text-secondary mb-0.5">
|
||||
Feature #{agent.featureId}
|
||||
</div>
|
||||
<div className="text-sm font-medium truncate" title={agent.featureName}>
|
||||
{agent.featureName}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Thought bubble */}
|
||||
{agent.thought && (
|
||||
<div className="relative mt-2 pt-2 border-t-2 border-neo-border/30">
|
||||
<div className="flex items-start gap-1.5">
|
||||
<MessageCircle size={14} className="text-neo-progress shrink-0 mt-0.5" />
|
||||
<p
|
||||
className="text-xs text-neo-text-secondary line-clamp-2 italic"
|
||||
title={agent.thought}
|
||||
>
|
||||
{agent.thought}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
Reference in New Issue
Block a user