Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions async-openai/src/types/chat/chat_.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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<bool>,

/// When true, stream obfuscation will be enabled. Stream obfuscation adds
Expand All @@ -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<bool>,
}

Expand Down
36 changes: 35 additions & 1 deletion async-openai/tests/ser_de.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
use async_openai::types::chat::{
ChatCompletionRequestSystemMessageArgs, ChatCompletionRequestUserMessageArgs,
CreateChatCompletionRequest, CreateChatCompletionRequestArgs,
ChatCompletionStreamOptions, CreateChatCompletionRequest, CreateChatCompletionRequestArgs,
};

#[test]
Expand All @@ -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);
}
Loading