mirror of
https://github.com/Aider-AI/aider.git
synced 2025-05-28 08:14:59 +00:00
wip
This commit is contained in:
parent
e24d03060d
commit
582143d563
5 changed files with 193 additions and 2 deletions
|
@ -1,6 +1,7 @@
|
||||||
from .base_coder import Coder
|
from .base_coder import Coder
|
||||||
from .editblock_coder import EditBlockCoder
|
from .editblock_coder import EditBlockCoder
|
||||||
|
from .editblock_func_coder import EditBlockFunctionCoder
|
||||||
from .wholefile_coder import WholeFileCoder
|
from .wholefile_coder import WholeFileCoder
|
||||||
from .wholefile_func_coder import WholeFileFunctionCoder
|
from .wholefile_func_coder import WholeFileFunctionCoder
|
||||||
|
|
||||||
__all__ = [Coder, EditBlockCoder, WholeFileCoder, WholeFileFunctionCoder]
|
__all__ = [Coder, EditBlockCoder, WholeFileCoder, WholeFileFunctionCoder, EditBlockFunctionCoder]
|
||||||
|
|
|
@ -55,7 +55,12 @@ class Coder:
|
||||||
openai_api_base="https://api.openai.com/v1",
|
openai_api_base="https://api.openai.com/v1",
|
||||||
**kwargs,
|
**kwargs,
|
||||||
):
|
):
|
||||||
from . import EditBlockCoder, WholeFileCoder, WholeFileFunctionCoder
|
from . import (
|
||||||
|
EditBlockCoder,
|
||||||
|
EditBlockFunctionCoder,
|
||||||
|
WholeFileCoder,
|
||||||
|
WholeFileFunctionCoder,
|
||||||
|
)
|
||||||
|
|
||||||
openai.api_key = openai_api_key
|
openai.api_key = openai_api_key
|
||||||
openai.api_base = openai_api_base
|
openai.api_base = openai_api_base
|
||||||
|
@ -81,6 +86,8 @@ class Coder:
|
||||||
return WholeFileCoder(main_model, io, **kwargs)
|
return WholeFileCoder(main_model, io, **kwargs)
|
||||||
elif edit_format == "whole-func":
|
elif edit_format == "whole-func":
|
||||||
return WholeFileFunctionCoder(main_model, io, **kwargs)
|
return WholeFileFunctionCoder(main_model, io, **kwargs)
|
||||||
|
elif edit_format == "diff-func":
|
||||||
|
return EditBlockFunctionCoder(main_model, io, **kwargs)
|
||||||
else:
|
else:
|
||||||
raise ValueError(f"Unknown edit format {edit_format}")
|
raise ValueError(f"Unknown edit format {edit_format}")
|
||||||
|
|
||||||
|
@ -559,6 +566,8 @@ class Coder:
|
||||||
if functions is not None:
|
if functions is not None:
|
||||||
kwargs["functions"] = self.functions
|
kwargs["functions"] = self.functions
|
||||||
|
|
||||||
|
dump(kwargs)
|
||||||
|
|
||||||
# Generate SHA1 hash of kwargs and append it to chat_completion_call_hashes
|
# Generate SHA1 hash of kwargs and append it to chat_completion_call_hashes
|
||||||
hash_object = hashlib.sha1(json.dumps(kwargs, sort_keys=True).encode())
|
hash_object = hashlib.sha1(json.dumps(kwargs, sort_keys=True).encode())
|
||||||
self.chat_completion_call_hashes.append(hash_object.hexdigest())
|
self.chat_completion_call_hashes.append(hash_object.hexdigest())
|
||||||
|
|
153
aider/coders/editblock_func_coder.py
Normal file
153
aider/coders/editblock_func_coder.py
Normal file
|
@ -0,0 +1,153 @@
|
||||||
|
import os
|
||||||
|
|
||||||
|
from aider import diffs
|
||||||
|
|
||||||
|
from ..dump import dump # noqa: F401
|
||||||
|
from .base_coder import Coder
|
||||||
|
from .editblock_func_prompts import EditBlockFunctionPrompts
|
||||||
|
|
||||||
|
|
||||||
|
class EditBlockFunctionCoder(Coder):
|
||||||
|
functions = [
|
||||||
|
dict(
|
||||||
|
name="replace_lines",
|
||||||
|
description="create or update one or more files",
|
||||||
|
parameters=dict(
|
||||||
|
type="object",
|
||||||
|
required=["explanation", "edits"],
|
||||||
|
properties=dict(
|
||||||
|
explanation=dict(
|
||||||
|
type="string",
|
||||||
|
description=(
|
||||||
|
"Step by step plan for the changes to be made to the code (future"
|
||||||
|
" tense, markdown format)"
|
||||||
|
),
|
||||||
|
),
|
||||||
|
edits=dict(
|
||||||
|
type="array",
|
||||||
|
items=dict(
|
||||||
|
parameters=dict(
|
||||||
|
type="object",
|
||||||
|
required=["path", "original_lines", "updated_lines"],
|
||||||
|
properties=dict(
|
||||||
|
file_path=dict(
|
||||||
|
type="string",
|
||||||
|
description="Path of file to edit",
|
||||||
|
),
|
||||||
|
original_lines=dict(
|
||||||
|
type="string",
|
||||||
|
description=(
|
||||||
|
(
|
||||||
|
"Portion of the original file, including all"
|
||||||
|
" whitespace, newlines, without skipping any lines"
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
updated_lines=dict(
|
||||||
|
type="string",
|
||||||
|
description=(
|
||||||
|
"New content to replace the `original_lines` with"
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
]
|
||||||
|
|
||||||
|
def __init__(self, *args, **kwargs):
|
||||||
|
self.gpt_prompts = EditBlockFunctionPrompts()
|
||||||
|
super().__init__(*args, **kwargs)
|
||||||
|
|
||||||
|
def update_cur_messages(self, content, edited):
|
||||||
|
if edited:
|
||||||
|
self.cur_messages += [
|
||||||
|
dict(role="assistant", content=self.gpt_prompts.redacted_edit_message)
|
||||||
|
]
|
||||||
|
else:
|
||||||
|
self.cur_messages += [dict(role="assistant", content=content)]
|
||||||
|
|
||||||
|
def get_context_from_history(self, history):
|
||||||
|
context = ""
|
||||||
|
if history:
|
||||||
|
context += "# Context:\n"
|
||||||
|
for msg in history:
|
||||||
|
if msg["role"] == "user":
|
||||||
|
context += msg["role"].upper() + ": " + msg["content"] + "\n"
|
||||||
|
return context
|
||||||
|
|
||||||
|
def render_incremental_response(self, final=False):
|
||||||
|
if self.partial_response_content:
|
||||||
|
return self.partial_response_content
|
||||||
|
|
||||||
|
args = self.parse_partial_args()
|
||||||
|
|
||||||
|
if not args:
|
||||||
|
return
|
||||||
|
|
||||||
|
explanation = args.get("explanation")
|
||||||
|
files = args.get("files", [])
|
||||||
|
|
||||||
|
res = ""
|
||||||
|
if explanation:
|
||||||
|
res += f"{explanation}\n\n"
|
||||||
|
|
||||||
|
for i, file_upd in enumerate(files):
|
||||||
|
path = file_upd.get("path")
|
||||||
|
if not path:
|
||||||
|
continue
|
||||||
|
content = file_upd.get("content")
|
||||||
|
if not content:
|
||||||
|
continue
|
||||||
|
|
||||||
|
this_final = (i < len(files) - 1) or final
|
||||||
|
res += self.live_diffs(path, content, this_final)
|
||||||
|
|
||||||
|
return res
|
||||||
|
|
||||||
|
def live_diffs(self, fname, content, final):
|
||||||
|
lines = content.splitlines(keepends=True)
|
||||||
|
|
||||||
|
# ending an existing block
|
||||||
|
full_path = os.path.abspath(os.path.join(self.root, fname))
|
||||||
|
|
||||||
|
with open(full_path, "r") as f:
|
||||||
|
orig_lines = f.readlines()
|
||||||
|
|
||||||
|
show_diff = diffs.diff_partial_update(
|
||||||
|
orig_lines,
|
||||||
|
lines,
|
||||||
|
final,
|
||||||
|
fname=fname,
|
||||||
|
).splitlines()
|
||||||
|
|
||||||
|
return "\n".join(show_diff)
|
||||||
|
|
||||||
|
def update_files(self):
|
||||||
|
name = self.partial_response_function_call.get("name")
|
||||||
|
if name and name != "replace_lines":
|
||||||
|
raise ValueError(f'Unknown function_call name="{name}", use name="write_file"')
|
||||||
|
|
||||||
|
args = self.parse_partial_args()
|
||||||
|
if not args:
|
||||||
|
return
|
||||||
|
|
||||||
|
files = args.get("files", [])
|
||||||
|
|
||||||
|
edited = set()
|
||||||
|
for file_upd in files:
|
||||||
|
path = file_upd.get("path")
|
||||||
|
if not path:
|
||||||
|
raise ValueError(f"Missing path parameter: {file_upd}")
|
||||||
|
|
||||||
|
content = file_upd.get("content")
|
||||||
|
if not content:
|
||||||
|
raise ValueError(f"Missing content parameter: {file_upd}")
|
||||||
|
|
||||||
|
if self.allowed_to_edit(path, content):
|
||||||
|
edited.add(path)
|
||||||
|
|
||||||
|
return edited
|
27
aider/coders/editblock_func_prompts.py
Normal file
27
aider/coders/editblock_func_prompts.py
Normal file
|
@ -0,0 +1,27 @@
|
||||||
|
# flake8: noqa: E501
|
||||||
|
|
||||||
|
from .base_prompts import CoderPrompts
|
||||||
|
|
||||||
|
|
||||||
|
class EditBlockFunctionPrompts(CoderPrompts):
|
||||||
|
main_system = """Act as an expert software developer.
|
||||||
|
Take requests for changes to the supplied code.
|
||||||
|
If the request is ambiguous, ask questions.
|
||||||
|
|
||||||
|
Once you understand the request you MUST use the `replace_lines` function to edit the files to make the needed changes.
|
||||||
|
"""
|
||||||
|
|
||||||
|
system_reminder = """
|
||||||
|
ONLY return code using the `replace_lines` function.
|
||||||
|
NEVER return code outside the `replace_lines` function.
|
||||||
|
"""
|
||||||
|
|
||||||
|
files_content_prefix = "Here is the current content of the files:\n"
|
||||||
|
files_no_full_files = "I am not sharing any files yet."
|
||||||
|
|
||||||
|
redacted_edit_message = "No changes are needed."
|
||||||
|
|
||||||
|
repo_content_prefix = (
|
||||||
|
"Below here are summaries of other files! Do not propose changes to these *read-only*"
|
||||||
|
" files without asking me first.\n"
|
||||||
|
)
|
|
@ -21,4 +21,5 @@ NEVER return code outside the `write_file` function.
|
||||||
|
|
||||||
redacted_edit_message = "No changes are needed."
|
redacted_edit_message = "No changes are needed."
|
||||||
|
|
||||||
|
# TODO: should this be present for using this with gpt-4?
|
||||||
repo_content_prefix = None
|
repo_content_prefix = None
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue