use std::collections::{BTreeMap, BTreeSet, HashMap};
use crate::manifest::{GenerationDefaults, InferenceType, Manifest, ManifestFiles};
use crate::session::CeraError;
pub fn known_bundle_manifest(bundle_id: &str, quant: &str) -> Option<Manifest> {
let clean_id = bundle_id.strip_prefix("LiquidAI/").unwrap_or(bundle_id);
let clean_quant = quant.split(['+', ' ']).next().unwrap_or(quant).trim();
if clean_id == "LFM2.5-VL-3B-GGUF" {
let mmproj = if clean_quant == "F16" || clean_quant == "BF16" {
"https://huggingface.co/LiquidAI/LFM2.5-VL-3B-GGUF/resolve/main/mmproj-LFM2.5-VL-3B-F16.gguf"
} else {
"https://huggingface.co/LiquidAI/LFM2.5-VL-3B-GGUF/resolve/main/mmproj-LFM2.5-VL-3B-Q8_0.gguf"
};
let model = format!(
"https://huggingface.co/LiquidAI/LFM2.5-VL-3B-GGUF/resolve/main/LFM2.5-VL-3B-{clean_quant}.gguf"
);
Some(Manifest {
inference_type: InferenceType::LlamaCppImageToText,
schema_version: "1.0.0".to_string(),
files: ManifestFiles {
model,
multimodal_projector: Some(mmproj.to_string()),
audio_decoder: None,
audio_tokenizer: None,
draft_model: None,
extras: HashMap::new(),
},
chat_template: None,
generation_defaults: GenerationDefaults::Text {
temperature: Some(0.1),
min_p: Some(0.15),
top_p: None,
top_k: None,
repetition_penalty: Some(1.05),
},
raw: serde_json::Value::Null,
})
} else {
None
}
}
pub const LEAP_BUNDLES_API_URL: &str = "https://huggingface.co/api/models/LiquidAI/LeapBundles";
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct LeapBundleEntry {
pub name: String,
pub quants: Vec<String>,
}
pub fn cache_relative_segments(url: &str) -> Result<Vec<String>, CeraError> {
let (host, path) = split_url(url)?;
let host_segment = encode_host(host);
validate_path_segment("url host", &host_segment)?;
let path_no_qs = path
.trim_start_matches('/')
.split(['?', '#'])
.next()
.unwrap_or("");
if path_no_qs.is_empty() {
return Err(CeraError::Backend(format!(
"url `{url}` has no path component"
)));
}
let mut segments = Vec::with_capacity(1 + path_no_qs.matches('/').count());
segments.push(host_segment);
for segment in path_no_qs.split('/') {
validate_path_segment("url path segment", segment)?;
segments.push(segment.to_string());
}
Ok(segments)
}
pub fn leap_bundles_manifest_url(bundle_id: &str, quant: &str) -> Result<String, CeraError> {
let clean_id = bundle_id.strip_prefix("LiquidAI/").unwrap_or(bundle_id);
validate_path_segment("bundle_id", clean_id)?;
validate_path_segment("quant", quant)?;
Ok(format!(
"https://huggingface.co/LiquidAI/LeapBundles/resolve/main/{clean_id}/{quant}.json"
))
}
pub fn parse_leap_bundles(body: &str) -> Result<Vec<LeapBundleEntry>, CeraError> {
#[derive(serde::Deserialize)]
struct Sibling {
rfilename: String,
}
#[derive(serde::Deserialize)]
struct Resp {
siblings: Vec<Sibling>,
}
let resp: Resp = serde_json::from_str(body)
.map_err(|e| CeraError::Backend(format!("list-bundles JSON parse failed: {e}")))?;
let mut by_bundle: BTreeMap<String, BTreeSet<String>> = BTreeMap::new();
for sib in resp.siblings {
let Some((dir, file)) = sib.rfilename.split_once('/') else {
continue;
};
let Some(quant) = file.strip_suffix(".json") else {
continue;
};
if quant.contains('/') {
continue;
}
if validate_path_segment("bundle_id", dir).is_err()
|| validate_path_segment("quant", quant).is_err()
{
continue;
}
by_bundle
.entry(dir.to_string())
.or_default()
.insert(quant.to_string());
}
Ok(by_bundle
.into_iter()
.map(|(name, quants)| LeapBundleEntry {
name,
quants: quants.into_iter().collect(),
})
.collect())
}
fn encode_host(host: &str) -> String {
let lower = host.to_ascii_lowercase();
match lower.split_once(':') {
Some((name, port)) if !port.is_empty() && port.bytes().all(|b| b.is_ascii_digit()) => {
format!("{}_{port}", name.replace('_', "__"))
}
_ => lower.replace('_', "__"),
}
}
pub fn validate_path_segment(kind: &str, segment: &str) -> Result<(), CeraError> {
if segment.is_empty() {
return Err(CeraError::Backend(format!("{kind} must not be empty")));
}
if segment == "." || segment == ".." {
return Err(CeraError::Backend(format!(
"{kind} `{segment}` is not a valid path component"
)));
}
for ch in segment.chars() {
let ok = ch.is_ascii_alphanumeric() || matches!(ch, '-' | '_' | '.');
if !ok {
return Err(CeraError::Backend(format!(
"{kind} `{segment}` contains forbidden character {ch:?}"
)));
}
}
Ok(())
}
fn split_url(url: &str) -> Result<(&str, &str), CeraError> {
let scheme_end = url.find("://").ok_or_else(|| {
CeraError::Backend(format!("url `{url}` must start with https:// or http://"))
})?;
let scheme = &url[..scheme_end];
let lower = scheme.to_ascii_lowercase();
if lower != "http" && lower != "https" {
return Err(CeraError::Backend(format!(
"url `{url}` must start with https:// or http://"
)));
}
let after_scheme = &url[scheme_end + 3..]; let (host, path) = after_scheme
.split_once('/')
.ok_or_else(|| CeraError::Backend(format!("url `{url}` has no path component")))?;
if host.is_empty() {
return Err(CeraError::Backend(format!(
"url `{url}` has empty host component"
)));
}
let path_start = url.len() - path.len() - 1;
Ok((host, &url[path_start..]))
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn cache_segments_mirror_host_and_path() {
let segs = cache_relative_segments(
"https://huggingface.co/LiquidAI/LFM2-1.2B-GGUF/resolve/main/x.gguf",
)
.unwrap();
assert_eq!(
segs,
[
"huggingface.co",
"LiquidAI",
"LFM2-1.2B-GGUF",
"resolve",
"main",
"x.gguf"
]
);
}
#[test]
fn split_url_rejects_missing_scheme() {
assert!(split_url("huggingface.co/x").is_err());
}
#[test]
fn split_url_rejects_missing_path() {
assert!(split_url("https://huggingface.co").is_err());
}
#[test]
fn split_url_accepts_http_and_https() {
assert!(split_url("http://example.com/x").is_ok());
assert!(split_url("https://example.com/x").is_ok());
}
#[test]
fn split_url_scheme_is_case_insensitive() {
assert!(split_url("HTTPS://example.com/x").is_ok());
assert!(split_url("Http://example.com/x").is_ok());
assert!(split_url("HTTP://example.com/x").is_ok());
}
#[test]
fn cache_segments_lowercase_host_for_cache_consistency() {
let a = cache_relative_segments("https://HuggingFace.co/LiquidAI/M/x.gguf").unwrap();
let b = cache_relative_segments("https://huggingface.co/LiquidAI/M/x.gguf").unwrap();
assert_eq!(a, b);
assert_eq!(a, ["huggingface.co", "LiquidAI", "M", "x.gguf"]);
}
#[test]
fn cache_segments_fold_a_port_into_the_host() {
let segs = cache_relative_segments("http://localhost:8731/model.gguf").unwrap();
assert_eq!(segs, ["localhost_8731", "model.gguf"]);
let other = cache_relative_segments("http://localhost:9000/model.gguf").unwrap();
assert_ne!(segs, other);
}
#[test]
fn cache_segments_keep_ports_distinct_from_underscored_hosts() {
let with_port = cache_relative_segments("https://a:1/m.gguf").unwrap();
let underscored = cache_relative_segments("https://a_1/m.gguf").unwrap();
assert_eq!(with_port, ["a_1", "m.gguf"]);
assert_eq!(underscored, ["a__1", "m.gguf"]);
assert_ne!(with_port, underscored);
}
#[test]
fn cache_segments_reject_a_malformed_port() {
for bad in [
"https://a:/m.gguf",
"https://a:80x/m.gguf",
"https://a:1:2/m.gguf",
] {
let e = cache_relative_segments(bad).expect_err(&format!("{bad} must be rejected"));
assert!(
format!("{e}").contains("forbidden character ':'"),
"unexpected error for {bad}: {e}"
);
}
}
#[test]
fn cache_segments_reject_parent_dir_segment() {
let e = cache_relative_segments("https://evil.example.com/a/../../etc/passwd")
.expect_err("`..` segment must be rejected");
assert!(format!("{e}").contains("not a valid path component"));
}
#[test]
fn cache_segments_reject_windows_reserved_chars() {
for bad in ["a*b", "a\"b", "a<b", "a>b", "a|b"] {
let url = format!("https://example.com/{bad}");
let e = cache_relative_segments(&url).expect_err(&format!("{bad:?} must be rejected"));
let msg = format!("{e}");
assert!(
msg.contains("forbidden"),
"unexpected error for {bad:?}: {msg}"
);
}
}
#[test]
fn cache_segments_reject_empty_segment() {
let e = cache_relative_segments("https://example.com/a//b")
.expect_err("empty path segment must be rejected");
assert!(format!("{e}").contains("must not be empty"));
}
#[test]
fn cache_segments_strip_query_and_fragment() {
let segs = cache_relative_segments("https://example.com/model.gguf?foo=bar#frag").unwrap();
assert_eq!(segs, ["example.com", "model.gguf"]);
}
#[test]
fn cache_segments_reject_null_byte_in_path() {
let e = cache_relative_segments("https://example.com/a\0b")
.expect_err("null byte in path must be rejected");
assert!(format!("{e}").contains("forbidden"));
}
#[test]
fn leap_manifest_url_happy_path() {
let url = leap_bundles_manifest_url("LFM2-1.2B-GGUF", "Q4_0").unwrap();
assert_eq!(
url,
"https://huggingface.co/LiquidAI/LeapBundles/resolve/main/LFM2-1.2B-GGUF/Q4_0.json"
);
}
#[test]
fn leap_manifest_url_rejects_empty() {
assert!(leap_bundles_manifest_url("", "Q4_0").is_err());
assert!(leap_bundles_manifest_url("LFM2-1.2B-GGUF", "").is_err());
}
#[test]
fn leap_manifest_url_rejects_path_separators() {
assert!(leap_bundles_manifest_url("LFM2/GGUF", "Q4_0").is_err());
assert!(leap_bundles_manifest_url("LFM2-1.2B-GGUF", "sub/Q4_0").is_err());
assert!(leap_bundles_manifest_url("LFM2\\GGUF", "Q4_0").is_err());
}
#[test]
fn leap_manifest_url_rejects_parent_dir() {
assert!(leap_bundles_manifest_url("..", "Q4_0").is_err());
assert!(leap_bundles_manifest_url("LFM2-1.2B-GGUF", "..").is_err());
}
#[test]
fn leap_manifest_url_rejects_whitespace_and_url_reserved() {
assert!(leap_bundles_manifest_url("LFM2 GGUF", "Q4_0").is_err());
assert!(leap_bundles_manifest_url("LFM2-1.2B-GGUF", "Q4 0").is_err());
assert!(leap_bundles_manifest_url("LFM2-1.2B-GGUF", "Q4_0\n").is_err());
assert!(leap_bundles_manifest_url("LFM2?x", "Q4_0").is_err());
assert!(leap_bundles_manifest_url("LFM2#x", "Q4_0").is_err());
assert!(leap_bundles_manifest_url("LFM2%2E", "Q4_0").is_err());
}
#[test]
fn parse_leap_bundles_groups_siblings() {
let body = r#"{
"siblings": [
{"rfilename": ".gitattributes"},
{"rfilename": "README.md"},
{"rfilename": "LFM2-1.2B-8da4w_output_8da8w-seq_4096.bundle"},
{"rfilename": "LFM2-1.2B-GGUF/Q8_0.json"},
{"rfilename": "LFM2-1.2B-GGUF/Q4_0.json"},
{"rfilename": "LFM2-1.2B-GGUF/Q4_K_M.json"},
{"rfilename": "LFM2-2.6B-GGUF/Q4_0.json"},
{"rfilename": "LFM2-2.6B-GGUF/notes/extra.json"},
{"rfilename": "LFM2-2.6B-GGUF/extras.txt"}
]
}"#;
let entries = parse_leap_bundles(body).unwrap();
assert_eq!(entries.len(), 2, "expected 2 bundles, got {entries:?}");
assert_eq!(entries[0].name, "LFM2-1.2B-GGUF");
assert_eq!(entries[0].quants, vec!["Q4_0", "Q4_K_M", "Q8_0"]);
assert_eq!(entries[1].name, "LFM2-2.6B-GGUF");
assert_eq!(entries[1].quants, vec!["Q4_0"]);
}
#[test]
fn parse_leap_bundles_rejects_malformed_json() {
let err = parse_leap_bundles("not json at all").unwrap_err();
let msg = format!("{err}");
assert!(msg.contains("JSON parse failed"), "got: {msg}");
}
#[test]
fn parse_leap_bundles_empty_siblings_is_ok() {
let entries = parse_leap_bundles(r#"{"siblings": []}"#).unwrap();
assert!(entries.is_empty());
}
#[test]
fn parse_leap_bundles_drops_invalid_path_segments() {
let body = r#"{
"siblings": [
{"rfilename": "Good-Bundle-GGUF/Q4_0.json"},
{"rfilename": "Has Space-GGUF/Q4_0.json"},
{"rfilename": "Good-Bundle-GGUF/Q 0.json"},
{"rfilename": "Has?Reserved/Q4_0.json"},
{"rfilename": "Café-GGUF/Q4_0.json"}
]
}"#;
let entries = parse_leap_bundles(body).unwrap();
assert_eq!(entries.len(), 1, "expected only the valid entry");
assert_eq!(entries[0].name, "Good-Bundle-GGUF");
assert_eq!(entries[0].quants, vec!["Q4_0"]);
}
}