Summary
src/interceptors/fetchInterceptor.ts clones the response and calls clonedResponse.json() to extract token usage. Streaming responses are chunked SSE; they have no JSON body. The .json() call throws, the catch block swallows it, and track() is never called.
Affected File
src/interceptors/fetchInterceptor.ts
All streaming LLM calls are tracked at $0 cost because clonedResponse.json() always throws for streaming responses.
Suggested Fix
Detect streaming responses by checking Content-Type: text/event-stream and accumulate token counts from the usage field in the final SSE chunk before calling track().
Severity
Critical
Summary
src/interceptors/fetchInterceptor.tsclones the response and callsclonedResponse.json()to extract token usage. Streaming responses are chunked SSE; they have no JSON body. The.json()call throws, the catch block swallows it, andtrack()is never called.Affected File
src/interceptors/fetchInterceptor.tsAll streaming LLM calls are tracked at $0 cost because
clonedResponse.json()always throws for streaming responses.Suggested Fix
Detect streaming responses by checking
Content-Type: text/event-streamand accumulate token counts from theusagefield in the final SSE chunk before callingtrack().Severity
Critical