use axum::response::sse::{Event, KeepAlive};
use axum::response::{IntoResponse, Response, Sse};
use futures::StreamExt;
use super::translator::*;
pub(super) fn anthropic_sse_from_deltas(
deltas: crate::ir::DeltaStream,
req_model: String,
dump: Option<(u64, crate::request_dumper::DumpHandle)>,
) -> Response {
let (tx, rx) = tokio::sync::mpsc::channel::<Result<Event, std::convert::Infallible>>(1024);
tokio::spawn(async move {
let mut translator = AnthropicTranslator::new(req_model);
let mut pending: Vec<SseEvent> = Vec::new();
let mut deltas = deltas;
let mut captured: Option<Vec<serde_json::Value>> = dump.as_ref().map(|_| Vec::new());
async fn flush(
tx: &tokio::sync::mpsc::Sender<Result<Event, std::convert::Infallible>>,
pending: &mut Vec<SseEvent>,
captured: &mut Option<Vec<serde_json::Value>>,
) -> bool {
for ev in pending.drain(..) {
if let Some(events) = captured {
events.push(serde_json::json!({"event": ev.event, "data": ev.data}));
}
if tx.send(Ok(ev.to_axum_event())).await.is_err() {
return false;
}
}
true
}
let mut aborted = false;
while let Some(delta) = deltas.next().await {
translator.on_delta(&delta, &mut pending);
if !flush(&tx, &mut pending, &mut captured).await {
aborted = true;
break;
}
}
if !aborted {
translator.finalize(&mut pending);
if !flush(&tx, &mut pending, &mut captured).await {
tracing::warn!("anthropic stream: final flush failed (receiver dropped)");
}
}
if let (Some((seq, writer)), Some(events)) = (dump, captured) {
writer.dump_response("/v1/messages", seq, &events, true);
}
});
let stream = tokio_stream::wrappers::ReceiverStream::new(rx);
Sse::new(stream)
.keep_alive(KeepAlive::default())
.into_response()
}