Integrations
Google ADK
Gate Google Agent Development Kit tool calls through Aira's policy engine via before_tool_call / after_tool_call plugin hooks.
Kind: gate · Pre-execution gate: yes · Peer dep: Google ADK
What this integration actually does
Google ADK's plugin system provides before_tool_call and after_tool_call hooks. before_tool_call runs BEFORE the tool executes and can raise to abort the call, so this is a real pre-execution gate.
AiraPlugin implements the plugin contract:
before_tool_call→aira.authorize(). RaisesAiraToolDeniedif the policy engine denies or holds the action. The tool never runs.after_tool_call→aira.notarize(outcome="completed").on_tool_error→aira.notarize(outcome="failed").
Install
pip install aira-sdk[google-adk]Full example — gated tool call
from aira import Aira
from aira.extras.google_adk import AiraPlugin, AiraToolDenied
aira = Aira(api_key="aira_live_...")
plugin = AiraPlugin(
client=aira,
agent_id="adk-agent",
model_id="gemini-2.0-flash",
)
def search_documents(query: str) -> list[dict]:
"""Real tool body — side effects happen here."""
# your search code
return [{"title": "...", "snippet": "..."}]
# Manual invocation with before/after hooks — works with any ADK runner
try:
plugin.before_tool_call("search_documents", args={"query": "confidential Q4 forecast"})
try:
result = search_documents(query="confidential Q4 forecast")
except Exception as e:
plugin.on_tool_error("search_documents", e)
raise
plugin.after_tool_call("search_documents", result=result)
except AiraToolDenied as e:
# Policy engine blocked — handle or surface to the agent
print(f"Blocked: {e.code} — {e.message}")Integrating with ADK's plugin registry
If you use Google ADK's plugin loader, register AiraPlugin as a before/after-tool-call listener:
from google.adk import Agent
from aira.extras.google_adk import AiraPlugin
aira_plugin = AiraPlugin(client=aira, agent_id="adk-agent")
agent = Agent(
name="my-agent",
plugins=[
aira_plugin, # ADK will call before_tool_call / after_tool_call on it
],
)What happens when a policy denies
- The agent decides to call
search_documents. - ADK invokes
before_tool_call("search_documents", args={"query": "..."}). - The plugin calls
aira.authorize(action_type="tool_invoked", ...). - Policy engine runs. If denied, the plugin raises
AiraToolDenied. - ADK propagates the exception as a tool error. The real tool body never runs.
Known limits
argsdict keys only. The plugin usessorted(args.keys())in the details string rather than the actual argument values. This keepsauthorize()latency low and avoids sending potentially sensitive tool arguments to Aira'sdetailscolumn. If you want to gate on argument values (e.g. "deny ifquerycontains 'confidential'"), use a content_scan policy or build a custom details string.- Thread safety. The plugin uses an in-memory
tool_name → action_uuidmap keyed by tool name. If the same tool is called concurrently in the same plugin instance, the second call will overwrite the first beforeafter_tool_callruns. For multi-threaded agents, create one plugin instance per thread or switch to keying on a run id if ADK exposes one. - Notarize is non-blocking. Notarize failures log a warning but don't crash the agent.
When to use this vs inline authorize()
| Use the plugin when... | Call authorize() inline when... |
|---|---|
| You're building a standard ADK agent with the plugin system | You have custom business logic per tool branch |
| You want blanket gating on every tool | You need argument values in the details string |
| Thread safety isn't a concern (single-threaded runners) | You're running multiple concurrent tool calls in the same plugin instance |
Proof it works
- Python:
tests/test_extras_google_adk.py(104 lines) - Pinned in the
INTEGRATIONSregistry askind="gate",pre_execution_gate=True.
Related
- OpenAI Agents — similar wrap-the-tool pattern
- Policies