adk-code-mode 1.6.0__tar.gz → 1.6.1__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.
Files changed (78) hide show
  1. adk_code_mode-1.6.1/.release-please-manifest.json +3 -0
  2. {adk_code_mode-1.6.0 → adk_code_mode-1.6.1}/CHANGELOG.md +7 -0
  3. {adk_code_mode-1.6.0 → adk_code_mode-1.6.1}/PKG-INFO +1 -1
  4. {adk_code_mode-1.6.0 → adk_code_mode-1.6.1}/sandbox-wheel/src/adk_code_mode_sandbox/__about__.py +1 -1
  5. {adk_code_mode-1.6.0 → adk_code_mode-1.6.1}/sandbox-wheel/src/adk_code_mode_sandbox/_entry.py +0 -1
  6. {adk_code_mode-1.6.0 → adk_code_mode-1.6.1}/sandbox-wheel/src/adk_code_mode_sandbox/_http_server.py +15 -5
  7. {adk_code_mode-1.6.0 → adk_code_mode-1.6.1}/src/adk_code_mode/__about__.py +1 -1
  8. {adk_code_mode-1.6.0 → adk_code_mode-1.6.1}/tests/test_remote_integration.py +35 -0
  9. adk_code_mode-1.6.0/.release-please-manifest.json +0 -3
  10. {adk_code_mode-1.6.0 → adk_code_mode-1.6.1}/.githooks/pre-commit +0 -0
  11. {adk_code_mode-1.6.0 → adk_code_mode-1.6.1}/.githooks/pre-push +0 -0
  12. {adk_code_mode-1.6.0 → adk_code_mode-1.6.1}/.github/workflows/ci.yml +0 -0
  13. {adk_code_mode-1.6.0 → adk_code_mode-1.6.1}/.github/workflows/release-please.yml +0 -0
  14. {adk_code_mode-1.6.0 → adk_code_mode-1.6.1}/.gitignore +0 -0
  15. {adk_code_mode-1.6.0 → adk_code_mode-1.6.1}/.prettierrc +0 -0
  16. {adk_code_mode-1.6.0 → adk_code_mode-1.6.1}/.vscode/settings.json +0 -0
  17. {adk_code_mode-1.6.0 → adk_code_mode-1.6.1}/.zed/settings.json +0 -0
  18. {adk_code_mode-1.6.0 → adk_code_mode-1.6.1}/LICENSE +0 -0
  19. {adk_code_mode-1.6.0 → adk_code_mode-1.6.1}/Makefile +0 -0
  20. {adk_code_mode-1.6.0 → adk_code_mode-1.6.1}/README.md +0 -0
  21. {adk_code_mode-1.6.0 → adk_code_mode-1.6.1}/docker/Dockerfile +0 -0
  22. {adk_code_mode-1.6.0 → adk_code_mode-1.6.1}/pyproject.toml +0 -0
  23. {adk_code_mode-1.6.0 → adk_code_mode-1.6.1}/release-please-config.json +0 -0
  24. {adk_code_mode-1.6.0 → adk_code_mode-1.6.1}/sandbox-wheel/README.md +0 -0
  25. {adk_code_mode-1.6.0 → adk_code_mode-1.6.1}/sandbox-wheel/pyproject.toml +0 -0
  26. {adk_code_mode-1.6.0 → adk_code_mode-1.6.1}/sandbox-wheel/src/adk_code_mode_sandbox/__init__.py +0 -0
  27. {adk_code_mode-1.6.0 → adk_code_mode-1.6.1}/sandbox-wheel/src/adk_code_mode_sandbox/__main__.py +0 -0
  28. {adk_code_mode-1.6.0 → adk_code_mode-1.6.1}/sandbox-wheel/src/adk_code_mode_sandbox/_rpc_client.py +0 -0
  29. {adk_code_mode-1.6.0 → adk_code_mode-1.6.1}/sandbox-wheel/src/adk_code_mode_sandbox/protocol.py +0 -0
  30. {adk_code_mode-1.6.0 → adk_code_mode-1.6.1}/scripts/install-git-hooks.sh +0 -0
  31. {adk_code_mode-1.6.0 → adk_code_mode-1.6.1}/src/adk_code_mode/__init__.py +0 -0
  32. {adk_code_mode-1.6.0 → adk_code_mode-1.6.1}/src/adk_code_mode/_artifact_tools.py +0 -0
  33. {adk_code_mode-1.6.0 → adk_code_mode-1.6.1}/src/adk_code_mode/metadata.py +0 -0
  34. {adk_code_mode-1.6.0 → adk_code_mode-1.6.1}/src/adk_code_mode/output.py +0 -0
  35. {adk_code_mode-1.6.0 → adk_code_mode-1.6.1}/src/adk_code_mode/py.typed +0 -0
  36. {adk_code_mode-1.6.0 → adk_code_mode-1.6.1}/src/adk_code_mode/runtime/__init__.py +0 -0
  37. {adk_code_mode-1.6.0 → adk_code_mode-1.6.1}/src/adk_code_mode/runtime/base.py +0 -0
  38. {adk_code_mode-1.6.0 → adk_code_mode-1.6.1}/src/adk_code_mode/runtime/docker.py +0 -0
  39. {adk_code_mode-1.6.0 → adk_code_mode-1.6.1}/src/adk_code_mode/runtime/protocol.py +0 -0
  40. {adk_code_mode-1.6.0 → adk_code_mode-1.6.1}/src/adk_code_mode/runtime/remote.py +0 -0
  41. {adk_code_mode-1.6.0 → adk_code_mode-1.6.1}/src/adk_code_mode/tool.py +0 -0
  42. {adk_code_mode-1.6.0 → adk_code_mode-1.6.1}/src/adk_code_mode/tool_result_artifacts.py +0 -0
  43. {adk_code_mode-1.6.0 → adk_code_mode-1.6.1}/src/adk_code_mode/tools/__init__.py +0 -0
  44. {adk_code_mode-1.6.0 → adk_code_mode-1.6.1}/src/adk_code_mode/tools/catalog.py +0 -0
  45. {adk_code_mode-1.6.0 → adk_code_mode-1.6.1}/src/adk_code_mode/tools/dispatcher.py +0 -0
  46. {adk_code_mode-1.6.0 → adk_code_mode-1.6.1}/src/adk_code_mode/tools/namespacing.py +0 -0
  47. {adk_code_mode-1.6.0 → adk_code_mode-1.6.1}/src/adk_code_mode/tools/normaliser.py +0 -0
  48. {adk_code_mode-1.6.0 → adk_code_mode-1.6.1}/src/adk_code_mode/tools/stubs.py +0 -0
  49. {adk_code_mode-1.6.0 → adk_code_mode-1.6.1}/src/adk_code_mode/workspace/__init__.py +0 -0
  50. {adk_code_mode-1.6.0 → adk_code_mode-1.6.1}/src/adk_code_mode/workspace/files.py +0 -0
  51. {adk_code_mode-1.6.0 → adk_code_mode-1.6.1}/tests/__init__.py +0 -0
  52. {adk_code_mode-1.6.0 → adk_code_mode-1.6.1}/tests/_docker_helpers.py +0 -0
  53. {adk_code_mode-1.6.0 → adk_code_mode-1.6.1}/tests/_fake_runtime.py +0 -0
  54. {adk_code_mode-1.6.0 → adk_code_mode-1.6.1}/tests/conftest.py +0 -0
  55. {adk_code_mode-1.6.0 → adk_code_mode-1.6.1}/tests/test_agent_with_fake_llm.py +0 -0
  56. {adk_code_mode-1.6.0 → adk_code_mode-1.6.1}/tests/test_artifact_tools.py +0 -0
  57. {adk_code_mode-1.6.0 → adk_code_mode-1.6.1}/tests/test_catalog.py +0 -0
  58. {adk_code_mode-1.6.0 → adk_code_mode-1.6.1}/tests/test_dispatcher.py +0 -0
  59. {adk_code_mode-1.6.0 → adk_code_mode-1.6.1}/tests/test_docker_image.py +0 -0
  60. {adk_code_mode-1.6.0 → adk_code_mode-1.6.1}/tests/test_docker_integration.py +0 -0
  61. {adk_code_mode-1.6.0 → adk_code_mode-1.6.1}/tests/test_host_loop.py +0 -0
  62. {adk_code_mode-1.6.0 → adk_code_mode-1.6.1}/tests/test_integration.py +0 -0
  63. {adk_code_mode-1.6.0 → adk_code_mode-1.6.1}/tests/test_metadata.py +0 -0
  64. {adk_code_mode-1.6.0 → adk_code_mode-1.6.1}/tests/test_namespacing.py +0 -0
  65. {adk_code_mode-1.6.0 → adk_code_mode-1.6.1}/tests/test_normaliser.py +0 -0
  66. {adk_code_mode-1.6.0 → adk_code_mode-1.6.1}/tests/test_output.py +0 -0
  67. {adk_code_mode-1.6.0 → adk_code_mode-1.6.1}/tests/test_protocol.py +0 -0
  68. {adk_code_mode-1.6.0 → adk_code_mode-1.6.1}/tests/test_remote_backend.py +0 -0
  69. {adk_code_mode-1.6.0 → adk_code_mode-1.6.1}/tests/test_runtime_docker.py +0 -0
  70. {adk_code_mode-1.6.0 → adk_code_mode-1.6.1}/tests/test_sandbox_entry.py +0 -0
  71. {adk_code_mode-1.6.0 → adk_code_mode-1.6.1}/tests/test_sandbox_rpc_client.py +0 -0
  72. {adk_code_mode-1.6.0 → adk_code_mode-1.6.1}/tests/test_stubs.py +0 -0
  73. {adk_code_mode-1.6.0 → adk_code_mode-1.6.1}/tests/test_stubs_json_schema.py +0 -0
  74. {adk_code_mode-1.6.0 → adk_code_mode-1.6.1}/tests/test_tool.py +0 -0
  75. {adk_code_mode-1.6.0 → adk_code_mode-1.6.1}/tests/test_tool_result_artifacts.py +0 -0
  76. {adk_code_mode-1.6.0 → adk_code_mode-1.6.1}/tests/test_version.py +0 -0
  77. {adk_code_mode-1.6.0 → adk_code_mode-1.6.1}/tests/test_workspace_files.py +0 -0
  78. {adk_code_mode-1.6.0 → adk_code_mode-1.6.1}/uv.lock +0 -0
