Coverage for /home/admin/Documents/AI/applications/lexigram-dev/lexigram/experimental/ai/lexigram-ai-guard/src/lexigram/ai/guard/input/length.py: 56%

18 statements  

« prev     ^ index     » next       coverage.py v7.15.4, created at 2026-08-25 07:19 +0800

1"""Input length guard. 

2 

3Rejects or warns on inputs that exceed a configured character or token 

4budget. This prevents prompt stuffing attacks and controls API costs. 

5""" 

6 

7from __future__ import annotations 

8 

9from typing import TYPE_CHECKING, Any 

10 

11from lexigram.ai.guard.input.base import AbstractInputGuard 

12from lexigram.ai.guard.pipeline.result import GuardCheckResult 

13from lexigram.contracts.ai.guards import GuardResultProtocol 

14from lexigram.result import Ok, Result 

15 

16if TYPE_CHECKING: 

17 from lexigram.contracts.ai.exceptions import GuardError 

18 

19 

20class InputLengthGuard(AbstractInputGuard): 

21 """GuardProtocol that enforces a maximum input length. 

22 

23 Length is measured in character count. For a rough token 

24 estimate divide by 4 (GPT tokenizer average). 

25 

26 Args: 

27 max_chars: Maximum allowed character count. 

28 action: Action when the limit is exceeded — ``"block"`` (default) 

29 or ``"warn"``. 

30 

31 Example:: 

32 

33 guard = InputLengthGuard(max_chars=8000, action="block") 

34 result = await guard.check(user_input) 

35 if not result.passed: 

36 return Err(InputTooLongError(len(user_input))) 

37 """ 

38 

39 def __init__(self, max_chars: int, action: str = "block") -> None: 

40 """Initialise the length guard. 

41 

42 Args: 

43 max_chars: Maximum allowed character count. 

44 action: ``"block"`` or ``"warn"``. 

45 """ 

46 super().__init__(action=action) 

47 self._max_chars = max_chars 

48 

49 async def check( 

50 self, 

51 content: str, 

52 *, 

53 messages: list[Any] | None = None, 

54 metadata: dict[str, Any] | None = None, 

55 ) -> Result[GuardResultProtocol, GuardError]: 

56 """Check whether content exceeds the configured length limit. 

57 

58 Args: 

59 content: Input text to measure. 

60 messages: Unused — present for protocol compatibility. 

61 metadata: Optional metadata. 

62 

63 Returns: 

64 PASS if within limit; BLOCK or WARN if exceeded. 

65 """ 

66 length = len(content) 

67 if length <= self._max_chars: 

68 return Ok(GuardCheckResult.allow(self.name, char_count=length)) 

69 

70 if self._action == "warn": 

71 return Ok( 

72 GuardCheckResult.warn( 

73 self.name, 

74 reason=f"Input length {length} chars exceeds soft limit {self._max_chars}", 

75 char_count=length, 

76 max_chars=self._max_chars, 

77 ) 

78 ) 

79 

80 return Ok( 

81 GuardCheckResult.block( 

82 self.name, 

83 reason=f"Input length {length} chars exceeds maximum {self._max_chars}", 

84 char_count=length, 

85 max_chars=self._max_chars, 

86 ) 

87 ) 

88 

89 

90__all__ = ["InputLengthGuard"]