Primary finding
OpenAIProvider streamMessage marks response incomplete=false even when aborted mid-stream after some data
- src/providers/openai.ts:60-75
- src/providers/openai.ts:162-175
processSSEStream exits cleanly on abort (break) so no exception is thrown. incomplete is then read from `options.signal?.aborted`, which is fine when actually aborted, but if abort happens after the stream naturally finished but before we read the flag, we may falsely mark complete responses as incomplete. More importantly, the asymmetric design (Anthropic throws on abort; OpenAI silently swallows) makes downstream incomplete semantics inconsistent. The bigger issue: token estimation runs on a possibly-truncated responseText, conflating estimated tokens for partial response with real usage when not delivered by API.
Recommendation
Distinguish between 'no usage provided' and 'aborted'; emit usage estimates only when complete, and clearly mark partials.