mirror of
https://github.com/leonvanzyl/autocoder.git
synced 2026-03-18 03: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:
@@ -1,6 +1,6 @@
|
||||
import { useState } from 'react'
|
||||
import { X, CheckCircle2, Circle, SkipForward, Trash2, Loader2, AlertCircle, Pencil } from 'lucide-react'
|
||||
import { useSkipFeature, useDeleteFeature } from '../hooks/useProjects'
|
||||
import { X, CheckCircle2, Circle, SkipForward, Trash2, Loader2, AlertCircle, Pencil, Link2, AlertTriangle } from 'lucide-react'
|
||||
import { useSkipFeature, useDeleteFeature, useFeatures } from '../hooks/useProjects'
|
||||
import { EditFeatureForm } from './EditFeatureForm'
|
||||
import type { Feature } from '../lib/types'
|
||||
|
||||
@@ -37,6 +37,25 @@ export function FeatureModal({ feature, projectName, onClose }: FeatureModalProp
|
||||
|
||||
const skipFeature = useSkipFeature(projectName)
|
||||
const deleteFeature = useDeleteFeature(projectName)
|
||||
const { data: allFeatures } = useFeatures(projectName)
|
||||
|
||||
// Build a map of feature ID to feature for looking up dependency names
|
||||
const featureMap = new Map<number, Feature>()
|
||||
if (allFeatures) {
|
||||
;[...allFeatures.pending, ...allFeatures.in_progress, ...allFeatures.done].forEach(f => {
|
||||
featureMap.set(f.id, f)
|
||||
})
|
||||
}
|
||||
|
||||
// Get dependency features
|
||||
const dependencies = (feature.dependencies || [])
|
||||
.map(id => featureMap.get(id))
|
||||
.filter((f): f is Feature => f !== undefined)
|
||||
|
||||
// Get blocking dependencies (unmet dependencies)
|
||||
const blockingDeps = (feature.blocking_dependencies || [])
|
||||
.map(id => featureMap.get(id))
|
||||
.filter((f): f is Feature => f !== undefined)
|
||||
|
||||
const handleSkip = async () => {
|
||||
setError(null)
|
||||
@@ -145,6 +164,57 @@ export function FeatureModal({ feature, projectName, onClose }: FeatureModalProp
|
||||
</p>
|
||||
</div>
|
||||
|
||||
{/* Blocked By Warning */}
|
||||
{blockingDeps.length > 0 && (
|
||||
<div className="p-4 bg-[var(--color-neo-warning-bg)] border-3 border-[var(--color-neo-warning-border)]">
|
||||
<h3 className="font-display font-bold mb-2 uppercase text-sm flex items-center gap-2 text-[var(--color-neo-warning-text)]">
|
||||
<AlertTriangle size={16} />
|
||||
Blocked By
|
||||
</h3>
|
||||
<p className="text-sm text-[var(--color-neo-warning-text)] mb-2">
|
||||
This feature cannot start until the following dependencies are complete:
|
||||
</p>
|
||||
<ul className="space-y-1">
|
||||
{blockingDeps.map(dep => (
|
||||
<li
|
||||
key={dep.id}
|
||||
className="flex items-center gap-2 text-sm"
|
||||
>
|
||||
<Circle size={14} className="text-[var(--color-neo-warning-text)]" />
|
||||
<span className="font-mono text-xs text-[var(--color-neo-warning-text)]">#{dep.id}</span>
|
||||
<span className="text-[var(--color-neo-warning-text)]">{dep.name}</span>
|
||||
</li>
|
||||
))}
|
||||
</ul>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* Dependencies */}
|
||||
{dependencies.length > 0 && (
|
||||
<div>
|
||||
<h3 className="font-display font-bold mb-2 uppercase text-sm flex items-center gap-2">
|
||||
<Link2 size={16} />
|
||||
Depends On
|
||||
</h3>
|
||||
<ul className="space-y-1">
|
||||
{dependencies.map(dep => (
|
||||
<li
|
||||
key={dep.id}
|
||||
className="flex items-center gap-2 p-2 bg-[var(--color-neo-bg)] border-2 border-[var(--color-neo-border)]"
|
||||
>
|
||||
{dep.passes ? (
|
||||
<CheckCircle2 size={16} className="text-[var(--color-neo-done)]" />
|
||||
) : (
|
||||
<Circle size={16} className="text-[var(--color-neo-text-secondary)]" />
|
||||
)}
|
||||
<span className="font-mono text-xs text-[var(--color-neo-text-secondary)]">#{dep.id}</span>
|
||||
<span className={dep.passes ? 'text-[var(--color-neo-done)]' : ''}>{dep.name}</span>
|
||||
</li>
|
||||
))}
|
||||
</ul>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* Steps */}
|
||||
{feature.steps.length > 0 && (
|
||||
<div>
|
||||
|
||||
Reference in New Issue
Block a user