Repository navigation
[Bug]: Transient Claude thinking-token counters occupy 38% of provider-log bytes #19777
Description
Before submitting
- Searched existing issues and PRs for
thinking_tokensand provider-event logging. - Included a source-level reproduction and measured log totals.
Area
apps/server
Steps to reproduce
- Run the Claude provider with thinking enabled and inspect
logs/provider/events.*.log*without changing them. - Count lines and bytes containing the exact substring
"subtype":"thinking_tokens". - Exercise the exported logging predicate from a checkout with dependencies installed:
import { shouldPersistProviderEvent } from './apps/server/src/provider/EventNdjsonLogger.ts';
const decoded = payload => ({ event: { stage: 'decoded', payload } });
console.log(shouldPersistProviderEvent('native', decoded({
type: 'system', subtype: 'thinking_tokens',
estimated_tokens: 100, estimated_tokens_delta: 1,
}))); // true
console.log(shouldPersistProviderEvent('native', decoded({
type: 'stream_event', event: { type: 'content_block_delta',
delta: { type: 'thinking_delta', thinking: 'x' } },
}))); // falseVerified with node --input-type=module on Node 26.10.0. This reproduction calls the production predicate and uses synthetic frames.
Expected behavior
Per-token counter telemetry receives the same filtering or sampling treatment as other transient token frames, while terminal usage and diagnostic records remain available.
Actual behavior and evidence
The logger retains every system/thinking_tokens frame. A read-only recount on one Linux installation on October 15 gave:
| All provider records | Thinking-token counters | |
|---|---|---|
| Lines | 430,306 | 299,160 (69.52%) |
| Bytes | 444,437,103 | 170,979,370 (38.47%) |
These are serialized log bytes, not model token counts. An earlier retained Mac audit independently counted 59,928 such lines of 80,917 and 33.5 MB of 70.7 MB; that historical Mac sample was not re-collected in this pass.
shouldPersistProviderEvent filters other transient frames but has no rule for these counters. The write path then serializes them and appends them to the same bounded log used for useful protocol history. At the existing 512 MiB total retention limit, these records consume a substantial part of that history budget. Logging is already asynchronous; this report does not claim event-loop stalls or a broken retention cap.
Recount with Python, without printing conversation contents:
from pathlib import Path
total_lines = total_bytes = counter_lines = counter_bytes = 0
for path in (Path.home() / '.t3/userdata/logs/provider').glob('events.*.log*'):
with path.open('rb') as stream:
for line in stream:
total_lines += 1
total_bytes += len(line)
if b'"subtype":"thinking_tokens"' in line:
counter_lines += 1
counter_bytes += len(line)
print(total_lines, total_bytes, counter_lines, counter_bytes)Impact / version / environment
Minor storage and diagnostic-retention overhead. Ubuntu 26.04, Claude provider, 0.0.46-nightly.20261014.3132. Predicate verified again on main e536bfd33bc3c351997141d93790df75eeded7b9; relevant code is unchanged from the original audit at ec1313c8f8333292506f05a355bb72d308a455d8. Related #19430 fixes the asynchronous sink, a different problem.
Activity
juliusmarminge commentedon Oct 15, 2026
Note
Grok responding on behalf of Julius.
Accepting this as a low-priority log-retention bug. On main (
e536bfd),shouldPersistProviderEventalready drops per-token native frames (rawframes,stream_event/content_block_delta,message.part.delta, and the transient native methods), but it has no rule for Claude'ssystem/thinking_tokenscounters, so every one of them is written into the bounded 512 MiB provider log.These counters don't look like something we keep on purpose for diagnostics. Thinking-token usage is tracked at runtime (
ClaudeTurnTokenUsage.ts), and the final usage and result records still get logged. So dropping the per-delta counters wouldn't lose anything the other transient-frame filters don't already give up. This is separate from #19430 (the async sink) and from #15396 (how thinking tokens are reported in usage).A small PR is welcome: return
falsefor decoded nativesystem/thinking_tokensframes inshouldPersistProviderEvent, and add a test next to the existing transient-frame cases. Please keep terminal usage and result records persisted.