wcgw 2.2.0__tar.gz → 2.2.2__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-2.2.0 → wcgw-2.2.2}/PKG-INFO +2 -2
- {wcgw-2.2.0 → wcgw-2.2.2}/gpt_instructions.txt +1 -1
- {wcgw-2.2.0 → wcgw-2.2.2}/pyproject.toml +1 -1
- {wcgw-2.2.0 → wcgw-2.2.2}/src/wcgw/client/anthropic_client.py +3 -2
- {wcgw-2.2.0 → wcgw-2.2.2}/src/wcgw/client/mcp_server/server.py +3 -1
- {wcgw-2.2.0 → wcgw-2.2.2}/src/wcgw/client/openai_client.py +1 -1
- {wcgw-2.2.0 → wcgw-2.2.2}/src/wcgw/client/tools.py +55 -63
- {wcgw-2.2.0 → wcgw-2.2.2}/uv.lock +1 -1
- {wcgw-2.2.0 → wcgw-2.2.2}/.github/workflows/python-publish.yml +0 -0
- {wcgw-2.2.0 → wcgw-2.2.2}/.github/workflows/python-tests.yml +0 -0
- {wcgw-2.2.0 → wcgw-2.2.2}/.github/workflows/python-types.yml +0 -0
- {wcgw-2.2.0 → wcgw-2.2.2}/.gitignore +0 -0
- {wcgw-2.2.0 → wcgw-2.2.2}/.python-version +0 -0
- {wcgw-2.2.0 → wcgw-2.2.2}/.vscode/settings.json +0 -0
- {wcgw-2.2.0 → wcgw-2.2.2}/README.md +0 -0
- {wcgw-2.2.0 → wcgw-2.2.2}/gpt_action_json_schema.json +0 -0
- {wcgw-2.2.0 → wcgw-2.2.2}/openai.md +0 -0
- {wcgw-2.2.0 → wcgw-2.2.2}/src/__init__.py +0 -0
- {wcgw-2.2.0 → wcgw-2.2.2}/src/wcgw/__init__.py +0 -0
- {wcgw-2.2.0 → wcgw-2.2.2}/src/wcgw/client/__init__.py +0 -0
- {wcgw-2.2.0 → wcgw-2.2.2}/src/wcgw/client/__main__.py +0 -0
- {wcgw-2.2.0 → wcgw-2.2.2}/src/wcgw/client/cli.py +0 -0
- {wcgw-2.2.0 → wcgw-2.2.2}/src/wcgw/client/common.py +0 -0
- {wcgw-2.2.0 → wcgw-2.2.2}/src/wcgw/client/computer_use.py +0 -0
- {wcgw-2.2.0 → wcgw-2.2.2}/src/wcgw/client/diff-instructions.txt +0 -0
- {wcgw-2.2.0 → wcgw-2.2.2}/src/wcgw/client/mcp_server/Readme.md +0 -0
- {wcgw-2.2.0 → wcgw-2.2.2}/src/wcgw/client/mcp_server/__init__.py +0 -0
- {wcgw-2.2.0 → wcgw-2.2.2}/src/wcgw/client/openai_utils.py +0 -0
- {wcgw-2.2.0 → wcgw-2.2.2}/src/wcgw/client/sys_utils.py +0 -0
- {wcgw-2.2.0 → wcgw-2.2.2}/src/wcgw/relay/serve.py +0 -0
- {wcgw-2.2.0 → wcgw-2.2.2}/src/wcgw/relay/static/privacy.txt +0 -0
- {wcgw-2.2.0 → wcgw-2.2.2}/src/wcgw/types_.py +0 -0
- {wcgw-2.2.0 → wcgw-2.2.2}/static/claude-ss.jpg +0 -0
- {wcgw-2.2.0 → wcgw-2.2.2}/static/computer-use.jpg +0 -0
- {wcgw-2.2.0 → wcgw-2.2.2}/static/example.jpg +0 -0
- {wcgw-2.2.0 → wcgw-2.2.2}/static/rocket-icon.png +0 -0
- {wcgw-2.2.0 → wcgw-2.2.2}/static/ss1.png +0 -0
- {wcgw-2.2.0 → wcgw-2.2.2}/tests/test_basic.py +0 -0
- {wcgw-2.2.0 → wcgw-2.2.2}/tests/test_tools.py +0 -0
|
@@ -16,7 +16,7 @@ Instructions for `BashCommand`:
|
|
|
16
16
|
- Do not use interactive commands like nano. Prefer writing simpler commands.
|
|
17
17
|
- Status of the command and the current working directory will always be returned at the end.
|
|
18
18
|
- Optionally `exit shell has restarted` is the output, in which case environment resets, you can run fresh commands.
|
|
19
|
-
- The first line might be `(...truncated)` if the output is too long.
|
|
19
|
+
- The first or the last line might be `(...truncated)` if the output is too long.
|
|
20
20
|
- 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.
|
|
21
21
|
- Run long running commands in background using screen instead of "&".
|
|
22
22
|
|
|
@@ -169,7 +169,7 @@ def loop(
|
|
|
169
169
|
- Do not use interactive commands like nano. Prefer writing simpler commands.
|
|
170
170
|
- Status of the command and the current working directory will always be returned at the end.
|
|
171
171
|
- Optionally `exit shell has restarted` is the output, in which case environment resets, you can run fresh commands.
|
|
172
|
-
- The first line might be `(...truncated)` if the output is too long.
|
|
172
|
+
- The first or the last line might be `(...truncated)` if the output is too long.
|
|
173
173
|
- Always run `pwd` if you get any file or directory not found error to make sure you're not lost.
|
|
174
174
|
- 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.
|
|
175
175
|
- Run long running commands in background using screen instead of "&".
|
|
@@ -186,7 +186,7 @@ def loop(
|
|
|
186
186
|
- Only one of send_text, send_specials, send_ascii should be provided.
|
|
187
187
|
- This returns within 5 seconds, for heavy programs keep checking status for upto 10 turns before asking user to continue checking again.
|
|
188
188
|
- Programs don't hang easily, so most likely explanation for no output is usually that the program is still running, and you need to check status again using ["Enter"].
|
|
189
|
-
|
|
189
|
+
- Do not send Ctrl-c before checking for status till 10 minutes or whatever is appropriate for the program to finish.
|
|
190
190
|
""",
|
|
191
191
|
),
|
|
192
192
|
ToolParam(
|
|
@@ -222,6 +222,7 @@ def loop(
|
|
|
222
222
|
description="""
|
|
223
223
|
- Use absolute file path only.
|
|
224
224
|
- Use SEARCH/REPLACE blocks to edit the file.
|
|
225
|
+
- If the edit fails due to block not matching, please retry with correct block till it matches. Re-read the file to ensure you've all the lines correct.
|
|
225
226
|
""",
|
|
226
227
|
),
|
|
227
228
|
]
|
|
@@ -89,7 +89,7 @@ async def handle_list_tools() -> list[types.Tool]:
|
|
|
89
89
|
- Do not use interactive commands like nano. Prefer writing simpler commands.
|
|
90
90
|
- Status of the command and the current working directory will always be returned at the end.
|
|
91
91
|
- Optionally `exit shell has restarted` is the output, in which case environment resets, you can run fresh commands.
|
|
92
|
-
- The first line might be `(...truncated)` if the output is too long.
|
|
92
|
+
- The first or the last line might be `(...truncated)` if the output is too long.
|
|
93
93
|
- Always run `pwd` if you get any file or directory not found error to make sure you're not lost.
|
|
94
94
|
- 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.
|
|
95
95
|
- Run long running commands in background using screen instead of "&".
|
|
@@ -106,6 +106,7 @@ async def handle_list_tools() -> list[types.Tool]:
|
|
|
106
106
|
- Only one of send_text, send_specials, send_ascii should be provided.
|
|
107
107
|
- This returns within 3 seconds, for heavy programs keep checking status for upto 10 turns before asking user to continue checking again.
|
|
108
108
|
- Programs don't hang easily, so most likely explanation for no output is usually that the program is still running, and you need to check status again using ["Enter"].
|
|
109
|
+
- Do not send Ctrl-c before checking for status till 10 minutes or whatever is appropriate for the program to finish.
|
|
109
110
|
""",
|
|
110
111
|
),
|
|
111
112
|
ToolParam(
|
|
@@ -141,6 +142,7 @@ async def handle_list_tools() -> list[types.Tool]:
|
|
|
141
142
|
description="""
|
|
142
143
|
- Use absolute file path only.
|
|
143
144
|
- Use SEARCH/REPLACE blocks to edit the file.
|
|
145
|
+
- If the edit fails due to block not matching, please retry with correct block till it matches. Re-read the file to ensure you've all the lines correct.
|
|
144
146
|
"""
|
|
145
147
|
+ diffinstructions,
|
|
146
148
|
),
|
|
@@ -172,7 +172,7 @@ def loop(
|
|
|
172
172
|
- Do not use interactive commands like nano. Prefer writing simpler commands.
|
|
173
173
|
- Status of the command and the current working directory will always be returned at the end.
|
|
174
174
|
- Optionally `exit shell has restarted` is the output, in which case environment resets, you can run fresh commands.
|
|
175
|
-
- The first line might be `(...truncated)` if the output is too long.
|
|
175
|
+
- The first or the last line might be `(...truncated)` if the output is too long.
|
|
176
176
|
- Always run `pwd` if you get any file or directory not found error to make sure you're not lost.
|
|
177
177
|
- 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.
|
|
178
178
|
- Run long running commands in background using screen instead of "&".
|
|
@@ -13,7 +13,7 @@ import threading
|
|
|
13
13
|
import importlib.metadata
|
|
14
14
|
import time
|
|
15
15
|
import traceback
|
|
16
|
-
from tempfile import TemporaryDirectory
|
|
16
|
+
from tempfile import NamedTemporaryFile, TemporaryDirectory
|
|
17
17
|
from typing import (
|
|
18
18
|
Callable,
|
|
19
19
|
Literal,
|
|
@@ -412,7 +412,7 @@ def execute_bash(
|
|
|
412
412
|
tokens = enc.encode(text)
|
|
413
413
|
|
|
414
414
|
if max_tokens and len(tokens) >= max_tokens:
|
|
415
|
-
text = "...
|
|
415
|
+
text = "(...truncated)\n" + enc.decode(tokens[-(max_tokens - 1) :])
|
|
416
416
|
|
|
417
417
|
if is_interrupt:
|
|
418
418
|
text = (
|
|
@@ -441,7 +441,7 @@ Otherwise, you may want to try Ctrl-c again or program specific exit interactive
|
|
|
441
441
|
|
|
442
442
|
tokens = enc.encode(output)
|
|
443
443
|
if max_tokens and len(tokens) >= max_tokens:
|
|
444
|
-
output = "...
|
|
444
|
+
output = "(...truncated)\n" + enc.decode(tokens[-(max_tokens - 1) :])
|
|
445
445
|
|
|
446
446
|
try:
|
|
447
447
|
exit_status = get_status()
|
|
@@ -537,6 +537,15 @@ def write_file(writefile: WriteIfEmpty, error_on_exist: bool) -> str:
|
|
|
537
537
|
else:
|
|
538
538
|
path_ = writefile.file_path
|
|
539
539
|
|
|
540
|
+
error_on_exist = (
|
|
541
|
+
not (
|
|
542
|
+
len(TOOL_CALLS) > 1
|
|
543
|
+
and isinstance(TOOL_CALLS[-2], FileEdit)
|
|
544
|
+
and TOOL_CALLS[-2].file_path == path_
|
|
545
|
+
)
|
|
546
|
+
and error_on_exist
|
|
547
|
+
)
|
|
548
|
+
|
|
540
549
|
if not BASH_STATE.is_in_docker:
|
|
541
550
|
if error_on_exist and os.path.exists(path_):
|
|
542
551
|
file_data = Path(path_).read_text()
|
|
@@ -583,7 +592,7 @@ def write_file(writefile: WriteIfEmpty, error_on_exist: bool) -> str:
|
|
|
583
592
|
|
|
584
593
|
def find_least_edit_distance_substring(
|
|
585
594
|
content: str, find_str: str
|
|
586
|
-
) -> tuple[str, float]:
|
|
595
|
+
) -> tuple[str, str, float]:
|
|
587
596
|
orig_content_lines = content.split("\n")
|
|
588
597
|
content_lines = [
|
|
589
598
|
line.strip() for line in orig_content_lines
|
|
@@ -598,11 +607,12 @@ def find_least_edit_distance_substring(
|
|
|
598
607
|
content_lines = new_content_lines
|
|
599
608
|
find_lines = find_str.split("\n")
|
|
600
609
|
find_lines = [
|
|
601
|
-
line.strip() for line in find_lines
|
|
610
|
+
line.strip() for line in find_lines if line.strip()
|
|
602
611
|
] # Remove trailing and leading space for calculating edit distance
|
|
603
612
|
# Slide window and find one with sum of edit distance least
|
|
604
613
|
min_edit_distance = float("inf")
|
|
605
614
|
min_edit_distance_lines = []
|
|
615
|
+
context_lines = []
|
|
606
616
|
for i in range(max(1, len(content_lines) - len(find_lines) + 1)):
|
|
607
617
|
edit_distance_sum = 0
|
|
608
618
|
for j in range(len(find_lines)):
|
|
@@ -620,19 +630,27 @@ def find_least_edit_distance_substring(
|
|
|
620
630
|
+ 1
|
|
621
631
|
)
|
|
622
632
|
min_edit_distance_lines = orig_content_lines[
|
|
633
|
+
orig_start_index:orig_end_index
|
|
634
|
+
]
|
|
635
|
+
|
|
636
|
+
context_lines = orig_content_lines[
|
|
623
637
|
max(0, orig_start_index - 10) : (orig_end_index + 10)
|
|
624
638
|
]
|
|
625
|
-
return
|
|
639
|
+
return (
|
|
640
|
+
"\n".join(min_edit_distance_lines),
|
|
641
|
+
"\n".join(context_lines),
|
|
642
|
+
min_edit_distance,
|
|
643
|
+
)
|
|
626
644
|
|
|
627
645
|
|
|
628
646
|
def edit_content(content: str, find_lines: str, replace_with_lines: str) -> str:
|
|
629
647
|
count = content.count(find_lines)
|
|
630
648
|
if count == 0:
|
|
631
|
-
closest_match, min_edit_distance =
|
|
632
|
-
content, find_lines
|
|
649
|
+
closest_match, context_lines, min_edit_distance = (
|
|
650
|
+
find_least_edit_distance_substring(content, find_lines)
|
|
633
651
|
)
|
|
634
652
|
if min_edit_distance == 0:
|
|
635
|
-
return
|
|
653
|
+
return content.replace(closest_match, replace_with_lines, 1)
|
|
636
654
|
else:
|
|
637
655
|
print(
|
|
638
656
|
f"Exact match not found, found with whitespace removed edit distance: {min_edit_distance}"
|
|
@@ -640,7 +658,9 @@ def edit_content(content: str, find_lines: str, replace_with_lines: str) -> str:
|
|
|
640
658
|
raise Exception(
|
|
641
659
|
f"""Error: no match found for the provided search block.
|
|
642
660
|
Requested search block: \n```\n{find_lines}\n```
|
|
643
|
-
Possible relevant section in the file:\n---\n```\n{
|
|
661
|
+
Possible relevant section in the file:\n---\n```\n{context_lines}\n```\n---\nFile not edited
|
|
662
|
+
\nPlease retry with exact search. Re-read the file if unsure.
|
|
663
|
+
"""
|
|
644
664
|
)
|
|
645
665
|
|
|
646
666
|
content = content.replace(find_lines, replace_with_lines, 1)
|
|
@@ -648,6 +668,24 @@ def edit_content(content: str, find_lines: str, replace_with_lines: str) -> str:
|
|
|
648
668
|
|
|
649
669
|
|
|
650
670
|
def do_diff_edit(fedit: FileEdit) -> str:
|
|
671
|
+
try:
|
|
672
|
+
return _do_diff_edit(fedit)
|
|
673
|
+
except Exception as e:
|
|
674
|
+
# Try replacing \"
|
|
675
|
+
try:
|
|
676
|
+
fedit = FileEdit(
|
|
677
|
+
file_path=fedit.file_path,
|
|
678
|
+
file_edit_using_search_replace_blocks=fedit.file_edit_using_search_replace_blocks.replace(
|
|
679
|
+
'\\"', '"'
|
|
680
|
+
),
|
|
681
|
+
)
|
|
682
|
+
return _do_diff_edit(fedit)
|
|
683
|
+
except Exception:
|
|
684
|
+
pass
|
|
685
|
+
raise e
|
|
686
|
+
|
|
687
|
+
|
|
688
|
+
def _do_diff_edit(fedit: FileEdit) -> str:
|
|
651
689
|
console.log(f"Editing file: {fedit.file_path}")
|
|
652
690
|
|
|
653
691
|
if not os.path.isabs(fedit.file_path):
|
|
@@ -824,70 +862,24 @@ def which_tool_name(name: str) -> Type[TOOLS]:
|
|
|
824
862
|
raise ValueError(f"Unknown tool name: {name}")
|
|
825
863
|
|
|
826
864
|
|
|
865
|
+
TOOL_CALLS: list[TOOLS] = []
|
|
866
|
+
|
|
867
|
+
|
|
827
868
|
def get_tool_output(
|
|
828
|
-
args: dict[object, object]
|
|
829
|
-
| Confirmation
|
|
830
|
-
| BashCommand
|
|
831
|
-
| BashInteraction
|
|
832
|
-
| ResetShell
|
|
833
|
-
| WriteIfEmpty
|
|
834
|
-
| FileEditFindReplace
|
|
835
|
-
| FileEdit
|
|
836
|
-
| AIAssistant
|
|
837
|
-
| DoneFlag
|
|
838
|
-
| ReadImage
|
|
839
|
-
| Initialize
|
|
840
|
-
| ReadFile
|
|
841
|
-
| Mouse
|
|
842
|
-
| Keyboard
|
|
843
|
-
| ScreenShot
|
|
844
|
-
| GetScreenInfo,
|
|
869
|
+
args: dict[object, object] | TOOLS,
|
|
845
870
|
enc: tiktoken.Encoding,
|
|
846
871
|
limit: float,
|
|
847
872
|
loop_call: Callable[[str, float], tuple[str, float]],
|
|
848
873
|
max_tokens: Optional[int],
|
|
849
874
|
) -> tuple[list[str | ImageData | DoneFlag], float]:
|
|
850
|
-
global IS_IN_DOCKER
|
|
875
|
+
global IS_IN_DOCKER, TOOL_CALLS
|
|
851
876
|
if isinstance(args, dict):
|
|
852
|
-
adapter = TypeAdapter[
|
|
853
|
-
Confirmation
|
|
854
|
-
| BashCommand
|
|
855
|
-
| BashInteraction
|
|
856
|
-
| ResetShell
|
|
857
|
-
| WriteIfEmpty
|
|
858
|
-
| FileEditFindReplace
|
|
859
|
-
| FileEdit
|
|
860
|
-
| AIAssistant
|
|
861
|
-
| DoneFlag
|
|
862
|
-
| ReadImage
|
|
863
|
-
| ReadFile
|
|
864
|
-
| Initialize
|
|
865
|
-
| Mouse
|
|
866
|
-
| Keyboard
|
|
867
|
-
| ScreenShot
|
|
868
|
-
| GetScreenInfo,
|
|
869
|
-
](
|
|
870
|
-
Confirmation
|
|
871
|
-
| BashCommand
|
|
872
|
-
| BashInteraction
|
|
873
|
-
| ResetShell
|
|
874
|
-
| WriteIfEmpty
|
|
875
|
-
| FileEditFindReplace
|
|
876
|
-
| FileEdit
|
|
877
|
-
| AIAssistant
|
|
878
|
-
| DoneFlag
|
|
879
|
-
| ReadImage
|
|
880
|
-
| ReadFile
|
|
881
|
-
| Initialize
|
|
882
|
-
| Mouse
|
|
883
|
-
| Keyboard
|
|
884
|
-
| ScreenShot
|
|
885
|
-
| GetScreenInfo
|
|
886
|
-
)
|
|
877
|
+
adapter = TypeAdapter[TOOLS](TOOLS)
|
|
887
878
|
arg = adapter.validate_python(args)
|
|
888
879
|
else:
|
|
889
880
|
arg = args
|
|
890
881
|
output: tuple[str | DoneFlag | ImageData, float]
|
|
882
|
+
TOOL_CALLS.append(arg)
|
|
891
883
|
if isinstance(arg, Confirmation):
|
|
892
884
|
console.print("Calling ask confirmation tool")
|
|
893
885
|
output = ask_confirmation(arg), 0.0
|
|
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
|
|
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
|