google-gemini / google-gemini/gemini-cli

Aborted streaming responses discard already-received usageMetadata

Open
#28,682 0 comments 0 reactions 0 assignees View on GitHub
area/agent status/need-triage
Dominant language
TypeScript
Stars
107k
Forks
14.6k
Avg merge
2d 3h
Merged PRs (30d)
45

Description

### What happened?

When a streaming response is aborted (Ctrl-C, timeout, or signal.abort), `Turn.run` yields `UserCancelled` and returns before emitting the `Finished` event (`packages/core/src/core/turn.ts:295-298`). The `Finished` event is the only place `usageMetadata` is emitted to consumers (`turn.ts:405-413`). Additionally, `LoggingContentGenerator` captures `lastUsageMetadata` from each received chunk (`loggingContentGenerator.ts:544-546`) but only flushes it via `_logApiResponse` on the success path (`loggingContentGenerator.ts:551`); the catch block for `AbortError` at `loggingContentGenerator.ts:584` skips the flush entirely.

So when a stream is aborted after content has been generated, the already-received usage metadata is discarded. Telemetry, logging, and token-usage displays show nothing for the aborted turn, even though the provider billed the partial generation.

The repo's own test confirms the abort path yields no Finished event: `turn.test.ts:199` asserts events = `[Content, UserCancelled]`.

### What did you expect to happen?

Usage metadata already received from the provider during streaming should be preserved and recorded even when the stream is aborted, not silently dropped.

### Client information

Source-level bug verified on `main` at `ac42fb0`. Mechanism confirmed by the repo's own test suite (`turn.test.ts:199`) and code inspection. Platform: macOS.

### Anything else we need to know?

The fix could flush `lastUsageMetadata` (already captured per-chunk) into telemetry on the abort path, marking the record as `aborted=true` to distinguish partial from complete usage.

Contributor guide

Open the contributing guide

Research direction

Start with the abort and Finished-event paths in packages/core/src/core/turn.ts:295-298 and 405-413, then inspect lastUsageMetadata handling in loggingContentGenerator.ts:544-546, 551, and 584. Run the abort case in turn.test.ts:199 first; done means already-received usage metadata is recorded for aborted streams and the partial record is distinguishable as aborted.

Written by the indexing model from the issue text.

Assessment

Tech stack
typescript
Domain
ai, cli, observability-sre
Issue type
Bug
Difficulty
3/5
Estimated time
1-2 days
Activity status
Quiet
Clarity
Clearly specified
Newbie friendliness
75/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.