Skip to content

docs(hooks): LLMResponse usageMetadata in the reference omits promptTokenCount and candidatesTokenCount (the hook receives all three) #320

Description

@chadd28

What happened?

In the hooks reference, the Stable Model API documents LLMResponse.usageMetadata as a single-field object:

docs/hooks/reference.md (line ~328, under **LLMResponse**:):

"usageMetadata": { "totalTokenCount": number }

But the hook-facing translator actually forwards three token fields, not one. packages/core/src/hooks/hookTranslator.ts toHookLLMResponse() (lines ~404-410) builds:

usageMetadata: sdkResponse.usageMetadata
  ? {
      promptTokenCount: sdkResponse.usageMetadata.promptTokenCount,
      candidatesTokenCount: sdkResponse.usageMetadata.candidatesTokenCount,
      totalTokenCount: sdkResponse.usageMetadata.totalTokenCount,
    }
  : undefined,

and the exported LLMResponse interface in the same file (lines ~60-63) declares all three as well:

usageMetadata?: {
  promptTokenCount?: number;
  candidatesTokenCount?: number;
  totalTokenCount?: number;
};

So an AfterModel (or BeforeModel) hook receives promptTokenCount and candidatesTokenCount in addition to totalTokenCount, yet the reference — which is explicitly presented as the stable model API hooks can rely on ("Gemini CLI uses these structures to ensure hooks don't break across SDK updates") — lists only totalTokenCount.

What did you expect to happen?

The documented stable schema should match the fields the hook actually receives, i.e.:

"usageMetadata": {
  "promptTokenCount": number,
  "candidatesTokenCount": number,
  "totalTokenCount": number
}

Why this matters

We hit this while building a cross-platform hook/MCP middleware adapter. AfterModel.usageMetadata is the one host-native token-usage signal a hook can read, so we want the exact field list to record accurate per-turn usage. Going by the reference alone, an integrator would assume only totalTokenCount is available and would not read the input/output token breakdown that the code is already handing them. (The per-chunk firing cadence of AfterModel is already correctly noted in docs/hooks/best-practices.md, so this is purely the field list in the schema.)

This is the same omission class — but a different surface — from google-gemini#27985 (ACP PromptResponse usage), which is about the ACP path, not the hooks LLMResponse stable-API schema; cross-referencing for context only.

Proposed fix

A one-block edit to docs/hooks/reference.md: expand the usageMetadata schema under **LLMResponse**: to list promptTokenCount, candidatesTokenCount, and totalTokenCount, matching hookTranslator.ts toHookLLMResponse() and the exported LLMResponse interface.

Happy to open the docs PR if a maintainer confirms this is the intended stable surface (I understand per CONTRIBUTING that the issue comes first).

Client information

Client Information

This is a documentation/code-consistency report based on the current main (docs/hooks/reference.md and packages/core/src/hooks/hookTranslator.ts), not a runtime fault, so a /about capture is not applicable. Platform: N/A (docs).

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions