From 9088d139b2b64384cf7821a1435861a281a1099c Mon Sep 17 00:00:00 2001 From: Paul Gauthier Date: Sun, 4 Jun 2023 11:36:50 -0700 Subject: [PATCH] refactor prompts --- aider/coder.py | 25 ++++++++++----- aider/prompts.py | 83 +++++++++++++++++++++++++++++++++++++----------- aider/repomap.py | 19 +++++++---- 3 files changed, 93 insertions(+), 34 deletions(-) diff --git a/aider/coder.py b/aider/coder.py index 57d364c77..141844aa6 100755 --- a/aider/coder.py +++ b/aider/coder.py @@ -83,6 +83,9 @@ class Coder: self.io.tool_error( f"Aider doesn't work well with {main_model}, use gpt-4 for best results." ) + self.gpt_prompts = prompts.GPT35() + else: + self.gpt_prompts = prompts.GPT4() self.set_repo(fnames) @@ -94,7 +97,13 @@ class Coder: self.find_common_root() rm_io = io if self.verbose else None - self.repo_map = RepoMap(map_tokens, self.root, self.main_model, rm_io) + self.repo_map = RepoMap( + map_tokens, + self.root, + self.main_model, + rm_io, + self.gpt_prompts.repo_content_prefix, + ) if self.repo_map.has_ctags: capabilities_msg += "using ctags." @@ -193,10 +202,10 @@ class Coder: def get_files_messages(self): all_content = "" if self.abs_fnames: - files_content = prompts.files_content_prefix + files_content = self.gpt_prompts.files_content_prefix files_content += self.get_files_content() else: - files_content = prompts.files_no_full_files + files_content = self.gpt_prompts.files_no_full_files all_content += files_content @@ -213,7 +222,7 @@ class Coder: ] if self.abs_fnames: files_messages += [ - dict(role="system", content=prompts.system_reminder), + dict(role="system", content=self.gpt_prompts.system_reminder), ] return files_messages @@ -269,7 +278,7 @@ class Coder: # files changed, move cur messages back behind the files messages self.done_messages += self.cur_messages self.done_messages += [ - dict(role="user", content=prompts.files_content_local_edits), + dict(role="user", content=self.gpt_prompts.files_content_local_edits), dict(role="assistant", content="Ok."), ] self.cur_messages = [] @@ -293,7 +302,7 @@ class Coder: dict(role="user", content=inp), ] - main_sys = prompts.main_system + "\n" + prompts.system_reminder + main_sys = self.gpt_prompts.main_system + "\n" + self.gpt_prompts.system_reminder messages = [ dict(role="system", content=main_sys), ] @@ -334,14 +343,14 @@ class Coder: commit_hash, commit_message = res self.last_aider_commit_hash = commit_hash - saved_message = prompts.files_content_gpt_edits.format( + saved_message = self.gpt_prompts.files_content_gpt_edits.format( hash=commit_hash, message=commit_message, ) else: # TODO: if not self.repo then the files_content_gpt_no_edits isn't appropriate self.io.tool_error("Warning: no changes found in tracked files.") - saved_message = prompts.files_content_gpt_no_edits + saved_message = self.gpt_prompts.files_content_gpt_no_edits self.done_messages += self.cur_messages self.done_messages += [ diff --git a/aider/prompts.py b/aider/prompts.py index b240e1435..b04f05d09 100644 --- a/aider/prompts.py +++ b/aider/prompts.py @@ -1,7 +1,68 @@ # flake8: noqa: E501 # MAIN -main_system = """Act as an expert software developer. + +class GPT4: + main_system = """Act as an expert software developer. +Be concise! + +Take requests for changes to the supplied code. +If the request is ambiguous, ask questions. + +Once you understand the request you MUST: +1. List the files you need to modify. *NEVER* suggest changes to *read-only* files. You *MUST* ask the user to make them *read-write* using the file's full path name. End your reply and wait for their approval. +2. Think step-by-step and explain the needed changes. +3. Describe each change with an *edit block* per the example below. +""" + + system_reminder = """You MUST format EVERY code change with an *edit block* like this: + +```python +some/dir/example.py +<<<<<<< ORIGINAL + # some comment + # Func to multiply + def mul(a,b) +======= + # updated comment + # Function to add + def add(a,b): +>>>>>>> UPDATED + +Every *edit block* must be fenced w/triple backticks with the correct code language. +Every *edit block* must start with the full path! *NEVER* propose edit blocks for *read-only* files. +The ORIGINAL section must be an *exact* set of lines from the file: +- NEVER SKIP LINES! +- Include all original leading spaces and indentation! + +Edits to different parts of a file each need their own *edit block*. + +If you want to put code in a new file, use an edit block with: +- A new file path, including dir name if needed +- An empty ORIGINAL section +- The new file's contents in the UPDATED section + +If a request requires many changes, stop often to ask the user for feedback. +""" + + files_content_gpt_edits = "I committed the changes with git hash {hash} & commit msg: {message}" + + files_content_gpt_no_edits = "I didn't see any properly formatted edits in your reply?!" + + files_content_local_edits = "I edited the files myself." + + files_content_prefix = "These are the *read-write* files:\n" + + files_no_full_files = "I am not sharing any *read-write* files yet." + + repo_content_prefix = ( + "Below here are summaries of other files! Do not propose changes to these *read-only*" + " files without asking me first.\n" + ) + + +class GPT35(GPT4): + main_system = """Act as an expert software developer. Be concise! Take requests for changes to the supplied code. @@ -12,7 +73,7 @@ Once you understand the request you MUST: 2. Output a new copy of each file which needs code changes. """ -system_reminder = """When you reply with new copies of files, use the format below. + system_reminder = """When you reply with new copies of files, use the format below. exact/path/to/filename.js ```javascript @@ -21,23 +82,7 @@ exact/path/to/filename.js ``` """ - -# FILES - -files_content_gpt_edits = "I committed the changes with git hash {hash} & commit msg: {message}" - -files_content_gpt_no_edits = "I didn't see any properly formatted edits in your reply?!" - -files_content_local_edits = "I edited the files myself." - -files_content_prefix = "Here is the current content of the files:\n" - -files_no_full_files = "I am not sharing any files yet." - -repo_content_prefix = ( - "Below here are summaries of other files! Do not propose changes to these *read-only*" - " files without asking me first.\n" -) + files_content_prefix = "Here is the current content of the files:\n" # COMMIT diff --git a/aider/repomap.py b/aider/repomap.py index d04174c73..9577c4e89 100644 --- a/aider/repomap.py +++ b/aider/repomap.py @@ -14,8 +14,6 @@ from pygments.lexers import guess_lexer_for_filename from pygments.token import Token from pygments.util import ClassNotFound -from aider import prompts - from .dump import dump # noqa: F402 @@ -61,7 +59,9 @@ class RepoMap: IDENT_CACHE_DIR = ".aider.ident.cache" TAGS_CACHE_DIR = ".aider.tags.cache" - def __init__(self, map_tokens=1024, root=None, main_model="gpt-4", io=None): + def __init__( + self, map_tokens=1024, root=None, main_model="gpt-4", io=None, repo_content_prefix=None + ): self.io = io if not root: @@ -78,6 +78,7 @@ class RepoMap: self.has_ctags = False self.tokenizer = tiktoken.encoding_for_model(main_model) + self.repo_content_prefix = repo_content_prefix def get_repo_map(self, chat_files, other_files): res = self.choose_files_listing(chat_files, other_files) @@ -91,10 +92,14 @@ class RepoMap: else: other = "" - repo_content = prompts.repo_content_prefix.format( - other=other, - ctags_msg=ctags_msg, - ) + if self.repo_content_prefix: + repo_content = self.repo_content_prefix.format( + other=other, + ctags_msg=ctags_msg, + ) + else: + repo_content = "" + repo_content += files_listing return repo_content