Three platforms, one seam
ADK 2.0, Claude Managed Agents and Gemini's Antigravity agent compared against your constraints, and how each would plug into the generation engine seam. About 15 minutes.
Warm-up: answer from memory before opening
(1) State the three parts of the climbing test. (2) Where does a Thread's state live when an agent writes its messages, and why?
(1) The model must decide what to fetch mid-task; the job can wait; the gain is worth the extra tokens. (2) In Postgres, with one agent session per job (session-per-job), because generators never write memory and there should be one source of truth. Lesson 1.
The three, side by side
Facts as of September 2026. All three are moving fast, so check the linked docs again before you build.
| Google ADK 2.0 (TypeScript) | Claude Managed Agents | Gemini Managed Agents (Antigravity) | |
|---|---|---|---|
| What it is | A framework: you host the loop and the graph[1] | A hosted API: versioned Agent → Session per run → event stream, with a container per session[2] | A hosted API: interactions.create with agent: "antigravity-preview-05-2026", running in a Linux sandbox[3] |
| Status | GA (TS 2.0.0, 2026-08-21) | Beta | Public preview |
| Runs on | Node, deployed to Cloud Run (not Deno or Supabase Edge)[4] | Anthropic's infrastructure | Google's infrastructure |
| Models | Gemini built in. OpenRouter needs a custom BaseLlm (your research) | Claude only, through the Anthropic API | Gemini 3.5–3.8 Flash only, through the Gemini API[5] |
| Fixed-shape output | Typed node outputSchema (zod)[6] | Validate the final message yourself | "Does not support structured outputs", so you validate the text |
| Your own tools | Ordinary functions or nodes, in your own process | The agent emits agent.custom_tool_use, the session goes idle, and you send back user.custom_tool_result | The interaction returns requires_action, and you call create again with a function_result |
| Long runs | Your Cloud Run request | Stream events, or state-change webhooks[7] | background: true, then poll interactions.get |
| State | In-memory, Postgres (DatabaseSessionService) or Agent Platform sessions; Memory Bank service (in the 2.1.0 package, although the docs lag)[8] | Sessions persist, and memory stores persist across sessions | previous_interaction_id; environments kept for 7 days |
| Secrets | Your own environment | Vault credentials, substituted when requests leave the sandbox | Network allowlist with header transform |
| Cost beyond tokens | Cloud Run, probably within the free tier | Runtime at $0.08 per active hour; a hard dollar budget per session is available | Sandbox compute is not billed during the preview |
The conflict to decide. Your map says all LLM calls go to OpenRouter directly. Of the three, only ADK can keep that rule. Both managed services run their own vendor's models on their own API. Using either one for the bot means relaxing that preference, at least for the jobs you move to it. That decision is yours to make, and it belongs in the map.
How each plugs into the seam
The worker is a Supabase Edge Function with a 150 s wall clock (ticket 01). An agent run can take longer than that. So an agent-ready seam needs two outcomes: done now or pending, collect later.
generate(kind, jobId, bundle) → { done, result } | { pending, runRef }
collect(runRef) → { done, result } | { pending } | { failed }
// The bot always validates `result` against the fixed shape, then records it.
- Plain calls (MVP): always return done. Nothing changes for the bot.
- ADK graph on Cloud Run:
load → select (agent node with read tools) → validate → write → validate. The worker POSTs the job and gets pending. Cloud Run posts the result back to a Supabase function, which validates, records and sends it. The session lives only as long as the job. - Claude Managed Agents: create a session per job, and put the context bundle in as mounted files so no custom-tool round trips are needed. Give it read-only GitHub access through a vault credential. Collect the result when a webhook says the session went idle.
- Antigravity:
background: truereturns an interaction id as therunRef. The existing pg_cron tick pollsinteractions.get. Credentials go through the network allowlist.
Why mount the bundle instead of exposing tools? Each custom-tool call pauses a managed session until your code answers, so every answer would be another Edge Function invocation. A bundle given up front plus read-only GitHub access avoids those round trips. Keep custom tools for the ADK graph, where tools run in the same process.
Where each one fits best in this project
| Use | Best fit | Why |
|---|---|---|
| Classify, Exercise, Answer feedback, Topic recap | Plain calls | All inputs are known and the latency targets are tight |
| Project-grounded Lesson; Follow-ups that need code | ADK 2.0 graph with one agent node | Keeps OpenRouter, typed outputs and fixed order, and adds exploration only where it pays |
| Project digest refresh (clone, read, list Candidate improvements) | Managed agent (either) | Sandbox with git and files, slow is fine, runs outside the Thread; Claude Managed Agents can also run it on a schedule |
| A trial against the ADK graph | Managed agent, session-per-job | Cheap to try behind the same seam, and the result shows whether a hosted harness writes better Lessons |
Practice
1. Which platform can keep the "all LLM calls go to OpenRouter" rule?
2. Whose docs say the agent "does not support structured outputs"?
3. The worker has a 150 s wall clock and a managed run may take minutes. What should the seam do?
4. A Claude Managed Agents run calls your custom tool readLessonLines. What happens?
5. Which is the best first job for a managed agent in this project?
Take back to your tickets. (1) Ticket 13: add a pending → collect result to the seam, and list which generations may go agentic (Lesson, code-aware Follow-up). (2) Map: decide whether the OpenRouter-only rule holds after the MVP, because that decides whether managed agents are allowed in the bot at all. (3) A possible new ticket: a managed-agent Project digest refresh.
node() and edges syntax.Questions, or a platform fact that looks out of date? Ask me, your teacher. To test these ideas with practitioners, try the Google AI Developers Forum or adk-js Discussions.