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 crate::domain::Model;
13use crate::download::Quantization;
14
15/// Information about a completed download for model registration.
16///
17/// This is a pure data transfer object containing all information
18/// needed to register a model after download completes.
19#[derive(Debug, Clone)]
20pub struct CompletedDownload {
21    /// Path to the primary downloaded file (first shard for sharded models).
22    pub primary_path: std::path::PathBuf,
23    /// All downloaded file paths (multiple for sharded models).
24    pub all_paths: Vec<std::path::PathBuf>,
25    /// The resolved quantization.
26    pub quantization: Quantization,
27    /// Repository ID (e.g., "unsloth/Llama-3-GGUF").
28    pub repo_id: String,
29    /// Commit SHA at time of download.
30    pub commit_sha: String,
31    /// Whether this was a sharded download.
32    pub is_sharded: bool,
33    /// Total bytes downloaded.
34    pub total_bytes: u64,
35    /// Ordered list of all file paths for sharded models (None for single-file models).
36    pub file_paths: Option<Vec<std::path::PathBuf>>,
37}
38
39impl CompletedDownload {
40    /// Get the primary file path for database registration.
41    ///
42    /// For sharded models, this returns the first shard path
43    /// (required by llama-server for loading split models).
44    pub fn db_path(&self) -> &Path {
45        &self.primary_path
46    }
47}
48
49/// Port for registering downloaded models in the database.
50///
51/// This trait is implemented by core services and injected into
52/// the download manager, allowing model registration without
53/// coupling to `AppCore` directly.
54///
55/// # Usage
56///
57/// ```ignore
58/// let registrar: Arc<dyn ModelRegistrarPort> = /* ... */;
59/// let download = CompletedDownload { ... };
60/// let model = registrar.register_model(&download).await?;
61/// ```
62#[async_trait]
63pub trait ModelRegistrarPort: Send + Sync {
64    /// Register a downloaded model in the database.
65    ///
66    /// Parses GGUF metadata from the downloaded file and creates a database entry.
67    /// For sharded models, the primary (first shard) path is used for registration.
68    ///
69    /// # Arguments
70    ///
71    /// * `download` - The completed download information
72    ///
73    /// # Returns
74    ///
75    /// Returns the created `Model` on success.
76    async fn register_model(&self, download: &CompletedDownload) -> Result<Model, RepositoryError>;
77
78    /// Register a model using raw path parameters.
79    ///
80    /// This is a simpler interface for cases where you have the file path
81    /// but not the full download metadata.
82    ///
83    /// # Arguments
84    ///
85    /// * `repo_id` - `HuggingFace` repository ID
86    /// * `commit_sha` - Git commit SHA
87    /// * `file_path` - Path to the GGUF file
88    /// * `quantization` - Quantization type as string
89    ///
90    /// # Returns
91    ///
92    /// Returns the created `Model` on success.
93    async fn register_model_from_path(
94        &self,
95        repo_id: &str,
96        commit_sha: &str,
97        file_path: &Path,
98        quantization: &str,
99    ) -> Result<Model, RepositoryError>;
100}