wcgw 2.8.7__py3-none-any.whl → 2.8.9__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/tools.py +15 -3
- {wcgw-2.8.7.dist-info → wcgw-2.8.9.dist-info}/METADATA +1 -1
- {wcgw-2.8.7.dist-info → wcgw-2.8.9.dist-info}/RECORD +7 -7
- wcgw_cli/anthropic_client.py +82 -10
- {wcgw-2.8.7.dist-info → wcgw-2.8.9.dist-info}/WHEEL +0 -0
- {wcgw-2.8.7.dist-info → wcgw-2.8.9.dist-info}/entry_points.txt +0 -0
- {wcgw-2.8.7.dist-info → wcgw-2.8.9.dist-info}/licenses/LICENSE +0 -0
wcgw/client/tools.py
CHANGED
|
@@ -146,6 +146,7 @@ def start_shell(is_restricted_mode: bool, initial_dir: str) -> pexpect.spawn: #
|
|
|
146
146
|
encoding="utf-8",
|
|
147
147
|
timeout=TIMEOUT,
|
|
148
148
|
cwd=initial_dir,
|
|
149
|
+
codec_errors="backslashreplace",
|
|
149
150
|
)
|
|
150
151
|
shell.sendline(
|
|
151
152
|
f"export PROMPT_COMMAND= PS1={PROMPT_CONST}"
|
|
@@ -161,6 +162,7 @@ def start_shell(is_restricted_mode: bool, initial_dir: str) -> pexpect.spawn: #
|
|
|
161
162
|
echo=False,
|
|
162
163
|
encoding="utf-8",
|
|
163
164
|
timeout=TIMEOUT,
|
|
165
|
+
codec_errors="backslashreplace",
|
|
164
166
|
)
|
|
165
167
|
shell.sendline(f"export PS1={PROMPT_CONST}")
|
|
166
168
|
shell.expect(PROMPT_CONST, timeout=TIMEOUT)
|
|
@@ -256,7 +258,9 @@ class BashState:
|
|
|
256
258
|
before = "\n".join(before_lines).strip()
|
|
257
259
|
counts += 1
|
|
258
260
|
if counts > 100:
|
|
259
|
-
raise ValueError(
|
|
261
|
+
raise ValueError(
|
|
262
|
+
"Error in understanding shell output. This shouldn't happen, likely shell is in a bad state, please reset it"
|
|
263
|
+
)
|
|
260
264
|
|
|
261
265
|
try:
|
|
262
266
|
return int(before)
|
|
@@ -273,7 +277,7 @@ class BashState:
|
|
|
273
277
|
self._bash_command_mode.bash_mode == "restricted_mode",
|
|
274
278
|
self._cwd,
|
|
275
279
|
)
|
|
276
|
-
|
|
280
|
+
|
|
277
281
|
self._pending_output = ""
|
|
278
282
|
|
|
279
283
|
# Get exit info to ensure shell is ready
|
|
@@ -414,7 +418,9 @@ class BashState:
|
|
|
414
418
|
index = self.shell.expect([self._prompt, pexpect.TIMEOUT], timeout=0.2)
|
|
415
419
|
counts += 1
|
|
416
420
|
if counts > 100:
|
|
417
|
-
raise ValueError(
|
|
421
|
+
raise ValueError(
|
|
422
|
+
"Error in understanding shell output. This shouldn't happen, likely shell is in a bad state, please reset it"
|
|
423
|
+
)
|
|
418
424
|
console.print(f"Prompt updated to: {self._prompt}")
|
|
419
425
|
return True
|
|
420
426
|
return False
|
|
@@ -457,6 +463,12 @@ def initialize(
|
|
|
457
463
|
folder_to_start = None
|
|
458
464
|
if any_workspace_path:
|
|
459
465
|
if os.path.exists(any_workspace_path):
|
|
466
|
+
if os.path.isfile(any_workspace_path):
|
|
467
|
+
# Set any_workspace_path to the directory containing the file
|
|
468
|
+
# Add the file to read_files_ only if empty to avoid duplicates
|
|
469
|
+
if not read_files_:
|
|
470
|
+
read_files_ = [any_workspace_path]
|
|
471
|
+
any_workspace_path = os.path.dirname(any_workspace_path)
|
|
460
472
|
repo_context, folder_to_start = get_repo_context(any_workspace_path, 200)
|
|
461
473
|
|
|
462
474
|
repo_context = f"---\n# Workspace structure\n{repo_context}\n---\n"
|
|
@@ -7,7 +7,7 @@ wcgw/client/diff-instructions.txt,sha256=tmJ9Fu9XdO_72lYXQQNY9RZyx91bjxrXJf9d_KB
|
|
|
7
7
|
wcgw/client/memory.py,sha256=8LdYsOhvCOoC1kfvDr85kNy07WnhPMvE6B2FRM2w85Y,2902
|
|
8
8
|
wcgw/client/modes.py,sha256=FkDJIgjKrlJEufLq3abWfqV25BdF2pH-HnoHafy9LrA,10484
|
|
9
9
|
wcgw/client/sys_utils.py,sha256=GajPntKhaTUMn6EOmopENWZNR2G_BJyuVbuot0x6veI,1376
|
|
10
|
-
wcgw/client/tools.py,sha256=
|
|
10
|
+
wcgw/client/tools.py,sha256=xgLsgkWZ5qRiLpdyF_1oKIJGy-tj9_WmJQW30-6KhhQ,52759
|
|
11
11
|
wcgw/client/file_ops/diff_edit.py,sha256=OlJCpPSE_3T41q9H0yDORm6trjm3w6zh1EkuPTxik2A,16832
|
|
12
12
|
wcgw/client/file_ops/search_replace.py,sha256=Napa7IWaYPGMNdttunKyRDkb90elZE7r23B_o_htRxo,5585
|
|
13
13
|
wcgw/client/mcp_server/Readme.md,sha256=I8N4dHkTUVGNQ63BQkBMBhCCBTgqGOSF_pUR6iOEiUk,2495
|
|
@@ -22,7 +22,7 @@ wcgw/relay/serve.py,sha256=Z5EwtaCAtKFBSnUw4mPYw0sze3Coc4Fa8gObRRG_bT0,9525
|
|
|
22
22
|
wcgw/relay/static/privacy.txt,sha256=s9qBdbx2SexCpC_z33sg16TptmAwDEehMCLz4L50JLc,529
|
|
23
23
|
wcgw_cli/__init__.py,sha256=TNxXsTPgb52OhakIda9wTRh91cqoBqgQRx5TxjzQQFU,21
|
|
24
24
|
wcgw_cli/__main__.py,sha256=wcCrL4PjG51r5wVKqJhcoJPTLfHW0wNbD31DrUN0MWI,28
|
|
25
|
-
wcgw_cli/anthropic_client.py,sha256=
|
|
25
|
+
wcgw_cli/anthropic_client.py,sha256=ZMFHD6g6h_PAReL8tubI8LnxVeRA3hcFLGNitjt9XhQ,24047
|
|
26
26
|
wcgw_cli/cli.py,sha256=GEje9ZBIaD5_-HK3zxZCGYaeDF8bfFxImloOR3O66Fw,1019
|
|
27
27
|
wcgw_cli/openai_client.py,sha256=wp4XDf3t3W6XG5LHgr6bFckePyty24BGtsOEjOrIrk0,17955
|
|
28
28
|
wcgw_cli/openai_utils.py,sha256=xGOb3W5ALrIozV7oszfGYztpj0FnXdD7jAxm5lEIVKY,2439
|
|
@@ -48,8 +48,8 @@ mcp_wcgw/shared/memory.py,sha256=dBsOghxHz8-tycdSVo9kSujbsC8xb_tYsGmuJobuZnw,281
|
|
|
48
48
|
mcp_wcgw/shared/progress.py,sha256=ymxOsb8XO5Mhlop7fRfdbmvPodANj7oq6O4dD0iUcnw,1048
|
|
49
49
|
mcp_wcgw/shared/session.py,sha256=e44a0LQOW8gwdLs9_DE9oDsxqW2U8mXG3d5KT95bn5o,10393
|
|
50
50
|
mcp_wcgw/shared/version.py,sha256=d2LZii-mgsPIxpshjkXnOTUmk98i0DT4ff8VpA_kAvE,111
|
|
51
|
-
wcgw-2.8.
|
|
52
|
-
wcgw-2.8.
|
|
53
|
-
wcgw-2.8.
|
|
54
|
-
wcgw-2.8.
|
|
55
|
-
wcgw-2.8.
|
|
51
|
+
wcgw-2.8.9.dist-info/METADATA,sha256=5QkVxDqkY5Flyvrua5JMbLoKnbdDlXfr4UdiLAJ3Ad0,13053
|
|
52
|
+
wcgw-2.8.9.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
|
|
53
|
+
wcgw-2.8.9.dist-info/entry_points.txt,sha256=vd3tj1_Kzfp55LscJ8-6WFMM5hm9cWTfNGFCrWBnH3Q,124
|
|
54
|
+
wcgw-2.8.9.dist-info/licenses/LICENSE,sha256=BvY8xqjOfc3X2qZpGpX3MZEmF-4Dp0LqgKBbT6L_8oI,11142
|
|
55
|
+
wcgw-2.8.9.dist-info/RECORD,,
|
wcgw_cli/anthropic_client.py
CHANGED
|
@@ -14,15 +14,17 @@ from anthropic import Anthropic
|
|
|
14
14
|
from anthropic.types import (
|
|
15
15
|
ImageBlockParam,
|
|
16
16
|
MessageParam,
|
|
17
|
+
ModelParam,
|
|
17
18
|
TextBlockParam,
|
|
18
19
|
ToolParam,
|
|
19
20
|
ToolResultBlockParam,
|
|
20
21
|
ToolUseBlockParam,
|
|
21
22
|
)
|
|
22
23
|
from dotenv import load_dotenv
|
|
24
|
+
from pydantic import BaseModel
|
|
23
25
|
from typer import Typer
|
|
24
26
|
|
|
25
|
-
from wcgw.client.common import discard_input
|
|
27
|
+
from wcgw.client.common import CostData, discard_input
|
|
26
28
|
from wcgw.client.memory import load_memory
|
|
27
29
|
from wcgw.client.tools import (
|
|
28
30
|
DoneFlag,
|
|
@@ -47,6 +49,14 @@ from wcgw.types_ import (
|
|
|
47
49
|
WriteIfEmpty,
|
|
48
50
|
)
|
|
49
51
|
|
|
52
|
+
|
|
53
|
+
class Config(BaseModel):
|
|
54
|
+
model: ModelParam
|
|
55
|
+
cost_limit: float
|
|
56
|
+
cost_file: dict[ModelParam, CostData]
|
|
57
|
+
cost_unit: str = "$"
|
|
58
|
+
|
|
59
|
+
|
|
50
60
|
History = list[MessageParam]
|
|
51
61
|
|
|
52
62
|
|
|
@@ -150,7 +160,51 @@ def loop(
|
|
|
150
160
|
first_message = ""
|
|
151
161
|
waiting_for_assistant = history[-1]["role"] != "assistant"
|
|
152
162
|
|
|
153
|
-
|
|
163
|
+
config = Config(
|
|
164
|
+
model="claude-3-5-sonnet-20241022",
|
|
165
|
+
cost_limit=0.1,
|
|
166
|
+
cost_unit="$",
|
|
167
|
+
cost_file={
|
|
168
|
+
# Claude 3.5 Haiku
|
|
169
|
+
"claude-3-5-haiku-latest": CostData(
|
|
170
|
+
cost_per_1m_input_tokens=0.80, cost_per_1m_output_tokens=4
|
|
171
|
+
),
|
|
172
|
+
"claude-3-5-haiku-20241022": CostData(
|
|
173
|
+
cost_per_1m_input_tokens=0.80, cost_per_1m_output_tokens=4
|
|
174
|
+
),
|
|
175
|
+
# Claude 3.5 Sonnet
|
|
176
|
+
"claude-3-5-sonnet-latest": CostData(
|
|
177
|
+
cost_per_1m_input_tokens=3.0, cost_per_1m_output_tokens=15.0
|
|
178
|
+
),
|
|
179
|
+
"claude-3-5-sonnet-20241022": CostData(
|
|
180
|
+
cost_per_1m_input_tokens=3.0, cost_per_1m_output_tokens=15.0
|
|
181
|
+
),
|
|
182
|
+
"claude-3-5-sonnet-20240620": CostData(
|
|
183
|
+
cost_per_1m_input_tokens=3.0, cost_per_1m_output_tokens=15.0
|
|
184
|
+
),
|
|
185
|
+
# Claude 3 Opus
|
|
186
|
+
"claude-3-opus-latest": CostData(
|
|
187
|
+
cost_per_1m_input_tokens=15.0, cost_per_1m_output_tokens=75.0
|
|
188
|
+
),
|
|
189
|
+
"claude-3-opus-20240229": CostData(
|
|
190
|
+
cost_per_1m_input_tokens=15.0, cost_per_1m_output_tokens=75.0
|
|
191
|
+
),
|
|
192
|
+
# Legacy Models
|
|
193
|
+
"claude-3-haiku-20240307": CostData(
|
|
194
|
+
cost_per_1m_input_tokens=0.25, cost_per_1m_output_tokens=1.25
|
|
195
|
+
),
|
|
196
|
+
"claude-2.1": CostData(
|
|
197
|
+
cost_per_1m_input_tokens=8.0, cost_per_1m_output_tokens=24.0
|
|
198
|
+
),
|
|
199
|
+
"claude-2.0": CostData(
|
|
200
|
+
cost_per_1m_input_tokens=8.0, cost_per_1m_output_tokens=24.0
|
|
201
|
+
),
|
|
202
|
+
},
|
|
203
|
+
)
|
|
204
|
+
|
|
205
|
+
if limit is not None:
|
|
206
|
+
config.cost_limit = limit
|
|
207
|
+
limit = config.cost_limit
|
|
154
208
|
|
|
155
209
|
tools = [
|
|
156
210
|
ToolParam(
|
|
@@ -321,9 +375,15 @@ Saves provided description and file contents of all the relevant file paths or g
|
|
|
321
375
|
while True:
|
|
322
376
|
if cost > limit:
|
|
323
377
|
system_console.print(
|
|
324
|
-
f"\nCost limit exceeded. Current cost: {
|
|
378
|
+
f"\nCost limit exceeded. Current cost: {config.cost_unit}{cost:.4f}, "
|
|
379
|
+
f"input tokens: {input_toks}"
|
|
380
|
+
f"output tokens: {output_toks}"
|
|
325
381
|
)
|
|
326
382
|
break
|
|
383
|
+
else:
|
|
384
|
+
system_console.print(
|
|
385
|
+
f"\nTotal cost: {config.cost_unit}{cost:.4f}, input tokens: {input_toks}, output tokens: {output_toks}"
|
|
386
|
+
)
|
|
327
387
|
|
|
328
388
|
if not waiting_for_assistant:
|
|
329
389
|
if first_message:
|
|
@@ -335,13 +395,8 @@ Saves provided description and file contents of all the relevant file paths or g
|
|
|
335
395
|
history.append(parse_user_message_special(msg))
|
|
336
396
|
else:
|
|
337
397
|
waiting_for_assistant = False
|
|
338
|
-
|
|
339
|
-
cost_, input_toks_ = 0, 0
|
|
340
|
-
cost += cost_
|
|
341
|
-
input_toks += input_toks_
|
|
342
|
-
|
|
343
398
|
stream = client.messages.stream(
|
|
344
|
-
model=
|
|
399
|
+
model=config.model,
|
|
345
400
|
messages=history,
|
|
346
401
|
tools=tools,
|
|
347
402
|
max_tokens=8096,
|
|
@@ -361,7 +416,24 @@ Saves provided description and file contents of all the relevant file paths or g
|
|
|
361
416
|
with stream as stream_:
|
|
362
417
|
for chunk in stream_:
|
|
363
418
|
type_ = chunk.type
|
|
364
|
-
if type_
|
|
419
|
+
if type_ == "message_start":
|
|
420
|
+
message_start = chunk.message
|
|
421
|
+
# Update cost based on token usage from the API response
|
|
422
|
+
input_tokens = message_start.usage.input_tokens
|
|
423
|
+
input_toks += input_tokens
|
|
424
|
+
cost += (
|
|
425
|
+
input_tokens
|
|
426
|
+
* config.cost_file[config.model].cost_per_1m_input_tokens
|
|
427
|
+
) / 1_000_000
|
|
428
|
+
elif type_ == "message_stop":
|
|
429
|
+
message_stop = chunk.message
|
|
430
|
+
# Update cost based on output tokens
|
|
431
|
+
output_tokens = message_stop.usage.output_tokens
|
|
432
|
+
output_toks += output_tokens
|
|
433
|
+
cost += (
|
|
434
|
+
output_tokens
|
|
435
|
+
* config.cost_file[config.model].cost_per_1m_output_tokens
|
|
436
|
+
) / 1_000_000
|
|
365
437
|
continue
|
|
366
438
|
elif type_ == "content_block_start" and hasattr(
|
|
367
439
|
chunk, "content_block"
|
|
File without changes
|
|
File without changes
|
|
File without changes
|