Skip to content

Commit 471e167

Browse files
committed
feat: add antigravity tools and external agent
Adds first-party support for Google's Gemini Agents API ("Antigravity") in Agno, in two integration shapes mapped to the API's two natural use cases: - AntigravityAgent (agno.agents.antigravity) — a BaseExternalAgent adapter so an Antigravity-backed agent can be served through AgentOS with native sessions, streaming, and UI. Mirrors the existing ClaudeAgent / LangGraphAgent / DSPyAgent pattern. - AntigravityTools (agno.tools.antigravity) — a Toolkit so a regular Agno agent (any model) can delegate a sub-task to a managed Antigravity sandbox as a single tool call. Mirrors the DaytonaTools / E2BTools pattern. Mirrored from agno-agi/agno-pvt#1 (squashed).
1 parent 3a0aaab commit 471e167

25 files changed

Lines changed: 2819 additions & 3 deletions

cookbook/91_tools/TEST_LOG.md

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,3 +29,43 @@
2929
**Result:** Ran `pytest libs/agno/tests/unit/tools/test_gitlab.py -q` and all 18 tests passed, including async methods, internal async client handling coverage, and `enable_*` tool-toggle coverage (with `enable_get_projects` as the canonical project-read toggle). Also ran `ruff check` for changed files and both validation scripts (`libs/agno/scripts/validate.bat`, `libs/agno_infra/scripts/validate.bat`) with no issues. Live toolkit checks passed for `get_project`, `list_issues`, and `list_merge_requests` against `SalimELMARDI/agno-gitlab-tools-test`. Negative live check also passed: `get_project('wrong-group/wrong-project')` returned expected JSON error (`404 Project Not Found`). The cookbook agent runtime file was not executed because it requires model credentials.
3030

