Skip to content

Step.usage_metadata is documented but always None since 0.1.10 — per-call token usage is no longer observable #182

Description

@wuthomas-mit

Summary

Step.usage_metadata is a public, documented field on the public Step type, and it was populated in 0.1.9. As of 0.1.10 it is never populated — every step returns None, with no deprecation notice and no changelog entry. Nothing replaces it at per-call granularity: usage is now only available as session- and trajectory-level cumulative totals.

The practical loss is peak per-call prompt_token_count, which is the only way to measure how large the context actually got. Cumulative totals cannot substitute: with prompt caching, cumulative prompt tokens mostly track how many calls a run made, not how big its context was. A 10M-token run can have a 30k context or a 130k one, and the totals look similar.

Observed

The field is still declared and documented in 0.1.12 — types.py:906, with the docstring at types.py:885:

usage_metadata: Token usage for this specific step's model invocation, or …

Minimal 4-step turn ("Reply with exactly: pong"), identical script, only the SDK version differs:

0.1.9 0.1.12
steps with usage_metadata is not None 1 0
steps with prompt_token_count 1 0
conversation.total_usage.prompt_token_count 11,994 10,829

On real multi-step tasks the gap is larger — 0.1.9 reported 20 and 29 usage-bearing steps (peak prompt_token_count 88,138 and 95,769); 0.1.12 reported zero on the same tasks.

Why this matters in practice

A concrete example from testing 0.1.12: I needed to know what context size triggers compaction. On 0.1.9 that's a one-liner over Step.usage_metadata. On 0.1.12 there is no supported way to get it — I had to scrape current tokens: N out of the harness's stderr (trajectory_chat_converter.go:1116) to recover it, and until I did, I drew the wrong conclusion about how the feature behaved. An undocumented log line in a Go binary is currently the only source for per-call context size.

Cause

The wire field was removed. Diffing the generated descriptors between 0.1.9 and 0.1.12:

  • removed: OutputEvent.usage_metadata
  • added: OutputEvent.usage_update, plus new UsageUpdate, TrajectoryUsageEntry, ModalityTokenCount messages

event_processor.py:599 folds usage_update into cumulative_usage, surfaced as conversation.total_usage / trajectory_usages. Nothing repopulates Step.usage_metadata, and grep -n 'usage_metadata=' over the non-proto Python finds no assignment.

Relatedly, the new proto UsageMetadata carries 10 fields but parse_usage_metadata reads 6 — prompt_tokens_details, cache_tokens_details, candidates_tokens_details and tool_use_prompt_tokens_details are dropped, and types.UsageMetadata has no field for them.

Ask

Either:

  1. repopulate Step.usage_metadata from the per-call usage the binary already reports; or
  2. if per-step usage is intentionally gone, remove the field and its docstring so it doesn't read as supported, and expose peak/current context another way — e.g. a peak_prompt_token_count on UsageMetadata, or per-call entries on UsageUpdate that consumers can max over.

Option 2 with no replacement would leave no supported way to measure context pressure from the SDK.

Repro

import asyncio
from google import antigravity
from google.antigravity import types

async def main():
    cfg = antigravity.LocalAgentConfig(
        model=types.ModelTarget(name="gemini-3.6-flash"),
        vertex=True, project="<project>", location="global")
    async with antigravity.Agent(cfg) as agent:
        resp = await agent.chat("Reply with exactly: pong")
        await resp.resolve()
        h = agent.conversation.history
        print("steps:", len(h),
              "with usage_metadata:", sum(1 for s in h if s.usage_metadata is not None))
        print("total_usage.prompt:", agent.conversation.total_usage.prompt_token_count)

asyncio.run(main())

with usage_metadata: 1 on 0.1.9, 0 on 0.1.10–0.1.12.

Environment

google-antigravity 0.1.9 vs 0.1.12, Python 3.12, macosx_11_0_arm64 wheel, Vertex AI, gemini-3.6-flash. The proto change ships in every wheel.

Metadata

Metadata

Assignees

Labels

No labels
No labels

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions