0.6.0

AgJSON draft.3 — `outputTokens` now means the same thing on every framework

A one-rule spec revision, shipped as a minor because it changes a number consumers may have pinned. The wire shape is untouched; one field’s meaning is now defined.

Breaking for Gemini / ADK consumers: usage.outputTokens includes reasoning

Spec 1.0.0-draft.3 defines AgUsage.outputTokens as every token the provider generated, including reasoning, with reasoningTokens a breakdown of it. That is the convention Anthropic and OpenAI already document (“billed as output tokens”), the one the OpenTelemetry GenAI conventions prescribe, and the one the Vercel AI SDK, LangChain, Pydantic AI and LiteLLM all normalize Gemini to. Until now @silverprotocol/google-adk copied Gemini’s candidatesTokenCount, which excludes thoughts — so outputTokens meant “billable output” on three frameworks and “visible text” on the fourth, and no consumer could tell which.

From 0.6.0 the adk facet folds thoughtsTokenCount into outputTokens, guarded by Gemini’s own total so an endpoint that already reports candidates inclusively is never double-added. On a thinking turn turn.done.usage.outputTokens rises by exactly reasoningTokens:

echo-gemini35     31 → 156   (394 + 156 == 550)
thinking-gemini37 29 → 152
tool-error        35 → 212

inputTokens, reasoningTokens and totalTokens are unchanged, and inputTokens + outputTokens + (toolUseInputTokens ?? 0) == totalTokens now holds on Gemini as it already did on OpenAI and Vercel. Claude, OpenAI and Vercel usage is byte-identical. Two correct ways to read the fields, everywhere:

  • All generated tokens, what you are billed for at the output rate: outputTokens.
  • Visible text only: outputTokens − reasoningTokens (approximate on Anthropic, whose thinking_tokens is a re-tokenization estimate).

Repairing persisted rows produced by earlier versions: a Gemini row is pre-0.6.0 exactly when totalTokens − inputTokens − outputTokens − (toolUseInputTokens ?? 0) == reasoningTokens > 0; add reasoningTokens to outputTokens for those rows. Claude, OpenAI and Vercel rows need no change.

Correction to the 0.5.4 claude facet documentation: its source comments stated that the adk facet already followed the subset convention. It did not; 0.6.0 makes the statement true. (The 0.5.4 release note itself spoke only about Claude and was accurate.)

Known gap: @google/adk’s Interactions-API route (useInteractionsApi) synthesizes usage without thoughts upstream, so on that route reasoningTokens is absent and outputTokens stays exclusive. An upstream issue is being filed against google/adk-js.

Wire version

AGJSON_VERSION is now 1.0.0-draft.3. Draft.2 inputs remain accepted (same major). Unlike draft.2, draft.3 is not byte-identical for Gemini/ADK producers, as described above; no field shapes changed, and the spec is explicit that the input side (inputTokens versus cache counters) is out of scope for this revision. A conformance identity joins §10 and the replay suite now asserts it on every golden that reports a total.

The compatibility tables on each npm page carry the dated evidence.