mirror of
https://github.com/Aider-AI/aider.git
synced 2025-06-13 16:15:00 +00:00
unified diffs
This commit is contained in:
parent
3aa17c46dd
commit
7113a30271
18 changed files with 243 additions and 96 deletions
|
@ -2,6 +2,7 @@ from .base_coder import Coder
|
|||
from .editblock_coder import EditBlockCoder
|
||||
from .editblock_func_coder import EditBlockFunctionCoder
|
||||
from .single_wholefile_func_coder import SingleWholeFileFunctionCoder
|
||||
from .udiff_coder import UnifiedDiffCoder
|
||||
from .wholefile_coder import WholeFileCoder
|
||||
from .wholefile_func_coder import WholeFileFunctionCoder
|
||||
|
||||
|
@ -12,4 +13,5 @@ __all__ = [
|
|||
WholeFileFunctionCoder,
|
||||
EditBlockFunctionCoder,
|
||||
SingleWholeFileFunctionCoder,
|
||||
UnifiedDiffCoder,
|
||||
]
|
||||
|
|
|
@ -49,7 +49,9 @@ class Coder:
|
|||
functions = None
|
||||
total_cost = 0.0
|
||||
num_exhausted_context_windows = 0
|
||||
num_malformed_responses = 0
|
||||
last_keyboard_interrupt = None
|
||||
max_apply_update_errors = 3
|
||||
|
||||
@classmethod
|
||||
def create(
|
||||
|
@ -61,7 +63,7 @@ class Coder:
|
|||
skip_model_availabily_check=False,
|
||||
**kwargs,
|
||||
):
|
||||
from . import EditBlockCoder, WholeFileCoder
|
||||
from . import EditBlockCoder, UnifiedDiffCoder, WholeFileCoder
|
||||
|
||||
if not main_model:
|
||||
main_model = models.GPT4
|
||||
|
@ -83,6 +85,8 @@ class Coder:
|
|||
return EditBlockCoder(client, main_model, io, **kwargs)
|
||||
elif edit_format == "whole":
|
||||
return WholeFileCoder(client, main_model, io, **kwargs)
|
||||
elif edit_format == "udiff":
|
||||
return UnifiedDiffCoder(client, main_model, io, **kwargs)
|
||||
else:
|
||||
raise ValueError(f"Unknown edit format {edit_format}")
|
||||
|
||||
|
@ -296,7 +300,13 @@ class Coder:
|
|||
prompt += "\n"
|
||||
prompt += relative_fname
|
||||
prompt += f"\n{self.fence[0]}\n"
|
||||
|
||||
prompt += content
|
||||
|
||||
# lines = content.splitlines(keepends=True)
|
||||
# lines = [f"{i+1:03}:{line}" for i, line in enumerate(lines)]
|
||||
# prompt += "".join(lines)
|
||||
|
||||
prompt += f"{self.fence[1]}\n"
|
||||
|
||||
return prompt
|
||||
|
@ -346,7 +356,7 @@ class Coder:
|
|||
new_user_message = self.send_new_user_message(new_user_message)
|
||||
|
||||
if with_message:
|
||||
return
|
||||
return self.partial_response_content
|
||||
|
||||
except KeyboardInterrupt:
|
||||
self.keyboard_interrupt()
|
||||
|
@ -456,12 +466,12 @@ class Coder:
|
|||
# add the reminder anyway
|
||||
total_tokens = 0
|
||||
|
||||
messages += self.cur_messages
|
||||
|
||||
# Add the reminder prompt if we still have room to include it.
|
||||
if total_tokens < self.main_model.max_context_tokens:
|
||||
messages += reminder_message
|
||||
|
||||
messages += self.cur_messages
|
||||
|
||||
return messages
|
||||
|
||||
def send_new_user_message(self, inp):
|
||||
|
@ -850,19 +860,19 @@ class Coder:
|
|||
return set(edit[0] for edit in edits)
|
||||
|
||||
def apply_updates(self):
|
||||
max_apply_update_errors = 3
|
||||
|
||||
try:
|
||||
edited = self.update_files()
|
||||
except ValueError as err:
|
||||
self.num_malformed_responses += 1
|
||||
err = err.args[0]
|
||||
self.apply_update_errors += 1
|
||||
if self.apply_update_errors < max_apply_update_errors:
|
||||
if self.apply_update_errors < self.max_apply_update_errors:
|
||||
self.io.tool_error(f"Malformed response #{self.apply_update_errors}, retrying...")
|
||||
self.io.tool_error(str(err))
|
||||
return None, err
|
||||
else:
|
||||
self.io.tool_error(f"Malformed response #{self.apply_update_errors}, aborting.")
|
||||
self.io.tool_error(str(err))
|
||||
return False, None
|
||||
|
||||
except Exception as err:
|
||||
|
@ -870,11 +880,13 @@ class Coder:
|
|||
print()
|
||||
traceback.print_exc()
|
||||
self.apply_update_errors += 1
|
||||
if self.apply_update_errors < max_apply_update_errors:
|
||||
if self.apply_update_errors < self.max_apply_update_errors:
|
||||
self.io.tool_error(f"Update exception #{self.apply_update_errors}, retrying...")
|
||||
self.io.tool_error(str(err))
|
||||
return None, str(err)
|
||||
else:
|
||||
self.io.tool_error(f"Update exception #{self.apply_update_errors}, aborting")
|
||||
self.io.tool_error(str(err))
|
||||
return False, None
|
||||
|
||||
self.apply_update_errors = 0
|
||||
|
|
|
@ -148,7 +148,7 @@ def main(argv=None, input=None, output=None, force_git_root=None):
|
|||
core_group.add_argument(
|
||||
"--model",
|
||||
metavar="MODEL",
|
||||
default=models.GPT4.name,
|
||||
default=models.GPT4_0613.name,
|
||||
help=f"Specify the model to use for the main chat (default: {models.GPT4.name})",
|
||||
)
|
||||
core_group.add_argument(
|
||||
|
@ -157,6 +157,14 @@ def main(argv=None, input=None, output=None, force_git_root=None):
|
|||
default=False,
|
||||
help="Override to skip model availability check (default: False)",
|
||||
)
|
||||
default_4_turbo_model = models.GPT4_1106_PREVIEW
|
||||
core_group.add_argument(
|
||||
"--4-turbo",
|
||||
action="store_const",
|
||||
dest="model",
|
||||
const=default_4_turbo_model.name,
|
||||
help=f"Use {default_4_turbo_model.name} model for the main chat (gpt-4 is better)",
|
||||
)
|
||||
default_3_model = models.GPT35_1106
|
||||
core_group.add_argument(
|
||||
"-3",
|
||||
|
@ -380,7 +388,10 @@ def main(argv=None, input=None, output=None, force_git_root=None):
|
|||
"--message-file",
|
||||
"-f",
|
||||
metavar="MESSAGE_FILE",
|
||||
help="Specify a file containing the message to send GPT, process reply, then exit (disables chat mode)",
|
||||
help=(
|
||||
"Specify a file containing the message to send GPT, process reply, then exit (disables"
|
||||
" chat mode)"
|
||||
),
|
||||
)
|
||||
other_group.add_argument(
|
||||
"--encoding",
|
||||
|
|
|
@ -3,6 +3,8 @@ from .openai import OpenAIModel
|
|||
from .openrouter import OpenRouterModel
|
||||
|
||||
GPT4 = Model.create("gpt-4")
|
||||
GPT4_0613 = Model.create("gpt-4-0613")
|
||||
GPT4_1106_PREVIEW = Model.create("gpt-4-1106-preview")
|
||||
GPT35 = Model.create("gpt-3.5-turbo")
|
||||
GPT35_1106 = Model.create("gpt-3.5-turbo-1106")
|
||||
GPT35_16k = Model.create("gpt-3.5-turbo-16k")
|
||||
|
|
|
@ -33,7 +33,11 @@ class OpenAIModel(Model):
|
|||
self.tokenizer = tiktoken.encoding_for_model(name)
|
||||
|
||||
if self.is_gpt4():
|
||||
self.edit_format = "diff"
|
||||
if name == "gpt-4-1106-preview":
|
||||
self.edit_format = "udiff"
|
||||
else:
|
||||
self.edit_format = "diff"
|
||||
|
||||
self.use_repo_map = True
|
||||
self.send_undo_reply = True
|
||||
|
||||
|
|
|
@ -1,6 +1,68 @@
|
|||
import os
|
||||
import tempfile
|
||||
from pathlib import Path
|
||||
|
||||
from .dump import dump # noqa: F401
|
||||
import git
|
||||
|
||||
from aider.dump import dump # noqa: F401
|
||||
|
||||
|
||||
class IgnorantTemporaryDirectory:
|
||||
def __init__(self):
|
||||
self.temp_dir = tempfile.TemporaryDirectory()
|
||||
|
||||
def __enter__(self):
|
||||
return self.temp_dir.__enter__()
|
||||
|
||||
def __exit__(self, exc_type, exc_val, exc_tb):
|
||||
try:
|
||||
self.temp_dir.__exit__(exc_type, exc_val, exc_tb)
|
||||
except (OSError, PermissionError):
|
||||
pass # Ignore errors (Windows)
|
||||
|
||||
|
||||
class ChdirTemporaryDirectory(IgnorantTemporaryDirectory):
|
||||
def __init__(self):
|
||||
try:
|
||||
self.cwd = os.getcwd()
|
||||
except FileNotFoundError:
|
||||
self.cwd = None
|
||||
|
||||
super().__init__()
|
||||
|
||||
def __enter__(self):
|
||||
res = super().__enter__()
|
||||
os.chdir(self.temp_dir.name)
|
||||
return res
|
||||
|
||||
def __exit__(self, exc_type, exc_val, exc_tb):
|
||||
if self.cwd:
|
||||
try:
|
||||
os.chdir(self.cwd)
|
||||
except FileNotFoundError:
|
||||
pass
|
||||
super().__exit__(exc_type, exc_val, exc_tb)
|
||||
|
||||
|
||||
class GitTemporaryDirectory(ChdirTemporaryDirectory):
|
||||
def __enter__(self):
|
||||
dname = super().__enter__()
|
||||
self.repo = make_repo(dname)
|
||||
return dname
|
||||
|
||||
def __exit__(self, exc_type, exc_val, exc_tb):
|
||||
del self.repo
|
||||
super().__exit__(exc_type, exc_val, exc_tb)
|
||||
|
||||
|
||||
def make_repo(path=None):
|
||||
if not path:
|
||||
path = "."
|
||||
repo = git.Repo.init(path)
|
||||
repo.config_writer().set_value("user", "name", "Test User").release()
|
||||
repo.config_writer().set_value("user", "email", "testuser@example.com").release()
|
||||
|
||||
return repo
|
||||
|
||||
|
||||
def safe_abs_path(res):
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue