neuralcad / core /backend_factory.py
CallMeDaniel's picture
feat: add BackendFactory registry for centralized backend creation
e787a71
"""Backend factory — centralized creation of LLM backends.
Replaces scattered if/elif backend selection across mcp.py, routes.py, web.py.
"""
from __future__ import annotations
import logging
from core.types import LLMBackend
logger = logging.getLogger(__name__)
class BackendFactory:
"""Registry and factory for LLM backends."""
_registry: dict[str, type[LLMBackend]] = {}
@classmethod
def register(cls, name: str, backend_cls: type[LLMBackend]) -> None:
cls._registry[name] = backend_cls
@classmethod
def create(cls, name: str, **kwargs) -> LLMBackend:
if name not in cls._registry:
raise ValueError(f"Unknown backend: {name!r}. Available: {list(cls._registry.keys())}")
return cls._registry[name](**kwargs)
@classmethod
def create_safe(cls, name: str, **kwargs) -> LLMBackend:
"""Create backend, falling back to mock on failure."""
try:
return cls.create(name, **kwargs)
except Exception as exc:
logger.warning("Backend %r unavailable (%s), falling back to mock", name, exc)
return cls.create("mock")
def _register_defaults() -> None:
"""Register all built-in backends. Called at module load."""
from core.backends import MockBackend
BackendFactory.register("mock", MockBackend)
try:
from core.backends import AnthropicBackend
BackendFactory.register("anthropic", AnthropicBackend)
except Exception:
pass
try:
from core.backends import OpenAIBackend
BackendFactory.register("openai", OpenAIBackend)
except Exception:
pass
try:
from core.backends import GeminiBackend
BackendFactory.register("gemini", GeminiBackend)
except Exception:
pass
_register_defaults()