diff --git a/aider/args.py b/aider/args.py index 08c9bde76..f0a1fe2f2 100644 --- a/aider/args.py +++ b/aider/args.py @@ -145,6 +145,14 @@ def get_parser(default_config_files, git_root): type=str, help="Set the thinking token budget for models that support it (default: not set)", ) + group.add_argument( + "--enable-thinking", + type=str, + help=( + "Switches between thinking and non-thinking modes for models that support it." + " (default: not set)" + ), + ) group.add_argument( "--verify-ssl", action=argparse.BooleanOptionalAction, diff --git a/aider/commands.py b/aider/commands.py index aaf6d7ddd..e96f5a81a 100644 --- a/aider/commands.py +++ b/aider/commands.py @@ -1588,6 +1588,27 @@ class Commands: announcements = "\n".join(self.coder.get_announcements()) self.io.tool_output(announcements) + def cmd_enable_thinking(self, args): + """Enable or disable thinking for models that support it.""" + model = self.coder.main_model + if isinstance(args, str) and not args.strip(): + # Display current value if no args are provided + thinking_value = model.get_enable_thinking() + if thinking_value is None: + self.io.tool_output("Thinking is not currently set.") + else: + self.io.tool_output(f"Current thinking setting: {thinking_value}") + return + + model.set_enable_thinking(args, self.io) + thinking_value = model.get_enable_thinking() + self.io.tool_output(f"Set enable thinking to {thinking_value}") + self.io.tool_output() + + # Output announcements + announcements = "\n".join(self.coder.get_announcements()) + self.io.tool_output(announcements) + def cmd_copy_context(self, args=None): """Copy the current chat context as markdown, suitable to paste into a web UI""" diff --git a/aider/models.py b/aider/models.py index 67f0458ef..026f36ffc 100644 --- a/aider/models.py +++ b/aider/models.py @@ -14,6 +14,7 @@ from typing import Optional, Union import json5 import yaml from PIL import Image +from pydantic import TypeAdapter, ValidationError from aider.dump import dump # noqa: F401 from aider.llm import litellm @@ -755,6 +756,19 @@ class Model(ModelSettings): self.extra_params["extra_body"] = {} self.extra_params["extra_body"]["reasoning_effort"] = effort + def set_enable_thinking(self, setting, io): + """Set the enable thinking parameter for models that support it""" + if setting is not None: + if not self.extra_params: + self.extra_params = {} + if "extra_body" not in self.extra_params: + self.extra_params["extra_body"] = {} + try: + setting = TypeAdapter(bool).validate_python(setting) + self.extra_params["extra_body"].setdefault("template_vars", {}).update({"enable_thinking": setting}) + except ValidationError: + io.tool_warning("Warning: the enable-thinking command expects true or false") + def parse_token_value(self, value): """ Parse a token value string into an integer. @@ -864,6 +878,17 @@ class Model(ModelSettings): return self.extra_params["extra_body"]["reasoning_effort"] return None + def get_enable_thinking(self): + """Get enable thinking value if available""" + if ( + self.extra_params + and "extra_body" in self.extra_params + and "template_vars" in self.extra_params["extra_body"] + and "enable_thinking" in self.extra_params["extra_body"]["template_vars"] + ): + return self.extra_params["extra_body"]["template_vars"]["enable_thinking"] + return None + def is_deepseek_r1(self): name = self.name.lower() if "deepseek" not in name: