langroid 0.16.5__py3-none-any.whl → 0.16.7__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (80) hide show
  1. langroid/agent/md_tool_message_grammar.py +455 -0
  2. langroid/agent/tools/code_file_tool_parse.py +150 -0
  3. langroid/agent/tools/code_file_tool_pyparsing.py +194 -0
  4. langroid/agent/tools/code_file_tool_pyparsing2.py +199 -0
  5. langroid/agent/tools/formatted_model_custom.py +150 -0
  6. langroid/agent/tools/formatted_model_custom2.py +168 -0
  7. langroid/agent/tools/formatted_model_custom3.py +279 -0
  8. langroid/agent/tools/formatted_model_custom4.py +395 -0
  9. langroid/agent/tools/formatted_model_jinja.py +133 -0
  10. langroid/agent/tools/formatted_model_jinja.py-e +122 -0
  11. langroid/agent/tools/formatted_model_jinja2.py +145 -0
  12. langroid/agent/tools/formatted_model_jinja2.py-e +135 -0
  13. langroid/agent/tools/formatted_model_lark.py +0 -0
  14. langroid/agent/tools/formatted_model_lark2.py +168 -0
  15. langroid/agent/tools/formatted_model_parse.py +105 -0
  16. langroid/agent/tools/formatted_model_parse.py-e +98 -0
  17. langroid/agent/tools/formatted_model_parse2.py +113 -0
  18. langroid/agent/tools/formatted_model_parse2.py-e +109 -0
  19. langroid/agent/tools/formatted_model_parse3.py +114 -0
  20. langroid/agent/tools/formatted_model_parse3.py-e +110 -0
  21. langroid/agent/tools/formatted_model_parsimon.py +194 -0
  22. langroid/agent/tools/formatted_model_parsimon.py-e +186 -0
  23. langroid/agent/tools/formatted_model_pyparsing.py +169 -0
  24. langroid/agent/tools/formatted_model_pyparsing.py-e +149 -0
  25. langroid/agent/tools/formatted_model_pyparsing2.py +159 -0
  26. langroid/agent/tools/formatted_model_pyparsing2.py-e +143 -0
  27. langroid/agent/tools/formatted_model_pyparsing3.py +133 -0
  28. langroid/agent/tools/formatted_model_pyparsing3.py-e +121 -0
  29. langroid/agent/tools/formatted_model_pyparsing4.py +213 -0
  30. langroid/agent/tools/formatted_model_pyparsing4.py-e +176 -0
  31. langroid/agent/tools/formatted_model_pyparsing5.py +173 -0
  32. langroid/agent/tools/formatted_model_pyparsing5.py-e +142 -0
  33. langroid/agent/tools/formatted_model_regex.py +246 -0
  34. langroid/agent/tools/formatted_model_regex.py-e +248 -0
  35. langroid/agent/tools/formatted_model_regex2.py +250 -0
  36. langroid/agent/tools/formatted_model_regex2.py-e +253 -0
  37. langroid/agent/tools/formatted_model_tatsu.py +172 -0
  38. langroid/agent/tools/formatted_model_tatsu.py-e +160 -0
  39. langroid/agent/tools/formatted_model_template.py +217 -0
  40. langroid/agent/tools/formatted_model_template.py-e +200 -0
  41. langroid/agent/tools/formatted_model_xml.py +178 -0
  42. langroid/agent/tools/formatted_model_xml2.py +178 -0
  43. langroid/agent/tools/formatted_model_xml3.py +132 -0
  44. langroid/agent/tools/formatted_model_xml4.py +130 -0
  45. langroid/agent/tools/formatted_model_xml5.py +130 -0
  46. langroid/agent/tools/formatted_model_xml6.py +113 -0
  47. langroid/agent/tools/formatted_model_xml7.py +117 -0
  48. langroid/agent/tools/formatted_model_xml8.py +164 -0
  49. langroid/agent/tools/generic_tool.py +165 -0
  50. langroid/agent/tools/generic_tool_tatsu.py +275 -0
  51. langroid/agent/tools/grammar_based_model.py +132 -0
  52. langroid/agent/tools/grammar_based_model.py-e +128 -0
  53. langroid/agent/tools/grammar_based_model_lark.py +156 -0
  54. langroid/agent/tools/grammar_based_model_lark.py-e +153 -0
  55. langroid/agent/tools/grammar_based_model_parse.py +86 -0
  56. langroid/agent/tools/grammar_based_model_parse.py-e +80 -0
  57. langroid/agent/tools/grammar_based_model_parsimonious.py +129 -0
  58. langroid/agent/tools/grammar_based_model_parsimonious.py-e +120 -0
  59. langroid/agent/tools/grammar_based_model_pyparsing.py +105 -0
  60. langroid/agent/tools/grammar_based_model_pyparsing.py-e +103 -0
  61. langroid/agent/tools/grammar_based_model_regex.py +139 -0
  62. langroid/agent/tools/grammar_based_model_regex.py-e +130 -0
  63. langroid/agent/tools/grammar_based_model_regex2.py +124 -0
  64. langroid/agent/tools/grammar_based_model_regex2.py-e +116 -0
  65. langroid/agent/tools/grammar_based_model_tatsu.py +80 -0
  66. langroid/agent/tools/grammar_based_model_tatsu.py-e +77 -0
  67. langroid/agent/tools/lark_earley_example.py +135 -0
  68. langroid/agent/tools/lark_earley_example.py-e +117 -0
  69. langroid/agent/tools/lark_example.py +72 -0
  70. langroid/agent/tools/parse_example.py +76 -0
  71. langroid/agent/tools/parse_example2.py +87 -0
  72. langroid/agent/tools/parse_example3.py +42 -0
  73. langroid/agent/tools/parse_test.py +791 -0
  74. langroid/agent/xml_tool_message.py +106 -0
  75. langroid/language_models/openai_gpt.py +6 -1
  76. {langroid-0.16.5.dist-info → langroid-0.16.7.dist-info}/METADATA +1 -1
  77. {langroid-0.16.5.dist-info → langroid-0.16.7.dist-info}/RECORD +80 -6
  78. pyproject.toml +1 -1
  79. {langroid-0.16.5.dist-info → langroid-0.16.7.dist-info}/LICENSE +0 -0
  80. {langroid-0.16.5.dist-info → langroid-0.16.7.dist-info}/WHEEL +0 -0
