From 85ae319690ea4e7f025ab071436b5f7f1f9d41be Mon Sep 17 00:00:00 2001 From: vikingowl Date: Fri, 17 Oct 2025 00:44:07 +0200 Subject: [PATCH] docs(architecture): clarify provider boundaries and MCP topology --- docs/architecture.md | 46 +++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 43 insertions(+), 3 deletions(-) diff --git a/docs/architecture.md b/docs/architecture.md index 9c32d08..2b94a85 100644 --- a/docs/architecture.md +++ b/docs/architecture.md @@ -37,9 +37,9 @@ A simplified diagram of how components interact: - `owlen-core`: Defines the `LlmProvider` abstraction, routing, configuration, session state, encryption, and the MCP client layer. This crate is UI-agnostic and must not depend on concrete providers, terminals, or blocking I/O. - `owlen-tui`: Hosts all terminal UI behaviour (event loop, rendering, input modes) while delegating business logic and provider access back to `owlen-core`. - `owlen-cli`: Small entry point that parses command-line options, resolves configuration, selects providers, and launches either the TUI or headless agent flows by calling into `owlen-core`. -- `owlen-mcp-llm-server`: Runs concrete providers (e.g., Ollama) behind an MCP boundary, exposing them as `generate_text` tools. This crate owns provider-specific wiring and process sandboxing. -- `owlen-mcp-server`: Generic MCP server for file operations and resource management. -- `owlen-ollama`: Direct Ollama provider implementation (legacy, used only by MCP servers). +- `owlen-mcp-llm-server`: Runs concrete providers (e.g., Ollama Local, Ollama Cloud) behind an MCP boundary, exposing them as `generate_text` tools. This crate owns provider-specific wiring and process sandboxing. +- `owlen-mcp-server`: Generic MCP server for file operations, resource projection, and other non-LLM tools. +- `owlen-providers`: Houses concrete provider adapters (today: Ollama local + cloud) that the MCP servers embed. ### Boundary Guidelines @@ -47,6 +47,46 @@ A simplified diagram of how components interact: - **owlen-cli**: Only orchestrates startup/shutdown. Avoid adding business logic; when a new command needs behaviour, implement it in `owlen-core` or another library crate and invoke it from the CLI. - **owlen-mcp-llm-server**: The only crate that should directly talk to Ollama (or other provider processes). TUI/CLI code communicates with providers exclusively through MCP clients in `owlen-core`. +## Provider Boundaries & MCP Topology + +Owlen’s runtime is intentionally layered so that user interfaces never couple to provider-specific code. The flow can be visualised as: + +``` +[owlen-tui] / [owlen-cli] + │ + │ chat + model requests + ▼ +[owlen-core::ProviderManager] ──> Arc + │ ▲ + │ │ implements `ModelProvider` + ▼ │ +[owlen-core::mcp::RemoteMcpClient] ─────┘ + │ (JSON-RPC over stdio) + ▼ +┌───────────────────────────────────────────────────────────┐ +│ MCP Process Boundary (spawned per provider) │ +│ │ +│ crates/mcp/llm-server ──> owlen-providers::ollama::* │ +│ crates/mcp/server ──> filesystem & workspace tools │ +│ crates/mcp/prompt-server ─> template rendering helpers │ +└───────────────────────────────────────────────────────────┘ +``` + +- **ProviderManager (owlen-core)** keeps the registry of `ModelProvider` implementations, merges model catalogues, and caches health. Local Ollama and Cloud Ollama appear as separate providers whose metadata is merged for the UI. +- **RemoteMcpClient (owlen-core)** is the default `ModelProvider`. It implements both the MCP client traits and the `ModelProvider` interface, allowing it to bridge chat streams back into the ProviderManager without exposing transport details. +- **MCP servers (crates/mcp/\*)** are short-lived binaries with narrowly scoped responsibilities: + - `crates/mcp/llm-server` wraps `owlen-providers::ollama` backends and exposes `generate_text` / `list_models`. + - `crates/mcp/server` offers tool calls (file reads/writes, search). + - `crates/mcp/prompt-server` renders prompt templates. +- **owlen-providers** contains the actual provider adapters (Ollama local & cloud today). MCP servers embed these adapters directly; nothing else should reach into them. + +### Health & Model Discovery Flow + +1. Frontends call `ProviderManager::list_all_models()`. The manager fans out health checks to each registered provider (including the MCP client) and collates their models into a single list tagged with scope (`Local`, `Cloud`, etc.). +2. The TUI model picker (`owlen-tui/src/widgets/model_picker.rs`) reads those annotated entries to drive filters like **Local**, **Cloud**, and **Available**. +3. When the user kicks off a chat, the TUI emits a request that flows through `Session::send_message`, which delegates to `ProviderManager::generate`. The selected provider (usually `RemoteMcpClient`) streams chunks back across the MCP transport and the manager updates health status based on success or failure. +4. Tool invocations travel the same transport: the MCP client sends tool calls to `crates/mcp/server`, and responses surface as consent prompts or streamed completions in the UI. + ## MCP Architecture (Phase 10) As of Phase 10, OWLEN uses a **MCP-only architecture** where all LLM interactions go through the Model Context Protocol: