Coverage for src/lexigram/ai/module.py: 100%
23 statements
« prev ^ index » next coverage.py v7.15.4, created at 2026-08-25 07:19 +0800
« prev ^ index » next coverage.py v7.15.4, created at 2026-08-25 07:19 +0800
1"""AI orchestration module for dependency injection."""
3from __future__ import annotations
5from typing import Any
7from lexigram.contracts.ai import AIProviderProtocol
8from lexigram.di.module import DynamicModule, Module, module
11@module()
12class AIModule(Module):
13 """Core AI layer: LLM orchestration, RAG pipelines, and governance.
15 Call :meth:`configure` to configure the AI subsystem. Sub-modules such as
16 :class:`~lexigram.ai.llm.LLMModule` and
17 :class:`~lexigram.ai.rag.RAGModule` may be imported independently
18 for more granular control.
20 Usage::
22 from lexigram.ai.config import AIConfig
23 from lexigram.ai.llm.config import ClientConfig
25 @module(
26 imports=[
27 AIModule.configure(
28 AIConfig(llm=ClientConfig(provider="openai", model="gpt-4o"))
29 )
30 ]
31 )
32 class AppModule(Module):
33 pass
34 """
36 @classmethod
37 def configure(cls, config: Any | None = None, **kwargs: Any) -> DynamicModule:
38 """Create an AIModule with explicit configuration.
40 Args:
41 config: :class:`~lexigram.ai.config.AIConfig` or ``None``
42 for framework defaults.
43 **kwargs: Additional keyword arguments forwarded to
44 :class:`~lexigram.ai.di.provider.AIProvider`.
46 Returns:
47 A :class:`~lexigram.di.module.DynamicModule` descriptor.
48 """
49 from lexigram.ai.di.provider import AIProvider
51 return DynamicModule(
52 module=cls,
53 providers=[AIProvider(config=config, **kwargs)],
54 exports=[AIProviderProtocol],
55 )
57 @classmethod
58 def stub(cls, config: Any = None) -> DynamicModule:
59 """Return a no-op AIModule for testing.
61 Registers all AI sub-modules with their testing stubs: agents,
62 LLM, RAG, memory, prompts, skills, sessions, feedback, governance,
63 and guards with minimal side effects.
65 Returns:
66 A DynamicModule with all AI sub-modules in testing configuration.
67 """
68 from importlib.metadata import entry_points
70 from lexigram.di.module import DynamicModule
72 stub_imports: list[Any] = []
73 for ep in entry_points(group="lexigram.ai.modules"):
74 try:
75 module_cls = ep.load()
76 stub_imports.append(module_cls.stub())
77 except (AttributeError, ImportError, RuntimeError):
78 pass
80 return DynamicModule(
81 module=cls,
82 imports=stub_imports,
83 exports=[AIProviderProtocol],
84 )
87__all__ = ["AIModule"]