wcgw 1.5.0__py3-none-any.whl → 1.5.1__py3-none-any.whl
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/client/computer_use.py +0 -1
- wcgw/client/mcp_server/Readme.md +13 -14
- wcgw/client/mcp_server/server.py +4 -2
- wcgw/client/sys_utils.py +2 -1
- wcgw/client/tools.py +11 -11
- {wcgw-1.5.0.dist-info → wcgw-1.5.1.dist-info}/METADATA +2 -2
- {wcgw-1.5.0.dist-info → wcgw-1.5.1.dist-info}/RECORD +9 -9
- {wcgw-1.5.0.dist-info → wcgw-1.5.1.dist-info}/WHEEL +0 -0
- {wcgw-1.5.0.dist-info → wcgw-1.5.1.dist-info}/entry_points.txt +0 -0
wcgw/client/computer_use.py
CHANGED
|
@@ -26,7 +26,6 @@ from ..types_ import (
|
|
|
26
26
|
OUTPUT_DIR = "/tmp/outputs"
|
|
27
27
|
TYPING_DELAY_MS = 12
|
|
28
28
|
TYPING_GROUP_SIZE = 50
|
|
29
|
-
TRUNCATED_MESSAGE: str = "<response clipped><NOTE>To save on context only part of this file has been shown to you.</NOTE>"
|
|
30
29
|
|
|
31
30
|
Action = Literal[
|
|
32
31
|
"key",
|
wcgw/client/mcp_server/Readme.md
CHANGED
|
@@ -2,23 +2,22 @@
|
|
|
2
2
|
|
|
3
3
|
## Setup
|
|
4
4
|
|
|
5
|
-
Install xdtool
|
|
6
|
-
|
|
7
|
-
```sh
|
|
8
|
-
brew install xdotool
|
|
9
|
-
|
|
10
|
-
# On macos:
|
|
11
|
-
defaults write org.x.X11 enable_test_extensions -boolean true
|
|
12
|
-
```
|
|
13
|
-
|
|
14
5
|
Update `claude_desktop_config.json` (~/Library/Application Support/Claude/claude_desktop_config.json)
|
|
15
6
|
|
|
16
7
|
```json
|
|
17
8
|
{
|
|
18
9
|
"mcpServers": {
|
|
19
10
|
"wcgw": {
|
|
20
|
-
"command": "
|
|
21
|
-
"args": [
|
|
11
|
+
"command": "uv",
|
|
12
|
+
"args": [
|
|
13
|
+
"tool",
|
|
14
|
+
"run",
|
|
15
|
+
"--from",
|
|
16
|
+
"wcgw@latest",
|
|
17
|
+
"--python",
|
|
18
|
+
"3.12",
|
|
19
|
+
"wcgw_mcp"
|
|
20
|
+
]
|
|
22
21
|
}
|
|
23
22
|
}
|
|
24
23
|
}
|
|
@@ -26,9 +25,9 @@ Update `claude_desktop_config.json` (~/Library/Application Support/Claude/claude
|
|
|
26
25
|
|
|
27
26
|
Then restart claude app.
|
|
28
27
|
|
|
29
|
-
### Computer use support using desktop on docker
|
|
28
|
+
### [Optional] Computer use support using desktop on docker
|
|
30
29
|
|
|
31
|
-
|
|
30
|
+
Computer use is enabled by default. Claude will be able to connect to any docker container with linux environment. Native system control isn't supported outside docker.
|
|
32
31
|
|
|
33
32
|
First run a sample docker image with desktop and optionally VNC connection:
|
|
34
33
|
|
|
@@ -47,7 +46,7 @@ docker run \
|
|
|
47
46
|
tail -f /dev/null"
|
|
48
47
|
```
|
|
49
48
|
|
|
50
|
-
Connect to `http://localhost:6080/vnc.html` for desktop view (VNC) of the system running in the docker.
|
|
49
|
+
Connect to `http://localhost:6080/vnc.html` for desktop view (VNC) of the system running in the docker. Then ask claude to control the docker os.
|
|
51
50
|
|
|
52
51
|
## Usage
|
|
53
52
|
|
wcgw/client/mcp_server/server.py
CHANGED
|
@@ -10,8 +10,9 @@ from mcp.server.models import InitializationOptions
|
|
|
10
10
|
import mcp.types as types
|
|
11
11
|
from mcp.types import Tool as ToolParam
|
|
12
12
|
from mcp.server import NotificationOptions, Server
|
|
13
|
-
from pydantic import AnyUrl, ValidationError
|
|
13
|
+
from pydantic import AnyUrl, BaseModel, ValidationError
|
|
14
14
|
import mcp.server.stdio
|
|
15
|
+
from .. import tools
|
|
15
16
|
from ..tools import DoneFlag, get_tool_output, which_tool_name, default_enc
|
|
16
17
|
from ...types_ import (
|
|
17
18
|
BashCommand,
|
|
@@ -29,6 +30,7 @@ from ...types_ import (
|
|
|
29
30
|
)
|
|
30
31
|
from ..computer_use import Computer
|
|
31
32
|
|
|
33
|
+
tools.TIMEOUT = 3
|
|
32
34
|
|
|
33
35
|
server = Server("wcgw")
|
|
34
36
|
|
|
@@ -272,7 +274,7 @@ async def main() -> None:
|
|
|
272
274
|
experimental_capabilities={},
|
|
273
275
|
),
|
|
274
276
|
),
|
|
275
|
-
raise_exceptions=
|
|
277
|
+
raise_exceptions=False,
|
|
276
278
|
)
|
|
277
279
|
except BaseException as e:
|
|
278
280
|
print(f"Server encountered an error: {e}", file=sys.stderr)
|
wcgw/client/sys_utils.py
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import subprocess
|
|
2
2
|
|
|
3
3
|
MAX_RESPONSE_LEN: int = 16000
|
|
4
|
+
TRUNCATED_MESSAGE: str = "<response clipped><NOTE>To save on context only part of this file has been shown to you.</NOTE>"
|
|
4
5
|
|
|
5
6
|
|
|
6
7
|
def maybe_truncate(content: str, truncate_after: int | None = MAX_RESPONSE_LEN) -> str:
|
|
@@ -14,7 +15,7 @@ def maybe_truncate(content: str, truncate_after: int | None = MAX_RESPONSE_LEN)
|
|
|
14
15
|
|
|
15
16
|
def command_run(
|
|
16
17
|
cmd: str,
|
|
17
|
-
timeout: float | None =
|
|
18
|
+
timeout: float | None = 3.0, # seconds
|
|
18
19
|
truncate_after: int | None = MAX_RESPONSE_LEN,
|
|
19
20
|
text: bool = True,
|
|
20
21
|
) -> tuple[int, str, str]:
|
wcgw/client/tools.py
CHANGED
|
@@ -71,7 +71,7 @@ from .openai_utils import get_input_cost, get_output_cost
|
|
|
71
71
|
|
|
72
72
|
console = rich.console.Console(style="magenta", highlight=False, markup=False)
|
|
73
73
|
|
|
74
|
-
TIMEOUT =
|
|
74
|
+
TIMEOUT = 5
|
|
75
75
|
|
|
76
76
|
|
|
77
77
|
def render_terminal_output(text: str) -> str:
|
|
@@ -113,9 +113,9 @@ def start_shell() -> pexpect.spawn: # type: ignore
|
|
|
113
113
|
encoding="utf-8",
|
|
114
114
|
timeout=TIMEOUT,
|
|
115
115
|
)
|
|
116
|
-
SHELL.expect(PROMPT)
|
|
116
|
+
SHELL.expect(PROMPT, timeout=TIMEOUT)
|
|
117
117
|
SHELL.sendline("stty -icanon -echo")
|
|
118
|
-
SHELL.expect(PROMPT)
|
|
118
|
+
SHELL.expect(PROMPT, timeout=TIMEOUT)
|
|
119
119
|
return SHELL
|
|
120
120
|
|
|
121
121
|
|
|
@@ -135,15 +135,15 @@ def _get_exit_code() -> int:
|
|
|
135
135
|
return 0
|
|
136
136
|
# First reset the prompt in case venv was sourced or other reasons.
|
|
137
137
|
SHELL.sendline(f"export PS1={PROMPT}")
|
|
138
|
-
SHELL.expect(PROMPT)
|
|
138
|
+
SHELL.expect(PROMPT, timeout=0.2)
|
|
139
139
|
# Reset echo also if it was enabled
|
|
140
140
|
SHELL.sendline("stty -icanon -echo")
|
|
141
|
-
SHELL.expect(PROMPT)
|
|
141
|
+
SHELL.expect(PROMPT, timeout=0.2)
|
|
142
142
|
SHELL.sendline("echo $?")
|
|
143
143
|
before = ""
|
|
144
144
|
while not _is_int(before): # Consume all previous output
|
|
145
145
|
try:
|
|
146
|
-
SHELL.expect(PROMPT)
|
|
146
|
+
SHELL.expect(PROMPT, timeout=0.2)
|
|
147
147
|
except pexpect.TIMEOUT:
|
|
148
148
|
print(f"Couldn't get exit code, before: {before}")
|
|
149
149
|
raise
|
|
@@ -215,7 +215,7 @@ def update_repl_prompt(command: str) -> bool:
|
|
|
215
215
|
|
|
216
216
|
def get_cwd() -> str:
|
|
217
217
|
SHELL.sendline("pwd")
|
|
218
|
-
SHELL.expect(PROMPT)
|
|
218
|
+
SHELL.expect(PROMPT, timeout=0.2)
|
|
219
219
|
assert isinstance(SHELL.before, str)
|
|
220
220
|
current_dir = render_terminal_output(SHELL.before).strip()
|
|
221
221
|
return current_dir
|
|
@@ -342,13 +342,13 @@ def execute_bash(
|
|
|
342
342
|
SHELL.expect(PROMPT)
|
|
343
343
|
return "---\n\nFailure: user interrupted the execution", 0.0
|
|
344
344
|
|
|
345
|
-
wait = timeout_s or
|
|
345
|
+
wait = timeout_s or TIMEOUT
|
|
346
346
|
index = SHELL.expect([PROMPT, pexpect.TIMEOUT], timeout=wait)
|
|
347
347
|
if index == 1:
|
|
348
348
|
BASH_STATE = "pending"
|
|
349
349
|
text = SHELL.before or ""
|
|
350
350
|
|
|
351
|
-
text = render_terminal_output(text)
|
|
351
|
+
text = render_terminal_output(text[-100_000:])
|
|
352
352
|
tokens = enc.encode(text)
|
|
353
353
|
|
|
354
354
|
if max_tokens and len(tokens) >= max_tokens:
|
|
@@ -855,7 +855,7 @@ def get_tool_output(
|
|
|
855
855
|
if imgBs64:
|
|
856
856
|
console.print("Captured screenshot")
|
|
857
857
|
outputs.append(ImageData(media_type="image/png", data=imgBs64))
|
|
858
|
-
if not IS_IN_DOCKER:
|
|
858
|
+
if not IS_IN_DOCKER and isinstance(arg, GetScreenInfo):
|
|
859
859
|
try:
|
|
860
860
|
# At this point we should go into the docker env
|
|
861
861
|
res, _ = execute_bash(
|
|
@@ -989,7 +989,7 @@ def read_file(readfile: ReadFile, max_tokens: Optional[int]) -> str:
|
|
|
989
989
|
|
|
990
990
|
else:
|
|
991
991
|
return_code, content, stderr = command_run(
|
|
992
|
-
f"cat {readfile.file_path}",
|
|
992
|
+
f"cat {readfile.file_path}", timeout=TIMEOUT
|
|
993
993
|
)
|
|
994
994
|
if return_code != 0:
|
|
995
995
|
raise Exception(
|
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
Metadata-Version: 2.3
|
|
2
2
|
Name: wcgw
|
|
3
|
-
Version: 1.5.
|
|
3
|
+
Version: 1.5.1
|
|
4
4
|
Summary: What could go wrong giving full shell access to chatgpt?
|
|
5
5
|
Project-URL: Homepage, https://github.com/rusiaaman/wcgw
|
|
6
6
|
Author-email: Aman Rusia <gapypi@arcfu.com>
|
|
7
7
|
Requires-Python: <3.13,>=3.11
|
|
8
8
|
Requires-Dist: anthropic>=0.39.0
|
|
9
9
|
Requires-Dist: fastapi>=0.115.0
|
|
10
|
-
Requires-Dist: mcp
|
|
10
|
+
Requires-Dist: mcp
|
|
11
11
|
Requires-Dist: mypy>=1.11.2
|
|
12
12
|
Requires-Dist: nltk>=3.9.1
|
|
13
13
|
Requires-Dist: openai>=1.46.0
|
|
@@ -5,18 +5,18 @@ wcgw/client/__main__.py,sha256=wcCrL4PjG51r5wVKqJhcoJPTLfHW0wNbD31DrUN0MWI,28
|
|
|
5
5
|
wcgw/client/anthropic_client.py,sha256=owR-nIxQVGgw_ned8JOQ-QmmCBQvZSqgD08kYpU_Rbg,17730
|
|
6
6
|
wcgw/client/cli.py,sha256=Oja42CHkVO8puqOXflko9NeephYCMa85aBmQTEjBZtI,932
|
|
7
7
|
wcgw/client/common.py,sha256=grH-yV_4tnTQZ29xExn4YicGLxEq98z-HkEZwH0ReSg,1410
|
|
8
|
-
wcgw/client/computer_use.py,sha256=
|
|
8
|
+
wcgw/client/computer_use.py,sha256=hadmsHpwVRqTZh4Q7Ssu3xdnNLnBW4y-pd5P6D-qqKE,14276
|
|
9
9
|
wcgw/client/diff-instructions.txt,sha256=s5AJKG23JsjwRYhFZFQVvwDpF67vElawrmdXwvukR1A,1683
|
|
10
10
|
wcgw/client/openai_client.py,sha256=L61ajFVQW2QPS3C0n1YsjgF4vQKfMIZHmp6iFBHutX8,17748
|
|
11
11
|
wcgw/client/openai_utils.py,sha256=YNwCsA-Wqq7jWrxP0rfQmBTb1dI0s7dWXzQqyTzOZT4,2629
|
|
12
|
-
wcgw/client/sys_utils.py,sha256=
|
|
13
|
-
wcgw/client/tools.py,sha256=
|
|
14
|
-
wcgw/client/mcp_server/Readme.md,sha256=
|
|
12
|
+
wcgw/client/sys_utils.py,sha256=GajPntKhaTUMn6EOmopENWZNR2G_BJyuVbuot0x6veI,1376
|
|
13
|
+
wcgw/client/tools.py,sha256=Ce_1eLXl6W1U2EcNk2JPiCAKmEnTHt3Jd78ZHlW-ET4,32629
|
|
14
|
+
wcgw/client/mcp_server/Readme.md,sha256=mztipVTwqXLLenbVihnodq7gUF2Q0_YOKOMW3MiV3UM,2020
|
|
15
15
|
wcgw/client/mcp_server/__init__.py,sha256=cQ7PUrEmXUpio8x0SEoGWP5hCRPd7z2bAkNCbYbtTys,236
|
|
16
|
-
wcgw/client/mcp_server/server.py,sha256=
|
|
16
|
+
wcgw/client/mcp_server/server.py,sha256=niS5elM7vdu181DjDSNXRbipFjt9Ke-H9HQMWMwNnXg,10211
|
|
17
17
|
wcgw/relay/serve.py,sha256=RUcUeyL4Xt0EEo12Ul6VQjb4tRle4uIdsa85v7XXxEw,8771
|
|
18
18
|
wcgw/relay/static/privacy.txt,sha256=s9qBdbx2SexCpC_z33sg16TptmAwDEehMCLz4L50JLc,529
|
|
19
|
-
wcgw-1.5.
|
|
20
|
-
wcgw-1.5.
|
|
21
|
-
wcgw-1.5.
|
|
22
|
-
wcgw-1.5.
|
|
19
|
+
wcgw-1.5.1.dist-info/METADATA,sha256=ls5ebZhUUraGJqdSIHCggftaq16jnGJS8VxHMj1Y0GY,6285
|
|
20
|
+
wcgw-1.5.1.dist-info/WHEEL,sha256=C2FUgwZgiLbznR-k0b_5k3Ai_1aASOXDss3lzCUsUug,87
|
|
21
|
+
wcgw-1.5.1.dist-info/entry_points.txt,sha256=eKo1omwbAggWlQ0l7GKoR7uV1-j16nk9tK0BhC2Oz_E,120
|
|
22
|
+
wcgw-1.5.1.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|