wcgw 2.8.10__py3-none-any.whl → 3.0.1rc1__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/py.typed ADDED
File without changes
wcgw/relay/client.py ADDED
@@ -0,0 +1,95 @@
1
+ import importlib.metadata
2
+ import os
3
+ import time
4
+ import traceback
5
+ import uuid
6
+ from typing import Optional
7
+
8
+ import rich
9
+ import typer
10
+ import websockets
11
+ from typer import Typer
12
+ from websockets.sync.client import connect as syncconnect
13
+
14
+ from ..client.bash_state.bash_state import BashState
15
+ from ..client.tools import Context, curr_cost, default_enc, get_tool_output
16
+ from ..types_ import Mdata
17
+
18
+
19
+ def register_client(server_url: str, client_uuid: str = "") -> None:
20
+ global default_enc, curr_cost
21
+ # Generate a unique UUID for this client
22
+ if not client_uuid:
23
+ client_uuid = str(uuid.uuid4())
24
+
25
+ # Create the WebSocket connection and context
26
+ the_console = rich.console.Console(style="magenta", highlight=False, markup=False)
27
+ with BashState(
28
+ the_console, os.getcwd(), None, None, None, None, False, None
29
+ ) as bash_state:
30
+ context = Context(bash_state=bash_state, console=the_console)
31
+
32
+ try:
33
+ with syncconnect(f"{server_url}/{client_uuid}") as websocket:
34
+ server_version = str(websocket.recv())
35
+ print(f"Server version: {server_version}")
36
+ client_version = importlib.metadata.version("wcgw")
37
+ websocket.send(client_version)
38
+
39
+ print(f"Connected. Share this user id with the chatbot: {client_uuid}")
40
+ while True:
41
+ # Wait to receive data from the server
42
+ message = websocket.recv()
43
+ mdata = Mdata.model_validate_json(message)
44
+ if isinstance(mdata.data, str):
45
+ raise Exception(mdata)
46
+ try:
47
+ outputs, cost = get_tool_output(
48
+ context,
49
+ mdata.data,
50
+ default_enc,
51
+ 0.0,
52
+ lambda x, y: ("", 0),
53
+ 8000,
54
+ )
55
+ output = outputs[0]
56
+ curr_cost += cost
57
+ print(f"{curr_cost=}")
58
+ except Exception as e:
59
+ output = f"GOT EXCEPTION while calling tool. Error: {e}"
60
+ context.console.print(traceback.format_exc())
61
+ assert isinstance(output, str)
62
+ websocket.send(output)
63
+
64
+ except (websockets.ConnectionClosed, ConnectionError, OSError):
65
+ print(f"Connection closed for UUID: {client_uuid}, retrying")
66
+ time.sleep(0.5)
67
+ register_client(server_url, client_uuid)
68
+
69
+
70
+ run = Typer(pretty_exceptions_show_locals=False, no_args_is_help=True)
71
+
72
+
73
+ @run.command()
74
+ def app(
75
+ server_url: str = "",
76
+ client_uuid: Optional[str] = None,
77
+ version: bool = typer.Option(False, "--version", "-v"),
78
+ ) -> None:
79
+ if version:
80
+ version_ = importlib.metadata.version("wcgw")
81
+ print(f"wcgw version: {version_}")
82
+ exit()
83
+ if not server_url:
84
+ server_url = os.environ.get("WCGW_RELAY_SERVER", "")
85
+ if not server_url:
86
+ print(
87
+ "Error: Please provide relay server url using --server_url or WCGW_RELAY_SERVER environment variable"
88
+ )
89
+ print(
90
+ "\tNOTE: you need to run a relay server first, author doesn't host a relay server anymore."
91
+ )
92
+ print("\thttps://github.com/rusiaaman/wcgw/blob/main/openai.md")
93
+ print("\tExample `--server-url=ws://localhost:8000/v1/register`")
94
+ raise typer.Exit(1)
95
+ register_client(server_url, client_uuid or "")
wcgw/relay/serve.py CHANGED
@@ -15,13 +15,11 @@ from pydantic import BaseModel
15
15
 
