Skip to main content

gglib_core/ports/
model_registrar.rs

1//! Model registrar port definition.
2//!
3//! This port defines the interface for registering downloaded models
4//! in the database. It breaks the circular dependency between download
5//! and core services by allowing the download crate to depend on a trait
6//! rather than concrete `AppCore`.
7
8use async_trait::async_trait;
9use std::path::Path;
10
11use super::RepositoryError;
12use super::download::ResolvedFile;
13use crate::domain::Model;
14use crate::download::Quantization;
15
16/// Information about a completed download for model registration.
17///
18/// This is a pure data transfer object containing all information
19/// needed to register a model after download completes.
20#[derive(Debug, Clone)]
21pub struct CompletedDownload {
22    /// Path to the primary downloaded file (first shard for sharded models).
23    pub primary_path: std::path::PathBuf,
24    /// All downloaded file paths (multiple for sharded models).
25    pub all_paths: Vec<std::path::PathBuf>,
26    /// The resolved quantization.
27    pub quantization: Quantization,
28    /// Repository ID (e.g., "unsloth/Llama-3-GGUF").
29    pub repo_id: String,
30    /// Commit SHA at time of download.
31    pub commit_sha: String,
32    /// Whether this was a sharded download.
33    pub is_sharded: bool,
34    /// Ordered list of all file paths for sharded models (None for single-file models).
35    pub file_paths: Option<Vec<std::path::PathBuf>>,
36    /// `HuggingFace` tags for the model.
37    pub hf_tags: Vec<String>,
38    /// File entries with OIDs from `HuggingFace` (for `model_files` table).
39    pub hf_file_entries: Vec<ResolvedFile>,
40}
41
42impl CompletedDownload {
43    /// Get the primary file path for database registration.
44    ///
45    /// For sharded models, this returns the first shard path
46    /// (required by llama-server for loading split models).
47    pub fn db_path(&self) -> &Path {
48        &self.primary_path
49    }
50}
51
52/// Port for registering downloaded models in the database.
53///
54/// This trait is implemented by core services and injected into
55/// the download manager, allowing model registration without
56/// coupling to `AppCore` directly.
57///
58/// # Usage
59///
60/// ```ignore
61/// let registrar: Arc<dyn ModelRegistrarPort> = /* ... */;
62/// let download = CompletedDownload { ... };
63/// let model = registrar.register_model(&download).await?;
64/// ```
65#[async_trait]
66pub trait ModelRegistrarPort: Send + Sync {
67    /// Register a downloaded model in the database.
68    ///
69    /// Parses GGUF metadata from the downloaded file and creates a database entry.
70    /// For sharded models, the primary (first shard) path is used for registration.
71    ///
72    /// # Arguments
73    ///
74    /// * `download` - The completed download information
75    ///
76    /// # Returns
77    ///
78    /// Returns the created `Model` on success.
79    async fn register_model(&self, download: &CompletedDownload) -> Result<Model, RepositoryError>;
80}