adk-code-mode 1.6.1__tar.gz → 2.0.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.
- {adk_code_mode-1.6.1 → adk_code_mode-2.0.1}/.github/workflows/release-please.yml +2 -2
- adk_code_mode-2.0.1/.release-please-manifest.json +3 -0
- adk_code_mode-2.0.1/CHANGELOG.md +169 -0
- {adk_code_mode-1.6.1 → adk_code_mode-2.0.1}/PKG-INFO +15 -14
- {adk_code_mode-1.6.1 → adk_code_mode-2.0.1}/README.md +10 -9
- {adk_code_mode-1.6.1 → adk_code_mode-2.0.1}/docker/Dockerfile +1 -1
- {adk_code_mode-1.6.1 → adk_code_mode-2.0.1}/pyproject.toml +4 -4
- adk_code_mode-2.0.1/sandbox-wheel/README.md +14 -0
- {adk_code_mode-1.6.1 → adk_code_mode-2.0.1}/sandbox-wheel/pyproject.toml +4 -4
- adk_code_mode-2.0.1/sandbox-wheel/src/adk_code_mode_sandbox/__about__.py +4 -0
- {adk_code_mode-1.6.1 → adk_code_mode-2.0.1}/sandbox-wheel/src/adk_code_mode_sandbox/__init__.py +1 -1
- {adk_code_mode-1.6.1 → adk_code_mode-2.0.1}/sandbox-wheel/src/adk_code_mode_sandbox/__main__.py +1 -1
- {adk_code_mode-1.6.1 → adk_code_mode-2.0.1}/sandbox-wheel/src/adk_code_mode_sandbox/_entry.py +57 -7
- {adk_code_mode-1.6.1 → adk_code_mode-2.0.1}/sandbox-wheel/src/adk_code_mode_sandbox/_http_server.py +5 -3
- adk_code_mode-2.0.1/sandbox-wheel/src/adk_code_mode_sandbox/_interrupt.py +67 -0
- {adk_code_mode-1.6.1 → adk_code_mode-2.0.1}/sandbox-wheel/src/adk_code_mode_sandbox/_rpc_client.py +20 -2
- {adk_code_mode-1.6.1 → adk_code_mode-2.0.1}/sandbox-wheel/src/adk_code_mode_sandbox/protocol.py +19 -2
- adk_code_mode-2.0.1/src/adk_code_mode/__about__.py +4 -0
- {adk_code_mode-1.6.1 → adk_code_mode-2.0.1}/src/adk_code_mode/__init__.py +1 -1
- {adk_code_mode-1.6.1 → adk_code_mode-2.0.1}/src/adk_code_mode/_artifact_tools.py +1 -1
- {adk_code_mode-1.6.1 → adk_code_mode-2.0.1}/src/adk_code_mode/metadata.py +1 -1
- {adk_code_mode-1.6.1 → adk_code_mode-2.0.1}/src/adk_code_mode/output.py +1 -1
- {adk_code_mode-1.6.1 → adk_code_mode-2.0.1}/src/adk_code_mode/runtime/__init__.py +1 -1
- {adk_code_mode-1.6.1 → adk_code_mode-2.0.1}/src/adk_code_mode/runtime/base.py +2 -1
- {adk_code_mode-1.6.1 → adk_code_mode-2.0.1}/src/adk_code_mode/runtime/docker.py +2 -2
- {adk_code_mode-1.6.1 → adk_code_mode-2.0.1}/src/adk_code_mode/runtime/protocol.py +19 -2
- {adk_code_mode-1.6.1 → adk_code_mode-2.0.1}/src/adk_code_mode/runtime/remote.py +1 -1
- {adk_code_mode-1.6.1 → adk_code_mode-2.0.1}/src/adk_code_mode/tool.py +141 -43
- adk_code_mode-2.0.1/src/adk_code_mode/tool_failures.py +54 -0
- {adk_code_mode-1.6.1 → adk_code_mode-2.0.1}/src/adk_code_mode/tool_result_artifacts.py +4 -1
- {adk_code_mode-1.6.1 → adk_code_mode-2.0.1}/src/adk_code_mode/tools/__init__.py +1 -1
- {adk_code_mode-1.6.1 → adk_code_mode-2.0.1}/src/adk_code_mode/tools/catalog.py +1 -1
- {adk_code_mode-1.6.1 → adk_code_mode-2.0.1}/src/adk_code_mode/tools/dispatcher.py +16 -2
- {adk_code_mode-1.6.1 → adk_code_mode-2.0.1}/src/adk_code_mode/tools/namespacing.py +1 -1
- {adk_code_mode-1.6.1 → adk_code_mode-2.0.1}/src/adk_code_mode/tools/normaliser.py +1 -1
- {adk_code_mode-1.6.1 → adk_code_mode-2.0.1}/src/adk_code_mode/tools/stubs.py +15 -9
- {adk_code_mode-1.6.1 → adk_code_mode-2.0.1}/src/adk_code_mode/workspace/__init__.py +1 -1
- {adk_code_mode-1.6.1 → adk_code_mode-2.0.1}/src/adk_code_mode/workspace/files.py +1 -1
- adk_code_mode-2.0.1/tests/__init__.py +3 -0
- {adk_code_mode-1.6.1 → adk_code_mode-2.0.1}/tests/_docker_helpers.py +1 -1
- {adk_code_mode-1.6.1 → adk_code_mode-2.0.1}/tests/_fake_runtime.py +1 -1
- adk_code_mode-2.0.1/tests/_rest_tool.py +49 -0
- {adk_code_mode-1.6.1 → adk_code_mode-2.0.1}/tests/conftest.py +1 -1
- {adk_code_mode-1.6.1 → adk_code_mode-2.0.1}/tests/test_agent_with_fake_llm.py +1 -1
- {adk_code_mode-1.6.1 → adk_code_mode-2.0.1}/tests/test_artifact_tools.py +1 -1
- {adk_code_mode-1.6.1 → adk_code_mode-2.0.1}/tests/test_catalog.py +1 -1
- {adk_code_mode-1.6.1 → adk_code_mode-2.0.1}/tests/test_dispatcher.py +107 -1
- {adk_code_mode-1.6.1 → adk_code_mode-2.0.1}/tests/test_docker_image.py +4 -1
- {adk_code_mode-1.6.1 → adk_code_mode-2.0.1}/tests/test_docker_integration.py +1 -1
- {adk_code_mode-1.6.1 → adk_code_mode-2.0.1}/tests/test_host_loop.py +66 -4
- {adk_code_mode-1.6.1 → adk_code_mode-2.0.1}/tests/test_integration.py +91 -8
- {adk_code_mode-1.6.1 → adk_code_mode-2.0.1}/tests/test_metadata.py +1 -1
- {adk_code_mode-1.6.1 → adk_code_mode-2.0.1}/tests/test_namespacing.py +1 -1
- {adk_code_mode-1.6.1 → adk_code_mode-2.0.1}/tests/test_normaliser.py +1 -1
- {adk_code_mode-1.6.1 → adk_code_mode-2.0.1}/tests/test_output.py +1 -1
- {adk_code_mode-1.6.1 → adk_code_mode-2.0.1}/tests/test_protocol.py +16 -1
- {adk_code_mode-1.6.1 → adk_code_mode-2.0.1}/tests/test_remote_backend.py +1 -1
- {adk_code_mode-1.6.1 → adk_code_mode-2.0.1}/tests/test_remote_integration.py +115 -4
- {adk_code_mode-1.6.1 → adk_code_mode-2.0.1}/tests/test_runtime_docker.py +1 -1
- {adk_code_mode-1.6.1 → adk_code_mode-2.0.1}/tests/test_sandbox_entry.py +29 -1
- {adk_code_mode-1.6.1 → adk_code_mode-2.0.1}/tests/test_sandbox_rpc_client.py +51 -2
- {adk_code_mode-1.6.1 → adk_code_mode-2.0.1}/tests/test_stubs.py +8 -6
- {adk_code_mode-1.6.1 → adk_code_mode-2.0.1}/tests/test_stubs_json_schema.py +1 -1
- {adk_code_mode-1.6.1 → adk_code_mode-2.0.1}/tests/test_tool.py +7 -1
- {adk_code_mode-1.6.1 → adk_code_mode-2.0.1}/tests/test_tool_result_artifacts.py +1 -1
- {adk_code_mode-1.6.1 → adk_code_mode-2.0.1}/tests/test_version.py +1 -1
- {adk_code_mode-1.6.1 → adk_code_mode-2.0.1}/tests/test_workspace_files.py +1 -1
- adk_code_mode-1.6.1/.release-please-manifest.json +0 -3
- adk_code_mode-1.6.1/CHANGELOG.md +0 -150
- adk_code_mode-1.6.1/sandbox-wheel/README.md +0 -14
- adk_code_mode-1.6.1/sandbox-wheel/src/adk_code_mode_sandbox/__about__.py +0 -4
- adk_code_mode-1.6.1/src/adk_code_mode/__about__.py +0 -4
- adk_code_mode-1.6.1/tests/__init__.py +0 -3
- {adk_code_mode-1.6.1 → adk_code_mode-2.0.1}/.githooks/pre-commit +0 -0
- {adk_code_mode-1.6.1 → adk_code_mode-2.0.1}/.githooks/pre-push +0 -0
- {adk_code_mode-1.6.1 → adk_code_mode-2.0.1}/.github/workflows/ci.yml +0 -0
- {adk_code_mode-1.6.1 → adk_code_mode-2.0.1}/.gitignore +0 -0
- {adk_code_mode-1.6.1 → adk_code_mode-2.0.1}/.prettierrc +0 -0
- {adk_code_mode-1.6.1 → adk_code_mode-2.0.1}/.vscode/settings.json +0 -0
- {adk_code_mode-1.6.1 → adk_code_mode-2.0.1}/.zed/settings.json +0 -0
- {adk_code_mode-1.6.1 → adk_code_mode-2.0.1}/LICENSE +0 -0
- {adk_code_mode-1.6.1 → adk_code_mode-2.0.1}/Makefile +0 -0
- {adk_code_mode-1.6.1 → adk_code_mode-2.0.1}/release-please-config.json +0 -0
- {adk_code_mode-1.6.1 → adk_code_mode-2.0.1}/scripts/install-git-hooks.sh +0 -0
- {adk_code_mode-1.6.1 → adk_code_mode-2.0.1}/src/adk_code_mode/py.typed +0 -0
- {adk_code_mode-1.6.1 → adk_code_mode-2.0.1}/uv.lock +0 -0
|
@@ -112,5 +112,5 @@ jobs:
|
|
|
112
112
|
file: docker/Dockerfile
|
|
113
113
|
push: true
|
|
114
114
|
tags: |
|
|
115
|
-
ghcr.io/
|
|
116
|
-
ghcr.io/
|
|
115
|
+
ghcr.io/buildagenta/adk-code-mode:${{ needs.release-please.outputs.version }}
|
|
116
|
+
ghcr.io/buildagenta/adk-code-mode:latest
|
|
@@ -0,0 +1,169 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
## [2.0.1](https://github.com/buildagenta/adk-code-mode/compare/adk-code-mode-v2.0.0...adk-code-mode-v2.0.1) (2026-11-02)
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
### Miscellaneous Chores
|
|
7
|
+
|
|
8
|
+
* credit Agenta as the author ([#25](https://github.com/buildagenta/adk-code-mode/issues/25)) ([bfe577e](https://github.com/buildagenta/adk-code-mode/commit/bfe577e9aaba31ed9d8f6423485b061deb77b963))
|
|
9
|
+
|
|
10
|
+
## [2.0.0](https://github.com/buildagenta/adk-code-mode/compare/adk-code-mode-v1.6.1...adk-code-mode-v2.0.0) (2026-09-25)
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
### ⚠ BREAKING CHANGES
|
|
14
|
+
|
|
15
|
+
* sandbox code that checked a tool result for an `error` key now gets an exception instead, and the sandbox image must be rebuilt for protocol version 3.
|
|
16
|
+
|
|
17
|
+
### Features
|
|
18
|
+
|
|
19
|
+
* raise when a tool call fails instead of returning the error ([#22](https://github.com/buildagenta/adk-code-mode/issues/22)) ([489083d](https://github.com/buildagenta/adk-code-mode/commit/489083d988cd7e958e94f3ef6acba6443284abd8))
|
|
20
|
+
* stop a timed-out block without losing the turn's state ([#23](https://github.com/buildagenta/adk-code-mode/issues/23)) ([4720156](https://github.com/buildagenta/adk-code-mode/commit/47201568d0bb06527e32f850b7abb1b465e36920))
|
|
21
|
+
|
|
22
|
+
## [1.6.1](https://github.com/buildagenta/adk-code-mode/compare/adk-code-mode-v1.6.0...adk-code-mode-v1.6.1) (2026-09-22)
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
### Bug Fixes
|
|
26
|
+
|
|
27
|
+
* exit the sandbox when the host disconnects mid-block ([bd3fb0f](https://github.com/buildagenta/adk-code-mode/commit/bd3fb0fb0d8a0cab9370f2ad6db56dfacf566cb4))
|
|
28
|
+
|
|
29
|
+
## [1.6.0](https://github.com/buildagenta/adk-code-mode/compare/adk-code-mode-v1.5.0...adk-code-mode-v1.6.0) (2026-08-29)
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
### Features
|
|
33
|
+
|
|
34
|
+
* bound an execute_code block by default ([1609c0d](https://github.com/buildagenta/adk-code-mode/commit/1609c0d24b8563cba51434cd1214b4299aeefc86))
|
|
35
|
+
* expand object oneOf/anyOf branches in tool stub docstrings ([#20](https://github.com/buildagenta/adk-code-mode/issues/20)) ([7d42cb1](https://github.com/buildagenta/adk-code-mode/commit/7d42cb1ee9d9e217d008776dc74a84034f4b67a9))
|
|
36
|
+
|
|
37
|
+
## [1.5.0](https://github.com/buildagenta/adk-code-mode/compare/adk-code-mode-v1.4.0...adk-code-mode-v1.5.0) (2026-08-10)
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
### Features
|
|
41
|
+
|
|
42
|
+
* scope tool-name uniqueness to each namespace ([#17](https://github.com/buildagenta/adk-code-mode/issues/17)) ([437bc0d](https://github.com/buildagenta/adk-code-mode/commit/437bc0dc930521a933e5c25b4bd6103e9434fc27))
|
|
43
|
+
|
|
44
|
+
## [1.4.0](https://github.com/buildagenta/adk-code-mode/compare/adk-code-mode-v1.3.0...adk-code-mode-v1.4.0) (2026-07-28)
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
### Features
|
|
48
|
+
|
|
49
|
+
* surface nested schema properties and validation keywords in tool stubs ([608d14b](https://github.com/buildagenta/adk-code-mode/commit/608d14bb115159b2991c7d8d4e3c641977fd0d66))
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
### Documentation
|
|
53
|
+
|
|
54
|
+
* document stub schema fidelity and the `JSON_SCHEMA_FOR_FUNC_DECL` flag in `README.md` ([219f02b](https://github.com/buildagenta/adk-code-mode/commit/219f02bd493c2e2d7275a0034ef2a40db933859f))
|
|
55
|
+
|
|
56
|
+
## [1.3.0](https://github.com/buildagenta/adk-code-mode/compare/adk-code-mode-v1.2.0...adk-code-mode-v1.3.0) (2026-07-23)
|
|
57
|
+
|
|
58
|
+
|
|
59
|
+
### Features
|
|
60
|
+
|
|
61
|
+
* describe the sandbox to the model in a tagged `<code-mode>` block ([#14](https://github.com/buildagenta/adk-code-mode/issues/14)) ([662a281](https://github.com/buildagenta/adk-code-mode/commit/662a28138e8632b434e5f1ecd52793f7d83ee097))
|
|
62
|
+
|
|
63
|
+
## [1.2.0](https://github.com/buildagenta/adk-code-mode/compare/adk-code-mode-v1.1.0...adk-code-mode-v1.2.0) (2026-07-23)
|
|
64
|
+
|
|
65
|
+
|
|
66
|
+
### Features
|
|
67
|
+
|
|
68
|
+
* add `custom_metadata` to the `save_artifact` tool ([dfd9a59](https://github.com/buildagenta/adk-code-mode/commit/dfd9a59bf1718084a1d5c02cc1ea453269223f16))
|
|
69
|
+
|
|
70
|
+
## [1.1.0](https://github.com/buildagenta/adk-code-mode/compare/adk-code-mode-v1.0.0...adk-code-mode-v1.1.0) (2026-07-15)
|
|
71
|
+
|
|
72
|
+
|
|
73
|
+
### Features
|
|
74
|
+
|
|
75
|
+
* expose `tools` and `backend` as public properties on `ExecuteCodeTool` ([acfb704](https://github.com/buildagenta/adk-code-mode/commit/acfb704d388da5d66e318775e03fe055467679c2))
|
|
76
|
+
|
|
77
|
+
## [1.0.0](https://github.com/buildagenta/adk-code-mode/compare/adk-code-mode-v0.4.1...adk-code-mode-v1.0.0) (2026-07-15)
|
|
78
|
+
|
|
79
|
+
|
|
80
|
+
### ⚠ BREAKING CHANGES
|
|
81
|
+
|
|
82
|
+
* `CodeModeCodeExecutor`, `code_mode_before_model_callback`, and `CODE_MODE_SYSTEM_INSTRUCTION` no longer exist. Add `ExecuteCodeTool` to the agent's `tools=[...]` instead of wiring `code_executor=`; drop `before_model_callback=`, `generate_content_config=`, and `CODE_MODE_SYSTEM_INSTRUCTION` entirely; `release_invocation` is now `async`. See the README's migration section.
|
|
83
|
+
|
|
84
|
+
### Features
|
|
85
|
+
|
|
86
|
+
* replace `CodeModeCodeExecutor` with `ExecuteCodeTool` ([#10](https://github.com/buildagenta/adk-code-mode/issues/10)) ([b78572e](https://github.com/buildagenta/adk-code-mode/commit/b78572e72446930548760756255390d1a3cc388a))
|
|
87
|
+
|
|
88
|
+
## [0.4.1](https://github.com/buildagenta/adk-code-mode/compare/adk-code-mode-v0.4.0...adk-code-mode-v0.4.1) (2026-07-10)
|
|
89
|
+
|
|
90
|
+
|
|
91
|
+
### Documentation
|
|
92
|
+
|
|
93
|
+
* note the sandbox writes to `/tools` in remote deployment guide ([96bb45e](https://github.com/buildagenta/adk-code-mode/commit/96bb45e4e18d9d54709f4c10b6b09cf3567ee385))
|
|
94
|
+
|
|
95
|
+
## [0.4.0](https://github.com/buildagenta/adk-code-mode/compare/adk-code-mode-v0.3.0...adk-code-mode-v0.4.0) (2026-07-09)
|
|
96
|
+
|
|
97
|
+
|
|
98
|
+
### Features
|
|
99
|
+
|
|
100
|
+
* save tool results as artifacts with optional model-supplied naming ([76a3671](https://github.com/buildagenta/adk-code-mode/commit/76a36713b2c52bd5b8dc51d3669226a47e7108e5))
|
|
101
|
+
|
|
102
|
+
|
|
103
|
+
### Bug Fixes
|
|
104
|
+
|
|
105
|
+
* align code-mode example with the `<code-mode>` catalog and fix fences ([4a0cc6d](https://github.com/buildagenta/adk-code-mode/commit/4a0cc6d0fc99d5425f6682cc489e76c9ddef7d46))
|
|
106
|
+
* clarify code-mode tools are a Python library, not function tools ([48d1018](https://github.com/buildagenta/adk-code-mode/commit/48d1018152a2ed2a8e7361de6ce0f43b31b429ce))
|
|
107
|
+
* nudge the model to call tools via Python in the code-mode block ([141baf3](https://github.com/buildagenta/adk-code-mode/commit/141baf3a44976e82cf437b2064666be893d6d409))
|
|
108
|
+
* update `CODE_MODE_SYSTEM_INSTRUCTION` and `README.md` ([933d42c](https://github.com/buildagenta/adk-code-mode/commit/933d42cb237b9d6deeb6611511cba28a0d5e9261))
|
|
109
|
+
|
|
110
|
+
|
|
111
|
+
### Documentation
|
|
112
|
+
|
|
113
|
+
* streamline `README.md` and fix broken code fences ([c237514](https://github.com/buildagenta/adk-code-mode/commit/c2375149df48e21318967090b6c85d0b1f411ea2))
|
|
114
|
+
|
|
115
|
+
## [0.3.0](https://github.com/buildagenta/adk-code-mode/compare/adk-code-mode-v0.2.2...adk-code-mode-v0.3.0) (2026-07-06)
|
|
116
|
+
|
|
117
|
+
|
|
118
|
+
### Features
|
|
119
|
+
|
|
120
|
+
* hold one sandbox container open per turn (protocol v2) ([#6](https://github.com/buildagenta/adk-code-mode/issues/6)) ([aebe17d](https://github.com/buildagenta/adk-code-mode/commit/aebe17d2bbbf21cc0f05852efaf910ff6adc3154))
|
|
121
|
+
|
|
122
|
+
|
|
123
|
+
### Documentation
|
|
124
|
+
|
|
125
|
+
* lower startup probe period in `README.md` for faster cold starts ([e251af2](https://github.com/buildagenta/adk-code-mode/commit/e251af2cf7307c9944361e1a0e37c7191822a9e1))
|
|
126
|
+
* note HTTP `/health` startup probe in `README.md` Cloud Run section ([d58fb10](https://github.com/buildagenta/adk-code-mode/commit/d58fb10f7aeda95e5c8cf29263a13e1333f661dd))
|
|
127
|
+
|
|
128
|
+
## [0.2.2](https://github.com/buildagenta/adk-code-mode/compare/adk-code-mode-v0.2.1...adk-code-mode-v0.2.2) (2026-05-08)
|
|
129
|
+
|
|
130
|
+
|
|
131
|
+
### Bug Fixes
|
|
132
|
+
|
|
133
|
+
* use `python` fences instead of `tool_code` in `CodeModeCodeExecutor` ([efcc11e](https://github.com/buildagenta/adk-code-mode/commit/efcc11e1020c7544223074e00a8649f9c85d4ad6))
|
|
134
|
+
|
|
135
|
+
## [0.2.1](https://github.com/buildagenta/adk-code-mode/compare/adk-code-mode-v0.2.0...adk-code-mode-v0.2.1) (2026-05-05)
|
|
136
|
+
|
|
137
|
+
|
|
138
|
+
### Bug Fixes
|
|
139
|
+
|
|
140
|
+
* rename `<tools>` tag to `<code-mode>` and update `CODE_MODE_SYSTEM_INSTRUCTION` ([0a06bfb](https://github.com/buildagenta/adk-code-mode/commit/0a06bfbdf22db6e0226e477d0ed074a6cc4d1515))
|
|
141
|
+
|
|
142
|
+
|
|
143
|
+
### Documentation
|
|
144
|
+
|
|
145
|
+
* update `README.md` with deployment instructions ([1dd7a95](https://github.com/buildagenta/adk-code-mode/commit/1dd7a95197fd56231ba97182526a825baf18508a))
|
|
146
|
+
|
|
147
|
+
## [0.2.0](https://github.com/buildagenta/adk-code-mode/compare/adk-code-mode-v0.1.0...adk-code-mode-v0.2.0) (2026-05-03)
|
|
148
|
+
|
|
149
|
+
|
|
150
|
+
### Features
|
|
151
|
+
|
|
152
|
+
* add `RemoteBackend`, sandbox hardening, and make `README.md` more concise ([a1a70ee](https://github.com/buildagenta/adk-code-mode/commit/a1a70eec0686f164ce3796ba1d82bb82b7fbda59))
|
|
153
|
+
|
|
154
|
+
|
|
155
|
+
### Bug Fixes
|
|
156
|
+
|
|
157
|
+
* improve `CODE_MODE_SYSTEM_INSTRUCTION` ([0d00863](https://github.com/buildagenta/adk-code-mode/commit/0d008636e2e273b438192f737e20e207c165a610))
|
|
158
|
+
|
|
159
|
+
## 0.1.0 (2026-04-29)
|
|
160
|
+
|
|
161
|
+
|
|
162
|
+
### Features
|
|
163
|
+
|
|
164
|
+
* ADK Code Mode: `CodeModeExecutor`, `DockerRuntime`, and more ([6ab1ac2](https://github.com/buildagenta/adk-code-mode/commit/6ab1ac28236d21ecb740d8e920e08e4d9bd969c5))
|
|
165
|
+
|
|
166
|
+
|
|
167
|
+
### Documentation
|
|
168
|
+
|
|
169
|
+
* shorten ADK code executor comparison table headers ([28116cf](https://github.com/buildagenta/adk-code-mode/commit/28116cf9f40b3623c31782a55885fa5c4f8c6bbf))
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
Metadata-Version: 2.5
|
|
2
2
|
Name: adk-code-mode
|
|
3
|
-
Version:
|
|
3
|
+
Version: 2.0.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
|
-
Project-URL: Documentation, https://github.com/
|
|
6
|
-
Project-URL: Issues, https://github.com/
|
|
7
|
-
Project-URL: Source, https://github.com/
|
|
8
|
-
Author-email:
|
|
5
|
+
Project-URL: Documentation, https://github.com/buildagenta/adk-code-mode#readme
|
|
6
|
+
Project-URL: Issues, https://github.com/buildagenta/adk-code-mode/issues
|
|
7
|
+
Project-URL: Source, https://github.com/buildagenta/adk-code-mode
|
|
8
|
+
Author-email: Agenta <hello@buildagenta.com>
|
|
9
9
|
License-Expression: Apache-2.0
|
|
10
10
|
License-File: LICENSE
|
|
11
11
|
Keywords: a2a,adk,agents,code-mode,execute-code
|
|
@@ -39,6 +39,7 @@ Inspired by Cloudflare's [Code Mode](https://blog.cloudflare.com/code-mode/) and
|
|
|
39
39
|
## ✨ Features
|
|
40
40
|
|
|
41
41
|
- **Call ADK tools from sandbox code** — imports against the `tools` package proxy back to the host and run through ADK's `before_tool` / `after_tool` / `on_error` callbacks and the plugin manager exactly as direct tool calls would.
|
|
42
|
+
- **Failed tool calls raise** — a REST tool whose API answers with an HTTP error raises `HTTPStatusError` (with `status_code` and `body`), and any other failure, including an MCP tool that reports one, raises `ToolError`. ADK returns these as values for a model to read, but sandbox code reads return values, so it would otherwise carry on as if the call had worked.
|
|
42
43
|
- **Bake any Python package into the image** — extend the published base image with anything the model's code needs to `import`, no runtime `pip install` required. The sandbox reports what it has installed, so the model is told about it automatically.
|
|
43
44
|
- **Cross-turn persistence via ADK Artifacts** — `save_artifact` / `load_artifact` / `list_artifacts` are auto-injected and route through your configured `ArtifactService`. Files the code creates or changes are saved as artifacts automatically too.
|
|
44
45
|
- **Tool results saved as artifacts** — on by default; every tool's result is persisted as a `code_mode.tool_result` artifact (with optional model-supplied name/description) so hosts can forward outputs and large results stay out of the prompt. Opt out with `save_tool_results_as_artifacts=False`.
|
|
@@ -124,7 +125,7 @@ override_feature_enabled(FeatureName.JSON_SCHEMA_FOR_FUNC_DECL, True)
|
|
|
124
125
|
|
|
125
126
|
tool = ExecuteCodeTool(
|
|
126
127
|
tools=[my_fn_tool, McpToolset(...), OpenAPIToolset(...)],
|
|
127
|
-
backend=UnsafeLocalDockerBackend(image="ghcr.io/
|
|
128
|
+
backend=UnsafeLocalDockerBackend(image="ghcr.io/buildagenta/adk-code-mode:latest"),
|
|
128
129
|
)
|
|
129
130
|
```
|
|
130
131
|
|
|
@@ -144,8 +145,8 @@ print(send_message(channel="C123", text="hi"))
|
|
|
144
145
|
```bash
|
|
145
146
|
# Push the sandbox image to Artifact Registry
|
|
146
147
|
gcloud auth configure-docker <region>-docker.pkg.dev
|
|
147
|
-
docker pull --platform linux/amd64 ghcr.io/
|
|
148
|
-
docker tag ghcr.io/
|
|
148
|
+
docker pull --platform linux/amd64 ghcr.io/buildagenta/adk-code-mode:latest
|
|
149
|
+
docker tag ghcr.io/buildagenta/adk-code-mode:latest \
|
|
149
150
|
<region>-docker.pkg.dev/<project>/<repository>/adk-code-mode-sandbox:latest
|
|
150
151
|
docker push <region>-docker.pkg.dev/<project>/<repository>/adk-code-mode-sandbox:latest
|
|
151
152
|
|
|
@@ -279,10 +280,10 @@ ExecuteCodeTool(tools=..., backend=..., save_tool_results_as_artifacts=True)
|
|
|
279
280
|
|
|
280
281
|
## 🐳 Sandbox Image
|
|
281
282
|
|
|
282
|
-
The published base image (`ghcr.io/
|
|
283
|
+
The published base image (`ghcr.io/buildagenta/adk-code-mode`) works as-is for tools whose execution is fully host-side. To bake in extra Python packages:
|
|
283
284
|
|
|
284
285
|
```dockerfile
|
|
285
|
-
FROM ghcr.io/
|
|
286
|
+
FROM ghcr.io/buildagenta/adk-code-mode:latest
|
|
286
287
|
RUN pip install --no-cache-dir pandas==2.2.*
|
|
287
288
|
```
|
|
288
289
|
|
|
@@ -300,7 +301,7 @@ All settings are `ExecuteCodeTool` constructor arguments:
|
|
|
300
301
|
| `max_code_mode_metadata_chars` | `50_000` | Budget for the whole rendered `<code-mode>` block, tags included. Oversized blocks degrade in tiers rather than disappearing — see [What the model sees](#what-the-model-sees). |
|
|
301
302
|
| `max_output_chars` | `50_000` | Caps stdout/stderr handed back to the model. Overflow is saved as a session artifact at `code_mode/stdout/<call-id>.txt` and the model sees a head-and-tail view pointing to it. |
|
|
302
303
|
| `max_code_chars` | `1_000_000` | Rejects oversized code payloads before starting a container. |
|
|
303
|
-
| `timeout_seconds` | `60` | Caps overall execution time of one `execute_code` call, and with it every tool the block calls. `None` lifts
|
|
304
|
+
| `timeout_seconds` | `60` | Caps overall execution time of one `execute_code` call, and with it every tool the block calls. A block past the cap is stopped with its output so far, keeping the turn's variables and working directory. If it won't stop within a few seconds or leaves a worker thread or child process running, its sandbox is restarted and its output and state are lost. The model is told the cap. `None` lifts it, leaving the platform request timeout (e.g. Cloud Run `--timeout`) as the only bound. |
|
|
304
305
|
| `per_tool_timeout_seconds` | `None` | Caps each individual tool call made from within the sandbox. |
|
|
305
306
|
| `session_idle_timeout_seconds` | `600` | Idle reaper: closes a turn's container once it goes untouched this long. Backstop for turns that never call `release_invocation`. |
|
|
306
307
|
|
|
@@ -469,9 +470,9 @@ uv run pytest -m docker
|
|
|
469
470
|
|
|
470
471
|
`adk-code-mode` is distributed under the terms of the [Apache-2.0](https://spdx.org/licenses/Apache-2.0.html) license.
|
|
471
472
|
|
|
472
|
-
## 🤝 Join the
|
|
473
|
+
## 🤝 Join the Agenta Community
|
|
473
474
|
|
|
474
|
-
|
|
475
|
+
Agenta is a site to find and share AI agents and open-source community. Join to share your A2A agents, ask questions, stay up-to-date with the latest A2A news, be the first to hear about open-source releases, tutorials, and more!
|
|
475
476
|
|
|
476
|
-
- 🌍 Site: [
|
|
477
|
+
- 🌍 Site: [Agenta](https://buildagenta.com)
|
|
477
478
|
- 🤖 Discord: [Join the Discord](https://discord.gg/674NGXpAjU)
|
|
@@ -12,6 +12,7 @@ Inspired by Cloudflare's [Code Mode](https://blog.cloudflare.com/code-mode/) and
|
|
|
12
12
|
## ✨ Features
|
|
13
13
|
|
|
14
14
|
- **Call ADK tools from sandbox code** — imports against the `tools` package proxy back to the host and run through ADK's `before_tool` / `after_tool` / `on_error` callbacks and the plugin manager exactly as direct tool calls would.
|
|
15
|
+
- **Failed tool calls raise** — a REST tool whose API answers with an HTTP error raises `HTTPStatusError` (with `status_code` and `body`), and any other failure, including an MCP tool that reports one, raises `ToolError`. ADK returns these as values for a model to read, but sandbox code reads return values, so it would otherwise carry on as if the call had worked.
|
|
15
16
|
- **Bake any Python package into the image** — extend the published base image with anything the model's code needs to `import`, no runtime `pip install` required. The sandbox reports what it has installed, so the model is told about it automatically.
|
|
16
17
|
- **Cross-turn persistence via ADK Artifacts** — `save_artifact` / `load_artifact` / `list_artifacts` are auto-injected and route through your configured `ArtifactService`. Files the code creates or changes are saved as artifacts automatically too.
|
|
17
18
|
- **Tool results saved as artifacts** — on by default; every tool's result is persisted as a `code_mode.tool_result` artifact (with optional model-supplied name/description) so hosts can forward outputs and large results stay out of the prompt. Opt out with `save_tool_results_as_artifacts=False`.
|
|
@@ -97,7 +98,7 @@ override_feature_enabled(FeatureName.JSON_SCHEMA_FOR_FUNC_DECL, True)
|
|
|
97
98
|
|
|
98
99
|
tool = ExecuteCodeTool(
|
|
99
100
|
tools=[my_fn_tool, McpToolset(...), OpenAPIToolset(...)],
|
|
100
|
-
backend=UnsafeLocalDockerBackend(image="ghcr.io/
|
|
101
|
+
backend=UnsafeLocalDockerBackend(image="ghcr.io/buildagenta/adk-code-mode:latest"),
|
|
101
102
|
)
|
|
102
103
|
```
|
|
103
104
|
|
|
@@ -117,8 +118,8 @@ print(send_message(channel="C123", text="hi"))
|
|
|
117
118
|
```bash
|
|
118
119
|
# Push the sandbox image to Artifact Registry
|
|
119
120
|
gcloud auth configure-docker <region>-docker.pkg.dev
|
|
120
|
-
docker pull --platform linux/amd64 ghcr.io/
|
|
121
|
-
docker tag ghcr.io/
|
|
121
|
+
docker pull --platform linux/amd64 ghcr.io/buildagenta/adk-code-mode:latest
|
|
122
|
+
docker tag ghcr.io/buildagenta/adk-code-mode:latest \
|
|
122
123
|
<region>-docker.pkg.dev/<project>/<repository>/adk-code-mode-sandbox:latest
|
|
123
124
|
docker push <region>-docker.pkg.dev/<project>/<repository>/adk-code-mode-sandbox:latest
|
|
124
125
|
|
|
@@ -252,10 +253,10 @@ ExecuteCodeTool(tools=..., backend=..., save_tool_results_as_artifacts=True)
|
|
|
252
253
|
|
|
253
254
|
## 🐳 Sandbox Image
|
|
254
255
|
|
|
255
|
-
The published base image (`ghcr.io/
|
|
256
|
+
The published base image (`ghcr.io/buildagenta/adk-code-mode`) works as-is for tools whose execution is fully host-side. To bake in extra Python packages:
|
|
256
257
|
|
|
257
258
|
```dockerfile
|
|
258
|
-
FROM ghcr.io/
|
|
259
|
+
FROM ghcr.io/buildagenta/adk-code-mode:latest
|
|
259
260
|
RUN pip install --no-cache-dir pandas==2.2.*
|
|
260
261
|
```
|
|
261
262
|
|
|
@@ -273,7 +274,7 @@ All settings are `ExecuteCodeTool` constructor arguments:
|
|
|
273
274
|
| `max_code_mode_metadata_chars` | `50_000` | Budget for the whole rendered `<code-mode>` block, tags included. Oversized blocks degrade in tiers rather than disappearing — see [What the model sees](#what-the-model-sees). |
|
|
274
275
|
| `max_output_chars` | `50_000` | Caps stdout/stderr handed back to the model. Overflow is saved as a session artifact at `code_mode/stdout/<call-id>.txt` and the model sees a head-and-tail view pointing to it. |
|
|
275
276
|
| `max_code_chars` | `1_000_000` | Rejects oversized code payloads before starting a container. |
|
|
276
|
-
| `timeout_seconds` | `60` | Caps overall execution time of one `execute_code` call, and with it every tool the block calls. `None` lifts
|
|
277
|
+
| `timeout_seconds` | `60` | Caps overall execution time of one `execute_code` call, and with it every tool the block calls. A block past the cap is stopped with its output so far, keeping the turn's variables and working directory. If it won't stop within a few seconds or leaves a worker thread or child process running, its sandbox is restarted and its output and state are lost. The model is told the cap. `None` lifts it, leaving the platform request timeout (e.g. Cloud Run `--timeout`) as the only bound. |
|
|
277
278
|
| `per_tool_timeout_seconds` | `None` | Caps each individual tool call made from within the sandbox. |
|
|
278
279
|
| `session_idle_timeout_seconds` | `600` | Idle reaper: closes a turn's container once it goes untouched this long. Backstop for turns that never call `release_invocation`. |
|
|
279
280
|
|
|
@@ -442,9 +443,9 @@ uv run pytest -m docker
|
|
|
442
443
|
|
|
443
444
|
`adk-code-mode` is distributed under the terms of the [Apache-2.0](https://spdx.org/licenses/Apache-2.0.html) license.
|
|
444
445
|
|
|
445
|
-
## 🤝 Join the
|
|
446
|
+
## 🤝 Join the Agenta Community
|
|
446
447
|
|
|
447
|
-
|
|
448
|
+
Agenta is a site to find and share AI agents and open-source community. Join to share your A2A agents, ask questions, stay up-to-date with the latest A2A news, be the first to hear about open-source releases, tutorials, and more!
|
|
448
449
|
|
|
449
|
-
- 🌍 Site: [
|
|
450
|
+
- 🌍 Site: [Agenta](https://buildagenta.com)
|
|
450
451
|
- 🤖 Discord: [Join the Discord](https://discord.gg/674NGXpAjU)
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
FROM python:3.13-slim
|
|
2
2
|
|
|
3
|
-
LABEL org.opencontainers.image.source="https://github.com/
|
|
3
|
+
LABEL org.opencontainers.image.source="https://github.com/buildagenta/adk-code-mode"
|
|
4
4
|
LABEL org.opencontainers.image.description="Sandbox base image for ADK Code Mode"
|
|
5
5
|
LABEL org.opencontainers.image.licenses="Apache-2.0"
|
|
6
6
|
|
|
@@ -11,7 +11,7 @@ requires-python = ">=3.10"
|
|
|
11
11
|
license = "Apache-2.0"
|
|
12
12
|
keywords = ["adk", "code-mode", "execute-code", "agents", "a2a"]
|
|
13
13
|
authors = [
|
|
14
|
-
{ name = "
|
|
14
|
+
{ name = "Agenta", email = "hello@buildagenta.com" },
|
|
15
15
|
]
|
|
16
16
|
classifiers = [
|
|
17
17
|
"Development Status :: 4 - Beta",
|
|
@@ -47,9 +47,9 @@ dev = [
|
|
|
47
47
|
]
|
|
48
48
|
|
|
49
49
|
[project.urls]
|
|
50
|
-
Documentation = "https://github.com/
|
|
51
|
-
Issues = "https://github.com/
|
|
52
|
-
Source = "https://github.com/
|
|
50
|
+
Documentation = "https://github.com/buildagenta/adk-code-mode#readme"
|
|
51
|
+
Issues = "https://github.com/buildagenta/adk-code-mode/issues"
|
|
52
|
+
Source = "https://github.com/buildagenta/adk-code-mode"
|
|
53
53
|
|
|
54
54
|
[tool.hatch.version]
|
|
55
55
|
path = "src/adk_code_mode/__about__.py"
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
# ADK Code Mode Sandbox
|
|
2
|
+
|
|
3
|
+
In-sandbox shim for [`adk-code-mode`](https://github.com/buildagenta/adk-code-mode). The host package launches a container that has this wheel installed, then talks to it over a TCP control connection so model code can call ADK tools that run on the host.
|
|
4
|
+
|
|
5
|
+
## 📄 License
|
|
6
|
+
|
|
7
|
+
`adk-code-mode-sandbox` is distributed under the terms of the [Apache-2.0](https://spdx.org/licenses/Apache-2.0.html) license.
|
|
8
|
+
|
|
9
|
+
## 🤝 Join the Agenta Community
|
|
10
|
+
|
|
11
|
+
Agenta is a site to find and share AI agents and open-source community. Join to share your A2A agents, ask questions, stay up-to-date with the latest A2A news, be the first to hear about open-source releases, tutorials, and more!
|
|
12
|
+
|
|
13
|
+
- 🌍 Site: [Agenta](https://buildagenta.com)
|
|
14
|
+
- 🤖 Discord: [Join the Discord](https://discord.gg/674NGXpAjU)
|
|
@@ -11,7 +11,7 @@ requires-python = ">=3.10"
|
|
|
11
11
|
license = "Apache-2.0"
|
|
12
12
|
keywords = ["adk", "code-mode", "sandbox"]
|
|
13
13
|
authors = [
|
|
14
|
-
{ name = "
|
|
14
|
+
{ name = "Agenta", email = "hello@buildagenta.com" },
|
|
15
15
|
]
|
|
16
16
|
classifiers = [
|
|
17
17
|
"Development Status :: 4 - Beta",
|
|
@@ -27,9 +27,9 @@ dependencies = [
|
|
|
27
27
|
]
|
|
28
28
|
|
|
29
29
|
[project.urls]
|
|
30
|
-
Documentation = "https://github.com/
|
|
31
|
-
Issues = "https://github.com/
|
|
32
|
-
Source = "https://github.com/
|
|
30
|
+
Documentation = "https://github.com/buildagenta/adk-code-mode#readme"
|
|
31
|
+
Issues = "https://github.com/buildagenta/adk-code-mode/issues"
|
|
32
|
+
Source = "https://github.com/buildagenta/adk-code-mode"
|
|
33
33
|
|
|
34
34
|
[tool.hatch.version]
|
|
35
35
|
path = "src/adk_code_mode_sandbox/__about__.py"
|
{adk_code_mode-1.6.1 → adk_code_mode-2.0.1}/sandbox-wheel/src/adk_code_mode_sandbox/_entry.py
RENAMED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
# SPDX-FileCopyrightText: 2025-present
|
|
1
|
+
# SPDX-FileCopyrightText: 2025-present Agenta <hello@buildagenta.com>
|
|
2
2
|
#
|
|
3
3
|
# SPDX-License-Identifier: Apache-2.0
|
|
4
4
|
"""Sandbox entry point.
|
|
@@ -28,11 +28,13 @@ import io
|
|
|
28
28
|
import os
|
|
29
29
|
import platform
|
|
30
30
|
import socket
|
|
31
|
+
import subprocess
|
|
31
32
|
import sys
|
|
33
|
+
import threading
|
|
32
34
|
import traceback
|
|
33
35
|
from typing import Any
|
|
34
36
|
|
|
35
|
-
from adk_code_mode_sandbox import _rpc_client
|
|
37
|
+
from adk_code_mode_sandbox import _interrupt, _rpc_client
|
|
36
38
|
from adk_code_mode_sandbox._rpc_client import RpcClient
|
|
37
39
|
from adk_code_mode_sandbox.protocol import (
|
|
38
40
|
DoneFrame,
|
|
@@ -184,7 +186,8 @@ def _exec_into(code: str, globs: dict[str, Any]) -> int:
|
|
|
184
186
|
traceback.print_exc()
|
|
185
187
|
return 1
|
|
186
188
|
try:
|
|
187
|
-
|
|
189
|
+
with _interrupt.running():
|
|
190
|
+
exec(compiled, globs)
|
|
188
191
|
except SystemExit as exc:
|
|
189
192
|
code_val = exc.code
|
|
190
193
|
if code_val is None:
|
|
@@ -199,7 +202,54 @@ def _exec_into(code: str, globs: dict[str, Any]) -> int:
|
|
|
199
202
|
return 0
|
|
200
203
|
|
|
201
204
|
|
|
202
|
-
def
|
|
205
|
+
def _has_linux_child_processes(task_dir: str = "/proc/self/task") -> bool:
|
|
206
|
+
"""Check each Linux thread for child processes still running."""
|
|
207
|
+
checked = False
|
|
208
|
+
try:
|
|
209
|
+
with os.scandir(task_dir) as tasks:
|
|
210
|
+
for task in tasks:
|
|
211
|
+
try:
|
|
212
|
+
with open(f"{task.path}/children") as children:
|
|
213
|
+
checked = True
|
|
214
|
+
if children.read().strip():
|
|
215
|
+
return True
|
|
216
|
+
except FileNotFoundError:
|
|
217
|
+
continue
|
|
218
|
+
except OSError:
|
|
219
|
+
return True
|
|
220
|
+
return not checked
|
|
221
|
+
|
|
222
|
+
|
|
223
|
+
def _has_child_processes() -> bool:
|
|
224
|
+
"""Check whether user code left a child process running."""
|
|
225
|
+
if sys.platform == "linux":
|
|
226
|
+
return _has_linux_child_processes()
|
|
227
|
+
try:
|
|
228
|
+
probe = subprocess.Popen(["ps", "-axo", "pid=,ppid="], stdout=subprocess.PIPE, text=True)
|
|
229
|
+
try:
|
|
230
|
+
output, _ = probe.communicate(timeout=2)
|
|
231
|
+
except subprocess.TimeoutExpired:
|
|
232
|
+
probe.kill()
|
|
233
|
+
probe.wait()
|
|
234
|
+
return True
|
|
235
|
+
except OSError:
|
|
236
|
+
return True
|
|
237
|
+
if probe.returncode != 0:
|
|
238
|
+
return True
|
|
239
|
+
return any(
|
|
240
|
+
int(pid) != probe.pid and int(ppid) == os.getpid()
|
|
241
|
+
for pid, ppid in (line.split() for line in output.splitlines())
|
|
242
|
+
)
|
|
243
|
+
|
|
244
|
+
|
|
245
|
+
def _has_background_work() -> bool:
|
|
246
|
+
"""Check whether code remains active outside the interrupted execution thread."""
|
|
247
|
+
reader_thread = _rpc_client.get()._reader_thread
|
|
248
|
+
trusted = {threading.current_thread(), threading.main_thread(), reader_thread}
|
|
249
|
+
return any(thread not in trusted for thread in threading.enumerate()) or _has_child_processes()
|
|
250
|
+
|
|
251
|
+
|
|
252
|
+
def run_block(code: str, globs: dict[str, Any]) -> tuple[str, str, int, bool]:
|
|
203
253
|
"""Run one code block with its stdout/stderr captured.
|
|
204
254
|
|
|
205
255
|
Redirects ``sys.stdout`` / ``sys.stderr`` to in-memory buffers for the
|
|
@@ -216,7 +266,7 @@ def run_block(code: str, globs: dict[str, Any]) -> tuple[str, str, int]:
|
|
|
216
266
|
finally:
|
|
217
267
|
sys.stdout = old_stdout
|
|
218
268
|
sys.stderr = old_stderr
|
|
219
|
-
return capture_out.getvalue(), capture_err.getvalue(), exit_code
|
|
269
|
+
return capture_out.getvalue(), capture_err.getvalue(), exit_code, _has_background_work()
|
|
220
270
|
|
|
221
271
|
|
|
222
272
|
def main() -> int:
|
|
@@ -246,8 +296,8 @@ def main() -> int:
|
|
|
246
296
|
if isinstance(frame, ShutdownFrame):
|
|
247
297
|
return 0
|
|
248
298
|
if isinstance(frame, RunFrame):
|
|
249
|
-
stdout_text, stderr_text, exit_code = run_block(frame.code, globs)
|
|
250
|
-
client.send(DoneFrame(exit_code=exit_code))
|
|
299
|
+
stdout_text, stderr_text, exit_code, background_work = run_block(frame.code, globs)
|
|
300
|
+
client.send(DoneFrame(exit_code=exit_code, background_work=background_work))
|
|
251
301
|
client.send(OutputFrame(stdout=stdout_text, stderr=stderr_text, exit_code=exit_code))
|
|
252
302
|
continue
|
|
253
303
|
# Any other frame kind is a host protocol error; keep going but log.
|
{adk_code_mode-1.6.1 → adk_code_mode-2.0.1}/sandbox-wheel/src/adk_code_mode_sandbox/_http_server.py
RENAMED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
# SPDX-FileCopyrightText: 2025-present
|
|
1
|
+
# SPDX-FileCopyrightText: 2025-present Agenta <hello@buildagenta.com>
|
|
2
2
|
#
|
|
3
3
|
# SPDX-License-Identifier: Apache-2.0
|
|
4
4
|
"""HTTP/WebSocket server mode for the sandbox (one connection per turn).
|
|
@@ -258,7 +258,7 @@ async def _run_one_block(
|
|
|
258
258
|
_rpc_client.install(client)
|
|
259
259
|
pump_task = asyncio.create_task(_pump_ws_to_reader(ws, bridge_reader))
|
|
260
260
|
try:
|
|
261
|
-
stdout_text, stderr_text, exit_code = await loop.run_in_executor(
|
|
261
|
+
stdout_text, stderr_text, exit_code, background_work = await loop.run_in_executor(
|
|
262
262
|
None, run_block, run_frame.code, globs
|
|
263
263
|
)
|
|
264
264
|
finally:
|
|
@@ -269,7 +269,9 @@ async def _run_one_block(
|
|
|
269
269
|
pass
|
|
270
270
|
|
|
271
271
|
# d-f. DoneFrame, OutputFrame, then the updated workspace tar (binary).
|
|
272
|
-
await ws.send(
|
|
272
|
+
await ws.send(
|
|
273
|
+
encode(DoneFrame(exit_code=exit_code, background_work=background_work)).decode("utf-8")
|
|
274
|
+
)
|
|
273
275
|
await ws.send(
|
|
274
276
|
encode(OutputFrame(stdout=stdout_text, stderr=stderr_text, exit_code=exit_code)).decode(
|
|
275
277
|
"utf-8"
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
# SPDX-FileCopyrightText: 2025-present Agenta <hello@buildagenta.com>
|
|
2
|
+
#
|
|
3
|
+
# SPDX-License-Identifier: Apache-2.0
|
|
4
|
+
"""Stop the running code block when the host asks, keeping the sandbox's state.
|
|
5
|
+
|
|
6
|
+
The host sends an ``InterruptFrame`` when a block runs past its timeout. Raising
|
|
7
|
+
``CodeTimeout`` in the thread running the block ends it like any other exception,
|
|
8
|
+
so its output so far, the globals and the working directory all survive for the
|
|
9
|
+
turn's next block. Code stuck outside the interpreter (a C call, a long
|
|
10
|
+
``time.sleep``) only sees the exception once it returns, which is why the host
|
|
11
|
+
still falls back to restarting the sandbox after a grace period.
|
|
12
|
+
"""
|
|
13
|
+
|
|
14
|
+
from __future__ import annotations
|
|
15
|
+
|
|
16
|
+
import ctypes
|
|
17
|
+
import threading
|
|
18
|
+
from collections.abc import Iterator
|
|
19
|
+
from contextlib import contextmanager
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
class CodeTimeout(BaseException):
|
|
23
|
+
"""Raised in running code when the host stops it at its timeout.
|
|
24
|
+
|
|
25
|
+
A ``BaseException`` so the code's own ``except Exception`` can't swallow it.
|
|
26
|
+
"""
|
|
27
|
+
|
|
28
|
+
message = ""
|
|
29
|
+
|
|
30
|
+
def __init__(self, *args: object) -> None:
|
|
31
|
+
# The interpreter raises an asynchronous exception without arguments.
|
|
32
|
+
super().__init__(*(args or (type(self).message,)))
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
_lock = threading.Lock()
|
|
36
|
+
_running_thread: int | None = None
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
def _set_async_exc(thread_id: int, exc: type[BaseException] | None) -> None:
|
|
40
|
+
ctypes.pythonapi.PyThreadState_SetAsyncExc(
|
|
41
|
+
ctypes.c_ulong(thread_id), ctypes.py_object(exc) if exc else None
|
|
42
|
+
)
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
@contextmanager
|
|
46
|
+
def running() -> Iterator[None]:
|
|
47
|
+
"""Mark the current thread as the one running a code block."""
|
|
48
|
+
global _running_thread
|
|
49
|
+
with _lock:
|
|
50
|
+
_running_thread = threading.get_ident()
|
|
51
|
+
try:
|
|
52
|
+
yield
|
|
53
|
+
finally:
|
|
54
|
+
with _lock:
|
|
55
|
+
_running_thread = None
|
|
56
|
+
# A stop that arrived as the block finished must not fire in the
|
|
57
|
+
# sandbox's own code afterwards.
|
|
58
|
+
_set_async_exc(threading.get_ident(), None)
|
|
59
|
+
|
|
60
|
+
|
|
61
|
+
def interrupt(message: str) -> None:
|
|
62
|
+
"""Raise ``CodeTimeout`` with ``message`` in the running block, if there is one."""
|
|
63
|
+
with _lock:
|
|
64
|
+
if _running_thread is None:
|
|
65
|
+
return
|
|
66
|
+
CodeTimeout.message = message
|
|
67
|
+
_set_async_exc(_running_thread, CodeTimeout)
|