use alloc::borrow::ToOwned;
use alloc::collections::BTreeMap;
use alloc::string::String;
#[derive(Debug, Clone, Default, PartialEq, Eq)]
pub struct ToolCall {
pub id: Option<String>,
pub name: Option<String>,
pub arguments: String,
}
#[derive(Debug, Clone, Default, PartialEq, Eq)]
pub struct Choice {
pub role: Option<String>,
pub content: String,
pub tool_calls: BTreeMap<usize, ToolCall>,
pub finish_reason: Option<String>,
}
#[derive(Debug, Default)]
pub struct OpenAiAccumulator {
choices: BTreeMap<usize, Choice>,
}
impl OpenAiAccumulator {
#[must_use]
pub fn new() -> Self {
Self::default()
}
pub fn push_role(&mut self, index: usize, role: &str) {
let choice = self.choice_mut(index);
if choice.role.is_none() {
choice.role = Some(role.to_owned());
}
}
pub fn push_content(&mut self, index: usize, fragment: &str) {
self.choice_mut(index).content.push_str(fragment);
}
pub fn set_finish_reason(&mut self, index: usize, reason: &str) {
self.choice_mut(index).finish_reason = Some(reason.to_owned());
}
pub fn push_tool_call(
&mut self,
index: usize,
tool_index: usize,
id: Option<&str>,
name: Option<&str>,
arguments: Option<&str>,
) {
let choice = self.choice_mut(index);
let tc = choice.tool_calls.entry(tool_index).or_default();
if let Some(id) = id {
if tc.id.is_none() {
tc.id = Some(id.to_owned());
}
}
if let Some(name) = name {
if tc.name.is_none() {
tc.name = Some(name.to_owned());
}
}
if let Some(args) = arguments {
tc.arguments.push_str(args);
}
}
#[must_use]
pub fn choice(&self, index: usize) -> Option<&Choice> {
self.choices.get(&index)
}
pub fn choices(&self) -> impl Iterator<Item = (usize, &Choice)> {
self.choices.iter().map(|(&i, c)| (i, c))
}
fn choice_mut(&mut self, index: usize) -> &mut Choice {
self.choices.entry(index).or_default()
}
}