diff --git a/conductor/tracks.md b/conductor/tracks.md index b0b15a0..3d43689 100644 --- a/conductor/tracks.md +++ b/conductor/tracks.md @@ -1,3 +1,5 @@ -# Project Tracks -This file tracks all major tracks for the project. Each track has its own detailed plan in its respective folder. \ No newline at end of file +--- + +## [~] Track: Owlen Evolution - From TUI to Agentic Workstation +*Link: [./conductor/tracks/owlen_evolution_20251226/](./conductor/tracks/owlen_evolution_20251226/)* diff --git a/conductor/tracks/owlen_evolution_20251226/metadata.json b/conductor/tracks/owlen_evolution_20251226/metadata.json new file mode 100644 index 0000000..b1bcc04 --- /dev/null +++ b/conductor/tracks/owlen_evolution_20251226/metadata.json @@ -0,0 +1,8 @@ +{ + "track_id": "owlen_evolution_20251226", + "type": "feature", + "status": "new", + "created_at": "2025-12-26T12:00:00Z", + "updated_at": "2025-12-26T12:00:00Z", + "description": "Transform Owlen from a blocking TUI into a non-blocking, agentic workstation." +} \ No newline at end of file diff --git a/conductor/tracks/owlen_evolution_20251226/plan.md b/conductor/tracks/owlen_evolution_20251226/plan.md new file mode 100644 index 0000000..4a4dfed --- /dev/null +++ b/conductor/tracks/owlen_evolution_20251226/plan.md @@ -0,0 +1,55 @@ +# Implementation Plan - Owlen Evolution + +## Phase 1: Asynchronous Foundation (The "Non-Blocking" Fix) +- [~] Task: Create `Message` enum and Central Message Hub using `tokio::sync::mpsc` + - Define the `Message` enum to handle UI events, Agent responses, and System notifications. + - Create the channel infrastructure in `main.rs`. +- [ ] Task: Refactor `main.rs` into UI and Engine Loops + - Separate the TUI rendering loop into its own async task or thread. + - Create the Engine loop (Tokio task) to handle `Message` processing. +- [ ] Task: Switch LLM interaction to Streaming-only + - Update the LLM client to use streaming responses. + - Ensure the UI updates incrementally as tokens arrive. +- [ ] Task: Introduce `Arc>` for shared state + - Create `AppState` struct to hold conversation history, current mode, etc. + - Share it between UI and Engine loops safely. +- [ ] Task: Conductor - User Manual Verification 'Phase 1: Asynchronous Foundation (The "Non-Blocking" Fix)' (Protocol in workflow.md) + +## Phase 2: The Agentic Orchestrator (Middleware) +- [ ] Task: Create `AgentManager` struct + - Implement the struct to manage the agent's lifecycle and state. +- [ ] Task: Implement the "Reasoning Loop" (Thought -> Action -> Observation) + - Build the loop logic to process user input, generate thoughts/actions, and handle results. + - Implement Sliding Window context management. + - Implement Context Summarization logic. +- [ ] Task: Develop Tool Registry System + - Define the `Tool` trait. + - Implement a registry to store and retrieve available tools. + - Implement logic to inject tool JSON schemas into the System Prompt. +- [ ] Task: Add Sub-Agent Support + - Allow the Orchestrator to spawn sub-tasks if needed (basic implementation). +- [ ] Task: Conductor - User Manual Verification 'Phase 2: The Agentic Orchestrator (Middleware)' (Protocol in workflow.md) + +## Phase 3: Permission & Mode Engine +- [ ] Task: Define `AppMode` enum + - Add `Normal`, `Plan`, `AcceptAll` variants. + - Integrate `AppMode` into `AppState`. +- [ ] Task: Implement Permission Interceptor + - Create logic to intercept tool calls based on `AppMode`. + - Implement the pause/resume mechanism for the Agent Loop. +- [ ] Task: Implement UI for Permission Requests + - Add a "Status Bar Prompt" component to the TUI. + - Connect the prompt to the Permission Interceptor via the Message Hub. +- [ ] Task: Build "Plan Mode" logic + - Implement the specific logic for batching actions in Plan Mode. +- [ ] Task: Conductor - User Manual Verification 'Phase 3: Permission & Mode Engine' (Protocol in workflow.md) + +## Phase 4: Extension & Integration (The "Gemini-CLI" Layer) +- [ ] Task: Create Dynamic Extension Loader + - Implement scanning of `~/.config/owlen/plugins/`. + - Implement reading of `config.yaml` for tool configuration. +- [ ] Task: Implement JSON-RPC Interface + - Create a standard interface for communicating with external tool binaries/scripts. +- [ ] Task: Integrate External Tools into Registry + - Map external tools to the `Tool` trait using the JSON-RPC bridge. +- [ ] Task: Conductor - User Manual Verification 'Phase 4: Extension & Integration (The "Gemini-CLI" Layer)' (Protocol in workflow.md) \ No newline at end of file diff --git a/conductor/tracks/owlen_evolution_20251226/spec.md b/conductor/tracks/owlen_evolution_20251226/spec.md new file mode 100644 index 0000000..77294e5 --- /dev/null +++ b/conductor/tracks/owlen_evolution_20251226/spec.md @@ -0,0 +1,45 @@ +# Specification: Owlen Evolution – From TUI to Agentic Workstation + +## Overview +Transform Owlen from a blocking TUI into a non-blocking, agentic workstation. This involves decoupling the UI from the LLM logic, implementing a reasoning loop (Thought-Action-Observation), a robust permission system, and an extensible plugin architecture. + +## Functional Requirements + +### 1. Asynchronous Foundation +- **Non-blocking UI:** Separate the Ratatui UI rendering loop from the LLM/Engine logic using `tokio::sync::mpsc`. +- **Streaming Response:** LLM interactions must be streaming-only to prevent UI freezes during long generations. +- **Central Message Hub:** Use a many-to-one or many-to-many communication pattern (via `mpsc`) to synchronize state between the background engine and the UI. + +### 2. Agentic Orchestrator +- **Reasoning Loop:** Implement a core loop that follows the "Thought -> Action -> Observation" pattern. +- **Context Management:** + - **Sliding Window:** Maintain only the most recent N interactions in the immediate context. + - **Summarization:** Use a secondary LLM call to periodically summarize older parts of the conversation to retain long-term state without hitting token limits. +- **Tool Registry:** Define a `Tool` trait and a system to automatically inject tool definitions (JSON Schema) into system prompts. + +### 3. Permission & Mode Engine +- **Modes:** Support `Normal` (default), `Plan` (propose all actions first), and `AcceptAll` (autonomous execution). +- **Permission Interceptor:** A mechanism to pause the agent loop when a tool requires approval. +- **UI Integration:** Requests for permissions must be displayed in the **Status Bar** to avoid obscuring the main conversation. + +### 4. Extension & Integration +- **Hybrid Extension Loader:** + - Scan a default directory (e.g., `~/.config/owlen/plugins/`) for executable extensions. + - Allow manual configuration and overrides via `config.yaml`. +- **JSON-RPC Interface:** Use a standardized JSON-RPC interface for communication with external extensions. + +## Non-Functional Requirements +- **Performance:** UI must remain responsive (60 FPS target for rendering) even during heavy LLM tasks. +- **Safety:** Explicit user consent required for "Write" or "Execute" operations by default. +- **Maintainability:** Clear separation of concerns between `crates/app/ui` and `crates/core/agent`. + +## Acceptance Criteria +- [ ] TUI remains responsive (can scroll/exit) while the model is "thinking" or "generating". +- [ ] Agent can successfully call a registered tool and process its output. +- [ ] User can approve or deny a tool execution via a status bar prompt. +- [ ] Context window manages long conversations via summarization without crashing. +- [ ] External scripts can be loaded as tools and invoked by the agent. + +## Out of Scope +- Implementation of complex multi-agent swarms (keeping to a single orchestrator with sub-task capability). +- Web-based UI (staying purely within TUI). \ No newline at end of file diff --git a/crates/app/cli/src/main.rs b/crates/app/cli/src/main.rs index 792abc2..1ae67d9 100644 --- a/crates/app/cli/src/main.rs +++ b/crates/app/cli/src/main.rs @@ -1,4 +1,5 @@ mod commands; +mod messages; use clap::{Parser, ValueEnum}; use color_eyre::eyre::{Result, eyre}; diff --git a/crates/app/cli/src/messages.rs b/crates/app/cli/src/messages.rs new file mode 100644 index 0000000..370c538 --- /dev/null +++ b/crates/app/cli/src/messages.rs @@ -0,0 +1,49 @@ +use serde::{Deserialize, Serialize}; + +#[derive(Debug, Clone, Serialize, Deserialize)] +pub enum Message { + UserAction(UserAction), + AgentResponse(AgentResponse), + System(SystemNotification), +} + +#[derive(Debug, Clone, Serialize, Deserialize)] +pub enum UserAction { + Input(String), + Command(String), + Exit, +} + +#[derive(Debug, Clone, Serialize, Deserialize)] +pub enum AgentResponse { + Token(String), + ToolCall { name: String, args: String }, + Complete, + Error(String), +} + +#[derive(Debug, Clone, Serialize, Deserialize)] +pub enum SystemNotification { + StateUpdate(String), + Warning(String), +} + +#[cfg(test)] +mod tests { + use super::*; + use tokio::sync::mpsc; + + #[tokio::test] + async fn test_message_channel() { + let (tx, mut rx) = mpsc::channel(32); + + let msg = Message::UserAction(UserAction::Input("Hello".to_string())); + tx.send(msg).await.unwrap(); + + let received = rx.recv().await.unwrap(); + match received { + Message::UserAction(UserAction::Input(s)) => assert_eq!(s, "Hello"), + _ => panic!("Wrong message type"), + } + } +}