fix(ai-formats): ignore null stream errors

This commit is contained in:
elky
2026-06-10 18:44:46 +08:00
parent aa58cb4a05
commit ff7ec8575c
2 changed files with 41 additions and 2 deletions
@@ -111,10 +111,10 @@ pub fn canonical_usage_from_openai_usage(value: Option<&Value>) -> Option<Canoni
pub fn openai_stream_payload_is_terminal_error(payload: &Value) -> bool {
let response = payload.get("response").and_then(Value::as_object);
if payload.get("error").is_some()
if payload.get("error").is_some_and(|error| !error.is_null())
|| response
.and_then(|response| response.get("error"))
.is_some()
.is_some_and(|error| !error.is_null())
{
return true;
}
@@ -700,3 +700,38 @@ fn inclusive_total_tokens_from_usage(usage: &CanonicalUsage, input_tokens: u64)
input_tokens.saturating_add(usage.output_tokens)
}
}
#[cfg(test)]
mod tests {
use serde_json::json;
use super::{
openai_stream_payload_is_terminal_error, openai_stream_terminal_error_body,
openai_stream_terminal_error_message,
};
#[test]
fn completed_openai_responses_payload_with_null_error_is_not_terminal_error() {
let payload = json!({
"type": "response.completed",
"response": {
"id": "resp_123",
"object": "response",
"status": "completed",
"error": null,
"incomplete_details": null,
"output": [],
"usage": {
"input_tokens": 1,
"output_tokens": 2,
"total_tokens": 3
}
},
"error": null
});
assert!(!openai_stream_payload_is_terminal_error(&payload));
assert!(openai_stream_terminal_error_body(&payload).is_none());
assert!(openai_stream_terminal_error_message(&payload).is_none());
}
}
@@ -1500,6 +1500,8 @@ mod tests {
"object": "response",
"model": "gpt-5.5",
"status": "completed",
"error": null,
"incomplete_details": null,
"output": [],
"usage": {
"input_tokens": 26,
@@ -1522,6 +1524,8 @@ mod tests {
.latest_summary()
.cloned()
.expect("summary should exist");
assert!(summary.observed_finish);
assert_eq!(summary.parser_error, None);
let usage = summary
.standardized_usage
.expect("standardized usage should exist");