Skip to main content
New to the adapters? Start with the wrapping overview and comparison table.
Compatible versions: see the compatibility table for the verified google-adk range.
The Google ADK wrapper exposes its own HexgateRunner. It’s constructed up front with the agent, app name, and session service (mirroring the ADK Runner constructor) — the underlying ADK Runner is built once and reused since role resolution happens at call time. run / run_async then yield ADK events.

Under the hood

  • At construction, HexgateRunner calls wrap_google_agent, which builds a PolicySet, constructs one PolicyEnforcer, and returns agent.model_copy(update={"tools": guarded_tools}) — your original agent is untouched.
  • Each tool is normalized first: bare callables in agent.tools are wrapped into FunctionTool (matching what ADK does internally) so the guard has a stable BaseTool surface. Each tool is then copy.copy’d and its run_async replaced with an enforcer-gated version.
  • Each run / run_async call opens a HexgateContext scope (hexgate_context.sync_scope() / async with hexgate_context:) and dispatches to the cached underlying Runner. On non-allow, the guard returns decision.as_error_message() so the ADK runtime forwards it to the model as the tool output instead of aborting the run.
  • Observability is set up lazily on each call: GoogleADKInstrumentor().instrument() plus nest_asyncio.apply() (ADK’s runner spins its own loop), and the run executes inside propagate_attributes(user_id=..., session_id=..., metadata={"user_roles": ...}, tags=["google.runner.run.<agent_name>"]).

Runnable example

examples/devops_google.pyHexgateRunner (Google ADK) end-to-end with InMemorySessionService.