fix: tolerate missing responses output (#9449)
Signed-off-by: Angie Jones <jones.angie@gmail.com>
This commit is contained in:
@@ -273,6 +273,7 @@ pub struct ResponseMetadata {
|
||||
pub created_at: i64,
|
||||
pub status: String,
|
||||
pub model: String,
|
||||
#[serde(default)]
|
||||
pub output: Vec<ResponseOutputItemInfo>,
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub usage: Option<ResponseUsage>,
|
||||
@@ -981,6 +982,47 @@ mod tests {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn test_responses_stream_completed_allows_missing_output() -> anyhow::Result<()> {
|
||||
let lines = vec![
|
||||
r#"data: {"type":"response.created","sequence_number":1,"response":{"id":"resp_1","object":"response","created_at":1737368310,"status":"in_progress","model":"gpt-5.2-pro","output":[]}}"#.to_string(),
|
||||
r#"data: {"type":"response.output_text.delta","sequence_number":2,"item_id":"msg_1","output_index":0,"content_index":0,"delta":"Hello"}"#.to_string(),
|
||||
r#"data: {"type":"response.output_text.delta","sequence_number":3,"item_id":"msg_1","output_index":0,"content_index":0,"delta":" world"}"#.to_string(),
|
||||
r#"data: {"type":"response.completed","sequence_number":4,"response":{"id":"resp_1","object":"response","created_at":1737368310,"status":"completed","model":"gpt-5.2-pro","usage":{"input_tokens":10,"output_tokens":4,"total_tokens":14}}}"#.to_string(),
|
||||
"data: [DONE]".to_string(),
|
||||
];
|
||||
|
||||
let response_stream = tokio_stream::iter(lines.into_iter().map(Ok));
|
||||
let messages = responses_api_to_streaming_message(response_stream);
|
||||
futures::pin_mut!(messages);
|
||||
|
||||
let mut text_parts = Vec::new();
|
||||
let mut usage: Option<ProviderUsage> = None;
|
||||
|
||||
while let Some(item) = messages.next().await {
|
||||
let (message, maybe_usage) = item?;
|
||||
if let Some(msg) = message {
|
||||
for content in msg.content {
|
||||
if let MessageContent::Text(text) = content {
|
||||
text_parts.push(text.text.clone());
|
||||
}
|
||||
}
|
||||
}
|
||||
if let Some(final_usage) = maybe_usage {
|
||||
usage = Some(final_usage);
|
||||
}
|
||||
}
|
||||
|
||||
assert_eq!(text_parts.concat(), "Hello world");
|
||||
let usage = usage.expect("usage should be present at completion");
|
||||
assert_eq!(usage.model, "gpt-5.2-pro");
|
||||
assert_eq!(usage.usage.input_tokens, Some(10));
|
||||
assert_eq!(usage.usage.output_tokens, Some(4));
|
||||
assert_eq!(usage.usage.total_tokens, Some(14));
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_responses_api_to_message_captures_reasoning_summary() -> anyhow::Result<()> {
|
||||
let response: ResponsesApiResponse = serde_json::from_value(serde_json::json!({
|
||||
|
||||
Reference in New Issue
Block a user