llm-connect/llm_connect/factory.py
tegwick 7cd633986e
All checks were successful
CI Smoke / host-smoke (push) Successful in 1s
CI Smoke / container-smoke (push) Successful in 2s
Close local release-quality gaps and reconcile workplan status
Assistant: codex
Assistant-Model: gpt-6-astra
Assistant-Session: 01a0e332-3365-77c0-8491-084e9ea33ac1
2026-09-27 17:36:27 +02:00

68 lines
2.4 KiB
Python

"""
Factory for creating LLM adapters by provider name.
"""
import os
from collections.abc import Callable
from typing import Any
from llm_connect.adapter import LLMAdapter
from llm_connect.exceptions import LLMConfigurationError
# Lazy imports to avoid pulling in every adapter at module load time.
_PROVIDERS: dict[str, str] = {
"openrouter": "llm_connect.openrouter.OpenRouterAdapter",
"claude-code": "llm_connect.claude_code.ClaudeCodeAdapter",
"gemini": "llm_connect.gemini.GeminiAdapter",
"openai": "llm_connect.openai.OpenAIAdapter",
"mock": "llm_connect.adapter.MockLLMAdapter",
}
def create_adapter(
provider: str = "openrouter",
model: str | None = None,
api_key: str | None = None,
system_prompt: str | None = None,
**kwargs: Any,
) -> LLMAdapter:
"""Instantiate an :class:`LLMAdapter` for the given *provider*.
Args:
provider: ``"openrouter"``, ``"claude-code"``, ``"gemini"``, or ``"openai"``.
model: Model name (passed to the adapter constructor).
api_key: Explicit API key (OpenRouter / Gemini / OpenAI).
system_prompt: Optional system prompt (OpenRouter / Gemini / OpenAI).
**kwargs: Extra keyword arguments forwarded to the adapter.
Returns:
A ready-to-use :class:`LLMAdapter` instance.
Raises:
LLMConfigurationError: If *provider* is not recognised.
"""
if provider not in _PROVIDERS:
known = ", ".join(sorted(_PROVIDERS))
raise LLMConfigurationError(
f"Unknown LLM provider {provider!r}. Choose from: {known}",
context={"provider": provider},
)
# Lazy import
fqn = _PROVIDERS[provider]
module_path, class_name = fqn.rsplit(".", 1)
import importlib
mod = importlib.import_module(module_path)
cls: Callable[..., LLMAdapter] = getattr(mod, class_name)
if provider in ("openrouter", "gemini", "openai"):
return cls(model=model, api_key=api_key, system_prompt=system_prompt, **kwargs)
elif provider == "claude-code":
return cls(model=model, **kwargs)
elif provider == "mock":
mock_response = os.environ.get("LLM_CONNECT_MOCK_RESPONSE")
if mock_response is not None and "mock_response" not in kwargs:
kwargs["mock_response"] = mock_response
return cls(**kwargs)
else:
return cls(**kwargs)