# Architecture

QueryMT is designed with a modular and extensible architecture to provide a flexible foundation for interacting with Large Language Models. Understanding its key components will help you leverage the library effectively.

## Core Abstractions

At the heart of QueryMT are several key traits that define the contract for LLM interactions:

*   **`querymt::LLMProvider`**: This is the central trait that all LLM provider implementations must conform to. It combines capabilities for chat, text completion, and embeddings into a single, unified interface by extending `querymt::chat::BasicChatProvider`, `querymt::chat::ToolChatProvider`, `querymt::completion::CompletionProvider`, and `querymt::embedding::EmbeddingProvider`. It also includes methods for listing available tools (`tools()`) and calling them (`call_tool()`).
    *   Source: `crates/querymt/src/lib.rs`

*   **`querymt::HTTPLLMProvider`**: A specialized trait for LLM providers that are accessed over HTTP. It defines methods for constructing HTTP requests and parsing HTTP responses for chat, completion, and embedding operations by extending the `http` sub-traits (e.g., `querymt::chat::http::HTTPChatProvider`).
    *   Source: `crates/querymt/src/lib.rs`

## Provider Adapters

*   **`querymt::adapters::LLMProviderFromHTTP`**: This struct acts as an adapter, allowing an `HTTPLLMProvider` (which handles the raw HTTP logic) to be used as a full-fledged `LLMProvider`. It takes care of calling the outbound HTTP mechanism (`fn@querymt::outbound::call_outbound`) and then parsing the response using the `HTTPLLMProvider` implementation.
    *   Source: `crates/querymt/src/adapters.rs`

## Building and Configuring Providers

*   **`querymt::builder::LLMBuilder`**: QueryMT provides a fluent builder pattern for configuring and instantiating `LLMProvider` instances. This builder allows you to set various options such as the model, API keys, temperature, custom parameters, and register tools. It uses a `querymt::plugin::host::PluginRegistry` to find the appropriate factory for the selected provider.
    *   Source: `crates/querymt/src/builder.rs`

## Tool and Function Calling

QueryMT has robust support for LLM tool usage (often called function calling):

*   **`querymt::chat::Tool` / `querymt::chat::FunctionTool`**: These structs define the schema of tools that an LLM can use.
*   **`querymt::tool_decorator::CallFunctionTool`**: A trait that your host-side functions must implement to be callable by the LLM. It includes a method to describe the tool (`descriptor()`) and a method to execute it (`call()`).
*   **`querymt::tool_decorator::ToolEnabledProvider`**: A decorator that wraps an existing `LLMProvider` and injects tool-calling capabilities. It manages a registry of `CallFunctionTool` implementations and handles the interaction logic when an LLM decides to call a tool.
    *   Source: `crates/querymt/src/tool_decorator.rs`

## Plugin System

A core strength of QueryMT is its plugin system, enabling easy addition of new LLM providers. The system has been unified to support different plugin types through a single registry.

*   **`querymt::plugin::LLMProviderFactory`**: A trait that plugin authors implement. Its primary role is to create an `LLMProvider` instance from a given configuration. It also provides metadata like the plugin name and configuration schema.
*   **`querymt::plugin::http::HTTPLLMProviderFactory`**: A specialized factory for plugins that expose an `HTTPLLMProvider`.

*   **`querymt::plugin::host::PluginRegistry`**: A central registry that discovers, loads, and manages `LLMProviderFactory` instances from a configuration file. The registry itself is loader-agnostic; it stores `PluginLoader` trait objects and uses them to resolve provider entries.
    *   **`querymt::plugin::host::PluginLoader`**: A trait for systems that can load a specific `querymt::plugin::host::PluginType`. QueryMT provides implementations for:
        *   **Native Plugins:** (`querymt::plugin::host::native::NativeLoader`) Loads plugins from shared libraries (`.so`, `.dll`, `.dylib`).
        *   **WASM Plugins via Extism:** (`querymt::plugin::extism_impl::host::ExtismLoader`) Loads plugins compiled to WebAssembly and executed via Extism, offering sandboxing and portability.
    *   **`querymt::dynamic::PluginRegistryDynamicExt`**: A convenience extension layer that registers the built-in dynamic loaders for common applications.
    *   Sources: `crates/querymt/src/plugin/host/mod.rs`, `crates/querymt/src/dynamic.rs`, `crates/querymt/src/plugin/host/native.rs`, `crates/querymt/src/plugin/extism_impl/host/loader.rs`

## Outbound HTTP Communication

*   The `outbound.rs` module provides a common function (`fn@querymt::outbound::call_outbound`) for making HTTP requests. This is used by HTTP-based providers and adapters. It's designed to work in both native environments (using `reqwest`) and potentially WASM environments.
    *   Source: `crates/querymt/src/outbound.rs`

## Error Handling

*   QueryMT defines a comprehensive `querymt::error::LLMError` to represent various issues that can occur, such as HTTP errors, authentication problems, provider-specific errors, and plugin issues.
    *   Source: `crates/querymt/src/error.rs`

## High-Level Flow

1.  An application initializes a `querymt::plugin::host::PluginRegistry` from a configuration file (e.g., `providers.toml`).
2.  For the common dynamic-plugin path, it attaches the built-in loaders with `querymt::dynamic::PluginRegistryDynamicExt::with_dynamic_loaders()`.
3.  The registry calls `load_all_plugins()`, which iterates through the configured providers. For each provider, it determines its type (e.g., local Wasm, OCI image, native library) and uses the appropriate `PluginLoader` to load it and create an `LLMProviderFactory`.
4.  The application uses `registry.builder("openai")` to create a registry-bound builder, or `querymt::provider("openai")` to create an unbound builder.
5.  The registry-bound builder finishes with `build()`, while the unbound builder finishes with `build_with(&registry)`.
6.  The builder looks up the `LLMProviderFactory` from the registry using the provider name.
7.  The builder merges defaults from `[providers.config]`, overlays explicit builder settings, prunes the merged config by schema, and then calls the factory's `from_config()` method.
8.  If tools were added via `add_tool()`, the base provider is wrapped in a `querymt::tool_decorator::ToolEnabledProvider`.
9.  If a validator is set, the provider is further wrapped in a `querymt::validated_llm::ValidatedLLM`.
10. The application can then use the resulting `Box<dyn LLMProvider>` instance to perform chat, completion, or embedding operations.

This layered and decoupled design makes QueryMT adaptable and easy to extend.
