Skip to content

fix: Groq usage.raw keeps null fields - #308

Merged
eric8810 merged 6 commits into
masterfrom
fix/groq-usage-raw-keeps-null-fields
Oct 25, 2026
Merged

eric8810 merged 6 commits into
masterfrom
fix/groq-usage-raw-keeps-null-fields

Conversation

@cunninghamcard-bit

Copy link
Copy Markdown
Contributor

Summary

Before: Groq's usage.raw was the typed GroqUsage struct serialized again, so a usage field the API sent as null (completion_tokens_details: null, prompt_tokens_details.cached_tokens: null, reasoning_tokens: null) disappeared. Generate and stream both.

After: usage.raw is the usage object as parsed, as @ai-sdk/groq 4.0.52 returns it (convertGroqUsage → raw: usage): a null stays null, keys outside the usage schema are dropped (zod object strips them), and the counts are read as before.

Found while porting the upstream Groq tests (#301, cases convertGroqUsage › should handle null completion_tokens_details and › should handle null reasoning_tokens in completion_tokens_details). Part of the #276 list.

How it works today

GroqChatLanguageModel::do_generate / do_stream          aimux-providers/src/groq/model.rs:276 / :347   // upstream: GroqChatLanguageModel  groq-chat-language-model.ts
├─ create_json_response_handler::<GroqChatResponse>     groq/model.rs:284                               // upstream: groqChatResponseSchema.usage  :564-580 (zod object, nullish fields)
│  └─ GroqUsage: #[derive(Deserialize, Serialize)]      groq/types.rs:10                                //   unknown keys stripped, null kept in the parsed value
│     fields Option<u32> / Option<Details>, skip_serializing_if = "Option::is_none"
└─ convert_groq_usage(usage)                            groq/usage.rs:9 (generate :335, stream x_groq.usage :475 / :541)   // upstream: convertGroqUsage  convert-groq-usage.ts
   └─ raw: serde_json::to_value(usage)                  groq/usage.rs:44   ← null and absent both become None, then skipped   //   raw: usage  :53

What this PR changes

create_json_response_handler::<GroqChatResponse>        groq/model.rs:284
└─ <GroqUsage as Deserialize>::deserialize              groq/types.rs:36    ← new hand-written impl
   ├─ KEYS: the schema's keys, nested ones included     :39                 ← upstream :564-580
   ├─ raw: Map<String, Value> = the object with only those keys, null kept    types.rs:21
   └─ counts parsed into Option<u32> as before
convert_groq_usage(usage)                               groq/usage.rs:9
└─ raw: Some(usage.raw.clone())                         groq/usage.rs:44    ← upstream convert-groq-usage.ts:53

Tests: usage_raw_keeps_null_fields (tests/groq_test.rs) sends null details and an extra queue_time key and checks usage.raw; it fails on master. The upstream cases are ported in #301.

Docs: CHANGELOG Fixed.

Type of change

  • Bug fix (non-breaking)
  • New feature (non-breaking)
  • Breaking change
  • New provider
  • New / updated binding
  • Docs / RFC

Checklist

  • cargo +1.99 fmt -p aimux-providers -- --check passes
  • cargo +1.99 clippy -p aimux-providers --lib --tests -- -D warnings passes
  • cargo +1.99 test -p aimux-providers --lib --test groq_test --test groq_transcription_test --test cassette_full_test --test conformance_test passes
  • scripts/check_provider_boundaries.sh passes
  • Updated relevant docs (CHANGELOG)
  • Commit messages follow Conventional Commits

Notes for reviewers

Keys Groq sends outside the usage schema (such as queue_time) were already dropped before, because the typed struct had no field for them; that stays.


Generated by Claude Code

convertGroqUsage (convert-groq-usage.ts:53) returns the usage object as
zod parsed it (groq-chat-language-model.ts:564-580): a null field stays
null and unknown keys are dropped. aimux re-serialized the typed struct,
which dropped null fields, so completion_tokens_details: null or
reasoning_tokens: null disappeared from usage.raw. GroqUsage now keeps
the parsed object (known keys only) and convert_groq_usage returns it.

Test: usage_raw_keeps_null_fields (tests/groq_test.rs).

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01RoxcKU4zBD64Lri3e4Lrq5
@cunninghamcard-bit
cunninghamcard-bit marked this pull request as ready for review October 24, 2026 10:14

@eric8810 eric8810 left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Groq usage.raw 保留五个 null 字段并 strip unknown,符合 pinned zod。Approve。

…keeps-null-fields

# Conflicts:
#	CHANGELOG.md
@eric8810
eric8810 merged commit 55d9c84 into master Oct 25, 2026
16 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants