wcgw 1.1.1__tar.gz → 1.2.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of wcgw might be problematic. Click here for more details.
- {wcgw-1.1.1 → wcgw-1.2.0}/PKG-INFO +1 -1
- {wcgw-1.1.1 → wcgw-1.2.0}/gpt_action_json_schema.json +75 -7
- {wcgw-1.1.1 → wcgw-1.2.0}/gpt_instructions.txt +29 -34
- {wcgw-1.1.1 → wcgw-1.2.0}/pyproject.toml +1 -1
- {wcgw-1.1.1 → wcgw-1.2.0}/src/wcgw/client/anthropic_client.py +16 -7
- {wcgw-1.1.1 → wcgw-1.2.0}/src/wcgw/client/diff-instructions.txt +6 -15
- {wcgw-1.1.1 → wcgw-1.2.0}/src/wcgw/client/openai_client.py +27 -12
- {wcgw-1.1.1 → wcgw-1.2.0}/src/wcgw/client/tools.py +87 -44
- {wcgw-1.1.1 → wcgw-1.2.0}/src/wcgw/relay/serve.py +46 -8
- {wcgw-1.1.1 → wcgw-1.2.0}/src/wcgw/types_.py +16 -3
- {wcgw-1.1.1 → wcgw-1.2.0}/uv.lock +1 -1
- wcgw-1.1.1/config.toml +0 -11
- {wcgw-1.1.1 → wcgw-1.2.0}/.github/workflows/python-publish.yml +0 -0
- {wcgw-1.1.1 → wcgw-1.2.0}/.github/workflows/python-tests.yml +0 -0
- {wcgw-1.1.1 → wcgw-1.2.0}/.gitignore +0 -0
- {wcgw-1.1.1 → wcgw-1.2.0}/.python-version +0 -0
- {wcgw-1.1.1 → wcgw-1.2.0}/.vscode/settings.json +0 -0
- {wcgw-1.1.1 → wcgw-1.2.0}/README.md +0 -0
- {wcgw-1.1.1 → wcgw-1.2.0}/src/__init__.py +0 -0
- {wcgw-1.1.1 → wcgw-1.2.0}/src/wcgw/__init__.py +0 -0
- {wcgw-1.1.1 → wcgw-1.2.0}/src/wcgw/client/__init__.py +0 -0
- {wcgw-1.1.1 → wcgw-1.2.0}/src/wcgw/client/__main__.py +0 -0
- {wcgw-1.1.1 → wcgw-1.2.0}/src/wcgw/client/cli.py +0 -0
- {wcgw-1.1.1 → wcgw-1.2.0}/src/wcgw/client/common.py +0 -0
- {wcgw-1.1.1 → wcgw-1.2.0}/src/wcgw/client/openai_utils.py +0 -0
- {wcgw-1.1.1 → wcgw-1.2.0}/src/wcgw/relay/static/privacy.txt +0 -0
- {wcgw-1.1.1 → wcgw-1.2.0}/static/ss1.png +0 -0
- {wcgw-1.1.1 → wcgw-1.2.0}/tests/test_basic.py +0 -0
- {wcgw-1.1.1 → wcgw-1.2.0}/tests/test_tools.py +0 -0
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
},
|
|
7
7
|
"servers": [
|
|
8
8
|
{
|
|
9
|
-
"url": "https://
|
|
9
|
+
"url": "https://a0e8-125-99-67-222.ngrok-free.app"
|
|
10
10
|
}
|
|
11
11
|
],
|
|
12
12
|
"paths": {
|
|
@@ -59,7 +59,7 @@
|
|
|
59
59
|
"content": {
|
|
60
60
|
"application/json": {
|
|
61
61
|
"schema": {
|
|
62
|
-
"$ref": "#/components/schemas/
|
|
62
|
+
"$ref": "#/components/schemas/FileEditWithUUID"
|
|
63
63
|
}
|
|
64
64
|
}
|
|
65
65
|
},
|
|
@@ -209,6 +209,46 @@
|
|
|
209
209
|
}
|
|
210
210
|
}
|
|
211
211
|
}
|
|
212
|
+
},
|
|
213
|
+
"/v1/read_file": {
|
|
214
|
+
"post": {
|
|
215
|
+
"x-openai-isConsequential": false,
|
|
216
|
+
"summary": "Read File Endpoint",
|
|
217
|
+
"operationId": "read_file_endpoint_v1_read_file_post",
|
|
218
|
+
"requestBody": {
|
|
219
|
+
"content": {
|
|
220
|
+
"application/json": {
|
|
221
|
+
"schema": {
|
|
222
|
+
"$ref": "#/components/schemas/ReadFileWithUUID"
|
|
223
|
+
}
|
|
224
|
+
}
|
|
225
|
+
},
|
|
226
|
+
"required": true
|
|
227
|
+
},
|
|
228
|
+
"responses": {
|
|
229
|
+
"200": {
|
|
230
|
+
"description": "Successful Response",
|
|
231
|
+
"content": {
|
|
232
|
+
"application/json": {
|
|
233
|
+
"schema": {
|
|
234
|
+
"type": "string",
|
|
235
|
+
"title": "Response Read File Endpoint V1 Read File Post"
|
|
236
|
+
}
|
|
237
|
+
}
|
|
238
|
+
}
|
|
239
|
+
},
|
|
240
|
+
"422": {
|
|
241
|
+
"description": "Validation Error",
|
|
242
|
+
"content": {
|
|
243
|
+
"application/json": {
|
|
244
|
+
"schema": {
|
|
245
|
+
"$ref": "#/components/schemas/HTTPValidationError"
|
|
246
|
+
}
|
|
247
|
+
}
|
|
248
|
+
}
|
|
249
|
+
}
|
|
250
|
+
}
|
|
251
|
+
}
|
|
212
252
|
}
|
|
213
253
|
},
|
|
214
254
|
"components": {
|
|
@@ -319,15 +359,15 @@
|
|
|
319
359
|
],
|
|
320
360
|
"title": "CreateFileNewWithUUID"
|
|
321
361
|
},
|
|
322
|
-
"
|
|
362
|
+
"FileEditWithUUID": {
|
|
323
363
|
"properties": {
|
|
324
364
|
"file_path": {
|
|
325
365
|
"type": "string",
|
|
326
366
|
"title": "File Path"
|
|
327
367
|
},
|
|
328
|
-
"
|
|
368
|
+
"file_edit_using_search_replace_blocks": {
|
|
329
369
|
"type": "string",
|
|
330
|
-
"title": "File Edit Using
|
|
370
|
+
"title": "File Edit Using Search Replace Blocks"
|
|
331
371
|
},
|
|
332
372
|
"user_id": {
|
|
333
373
|
"type": "string",
|
|
@@ -338,10 +378,10 @@
|
|
|
338
378
|
"type": "object",
|
|
339
379
|
"required": [
|
|
340
380
|
"file_path",
|
|
341
|
-
"
|
|
381
|
+
"file_edit_using_search_replace_blocks",
|
|
342
382
|
"user_id"
|
|
343
383
|
],
|
|
344
|
-
"title": "
|
|
384
|
+
"title": "FileEditWithUUID"
|
|
345
385
|
},
|
|
346
386
|
"HTTPValidationError": {
|
|
347
387
|
"properties": {
|
|
@@ -356,6 +396,34 @@
|
|
|
356
396
|
"type": "object",
|
|
357
397
|
"title": "HTTPValidationError"
|
|
358
398
|
},
|
|
399
|
+
"ReadFileWithUUID": {
|
|
400
|
+
"properties": {
|
|
401
|
+
"file_path": {
|
|
402
|
+
"type": "string",
|
|
403
|
+
"title": "File Path"
|
|
404
|
+
},
|
|
405
|
+
"type": {
|
|
406
|
+
"type": "string",
|
|
407
|
+
"enum": [
|
|
408
|
+
"ReadFile"
|
|
409
|
+
],
|
|
410
|
+
"const": "ReadFile",
|
|
411
|
+
"title": "Type"
|
|
412
|
+
},
|
|
413
|
+
"user_id": {
|
|
414
|
+
"type": "string",
|
|
415
|
+
"format": "uuid",
|
|
416
|
+
"title": "User Id"
|
|
417
|
+
}
|
|
418
|
+
},
|
|
419
|
+
"type": "object",
|
|
420
|
+
"required": [
|
|
421
|
+
"file_path",
|
|
422
|
+
"type",
|
|
423
|
+
"user_id"
|
|
424
|
+
],
|
|
425
|
+
"title": "ReadFileWithUUID"
|
|
426
|
+
},
|
|
359
427
|
"ResetShellWithUUID": {
|
|
360
428
|
"properties": {
|
|
361
429
|
"should_reset": {
|
|
@@ -1,14 +1,13 @@
|
|
|
1
|
-
You're
|
|
1
|
+
You're an expert software engineer with shell and code knowledge.
|
|
2
2
|
|
|
3
3
|
Instructions:
|
|
4
4
|
|
|
5
|
-
- You should use the provided bash execution
|
|
6
|
-
-
|
|
7
|
-
-
|
|
5
|
+
- You should use the provided bash execution, reading and writing file tools to complete objective.
|
|
6
|
+
- First understand about the project by getting the folder structure (ignoring .git, node_modules, venv, etc.)
|
|
7
|
+
- Always read relevant files before editing.
|
|
8
|
+
- Do not provide code snippets unless asked by the user, instead directly edit the code.
|
|
8
9
|
|
|
9
10
|
|
|
10
|
-
To execute bash commands OR write files use the provided api.
|
|
11
|
-
|
|
12
11
|
Instructions for `BashCommand`:
|
|
13
12
|
- Execute a bash command. This is stateful (beware with subsequent calls).
|
|
14
13
|
- Do not use interactive commands like nano. Prefer writing simpler commands.
|
|
@@ -16,11 +15,15 @@ Instructions for `BashCommand`:
|
|
|
16
15
|
- Optionally `exit shell has restarted` is the output, in which case environment resets, you can run fresh commands.
|
|
17
16
|
- The first line might be `(...truncated)` if the output is too long.
|
|
18
17
|
|
|
18
|
+
Instructions for `Read File`
|
|
19
|
+
- Read full content of a file.
|
|
20
|
+
- Provide absolute file path only.
|
|
21
|
+
|
|
19
22
|
Instructions for `Create File New`
|
|
20
23
|
- Write content to a new file. Provide file path and content. Use this instead of BashCommand for writing new files.
|
|
21
24
|
- This doesn't create any directories, please create directories using `mkdir -p` BashCommand.
|
|
22
25
|
- Provide absolute file path only.
|
|
23
|
-
- For editing existing files, use
|
|
26
|
+
- For editing existing files, use FileEdit.
|
|
24
27
|
|
|
25
28
|
Instructions for `BashInteraction`
|
|
26
29
|
- Interact with running program using this tool
|
|
@@ -31,42 +34,33 @@ Instructions for `BashInteraction`
|
|
|
31
34
|
Instructions for `ResetShell`
|
|
32
35
|
- Resets the shell. Use only if all interrupts and prompt reset attempts have failed repeatedly.
|
|
33
36
|
|
|
34
|
-
Instructions for `
|
|
37
|
+
Instructions for `FileEdit`:
|
|
35
38
|
- Use absolute file path only.
|
|
36
39
|
- Use SEARCH/REPLACE blocks to edit the file.
|
|
37
40
|
Only edit the files using the following SEARCH/REPLACE blocks.
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
print("hello")
|
|
52
|
-
=======
|
|
53
|
-
from hello import hello
|
|
54
|
-
>>>>>>> REPLACE
|
|
55
|
-
```
|
|
41
|
+
```
|
|
42
|
+
<<<<<<< SEARCH
|
|
43
|
+
// Original code
|
|
44
|
+
=======
|
|
45
|
+
// New code
|
|
46
|
+
>>>>>>> REPLACE
|
|
47
|
+
<<<<<<< SEARCH
|
|
48
|
+
// Original code further down in the file
|
|
49
|
+
=======
|
|
50
|
+
// New code to replace
|
|
51
|
+
>>>>>>> REPLACE
|
|
52
|
+
```
|
|
56
53
|
|
|
57
54
|
# *SEARCH/REPLACE block* Rules:
|
|
58
55
|
|
|
59
56
|
Every *SEARCH/REPLACE block* must use this format:
|
|
60
|
-
1. The start of
|
|
61
|
-
2. A contiguous chunk of lines to
|
|
57
|
+
1. The start of match block: <<<<<<< SEARCH
|
|
58
|
+
2. A contiguous chunk of lines to do exact match for in the existing source code
|
|
62
59
|
3. The dividing line: =======
|
|
63
60
|
4. The lines to replace into the source code
|
|
64
61
|
5. The end of the replace block: >>>>>>> REPLACE
|
|
65
62
|
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
Every *SEARCH* section must *EXACTLY MATCH* the existing file content, character for character, including all comments, docstrings, etc.
|
|
69
|
-
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.
|
|
63
|
+
Every "<<<<<<< SEARCH" section must *EXACTLY MATCH* the existing file content, character for character, including all comments, docstrings, etc.
|
|
70
64
|
|
|
71
65
|
*SEARCH/REPLACE* blocks will *only* replace the first match occurrence.
|
|
72
66
|
Including multiple unique *SEARCH/REPLACE* blocks if needed.
|
|
@@ -77,10 +71,11 @@ Instructions for `FullFileEdit`:
|
|
|
77
71
|
Include just the changing lines, and a few surrounding lines if needed for uniqueness.
|
|
78
72
|
Do not include long runs of unchanging lines in *SEARCH/REPLACE* blocks.
|
|
79
73
|
|
|
74
|
+
Include context lines before and after the code to edit for better matching in "<<<<<<< SEARCH" and ">>>>>>> REPLACE". Recommended to add 3 lines on each side.
|
|
75
|
+
|
|
80
76
|
---
|
|
81
77
|
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.
|
|
82
78
|
|
|
83
|
-
Always
|
|
84
|
-
|
|
79
|
+
Always write production ready, syntactically correct code.
|
|
85
80
|
---
|
|
86
81
|
Ask the user for the user_id `UUID` if they haven't provided in the first message.
|
|
@@ -26,7 +26,8 @@ from ..types_ import (
|
|
|
26
26
|
BashInteraction,
|
|
27
27
|
CreateFileNew,
|
|
28
28
|
FileEditFindReplace,
|
|
29
|
-
|
|
29
|
+
FileEdit,
|
|
30
|
+
ReadFile,
|
|
30
31
|
ReadImage,
|
|
31
32
|
Writefile,
|
|
32
33
|
ResetShell,
|
|
@@ -175,6 +176,14 @@ def loop(
|
|
|
175
176
|
- Send text input to the running program.
|
|
176
177
|
- Send send_specials=["Enter"] to recheck status of a running program.
|
|
177
178
|
- Only one of send_text, send_specials, send_ascii should be provided.
|
|
179
|
+
""",
|
|
180
|
+
),
|
|
181
|
+
ToolParam(
|
|
182
|
+
input_schema=ReadFile.model_json_schema(),
|
|
183
|
+
name="ReadFile",
|
|
184
|
+
description="""
|
|
185
|
+
- Read full file content
|
|
186
|
+
- Provide absolute file path only
|
|
178
187
|
""",
|
|
179
188
|
),
|
|
180
189
|
ToolParam(
|
|
@@ -184,7 +193,7 @@ def loop(
|
|
|
184
193
|
- Write content to a new file. Provide file path and content. Use this instead of BashCommand for writing new files.
|
|
185
194
|
- This doesn't create any directories, please create directories using `mkdir -p` BashCommand.
|
|
186
195
|
- Provide absolute file path only.
|
|
187
|
-
- For editing existing files, use
|
|
196
|
+
- For editing existing files, use FileEdit.
|
|
188
197
|
""",
|
|
189
198
|
),
|
|
190
199
|
ToolParam(
|
|
@@ -198,8 +207,8 @@ def loop(
|
|
|
198
207
|
description="Resets the shell. Use only if all interrupts and prompt reset attempts have failed repeatedly.",
|
|
199
208
|
),
|
|
200
209
|
ToolParam(
|
|
201
|
-
input_schema=
|
|
202
|
-
name="
|
|
210
|
+
input_schema=FileEdit.model_json_schema(),
|
|
211
|
+
name="FileEdit",
|
|
203
212
|
description="""
|
|
204
213
|
- Use absolute file path only.
|
|
205
214
|
- Use SEARCH/REPLACE blocks to edit the file.
|
|
@@ -214,9 +223,9 @@ You're a cli assistant.
|
|
|
214
223
|
|
|
215
224
|
Instructions:
|
|
216
225
|
|
|
217
|
-
- You should use the provided bash execution tool to run script to complete objective.
|
|
218
|
-
-
|
|
219
|
-
-
|
|
226
|
+
- You should use the provided bash execution tool to run script to complete objective.
|
|
227
|
+
- First understand about the project by understanding the folder structure (ignoring node_modules or venv, etc.)
|
|
228
|
+
- Always read relevant files before making any changes.
|
|
220
229
|
|
|
221
230
|
System information:
|
|
222
231
|
- System: {uname_sysname}
|
|
@@ -2,14 +2,6 @@
|
|
|
2
2
|
Instructions for
|
|
3
3
|
Only edit the files using the following SEARCH/REPLACE blocks.
|
|
4
4
|
```
|
|
5
|
-
<<<<<<< SEARCH
|
|
6
|
-
=======
|
|
7
|
-
def hello():
|
|
8
|
-
"print a greeting"
|
|
9
|
-
|
|
10
|
-
print("hello")
|
|
11
|
-
>>>>>>> REPLACE
|
|
12
|
-
|
|
13
5
|
<<<<<<< SEARCH
|
|
14
6
|
def hello():
|
|
15
7
|
"print a greeting"
|
|
@@ -23,16 +15,13 @@ from hello import hello
|
|
|
23
15
|
# *SEARCH/REPLACE block* Rules:
|
|
24
16
|
|
|
25
17
|
Every *SEARCH/REPLACE block* must use this format:
|
|
26
|
-
1. The start of
|
|
27
|
-
2. A contiguous chunk of lines to
|
|
18
|
+
1. The start of match block: <<<<<<< SEARCH
|
|
19
|
+
2. A contiguous chunk of lines to do exact match for in the existing source code
|
|
28
20
|
3. The dividing line: =======
|
|
29
21
|
4. The lines to replace into the source code
|
|
30
22
|
5. The end of the replace block: >>>>>>> REPLACE
|
|
31
23
|
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
Every *SEARCH* section must *EXACTLY MATCH* the existing file content, character for character, including all comments, docstrings, etc.
|
|
35
|
-
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.
|
|
24
|
+
Every "<<<<<<< SEARCH" section must *EXACTLY MATCH* the existing file content, character for character, including all comments, docstrings, etc.
|
|
36
25
|
|
|
37
26
|
*SEARCH/REPLACE* blocks will *only* replace the first match occurrence.
|
|
38
27
|
Including multiple unique *SEARCH/REPLACE* blocks if needed.
|
|
@@ -41,4 +30,6 @@ Include enough lines in each SEARCH section to uniquely match each set of lines
|
|
|
41
30
|
Keep *SEARCH/REPLACE* blocks concise.
|
|
42
31
|
Break large *SEARCH/REPLACE* blocks into a series of smaller blocks that each change a small portion of the file.
|
|
43
32
|
Include just the changing lines, and a few surrounding lines if needed for uniqueness.
|
|
44
|
-
Do not include long runs of unchanging lines in *SEARCH/REPLACE* blocks.
|
|
33
|
+
Do not include long runs of unchanging lines in *SEARCH/REPLACE* blocks.
|
|
34
|
+
|
|
35
|
+
Include context lines before and after the code to edit for better matching in "<<<<<<< SEARCH". Recommended to add 3 lines on each side.
|
|
@@ -24,8 +24,9 @@ from ..types_ import (
|
|
|
24
24
|
BashCommand,
|
|
25
25
|
BashInteraction,
|
|
26
26
|
CreateFileNew,
|
|
27
|
-
|
|
27
|
+
FileEdit,
|
|
28
28
|
ReadImage,
|
|
29
|
+
ReadFile,
|
|
29
30
|
Writefile,
|
|
30
31
|
ResetShell,
|
|
31
32
|
)
|
|
@@ -58,7 +59,6 @@ from dotenv import load_dotenv
|
|
|
58
59
|
|
|
59
60
|
class Config(BaseModel):
|
|
60
61
|
model: Models
|
|
61
|
-
secondary_model: Models
|
|
62
62
|
cost_limit: float
|
|
63
63
|
cost_file: dict[Models, CostData]
|
|
64
64
|
cost_unit: str = "$"
|
|
@@ -146,10 +146,18 @@ def loop(
|
|
|
146
146
|
waiting_for_assistant = history[-1]["role"] != "assistant"
|
|
147
147
|
|
|
148
148
|
my_dir = os.path.dirname(__file__)
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
149
|
+
|
|
150
|
+
config = Config(
|
|
151
|
+
model=cast(
|
|
152
|
+
Models, os.getenv("OPENAI_MODEL", "gpt-4o-2024-08-06").lower()),
|
|
153
|
+
cost_limit=0.1,
|
|
154
|
+
cost_unit="$",
|
|
155
|
+
cost_file={
|
|
156
|
+
"gpt-4o-2024-08-06": CostData(
|
|
157
|
+
cost_per_1m_input_tokens=5, cost_per_1m_output_tokens=15
|
|
158
|
+
),
|
|
159
|
+
},
|
|
160
|
+
)
|
|
153
161
|
|
|
154
162
|
if limit is not None:
|
|
155
163
|
config.cost_limit = limit
|
|
@@ -178,6 +186,13 @@ def loop(
|
|
|
178
186
|
- Special keys like arrows, interrupts, enter, etc.
|
|
179
187
|
- Send text input to the running program.
|
|
180
188
|
- Only one of send_text, send_specials, send_ascii should be provided.""",
|
|
189
|
+
),
|
|
190
|
+
openai.pydantic_function_tool(
|
|
191
|
+
ReadFile,
|
|
192
|
+
description="""
|
|
193
|
+
- Read full file content
|
|
194
|
+
- Provide absolute file path only
|
|
195
|
+
""",
|
|
181
196
|
),
|
|
182
197
|
openai.pydantic_function_tool(
|
|
183
198
|
CreateFileNew,
|
|
@@ -185,14 +200,14 @@ def loop(
|
|
|
185
200
|
- Write content to a new file. Provide file path and content. Use this instead of BashCommand for writing new files.
|
|
186
201
|
- This doesn't create any directories, please create directories using `mkdir -p` BashCommand.
|
|
187
202
|
- Provide absolute file path only.
|
|
188
|
-
- For editing existing files, use
|
|
203
|
+
- For editing existing files, use FileEdit.""",
|
|
189
204
|
),
|
|
190
205
|
openai.pydantic_function_tool(
|
|
191
|
-
|
|
206
|
+
FileEdit,
|
|
192
207
|
description="""
|
|
193
208
|
- Use absolute file path only.
|
|
194
209
|
- Use ONLY SEARCH/REPLACE blocks to edit the file.
|
|
195
|
-
-
|
|
210
|
+
- file_edit_using_search_replace_blocks should start with <<<<<<< SEARCH
|
|
196
211
|
""",
|
|
197
212
|
),
|
|
198
213
|
openai.pydantic_function_tool(
|
|
@@ -211,9 +226,9 @@ You're a cli assistant.
|
|
|
211
226
|
|
|
212
227
|
Instructions:
|
|
213
228
|
|
|
214
|
-
- You should use the provided bash execution tool to run script to complete objective.
|
|
215
|
-
-
|
|
216
|
-
-
|
|
229
|
+
- You should use the provided bash execution tool to run script to complete objective.
|
|
230
|
+
- First understand about the project by understanding the folder structure (ignoring node_modules or venv, etc.)
|
|
231
|
+
- Always read relevant files before making any changes.
|
|
217
232
|
|
|
218
233
|
System information:
|
|
219
234
|
- System: {uname_sysname}
|
|
@@ -9,6 +9,7 @@ import re
|
|
|
9
9
|
import sys
|
|
10
10
|
import threading
|
|
11
11
|
import importlib.metadata
|
|
12
|
+
import time
|
|
12
13
|
import traceback
|
|
13
14
|
from typing import (
|
|
14
15
|
Callable,
|
|
@@ -47,19 +48,17 @@ from openai.types.chat import (
|
|
|
47
48
|
from nltk.metrics.distance import edit_distance
|
|
48
49
|
|
|
49
50
|
from ..types_ import (
|
|
51
|
+
BashCommand,
|
|
52
|
+
BashInteraction,
|
|
50
53
|
CreateFileNew,
|
|
51
54
|
FileEditFindReplace,
|
|
52
|
-
|
|
55
|
+
FileEdit,
|
|
56
|
+
ReadFile,
|
|
57
|
+
ReadImage,
|
|
53
58
|
ResetShell,
|
|
54
59
|
Writefile,
|
|
55
60
|
)
|
|
56
61
|
|
|
57
|
-
from ..types_ import BashCommand
|
|
58
|
-
|
|
59
|
-
from ..types_ import BashInteraction
|
|
60
|
-
|
|
61
|
-
from ..types_ import ReadImage
|
|
62
|
-
|
|
63
62
|
from .common import CostData, Models, discard_input
|
|
64
63
|
|
|
65
64
|
from .openai_utils import get_input_cost, get_output_cost
|
|
@@ -319,7 +318,7 @@ def execute_bash(
|
|
|
319
318
|
tokens = enc.encode(text)
|
|
320
319
|
|
|
321
320
|
if max_tokens and len(tokens) >= max_tokens:
|
|
322
|
-
text = "...(truncated)\n" + enc.decode(tokens[-(max_tokens - 1)
|
|
321
|
+
text = "...(truncated)\n" + enc.decode(tokens[-(max_tokens - 1):])
|
|
323
322
|
|
|
324
323
|
if is_interrupt:
|
|
325
324
|
text = (
|
|
@@ -346,7 +345,7 @@ Otherwise, you may want to try Ctrl-c again or program specific exit interactive
|
|
|
346
345
|
|
|
347
346
|
tokens = enc.encode(output)
|
|
348
347
|
if max_tokens and len(tokens) >= max_tokens:
|
|
349
|
-
output = "...(truncated)\n" + enc.decode(tokens[-(max_tokens - 1)
|
|
348
|
+
output = "...(truncated)\n" + enc.decode(tokens[-(max_tokens - 1):])
|
|
350
349
|
|
|
351
350
|
try:
|
|
352
351
|
exit_status = get_status()
|
|
@@ -426,7 +425,7 @@ def read_image_from_shell(file_path: str) -> ImageData:
|
|
|
426
425
|
|
|
427
426
|
def write_file(writefile: Writefile | CreateFileNew, error_on_exist: bool) -> str:
|
|
428
427
|
if not os.path.isabs(writefile.file_path):
|
|
429
|
-
return "Failure: file_path should be absolute path"
|
|
428
|
+
return f"Failure: file_path should be absolute path, current working directory is {CWD}"
|
|
430
429
|
else:
|
|
431
430
|
path_ = writefile.file_path
|
|
432
431
|
|
|
@@ -465,12 +464,14 @@ def find_least_edit_distance_substring(
|
|
|
465
464
|
edit_distance_sum = 0
|
|
466
465
|
for j in range(len(find_lines)):
|
|
467
466
|
if (i + j) < len(content_lines):
|
|
468
|
-
edit_distance_sum += edit_distance(
|
|
467
|
+
edit_distance_sum += edit_distance(
|
|
468
|
+
content_lines[i + j], find_lines[j])
|
|
469
469
|
else:
|
|
470
470
|
edit_distance_sum += len(find_lines[j])
|
|
471
471
|
if edit_distance_sum < min_edit_distance:
|
|
472
472
|
min_edit_distance = edit_distance_sum
|
|
473
|
-
min_edit_distance_lines = orig_content_lines[i
|
|
473
|
+
min_edit_distance_lines = orig_content_lines[i: i + len(
|
|
474
|
+
find_lines)]
|
|
474
475
|
return "\n".join(min_edit_distance_lines), min_edit_distance
|
|
475
476
|
|
|
476
477
|
|
|
@@ -494,11 +495,12 @@ def edit_content(content: str, find_lines: str, replace_with_lines: str) -> str:
|
|
|
494
495
|
return content
|
|
495
496
|
|
|
496
497
|
|
|
497
|
-
def do_diff_edit(fedit:
|
|
498
|
+
def do_diff_edit(fedit: FileEdit) -> str:
|
|
498
499
|
console.log(f"Editing file: {fedit.file_path}")
|
|
499
500
|
|
|
500
501
|
if not os.path.isabs(fedit.file_path):
|
|
501
|
-
raise Exception(
|
|
502
|
+
raise Exception(
|
|
503
|
+
f"Failure: file_path should be absolute path, current working directory is {CWD}")
|
|
502
504
|
else:
|
|
503
505
|
path_ = fedit.file_path
|
|
504
506
|
|
|
@@ -508,9 +510,10 @@ def do_diff_edit(fedit: FullFileEdit) -> str:
|
|
|
508
510
|
with open(path_) as f:
|
|
509
511
|
apply_diff_to = f.read()
|
|
510
512
|
|
|
511
|
-
lines = fedit.
|
|
513
|
+
lines = fedit.file_edit_using_search_replace_blocks.split("\n")
|
|
512
514
|
n_lines = len(lines)
|
|
513
515
|
i = 0
|
|
516
|
+
replacement_count = 0
|
|
514
517
|
while i < n_lines:
|
|
515
518
|
if re.match(r"^<<<<<<+\s*SEARCH\s*$", lines[i]):
|
|
516
519
|
search_block = []
|
|
@@ -534,10 +537,17 @@ def do_diff_edit(fedit: FullFileEdit) -> str:
|
|
|
534
537
|
search_block_ = "\n".join(search_block)
|
|
535
538
|
replace_block_ = "\n".join(replace_block)
|
|
536
539
|
|
|
537
|
-
apply_diff_to = edit_content(
|
|
540
|
+
apply_diff_to = edit_content(
|
|
541
|
+
apply_diff_to, search_block_, replace_block_)
|
|
542
|
+
replacement_count += 1
|
|
538
543
|
else:
|
|
539
544
|
i += 1
|
|
540
545
|
|
|
546
|
+
if replacement_count == 0:
|
|
547
|
+
raise Exception(
|
|
548
|
+
"Error: no valid search-replace blocks found, please check your syntax for FileEdit"
|
|
549
|
+
)
|
|
550
|
+
|
|
541
551
|
with open(path_, "w") as f:
|
|
542
552
|
f.write(apply_diff_to)
|
|
543
553
|
|
|
@@ -546,7 +556,8 @@ def do_diff_edit(fedit: FullFileEdit) -> str:
|
|
|
546
556
|
|
|
547
557
|
def file_edit(fedit: FileEditFindReplace) -> str:
|
|
548
558
|
if not os.path.isabs(fedit.file_path):
|
|
549
|
-
raise Exception(
|
|
559
|
+
raise Exception(
|
|
560
|
+
f"Failure: file_path should be absolute path, current working directory is {CWD}")
|
|
550
561
|
else:
|
|
551
562
|
path_ = fedit.file_path
|
|
552
563
|
|
|
@@ -556,14 +567,17 @@ def file_edit(fedit: FileEditFindReplace) -> str:
|
|
|
556
567
|
if not fedit.find_lines:
|
|
557
568
|
raise Exception("Error: `find_lines` cannot be empty")
|
|
558
569
|
|
|
559
|
-
out_string = "\n".join(
|
|
560
|
-
|
|
570
|
+
out_string = "\n".join(
|
|
571
|
+
"> " + line for line in fedit.find_lines.split("\n"))
|
|
572
|
+
in_string = "\n".join(
|
|
573
|
+
"< " + line for line in fedit.replace_with_lines.split("\n"))
|
|
561
574
|
console.log(f"Editing file: {path_}\n---\n{out_string}\n---\n{in_string}\n---")
|
|
562
575
|
try:
|
|
563
576
|
with open(path_) as f:
|
|
564
577
|
content = f.read()
|
|
565
578
|
|
|
566
|
-
content = edit_content(content, fedit.find_lines,
|
|
579
|
+
content = edit_content(content, fedit.find_lines,
|
|
580
|
+
fedit.replace_with_lines)
|
|
567
581
|
|
|
568
582
|
with open(path_, "w") as f:
|
|
569
583
|
f.write(content)
|
|
@@ -603,10 +617,11 @@ TOOLS = (
|
|
|
603
617
|
| Writefile
|
|
604
618
|
| CreateFileNew
|
|
605
619
|
| FileEditFindReplace
|
|
606
|
-
|
|
|
620
|
+
| FileEdit
|
|
607
621
|
| AIAssistant
|
|
608
622
|
| DoneFlag
|
|
609
623
|
| ReadImage
|
|
624
|
+
| ReadFile
|
|
610
625
|
)
|
|
611
626
|
|
|
612
627
|
|
|
@@ -630,14 +645,16 @@ def which_tool_name(name: str) -> Type[TOOLS]:
|
|
|
630
645
|
return CreateFileNew
|
|
631
646
|
elif name == "FileEditFindReplace":
|
|
632
647
|
return FileEditFindReplace
|
|
633
|
-
elif name == "
|
|
634
|
-
return
|
|
648
|
+
elif name == "FileEdit":
|
|
649
|
+
return FileEdit
|
|
635
650
|
elif name == "AIAssistant":
|
|
636
651
|
return AIAssistant
|
|
637
652
|
elif name == "DoneFlag":
|
|
638
653
|
return DoneFlag
|
|
639
654
|
elif name == "ReadImage":
|
|
640
655
|
return ReadImage
|
|
656
|
+
elif name == "ReadFile":
|
|
657
|
+
return ReadFile
|
|
641
658
|
else:
|
|
642
659
|
raise ValueError(f"Unknown tool name: {name}")
|
|
643
660
|
|
|
@@ -651,10 +668,11 @@ def get_tool_output(
|
|
|
651
668
|
| Writefile
|
|
652
669
|
| CreateFileNew
|
|
653
670
|
| FileEditFindReplace
|
|
654
|
-
|
|
|
671
|
+
| FileEdit
|
|
655
672
|
| AIAssistant
|
|
656
673
|
| DoneFlag
|
|
657
|
-
| ReadImage
|
|
674
|
+
| ReadImage
|
|
675
|
+
| ReadFile,
|
|
658
676
|
enc: tiktoken.Encoding,
|
|
659
677
|
limit: float,
|
|
660
678
|
loop_call: Callable[[str, float], tuple[str, float]],
|
|
@@ -669,10 +687,11 @@ def get_tool_output(
|
|
|
669
687
|
| Writefile
|
|
670
688
|
| CreateFileNew
|
|
671
689
|
| FileEditFindReplace
|
|
672
|
-
|
|
|
690
|
+
| FileEdit
|
|
673
691
|
| AIAssistant
|
|
674
692
|
| DoneFlag
|
|
675
693
|
| ReadImage
|
|
694
|
+
| ReadFile
|
|
676
695
|
](
|
|
677
696
|
Confirmation
|
|
678
697
|
| BashCommand
|
|
@@ -681,10 +700,11 @@ def get_tool_output(
|
|
|
681
700
|
| Writefile
|
|
682
701
|
| CreateFileNew
|
|
683
702
|
| FileEditFindReplace
|
|
684
|
-
|
|
|
703
|
+
| FileEdit
|
|
685
704
|
| AIAssistant
|
|
686
705
|
| DoneFlag
|
|
687
706
|
| ReadImage
|
|
707
|
+
| ReadFile
|
|
688
708
|
)
|
|
689
709
|
arg = adapter.validate_python(args)
|
|
690
710
|
else:
|
|
@@ -705,7 +725,7 @@ def get_tool_output(
|
|
|
705
725
|
elif isinstance(arg, FileEditFindReplace):
|
|
706
726
|
console.print("Calling file edit tool")
|
|
707
727
|
output = file_edit(arg), 0.0
|
|
708
|
-
elif isinstance(arg,
|
|
728
|
+
elif isinstance(arg, FileEdit):
|
|
709
729
|
console.print("Calling full file edit tool")
|
|
710
730
|
output = do_diff_edit(arg), 0.0
|
|
711
731
|
elif isinstance(arg, DoneFlag):
|
|
@@ -717,6 +737,9 @@ def get_tool_output(
|
|
|
717
737
|
elif isinstance(arg, ReadImage):
|
|
718
738
|
console.print("Calling read image tool")
|
|
719
739
|
output = read_image_from_shell(arg.file_path), 0.0
|
|
740
|
+
elif isinstance(arg, ReadFile):
|
|
741
|
+
console.print("Calling read file tool")
|
|
742
|
+
output = read_file(arg), 0.0
|
|
720
743
|
elif isinstance(arg, ResetShell):
|
|
721
744
|
console.print("Calling reset shell tool")
|
|
722
745
|
output = reset_shell(), 0.0
|
|
@@ -731,7 +754,8 @@ History = list[ChatCompletionMessageParam]
|
|
|
731
754
|
|
|
732
755
|
default_enc = tiktoken.encoding_for_model("gpt-4o")
|
|
733
756
|
default_model: Models = "gpt-4o-2024-08-06"
|
|
734
|
-
default_cost = CostData(cost_per_1m_input_tokens=0.15,
|
|
757
|
+
default_cost = CostData(cost_per_1m_input_tokens=0.15,
|
|
758
|
+
cost_per_1m_output_tokens=0.6)
|
|
735
759
|
curr_cost = 0.0
|
|
736
760
|
|
|
737
761
|
|
|
@@ -743,8 +767,9 @@ class Mdata(BaseModel):
|
|
|
743
767
|
| CreateFileNew
|
|
744
768
|
| ResetShell
|
|
745
769
|
| FileEditFindReplace
|
|
746
|
-
|
|
|
770
|
+
| FileEdit
|
|
747
771
|
| str
|
|
772
|
+
| ReadFile
|
|
748
773
|
)
|
|
749
774
|
|
|
750
775
|
|
|
@@ -755,16 +780,16 @@ def register_client(server_url: str, client_uuid: str = "") -> None:
|
|
|
755
780
|
client_uuid = str(uuid.uuid4())
|
|
756
781
|
|
|
757
782
|
# Create the WebSocket connection
|
|
758
|
-
|
|
759
|
-
|
|
760
|
-
|
|
761
|
-
|
|
762
|
-
|
|
763
|
-
|
|
764
|
-
|
|
765
|
-
|
|
766
|
-
|
|
767
|
-
|
|
783
|
+
try:
|
|
784
|
+
with syncconnect(f"{server_url}/{client_uuid}") as websocket:
|
|
785
|
+
server_version = str(websocket.recv())
|
|
786
|
+
print(f"Server version: {server_version}")
|
|
787
|
+
client_version = importlib.metadata.version("wcgw")
|
|
788
|
+
websocket.send(client_version)
|
|
789
|
+
|
|
790
|
+
print(
|
|
791
|
+
f"Connected. Share this user id with the chatbot: {client_uuid} \nLink: https://chatgpt.com/g/g-Us0AAXkRh-wcgw-giving-shell-access"
|
|
792
|
+
)
|
|
768
793
|
while True:
|
|
769
794
|
# Wait to receive data from the server
|
|
770
795
|
message = websocket.recv()
|
|
@@ -773,7 +798,8 @@ def register_client(server_url: str, client_uuid: str = "") -> None:
|
|
|
773
798
|
raise Exception(mdata)
|
|
774
799
|
try:
|
|
775
800
|
output, cost = get_tool_output(
|
|
776
|
-
mdata.data, default_enc, 0.0, lambda x, y: (
|
|
801
|
+
mdata.data, default_enc, 0.0, lambda x, y: (
|
|
802
|
+
"", 0), None
|
|
777
803
|
)
|
|
778
804
|
curr_cost += cost
|
|
779
805
|
print(f"{curr_cost=}")
|
|
@@ -783,9 +809,10 @@ def register_client(server_url: str, client_uuid: str = "") -> None:
|
|
|
783
809
|
assert isinstance(output, str)
|
|
784
810
|
websocket.send(output)
|
|
785
811
|
|
|
786
|
-
|
|
787
|
-
|
|
788
|
-
|
|
812
|
+
except (websockets.ConnectionClosed, ConnectionError, OSError):
|
|
813
|
+
print(f"Connection closed for UUID: {client_uuid}, retrying")
|
|
814
|
+
time.sleep(0.5)
|
|
815
|
+
register_client(server_url, client_uuid)
|
|
789
816
|
|
|
790
817
|
|
|
791
818
|
run = Typer(pretty_exceptions_show_locals=False, no_args_is_help=True)
|
|
@@ -803,3 +830,19 @@ def app(
|
|
|
803
830
|
exit()
|
|
804
831
|
|
|
805
832
|
register_client(server_url, client_uuid or "")
|
|
833
|
+
|
|
834
|
+
|
|
835
|
+
def read_file(readfile: ReadFile) -> str:
|
|
836
|
+
|
|
837
|
+
console.print(f"Reading file: {readfile.file_path}")
|
|
838
|
+
|
|
839
|
+
if not os.path.isabs(readfile.file_path):
|
|
840
|
+
return f"Failure: file_path should be absolute path, current working directory is {CWD}"
|
|
841
|
+
|
|
842
|
+
path = Path(readfile.file_path)
|
|
843
|
+
if not path.exists():
|
|
844
|
+
return f"Error: file {readfile.file_path} does not exist"
|
|
845
|
+
|
|
846
|
+
with path.open("r") as f:
|
|
847
|
+
content = f.read()
|
|
848
|
+
return content
|
|
@@ -19,7 +19,8 @@ from ..types_ import (
|
|
|
19
19
|
BashInteraction,
|
|
20
20
|
CreateFileNew,
|
|
21
21
|
FileEditFindReplace,
|
|
22
|
-
|
|
22
|
+
FileEdit,
|
|
23
|
+
ReadFile,
|
|
23
24
|
ResetShell,
|
|
24
25
|
Writefile,
|
|
25
26
|
Specials,
|
|
@@ -34,7 +35,8 @@ class Mdata(BaseModel):
|
|
|
34
35
|
| CreateFileNew
|
|
35
36
|
| ResetShell
|
|
36
37
|
| FileEditFindReplace
|
|
37
|
-
|
|
|
38
|
+
| FileEdit
|
|
39
|
+
| ReadFile
|
|
38
40
|
| str
|
|
39
41
|
)
|
|
40
42
|
user_id: UUID
|
|
@@ -49,7 +51,7 @@ gpts: dict[UUID, Callable[[str], None]] = {}
|
|
|
49
51
|
images: DefaultDict[UUID, dict[str, dict[str, Any]]] = DefaultDict(dict)
|
|
50
52
|
|
|
51
53
|
|
|
52
|
-
CLIENT_VERSION_MINIMUM = "1.
|
|
54
|
+
CLIENT_VERSION_MINIMUM = "1.2.0"
|
|
53
55
|
|
|
54
56
|
|
|
55
57
|
@app.websocket("/v1/register/{uuid}")
|
|
@@ -63,12 +65,14 @@ async def register_websocket(websocket: WebSocket, uuid: UUID) -> None:
|
|
|
63
65
|
# receive client version
|
|
64
66
|
client_version = await websocket.receive_text()
|
|
65
67
|
sem_version_client = semantic_version.Version.coerce(client_version)
|
|
66
|
-
sem_version_server = semantic_version.Version.coerce(
|
|
68
|
+
sem_version_server = semantic_version.Version.coerce(
|
|
69
|
+
CLIENT_VERSION_MINIMUM)
|
|
67
70
|
if sem_version_client < sem_version_server:
|
|
68
71
|
await websocket.send_text(
|
|
69
72
|
Mdata(
|
|
70
73
|
user_id=uuid,
|
|
71
|
-
data=f"Client version {client_version} is outdated. Please upgrade to {
|
|
74
|
+
data=f"Client version {client_version} is outdated. Please upgrade to {
|
|
75
|
+
CLIENT_VERSION_MINIMUM} or higher.",
|
|
72
76
|
).model_dump_json()
|
|
73
77
|
)
|
|
74
78
|
await websocket.close(
|
|
@@ -88,7 +92,8 @@ async def register_websocket(websocket: WebSocket, uuid: UUID) -> None:
|
|
|
88
92
|
while True:
|
|
89
93
|
received_data = await websocket.receive_text()
|
|
90
94
|
if uuid not in gpts:
|
|
91
|
-
raise fastapi.HTTPException(
|
|
95
|
+
raise fastapi.HTTPException(
|
|
96
|
+
status_code=400, detail="No call made")
|
|
92
97
|
gpts[uuid](received_data)
|
|
93
98
|
except WebSocketDisconnect:
|
|
94
99
|
# Remove the client if the WebSocket is disconnected
|
|
@@ -126,13 +131,13 @@ async def create_file(write_file_data: CreateFileNewWithUUID) -> str:
|
|
|
126
131
|
raise fastapi.HTTPException(status_code=500, detail="Timeout error")
|
|
127
132
|
|
|
128
133
|
|
|
129
|
-
class
|
|
134
|
+
class FileEditWithUUID(FileEdit):
|
|
130
135
|
user_id: UUID
|
|
131
136
|
|
|
132
137
|
|
|
133
138
|
@app.post("/v1/full_file_edit")
|
|
134
139
|
async def file_edit_find_replace(
|
|
135
|
-
file_edit_find_replace:
|
|
140
|
+
file_edit_find_replace: FileEditWithUUID,
|
|
136
141
|
) -> str:
|
|
137
142
|
user_id = file_edit_find_replace.user_id
|
|
138
143
|
if user_id not in clients:
|
|
@@ -257,6 +262,39 @@ async def bash_interaction(bash_interaction: BashInteractionWithUUID) -> str:
|
|
|
257
262
|
raise fastapi.HTTPException(status_code=500, detail="Timeout error")
|
|
258
263
|
|
|
259
264
|
|
|
265
|
+
class ReadFileWithUUID(ReadFile):
|
|
266
|
+
user_id: UUID
|
|
267
|
+
|
|
268
|
+
|
|
269
|
+
@app.post("/v1/read_file")
|
|
270
|
+
async def read_file_endpoint(read_file_data: ReadFileWithUUID) -> str:
|
|
271
|
+
user_id = read_file_data.user_id
|
|
272
|
+
if user_id not in clients:
|
|
273
|
+
return "Failure: id not found, ask the user to check it."
|
|
274
|
+
|
|
275
|
+
results: Optional[str] = None
|
|
276
|
+
|
|
277
|
+
def put_results(result: str) -> None:
|
|
278
|
+
nonlocal results
|
|
279
|
+
results = result
|
|
280
|
+
|
|
281
|
+
gpts[user_id] = put_results
|
|
282
|
+
|
|
283
|
+
await clients[user_id](
|
|
284
|
+
Mdata(data=ReadFile(file_path=read_file_data.file_path,
|
|
285
|
+
type=read_file_data.type
|
|
286
|
+
), user_id=user_id)
|
|
287
|
+
)
|
|
288
|
+
|
|
289
|
+
start_time = time.time()
|
|
290
|
+
while time.time() - start_time < 30:
|
|
291
|
+
if results is not None:
|
|
292
|
+
return results
|
|
293
|
+
await asyncio.sleep(0.1)
|
|
294
|
+
|
|
295
|
+
raise fastapi.HTTPException(status_code=500, detail="Timeout error")
|
|
296
|
+
|
|
297
|
+
|
|
260
298
|
app.mount("/static", StaticFiles(directory="static"), name="static")
|
|
261
299
|
|
|
262
300
|
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import re
|
|
1
2
|
from typing import Literal, Optional, Sequence
|
|
2
3
|
from pydantic import BaseModel
|
|
3
4
|
|
|
@@ -35,7 +36,7 @@ class BashInteraction(BaseModel):
|
|
|
35
36
|
|
|
36
37
|
class ReadImage(BaseModel):
|
|
37
38
|
file_path: str
|
|
38
|
-
type: Literal["ReadImage"]
|
|
39
|
+
type: Literal["ReadImage"]
|
|
39
40
|
|
|
40
41
|
|
|
41
42
|
class Writefile(BaseModel):
|
|
@@ -48,6 +49,11 @@ class CreateFileNew(BaseModel):
|
|
|
48
49
|
file_content: str
|
|
49
50
|
|
|
50
51
|
|
|
52
|
+
class ReadFile(BaseModel):
|
|
53
|
+
file_path: str # The path to the file to read
|
|
54
|
+
type: Literal["ReadFile"]
|
|
55
|
+
|
|
56
|
+
|
|
51
57
|
class FileEditFindReplace(BaseModel):
|
|
52
58
|
file_path: str
|
|
53
59
|
find_lines: str
|
|
@@ -58,6 +64,13 @@ class ResetShell(BaseModel):
|
|
|
58
64
|
should_reset: Literal[True] = True
|
|
59
65
|
|
|
60
66
|
|
|
61
|
-
class
|
|
67
|
+
class FileEdit(BaseModel):
|
|
62
68
|
file_path: str
|
|
63
|
-
|
|
69
|
+
file_edit_using_search_replace_blocks: str
|
|
70
|
+
|
|
71
|
+
def model_post_init(self, __context: object) -> None:
|
|
72
|
+
# Ensure first line is "<<<<<<< SEARCH"
|
|
73
|
+
|
|
74
|
+
if not re.match(r"^<<<<<<+\s*SEARCH\s*$", self.file_edit_using_search_replace_blocks.split("\n")[0]):
|
|
75
|
+
|
|
76
|
+
raise ValueError("First line of file_edit_using_search_replace_blocks must be '<<<<<<< SEARCH'")
|
wcgw-1.1.1/config.toml
DELETED
|
@@ -1,11 +0,0 @@
|
|
|
1
|
-
model = "gpt-4o-2024-08-06"
|
|
2
|
-
secondary_model = 'gpt-4o-2024-08-06'
|
|
3
|
-
cost_limit = 0.1
|
|
4
|
-
|
|
5
|
-
[cost_file.gpt-4o-2024-08-06]
|
|
6
|
-
cost_per_1m_input_tokens = 5
|
|
7
|
-
cost_per_1m_output_tokens = 15
|
|
8
|
-
|
|
9
|
-
[cost_file.gpt-4o-mini]
|
|
10
|
-
cost_per_1m_input_tokens = 0.15
|
|
11
|
-
cost_per_1m_output_tokens = 0.6
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|