synth-ai-core 0.3.0

Rust core for Synth AI SDKs - API client, streaming, tracing, and tunnels
Documentation
use crate::data::{Artifact, ContextOverride};
use crate::errors::CoreError;
use serde_json::Value;

pub const MAX_INLINE_ARTIFACT_BYTES: usize = 64 * 1024;
pub const MAX_TOTAL_INLINE_ARTIFACTS_BYTES: usize = 256 * 1024;
pub const MAX_ARTIFACTS_PER_ROLLOUT: usize = 10;
pub const MAX_ARTIFACT_METADATA_BYTES: usize = 16 * 1024;
pub const MAX_ARTIFACT_CONTENT_TYPE_LENGTH: usize = 128;
pub const MAX_CONTEXT_SNAPSHOT_BYTES: usize = 1 * 1024 * 1024;
pub const MAX_CONTEXT_OVERRIDES_PER_ROLLOUT: usize = 20;

pub fn validate_artifact_size(artifact: &Artifact, max_bytes: usize) -> Result<(), CoreError> {
    artifact
        .validate_size(max_bytes as i64)
        .map_err(CoreError::InvalidInput)
}

pub fn validate_artifacts_list(artifacts: &[Artifact]) -> Result<(), CoreError> {
    if artifacts.len() > MAX_ARTIFACTS_PER_ROLLOUT {
        return Err(CoreError::InvalidInput(format!(
            "Too many artifacts: {} > {}",
            artifacts.len(),
            MAX_ARTIFACTS_PER_ROLLOUT
        )));
    }

    let mut total_size = 0usize;

    for artifact in artifacts {
        let size = match &artifact.content {
            crate::data::ArtifactContent::Text(text) => text.as_bytes().len(),
            crate::data::ArtifactContent::Structured(map) => {
                serde_json::to_string(map).map(|s| s.len()).unwrap_or(0)
            }
        };
        total_size += size;

        if let Some(content_type) = &artifact.content_type {
            if content_type.len() > MAX_ARTIFACT_CONTENT_TYPE_LENGTH {
                return Err(CoreError::InvalidInput(format!(
                    "Artifact content_type too long: {} > {}",
                    content_type.len(),
                    MAX_ARTIFACT_CONTENT_TYPE_LENGTH
                )));
            }
        }

        if !artifact.metadata.is_empty() {
            let metadata_size = serde_json::to_string(&artifact.metadata)
                .map(|s| s.len())
                .unwrap_or(0);
            if metadata_size > MAX_ARTIFACT_METADATA_BYTES {
                return Err(CoreError::InvalidInput(format!(
                    "Artifact metadata too large: {} > {}",
                    metadata_size, MAX_ARTIFACT_METADATA_BYTES
                )));
            }
        }
    }

    if total_size > MAX_TOTAL_INLINE_ARTIFACTS_BYTES {
        return Err(CoreError::InvalidInput(format!(
            "Total artifacts size {} exceeds {} bytes",
            total_size, MAX_TOTAL_INLINE_ARTIFACTS_BYTES
        )));
    }

    Ok(())
}

pub fn validate_context_overrides(overrides: &[ContextOverride]) -> Result<(), CoreError> {
    if overrides.len() > MAX_CONTEXT_OVERRIDES_PER_ROLLOUT {
        return Err(CoreError::InvalidInput(format!(
            "Too many context overrides: {} > {}",
            overrides.len(),
            MAX_CONTEXT_OVERRIDES_PER_ROLLOUT
        )));
    }

    let mut total_size = 0usize;
    let mut total_files = 0usize;
    for override_item in overrides {
        total_size += override_item.size_bytes();
        total_files += override_item.file_artifacts.len();
    }

    if total_size > MAX_CONTEXT_SNAPSHOT_BYTES {
        return Err(CoreError::InvalidInput(format!(
            "Total context override size {} exceeds {} bytes",
            total_size, MAX_CONTEXT_SNAPSHOT_BYTES
        )));
    }

    let max_files = 50usize;
    if total_files > max_files {
        return Err(CoreError::InvalidInput(format!(
            "Too many file artifacts across overrides: {} > {}",
            total_files, max_files
        )));
    }

    Ok(())
}

pub fn validate_context_snapshot(snapshot_data: &Value) -> Result<(), CoreError> {
    let size = serde_json::to_string(snapshot_data)
        .map(|s| s.len())
        .unwrap_or(0);
    if size > MAX_CONTEXT_SNAPSHOT_BYTES {
        return Err(CoreError::InvalidInput(format!(
            "Context snapshot size {} exceeds {} bytes",
            size, MAX_CONTEXT_SNAPSHOT_BYTES
        )));
    }
    Ok(())
}