Coverage for src/lilbee/providers/factory.py: 100%
31 statements
« prev ^ index » next coverage.py v7.15.2, created at 2026-11-06 08:17 +0000
« prev ^ index » next coverage.py v7.15.2, created at 2026-11-06 08:17 +0000
1"""Factory for creating LLM provider instances."""
3from __future__ import annotations
5from collections.abc import Callable
6from dataclasses import dataclass
7from typing import TYPE_CHECKING, assert_never
9from lilbee.core.config.enums import LlmProvider
10from lilbee.providers import availability
11from lilbee.providers.base import ProviderError
13if TYPE_CHECKING:
14 from lilbee.core.config import Config
15 from lilbee.providers.base import LLMProvider
16 from lilbee.providers.sdk_backend import LlmSdkBackend
17 from lilbee.providers.sdk_llm_provider import SdkLLMProvider
19__all__ = ["SdkLibrary", "create_provider", "create_sdk_provider", "sdk_library"]
22@dataclass(frozen=True)
23class SdkLibrary:
24 """The client library behind the SDK backend."""
26 dist: str
27 """Distribution name, as package metadata lists it."""
28 module: str
29 """Top-level import name."""
30 create_backend: Callable[[], LlmSdkBackend]
31 """Builds a new backend over the library."""
34def sdk_library() -> SdkLibrary:
35 """Return the client library's names and backend builder, importing nothing heavy."""
36 # heavy: setup.py imports this module at CLI startup; the backend package
37 # defers its backend module and the library to create_backend
38 from lilbee.providers.backends.liter_llm import SDK_DIST, SDK_MODULE, create_sdk_backend
40 return SdkLibrary(dist=SDK_DIST, module=SDK_MODULE, create_backend=create_sdk_backend)
43def create_sdk_provider() -> SdkLLMProvider:
44 """Return a new provider over the SDK backend, for remote and API models."""
45 from lilbee.providers.sdk_llm_provider import SdkLLMProvider
47 return SdkLLMProvider(sdk_library().create_backend())
50def create_provider(
51 config: Config,
52 *,
53 hold_warm: bool = False,
54 config_refresh: Callable[[], None] | None = None,
55) -> LLMProvider:
56 """Create a new LLM provider instance from the given config.
58 *hold_warm* marks the provider as serving an interactive session, so a local
59 fleet bound to that session keeps its weights resident instead of
60 idle-unloading for as long as the session owns the process (a fleet shared
61 with other users, or kept warm, outlives it and keeps its idle window).
62 Irrelevant to a remote provider, which has no local engine to hold.
63 *config_refresh* takes config.toml changes now; the local engine runs it
64 before it retries a call on an engine that went away.
65 """
66 match config.llm_provider:
67 case LlmProvider.AUTO:
68 # circular: routing_provider -> factory via create_sdk_provider
69 from lilbee.providers.routing_provider import RoutingProvider
71 return RoutingProvider(hold_warm=hold_warm, config_refresh=config_refresh)
73 case LlmProvider.REMOTE:
74 if not availability.provider_sdk_available():
75 raise ProviderError(availability.PROVIDER_SDK_MISSING_MESSAGE)
76 return create_sdk_provider()
78 assert_never(config.llm_provider) # pragma: no cover