bitrouter 1.0.0-alpha.34

BitRouter: an LLM API router. CLI + assembly library.
Documentation
use bitrouter_ai::catalog::Catalog;
use bitrouter_ai::catalog::store::{CatalogSnapshot, CatalogStore, Durability, StoreError};
use bitrouter_ai::catalog::types::{CanonicalModel, RegistryData};
use bitrouter_sdk::config::DEFAULT_REGISTRY_URL;
use std::sync::Arc;

use super::{CachedPayload, DiskCache, TTL};

fn snapshot(id: &str) -> CatalogSnapshot {
    CatalogSnapshot {
        fetched_at: 0,
        data: RegistryData {
            providers: Vec::new(),
            canonical: vec![CanonicalModel {
                id: id.into(),
                ..Default::default()
            }],
        },
    }
}

#[test]
fn unbound_legacy_cache_is_preserved_without_guessing_its_source() -> anyhow::Result<()> {
    let dir = tempfile::tempdir()?;
    let path = dir.path().join("registry.json");
    std::fs::write(
        &path,
        serde_json::to_vec(&CachedPayload {
            source: None,
            snapshot: snapshot("old/model"),
        })?,
    )?;
    let original = std::fs::read(&path)?;
    let cache = Arc::new(DiskCache::at(&path));
    let mut public = Catalog::with_store(DEFAULT_REGISTRY_URL, cache.clone());
    public.load()?;
    assert!(public.snapshot().is_none());
    assert!(!public.is_fresh(TTL));
    let mut custom = Catalog::with_store("https://private.invalid/catalog", cache);
    custom.load()?;
    assert!(custom.snapshot().is_none());
    assert_eq!(std::fs::read(path)?, original);
    Ok(())
}

#[test]
fn persistent_snapshot_round_trip_is_bound_to_its_source() -> anyhow::Result<()> {
    let dir = tempfile::tempdir()?;
    let cache = DiskCache::at(dir.path().join("registry.json"));
    assert!(cache.load("https://first.invalid")?.is_none());
    assert_eq!(
        cache.save("https://first.invalid/", &snapshot("first/model"))?,
        Durability::Persistent
    );
    assert_eq!(
        cache
            .load("https://first.invalid")?
            .ok_or_else(|| anyhow::anyhow!("missing persisted snapshot"))?
            .data
            .canonical[0]
            .id,
        "first/model"
    );
    assert!(cache.load("https://second.invalid")?.is_none());
    assert!(cache.load(DEFAULT_REGISTRY_URL)?.is_none());
    Ok(())
}

#[test]
fn corrupt_cache_is_an_explicit_error_and_failed_save_preserves_previous_file() -> anyhow::Result<()>
{
    let dir = tempfile::tempdir()?;
    let path = dir.path().join("registry.json");
    let cache = DiskCache::at(&path);
    std::fs::write(&path, b"not json")?;
    assert!(matches!(cache.load("source"), Err(StoreError::Invalid)));
    cache.save("source", &snapshot("old/model"))?;
    std::fs::create_dir(path.with_extension("json.tmp"))?;
    assert!(matches!(
        cache.save("source", &snapshot("new/model")),
        Err(StoreError::Unavailable)
    ));
    assert_eq!(
        cache
            .load("source")?
            .ok_or_else(|| anyhow::anyhow!("old snapshot lost"))?
            .data
            .canonical[0]
            .id,
        "old/model"
    );
    Ok(())
}

#[test]
fn bundled_credential_variables_are_available_without_any_cache_or_network() -> anyhow::Result<()> {
    let defaults = crate::bundled_registry::supplement(
        &bitrouter_sdk::config::RegistryConfig::default(),
        None,
    )?
    .ok_or_else(|| anyhow::anyhow!("missing baseline"))?;
    let variables = crate::providers::apply::zero_config_env_var_providers(Some(&defaults));
    for provider in defaults
        .providers
        .iter()
        .filter(|provider| provider.is_public())
    {
        if let Some(variable) = provider.env_credential_var() {
            assert!(variables.iter().any(|(_, value)| value == &variable));
        }
    }
    Ok(())
}

#[test]
fn reload_keeps_custom_source_credential_names_without_mixing_routing_catalogs()
-> anyhow::Result<()> {
    let dir = tempfile::tempdir()?;
    let path = dir.path().join("registry.json");
    let cache = DiskCache::at(&path);
    let mut custom = snapshot("custom/model");
    custom
        .data
        .providers
        .push(serde_json::from_value(serde_json::json!({
            "name":"custom-source-provider", "status":"active",
            "auth":{"kind":"bearer", "env":"CUSTOM_CATALOG_KEY"}, "models":[]
        }))?);
    cache.save("https://custom.invalid/catalog", &custom)?;
    let variables = super::credential_variables(Some(DiskCache::at(&path)));
    assert!(
        variables
            .iter()
            .any(|(_, variable)| variable == "CUSTOM_CATALOG_KEY")
    );
    assert!(
        !super::credential_variables(None)
            .iter()
            .any(|(_, variable)| variable == "CUSTOM_CATALOG_KEY")
    );
    let mut public = Catalog::with_store(DEFAULT_REGISTRY_URL, Arc::new(cache));
    public.load()?;
    assert!(public.snapshot().is_none());
    Ok(())
}

#[test]
fn retired_catalog_cache_is_quarantined_without_rewriting_saved_bytes() -> anyhow::Result<()> {
    let directory = tempfile::tempdir()?;
    let path = directory.path().join("registry.json");
    let bytes = serde_json::to_vec(
        &serde_json::json!({"source":DEFAULT_REGISTRY_URL,"fetched_at":1,"data":{"canonical":[{"id":"org/chat"}],"providers":[
            {"name":"google-ai","status":"active","models":[{"api_protocol":"antigravity"}]},
            {"name":"fixture","status":"active","models":[{"id":"org/chat","provider_model_id":"chat","api_protocol":"openai"}]}
        ]}}),
    )?;
    std::fs::write(&path, &bytes)?;
    let loaded = DiskCache::at(&path)
        .load(DEFAULT_REGISTRY_URL)?
        .ok_or_else(|| anyhow::anyhow!("cache unavailable"))?;
    assert_eq!(loaded.data.providers.len(), 1);
    assert_eq!(loaded.data.providers[0].name, "fixture");
    assert_eq!(std::fs::read(&path)?, bytes);
    Ok(())
}