16
16
  from ..types_ import (
17
17
  BashCommand,
18
- BashInteraction,
19
18
  ContextSave,
20
19
  FileEdit,
21
- FileEditFindReplace,
22
20
  Initialize,
23
21
  ReadFiles,
24
- ResetShell,
22
+ ResetWcgw,
25
23
  WriteIfEmpty,
26
24
  )
27
25
 
@@ -29,10 +27,8 @@ from ..types_ import (
29
27
  class Mdata(BaseModel):
30
28
  data: (
31
29
  BashCommand
32
- | BashInteraction
33
30
  | WriteIfEmpty
34
- | ResetShell
35
- | FileEditFindReplace
31
+ | ResetWcgw
36
32
  | FileEdit
37
33
  | ReadFiles
38
34
  | Initialize
@@ -164,13 +160,13 @@ async def file_edit_find_replace(
164
160
  raise fastapi.HTTPException(status_code=500, detail="Timeout error")
165
161
 
166
162
 
167
- class ResetShellWithUUID(ResetShell):
163
+ class ResetWcgwWithUUID(ResetWcgw):
168
164
  user_id: UUID
169
165
 
170
166
 
171
- @app.post("/v1/reset_shell")
172
- async def reset_shell(reset_shell: ResetShellWithUUID) -> str:
173
- user_id = reset_shell.user_id
167
+ @app.post("/v1/reset_wcgw")
168
+ async def reset_wcgw(reset_wcgw: ResetWcgwWithUUID) -> str:
169
+ user_id = reset_wcgw.user_id
174
170
  if user_id not in clients:
175
171
  return "Failure: id not found, ask the user to check it."
176
172
 
@@ -182,7 +178,7 @@ async def reset_shell(reset_shell: ResetShellWithUUID) -> str:
182
178
 
183
179
  gpts[user_id] = put_results
184
180
 
185
- await clients[user_id](Mdata(data=reset_shell, user_id=user_id))
181
+ await clients[user_id](Mdata(data=reset_wcgw, user_id=user_id))
186
182
 
187
183
  start_time = time.time()
188
184
  while time.time() - start_time < 30:
@@ -193,8 +189,7 @@ async def reset_shell(reset_shell: ResetShellWithUUID) -> str:
193
189
  raise fastapi.HTTPException(status_code=500, detail="Timeout error")
194
190
 
195
191
 
196
- class CommandWithUUID(BaseModel):
197
- command: str
192
+ class CommandWithUUID(BashCommand):
198
193
  user_id: UUID
199
194
 
200
195
 
@@ -212,40 +207,11 @@ async def bash_command(command: CommandWithUUID) -> str:
212
207
 
213
208
  gpts[user_id] = put_results
214
209
 
215
- await clients[user_id](
216
- Mdata(data=BashCommand(command=command.command), user_id=user_id)
217
- )
218
-
219
- start_time = time.time()
220
- while time.time() - start_time < 30:
221
- if results is not None:
222
- return results
223
- await asyncio.sleep(0.1)
224
-
225
- raise fastapi.HTTPException(status_code=500, detail="Timeout error")
226
-
227
-
228
- class BashInteractionWithUUID(BashInteraction):
229
- user_id: UUID
230
-
231
-
232
- @app.post("/v1/bash_interaction")
233
- async def bash_interaction(bash_interaction: BashInteractionWithUUID) -> str:
234
- user_id = bash_interaction.user_id
235
- if user_id not in clients:
236
- return "Failure: id not found, ask the user to check it."
237
-
238
- results: Optional[str] = None
239
-
240
- def put_results(result: str) -> None:
241
- nonlocal results
242
- results = result
243
-
244
- gpts[user_id] = put_results
245
-
246
210
  await clients[user_id](
247
211
  Mdata(
248
- data=bash_interaction,
212
+ data=BashCommand(
213
+ action=command.action, wait_for_seconds=command.wait_for_seconds
214
+ ),
249
215
  user_id=user_id,
250
216
  )
251
217
  )
wcgw/types_.py CHANGED
@@ -1,6 +1,6 @@
1
1
  import os
2
2
  from enum import Enum
3
- from typing import Any, Literal, Optional, Sequence, Union
3
+ from typing import Any, Literal, Optional, Protocol, Sequence, Union
4
4
 
5
5
  from pydantic import BaseModel as PydanticBaseModel
6
6
 
@@ -44,9 +44,9 @@ class Initialize(BaseModel):
44
44
 
45
45
  def model_post_init(self, __context: Any) -> None:
46
46
  if self.mode_name == "code_writer":
47
- assert (
48
- self.code_writer_config is not None
49
- ), "code_writer_config can't be null when the mode is code_writer"
47
+ assert self.code_writer_config is not None, (
48
+ "code_writer_config can't be null when the mode is code_writer"
49
+ )
50
50
  return super().model_post_init(__context)
51
51
 
52
52
  @property
@@ -55,27 +55,40 @@ class Initialize(BaseModel):
55
55
  return "wcgw"
56
56
  if self.mode_name == "architect":
57
57
  return "architect"
58
- assert (
59
- self.code_writer_config is not None
60
- ), "code_writer_config can't be null when the mode is code_writer"
58
+ assert self.code_writer_config is not None, (
59
+ "code_writer_config can't be null when the mode is code_writer"
60
+ )
61
61
  return self.code_writer_config
62
62
 
63
63
 
64
- class BashCommand(BaseModel):
64
+ class Command(BaseModel):
65
65
  command: str
66
- wait_for_seconds: Optional[int] = None
66
+
67
+
68
+ class StatusCheck(BaseModel):
69
+ status_check: Literal[True]
70
+
71
+
72
+ class SendText(BaseModel):
73
+ send_text: str
67
74
 
68
75
 
69
76
  Specials = Literal[
70
- "Key-up", "Key-down", "Key-left", "Key-right", "Enter", "Ctrl-c", "Ctrl-d", "Ctrl-z"
77
+ "Enter", "Key-up", "Key-down", "Key-left", "Key-right", "Ctrl-c", "Ctrl-d", "Ctrl-z"
71
78
  ]
72
79
 
73
80
 
74
- class BashInteraction(BaseModel):
75
- send_text: Optional[str] = None
76
- send_specials: Optional[Sequence[Specials]] = None
77
- send_ascii: Optional[Sequence[int]] = None
78
- wait_for_seconds: Optional[int] = None
81
+ class SendSpecials(BaseModel):
82
+ send_specials: Sequence[Specials]
83
+
84
+
85
+ class SendAscii(BaseModel):
86
+ send_ascii: Sequence[int]
87
+
88
+
89
+ class BashCommand(BaseModel):
90
+ action: Command | StatusCheck | SendText | SendSpecials | SendAscii
91
+ wait_for_seconds: Optional[float] = None
79
92
 
80
93
 
81
94
  class ReadImage(BaseModel):
@@ -91,14 +104,11 @@ class ReadFiles(BaseModel):
91
104
  file_paths: list[str]
92
105
 
93
106
 
94
- class FileEditFindReplace(BaseModel):
95
- file_path: str
96
- find_lines: str
97
- replace_with_lines: str
98
-
99
-
100
- class ResetShell(BaseModel):
107
+ class ResetWcgw(BaseModel):
101
108
  should_reset: Literal[True]
109
+ change_mode: Optional[Literal["wcgw", "architect", "code_writer"]]
110
+ code_writer_config: Optional[CodeWriterMode] = None
111
+ starting_directory: str
102
112
 
103
113
 
104
114
  class FileEdit(BaseModel):
@@ -106,47 +116,27 @@ class FileEdit(BaseModel):
106
116
  file_edit_using_search_replace_blocks: str
107
117
 
108
118
 
109
- class GetScreenInfo(BaseModel):
110
- docker_image_id: str
111
-
112
-
113
- class ScreenShot(BaseModel):
114
- take_after_delay_seconds: int
115
-
116
-
117
- class MouseMove(BaseModel):
118
- x: int
119
- y: int
120
- do_left_click_on_move: bool
121
-
122
-
123
- class LeftClickDrag(BaseModel):
124
- x: int
125
- y: int
126
-
127
-
128
- class MouseButton(BaseModel):
129
- button_type: Literal[
130
- "left_click",
131
- "right_click",
132
- "middle_click",
133
- "double_click",
134
- "scroll_up",
135
- "scroll_down",
136
- ]
137
-
138
-
139
- class Mouse(BaseModel):
140
- action: MouseButton | LeftClickDrag | MouseMove
141
-
142
-
143
- class Keyboard(BaseModel):
144
- action: Literal["key", "type"]
145
- text: str
146
-
147
-
148
119
  class ContextSave(BaseModel):
149
120
  id: str
150
121
  project_root_path: str
151
122
  description: str
152
123
  relevant_file_globs: list[str]
124
+
125
+
126
+ class Console(Protocol):
127
+ def print(self, msg: str, *args: Any, **kwargs: Any) -> None: ...
128
+
129
+ def log(self, msg: str, *args: Any, **kwargs: Any) -> None: ...
130
+
131
+
132
+ class Mdata(PydanticBaseModel):
133
+ data: (
134
+ BashCommand
135
+ | WriteIfEmpty
136
+ | ResetWcgw
137
+ | FileEdit
138
+ | str
139
+ | ReadFiles
140
+ | Initialize
141
+ | ContextSave
142
+ )
@@ -1,11 +1,11 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: wcgw
3
- Version: 2.8.10
3
+ Version: 3.0.1rc1
4
4
  Summary: Shell and coding agent on claude and chatgpt
5
5
  Project-URL: Homepage, https://github.com/rusiaaman/wcgw
6
6
  Author-email: Aman Rusia <gapypi@arcfu.com>
7
7
  License-File: LICENSE
8
- Requires-Python: <3.13,>=3.11
8
+ Requires-Python: >=3.11
9
9
  Requires-Dist: anthropic>=0.39.0
10
10
  Requires-Dist: fastapi>=0.115.0
11
11
  Requires-Dist: openai>=1.46.0
@@ -22,7 +22,6 @@ Requires-Dist: syntax-checker>=0.3.0
22
22
  Requires-Dist: tokenizers>=0.21.0
23
23
  Requires-Dist: toml>=0.10.2
24
24
  Requires-Dist: typer>=0.12.5
25
- Requires-Dist: types-pexpect>=4.9.0.20240806
26
25
  Requires-Dist: uvicorn>=0.31.0
27
26
  Requires-Dist: websockets>=13.1
28
27
  Description-Content-Type: text/markdown
@@ -1,30 +1,33 @@
1
- wcgw/__init__.py,sha256=sQZHC74HPFyE9XqWZDCVmgdBXVK1xkHrMtMSLBZ5BOY,90
2
- wcgw/types_.py,sha256=D3518a2azSKeW3D-ACYWJwsaqo7Oj-8BRRR2IhCUtNU,3414
1
+ wcgw/__init__.py,sha256=qUofQOAXCGcWr2u_B8U-MIMhhYaBUpUwNDcscvRmYfo,90
2
+ wcgw/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
3
+ wcgw/types_.py,sha256=_r4H9Kebu22nSxD8wvtGhAOGlJheshLBggI2IE9F7tY,3355
3
4
  wcgw/client/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
4
5
  wcgw/client/common.py,sha256=OCH7Tx64jojz3M3iONUrGMadE07W21DiZs5sOxWX1Qc,1456
5
- wcgw/client/computer_use.py,sha256=35NKAlMrxwD0TBlMMRnbCwz4g8TBRGOlcy-cmS-yJ_A,15247
6
6
  wcgw/client/diff-instructions.txt,sha256=tmJ9Fu9XdO_72lYXQQNY9RZyx91bjxrXJf9d_KBz57k,1611
7
7
  wcgw/client/memory.py,sha256=8LdYsOhvCOoC1kfvDr85kNy07WnhPMvE6B2FRM2w85Y,2902
8
- wcgw/client/modes.py,sha256=FkDJIgjKrlJEufLq3abWfqV25BdF2pH-HnoHafy9LrA,10484
9
- wcgw/client/sys_utils.py,sha256=GajPntKhaTUMn6EOmopENWZNR2G_BJyuVbuot0x6veI,1376
10
- wcgw/client/tools.py,sha256=c-LipooLb6XBF9l-qwJlzBLzznlqQQuCXRB9HSZJFT0,53450
8
+ wcgw/client/modes.py,sha256=dBkiMNQevTFNkhplrDsDuSIyeU-wLmAIfAa9Dqowvk8,10387
9
+ wcgw/client/tool_prompts.py,sha256=j82aYnlr1pcinsOYitSrlyYz4-9K3KcqnAfGqot21NQ,4158
10
+ wcgw/client/tools.py,sha256=djXlF83gp07nFl-jmYaufrxiSVCI1aoEyGLs9RBgRRs,22622
11
+ wcgw/client/bash_state/bash_state.py,sha256=IG2IdGhMEYyDsH7MUhu4pvlfWtIDAeXv4yuAs-CZ1GY,26184
12
+ wcgw/client/encoder/__init__.py,sha256=Y-8f43I6gMssUCWpX5rLYiAFv3D-JPRs4uNEejPlke8,1514
11
13
  wcgw/client/file_ops/diff_edit.py,sha256=OlJCpPSE_3T41q9H0yDORm6trjm3w6zh1EkuPTxik2A,16832
12
14
  wcgw/client/file_ops/search_replace.py,sha256=Napa7IWaYPGMNdttunKyRDkb90elZE7r23B_o_htRxo,5585
13
- wcgw/client/mcp_server/Readme.md,sha256=I8N4dHkTUVGNQ63BQkBMBhCCBTgqGOSF_pUR6iOEiUk,2495
14
- wcgw/client/mcp_server/__init__.py,sha256=hyPPwO9cabAJsOMWhKyat9yl7OlSmIobaoAZKHu3DMc,381
15
- wcgw/client/mcp_server/server.py,sha256=zMVa2nR2hapQZAtR34POch3VLVEEnJ6SQ8iWYLDxJrU,13199
16
- wcgw/client/repo_ops/display_tree.py,sha256=5FD4hfMkM2cIZnXlu7WfJswJLthj0SkuHlkGH6dpWQU,4632
15
+ wcgw/client/mcp_server/Readme.md,sha256=2Z88jj1mf9daYGW1CWaldcJ0moy8owDumhR2glBY3A8,109
16
+ wcgw/client/mcp_server/__init__.py,sha256=mm7xhBIPwJpRT3u-Qsj4cKVMpVyucJoKRlbMP_gRRB0,343
17
+ wcgw/client/mcp_server/server.py,sha256=3IEZqKNCiJl8J7Ibcksy4nlwW7yNtCnRK6RyE-jPuTo,5372
18
+ wcgw/client/repo_ops/display_tree.py,sha256=E5q9mrGBb57NyvudSmRIG-fj4FUqupbzjmARpX8X0XY,4166
17
19
  wcgw/client/repo_ops/path_prob.py,sha256=SWf0CDn37rtlsYRQ51ufSxay-heaQoVIhr1alB9tZ4M,2144
18
20
  wcgw/client/repo_ops/paths_model.vocab,sha256=M1pXycYDQehMXtpp-qAgU7rtzeBbCOiJo4qcYFY0kqk,315087
19
21
  wcgw/client/repo_ops/paths_tokens.model,sha256=jiwwE4ae8ADKuTZISutXuM5Wfyc_FBmN5rxTjoNnCos,1569052
20
22
  wcgw/client/repo_ops/repo_context.py,sha256=5NqRxBY0K-SBFXJ0Ybt7llzYOBD8pRkTpruMMJHWxv4,4336
21
- wcgw/relay/serve.py,sha256=Z5EwtaCAtKFBSnUw4mPYw0sze3Coc4Fa8gObRRG_bT0,9525
23
+ wcgw/relay/client.py,sha256=HU3gzVaYRRiCZedQTEtV-iN8JI--A_St2hTbeOYOFOw,3619
24
+ wcgw/relay/serve.py,sha256=Ofq6PjW3zVVA2-9MVviGRiUESTD3sXb-482Q4RV13q8,8664
22
25
  wcgw/relay/static/privacy.txt,sha256=s9qBdbx2SexCpC_z33sg16TptmAwDEehMCLz4L50JLc,529
23
26
  wcgw_cli/__init__.py,sha256=TNxXsTPgb52OhakIda9wTRh91cqoBqgQRx5TxjzQQFU,21
24
27
  wcgw_cli/__main__.py,sha256=wcCrL4PjG51r5wVKqJhcoJPTLfHW0wNbD31DrUN0MWI,28
25
- wcgw_cli/anthropic_client.py,sha256=ZMFHD6g6h_PAReL8tubI8LnxVeRA3hcFLGNitjt9XhQ,24047
26
- wcgw_cli/cli.py,sha256=GEje9ZBIaD5_-HK3zxZCGYaeDF8bfFxImloOR3O66Fw,1019
27
- wcgw_cli/openai_client.py,sha256=wp4XDf3t3W6XG5LHgr6bFckePyty24BGtsOEjOrIrk0,17955
28
+ wcgw_cli/anthropic_client.py,sha256=sRpu9L9yhYgk-XPkiUDPkxUqeB5jX28qBQPQ6o5YSaQ,18968
29
+ wcgw_cli/cli.py,sha256=-7FBe_lahKyUOhf65iurTA1M1gXXXAiT0OVKQVcZKKo,948
30
+ wcgw_cli/openai_client.py,sha256=sVIJ0VEe--TTV3M2uoWMMJVZltiXCXxJaQD6AF0OraM,15996
28
31
  wcgw_cli/openai_utils.py,sha256=xGOb3W5ALrIozV7oszfGYztpj0FnXdD7jAxm5lEIVKY,2439
29
32
  mcp_wcgw/__init__.py,sha256=fKCgOdN7cn7gR3YGFaGyV5Goe8A2sEyllLcsRkN0i-g,2601
30
33
  mcp_wcgw/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
@@ -48,8 +51,8 @@ mcp_wcgw/shared/memory.py,sha256=dBsOghxHz8-tycdSVo9kSujbsC8xb_tYsGmuJobuZnw,281
48
51
  mcp_wcgw/shared/progress.py,sha256=ymxOsb8XO5Mhlop7fRfdbmvPodANj7oq6O4dD0iUcnw,1048
49
52
  mcp_wcgw/shared/session.py,sha256=e44a0LQOW8gwdLs9_DE9oDsxqW2U8mXG3d5KT95bn5o,10393
50
53
  mcp_wcgw/shared/version.py,sha256=d2LZii-mgsPIxpshjkXnOTUmk98i0DT4ff8VpA_kAvE,111
51
- wcgw-2.8.10.dist-info/METADATA,sha256=-bjtkmro5UQVMBYYzxbakEIADO-VOpONetLtwxb1vX4,13054
52
- wcgw-2.8.10.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
53
- wcgw-2.8.10.dist-info/entry_points.txt,sha256=vd3tj1_Kzfp55LscJ8-6WFMM5hm9cWTfNGFCrWBnH3Q,124
54
- wcgw-2.8.10.dist-info/licenses/LICENSE,sha256=BvY8xqjOfc3X2qZpGpX3MZEmF-4Dp0LqgKBbT6L_8oI,11142
55
- wcgw-2.8.10.dist-info/RECORD,,
54
+ wcgw-3.0.1rc1.dist-info/METADATA,sha256=G7TKicqyb4Lo8_djHNi9Fm2PQ1w_DYBDY3BvrIazTvY,13005
55
+ wcgw-3.0.1rc1.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
56
+ wcgw-3.0.1rc1.dist-info/entry_points.txt,sha256=vd3tj1_Kzfp55LscJ8-6WFMM5hm9cWTfNGFCrWBnH3Q,124
57
+ wcgw-3.0.1rc1.dist-info/licenses/LICENSE,sha256=BvY8xqjOfc3X2qZpGpX3MZEmF-4Dp0LqgKBbT6L_8oI,11142
58
+ wcgw-3.0.1rc1.dist-info/RECORD,,