langchain-agentcore-codeinterpreter 0.0.2__tar.gz → 0.0.3__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.
- {langchain_agentcore_codeinterpreter-0.0.2 → langchain_agentcore_codeinterpreter-0.0.3}/PKG-INFO +1 -1
- {langchain_agentcore_codeinterpreter-0.0.2 → langchain_agentcore_codeinterpreter-0.0.3}/langchain_agentcore_codeinterpreter/sandbox.py +23 -6
- {langchain_agentcore_codeinterpreter-0.0.2 → langchain_agentcore_codeinterpreter-0.0.3}/pyproject.toml +1 -1
- langchain_agentcore_codeinterpreter-0.0.3/tests/unit_tests/__init__.py +0 -0
- {langchain_agentcore_codeinterpreter-0.0.2 → langchain_agentcore_codeinterpreter-0.0.3}/tests/unit_tests/test_sandbox.py +37 -0
- {langchain_agentcore_codeinterpreter-0.0.2 → langchain_agentcore_codeinterpreter-0.0.3}/tests/unit_tests/test_stream_parsing.py +48 -0
- langchain_agentcore_codeinterpreter-0.0.3/uv.lock +2571 -0
- langchain_agentcore_codeinterpreter-0.0.2/uv.lock +0 -2470
- {langchain_agentcore_codeinterpreter-0.0.2 → langchain_agentcore_codeinterpreter-0.0.3}/.gitignore +0 -0
- {langchain_agentcore_codeinterpreter-0.0.2 → langchain_agentcore_codeinterpreter-0.0.3}/LICENSE +0 -0
- {langchain_agentcore_codeinterpreter-0.0.2 → langchain_agentcore_codeinterpreter-0.0.3}/Makefile +0 -0
- {langchain_agentcore_codeinterpreter-0.0.2 → langchain_agentcore_codeinterpreter-0.0.3}/README.md +0 -0
- {langchain_agentcore_codeinterpreter-0.0.2 → langchain_agentcore_codeinterpreter-0.0.3}/langchain_agentcore_codeinterpreter/__init__.py +0 -0
- {langchain_agentcore_codeinterpreter-0.0.2 → langchain_agentcore_codeinterpreter-0.0.3}/scripts/check_imports.py +0 -0
- {langchain_agentcore_codeinterpreter-0.0.2 → langchain_agentcore_codeinterpreter-0.0.3}/tests/__init__.py +0 -0
- {langchain_agentcore_codeinterpreter-0.0.2 → langchain_agentcore_codeinterpreter-0.0.3}/tests/integration_tests/__init__.py +0 -0
- {langchain_agentcore_codeinterpreter-0.0.2/tests/unit_tests → langchain_agentcore_codeinterpreter-0.0.3/tests/integration_tests/sandbox}/__init__.py +0 -0
- /langchain_agentcore_codeinterpreter-0.0.2/tests/integration_tests/test_integration.py → /langchain_agentcore_codeinterpreter-0.0.3/tests/integration_tests/sandbox/test_sandbox.py +0 -0
- {langchain_agentcore_codeinterpreter-0.0.2 → langchain_agentcore_codeinterpreter-0.0.3}/tests/integration_tests/test_compile.py +0 -0
- {langchain_agentcore_codeinterpreter-0.0.2 → langchain_agentcore_codeinterpreter-0.0.3}/tests/unit_tests/test_imports.py +0 -0
{langchain_agentcore_codeinterpreter-0.0.2 → langchain_agentcore_codeinterpreter-0.0.3}/PKG-INFO
RENAMED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: langchain-agentcore-codeinterpreter
|
|
3
|
-
Version: 0.0.
|
|
3
|
+
Version: 0.0.3
|
|
4
4
|
Summary: Amazon Bedrock AgentCore Code Interpreter sandbox integration for Deep Agents
|
|
5
5
|
Project-URL: Source Code, https://github.com/langchain-ai/langchain-aws/tree/main/libs/agentcore-codeinterpreter
|
|
6
6
|
Project-URL: Repository, https://github.com/langchain-ai/langchain-aws
|
|
@@ -32,6 +32,21 @@ _AGENTCORE_EXECUTOR = ThreadPoolExecutor(
|
|
|
32
32
|
)
|
|
33
33
|
|
|
34
34
|
|
|
35
|
+
def _normalize_relative_path(path: str) -> str:
|
|
36
|
+
"""Strip leading slashes and ``./`` prefixes to a canonical relative path.
|
|
37
|
+
|
|
38
|
+
Args:
|
|
39
|
+
path: File path (absolute or relative).
|
|
40
|
+
|
|
41
|
+
Returns:
|
|
42
|
+
Canonical relative path string with no leading ``/`` or ``./``.
|
|
43
|
+
"""
|
|
44
|
+
path = path.lstrip("/")
|
|
45
|
+
while path.startswith("./"):
|
|
46
|
+
path = path[2:]
|
|
47
|
+
return path
|
|
48
|
+
|
|
49
|
+
|
|
35
50
|
class SessionExpiredError(Exception):
|
|
36
51
|
"""Raised when the AgentCore session has expired or been terminated."""
|
|
37
52
|
|
|
@@ -104,8 +119,7 @@ def _extract_files_from_stream(
|
|
|
104
119
|
"""
|
|
105
120
|
path_lookup: dict[str, str] = {}
|
|
106
121
|
for path in requested_paths:
|
|
107
|
-
|
|
108
|
-
path_lookup[stripped] = path
|
|
122
|
+
path_lookup[_normalize_relative_path(path)] = path
|
|
109
123
|
|
|
110
124
|
files: dict[str, bytes] = {}
|
|
111
125
|
|
|
@@ -117,13 +131,16 @@ def _extract_files_from_stream(
|
|
|
117
131
|
continue
|
|
118
132
|
resource = item.get("resource", {})
|
|
119
133
|
uri = resource.get("uri", "")
|
|
120
|
-
file_path = uri.replace("file://", "")
|
|
134
|
+
file_path = _normalize_relative_path(uri.replace("file://", ""))
|
|
121
135
|
|
|
122
136
|
content: bytes | None = None
|
|
123
137
|
if "text" in resource:
|
|
124
138
|
content = resource["text"].encode("utf-8")
|
|
125
139
|
elif "blob" in resource:
|
|
126
|
-
|
|
140
|
+
blob = resource["blob"]
|
|
141
|
+
# The AgentCore stream may deliver blob as already-decoded bytes.
|
|
142
|
+
# Only base64-decode when it arrives as encoded text.
|
|
143
|
+
content = blob if isinstance(blob, bytes) else base64.b64decode(blob)
|
|
127
144
|
|
|
128
145
|
if content is not None:
|
|
129
146
|
original_path = path_lookup.get(file_path, file_path)
|
|
@@ -178,7 +195,7 @@ class AgentCoreSandbox(BaseSandbox):
|
|
|
178
195
|
|
|
179
196
|
@staticmethod
|
|
180
197
|
def _to_relative_path(path: str) -> str:
|
|
181
|
-
"""Strip leading slashes
|
|
198
|
+
"""Strip leading slashes and ``./`` prefixes for AgentCore APIs.
|
|
182
199
|
|
|
183
200
|
Args:
|
|
184
201
|
path: File path (absolute or relative).
|
|
@@ -186,7 +203,7 @@ class AgentCoreSandbox(BaseSandbox):
|
|
|
186
203
|
Returns:
|
|
187
204
|
Relative path string.
|
|
188
205
|
"""
|
|
189
|
-
return path
|
|
206
|
+
return _normalize_relative_path(path)
|
|
190
207
|
|
|
191
208
|
def _invoke(self, method: str, params: dict[str, Any]) -> dict[str, Any]:
|
|
192
209
|
"""Invoke the interpreter and eagerly consume the response stream.
|
|
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "langchain-agentcore-codeinterpreter"
|
|
7
|
-
version = "0.0.
|
|
7
|
+
version = "0.0.3"
|
|
8
8
|
description = "Amazon Bedrock AgentCore Code Interpreter sandbox integration for Deep Agents"
|
|
9
9
|
readme = "README.md"
|
|
10
10
|
license = "MIT"
|
|
File without changes
|
|
@@ -228,6 +228,36 @@ def test_download_files_handles_session_expiry() -> None:
|
|
|
228
228
|
assert results[0].error == "permission_denied"
|
|
229
229
|
|
|
230
230
|
|
|
231
|
+
def test_download_files_dot_slash_path() -> None:
|
|
232
|
+
"""./-prefixed paths must round-trip through readFiles and lookup."""
|
|
233
|
+
fake_png = b"\x89PNG\r\n\x1a\n" + b"\x00" * 100
|
|
234
|
+
sandbox, mock = _make_sandbox(
|
|
235
|
+
{
|
|
236
|
+
"stream": [
|
|
237
|
+
{
|
|
238
|
+
"result": {
|
|
239
|
+
"content": [
|
|
240
|
+
{
|
|
241
|
+
"type": "resource",
|
|
242
|
+
"resource": {
|
|
243
|
+
"uri": "file:///data/foo.png",
|
|
244
|
+
"blob": fake_png,
|
|
245
|
+
},
|
|
246
|
+
}
|
|
247
|
+
]
|
|
248
|
+
}
|
|
249
|
+
}
|
|
250
|
+
]
|
|
251
|
+
}
|
|
252
|
+
)
|
|
253
|
+
results = sandbox.download_files(["./data/foo.png"])
|
|
254
|
+
mock.invoke.assert_called_once_with(
|
|
255
|
+
method="readFiles", params={"paths": ["data/foo.png"]}
|
|
256
|
+
)
|
|
257
|
+
assert results[0].error is None
|
|
258
|
+
assert results[0].content == fake_png
|
|
259
|
+
|
|
260
|
+
|
|
231
261
|
# ------------------------------------------------------------------
|
|
232
262
|
# _to_relative_path()
|
|
233
263
|
# ------------------------------------------------------------------
|
|
@@ -240,6 +270,13 @@ def test_relative_path_stripping() -> None:
|
|
|
240
270
|
assert AgentCoreSandbox._to_relative_path("///triple.txt") == "triple.txt"
|
|
241
271
|
|
|
242
272
|
|
|
273
|
+
def test_relative_path_strips_dot_slash() -> None:
|
|
274
|
+
"""./ and repeated ././ prefixes should be stripped."""
|
|
275
|
+
assert AgentCoreSandbox._to_relative_path("./data/foo.png") == "data/foo.png"
|
|
276
|
+
assert AgentCoreSandbox._to_relative_path("././foo.png") == "foo.png"
|
|
277
|
+
assert AgentCoreSandbox._to_relative_path("/./data/foo.png") == "data/foo.png"
|
|
278
|
+
|
|
279
|
+
|
|
243
280
|
# ------------------------------------------------------------------
|
|
244
281
|
# Constructor
|
|
245
282
|
# ------------------------------------------------------------------
|
|
@@ -182,6 +182,54 @@ def test_extract_files_blob_resource() -> None:
|
|
|
182
182
|
assert files["/data.bin"] == b"binary data"
|
|
183
183
|
|
|
184
184
|
|
|
185
|
+
def test_extract_files_blob_already_bytes() -> None:
|
|
186
|
+
"""Blob delivered as raw bytes must not be base64-decoded again."""
|
|
187
|
+
png_magic = b"\x89PNG\r\n\x1a\n"
|
|
188
|
+
fake_png = png_magic + b"\x00" * 100
|
|
189
|
+
response: dict[str, Any] = {
|
|
190
|
+
"stream": [
|
|
191
|
+
{
|
|
192
|
+
"result": {
|
|
193
|
+
"content": [
|
|
194
|
+
{
|
|
195
|
+
"type": "resource",
|
|
196
|
+
"resource": {
|
|
197
|
+
"uri": "file:///test.png",
|
|
198
|
+
"blob": fake_png,
|
|
199
|
+
},
|
|
200
|
+
}
|
|
201
|
+
]
|
|
202
|
+
}
|
|
203
|
+
}
|
|
204
|
+
]
|
|
205
|
+
}
|
|
206
|
+
files = _extract_files_from_stream(response, ["test.png"])
|
|
207
|
+
assert files["test.png"] == fake_png
|
|
208
|
+
|
|
209
|
+
|
|
210
|
+
def test_extract_files_dot_slash_path() -> None:
|
|
211
|
+
"""./-prefixed requested paths should match URIs without the prefix."""
|
|
212
|
+
response: dict[str, Any] = {
|
|
213
|
+
"stream": [
|
|
214
|
+
{
|
|
215
|
+
"result": {
|
|
216
|
+
"content": [
|
|
217
|
+
{
|
|
218
|
+
"type": "resource",
|
|
219
|
+
"resource": {
|
|
220
|
+
"uri": "file:///data/foo.png",
|
|
221
|
+
"text": "x",
|
|
222
|
+
},
|
|
223
|
+
}
|
|
224
|
+
]
|
|
225
|
+
}
|
|
226
|
+
}
|
|
227
|
+
]
|
|
228
|
+
}
|
|
229
|
+
files = _extract_files_from_stream(response, ["./data/foo.png"])
|
|
230
|
+
assert files["./data/foo.png"] == b"x"
|
|
231
|
+
|
|
232
|
+
|
|
185
233
|
def test_extract_files_path_normalization() -> None:
|
|
186
234
|
"""Relative requested paths should still match file:/// URIs."""
|
|
187
235
|
response: dict[str, Any] = {
|