Skip to content

feat(google): report Gemini Live reasoning token usage - #7326

Open
rosetta-livekit-bot[bot] wants to merge 1 commit into
mainfrom
griffins-ballasts-cope
Open

rosetta-livekit-bot[bot] wants to merge 1 commit into
mainfrom
griffins-ballasts-cope

Conversation

@rosetta-livekit-bot

@rosetta-livekit-bot rosetta-livekit-bot Bot commented Sep 17, 2026

Copy link
Copy Markdown
Contributor

Ports livekit/agents-js#2517.

Summary

  • expose optional reasoning tokens on realtime model metrics
  • aggregate, log, and trace realtime reasoning usage without adding it to output totals
  • map Gemini Live thoughts_token_count while preserving reported zero versus omitted values
Source diff coverage
  • .changeset/gemini-live-reasoning-tokens.md: not applicable. The Python repository does not use Changesets and has no counterpart release-note mechanism.
  • agents/etc/agents.api.md: not applicable. Generated TypeScript API output has no Python counterpart; the corresponding Python public models are covered below.
  • agents/src/inference/llm.ts: ported already in livekit-agents/livekit/agents/inference/llm.py; gateway completion_tokens_details.reasoning_tokens is already mapped.
  • agents/src/llm/llm.ts: ported already in livekit-agents/livekit/agents/llm/llm.py; CompletionUsage.reasoning_tokens and propagation into LLMMetrics already exist.
  • agents/src/metrics/base.ts: adapted in livekit-agents/livekit/agents/metrics/base.py; LLMMetrics.reasoning_tokens already existed, and this PR adds optional RealtimeModelMetrics.reasoning_tokens with Python naming and None semantics.
  • agents/src/metrics/model_usage.test.ts: adapted in tests/test_metrics_usage.py; ports the realtime reasoning aggregation assertion using Python metric models.
  • agents/src/metrics/model_usage.ts: adapted in livekit-agents/livekit/agents/metrics/usage.py; LLM reasoning aggregation already existed, and this PR adds realtime reasoning aggregation.
  • agents/src/metrics/utils.ts: adapted in livekit-agents/livekit/agents/metrics/utils.py; realtime structured logging now includes reasoning_tokens.
  • agents/src/telemetry/gen_ai.ts: adapted in livekit-agents/livekit/agents/telemetry/utils.py, where Python builds realtime GenAI attributes; emits both standard and Langfuse-compatible reasoning attributes.
  • plugins/google/src/realtime/realtime_api.test.ts: adapted in tests/test_plugin_google_realtime.py; ports both source cases for mapping and zero-versus-omitted behavior.
  • plugins/google/src/realtime/realtime_api.ts: adapted in livekit-plugins/livekit-plugins-google/livekit/plugins/google/realtime/realtime_api.py; maps thoughts_token_count directly without changing output totals.
  • plugins/openai/src/realtime/gpt_live_model.ts: not applicable. The source removes a TypeScript intersection-type workaround; Python LLMMetrics already accepts the existing reasoning_tokens assignment directly.

Validation

  • uv run pytest tests/test_metrics_usage.py: 10 passed
  • uv run pytest tests/test_plugin_google_realtime.py: 28 passed
  • env -u LIVEKIT_API_KEY -u LIVEKIT_API_SECRET -u LIVEKIT_URL uv run pytest --unit --audio_eot --ignore=tests/test_room.py: 3493 passed, 3 skipped
  • make check: passed formatting, lint, and strict type checking
  • uv build --package livekit-agents: passed
  • uv build --package livekit-plugins-google: passed
  • uv run pytest --plugin google: all 76 assertions passed, but teardown reports two pending TTS tasks in the pre-existing test_gemini_tts_success; the same error reproduces when that untouched test runs alone

The unfiltered make unit-tests additionally requires Docker for tests/test_room.py; Docker is unavailable in this environment. Ambient invalid LiveKit credentials also caused unrelated cloud tests to run and return 401, so the successful hermetic rerun explicitly removed them.


Ported from livekit/agents-js#2517

Original PR description

No description.

@rosetta-livekit-bot
rosetta-livekit-bot Bot requested a review from a team as a code owner September 17, 2026 18:37

@devin-ai-integration devin-ai-integration Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Devin Review found 2 potential issues.

Devin Review

Comment on lines +1622 to +1624
# Gemini includes thinking tokens in response_token_count. Keep None when
# omitted so a reported zero remains distinguishable from a missing count.
reasoning_tokens=usage_metadata.thoughts_token_count,

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟑 Gemini output totals omit reasoning

When Gemini reports thoughts, reasoning_tokens captures them while output_tokens excludes them. Usage summaries therefore undercount output tokens.

Learn more

Gemini Live maps the provider's candidatesTokenCount into response_token_count. The provider defines total_token_count as prompt, response candidates, tool-use prompt, and thoughts combined, so thoughts are separate from response_token_count. The shared RealtimeModelMetrics and LLMModelUsage contracts instead define reasoning as a subset of output tokens. Recording the separate count without folding it into output_tokens violates that contract and makes aggregate output usage too small.

Example: With 397 prompt tokens, 49 response tokens, and 26 thought tokens, the emitted output count is 49. The contract requires 75 output tokens, including 26 reasoning tokens, while the provider total also includes those thoughts.

Recommended fix: Set output_tokens to (usage_metadata.response_token_count or 0) + (usage_metadata.thoughts_token_count or 0), and calculate tokens_per_second from the same combined value. Update the test fixture's total_token_count to reflect the provider's separate thought count.

Devin Review


Was this helpful? React with πŸ‘ or πŸ‘Ž to provide feedback.

if metrics.input_token_details.cached_tokens_details
else 0,
"output_tokens": metrics.output_tokens,
"reasoning_tokens": metrics.reasoning_tokens or 0,

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟑 Logs erase missing reasoning counts

When a provider omits reasoning usage, log_metrics emits reasoning_tokens=0. Consumers cannot distinguish missing data from a reported zero.

Learn more

RealtimeModelMetrics.reasoning_tokens uses None specifically to represent an unreported value. The structured log converts that value to zero, unlike the telemetry path, which omits reasoning attributes when it is None. Any log-based usage pipeline therefore records a provider-reported zero even when no reasoning count was supplied.

Example: A realtime provider emits reasoning_tokens=None. The metric object and trace preserve that absence, but the metrics log contains "reasoning_tokens": 0.

Recommended fix: Preserve None in the log field or omit reasoning_tokens from extra when it is absent. Adjust the local metadata value type if needed.

Devin Review


Was this helpful? React with πŸ‘ or πŸ‘Ž to provide feedback.

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

0 participants