wcgw 1.2.2__tar.gz → 1.4.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.4.0}/.vscode/settings.json +2 -1
- {wcgw-1.2.2 → wcgw-1.4.0}/PKG-INFO +6 -2
- {wcgw-1.2.2 → wcgw-1.4.0}/README.md +4 -1
- wcgw-1.4.0/add.py +6 -0
- wcgw-1.4.0/claude_desktop_config.json +15 -0
- {wcgw-1.2.2 → wcgw-1.4.0}/gpt_action_json_schema.json +68 -6
- {wcgw-1.2.2 → wcgw-1.4.0}/gpt_instructions.txt +9 -3
- {wcgw-1.2.2 → wcgw-1.4.0}/pyproject.toml +3 -1
- {wcgw-1.2.2 → wcgw-1.4.0}/src/wcgw/__init__.py +1 -0
- {wcgw-1.2.2 → wcgw-1.4.0}/src/wcgw/client/anthropic_client.py +6 -5
- {wcgw-1.2.2 → wcgw-1.4.0}/src/wcgw/client/diff-instructions.txt +5 -1
- wcgw-1.4.0/src/wcgw/client/mcp_server/Readme.md +26 -0
- wcgw-1.4.0/src/wcgw/client/mcp_server/__init__.py +11 -0
- wcgw-1.4.0/src/wcgw/client/mcp_server/server.py +222 -0
- {wcgw-1.2.2 → wcgw-1.4.0}/src/wcgw/client/openai_client.py +6 -6
- {wcgw-1.2.2 → wcgw-1.4.0}/src/wcgw/client/tools.py +65 -45
- {wcgw-1.2.2 → wcgw-1.4.0}/src/wcgw/relay/serve.py +36 -14
- {wcgw-1.2.2 → wcgw-1.4.0}/src/wcgw/types_.py +4 -5
- wcgw-1.4.0/static/rocket-icon.png +0 -0
- {wcgw-1.2.2 → wcgw-1.4.0}/tests/test_tools.py +2 -2
- {wcgw-1.2.2 → wcgw-1.4.0}/uv.lock +201 -159
- {wcgw-1.2.2 → wcgw-1.4.0}/.github/workflows/python-publish.yml +0 -0
- {wcgw-1.2.2 → wcgw-1.4.0}/.github/workflows/python-tests.yml +0 -0
- {wcgw-1.2.2 → wcgw-1.4.0}/.gitignore +0 -0
- {wcgw-1.2.2 → wcgw-1.4.0}/.python-version +0 -0
- {wcgw-1.2.2 → wcgw-1.4.0}/src/__init__.py +0 -0
- {wcgw-1.2.2 → wcgw-1.4.0}/src/wcgw/client/__init__.py +0 -0
- {wcgw-1.2.2 → wcgw-1.4.0}/src/wcgw/client/__main__.py +0 -0
- {wcgw-1.2.2 → wcgw-1.4.0}/src/wcgw/client/cli.py +0 -0
- {wcgw-1.2.2 → wcgw-1.4.0}/src/wcgw/client/common.py +0 -0
- {wcgw-1.2.2 → wcgw-1.4.0}/src/wcgw/client/openai_utils.py +0 -0
- {wcgw-1.2.2 → wcgw-1.4.0}/src/wcgw/relay/static/privacy.txt +0 -0
- {wcgw-1.2.2 → wcgw-1.4.0}/static/ss1.png +0 -0
- {wcgw-1.2.2 → wcgw-1.4.0}/tests/test_basic.py +0 -0
|
@@ -1,12 +1,13 @@
|
|
|
1
1
|
Metadata-Version: 2.3
|
|
2
2
|
Name: wcgw
|
|
3
|
-
Version: 1.
|
|
3
|
+
Version: 1.4.0
|
|
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.10
|
|
8
8
|
Requires-Dist: anthropic>=0.39.0
|
|
9
9
|
Requires-Dist: fastapi>=0.115.0
|
|
10
|
+
Requires-Dist: mcp>=1.0.0
|
|
10
11
|
Requires-Dist: mypy>=1.11.2
|
|
11
12
|
Requires-Dist: nltk>=3.9.1
|
|
12
13
|
Requires-Dist: openai>=1.46.0
|
|
@@ -50,7 +51,7 @@ You need to keep running this client for GPT to access your shell. Run it in a v
|
|
|
50
51
|
### Option 1: using uv [Recommended]
|
|
51
52
|
```sh
|
|
52
53
|
$ curl -LsSf https://astral.sh/uv/install.sh | sh
|
|
53
|
-
$
|
|
54
|
+
$ uvx wcgw@latest
|
|
54
55
|
```
|
|
55
56
|
|
|
56
57
|
### Option 2: using pip
|
|
@@ -109,6 +110,9 @@ If you don't have public ip and domain name, you can use `ngrok` or similar serv
|
|
|
109
110
|
The specify the server url in the `wcgw` command like so
|
|
110
111
|
`wcgw --server-url https://your-url/v1/register`
|
|
111
112
|
|
|
113
|
+
# Claude Support
|
|
114
|
+
WCGW now supports Claude Desktop through the MCP protocol, allowing you to use Claude's capabilities directly from your desktop environment. This integration enables seamless interaction between Claude and your local shell.
|
|
115
|
+
|
|
112
116
|
# [Optional] Local shell access with openai API key
|
|
113
117
|
|
|
114
118
|
Add `OPENAI_API_KEY` and `OPENAI_ORG_ID` env variables.
|
|
@@ -22,7 +22,7 @@ You need to keep running this client for GPT to access your shell. Run it in a v
|
|
|
22
22
|
### Option 1: using uv [Recommended]
|
|
23
23
|
```sh
|
|
24
24
|
$ curl -LsSf https://astral.sh/uv/install.sh | sh
|
|
25
|
-
$
|
|
25
|
+
$ uvx wcgw@latest
|
|
26
26
|
```
|
|
27
27
|
|
|
28
28
|
### Option 2: using pip
|
|
@@ -81,6 +81,9 @@ If you don't have public ip and domain name, you can use `ngrok` or similar serv
|
|
|
81
81
|
The specify the server url in the `wcgw` command like so
|
|
82
82
|
`wcgw --server-url https://your-url/v1/register`
|
|
83
83
|
|
|
84
|
+
# Claude Support
|
|
85
|
+
WCGW now supports Claude Desktop through the MCP protocol, allowing you to use Claude's capabilities directly from your desktop environment. This integration enables seamless interaction between Claude and your local shell.
|
|
86
|
+
|
|
84
87
|
# [Optional] Local shell access with openai API key
|
|
85
88
|
|
|
86
89
|
Add `OPENAI_API_KEY` and `OPENAI_ORG_ID` env variables.
|
wcgw-1.4.0/add.py
ADDED
|
@@ -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.
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
[project]
|
|
2
2
|
authors = [{ name = "Aman Rusia", email = "gapypi@arcfu.com" }]
|
|
3
3
|
name = "wcgw"
|
|
4
|
-
version = "1.
|
|
4
|
+
version = "1.4.0"
|
|
5
5
|
description = "What could go wrong giving full shell access to chatgpt?"
|
|
6
6
|
readme = "README.md"
|
|
7
7
|
requires-python = ">=3.10, <3.13"
|
|
@@ -25,6 +25,7 @@ dependencies = [
|
|
|
25
25
|
"semantic-version>=2.10.0",
|
|
26
26
|
"nltk>=3.9.1",
|
|
27
27
|
"anthropic>=0.39.0",
|
|
28
|
+
"mcp>=1.0.0",
|
|
28
29
|
]
|
|
29
30
|
|
|
30
31
|
[project.urls]
|
|
@@ -38,6 +39,7 @@ build-backend = "hatchling.build"
|
|
|
38
39
|
wcgw_local = "wcgw:app"
|
|
39
40
|
wcgw = "wcgw:listen"
|
|
40
41
|
wcgw_relay = "wcgw.relay.serve:run"
|
|
42
|
+
wcgw_mcp = "wcgw:mcp_server"
|
|
41
43
|
|
|
42
44
|
[tool.uv]
|
|
43
45
|
dev-dependencies = [
|
|
@@ -29,7 +29,6 @@ from ..types_ import (
|
|
|
29
29
|
FileEdit,
|
|
30
30
|
ReadFile,
|
|
31
31
|
ReadImage,
|
|
32
|
-
Writefile,
|
|
33
32
|
ResetShell,
|
|
34
33
|
)
|
|
35
34
|
|
|
@@ -165,6 +164,7 @@ def loop(
|
|
|
165
164
|
- Optionally `exit shell has restarted` is the output, in which case environment resets, you can run fresh commands.
|
|
166
165
|
- The first line might be `(...truncated)` if the output is too long.
|
|
167
166
|
- Always run `pwd` if you get any file or directory not found error to make sure you're not lost.
|
|
167
|
+
- 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
168
|
""",
|
|
169
169
|
),
|
|
170
170
|
ToolParam(
|
|
@@ -193,7 +193,7 @@ def loop(
|
|
|
193
193
|
- Write content to a new file. Provide file path and content. Use this instead of BashCommand for writing new files.
|
|
194
194
|
- This doesn't create any directories, please create directories using `mkdir -p` BashCommand.
|
|
195
195
|
- Provide absolute file path only.
|
|
196
|
-
- For editing existing files, use FileEdit.
|
|
196
|
+
- For editing existing files, use FileEdit instead of this tool.
|
|
197
197
|
""",
|
|
198
198
|
),
|
|
199
199
|
ToolParam(
|
|
@@ -219,7 +219,7 @@ def loop(
|
|
|
219
219
|
uname_machine = os.uname().machine
|
|
220
220
|
|
|
221
221
|
system = f"""
|
|
222
|
-
You're
|
|
222
|
+
You're an expert software engineer with shell and code knowledge.
|
|
223
223
|
|
|
224
224
|
Instructions:
|
|
225
225
|
|
|
@@ -227,10 +227,11 @@ Instructions:
|
|
|
227
227
|
- First understand about the project by getting the folder structure (ignoring .git, node_modules, venv, etc.)
|
|
228
228
|
- Always read relevant files before editing.
|
|
229
229
|
- Do not provide code snippets unless asked by the user, instead directly edit the code.
|
|
230
|
-
|
|
230
|
+
|
|
231
231
|
System information:
|
|
232
232
|
- System: {uname_sysname}
|
|
233
233
|
- Machine: {uname_machine}
|
|
234
|
+
- Current directory: {os.getcwd()}
|
|
234
235
|
"""
|
|
235
236
|
|
|
236
237
|
with open(os.path.join(os.path.dirname(__file__), "diff-instructions.txt")) as f:
|
|
@@ -361,7 +362,7 @@ System information:
|
|
|
361
362
|
enc,
|
|
362
363
|
limit - cost,
|
|
363
364
|
loop,
|
|
364
|
-
max_tokens=
|
|
365
|
+
max_tokens=8000,
|
|
365
366
|
)
|
|
366
367
|
except Exception as e:
|
|
367
368
|
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.
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
# Claude desktop support
|
|
2
|
+
|
|
3
|
+
## Setup
|
|
4
|
+
|
|
5
|
+
Update `claude_desktop_config.json`
|
|
6
|
+
|
|
7
|
+
```json
|
|
8
|
+
{
|
|
9
|
+
"mcpServers": {
|
|
10
|
+
"wcgw": {
|
|
11
|
+
"command": "uvx",
|
|
12
|
+
"args": ["--from", "wcgw", "wcgw_mcp"]
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
Then restart claude app.
|
|
19
|
+
|
|
20
|
+
## Usage
|
|
21
|
+
|
|
22
|
+
You should be able to see this icon if everything goes right.
|
|
23
|
+
|
|
24
|
+

|
|
25
|
+
|
|
26
|
+
Then ask claude to execute shell commands, read files, edit files, run your code, etc.
|
|
@@ -0,0 +1,222 @@
|
|
|
1
|
+
import asyncio
|
|
2
|
+
import importlib
|
|
3
|
+
import json
|
|
4
|
+
import os
|
|
5
|
+
import traceback
|
|
6
|
+
from typing import Any
|
|
7
|
+
|
|
8
|
+
from mcp.server.models import InitializationOptions
|
|
9
|
+
import mcp.types as types
|
|
10
|
+
from mcp.types import Tool as ToolParam
|
|
11
|
+
from mcp.server import NotificationOptions, Server
|
|
12
|
+
from pydantic import AnyUrl, ValidationError
|
|
13
|
+
import mcp.server.stdio
|
|
14
|
+
from ..tools import DoneFlag, get_tool_output, which_tool_name, default_enc
|
|
15
|
+
from ...types_ import (
|
|
16
|
+
BashCommand,
|
|
17
|
+
BashInteraction,
|
|
18
|
+
CreateFileNew,
|
|
19
|
+
FileEdit,
|
|
20
|
+
ReadFile,
|
|
21
|
+
ReadImage,
|
|
22
|
+
ResetShell,
|
|
23
|
+
Initialize,
|
|
24
|
+
)
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
server = Server("wcgw")
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
@server.list_resources()
|
|
31
|
+
async def handle_list_resources() -> list[types.Resource]:
|
|
32
|
+
return []
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
@server.read_resource()
|
|
36
|
+
async def handle_read_resource(uri: AnyUrl) -> str:
|
|
37
|
+
raise ValueError("No resources available")
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
@server.list_prompts()
|
|
41
|
+
async def handle_list_prompts() -> list[types.Prompt]:
|
|
42
|
+
return []
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
@server.get_prompt()
|
|
46
|
+
async def handle_get_prompt(
|
|
47
|
+
name: str, arguments: dict[str, str] | None
|
|
48
|
+
) -> types.GetPromptResult:
|
|
49
|
+
types.GetPromptResult(messages=[])
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
@server.list_tools()
|
|
53
|
+
async def handle_list_tools() -> list[types.Tool]:
|
|
54
|
+
"""
|
|
55
|
+
List available tools.
|
|
56
|
+
Each tool specifies its arguments using JSON Schema validation.
|
|
57
|
+
"""
|
|
58
|
+
|
|
59
|
+
with open(
|
|
60
|
+
os.path.join(
|
|
61
|
+
os.path.dirname(os.path.dirname(__file__)), "diff-instructions.txt"
|
|
62
|
+
)
|
|
63
|
+
) as f:
|
|
64
|
+
diffinstructions = f.read()
|
|
65
|
+
return [
|
|
66
|
+
ToolParam(
|
|
67
|
+
inputSchema=Initialize.model_json_schema(),
|
|
68
|
+
name="Initialize",
|
|
69
|
+
description="""
|
|
70
|
+
- Always call this at the start of the conversation before anything else.
|
|
71
|
+
""",
|
|
72
|
+
),
|
|
73
|
+
ToolParam(
|
|
74
|
+
inputSchema=BashCommand.model_json_schema(),
|
|
75
|
+
name="BashCommand",
|
|
76
|
+
description="""
|
|
77
|
+
- Execute a bash command. This is stateful (beware with subsequent calls).
|
|
78
|
+
- Do not use interactive commands like nano. Prefer writing simpler commands.
|
|
79
|
+
- Status of the command and the current working directory will always be returned at the end.
|
|
80
|
+
- Optionally `exit shell has restarted` is the output, in which case environment resets, you can run fresh commands.
|
|
81
|
+
- The first line might be `(...truncated)` if the output is too long.
|
|
82
|
+
- Always run `pwd` if you get any file or directory not found error to make sure you're not lost.
|
|
83
|
+
- 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.
|
|
84
|
+
""",
|
|
85
|
+
),
|
|
86
|
+
ToolParam(
|
|
87
|
+
inputSchema=BashInteraction.model_json_schema(),
|
|
88
|
+
name="BashInteraction",
|
|
89
|
+
description="""
|
|
90
|
+
- Interact with running program using this tool
|
|
91
|
+
- Special keys like arrows, interrupts, enter, etc.
|
|
92
|
+
- Send text input to the running program.
|
|
93
|
+
- Send send_specials=["Enter"] to recheck status of a running program.
|
|
94
|
+
- Only one of send_text, send_specials, send_ascii should be provided.
|
|
95
|
+
""",
|
|
96
|
+
),
|
|
97
|
+
ToolParam(
|
|
98
|
+
inputSchema=ReadFile.model_json_schema(),
|
|
99
|
+
name="ReadFile",
|
|
100
|
+
description="""
|
|
101
|
+
- Read full file content
|
|
102
|
+
- Provide absolute file path only
|
|
103
|
+
""",
|
|
104
|
+
),
|
|
105
|
+
ToolParam(
|
|
106
|
+
inputSchema=CreateFileNew.model_json_schema(),
|
|
107
|
+
name="CreateFileNew",
|
|
108
|
+
description="""
|
|
109
|
+
- Write content to a new file. Provide file path and content. Use this instead of BashCommand for writing new files.
|
|
110
|
+
- This doesn't create any directories, please create directories using `mkdir -p` BashCommand.
|
|
111
|
+
- Provide absolute file path only.
|
|
112
|
+
- For editing existing files, use FileEdit instead of this tool.
|
|
113
|
+
""",
|
|
114
|
+
),
|
|
115
|
+
ToolParam(
|
|
116
|
+
inputSchema=ReadImage.model_json_schema(),
|
|
117
|
+
name="ReadImage",
|
|
118
|
+
description="Read an image from the shell.",
|
|
119
|
+
),
|
|
120
|
+
ToolParam(
|
|
121
|
+
inputSchema=ResetShell.model_json_schema(),
|
|
122
|
+
name="ResetShell",
|
|
123
|
+
description="Resets the shell. Use only if all interrupts and prompt reset attempts have failed repeatedly.",
|
|
124
|
+
),
|
|
125
|
+
ToolParam(
|
|
126
|
+
inputSchema=FileEdit.model_json_schema(),
|
|
127
|
+
name="FileEdit",
|
|
128
|
+
description="""
|
|
129
|
+
- Use absolute file path only.
|
|
130
|
+
- Use SEARCH/REPLACE blocks to edit the file.
|
|
131
|
+
"""
|
|
132
|
+
+ diffinstructions,
|
|
133
|
+
),
|
|
134
|
+
ToolParam(
|
|
135
|
+
inputSchema=ReadImage.model_json_schema(),
|
|
136
|
+
name="ReadImage",
|
|
137
|
+
description="""
|
|
138
|
+
- Read an image from the shell.
|
|
139
|
+
""",
|
|
140
|
+
),
|
|
141
|
+
]
|
|
142
|
+
|
|
143
|
+
|
|
144
|
+
@server.call_tool()
|
|
145
|
+
async def handle_call_tool(
|
|
146
|
+
name: str, arguments: dict | None
|
|
147
|
+
) -> list[types.TextContent | types.ImageContent | types.EmbeddedResource]:
|
|
148
|
+
if not arguments:
|
|
149
|
+
raise ValueError("Missing arguments")
|
|
150
|
+
|
|
151
|
+
tool_type = which_tool_name(name)
|
|
152
|
+
|
|
153
|
+
try:
|
|
154
|
+
tool_call = tool_type(**arguments)
|
|
155
|
+
except ValidationError:
|
|
156
|
+
|
|
157
|
+
def try_json(x: str) -> Any:
|
|
158
|
+
try:
|
|
159
|
+
return json.loads(x)
|
|
160
|
+
except json.JSONDecodeError:
|
|
161
|
+
return x
|
|
162
|
+
|
|
163
|
+
tool_call = tool_type(**{k: try_json(v) for k, v in arguments.items()})
|
|
164
|
+
|
|
165
|
+
try:
|
|
166
|
+
output_or_done, _ = get_tool_output(
|
|
167
|
+
tool_call, default_enc, 0.0, lambda x, y: ("", 0), 8000
|
|
168
|
+
)
|
|
169
|
+
|
|
170
|
+
except Exception as e:
|
|
171
|
+
output_or_done = f"GOT EXCEPTION while calling tool. Error: {e}"
|
|
172
|
+
tb = traceback.format_exc()
|
|
173
|
+
print(output_or_done + "\n" + tb)
|
|
174
|
+
|
|
175
|
+
assert not isinstance(output_or_done, DoneFlag)
|
|
176
|
+
if isinstance(output_or_done, str):
|
|
177
|
+
if issubclass(tool_type, Initialize):
|
|
178
|
+
output_or_done += """
|
|
179
|
+
|
|
180
|
+
You're an expert software engineer with shell and code knowledge.
|
|
181
|
+
|
|
182
|
+
Instructions:
|
|
183
|
+
|
|
184
|
+
- You should use the provided bash execution, reading and writing file tools to complete objective.
|
|
185
|
+
- First understand about the project by getting the folder structure (ignoring .git, node_modules, venv, etc.)
|
|
186
|
+
- Always read relevant files before editing.
|
|
187
|
+
- Do not provide code snippets unless asked by the user, instead directly edit the code.
|
|
188
|
+
|
|
189
|
+
|
|
190
|
+
Additional instructions:
|
|
191
|
+
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.
|
|
192
|
+
|
|
193
|
+
Always write production ready, syntactically correct code.
|
|
194
|
+
"""
|
|
195
|
+
|
|
196
|
+
return [types.TextContent(type="text", text=output_or_done)]
|
|
197
|
+
|
|
198
|
+
return [
|
|
199
|
+
types.ImageContent(
|
|
200
|
+
type="image",
|
|
201
|
+
data=output_or_done.data,
|
|
202
|
+
mimeType=output_or_done.media_type,
|
|
203
|
+
)
|
|
204
|
+
]
|
|
205
|
+
|
|
206
|
+
|
|
207
|
+
async def main() -> None:
|
|
208
|
+
version = importlib.metadata.version("wcgw")
|
|
209
|
+
# Run the server using stdin/stdout streams
|
|
210
|
+
async with mcp.server.stdio.stdio_server() as (read_stream, write_stream):
|
|
211
|
+
await server.run(
|
|
212
|
+
read_stream,
|
|
213
|
+
write_stream,
|
|
214
|
+
InitializationOptions(
|
|
215
|
+
server_name="wcgw",
|
|
216
|
+
server_version=version,
|
|
217
|
+
capabilities=server.get_capabilities(
|
|
218
|
+
notification_options=NotificationOptions(),
|
|
219
|
+
experimental_capabilities={},
|
|
220
|
+
),
|
|
221
|
+
),
|
|
222
|
+
)
|
|
@@ -27,7 +27,6 @@ from ..types_ import (
|
|
|
27
27
|
FileEdit,
|
|
28
28
|
ReadImage,
|
|
29
29
|
ReadFile,
|
|
30
|
-
Writefile,
|
|
31
30
|
ResetShell,
|
|
32
31
|
)
|
|
33
32
|
|
|
@@ -148,8 +147,7 @@ def loop(
|
|
|
148
147
|
my_dir = os.path.dirname(__file__)
|
|
149
148
|
|
|
150
149
|
config = Config(
|
|
151
|
-
model=cast(
|
|
152
|
-
Models, os.getenv("OPENAI_MODEL", "gpt-4o-2024-08-06").lower()),
|
|
150
|
+
model=cast(Models, os.getenv("OPENAI_MODEL", "gpt-4o-2024-08-06").lower()),
|
|
153
151
|
cost_limit=0.1,
|
|
154
152
|
cost_unit="$",
|
|
155
153
|
cost_file={
|
|
@@ -177,6 +175,7 @@ def loop(
|
|
|
177
175
|
- Optionally `exit shell has restarted` is the output, in which case environment resets, you can run fresh commands.
|
|
178
176
|
- The first line might be `(...truncated)` if the output is too long.
|
|
179
177
|
- Always run `pwd` if you get any file or directory not found error to make sure you're not lost.
|
|
178
|
+
- 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
179
|
""",
|
|
181
180
|
),
|
|
182
181
|
openai.pydantic_function_tool(
|
|
@@ -201,7 +200,7 @@ def loop(
|
|
|
201
200
|
- Write content to a new file. Provide file path and content. Use this instead of BashCommand for writing new files.
|
|
202
201
|
- This doesn't create any directories, please create directories using `mkdir -p` BashCommand.
|
|
203
202
|
- Provide absolute file path only.
|
|
204
|
-
- For editing existing files, use FileEdit.""",
|
|
203
|
+
- For editing existing files, use FileEdit instead of this tool.""",
|
|
205
204
|
),
|
|
206
205
|
openai.pydantic_function_tool(
|
|
207
206
|
FileEdit,
|
|
@@ -223,7 +222,7 @@ def loop(
|
|
|
223
222
|
uname_machine = os.uname().machine
|
|
224
223
|
|
|
225
224
|
system = f"""
|
|
226
|
-
You're
|
|
225
|
+
You're an expert software engineer with shell and code knowledge.
|
|
227
226
|
|
|
228
227
|
Instructions:
|
|
229
228
|
|
|
@@ -235,6 +234,7 @@ Instructions:
|
|
|
235
234
|
System information:
|
|
236
235
|
- System: {uname_sysname}
|
|
237
236
|
- Machine: {uname_machine}
|
|
237
|
+
- Current directory: {os.getcwd()}
|
|
238
238
|
|
|
239
239
|
"""
|
|
240
240
|
|
|
@@ -341,7 +341,7 @@ System information:
|
|
|
341
341
|
enc,
|
|
342
342
|
limit - cost,
|
|
343
343
|
loop,
|
|
344
|
-
max_tokens=
|
|
344
|
+
max_tokens=8000,
|
|
345
345
|
)
|
|
346
346
|
except Exception as e:
|
|
347
347
|
output_or_done = (
|