feat: Generate commands or ask questions with atuin ai#3199
Open
BinaryMuse wants to merge 77 commits intomainfrom
Open
feat: Generate commands or ask questions with atuin ai#3199BinaryMuse wants to merge 77 commits intomainfrom
atuin ai#3199BinaryMuse wants to merge 77 commits intomainfrom
Conversation
- Add TerminalGuard with panic hook and Drop-based cleanup - Implement install_panic_hook() for terminal restoration after panic - Add non-TTY detection for early error handling - Use Viewport::Inline(16) matching existing inline.rs behavior - Capture cursor position before raw mode for accurate anchor
- Add AppEvent enum with Key, Tick, Resize, and Stream placeholders - Implement EventLoop with biased tokio::select! for priority handling - Add SIGINT/Ctrl+C handler for graceful shutdown - Implement rapid keypress batching - Use 150ms tick interval for spinner animation - Filter keyboard events to Press only for cross-platform safety - Add futures dependency for StreamExt trait
- Add tui module to main.rs - Import and call install_panic_hook() in inline.rs run() - Add event-stream feature to crossterm for async EventStream - Verify existing inline functionality still works - Build and help command tests pass
- BlockState enum with Building/Active/Static variants - State transition methods (finish_building, make_static, tick) - BlockKind enum for Input/Command/Spinner/Text - Block struct combining kind, state, and content
- AppMode enum for Input/Generating/Review/Error states - ExitAction enum for Execute/Insert/Cancel - App struct managing blocks, mode, input, and exit state - State transition methods (start_generating, generation_complete, cancel_generation, generation_error) - Cancel during generation removes partial block and reverts previous to Active - Tick method for advancing spinner animations
- App.handle_key() processes keyboard events per mode - Input mode: Esc exits, Enter submits or cancels if empty, chars build input - Generating mode: Esc cancels, other keys discarded - Review mode: Esc cancels, Enter runs, Tab inserts, 'e' edits - Error mode: Esc cancels, Enter/r retries - Ctrl combinations pass through - EventLoop.poll_and_apply() integrates events with App state
- Replace InlineUi::new() with TerminalGuard::new() - Replace blocking event::poll() loop with async EventLoop - Wire EventLoop.run().await to drive TUI state - Remove old InlineUi struct and Screen enum - Integrate App state management with event handling
- Remove unused wait_for_retry_or_cancel function - Apply clippy suggestions to collapse nested if statements - Verify all state transitions work correctly - Pass cargo clippy and cargo build with no warnings
- Add render.rs with RenderContext struct and render_blocks() function - Implement block-specific renderers for Input, Command, Spinner, Text - Add theme integration using Style::from_crossterm() - Implement cursor positioning with word wrapping support - Add horizontal separators between blocks - Use dynamic layout calculations for proper sizing
- Add ThemeManager import and load theme from settings - Replace render_app() with render_blocks() call - Remove old rendering functions (render_app, format_prompt, wrapped_line_count, prompt_cursor_position) - Remove local SPINNER_FRAMES constant (now in render.rs) - Remove unused ratatui imports - Theme passed through RenderContext to render module
Phase 3 has most functionality already implemented from earlier work. This plan fills remaining gaps: - Task 1: Error block rendering with "!" symbol and Alert theme color - Task 2: Exit mode configuration (keep_output parameter) 1 plan, 2 tasks, single wave. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Add BlockKind::Error variant to block types - Add Block::new_error() constructor with Static state - Add render_error_block() with "!" symbol styled as AlertError - Modify generation_error() to push error block to blocks vec - Fix clippy warning in inline.rs (unnecessary_unwrap)
- Add keep_output parameter to TerminalGuard::new() - Store keep_output as field in TerminalGuard struct - Modify Drop impl to conditionally clear based on keep_output - Add --keep CLI flag to Inline command - Pass keep_output through run() and run_inline_tui() - Default to false (erase behavior) for backward compatibility
Plan 01: SSE streaming infrastructure - Add reqwest-eventsource and pulldown-cmark dependencies - Add BlockState::Streaming and AppMode::Streaming variants - Implement refine stream with event loop polling Plan 02: Markdown rendering and edit mode - Add markdown_to_spans() for bold/italic/code formatting - Implement edit mode transition and conversation history - Wire refine stream trigger on edit submission Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- reqwest-eventsource 0.6.0 for SSE streaming - pulldown-cmark 0.13.0 for markdown parsing - async-stream 0.3 for stream creation
- Add BlockState::Streaming variant with is_streaming() method - Add Block::new_streaming_text() constructor - Add AppMode::Streaming variant - Add streaming lifecycle methods to App: - start_streaming_response() - append_to_streaming_block() - finalize_streaming() - streaming_error() - Add handle_streaming_key() for Esc cancellation - Update render footer for Streaming mode
- Add RefineRequest and RefineMessage structs - Add create_refine_stream() function using eventsource-stream - Add refine_stream tracking variable in event loop - Poll stream in Tick handler without blocking - Handle stream chunks, errors, and completion - Add stream cancellation on mode change - Enable stream feature in workspace reqwest dependency
- Import pulldown_cmark for markdown parsing - Add markdown_to_spans() to convert markdown to styled Lines - Support **bold** (BOLD modifier), *italics* (UNDERLINED), `code` (Important style) - Update render_text_block() to use markdown parsing - Handle paragraphs, soft/hard breaks, nested formatting
- Add is_refine_mode flag to App struct
- Add start_edit_mode() method to transition to Input with refine flag set
- Add build_conversation_history() to create (role, content) pairs from blocks
- Update KeyCode::Char('e') handler to call start_edit_mode()
- Update inline.rs to trigger refine stream when is_refine_mode is true
- Update retry logic to skip refine mode (retry only works for initial generation)
- Remove #[allow(dead_code)] from refine stream functions (now in use)
Summary: - 3 tasks completed (markdown parsing, edit mode, verification) - 2 commits (Task 1: markdown_to_spans, Task 2: edit mode flow) - 3 files modified (render.rs, app.rs, inline.rs) - Duration: 3 minutes State updates: - Advanced to Phase 4 Plan 2 of 2 complete - Updated progress to 75% (6 plans complete) - Added decision D04-02-001 (Task 3 already complete) - Removed blocker about edit mode implementation (now done) - Updated session continuity
Plan 01: State and view model type definitions (state.rs, view_model.rs) Plan 02: State transition methods and keyboard handling Plan 03: Render integration and blocks module removal 3 plans in 3 sequential waves - foundation types, state management, integration. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Create AppState struct with flat fields (mode, messages, input, cursor_pos, error) - Define AppMode enum (Input, Generating, Streaming, Review, Error) - Add Message/MessageRole types for conversation history - Implement character-based cursor handling with byte index conversion - Add ExitAction enum for exit flow control
- Create Content enum with struct-like variants (Input, Command, Text, Error, Spinner) - Define Block struct with content, separator_above, title fields - Implement Blocks::from_state() as pure derivation function - Derive complete view specification from AppState (messages, mode, error) - Generate mode-dependent footer keybinds
- Add pub mod declarations for state and view_model - Export AppState, Message, MessageRole from state - Export Blocks and Content from view_model - Maintain existing module exports for compatibility
- Generation lifecycle: start_generating, generation_complete, generation_error, cancel_generation - Streaming lifecycle: start_streaming_response, append_streaming_text, finalize_streaming_with_command, streaming_error - Edit mode and exit: start_edit_mode, exit, retry - Utility: tick, current_command - Conversation events tracked for refine API - Messages mutated in place during streaming per user decision
- App now wraps AppState and delegates keyboard handling - Keyboard events route to appropriate AppState methods based on mode - Added delegation methods for backward compatibility with inline.rs - Added blocks() method to convert messages to legacy blocks for render.rs - Updated mod.rs exports to expose AppState types - Fixed inline.rs and render.rs to use app.state fields - All mutable state logic now centralized in AppState Deviation (Rule 3 - Blocking): Added compatibility layer to App for render.rs and inline.rs to maintain compilation during transition
- Replace legacy block-based rendering with pure view derivation - render() calls Blocks::from_state() each frame - Renderer only reads Content variants from view model - Cursor position calculated from view model's cursor_pos field - Keep render_blocks() as legacy wrapper for compatibility
- Import render() function from render module - Update render call to pass &app.state instead of &app - Replace all app.method() calls with app.state.method() - Direct state access via app.state for all state transitions - Remove dependency on legacy app delegation methods
- Delete crates/atuin-ai/src/tui/blocks/ directory - Remove blocks module from tui/mod.rs - Clean up exports to only include new architecture types - Remove legacy delegation methods from app.rs - Remove render_blocks() compatibility wrapper - Fix event.rs to use app.state.tick() directly - No BlockKind, BlockState, or LegacyBlock types remain
- Add test-renders.json with 23 UI state test cases covering: - Input states (empty, typing, follow-up) - Streaming states (spinner, text, tool calls) - Review states (commands, warnings, errors) - Edge cases (long text, multi-turn, null commands) - Add render-tests.sh script to run all tests through debug-render Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Add debug state logging to the inline command for debugging UI issues: - New --debug-state <FILE> flag to log state changes as JSONL - Logs include: events, mode, input, cursor_pos, streaming_text, etc. - Each entry labeled with event type (key, text_chunk, tool_call, etc.) - Useful for capturing real UI states to create accurate test cases Usage: atuin-ai inline --debug-state /tmp/state.jsonl Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Interactive script to replay state snapshots from --debug-state output: - ./replay-states.sh <file.jsonl> # Interactive replay - ./replay-states.sh <file.jsonl> 15 # Show specific entry Interactive mode supports: next, prev, jump to entry, show raw JSON Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
LLM responses often start with "\n\n" which caused extra blank lines at the top of text blocks. Now trim_start() when finalizing streaming text to events. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Dynamic viewport: starts at 15 lines, grows +5 when needed - Event ordering: flush streaming text before adding tool calls - Hide conversation-only suggest_command tool calls (null command) - Trim leading whitespace from LLM responses during streaming - Debug logger captures actual content height for accurate replay - Extract calculate_needed_height() for viewport sizing Note: cursor positioning for wrapped input is WIP, will be replaced with tui-textarea integration. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Replace manual input/cursor handling with tui-textarea-2 library which properly handles cursor positioning, word wrapping, and text editing. - Switch to tui-textarea-2 (compatible with ratatui 0.30) - Replace input/cursor_pos fields with TextArea widget in AppState - Delegate key handling to TextArea (handles cursor movement, editing) - Render TextArea directly for active inputs (cursor via styled spans) - Enable word wrapping (WrapMode::Word) for long input text - Disable cursor line underline for cleaner appearance - Add REVERSED/UNDERLINED modifier support to debug render output Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Contributor
Greptile SummaryIntroduces Key additions:
Important Files Changed
Last reviewed commit: fff2360 |
Member
Author
This seems to be caused by versions of `click`, a sub-dependency of mkdocs, higher than 8.2.1. This commit locks it.
Member
Author
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
This PR refines the system created in #3178 to be suitable for a v1 release.
Overview
atuin-aiis a separate binary that allows for generating commands and asking questions from the command line.It is fully opt-in.
Usage
atuin ai initwill output bindings for your shell. Currently, bash, zsh, and fish are supported.Once the hooks are installed, just press
?on an empty prompt line to call up the TUI.atuin airequires an account on Atuin Hub; you will be prompted to log in on first use.Features
Command generation
Prompt the LLM to create a command, and get one back, no fuss. Press
enterto run, ortabto insert.Follow-up
You can follow-up with
fto specify a refinement prompt to update the command that will be inserted.You can also follow-up with questions to get responses in natural language.
You can use
enterortabat any time to run or insert the last suggested command, even if it was suggested in a previous turn.Conversational and search usage
If you prompt the LLM with a question that doesn't imply you want to generate a command, it can respond in natural language, and use web search if necessary to fetch the data it needs.
Dangerous or low-confidence command detection
The LLM scores its confidence in the command, as well as how dangerous the command is. This information is shown if a threshold is exceeded, and requires an extra confirmation step before running automatically with
enter.The Atuin Hub server also monitors suggested commands for dangerous patterns the LLM didn't catch, and appends its own assessment at the end of the LLM's own assessment.