UnsafeLocalCodeExecutor ran each program as a multiprocessing spawn child,
which had to import this package before it could run a single line, costing
about 2.3 seconds per execution. It now runs the program in a plain child
interpreter, the shape ContainerCodeExecutor already uses, which brings a
trivial program down to about 35 milliseconds. The result now comes from the
child's exit status and pipes rather than a queue the child has to write to,
so a program that dies without reporting anything no longer leaves the agent
waiting forever, and the traceback the model is shown no longer opens with a
frame from inside this package.
One behavior change follows from taking the result from the exit status: a
program calling sys.exit(0) is now reported as having succeeded. It was
previously reported as a failure, because the spawn child raised SystemExit
before it could write to the result queue.
Co-authored-by: George Weale <gweale@google.com>
PiperOrigin-RevId: 967496975
Gemini 1.x is fully deprecated, so sorting Gemini model ids into "1.x"
and "or 2.0+" buckets no longer buys anything. Non-Gemini ids are unaffected: they still raise error.
PiperOrigin-RevId: 960655458
Not annotations-only. This is one component's slice of a repo-wide typing
cleanup, and the wider change was found to contain behavior changes that have
not all been individually triaged, so please review it as a functional change.
Co-authored-by: George Weale <gweale@google.com>
PiperOrigin-RevId: 958458433
Pre-emptive: every CI job is ubuntu-latest, so none of these tests fail today.
No assertion is weakened - each replacement is equivalent or stricter on Linux.
Co-authored-by: George Weale <gweale@google.com>
PiperOrigin-RevId: 954835278
Merge https://github.com/google/adk-python/pull/6074
## Summary
`ContainerCodeExecutor` runs model-generated code, which can be influenced by untrusted input (e.g. via prompt injection). It starts the container with default Docker networking and no capability restrictions, so the executed code can reach the cloud metadata endpoint (`169.254.169.254`) — which yields the host service-account token — reach internal services, or escalate privileges.
This is inconsistent with the isolation posture of every other ADK code executor:
- `GkeCodeExecutor` runs under gVisor with `cap_drop: ["ALL"]`, non-root, read-only root filesystem, and a strict security context.
- `BuiltInCodeExecutor` / `VertexAiCodeExecutor` / `AgentEngineSandboxCodeExecutor` run in managed server-side sandboxes.
- `UnsafeLocalCodeExecutor` is explicitly documented as unsafe.
`ContainerCodeExecutor` was the only executor running code with full network access and no isolation flags or warning.
## Change
- Start the container with networking disabled by default. This is exposed as a configurable `network_enabled` field — set it to `True` to re-enable networking when the executed code is trusted.
- Drop all Linux capabilities (`cap_drop=["ALL"]`) and forbid privilege escalation (`security_opt=["no-new-privileges"]`), matching `GkeCodeExecutor`.
- Document the security posture in the class docstring and point users to the sandboxed executors for untrusted code.
- Add unit tests covering the hardened defaults and the opt-in network path.
## Compatibility
Code that legitimately needs network access can opt back in with `ContainerCodeExecutor(..., network_enabled=True)`. Dropping capabilities and `no-new-privileges` do not affect normal Python code execution.
Co-authored-by: George Weale <gweale@google.com>
COPYBARA_INTEGRATE_REVIEW=https://github.com/google/adk-python/pull/6074 from adilburaksen:harden/container-code-executor-network f7eaec252d2369d710eb54ea6c51b2bc4e525e7a
PiperOrigin-RevId: 938260811
Merge https://github.com/google/adk-python/pull/5958
## Problem
`AgentEngineSandboxCodeExecutor` was building the input-file payload with
incorrect JSON field names:
| Code sent | API expects |
|------------|-------------|
| `contents` | `content` |
| `mimeType` | `mime_type` |
This caused all input files to be silently unreadable inside the sandbox,
producing errors such as:
```
pandas.errors.EmptyDataError: No columns to parse from file
```
Fixes#3690
## Changes
- `src/google/adk/code_executors/agent_engine_sandbox_code_executor.py` — rename the two dict keys in the `input_data['files']` list comprehension.
- `tests/unittests/code_executors/test_agent_engine_sandbox_code_executor.py` — add regression test `test_execute_code_sends_correct_field_names_for_input_files` that verifies the correct keys are sent to the API.
## Testing plan
- [x] New regression test added that asserts `content` and `mime_type` are used (was failing before the fix, passes after).
- [x] All existing tests in the file still pass.
### pytest output
```
uv run --extra test python -m pytest tests/unittests/code_executors/test_agent_engine_sandbox_code_executor.py -v
======================== 11 passed, 5 warnings in 2.04s ========================
```
### pre-commit
```
pre-commit run --files src/google/adk/code_executors/agent_engine_sandbox_code_executor.py \
tests/unittests/code_executors/test_agent_engine_sandbox_code_executor.py
isort....................................................................Passed
pyink....................................................................Passed
addlicense...............................................................Passed
```
Co-authored-by: Kathy Wu <wukathy@google.com>
COPYBARA_INTEGRATE_REVIEW=https://github.com/google/adk-python/pull/5958 from jordanchendev:fix/3690-sandbox-input-file-field-names eefe91165fb5ea156b6e473adb329ce12d13616f
PiperOrigin-RevId: 933868136
Merge https://github.com/google/adk-python/pull/6118
## Summary
- Replace regular expression-based code block extraction with a simple and safe string-find based search. This avoids exponential backtracking (ReDoS) when processing long or repeating inputs with missing trailing delimiters.
- Add unit tests to verify standard behavior and test against ReDoS vulnerability.
Co-authored-by: Kathy Wu <wukathy@google.com>
PiperOrigin-RevId: 933834549
Merge https://github.com/google/adk-python/pull/5505Fixes#5500
### Root Cause
`AgentEngineSandboxCodeExecutor` builds the input file payload with key `'contents'` (plural), but the Vertex AI SDK (`vertexai/_genai/sandboxes.py`) reads `'content'` (singular). This causes `file.get("content", b"")` to always return the default empty bytes, so uploaded input files silently arrive as zero bytes in the sandbox.
### Fix
One-character change: `'contents'` → `'content'` at line 177.
Co-authored-by: George Weale <gweale@google.com>
PiperOrigin-RevId: 930814004
This fixes an issue where AgentEngineSandboxCodeExecutor catches the wrong exception class when attempting to recover from externally-deleted sandboxes.
Fixes#5480
Co-authored-by: Amaad Martin <amaadmartin@google.com>
PiperOrigin-RevId: 908965545
`gemini-1.*` and `gemini-2.0*` models are respectively deprecated and scheduled for shutdown on June 1, 2026. `gemini-2.5*` models are their successors.
No regressions in unit tests:
```
========================================================================================== 5583 passed, 2237 warnings in 84.91s (0:01:24) ===========================================================================================
```
PiperOrigin-RevId: 907663315
The AgentEngineSandboxCodeExecutor now has three initialization modes:
1. Create both an Agent Engine and sandbox if neither resource name is provided.
2. Creating a new sandbox within a provided agent_engine_resource_name.
3. Using a provided sandbox_resource_name.
PiperOrigin-RevId: 884088248
1. For prototyping and testing purposes, sandbox name can be provided, and it will be used for all requests across the lifecycle of an agent
2. If no sandbox name is provided, agent engine name will be provided, and we will automatically create one sandbox per session, and the sandbox has TTL set for a year.
If the sandbox stored in the session hits the TTL, it will not be in "STATE_RUNNING" so a new sandbox will be created.
Co-authored-by: Lusha Wang <lusha@google.com>
PiperOrigin-RevId: 876450610
1. For prototyping and testing purposes, sandbox name can be provided, and it will be used for all requests across the lifecycle of an agent
2. If no sandbox name is provided, agent engine name will be provided, and we will automatically create one sandbox per session, and the sandbox has TTL set for a year.
If the sandbox stored in the session hits the TTL, it will not be in "STATE_RUNNING" so a new sandbox will be created.
PiperOrigin-RevId: 874705260
1. For prototyping and testing purposes, sandbox name can be provided, and it will be used for all requests across the lifecycle of an agent
2. If no sandbox name is provided, agent engine name will be provided, and we will automatically create one sandbox per session, and the sandbox has TTL set for a year.
If the sandbox stored in the session hits the TTL, it will not be in "STATE_RUNNING" so a new sandbox will be created.
Co-authored-by: Lusha Wang <lusha@google.com>
PiperOrigin-RevId: 874415933
LlmResponse/Event now keep both provider reasoning output and the raw vendor payload so callbacks and loggers can inspect hidden “thoughts” or trace bugs without rewriting adapters.
LiteLLM’s adapter and streaming loop emit reasoning chunks alongside text and aggregate them into final events -> all responses now carry a JSON-safe copy of the source payload for debug. UnsafeLocalCodeExecutor uses the documented exec(code, globals, globals) form, letting helper functions defined inside snippets call each other.
Close#1749
Co-authored-by: George Weale <gweale@google.com>
PiperOrigin-RevId: 834956847
This is about 35% decrease. This change refactors several ADK modules to import `vertexai` and its submodules only when they are first used, rather than at the top of the file. This improves module load times by avoiding unnecessary imports of large dependencies. Imports are also placed within `if TYPE_CHECKING:` blocks where appropriate.
Co-authored-by: Liang Wu <wuliang@google.com>
PiperOrigin-RevId: 829017293
Merge https://github.com/google/adk-python/pull/1629
close https://github.com/google/adk-python/issues/2170
### Summary
This PR introduces `GkeCodeExecutor`, a new code executor that provides a secure and scalable method for running LLM-generated code by leveraging GKE Sandbox. It serves as a robust alternative to local or standard containerized executors by leveraging the **GKE Sandbox** environment, which uses gVisor for workload isolation.
For each code execution request, it dynamically creates an ephemeral Kubernetes Job with a hardened Pod configuration, offering significant security benefits and ensuring that each code execution runs in a clean, isolated environment.
### Key Features of GkeCodeExecutor
* **Dynamic Job Creation**: Uses the Kubernetes `batch/v1` API to create a new Job for each code snippet.
* **Secure Code Mounting**: Injects code into the Pod via a temporary `ConfigMap`, which is mounted to a read-only file.
* **gVisor Sandboxing**: Enforces execution within a `gvisor` runtime for kernel-level isolation.
* **Hardened Security Context**: Pods run as non-root with all Linux capabilities dropped and a read-only root filesystem.
* **Resource Management**: Applies configurable CPU and memory limits to prevent abuse.
* **Automatic Cleanup**: Uses the `ttl_seconds_after_finished` feature on Jobs for robust, automatic garbage collection of completed Pods and Jobs.
* **Node Scheduling**: The executor uses Kubernetes `tolerations` in its Pod specification. This allows the k8s scheduler to place the execution Pod onto a **_pre-configured_** gVisor-enabled node.
* **Module Integration**: The `GkeCodeExecutor` is registered in the `code_executors/__init__.py`, making it available for use by agents. The `ImportError` handling is configured to check for the required `kubernetes` SDK.
### Execution Flow:
1. Agent invokes `GkeCodeExecutor` with the LLM-generated code.
2. The `GkeCodeExecutor` will `execute_code` – creates a temporary `ConfigMap`, and then create a k8s `Job` to run it.
3. This Job runs a standard `python:3.11-slim` container. The image is pulled once to the node and cached. The Job will mount the ConfigMap as `/app/code.py`
4. The GkeCodeExecutor will monitor the Job to completion, fetch `stdout/stderr` logs from the container, return `CodeExecutionResult` to the LlmAgent, and ensure all temp resources are deleted.
5. The calling agent formats the result and provides a final response to the user. If the result contains error, it will retry up to `error_retry_attempts` times.
PiperOrigin-RevId: 804511467
--
8baeb0b569eaedc638b20e46894178a3b878dbd6 by Amulya Bhatia <amulya.bhatia@t-online.de>:
test: unit tests for built_in_code_executor and unsafe_code_executor
--
cfac73b9271557ead96eb5fb419e05d88c6e8cd4 by Amulya Bhatia <amulya.bhatia@t-online.de>:
test: unit tests for built_in_code_executor and unsafe_code_executor
COPYBARA_INTEGRATE_REVIEW=https://github.com/google/adk-python/pull/971 from iamulya:code-executor-tests 55290e27b5e58ef3835905aec88639e936318d01
PiperOrigin-RevId: 764976316
Copybara import of the project:
--
9e51865a6dd4de4d20088e8a7ac9f3a75501aa6b by Amulya Bhatia <amulya.bhatia@t-online.de>:
test: unit tests for code_executor_context.py
COPYBARA_INTEGRATE_REVIEW=https://github.com/google/adk-python/pull/780 from iamulya:test-code-executor-context 907b1712e43b8ce90cd8786780bef863adfcc167
PiperOrigin-RevId: 761294975