Files
autocoder/ui/src/components/KanbanColumn.tsx
Auto 1607fc8175 feat: add multi-feature batching for coding agents
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>
2026-02-01 16:35:07 +02:00

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>
)
}