diff --git a/aider/coders/base_coder.py b/aider/coders/base_coder.py index 4884a0eac..555868c31 100755 --- a/aider/coders/base_coder.py +++ b/aider/coders/base_coder.py @@ -1830,9 +1830,12 @@ class Coder: def remove_reasoning_content(self): """Remove reasoning content from the model's response.""" - self.partial_response_content = self.main_model.remove_reasoning_content( + from aider.reasoning_tags import remove_reasoning_content + + self.partial_response_content = remove_reasoning_content( self.partial_response_content, self.reasoning_tag_name, + self.main_model.remove_reasoning, ) def calculate_and_show_tokens_and_cost(self, messages, completion=None): diff --git a/aider/models.py b/aider/models.py index 44bec7770..bac846fba 100644 --- a/aider/models.py +++ b/aider/models.py @@ -633,26 +633,6 @@ class Model(ModelSettings): res = litellm.completion(**kwargs) return hash_object, res - def remove_reasoning_content(self, res, reasoning_tag=None): - if not reasoning_tag: - reasoning_tag = self.remove_reasoning - - if not reasoning_tag: - return res - - # Try to match the complete tag pattern first - pattern = f"<{reasoning_tag}>.*?" - res = re.sub(pattern, "", res, flags=re.DOTALL).strip() - - # If closing tag exists but opening tag might be missing, remove everything before closing - # tag - closing_tag = f"" - if closing_tag in res: - # Split on the closing tag and keep everything after it - parts = res.split(closing_tag, 1) - res = parts[1].strip() if len(parts) > 1 else res - - return res def simple_send_with_retries(self, messages): from aider.exceptions import LiteLLMExceptions @@ -674,7 +654,8 @@ class Model(ModelSettings): if not response or not hasattr(response, "choices") or not response.choices: return None res = response.choices[0].message.content - return self.remove_reasoning_content(res) + from aider.reasoning_tags import remove_reasoning_content + return remove_reasoning_content(res, self.remove_reasoning) except litellm_ex.exceptions_tuple() as err: ex_info = litellm_ex.get_ex_info(err) diff --git a/aider/reasoning_tags.py b/aider/reasoning_tags.py index d7af23e9e..5a8381fb5 100644 --- a/aider/reasoning_tags.py +++ b/aider/reasoning_tags.py @@ -11,6 +11,39 @@ REASONING_START = "> Thinking ..." REASONING_END = "> ... done thinking.\n\n------" +def remove_reasoning_content(res, reasoning_tag=None, model_remove_reasoning=None): + """ + Remove reasoning content from text based on tags. + + Args: + res (str): The text to process + reasoning_tag (str): The tag name to remove + model_remove_reasoning (str): Fallback tag name from model settings + + Returns: + str: Text with reasoning content removed + """ + if not reasoning_tag: + reasoning_tag = model_remove_reasoning + + if not reasoning_tag: + return res + + # Try to match the complete tag pattern first + pattern = f"<{reasoning_tag}>.*?" + res = re.sub(pattern, "", res, flags=re.DOTALL).strip() + + # If closing tag exists but opening tag might be missing, remove everything before closing + # tag + closing_tag = f"" + if closing_tag in res: + # Split on the closing tag and keep everything after it + parts = res.split(closing_tag, 1) + res = parts[1].strip() if len(parts) > 1 else res + + return res + + def replace_reasoning_tags(text, tag_name): """ Replace opening and closing reasoning tags with standard formatting.