use crate::model::{
FinishReason,
response::{Choice, CompletionMeta, Delta},
tool::ToolCall,
};
use serde::Deserialize;
#[derive(Debug, Clone, Deserialize, Default)]
pub struct StreamChunk {
#[serde(flatten)]
pub meta: CompletionMeta,
pub choices: Vec<Choice>,
pub usage: Option<crate::model::Usage>,
}
impl StreamChunk {
pub fn tool(calls: &[ToolCall]) -> Self {
Self {
choices: vec![Choice {
delta: Delta {
tool_calls: Some(calls.to_vec()),
..Default::default()
},
..Default::default()
}],
..Default::default()
}
}
pub fn text(content: String) -> Self {
Self {
choices: vec![Choice {
delta: Delta {
content: Some(content),
..Default::default()
},
..Default::default()
}],
..Default::default()
}
}
pub fn separator() -> Self {
Self {
choices: vec![Choice {
delta: Delta {
content: Some("\n".into()),
..Default::default()
},
..Default::default()
}],
..Default::default()
}
}
pub fn content(&self) -> Option<&str> {
self.choices
.first()
.and_then(|c| c.delta.content.as_deref())
.filter(|s| !s.is_empty())
}
pub fn reasoning_content(&self) -> Option<&str> {
self.choices
.first()
.and_then(|c| c.delta.reasoning_content.as_deref())
.filter(|s| !s.is_empty())
}
pub fn tool_calls(&self) -> Option<&[ToolCall]> {
self.choices
.first()
.and_then(|choice| choice.delta.tool_calls.as_deref())
}
pub fn reason(&self) -> Option<&FinishReason> {
self.choices
.first()
.and_then(|choice| choice.finish_reason.as_ref())
}
}