use crate::error::{EncodeError, ProviderError};
use crate::model::{ModelInfo, ModelList};
use crate::operation::{ModelListing, ModelPage};
use crate::wire::{
Body, Decoder, Descriptor, Encoded, Flow, Framing, Mode, Out, Wire, WireEvent, WireFrame,
};
use serde::{Deserialize, Serialize};
use super::{OllamaConfig, PROVIDER_NAME};
#[derive(Debug, Deserialize)]
pub struct ListModelsResponse {
pub models: Vec<ListModelEntry>,
}
#[derive(Debug, Deserialize)]
pub struct ListModelEntry {
pub name: String,
pub model: String,
}
impl From<ListModelEntry> for ModelInfo {
fn from(value: ListModelEntry) -> Self {
ModelInfo::new(value.model, value.name)
}
}
impl OllamaConfig {
pub(crate) fn models(&self) -> Models {
Models {
provider: self.clone(),
}
}
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct Models {
pub provider: OllamaConfig,
}
impl Wire for Models {
type Op = ModelListing;
type Payload = crate::wire::Encoded;
type Frame = crate::wire::WireFrame;
type Decoder<'id> = ModelsDecoder;
type Reassembler = crate::wire::document::Unreassembled;
fn describe(&self) -> Descriptor<'_> {
Descriptor::new(PROVIDER_NAME)
}
fn encode(&self, _cursor: Option<String>, _mode: Mode) -> Result<Encoded, EncodeError> {
let request = self
.provider
.request(http::Method::GET, "/api/tags")
.body(Body::empty())?;
Ok(Encoded::new(request, Framing::Whole))
}
fn decoder<'id>(&self) -> Self::Decoder<'id> {
ModelsDecoder
}
}
pub struct ModelsDecoder;
impl<'id> Decoder<'id, ModelListing> for ModelsDecoder {
type Event = ListModelsResponse;
fn classify(&self, frame: WireFrame) -> WireEvent<Self::Event> {
crate::providers::internal::wire::classify_marker_keyed_frame(&frame.as_str(), &["models"])
}
fn decode(
&mut self,
reply: Self::Event,
out: Out<'id, ModelListing>,
) -> Result<Flow, ProviderError> {
Ok(out.end(ModelPage {
models: ModelList::new(reply.models.into_iter().map(ModelInfo::from).collect()),
next: None,
}))
}
}
#[cfg(test)]
mod tests;