Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
92 changes: 58 additions & 34 deletions PLAN.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,54 +8,78 @@ A Rust-based TUI for multi-agent AI orchestration with dynamic task routing, par

### ✅ Completed

#### Phase 0: Foundation
#### Phase 0: Foundation (100%)
- [x] Project setup with Cargo.toml and all dependencies
- [x] Directory structure created
- [x] Core types defined (Agent, Task, Message, Session, etc.)
- [x] Configuration module with TOML support

#### Phase 1: TUI Foundation
#### Phase 1: TUI Foundation (100%)
- [x] Main entry point with async tokio runtime
- [x] App loop with event handling
- [x] Terminal setup/cleanup with raw mode
- [x] Chat component with scrolling and message display
- [x] Input component with history and cursor navigation
- [x] Sidebar component with agent status
- [x] Placeholder modules for agent, llm, orchestrator, persistence, shared
- [x] Markdown rendering with pulldown-cmark

#### Phase 1.5: Bug Fixes & Improvements
#### Phase 1.5: Bug Fixes & Improvements (100%)
- [x] Fixed input mode glitch (command mode entry)
- [x] Fixed agent selector to use dynamic AgentRegistry
- [x] Added task cancellation mechanism (Ctrl+X, /cancel)
- [x] Implemented streaming UI with real-time updates
- [x] Implemented markdown rendering with pulldown-cmark

#### Phase 2: LLM & Agent Runtime (95%)
- [x] OpenAI LLM client integration with streaming
- [x] Agent runtime with command loop
- [x] Agent lifecycle management (spawn, shutdown, state tracking)
- [x] Event system (Started, Completed, Message, Error, StateChanged)
- [x] Built-in agents defined (Planner, Coder, Reviewer, Tester, Explorer, Integrator)

#### Phase 3: Orchestration (85%)
- [x] Dynamic router with LLM-based task analysis
- [x] Task planner with decomposition into subtasks
- [x] Executor with agent pool management
- [x] Parallel execution support via JoinSet
- [x] Auto-routing and manual mode support

#### Phase 4: Persistence & Shared Memory (75%)
- [x] SessionStore with save/load/list/delete
- [x] MemoryStore with scoped key-value storage
- [x] Atomic writes for session saving
- [x] Auto-save on configurable interval
- [x] Shared memory with hierarchical namespaces
- [ ] UI integration for persistence commands
- [ ] Shared memory connected to agent runtime

#### Testing & Quality (60%)
- [x] 140 unit tests across all modules
- [x] Tests for types, config, agent runtime, orchestrator, pool, TUI components
- [ ] Integration tests for agent workflows
- [ ] Mock LLM client for testing without API key
- [ ] End-to-end tests
- [ ] Test coverage reporting
- [ ] CI/CD pipeline with automated testing

### 🚧 In Progress
- [ ] OpenAI LLM client integration
- [ ] Agent runtime implementation
- [ ] Persistence UI integration (save/load sessions via commands)
- [ ] Shared memory integration with agent runtime
- [ ] Fixing 39 compiler warnings (unused code)

### ⏳ Pending

#### Core Features
- [ ] Built-in agents (Coder, Reviewer, Tester, Explorer, Planner)
- [ ] Dynamic router
- [ ] User override system
- [ ] Agent pool with concurrent execution
- [ ] Shared memory implementation
- [ ] Persistence layer
- [ ] Memory management UI
- [ ] Agent flow visualization
- [ ] Themes and advanced configuration
- [ ] Custom keybindings from config

#### Testing & Quality
- [ ] Unit tests for orchestrator module
- [ ] Unit tests for agent runtime
- [ ] Unit tests for TUI components
- [ ] Integration tests for agent workflows
- [ ] Mock LLM client for testing
- [ ] End-to-end tests
- [ ] Test coverage reporting
- [ ] CI/CD pipeline with automated testing
#### Advanced Features
- [ ] MCP support
- [ ] Multiple LLM providers (Anthropic, local models)
- [ ] Plugin system for custom agents
- [ ] GitHub integration

## Architecture Overview

Expand Down Expand Up @@ -600,21 +624,21 @@ mockall = "0.13"

