# Owlen Architecture This document provides a high-level overview of the Owlen architecture. Its purpose is to help developers understand how the different parts of the application fit together. ## Core Concepts The architecture is designed to be modular and extensible, centered around a few key concepts: - **Providers**: Connect to various LLM APIs (Ollama, OpenAI, etc.). - **Session**: Manages the conversation history and state. - **TUI**: The terminal user interface, built with `ratatui`. - **Events**: A system for handling user input and other events. ## Component Interaction A simplified diagram of how components interact: ``` [User Input] -> [Event Loop] -> [Session Controller] -> [Provider] ^ | | v [TUI Renderer] <------------------------------------ [API Response] ``` 1. **User Input**: The user interacts with the TUI, generating events (e.g., key presses). 2. **Event Loop**: The main event loop in `owlen-tui` captures these events. 3. **Session Controller**: The event is processed, and if it's a prompt, the session controller sends a request to the current provider. 4. **Provider**: The provider formats the request for the specific LLM API and sends it. 5. **API Response**: The LLM API returns a response. 6. **TUI Renderer**: The response is processed, the session state is updated, and the TUI is re-rendered to display the new information. ## Crate Breakdown - `owlen-core`: Defines the core traits and data structures, like `Provider` and `Session`. Also contains the MCP client implementation. - `owlen-tui`: Contains all the logic for the terminal user interface, including event handling and rendering. - `owlen-cli`: The command-line entry point, responsible for parsing arguments and starting the TUI. - `owlen-mcp-llm-server`: MCP server that wraps Ollama providers and exposes them via the Model Context Protocol. - `owlen-mcp-server`: Generic MCP server for file operations and resource management. - `owlen-ollama`: Direct Ollama provider implementation (legacy, used only by MCP servers). ## MCP Architecture (Phase 10) As of Phase 10, OWLEN uses a **MCP-only architecture** where all LLM interactions go through the Model Context Protocol: ``` [TUI/CLI] -> [RemoteMcpClient] -> [MCP LLM Server] -> [Ollama Provider] -> [Ollama API] ``` ### Benefits of MCP Architecture 1. **Separation of Concerns**: The TUI/CLI never directly instantiates provider implementations. 2. **Process Isolation**: LLM interactions run in a separate process, improving stability. 3. **Extensibility**: New providers can be added by implementing MCP servers. 4. **Multi-Transport**: Supports STDIO, HTTP, and WebSocket transports. 5. **Tool Integration**: MCP servers can expose tools (file operations, web search, etc.) to the LLM. ### MCP Communication Flow 1. **Client Creation**: `RemoteMcpClient::new()` spawns an MCP server binary via STDIO. 2. **Initialization**: Client sends `initialize` request to establish protocol version. 3. **Tool Discovery**: Client calls `tools/list` to discover available LLM operations. 4. **Chat Requests**: Client calls the `generate_text` tool with chat parameters. 5. **Streaming**: Server sends progress notifications during generation, then final response. 6. **Response Handling**: Client skips notifications and returns the final text to the caller. ### Cloud Provider Support For Ollama Cloud providers, the MCP server accepts an `OLLAMA_URL` environment variable: ```rust let env_vars = HashMap::from([ ("OLLAMA_URL".to_string(), "https://cloud-provider-url".to_string()) ]); let config = McpServerConfig { command: "path/to/owlen-mcp-llm-server", env: env_vars, transport: "stdio", ... }; let client = RemoteMcpClient::new_with_config(&config)?; ``` ## Session Management The session management system is responsible for tracking the state of a conversation. The two main structs are: - **`Conversation`**: Found in `owlen-core`, this struct holds the messages of a single conversation, the model being used, and other metadata. It is a simple data container. - **`SessionController`**: This is the high-level controller that manages the active conversation. It handles: - Storing and retrieving conversation history via the `ConversationManager`. - Managing the context that is sent to the LLM provider. - Switching between different models. - Sending requests to the provider and handling the responses (both streaming and complete). When a user sends a message, the `SessionController` adds the message to the current `Conversation`, sends the updated message list to the `Provider`, and then adds the provider's response to the `Conversation`. ## Event Flow The event flow is managed by the `EventHandler` in `owlen-tui`. It operates in a loop, waiting for events and dispatching them to the active application (`ChatApp` or `CodeApp`). 1. **Event Source**: Events are primarily generated by `crossterm` from user keyboard input. Asynchronous events, like responses from a `Provider`, are also fed into the event system via a `tokio::mpsc` channel. 2. **`EventHandler::next()`**: The main application loop calls this method to wait for the next event. 3. **Event Enum**: Events are defined in the `owlen_tui::events::Event` enum. This includes `Key` events, `Tick` events (for UI updates), and `Message` events (for async provider data). 4. **Dispatch**: The application's `run` method matches on the `Event` type and calls the appropriate handler function (e.g., `dispatch_key_event`). 5. **State Update**: The handler function updates the application state based on the event. For example, a key press might change the `InputMode` or modify the text in the input buffer. 6. **Re-render**: After the state is updated, the UI is re-rendered to reflect the changes. ## TUI Rendering Pipeline The TUI is rendered on each iteration of the main application loop in `owlen-tui`. The process is as follows: 1. **`tui.draw()`**: The main loop calls this method, passing the current application state. 2. **`Terminal::draw()`**: This method, from `ratatui`, takes a closure that receives a `Frame`. 3. **UI Composition**: Inside the closure, the UI is built by composing `ratatui` widgets. The root UI is defined in `owlen_tui::ui::render`, which builds the main layout and calls other functions to render specific components (like the chat panel, input box, etc.). 4. **State-Driven Rendering**: Each rendering function takes the current application state as an argument. It uses this state to decide what and how to render. For example, the border color of a panel might change if it is focused. 5. **Buffer and Diff**: `ratatui` does not draw directly to the terminal. Instead, it renders the widgets to an in-memory buffer. It then compares this buffer to the previous buffer and only sends the necessary changes to the terminal. This is highly efficient and prevents flickering.