Coverage for src / lexigram / contracts / ai / governance / __init__.py: 0%
50 statements
« prev ^ index » next coverage.py v7.13.5, created at 2026-08-15 18:57 +0800
« prev ^ index » next coverage.py v7.13.5, created at 2026-08-15 18:57 +0800
1"""AI governance contracts."""
3from __future__ import annotations
5from dataclasses import dataclass, field
6from datetime import UTC, datetime
7from enum import StrEnum
8from typing import Any, Protocol, runtime_checkable
9from uuid import uuid4
11from lexigram.contracts.ai.governance.errors import (
12 BudgetExceededError,
13 GovernanceError,
14 PolicyViolationError,
15)
16from lexigram.contracts.ai.governance.relay_billing import (
17 RelayBillingError,
18 RelayBillingProtocol,
19 RelayChargeBreakdown,
20 RelayPriceEstimatorProtocol,
21 RelayUsageRecord,
22 RelayUsageReservation,
23 RelayUsageScope,
24 RelayUsageStoreProtocol,
25 billing_store_unavailable,
26 charge_overflow,
27 duplicate_settlement,
28 invalid_usage,
29 quota_exhausted,
30 reservation_expired,
31 unknown_price,
32)
33from lexigram.contracts.ai.governance.resource_unit import (
34 ResourceExhaustedError,
35 ResourceQuota,
36 ResourceUnit,
37 ResourceUsageResult,
38 ResourceUsageSnapshot,
39 ResourceWindowKind,
40)
43@dataclass(frozen=True)
44class GovernanceDecision:
45 """Decision from the governance layer."""
47 allowed: bool
48 reason: str | None = None
49 remaining_budget: float | None = None
52@runtime_checkable
53class CostTrackingProtocol(Protocol):
54 """Protocol for tracking costs."""
56 async def track_cost(
57 self,
58 cost: float,
59 model: str,
60 user_id: str | None = None,
61 ) -> None:
62 """Track cost for an operation."""
63 ...
65 async def get_budget(self, user_id: str | None = None) -> float:
66 """Get remaining budget."""
67 ...
70@runtime_checkable
71class AIGovernanceProtocol(Protocol):
72 """Protocol for AI Governance and cost tracking."""
74 async def check_request(
75 self,
76 model: str,
77 provider: str,
78 user_id: str | None = None,
79 ) -> GovernanceDecision:
80 """Check if request is allowed by governance policies."""
81 ...
83 async def check_budget(self, cost: float, user_id: str | None = None) -> bool:
84 """Check if operation fits within budget."""
85 ...
87 async def track_cost(
88 self,
89 cost: float,
90 model: str,
91 user_id: str | None = None,
92 ) -> None:
93 """Track cost for an operation."""
94 ...
97class AuditEventType(StrEnum):
98 """Categories of auditable AI operations.
100 Shared across the AI governance and observability layers
101 via ``lexigram-contracts``.
102 """
104 CREATED = "created"
105 LLM_CALL = "llm_call"
106 MODEL_DENIED = "model_denied"
107 BUDGET_EXCEEDED = "budget_exceeded"
108 RATE_LIMITED = "rate_limited"
109 TOOL_CALL = "tool_call"
110 AGENT_EXECUTION = "agent_execution"
111 SOFT_LIMIT_REACHED = "soft_limit_reached"
112 CONFIG_RELOADED = "config_reloaded"
115@dataclass(frozen=True)
116class AIAuditEvent:
117 """Structured representation of an auditable AI operation.
119 Concrete data class shared across AI packages via ``lexigram-contracts``.
121 Attributes:
122 event_type: Category of the operation.
123 model: Model identifier (if applicable).
124 provider: Provider name (if applicable).
125 user_id: User who triggered the operation.
126 status: Outcome — ``"allowed"``, ``"denied"``, ``"success"``, ``"error"``.
127 tokens: Token count consumed (if applicable).
128 cost: Dollar cost incurred (if applicable).
129 latency_ms: Request latency in milliseconds (if applicable).
130 metadata: Free-form key/value bag for additional context.
131 event_id: Unique UUID for the event (auto-generated).
132 """
134 event_type: AuditEventType
135 model: str | None = None
136 provider: str | None = None
137 user_id: str | None = None
138 status: str = "success"
139 tokens: int | None = None
140 cost: float | None = None
141 latency_ms: float | None = None
142 metadata: dict[str, Any] = field(default_factory=dict)
143 event_id: str = field(default_factory=lambda: str(uuid4()))
144 timestamp: datetime = field(default_factory=lambda: datetime.now(UTC))
147@runtime_checkable
148class AIAuditStoreProtocol(Protocol):
149 """Protocol for AI audit event persistence backends.
151 Implementations must be async and treat ``record()`` as
152 fire-and-forget safe — hot-paths must never block on audit persistence.
153 """
155 async def record(self, event: AIAuditEvent) -> None:
156 """Persist a single audit event.
158 Args:
159 event: The audit event to store.
160 """
161 ...
164__all__ = [
165 "AIAuditEvent",
166 "AIAuditStoreProtocol",
167 "AIGovernanceProtocol",
168 "AuditEventType",
169 "BudgetExceededError",
170 "CostTrackingProtocol",
171 "GovernanceDecision",
172 "GovernanceError",
173 "PolicyViolationError",
174 "RelayBillingError",
175 "RelayBillingProtocol",
176 "RelayChargeBreakdown",
177 "RelayPriceEstimatorProtocol",
178 "RelayUsageRecord",
179 "RelayUsageReservation",
180 "RelayUsageScope",
181 "RelayUsageStoreProtocol",
182 "ResourceExhaustedError",
183 "ResourceQuota",
184 "ResourceUnit",
185 "ResourceUsageResult",
186 "ResourceUsageSnapshot",
187 "ResourceWindowKind",
188 "billing_store_unavailable",
189 "charge_overflow",
190 "duplicate_settlement",
191 "invalid_usage",
192 "quota_exhausted",
193 "reservation_expired",
194 "unknown_price",
195]