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

11 statements  

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

1"""Rate-limit contracts for the relay gateway. 

2 

3A counter is a fixed-window atomic ``take`` matched to new-api's Redis 

4Lua semantics: the counter is incremented, the window expiry is set on 

5first increment, and the decision is returned atomically. Bursts of up 

6to 2x the limit at a window boundary are intentional. 

7""" 

8 

9from __future__ import annotations 

10 

11from dataclasses import dataclass 

12from typing import Protocol, runtime_checkable 

13 

14 

15@dataclass(frozen=True, slots=True) 

16class RelayRateLimitDecision: 

17 """Outcome of one ``take`` against a rate-limit window. 

18 

19 Attributes: 

20 allowed: Whether the caller may proceed within the window. 

21 count: The counter value after this take, 1-based. 

22 ttl_seconds: Remaining seconds in the window. 

23 """ 

24 

25 allowed: bool 

26 count: int 

27 ttl_seconds: int 

28 

29 

30@runtime_checkable 

31class RelayRateLimitCounterProtocol(Protocol): 

32 """Atomic fixed-window counter backend. 

33 

34 ``take`` must behave atomically for a given ``key``: increment, 

35 set/refresh expiry on first increment, compare against ``limit``, 

36 return the decision plus the current window TTL. 

37 """ 

38 

39 async def take( 

40 self, key: str, limit: int, window_seconds: int 

41 ) -> RelayRateLimitDecision: ... 

42 

43 

44__all__ = ["RelayRateLimitCounterProtocol", "RelayRateLimitDecision"]