use serde::{Deserialize, Serialize};
use super::common::{Message, ModelDetails};
#[derive(Deserialize, Debug, Clone)]
#[non_exhaustive]
pub struct ListModelsResponse {
pub models: Vec<ModelInfo>,
}
#[derive(Deserialize, Debug, Clone)]
#[non_exhaustive]
pub struct ModelInfo {
pub name: String,
pub model: String,
pub modified_at: String,
pub size: u64,
pub digest: String,
pub details: ModelDetails,
}
#[derive(Serialize, Debug)]
pub struct ShowModelRequest {
pub model: String,
#[serde(skip_serializing_if = "Option::is_none")]
pub verbose: Option<bool>,
}
#[derive(Deserialize, Debug, Clone)]
#[non_exhaustive]
pub struct ShowModelResponse {
#[serde(default)]
pub modelfile: Option<String>,
#[serde(default)]
pub parameters: Option<String>,
#[serde(default)]
pub template: Option<String>,
#[serde(default)]
pub details: Option<ModelDetails>,
#[serde(default)]
pub model_info: Option<serde_json::Value>,
#[serde(default)]
pub capabilities: Option<Vec<String>>,
}
#[derive(Serialize, Debug)]
pub struct CopyModelRequest {
pub source: String,
pub destination: String,
}
#[derive(Serialize, Debug)]
pub struct DeleteModelRequest {
pub model: String,
}
#[derive(Serialize, Debug)]
pub struct PullModelRequest {
pub model: String,
#[serde(skip_serializing_if = "Option::is_none")]
pub insecure: Option<bool>,
#[serde(skip_serializing_if = "Option::is_none")]
pub stream: Option<bool>,
}
#[derive(Deserialize, Debug, Clone)]
#[non_exhaustive]
pub struct PullModelStatus {
pub status: String,
#[serde(default)]
pub digest: Option<String>,
#[serde(default)]
pub total: Option<u64>,
#[serde(default)]
pub completed: Option<u64>,
}
#[derive(Serialize, Debug)]
pub struct PushModelRequest {
pub model: String,
#[serde(skip_serializing_if = "Option::is_none")]
pub insecure: Option<bool>,
#[serde(skip_serializing_if = "Option::is_none")]
pub stream: Option<bool>,
}
#[derive(Deserialize, Debug, Clone)]
#[non_exhaustive]
pub struct PushModelStatus {
pub status: String,
#[serde(default)]
pub digest: Option<String>,
#[serde(default)]
pub total: Option<u64>,
#[serde(default)]
pub completed: Option<u64>,
}
#[derive(Serialize, Debug)]
pub struct CreateModelRequest {
pub model: String,
#[serde(skip_serializing_if = "Option::is_none")]
pub from: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub system: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub template: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub parameters: Option<serde_json::Value>,
#[serde(skip_serializing_if = "Option::is_none")]
pub quantize: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub license: Option<serde_json::Value>,
#[serde(skip_serializing_if = "Option::is_none")]
pub messages: Option<Vec<Message>>,
#[serde(skip_serializing_if = "Option::is_none")]
pub stream: Option<bool>,
}
#[derive(Deserialize, Debug, Clone)]
#[non_exhaustive]
pub struct CreateModelStatus {
pub status: String,
#[serde(default)]
pub digest: Option<String>,
#[serde(default)]
pub total: Option<u64>,
#[serde(default)]
pub completed: Option<u64>,
}
#[derive(Deserialize, Debug, Clone)]
#[non_exhaustive]
pub struct ListRunningResponse {
pub models: Vec<RunningModel>,
}
#[derive(Deserialize, Debug, Clone)]
#[non_exhaustive]
pub struct RunningModel {
pub name: String,
pub model: String,
pub size: u64,
pub digest: String,
pub details: ModelDetails,
#[serde(default)]
pub expires_at: Option<String>,
#[serde(default)]
pub size_vram: Option<u64>,
#[serde(default)]
pub context_length: Option<u64>,
}
#[derive(Deserialize, Debug, Clone)]
#[non_exhaustive]
pub struct VersionResponse {
pub version: String,
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn list_models_response_deserialization() {
let json = r#"{
"models": [{
"name": "gemma4:latest",
"model": "gemma4:latest",
"modified_at": "2025-01-01T00:00:00Z",
"size": 5000000000,
"digest": "abc123",
"details": {
"format": "gguf",
"family": "gemma",
"parameter_size": "9B",
"quantization_level": "Q4_K_M"
}
}]
}"#;
let resp: ListModelsResponse = serde_json::from_str(json).unwrap();
assert_eq!(resp.models.len(), 1);
assert_eq!(resp.models[0].name, "gemma4:latest");
assert_eq!(resp.models[0].details.family.as_deref(), Some("gemma"));
}
#[test]
fn pull_model_status_deserialization() {
let json = r#"{"status": "pulling manifest", "digest": "sha256:abc", "total": 1000, "completed": 500}"#;
let status: PullModelStatus = serde_json::from_str(json).unwrap();
assert_eq!(status.status, "pulling manifest");
assert_eq!(status.total, Some(1000));
assert_eq!(status.completed, Some(500));
}
#[test]
fn version_response_deserialization() {
let json = r#"{"version": "0.5.1"}"#;
let resp: VersionResponse = serde_json::from_str(json).unwrap();
assert_eq!(resp.version, "0.5.1");
}
}