Skip to main content
StiggAdkPlugin governs a Google ADK graph. Add it to a Runner’s plugins, and ADK runs it for every agent the Runner reaches, including sub-agents. Each model call and paid tool is then checked before it runs, and its usage is reported as the agent that made it. For how Stigg governs a team of agents and what it’s used for, see Agent frameworks.

Quick start

You need a Google ADK app, a Stigg server API key, and a credit type in Stigg, here credits, that your customers have.
1

Install the SDK

@google/adk 2.x is an optional peer dependency. The plugin uses the copy your app already has.
2

Create the Stigg client

Create it once, when your server starts:
3

Create the plugin

Tell the plugin what to check each step against, and how to find the customer a step is for:
ADK has no per-run metadata, so stepContext names the customer. It’s called for every step, and customerOf stands for your own lookup from the logged-in user. See Naming the customer safely.
4

Add the plugin to the Runner

Your agents need no changes. Put the plugin first in plugins:
ADK stops at the first plugin that answers a step, so a plugin before Stigg’s can hide that step from Stigg.
5

Check that it works

Run the agent once. Then confirm in Stigg that the customer’s credits balance went down. If it didn’t, the token counts the plugin reports aren’t converted into credits yet. See The credit balance does not go down.To see each decision while you test, add a hook to the plugin:

Naming the customer safely

The customer ID decides who pays for a run. If it comes from the user’s request, a user can send another customer’s ID and charge their usage to that customer. Always resolve it on your server, from the logged-in user.
  • adkContext.userId is safe only when your server sets it from the login. ADK’s own API server lets the client choose userId.
  • Session state is never safe, because the client can send a stateDelta with every run.
  • A default customer in the plugin’s stiggContext: { customerId } is charged for any step whose stepContext returns nothing. Set one only in a process that serves one customer.
The agent a step belongs to comes from the agent tree you built, not from the request, so a client can’t change whose budget pays.

Configurations

The plugin takes the same stiggContext, agents, tools and hooks options as the LangChain handler. Each configuration below adds to the one before it.

Metering only

With no entitlement, nothing is checked or denied. Every model call is reported, and the agents run as they would without Stigg. By default each call reports ADK’s token counts under Gemini’s names, such as promptTokenCount and candidatesTokenCount. See the Gemini page for what each count includes, then create meters for them in Stigg or convert them with a usageMapper.

One budget for the whole team

Every model call, by every agent the Runner reaches, is checked against the customer’s credits, and its usage is reported against them.

A budget per agent

Register a parent agent and one agent per team member in Stigg, as in Register the agents. Then key agents by the name given to each LlmAgent:
Each step is now checked against its agent’s budget and the parent’s. When the researcher runs out, its steps are denied, and the coordinator keeps working. What stepContext returns is merged over the plugin’s and the agent’s settings, and a tool’s price from tools still applies over it.

Tools

Paid tools are listed under tools, as in the LangChain handler. A tool counts against the agent whose model asked for it. Three kinds of tools work differently in ADK:
  • ADK’s control tools, transfer_to_agent, exit_loop, set_model_response and finish_task, are never checked, not even by '*'. They do no work, and denying one would break the agent.
  • Gemini’s built-in tools, such as GOOGLE_SEARCH, run inside the model call, so they’re counted in the call’s tokens.
  • An agent wrapped in an AgentTool runs in a Runner of its own, without the plugin, so its model calls aren’t governed. The plugin warns once. Add the agent as a sub-agent instead.

When access is denied

ADK doesn’t let a plugin throw, so the plugin answers a denied step instead: Use onRefusal to hand a denied agent’s turn to another agent. In this example, a researcher that runs out of budget hands its turn to a cheaper generalist agent, which answers without search:
  • transferTo must name an agent ADK lets the denied one transfer to. Any other name throws, as a configuration error.
  • An agent hands off at most once per run, so two denied agents can’t pass the turn back and forth.
  • Any other LlmResponse you return is used as the agent’s answer.
To show the denial to the user, read it from the run’s events with stiggPlugin.denialOf(event). It returns the decision behind a denied step, with a message you can show, or undefined for any other event:
A denied model call’s decision travels in its event’s customMetadata, which the model never sees. If Stigg can’t be reached to check, the SDK follows checkErrorAction, which lets the step run by default. See Fallback strategy. Reporting usage never throws into the run.

How usage is reported

  • A model call is reported when its last response arrives, before ADK hands that event to you. A caller that stops reading after the answer still has the call reported.
  • A streamed call is reported once, with its final total.
  • A call with no finish reason is reported at the agent’s next step, or when the agent or the run ends.
  • A failed model call or tool reports nothing.

Observability

Hooks, tracing spans and flushing work as they do in the LangChain handler. See Observability.

Best practices

  • Set the customer on your server. The customer ID decides who pays for a run. Take it from the logged-in user, never from the request, or a user can charge their usage to another customer. Return it from stepContext. See Naming the customer safely.
  • Keep parallel spend within budget. Each check reads the balance at that moment, so steps that start together can each pass. Keep limits a little below the true cap, or reserve credits for the whole task. See Caching and accuracy.
  • Choose small credit units. Agent budgets count whole units and round each call up, so define your credit type in small units, such as thousandths of a dollar, to keep rounding negligible. See Usage governance.
  • Roll out without denials. Start with metering only, or register agents with no limit, then add limits once usage looks right. See Observe-only rollout.