generated from coulomb/repo-seed
FR-2 RoutingPolicy: - RoutingPolicy + RoutingRule dataclasses in llm_connect/routing.py - resolve(task_type, estimated_cost_per_1k=None) with cost-cap fallback - Exported from llm_connect.__init__; contract doc at contracts/functional/routing-policy.md - 11 tests covering rule match, cost-cap, fallback, unknown type, no-match FR-1 HTTP serve mode: - LLMServer in llm_connect/server.py (stdlib http.server, zero extra deps) - POST /execute + GET /health; CLI via python -m llm_connect.server - [server] optional-dep group added to pyproject.toml - Contract doc at contracts/functional/server.md - 9 tests: health, round-trip, 400/404/500 errors, config forwarding - Added "mock" provider to factory for CLI default All 101 tests pass. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
62 lines
2.1 KiB
Python
62 lines
2.1 KiB
Python
"""
|
|
Factory for creating LLM adapters by provider name.
|
|
"""
|
|
|
|
from typing import Optional, Dict, 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: Optional[str] = None,
|
|
api_key: Optional[str] = None,
|
|
system_prompt: Optional[str] = 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 = 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)
|
|
else:
|
|
return cls(**kwargs)
|