|
| 1 | +# Antigravity SDK Integration |
| 2 | + |
| 3 | +The ADK Antigravity integration provides `AntigravityAgent`, which runs a |
| 4 | +[Google Antigravity SDK](https://pypi.org/project/google-antigravity/) agent — |
| 5 | +described by an `AgentConfig` — as a native ADK `BaseAgent`. Each turn is |
| 6 | +delegated to the Antigravity runner, and its trajectory steps (model text, tool |
| 7 | +calls, and tool responses) are streamed back as standard ADK events recorded in |
| 8 | +the session. |
| 9 | + |
| 10 | +## Prerequisites |
| 11 | + |
| 12 | +Install the ADK with Antigravity support: |
| 13 | + |
| 14 | +```bash |
| 15 | +pip install "google-adk[antigravity]" |
| 16 | +``` |
| 17 | + |
| 18 | +Set a Gemini API key (used by the SDK agent): |
| 19 | + |
| 20 | +```bash |
| 21 | +export GEMINI_API_KEY="your-api-key" |
| 22 | +``` |
| 23 | + |
| 24 | +Set `save_dir` on the config — it is the folder where conversation trajectories |
| 25 | +are persisted so sessions resume across turns (see |
| 26 | +[Session Resumption](#session-resumption)). |
| 27 | + |
| 28 | +## Limitations |
| 29 | + |
| 30 | +The Antigravity SDK currently only supports its **local mode** (an in-process |
| 31 | +Go harness that owns its own session lifecycle). Because of this, an |
| 32 | +`AntigravityAgent` must be used as a **standalone root agent**: |
| 33 | + |
| 34 | +- It cannot be given `sub_agents`. |
| 35 | +- It cannot be nested under a parent agent. |
| 36 | + |
| 37 | +Both are rejected at construction time. This restriction is temporary and will |
| 38 | +be lifted once the SDK supports remote connection modes. |
| 39 | + |
| 40 | +## Usage |
| 41 | + |
| 42 | +```python |
| 43 | +from google.adk.labs.antigravity import AntigravityAgent |
| 44 | +from google.antigravity import LocalAgentConfig |
| 45 | +from google.antigravity.hooks import policy |
| 46 | + |
| 47 | +# 1. Configure the Antigravity SDK agent. ``save_dir`` is the folder where |
| 48 | +# conversation trajectories are persisted for resumption. |
| 49 | +sdk_config = LocalAgentConfig( |
| 50 | + system_instructions="You are a helpful local environment assistant.", |
| 51 | + workspaces=["./sandbox"], |
| 52 | + policies=[*policy.workspace_only(["./sandbox"])], |
| 53 | + save_dir="./trajectories", |
| 54 | +) |
| 55 | + |
| 56 | +# 2. Wrap the config as a standalone ADK root agent. |
| 57 | +root_agent = AntigravityAgent( |
| 58 | + name="antigravity_assistant", |
| 59 | + description="Runs an Antigravity SDK agent inside ADK.", |
| 60 | + config=sdk_config, |
| 61 | +) |
| 62 | +``` |
| 63 | + |
| 64 | +For a runnable end-to-end example, see |
| 65 | +`contributing/samples/integrations/antigravity_agent/`. |
| 66 | + |
| 67 | +## How It Works |
| 68 | + |
| 69 | +`AntigravityAgent._run_async_impl` deep-copies `config` on every turn (the SDK |
| 70 | +`Agent`'s `AsyncExitStack` is single-use, so a fresh instance is needed for each |
| 71 | +of the stateless turns of a long-lived server), enters a fresh SDK `Agent`, sends |
| 72 | +the latest user prompt, and converts each streamed Step into ADK events. |
| 73 | + |
| 74 | +Step-to-event mapping covers model text responses, function calls, and function |
| 75 | +responses. In SSE streaming mode (`RunConfig(streaming_mode=StreamingMode.SSE)`), |
| 76 | +incremental thinking and text deltas are additionally emitted as `partial=True` |
| 77 | +events as they arrive, followed by the final aggregated response event — matching |
| 78 | +ADK's standard streaming behavior. In the default non-streaming mode, only final |
| 79 | +events are emitted. |
| 80 | + |
| 81 | +## Session Resumption |
| 82 | + |
| 83 | +The SDK's local harness persists conversation state to a `traj-*` file in |
| 84 | +`config.save_dir` and rehydrates it when a matching `conversation_id` is passed |
| 85 | +on a later turn. The wrapper keys this on the ADK session: |
| 86 | + |
| 87 | +- **Fresh turn**: no `conversation_id` is passed, so the harness writes a |
| 88 | + randomly-named `traj-<random>` file. After the turn, the wrapper renames it to |
| 89 | + `traj-<session_id>_<agent_name>` so later turns can find it. |
| 90 | +- **Resume turn**: when `traj-<session_id>_<agent_name>` already exists, the |
| 91 | + wrapper passes that `conversation_id` so the harness rehydrates the |
| 92 | + conversation. |
| 93 | + |
| 94 | +On resume, the harness replays the entire rehydrated trajectory through its step |
| 95 | +stream before producing new steps. To avoid re-emitting prior turns into the ADK |
| 96 | +session, the **resume step index** (the highest harness `step_index` already |
| 97 | +emitted) is persisted in a `traj-<...>.resume` file alongside the trajectory; |
| 98 | +steps at or below it are skipped. |
| 99 | + |
| 100 | +`config.save_dir` is required, and because the trajectory lives on disk there, |
| 101 | +conversations survive server restarts as long as the folder persists. |
0 commit comments