## Development Roadmap

### MVP (Week 1-2)
### MVP (Week 1-2) - 90% Complete
- [x] Basic TUI with chat
- [ ] OpenAI integration
- [x] 3 core agents (Coder, Planner, Explorer) - Defined, not runtime
- [x] Manual mode - UI support implemented
- [ ] Simple auto-routing
- [ ] Session persistence
- [ ] Basic memory

### Advanced (Week 3-4)
- [ ] Parallel agent execution
- [x] OpenAI integration
- [x] 6 core agents (Coder, Planner, Reviewer, Tester, Explorer, Integrator) - Defined and runtime-ready
- [x] Manual mode - Fully functional
- [x] Simple auto-routing - Implemented with LLM analysis
- [x] Session persistence - Store implemented, UI integration pending
- [x] Basic memory - Store implemented, UI integration pending

### Advanced (Week 3-4) - 40% Complete
- [x] Parallel agent execution - JoinSet-based execution
- [ ] Agent flow visualization
- [ ] Advanced memory management
- [ ] Custom agents via config
- [ ] Themes system
- [ ] Advanced memory management UI
- [x] Custom agents via config - Config structure ready
- [ ] Themes system - Config structure ready, implementation pending

### Future
- [ ] MCP support
Expand Down
33 changes: 28 additions & 5 deletions agent-tui/src/tui/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -648,10 +648,13 @@ impl App {
/mode auto - Enable automatic agent routing
/mode manual - Enable manual agent selection
/agent <name> - Select specific agent (manual mode)
/agents - List all available agents
/clear - Clear current session
/save <name> - Save current session
/load <id> - Load session by ID
/new - Start a new session
/save <name> - Save current session to file
/load <id> - Load a session by ID
/sessions - List all saved sessions
/delete <id> - Delete a session by ID
/remember <key> <value> - Store a value in session memory
/recall <key> - Retrieve a value from session memory
/forget <key> - Delete a value from session memory
Expand Down Expand Up @@ -771,12 +774,12 @@ impl App {
self.chat.add_message(msg);
}
"/save" => {
if let Some(name) = args.first() {
self.session.title = name.to_string();
if !args.is_empty() {
self.session.title = args.join(" ");
}
match self.session_store.save(&self.session).await {
Ok(_) => {
let msg = Message::system(&format!("Session '{}' saved successfully.", self.session.title));
let msg = Message::system(&format!("Session '{}' saved successfully (ID: {}).", self.session.title, self.session.id));
self.session.add_message(msg.clone());
self.chat.add_message(msg);
}
Expand Down Expand Up @@ -838,6 +841,26 @@ impl App {
}
}
}
"/delete" => {
if let Some(id) = args.first() {
match self.session_store.delete(id).await {
Comment on lines +845 to +846
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Validate session IDs before deleting files

This passes raw command input directly to session_store.delete(id), and the store builds file paths by joining session_id into the base directory. Without input validation, IDs containing path segments like ../ can resolve outside the sessions folder and delete unintended .json files, so /delete should reject non-ID characters (or canonicalize/guard paths) before calling delete.

Useful? React with 👍 / 👎.

Ok(_) => {
let msg = Message::system(&format!("Session '{}' deleted successfully.", id));
self.session.add_message(msg.clone());
Comment on lines +846 to +849
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Report missing sessions as errors in /delete

The /delete handler treats every Ok(()) from SessionStore::delete as a successful deletion, but SessionStore::delete returns Ok(()) even when the target file does not exist. In practice, a mistyped or stale session ID will still show deleted successfully, which hides operator mistakes and makes it hard to trust cleanup actions.

Useful? React with 👍 / 👎.

self.chat.add_message(msg);
}
Err(e) => {
let msg = Message::system(&format!("Failed to delete session: {}", e));
self.session.add_message(msg.clone());
self.chat.add_message(msg);
}
}
} else {
let msg = Message::system("Usage: /delete <session_id>");
self.session.add_message(msg.clone());
self.chat.add_message(msg);
}
}
"/remember" => {
if args.len() >= 2 {
let key = args[0];
Expand Down