@@ -0,0 +1,3 @@
1
+ {
2
+ ".": "1.6.1"
3
+ }
@@ -1,5 +1,12 @@
1
1
  # Changelog
2
2
 
3
+ ## [1.6.1](https://github.com/a2anet/adk-code-mode/compare/adk-code-mode-v1.6.0...adk-code-mode-v1.6.1) (2026-09-22)
4
+
5
+
6
+ ### Bug Fixes
7
+
8
+ * exit the sandbox when the host disconnects mid-block ([bd3fb0f](https://github.com/a2anet/adk-code-mode/commit/bd3fb0fb0d8a0cab9370f2ad6db56dfacf566cb4))
9
+
3
10
  ## [1.6.0](https://github.com/a2anet/adk-code-mode/compare/adk-code-mode-v1.5.0...adk-code-mode-v1.6.0) (2026-08-29)
4
11
 
5
12
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.5
2
2
  Name: adk-code-mode
3
- Version: 1.6.0
3
+ Version: 1.6.1
4
4
  Summary: A "Code Mode" sandboxed code-execution tool for ADK agents to interact with tools, files, and custom packages with Python
5
5
  Project-URL: Documentation, https://github.com/A2ANet/adk-code-mode#readme
6
6
  Project-URL: Issues, https://github.com/A2ANet/adk-code-mode/issues
@@ -1,4 +1,4 @@
1
1
  # SPDX-FileCopyrightText: 2025-present A2A Net <hello@a2anet.com>
2
2
  #
3
3
  # SPDX-License-Identifier: Apache-2.0
4
- __version__ = "1.6.0" # x-release-please-version
4
+ __version__ = "1.6.1" # x-release-please-version
@@ -228,7 +228,6 @@ def main() -> int:
228
228
  port = int(os.environ.get("PORT", "8080"))
229
229
  token = os.environ.get(AUTH_TOKEN_ENV)
230
230
  asyncio.run(serve(port, token))
231
- return 0
232
231
 
233
232
  reader, writer = _open_control_streams()
234
233
  client = RpcClient(reader=reader, writer=writer)
@@ -38,7 +38,7 @@ import shutil
38
38
  import tarfile
39
39
  import tempfile
40
40
  from http import HTTPStatus
41
- from typing import Any
41
+ from typing import Any, NoReturn
42
42
 
43
43
  import websockets
44
44
  import websockets.asyncio.server
@@ -112,10 +112,11 @@ class _WsBridgeWriter:
112
112
  pass
113
113
 
114
114
 
115
- async def serve(port: int, token: str | None) -> None:
115
+ async def serve(port: int, token: str | None) -> NoReturn:
116
116
  """Start the WebSocket server on *port* with optional bearer *token* auth.
117
117
 
118
- Accepts exactly one WebSocket connection, runs user code, then returns.
118
+ Accepts exactly one WebSocket connection, runs user code, then exits the
119
+ process.
119
120
  """
120
121
  stop = asyncio.Event()
121
122
  accepted = False
@@ -136,9 +137,15 @@ async def serve(port: int, token: str | None) -> None:
136
137
  return None
137
138
 
138
139
  async def handler(ws: Any) -> None:
140
+ turn = asyncio.create_task(_handle_connection(ws))
141
+ # End the turn when the socket closes, even mid-block: user code that
142
+ # ignores the disconnect would otherwise keep this single-use container
143
+ # alive, answering every later connection with "Busy".
144
+ ws_closed = asyncio.create_task(ws.wait_closed())
145
+ ws_closed.add_done_callback(lambda _: turn.cancel())
139
146
  try:
140
- await _handle_connection(ws)
141
- except websockets.ConnectionClosed:
147
+ await turn
148
+ except (websockets.ConnectionClosed, asyncio.CancelledError):
142
149
  logger.debug("client disconnected")
143
150
  except Exception:
144
151
  logger.exception("error handling WebSocket connection")
@@ -154,6 +161,9 @@ async def serve(port: int, token: str | None) -> None:
154
161
  ):
155
162
  logger.info("sandbox HTTP server listening on port %d", port)
156
163
  await stop.wait()
164
+ # Don't let interpreter shutdown join a worker thread still running user code
165
+ # the host has given up on.
166
+ os._exit(0)
157
167
 
158
168
 
159
169
  async def _handle_connection(ws: Any) -> None:
@@ -1,4 +1,4 @@
1
1
  # SPDX-FileCopyrightText: 2025-present A2A Net <hello@a2anet.com>
2
2
  #
3
3
  # SPDX-License-Identifier: Apache-2.0
4
- __version__ = "1.6.0" # x-release-please-version
4
+ __version__ = "1.6.1" # x-release-please-version
@@ -340,3 +340,38 @@ async def test_remote_close_shuts_the_container_down(
340
340
  break
341
341
  await asyncio.sleep(0.02)
342
342
  assert http_server.poll() is not None # container exited after ShutdownFrame
343
+
344
+
345
+ @pytest.mark.asyncio
346
+ async def test_remote_timed_out_block_shuts_the_container_down(
347
+ http_server: subprocess.Popen[bytes],
348
+ ) -> None:
349
+ """A block still running when the host gives up doesn't keep the server alive."""
350
+ artifact_service = InMemoryArtifactService()
351
+ session = Session(
352
+ id="remote-timeout",
353
+ app_name="test-app",
354
+ user_id="u1",
355
+ state={},
356
+ events=[],
357
+ last_update_time=0.0,
358
+ )
359
+ ctx = _make_ctx(artifact_service, session)
360
+
361
+ tool = ExecuteCodeTool(
362
+ tools=[],
363
+ backend=RemoteBackend(url=_server_url(http_server)),
364
+ max_output_chars=10_000,
365
+ timeout_seconds=1,
366
+ )
367
+ result = await tool.run_async(
368
+ args={"code": "import time\ntime.sleep(3600)\n"},
369
+ tool_context=_tool_context(ctx, call_id="remote-timeout-1"),
370
+ )
371
+ assert "exceeded timeout" in result["stderr"]
372
+
373
+ for _ in range(200):
374
+ if http_server.poll() is not None:
375
+ break
376
+ await asyncio.sleep(0.02)
377
+ assert http_server.poll() is not None # container exited despite the running block
@@ -1,3 +0,0 @@
1
- {
2
- ".": "1.6.0"
3
- }
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes