Skip to content

Feature request: built-in budget enforcement hooks #59

@hemanth

Description

@hemanth

The SDK surfaces usage_metadata on every ChatResponseprompt_token_count, candidates_token_count, thinking_token_count, total_token_count. The hook system gives us AfterModelHook to inspect and BeforeModelHook to gate. SessionContext.state persists across turns.

All the building blocks for budget enforcement are there. But there's no built-in way to say "stop this agent after 500K tokens" or "kill the session if it loops."

Every team running /goal tasks or subagent trees ends up building this themselves. The patterns are always the same:

  1. Token ceiling — hard limit, HookResult(allow=False) when breached
  2. Cost ceiling — dollar-based, same mechanism
  3. Velocity guard — sliding window anomaly detection (spike = probable loop)
  4. Loop detector — identical tool+args called N times in a row via PostToolCallHook
  5. Reasoning guardthinking_token_count / total_token_count ratio sustained above 80% = model going in circles

Proposed API

Following the existing deny() / allow() / ask_user() pattern — functional primitives that compose:

from google.antigravity.hooks.budget import token_budget, cost_budget, velocity_guard

config = LocalAgentConfig(
    hooks=[
        token_budget(500_000),
        cost_budget(5.00),
        velocity_guard(window=5, threshold=2.5),
    ]
)

Each function returns a pair of hooks (one AfterModelHook to accumulate, one BeforeModelHook to gate). They share state via SessionContext.state under namespaced keys.

Reference implementation

I built a framework-agnostic version of these patterns as a zero-dependency Node.js library: token-budgets. Same concepts, validates the approach. Happy to port this to Python and open a PR if external contributions become accepted.

Why this matters

deny() controls what an agent can do. Budget hooks would control how much. Together they're the governance stack that makes autonomous agents safe for production.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions