mirror of
https://github.com/leonvanzyl/autocoder.git
synced 2026-02-05 08:23:08 +00:00
Enable the orchestrator to assign 1-3 features per coding agent subprocess, selected via dependency chain extension + same-category fill. This reduces cold-start overhead and leverages shared context across related features. Orchestrator (parallel_orchestrator.py): - Add batch tracking: _batch_features and _feature_to_primary data structures - Add build_feature_batches() with dependency chain + category fill algorithm - Add start_feature_batch() and _spawn_coding_agent_batch() methods - Update _on_agent_complete() for batch cleanup across all features - Update stop_feature() with _feature_to_primary lookup - Update get_ready_features() to exclude all batch feature IDs - Update main loop to build batches then spawn per available slot CLI and agent layer: - Add --feature-ids (comma-separated) and --batch-size CLI args - Add feature_ids parameter to run_autonomous_agent() with batch prompt selection - Add get_batch_feature_prompt() with sequential workflow instructions WebSocket layer (server/websocket.py): - Add BATCH_CODING_AGENT_START_PATTERN and BATCH_FEATURES_COMPLETE_PATTERN - Add _handle_batch_agent_start() and _handle_batch_agent_complete() methods - Add featureIds field to all agent_update messages - Track current_feature_id updates as agent moves through batch Frontend (React UI): - Add featureIds to ActiveAgent and WSAgentUpdateMessage types - Update KanbanColumn and DependencyGraph agent-feature maps for batch - Update AgentCard to show "Batch: #X, #Y, #Z" with active feature highlight - Add "Features per Agent" segmented control (1-3) in SettingsModal Settings integration (full stack): - Add batch_size to schemas, settings router, agent router, process manager - Default batch_size=3, user-configurable 1-3 via settings UI - batch_size=1 is functionally identical to pre-batching behavior Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
127 lines
3.8 KiB
TypeScript
127 lines
3.8 KiB
TypeScript
import { FeatureCard } from './FeatureCard'
|
|
import { Plus, Sparkles, Wand2 } from 'lucide-react'
|
|
import type { Feature, ActiveAgent } from '../lib/types'
|
|
import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card'
|
|
import { Button } from '@/components/ui/button'
|
|
import { Badge } from '@/components/ui/badge'
|
|
|
|
interface KanbanColumnProps {
|
|
title: string
|
|
count: number
|
|
features: Feature[]
|
|
allFeatures?: Feature[]
|
|
activeAgents?: ActiveAgent[]
|
|
color: 'pending' | 'progress' | 'done'
|
|
onFeatureClick: (feature: Feature) => void
|
|
onAddFeature?: () => void
|
|
onExpandProject?: () => void
|
|
showExpandButton?: boolean
|
|
onCreateSpec?: () => void
|
|
showCreateSpec?: boolean
|
|
}
|
|
|
|
const colorMap = {
|
|
pending: 'border-t-4 border-t-muted',
|
|
progress: 'border-t-4 border-t-primary',
|
|
done: 'border-t-4 border-t-primary',
|
|
}
|
|
|
|
export function KanbanColumn({
|
|
title,
|
|
count,
|
|
features,
|
|
allFeatures = [],
|
|
activeAgents = [],
|
|
color,
|
|
onFeatureClick,
|
|
onAddFeature,
|
|
onExpandProject,
|
|
showExpandButton,
|
|
onCreateSpec,
|
|
showCreateSpec,
|
|
}: KanbanColumnProps) {
|
|
// Create a map of feature ID to active agent for quick lookup
|
|
// Maps ALL batch feature IDs to the same agent
|
|
const agentByFeatureId = new Map<number, ActiveAgent>()
|
|
for (const agent of activeAgents) {
|
|
const ids = agent.featureIds || [agent.featureId]
|
|
for (const fid of ids) {
|
|
agentByFeatureId.set(fid, agent)
|
|
}
|
|
}
|
|
|
|
return (
|
|
<Card className={`overflow-hidden ${colorMap[color]} py-0`}>
|
|
{/* Header */}
|
|
<CardHeader className="px-4 py-3 border-b flex-row items-center justify-between space-y-0">
|
|
<CardTitle className="text-lg font-semibold flex items-center gap-2">
|
|
{title}
|
|
<Badge variant="secondary">{count}</Badge>
|
|
</CardTitle>
|
|
{(onAddFeature || onExpandProject) && (
|
|
<div className="flex items-center gap-2">
|
|
{onAddFeature && (
|
|
<Button
|
|
onClick={onAddFeature}
|
|
size="icon-sm"
|
|
title="Add new feature (N)"
|
|
>
|
|
<Plus size={16} />
|
|
</Button>
|
|
)}
|
|
{onExpandProject && showExpandButton && (
|
|
<Button
|
|
onClick={onExpandProject}
|
|
size="icon-sm"
|
|
variant="secondary"
|
|
title="Expand project with AI (E)"
|
|
>
|
|
<Sparkles size={16} />
|
|
</Button>
|
|
)}
|
|
</div>
|
|
)}
|
|
</CardHeader>
|
|
|
|
{/* Cards */}
|
|
<CardContent className="p-0">
|
|
<div className="h-[600px] overflow-y-auto">
|
|
<div className="p-4 space-y-3">
|
|
{features.length === 0 ? (
|
|
<div className="text-center py-8 text-muted-foreground">
|
|
{showCreateSpec && onCreateSpec ? (
|
|
<div className="space-y-4">
|
|
<p>No spec created yet</p>
|
|
<Button onClick={onCreateSpec}>
|
|
<Wand2 size={18} />
|
|
Create Spec with AI
|
|
</Button>
|
|
</div>
|
|
) : (
|
|
'No features'
|
|
)}
|
|
</div>
|
|
) : (
|
|
features.map((feature, index) => (
|
|
<div
|
|
key={feature.id}
|
|
className="animate-slide-in"
|
|
style={{ animationDelay: `${index * 50}ms` }}
|
|
>
|
|
<FeatureCard
|
|
feature={feature}
|
|
onClick={() => onFeatureClick(feature)}
|
|
isInProgress={color === 'progress'}
|
|
allFeatures={allFeatures}
|
|
activeAgent={agentByFeatureId.get(feature.id)}
|
|
/>
|
|
</div>
|
|
))
|
|
)}
|
|
</div>
|
|
</div>
|
|
</CardContent>
|
|
</Card>
|
|
)
|
|
}
|