fix: tolerate missing responses output (#9449)

Signed-off-by: Angie Jones <jones.angie@gmail.com>
This commit is contained in:
Angie Jones
2026-05-27 13:05:00 -05:00
committed by GitHub
parent 27b41d93f5
commit d017295f32
@@ -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!({