12
12
"""
13
13
14
14
import json
15
- from typing import Any , Dict
15
+ from typing import Any , Dict , Optional
16
16
17
+ from pydantic import BaseModel , Field , validator
17
18
from langchain .prompts import PromptTemplate
18
19
from langchain_core .output_parsers import StrOutputParser
19
20
25
26
)
26
27
27
28
28
- def syntax_focused_analysis (state : dict , llm_model ) -> str :
29
+ class AnalysisError (Exception ):
30
+ """Base exception for code analysis errors."""
31
+ pass
32
+
33
+
34
+ class InvalidStateError (AnalysisError ):
35
+ """Exception raised when state dictionary is missing required keys."""
36
+ pass
37
+
38
+
39
+ class CodeAnalysisState (BaseModel ):
40
+ """Base model for code analysis state validation."""
41
+ generated_code : str = Field (..., description = "The generated code to analyze" )
42
+ errors : Dict [str , Any ] = Field (..., description = "Dictionary containing error information" )
43
+
44
+ @validator ('errors' )
45
+ def validate_errors (cls , v ):
46
+ """Ensure errors dictionary has expected structure."""
47
+ if not isinstance (v , dict ):
48
+ raise ValueError ("errors must be a dictionary" )
49
+ return v
50
+
51
+
52
+ class ExecutionAnalysisState (CodeAnalysisState ):
53
+ """Model for execution analysis state validation."""
54
+ html_code : Optional [str ] = Field (None , description = "HTML code if available" )
55
+ html_analysis : Optional [str ] = Field (None , description = "Analysis of HTML code" )
56
+
57
+ @validator ('errors' )
58
+ def validate_execution_errors (cls , v ):
59
+ """Ensure errors dictionary contains execution key."""
60
+ super ().validate_errors (v )
61
+ if 'execution' not in v :
62
+ raise ValueError ("errors dictionary must contain 'execution' key" )
63
+ return v
64
+
65
+
66
+ class ValidationAnalysisState (CodeAnalysisState ):
67
+ """Model for validation analysis state validation."""
68
+ json_schema : Dict [str , Any ] = Field (..., description = "JSON schema for validation" )
69
+ execution_result : Any = Field (..., description = "Result of code execution" )
70
+
71
+ @validator ('errors' )
72
+ def validate_validation_errors (cls , v ):
73
+ """Ensure errors dictionary contains validation key."""
74
+ super ().validate_errors (v )
75
+ if 'validation' not in v :
76
+ raise ValueError ("errors dictionary must contain 'validation' key" )
77
+ return v
78
+
79
+
80
+ def get_optimal_analysis_template (error_type : str ) -> str :
81
+ """
82
+ Returns the optimal prompt template based on the error type.
83
+
84
+ Args:
85
+ error_type (str): Type of error to analyze.
86
+
87
+ Returns:
88
+ str: The prompt template text.
89
+ """
90
+ template_registry = {
91
+ "syntax" : TEMPLATE_SYNTAX_ANALYSIS ,
92
+ "execution" : TEMPLATE_EXECUTION_ANALYSIS ,
93
+ "validation" : TEMPLATE_VALIDATION_ANALYSIS ,
94
+ "semantic" : TEMPLATE_SEMANTIC_ANALYSIS ,
95
+ }
96
+ return template_registry .get (error_type , TEMPLATE_SYNTAX_ANALYSIS )
97
+
98
+
99
+ def syntax_focused_analysis (state : Dict [str , Any ], llm_model ) -> str :
29
100
"""
30
101
Analyzes the syntax errors in the generated code.
31
102
@@ -35,17 +106,48 @@ def syntax_focused_analysis(state: dict, llm_model) -> str:
35
106
36
107
Returns:
37
108
str: The result of the syntax error analysis.
109
+
110
+ Raises:
111
+ InvalidStateError: If state is missing required keys.
112
+
113
+ Example:
114
+ >>> state = {
115
+ 'generated_code': 'print("Hello World")',
116
+ 'errors': {'syntax': 'Missing parenthesis'}
117
+ }
118
+ >>> analysis = syntax_focused_analysis(state, mock_llm)
38
119
"""
39
- prompt = PromptTemplate (
40
- template = TEMPLATE_SYNTAX_ANALYSIS , input_variables = ["generated_code" , "errors" ]
41
- )
42
- chain = prompt | llm_model | StrOutputParser ()
43
- return chain .invoke (
44
- {"generated_code" : state ["generated_code" ], "errors" : state ["errors" ]["syntax" ]}
45
- )
120
+ try :
121
+ # Validate state using Pydantic model
122
+ validated_state = CodeAnalysisState (
123
+ generated_code = state .get ("generated_code" , "" ),
124
+ errors = state .get ("errors" , {})
125
+ )
126
+
127
+ # Check if syntax errors exist
128
+ if "syntax" not in validated_state .errors :
129
+ raise InvalidStateError ("No syntax errors found in state dictionary" )
130
+
131
+ # Create prompt template and chain
132
+ prompt = PromptTemplate (
133
+ template = get_optimal_analysis_template ("syntax" ),
134
+ input_variables = ["generated_code" , "errors" ]
135
+ )
136
+ chain = prompt | llm_model | StrOutputParser ()
137
+
138
+ # Execute chain with validated state
139
+ return chain .invoke ({
140
+ "generated_code" : validated_state .generated_code ,
141
+ "errors" : validated_state .errors ["syntax" ]
142
+ })
143
+
144
+ except KeyError as e :
145
+ raise InvalidStateError (f"Missing required key in state dictionary: { e } " )
146
+ except Exception as e :
147
+ raise AnalysisError (f"Syntax analysis failed: { str (e )} " )
46
148
47
149
48
- def execution_focused_analysis (state : dict , llm_model ) -> str :
150
+ def execution_focused_analysis (state : Dict [ str , Any ] , llm_model ) -> str :
49
151
"""
50
152
Analyzes the execution errors in the generated code and HTML code.
51
153
@@ -55,23 +157,50 @@ def execution_focused_analysis(state: dict, llm_model) -> str:
55
157
56
158
Returns:
57
159
str: The result of the execution error analysis.
58
- """
59
- prompt = PromptTemplate (
60
- template = TEMPLATE_EXECUTION_ANALYSIS ,
61
- input_variables = ["generated_code" , "errors" , "html_code" , "html_analysis" ],
62
- )
63
- chain = prompt | llm_model | StrOutputParser ()
64
- return chain .invoke (
65
- {
66
- "generated_code" : state ["generated_code" ],
67
- "errors" : state ["errors" ]["execution" ],
68
- "html_code" : state ["html_code" ],
69
- "html_analysis" : state ["html_analysis" ],
160
+
161
+ Raises:
162
+ InvalidStateError: If state is missing required keys.
163
+
164
+ Example:
165
+ >>> state = {
166
+ 'generated_code': 'print(x)',
167
+ 'errors': {'execution': 'NameError: name "x" is not defined'},
168
+ 'html_code': '<div>Test</div>',
169
+ 'html_analysis': 'Valid HTML'
70
170
}
71
- )
171
+ >>> analysis = execution_focused_analysis(state, mock_llm)
172
+ """
173
+ try :
174
+ # Validate state using Pydantic model
175
+ validated_state = ExecutionAnalysisState (
176
+ generated_code = state .get ("generated_code" , "" ),
177
+ errors = state .get ("errors" , {}),
178
+ html_code = state .get ("html_code" , "" ),
179
+ html_analysis = state .get ("html_analysis" , "" )
180
+ )
181
+
182
+ # Create prompt template and chain
183
+ prompt = PromptTemplate (
184
+ template = get_optimal_analysis_template ("execution" ),
185
+ input_variables = ["generated_code" , "errors" , "html_code" , "html_analysis" ],
186
+ )
187
+ chain = prompt | llm_model | StrOutputParser ()
188
+
189
+ # Execute chain with validated state
190
+ return chain .invoke ({
191
+ "generated_code" : validated_state .generated_code ,
192
+ "errors" : validated_state .errors ["execution" ],
193
+ "html_code" : validated_state .html_code ,
194
+ "html_analysis" : validated_state .html_analysis ,
195
+ })
196
+
197
+ except KeyError as e :
198
+ raise InvalidStateError (f"Missing required key in state dictionary: { e } " )
199
+ except Exception as e :
200
+ raise AnalysisError (f"Execution analysis failed: { str (e )} " )
72
201
73
202
74
- def validation_focused_analysis (state : dict , llm_model ) -> str :
203
+ def validation_focused_analysis (state : Dict [ str , Any ] , llm_model ) -> str :
75
204
"""
76
205
Analyzes the validation errors in the generated code based on a JSON schema.
77
206
@@ -82,24 +211,51 @@ def validation_focused_analysis(state: dict, llm_model) -> str:
82
211
83
212
Returns:
84
213
str: The result of the validation error analysis.
85
- """
86
- prompt = PromptTemplate (
87
- template = TEMPLATE_VALIDATION_ANALYSIS ,
88
- input_variables = ["generated_code" , "errors" , "json_schema" , "execution_result" ],
89
- )
90
- chain = prompt | llm_model | StrOutputParser ()
91
- return chain .invoke (
92
- {
93
- "generated_code" : state ["generated_code" ],
94
- "errors" : state ["errors" ]["validation" ],
95
- "json_schema" : state ["json_schema" ],
96
- "execution_result" : state ["execution_result" ],
214
+
215
+ Raises:
216
+ InvalidStateError: If state is missing required keys.
217
+
218
+ Example:
219
+ >>> state = {
220
+ 'generated_code': 'return {"name": "John"}',
221
+ 'errors': {'validation': 'Missing required field: age'},
222
+ 'json_schema': {'required': ['name', 'age']},
223
+ 'execution_result': {'name': 'John'}
97
224
}
98
- )
225
+ >>> analysis = validation_focused_analysis(state, mock_llm)
226
+ """
227
+ try :
228
+ # Validate state using Pydantic model
229
+ validated_state = ValidationAnalysisState (
230
+ generated_code = state .get ("generated_code" , "" ),
231
+ errors = state .get ("errors" , {}),
232
+ json_schema = state .get ("json_schema" , {}),
233
+ execution_result = state .get ("execution_result" , {})
234
+ )
235
+
236
+ # Create prompt template and chain
237
+ prompt = PromptTemplate (
238
+ template = get_optimal_analysis_template ("validation" ),
239
+ input_variables = ["generated_code" , "errors" , "json_schema" , "execution_result" ],
240
+ )
241
+ chain = prompt | llm_model | StrOutputParser ()
242
+
243
+ # Execute chain with validated state
244
+ return chain .invoke ({
245
+ "generated_code" : validated_state .generated_code ,
246
+ "errors" : validated_state .errors ["validation" ],
247
+ "json_schema" : validated_state .json_schema ,
248
+ "execution_result" : validated_state .execution_result ,
249
+ })
250
+
251
+ except KeyError as e :
252
+ raise InvalidStateError (f"Missing required key in state dictionary: { e } " )
253
+ except Exception as e :
254
+ raise AnalysisError (f"Validation analysis failed: { str (e )} " )
99
255
100
256
101
257
def semantic_focused_analysis (
102
- state : dict , comparison_result : Dict [str , Any ], llm_model
258
+ state : Dict [ str , Any ] , comparison_result : Dict [str , Any ], llm_model
103
259
) -> str :
104
260
"""
105
261
Analyzes the semantic differences in the generated code based on a comparison result.
@@ -112,16 +268,48 @@ def semantic_focused_analysis(
112
268
113
269
Returns:
114
270
str: The result of the semantic error analysis.
271
+
272
+ Raises:
273
+ InvalidStateError: If state or comparison_result is missing required keys.
274
+
275
+ Example:
276
+ >>> state = {
277
+ 'generated_code': 'def add(a, b): return a + b'
278
+ }
279
+ >>> comparison_result = {
280
+ 'differences': ['Missing docstring', 'No type hints'],
281
+ 'explanation': 'The code is missing documentation'
282
+ }
283
+ >>> analysis = semantic_focused_analysis(state, comparison_result, mock_llm)
115
284
"""
116
- prompt = PromptTemplate (
117
- template = TEMPLATE_SEMANTIC_ANALYSIS ,
118
- input_variables = ["generated_code" , "differences" , "explanation" ],
119
- )
120
- chain = prompt | llm_model | StrOutputParser ()
121
- return chain .invoke (
122
- {
123
- "generated_code" : state ["generated_code" ],
285
+ try :
286
+ # Validate state using Pydantic model
287
+ validated_state = CodeAnalysisState (
288
+ generated_code = state .get ("generated_code" , "" ),
289
+ errors = state .get ("errors" , {})
290
+ )
291
+
292
+ # Validate comparison_result
293
+ if "differences" not in comparison_result :
294
+ raise InvalidStateError ("comparison_result missing 'differences' key" )
295
+ if "explanation" not in comparison_result :
296
+ raise InvalidStateError ("comparison_result missing 'explanation' key" )
297
+
298
+ # Create prompt template and chain
299
+ prompt = PromptTemplate (
300
+ template = get_optimal_analysis_template ("semantic" ),
301
+ input_variables = ["generated_code" , "differences" , "explanation" ],
302
+ )
303
+ chain = prompt | llm_model | StrOutputParser ()
304
+
305
+ # Execute chain with validated inputs
306
+ return chain .invoke ({
307
+ "generated_code" : validated_state .generated_code ,
124
308
"differences" : json .dumps (comparison_result ["differences" ], indent = 2 ),
125
309
"explanation" : comparison_result ["explanation" ],
126
- }
127
- )
310
+ })
311
+
312
+ except KeyError as e :
313
+ raise InvalidStateError (f"Missing required key: { e } " )
314
+ except Exception as e :
315
+ raise AnalysisError (f"Semantic analysis failed: { str (e )} " )
0 commit comments