@@ -28,6 +28,21 @@ def extract_output(self, text: str) -> str:
2828 match = re .search (r'<output>(.*?)(?:</output>|$)' , text , re .DOTALL )
2929 return match .group (1 ).strip () if match else ""
3030
31+ def _extract_content (self , response , context : str ) -> str :
32+ """Validate a provider response and return its message content.
33+
34+ Guards against the empty / None / length-truncated responses that would
35+ otherwise raise IndexError/TypeError downstream (e.g. when the content
36+ is fed to extract_output or split). Mirrors the response-validation
37+ idiom already used in moa/bon/plansearch.
38+ """
39+ if (response is None or
40+ not response .choices or
41+ response .choices [0 ].message .content is None or
42+ response .choices [0 ].finish_reason == "length" ):
43+ raise Exception (f"LEAP: provider returned an empty, None, or truncated response while { context } " )
44+ return response .choices [0 ].message .content
45+
3146 def extract_examples_from_query (self , initial_query : str ) -> List [Tuple [str , str ]]:
3247 logger .info ("Extracting examples from initial query" )
3348
@@ -66,7 +81,7 @@ def extract_examples_from_query(self, initial_query: str) -> List[Tuple[str, str
6681 optillm .conversation_logger .log_provider_call (self .request_id , provider_request , response_dict )
6782
6883 self .leap_completion_tokens += response .usage .completion_tokens
69- examples_str = self .extract_output (response . choices [ 0 ]. message . content )
84+ examples_str = self .extract_output (self . _extract_content ( response , "extracting examples from the query" ) )
7085 logger .debug (f"Extracted examples: { examples_str } " )
7186 examples = []
7287 if examples_str :
@@ -109,7 +124,7 @@ def generate_mistakes(self, examples: List[Tuple[str, str]]) -> List[Tuple[str,
109124 response_dict = response .model_dump () if hasattr (response , 'model_dump' ) else response
110125 optillm .conversation_logger .log_provider_call (self .request_id , provider_request , response_dict )
111126 self .leap_completion_tokens += response .usage .completion_tokens
112- generated_reasoning = response . choices [ 0 ]. message . content
127+ generated_reasoning = self . _extract_content ( response , "generating reasoning for a mistake example" )
113128 generated_answer = self .extract_output (generated_reasoning )
114129 if generated_answer != correct_answer :
115130 mistakes .append ((question , generated_reasoning , generated_answer , correct_answer ))
@@ -148,7 +163,7 @@ def generate_low_level_principles(self, mistakes: List[Tuple[str, str, str, str]
148163 response_dict = response .model_dump () if hasattr (response , 'model_dump' ) else response
149164 optillm .conversation_logger .log_provider_call (self .request_id , provider_request , response_dict )
150165 self .leap_completion_tokens += response .usage .completion_tokens
151- self .low_level_principles .append (self .extract_output (response . choices [ 0 ]. message . content ))
166+ self .low_level_principles .append (self .extract_output (self . _extract_content ( response , "generating low-level principles" ) ))
152167 return self .low_level_principles
153168
154169 def generate_high_level_principles (self ) -> List [str ]:
@@ -181,7 +196,7 @@ def generate_high_level_principles(self) -> List[str]:
181196 response_dict = response .model_dump () if hasattr (response , 'model_dump' ) else response
182197 optillm .conversation_logger .log_provider_call (self .request_id , provider_request , response_dict )
183198 self .leap_completion_tokens += response .usage .completion_tokens
184- self .high_level_principles = self .extract_output (response . choices [ 0 ]. message . content ).split ("\n " )
199+ self .high_level_principles = self .extract_output (self . _extract_content ( response , "generating high-level principles" ) ).split ("\n " )
185200 return self .high_level_principles
186201
187202 def apply_principles (self , query : str ) -> str :
@@ -210,7 +225,7 @@ def apply_principles(self, query: str) -> str:
210225 response_dict = response .model_dump () if hasattr (response , 'model_dump' ) else response
211226 optillm .conversation_logger .log_provider_call (self .request_id , provider_request , response_dict )
212227 self .leap_completion_tokens += response .usage .completion_tokens
213- return response . choices [ 0 ]. message . content
228+ return self . _extract_content ( response , "applying principles to the query" )
214229
215230 def solve (self , initial_query : str ) -> str :
216231 logger .info ("Starting LEAP process" )
0 commit comments