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.

Files changed (34) hide show
  1. {wcgw-1.2.2 → wcgw-1.4.0}/.vscode/settings.json +2 -1
  2. {wcgw-1.2.2 → wcgw-1.4.0}/PKG-INFO +6 -2
  3. {wcgw-1.2.2 → wcgw-1.4.0}/README.md +4 -1
  4. wcgw-1.4.0/add.py +6 -0
  5. wcgw-1.4.0/claude_desktop_config.json +15 -0
  6. {wcgw-1.2.2 → wcgw-1.4.0}/gpt_action_json_schema.json +68 -6
  7. {wcgw-1.2.2 → wcgw-1.4.0}/gpt_instructions.txt +9 -3
  8. {wcgw-1.2.2 → wcgw-1.4.0}/pyproject.toml +3 -1
  9. {wcgw-1.2.2 → wcgw-1.4.0}/src/wcgw/__init__.py +1 -0
  10. {wcgw-1.2.2 → wcgw-1.4.0}/src/wcgw/client/anthropic_client.py +6 -5
  11. {wcgw-1.2.2 → wcgw-1.4.0}/src/wcgw/client/diff-instructions.txt +5 -1
  12. wcgw-1.4.0/src/wcgw/client/mcp_server/Readme.md +26 -0
  13. wcgw-1.4.0/src/wcgw/client/mcp_server/__init__.py +11 -0
  14. wcgw-1.4.0/src/wcgw/client/mcp_server/server.py +222 -0
  15. {wcgw-1.2.2 → wcgw-1.4.0}/src/wcgw/client/openai_client.py +6 -6
  16. {wcgw-1.2.2 → wcgw-1.4.0}/src/wcgw/client/tools.py +65 -45
  17. {wcgw-1.2.2 → wcgw-1.4.0}/src/wcgw/relay/serve.py +36 -14
  18. {wcgw-1.2.2 → wcgw-1.4.0}/src/wcgw/types_.py +4 -5
  19. wcgw-1.4.0/static/rocket-icon.png +0 -0
  20. {wcgw-1.2.2 → wcgw-1.4.0}/tests/test_tools.py +2 -2
  21. {wcgw-1.2.2 → wcgw-1.4.0}/uv.lock +201 -159
  22. {wcgw-1.2.2 → wcgw-1.4.0}/.github/workflows/python-publish.yml +0 -0
  23. {wcgw-1.2.2 → wcgw-1.4.0}/.github/workflows/python-tests.yml +0 -0
  24. {wcgw-1.2.2 → wcgw-1.4.0}/.gitignore +0 -0
  25. {wcgw-1.2.2 → wcgw-1.4.0}/.python-version +0 -0
  26. {wcgw-1.2.2 → wcgw-1.4.0}/src/__init__.py +0 -0
  27. {wcgw-1.2.2 → wcgw-1.4.0}/src/wcgw/client/__init__.py +0 -0
  28. {wcgw-1.2.2 → wcgw-1.4.0}/src/wcgw/client/__main__.py +0 -0
  29. {wcgw-1.2.2 → wcgw-1.4.0}/src/wcgw/client/cli.py +0 -0
  30. {wcgw-1.2.2 → wcgw-1.4.0}/src/wcgw/client/common.py +0 -0
  31. {wcgw-1.2.2 → wcgw-1.4.0}/src/wcgw/client/openai_utils.py +0 -0
  32. {wcgw-1.2.2 → wcgw-1.4.0}/src/wcgw/relay/static/privacy.txt +0 -0
  33. {wcgw-1.2.2 → wcgw-1.4.0}/static/ss1.png +0 -0
  34. {wcgw-1.2.2 → wcgw-1.4.0}/tests/test_basic.py +0 -0
@@ -9,7 +9,8 @@
9
9
  ],
10
10
  "mypy-type-checker.args": [
11
11
  "--enable-incomplete-feature=NewGenericSyntax",
12
- "--strict"
12
+ "--strict",
13
+
13
14
  ],
14
15
  "editor.formatOnSave": true,
15
16
  "editor.renderWhitespace": "selection",
@@ -1,12 +1,13 @@
1
1
  Metadata-Version: 2.3
2
2
  Name: wcgw
3
- Version: 1.2.2
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
- $ uv tool run --python 3.12 wcgw@latest
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
- $ uv tool run --python 3.12 wcgw@latest
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
@@ -0,0 +1,6 @@
1
+ def add_numbers(a: int, b: int) -> int:
2
+ return a + b
3
+
4
+ # Test the function
5
+ result = add_numbers(5, 3)
6
+ print(f"5 + 3 = {result}")
@@ -0,0 +1,15 @@
1
+ {
2
+ "mcpServers": {
3
+ "wcgw": {
4
+ "command": "uvx",
5
+ "args": [
6
+ "--from",
7
+ "wcgw",
8
+ "wcgw_mcp"
9
+ ],
10
+ "protocol": "mcp",
11
+ "defaultModel": "claude-3-sonnet",
12
+ "maxTokens": 4096
13
+ }
14
+ }
15
+ }
@@ -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
- "user_id",
324
- "type"
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
- "user_id",
456
- "should_reset"
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.2.2"
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 = [
@@ -1,2 +1,3 @@
1
1
  from .client.cli import app
2
2
  from .client.tools import run as listen
3
+ from .client.mcp_server import main as mcp_server
@@ -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 a cli assistant.
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=8096,
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
+ ![mcp icon](https://github.com/rusiaaman/wcgw/blob/main/static/rocket-icon.png?raw=true)
25
+
26
+ Then ask claude to execute shell commands, read files, edit files, run your code, etc.
@@ -0,0 +1,11 @@
1
+ from wcgw.client.mcp_server import server
2
+ import asyncio
3
+
4
+
5
+ def main():
6
+ """Main entry point for the package."""
7
+ asyncio.run(server.main())
8
+
9
+
10
+ # Optionally expose other important items at package level
11
+ __all__ = ["main", "server"]
@@ -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 a cli assistant.
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=2048,
344
+ max_tokens=8000,
345
345
  )
346
346
  except Exception as e:
347
347
  output_or_done = (