Skip to content

Google ADK adapter

For the Google Agent Development Kit. ADK accepts plain callables for Agent(tools=…) and infers tool schemas from the callable's signature — so the adapter returns signature-preserving governed wrappers (via functools.wraps), not opaque tool objects. ADK introspects them as if you'd passed the underlying function directly.

Install

bash
pip install kitelogik google-adk

If you also want the Google Gemini provider:

bash
pip install "kitelogik[google]" google-adk    # adds google-genai

google-adk is not a hard dependency — only imported when you call adk_tools().

Setup

python
from kitelogik import OPAClient, PolicyGate, SessionContext
from kitelogik.adapters.google_adk import GoogleADKAdapter

gate = PolicyGate(opa_client=OPAClient())
context = SessionContext(
    session_id="sess_001",
    user_role="analyst",
    session_scopes=["read_customer"],
)

adapter = GoogleADKAdapter(gate=gate, context=context)

Register tools

register(name, fn, description="", action=None) — chainable.

python
async def get_customer(customer_id: str) -> str:
    """Look up a customer record by ID."""
    return f"Customer {customer_id}: Acme Corp, plan=enterprise"

adapter.register("get_customer", get_customer, description="Look up a customer")

The original function's signature, name, and docstring are preserved on the governed wrapper, so ADK's auto-schema inference produces the right tool spec.

Pass governed tools to an ADK Agent

python
from google.adk import Agent

agent = Agent(
    name="support",
    model="gemini-2.0-flash",
    tools=adapter.adk_tools(),    # ← signature-preserving callables
)

ADK reads each callable's annotated parameters to build the tool schema, dispatches calls into the governed wrapper, which routes through the policy gate before the underlying function runs.

What happens on a deny

Denied calls return a JSON string {"blocked": true, "reason": "..."} as the tool result, matching ADK's expectation that tools return strings. The agent loop continues; the model sees the structured denial.

json
{"blocked": true, "reason": "Action blocked by governance policy."}

To customise the message, pass deny_message= to the adapter constructor.

Constructor parameters

GoogleADKAdapter extends BaseGovernedAdapter:

python
GoogleADKAdapter(
    gate: PolicyGate,
    context: SessionContext,
    sanitize: bool = True,
    deny_message: str | None = None,
)
ParamDefaultPurpose
sanitizeTrueRun prompt-injection sanitiser on string return values
deny_message"Action blocked by governance policy."The string surfaced to the model on deny

Source

kitelogik/adapters/google_adk.py on GitHub.

Released under the Apache 2.0 License.