Conversation
usage read its fields through Integer(value, exception: false) and Float(value, exception: false), which is a parser, not a check. It accepted things that are not token counts and produced a number anyway: 30.9 became 30, "120" became 120. And everything it could not read at all -- [], true, "120.5", an error object sitting where usage should be -- became nil, which is exactly what a provider that does not report the field produces. There was no way to tell "this provider sends no cost" from "this response was malformed". Requests are billed per input token. A usage number that silently lost its fraction, or silently became nil, is worse than no number, because whatever is adding these up keeps adding them up. A present field now has to be a whole token count -- an Integer, or a Float with nothing after the point, since JSON has one number type and 120 may arrive as 120.0. Anything else raises InvalidResponse naming the field and showing the value. An absent field is still nil, and a provider that does not report cost still reports nil for it without looking at what was sent. The test that asserted junk becomes nil now asserts it is rejected. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
usageread its fields throughInteger(value, exception: false)andFloat(value, exception: false), which is a parser, not a check. Verified:30.930"120"120"120.5"nil[],{},truenilIt accepted things that are not token counts and produced a number anyway, and everything it couldn't read became
nil— which is exactly what a provider that doesn't report the field produces. There was no way to tell "this provider sends no cost" from "this response was malformed".Requests are billed per input token. A usage number that silently lost its fraction, or silently became
nil, is worse than no number, because whatever is adding these up keeps adding them up.The fix
A present field has to be a whole token count — an
Integer, or aFloatwith nothing after the point, since JSON has one number type and120may arrive as120.0. Anything else raisesInvalidResponsenaming the field and showing the value. An absent field is stillnil, and a provider that doesn't report cost still reportsnilwithout looking at what was sent.Tests
test/usage_test.rb, 14 cases. One existing test that asserted junk becomesnilnow asserts it's rejected.Draft: part of a security and API-coverage audit, opened for reference rather than as a request for immediate review. Independent of the other branches, each off
main. Suite green on Ruby 3.2.11, 3.3.8 and 3.4.8.🤖 Generated with Claude Code