feat(core): Introduce Message enum for async communication
This commit is contained in:
@@ -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/)*
|
||||
|
||||
8
conductor/tracks/owlen_evolution_20251226/metadata.json
Normal file
8
conductor/tracks/owlen_evolution_20251226/metadata.json
Normal 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."
|
||||
}
|
||||
55
conductor/tracks/owlen_evolution_20251226/plan.md
Normal file
55
conductor/tracks/owlen_evolution_20251226/plan.md
Normal 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)
|
||||
45
conductor/tracks/owlen_evolution_20251226/spec.md
Normal file
45
conductor/tracks/owlen_evolution_20251226/spec.md
Normal 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).
|
||||
@@ -1,4 +1,5 @@
|
||||
mod commands;
|
||||
mod messages;
|
||||
|
||||
use clap::{Parser, ValueEnum};
|
||||
use color_eyre::eyre::{Result, eyre};
|
||||
|
||||
49
crates/app/cli/src/messages.rs
Normal file
49
crates/app/cli/src/messages.rs
Normal 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"),
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user