feat(auto-mode): enhance error handling and feature status updates

- Improved error handling in AutoModeService to log errors and update feature status to "waiting_approval" when an error occurs during feature execution.
- Added error message writing to the context file for better debugging.
- Updated FeatureLoader to include an optional error message parameter when updating feature status.
- Enhanced prompt generation to include detailed context about attached images for better user guidance during feature implementation.
- Modified KanbanCard component to visually indicate features with errors, improving user awareness of issues.

These changes significantly enhance the robustness of the auto mode feature and improve the user experience by providing clearer feedback on feature execution status.
This commit is contained in:
Cody Seibert
2025-12-09 22:06:52 -05:00
parent 7b760090e4
commit 39043b8958
12 changed files with 261 additions and 429 deletions

View File

@@ -581,7 +581,7 @@ export function Sidebar() {
isActive
? "bg-sidebar-accent/50 text-foreground border border-sidebar-border"
: "text-muted-foreground hover:text-foreground hover:bg-sidebar-accent/50",
!sidebarOpen && "justify-center"
sidebarOpen ? "justify-start" : "justify-center"
)}
title={!sidebarOpen ? item.label : undefined}
data-testid={`nav-${item.id}`}
@@ -599,7 +599,7 @@ export function Sidebar() {
/>
<span
className={cn(
"ml-2.5 font-medium text-sm flex-1",
"ml-2.5 font-medium text-sm flex-1 text-left",
sidebarOpen ? "hidden lg:block" : "hidden"
)}
>
@@ -665,7 +665,7 @@ export function Sidebar() {
/>
<span
className={cn(
"ml-2.5 font-medium text-sm flex-1",
"ml-2.5 font-medium text-sm flex-1 text-left",
sidebarOpen ? "hidden lg:block" : "hidden"
)}
>

View File

@@ -202,7 +202,7 @@ export function AgentOutputModal({
return (
<Dialog open={open} onOpenChange={onClose}>
<DialogContent
className="w-[90vw] max-w-[90vw] max-h-[80vh] flex flex-col"
className="w-[60vw] max-w-[60vw] max-h-[80vh] flex flex-col"
data-testid="agent-output-modal"
>
<DialogHeader className="flex-shrink-0">

View File

@@ -338,16 +338,32 @@ export function BoardView() {
}, [showAddDialog, defaultSkipTests]);
// Listen for auto mode feature completion and reload features
// Listen for auto mode feature completion and errors to reload features
useEffect(() => {
const api = getElectronAPI();
if (!api?.autoMode) return;
const { removeRunningTask } = useAppStore.getState();
const unsubscribe = api.autoMode.onEvent((event) => {
if (event.type === "auto_mode_feature_complete") {
// Reload features when a feature is completed
console.log("[Board] Feature completed, reloading features...");
loadFeatures();
} else if (event.type === "auto_mode_error") {
// Reload features when an error occurs (feature moved to waiting_approval)
console.log("[Board] Feature error, reloading features...", event.error);
// Remove from running tasks so it moves to the correct column
if (event.featureId) {
removeRunningTask(event.featureId);
}
loadFeatures();
// Show error toast
toast.error("Agent encountered an error", {
description: event.error || "Check the logs for details",
});
}
});
@@ -439,6 +455,7 @@ export function BoardView() {
imagePaths: f.imagePaths,
skipTests: f.skipTests,
summary: f.summary,
error: f.error,
}));
await api.writeFile(
`${currentProject.path}/.automaker/feature_list.json`,

View File

@@ -39,7 +39,6 @@ import {
RotateCcw,
StopCircle,
Hand,
ArrowLeft,
MessageSquare,
GitCommit,
Cpu,
@@ -49,6 +48,7 @@ import {
Expand,
FileText,
MoreVertical,
AlertCircle,
} from "lucide-react";
import { CountUpTimer } from "@/components/ui/count-up-timer";
import { getElectronAPI } from "@/lib/electron";
@@ -199,7 +199,10 @@ export function KanbanCard({
"cursor-grab active:cursor-grabbing transition-all backdrop-blur-sm border-border relative",
isDragging && "opacity-50 scale-105 shadow-lg",
isCurrentAutoTask &&
"border-running-indicator border-2 shadow-running-indicator/50 shadow-lg animate-pulse"
"border-running-indicator border-2 shadow-running-indicator/50 shadow-lg animate-pulse",
feature.error &&
!isCurrentAutoTask &&
"border-red-500 border-2 shadow-red-500/30 shadow-lg"
)}
data-testid={`kanban-card-${feature.id}`}
{...attributes}
@@ -214,7 +217,7 @@ export function KanbanCard({
</div>
)}
{/* Skip Tests indicator badge */}
{feature.skipTests && (
{feature.skipTests && !feature.error && (
<div
className={cn(
"absolute px-1.5 py-0.5 text-[10px] font-medium rounded flex items-center gap-1 z-10",
@@ -228,6 +231,21 @@ export function KanbanCard({
<span>Manual</span>
</div>
)}
{/* Error indicator badge */}
{feature.error && (
<div
className={cn(
"absolute px-1.5 py-0.5 text-[10px] font-medium rounded flex items-center gap-1 z-10",
shortcutKey ? "top-2 left-10" : "top-2 left-2",
"bg-red-500/20 border border-red-500/50 text-red-400"
)}
data-testid={`error-badge-${feature.id}`}
title={feature.error}
>
<AlertCircle className="w-3 h-3" />
<span>Errored</span>
</div>
)}
<CardHeader className="p-3 pb-2">
{isCurrentAutoTask && (
<div className="absolute top-2 right-2 flex items-center justify-center gap-2 bg-running-indicator/20 border border-running-indicator rounded px-2 py-0.5">
@@ -255,6 +273,28 @@ export function KanbanCard({
</Button>
</DropdownMenuTrigger>
<DropdownMenuContent align="end">
<DropdownMenuItem
onClick={(e) => {
e.stopPropagation();
onEdit();
}}
data-testid={`edit-feature-${feature.id}`}
>
<Edit className="w-3 h-3 mr-2" />
Edit
</DropdownMenuItem>
{onViewOutput && (
<DropdownMenuItem
onClick={(e) => {
e.stopPropagation();
onViewOutput();
}}
data-testid={`view-logs-${feature.id}`}
>
<FileText className="w-3 h-3 mr-2" />
Logs
</DropdownMenuItem>
)}
<DropdownMenuItem
className="text-destructive focus:text-destructive"
onClick={(e) => {
@@ -565,55 +605,10 @@ export function KanbanCard({
Logs
</Button>
)}
{/* Move back button for skipTests verified features */}
{feature.skipTests && onMoveBackToInProgress && (
<Button
variant="ghost"
size="sm"
className="h-7 text-xs text-yellow-500 hover:text-yellow-500 hover:bg-yellow-500/10"
onClick={(e) => {
e.stopPropagation();
onMoveBackToInProgress();
}}
data-testid={`move-back-${feature.id}`}
>
<ArrowLeft className="w-3 h-3 mr-1" />
Back
</Button>
)}
<Button
variant="ghost"
size="sm"
className="flex-1 h-7 text-xs"
onClick={(e) => {
e.stopPropagation();
onEdit();
}}
data-testid={`edit-feature-${feature.id}`}
>
<Edit className="w-3 h-3 mr-1" />
Edit
</Button>
</>
)}
{!isCurrentAutoTask && feature.status === "waiting_approval" && (
<>
{/* Logs button if context exists */}
{hasContext && onViewOutput && (
<Button
variant="ghost"
size="sm"
className="h-7 text-xs"
onClick={(e) => {
e.stopPropagation();
onViewOutput();
}}
data-testid={`view-output-waiting-${feature.id}`}
>
<FileText className="w-3 h-3 mr-1" />
Logs
</Button>
)}
{/* Follow-up prompt button */}
{onFollowUp && (
<Button
@@ -665,19 +660,6 @@ export function KanbanCard({
Logs
</Button>
)}
<Button
variant="ghost"
size="sm"
className="flex-1 h-7 text-xs"
onClick={(e) => {
e.stopPropagation();
onEdit();
}}
data-testid={`edit-feature-${feature.id}`}
>
<Edit className="w-3 h-3 mr-1" />
Edit
</Button>
</>
)}
</div>