use std::collections::VecDeque;
use std::sync::Mutex;
use async_trait::async_trait;
use crate::event::{Event, EventSink};
use crate::output::ModelOutput;
use crate::provider::{ModelProvider, ProviderError};
use crate::request::ModelRequest;
pub struct MockProvider {
replies: Mutex<VecDeque<ModelOutput>>,
}
impl MockProvider {
pub fn new(replies: impl IntoIterator<Item = ModelOutput>) -> Self {
Self {
replies: Mutex::new(replies.into_iter().collect()),
}
}
pub fn push(&self, reply: ModelOutput) {
self.replies
.lock()
.unwrap_or_else(std::sync::PoisonError::into_inner)
.push_back(reply);
}
}
#[async_trait]
impl ModelProvider for MockProvider {
async fn complete(
&self,
_req: ModelRequest,
sink: &mut dyn EventSink,
) -> Result<ModelOutput, ProviderError> {
let mut replies = self
.replies
.lock()
.unwrap_or_else(std::sync::PoisonError::into_inner);
let out = replies.pop_front().ok_or(ProviderError::Exhausted)?;
drop(replies);
for content in &out.message.content {
match content {
crate::message::Content::Text(text) => sink.emit(Event::TextDelta(text)),
crate::message::Content::ToolCall(call) => {
sink.emit(Event::ToolCallStart {
id: &call.id,
name: &call.name,
});
sink.emit(Event::ToolCallArgsDelta {
id: &call.id,
delta: call.args.to_string().as_str(),
});
}
crate::message::Content::ToolResult(_) => {}
crate::message::Content::Image(_) => {}
}
}
Ok(out)
}
}