Skip to content

Commit ed0b462

Browse files
CopilotOhYee
andauthored
fix: default read_file to raw text for backward compat, add encode_base64 opt-in
- Default behavior now returns plain text (backward compatible with callers that expected raw content from the original read_file) - New encode_base64=True parameter opts into base64 encoding for binary file support - Response always includes 'encoding' field ('raw' or 'base64') - Updated unit tests to reflect new API Agent-Logs-Url: https://github.com/Serverless-Devs/agentrun-sdk-python/sessions/c48cff08-0e34-425e-a6e6-aafbaee14a00 Co-authored-by: OhYee <13498329+OhYee@users.noreply.github.com>
1 parent 2517f71 commit ed0b462

File tree

2 files changed

+57
-49
lines changed

2 files changed

+57
-49
lines changed

agentrun/integration/builtin/sandbox.py

Lines changed: 18 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -388,24 +388,32 @@ def inner(sb: Sandbox):
388388
name="read_file",
389389
description=(
390390
"Read the content of a file at the specified path in the sandbox."
391-
" By default returns the file content encoded as a base64 string."
392-
" Set raw=True to get the plain text content instead."
391+
" Returns the plain text content by default."
392+
" Set encode_base64=True to get the content as a base64-encoded"
393+
" string instead, which is useful for binary files."
393394
" Suitable for reading code files, configs, logs, binary files,"
394395
" etc."
395396
),
396397
)
397-
def read_file(self, path: str, raw: bool = False) -> Dict[str, Any]:
398-
"""读取文件内容,默认返回 base64 编码结果 / Read file content, returns base64 by default"""
398+
def read_file(
399+
self, path: str, encode_base64: bool = False
400+
) -> Dict[str, Any]:
401+
"""读取文件内容 / Read file content.
402+
403+
默认返回原始文本,传入 encode_base64=True 时返回 base64 编码字符串。
404+
Returns plain text by default; returns base64-encoded string when
405+
encode_base64=True.
406+
"""
399407

400408
def inner(sb: Sandbox):
401409
assert isinstance(sb, CodeInterpreterSandbox)
402410
content = sb.file.read(path=path)
403-
if raw:
404-
return {"path": path, "content": content, "encoding": "raw"}
405-
encoded = base64.b64encode(
406-
content.encode("utf-8") if isinstance(content, str) else content
407-
).decode("ascii")
408-
return {"path": path, "content": encoded, "encoding": "base64"}
411+
if encode_base64:
412+
encoded = base64.b64encode(
413+
content.encode("utf-8") if isinstance(content, str) else content
414+
).decode("ascii")
415+
return {"path": path, "content": encoded, "encoding": "base64"}
416+
return {"path": path, "content": content, "encoding": "raw"}
409417

410418
return self._run_in_sandbox(inner)
411419

tests/unittests/integration/test_code_interpreter_toolset_read_file.py

Lines changed: 39 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
"""CodeInterpreterToolSet read_file 工具单元测试
22
3-
测试 read_file 工具的 base64 编码行为和 raw 参数控制。
4-
Tests the read_file tool's base64 encoding behavior and the raw parameter control.
3+
测试 read_file 工具的 base64 编码行为和 encode_base64 参数控制。
4+
Tests the read_file tool's base64 encoding behavior and the encode_base64 parameter control.
55
"""
66

77
import base64
@@ -40,17 +40,48 @@ def _make_mock_sandbox(file_content: str):
4040
return mock_sb
4141

4242

43-
class TestReadFileBase64Default:
44-
"""测试 read_file 默认返回 base64 编码内容 / Test that read_file returns base64 by default."""
43+
class TestReadFileRawDefault:
44+
"""测试 read_file 默认返回原始文本(向前兼容)/ Test that read_file returns raw text by default."""
4545

46-
def test_returns_base64_encoded_content(self, toolset):
47-
"""默认情况下内容应为 base64 编码 / Content should be base64 encoded by default."""
46+
def test_returns_plain_content_by_default(self, toolset):
47+
"""默认情况下应返回原始文本 / Content should be plain text by default."""
4848
file_content = "hello world"
4949
mock_sb = _make_mock_sandbox(file_content)
5050

5151
with patch.object(toolset, "_run_in_sandbox", side_effect=lambda fn: fn(mock_sb)):
5252
result = toolset.read_file(path="/tmp/test.txt")
5353