3131
---
32+
33+
### antigravity_tools.py
34+
35+
**Status:** PENDING
36+
37+
**Description:** Gemini-driven Agno agent delegates a research sub-task to an Antigravity sandbox via `AntigravityTools.run_antigravity_task`. The toolkit POSTs to the Gemini Agents API `/interactions` endpoint, caches `environment_id` in `agent.session_state` so the sandbox persists across calls in non-streaming mode, and returns the final text response.
38+
39+
**Result:** Unit tests pass covering session-state caching, env-id reuse on subsequent calls, HTTP error surfacing, custom-agent creation, and the delete endpoint. Live cookbook run with a partner Gemini API key remains the gating verification before merge.
40+
41+
---
42+
43+
### antigravity_agents_crud_tools.py
44+
45+
**Status:** PENDING
46+
47+
**Description:** Gemini-driven Agno agent drives the full Agents API lifecycle via `AntigravityTools``create_custom_antigravity_agent`, `run_custom_antigravity_agent`, then `delete_antigravity_agent`. Toolkit also exposes `get_custom_antigravity_agent`, `update_custom_antigravity_agent`, `list_antigravity_agents`, and `list_antigravity_agent_versions` for full CRUD coverage of `/v1beta/agents`.
48+
49+
**Result:** Unit tests pass. Live cookbook run with a partner Gemini API key remains the gating verification.
50+
51+
---
52+
53+
### antigravity_directory_tools.py
54+
55+
**Status:** PENDING
56+
57+
**Description:** `AntigravityTools(agent_directory=...)` parses a local agent folder (`agent.yaml` + `AGENTS.md` + `workspace/` + `skills/`), registers it via POST /agents (idempotent), and routes subsequent `run_antigravity_task` calls at the named agent. Re-uses the `example_agent/` folder from `cookbook/frameworks/antigravity/`.
58+
59+
**Result:** Unit tests pass for the new constructor path (register=False parse-only, register=True POSTs, 409 = success, agent= / default_sources= conflict validation, required-key validation, run_antigravity_task routes at the named agent post-load). Live cookbook awaiting partner key.
60+
61+
---
62+
63+
### antigravity_snapshot_tools.py
64+
65+
**Status:** PENDING
66+
67+
**Description:** Gemini-driven Agno agent runs `run_antigravity_task` to write a few files in the sandbox, then calls `download_antigravity_environment_snapshot` with `environment_id="current"` to resolve the env id from `agent.session_state` and save the resulting tar to disk. Demonstrates the full sandbox-write → archive flow through tool calls.
68+
69+
**Result:** Unit tests pass covering snapshot URL construction, byte-for-byte write to disk, "current" resolution from session_state, and the no-cached-env error path. Live cookbook awaiting partner key.
70+
71+
---
Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
"""
2+
Manage Antigravity custom agents via the Agents API toolkit.
3+
4+
`AntigravityTools` exposes the full CRUD surface of `/v1beta/agents` as tools
5+
that an Agno agent can call:
6+
7+
- create_custom_antigravity_agent: POST /agents
8+
- get_custom_antigravity_agent: GET /agents/{name}
9+
- list_antigravity_agents: GET /agents
10+
- list_antigravity_agent_versions: GET /agents/{name}/versions
11+
- update_custom_antigravity_agent: PATCH /agents/{name}
12+
- delete_antigravity_agent: DELETE /agents/{name}
13+
- run_custom_antigravity_agent: POST /interactions with `agent=<name>`
14+
15+
Plus `run_antigravity_task` for one-off invocations of the base antigravity agent.
16+
17+
This cookbook shows a Gemini-driven Agno agent driving the full lifecycle:
18+
create a haiku-bot definition, invoke it, then clean up.
19+
20+
Requirements:
21+
export GEMINI_API_KEY=...
22+
uv pip install agno google-genai
23+
24+
Usage:
25+
.venvs/demo/bin/python cookbook/91_tools/antigravity_agents_crud_tools.py
26+
"""
27+
28+
from agno.agent import Agent
29+
from agno.models.google import Gemini
30+
from agno.tools.antigravity import AntigravityTools
31+
32+
agent = Agent(
33+
name="Antigravity Admin",
34+
model=Gemini(id="gemini-2.5-pro"),
35+
tools=[AntigravityTools()],
36+
markdown=True,
37+
instructions=[
38+
"You manage custom Antigravity agents via the Agents API tools.",
39+
"When asked to create an agent, use create_custom_antigravity_agent with the requested name and instructions.",
40+
"When asked to invoke a named agent, use run_custom_antigravity_agent.",
41+
"When asked to clean up, use delete_antigravity_agent.",
42+
"Surface the agent ids / responses to the user clearly.",
43+
],
44+
)
45+
46+
if __name__ == "__main__":
47+
agent.print_response(
48+
"Create a custom Antigravity agent called 'demo-haiku-bot' whose only job is to "
49+
"write a single haiku in response to any prompt. Then invoke it with the prompt "
50+
"'autumn leaves'. Finally, delete the agent."
51+
)
Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
"""
2+
Use a local Antigravity agent directory through AntigravityTools.
3+
4+
Pass `agent_directory=` to the toolkit constructor and it will:
5+
1. Parse `agent.yaml`, `AGENTS.md`, `workspace/`, and `skills/`.
6+
2. Register the agent definition via POST /v1beta/agents (idempotent).
7+
3. Route all subsequent `run_antigravity_task` calls at the named custom agent.
8+
9+
This is the "Yash bucket" of the integration: a regular Agno agent (any model)
10+
can now delegate sub-tasks to a folder-defined Antigravity agent without you
11+
having to wire up `/agents` calls yourself.
12+
13+
Re-uses the example folder from
14+
`cookbook/frameworks/antigravity/example_agent/`.
15+
16+
Requirements:
17+
export GEMINI_API_KEY=...
18+
uv pip install agno google-genai pyyaml
19+
20+
Usage:
21+
.venvs/demo/bin/python cookbook/91_tools/antigravity_directory_tools.py
22+
"""
23+
24+
from pathlib import Path
25+
26+
from agno.agent import Agent
27+
from agno.models.google import Gemini
28+
from agno.tools.antigravity import AntigravityTools
29+
30+
AGENT_DIR = Path(__file__).parent.parent.parent / "frameworks" / "antigravity" / "example_agent"
31+
32+
agent = Agent(
33+
name="Haiku Requester",
34+
model=Gemini(id="gemini-2.5-pro"),
35+
# Register the folder once at construction; subsequent run_antigravity_task
36+
# calls invoke the named agent (`agno-haiku-bot-from-dir`).
37+
tools=[AntigravityTools(agent_directory=str(AGENT_DIR))],
38+
markdown=True,
39+
instructions=[
40+
"When the user asks for a haiku, delegate to the Antigravity sandbox via run_antigravity_task.",
41+
"Pass the topic through as-is; the sandbox agent enforces house style.",
42+
],
43+
)
44+
45+
if __name__ == "__main__":
46+
agent.print_response("Write a haiku about autumn maples.")
Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
"""
2+
Download a Antigravity sandbox snapshot through AntigravityTools.
3+
4+
`download_antigravity_environment_snapshot` hits the Files API endpoint:
5+
GET /v1beta/files/environment-{env_id}:download?alt=media
6+
7+
Pass `environment_id="current"` to resolve the env id from the calling Agno
8+
agent's `session_state` — it's set there by a prior `run_antigravity_task` call
9+
within the same session.
10+
11+
Useful for letting an Agno agent introspect or archive what the Antigravity
12+
sandbox produced during a task.
13+
14+
Requirements:
15+
export GEMINI_API_KEY=...
16+
uv pip install agno google-genai
17+
18+
Usage:
19+
.venvs/demo/bin/python cookbook/91_tools/antigravity_snapshot_tools.py
20+
"""
21+
22+
import tarfile
23+
from pathlib import Path
24+
25+
from agno.agent import Agent
26+
from agno.models.google import Gemini
27+
from agno.tools.antigravity import AntigravityTools
28+
29+
OUT_PATH = Path("tmp/antigravity_snapshot_from_tools.tar")
30+
OUT_PATH.parent.mkdir(parents=True, exist_ok=True)
31+
32+
agent = Agent(
33+
name="Snapshot Demo",
34+
model=Gemini(id="gemini-2.5-pro"),
35+
tools=[AntigravityTools()],
36+
markdown=True,
37+
instructions=[
38+
"Step 1: Use run_antigravity_task to ask the sandbox to create a few files under /workspace/ "
39+
"(e.g. notes.txt with 'hello', summary.md with a brief intro).",
40+
f"Step 2: Use download_antigravity_environment_snapshot with environment_id='current' and "
41+
f"output_path='{OUT_PATH}' to save the snapshot tar.",
42+
"Step 3: Tell the user where the tar was saved.",
43+
],
44+
)
45+
46+
if __name__ == "__main__":
47+
agent.print_response(
48+
"Have the sandbox create a couple of files under /workspace, then archive the environment to disk."
49+
)
50+
51+
if OUT_PATH.exists():
52+
print(f"\nSnapshot saved: {OUT_PATH} ({OUT_PATH.stat().st_size} bytes)")
53+
with tarfile.open(OUT_PATH, "r") as tf:
54+
members = tf.getnames()
55+
print(f"Archive contains {len(members)} entries. First 10:")
56+
for name in members[:10]:
57+
print(f" {name}")
Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
"""
2+
Agent with Antigravity tools
3+
4+
This example shows how to use Agno's integration with Google's Gemini Agents API
5+
(Antigravity) as a tool. The Agno agent's brain (Gemini, here) decides when to
6+
delegate a sub-task to a managed Antigravity sandbox, which runs an autonomous
7+
loop with web search, code execution, and file I/O built in.
8+
9+
The sandbox persists across calls within the same Agno session, so subsequent
10+
calls can build on prior files and state.
11+
12+
1. Get a Gemini API key enrolled in the Agents API EAP.
13+
2. Set the API key as an environment variable:
14+
export GEMINI_API_KEY=<your_api_key>
15+
3. Install the dependencies:
16+
uv pip install agno google-genai
17+
"""
18+
19+
from agno.agent import Agent
20+
from agno.models.google import Gemini
21+
from agno.tools.antigravity import AntigravityTools
22+
23+
# ---------------------------------------------------------------------------
24+
# Create Agent
25+
# ---------------------------------------------------------------------------
26+
27+
agent = Agent(
28+
name="Research Assistant with Antigravity tools",
29+
model=Gemini(id="gemini-2.5-pro"),
30+
tools=[AntigravityTools()],
31+
markdown=True,
32+
instructions=[
33+
"You have access to a managed Antigravity sandbox with web search, code execution, and file I/O.",
34+
"When the user asks for something that benefits from those capabilities — multi-step research, "
35+
"analysing a repo, generating files, or running code you cannot run locally — delegate the work "
36+
"to the sandbox via the run_antigravity_task tool.",
37+
"Otherwise, answer directly without invoking the tool.",
38+
"The sandbox persists across calls in the same session, so follow-up tasks can build on prior state.",
39+
],
40+
)
41+
42+
# ---------------------------------------------------------------------------
43+
# Run Agent
44+
# ---------------------------------------------------------------------------
45+
if __name__ == "__main__":
46+
agent.print_response(
47+
"Use the Antigravity sandbox to find the latest stable Python release "
48+
"and summarize what changed in it."
49+
)
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
# Antigravity (Gemini Agents API)
2+
3+
Examples for integrating Google's Gemini Agents API ("Antigravity") with Agno.
4+
5+
Antigravity is a managed agent loop: a single REST call spins up a sandboxed
6+
Linux environment with web search, code execution, and file I/O built in,
7+
runs an autonomous loop to satisfy the request, and returns or streams
8+
events. Environments persist across turns via an `environment_id`.
9+
10+
Agno integrates Antigravity two ways. Pick based on who drives the loop:
11+
12+
| Integration | When to use | Example |
13+
|---|---|---|
14+
| `AntigravityAgent` (external agent) | You want Antigravity to **be** the agent — served through AgentOS, with Agno handling sessions, streaming, and the UI. | `antigravity_basic.py`, `antigravity_agentos.py` (this folder) |
15+
| `AntigravityTools` (toolkit) | You want a regular Agno agent (any model) to **delegate** a sub-task to a Antigravity sandbox as one tool call. | [`cookbook/91_tools/antigravity_tools.py`](../../91_tools/antigravity_tools.py) |
16+
17+
## Setup
18+
19+
```bash
20+
export GEMINI_API_KEY=...
21+
```
22+
23+
## Files
24+
25+
- `antigravity_basic.py` — minimal standalone run
26+
- `antigravity_session.py` — multi-turn session, environment reused across turns
27+
- `antigravity_sources.py` — pre-load files into the sandbox (inline / GCS / repo)
28+
- `antigravity_custom_agent.py` — register a named custom agent (Agents API) and invoke it
29+
- `antigravity_from_agent_directory.py` — load an agent from a local `agent.yaml` + `AGENTS.md` + `workspace/` + `skills/` folder (see `example_agent/`)
30+
- `antigravity_snapshot.py` — download an environment's filesystem as a tar archive
31+
- `antigravity_session_agentos.py` — same with SQLite-backed sessions
32+
33+
For the toolkit examples (Antigravity-as-a-tool), see:
34+
- [`cookbook/91_tools/antigravity_tools.py`](../../91_tools/antigravity_tools.py) — delegate a sub-task to a sandbox
35+
- [`cookbook/91_tools/antigravity_agents_crud_tools.py`](../../91_tools/antigravity_agents_crud_tools.py) — full Agents API CRUD (create / get / update / list / versions / delete / invoke)
36+
- [`cookbook/91_tools/antigravity_directory_tools.py`](../../91_tools/antigravity_directory_tools.py) — wire a local `agent.yaml` folder into the toolkit (parses, registers, routes future tool calls at the named agent)
37+
- [`cookbook/91_tools/antigravity_snapshot_tools.py`](../../91_tools/antigravity_snapshot_tools.py) — have an Agno agent run a sandbox task then download the resulting environment as a tar
38+
39+
Test results are tracked in `TEST_LOG.md`.
Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,85 @@
1+
# Antigravity cookbook test log
2+
3+
### antigravity_basic.py
4+
5+
**Status:** PENDING
6+
7+
**Description:** Smoke test — `AntigravityAgent.print_response("What is 2+2?", stream=True)`.
8+
9+
**Result:** Awaiting live-API verification with partner key.
10+
11+
---
12+
13+
### antigravity_session.py
14+
15+
**Status:** PENDING
16+
17+
**Description:** Two-turn session — turn 1 writes notes.txt in the sandbox, turn 2 reads it back; verifies environment_id is reused across turns.
18+
19+
**Result:** Awaiting live-API verification.
20+
21+
---
22+
23+
### antigravity_sources.py
24+
25+
**Status:** PENDING
26+
27+
**Description:** Provision a sandbox with an inline source file at /workspace/about.txt and ask the agent to read it.
28+
29+
**Result:** Awaiting live-API verification.
30+
31+
---
32+
33+
### antigravity_custom_agent.py
34+
35+
**Status:** PENDING
36+
37+
**Description:** POST /v1beta/agents to create a haiku-writing custom agent, then invoke it through AntigravityAgent.
38+
39+
**Result:** Awaiting live-API verification.
40+
41+
---
42+
43+
### antigravity_agentos.py
44+
45+
**Status:** PENDING
46+
47+
**Description:** Serve a AntigravityAgent through AgentOS; verify /agents list + streaming /runs.
48+
49+
**Result:** Awaiting live-API verification.
50+
51+
---
52+
53+
### antigravity_session_agentos.py
54+
55+
**Status:** PENDING
56+
57+
**Description:** Same as antigravity_agentos.py with SqliteDb-backed sessions; verify sessions persist across restarts.
58+
59+
**Result:** Awaiting live-API verification.
60+
61+
---
62+
63+
### antigravity_from_agent_directory.py
64+
65+
**Status:** PENDING
66+
67+
**Description:** Load a Antigravity agent from a local directory (`agent.yaml` + `AGENTS.md` + `workspace/` + `skills/`) via `AntigravityAgent.from_agent_directory()`. Auto-registers the named agent on first invocation. The `example_agent/` folder in this directory exercises all four layout elements.
68+
69+
**Result:** Unit tests pass for the directory parser (required-key validation, AGENTS.md precedence, workspace + skills targets, 75 KB size limit). Live cookbook run awaiting partner key.
70+
71+
---
72+
73+
### antigravity_snapshot.py
74+
75+
**Status:** PENDING
76+
77+
**Description:** Run a task that writes a file in the sandbox, then download the environment snapshot tar via `AntigravityAgent.download_environment_snapshot()`. Uses non-streaming because SSE doesn't expose `environment_id` (see open partner question).
78+
79+
**Result:** Unit tests pass for the snapshot toolkit method (env-id resolution from session_state, error surfacing). Live cookbook run awaiting partner key.
80+
81+
---
82+
83+
Note: the `AntigravityTools` toolkit example lives at `cookbook/91_tools/antigravity_tools.py` and is tracked in that folder's TEST_LOG.
84+
85+
---
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
"""
2+
Standalone usage of Google's Gemini Agents API (Antigravity) via Agno's
3+
.run() and .print_response() methods.
4+
5+
Requirements:
6+
export GEMINI_API_KEY=...
7+
8+
Usage:
9+
.venvs/demo/bin/python cookbook/frameworks/antigravity/antigravity_basic.py
10+
"""
11+
12+
from agno.agents.antigravity import AntigravityAgent
13+
14+
agent = AntigravityAgent(name="Antigravity")
15+
16+
agent.print_response(
17+
"What is 2 + 2? Explain your reasoning briefly.",
18+
stream=True,
19+
)

0 commit comments

Comments
 (0)