Skip to content

Commit

Permalink
Diff based file editing for all modes
Browse files Browse the repository at this point in the history
  • Loading branch information
Aman Rusia committed Nov 21, 2024
1 parent 2291895 commit 69f4e61
Show file tree
Hide file tree
Showing 10 changed files with 323 additions and 160 deletions.
124 changes: 94 additions & 30 deletions gpt_action_json_schema.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,20 +6,20 @@
},
"servers": [
{
"url": "https://abe7-106-213-82-238.ngrok-free.app"
"url": "https://7d75-103-212-152-58.ngrok-free.app"
}
],
"paths": {
"/v1/write_file": {
"/v1/create_file": {
"post": {
"x-openai-isConsequential": false,
"summary": "Write File",
"operationId": "write_file_v1_write_file_post",
"summary": "Create File",
"operationId": "create_file_v1_create_file_post",
"requestBody": {
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/WritefileWithUUID"
"$ref": "#/components/schemas/CreateFileNewWithUUID"
}
}
},
Expand All @@ -32,7 +32,47 @@
"application/json": {
"schema": {
"type": "string",
"title": "Response Write File V1 Write File Post"
"title": "Response Create File V1 Create File Post"
}
}
}
},
"422": {
"description": "Validation Error",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/HTTPValidationError"
}
}
}
}
}
}
},
"/v1/full_file_edit": {
"post": {
"x-openai-isConsequential": false,
"summary": "File Edit Find Replace",
"operationId": "file_edit_find_replace_v1_full_file_edit_post",
"requestBody": {
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/FullFileEditWithUUID"
}
}
},
"required": true
},
"responses": {
"200": {
"description": "Successful Response",
"content": {
"application/json": {
"schema": {
"type": "string",
"title": "Response File Edit Find Replace V1 Full File Edit Post"
}
}
}
Expand Down Expand Up @@ -255,6 +295,54 @@
],
"title": "CommandWithUUID"
},
"CreateFileNewWithUUID": {
"properties": {
"file_path": {
"type": "string",
"title": "File Path"
},
"file_content": {
"type": "string",
"title": "File Content"
},
"user_id": {
"type": "string",
"format": "uuid",
"title": "User Id"
}
},
"type": "object",
"required": [
"file_path",
"file_content",
"user_id"
],
"title": "CreateFileNewWithUUID"
},
"FullFileEditWithUUID": {
"properties": {
"file_path": {
"type": "string",
"title": "File Path"
},
"file_edit_using_searh_replace_blocks": {
"type": "string",
"title": "File Edit Using Searh Replace Blocks"
},
"user_id": {
"type": "string",
"format": "uuid",
"title": "User Id"
}
},
"type": "object",
"required": [
"file_path",
"file_edit_using_searh_replace_blocks",
"user_id"
],
"title": "FullFileEditWithUUID"
},
"HTTPValidationError": {
"properties": {
"detail": {
Expand Down Expand Up @@ -323,30 +411,6 @@
"type"
],
"title": "ValidationError"
},
"WritefileWithUUID": {
"properties": {
"file_path": {
"type": "string",
"title": "File Path"
},
"file_content": {
"type": "string",
"title": "File Content"
},
"user_id": {
"type": "string",
"format": "uuid",
"title": "User Id"
}
},
"type": "object",
"required": [
"file_path",
"file_content",
"user_id"
],
"title": "WritefileWithUUID"
}
}
}
Expand Down
53 changes: 50 additions & 3 deletions gpt_instructions.txt
Original file line number Diff line number Diff line change
Expand Up @@ -15,12 +15,12 @@ Instructions for `BashCommand`:
- Status of the command and the current working directory will always be returned at the end.
- Optionally `exit shell has restarted` is the output, in which case environment resets, you can run fresh commands.
- The first line might be `(...truncated)` if the output is too long.
- Always run `pwd` if you get any file or directory not found error to make sure you're not lost.

Instructions for `Write File`
- Write content to a file. Provide file path and content. Use this instead of BashCommand for writing files.
Instructions for `Create File New`
- Write content to a new file. Provide file path and content. Use this instead of BashCommand for writing new files.
- This doesn't create any directories, please create directories using `mkdir -p` BashCommand.
- Provide absolute file path only.
- For editing existing files, use FullFileEdit.

Instructions for `BashInteraction`
- Interact with running program using this tool
Expand All @@ -31,7 +31,54 @@ Instructions for `BashInteraction`
Instructions for `ResetShell`
- Resets the shell. Use only if all interrupts and prompt reset attempts have failed repeatedly.

Instructions for `FullFileEdit`:
- Use absolute file path only.
- Use SEARCH/REPLACE blocks to edit the file.
Only edit the files using the following SEARCH/REPLACE blocks.
```
<<<<<<< SEARCH
=======
def hello():
"print a greeting"

print("hello")
>>>>>>> REPLACE

<<<<<<< SEARCH
def hello():
"print a greeting"

print("hello")
=======
from hello import hello
>>>>>>> REPLACE
```

# *SEARCH/REPLACE block* Rules:

Every *SEARCH/REPLACE block* must use this format:
1. The start of search block: <<<<<<< SEARCH
2. A contiguous chunk of lines to search for in the existing source code
3. The dividing line: =======
4. The lines to replace into the source code
5. The end of the replace block: >>>>>>> REPLACE

