diff --git a/crates/switchyard-translation/src/helpers.rs b/crates/switchyard-translation/src/helpers.rs index f1fc7c32..3be925cf 100644 --- a/crates/switchyard-translation/src/helpers.rs +++ b/crates/switchyard-translation/src/helpers.rs @@ -582,6 +582,17 @@ mod tests { Ok(()) } + #[test] + fn decode_stream_accepts_sse_data_without_optional_space() -> Result<(), LlmClientError> { + let sse = b"data:{\"choices\":[{\"delta\":{\"content\":\"Hello\"}}]}\n\n\ + data:[DONE]\n\n" + .to_vec(); + let bytes = stream::once(async move { Ok::, LlmClientError>(sse) }); + let chunks = decode_all(bytes, WireFormat::OpenAiChat)?; + assert_eq!(text_of(&chunks), "Hello"); + Ok(()) + } + #[test] fn stream_helpers_replay_same_format_provider_fields() -> Result<(), BoxError> { let provider_event = json!({ diff --git a/crates/switchyard-translation/src/sse.rs b/crates/switchyard-translation/src/sse.rs index dce5a361..08b8045a 100644 --- a/crates/switchyard-translation/src/sse.rs +++ b/crates/switchyard-translation/src/sse.rs @@ -36,7 +36,10 @@ pub(crate) fn parse_json_sse_frame( let data = frame .lines() .filter(|line| !line.is_empty() && !line.starts_with(':')) - .filter_map(|line| line.strip_prefix("data: ").map(|l| l.to_string())) + .filter_map(|line| { + line.strip_prefix("data:") + .map(|value| value.strip_prefix(' ').unwrap_or(value).to_string()) + }) .fold(String::new(), |mut a, b| { a.reserve(b.len() + 1); a.push_str(&b);