Skip to content

Commit 2aa245e

Browse files
committed
fix(tui): display error message when subagent crashes
Previously when a subagent task crashed or failed, it was immediately removed from the UI without displaying what error occurred. This made debugging very difficult as users could see the task disappear but had no information about what went wrong. Changes: - Add error_message field to SubagentTaskDisplay to store the error - Update ToolEvent::Failed handler to set the error message and keep the failed subagent visible instead of immediately removing it - Update render_subagent to display the error message in red when status is Failed - Failed subagents are still cleaned up on the next conversation turn via clear_tool_calls which retains only non-terminal subagents
1 parent 039cd2a commit 2aa245e

File tree

3 files changed

+48
-6
lines changed

3 files changed

+48
-6
lines changed

cortex-tui/src/app.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -272,6 +272,9 @@ pub struct SubagentTaskDisplay {
272272
pub started_at: Instant,
273273
/// Current todo items from the subagent (if any).
274274
pub todos: Vec<SubagentTodoItem>,
275+
/// Error message if the subagent failed.
276+
/// Stored separately so it can be displayed even when the task is removed.
277+
pub error_message: Option<String>,
275278
}
276279

277280
impl SubagentTaskDisplay {
@@ -294,6 +297,7 @@ impl SubagentTaskDisplay {
294297
output_preview: String::new(),
295298
started_at: Instant::now(),
296299
todos: Vec::new(),
300+
error_message: None,
297301
}
298302
}
299303

cortex-tui/src/runner/event_loop.rs

Lines changed: 15 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3419,12 +3419,23 @@ impl EventLoop {
34193419
format!("Error: {}", error),
34203420
);
34213421

3422-
// If this is a Task tool, remove the subagent from display
3422+
// If this is a Task tool, update subagent status to Failed with error message
3423+
// Keep the subagent visible so users can see what error occurred
34233424
if name == "Task" || name == "task" {
34243425
let session_id = format!("subagent_{}", id);
3425-
self.app_state.remove_subagent(&session_id);
3426-
// Stop delegation mode if no more active subagents
3427-
if !self.app_state.has_active_subagents() {
3426+
let error_clone = error.clone();
3427+
self.app_state.update_subagent(&session_id, |task| {
3428+
task.status = SubagentDisplayStatus::Failed;
3429+
task.error_message = Some(error_clone);
3430+
task.current_activity = "Failed".to_string();
3431+
});
3432+
// Stop delegation mode if no more active (non-failed) subagents
3433+
let has_running_subagents = self
3434+
.app_state
3435+
.active_subagents
3436+
.iter()
3437+
.any(|t| !t.status.is_terminal());
3438+
if !has_running_subagents {
34283439
self.app_state.streaming.stop_delegation();
34293440
}
34303441
}

cortex-tui/src/views/minimal_session.rs

Lines changed: 29 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -413,8 +413,35 @@ impl<'a> MinimalSessionView<'a> {
413413
),
414414
]));
415415

416-
// Display todos if any - use ⎿ prefix for first, space for rest
417-
if !task.todos.is_empty() {
416+
// Display error message if task failed
417+
if task.status == SubagentDisplayStatus::Failed {
418+
if let Some(ref error_msg) = task.error_message {
419+
lines.push(Line::from(vec![
420+
Span::styled(" ⎿ ", Style::default().fg(self.colors.text_muted)),
421+
Span::styled("Error: ", Style::default().fg(self.colors.error)),
422+
]));
423+
// Display error message, truncate if too long
424+
for (i, err_line) in error_msg.lines().take(5).enumerate() {
425+
let truncated = if err_line.len() > 70 {
426+
format!("{}...", &err_line.chars().take(67).collect::<String>())
427+
} else {
428+
err_line.to_string()
429+
};
430+
let prefix = if i == 0 { " " } else { " " };
431+
lines.push(Line::from(vec![
432+
Span::styled(prefix, Style::default().fg(self.colors.text_muted)),
433+
Span::styled(truncated, Style::default().fg(self.colors.error)),
434+
]));
435+
}
436+
} else {
437+
// Fallback: no error message provided
438+
lines.push(Line::from(vec![
439+
Span::styled(" ⎿ ", Style::default().fg(self.colors.text_muted)),
440+
Span::styled("Task failed", Style::default().fg(self.colors.error)),
441+
]));
442+
}
443+
} else if !task.todos.is_empty() {
444+
// Display todos if any - use ⎿ prefix for first, space for rest
418445
for (i, todo) in task.todos.iter().enumerate() {
419446
let (status_text, status_color) = match todo.status {
420447
SubagentTodoStatus::Completed => ("[completed]", self.colors.success),

0 commit comments

Comments
 (0)