From 20c90cbfdfd40875a7a55191f880a31bdcc5525c Mon Sep 17 00:00:00 2001 From: Evgenii Khramkov Date: Tue, 6 Jan 2026 22:44:05 +0900 Subject: [PATCH] Skip serializing None fields in ChatCompletionStreamOptions Add serde attribute to omit None values for include_usage and include_obfuscation. Add tests to verify correct serialization and deserialization behavior. --- async-openai/src/types/chat/chat_.rs | 2 ++ async-openai/tests/ser_de.rs | 36 +++++++++++++++++++++++++++- 2 files changed, 37 insertions(+), 1 deletion(-) diff --git a/async-openai/src/types/chat/chat_.rs b/async-openai/src/types/chat/chat_.rs index 0fb57443..6727cd65 100644 --- a/async-openai/src/types/chat/chat_.rs +++ b/async-openai/src/types/chat/chat_.rs @@ -1005,6 +1005,7 @@ pub struct ChatCompletionStreamOptions { /// All other chunks will also include a `usage` field, but with a null /// value. **NOTE:** If the stream is interrupted, you may not receive the /// final usage chunk which contains the total token usage for the request. + #[serde(skip_serializing_if = "Option::is_none")] pub include_usage: Option, /// When true, stream obfuscation will be enabled. Stream obfuscation adds @@ -1014,6 +1015,7 @@ pub struct ChatCompletionStreamOptions { /// of overhead to the data stream. You can set `include_obfuscation` to /// false to optimize for bandwidth if you trust the network links between /// your application and the OpenAI API. + #[serde(skip_serializing_if = "Option::is_none")] pub include_obfuscation: Option, } diff --git a/async-openai/tests/ser_de.rs b/async-openai/tests/ser_de.rs index 2ceb0d5b..49d36774 100644 --- a/async-openai/tests/ser_de.rs +++ b/async-openai/tests/ser_de.rs @@ -1,6 +1,6 @@ use async_openai::types::chat::{ ChatCompletionRequestSystemMessageArgs, ChatCompletionRequestUserMessageArgs, - CreateChatCompletionRequest, CreateChatCompletionRequestArgs, + ChatCompletionStreamOptions, CreateChatCompletionRequest, CreateChatCompletionRequestArgs, }; #[test] @@ -26,3 +26,37 @@ fn chat_types_serde() { let deserialized: CreateChatCompletionRequest = serde_json::from_str(&serialized).unwrap(); assert_eq!(request, deserialized); } + +#[test] +fn stream_options_none_fields_not_serialized() { + // When include_obfuscation is None, it should not appear in the serialized JSON. + // This is important for OpenAI-compatible providers (like NVIDIA NIM) that reject unknown fields. + let stream_options = ChatCompletionStreamOptions { + include_usage: Some(true), + include_obfuscation: None, + }; + + let serialized = serde_json::to_string(&stream_options).unwrap(); + + // Verify include_usage is present + assert!(serialized.contains("include_usage")); + // Verify include_obfuscation is NOT present (not even as null) + assert!( + !serialized.contains("include_obfuscation"), + "include_obfuscation should not be serialized when None, but got: {}", + serialized + ); + + // Test when both are None + let stream_options_empty = ChatCompletionStreamOptions { + include_usage: None, + include_obfuscation: None, + }; + + let serialized_empty = serde_json::to_string(&stream_options_empty).unwrap(); + assert_eq!(serialized_empty, "{}"); + + // Test roundtrip deserialization + let deserialized: ChatCompletionStreamOptions = serde_json::from_str(&serialized).unwrap(); + assert_eq!(stream_options, deserialized); +}