Coverage for /home/admin/Documents/AI/applications/lexigram-dev/lexigram/experimental/ai/lexigram-ai-llm/src/lexigram/ai/llm/di/factories.py: 52%

25 statements  

« prev     ^ index     » next       coverage.py v7.15.4, created at 2026-08-25 07:19 +0800

1"""Factory functions for creating LLM service instances from configuration. 

2 

3These factories are used by LLMProvider to construct concrete client 

4implementations from typed config objects without hardcoding dependencies. 

5""" 

6 

7from __future__ import annotations 

8 

9from typing import TYPE_CHECKING 

10 

11from lexigram.contracts.ai import LLMClientProtocol 

12from lexigram.contracts.ai.providers import ProviderRegistryProtocol 

13from lexigram.logging import ( 

14 get_logger, 

15) 

16 

17if TYPE_CHECKING: 

18 from lexigram.ai.llm.config import ClientConfig 

19 from lexigram.ai.llm.protocols import LLMCacheProtocol 

20 from lexigram.contracts.infra.cache import CacheBackendProtocol 

21 

22logger = get_logger(__name__) 

23 

24 

25async def create_llm_client( 

26 config: ClientConfig, 

27 registry: ProviderRegistryProtocol, 

28) -> LLMClientProtocol: 

29 """Instantiate an LLM client from provider configuration via the registry. 

30 

31 Delegates to :class:`~lexigram.ai.llm.registry.ProviderRegistry` so that 

32 all built-in **and** custom providers registered at runtime are supported 

33 without requiring changes to this factory. 

34 

35 Args: 

36 config: LLM-specific configuration block. 

37 

38 Returns: 

39 A concrete LLMClientProtocol for the configured provider. 

40 

41 Raises: 

42 ValueError: When ``config.provider`` is not registered. 

43 """ 

44 try: 

45 provider_info = registry.get_provider(config.provider) # type: ignore[attr-defined] 

46 except KeyError as exc: 

47 msg = f"Unsupported LLM provider: {config.provider!r}" 

48 raise ValueError(msg) from exc 

49 

50 client = provider_info.client_class(config) 

51 if not isinstance(client, LLMClientProtocol): 

52 msg = ( 

53 f"LLM client for provider {config.provider!r} does not satisfy " 

54 "the LLMClientProtocol protocol. Ensure the client implements complete(), " 

55 "stream_chat(), health_check(), and close()." 

56 ) 

57 raise TypeError(msg) 

58 return client 

59 

60 

61async def create_llm_cache( 

62 config: ClientConfig, 

63 cache: CacheBackendProtocol | None, 

64) -> LLMCacheProtocol: 

65 """Create an LLM response cache instance from configuration. 

66 

67 Args: 

68 config: LLM configuration carrying cache settings. 

69 cache: Platform cache backend (required when enable_cache=True). 

70 

71 Returns: 

72 A configured LLMCacheProtocol instance. 

73 

74 Raises: 

75 ValueError: When enable_cache is True but no CacheBackendProtocol is provided. 

76 """ 

77 from lexigram.ai.llm.caching.core import LLMCache, RedisLLMCache 

78 

79 if cache is not None: 

80 return RedisLLMCache(cache_backend=cache, ttl=config.cache_ttl) # type: ignore[return-value] 

81 

82 if config.enable_cache and cache is None: 

83 msg = "CacheBackendProtocol required for LLM caching but not found in container" 

84 raise ValueError(msg) 

85 

86 return LLMCache(ttl=config.cache_ttl) # type: ignore[return-value]