feat(core): Introduce Message enum for async communication

This commit is contained in:
2025-12-26 19:08:16 +01:00
parent abbda81659
commit b0e65e4041
6 changed files with 162 additions and 2 deletions

View File

@@ -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.
---
## [~] Track: Owlen Evolution - From TUI to Agentic Workstation
*Link: [./conductor/tracks/owlen_evolution_20251226/](./conductor/tracks/owlen_evolution_20251226/)*

View File

@@ -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."
}

View File

@@ -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<Mutex<AppState>>` 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)

View File

@@ -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).

View File

@@ -1,4 +1,5 @@
mod commands;
mod messages;
use clap::{Parser, ValueEnum};
use color_eyre::eyre::{Result, eyre};

View File

@@ -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"),
}
}
}