Coverage for src / lexigram / contracts / ai / parsers.py: 79%
43 statements
« prev ^ index » next coverage.py v7.13.5, created at 2026-08-19 05:41 +0800
« prev ^ index » next coverage.py v7.13.5, created at 2026-08-19 05:41 +0800
1"""Output Parser contracts for G-04 parity.
3Defines output parsers analogous to LangChain's output parsers.
4"""
6from __future__ import annotations
8from abc import ABC, abstractmethod
9import json
10from typing import Any, cast
13class BaseOutputParser(ABC):
14 """Base class for output parsers (like LangChain's BaseOutputParser)."""
16 @abstractmethod
17 def parse(self, text: str) -> Any:
18 """Parse text into structured output.
20 Args:
21 text: Text to parse.
23 Returns:
24 Parsed output.
25 """
26 ...
28 def get_format_instructions(self) -> str:
29 """Get format instructions for the model.
31 Returns:
32 Format instructions string.
33 """
34 return ""
37class JSONOutputParser(BaseOutputParser):
38 """Parse JSON responses (like LangChain's JsonOutputParser)."""
40 def parse(self, text: str) -> dict[str, Any]:
41 """Parse JSON from text.
43 Args:
44 text: Text containing JSON.
46 Returns:
47 Parsed JSON as dict.
48 """
49 text = text.strip()
50 if text.startswith("```json"):
51 text = text[7:]
52 elif text.startswith("```"):
53 text = text[3:]
54 if text.endswith("```"):
55 text = text[:-3]
56 text = text.strip()
57 return cast("dict[str, Any]", json.loads(text))
59 def get_format_instructions(self) -> str:
60 return "Return a valid JSON object."
63class XMLOutputParser(BaseOutputParser):
64 """Parse XML responses (like LangChain's XMLOutputParser)."""
66 def parse(self, text: str) -> Any:
67 """Parse XML from text."""
68 return text.strip()
70 def get_format_instructions(self) -> str:
71 return "Return XML."
74class PydanticOutputParser(BaseOutputParser):
75 """Parse into Pydantic model (like LangChain's PydanticOutputParser)."""
77 def __init__(self, model: type) -> None:
78 self.model = model
80 def parse(self, text: str) -> Any:
81 """Parse text into Pydantic model."""
82 text = text.strip()
83 if text.startswith("```json"):
84 text = text[7:]
85 elif text.startswith("```"):
86 text = text[3:]
87 if text.endswith("```"):
88 text = text[:-3]
89 data = json.loads(text.strip())
90 return self.model(**data)
92 def get_format_instructions(self) -> str:
93 return "Return a valid JSON object."
96__all__ = [
97 "BaseOutputParser",
98 "JSONOutputParser",
99 "PydanticOutputParser",
100 "XMLOutputParser",
101]