Extract _get_api_key() and _create_provider_instance() as a single internal
factory that handles all provider types, including MOCK. Both create_llm() and
create_ai_provider() now delegate to _create_provider_instance(), eliminating
the duplicated if/elif provider-switching chains and the divergence between the
two code paths. Adding a new provider now requires touching exactly one place.
Key changes:
- New _get_api_key(provider_type) consolidates API key lookup and validation
that was previously duplicated across create_llm(), _create_provider_llm(),
and every branch of create_ai_provider().
- New _create_provider_instance() is the unified raw-LLM factory, replacing
_create_provider_llm() and the specialised adapter constructors in
create_ai_provider(). MOCK is now handled here via FakeListLLM.
- create_ai_provider() wraps all providers uniformly in LangChainChatProvider
instead of using specialised adapters (OpenAIChatProvider, AnthropicChatProvider,
GoogleChatProvider, OpenRouterChatProvider) for the four primary providers.
- create_llm() drops its own API key validation block; validation now happens
inside _create_provider_instance() via _get_api_key().
- All BDD scenarios updated: _create_provider_llm references become
_create_provider_instance, and provider-type assertions on create_ai_provider
results are updated to LangChainChatProvider.
Review fixes (Cycle 2):
- Add _coerce_env_bool() for consistent boolean env-var coercion in
CLEVERAGENTS_ALLOW_MOCK_PROVIDER checks.
- Introduce _ApiKeyMissing sentinel to distinguish 'not provided' from None
in provider configuration.
- Set MOCK supports_streaming=False in DEFAULT_CAPABILITIES to align with
FakeListLLM semantics.
- Make MOCK is_configured conditional on CLEVERAGENTS_ALLOW_MOCK_PROVIDER.
- Use FakeListLLM(responses=['mock response'] * 10) to prevent IndexError
in multi-step workflows.
- Strip max_retries from kwargs before passing to LangChain constructors.
- Extract _resolve_provider_type() helper shared by create_llm() and
create_ai_provider() to reduce duplication and improve readability.
- Ensure __api_key_sentinel flows through factory_kwargs even when api_key
is None, avoiding double _get_api_key() calls.
- Add CHANGELOG env-var documentation and providers.md env-var table.
- Resolve template DB lock issues by persisting in-memory SQLite via
VACUUM INTO instead of direct file creation on tmpfs.
ISSUES CLOSED: #10949
Add a ProviderType.OPENROUTER branch to ProviderRegistry._create_provider_llm()
so that create_llm("openrouter") returns a configured LangChain BaseLanguageModel
instead of raising ValueError("Unsupported provider type: openrouter").
The new branch creates a ChatOpenAI instance with openai_api_base set to the
OpenRouter gateway URL and openai_api_key from settings, matching the credentials
used by create_ai_provider(). Optional default_headers are sanitized to
dict[str, str] (string-coerced keys and values) via inline dict comprehension.
Also includes review fixes:
- M1: Added openrouter_organization header support (HTTP-Referer, X-Title)
- m1: Added explicit ValueError when openrouter_api_key is empty/missing
- M2: Added openai_api_key assertions to all OpenRouter BDD scenarios
- m2: Added default model fallback scenario for model_id=None
- m4: Added empty default_headers edge case scenario
- m5: Added extra kwargs forwarding scenario (temperature)
- m6: Added empty API key error scenario
- m7: Added negative assertion verifying original integer key 123 is absent
- m8: Added openai_api_key assertion to sanitized headers scenario
ISSUES CLOSED: #10948
Previously, ProviderRegistry.create_ai_provider() dispatched to dedicated
provider classes only for Google and OpenRouter. For OpenAI and Anthropic,
execution fell through to the generic LangChainChatProvider factory, leaving
OpenAIChatProvider and AnthropicChatProvider as dead code in production.
This commit:
- Adds ProviderType.OPENAI dispatch branch in create_ai_provider() to
instantiate OpenAIChatProvider with the configured API key and model
- Adds ProviderType.ANTHROPIC dispatch branch in create_ai_provider() to
instantiate AnthropicChatProvider with the configured API key and model
- Both branches raise ValueError with the missing env var name when the
API key is not configured, consistent with Google and OpenRouter branches
- Updates src/cleveragents/providers/llm/__init__.py to export all four
dedicated provider classes (OpenAIChatProvider, AnthropicChatProvider,
GoogleChatProvider, OpenRouterChatProvider)
- Updates provider_registry_coverage.feature to assert that create_ai_provider
returns OpenAIChatProvider for openai and AnthropicChatProvider for anthropic
- Adds new scenarios for Anthropic dispatch and missing-key error paths for
both OpenAI and Anthropic
- Updates the 'AI provider exposes working llm factory' scenario to use groq
(which still goes through the generic LangChainChatProvider path) since
OpenAI now uses the dedicated class
- Adds step definitions for OpenAIChatProvider and AnthropicChatProvider
isinstance assertions
Closes#3427