feat: add "blocked for human input" feature across full stack

Agents can now request structured human input when they encounter
genuine blockers (API keys, design choices, external configs). The
request is displayed in the UI with a dynamic form, and the human's
response is stored and made available when the agent resumes.

Changes span 21 files + 1 new component:
- Database: 3 new columns (needs_human_input, human_input_request,
  human_input_response) with migration
- MCP: new feature_request_human_input tool + guards on existing tools
- API: new resolve-human-input endpoint, 4th feature bucket
- Orchestrator: skip needs_human_input features in scheduling
- Progress: 4-tuple return from count_passing_tests
- WebSocket: needs_human_input count in progress messages
- UI: conditional 4th Kanban column, HumanInputForm component,
  amber status indicators, dependency graph support

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
Caitlyn Byrne
2026-02-08 14:11:35 -05:00
parent 9eb08d3f71
commit 656df0fd9a
21 changed files with 570 additions and 53 deletions

View File

@@ -181,7 +181,7 @@ function App() {
// E : Expand project with AI (when project selected, has spec and has features)
if ((e.key === 'e' || e.key === 'E') && selectedProject && hasSpec && features &&
(features.pending.length + features.in_progress.length + features.done.length) > 0) {
(features.pending.length + features.in_progress.length + features.done.length + (features.needs_human_input?.length || 0)) > 0) {
e.preventDefault()
setShowExpandProject(true)
}
@@ -443,6 +443,7 @@ function App() {
features.pending.length === 0 &&
features.in_progress.length === 0 &&
features.done.length === 0 &&
(features.needs_human_input?.length || 0) === 0 &&
wsState.agentStatus === 'running' && (
<Card className="p-8 text-center">
<CardContent className="p-0">
@@ -458,7 +459,7 @@ function App() {
)}
{/* View Toggle - only show when there are features */}
{features && (features.pending.length + features.in_progress.length + features.done.length) > 0 && (
{features && (features.pending.length + features.in_progress.length + features.done.length + (features.needs_human_input?.length || 0)) > 0 && (
<div className="flex justify-center">
<ViewToggle viewMode={viewMode} onViewModeChange={setViewMode} />
</div>