Coverage for src / lexigram / ai / relay / di / provider.py: 96%
24 statements
« prev ^ index » next coverage.py v7.13.5, created at 2026-08-08 23:08 +0800
« prev ^ index » next coverage.py v7.13.5, created at 2026-08-08 23:08 +0800
1"""RelayProvider — registers the relay registry and conversion engine."""
3from __future__ import annotations
5from typing import TYPE_CHECKING
7from lexigram.ai.relay.engine import RelayConverterEngine
8from lexigram.ai.relay.registry import RelayConverterRegistry
9from lexigram.contracts.ai.relay.protocols import (
10 RelayConverterProtocol,
11 RelayRegistryProtocol,
12)
13from lexigram.contracts.core.health import HealthCheckResult, HealthStatus
14from lexigram.contracts.core.provider import ProviderPriority
15from lexigram.di.provider import Provider
16from lexigram.logging import get_logger
18if TYPE_CHECKING:
19 from lexigram.contracts.core.di import (
20 BootContainerProtocol,
21 ContainerRegistrarProtocol,
22 )
24logger = get_logger(__name__)
27class RelayProvider(Provider):
28 """Registers the caller-owned relay registry and the public engine.
30 The provider binds a default :class:`RelayConverterRegistry` when the
31 caller did not already register their own ``RelayRegistryProtocol``;
32 it never overrides an existing caller-owned registry. The engine is
33 registered as its class so the container constructs it against
34 whichever registry binding wins.
36 Registers:
37 - ``RelayRegistryProtocol`` — the default registry (only when absent)
38 - ``RelayConverterProtocol`` — the public conversion engine
40 The provider requires no LLM API credentials and never creates an
41 HTTP client.
42 """
44 name = "ai-relay"
45 priority = ProviderPriority.DOMAIN
47 async def register(self, container: ContainerRegistrarProtocol) -> None:
48 """Register the relay registry and engine."""
49 if not container.has(RelayRegistryProtocol):
50 container.singleton(
51 RelayRegistryProtocol,
52 RelayConverterRegistry.with_defaults(),
53 )
54 container.singleton(RelayConverterProtocol, RelayConverterEngine)
55 logger.info("relay_provider_registered")
57 async def boot(self, container: BootContainerProtocol) -> None:
58 """No-op boot; the engine needs no runtime wiring."""
59 logger.info("relay_provider_booted")
61 async def shutdown(self) -> None:
62 """No-op shutdown."""
63 logger.info("relay_provider_shutdown")
65 async def health_check(self, timeout: float = 5.0) -> HealthCheckResult:
66 """Report the relay engine as healthy.
68 Args:
69 timeout: Ignored; the engine performs no I/O.
71 Returns:
72 A healthy check result.
73 """
74 return HealthCheckResult(
75 component=self.name,
76 status=HealthStatus.HEALTHY,
77 )