seasoning 0.1.4

Embedding and reranking infrastructure with rate limiting and retry logic
Documentation
use reqwest::StatusCode;

#[derive(Debug, thiserror::Error)]
pub enum Error {
    #[error("invalid api key header value: {0}")]
    InvalidApiKeyHeaderValue(#[source] http::header::InvalidHeaderValue),

    #[error("http client build failed: {0}")]
    HttpClientBuild(#[source] reqwest::Error),

    #[error("request failed: {0}")]
    Request(#[source] reqwest::Error),

    #[error("response body read failed: {0}")]
    ResponseBody(#[source] reqwest::Error),

    #[error(transparent)]
    ResponseJson(#[from] reqwest::Error),

    #[error("request json encode failed: {0}")]
    JsonEncode(#[source] serde_json::Error),

    #[error("response json decode failed: {0}")]
    JsonDecode(#[source] serde_json::Error),

    #[error("rate limiter semaphore closed")]
    SemaphoreClosed,

    #[error("embedder batch channel closed")]
    BatchChannelClosed,

    #[error("rerank query cannot be empty")]
    EmptyRerankQuery,

    #[error("provider dialect '{value}' is invalid (expected: openai|deepinfra|llamacpp)")]
    InvalidProviderDialect { value: String },

    #[error("model family '{value}' is invalid (expected: gemma|qwen3)")]
    InvalidModelFamily { value: String },

    #[error("dialect '{dialect}' requires the `local` feature")]
    LocalFeatureRequired { dialect: String },

    #[error("unsupported configuration: {message}")]
    UnsupportedConfiguration { message: String },

    #[error("invalid configuration: {message}")]
    InvalidConfiguration { message: String },

    #[error("unsupported local model '{model}' for {kind}")]
    UnsupportedLocalModel { kind: &'static str, model: String },

    #[error("local runtime failed: {message}")]
    LocalRuntime { message: String },

    #[error("local runtime channel closed unexpectedly")]
    LocalRuntimeChannelClosed,

    #[error("prepared embedding input token ids cannot be empty")]
    EmptyPreparedEmbeddingInput,

    #[error(
        "embedding input at index {index} contains token id {token_id} that does not fit in i32"
    )]
    InvalidEmbeddingTokenId { index: usize, token_id: u32 },

    #[error("api request failed with status {status}")]
    ApiStatus {
        status: StatusCode,
        body: Option<String>,
    },

    #[error("embedder returned {embeddings} embeddings for {inputs} inputs")]
    EmbeddingCountMismatch { embeddings: usize, inputs: usize },

    #[error("embedder returned an invalid embedding index {index} for {inputs} inputs")]
    InvalidEmbeddingIndex { index: usize, inputs: usize },

    #[error("reranker returned {scores} scores for {inputs} inputs")]
    RerankScoreCountMismatch { scores: usize, inputs: usize },

    #[error("reranker returned an invalid score index {index} for {inputs} inputs")]
    InvalidRerankScoreIndex { index: usize, inputs: usize },
}

pub type Result<T> = std::result::Result<T, Error>;