feat: use 'cp:' prefix in model args to toggle copy-paste mode

This commit is contained in:
Roberto Gudelj 2025-03-16 17:05:13 +00:00
parent 8bc7e32fa7
commit d2dc533de7
No known key found for this signature in database
4 changed files with 34 additions and 28 deletions

View file

@ -647,12 +647,6 @@ def get_parser(default_config_files, git_root):
default=False, default=False,
help="Enable automatic copy/paste of chat between aider and web UI (default: False)", help="Enable automatic copy/paste of chat between aider and web UI (default: False)",
) )
group.add_argument(
"--copy-paste-no-api",
action=argparse.BooleanOptionalAction,
default=False,
help="Use automatic copy/paste of chat between aider and web UI instead of API (default: False)",
)
group.add_argument( group.add_argument(
"--apply", "--apply",
metavar="FILE", metavar="FILE",

View file

@ -211,9 +211,6 @@ class Coder:
main_model = self.main_model main_model = self.main_model
weak_model = main_model.weak_model weak_model = main_model.weak_model
if main_model.copy_paste_no_api:
lines.append("Running in copy-paste mode instead of using API")
if weak_model is not main_model: if weak_model is not main_model:
prefix = "Main model" prefix = "Main model"
else: else:
@ -221,6 +218,10 @@ class Coder:
output = f"{prefix}: {main_model.name} with {self.edit_format} edit format" output = f"{prefix}: {main_model.name} with {self.edit_format} edit format"
# Check for copy paste mode instead of api
if main_model.copy_paste_instead_of_api:
output += ", copy paste mode"
# Check for thinking token budget # Check for thinking token budget
thinking_tokens = main_model.get_thinking_tokens() thinking_tokens = main_model.get_thinking_tokens()
if thinking_tokens: if thinking_tokens:
@ -243,10 +244,18 @@ class Coder:
f"Editor model: {main_model.editor_model.name} with" f"Editor model: {main_model.editor_model.name} with"
f" {main_model.editor_edit_format} edit format" f" {main_model.editor_edit_format} edit format"
) )
if main_model.editor_model.copy_paste_instead_of_api:
output += ", copy paste mode"
lines.append(output) lines.append(output)
if weak_model is not main_model: if weak_model is not main_model:
output = f"Weak model: {weak_model.name}" output = f"Weak model: {weak_model.name}"
if main_model.weak_model.copy_paste_instead_of_api:
output += ", copy paste mode"
lines.append(output) lines.append(output)
# Repo # Repo
@ -419,7 +428,7 @@ class Coder:
self.main_model.reasoning_tag if self.main_model.reasoning_tag else REASONING_TAG self.main_model.reasoning_tag if self.main_model.reasoning_tag else REASONING_TAG
) )
self.stream = stream and main_model.streaming self.stream = stream and main_model.streaming and not main_model.copy_paste_instead_of_api
if cache_prompts and self.main_model.cache_control: if cache_prompts and self.main_model.cache_control:
self.add_cache_headers = True self.add_cache_headers = True

View file

