fix(providers): export dedicated LLM provider classes from providers/llm/__init__.py #3454

Closed
freemo wants to merge 1 commits from fix/llm-provider-subpackage-exports into master
3 changed files with 259 additions and 4 deletions
@@ -0,0 +1,68 @@
Feature: LLM provider subpackage exports
As a developer using the CleverAgents providers
I want to import LLM provider classes directly from cleveragents.providers.llm
So that I can use a consistent, package-level import path
@unit @providers @llm
Scenario: LangChainChatProvider is importable from the llm subpackage
Given I import LangChainChatProvider from cleveragents.providers.llm
Then the imported LangChainChatProvider class should not be None
@unit @providers @llm
Scenario: OpenAIChatProvider is importable from the llm subpackage
Given I import OpenAIChatProvider from cleveragents.providers.llm
Then the imported OpenAIChatProvider class should not be None
@unit @providers @llm
Scenario: AnthropicChatProvider is importable from the llm subpackage
Given I import AnthropicChatProvider from cleveragents.providers.llm
Then the imported AnthropicChatProvider class should not be None
@unit @providers @llm
Scenario: GoogleChatProvider is importable from the llm subpackage
Given I import GoogleChatProvider from cleveragents.providers.llm
Then the imported GoogleChatProvider class should not be None
@unit @providers @llm
Scenario: OpenRouterChatProvider is importable from the llm subpackage
Given I import OpenRouterChatProvider from cleveragents.providers.llm
Then the imported OpenRouterChatProvider class should not be None
@unit @providers @llm
Scenario: All provider classes are listed in __all__
Given I inspect the cleveragents.providers.llm module
Then __all__ should contain "LangChainChatProvider"
And __all__ should contain "OpenAIChatProvider"
And __all__ should contain "AnthropicChatProvider"
And __all__ should contain "GoogleChatProvider"
And __all__ should contain "OpenRouterChatProvider"
@unit @providers @llm
Scenario: Package-level import matches direct module import for OpenAIChatProvider
Given I import OpenAIChatProvider from cleveragents.providers.llm
And I import OpenAIChatProvider directly from cleveragents.providers.llm.openai_provider
Then both OpenAIChatProvider imports should refer to the same class
@unit @providers @llm
Scenario: Package-level import matches direct module import for AnthropicChatProvider
Given I import AnthropicChatProvider from cleveragents.providers.llm
And I import AnthropicChatProvider directly from cleveragents.providers.llm.anthropic_provider
Then both AnthropicChatProvider imports should refer to the same class
@unit @providers @llm
Scenario: Package-level import matches direct module import for GoogleChatProvider
Given I import GoogleChatProvider from cleveragents.providers.llm
And I import GoogleChatProvider directly from cleveragents.providers.llm.google_provider
Then both GoogleChatProvider imports should refer to the same class
@unit @providers @llm
Scenario: Package-level import matches direct module import for OpenRouterChatProvider
Given I import OpenRouterChatProvider from cleveragents.providers.llm
And I import OpenRouterChatProvider directly from cleveragents.providers.llm.openrouter_provider
Then both OpenRouterChatProvider imports should refer to the same class
@unit @providers @llm
Scenario: Package-level import matches direct module import for LangChainChatProvider
Given I import LangChainChatProvider from cleveragents.providers.llm
And I import LangChainChatProvider directly from cleveragents.providers.llm.langchain_chat_provider
Then both LangChainChatProvider imports should refer to the same class
@@ -0,0 +1,177 @@
"""Step definitions for llm_provider_subpackage_exports.feature."""
from __future__ import annotations
import importlib
from behave import given, then
# ---------------------------------------------------------------------------
# Given steps — import from package level
# ---------------------------------------------------------------------------
@given("I import LangChainChatProvider from cleveragents.providers.llm")
def step_import_langchain_chat_provider(context):
from cleveragents.providers.llm import LangChainChatProvider
context.pkg_LangChainChatProvider = LangChainChatProvider
@given("I import OpenAIChatProvider from cleveragents.providers.llm")
def step_import_openai_chat_provider(context):
from cleveragents.providers.llm import OpenAIChatProvider
context.pkg_OpenAIChatProvider = OpenAIChatProvider
@given("I import AnthropicChatProvider from cleveragents.providers.llm")
def step_import_anthropic_chat_provider(context):
from cleveragents.providers.llm import AnthropicChatProvider
context.pkg_AnthropicChatProvider = AnthropicChatProvider
@given("I import GoogleChatProvider from cleveragents.providers.llm")
def step_import_google_chat_provider(context):
from cleveragents.providers.llm import GoogleChatProvider
context.pkg_GoogleChatProvider = GoogleChatProvider
@given("I import OpenRouterChatProvider from cleveragents.providers.llm")
def step_import_openrouter_chat_provider(context):
from cleveragents.providers.llm import OpenRouterChatProvider
context.pkg_OpenRouterChatProvider = OpenRouterChatProvider
@given("I inspect the cleveragents.providers.llm module")
def step_inspect_llm_module(context):
context.llm_module = importlib.import_module("cleveragents.providers.llm")
# ---------------------------------------------------------------------------
# Given steps — direct module imports (for identity checks)
# ---------------------------------------------------------------------------
@given(
"I import OpenAIChatProvider directly from cleveragents.providers.llm.openai_provider"
)
def step_import_openai_direct(context):
from cleveragents.providers.llm.openai_provider import OpenAIChatProvider
context.direct_OpenAIChatProvider = OpenAIChatProvider
@given(
"I import AnthropicChatProvider directly from cleveragents.providers.llm.anthropic_provider"
)
def step_import_anthropic_direct(context):
from cleveragents.providers.llm.anthropic_provider import AnthropicChatProvider
context.direct_AnthropicChatProvider = AnthropicChatProvider
@given(
"I import GoogleChatProvider directly from cleveragents.providers.llm.google_provider"
)
def step_import_google_direct(context):
from cleveragents.providers.llm.google_provider import GoogleChatProvider
context.direct_GoogleChatProvider = GoogleChatProvider
@given(
"I import OpenRouterChatProvider directly from cleveragents.providers.llm.openrouter_provider"
)
def step_import_openrouter_direct(context):
from cleveragents.providers.llm.openrouter_provider import OpenRouterChatProvider
context.direct_OpenRouterChatProvider = OpenRouterChatProvider
@given(
"I import LangChainChatProvider directly from cleveragents.providers.llm.langchain_chat_provider"
)
def step_import_langchain_direct(context):
from cleveragents.providers.llm.langchain_chat_provider import LangChainChatProvider
context.direct_LangChainChatProvider = LangChainChatProvider
# ---------------------------------------------------------------------------
# Then steps — assertions
# ---------------------------------------------------------------------------
@then("the imported LangChainChatProvider class should not be None")
def step_assert_langchain_not_none(context):
assert context.pkg_LangChainChatProvider is not None
@then("the imported OpenAIChatProvider class should not be None")
def step_assert_openai_not_none(context):
assert context.pkg_OpenAIChatProvider is not None
@then("the imported AnthropicChatProvider class should not be None")
def step_assert_anthropic_not_none(context):
assert context.pkg_AnthropicChatProvider is not None
@then("the imported GoogleChatProvider class should not be None")
def step_assert_google_not_none(context):
assert context.pkg_GoogleChatProvider is not None
@then("the imported OpenRouterChatProvider class should not be None")
def step_assert_openrouter_not_none(context):
assert context.pkg_OpenRouterChatProvider is not None
@then('__all__ should contain "{class_name}"')
def step_assert_all_contains(context, class_name):
module = context.llm_module
all_exports = getattr(module, "__all__", [])
assert class_name in all_exports, (
f"Expected '{class_name}' in __all__, but __all__ = {all_exports!r}"
)
@then("both OpenAIChatProvider imports should refer to the same class")
def step_assert_openai_same_class(context):
assert context.pkg_OpenAIChatProvider is context.direct_OpenAIChatProvider, (
"Package-level OpenAIChatProvider is not the same object as the direct import"
)
@then("both AnthropicChatProvider imports should refer to the same class")
def step_assert_anthropic_same_class(context):
assert context.pkg_AnthropicChatProvider is context.direct_AnthropicChatProvider, (
"Package-level AnthropicChatProvider is not the same object as the direct import"
)
@then("both GoogleChatProvider imports should refer to the same class")
def step_assert_google_same_class(context):
assert context.pkg_GoogleChatProvider is context.direct_GoogleChatProvider, (
"Package-level GoogleChatProvider is not the same object as the direct import"
)
@then("both OpenRouterChatProvider imports should refer to the same class")
def step_assert_openrouter_same_class(context):
assert (
context.pkg_OpenRouterChatProvider is context.direct_OpenRouterChatProvider
), (
"Package-level OpenRouterChatProvider is not the same object as the direct import"
)
@then("both LangChainChatProvider imports should refer to the same class")
def step_assert_langchain_same_class(context):
assert context.pkg_LangChainChatProvider is context.direct_LangChainChatProvider, (
"Package-level LangChainChatProvider is not the same object as the direct import"
)
+14 -4
View File
@@ -2,16 +2,26 @@
Exports all concrete LangChain-backed provider classes so that consumers can
import them directly from the ``cleveragents.providers.llm`` subpackage.
Example
-------
>>> from cleveragents.providers.llm import OpenAIChatProvider
>>> OpenAIChatProvider # doctest: +ELLIPSIS
<class 'cleveragents.providers.llm.openai_provider.OpenAIChatProvider'>
"""
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
from __future__ import annotations
from .anthropic_provider import AnthropicChatProvider
from .google_provider import GoogleChatProvider
from .langchain_chat_provider import LangChainChatProvider
from .openai_provider import OpenAIChatProvider
from .openrouter_provider import OpenRouterChatProvider
__all__ = [
"AnthropicChatProvider",
"GoogleChatProvider",
"LangChainChatProvider",
"OpenAIChatProvider",
"OpenRouterChatProvider",
]