Coverage for /home/admin/Documents/AI/applications/lexigram-dev/lexigram/experimental/ai/lexigram-ai-llm/src/lexigram/ai/llm/parsers/json.py: 53%

19 statements  

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

1"""JSON Output Parser.""" 

2 

3from __future__ import annotations 

4 

5from typing import Any 

6 

7from lexigram.ai.llm.structured.exceptions import ParseError 

8from lexigram.ai.llm.structured.parser import extract_json_block 

9from lexigram.logging import ( 

10 get_logger, 

11) 

12 

13logger = get_logger(__name__) 

14 

15 

16class JSONOutputParser: 

17 """Parse LLM responses into JSON dicts. 

18 

19 Handles common LLM output patterns like markdown code fences, 

20 prose before/after JSON, and malformed JSON. 

21 

22 Example: 

23 >>> parser = JSONOutputParser() 

24 >>> result = parser.parse('{"key": "value"}') 

25 >>> assert result == {"key": "value"} 

26 """ 

27 

28 def parse(self, text: str) -> dict[str, Any]: 

29 """Parse text into a JSON dict. 

30 

31 Args: 

32 text: Raw LLM response text that may contain JSON. 

33 

34 Returns: 

35 Parsed JSON as a dict. 

36 

37 Raises: 

38 ParseError: When JSON cannot be extracted or parsed. 

39 """ 

40 try: 

41 parsed = extract_json_block(text) 

42 except ValueError as exc: 

43 raise ParseError(str(exc)) from exc 

44 

45 if not isinstance(parsed, dict): 

46 raise ParseError(f"Expected JSON object, got {type(parsed).__name__}") 

47 

48 logger.debug("json_parsed", keys=list(parsed.keys())) 

49 return parsed 

50 

51 def get_format_instructions(self) -> str: 

52 """Return format instructions for the LLM. 

53 

54 Returns: 

55 Format instruction string telling the model to output valid JSON. 

56 """ 

57 return ( 

58 "Your response should be a valid JSON object. " 

59 "Do not include any text before or after the JSON. " 

60 "Do not use markdown code fences." 

61 ) 

62 

63 

64__all__ = ["JSONOutputParser"]