Repository navigation
fix(firebase_ai): parse promptTokensDetails and empty CountTokensResponse on GoogleAI - #18916
cynthiajoan wants to merge 3 commits into
Conversation
There was a problem hiding this comment.
Code Review
This pull request updates parseCountTokensResponse in the developer API to parse promptTokensDetails and handle empty JSON objects, updates documentation for LiveSession.receive(), and adds corresponding unit tests. Feedback highlights a potential parsing failure if totalTokens is omitted while promptTokensDetails is present, and recommends avoiding the ! operator in tests to comply with the repository's null safety style guide.
| ), | ||
| _ => null, | ||
| }; | ||
| if (totalTokens == null && promptTokensDetails == null) { |
There was a problem hiding this comment.
Optional: iOS and Android return 0 for any JSON object, while this still rejects an object that has neither totalTokens nor promptTokensDetails. No current response hits that, but dropping the isEmpty branch and this check (totalTokens ?? 0 for any map) would match the other SDKs and be simpler. It would mean replacing the {'wrongKey': 123} case in throws unhandledFormat on invalid JSON.
| /// Returns a [Stream] of [LiveServerResponse] objects representing the | ||
| /// messages received from the server. The stream will stops once the server | ||
| /// sends turn complete message. | ||
| /// messages received from the server. The stream remains open across turns |
There was a problem hiding this comment.
The stream also ends when the server or the network closes the socket: onDone closes _messageController. Maybe "until the session is closed or the connection ends"? (resumeSession() doesn't reopen it after that either, but that's a separate, older bug.)
| ); | ||
| expect(response.totalTokens, 123); | ||
| // Developer API does not return other fields | ||
| // ignore: deprecated_member_use_from_same_package |
There was a problem hiding this comment.
Nit: CountTokensResponse.promptTokensDetails isn't deprecated, so this // ignore: deprecated_member_use_from_same_package (left over from totalBillableCharacters, removed in #18708) and the three new ones below can go.
Description
DeveloperSerialization.parseCountTokensResponse(lib/src/developer/api.dart) droppedpromptTokensDetailsreturned by the Gemini Developer API (googleAIbackend), so per-modality token counts such asTEXTandAUDIOwere alwaysnull, and it threwUnhandled format for CountTokensResponsewhen the server omittedtotalTokens(protobuf JSON omits zero values, returning{}or onlypromptTokensDetails).parseCountTokensResponsenow defaultstotalTokensto0on an empty object or whenpromptTokensDetailsis present withouttotalTokens, parsespromptTokensDetailswith the existingparseUsageMetadatahelper (matching theagentPlatformserializer), and rejects non-integertotalTokensor non-listpromptTokensDetailswithunhandledFormat. TheLiveSession.receive()doc comment is also corrected: the stream stays open across turns until the session is closed.Verification
bugfixd07113e3a+ only the new tests):flutter test --no-pub test/developer_api_test.dart→ exit 1, 25 passed, 3 failed; new tests failing:parses promptTokensDetails when present,defaults totalTokens to 0 on empty JSON object:5d2cc3751):flutter test --no-pub test/developer_api_test.dart→ exit 0, 28 passed (4s).Related Issues
N/A (
AI-COUNT-TOKENS-1)Checklist
Before you create this PR confirm that it meets all requirements listed below by checking the relevant checkboxes (
[x]).This will ensure a smooth and quick review process. Updating the
pubspec.yamland changelogs is not required.///).melos run analyze) does not report any problems on my PR.Breaking Change
Does your PR require plugin users to manually update their apps to accommodate your change?
Prepared with the Firebase SDK dev-loop agent (Google-internal, built on Jetski) and reviewed by @cynthiajoan before opening. Evidence: red/green captured by
verify-redgreen(verdictverified) at based07113e3a/ head5d2cc3751.