@@ -0,0 +1,246 @@
1
+ import re
2
+ from abc import ABC, abstractmethod
3
+ from typing import Dict, Type, TypeVar
4
+
5
+ from langroid.pydantic_v1 import BaseModel
6
+
7
+ T = TypeVar("T", bound="FormattingModel")
8
+
9
+
10
+ class FormattingModel(BaseModel, ABC):
11
+ @classmethod
12
+ @abstractmethod
13
+ def format_spec(cls) -> str:
14
+ pass
15
+
16
+ @classmethod
17
+ @abstractmethod
18
+ def start_token(cls) -> str:
19
+ pass
20
+
21
+ @classmethod
22
+ @abstractmethod
23
+ def end_token(cls) -> str:
24
+ pass
25
+
26
+ @classmethod
27
+ @abstractmethod
28
+ def field_mappings(cls) -> Dict[str, str]:
29
+ pass
30
+
31
+ @classmethod
32
+ def parse(cls: Type[T], text: str) -> T:
33
+ # Remove start and end tokens
34
+ content = text.strip()[len(cls.start_token()) : -len(cls.end_token())].strip()
35
+
36
+ # Create regex pattern from format_spec
37
+ pattern = cls.format_spec()
38
+ for field, token in cls.field_mappings().items():
39
+ pattern = pattern.replace(token, f"(?P<{field}>.*?)")
40
+
41
+ # Extract data using regex
42
+ match = re.match(pattern, content, re.DOTALL)
43
+ if not match:
44
+ raise ValueError("Invalid format")
45
+
46
+ # Create instance with extracted data
47
+ data = {field: match.group(field).strip() for field in cls.field_mappings()}
48
+ return cls(**data)
49
+
50
+ def generate(self) -> str:
51
+ # Start with the format spec
52
+ result = self.format_spec()
53
+
54
+ # Replace tokens with actual values
55
+ for field, token in self.field_mappings().items():
56
+ value = getattr(self, field)
57
+ result = result.replace(token, str(value))
58
+
59
+ # Wrap with start and end tokens
60
+ return f"{self.start_token()}\n{result}\n{self.end_token()}"
61
+
62
+
63
+ class MyFormattedModel(FormattingModel):
64
+ name: str
65
+ age: int
66
+ city: str
67
+
68
+ @classmethod
69
+ def format_spec(cls) -> str:
70
+ return "name: {NAME}\n{AGE} is the age\nlives in {CITY}"
71
+
72
+ @classmethod
73
+ def start_token(cls) -> str:
74
+ return "<format>"
75
+
76
+ @classmethod
77
+ def end_token(cls) -> str:
78
+ return "</format>"
79
+
80
+ @classmethod
81
+ def field_mappings(cls) -> Dict[str, str]:
82
+ return {"name": "{NAME}", "age": "{AGE}", "city": "{CITY}"}
83
+
84
+
85
+ if __name__ == "__main__":
86
+ # Test object to string
87
+ model = MyFormattedModel(name="John", age=30, city="Tokyo")
88
+ generated = model.generate()
89
+ print("Generated string:")
90
+ print(generated)
91
+ print()
92
+
93
+ # Test string to object
94
+ parsed = MyFormattedModel.parse(generated)
95
+ print("Parsed object:")
96
+ print(parsed)
97
+ print()
98
+
99
+ # Test round-trip
100
+ print("Round-trip test:")
101
+ print("Original == Parsed:", model == parsed)
102
+
103
+ # Test with different values
104
+ another_model = MyFormattedModel(name="Alice", age=25, city="New York")
105
+ another_generated = another_model.generate()
106
+ print("\nAnother generated string:")
107
+ print(another_generated)
108
+ print()
109
+
110
+ another_parsed = MyFormattedModel.parse(another_generated)
111
+ print("Another parsed object:")
112
+ print(another_parsed)
113
+ print("Another Original == Another Parsed:", another_model == another_parsed)
114
+
115
+ # code file model
116
+ class CodeFileModel(FormattingModel):
117
+ language: str
118
+ file_path: str
119
+ code: str
120
+
121
+ @classmethod
122
+ def format_spec(cls) -> str:
123
+ return "code_file_model\nfile_path: {FILE_PATH}\n```{LANGUAGE}\n{CODE}\n```"
124
+
125
+ @classmethod
126
+ def start_token(cls) -> str:
127
+ return "<format>"
128
+
129
+ @classmethod
130
+ def end_token(cls) -> str:
131
+ return "</format>"
132
+
133
+ @classmethod
134
+ def field_mappings(cls) -> Dict[str, str]:
135
+ return {
136
+ "file_path": "{FILE_PATH}",
137
+ "language": "{LANGUAGE}",
138
+ "code": "{CODE}",
139
+ }
140
+
141
+ print("\nTesting CodeFileModel:")
142
+ code_model = CodeFileModel(
143
+ language="python",
144
+ file_path="src/main.py",
145
+ code='def hello():\n print("Hello, World!")',
146
+ )
147
+ code_generated = code_model.generate()
148
+ print("Generated CodeFileModel string:")
149
+ print(code_generated)
150
+ print()
151
+
152
+ code_parsed = CodeFileModel.parse(code_generated)
153
+ print("Parsed CodeFileModel object:")
154
+ print(code_parsed)
155
+ print()
156
+
157
+ print("CodeFileModel Round-trip test:")
158
+ print("Original == Parsed:", code_model == code_parsed)
159
+
160
+ # tolerant format
161
+ #
162
+ class CodeFileModel(FormattingModel):
163
+ language: str
164
+ file_path: str
165
+ code: str
166
+
167
+ @classmethod
168
+ def format_spec(cls) -> str:
169
+ return (
170
+ r"code_file_model\s*\n"
171
+ r"file_path:\s*{FILE_PATH}\s*\n"
172
+ r"```\s*{LANGUAGE}\s*\n"
173
+ r"{CODE}\s*"
174
+ r"```"
175
+ )
176
+
177
+ @classmethod
178
+ def start_token(cls) -> str:
179
+ return "<format>"
180
+
181
+ @classmethod
182
+ def end_token(cls) -> str:
183
+ return "</format>"
184
+
185
+ @classmethod
186
+ def field_mappings(cls) -> Dict[str, str]:
187
+ return {
188
+ "file_path": "{FILE_PATH}",
189
+ "language": "{LANGUAGE}",
190
+ "code": "{CODE}",
191
+ }
192
+
193
+ print("\nTesting CodeFileModel with various whitespace variations:")
194
+
195
+ test_strings = [
196
+ # Standard format
197
+ """<format>
198
+ code_file_model
199
+ file_path: src/main.py
200
+ ```python
201
+ def hello():
202
+ print("Hello, World!")
203
+ ```
204
+ </format>""",
205
+ # Extra whitespace
206
+ """<format>
207
+ code_file_model
208
+ file_path: src/main.py
209
+ ``` python
210
+ def hello():
211
+ print("Hello, World!")
212
+ ```
213
+ </format>""",
214
+ # Extra newlines
215
+ """<format>
216
+ code_file_model
217
+
218
+ file_path: src/main.py
219
+
220
+ ```python
221
+
222
+ def hello():
223
+ print("Hello, World!")
224
+
225
+ ```
226
+
227
+ </format>""",
228
+ ]
229
+
230
+ for i, test_string in enumerate(test_strings, 1):
231
+ print(f"\nTest {i}:")
232
+ print("Input string:")
233
+ print(test_string)
234
+
235
+ parsed = CodeFileModel.parse(test_string)
236
+ print("\nParsed object:")
237
+ print(parsed)
238
+
239
+ regenerated = parsed.generate()
240
+ print("\nRegenerated string:")
241
+ print(regenerated)
242
+
243
+ reparsed = CodeFileModel.parse(regenerated)
244
+ print("\nRound-trip test:")
245
+ print("Original parsed == Reparsed:", parsed == reparsed)
246
+ print("-" * 50)
@@ -0,0 +1,248 @@
1
+ from pydantic import BaseModel
2
+ from abc import ABC, abstractmethod
3
+ import re
4
+ from typing import Dict, Type, TypeVar
5
+
6
+ T = TypeVar('T', bound='FormattingModel')
7
+
8
+ class FormattingModel(BaseModel, ABC):
9
+ @classmethod
10
+ @abstractmethod
11
+ def format_spec(cls) -> str:
12
+ pass
13
+
14
+ @classmethod
15
+ @abstractmethod
16
+ def start_token(cls) -> str:
17
+ pass
18
+
19
+ @classmethod
20
+ @abstractmethod
21
+ def end_token(cls) -> str:
22
+ pass
23
+
24
+ @classmethod
25
+ @abstractmethod
26
+ def field_mappings(cls) -> Dict[str, str]:
27
+ pass
28
+
29
+ @classmethod
30
+ def parse(cls: Type[T], text: str) -> T:
31
+ # Remove start and end tokens
32
+ content = text.strip()[len(cls.start_token()):-len(cls.end_token())].strip()
33
+
34
+ # Create regex pattern from format_spec
35
+ pattern = cls.format_spec()
36
+ for field, token in cls.field_mappings().items():
37
+ pattern = pattern.replace(token, f"(?P<{field}>.*?)")
38
+
39
+ # Extract data using regex
40
+ match = re.match(pattern, content, re.DOTALL)
41
+ if not match:
42
+ raise ValueError("Invalid format")
43
+
44
+ # Create instance with extracted data
45
+ data = {field: match.group(field).strip() for field in cls.field_mappings()}
46
+ return cls(**data)
47
+
48
+ def generate(self) -> str:
49
+ # Start with the format spec
50
+ result = self.format_spec()
51
+
52
+ # Replace tokens with actual values
53
+ for field, token in self.field_mappings().items():
54
+ value = getattr(self, field)
55
+ result = result.replace(token, str(value))
56
+
57
+ # Wrap with start and end tokens
58
+ return f"{self.start_token()}\n{result}\n{self.end_token()}"
59
+
60
+ class MyFormattedModel(FormattingModel):
61
+ name: str
62
+ age: int
63
+ city: str
64
+
65
+ @classmethod
66
+ def format_spec(cls) -> str:
67
+ return "name: {NAME}\n{AGE} is the age\nlives in {CITY}"
68
+
69
+ @classmethod
70
+ def start_token(cls) -> str:
71
+ return "<format>"
72
+
73
+ @classmethod
74
+ def end_token(cls) -> str:
75
+ return "</format>"
76
+
77
+ @classmethod
78
+ def field_mappings(cls) -> Dict[str, str]:
79
+ return {
80
+ "name": "{NAME}",
81
+ "age": "{AGE}",
82
+ "city": "{CITY}"
83
+ }
84
+
85
+ if __name__ == "__main__":
86
+ # Test object to string
87
+ model = MyFormattedModel(name="John", age=30, city="Tokyo")
88
+ generated = model.generate()
89
+ print("Generated string:")
90
+ print(generated)
91
+ print()
92
+
93
+ # Test string to object
94
+ parsed = MyFormattedModel.parse(generated)
95
+ print("Parsed object:")
96
+ print(parsed)
97
+ print()
98
+
99
+ # Test round-trip
100
+ print("Round-trip test:")
101
+ print("Original == Parsed:", model == parsed)
102
+
103
+ # Test with different values
104
+ another_model = MyFormattedModel(name="Alice", age=25, city="New York")
105
+ another_generated = another_model.generate()
106
+ print("\nAnother generated string:")
107
+ print(another_generated)
108
+ print()
109
+
110
+ another_parsed = MyFormattedModel.parse(another_generated)
111
+ print("Another parsed object:")
112
+ print(another_parsed)
113
+ print("Another Original == Another Parsed:", another_model == another_parsed)
114
+
115
+
116
+ # code file model
117
+ class CodeFileModel(FormattingModel):
118
+ language: str
119
+ file_path: str
120
+ code: str
121
+
122
+ @classmethod
123
+ def format_spec(cls) -> str:
124
+ return "code_file_model\nfile_path: {FILE_PATH}\n```{LANGUAGE}\n{CODE}\n```"
125
+
126
+ @classmethod
127
+ def start_token(cls) -> str:
128
+ return "<format>"
129
+
130
+ @classmethod
131
+ def end_token(cls) -> str:
132
+ return "</format>"
133
+
134
+ @classmethod
135
+ def field_mappings(cls) -> Dict[str, str]:
136
+ return {
137
+ "file_path": "{FILE_PATH}",
138
+ "language": "{LANGUAGE}",
139
+ "code": "{CODE}"
140
+ }
141
+
142
+
143
+ print("\nTesting CodeFileModel:")
144
+ code_model = CodeFileModel(
145
+ language="python",
146
+ file_path="src/main.py",
147
+ code="def hello():\n print(\"Hello, World!\")"
148
+ )
149
+ code_generated = code_model.generate()
150
+ print("Generated CodeFileModel string:")
151
+ print(code_generated)
152
+ print()
153
+
154
+ code_parsed = CodeFileModel.parse(code_generated)
155
+ print("Parsed CodeFileModel object:")
156
+ print(code_parsed)
157
+ print()
158
+
159
+ print("CodeFileModel Round-trip test:")
160
+ print("Original == Parsed:", code_model == code_parsed)
161
+
162
+ # tolerant format
163
+ #
164
+ class CodeFileModel(FormattingModel):
165
+ language: str
166
+ file_path: str
167
+ code: str
168
+
169
+ @classmethod
170
+ def format_spec(cls) -> str:
171
+ return (
172
+ r"code_file_model\s*\n"
173
+ r"file_path:\s*{FILE_PATH}\s*\n"
174
+ r"```\s*{LANGUAGE}\s*\n"
175
+ r"{CODE}\s*"
176
+ r"```"
177
+ )
178
+
179
+ @classmethod
180
+ def start_token(cls) -> str:
181
+ return "<format>"
182
+
183
+ @classmethod
184
+ def end_token(cls) -> str:
185
+ return "</format>"
186
+
187
+ @classmethod
188
+ def field_mappings(cls) -> Dict[str, str]:
189
+ return {
190
+ "file_path": "{FILE_PATH}",
191
+ "language": "{LANGUAGE}",
192
+ "code": "{CODE}"
193
+ }
194
+
195
+ print("\nTesting CodeFileModel with various whitespace variations:")
196
+
197
+ test_strings = [
198
+ # Standard format
199
+ """<format>
200
+ code_file_model
201
+ file_path: src/main.py
202
+ ```python
203
+ def hello():
204
+ print("Hello, World!")
205
+ ```
206
+ </format>""",
207
+ # Extra whitespace
208
+ """<format>
209
+ code_file_model
210
+ file_path: src/main.py
211
+ ``` python
212
+ def hello():
213
+ print("Hello, World!")
214
+ ```
215
+ </format>""",
216
+ # Extra newlines
217
+ """<format>
218
+ code_file_model
219
+
220
+ file_path: src/main.py
221
+
222
+ ```python
223
+
224
+ def hello():
225
+ print("Hello, World!")
226
+
227
+ ```
228
+
229
+ </format>"""
230
+ ]
231
+
232
+ for i, test_string in enumerate(test_strings, 1):
233
+ print(f"\nTest {i}:")
234
+ print("Input string:")
235
+ print(test_string)
236
+
237
+ parsed = CodeFileModel.parse(test_string)
238
+ print("\nParsed object:")
239
+ print(parsed)
240
+
241
+ regenerated = parsed.generate()
242
+ print("\nRegenerated string:")
243
+ print(regenerated)
244
+
245
+ reparsed = CodeFileModel.parse(regenerated)
246
+ print("\nRound-trip test:")
247
+ print("Original parsed == Reparsed:", parsed == reparsed)
248
+ print("-" * 50)