fix(providers): wire OpenAIChatProvider and AnthropicChatProvider into ProviderRegistry #3464

Merged
freemo merged 1 commits from fix/backlog-openai-anthropic-provider-registry-integration into master 2026-04-05 21:07:03 +00:00
4 changed files with 101 additions and 6 deletions
+29 -6
View File
@@ -373,10 +373,33 @@ Feature: Provider Registry Coverage
Given I have a ProviderRegistry with OpenAI API key set
And CLEVERAGENTS_DEFAULT_MODEL is not set
When I create an AI provider for provider "openai"
Then the provider registry AI provider should be a LangChainChatProvider
Then the provider registry AI provider should be an OpenAIChatProvider
And the provider registry AI provider name should be "openai"
And the provider registry AI provider model_id should be "gpt-4o"
@unit @providers @registry
Scenario: Create AI provider returns Anthropic adapter
Given I have a ProviderRegistry with Anthropic API key set
And CLEVERAGENTS_DEFAULT_MODEL is not set
When I create an AI provider for provider "anthropic"
Then the provider registry AI provider should be an AnthropicChatProvider
And the provider registry AI provider name should be "anthropic"
And the provider registry AI provider model_id should be "claude-sonnet-4-20250514"
@unit @providers @registry
Scenario: Create AI provider raises error when OpenAI API key is missing
Given I have a ProviderRegistry with no API keys
When I try to create an AI provider for provider "openai"
Then a provider registry ValueError should be raised
And the provider registry error should mention missing "OPENAI_API_KEY" environment variable
@unit @providers @registry
Scenario: Create AI provider raises error when Anthropic API key is missing
Given I have a ProviderRegistry with no API keys
When I try to create an AI provider for provider "anthropic"
Then a provider registry ValueError should be raised
And the provider registry error should mention missing "ANTHROPIC_API_KEY" environment variable
@unit @providers @registry
Scenario: Create AI provider returns Google adapter
Given I have a ProviderRegistry with "google" API key set
@@ -401,7 +424,7 @@ Feature: Provider Registry Coverage
And CLEVERAGENTS_DEFAULT_PROVIDER is not set
And CLEVERAGENTS_DEFAULT_MODEL is not set
When I create an AI provider without specifying a provider
Then the provider registry AI provider should be a LangChainChatProvider
Then the provider registry AI provider should be an OpenAIChatProvider
And the provider registry AI provider name should be "openai"
@@ -414,11 +437,11 @@ Feature: Provider Registry Coverage
@unit @providers @registry
Scenario: AI provider exposes working llm factory
Given I have a ProviderRegistry with OpenAI API key set
Given I have a ProviderRegistry with "groq" API key set
And the provider registry LLM factory is stubbed
When I create an AI provider for provider "openai"
And I call the AI provider llm factory with model "gpt-mini-cover"
Then the stubbed LLM factory should be called for ProviderType.OPENAI with model "gpt-mini-cover"
When I create an AI provider for provider "groq"
And I call the AI provider llm factory with model "llama-mini-cover"
Then the stubbed LLM factory should be called for ProviderType.GROQ with model "llama-mini-cover"
@unit @providers @registry
Scenario: ProviderCapabilities is immutable
+12
View File
@@ -9,8 +9,10 @@ from unittest.mock import MagicMock
from behave import given, then, when # type: ignore[import-untyped]
from cleveragents.providers.llm.anthropic_provider import AnthropicChatProvider
from cleveragents.providers.llm.google_provider import GoogleChatProvider
from cleveragents.providers.llm.langchain_chat_provider import LangChainChatProvider
from cleveragents.providers.llm.openai_provider import OpenAIChatProvider
from cleveragents.providers.llm.openrouter_provider import OpenRouterChatProvider
from cleveragents.providers.registry import (
ProviderCapabilities,
@@ -781,6 +783,16 @@ def step_impl_ai_provider_is_langchain(context: Any) -> None:
assert isinstance(context.ai_provider, LangChainChatProvider)
@then("the provider registry AI provider should be an OpenAIChatProvider")
def step_impl_ai_provider_is_openai(context: Any) -> None:
assert isinstance(context.ai_provider, OpenAIChatProvider)
@then("the provider registry AI provider should be an AnthropicChatProvider")
def step_impl_ai_provider_is_anthropic(context: Any) -> None:
assert isinstance(context.ai_provider, AnthropicChatProvider)
@then("the provider registry AI provider should be a GoogleChatProvider")
def step_impl_ai_provider_is_google(context: Any) -> None:
assert isinstance(context.ai_provider, GoogleChatProvider)
@@ -0,0 +1,17 @@
"""LLM provider adapters for CleverAgents.
Exports all concrete LangChain-backed provider classes so that consumers can
import them directly from the ``cleveragents.providers.llm`` subpackage.
"""
from cleveragents.providers.llm.anthropic_provider import AnthropicChatProvider
from cleveragents.providers.llm.google_provider import GoogleChatProvider
from cleveragents.providers.llm.openai_provider import OpenAIChatProvider
from cleveragents.providers.llm.openrouter_provider import OpenRouterChatProvider
__all__ = [
"AnthropicChatProvider",
"GoogleChatProvider",
"OpenAIChatProvider",
"OpenRouterChatProvider",
]
+43
View File
@@ -600,6 +600,49 @@ class ProviderRegistry:
provider_info.capabilities if provider_info else ProviderCapabilities()
)
if provider_type == ProviderType.OPENAI:
from cleveragents.providers.llm.openai_provider import OpenAIChatProvider
key_attr = self.PROVIDER_KEY_ATTRS.get(provider_type)
api_key = getattr(self._settings, key_attr, None) if key_attr else None
if not api_key:
missing_env = (
key_attr.upper() if key_attr else provider_type.value.upper()
)
raise ValueError(
f"Provider {provider_type.value} is not configured. "
f"Please set the {missing_env} environment variable."
)
return OpenAIChatProvider(
api_key=api_key,
model=model_id or self.DEFAULT_MODELS.get(provider_type, "gpt-4o"),
max_retries=max_retries,
)
if provider_type == ProviderType.ANTHROPIC:
from cleveragents.providers.llm.anthropic_provider import (
AnthropicChatProvider,
)
key_attr = self.PROVIDER_KEY_ATTRS.get(provider_type)
api_key = getattr(self._settings, key_attr, None) if key_attr else None
if not api_key:
missing_env = (
key_attr.upper() if key_attr else provider_type.value.upper()
)
raise ValueError(
f"Provider {provider_type.value} is not configured. "
f"Please set the {missing_env} environment variable."
)
return AnthropicChatProvider(
api_key=api_key,
model=model_id
or self.DEFAULT_MODELS.get(provider_type, "claude-sonnet-4-20250514"),
max_retries=max_retries,
)
if provider_type == ProviderType.GOOGLE:
from cleveragents.providers.llm.google_provider import GoogleChatProvider