Use the *FULL* file path, as shown to you by the user.

Every *SEARCH* section must *EXACTLY MATCH* the existing file content, character for character, including all comments, docstrings, etc.
If the file contains code or other data wrapped/escaped in json/xml/quotes or other containers, you need to propose edits to the literal contents of the file, including the container markup.

*SEARCH/REPLACE* blocks will *only* replace the first match occurrence.
Including multiple unique *SEARCH/REPLACE* blocks if needed.
Include enough lines in each SEARCH section to uniquely match each set of lines that need to change.

Keep *SEARCH/REPLACE* blocks concise.
Break large *SEARCH/REPLACE* blocks into a series of smaller blocks that each change a small portion of the file.
Include just the changing lines, and a few surrounding lines if needed for uniqueness.
Do not include long runs of unchanging lines in *SEARCH/REPLACE* blocks.

---
Always run `pwd` if you get any file or directory not found error to make sure you're not lost, or to get absolute cwd.

Always critically think and debate with yourself to solve the problem. Understand the context and the code by reading as much resources as possible before writing a single piece of code.

Expand Down
2 changes: 1 addition & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
[project]
authors = [{ name = "Aman Rusia", email = "[email protected]" }]
name = "wcgw"
version = "1.0.3"
version = "1.1.0"
description = "What could go wrong giving full shell access to chatgpt?"
readme = "README.md"
requires-python = ">=3.10, <3.13"
Expand Down
20 changes: 10 additions & 10 deletions src/wcgw/client/anthropic_client.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
BashInteraction,
CreateFileNew,
FileEditFindReplace,
FullFileEdit,
ReadImage,
Writefile,
ResetShell,
Expand Down Expand Up @@ -143,8 +144,6 @@ def loop(
history = json.load(f)
if len(history) <= 2:
raise ValueError("Invalid history file")
if history[1]["role"] != "user":
raise ValueError("Invalid history file, second message should be user")
first_message = ""
waiting_for_assistant = history[-1]["role"] != "assistant"

Expand Down Expand Up @@ -185,7 +184,7 @@ def loop(
- Write content to a new file. Provide file path and content. Use this instead of BashCommand for writing new files.
- This doesn't create any directories, please create directories using `mkdir -p` BashCommand.
- Provide absolute file path only.
- For editing existing files, use FileEditFindReplace.
- For editing existing files, use FullFileEdit.
""",
),
ToolParam(
Expand All @@ -199,12 +198,11 @@ def loop(
description="Resets the shell. Use only if all interrupts and prompt reset attempts have failed repeatedly.",
),
ToolParam(
input_schema=FileEditFindReplace.model_json_schema(),
name="FileEditFindReplace",
input_schema=FullFileEdit.model_json_schema(),
name="FullFileEdit",
description="""
- Find and replace multiple lines in a file.
- Use absolute file path only.
- Replaces complete lines.
- Use SEARCH/REPLACE blocks to edit the file.
""",
),
]
Expand All @@ -225,9 +223,10 @@ def loop(
- Machine: {uname_machine}
"""

if not history:
history = [{"role": "assistant", "content": system}]
else:
with open(os.path.join(os.path.dirname(__file__), "diff-instructions.txt")) as f:
system += f.read()

if history:
if (
(last_msg := history[-1])["role"] == "user"
and isinstance((content := last_msg["content"]), dict)
Expand Down Expand Up @@ -275,6 +274,7 @@ def loop(
messages=history,
tools=tools,
max_tokens=8096,
system=system,
)

system_console.print(
Expand Down
44 changes: 44 additions & 0 deletions src/wcgw/client/diff-instructions.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@

Instructions for
Only edit the files using the following SEARCH/REPLACE blocks.
```
<<<<<<< SEARCH
=======
def hello():
"print a greeting"

print("hello")
>>>>>>> REPLACE

<<<<<<< SEARCH
def hello():
"print a greeting"

print("hello")
=======
from hello import hello
>>>>>>> REPLACE
```

# *SEARCH/REPLACE block* Rules:

Every *SEARCH/REPLACE block* must use this format:
1. The start of search block: <<<<<<< SEARCH
2. A contiguous chunk of lines to search for in the existing source code
3. The dividing line: =======
4. The lines to replace into the source code
5. The end of the replace block: >>>>>>> REPLACE

Use the *FULL* file path, as shown to you by the user.

Every *SEARCH* section must *EXACTLY MATCH* the existing file content, character for character, including all comments, docstrings, etc.
If the file contains code or other data wrapped/escaped in json/xml/quotes or other containers, you need to propose edits to the literal contents of the file, including the container markup.

*SEARCH/REPLACE* blocks will *only* replace the first match occurrence.
Including multiple unique *SEARCH/REPLACE* blocks if needed.
Include enough lines in each SEARCH section to uniquely match each set of lines that need to change.

Keep *SEARCH/REPLACE* blocks concise.
Break large *SEARCH/REPLACE* blocks into a series of smaller blocks that each change a small portion of the file.
Include just the changing lines, and a few surrounding lines if needed for uniqueness.
Do not include long runs of unchanging lines in *SEARCH/REPLACE* blocks.
Loading

0 comments on commit 69f4e61

Please sign in to comment.