wcgw 1.2.2__tar.gz → 1.3.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.2.2 → wcgw-1.3.0}/PKG-INFO +1 -1
- {wcgw-1.2.2 → wcgw-1.3.0}/gpt_action_json_schema.json +68 -6
- {wcgw-1.2.2 → wcgw-1.3.0}/gpt_instructions.txt +9 -3
- {wcgw-1.2.2 → wcgw-1.3.0}/pyproject.toml +1 -1
- {wcgw-1.2.2 → wcgw-1.3.0}/src/wcgw/client/anthropic_client.py +6 -4
- {wcgw-1.2.2 → wcgw-1.3.0}/src/wcgw/client/diff-instructions.txt +5 -1
- {wcgw-1.2.2 → wcgw-1.3.0}/src/wcgw/client/openai_client.py +6 -5
- {wcgw-1.2.2 → wcgw-1.3.0}/src/wcgw/client/tools.py +61 -31
- {wcgw-1.2.2 → wcgw-1.3.0}/src/wcgw/relay/serve.py +35 -6
- {wcgw-1.2.2 → wcgw-1.3.0}/src/wcgw/types_.py +4 -0
- {wcgw-1.2.2 → wcgw-1.3.0}/.github/workflows/python-publish.yml +0 -0
- {wcgw-1.2.2 → wcgw-1.3.0}/.github/workflows/python-tests.yml +0 -0
- {wcgw-1.2.2 → wcgw-1.3.0}/.gitignore +0 -0
- {wcgw-1.2.2 → wcgw-1.3.0}/.python-version +0 -0
- {wcgw-1.2.2 → wcgw-1.3.0}/.vscode/settings.json +0 -0
- {wcgw-1.2.2 → wcgw-1.3.0}/README.md +0 -0
- {wcgw-1.2.2 → wcgw-1.3.0}/src/__init__.py +0 -0
- {wcgw-1.2.2 → wcgw-1.3.0}/src/wcgw/__init__.py +0 -0
- {wcgw-1.2.2 → wcgw-1.3.0}/src/wcgw/client/__init__.py +0 -0
- {wcgw-1.2.2 → wcgw-1.3.0}/src/wcgw/client/__main__.py +0 -0
- {wcgw-1.2.2 → wcgw-1.3.0}/src/wcgw/client/cli.py +0 -0
- {wcgw-1.2.2 → wcgw-1.3.0}/src/wcgw/client/common.py +0 -0
- {wcgw-1.2.2 → wcgw-1.3.0}/src/wcgw/client/openai_utils.py +0 -0
- {wcgw-1.2.2 → wcgw-1.3.0}/src/wcgw/relay/static/privacy.txt +0 -0
- {wcgw-1.2.2 → wcgw-1.3.0}/static/ss1.png +0 -0
- {wcgw-1.2.2 → wcgw-1.3.0}/tests/test_basic.py +0 -0
- {wcgw-1.2.2 → wcgw-1.3.0}/tests/test_tools.py +0 -0
- {wcgw-1.2.2 → wcgw-1.3.0}/uv.lock +0 -0
|
@@ -249,6 +249,46 @@
|
|
|
249
249
|
}
|
|
250
250
|
}
|
|
251
251
|
}
|
|
252
|
+
},
|
|
253
|
+
"/v1/initialize": {
|
|
254
|
+
"post": {
|
|
255
|
+
"x-openai-isConsequential": false,
|
|
256
|
+
"summary": "Initialize",
|
|
257
|
+
"operationId": "initialize_v1_initialize_post",
|
|
258
|
+
"requestBody": {
|
|
259
|
+
"content": {
|
|
260
|
+
"application/json": {
|
|
261
|
+
"schema": {
|
|
262
|
+
"$ref": "#/components/schemas/InitializeWithUUID"
|
|
263
|
+
}
|
|
264
|
+
}
|
|
265
|
+
},
|
|
266
|
+
"required": true
|
|
267
|
+
},
|
|
268
|
+
"responses": {
|
|
269
|
+
"200": {
|
|
270
|
+
"description": "Successful Response",
|
|
271
|
+
"content": {
|
|
272
|
+
"application/json": {
|
|
273
|
+
"schema": {
|
|
274
|
+
"type": "string",
|
|
275
|
+
"title": "Response Initialize V1 Initialize Post"
|
|
276
|
+
}
|
|
277
|
+
}
|
|
278
|
+
}
|
|
279
|
+
},
|
|
280
|
+
"422": {
|
|
281
|
+
"description": "Validation Error",
|
|
282
|
+
"content": {
|
|
283
|
+
"application/json": {
|
|
284
|
+
"schema": {
|
|
285
|
+
"$ref": "#/components/schemas/HTTPValidationError"
|
|
286
|
+
}
|
|
287
|
+
}
|
|
288
|
+
}
|
|
289
|
+
}
|
|
290
|
+
}
|
|
291
|
+
}
|
|
252
292
|
}
|
|
253
293
|
},
|
|
254
294
|
"components": {
|
|
@@ -320,8 +360,8 @@
|
|
|
320
360
|
},
|
|
321
361
|
"type": "object",
|
|
322
362
|
"required": [
|
|
323
|
-
"
|
|
324
|
-
"
|
|
363
|
+
"type",
|
|
364
|
+
"user_id"
|
|
325
365
|
],
|
|
326
366
|
"title": "BashInteractionWithUUID"
|
|
327
367
|
},
|
|
@@ -405,6 +445,29 @@
|
|
|
405
445
|
"type": "object",
|
|
406
446
|
"title": "HTTPValidationError"
|
|
407
447
|
},
|
|
448
|
+
"InitializeWithUUID": {
|
|
449
|
+
"properties": {
|
|
450
|
+
"type": {
|
|
451
|
+
"type": "string",
|
|
452
|
+
"enum": [
|
|
453
|
+
"Initialize"
|
|
454
|
+
],
|
|
455
|
+
"const": "Initialize",
|
|
456
|
+
"title": "Type"
|
|
457
|
+
},
|
|
458
|
+
"user_id": {
|
|
459
|
+
"type": "string",
|
|
460
|
+
"format": "uuid",
|
|
461
|
+
"title": "User Id"
|
|
462
|
+
}
|
|
463
|
+
},
|
|
464
|
+
"type": "object",
|
|
465
|
+
"required": [
|
|
466
|
+
"type",
|
|
467
|
+
"user_id"
|
|
468
|
+
],
|
|
469
|
+
"title": "InitializeWithUUID"
|
|
470
|
+
},
|
|
408
471
|
"ReadFileWithUUID": {
|
|
409
472
|
"properties": {
|
|
410
473
|
"file_path": {
|
|
@@ -441,8 +504,7 @@
|
|
|
441
504
|
true
|
|
442
505
|
],
|
|
443
506
|
"const": true,
|
|
444
|
-
"title": "Should Reset"
|
|
445
|
-
"default": true
|
|
507
|
+
"title": "Should Reset"
|
|
446
508
|
},
|
|
447
509
|
"user_id": {
|
|
448
510
|
"type": "string",
|
|
@@ -452,8 +514,8 @@
|
|
|
452
514
|
},
|
|
453
515
|
"type": "object",
|
|
454
516
|
"required": [
|
|
455
|
-
"
|
|
456
|
-
"
|
|
517
|
+
"should_reset",
|
|
518
|
+
"user_id"
|
|
457
519
|
],
|
|
458
520
|
"title": "ResetShellWithUUID"
|
|
459
521
|
},
|
|
@@ -1,12 +1,14 @@
|
|
|
1
1
|
You're an expert software engineer with shell and code knowledge.
|
|
2
2
|
|
|
3
3
|
Instructions:
|
|
4
|
-
|
|
4
|
+
|
|
5
5
|
- You should use the provided bash execution, reading and writing file tools to complete objective.
|
|
6
6
|
- First understand about the project by getting the folder structure (ignoring .git, node_modules, venv, etc.)
|
|
7
7
|
- Always read relevant files before editing.
|
|
8
8
|
- Do not provide code snippets unless asked by the user, instead directly edit the code.
|
|
9
9
|
|
|
10
|
+
Instructions for `Initialize`:
|
|
11
|
+
- Always call this at the start of the conversation.
|
|
10
12
|
|
|
11
13
|
Instructions for `BashCommand`:
|
|
12
14
|
- Execute a bash command. This is stateful (beware with subsequent calls).
|
|
@@ -14,6 +16,7 @@ Instructions for `BashCommand`:
|
|
|
14
16
|
- Status of the command and the current working directory will always be returned at the end.
|
|
15
17
|
- Optionally `exit shell has restarted` is the output, in which case environment resets, you can run fresh commands.
|
|
16
18
|
- The first line might be `(...truncated)` if the output is too long.
|
|
19
|
+
- The control will return to you in 5 seconds regardless of the status. For heavy commands, keep checking status using BashInteraction till they are finished.
|
|
17
20
|
|
|
18
21
|
Instructions for `Read File`
|
|
19
22
|
- Read full content of a file.
|
|
@@ -80,7 +83,7 @@ def call_hello_renamed():
|
|
|
80
83
|
4. The lines to replace into the source code
|
|
81
84
|
5. The end of the replace block: >>>>>>> REPLACE
|
|
82
85
|
|
|
83
|
-
Every "<<<<<<< SEARCH" section must *EXACTLY MATCH* the existing file content, character for character, including all comments, docstrings, etc.
|
|
86
|
+
Every "<<<<<<< SEARCH" section must *EXACTLY MATCH* the existing file content, character for character, including all comments, docstrings, whitespaces etc.
|
|
84
87
|
|
|
85
88
|
*SEARCH/REPLACE* blocks will *only* replace the first match occurrence.
|
|
86
89
|
Including multiple unique *SEARCH/REPLACE* blocks if needed.
|
|
@@ -91,9 +94,12 @@ def call_hello_renamed():
|
|
|
91
94
|
Include just the changing lines, and a few surrounding lines if needed for uniqueness.
|
|
92
95
|
Do not include long runs of unchanging lines in *SEARCH/REPLACE* blocks.
|
|
93
96
|
|
|
97
|
+
Preserve leading spaces and indentations in both SEARCH and REPLACE blocks.
|
|
98
|
+
|
|
94
99
|
---
|
|
95
100
|
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.
|
|
96
101
|
|
|
97
102
|
Always write production ready, syntactically correct code.
|
|
98
103
|
---
|
|
99
|
-
Ask the user for the user_id `UUID` if they haven't provided in the first message.
|
|
104
|
+
- Ask the user for the user_id `UUID` if they haven't provided in the first message.
|
|
105
|
+
- Call "Initialize" as soon as you get the UUID.
|
|
@@ -165,6 +165,7 @@ def loop(
|
|
|
165
165
|
- Optionally `exit shell has restarted` is the output, in which case environment resets, you can run fresh commands.
|
|
166
166
|
- The first line might be `(...truncated)` if the output is too long.
|
|
167
167
|
- Always run `pwd` if you get any file or directory not found error to make sure you're not lost.
|
|
168
|
+
- The control will return to you in 5 seconds regardless of the status. For heavy commands, keep checking status using BashInteraction till they are finished.
|
|
168
169
|
""",
|
|
169
170
|
),
|
|
170
171
|
ToolParam(
|
|
@@ -193,7 +194,7 @@ def loop(
|
|
|
193
194
|
- Write content to a new file. Provide file path and content. Use this instead of BashCommand for writing new files.
|
|
194
195
|
- This doesn't create any directories, please create directories using `mkdir -p` BashCommand.
|
|
195
196
|
- Provide absolute file path only.
|
|
196
|
-
- For editing existing files, use FileEdit.
|
|
197
|
+
- For editing existing files, use FileEdit instead of this tool.
|
|
197
198
|
""",
|
|
198
199
|
),
|
|
199
200
|
ToolParam(
|
|
@@ -219,7 +220,7 @@ def loop(
|
|
|
219
220
|
uname_machine = os.uname().machine
|
|
220
221
|
|
|
221
222
|
system = f"""
|
|
222
|
-
You're
|
|
223
|
+
You're an expert software engineer with shell and code knowledge.
|
|
223
224
|
|
|
224
225
|
Instructions:
|
|
225
226
|
|
|
@@ -227,10 +228,11 @@ Instructions:
|
|
|
227
228
|
- First understand about the project by getting the folder structure (ignoring .git, node_modules, venv, etc.)
|
|
228
229
|
- Always read relevant files before editing.
|
|
229
230
|
- Do not provide code snippets unless asked by the user, instead directly edit the code.
|
|
230
|
-
|
|
231
|
+
|
|
231
232
|
System information:
|
|
232
233
|
- System: {uname_sysname}
|
|
233
234
|
- Machine: {uname_machine}
|
|
235
|
+
- Current directory: {os.getcwd()}
|
|
234
236
|
"""
|
|
235
237
|
|
|
236
238
|
with open(os.path.join(os.path.dirname(__file__), "diff-instructions.txt")) as f:
|
|
@@ -361,7 +363,7 @@ System information:
|
|
|
361
363
|
enc,
|
|
362
364
|
limit - cost,
|
|
363
365
|
loop,
|
|
364
|
-
max_tokens=
|
|
366
|
+
max_tokens=8000,
|
|
365
367
|
)
|
|
366
368
|
except Exception as e:
|
|
367
369
|
output_or_done = (
|
|
@@ -4,6 +4,7 @@ Instructions for editing files.
|
|
|
4
4
|
|
|
5
5
|
Only edit the files using the following SEARCH/REPLACE blocks.
|
|
6
6
|
```
|
|
7
|
+
file_edit_using_search_replace_blocks="""
|
|
7
8
|
<<<<<<< SEARCH
|
|
8
9
|
def hello():
|
|
9
10
|
"print a greeting"
|
|
@@ -32,6 +33,7 @@ def call_hello_renamed():
|
|
|
32
33
|
hello_renamed()
|
|
33
34
|
impl2()
|
|
34
35
|
>>>>>>> REPLACE
|
|
36
|
+
"""
|
|
35
37
|
```
|
|
36
38
|
|
|
37
39
|
# *SEARCH/REPLACE block* Rules:
|
|
@@ -43,7 +45,7 @@ Every *SEARCH/REPLACE block* must use this format:
|
|
|
43
45
|
4. The lines to replace into the source code
|
|
44
46
|
5. The end of the replace block: >>>>>>> REPLACE
|
|
45
47
|
|
|
46
|
-
Every "<<<<<<< SEARCH" section must *EXACTLY MATCH* the existing file content, character for character, including all comments, docstrings, etc.
|
|
48
|
+
Every "<<<<<<< SEARCH" section must *EXACTLY MATCH* the existing file content, character for character, including all comments, docstrings, whitespaces, etc.
|
|
47
49
|
|
|
48
50
|
*SEARCH/REPLACE* blocks will *only* replace the first match occurrence.
|
|
49
51
|
Including multiple unique *SEARCH/REPLACE* blocks if needed.
|
|
@@ -53,3 +55,5 @@ Keep *SEARCH/REPLACE* blocks concise.
|
|
|
53
55
|
Break large *SEARCH/REPLACE* blocks into a series of smaller blocks that each change a small portion of the file.
|
|
54
56
|
Include just the changing lines, and a few surrounding lines if needed for uniqueness.
|
|
55
57
|
Do not include long runs of unchanging lines in *SEARCH/REPLACE* blocks.
|
|
58
|
+
|
|
59
|
+
Preserve leading spaces and indentations in both SEARCH and REPLACE blocks.
|
|
@@ -148,8 +148,7 @@ def loop(
|
|
|
148
148
|
my_dir = os.path.dirname(__file__)
|
|
149
149
|
|
|
150
150
|
config = Config(
|
|
151
|
-
model=cast(
|
|
152
|
-
Models, os.getenv("OPENAI_MODEL", "gpt-4o-2024-08-06").lower()),
|
|
151
|
+
model=cast(Models, os.getenv("OPENAI_MODEL", "gpt-4o-2024-08-06").lower()),
|
|
153
152
|
cost_limit=0.1,
|
|
154
153
|
cost_unit="$",
|
|
155
154
|
cost_file={
|
|
@@ -177,6 +176,7 @@ def loop(
|
|
|
177
176
|
- Optionally `exit shell has restarted` is the output, in which case environment resets, you can run fresh commands.
|
|
178
177
|
- The first line might be `(...truncated)` if the output is too long.
|
|
179
178
|
- Always run `pwd` if you get any file or directory not found error to make sure you're not lost.
|
|
179
|
+
- The control will return to you in 5 seconds regardless of the status. For heavy commands, keep checking status using BashInteraction till they are finished.
|
|
180
180
|
""",
|
|
181
181
|
),
|
|
182
182
|
openai.pydantic_function_tool(
|
|
@@ -201,7 +201,7 @@ def loop(
|
|
|
201
201
|
- Write content to a new file. Provide file path and content. Use this instead of BashCommand for writing new files.
|
|
202
202
|
- This doesn't create any directories, please create directories using `mkdir -p` BashCommand.
|
|
203
203
|
- Provide absolute file path only.
|
|
204
|
-
- For editing existing files, use FileEdit.""",
|
|
204
|
+
- For editing existing files, use FileEdit instead of this tool.""",
|
|
205
205
|
),
|
|
206
206
|
openai.pydantic_function_tool(
|
|
207
207
|
FileEdit,
|
|
@@ -223,7 +223,7 @@ def loop(
|
|
|
223
223
|
uname_machine = os.uname().machine
|
|
224
224
|
|
|
225
225
|
system = f"""
|
|
226
|
-
You're
|
|
226
|
+
You're an expert software engineer with shell and code knowledge.
|
|
227
227
|
|
|
228
228
|
Instructions:
|
|
229
229
|
|
|
@@ -235,6 +235,7 @@ Instructions:
|
|
|
235
235
|
System information:
|
|
236
236
|
- System: {uname_sysname}
|
|
237
237
|
- Machine: {uname_machine}
|
|
238
|
+
- Current directory: {os.getcwd()}
|
|
238
239
|
|
|
239
240
|
"""
|
|
240
241
|
|
|
@@ -341,7 +342,7 @@ System information:
|
|
|
341
342
|
enc,
|
|
342
343
|
limit - cost,
|
|
343
344
|
loop,
|
|
344
|
-
max_tokens=
|
|
345
|
+
max_tokens=8000,
|
|
345
346
|
)
|
|
346
347
|
except Exception as e:
|
|
347
348
|
output_or_done = (
|
|
@@ -45,7 +45,7 @@ from openai.types.chat import (
|
|
|
45
45
|
ChatCompletionMessage,
|
|
46
46
|
ParsedChatCompletionMessage,
|
|
47
47
|
)
|
|
48
|
-
from nltk.metrics.distance import edit_distance
|
|
48
|
+
from nltk.metrics.distance import edit_distance # type: ignore[import-untyped]
|
|
49
49
|
|
|
50
50
|
from ..types_ import (
|
|
51
51
|
BashCommand,
|
|
@@ -53,6 +53,7 @@ from ..types_ import (
|
|
|
53
53
|
CreateFileNew,
|
|
54
54
|
FileEditFindReplace,
|
|
55
55
|
FileEdit,
|
|
56
|
+
Initialize,
|
|
56
57
|
ReadFile,
|
|
57
58
|
ReadImage,
|
|
58
59
|
ResetShell,
|
|
@@ -155,6 +156,16 @@ BASH_STATE: BASH_CLF_OUTPUT = "repl"
|
|
|
155
156
|
CWD = os.getcwd()
|
|
156
157
|
|
|
157
158
|
|
|
159
|
+
def initial_info() -> str:
|
|
160
|
+
uname_sysname = os.uname().sysname
|
|
161
|
+
uname_machine = os.uname().machine
|
|
162
|
+
return f"""
|
|
163
|
+
System: {uname_sysname}
|
|
164
|
+
Machine: {uname_machine}
|
|
165
|
+
Current working directory: {CWD}
|
|
166
|
+
"""
|
|
167
|
+
|
|
168
|
+
|
|
158
169
|
def reset_shell() -> str:
|
|
159
170
|
global SHELL, BASH_STATE, CWD
|
|
160
171
|
SHELL.close(True)
|
|
@@ -306,9 +317,7 @@ def execute_bash(
|
|
|
306
317
|
updated_repl_mode = update_repl_prompt(bash_arg.send_text)
|
|
307
318
|
if updated_repl_mode:
|
|
308
319
|
BASH_STATE = "repl"
|
|
309
|
-
response =
|
|
310
|
-
"Prompt updated, you can execute REPL lines using BashCommand now"
|
|
311
|
-
)
|
|
320
|
+
response = "Prompt updated, you can execute REPL lines using BashCommand now"
|
|
312
321
|
console.print(response)
|
|
313
322
|
return (
|
|
314
323
|
response,
|
|
@@ -334,7 +343,7 @@ def execute_bash(
|
|
|
334
343
|
tokens = enc.encode(text)
|
|
335
344
|
|
|
336
345
|
if max_tokens and len(tokens) >= max_tokens:
|
|
337
|
-
text = "...(truncated)\n" + enc.decode(tokens[-(max_tokens - 1):])
|
|
346
|
+
text = "...(truncated)\n" + enc.decode(tokens[-(max_tokens - 1) :])
|
|
338
347
|
|
|
339
348
|
if is_interrupt:
|
|
340
349
|
text = (
|
|
@@ -361,7 +370,7 @@ Otherwise, you may want to try Ctrl-c again or program specific exit interactive
|
|
|
361
370
|
|
|
362
371
|
tokens = enc.encode(output)
|
|
363
372
|
if max_tokens and len(tokens) >= max_tokens:
|
|
364
|
-
output = "...(truncated)\n" + enc.decode(tokens[-(max_tokens - 1):])
|
|
373
|
+
output = "...(truncated)\n" + enc.decode(tokens[-(max_tokens - 1) :])
|
|
365
374
|
|
|
366
375
|
try:
|
|
367
376
|
exit_status = get_status()
|
|
@@ -436,7 +445,7 @@ def read_image_from_shell(file_path: str) -> ImageData:
|
|
|
436
445
|
image_bytes = image_file.read()
|
|
437
446
|
image_b64 = base64.b64encode(image_bytes).decode("utf-8")
|
|
438
447
|
image_type = mimetypes.guess_type(file_path)[0]
|
|
439
|
-
return ImageData(media_type=image_type, data=image_b64)
|
|
448
|
+
return ImageData(media_type=image_type, data=image_b64) # type: ignore
|
|
440
449
|
|
|
441
450
|
|
|
442
451
|
def write_file(writefile: Writefile | CreateFileNew, error_on_exist: bool) -> str:
|
|
@@ -488,15 +497,21 @@ def find_least_edit_distance_substring(
|
|
|
488
497
|
edit_distance_sum = 0
|
|
489
498
|
for j in range(len(find_lines)):
|
|
490
499
|
if (i + j) < len(content_lines):
|
|
491
|
-
edit_distance_sum += edit_distance(
|
|
492
|
-
content_lines[i + j], find_lines[j])
|
|
500
|
+
edit_distance_sum += edit_distance(content_lines[i + j], find_lines[j])
|
|
493
501
|
else:
|
|
494
502
|
edit_distance_sum += len(find_lines[j])
|
|
495
503
|
if edit_distance_sum < min_edit_distance:
|
|
496
504
|
min_edit_distance = edit_distance_sum
|
|
497
505
|
orig_start_index = new_to_original_indices[i]
|
|
498
|
-
orig_end_index =
|
|
499
|
-
|
|
506
|
+
orig_end_index = (
|
|
507
|
+
new_to_original_indices.get(
|
|
508
|
+
i + len(find_lines) - 1, len(orig_content_lines) - 1
|
|
509
|
+
)
|
|
510
|
+
+ 1
|
|
511
|
+
)
|
|
512
|
+
min_edit_distance_lines = orig_content_lines[
|
|
513
|
+
orig_start_index:orig_end_index
|
|
514
|
+
]
|
|
500
515
|
return "\n".join(min_edit_distance_lines), min_edit_distance
|
|
501
516
|
|
|
502
517
|
|
|
@@ -525,7 +540,8 @@ def do_diff_edit(fedit: FileEdit) -> str:
|
|
|
525
540
|
|
|
526
541
|
if not os.path.isabs(fedit.file_path):
|
|
527
542
|
raise Exception(
|
|
528
|
-
f"Failure: file_path should be absolute path, current working directory is {CWD}"
|
|
543
|
+
f"Failure: file_path should be absolute path, current working directory is {CWD}"
|
|
544
|
+
)
|
|
529
545
|
else:
|
|
530
546
|
path_ = fedit.file_path
|
|
531
547
|
|
|
@@ -535,13 +551,16 @@ def do_diff_edit(fedit: FileEdit) -> str:
|
|
|
535
551
|
with open(path_) as f:
|
|
536
552
|
apply_diff_to = f.read()
|
|
537
553
|
|
|
554
|
+
fedit.file_edit_using_search_replace_blocks = (
|
|
555
|
+
fedit.file_edit_using_search_replace_blocks.strip()
|
|
556
|
+
)
|
|
538
557
|
lines = fedit.file_edit_using_search_replace_blocks.split("\n")
|
|
539
558
|
|
|
540
559
|
if not lines or not re.match(r"^<<<<<<+\s*SEARCH\s*$", lines[0]):
|
|
541
560
|
raise Exception(
|
|
542
561
|
"Error: first line should be `<<<<<< SEARCH` to start a search-replace block"
|
|
543
562
|
)
|
|
544
|
-
|
|
563
|
+
|
|
545
564
|
n_lines = len(lines)
|
|
546
565
|
i = 0
|
|
547
566
|
replacement_count = 0
|
|
@@ -561,15 +580,14 @@ def do_diff_edit(fedit: FileEdit) -> str:
|
|
|
561
580
|
|
|
562
581
|
for line in search_block:
|
|
563
582
|
console.log("> " + line)
|
|
564
|
-
console.log("
|
|
583
|
+
console.log("=======")
|
|
565
584
|
for line in replace_block:
|
|
566
585
|
console.log("< " + line)
|
|
567
|
-
|
|
586
|
+
console.log("\n\n\n\n")
|
|
568
587
|
search_block_ = "\n".join(search_block)
|
|
569
588
|
replace_block_ = "\n".join(replace_block)
|
|
570
589
|
|
|
571
|
-
apply_diff_to = edit_content(
|
|
572
|
-
apply_diff_to, search_block_, replace_block_)
|
|
590
|
+
apply_diff_to = edit_content(apply_diff_to, search_block_, replace_block_)
|
|
573
591
|
replacement_count += 1
|
|
574
592
|
else:
|
|
575
593
|
i += 1
|
|
@@ -588,7 +606,8 @@ def do_diff_edit(fedit: FileEdit) -> str:
|
|
|
588
606
|
def file_edit(fedit: FileEditFindReplace) -> str:
|
|
589
607
|
if not os.path.isabs(fedit.file_path):
|
|
590
608
|
raise Exception(
|
|
591
|
-
f"Failure: file_path should be absolute path, current working directory is {CWD}"
|
|
609
|
+
f"Failure: file_path should be absolute path, current working directory is {CWD}"
|
|
610
|
+
)
|
|
592
611
|
else:
|
|
593
612
|
path_ = fedit.file_path
|
|
594
613
|
|
|
@@ -598,17 +617,14 @@ def file_edit(fedit: FileEditFindReplace) -> str:
|
|
|
598
617
|
if not fedit.find_lines:
|
|
599
618
|
raise Exception("Error: `find_lines` cannot be empty")
|
|
600
619
|
|
|
601
|
-
out_string = "\n".join(
|
|
602
|
-
|
|
603
|
-
in_string = "\n".join(
|
|
604
|
-
"< " + line for line in fedit.replace_with_lines.split("\n"))
|
|
620
|
+
out_string = "\n".join("> " + line for line in fedit.find_lines.split("\n"))
|
|
621
|
+
in_string = "\n".join("< " + line for line in fedit.replace_with_lines.split("\n"))
|
|
605
622
|
console.log(f"Editing file: {path_}\n---\n{out_string}\n---\n{in_string}\n---")
|
|
606
623
|
try:
|
|
607
624
|
with open(path_) as f:
|
|
608
625
|
content = f.read()
|
|
609
626
|
|
|
610
|
-
content = edit_content(content, fedit.find_lines,
|
|
611
|
-
fedit.replace_with_lines)
|
|
627
|
+
content = edit_content(content, fedit.find_lines, fedit.replace_with_lines)
|
|
612
628
|
|
|
613
629
|
with open(path_, "w") as f:
|
|
614
630
|
f.write(content)
|
|
@@ -653,6 +669,7 @@ TOOLS = (
|
|
|
653
669
|
| DoneFlag
|
|
654
670
|
| ReadImage
|
|
655
671
|
| ReadFile
|
|
672
|
+
| Initialize
|
|
656
673
|
)
|
|
657
674
|
|
|
658
675
|
|
|
@@ -686,6 +703,8 @@ def which_tool_name(name: str) -> Type[TOOLS]:
|
|
|
686
703
|
return ReadImage
|
|
687
704
|
elif name == "ReadFile":
|
|
688
705
|
return ReadFile
|
|
706
|
+
elif name == "Initialize":
|
|
707
|
+
return Initialize
|
|
689
708
|
else:
|
|
690
709
|
raise ValueError(f"Unknown tool name: {name}")
|
|
691
710
|
|
|
@@ -703,6 +722,7 @@ def get_tool_output(
|
|
|
703
722
|
| AIAssistant
|
|
704
723
|
| DoneFlag
|
|
705
724
|
| ReadImage
|
|
725
|
+
| Initialize
|
|
706
726
|
| ReadFile,
|
|
707
727
|
enc: tiktoken.Encoding,
|
|
708
728
|
limit: float,
|
|
@@ -723,6 +743,7 @@ def get_tool_output(
|
|
|
723
743
|
| DoneFlag
|
|
724
744
|
| ReadImage
|
|
725
745
|
| ReadFile
|
|
746
|
+
| Initialize
|
|
726
747
|
](
|
|
727
748
|
Confirmation
|
|
728
749
|
| BashCommand
|
|
@@ -736,6 +757,7 @@ def get_tool_output(
|
|
|
736
757
|
| DoneFlag
|
|
737
758
|
| ReadImage
|
|
738
759
|
| ReadFile
|
|
760
|
+
| Initialize
|
|
739
761
|
)
|
|
740
762
|
arg = adapter.validate_python(args)
|
|
741
763
|
else:
|
|
@@ -770,10 +792,13 @@ def get_tool_output(
|
|
|
770
792
|
output = read_image_from_shell(arg.file_path), 0.0
|
|
771
793
|
elif isinstance(arg, ReadFile):
|
|
772
794
|
console.print("Calling read file tool")
|
|
773
|
-
output = read_file(arg), 0.0
|
|
795
|
+
output = read_file(arg, max_tokens), 0.0
|
|
774
796
|
elif isinstance(arg, ResetShell):
|
|
775
797
|
console.print("Calling reset shell tool")
|
|
776
798
|
output = reset_shell(), 0.0
|
|
799
|
+
elif isinstance(arg, Initialize):
|
|
800
|
+
console.print("Calling initial info tool")
|
|
801
|
+
output = initial_info(), 0.0
|
|
777
802
|
else:
|
|
778
803
|
raise ValueError(f"Unknown tool: {arg}")
|
|
779
804
|
|
|
@@ -785,8 +810,7 @@ History = list[ChatCompletionMessageParam]
|
|
|
785
810
|
|
|
786
811
|
default_enc = tiktoken.encoding_for_model("gpt-4o")
|
|
787
812
|
default_model: Models = "gpt-4o-2024-08-06"
|
|
788
|
-
default_cost = CostData(cost_per_1m_input_tokens=0.15,
|
|
789
|
-
cost_per_1m_output_tokens=0.6)
|
|
813
|
+
default_cost = CostData(cost_per_1m_input_tokens=0.15, cost_per_1m_output_tokens=0.6)
|
|
790
814
|
curr_cost = 0.0
|
|
791
815
|
|
|
792
816
|
|
|
@@ -801,6 +825,7 @@ class Mdata(BaseModel):
|
|
|
801
825
|
| FileEdit
|
|
802
826
|
| str
|
|
803
827
|
| ReadFile
|
|
828
|
+
| Initialize
|
|
804
829
|
)
|
|
805
830
|
|
|
806
831
|
|
|
@@ -829,8 +854,7 @@ def register_client(server_url: str, client_uuid: str = "") -> None:
|
|
|
829
854
|
raise Exception(mdata)
|
|
830
855
|
try:
|
|
831
856
|
output, cost = get_tool_output(
|
|
832
|
-
mdata.data, default_enc, 0.0, lambda x, y: (
|
|
833
|
-
"", 0), None
|
|
857
|
+
mdata.data, default_enc, 0.0, lambda x, y: ("", 0), 8000
|
|
834
858
|
)
|
|
835
859
|
curr_cost += cost
|
|
836
860
|
print(f"{curr_cost=}")
|
|
@@ -863,8 +887,7 @@ def app(
|
|
|
863
887
|
register_client(server_url, client_uuid or "")
|
|
864
888
|
|
|
865
889
|
|
|
866
|
-
def read_file(readfile: ReadFile) -> str:
|
|
867
|
-
|
|
890
|
+
def read_file(readfile: ReadFile, max_tokens: Optional[int]) -> str:
|
|
868
891
|
console.print(f"Reading file: {readfile.file_path}")
|
|
869
892
|
|
|
870
893
|
if not os.path.isabs(readfile.file_path):
|
|
@@ -876,4 +899,11 @@ def read_file(readfile: ReadFile) -> str:
|
|
|
876
899
|
|
|
877
900
|
with path.open("r") as f:
|
|
878
901
|
content = f.read()
|
|
902
|
+
|
|
903
|
+
if max_tokens is not None:
|
|
904
|
+
tokens = default_enc.encode(content)
|
|
905
|
+
if len(tokens) > max_tokens:
|
|
906
|
+
content = default_enc.decode(tokens[: max_tokens - 5])
|
|
907
|
+
content += "\n...(truncated)"
|
|
908
|
+
|
|
879
909
|
return content
|
|
@@ -20,6 +20,7 @@ from ..types_ import (
|
|
|
20
20
|
CreateFileNew,
|
|
21
21
|
FileEditFindReplace,
|
|
22
22
|
FileEdit,
|
|
23
|
+
Initialize,
|
|
23
24
|
ReadFile,
|
|
24
25
|
ResetShell,
|
|
25
26
|
Writefile,
|
|
@@ -37,6 +38,7 @@ class Mdata(BaseModel):
|
|
|
37
38
|
| FileEditFindReplace
|
|
38
39
|
| FileEdit
|
|
39
40
|
| ReadFile
|
|
41
|
+
| Initialize
|
|
40
42
|
| str
|
|
41
43
|
)
|
|
42
44
|
user_id: UUID
|
|
@@ -51,7 +53,7 @@ gpts: dict[UUID, Callable[[str], None]] = {}
|
|
|
51
53
|
images: DefaultDict[UUID, dict[str, dict[str, Any]]] = DefaultDict(dict)
|
|
52
54
|
|
|
53
55
|
|
|
54
|
-
CLIENT_VERSION_MINIMUM = "1.
|
|
56
|
+
CLIENT_VERSION_MINIMUM = "1.3.0"
|
|
55
57
|
|
|
56
58
|
|
|
57
59
|
@app.websocket("/v1/register/{uuid}")
|
|
@@ -71,8 +73,7 @@ async def register_websocket(websocket: WebSocket, uuid: UUID) -> None:
|
|
|
71
73
|
await websocket.send_text(
|
|
72
74
|
Mdata(
|
|
73
75
|
user_id=uuid,
|
|
74
|
-
data=f"Client version {client_version} is outdated. Please upgrade to {
|
|
75
|
-
CLIENT_VERSION_MINIMUM} or higher.",
|
|
76
|
+
data=f"Client version {client_version} is outdated. Please upgrade to {CLIENT_VERSION_MINIMUM} or higher.",
|
|
76
77
|
).model_dump_json()
|
|
77
78
|
)
|
|
78
79
|
await websocket.close(
|
|
@@ -281,9 +282,37 @@ async def read_file_endpoint(read_file_data: ReadFileWithUUID) -> str:
|
|
|
281
282
|
gpts[user_id] = put_results
|
|
282
283
|
|
|
283
284
|
await clients[user_id](
|
|
284
|
-
Mdata(data=
|
|
285
|
-
|
|
286
|
-
|
|
285
|
+
Mdata(data=read_file_data, user_id=user_id)
|
|
286
|
+
)
|
|
287
|
+
|
|
288
|
+
start_time = time.time()
|
|
289
|
+
while time.time() - start_time < 30:
|
|
290
|
+
if results is not None:
|
|
291
|
+
return results
|
|
292
|
+
await asyncio.sleep(0.1)
|
|
293
|
+
|
|
294
|
+
raise fastapi.HTTPException(status_code=500, detail="Timeout error")
|
|
295
|
+
|
|
296
|
+
class InitializeWithUUID(Initialize):
|
|
297
|
+
user_id: UUID
|
|
298
|
+
|
|
299
|
+
|
|
300
|
+
@app.post("/v1/initialize")
|
|
301
|
+
async def initialize(initialize_data: InitializeWithUUID) -> str:
|
|
302
|
+
user_id = initialize_data.user_id
|
|
303
|
+
if user_id not in clients:
|
|
304
|
+
return "Failure: id not found, ask the user to check it."
|
|
305
|
+
|
|
306
|
+
results: Optional[str] = None
|
|
307
|
+
|
|
308
|
+
def put_results(result: str) -> None:
|
|
309
|
+
nonlocal results
|
|
310
|
+
results = result
|
|
311
|
+
|
|
312
|
+
gpts[user_id] = put_results
|
|
313
|
+
|
|
314
|
+
await clients[user_id](
|
|
315
|
+
Mdata(data=initialize_data, user_id=user_id)
|
|
287
316
|
)
|
|
288
317
|
|
|
289
318
|
start_time = time.time()
|
|
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
|
|
File without changes
|