wcgw 2.8.7__tar.gz → 2.8.10__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-2.8.7 → wcgw-2.8.10}/PKG-INFO +1 -1
- {wcgw-2.8.7 → wcgw-2.8.10}/pyproject.toml +1 -1
- {wcgw-2.8.7 → wcgw-2.8.10}/src/mcp_wcgw_fork/src/mcp_wcgw/types.py +1 -1
- {wcgw-2.8.7 → wcgw-2.8.10}/src/wcgw/client/tools.py +43 -6
- {wcgw-2.8.7 → wcgw-2.8.10}/src/wcgw_cli/anthropic_client.py +82 -10
- {wcgw-2.8.7 → wcgw-2.8.10}/tests/test_initialize.py +75 -0
- {wcgw-2.8.7 → wcgw-2.8.10}/uv.lock +1 -1
- {wcgw-2.8.7 → wcgw-2.8.10}/.github/workflows/python-publish.yml +0 -0
- {wcgw-2.8.7 → wcgw-2.8.10}/.github/workflows/python-tests.yml +0 -0
- {wcgw-2.8.7 → wcgw-2.8.10}/.github/workflows/python-types.yml +0 -0
- {wcgw-2.8.7 → wcgw-2.8.10}/.gitignore +0 -0
- {wcgw-2.8.7 → wcgw-2.8.10}/.gitmodules +0 -0
- {wcgw-2.8.7 → wcgw-2.8.10}/.python-version +0 -0
- {wcgw-2.8.7 → wcgw-2.8.10}/.vscode/settings.json +0 -0
- {wcgw-2.8.7 → wcgw-2.8.10}/Dockerfile +0 -0
- {wcgw-2.8.7 → wcgw-2.8.10}/LICENSE +0 -0
- {wcgw-2.8.7 → wcgw-2.8.10}/README.md +0 -0
- {wcgw-2.8.7 → wcgw-2.8.10}/gpt_action_json_schema.json +0 -0
- {wcgw-2.8.7 → wcgw-2.8.10}/gpt_instructions.txt +0 -0
- {wcgw-2.8.7 → wcgw-2.8.10}/openai.md +0 -0
- {wcgw-2.8.7 → wcgw-2.8.10}/src/__init__.py +0 -0
- {wcgw-2.8.7 → wcgw-2.8.10}/src/mcp_wcgw_fork/.git +0 -0
- {wcgw-2.8.7 → wcgw-2.8.10}/src/mcp_wcgw_fork/.github/ISSUE_TEMPLATE/bug_report.md +0 -0
- {wcgw-2.8.7 → wcgw-2.8.10}/src/mcp_wcgw_fork/.github/ISSUE_TEMPLATE/feature_request.md +0 -0
- {wcgw-2.8.7 → wcgw-2.8.10}/src/mcp_wcgw_fork/.github/workflows/main-checks.yml +0 -0
- {wcgw-2.8.7 → wcgw-2.8.10}/src/mcp_wcgw_fork/.github/workflows/publish-pypi.yml +0 -0
- {wcgw-2.8.7 → wcgw-2.8.10}/src/mcp_wcgw_fork/.github/workflows/pull-request-checks.yml +0 -0
- {wcgw-2.8.7 → wcgw-2.8.10}/src/mcp_wcgw_fork/.github/workflows/shared.yml +0 -0
- {wcgw-2.8.7 → wcgw-2.8.10}/src/mcp_wcgw_fork/.gitignore +0 -0
- {wcgw-2.8.7 → wcgw-2.8.10}/src/mcp_wcgw_fork/.python-version +0 -0
- {wcgw-2.8.7 → wcgw-2.8.10}/src/mcp_wcgw_fork/CODE_OF_CONDUCT.md +0 -0
- {wcgw-2.8.7 → wcgw-2.8.10}/src/mcp_wcgw_fork/CONTRIBUTING.md +0 -0
- {wcgw-2.8.7 → wcgw-2.8.10}/src/mcp_wcgw_fork/LICENSE +0 -0
- {wcgw-2.8.7 → wcgw-2.8.10}/src/mcp_wcgw_fork/README.md +0 -0
- {wcgw-2.8.7 → wcgw-2.8.10}/src/mcp_wcgw_fork/RELEASE.md +0 -0
- {wcgw-2.8.7 → wcgw-2.8.10}/src/mcp_wcgw_fork/SECURITY.md +0 -0
- {wcgw-2.8.7 → wcgw-2.8.10}/src/mcp_wcgw_fork/examples/README.md +0 -0
- {wcgw-2.8.7 → wcgw-2.8.10}/src/mcp_wcgw_fork/examples/servers/simple-prompt/.python-version +0 -0
- {wcgw-2.8.7 → wcgw-2.8.10}/src/mcp_wcgw_fork/examples/servers/simple-prompt/README.md +0 -0
- {wcgw-2.8.7 → wcgw-2.8.10}/src/mcp_wcgw_fork/examples/servers/simple-prompt/mcp_simple_prompt/__init__.py +0 -0
- {wcgw-2.8.7 → wcgw-2.8.10}/src/mcp_wcgw_fork/examples/servers/simple-prompt/mcp_simple_prompt/__main__.py +0 -0
- {wcgw-2.8.7 → wcgw-2.8.10}/src/mcp_wcgw_fork/examples/servers/simple-prompt/mcp_simple_prompt/server.py +0 -0
- {wcgw-2.8.7 → wcgw-2.8.10}/src/mcp_wcgw_fork/examples/servers/simple-prompt/pyproject.toml +0 -0
- {wcgw-2.8.7 → wcgw-2.8.10}/src/mcp_wcgw_fork/examples/servers/simple-resource/.python-version +0 -0
- {wcgw-2.8.7 → wcgw-2.8.10}/src/mcp_wcgw_fork/examples/servers/simple-resource/README.md +0 -0
- {wcgw-2.8.7 → wcgw-2.8.10}/src/mcp_wcgw_fork/examples/servers/simple-resource/mcp_simple_resource/__init__.py +0 -0
- {wcgw-2.8.7 → wcgw-2.8.10}/src/mcp_wcgw_fork/examples/servers/simple-resource/mcp_simple_resource/__main__.py +0 -0
- {wcgw-2.8.7 → wcgw-2.8.10}/src/mcp_wcgw_fork/examples/servers/simple-resource/mcp_simple_resource/server.py +0 -0
- {wcgw-2.8.7 → wcgw-2.8.10}/src/mcp_wcgw_fork/examples/servers/simple-resource/pyproject.toml +0 -0
- {wcgw-2.8.7 → wcgw-2.8.10}/src/mcp_wcgw_fork/examples/servers/simple-tool/.python-version +0 -0
- {wcgw-2.8.7 → wcgw-2.8.10}/src/mcp_wcgw_fork/examples/servers/simple-tool/README.md +0 -0
- {wcgw-2.8.7 → wcgw-2.8.10}/src/mcp_wcgw_fork/examples/servers/simple-tool/mcp_simple_tool/__init__.py +0 -0
- {wcgw-2.8.7 → wcgw-2.8.10}/src/mcp_wcgw_fork/examples/servers/simple-tool/mcp_simple_tool/__main__.py +0 -0
- {wcgw-2.8.7 → wcgw-2.8.10}/src/mcp_wcgw_fork/examples/servers/simple-tool/mcp_simple_tool/server.py +0 -0
- {wcgw-2.8.7 → wcgw-2.8.10}/src/mcp_wcgw_fork/examples/servers/simple-tool/pyproject.toml +0 -0
- {wcgw-2.8.7 → wcgw-2.8.10}/src/mcp_wcgw_fork/pyproject.toml +0 -0
- {wcgw-2.8.7 → wcgw-2.8.10}/src/mcp_wcgw_fork/src/mcp_wcgw/__init__.py +0 -0
- {wcgw-2.8.7 → wcgw-2.8.10}/src/mcp_wcgw_fork/src/mcp_wcgw/client/__init__.py +0 -0
- {wcgw-2.8.7 → wcgw-2.8.10}/src/mcp_wcgw_fork/src/mcp_wcgw/client/__main__.py +0 -0
- {wcgw-2.8.7 → wcgw-2.8.10}/src/mcp_wcgw_fork/src/mcp_wcgw/client/session.py +0 -0
- {wcgw-2.8.7 → wcgw-2.8.10}/src/mcp_wcgw_fork/src/mcp_wcgw/client/sse.py +0 -0
- {wcgw-2.8.7 → wcgw-2.8.10}/src/mcp_wcgw_fork/src/mcp_wcgw/client/stdio.py +0 -0
- {wcgw-2.8.7 → wcgw-2.8.10}/src/mcp_wcgw_fork/src/mcp_wcgw/py.typed +0 -0
- {wcgw-2.8.7 → wcgw-2.8.10}/src/mcp_wcgw_fork/src/mcp_wcgw/server/__init__.py +0 -0
- {wcgw-2.8.7 → wcgw-2.8.10}/src/mcp_wcgw_fork/src/mcp_wcgw/server/__main__.py +0 -0
- {wcgw-2.8.7 → wcgw-2.8.10}/src/mcp_wcgw_fork/src/mcp_wcgw/server/models.py +0 -0
- {wcgw-2.8.7 → wcgw-2.8.10}/src/mcp_wcgw_fork/src/mcp_wcgw/server/session.py +0 -0
- {wcgw-2.8.7 → wcgw-2.8.10}/src/mcp_wcgw_fork/src/mcp_wcgw/server/sse.py +0 -0
- {wcgw-2.8.7 → wcgw-2.8.10}/src/mcp_wcgw_fork/src/mcp_wcgw/server/stdio.py +0 -0
- {wcgw-2.8.7 → wcgw-2.8.10}/src/mcp_wcgw_fork/src/mcp_wcgw/server/websocket.py +0 -0
- {wcgw-2.8.7 → wcgw-2.8.10}/src/mcp_wcgw_fork/src/mcp_wcgw/shared/__init__.py +0 -0
- {wcgw-2.8.7 → wcgw-2.8.10}/src/mcp_wcgw_fork/src/mcp_wcgw/shared/context.py +0 -0
- {wcgw-2.8.7 → wcgw-2.8.10}/src/mcp_wcgw_fork/src/mcp_wcgw/shared/exceptions.py +0 -0
- {wcgw-2.8.7 → wcgw-2.8.10}/src/mcp_wcgw_fork/src/mcp_wcgw/shared/memory.py +0 -0
- {wcgw-2.8.7 → wcgw-2.8.10}/src/mcp_wcgw_fork/src/mcp_wcgw/shared/progress.py +0 -0
- {wcgw-2.8.7 → wcgw-2.8.10}/src/mcp_wcgw_fork/src/mcp_wcgw/shared/session.py +0 -0
- {wcgw-2.8.7 → wcgw-2.8.10}/src/mcp_wcgw_fork/src/mcp_wcgw/shared/version.py +0 -0
- {wcgw-2.8.7 → wcgw-2.8.10}/src/mcp_wcgw_fork/tests/__init__.py +0 -0
- {wcgw-2.8.7 → wcgw-2.8.10}/src/mcp_wcgw_fork/tests/client/__init__.py +0 -0
- {wcgw-2.8.7 → wcgw-2.8.10}/src/mcp_wcgw_fork/tests/client/test_session.py +0 -0
- {wcgw-2.8.7 → wcgw-2.8.10}/src/mcp_wcgw_fork/tests/client/test_stdio.py +0 -0
- {wcgw-2.8.7 → wcgw-2.8.10}/src/mcp_wcgw_fork/tests/conftest.py +0 -0
- {wcgw-2.8.7 → wcgw-2.8.10}/src/mcp_wcgw_fork/tests/server/__init__.py +0 -0
- {wcgw-2.8.7 → wcgw-2.8.10}/src/mcp_wcgw_fork/tests/server/test_session.py +0 -0
- {wcgw-2.8.7 → wcgw-2.8.10}/src/mcp_wcgw_fork/tests/server/test_stdio.py +0 -0
- {wcgw-2.8.7 → wcgw-2.8.10}/src/mcp_wcgw_fork/tests/shared/test_memory.py +0 -0
- {wcgw-2.8.7 → wcgw-2.8.10}/src/mcp_wcgw_fork/tests/test_types.py +0 -0
- {wcgw-2.8.7 → wcgw-2.8.10}/src/mcp_wcgw_fork/uv.lock +0 -0
- {wcgw-2.8.7 → wcgw-2.8.10}/src/wcgw/__init__.py +0 -0
- {wcgw-2.8.7 → wcgw-2.8.10}/src/wcgw/client/__init__.py +0 -0
- {wcgw-2.8.7 → wcgw-2.8.10}/src/wcgw/client/common.py +0 -0
- {wcgw-2.8.7 → wcgw-2.8.10}/src/wcgw/client/computer_use.py +0 -0
- {wcgw-2.8.7 → wcgw-2.8.10}/src/wcgw/client/diff-instructions.txt +0 -0
- {wcgw-2.8.7 → wcgw-2.8.10}/src/wcgw/client/file_ops/diff_edit.py +0 -0
- {wcgw-2.8.7 → wcgw-2.8.10}/src/wcgw/client/file_ops/search_replace.py +0 -0
- {wcgw-2.8.7 → wcgw-2.8.10}/src/wcgw/client/mcp_server/Readme.md +0 -0
- {wcgw-2.8.7 → wcgw-2.8.10}/src/wcgw/client/mcp_server/__init__.py +0 -0
- {wcgw-2.8.7 → wcgw-2.8.10}/src/wcgw/client/mcp_server/server.py +0 -0
- {wcgw-2.8.7 → wcgw-2.8.10}/src/wcgw/client/memory.py +0 -0
- {wcgw-2.8.7 → wcgw-2.8.10}/src/wcgw/client/modes.py +0 -0
- {wcgw-2.8.7 → wcgw-2.8.10}/src/wcgw/client/repo_ops/display_tree.py +0 -0
- {wcgw-2.8.7 → wcgw-2.8.10}/src/wcgw/client/repo_ops/path_prob.py +0 -0
- {wcgw-2.8.7 → wcgw-2.8.10}/src/wcgw/client/repo_ops/paths_model.vocab +0 -0
- {wcgw-2.8.7 → wcgw-2.8.10}/src/wcgw/client/repo_ops/paths_tokens.model +0 -0
- {wcgw-2.8.7 → wcgw-2.8.10}/src/wcgw/client/repo_ops/repo_context.py +0 -0
- {wcgw-2.8.7 → wcgw-2.8.10}/src/wcgw/client/sys_utils.py +0 -0
- {wcgw-2.8.7 → wcgw-2.8.10}/src/wcgw/relay/serve.py +0 -0
- {wcgw-2.8.7 → wcgw-2.8.10}/src/wcgw/relay/static/privacy.txt +0 -0
- {wcgw-2.8.7 → wcgw-2.8.10}/src/wcgw/types_.py +0 -0
- {wcgw-2.8.7 → wcgw-2.8.10}/src/wcgw_cli/__init__.py +0 -0
- {wcgw-2.8.7 → wcgw-2.8.10}/src/wcgw_cli/__main__.py +0 -0
- {wcgw-2.8.7 → wcgw-2.8.10}/src/wcgw_cli/cli.py +0 -0
- {wcgw-2.8.7 → wcgw-2.8.10}/src/wcgw_cli/openai_client.py +0 -0
- {wcgw-2.8.7 → wcgw-2.8.10}/src/wcgw_cli/openai_utils.py +0 -0
- {wcgw-2.8.7 → wcgw-2.8.10}/static/claude-ss.jpg +0 -0
- {wcgw-2.8.7 → wcgw-2.8.10}/static/computer-use.jpg +0 -0
- {wcgw-2.8.7 → wcgw-2.8.10}/static/example.jpg +0 -0
- {wcgw-2.8.7 → wcgw-2.8.10}/static/rocket-icon.png +0 -0
- {wcgw-2.8.7 → wcgw-2.8.10}/static/ss1.png +0 -0
- {wcgw-2.8.7 → wcgw-2.8.10}/tests/client/file_ops/test_diff_edit.py +0 -0
- {wcgw-2.8.7 → wcgw-2.8.10}/tests/client/file_ops/test_search_replace.py +0 -0
- {wcgw-2.8.7 → wcgw-2.8.10}/tests/client/repo_ops/__init__.py +0 -0
- {wcgw-2.8.7 → wcgw-2.8.10}/tests/client/repo_ops/test_display_tree.py +0 -0
- {wcgw-2.8.7 → wcgw-2.8.10}/tests/client/repo_ops/test_display_tree_simple.py +0 -0
- {wcgw-2.8.7 → wcgw-2.8.10}/tests/client/repo_ops/test_path_prob.py +0 -0
- {wcgw-2.8.7 → wcgw-2.8.10}/tests/client/repo_ops/test_repo_context.py +0 -0
- {wcgw-2.8.7 → wcgw-2.8.10}/tests/client/test_anthropic_client_utils.py +0 -0
- {wcgw-2.8.7 → wcgw-2.8.10}/tests/client/test_memory.py +0 -0
- {wcgw-2.8.7 → wcgw-2.8.10}/tests/client/test_openai_utils.py +0 -0
- {wcgw-2.8.7 → wcgw-2.8.10}/tests/client/test_tools_basic.py +0 -0
- {wcgw-2.8.7 → wcgw-2.8.10}/tests/client/test_tools_extended.py +0 -0
- {wcgw-2.8.7 → wcgw-2.8.10}/tests/client/test_tools_file_ops.py +0 -0
- {wcgw-2.8.7 → wcgw-2.8.10}/tests/client/test_tools_files.py +0 -0
- {wcgw-2.8.7 → wcgw-2.8.10}/tests/client/test_tools_shell.py +0 -0
- {wcgw-2.8.7 → wcgw-2.8.10}/tests/client/test_tools_validation.py +0 -0
- {wcgw-2.8.7 → wcgw-2.8.10}/tests/client/tools/__init__.py +0 -0
- {wcgw-2.8.7 → wcgw-2.8.10}/tests/client/tools/test_command_validation.py +0 -0
- {wcgw-2.8.7 → wcgw-2.8.10}/tests/client/tools/test_docker_operations.py +0 -0
- {wcgw-2.8.7 → wcgw-2.8.10}/tests/client/tools/test_error_handling.py +0 -0
- {wcgw-2.8.7 → wcgw-2.8.10}/tests/client/tools/test_error_handling_full.py +0 -0
- {wcgw-2.8.7 → wcgw-2.8.10}/tests/client/tools/test_execute_bash.py +0 -0
- {wcgw-2.8.7 → wcgw-2.8.10}/tests/client/tools/test_file_errors.py +0 -0
- {wcgw-2.8.7 → wcgw-2.8.10}/tests/client/tools/test_file_operations.py +0 -0
- {wcgw-2.8.7 → wcgw-2.8.10}/tests/client/tools/test_files/test1.py +0 -0
- {wcgw-2.8.7 → wcgw-2.8.10}/tests/client/tools/test_files/test2.py +0 -0
- {wcgw-2.8.7 → wcgw-2.8.10}/tests/client/tools/test_files/test_file.py +0 -0
- {wcgw-2.8.7 → wcgw-2.8.10}/tests/client/tools/test_full_coverage.py +0 -0
- {wcgw-2.8.7 → wcgw-2.8.10}/tests/client/tools/test_is_int.py +0 -0
- {wcgw-2.8.7 → wcgw-2.8.10}/tests/client/tools/test_knowledge_transfer.py +0 -0
- {wcgw-2.8.7 → wcgw-2.8.10}/tests/client/tools/test_large_blocks.py +0 -0
- {wcgw-2.8.7 → wcgw-2.8.10}/tests/client/tools/test_prompt_update.py +0 -0
- {wcgw-2.8.7 → wcgw-2.8.10}/tests/client/tools/test_render_terminal.py +0 -0
- {wcgw-2.8.7 → wcgw-2.8.10}/tests/client/tools/test_terminal_output.py +0 -0
- {wcgw-2.8.7 → wcgw-2.8.10}/tests/client/tools/test_terminal_output_full.py +0 -0
- {wcgw-2.8.7 → wcgw-2.8.10}/tests/client/tools/test_terminal_output_incremental.py +0 -0
- {wcgw-2.8.7 → wcgw-2.8.10}/tests/client/tools/test_terminal_output_raw.py +0 -0
- {wcgw-2.8.7 → wcgw-2.8.10}/tests/client/tools/test_terminal_sequence.py +0 -0
- {wcgw-2.8.7 → wcgw-2.8.10}/tests/client/tools/test_timeout_handling.py +0 -0
- {wcgw-2.8.7 → wcgw-2.8.10}/tests/client/tools/test_timeout_state.py +0 -0
- {wcgw-2.8.7 → wcgw-2.8.10}/tests/client/tools/test_user_interaction.py +0 -0
- {wcgw-2.8.7 → wcgw-2.8.10}/tests/client/tools/test_write_file.py +0 -0
- {wcgw-2.8.7 → wcgw-2.8.10}/tests/conftest.py +0 -0
- {wcgw-2.8.7 → wcgw-2.8.10}/tests/test_anthropic_client.py +0 -0
- {wcgw-2.8.7 → wcgw-2.8.10}/tests/test_basic.py +0 -0
- {wcgw-2.8.7 → wcgw-2.8.10}/tests/test_common.py +0 -0
- {wcgw-2.8.7 → wcgw-2.8.10}/tests/test_computer_use.py +0 -0
- {wcgw-2.8.7 → wcgw-2.8.10}/tests/test_computer_use_base.py +0 -0
- {wcgw-2.8.7 → wcgw-2.8.10}/tests/test_computer_use_shell.py +0 -0
- {wcgw-2.8.7 → wcgw-2.8.10}/tests/test_sys_utils.py +0 -0
- {wcgw-2.8.7 → wcgw-2.8.10}/tests/test_tools.py +0 -0
|
@@ -6,8 +6,10 @@ import importlib.metadata
|
|
|
6
6
|
import json
|
|
7
7
|
import mimetypes
|
|
8
8
|
import os
|
|
9
|
+
import platform
|
|
9
10
|
import re
|
|
10
11
|
import shlex
|
|
12
|
+
import subprocess
|
|
11
13
|
import time
|
|
12
14
|
import traceback
|
|
13
15
|
import uuid
|
|
@@ -133,19 +135,43 @@ def ask_confirmation(prompt: Confirmation) -> str:
|
|
|
133
135
|
PROMPT_CONST = "#" + "@wcgw@#"
|
|
134
136
|
|
|
135
137
|
|
|
136
|
-
def
|
|
138
|
+
def is_mac() -> bool:
|
|
139
|
+
return platform.system() == "Darwin"
|
|
140
|
+
|
|
141
|
+
|
|
142
|
+
def get_tmpdir() -> str:
|
|
143
|
+
current_tmpdir = os.environ.get("TMPDIR", "")
|
|
144
|
+
if current_tmpdir or not is_mac():
|
|
145
|
+
return current_tmpdir
|
|
146
|
+
try:
|
|
147
|
+
# Fix issue while running ocrmypdf -> tesseract -> leptonica, set TMPDIR
|
|
148
|
+
# https://github.com/tesseract-ocr/tesseract/issues/4333
|
|
149
|
+
result = subprocess.check_output(
|
|
150
|
+
["getconf", "DARWIN_USER_TEMP_DIR"],
|
|
151
|
+
text=True,
|
|
152
|
+
).strip()
|
|
153
|
+
return result
|
|
154
|
+
except subprocess.CalledProcessError:
|
|
155
|
+
return "//tmp"
|
|
156
|
+
except Exception:
|
|
157
|
+
return ""
|
|
158
|
+
|
|
159
|
+
|
|
160
|
+
def start_shell(is_restricted_mode: bool, initial_dir: str) -> pexpect.spawn: # type: ignore[type-arg]
|
|
137
161
|
cmd = "/bin/bash"
|
|
138
162
|
if is_restricted_mode:
|
|
139
163
|
cmd += " -r"
|
|
140
164
|
|
|
165
|
+
overrideenv = {**os.environ, "PS1": PROMPT_CONST, "TMPDIR": get_tmpdir()}
|
|
141
166
|
try:
|
|
142
167
|
shell = pexpect.spawn(
|
|
143
168
|
cmd,
|
|
144
|
-
env=
|
|
169
|
+
env=overrideenv, # type: ignore[arg-type]
|
|
145
170
|
echo=False,
|
|
146
171
|
encoding="utf-8",
|
|
147
172
|
timeout=TIMEOUT,
|
|
148
173
|
cwd=initial_dir,
|
|
174
|
+
codec_errors="backslashreplace",
|
|
149
175
|
)
|
|
150
176
|
shell.sendline(
|
|
151
177
|
f"export PROMPT_COMMAND= PS1={PROMPT_CONST}"
|
|
@@ -157,10 +183,11 @@ def start_shell(is_restricted_mode: bool, initial_dir: str) -> pexpect.spawn: #
|
|
|
157
183
|
|
|
158
184
|
shell = pexpect.spawn(
|
|
159
185
|
"/bin/bash --noprofile --norc",
|
|
160
|
-
env=
|
|
186
|
+
env=overrideenv, # type: ignore[arg-type]
|
|
161
187
|
echo=False,
|
|
162
188
|
encoding="utf-8",
|
|
163
189
|
timeout=TIMEOUT,
|
|
190
|
+
codec_errors="backslashreplace",
|
|
164
191
|
)
|
|
165
192
|
shell.sendline(f"export PS1={PROMPT_CONST}")
|
|
166
193
|
shell.expect(PROMPT_CONST, timeout=TIMEOUT)
|
|
@@ -256,7 +283,9 @@ class BashState:
|
|
|
256
283
|
before = "\n".join(before_lines).strip()
|
|
257
284
|
counts += 1
|
|
258
285
|
if counts > 100:
|
|
259
|
-
raise ValueError(
|
|
286
|
+
raise ValueError(
|
|
287
|
+
"Error in understanding shell output. This shouldn't happen, likely shell is in a bad state, please reset it"
|
|
288
|
+
)
|
|
260
289
|
|
|
261
290
|
try:
|
|
262
291
|
return int(before)
|
|
@@ -273,7 +302,7 @@ class BashState:
|
|
|
273
302
|
self._bash_command_mode.bash_mode == "restricted_mode",
|
|
274
303
|
self._cwd,
|
|
275
304
|
)
|
|
276
|
-
|
|
305
|
+
|
|
277
306
|
self._pending_output = ""
|
|
278
307
|
|
|
279
308
|
# Get exit info to ensure shell is ready
|
|
@@ -414,7 +443,9 @@ class BashState:
|
|
|
414
443
|
index = self.shell.expect([self._prompt, pexpect.TIMEOUT], timeout=0.2)
|
|
415
444
|
counts += 1
|
|
416
445
|
if counts > 100:
|
|
417
|
-
raise ValueError(
|
|
446
|
+
raise ValueError(
|
|
447
|
+
"Error in understanding shell output. This shouldn't happen, likely shell is in a bad state, please reset it"
|
|
448
|
+
)
|
|
418
449
|
console.print(f"Prompt updated to: {self._prompt}")
|
|
419
450
|
return True
|
|
420
451
|
return False
|
|
@@ -457,6 +488,12 @@ def initialize(
|
|
|
457
488
|
folder_to_start = None
|
|
458
489
|
if any_workspace_path:
|
|
459
490
|
if os.path.exists(any_workspace_path):
|
|
491
|
+
if os.path.isfile(any_workspace_path):
|
|
492
|
+
# Set any_workspace_path to the directory containing the file
|
|
493
|
+
# Add the file to read_files_ only if empty to avoid duplicates
|
|
494
|
+
if not read_files_:
|
|
495
|
+
read_files_ = [any_workspace_path]
|
|
496
|
+
any_workspace_path = os.path.dirname(any_workspace_path)
|
|
460
497
|
repo_context, folder_to_start = get_repo_context(any_workspace_path, 200)
|
|
461
498
|
|
|
462
499
|
repo_context = f"---\n# Workspace structure\n{repo_context}\n---\n"
|
|
@@ -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"
|
|
@@ -248,3 +248,78 @@ class TestInitialize(unittest.TestCase):
|
|
|
248
248
|
|
|
249
249
|
# Verify task memory was still loaded despite state error
|
|
250
250
|
self.assertIn("Following is the retrieved task:\ntest_memory", result)
|
|
251
|
+
|
|
252
|
+
|
|
253
|
+
def test_workspace_path_is_file(self):
|
|
254
|
+
"""Test initialize when workspace path points to a file"""
|
|
255
|
+
# Create a test file
|
|
256
|
+
test_file = os.path.join(self.test_workspace, "test.py")
|
|
257
|
+
os.makedirs(os.path.dirname(test_file), exist_ok=True)
|
|
258
|
+
with open(test_file, "w") as f:
|
|
259
|
+
f.write("print('test')")
|
|
260
|
+
|
|
261
|
+
with (
|
|
262
|
+
patch("os.path.exists") as mock_exists,
|
|
263
|
+
patch("os.path.isfile") as mock_isfile,
|
|
264
|
+
patch("wcgw.client.tools.get_repo_context") as mock_get_context,
|
|
265
|
+
patch("wcgw.client.tools.read_files") as mock_read_files,
|
|
266
|
+
):
|
|
267
|
+
mock_exists.return_value = True
|
|
268
|
+
mock_isfile.return_value = True
|
|
269
|
+
mock_get_context.return_value = (self.repo_context, os.path.dirname(test_file))
|
|
270
|
+
mock_read_files.return_value = f"``` {test_file}print('test')```"
|
|
271
|
+
|
|
272
|
+
# Call initialize with file path and no read_files_
|
|
273
|
+
result = initialize(
|
|
274
|
+
any_workspace_path=test_file,
|
|
275
|
+
read_files_=[],
|
|
276
|
+
task_id_to_resume="",
|
|
277
|
+
max_tokens=None,
|
|
278
|
+
mode=Modes.wcgw,
|
|
279
|
+
)
|
|
280
|
+
|
|
281
|
+
# Verify read_files was called with the file path
|
|
282
|
+
mock_read_files.assert_called_once_with([test_file], None)
|
|
283
|
+
|
|
284
|
+
# Verify repo context uses parent directory
|
|
285
|
+
mock_get_context.assert_called_once_with(os.path.dirname(test_file), 200)
|
|
286
|
+
|
|
287
|
+
# Verify file content is in output
|
|
288
|
+
self.assertIn(f"``` {test_file}print('test')", result)
|
|
289
|
+
|
|
290
|
+
# Verify cwd
|
|
291
|
+
self.assertIn(f"Initialized in directory (also cwd): {os.path.dirname(test_file)}\n", result)
|
|
292
|
+
|
|
293
|
+
def test_workspace_path_is_file_with_read_files(self):
|
|
294
|
+
"""Test initialize when workspace path points to a file and read_files_ is provided"""
|
|
295
|
+
test_file = os.path.join(self.test_workspace, "test.py")
|
|
296
|
+
extra_file = os.path.join(self.test_workspace, "extra.py")
|
|
297
|
+
|
|
298
|
+
with (
|
|
299
|
+
patch("os.path.exists") as mock_exists,
|
|
300
|
+
patch("os.path.isfile") as mock_isfile,
|
|
301
|
+
patch("wcgw.client.tools.get_repo_context") as mock_get_context,
|
|
302
|
+
patch("wcgw.client.tools.read_files") as mock_read_files,
|
|
303
|
+
):
|
|
304
|
+
mock_exists.return_value = True
|
|
305
|
+
mock_isfile.return_value = True
|
|
306
|
+
mock_get_context.return_value = (self.repo_context, os.path.dirname(test_file))
|
|
307
|
+
mock_read_files.return_value = f"``` {extra_file}extra content```"
|
|
308
|
+
|
|
309
|
+
# Call initialize with file path and explicit read_files_
|
|
310
|
+
result = initialize(
|
|
311
|
+
any_workspace_path=test_file,
|
|
312
|
+
read_files_=[extra_file],
|
|
313
|
+
task_id_to_resume="",
|
|
314
|
+
max_tokens=None,
|
|
315
|
+
mode=Modes.wcgw,
|
|
316
|
+
)
|
|
317
|
+
|
|
318
|
+
# Verify read_files was called with the provided read_files_ only
|
|
319
|
+
mock_read_files.assert_called_once_with([extra_file], None)
|
|
320
|
+
|
|
321
|
+
# Verify repo context uses parent directory
|
|
322
|
+
mock_get_context.assert_called_once_with(os.path.dirname(test_file), 200)
|
|
323
|
+
|
|
324
|
+
# Verify extra file content is in output
|
|
325
|
+
self.assertIn(f"``` {extra_file}extra content", result)
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{wcgw-2.8.7 → wcgw-2.8.10}/src/mcp_wcgw_fork/examples/servers/simple-resource/.python-version
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{wcgw-2.8.7 → wcgw-2.8.10}/src/mcp_wcgw_fork/examples/servers/simple-resource/pyproject.toml
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{wcgw-2.8.7 → wcgw-2.8.10}/src/mcp_wcgw_fork/examples/servers/simple-tool/mcp_simple_tool/server.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|