Get to know Cadenya
We’re developers who love to build. We set out to create a yes-code platform that makes building agents feel like the best parts of building software.
A Google ADK agent in Python needs three decisions before it ships: a session service, tool confirmation for the human-in-the-loop steps, and a place to deploy it. The Google ADK docs give you DatabaseSessionService or VertexAiSessionService for sessions, require_confirmation for approvals, and adk deploy agent_engine or adk deploy cloud_run for deployment.
So pick Agent Engine (Google’s docs call the service Agent Runtime) when you want Google to build the container and store the sessions. Pick Cloud Run when you want your own SQL session database. Pick the Temporal plugin when you already run Temporal. And if you’d rather host none of it, Cadenya is a hosted agent loop with conversation state, approvals and model choice built in. What it offers is at the end.
Every price and limit below comes from each vendor’s own pages, checked on October 13, 2026.
Google ADK Python on Agent Engine, Cloud Run, or Temporal
ADK itself is a Python library (google-adk 2.11.0, Apache 2.0, Python 3.10 or later). Where it runs is your call:
| Agent Engine (Agent Runtime) | Cloud Run | Your own container | Temporal plugin | |
|---|---|---|---|---|
| How you deploy | adk deploy agent_engine packages your code and builds the container | adk deploy cloud_run, or gcloud run deploy | A Dockerfile and a FastAPI app from get_fast_api_app() | A Worker you run, with GoogleAdkPlugin on the Client and the Worker |
| Where sessions live | Agent Runtime Sessions, through VertexAiSessionService | In memory unless you set --session_service_uri | The session_service_uri you pass | Inside the Workflow, “without managing sessions, a database, or your own retry logic” |
| Tool confirmation with stored sessions | VertexAiSessionService is listed as not supported | Works in memory. DatabaseSessionService is listed as not supported | Same as Cloud Run | Not covered in the integration guide |
| What you install | google-adk[gcp] | google-adk[db] for SQL sessions | google-adk[db] for SQL sessions | temporalio[google-adk]>=1.28.0 |
| What you pay | 50 vCPU-hours and 100 GiB-hours free a month, then $0.085 per vCPU-hour and $0.009 per GiB-hour | Cloud Run usage plus your database | Your servers plus your database | Temporal Cloud or your own Temporal Service, plus the Workers |
The rest of this page walks through each piece in the order you hit it.
Google ADK sessions: DatabaseSessionService and VertexAiSessionService
A session in ADK is “a single conversation thread between a user and your agent.” The SessionService stores its events and state, and you pick one of three:
InMemorySessionServicekeeps everything in the process. “All conversation data is lost if the application restarts.”DatabaseSessionServicewrites to PostgreSQL, MySQL, or SQLite through SQLAlchemy. It needs thedbextra and an async driver.VertexAiSessionServicestores sessions in Agent Runtime. It needs a Google Cloud project, thegcpextra, a storage bucket, and an Agent Runtime resource ID.
The database version looks like this:
from google.adk.sessions import DatabaseSessionService
# Example using a local SQLite file:
# Note: The implementation requires an async database driver.
# For SQLite, use 'sqlite+aiosqlite' instead of 'sqlite' to ensure async compatibility.
db_url = "sqlite+aiosqlite:///./my_agent_data.db"
session_service = DatabaseSessionService(db_url=db_url)
The database is yours to run and to migrate. ADK Python 1.22.0 moved the session schema “from v0, which is a pickle-based serialization, to v1, which uses JSON-based serialization,” and adk migrate session copies the old rows into a new database.
Long sessions also grow the prompt. ADK’s context compaction summarizes “older session history” on rules you set in EventsCompactionConfig:
from google.adk.apps.app import App, EventsCompactionConfig
compaction_config = EventsCompactionConfig(
token_threshold=4000, # Triggers compaction when actual token count exceeds this
event_retention_size=5 # Number of recent raw events to keep intact when token limit is hit
)
app = App(
name="my_compacting_agent_app",
root_agent=root_agent,
events_compaction_config=compaction_config
)
A sliding window (compaction_interval and overlap_size) works too, and token-based compaction wins when you set both. Agent memory and context windows covers the general problem.
Google ADK tool confirmation and human-in-the-loop
Tool confirmation lets a tool “pause its execution and interact with a user or other system for confirmation” before it runs. It shipped in ADK Python 1.14.0. The yes or no version is one flag, and a function can decide per call:
async def confirmation_threshold(
amount: int, tool_context: ToolContext
) -> bool:
"""Returns true if the amount is greater than 1000."""
return amount > 1000
root_agent = Agent(
# ...
tools = [
# Pass the threshold function to dynamically require confirmation
FunctionTool(reimburse, require_confirmation=confirmation_threshold),
],
# ...
)
For a structured answer, the tool calls tool_context.request_confirmation(hint=..., payload=...) and reads tool_confirmation.payload on the next pass. Without the ADK web UI, your app answers over REST: it posts a function_response named adk_request_confirmation to /run_sse, with the id of the original FunctionCall. With resumability on, it “also must include the Invocation ID,” or ADK “starts a new invocation with the confirmation response.”
Here’s the catch for production. The same page lists two known limitations: “DatabaseSessionService is not supported by this feature” and “VertexAiSessionService is not supported by this feature.” So the approval flow and the persistent session stores don’t mix today.
The older route is LongRunningFunctionTool. When the model calls one, “the agent runner pauses the agent run,” and your client sends the final response back “for the next run.” Your code owns the waiting and the follow-up message. Human-in-the-loop approvals for AI agents compares this pattern across frameworks.
Google ADK resumability with ResumabilityConfig
Resumability (ADK Python 1.16 and later) lets a run “pick up where it left off” after a crash or a dropped connection. You switch it on for the whole App:
app = App(
name='my_resumable_agent',
root_agent=root_agent,
# Set the resumability config to enable resumability.
resumability_config=ResumabilityConfig(
is_resumable=True,
),
)
Then you resume with the Invocation ID from the event history, through /run_sse or runner.run_async(..., invocation_id=...). Three rules on the same page shape how you use it:
- Tools run “at least once,” and “may run more than once when resuming a workflow.” A refund tool needs its own duplicate check. (Retries and idempotency for agent tool calls shows how.)
- “Do not modify a stopped agent workflow before resuming it.” Adding or removing agents before a resume “is not supported.”
- Custom agents need code changes: a state class, checkpoints for each step, and an
end_of_agent=Truemarker.
Rule 2 matters most if you deploy often. A stopped run has to resume on the agent definition it started with.
Google ADK OpenAPIToolset and LiteLLM with Claude
OpenAPIToolset turns an OpenAPI spec into tools. It reads “OpenAPI Specification (v3.x)” as a dict, a JSON string, or a YAML string, resolves “any internal references ($ref),” and creates one RestApiTool per operation. Tool names come from the operationId, in snake case, up to 60 characters:
from google.adk.tools.openapi_tool.openapi_spec_parser.openapi_toolset import OpenAPIToolset
# Example with a JSON string
openapi_spec_json = '...' # Your OpenAPI JSON string
toolset = OpenAPIToolset(spec_str=openapi_spec_json, spec_str_type="json")
ADK Python 2.0.0 added header_provider, ssl_verify, and tool_name_prefix (for two specs with clashing names). You pass the spec in as a string or a dict, so the tools match whatever copy you loaded.
For a model other than Gemini, ADK wraps LiteLLM, “an OpenAI-compatible interface to over 100+ LLMs.” Claude looks like this:
from google.adk.agents import LlmAgent
from google.adk.models.lite_llm import LiteLlm
agent_claude_direct = LlmAgent(
model=LiteLlm(model="anthropic/claude-3-haiku-20240307"),
name="claude_direct_agent",
instruction="You are an assistant powered by Claude Haiku.",
# ... other agent parameters
)
ADK requires litellm>=1.84. (The LiteLLM page opens with a security advisory: unauthorized code shipped in LiteLLM 1.82.7 and 1.82.8 on PyPI on March 24, 2026.) The model is a line of Python in the agent definition. Switching model providers for AI agents goes deeper.
Deploy Google ADK to Agent Engine or Cloud Run
Agent Engine is “a fully managed auto-scaling service on Google Cloud” for ADK agents. You enable the Agent Platform and Cloud Resource Manager APIs, then run:
adk deploy agent_engine \
--project=$PROJECT_ID \
--region=$LOCATION_ID \
--display_name="My First Agent" \
multi_tool_agent
The command “packages your code, builds it into a container, and deploys it.” Billing runs on Agent Compute and Agent Memory: the first 50 vCPU-hours and 100 GiB-hours each month are free, then $0.085 per vCPU-hour and $0.009 per GiB-hour. “For Runtime, idle time spent waiting for the next prompt between turns is not billed.” Sessions add $0.30 per GiB-month of storage and one vCPU-hour per million writes.
Cloud Run is the container route, and adk deploy cloud_run is “recommended for Python.” Set the session flag, or your sessions vanish. Without --session_service_uri and --artifact_service_uri, “sessions and artifacts are lost whenever a Cloud Run instance is recycled.” Pass agentengine://<agent_engine> to use Agent Runtime Sessions, or any SQLAlchemy URL for your own database. The dev UI ships only with --with_ui.
And Temporal? Its GoogleAdkPlugin “runs each model call and tool call as a Temporal Activity,” so an agent “keeps its place across Worker restarts, deploys, and transient failures.” You run the Workers and either a Temporal Service or Temporal Cloud (the cost breakdown has the numbers).
What does Cadenya offer that Google ADK on Agent Engine or Cloud Run doesn’t?
Google ADK gives you the agent code, and you still pick, run, and wire the session store, the approval flow, and the deployment. Cadenya is the whole loop: conversation state, approvals, tools from your spec, and any model, with nothing to deploy. Here’s what that covers:
- Nothing else to run. No Google Cloud project, no Agent Runtime resource, no Cloud Run service, no Temporal Worker. You create an objective over HTTP, and your app stays a stateless web tier.
- No session database to choose or migrate. Every objective carries a durable event log of its loop. You list the stored events after a run or stream them live, with no async driver, no SQLAlchemy URL, and no
adk migrate session. - Approvals that work with stored state. Mark a tool set as needing approval, for every tool or the ones a filter matches. The objective pauses on
toolApprovalRequested, and “multiple tools can wait at the same time.” You approve with thetoolCallId, or deny with a memo that steers the agent. - Edit the agent while objectives wait. An objective “keeps that variation’s configuration snapshot even if you edit the variation later.” So you can change the prompt, tools or model while an objective waits, and that objective keeps the configuration it started with.
- Tools from your OpenAPI spec, kept current. Point a tool set at an OpenAPI 3.0 or later document by URL, and Cadenya “checks the specification for changes each hour.” Filters and progressive discovery keep a big API out of the context window. MCP servers and plain HTTP endpoints work too.
- Any model, on your own keys. The model is a setting on a variation, not a line of Python, so a switch needs no deploy and no LiteLLM pin. Use any model on OpenRouter or your own endpoint that speaks the OpenAI chat format, and pay your provider directly. Weighted variations route more traffic to whichever model or prompt scores higher.
- Context compaction included. Cadenya compacts the context window when a conversation gets long and records a
contextWindowCompactedevent. One API call compacts a running objective on demand. - Acting on behalf of the signed-in user. An objective can carry a short-lived token, such as “a JWT minted to act on behalf of a user,” and the objective secret wins over the shared one on each tool call.
- A Python SDK for the Python you run. The
cadenyapackage supports Python 3.9 and later, and the TypeScript, Ruby, and Go SDKs ship alongside it. All four are at 1.9.0 under Apache-2.0, and the TypeScript SDK has shipped 113 versions since April 2026. - A price in one line. Free for 1,000 loops a month, $49 a month for 50,000, then $0.0015 a loop. A loop is one LLM request, so there are no vCPU-hours or GiB-hours to estimate.
How objectives work walks through a full run, and the free plan needs no card.
Create an account at app.cadenya.com/signup, then copy your API key from the API keys page.
Grow wherever AI goes next.
Start shipping agents that are equipped to evolve.