@@ -83,10 +83,11 @@ def _select_modules(self, task_description: str, task_examples: List[str] = None
83832. Select 3-7 reasoning modules that are most relevant for this task
84843. Consider both the complexity of the task and the complementary nature of different modules
85854. Avoid selecting too many similar modules
86+ 5. IMPORTANT: Respond ONLY with a valid JSON array of numbers
8687
87- Respond with a JSON list containing the numbers of the selected modules. For example : [1, 5, 9, 15, 23]
88+ Example response format : [1, 5, 9, 15, 23]
8889
89- Selected modules:"""
90+ Selected modules (JSON array only) :"""
9091
9192 response = self .client .chat .completions .create (
9293 model = self .model ,
@@ -209,7 +210,10 @@ def _implement_structure(self, adapted_modules: List[str], task_description: str
2092105. Ensure the structure flows logically from problem understanding to final answer
2102116. The structure should be comprehensive enough to handle the complexity of the task
211212
212- Create the reasoning structure in valid JSON format:"""
213+ 7. IMPORTANT: Return ONLY valid JSON with double quotes around all property names and string values
214+ 8. Do not include any text before or after the JSON structure
215+
216+ Valid JSON reasoning structure:"""
213217
214218 response = self .client .chat .completions .create (
215219 model = self .model ,
@@ -222,33 +226,131 @@ def _implement_structure(self, adapted_modules: List[str], task_description: str
222226
223227 response_text = response .choices [0 ].message .content .strip ()
224228
225- # Extract JSON from response
229+ # Extract and parse JSON from response with improved error handling
230+ return self ._parse_json_structure (response_text )
231+
232+ def _parse_json_structure (self , response_text : str ) -> Dict [str , Any ]:
233+ """Parse JSON structure with robust error handling and cleanup."""
234+
235+ # Define fallback structure
236+ fallback_structure = {
237+ "problem_understanding" : "Analyze and understand the problem requirements" ,
238+ "solution_approach" : "Determine the best approach based on problem characteristics" ,
239+ "step_by_step_reasoning" : "Work through the problem systematically" ,
240+ "verification" : "Verify the solution is correct and complete" ,
241+ "final_answer" : "State the final answer clearly"
242+ }
243+
244+ # Try multiple JSON extraction and parsing strategies
245+ strategies = [
246+ self ._extract_json_strategy_1 ,
247+ self ._extract_json_strategy_2 ,
248+ self ._extract_json_strategy_3 ,
249+ self ._clean_and_parse_strategy
250+ ]
251+
252+ for i , strategy in enumerate (strategies , 1 ):
253+ try :
254+ structure = strategy (response_text )
255+ if structure and isinstance (structure , dict ) and len (structure ) > 0 :
256+ logger .debug (f"Successfully parsed JSON using strategy { i } " )
257+ return structure
258+ except Exception as e :
259+ logger .debug (f"Strategy { i } failed: { e } " )
260+ continue
261+
262+ logger .warning (f"All JSON parsing strategies failed. Using fallback structure." )
263+ logger .debug (f"Raw response that failed to parse: { response_text [:500 ]} ..." )
264+ return fallback_structure
265+
266+ def _extract_json_strategy_1 (self , text : str ) -> Dict [str , Any ]:
267+ """Strategy 1: Find first complete JSON object with balanced braces."""
268+ start_idx = text .find ('{' )
269+ if start_idx == - 1 :
270+ raise ValueError ("No opening brace found" )
271+
272+ brace_count = 0
273+ end_idx = start_idx
274+
275+ for i in range (start_idx , len (text )):
276+ if text [i ] == '{' :
277+ brace_count += 1
278+ elif text [i ] == '}' :
279+ brace_count -= 1
280+ if brace_count == 0 :
281+ end_idx = i + 1
282+ break
283+
284+ if brace_count != 0 :
285+ raise ValueError ("Unbalanced braces" )
286+
287+ json_str = text [start_idx :end_idx ]
288+ return json .loads (json_str )
289+
290+ def _extract_json_strategy_2 (self , text : str ) -> Dict [str , Any ]:
291+ """Strategy 2: Use regex with non-greedy matching."""
292+ # Look for JSON object with non-greedy matching
293+ json_match = re .search (r'\{[^{}]*(?:\{[^{}]*\}[^{}]*)*\}' , text )
294+ if not json_match :
295+ raise ValueError ("No JSON object found with regex" )
296+
297+ json_str = json_match .group (0 )
298+ return json .loads (json_str )
299+
300+ def _extract_json_strategy_3 (self , text : str ) -> Dict [str , Any ]:
301+ """Strategy 3: Extract between ```json``` code blocks."""
302+ patterns = [
303+ r'```json\s*([^`]+)```' ,
304+ r'```\s*([^`]+)```' ,
305+ r'`([^`]+)`'
306+ ]
307+
308+ for pattern in patterns :
309+ match = re .search (pattern , text , re .DOTALL )
310+ if match :
311+ json_str = match .group (1 ).strip ()
312+ try :
313+ return json .loads (json_str )
314+ except :
315+ continue
316+
317+ raise ValueError ("No valid JSON found in code blocks" )
318+
319+ def _clean_and_parse_strategy (self , text : str ) -> Dict [str , Any ]:
320+ """Strategy 4: Clean common formatting issues and parse."""
321+ # Find JSON-like content
322+ json_match = re .search (r'\{.*\}' , text , re .DOTALL )
323+ if not json_match :
324+ raise ValueError ("No JSON-like content found" )
325+
326+ json_str = json_match .group (0 )
327+
328+ # Common cleanup operations
329+ cleanups = [
330+ # Fix single quotes to double quotes (but be careful about apostrophes)
331+ (r"(?<!\\)'([^']*)'(?=\s*[,}])" , r'"\1"' ),
332+ # Fix unquoted property names
333+ (r'([{,]\s*)([a-zA-Z_][a-zA-Z0-9_]*)\s*:' , r'\1"\2":' ),
334+ # Fix trailing commas
335+ (r',\s*([}\]])' , r'\1' ),
336+ # Fix extra commas
337+ (r',,+' , r',' ),
338+ ]
339+
340+ for pattern , replacement in cleanups :
341+ json_str = re .sub (pattern , replacement , json_str )
342+
343+ # Try parsing the cleaned JSON
226344 try :
227- # Look for JSON object in the response
228- json_match = re .search (r'\{.*\}' , response_text , re .DOTALL )
229- if json_match :
230- structure = json .loads (json_match .group (0 ))
345+ return json .loads (json_str )
346+ except json .JSONDecodeError as e :
347+ # One more attempt: try to fix the specific error location
348+ if "line 1 column 2" in str (e ):
349+ # Common issue: extra characters at start
350+ json_str = re .sub (r'^[^{]*' , '' , json_str )
351+ return json .loads (json_str )
231352 else :
232- # Fallback structure
233- structure = {
234- "problem_understanding" : "Analyze and understand the problem requirements" ,
235- "solution_approach" : "Determine the best approach based on problem characteristics" ,
236- "step_by_step_reasoning" : "Work through the problem systematically" ,
237- "verification" : "Verify the solution is correct and complete" ,
238- "final_answer" : "State the final answer clearly"
239- }
240-
241- return structure
242-
243- except Exception as e :
244- logger .warning (f"Error parsing reasoning structure: { e } " )
245- # Return fallback structure
246- return {
247- "analysis" : "Analyze the problem systematically" ,
248- "approach" : "Select appropriate solution method" ,
249- "reasoning" : "Apply step-by-step logical reasoning" ,
250- "conclusion" : "Draw final conclusion with supporting evidence"
251- }
353+ raise e
252354
253355 def solve_with_structure (self , problem : str , reasoning_structure : Dict [str , Any ]) -> str :
254356 """
0 commit comments