Coverage for src / lexigram / contracts / observability / ai.py: 0%

26 statements  

« prev     ^ index     » next       coverage.py v7.13.5, created at 2026-08-15 18:57 +0800

1"""AI observability contracts.""" 

2 

3from __future__ import annotations 

4 

5from typing import Any, Protocol, runtime_checkable 

6 

7from lexigram.contracts.exceptions import LexigramError 

8 

9 

10# Observability Errors 

11class MonitoringError(LexigramError): 

12 """Base error raised during AI observability monitoring.""" 

13 

14 _code: str = "LEX_ERR_AI_005" 

15 

16 

17class MetricsCollectionError(MonitoringError): 

18 """Error raised during metrics collection.""" 

19 

20 _code: str = "LEX_ERR_AI_003" 

21 

22 

23class TracingError(LexigramError): 

24 """Error raised during tracing operations.""" 

25 

26 _code: str = "LEX_ERR_AI_004" 

27 

28 

29@runtime_checkable 

30class ObservabilityProtocol(Protocol): 

31 """Protocol for AI-specific metrics and tracing.""" 

32 

33 async def record_generation( 

34 self, 

35 model: str, 

36 provider: str, 

37 tokens_prompt: int, 

38 tokens_completion: int, 

39 latency_ms: float, 

40 successful: bool, 

41 ) -> None: 

42 """Record a single LLM generation event.""" 

43 ... 

44 

45 async def start_trace( 

46 self, name: str, metadata: dict[str, Any] | None = None 

47 ) -> str: 

48 """Start a trace block, returning a trace ID.""" 

49 ... 

50 

51 async def end_trace( 

52 self, trace_id: str, metadata: dict[str, Any] | None = None 

53 ) -> None: 

54 """End a trace block.""" 

55 ... 

56 

57 

58@runtime_checkable 

59class AITracerProtocol(Protocol): 

60 """Protocol for AI distributed tracing. 

61 

62 Implementations wrap individual LLM/vector calls in named spans, 

63 allowing distributed trace propagation without coupling to a 

64 specific tracing backend (OpenTelemetry, Jaeger, etc.). 

65 """ 

66 

67 def trace_llm_call( 

68 self, 

69 provider: str, 

70 model: str, 

71 *, 

72 streaming: bool = False, 

73 ) -> Any: 

74 """Return a context manager that wraps an LLM call in a trace span. 

75 

76 Args: 

77 provider: Provider name (e.g. ``"openai"``). 

78 model: Model identifier. 

79 streaming: Whether this is a streaming call. 

80 

81 Returns: 

82 A synchronous context manager. 

83 """ 

84 ... 

85 

86 

87@runtime_checkable 

88class AIMetricsProtocol(Protocol): 

89 """Protocol for AI metrics collection. 

90 

91 Implementations record counters, histograms, and gauges for 

92 LLM/vector operations without coupling to a specific metrics 

93 backend (Prometheus, StatsD, etc.). 

94 """ 

95 

96 def record_completion( 

97 self, 

98 provider: str, 

99 model: str, 

100 tokens: int, 

101 cost: float, 

102 ) -> None: 

103 """Record a successful LLM completion. 

104 

105 Args: 

106 provider: Provider name. 

107 model: Model identifier. 

108 tokens: Total tokens consumed. 

109 cost: Estimated dollar cost. 

110 """ 

111 ... 

112 

113 def record_error(self, provider: str, error_type: str) -> None: 

114 """Record an LLM or vector store error. 

115 

116 Args: 

117 provider: Provider name. 

118 error_type: Short error category string. 

119 """ 

120 ... 

121 

122 

123@runtime_checkable 

124class AIHealthMonitorProtocol(Protocol): 

125 """Protocol for AI health monitoring. 

126 

127 Allows the DI container to resolve health status of AI sub-systems 

128 (LLM availability, vector store connectivity, etc.) through a 

129 stable interface. 

130 """ 

131 

132 async def check(self) -> Any: 

133 """Run health checks and return a ``HealthCheckResult``-like object. 

134 

135 Returns: 

136 An object with at least a ``status`` attribute. 

137 """ 

138 ... 

139 

140 def register_check(self, name: str, check: Any) -> None: 

141 """Register a named health-check callable. 

142 

143 Args: 

144 name: Unique check name. 

145 check: An async callable returning a health status. 

146 """ 

147 ... 

148 

149 

150__all__ = [ 

151 "AIHealthMonitorProtocol", 

152 "AIMetricsProtocol", 

153 "AITracerProtocol", 

154 "MetricsCollectionError", 

155 "MonitoringError", 

156 "ObservabilityProtocol", 

157 "TracingError", 

158]