54+
assert result["content"] == file_content
55+
assert result["encoding"] == "raw"
56+
assert result["path"] == "/tmp/test.txt"
57+
58+
def test_encode_base64_false_same_as_default(self, toolset):
59+
"""encode_base64=False 应与默认行为一致 / encode_base64=False should behave identically to default."""
60+
file_content = "some content"
61+
mock_sb = _make_mock_sandbox(file_content)
62+
63+
with patch.object(toolset, "_run_in_sandbox", side_effect=lambda fn: fn(mock_sb)):
64+
result_explicit = toolset.read_file(path="/tmp/f.txt", encode_base64=False)
65+
66+
mock_sb2 = _make_mock_sandbox(file_content)
67+
with patch.object(toolset, "_run_in_sandbox", side_effect=lambda fn: fn(mock_sb2)):
68+
result_default = toolset.read_file(path="/tmp/f.txt")
69+
70+
assert result_explicit == result_default
71+
assert result_explicit["encoding"] == "raw"
72+
73+
74+
class TestReadFileBase64Param:
75+
"""测试 encode_base64=True 时返回 base64 编码内容 / Test that encode_base64=True returns base64 content."""
76+
77+
def test_returns_base64_encoded_content(self, toolset):
78+
"""encode_base64=True 时内容应为 base64 编码 / Content should be base64 encoded when encode_base64=True."""
79+
file_content = "hello world"
80+
mock_sb = _make_mock_sandbox(file_content)
81+
82+
with patch.object(toolset, "_run_in_sandbox", side_effect=lambda fn: fn(mock_sb)):
83+
result = toolset.read_file(path="/tmp/test.txt", encode_base64=True)
84+
5485
expected_b64 = base64.b64encode(b"hello world").decode("ascii")
5586
assert result["content"] == expected_b64
5687
assert result["encoding"] == "base64"
@@ -62,7 +93,7 @@ def test_base64_roundtrip(self, toolset):
6293
mock_sb = _make_mock_sandbox(file_content)
6394

6495
with patch.object(toolset, "_run_in_sandbox", side_effect=lambda fn: fn(mock_sb)):
65-
result = toolset.read_file(path="/tmp/utf8.txt")
96+
result = toolset.read_file(path="/tmp/utf8.txt", encode_base64=True)
6697

6798
decoded = base64.b64decode(result["content"]).decode("utf-8")
6899
assert decoded == file_content
@@ -76,39 +107,8 @@ def test_bytes_content_also_base64_encoded(self, toolset):
76107
mock_sb.file.read.return_value = file_bytes
77108

78109
with patch.object(toolset, "_run_in_sandbox", side_effect=lambda fn: fn(mock_sb)):
79-
result = toolset.read_file(path="/tmp/binary.bin")
110+
result = toolset.read_file(path="/tmp/binary.bin", encode_base64=True)
80111

81112
expected_b64 = base64.b64encode(file_bytes).decode("ascii")
82113
assert result["content"] == expected_b64
83114
assert result["encoding"] == "base64"
84-
85-
86-
class TestReadFileRawParam:
87-
"""测试 raw=True 时返回原始内容 / Test that raw=True returns plain text content."""
88-
89-
def test_raw_true_returns_plain_content(self, toolset):
90-
"""raw=True 时应返回原始文本 / raw=True should return raw text."""
91-
file_content = "plain text content"
92-
mock_sb = _make_mock_sandbox(file_content)
93-
94-
with patch.object(toolset, "_run_in_sandbox", side_effect=lambda fn: fn(mock_sb)):
95-
result = toolset.read_file(path="/tmp/plain.txt", raw=True)
96-
97-
assert result["content"] == file_content
98-
assert result["encoding"] == "raw"
99-
assert result["path"] == "/tmp/plain.txt"
100-
101-
def test_raw_false_same_as_default(self, toolset):
102-
"""raw=False 应与默认行为一致 / raw=False should behave identically to default."""
103-
file_content = "some content"
104-
mock_sb = _make_mock_sandbox(file_content)
105-
106-
with patch.object(toolset, "_run_in_sandbox", side_effect=lambda fn: fn(mock_sb)):
107-
result_explicit = toolset.read_file(path="/tmp/f.txt", raw=False)
108-
109-
mock_sb2 = _make_mock_sandbox(file_content)
110-
with patch.object(toolset, "_run_in_sandbox", side_effect=lambda fn: fn(mock_sb2)):
111-
result_default = toolset.read_file(path="/tmp/f.txt")
112-
113-
assert result_explicit == result_default
114-
assert result_explicit["encoding"] == "base64"

0 commit comments

Comments
 (0)