use anyhow::Result;
use async_trait::async_trait;
use tokio::sync::mpsc;
use tokio_util::sync::CancellationToken;
use super::stream::ApiEvent;
use super::types::{Message, ToolDefinition};
pub struct ProviderStream {
rx: mpsc::Receiver<ApiEvent>,
cancel: CancellationToken,
}
impl ProviderStream {
pub(crate) fn new(rx: mpsc::Receiver<ApiEvent>, cancel: CancellationToken) -> Self {
Self { rx, cancel }
}
pub async fn recv(&mut self) -> Option<ApiEvent> {
self.rx.recv().await
}
}
impl Drop for ProviderStream {
fn drop(&mut self) {
self.cancel.cancel();
}
}
#[async_trait]
pub trait Provider: Send + Sync {
fn name(&self) -> &str;
fn model(&self) -> &str;
fn set_model(&mut self, model: &str);
async fn stream(
&self,
messages: &[Message],
system: &str,
tools: &[ToolDefinition],
max_tokens: u32,
cancel: CancellationToken,
) -> Result<ProviderStream>;
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn dropping_provider_stream_cancels_its_reader() {
let (_tx, rx) = mpsc::channel(1);
let cancel = CancellationToken::new();
let stream = ProviderStream::new(rx, cancel.clone());
drop(stream);
assert!(cancel.is_cancelled());
}
}