systemprompt-traits 0.2.2

Trait-first interface contracts for systemprompt.io AI governance infrastructure. Repository, provider, and service abstractions shared across the MCP governance pipeline.
Documentation
use async_trait::async_trait;
use std::sync::Arc;
use systemprompt_identifiers::{ContextId, FileId, SessionId, TraceId, UserId};

pub type FileUploadResult<T> = Result<T, FileUploadProviderError>;

#[derive(Debug, thiserror::Error)]
#[non_exhaustive]
pub enum FileUploadProviderError {
    #[error("Upload disabled")]
    Disabled,

    #[error("Validation failed: {0}")]
    ValidationFailed(String),

    #[error("Storage error: {0}")]
    StorageError(String),

    #[error("Internal error: {0}")]
    Internal(String),
}

impl From<anyhow::Error> for FileUploadProviderError {
    fn from(err: anyhow::Error) -> Self {
        Self::Internal(err.to_string())
    }
}

#[derive(Debug, Clone)]
pub struct FileUploadInput {
    pub mime_type: String,
    pub bytes_base64: String,
    pub name: Option<String>,
    pub context_id: ContextId,
    pub user_id: Option<UserId>,
    pub session_id: Option<SessionId>,
    pub trace_id: Option<TraceId>,
}

impl FileUploadInput {
    #[must_use]
    pub fn new(
        mime_type: impl Into<String>,
        bytes_base64: impl Into<String>,
        context_id: ContextId,
    ) -> Self {
        Self {
            mime_type: mime_type.into(),
            bytes_base64: bytes_base64.into(),
            name: None,
            context_id,
            user_id: None,
            session_id: None,
            trace_id: None,
        }
    }

    #[must_use]
    pub fn with_name(mut self, name: impl Into<String>) -> Self {
        self.name = Some(name.into());
        self
    }

    #[must_use]
    pub fn with_user_id(mut self, user_id: UserId) -> Self {
        self.user_id = Some(user_id);
        self
    }

    #[must_use]
    pub fn with_session_id(mut self, session_id: SessionId) -> Self {
        self.session_id = Some(session_id);
        self
    }

    #[must_use]
    pub fn with_trace_id(mut self, trace_id: TraceId) -> Self {
        self.trace_id = Some(trace_id);
        self
    }
}

#[derive(Debug, Clone)]
pub struct UploadedFileInfo {
    pub file_id: FileId,
    pub public_url: String,
    pub size_bytes: Option<i64>,
}

#[async_trait]
pub trait FileUploadProvider: Send + Sync {
    fn is_enabled(&self) -> bool;

    async fn upload_file(&self, input: FileUploadInput) -> FileUploadResult<UploadedFileInfo>;
}

pub type DynFileUploadProvider = Arc<dyn FileUploadProvider>;