paul-gauthier / aider

aider is AI pair programming in your terminal
https://aider.chat/
Apache License 2.0
18.02k stars 1.69k forks source link

Undo prompt command #1018

Open Aeraxys opened 1 month ago

Aeraxys commented 1 month ago

Issue

Hi,

I'd like for there to exist an undo prompt command, in addition to the undo command that currently exists. I only use aider in no-auto-commit mode, as I like to view the changes in my editor and control the commits myself. In this workflow, the undo command currently in aider is of no use.

I often find myself in a situation where I write a prompt that doesn't do what I want, and I therefore want to revert it. This command would do exactly that, allowing me to write a different prompt, or maybe remove more prompts.

I can imagine it working like this:

command: /undo-prompt result: Undoes all edits done by the last prompt, and resets the chat history to what it was before the last prompt was issued. Can be issued multiple times to gradually remove prompts until there are none left.

I hope this gets considered added!

Thanks

Version and model info

No response

sholub89 commented 1 month ago

I would love to see this feature as well. I believe very many developers use it with --no-auto-commit because we want to inspect the changes before committing them. Undoing the last change would be a super helpful feature if possible.

Aeraxys commented 1 month ago

Yeah, imo that is the only way it makes sense to use this tool.

If it was up to me, this would be the default workflow and the command I described would be the default /undo command, as It's what I think most people would expect an undo command to do in a tool like this.

eaubin commented 1 month ago

FWIW, I started doing something similar to modify the chat history, my wip code

Add to commands.py

    def cmd_pop(self, args):
        args = args.split()
        msgs = self.coder.cur_messages
        if len(args)==0:
            msgs.pop()
            msgs.pop()
            return
        try:
            to_pop = int(args[0])
            self.coder.cur_messages = self.coder.cur_messages[0:-to_pop]
        except ValueError:
            self.io.tool_output("Could not parse {args[0]}")
            return

    def cmd_history(self, args):
        "Print the message history"

        self.coder.choose_fence()

        main_sys = self.coder.fmt_system_prompt(self.coder.gpt_prompts.main_system)
        main_sys += "\n" + self.coder.fmt_system_prompt(self.coder.gpt_prompts.system_reminder)

        msgs = [
            dict(role="system", content=main_sys),
            dict(
                role="system",
                content=self.coder.fmt_system_prompt(self.coder.gpt_prompts.system_reminder),
            ),
        ]
        self.io.tool_output("SYSTEM MESSAGES")
        for msg in msgs:
            self.io.tool_output(f"""{msg["role"]}: {msg["content"]}""")

        if self.coder.done_messages:
            self.io.tool_output("""DONE MESSAGES""")
            for i, msg in enumerate(self.coder.done_messages):
                tokens = self.coder.main_model.token_count([msg])
                self.io.tool_output(f"""{i} {tokens=:} {msg["role"]}: {msg["content"]}""")

        if self.coder.cur_messages:
            self.io.tool_output("""CUR MESSAGES""")
            for i, msg in enumerate(self.coder.cur_messages):
                tokens = self.coder.main_model.token_count([msg])
                self.io.tool_output(f"""{i} {tokens=:} {msg["role"]}: {msg["content"]}""")

    def cmd_repo_map(self, args):
        other_files = set(self.coder.get_all_abs_files()) - set(self.coder.abs_fnames)
        if self.coder.repo_map:
            repo_content = self.coder.repo_map.get_repo_map(self.coder.abs_fnames, other_files)
            self.io.tool_output(repo_content)
Qubhis commented 1 month ago

I would appreciate such feature as well. I can think of two ways how to do it:

  1. To just literally reverse everything from the last SEARCH/REPLACE block. It would search the REPLACE block and replaced it with SEARCH. However, this would become problematic when you've already adjusted the code after the prompt as the original REPLACE block could be different and it would failed to match.
  2. IMO easier and better approach: a) Introduce a new mode which would make GPT to produce diff blocks as in the existing chat mode, but aider wouldn't change the files. b) a new command /apply-last which would apply the SEARCH/REPLACE from the last LLMs output. I would throw an error message if no diff blocks is found in the last response. This would still respected the env for no-auto-commit.