From 22d7b327a0e3472d4be92e990ab83263f0a0c794 Mon Sep 17 00:00:00 2001 From: "Rai (Michael Pokorny)" Date: Tue, 24 Jun 2025 14:31:38 -0700 Subject: [PATCH] Auto-commit pending changes on agentydragon-task/13-interactive-prompt-during-execution --- .../13-interactive-prompt-during-execution.md | 10 ++-- codex-rs/tui/src/bottom_pane/mod.rs | 59 ++++++++++++++++++- 2 files changed, 62 insertions(+), 7 deletions(-) diff --git a/agentydragon/tasks/13-interactive-prompt-during-execution.md b/agentydragon/tasks/13-interactive-prompt-during-execution.md index c356c31a2a..a914ac0a6c 100644 --- a/agentydragon/tasks/13-interactive-prompt-during-execution.md +++ b/agentydragon/tasks/13-interactive-prompt-during-execution.md @@ -4,8 +4,8 @@ ## Status -**General Status**: Not started -**Summary**: Not started; missing Implementation details (How it was implemented and How it works). +**General Status**: Done +**Summary**: Implemented interactive prompt overlay allowing user input during streaming without aborting runs. ## Goal @@ -23,10 +23,12 @@ Allow users to interleave composing prompts and issuing slash-commands while the ## Implementation **How it was implemented** -*(Not implemented yet)* +- Modified `BottomPane::handle_key_event` in `tui/src/bottom_pane/mod.rs` to special-case the `StatusIndicatorView` while `is_task_running`, forwarding key events to `ChatComposer` and preserving the overlay. +- Updated `BottomPane::render_ref` to always render the composer first and then overlay the active view, ensuring the input box remains visible and editable under the status indicator. +- Added unit tests in `tui/src/bottom_pane/mod.rs` to verify input is forwarded during task execution and that the status indicator overlay is removed upon task completion. **How it works** -*(Not implemented yet)* +During LLM streaming or tool execution, the `StatusIndicatorView` remains active as an overlay. The modified event handler detects this overlay and forwards user key events to the underlying `ChatComposer` without dismissing the overlay. On task completion (`set_task_running(false)`), the overlay is automatically removed (via `should_hide_when_task_is_done`), returning to the normal input-only view. ## Notes diff --git a/codex-rs/tui/src/bottom_pane/mod.rs b/codex-rs/tui/src/bottom_pane/mod.rs index 330c38aeaf..2634907319 100644 --- a/codex-rs/tui/src/bottom_pane/mod.rs +++ b/codex-rs/tui/src/bottom_pane/mod.rs @@ -63,6 +63,16 @@ impl BottomPane<'_> { /// Forward a key event to the active view or the composer. pub fn handle_key_event(&mut self, key_event: KeyEvent) -> InputResult { if let Some(mut view) = self.active_view.take() { + // During task execution, allow input to pass through status indicator overlay + if self.is_task_running && view.should_hide_when_task_is_done() { + // restore overlay view and forward input to composer + self.active_view = Some(view); + let (input_result, needs_redraw) = self.composer.handle_key_event(key_event); + if needs_redraw { + self.request_redraw(); + } + return input_result; + } view.handle_key_event(self, key_event); if !view.is_complete() { self.active_view = Some(view); @@ -197,11 +207,54 @@ impl BottomPane<'_> { impl WidgetRef for &BottomPane<'_> { fn render_ref(&self, area: Rect, buf: &mut Buffer) { - // Show BottomPaneView if present. + // Always render composer, then overlay any active view (e.g., status indicator or modal) + (&self.composer).render_ref(area, buf); if let Some(ov) = &self.active_view { ov.render(area, buf); - } else { - (&self.composer).render_ref(area, buf); } } } + +#[cfg(test)] +mod tests { + use super::*; + use crossterm::event::{KeyCode, KeyEvent, KeyModifiers}; + + /// Construct a BottomPane with default parameters for testing. + fn make_pane() -> BottomPane<'static> { + let (tx, _rx) = std::sync::mpsc::channel(); + let app_event_tx = AppEventSender::new(tx); + BottomPane::new(BottomPaneParams { + app_event_tx, + has_input_focus: true, + composer_max_rows: 3, + }) + } + + #[test] + fn forward_input_during_status_indicator() { + let mut pane = make_pane(); + // Start task to show status indicator overlay + pane.set_task_running(true); + // Simulate typing 'h' + let key = KeyEvent::new(KeyCode::Char('h'), KeyModifiers::NONE); + let result = pane.handle_key_event(key); + // No submission event is returned + assert!(matches!(result, InputResult::None)); + // Composer should have recorded the input + let content = pane.composer.textarea.lines().join("\n"); + assert_eq!(content, "h"); + // Status indicator overlay remains active + assert!(pane.active_view.is_some()); + } + + #[test] + fn remove_status_indicator_after_task_complete() { + let mut pane = make_pane(); + pane.set_task_running(true); + assert!(pane.active_view.is_some()); + pane.set_task_running(false); + // Overlay should be removed when task finishes + assert!(pane.active_view.is_none()); + } +}