use std::{
fmt,
pin::Pin,
task::{Context, Poll},
};
use async_trait::async_trait;
use futures_core::Stream;
use crate::{
error::{BackendError, Capability, CapabilityError},
types::{balance::BalanceSnapshot, chat::ChatCompletionChunk, model::ModelCatalogResponse},
};
#[must_use = "streams are lazy; call .next() to drive them"]
pub struct ChatCompletionStream {
inner: Pin<
Box<
dyn Stream<Item = Result<ChatCompletionChunk, just_common::error::TransportError>>
+ Send,
>,
>,
}
impl ChatCompletionStream {
pub fn new(
inner: Pin<
Box<
dyn Stream<Item = Result<ChatCompletionChunk, just_common::error::TransportError>>
+ Send,
>,
>,
) -> Self {
Self { inner }
}
}
impl fmt::Debug for ChatCompletionStream {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("ChatCompletionStream")
.finish_non_exhaustive()
}
}
impl Stream for ChatCompletionStream {
type Item = Result<ChatCompletionChunk, just_common::error::TransportError>;
fn poll_next(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<Self::Item>> {
self.inner.as_mut().poll_next(cx)
}
}
pub trait Identifiable: Send + Sync {
fn family(&self) -> &'static str;
}
#[async_trait]
pub trait ModelCatalog: Identifiable {
async fn list_models(&self) -> Result<ModelCatalogResponse, BackendError>;
}
#[async_trait]
pub trait Balance: Identifiable {
async fn get_balance(&self) -> Result<BalanceSnapshot, BackendError>;
}
pub trait CapabilityNegotiation: Identifiable {
fn model_catalog(&self) -> Result<&dyn ModelCatalog, CapabilityError> {
Err(CapabilityError::unsupported(
self.family(),
Capability::ModelCatalog,
))
}
fn balance(&self) -> Result<&dyn Balance, CapabilityError> {
Err(CapabilityError::unsupported(
self.family(),
Capability::Balance,
))
}
}