From 676ba17bb67b47dfa5e5121cc67ba30a9e74de8c Mon Sep 17 00:00:00 2001 From: Maksim Obukhov Date: Mon, 13 Jul 2026 15:25:09 +0200 Subject: [PATCH 1/4] docs: add Google ADK integration guide --- docs.json | 1 + docs/agents/google-adk.mdx | 262 ++++++++++++++++++++++++++++++++++++ images/icons/google-adk.svg | 17 +++ 3 files changed, 280 insertions(+) create mode 100644 docs/agents/google-adk.mdx create mode 100644 images/icons/google-adk.svg diff --git a/docs.json b/docs.json index 5122fde4..7866c97c 100644 --- a/docs.json +++ b/docs.json @@ -64,6 +64,7 @@ "docs/agents/crabbox", "docs/agents/devin", "docs/agents/grok", + "docs/agents/google-adk", "docs/agents/openai-agents-sdk", { "group": "OpenClaw", diff --git a/docs/agents/google-adk.mdx b/docs/agents/google-adk.mdx new file mode 100644 index 00000000..04d9975a --- /dev/null +++ b/docs/agents/google-adk.mdx @@ -0,0 +1,262 @@ +--- +title: "Google ADK" +description: "Give Google ADK agents a secure E2B sandbox to run code, commands, and files in." +icon: "/images/icons/google-adk.svg" +--- + +[Google ADK](https://google.github.io/adk-docs/) (Agent Development Kit) is +Google's framework for building agents, with Gemini as the default model. The +[`e2b-adk`](https://github.com/e2b-dev/e2b-adk-plugin) plugin adds a set of tools +your agent can call to generate and run code, execute shell commands, and manage +files — each backed by the [E2B Code Interpreter](/docs) running in an isolated +sandbox. The model's code executes in a real Python kernel instead of being +trusted blind. + +To use E2B with ADK: + +1. Create an `E2BPlugin`. +2. Hand `plugin.get_tools()` to your `Agent` and register the plugin on the `App`. +3. Run the agent — every tool call executes inside the sandbox, and the plugin + creates and tears the sandbox down for you. + +## Install the dependencies + +Install the plugin. It pulls in Google ADK and the E2B Code Interpreter SDK. + +```bash +pip install e2b-adk +``` + +You need an E2B API key for the sandbox and a Gemini key for the model. + +```bash +export E2B_API_KEY="..." +export GOOGLE_API_KEY="..." +``` + +## Data analysis agent + +A good fit for a sandbox is analysis the model shouldn't do in its head. Here the +agent is given a raw dataset and a question. Rather than eyeballing the numbers, +it writes the data to a file, runs real pandas against it, and reports figures it +actually computed — the sandbox is a calculator it can't fool. + +### Create the plugin and agent + +The plugin owns the sandbox. Pass its tools to the `Agent` and register it on the +`App`; the instruction is what makes the agent *run* code rather than guess. + +```python +from google.adk.agents import Agent +from google.adk.apps import App + +from e2b_adk import E2BPlugin + +INSTRUCTION = """You are a data analyst. You never guess numbers — you compute +them. Save any data you are given to a file with write_file, analyse it by +running real pandas with run_code, fix and re-run if the code errors, and report +the figures you computed. Never report a number you have not verified by running +code.""" + +plugin = E2BPlugin() +agent = Agent( + model="gemini-2.5-flash", + name="data_analyst", + instruction=INSTRUCTION, + tools=plugin.get_tools(), +) +app = App(name="data_analysis", root_agent=agent, plugins=[plugin]) +``` + +### Run the analysis + +Run the agent inside an `InMemoryRunner`. The sandbox is created lazily on the +first tool call, kept alive while the agent works, and killed when the +`async with` block exits — you never manage it yourself. + +```python +from google.adk.runners import InMemoryRunner + +DATASET = """month,region,marketing_spend,revenue +2024-01,North,12000,48000 +2024-02,North,15000,61000 +2024-03,North,9000,37000 +2024-04,North,18000,72000 +2024-01,South,8000,26000 +2024-02,South,11000,30000 +2024-03,South,14000,33000 +2024-04,South,17000,38000""" + +async with InMemoryRunner(app=app) as runner: + # run_debug prints the conversation as it runs. + await runner.run_debug( + f"Here is marketing spend and revenue as CSV:\n\n{DATASET}\n\n" + "Save it to sales.csv, then tell me which region converts spend into " + "revenue more efficiently and which month performed best." + ) +``` + +The agent writes `sales.csv` with `write_file`, then uses `run_code` to load it +with pandas, compute revenue-per-dollar and per-month totals, and answer in +prose — every number backed by an execution in the sandbox: + +```text +data_analyst > North converts marketing spend into revenue more efficiently — +about $4.0 of revenue per $1 of spend versus roughly $2.5 for South. The best +single month was 2024-04 in North: $72,000 revenue from $18,000 spend. +``` + +Pass `verbose=True` to `run_debug` to also print each tool call and its result +as the agent works. + +### Full example + +```python expandable +import asyncio + +from google.adk.agents import Agent +from google.adk.apps import App +from google.adk.runners import InMemoryRunner + +from e2b_adk import E2BPlugin + +INSTRUCTION = """You are a data analyst. You never guess numbers — you compute +them. Save any data you are given to a file with write_file, analyse it by +running real pandas with run_code, fix and re-run if the code errors, and report +the figures you computed. Never report a number you have not verified by running +code.""" + +DATASET = """month,region,marketing_spend,revenue +2024-01,North,12000,48000 +2024-02,North,15000,61000 +2024-03,North,9000,37000 +2024-04,North,18000,72000 +2024-01,South,8000,26000 +2024-02,South,11000,30000 +2024-03,South,14000,33000 +2024-04,South,17000,38000""" + + +async def main() -> None: + plugin = E2BPlugin(metadata={"example": "data-analysis"}) + agent = Agent( + model="gemini-2.5-flash", + name="data_analyst", + instruction=INSTRUCTION, + tools=plugin.get_tools(), + ) + app = App(name="data_analysis", root_agent=agent, plugins=[plugin]) + + async with InMemoryRunner(app=app) as runner: + # run_debug prints the conversation as it runs. + await runner.run_debug( + f"Here is marketing spend and revenue as CSV:\n\n{DATASET}\n\n" + "Save it to sales.csv, then tell me which region converts spend " + "into revenue more efficiently and which month performed best." + ) + + +asyncio.run(main()) +``` + +## Code generation agent + +The same tools support a code generator that verifies its own work. The +instruction tells the agent to execute every snippet in the sandbox before +returning it, so what you get back has already run and passed its tests — no +untested code reaches the user. + +### Full example + +```python expandable +import asyncio + +from google.adk.agents import Agent +from google.adk.apps import App +from google.adk.runners import InMemoryRunner + +from e2b_adk import E2BPlugin + +INSTRUCTION = """You are a code generator that returns verified, working code. +For every request: (1) write the function, (2) write tests, (3) EXECUTE in the +sandbox with run_code, (4) if it fails, fix and re-run until tests pass, +(5) return ONLY the final function. Never return code you haven't executed.""" + + +async def main() -> None: + plugin = E2BPlugin(metadata={"example": "code-generator"}) + agent = Agent( + model="gemini-2.5-flash", + name="codegen", + instruction=INSTRUCTION, + tools=plugin.get_tools(), + ) + app = App(name="codegen", root_agent=agent, plugins=[plugin]) + + async with InMemoryRunner(app=app) as runner: + # run_debug prints the conversation as it runs. + await runner.run_debug( + "Write a Python function group_by(items, key) that groups a list " + "by a key function." + ) + + +asyncio.run(main()) +``` + +## Tools + +`plugin.get_tools()` returns six tools, all sharing the plugin's single sandbox +so state persists across calls. Each returns a dict with a `success` flag and +reports failures in the result rather than raising, so a bad call never aborts +the agent run. `success` means the tool *ran*: code that raised or a command +that exited non-zero still returns `success: True` with the failure captured in +`error` / `exit_code` — only a call that could not run at all returns +`success: False`. + +| Tool | Does | +|------|------| +| `run_code` | Run code in a stateful kernel (variables persist across calls) | +| `run_command` | Run a shell command | +| `write_file` / `read_file` | Write and read files in the sandbox | +| `list_files` | List a directory | +| `start_background_command` | Start a long-running process, with an optional preview URL for a port | + +## Configuration + +`E2BPlugin` accepts keyword-only options, all optional. Anything you don't set +falls back to the E2B SDK's own default — the plugin overrides none of them. + +```python +plugin = E2BPlugin( + api_key=None, # defaults to the E2B_API_KEY env var + template=None, # E2B sandbox template + metadata=None, # dict[str, str] attached to the sandbox + envs=None, # environment variables inside the sandbox + timeout=None, # sandbox timeout in seconds (re-applied on every tool call) + lifecycle=None, # what happens on timeout — see below + # ...every other AsyncSandbox.create() option is forwarded verbatim +) +``` + +The plugin keeps the sandbox alive while the agent is working: every tool call +pushes the expiry window forward by `timeout` (E2B's default is 300s). An idle +gap longer than `timeout` still expires the sandbox under E2B's default +lifecycle — pass +`lifecycle={"on_timeout": {"action": "pause"}, "auto_resume": True}` to pause +and auto-resume across idle gaps instead. See the +[repository README](https://github.com/e2b-dev/e2b-adk-plugin#configuration) +for the full option list. + +## Reference examples + +Complete, runnable scripts live in the plugin repository. + + + + Compute real answers from a dataset with pandas in the sandbox + + + Return only code that has been executed and tested + + diff --git a/images/icons/google-adk.svg b/images/icons/google-adk.svg new file mode 100644 index 00000000..9670ee83 --- /dev/null +++ b/images/icons/google-adk.svg @@ -0,0 +1,17 @@ + + + + + + + + + + + + + + + + + From 25981bd53166760c4d9195965b25659430266e2b Mon Sep 17 00:00:00 2001 From: Maksim Obukhov Date: Mon, 13 Jul 2026 16:39:23 +0200 Subject: [PATCH 2/4] Update docs/agents/google-adk.mdx Co-authored-by: Tomas Varga --- docs/agents/google-adk.mdx | 1 - 1 file changed, 1 deletion(-) diff --git a/docs/agents/google-adk.mdx b/docs/agents/google-adk.mdx index 04d9975a..20eabaff 100644 --- a/docs/agents/google-adk.mdx +++ b/docs/agents/google-adk.mdx @@ -166,7 +166,6 @@ instruction tells the agent to execute every snippet in the sandbox before returning it, so what you get back has already run and passed its tests — no untested code reaches the user. -### Full example ```python expandable import asyncio From c2f1e121b52219bd50a78c6da4fb194544a730ea Mon Sep 17 00:00:00 2001 From: Maksim Obukhov Date: Mon, 13 Jul 2026 16:39:31 +0200 Subject: [PATCH 3/4] Update docs/agents/google-adk.mdx Co-authored-by: Tomas Varga --- docs/agents/google-adk.mdx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/agents/google-adk.mdx b/docs/agents/google-adk.mdx index 20eabaff..15749a51 100644 --- a/docs/agents/google-adk.mdx +++ b/docs/agents/google-adk.mdx @@ -34,7 +34,7 @@ export E2B_API_KEY="..." export GOOGLE_API_KEY="..." ``` -## Data analysis agent +## Example: Data analysis agent A good fit for a sandbox is analysis the model shouldn't do in its head. Here the agent is given a raw dataset and a question. Rather than eyeballing the numbers, From d09b933c995140d971c12a94805375e009e0dfbf Mon Sep 17 00:00:00 2001 From: Maksim Obukhov Date: Mon, 13 Jul 2026 16:39:43 +0200 Subject: [PATCH 4/4] Update docs/agents/google-adk.mdx Co-authored-by: Tomas Varga --- docs/agents/google-adk.mdx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/agents/google-adk.mdx b/docs/agents/google-adk.mdx index 15749a51..dfc35fcb 100644 --- a/docs/agents/google-adk.mdx +++ b/docs/agents/google-adk.mdx @@ -159,7 +159,7 @@ async def main() -> None: asyncio.run(main()) ``` -## Code generation agent +## Example: Code generation agent The same tools support a code generator that verifies its own work. The instruction tells the agent to execute every snippet in the sandbox before