@ -820,7 +820,6 @@ def main(argv=None, input=None, output=None, force_git_root=None, return_coder=F
editor_model=args.editor_model, editor_model=args.editor_model,
editor_edit_format=args.editor_edit_format, editor_edit_format=args.editor_edit_format,
verbose=args.verbose, verbose=args.verbose,
copy_paste_no_api=args.copy_paste_no_api,
io=io, io=io,
) )
@ -949,9 +948,6 @@ def main(argv=None, input=None, output=None, force_git_root=None, return_coder=F
if args.cache_prompts and args.map_refresh == "auto": if args.cache_prompts and args.map_refresh == "auto":
args.map_refresh = "files" args.map_refresh = "files"
if args.copy_paste_no_api:
args.stream = False
if not main_model.streaming: if not main_model.streaming:
if args.stream: if args.stream:

View file

@ -306,7 +306,13 @@ model_info_manager = ModelInfoManager()
class Model(ModelSettings): class Model(ModelSettings):
def __init__(self, model, weak_model=None, editor_model=None, editor_edit_format=None, verbose=False, copy_paste_no_api=False, io=None): COPY_PASTE_PREFIX = "cp:"
def __init__(self, model, weak_model=None, editor_model=None, editor_edit_format=None, verbose=False, io=None):
self.io = io
self.copy_paste_instead_of_api = model.startswith(self.COPY_PASTE_PREFIX)
model = model.removeprefix(self.COPY_PASTE_PREFIX)
# Map any alias to its canonical name # Map any alias to its canonical name
model = MODEL_ALIASES.get(model, model) model = MODEL_ALIASES.get(model, model)
@ -317,9 +323,6 @@ class Model(ModelSettings):
self.weak_model = None self.weak_model = None
self.editor_model = None self.editor_model = None
self.io = io
self.copy_paste_no_api=copy_paste_no_api
# Find the extra settings # Find the extra settings
self.extra_model_settings = next( self.extra_model_settings = next(
(ms for ms in MODEL_SETTINGS if ms.name == "aider/extra_params"), None (ms for ms in MODEL_SETTINGS if ms.name == "aider/extra_params"), None
@ -337,7 +340,7 @@ class Model(ModelSettings):
# with minimum 1k and maximum 8k # with minimum 1k and maximum 8k
self.max_chat_history_tokens = min(max(max_input_tokens / 16, 1024), 8192) self.max_chat_history_tokens = min(max(max_input_tokens / 16, 1024), 8192)
self.configure_model_settings(model) self.configure_model_settings(model)
if weak_model is False: if weak_model is False:
self.weak_model_name = None self.weak_model_name = None
else: else:
@ -348,10 +351,6 @@ class Model(ModelSettings):
else: else:
self.get_editor_model(editor_model, editor_edit_format) self.get_editor_model(editor_model, editor_edit_format)
if self.copy_paste_no_api:
self.weak_model = self
self.editor_model = self
def get_model_info(self, model): def get_model_info(self, model):
return model_info_manager.get_model_info(model) return model_info_manager.get_model_info(model)
@ -385,7 +384,7 @@ class Model(ModelSettings):
# If no exact match, try generic settings # If no exact match, try generic settings
if not exact_match: if not exact_match:
self.apply_generic_model_settings(model) self.apply_generic_model_settings(model)
# Apply override settings last if they exist # Apply override settings last if they exist
if ( if (
self.extra_model_settings self.extra_model_settings
@ -562,6 +561,9 @@ class Model(ModelSettings):
# If weak_model_name is provided, override the model settings # If weak_model_name is provided, override the model settings
if provided_weak_model_name: if provided_weak_model_name:
self.weak_model_name = provided_weak_model_name self.weak_model_name = provided_weak_model_name
elif self.copy_paste_instead_of_api:
self.weak_model = self
return
if not self.weak_model_name: if not self.weak_model_name:
self.weak_model = self self.weak_model = self
@ -575,7 +577,7 @@ class Model(ModelSettings):
self.weak_model_name, self.weak_model_name,
weak_model=False, weak_model=False,
) )
return self.weak_model return
def commit_message_models(self): def commit_message_models(self):
return [self.weak_model, self] return [self.weak_model, self]
@ -584,6 +586,9 @@ class Model(ModelSettings):
# If editor_model_name is provided, override the model settings # If editor_model_name is provided, override the model settings
if provided_editor_model_name: if provided_editor_model_name:
self.editor_model_name = provided_editor_model_name self.editor_model_name = provided_editor_model_name
elif self.copy_paste_instead_of_api:
self.editor_model_name = self.name
if editor_edit_format: if editor_edit_format:
self.editor_edit_format = editor_edit_format self.editor_edit_format = editor_edit_format
@ -881,7 +886,7 @@ class Model(ModelSettings):
return self.name.startswith("ollama/") or self.name.startswith("ollama_chat/") return self.name.startswith("ollama/") or self.name.startswith("ollama_chat/")
def send_completion(self, messages, functions, stream, temperature=None): def send_completion(self, messages, functions, stream, temperature=None):
if self.copy_paste_no_api: if self.copy_paste_instead_of_api:
return self.copy_paste_completion(messages) return self.copy_paste_completion(messages)
if os.environ.get("AIDER_SANITY_CHECK_TURNS"): if os.environ.get("AIDER_SANITY_CHECK_TURNS"):
@ -939,7 +944,8 @@ class Model(ModelSettings):
"""✓ Request copied to clipboard """✓ Request copied to clipboard
Paste into LLM web UI Paste into LLM web UI
Copy response back to clipboard Copy response back to clipboard
Monitoring clipboard for changes..."""
Monitoring clipboard for changes (press Ctrl+C to cancel)..."""
) )
last_clipboard = pyperclip.paste() last_clipboard = pyperclip.paste()
@ -1108,7 +1114,8 @@ def sanity_check_models(io, main_model):
def sanity_check_model(io, model): def sanity_check_model(io, model):
show = False show = False
if model.copy_paste_no_api: # Skip sanity check if using copy paste mode instead of api
if model.copy_paste_instead_of_api:
return show return show
if model.missing_keys: if model.missing_keys: