Skip to main content

gglib_core/ports/
mod.rs

1#![doc = include_str!("README.md")]
2pub(crate) mod agent;
3pub(crate) mod benchmark;
4pub mod chat_history;
5pub(crate) mod download;
6pub(crate) mod download_manager;
7pub(crate) mod event_emitter;
8pub(crate) mod gguf_parser;
9pub mod huggingface;
10pub(crate) mod llm_completion;
11pub(crate) mod loop_guard_trips;
12pub(crate) mod mcp_dto;
13pub(crate) mod mcp_error;
14pub(crate) mod mcp_repository;
15pub mod model_catalog;
16pub(crate) mod model_registrar;
17pub(crate) mod model_repository;
18pub mod model_runtime;
19pub(crate) mod process_runner;
20pub(crate) mod remote_gateway;
21pub(crate) mod retry_observer;
22pub(crate) mod server_health;
23pub(crate) mod server_log_sink;
24pub(crate) mod settings_repository;
25pub(crate) mod system_probe;
26pub(crate) mod tool_executor_filter;
27pub(crate) mod tool_support;
28pub(crate) mod usage_sink;
29
30use std::sync::Arc;
31use thiserror::Error;
32
33// Re-export agent port types for convenience
34pub use agent::{AgentError, AgentLoopPort, AgentRunOutput, ToolExecutorPort};
35// Re-export LLM completion port (LlmStreamEvent lives in domain::agent)
36pub use llm_completion::LlmCompletionPort;
37pub use loop_guard_trips::{LoopGuardTripLog, LoopGuardTripSink};
38// Re-export tool-executor filter decorators
39pub use tool_executor_filter::{EmptyToolExecutor, FilteredToolExecutor, TOOL_NOT_AVAILABLE_MSG};
40
41// Re-export repository traits for convenience
42pub use benchmark::BenchmarkRepositoryPort;
43pub use chat_history::{ChatHistoryError, ChatHistoryRepository};
44pub use download::{QuantizationResolver, Resolution, ResolvedFile};
45pub use download_manager::{DownloadManagerConfig, DownloadManagerPort, DownloadRequest};
46pub use event_emitter::{AppEventEmitter, NoopEmitter};
47pub use gguf_parser::{
48    GgufCapabilities, GgufMetadata, GgufParseError, GgufParserPort, NoopGgufParser,
49};
50pub use huggingface::{
51    HfClientPort, HfFileInfo, HfPortError, HfQuantInfo, HfRepoInfo, HfSearchOptions, HfSearchResult,
52};
53pub use mcp_dto::{ResolutionAttempt, ResolutionStatus};
54pub use mcp_error::McpServiceError;
55pub use mcp_repository::{McpRepositoryError, McpServerRepository};
56pub use model_catalog::{CatalogError, ModelCatalogPort, ModelLaunchSpec, ModelSummary};
57pub use model_registrar::{CompletedDownload, ModelRegistrarPort};
58pub use model_repository::ModelRepository;
59pub use model_runtime::{
60    Admission, AdmissionLease, AdmissionRelease, LaunchOverrides, ModelRuntimeError,
61    ModelRuntimePort, NoopModelRuntime, PinnedSpec, RunningTarget, RuntimeErrorEnvelope,
62};
63pub use process_runner::{JinjaMode, ProcessHandle, ServerConfig};
64pub use remote_gateway::RemoteGatewayPort;
65pub use retry_observer::RetryObserver;
66pub use server_health::ServerHealthStatus;
67pub use server_log_sink::ServerLogSinkPort;
68pub use settings_repository::{SettingsChange, SettingsRepository};
69pub use system_probe::SystemProbePort;
70pub use tool_support::{
71    ModelSource, ToolFormat, ToolSupportDetection, ToolSupportDetectionInput,
72    ToolSupportDetectorPort,
73};
74pub use usage_sink::UsageSink;
75
76/// Container for all repository trait objects.
77///
78/// This struct provides a consistent way to wire repositories across adapters
79/// without coupling them to concrete implementations. It lives in `gglib-core`
80/// so that `AppCore` can accept it without depending on `gglib-db`.
81///
82/// # Example
83///
84/// ```ignore
85/// // In gglib-db factory:
86/// pub fn build_repos(pool: &SqlitePool) -> Repos { ... }
87///
88/// // In adapter bootstrap:
89/// let repos = gglib_db::factory::build_repos(&pool);
90/// let core = AppCore::new(repos);
91/// ```
92#[derive(Clone)]
93pub struct Repos {
94    /// Model repository for CRUD operations on models.
95    pub models: Arc<dyn ModelRepository>,
96    /// Settings repository for application settings.
97    pub settings: Arc<dyn SettingsRepository>,
98    /// MCP server repository for MCP server configurations.
99    pub mcp_servers: Arc<dyn McpServerRepository>,
100    /// Chat history repository for conversations and messages.
101    pub chat_history: Arc<dyn ChatHistoryRepository>,
102}
103
104impl Repos {
105    /// Create a new Repos container.
106    pub fn new(
107        models: Arc<dyn ModelRepository>,
108        settings: Arc<dyn SettingsRepository>,
109        mcp_servers: Arc<dyn McpServerRepository>,
110        chat_history: Arc<dyn ChatHistoryRepository>,
111    ) -> Self {
112        Self {
113            models,
114            settings,
115            mcp_servers,
116            chat_history,
117        }
118    }
119}
120
121/// Domain-specific errors for repository operations.
122///
123/// This error type abstracts away storage implementation details (e.g., sqlx errors)
124/// and provides a clean interface for services to handle storage failures.
125#[derive(Debug, Error)]
126pub enum RepositoryError {
127    /// The requested entity was not found.
128    #[error("Not found: {0}")]
129    NotFound(String),
130
131    /// An entity with the same identifier already exists.
132    #[error("Already exists: {0}")]
133    AlreadyExists(String),
134
135    /// Storage backend error (database, filesystem, etc.).
136    #[error("Storage error: {0}")]
137    Storage(String),
138
139    /// Serialization or deserialization failed.
140    #[error("Serialization error: {0}")]
141    Serialization(String),
142
143    /// A constraint was violated (e.g., foreign key, unique constraint).
144    #[error("Constraint violation: {0}")]
145    Constraint(String),
146}
147
148/// Core error type for semantic domain errors.
149///
150/// This is the canonical error type used across the core domain.
151/// Adapters should map this to their own error types (HTTP status codes,
152/// CLI exit codes, Tauri serialized errors).
153#[derive(Debug, Error)]
154pub enum CoreError {
155    /// Repository operation failed.
156    #[error(transparent)]
157    Repository(#[from] RepositoryError),
158
159    /// Settings validation error.
160    #[error(transparent)]
161    Settings(#[from] crate::settings::SettingsError),
162
163    /// Validation error (invalid input).
164    #[error("Validation error: {0}")]
165    Validation(String),
166}