use std::path::Path;
use serde_json::{json, Value};
use crate::capabilities::{Cap, Capabilities};
use crate::runtimes::{Catalog, Found, Runtime};
fn short_version(v: Option<&str>) -> String {
v.map(|v| v.split(" (").next().unwrap_or(v).to_string()).unwrap_or_else(|| "-".into())
}
fn state(f: &Found) -> &'static str {
match (&f.usable, &f.worker) {
(Ok(_), _) => "ready",
(Err(_), None) => "missing",
(Err(_), Some(w)) if matches!(w.source, crate::runtimes::Source::Installed | crate::runtimes::Source::Env) => "broken",
(Err(_), Some(_)) => "not installed",
}
}
pub(crate) fn columns(rows: &[Vec<String>]) -> String {
let n = rows.iter().map(Vec::len).max().unwrap_or(0);
let widths: Vec<usize> = (0..n).map(|c| rows.iter().filter_map(|r| r.get(c)).map(|s| s.chars().count()).max().unwrap_or(0)).collect();
let mut out = String::new();
for r in rows {
let line: Vec<String> = r
.iter()
.enumerate()
.map(|(c, cell)| if c + 1 == r.len() { cell.clone() } else { format!("{cell:<w$}", w = widths[c]) })
.collect();
out.push_str(line.join(" ").trim_end());
out.push('\n');
}
out
}
pub fn with_installs(catalog: &Catalog) -> Vec<Found> {
let mut all = Vec::new();
for found in catalog.survey() {
let id = found.id;
let default = found.worker.as_ref().and_then(|w| w.install());
all.push(found);
for install in crate::installs::list(catalog, id) {
if Some(&install.name) != default.as_ref() {
if let Some(at) = crate::runtime_pick::RuntimeId::parse(&format!("{id}@{}", install.name)) {
all.push(catalog.inspect(at));
}
}
}
}
all
}
fn install_cell(f: &Found, catalog: Option<&Catalog>) -> String {
let Some(name) = f.worker.as_ref().and_then(|w| w.install()) else { return "-".into() };
if f.id.install().is_some() {
return name;
}
match catalog.and_then(|c| crate::installs::pinned(c, f.id)) {
Some(p) if p == name => format!("{name} (pinned)"),
_ => format!("{name} (default)"),
}
}
pub fn table(found: &[Found], packages: &Path) -> String {
table_of(found, packages, None)
}
pub fn table_of(found: &[Found], packages: &Path, catalog: Option<&Catalog>) -> String {
let mut rows = vec![["RUNTIME", "STATE", "INSTALL", "VERSION", "INSTALLABLE", "READS", "DEVICE", "WORKER"].map(String::from).to_vec()];
let mut problems = Vec::new();
for f in found {
let installable = match (catalog, f.id.install()) {
(Some(c), None) => crate::versions::cell(&crate::versions::of(c, f.id)),
_ => "-".to_string(),
};
let reads = f
.info
.as_ref()
.map(|i| i.formats.iter().map(|x| x.id.as_str()).collect::<Vec<_>>().join(","))
.filter(|s| !s.is_empty())
.unwrap_or_else(|| "-".into());
let (version, device) = match &f.usable {
Ok(rt) => (short_version(rt.version.as_deref()), rt.device().map(|d| d.summary()).unwrap_or_else(|| "-".into())),
Err(why) => {
problems.push(format!("{}: {why}", f.id));
("-".into(), "-".into())
}
};
let worker = f.worker.as_ref().map(|w| format!("{}: {}", w.source.name(), w.bin.display())).unwrap_or_else(|| "-".into());
rows.push(vec![f.id.to_string(), state(f).into(), install_cell(f, catalog), version, installable, reads, device, worker]);
}
let mut out = if found.is_empty() { "no runtime is installed here\n".to_string() } else { columns(&rows) };
for p in problems {
out.push_str(&p);
out.push('\n');
}
if catalog.is_some() && !found.is_empty() {
out.push_str("`superfluid runtime versions <id>` lists every version an adapter installs on its own\n");
}
out.push_str(&format!("installed runtimes: {}\n", packages.display()));
out
}
pub fn table_json(found: &[Found]) -> Value {
table_json_of(found, None)
}
pub fn table_json_of(found: &[Found], catalog: Option<&Catalog>) -> Value {
Value::Array(
found
.iter()
.map(|f| {
let mut v = runtime_json(f);
if let (Some(c), None) = (catalog, f.id.install()) {
if let Ok(listing) = crate::versions::of(c, f.id) {
v["installable"] = json!(crate::versions::here(&listing));
}
}
v
})
.collect(),
)
}
fn runtime_json(f: &Found) -> Value {
use superfluid_worker::check::{device_json, format_json, tokenizer_json};
let mut v = json!({"id": f.id.name(), "state": state(f)});
#[cfg(feature = "basert")]
if f.id.base().name() == "basert" {
v["requires"] = json!({
"basert_version": superfluid_engine_ffi::libbasert::BUILT_FOR,
"basert_abi": superfluid_engine_ffi::libbasert::abi_built_for(),
"basert_unnumbered_minor": superfluid_engine_ffi::libbasert::abi_built_for().and_then(superfluid_engine_ffi::libbasert::unnumbered_minor_for),
});
}
if let Some(info) = &f.info {
v["aliases"] = json!(info.aliases);
v["formats"] = Value::Array(info.formats.iter().map(format_json).collect());
v["reads"] = json!(info.reads_described());
if let Some(t) = &info.tokenizer {
v["tokenizer_source"] = tokenizer_json(t);
}
}
if let Some(w) = &f.worker {
v["worker"] = json!({"path": w.bin, "source": w.source.name()});
if let Some(install) = w.install() {
v["install"] = json!(install);
}
}
match &f.usable {
Ok(rt) => {
v["ready"] = true.into();
v["version"] = json!(rt.version);
if let Some(abi) = rt.abi {
v["abi"] = json!(abi);
}
v["devices"] = Value::Array(rt.devices.iter().map(device_json).collect());
if let Some(t) = &rt.tokenizer {
v["tokenizer"] = json!(t);
}
if let Some(c) = &rt.capabilities {
v["capabilities"] = serde_json::from_str(c).unwrap_or_default();
}
if !rt.options.is_empty() {
v["options"] = Value::Array(rt.options.iter().map(|o| o.to_json()).collect());
}
}
Err(why) => v["ready"] = why.clone().into(),
}
v
}
struct Answer {
found: Found,
reads: Result<(), String>,
facts: Option<Value>,
}
fn ask(catalog: &Catalog, found: Found, model: &Path) -> Answer {
let _ = catalog;
let by_format = |f: &Found| -> Result<(), String> {
match &f.info {
Some(i) if i.format_of(model).is_some() => Ok(()),
Some(i) => Err(format!("it reads {}", i.reads_described())),
None => Err(f.usable.as_ref().err().cloned().unwrap_or_default()),
}
};
let report = found.worker.as_ref().and_then(|w| {
if w.source == crate::runtimes::Source::BuiltIn && !w.bin.is_file() {
crate::linked::report(found.id, Some(model))
} else {
crate::runtimes::run_check_model(w, Some(model)).ok()
}
});
let (reads, facts) = match report.as_ref().map(|r| &r["model"]) {
Some(m) if !m.is_null() => {
let reads = match &m["reads"] {
Value::Bool(true) => Ok(()),
Value::String(why) => Err(why.clone()),
_ => by_format(&found),
};
(reads, m.get("facts").filter(|f| f.is_object()).cloned())
}
_ => (by_format(&found), None),
};
Answer { found, reads, facts }
}
fn facts_line(facts: &Value) -> String {
let mut parts = Vec::new();
if let Some(a) = facts["architecture"].as_str().filter(|a| !a.is_empty()) {
parts.push(a.to_string());
}
if let Some(sd) = facts["sampling_defaults"].as_object() {
let kv: Vec<String> = sd.iter().map(|(k, v)| format!("{k} {v}")).collect();
parts.push(format!("sampling defaults: {}", kv.join(", ")));
}
parts.join("; ")
}
fn serves_lines(rt: &Runtime) -> Vec<(String, String)> {
let caps: Capabilities = rt.static_capabilities();
if caps.record().is_none() {
return vec![("capabilities".into(), format!("the {} runtime describes a model once it is loaded", rt.id))];
}
let show = |c: Cap<'_>| match c {
Cap::Yes => "yes".to_string(),
Cap::No(why) => format!("no: {why}"),
Cap::Unknown => "said once the model is loaded".to_string(),
};
[
("images", "modalities", "image_encode"),
("audio", "modalities", "gemma_audio_encode"),
("speech to text", "workload", "speech_to_text"),
("embeddings", "workload", "embedding"),
("grammar", "sampling", "grammar"),
("--speculate", "serving", "multi_row_verification"),
("--park-lossy", "serving", "park_lossy"),
("--kv-bits", "load", "kv_bits"),
]
.into_iter()
.map(|(what, section, key)| (what.to_string(), show(caps.get(section, key))))
.collect()
}
pub fn model(catalog: &Catalog, model: &Path) -> (String, Value, bool) {
let answers: Vec<Answer> = catalog.survey().into_iter().map(|f| ask(catalog, f, model)).collect();
let format = answers.iter().find_map(|a| a.found.info.as_ref()?.format_of(model).cloned());
let serving = catalog.reader_of(model).and_then(|id| catalog.require(id));
let mut out = format!(
"{}: {}\n\n",
model.display(),
format.as_ref().map(|f| f.describe.clone()).unwrap_or_else(|| "no runtime here declares this format".into())
);
let mut rows = vec![["RUNTIME", "READS IT", "DEVICE", "MODEL"].map(String::from).to_vec()];
for a in &answers {
let device = a.found.usable.as_ref().ok().and_then(|r| r.device()).map(|d| d.summary()).unwrap_or_else(|| "-".into());
let (reads, detail) = match &a.reads {
Ok(()) => ("yes".to_string(), a.facts.as_ref().map(facts_line).unwrap_or_default()),
Err(why) => ("no".to_string(), why.clone()),
};
rows.push(vec![a.found.id.to_string(), reads, device, detail]);
}
if answers.is_empty() {
out.push_str("no runtime is installed here\n");
} else {
out.push_str(&columns(&rows));
}
out.push('\n');
match &serving {
Ok(rt) => {
out.push_str(&format!(
"{} serves it: the runtime that reads its format (--runtime picks another that reads it)\n",
rt.id
));
let lines = serves_lines(rt);
let w = lines.iter().map(|(k, _)| k.len()).max().unwrap_or(0);
for (what, verdict) in lines {
out.push_str(&format!(" {what:<w$} {verdict}\n"));
}
}
Err(why) => out.push_str(&format!("no runtime here serves it: {why}\n")),
}
let json = json!({
"model": model,
"format": format.as_ref().map(superfluid_worker::check::format_json),
"runtimes": answers.iter().map(|a| {
let mut v = runtime_json(&a.found);
v["reads_model"] = match &a.reads { Ok(()) => true.into(), Err(why) => why.clone().into() };
if let Some(f) = &a.facts { v["model_facts"] = f.clone(); }
v
}).collect::<Vec<_>>(),
"serves": match &serving { Ok(rt) => json!(rt.id.name()), Err(why) => json!({"none": why}) },
});
(out, json, serving.is_ok())
}
#[cfg(test)]
mod tests {
use super::*;
use crate::runtime_pick::RuntimeId;
use crate::runtimes::tests::{fake_worker, report};
const V: u16 = superfluid_agent::client::PROTO_VERSION;
fn scratch(tag: &str) -> std::path::PathBuf {
let d = std::env::temp_dir().join(format!("superfluid-runtimes-report-{tag}-{}", std::process::id()));
let _ = std::fs::remove_dir_all(&d);
std::fs::create_dir_all(&d).unwrap();
d
}
fn install(home: &Path, id: &str, text: &str, exit: i32) {
let root = home.join("runtimes").join(id);
let bin = root.join("v1-metal/bin");
std::fs::create_dir_all(&bin).unwrap();
fake_worker(&bin, &format!("superfluid-worker-{id}"), text, exit);
let lib = root.join("v1-metal/lib");
std::fs::create_dir_all(&lib).unwrap();
std::fs::write(lib.join(crate::dylib_tokenizer::library_file("superfluid_tokenizer_llamacpp")), b"").unwrap();
let _ = std::fs::remove_file(root.join("current"));
std::os::unix::fs::symlink("v1-metal", root.join("current")).unwrap();
}
#[test]
fn the_table_shows_what_each_runtime_reads_and_runs_on_and_what_is_wrong() {
if !crate::linked::ids().is_empty() {
return;
}
let home = scratch("table");
install(&home, "llamacpp", &report("llamacpp", V, "true"), 0);
install(&home, "mlx", &report("mlx", V, r#""ModuleNotFoundError: No module named 'mlx'""#), 1);
let cat = Catalog::new(home.clone(), None, home.join("superfluid-workerd"));
let text = table(&cat.survey(), &home.join("runtimes"));
let lines: Vec<&str> = text.lines().collect();
assert!(lines[0].starts_with("RUNTIME STATE INSTALL VERSION INSTALLABLE READS DEVICE"), "{text}");
assert!(lines[1].starts_with("llamacpp ready v1-metal (default) v1 - gguf Metal: Apple M5 Pro, 36.0 GB installed: "), "{text}");
assert!(lines[2].starts_with("mlx broken v1-metal (default) - - mlx -"), "{text}");
assert!(lines[3].starts_with("mlx: the mlx runtime at ") && lines[3].contains("`superfluid runtime repair mlx`"), "{text}");
let json = table_json(&cat.survey());
assert_eq!(json[0]["formats"][0]["id"], "gguf");
assert_eq!(json[0]["reads"], "a GGUF file");
assert_eq!(json[0]["devices"][0]["backend"], "Metal");
assert_eq!(json[1]["state"], "broken");
}
#[test]
fn an_adapter_with_no_install_is_listed_as_not_installed() {
if !crate::linked::ids().is_empty() {
return;
}
let root = scratch("shipped");
let (beside, libexec) = (root.join("bin"), root.join("libexec").join("superfluid"));
std::fs::create_dir_all(&beside).unwrap();
std::fs::create_dir_all(&libexec).unwrap();
let not_found = r#""llama.cpp not found: install it with `superfluid runtime install llamacpp`""#;
fake_worker(&libexec, "superfluid-worker-llamacpp", &report("llamacpp", V, not_found), 1);
let home = root.join("home");
let cat = Catalog::new(home.clone(), Some(beside.clone()), beside.join("superfluid-workerd"));
let text = table(&cat.survey(), &home.join("runtimes"));
let lines: Vec<&str> = text.lines().collect();
assert!(lines[1].starts_with("llamacpp not installed - - - gguf - shipped with superfluid: "), "{text}");
assert_eq!(
lines[2],
"llamacpp: the llamacpp runtime is not installed: llama.cpp not found: install it with `superfluid runtime install llamacpp`",
"{text}"
);
let json = table_json(&cat.survey());
assert_eq!(json[0]["state"], "not installed");
assert_eq!(json[0]["worker"]["source"], "shipped with superfluid");
assert_eq!(json[0]["formats"][0]["id"], "gguf");
}
#[test]
fn with_a_catalog_the_table_says_what_installs_here() {
if !crate::linked::ids().is_empty() {
return;
}
use crate::versions::tests::{fake_worker_listing, manifest, LISTING};
let home = scratch("installable");
let dir = manifest(&home, "llamacpp", "v1-metal", "t1", "metal", true);
fake_worker_listing(&dir.join("bin"), "superfluid-worker-llamacpp", &report("llamacpp", V, "true"), LISTING);
std::fs::create_dir_all(dir.join("lib")).unwrap();
std::fs::write(dir.join("lib").join(crate::dylib_tokenizer::library_file("superfluid_tokenizer_llamacpp")), b"").unwrap();
std::os::unix::fs::symlink("v1-metal", home.join("runtimes").join("llamacpp").join("current")).unwrap();
install(&home, "mlx", &report("mlx", V, "true"), 0);
let cat = Catalog::new(home.clone(), None, home.join("superfluid-workerd"));
let found = with_installs(&cat);
let text = table_of(&found, &home.join("runtimes"), Some(&cat));
let lines: Vec<&str> = text.lines().collect();
assert!(lines[0].starts_with("RUNTIME STATE INSTALL VERSION INSTALLABLE READS DEVICE"), "{text}");
assert!(lines[1].starts_with("llamacpp ready v1-metal (default) v1 t1 (installed) gguf Metal"), "{text}");
assert!(lines[2].starts_with("mlx ready v1-metal (default) v1 - mlx Metal"), "{text}");
assert!(text.contains("\n`superfluid runtime versions <id>` lists every version an adapter installs on its own\ninstalled runtimes: "), "{text}");
let json = table_json_of(&found, Some(&cat));
assert_eq!(json[0]["installable"], json!(["t1"]));
assert!(json[1]["installable"].is_null());
assert!(table_json(&found)[0]["installable"].is_null(), "without a catalog nothing is asked");
}
#[test]
fn a_model_is_answered_by_every_runtime_and_served_by_its_formats() {
if !crate::linked::ids().is_empty() {
return;
}
let home = scratch("model");
let with_model = |id: &str, reads: &str| {
let r: Value = serde_json::from_str(&report(id, V, "true")).unwrap();
let mut r = r;
r["model"] = json!({"path": "/m", "reads": serde_json::from_str::<Value>(reads).unwrap()});
if reads == "true" {
r["model"]["facts"] = json!({"architecture": "qwen3", "sampling_defaults": {"temperature": 0.6}});
}
r.to_string()
};
install(&home, "llamacpp", &with_model("llamacpp", "true"), 0);
install(&home, "mlx", &with_model("mlx", r#""/m is not a directory; an MLX model is a directory""#), 1);
let cat = Catalog::new(home.clone(), None, home.join("superfluid-workerd"));
let m = scratch("model-file").join("q.gguf");
std::fs::write(&m, b"GGUF").unwrap();
let (text, json, ok) = model(&cat, &m);
assert!(ok, "{text}");
assert!(text.starts_with(&format!("{}: a GGUF file\n", m.display())), "{text}");
assert!(text.contains("llamacpp yes Metal: Apple M5 Pro, 36.0 GB qwen3; sampling defaults: temperature 0.6"), "{text}");
assert!(text.contains("mlx no Metal: Apple M5 Pro, 36.0 GB /m is not a directory; an MLX model is a directory"), "{text}");
assert!(text.contains("llamacpp serves it"), "{text}");
assert!(text.contains("--park-lossy no: no lossy encoding"), "{text}");
assert!(text.contains("--kv-bits no: no such knob"), "{text}");
assert!(text.contains("images said once the model is loaded"), "{text}");
assert_eq!(json["serves"], "llamacpp");
assert_eq!(json["format"]["id"], "gguf");
assert_eq!(json["runtimes"][1]["reads_model"], "/m is not a directory; an MLX model is a directory");
let b = m.with_file_name("q.base");
std::fs::write(&b, b"BASE").unwrap();
let (text, json, ok) = model(&cat, &b);
assert!(!ok);
assert!(text.starts_with(&format!("{}: no runtime here declares this format", b.display())), "{text}");
assert!(text.contains("no runtime here serves it: no runtime here reads"), "{text}");
assert!(json["serves"]["none"].as_str().unwrap().contains("runtimes here: llamacpp reads a GGUF file"));
let _ = RuntimeId::new("llamacpp");
}
}