Problem
OpenAICompatibleProvider.parseProviderResponse reads message("content").str unconditionally. OpenAI's structured-output refusals return content: null with a refusal string and a full usage block. The parser throws before parseUsage runs, so the extension reports a parse failure and records neither the call nor its tokens, even though the provider billed them. Same shape can appear on any OpenAI-compatible provider.
Found by a Codex review on 2026-09-08. The parser assumption predates today's changes; the accounting consequence is new with #78.
Fix
Treat missing or null content as an empty string, carry the refusal text on the response (or surface it as the content with a clear marker), parse usage regardless, and let the calling primitive decide what to do with a refusal after recordUsage.
Test
A canned refusal body in UsageParsingSpec asserting usage is parsed, plus a tests.txt case asserting the call is counted.
Problem
OpenAICompatibleProvider.parseProviderResponsereadsmessage("content").strunconditionally. OpenAI's structured-output refusals returncontent: nullwith arefusalstring and a fullusageblock. The parser throws beforeparseUsageruns, so the extension reports a parse failure and records neither the call nor its tokens, even though the provider billed them. Same shape can appear on any OpenAI-compatible provider.Found by a Codex review on 2026-09-08. The parser assumption predates today's changes; the accounting consequence is new with #78.
Fix
Treat missing or null
contentas an empty string, carry therefusaltext on the response (or surface it as the content with a clear marker), parse usage regardless, and let the calling primitive decide what to do with a refusal afterrecordUsage.Test
A canned refusal body in
UsageParsingSpecasserting usage is parsed, plus atests.txtcase asserting the call is counted.