# `cleveragents.providers` — AI Provider Registry The `providers` package implements the AI provider registry that discovers, selects, and instantiates LLM backends. It follows the provider plugin architecture described in ADR-008 and wires into the actor system via `AIProviderInterface`. --- ## Overview The registry discovers configured providers from environment variables and `Settings`, selects a default using a configurable fallback chain, and creates `LangChain` LLM instances or `AIProviderInterface` wrappers on demand. ```python from cleveragents.providers.registry import get_provider_registry registry = get_provider_registry() provider = registry.create_ai_provider() # uses default provider llm = registry.create_llm() # returns a LangChain BaseLanguageModel ``` --- ## `ProviderType` ```python class ProviderType(StrEnum): OPENAI = "openai" ANTHROPIC = "anthropic" GOOGLE = "google" AZURE = "azure" OPENROUTER = "openrouter" GEMINI = "gemini" COHERE = "cohere" GROQ = "groq" TOGETHER = "together" MOCK = "mock" ``` String enum of all supported provider identifiers. Values are used in `CLEVERAGENTS_DEFAULT_PROVIDER` and in actor YAML `provider:` fields. --- ## `ProviderCapabilities` ```python @dataclass(frozen=True) class ProviderCapabilities: supports_streaming: bool = True supports_tool_calls: bool = False supports_vision: bool = False max_context_length: int = 4096 supports_json_mode: bool = False ``` Immutable capability metadata for a provider. Used by the actor system to gate features (e.g., tool calls, vision inputs) at runtime. ### Default capabilities by provider | Provider | Streaming | Tool calls | Vision | Context (tokens) | JSON mode | |----------|-----------|------------|--------|-----------------|-----------| | OpenAI | ✓ | ✓ | ✓ | 128 000 | ✓ | | Anthropic | ✓ | ✓ | ✓ | 200 000 | ✗ | | Google / Gemini | ✓ | ✓ | ✓ | 1 000 000 | ✓ | | Azure OpenAI | ✓ | ✓ | ✓ | 128 000 | ✓ | | OpenRouter | ✓ | ✓ | ✓ | 128 000 | ✓ | | Cohere | ✓ | ✓ | ✗ | 128 000 | ✗ | | Groq | ✓ | ✓ | ✗ | 32 000 | ✓ | | Together | ✓ | ✓ | ✗ | 32 000 | ✗ | | Mock | ✗ | ✗ | ✗ | 4 096 | ✗ | --- ## `ProviderInfo` ```python class ProviderInfo(BaseModel): provider_type: ProviderType name: str api_key_env_var: str default_model: str capabilities: ProviderCapabilities is_configured: bool ``` Read-only snapshot of a provider's registration state. Returned by `ProviderRegistry.get_provider_info()` and `get_all_providers()`. --- ## `ProviderRegistry` Central registry for discovering and managing AI providers. ```python from cleveragents.providers.registry import ProviderRegistry registry = ProviderRegistry() # uses global Settings registry = ProviderRegistry(settings=my_cfg) # override settings ``` ### Default models | Provider | Default model | |----------|--------------| | OpenAI | `gpt-4o` | | Anthropic | `claude-sonnet-4-20250514` | | Google / Gemini | `gemini-2.0-flash` | | Azure | `gpt-4o` | | OpenRouter | `anthropic/claude-sonnet-4-20250514` | | Cohere | `command-r-plus` | | Groq | `llama-3.1-70b-versatile` | | Together | `meta-llama/Llama-3.1-70B-Instruct-Turbo` | | Mock | `mock-gpt` | ### Provider fallback order When `CLEVERAGENTS_DEFAULT_PROVIDER` is not set, the registry selects the first configured provider in this order: `openai → anthropic → google → azure → openrouter → groq → together → cohere` ### Methods #### `get_configured_providers() → list[ProviderInfo]` Returns only providers that have valid API credentials configured. #### `get_all_providers() → list[ProviderInfo]` Returns all known providers regardless of configuration state. #### `get_provider_info(provider_type) → ProviderInfo | None` Look up a provider by `ProviderType` or string name. Returns `None` if the provider is unknown. #### `is_provider_configured(provider_type) → bool` Returns `True` if the provider has a non-empty API key in `Settings`. #### `get_default_provider_type() → ProviderType | None` Resolves the default provider using this precedence: 1. `CLEVERAGENTS_DEFAULT_PROVIDER` environment variable 2. `Settings.default_provider` 3. First configured provider in fallback order Returns `None` if no provider is configured. #### `get_default_model(provider_type=None) → str | None` Resolves the default model using this precedence: 1. `CLEVERAGENTS_DEFAULT_MODEL` environment variable 2. `Settings.default_model` 3. Provider's built-in default model #### `create_llm(provider_type=None, model_id=None, **kwargs) → BaseLanguageModel` Creates a LangChain `BaseLanguageModel` for the specified provider and model. ```python llm = registry.create_llm("anthropic", model_id="claude-3-haiku-20240307") ``` Raises `ValueError` if no provider is configured or the provider name is unknown. #### `create_ai_provider(provider_type=None, model_id=None, max_retries=3) → AIProviderInterface` Creates an `AIProviderInterface` implementation. **All** providers are now wrapped uniformly in `LangChainChatProvider`; the raw LLM instantiation is delegated to `_create_provider_instance()` internally. Previously, some providers (Google, OpenRouter) returned specialised adapter classes, but the unified factory now handles every provider type consistently. ```python provider = registry.create_ai_provider("openai", model_id="gpt-4o-mini") ``` --- ## `LangChainChatProvider` **Module:** `cleveragents.providers.llm.langchain_chat_provider` Wraps a LangChain chat model with the `AIProviderInterface` protocol and wires it into `PlanGenerationGraph`. ```python class LangChainChatProvider(AIProviderInterface): def __init__( self, *, name: str, model_id: str, llm_factory: Callable[[str], BaseLanguageModel], max_retries: int = 3, supports_streaming: bool = True, progress_map: dict[str, int] | None = None, ) -> None: ... @property def name(self) -> str: ... @name.setter def name(self, value: str) -> None: ... @property def model_id(self) -> str: ... @model_id.setter def model_id(self, value: str) -> None: ... ``` > **Note (v3.7.0+):** `name` and `model_id` are now mutable properties with > setters, fixing an `AttributeError` when `PlanService` attempted to resolve > provider names after instantiation. (#1553) --- ## Module-level helpers ### `get_provider_registry(settings=None) → ProviderRegistry` Returns the global singleton `ProviderRegistry`. Pass `settings` to force a fresh instance (useful in tests). ### `reset_provider_registry() → None` Clears the global singleton. Call this between tests to ensure clean state. ### `resolve_provider_by_name(name, settings=None) → AIProviderInterface` Convenience function that resolves a provider by string name and raises a descriptive `ValueError` if the provider is not configured. ```python from cleveragents.providers.registry import resolve_provider_by_name provider = resolve_provider_by_name("anthropic") ``` --- ## Environment variables | Variable | Description | |----------|-------------| | `CLEVERAGENTS_DEFAULT_PROVIDER` | Pin the global provider (e.g. `openai`) | | `CLEVERAGENTS_DEFAULT_MODEL` | Pin the global model ID | | `OPENAI_API_KEY` | OpenAI credentials | | `ANTHROPIC_API_KEY` | Anthropic credentials | | `GOOGLE_API_KEY` / `GOOGLE_GENAI_API_KEY` | Google credentials | | `AZURE_OPENAI_API_KEY` | Azure OpenAI credentials | | `AZURE_OPENAI_ENDPOINT` | Azure OpenAI endpoint URL | | `AZURE_OPENAI_DEPLOYMENT` | Azure deployment name | | `OPENROUTER_API_KEY` | OpenRouter credentials | | `GEMINI_API_KEY` / `GOOGLE_GEMINI_API_KEY` | Gemini credentials | | `COHERE_API_KEY` | Cohere credentials | | `GROQ_API_KEY` | Groq credentials | | `TOGETHER_API_KEY` | Together AI credentials | | `CLEVERAGENTS_TESTING_USE_MOCK_AI` | Force mock provider in tests | | `CLEVERAGENTS_ALLOW_MOCK_PROVIDER` | Enable MOCK provider for testing (set to true) | --- ## ASV Performance Benchmarks The `benchmarks/` directory contains ASV (airspeed velocity) benchmark suites for the providers module. Run them with: ```bash nox -s benchmarks # or directly: asv run --config asv.conf.json ``` Benchmarks cover provider discovery, registry initialization, and LLM factory creation latency. Results are tracked over time to detect performance regressions.