openreward 0.1.159.dev1__tar.gz → 0.1.159.dev2__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.
- {openreward-0.1.159.dev1 → openreward-0.1.159.dev2}/PKG-INFO +1 -1
- {openreward-0.1.159.dev1 → openreward-0.1.159.dev2}/openreward/environments/_sandbox_tools.py +4 -7
- {openreward-0.1.159.dev1 → openreward-0.1.159.dev2}/openreward/toolsets/gemini_cli.py +3 -16
- {openreward-0.1.159.dev1 → openreward-0.1.159.dev2}/openreward/toolsets/hermes.py +4 -17
- {openreward-0.1.159.dev1 → openreward-0.1.159.dev2}/openreward/toolsets/openclaw.py +4 -17
- {openreward-0.1.159.dev1 → openreward-0.1.159.dev2}/openreward.egg-info/PKG-INFO +1 -1
- {openreward-0.1.159.dev1 → openreward-0.1.159.dev2}/pyproject.toml +1 -1
- {openreward-0.1.159.dev1 → openreward-0.1.159.dev2}/tests/test_cli_toolset_root_and_timeout.py +3 -0
- {openreward-0.1.159.dev1 → openreward-0.1.159.dev2}/tests/test_gemini_cli_toolset.py +3 -5
- {openreward-0.1.159.dev1 → openreward-0.1.159.dev2}/tests/test_sandbox_tool_shell_safety.py +5 -0
- {openreward-0.1.159.dev1 → openreward-0.1.159.dev2}/tests/test_sandbox_tools.py +3 -5
- {openreward-0.1.159.dev1 → openreward-0.1.159.dev2}/tests/test_session_toolset.py +3 -6
- {openreward-0.1.159.dev1 → openreward-0.1.159.dev2}/tests/test_toolsets.py +4 -7
- {openreward-0.1.159.dev1 → openreward-0.1.159.dev2}/LICENSE +0 -0
- {openreward-0.1.159.dev1 → openreward-0.1.159.dev2}/README.md +0 -0
- {openreward-0.1.159.dev1 → openreward-0.1.159.dev2}/openreward/__init__.py +0 -0
- {openreward-0.1.159.dev1 → openreward-0.1.159.dev2}/openreward/_update_check.py +0 -0
- {openreward-0.1.159.dev1 → openreward-0.1.159.dev2}/openreward/_version.py +0 -0
- {openreward-0.1.159.dev1 → openreward-0.1.159.dev2}/openreward/api/__init__.py +0 -0
- {openreward-0.1.159.dev1 → openreward-0.1.159.dev2}/openreward/api/_session/__init__.py +0 -0
- {openreward-0.1.159.dev1 → openreward-0.1.159.dev2}/openreward/api/_session/http.py +0 -0
- {openreward-0.1.159.dev1 → openreward-0.1.159.dev2}/openreward/api/_session/ping.py +0 -0
- {openreward-0.1.159.dev1 → openreward-0.1.159.dev2}/openreward/api/_session/session.py +0 -0
- {openreward-0.1.159.dev1 → openreward-0.1.159.dev2}/openreward/api/environments/__init__.py +0 -0
- {openreward-0.1.159.dev1 → openreward-0.1.159.dev2}/openreward/api/environments/client.py +0 -0
- {openreward-0.1.159.dev1 → openreward-0.1.159.dev2}/openreward/api/environments/types.py +0 -0
- {openreward-0.1.159.dev1 → openreward-0.1.159.dev2}/openreward/api/errors.py +0 -0
- {openreward-0.1.159.dev1 → openreward-0.1.159.dev2}/openreward/api/rollouts/__init__.py +0 -0
- {openreward-0.1.159.dev1 → openreward-0.1.159.dev2}/openreward/api/rollouts/background.py +0 -0
- {openreward-0.1.159.dev1 → openreward-0.1.159.dev2}/openreward/api/rollouts/rollout.py +0 -0
- {openreward-0.1.159.dev1 → openreward-0.1.159.dev2}/openreward/api/rollouts/serializers/__init__.py +0 -0
- {openreward-0.1.159.dev1 → openreward-0.1.159.dev2}/openreward/api/rollouts/serializers/ant.py +0 -0
- {openreward-0.1.159.dev1 → openreward-0.1.159.dev2}/openreward/api/rollouts/serializers/base.py +0 -0
- {openreward-0.1.159.dev1 → openreward-0.1.159.dev2}/openreward/api/rollouts/serializers/gdm.py +0 -0
- {openreward-0.1.159.dev1 → openreward-0.1.159.dev2}/openreward/api/rollouts/serializers/models.py +0 -0
- {openreward-0.1.159.dev1 → openreward-0.1.159.dev2}/openreward/api/rollouts/serializers/oai_completions.py +0 -0
- {openreward-0.1.159.dev1 → openreward-0.1.159.dev2}/openreward/api/rollouts/serializers/oai_responses.py +0 -0
- {openreward-0.1.159.dev1 → openreward-0.1.159.dev2}/openreward/api/rollouts/serializers/utils.py +0 -0
- {openreward-0.1.159.dev1 → openreward-0.1.159.dev2}/openreward/api/sandboxes/__init__.py +0 -0
- {openreward-0.1.159.dev1 → openreward-0.1.159.dev2}/openreward/api/sandboxes/client.py +0 -0
- {openreward-0.1.159.dev1 → openreward-0.1.159.dev2}/openreward/api/sandboxes/secrets.py +0 -0
- {openreward-0.1.159.dev1 → openreward-0.1.159.dev2}/openreward/api/sandboxes/types.py +0 -0
- {openreward-0.1.159.dev1 → openreward-0.1.159.dev2}/openreward/chat_backends/__init__.py +0 -0
- {openreward-0.1.159.dev1 → openreward-0.1.159.dev2}/openreward/chat_backends/base.py +0 -0
- {openreward-0.1.159.dev1 → openreward-0.1.159.dev2}/openreward/chat_backends/openai.py +0 -0
- {openreward-0.1.159.dev1 → openreward-0.1.159.dev2}/openreward/cli.py +0 -0
- {openreward-0.1.159.dev1 → openreward-0.1.159.dev2}/openreward/client.py +0 -0
- {openreward-0.1.159.dev1 → openreward-0.1.159.dev2}/openreward/environments/__init__.py +0 -0
- {openreward-0.1.159.dev1 → openreward-0.1.159.dev2}/openreward/environments/_metrics.py +0 -0
- {openreward-0.1.159.dev1 → openreward-0.1.159.dev2}/openreward/environments/environment.py +0 -0
- {openreward-0.1.159.dev1 → openreward-0.1.159.dev2}/openreward/environments/reconnect.py +0 -0
- {openreward-0.1.159.dev1 → openreward-0.1.159.dev2}/openreward/environments/server.py +0 -0
- {openreward-0.1.159.dev1 → openreward-0.1.159.dev2}/openreward/environments/session.py +0 -0
- {openreward-0.1.159.dev1 → openreward-0.1.159.dev2}/openreward/environments/toolset.py +0 -0
- {openreward-0.1.159.dev1 → openreward-0.1.159.dev2}/openreward/environments/types.py +0 -0
- {openreward-0.1.159.dev1 → openreward-0.1.159.dev2}/openreward/environments/utils.py +0 -0
- {openreward-0.1.159.dev1 → openreward-0.1.159.dev2}/openreward/http_client.py +0 -0
- {openreward-0.1.159.dev1 → openreward-0.1.159.dev2}/openreward/judging/__init__.py +0 -0
- {openreward-0.1.159.dev1 → openreward-0.1.159.dev2}/openreward/judging/_render.py +0 -0
- {openreward-0.1.159.dev1 → openreward-0.1.159.dev2}/openreward/judging/group.py +0 -0
- {openreward-0.1.159.dev1 → openreward-0.1.159.dev2}/openreward/judging/groupwise.py +0 -0
- {openreward-0.1.159.dev1 → openreward-0.1.159.dev2}/openreward/judging/pairwise.py +0 -0
- {openreward-0.1.159.dev1 → openreward-0.1.159.dev2}/openreward/judging/types.py +0 -0
- {openreward-0.1.159.dev1 → openreward-0.1.159.dev2}/openreward/log_utils.py +0 -0
- {openreward-0.1.159.dev1 → openreward-0.1.159.dev2}/openreward/models.py +0 -0
- {openreward-0.1.159.dev1 → openreward-0.1.159.dev2}/openreward/search_backends/__init__.py +0 -0
- {openreward-0.1.159.dev1 → openreward-0.1.159.dev2}/openreward/search_backends/backsearch.py +0 -0
- {openreward-0.1.159.dev1 → openreward-0.1.159.dev2}/openreward/search_backends/base.py +0 -0
- {openreward-0.1.159.dev1 → openreward-0.1.159.dev2}/openreward/search_backends/tavily.py +0 -0
- {openreward-0.1.159.dev1 → openreward-0.1.159.dev2}/openreward/templates/__init__.py +0 -0
- {openreward-0.1.159.dev1 → openreward-0.1.159.dev2}/openreward/templates/basic/Dockerfile +0 -0
- {openreward-0.1.159.dev1 → openreward-0.1.159.dev2}/openreward/templates/basic/__init__.py +0 -0
- {openreward-0.1.159.dev1 → openreward-0.1.159.dev2}/openreward/templates/basic/requirements.txt +0 -0
- {openreward-0.1.159.dev1 → openreward-0.1.159.dev2}/openreward/templates/basic/requirements.txt.tmpl +0 -0
- {openreward-0.1.159.dev1 → openreward-0.1.159.dev2}/openreward/templates/basic/server.py.tmpl +0 -0
- {openreward-0.1.159.dev1 → openreward-0.1.159.dev2}/openreward/templates/sandbox/Dockerfile +0 -0
- {openreward-0.1.159.dev1 → openreward-0.1.159.dev2}/openreward/templates/sandbox/__init__.py +0 -0
- {openreward-0.1.159.dev1 → openreward-0.1.159.dev2}/openreward/templates/sandbox/requirements.txt +0 -0
- {openreward-0.1.159.dev1 → openreward-0.1.159.dev2}/openreward/templates/sandbox/sandbox_env.py +0 -0
- {openreward-0.1.159.dev1 → openreward-0.1.159.dev2}/openreward/templates/sandbox/server.py +0 -0
- {openreward-0.1.159.dev1 → openreward-0.1.159.dev2}/openreward/tools/__init__.py +0 -0
- {openreward-0.1.159.dev1 → openreward-0.1.159.dev2}/openreward/tools/search.py +0 -0
- {openreward-0.1.159.dev1 → openreward-0.1.159.dev2}/openreward/tools/web.py +0 -0
- {openreward-0.1.159.dev1 → openreward-0.1.159.dev2}/openreward/toolsets/__init__.py +0 -0
- {openreward-0.1.159.dev1 → openreward-0.1.159.dev2}/openreward/toolsets/_web_common.py +0 -0
- {openreward-0.1.159.dev1 → openreward-0.1.159.dev2}/openreward/toolsets/backsearch.py +0 -0
- {openreward-0.1.159.dev1 → openreward-0.1.159.dev2}/openreward/toolsets/claude_code.py +0 -0
- {openreward-0.1.159.dev1 → openreward-0.1.159.dev2}/openreward/toolsets/cli.py +0 -0
- {openreward-0.1.159.dev1 → openreward-0.1.159.dev2}/openreward/toolsets/codex.py +0 -0
- {openreward-0.1.159.dev1 → openreward-0.1.159.dev2}/openreward/toolsets/excel.py +0 -0
- {openreward-0.1.159.dev1 → openreward-0.1.159.dev2}/openreward/toolsets/pdf.py +0 -0
- {openreward-0.1.159.dev1 → openreward-0.1.159.dev2}/openreward/toolsets/powerpoint.py +0 -0
- {openreward-0.1.159.dev1 → openreward-0.1.159.dev2}/openreward/toolsets/web.py +0 -0
- {openreward-0.1.159.dev1 → openreward-0.1.159.dev2}/openreward/toolsets/word.py +0 -0
- {openreward-0.1.159.dev1 → openreward-0.1.159.dev2}/openreward/web_service.py +0 -0
- {openreward-0.1.159.dev1 → openreward-0.1.159.dev2}/openreward.egg-info/SOURCES.txt +0 -0
- {openreward-0.1.159.dev1 → openreward-0.1.159.dev2}/openreward.egg-info/dependency_links.txt +0 -0
- {openreward-0.1.159.dev1 → openreward-0.1.159.dev2}/openreward.egg-info/entry_points.txt +0 -0
- {openreward-0.1.159.dev1 → openreward-0.1.159.dev2}/openreward.egg-info/requires.txt +0 -0
- {openreward-0.1.159.dev1 → openreward-0.1.159.dev2}/openreward.egg-info/top_level.txt +0 -0
- {openreward-0.1.159.dev1 → openreward-0.1.159.dev2}/setup.cfg +0 -0
- {openreward-0.1.159.dev1 → openreward-0.1.159.dev2}/tests/test_chat_backends.py +0 -0
- {openreward-0.1.159.dev1 → openreward-0.1.159.dev2}/tests/test_cli_toolset_todo_write.py +0 -0
- {openreward-0.1.159.dev1 → openreward-0.1.159.dev2}/tests/test_env_server_retry.py +0 -0
- {openreward-0.1.159.dev1 → openreward-0.1.159.dev2}/tests/test_environment.py +0 -0
- {openreward-0.1.159.dev1 → openreward-0.1.159.dev2}/tests/test_errors.py +0 -0
- {openreward-0.1.159.dev1 → openreward-0.1.159.dev2}/tests/test_excel_toolset.py +0 -0
- {openreward-0.1.159.dev1 → openreward-0.1.159.dev2}/tests/test_judging.py +0 -0
- {openreward-0.1.159.dev1 → openreward-0.1.159.dev2}/tests/test_log_utils.py +0 -0
- {openreward-0.1.159.dev1 → openreward-0.1.159.dev2}/tests/test_messages.py +0 -0
- {openreward-0.1.159.dev1 → openreward-0.1.159.dev2}/tests/test_metrics.py +0 -0
- {openreward-0.1.159.dev1 → openreward-0.1.159.dev2}/tests/test_rich_messages.py +0 -0
- {openreward-0.1.159.dev1 → openreward-0.1.159.dev2}/tests/test_rollout_info.py +0 -0
- {openreward-0.1.159.dev1 → openreward-0.1.159.dev2}/tests/test_sandbox_secrets.py +0 -0
- {openreward-0.1.159.dev1 → openreward-0.1.159.dev2}/tests/test_sandboxes_client_paths.py +0 -0
- {openreward-0.1.159.dev1 → openreward-0.1.159.dev2}/tests/test_sanitise.py +0 -0
- {openreward-0.1.159.dev1 → openreward-0.1.159.dev2}/tests/test_score_group.py +0 -0
- {openreward-0.1.159.dev1 → openreward-0.1.159.dev2}/tests/test_search_backends.py +0 -0
- {openreward-0.1.159.dev1 → openreward-0.1.159.dev2}/tests/test_session.py +0 -0
- {openreward-0.1.159.dev1 → openreward-0.1.159.dev2}/tests/test_terminal_tool.py +0 -0
- {openreward-0.1.159.dev1 → openreward-0.1.159.dev2}/tests/test_tool_conversion.py +0 -0
- {openreward-0.1.159.dev1 → openreward-0.1.159.dev2}/tests/test_toolset_shell_safety.py +0 -0
- {openreward-0.1.159.dev1 → openreward-0.1.159.dev2}/tests/test_web_tools.py +0 -0
{openreward-0.1.159.dev1 → openreward-0.1.159.dev2}/openreward/environments/_sandbox_tools.py
RENAMED
|
@@ -15,7 +15,6 @@ Public exports:
|
|
|
15
15
|
"""
|
|
16
16
|
from __future__ import annotations
|
|
17
17
|
|
|
18
|
-
import base64
|
|
19
18
|
import os
|
|
20
19
|
import shlex
|
|
21
20
|
from typing import Any, Dict, List, Optional, overload
|
|
@@ -62,15 +61,13 @@ async def upload_text(
|
|
|
62
61
|
) -> None:
|
|
63
62
|
"""Write text content to a file in the sandbox.
|
|
64
63
|
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
64
|
+
Goes through ``sandbox.upload_bytes`` (the exec-agent's ``/files``
|
|
65
|
+
endpoint), so no shell and no ``base64`` binary are involved and the
|
|
66
|
+
path needs no quoting. Parent directories are not created.
|
|
68
67
|
"""
|
|
69
68
|
if ensure_trailing_newline and not content.endswith("\n"):
|
|
70
69
|
content = content + "\n"
|
|
71
|
-
|
|
72
|
-
# Quote the destination; the base64 payload is [A-Za-z0-9+/=] and needs none.
|
|
73
|
-
await sandbox.check_run(f"echo '{encoded}' | base64 -d > {shlex.quote(path)}")
|
|
70
|
+
await sandbox.upload_bytes(content.encode("utf-8"), path)
|
|
74
71
|
|
|
75
72
|
|
|
76
73
|
# ── Workspace rooting ───────────────────────────────────────────────────────
|
|
@@ -10,7 +10,6 @@ source (``google-gemini/gemini-cli/packages/core/src/tools``).
|
|
|
10
10
|
"""
|
|
11
11
|
from __future__ import annotations
|
|
12
12
|
|
|
13
|
-
import base64
|
|
14
13
|
import os
|
|
15
14
|
import shlex
|
|
16
15
|
from typing import Any, Dict, List, Literal, Optional
|
|
@@ -18,6 +17,7 @@ from typing import Any, Dict, List, Literal, Optional
|
|
|
18
17
|
from pydantic import BaseModel, Field
|
|
19
18
|
|
|
20
19
|
from openreward.environments import TextBlock, Toolset, ToolOutput, tool
|
|
20
|
+
from openreward.environments._sandbox_tools import upload_text
|
|
21
21
|
|
|
22
22
|
|
|
23
23
|
# ── Pydantic parameter models ──
|
|
@@ -87,19 +87,6 @@ async def _download_text(sandbox: Any, path: str) -> str:
|
|
|
87
87
|
return data.decode("utf-8")
|
|
88
88
|
|
|
89
89
|
|
|
90
|
-
async def _upload_text(
|
|
91
|
-
sandbox: Any,
|
|
92
|
-
path: str,
|
|
93
|
-
content: str,
|
|
94
|
-
ensure_trailing_newline: bool = True,
|
|
95
|
-
) -> None:
|
|
96
|
-
if ensure_trailing_newline and not content.endswith("\n"):
|
|
97
|
-
content = content + "\n"
|
|
98
|
-
encoded = base64.b64encode(content.encode("utf-8")).decode("ascii")
|
|
99
|
-
# Quote the destination; the base64 payload is [A-Za-z0-9+/=] and needs none.
|
|
100
|
-
await sandbox.check_run(f"echo '{encoded}' | base64 -d > {shlex.quote(path)}")
|
|
101
|
-
|
|
102
|
-
|
|
103
90
|
# ── Tool descriptions (verbatim from upstream Gemini CLI source) ──
|
|
104
91
|
# Source: packages/core/src/tools/definitions/model-family-sets/default-legacy.ts
|
|
105
92
|
# Shell description: packages/core/src/tools/definitions/dynamic-declaration-helpers.ts
|
|
@@ -272,7 +259,7 @@ class GeminiCliToolset(Toolset):
|
|
|
272
259
|
dir_name = os.path.dirname(params.file_path)
|
|
273
260
|
if dir_name:
|
|
274
261
|
await self.sandbox.run(f"mkdir -p {shlex.quote(dir_name)}")
|
|
275
|
-
await
|
|
262
|
+
await upload_text(
|
|
276
263
|
self.sandbox,
|
|
277
264
|
params.file_path,
|
|
278
265
|
params.content,
|
|
@@ -329,7 +316,7 @@ class GeminiCliToolset(Toolset):
|
|
|
329
316
|
else:
|
|
330
317
|
new_content = content.replace(params.old_string, params.new_string, 1)
|
|
331
318
|
|
|
332
|
-
await
|
|
319
|
+
await upload_text(
|
|
333
320
|
self.sandbox, params.file_path, new_content, ensure_trailing_newline=True
|
|
334
321
|
)
|
|
335
322
|
|
|
@@ -7,7 +7,6 @@ upstream registry definitions (``nousresearch/hermes-agent``).
|
|
|
7
7
|
"""
|
|
8
8
|
from __future__ import annotations
|
|
9
9
|
|
|
10
|
-
import base64
|
|
11
10
|
import os
|
|
12
11
|
import shlex
|
|
13
12
|
from typing import Any, Optional
|
|
@@ -17,6 +16,7 @@ from pydantic import BaseModel
|
|
|
17
16
|
from openreward.environments.environment import tool
|
|
18
17
|
from openreward.environments.toolset import Toolset
|
|
19
18
|
from openreward.environments.types import TextBlock, ToolOutput
|
|
19
|
+
from openreward.environments._sandbox_tools import upload_text
|
|
20
20
|
|
|
21
21
|
|
|
22
22
|
async def _download_text(sandbox: Any, path: str) -> str:
|
|
@@ -24,19 +24,6 @@ async def _download_text(sandbox: Any, path: str) -> str:
|
|
|
24
24
|
return data.decode("utf-8")
|
|
25
25
|
|
|
26
26
|
|
|
27
|
-
async def _upload_text(
|
|
28
|
-
sandbox: Any,
|
|
29
|
-
path: str,
|
|
30
|
-
content: str,
|
|
31
|
-
ensure_trailing_newline: bool = True,
|
|
32
|
-
) -> None:
|
|
33
|
-
if ensure_trailing_newline and not content.endswith("\n"):
|
|
34
|
-
content = content + "\n"
|
|
35
|
-
encoded = base64.b64encode(content.encode("utf-8")).decode("ascii")
|
|
36
|
-
# Quote the destination; the base64 payload is [A-Za-z0-9+/=] and needs none.
|
|
37
|
-
await sandbox.check_run(f"echo '{encoded}' | base64 -d > {shlex.quote(path)}")
|
|
38
|
-
|
|
39
|
-
|
|
40
27
|
# ── Pydantic parameter models ──
|
|
41
28
|
|
|
42
29
|
class TerminalParams(BaseModel, extra="forbid"):
|
|
@@ -188,7 +175,7 @@ class HermesToolset(Toolset):
|
|
|
188
175
|
dir_name = os.path.dirname(params.path)
|
|
189
176
|
if dir_name:
|
|
190
177
|
await self.sandbox.run(f"mkdir -p {shlex.quote(dir_name)}")
|
|
191
|
-
await
|
|
178
|
+
await upload_text(
|
|
192
179
|
self.sandbox,
|
|
193
180
|
params.path,
|
|
194
181
|
params.content,
|
|
@@ -319,7 +306,7 @@ class HermesToolset(Toolset):
|
|
|
319
306
|
else:
|
|
320
307
|
new_content = content.replace(params.old_string, params.new_string, 1)
|
|
321
308
|
|
|
322
|
-
await
|
|
309
|
+
await upload_text(self.sandbox, params.path, new_content, ensure_trailing_newline=True)
|
|
323
310
|
|
|
324
311
|
return ToolOutput(
|
|
325
312
|
metadata={"output": "", "exit_code": 0},
|
|
@@ -344,7 +331,7 @@ class HermesToolset(Toolset):
|
|
|
344
331
|
)
|
|
345
332
|
|
|
346
333
|
patch_tmp = "/tmp/_hermes_patch.diff"
|
|
347
|
-
await
|
|
334
|
+
await upload_text(self.sandbox, patch_tmp, params.patch, ensure_trailing_newline=True)
|
|
348
335
|
|
|
349
336
|
output, code = await self.sandbox.run(f"patch -p1 < {shlex.quote(patch_tmp)}")
|
|
350
337
|
if code != 0:
|
|
@@ -7,7 +7,6 @@ upstream definitions.
|
|
|
7
7
|
"""
|
|
8
8
|
from __future__ import annotations
|
|
9
9
|
|
|
10
|
-
import base64
|
|
11
10
|
import os
|
|
12
11
|
import shlex
|
|
13
12
|
from typing import Any, List, Optional
|
|
@@ -17,6 +16,7 @@ from pydantic import BaseModel
|
|
|
17
16
|
from openreward.environments.environment import tool
|
|
18
17
|
from openreward.environments.toolset import Toolset
|
|
19
18
|
from openreward.environments.types import TextBlock, ToolOutput
|
|
19
|
+
from openreward.environments._sandbox_tools import upload_text
|
|
20
20
|
|
|
21
21
|
|
|
22
22
|
def _proc_path(sid: str, ext: str) -> str:
|
|
@@ -29,19 +29,6 @@ async def _download_text(sandbox: Any, path: str) -> str:
|
|
|
29
29
|
return data.decode("utf-8")
|
|
30
30
|
|
|
31
31
|
|
|
32
|
-
async def _upload_text(
|
|
33
|
-
sandbox: Any,
|
|
34
|
-
path: str,
|
|
35
|
-
content: str,
|
|
36
|
-
ensure_trailing_newline: bool = True,
|
|
37
|
-
) -> None:
|
|
38
|
-
if ensure_trailing_newline and not content.endswith("\n"):
|
|
39
|
-
content = content + "\n"
|
|
40
|
-
encoded = base64.b64encode(content.encode("utf-8")).decode("ascii")
|
|
41
|
-
# Quote the destination; the base64 payload is [A-Za-z0-9+/=] and needs none.
|
|
42
|
-
await sandbox.check_run(f"echo '{encoded}' | base64 -d > {shlex.quote(path)}")
|
|
43
|
-
|
|
44
|
-
|
|
45
32
|
# ── Pydantic parameter models ──
|
|
46
33
|
|
|
47
34
|
class ExecParams(BaseModel, extra="forbid"):
|
|
@@ -277,7 +264,7 @@ class OpenClawToolset(Toolset):
|
|
|
277
264
|
dir_name = os.path.dirname(params.path)
|
|
278
265
|
if dir_name:
|
|
279
266
|
await self.sandbox.run(f"mkdir -p {shlex.quote(dir_name)}")
|
|
280
|
-
await
|
|
267
|
+
await upload_text(
|
|
281
268
|
self.sandbox,
|
|
282
269
|
params.path,
|
|
283
270
|
params.content,
|
|
@@ -317,7 +304,7 @@ class OpenClawToolset(Toolset):
|
|
|
317
304
|
)
|
|
318
305
|
content = content.replace(item.oldText, item.newText, 1)
|
|
319
306
|
|
|
320
|
-
await
|
|
307
|
+
await upload_text(self.sandbox, params.path, content, ensure_trailing_newline=True)
|
|
321
308
|
|
|
322
309
|
return ToolOutput(
|
|
323
310
|
metadata={"output": "", "exit_code": 0},
|
|
@@ -336,7 +323,7 @@ class OpenClawToolset(Toolset):
|
|
|
336
323
|
async def apply_patch(self, params: ApplyPatchParams) -> ToolOutput:
|
|
337
324
|
try:
|
|
338
325
|
patch_tmp = "/tmp/_openclaw_patch.diff"
|
|
339
|
-
await
|
|
326
|
+
await upload_text(self.sandbox, patch_tmp, params.input, ensure_trailing_newline=True)
|
|
340
327
|
|
|
341
328
|
output, code = await self.sandbox.run(f"patch -p1 < {shlex.quote(patch_tmp)}")
|
|
342
329
|
if code != 0:
|
{openreward-0.1.159.dev1 → openreward-0.1.159.dev2}/tests/test_cli_toolset_root_and_timeout.py
RENAMED
|
@@ -24,6 +24,9 @@ class RecordingSandbox:
|
|
|
24
24
|
self.uploads.append(cmd)
|
|
25
25
|
return RunResult(output="", return_code=0)
|
|
26
26
|
|
|
27
|
+
async def upload_bytes(self, data: bytes, path: str) -> None:
|
|
28
|
+
self.uploads.append(f"upload:{path}")
|
|
29
|
+
|
|
27
30
|
async def download(self, path: str) -> bytes:
|
|
28
31
|
self.uploads.append(f"download:{path}")
|
|
29
32
|
return self.file_content.encode()
|
|
@@ -6,7 +6,6 @@ FastAPI server to verify end-to-end HTTP routing through the session layer.
|
|
|
6
6
|
"""
|
|
7
7
|
|
|
8
8
|
import asyncio
|
|
9
|
-
import base64
|
|
10
9
|
from threading import Thread
|
|
11
10
|
from typing import Generator
|
|
12
11
|
|
|
@@ -37,12 +36,11 @@ class _MockSandbox:
|
|
|
37
36
|
|
|
38
37
|
async def check_run(self, cmd: str, **kwargs) -> str:
|
|
39
38
|
self.commands.append(cmd)
|
|
40
|
-
if " | base64 -d > " in cmd:
|
|
41
|
-
encoded = cmd.split("'", 2)[1]
|
|
42
|
-
path = cmd.split(" > ", 1)[1]
|
|
43
|
-
self.files[path] = base64.b64decode(encoded)
|
|
44
39
|
return ""
|
|
45
40
|
|
|
41
|
+
async def upload_bytes(self, data: bytes, path: str) -> None:
|
|
42
|
+
self.files[path] = data
|
|
43
|
+
|
|
46
44
|
async def download(self, path: str) -> bytes:
|
|
47
45
|
return self.files.get(path, b"")
|
|
48
46
|
|
|
@@ -69,6 +69,11 @@ class RealShellSandbox:
|
|
|
69
69
|
async def download(self, path: str) -> bytes:
|
|
70
70
|
return Path(path).read_bytes()
|
|
71
71
|
|
|
72
|
+
async def upload_bytes(self, data: bytes, path: str) -> None:
|
|
73
|
+
# The agent writes the path verbatim: no shell, so no quoting to test here,
|
|
74
|
+
# but a missing parent directory still fails like the agent's 404 would.
|
|
75
|
+
Path(path).write_bytes(data)
|
|
76
|
+
|
|
72
77
|
|
|
73
78
|
class RaisingSandbox:
|
|
74
79
|
"""Every sandbox call raises the given exception."""
|
|
@@ -1,7 +1,5 @@
|
|
|
1
1
|
"""``_sandbox_tools`` outputs carry no reward."""
|
|
2
2
|
|
|
3
|
-
import base64
|
|
4
|
-
import re
|
|
5
3
|
from functools import partial
|
|
6
4
|
|
|
7
5
|
import pytest
|
|
@@ -39,11 +37,11 @@ class FakeSandbox:
|
|
|
39
37
|
return (f"ran: {cmd}", 0)
|
|
40
38
|
|
|
41
39
|
async def check_run(self, cmd: str, **kwargs) -> str:
|
|
42
|
-
m = re.fullmatch(r"echo '([A-Za-z0-9+/=]+)' \| base64 -d > (.+)", cmd)
|
|
43
|
-
if m:
|
|
44
|
-
self.files[m.group(2)] = base64.b64decode(m.group(1).encode("ascii"))
|
|
45
40
|
return ""
|
|
46
41
|
|
|
42
|
+
async def upload_bytes(self, data: bytes, path: str) -> None:
|
|
43
|
+
self.files[path] = data
|
|
44
|
+
|
|
47
45
|
async def download(self, path: str) -> bytes:
|
|
48
46
|
if path not in self.files:
|
|
49
47
|
raise FileNotFoundError(path)
|
|
@@ -6,7 +6,6 @@ through the HTTP layer (POST /create, GET /task_tools, POST /call).
|
|
|
6
6
|
"""
|
|
7
7
|
|
|
8
8
|
import asyncio
|
|
9
|
-
import base64
|
|
10
9
|
from threading import Thread
|
|
11
10
|
from typing import Generator
|
|
12
11
|
|
|
@@ -37,13 +36,11 @@ class _MockSandbox:
|
|
|
37
36
|
|
|
38
37
|
async def check_run(self, cmd: str, **kwargs) -> str:
|
|
39
38
|
self.commands.append(cmd)
|
|
40
|
-
# Emulate "echo BASE64 | base64 -d > path" used by _upload_text.
|
|
41
|
-
if " | base64 -d > " in cmd:
|
|
42
|
-
encoded = cmd.split("'", 2)[1]
|
|
43
|
-
path = cmd.split(" > ", 1)[1]
|
|
44
|
-
self.files[path] = base64.b64decode(encoded)
|
|
45
39
|
return ""
|
|
46
40
|
|
|
41
|
+
async def upload_bytes(self, data: bytes, path: str) -> None:
|
|
42
|
+
self.files[path] = data
|
|
43
|
+
|
|
47
44
|
async def download(self, path: str) -> bytes:
|
|
48
45
|
return self.files.get(path, b"")
|
|
49
46
|
|
|
@@ -532,7 +532,6 @@ def test_list_task_tools_override():
|
|
|
532
532
|
# A FakeFsSandbox in-memory file dict is enough — none of the tools talk
|
|
533
533
|
# to a real container.
|
|
534
534
|
|
|
535
|
-
import base64
|
|
536
535
|
import re
|
|
537
536
|
|
|
538
537
|
from openreward.toolsets import CLIToolset
|
|
@@ -555,7 +554,7 @@ class FakeFsSandbox:
|
|
|
555
554
|
Supports the three calls the SDK helpers make:
|
|
556
555
|
* ``await sandbox.download(path)`` -> bytes (from ``self.files``)
|
|
557
556
|
* ``await sandbox.check_run(cmd)`` -> recognises the base64 upload
|
|
558
|
-
|
|
557
|
+
``upload_bytes`` call made by ``upload_text`` and updates ``self.files``;
|
|
559
558
|
otherwise echoes the command.
|
|
560
559
|
* ``await sandbox.run(cmd)`` -> echoes ``(cmd, return_code)`` with a
|
|
561
560
|
configurable default return code.
|
|
@@ -582,13 +581,11 @@ class FakeFsSandbox:
|
|
|
582
581
|
|
|
583
582
|
async def check_run(self, cmd: str):
|
|
584
583
|
self.check_run_log.append(cmd)
|
|
585
|
-
m = re.fullmatch(r"echo '([A-Za-z0-9+/=]+)' \| base64 -d > (.+)", cmd)
|
|
586
|
-
if m:
|
|
587
|
-
payload = base64.b64decode(m.group(1).encode("ascii"))
|
|
588
|
-
self.files[m.group(2)] = payload
|
|
589
|
-
return ("", 0)
|
|
590
584
|
return ("", 0)
|
|
591
585
|
|
|
586
|
+
async def upload_bytes(self, data: bytes, path: str) -> None:
|
|
587
|
+
self.files[path] = data
|
|
588
|
+
|
|
592
589
|
async def run(self, cmd: str, **kwargs):
|
|
593
590
|
self.run_log.append(cmd)
|
|
594
591
|
for pat, (output, code) in self.run_responses:
|
|
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
|
{openreward-0.1.159.dev1 → openreward-0.1.159.dev2}/openreward/api/rollouts/serializers/__init__.py
RENAMED
|
File without changes
|
{openreward-0.1.159.dev1 → openreward-0.1.159.dev2}/openreward/api/rollouts/serializers/ant.py
RENAMED
|
File without changes
|
{openreward-0.1.159.dev1 → openreward-0.1.159.dev2}/openreward/api/rollouts/serializers/base.py
RENAMED
|
File without changes
|
{openreward-0.1.159.dev1 → openreward-0.1.159.dev2}/openreward/api/rollouts/serializers/gdm.py
RENAMED
|
File without changes
|
{openreward-0.1.159.dev1 → openreward-0.1.159.dev2}/openreward/api/rollouts/serializers/models.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{openreward-0.1.159.dev1 → openreward-0.1.159.dev2}/openreward/api/rollouts/serializers/utils.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
|
{openreward-0.1.159.dev1 → openreward-0.1.159.dev2}/openreward/search_backends/backsearch.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{openreward-0.1.159.dev1 → openreward-0.1.159.dev2}/openreward/templates/basic/requirements.txt
RENAMED
|
File without changes
|
{openreward-0.1.159.dev1 → openreward-0.1.159.dev2}/openreward/templates/basic/requirements.txt.tmpl
RENAMED
|
File without changes
|
{openreward-0.1.159.dev1 → openreward-0.1.159.dev2}/openreward/templates/basic/server.py.tmpl
RENAMED
|
File without changes
|
|
File without changes
|
{openreward-0.1.159.dev1 → openreward-0.1.159.dev2}/openreward/templates/sandbox/__init__.py
RENAMED
|
File without changes
|
{openreward-0.1.159.dev1 → openreward-0.1.159.dev2}/openreward/templates/sandbox/requirements.txt
RENAMED
|
File without changes
|
{openreward-0.1.159.dev1 → openreward-0.1.159.dev2}/openreward/templates/sandbox/sandbox_env.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
|
{openreward-0.1.159.dev1 → openreward-0.1.159.dev2}/openreward.egg-info/dependency_links.txt
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
|