1use std::collections::HashMap;
4use std::path::{Path, PathBuf};
5use std::process::Command;
6use std::sync::Mutex;
7use superfluid_engine::artifact::{Device, Format, TokenizerSource};
8use serde_json::Value;
9
10use crate::runtime_pick::RuntimeId;
11
12#[derive(Debug, Clone, Copy, PartialEq, Eq)]
13pub enum Source {
14 Env,
15 BesideDaemon,
16 BuiltIn,
17 Installed,
18 Shipped,
19}
20
21impl Source {
22 pub fn name(self) -> &'static str {
23 match self {
24 Source::Env => "environment",
25 Source::BesideDaemon => "beside superfluid",
26 Source::BuiltIn => "built in",
27 Source::Installed => "installed",
28 Source::Shipped => "shipped with superfluid",
29 }
30 }
31}
32
33#[derive(Debug, Clone, PartialEq, Eq)]
34pub struct Worker {
35 pub bin: PathBuf,
36 pub prefix: Vec<String>,
37 pub source: Source,
38}
39
40impl Worker {
41 pub fn install(&self) -> Option<String> {
42 if self.source != Source::Installed {
43 return None;
44 }
45 self.bin.parent()?.parent()?.file_name().and_then(|n| n.to_str()).map(str::to_string)
46 }
47}
48
49#[derive(Debug, Clone, Default, PartialEq)]
50pub struct Info {
51 pub aliases: Vec<String>,
52 pub formats: Vec<Format>,
53 pub tokenizer: Option<TokenizerSource>,
54 pub named: Option<String>,
55}
56
57impl Info {
58 fn from_report(report: &Value) -> Info {
59 use superfluid_worker::check::{formats_from, tokenizer_from};
60 Info {
61 aliases: report["runtime"]["aliases"]
62 .as_array()
63 .map(|a| a.iter().filter_map(|x| x.as_str().map(str::to_string)).collect())
64 .unwrap_or_default(),
65 formats: formats_from(&report["formats"]),
66 tokenizer: tokenizer_from(&report["tokenizer"]),
67 named: report["named"].as_str().map(str::to_string),
68 }
69 }
70
71 pub fn format_of(&self, path: &Path) -> Option<&Format> {
72 self.formats.iter().find(|f| f.matches(path))
73 }
74
75 pub fn reads_described(&self) -> String {
76 let all: Vec<&str> = self.formats.iter().map(|f| f.describe.as_str()).collect();
77 match all.as_slice() {
78 [] => "no format: its worker declares none, so it is older than this superfluid (rebuild or update it)".to_string(),
79 [one] => one.to_string(),
80 [init @ .., last] => format!("{} or {last}", init.join(", ")),
81 }
82 }
83}
84
85#[derive(Debug, Clone)]
86pub struct Runtime {
87 pub id: RuntimeId,
88 pub worker: Worker,
89 pub version: Option<String>,
90 pub abi: Option<u64>,
92 pub capabilities: Option<String>,
93 pub info: Info,
94 pub devices: Vec<Device>,
95 pub tokenizer: Option<PathBuf>,
96 pub pull: Option<Vec<(String, bool)>>,
97 pub options: Vec<superfluid_worker::check::OptionDecl>,
99}
100
101impl Runtime {
102 pub fn serve_args(&self, model: &Path, ctx: i32, max_batch: u32, kv_bits: i32) -> Vec<String> {
103 let mut args = self.worker.prefix.clone();
104 args.extend([
105 "--model".to_string(),
106 model.to_string_lossy().into_owned(),
107 "--max-context".to_string(),
108 ctx.to_string(),
109 "--max-batch".to_string(),
110 max_batch.to_string(),
111 ]);
112 if !matches!(self.static_capabilities().get("load", "kv_bits"), crate::capabilities::Cap::No(_)) {
113 args.push("--kv-bits".to_string());
114 args.push(kv_bits.to_string());
115 }
116 args
118 }
119
120 pub fn static_capabilities(&self) -> crate::capabilities::Capabilities {
121 self.capabilities.as_deref().map(crate::capabilities::Capabilities::parse).unwrap_or_default()
122 }
123
124 pub fn in_process_capable(&self) -> bool {
125 crate::linked::get(self.id).is_some()
126 }
127
128 pub fn device(&self) -> Option<&Device> {
129 self.devices.first()
130 }
131}
132
133#[derive(Debug, Clone)]
134pub struct Found {
135 pub id: RuntimeId,
136 pub worker: Option<Worker>,
137 pub info: Option<Info>,
138 pub usable: Result<Runtime, String>,
139}
140
141pub struct Catalog {
142 home: PathBuf,
143 beside: Option<PathBuf>,
144 workerd: PathBuf,
145 usable: Mutex<HashMap<RuntimeId, Runtime>>,
146}
147
148pub fn default_home() -> PathBuf {
149 home_from(std::env::var_os("SUPERFLUID_HOME"), std::env::home_dir())
150}
151
152fn home_from(superfluid_home: Option<std::ffi::OsString>, user_home: Option<PathBuf>) -> PathBuf {
153 if let Some(h) = superfluid_home.filter(|h| !h.is_empty()) {
154 return PathBuf::from(h);
155 }
156 user_home.filter(|h| h.is_absolute()).unwrap_or_else(|| PathBuf::from("/")).join(".superfluid")
157}
158
159pub fn worker_name(id: RuntimeId) -> String {
160 format!("superfluid-worker-{}", id.base().name())
161}
162
163pub fn worker_env(id: RuntimeId) -> String {
164 format!("SUPERFLUID_WORKER_{}", id.base().name().to_ascii_uppercase().replace(['-', '.'], "_"))
165}
166
167impl Catalog {
168 pub fn new(home: PathBuf, beside: Option<PathBuf>, workerd: PathBuf) -> Catalog {
169 Catalog { home, beside, workerd, usable: Mutex::new(HashMap::new()) }
170 }
171
172 pub fn from_env() -> Catalog {
173 let beside = beside_this_executable();
174 let workerd = beside.clone().unwrap_or_default().join("superfluid-workerd");
175 Catalog::new(default_home(), beside, workerd)
176 }
177
178 pub fn with_workerd(workerd: PathBuf) -> Catalog {
181 Catalog::new(default_home(), beside_this_executable(), workerd)
182 }
183
184 pub fn home(&self) -> &Path {
185 &self.home
186 }
187
188 pub fn workerd(&self) -> &Path {
190 &self.workerd
191 }
192
193 pub fn beside(&self) -> Option<&Path> {
194 self.beside.as_deref()
195 }
196
197 pub fn package_dir(&self, id: RuntimeId) -> PathBuf {
198 self.home.join("runtimes").join(id.base().name())
199 }
200
201 fn shipped_dirs(&self) -> Vec<PathBuf> {
202 let Some(beside) = &self.beside else { return Vec::new() };
203 [beside.join("..").join("libexec").join("superfluid"), beside.join("libexec").join("superfluid")]
204 .into_iter()
205 .filter_map(|d| std::fs::canonicalize(d).ok())
206 .filter(|d| d.is_dir())
207 .collect()
208 }
209
210 pub fn shipped(&self, id: RuntimeId) -> Option<PathBuf> {
211 let own = worker_name(id);
212 self.shipped_dirs().into_iter().map(|d| d.join(&own)).find(|p| is_executable(p))
213 }
214
215 pub fn shipped_ids(&self) -> Vec<RuntimeId> {
216 let mut ids: Vec<RuntimeId> = self.shipped_dirs().iter().flat_map(|d| workers_in(d)).collect();
217 ids.sort();
218 ids.dedup();
219 ids
220 }
221
222 pub fn ids(&self) -> Vec<RuntimeId> {
223 let mut ids: Vec<RuntimeId> = Vec::new();
224 for (k, _) in std::env::vars_os() {
225 if let Some(id) = k.to_str().and_then(|k| k.strip_prefix("SUPERFLUID_WORKER_")) {
226 ids.extend(RuntimeId::parse(&id.to_ascii_lowercase()));
227 }
228 }
229 if let Some(dir) = &self.beside {
230 ids.extend(workers_in(dir));
231 }
232 ids.extend(self.shipped_ids());
233 ids.extend(crate::linked::ids());
234 if let Ok(rd) = std::fs::read_dir(self.home.join("runtimes")) {
235 ids.extend(
236 rd.flatten()
237 .filter(|e| e.path().is_dir())
238 .filter_map(|e| e.file_name().to_str().and_then(RuntimeId::parse)),
239 );
240 }
241 ids.sort();
242 ids.dedup();
243 ids
244 }
245
246 pub fn locate(&self, id: RuntimeId) -> Option<Worker> {
248 let mut worker = self.locate_plain(id)?;
249 for (flag, value) in crate::runtime_options::for_runtime(id) {
250 worker.prefix.push(flag);
251 worker.prefix.push(value);
252 }
253 Some(worker)
254 }
255
256 pub(crate) fn locate_plain(&self, id: RuntimeId) -> Option<Worker> {
258 if let Some(install) = id.install() {
259 let bin = self.package_dir(id).join(install).join("bin").join(worker_name(id));
260 return std::fs::canonicalize(bin).ok().filter(|p| p.is_file()).map(|bin| Worker {
261 bin,
262 prefix: Vec::new(),
263 source: Source::Installed,
264 });
265 }
266 if let Some(p) = std::env::var_os(worker_env(id)) {
267 return Some(Worker { bin: PathBuf::from(p), prefix: Vec::new(), source: Source::Env });
268 }
269 if crate::linked::get(id).is_some() {
270 return Some(Worker {
271 bin: self.workerd.clone(),
272 prefix: vec!["--engine".into(), id.name().into()],
273 source: Source::BuiltIn,
274 });
275 }
276 let own = worker_name(id);
277 if let Some(bin) = self.beside.as_ref().map(|d| d.join(&own)).filter(|p| is_executable(p)) {
278 return Some(Worker { bin, prefix: Vec::new(), source: Source::BesideDaemon });
279 }
280 let bin = self.package_dir(id).join("current").join("bin").join(&own);
281 let installed = std::fs::canonicalize(bin).ok().filter(|p| p.is_file()).map(|bin| Worker {
282 bin,
283 prefix: Vec::new(),
284 source: Source::Installed,
285 });
286 installed.or_else(|| self.shipped(id).map(|bin| Worker { bin, prefix: Vec::new(), source: Source::Shipped }))
287 }
288
289 pub fn require(&self, id: RuntimeId) -> Result<Runtime, String> {
290 if let Some(r) = self.remembered(id) {
291 return Ok(r);
292 }
293 let found = self.inspect(id);
294 if let Ok(runtime) = &found.usable {
295 self.usable.lock().expect("runtime catalog").insert(id, runtime.clone());
296 }
297 found.usable
298 }
299
300 fn remembered(&self, id: RuntimeId) -> Option<Runtime> {
301 let mut usable = self.usable.lock().expect("runtime catalog");
302 let r = usable.get(&id)?;
303 if r.worker.source != Source::BuiltIn && !r.worker.bin.is_file() {
304 usable.remove(&id);
305 return None;
306 }
307 Some(r.clone())
308 }
309
310 pub fn inspect(&self, id: RuntimeId) -> Found {
311 if let Some(r) = self.remembered(id) {
312 return Found { id, worker: Some(r.worker.clone()), info: Some(r.info.clone()), usable: Ok(r) };
313 }
314 let Some(worker) = self.locate(id) else {
315 return Found { id, worker: None, info: None, usable: Err(self.missing(id)) };
316 };
317 let report = if worker.source == Source::BuiltIn && !worker.bin.is_file() {
318 crate::linked::report(id, None).ok_or_else(|| format!("this build does not link the {id} runtime"))
319 } else {
320 run_check(&worker)
321 };
322 let report = match report {
323 Ok(r) => r,
324 Err(why) => return Found { id, worker: Some(worker), info: None, usable: Err(why) },
325 };
326 let info = Info::from_report(&report);
327 let usable = runtime_from_check(id, worker.clone(), &report).and_then(|r| self.with_tokenizer(r));
328 if let Ok(runtime) = &usable {
331 self.usable.lock().expect("runtime catalog").insert(id, runtime.clone());
332 }
333 Found { id, worker: Some(worker), info: Some(info), usable }
334 }
335
336 fn with_tokenizer(&self, mut runtime: Runtime) -> Result<Runtime, String> {
337 let linked = crate::linked::get(runtime.id.base()).is_some();
338 match runtime.info.tokenizer.clone() {
339 Some(TokenizerSource::Library(stem)) => {
340 runtime.tokenizer = crate::dylib_tokenizer::find_library(&runtime.worker.bin, &stem);
341 if runtime.tokenizer.is_none() && !linked {
342 return Err(format!(
343 "the {} runtime at {} ships no tokenizer library ({} beside it or in ../lib)",
344 runtime.id,
345 runtime.worker.bin.display(),
346 crate::dylib_tokenizer::library_file(&stem)
347 ));
348 }
349 }
350 Some(TokenizerSource::HuggingFace) => {}
351 Some(TokenizerSource::Engine) if linked => {}
352 Some(TokenizerSource::Engine) => {
353 return Err(format!(
354 "only the {id} runtime's engine tokenizes its artifacts, and this superfluid does not link it \
355 (a source build adds it with --features {feature})",
356 id = runtime.id,
357 feature = crate::linked::feature_for(runtime.id.base().name()).unwrap_or("<the runtime>"),
358 ))
359 }
360 None => {}
361 }
362 Ok(runtime)
363 }
364
365 fn missing(&self, id: RuntimeId) -> String {
366 if let Some(install) = id.install() {
367 let have: Vec<String> = crate::installs::list(self, id).into_iter().map(|i| i.name).collect();
368 return format!(
369 "{} has no install {install} here (installed: {})",
370 id.base(),
371 if have.is_empty() { "none".to_string() } else { have.join(", ") }
372 );
373 }
374 let shipped = self.shipped_ids();
375 if !shipped.is_empty() {
376 return format!(
377 "the {id} runtime is not here: this superfluid ships no adapter for it (it ships: {}), and none is installed in {}",
378 shipped.iter().map(|i| i.name()).collect::<Vec<_>>().join(", "),
379 self.package_dir(id).display()
380 );
381 }
382 format!(
383 "the {id} runtime is not installed: no {w} in {pkg} or beside superfluid \
384 (install it with `superfluid runtime install {id}`, or build {w} with `cargo build -p superfluid-adapter-{id}`)",
385 w = worker_name(id),
386 pkg = self.package_dir(id).join("current").join("bin").display(),
387 )
388 }
389
390 pub fn survey(&self) -> Vec<Found> {
391 self.ids().into_iter().map(|id| self.inspect(id)).collect()
392 }
393
394 pub fn named(&self, name: &str) -> Result<RuntimeId, String> {
395 let name = name.trim();
396 if let Some((base, install)) = name.split_once('@') {
397 let id = self.named(base)?;
398 let at = RuntimeId::parse(&format!("{id}@{install}")).ok_or_else(|| format!("'{install}' is not an install's name"))?;
399 if crate::installs::list(self, id).iter().any(|i| i.name == install) {
400 return Ok(at);
401 }
402 return Err(self.missing(at));
403 }
404 let ids = self.ids();
405 if let Some(id) = ids.iter().copied().find(|id| id.name() == name) {
406 return Ok(id);
407 }
408 for found in self.survey() {
409 if found.info.is_some_and(|i| i.aliases.iter().any(|a| a == name)) {
410 return Ok(found.id);
411 }
412 }
413 Err(format!("no runtime '{name}' here"))
414 }
415
416 pub fn reads(&self, id: RuntimeId, path: &Path) -> Result<(), String> {
417 let found = self.inspect(id);
418 let Some(info) = &found.info else {
419 return found.usable.map(|_| ());
420 };
421 if info.format_of(path).is_some() {
422 return Ok(());
423 }
424 let mut why = format!("runtime {id} cannot serve {}: it reads {}", path.display(), info.reads_described());
425 match self.readers(path).first() {
426 Some((other, format)) => why.push_str(&format!(
427 ", and this is {} (pass --runtime {other}, or convert the model)",
428 format.describe
429 )),
430 None => why.push_str(", and no runtime here reads this file"),
431 }
432 Err(why)
433 }
434
435 pub fn readers(&self, path: &Path) -> Vec<(RuntimeId, Format)> {
436 let mut known = self.known_readers(path);
437 if known.is_empty() {
438 let found = self.survey();
439 let cannot_run = |id: &RuntimeId| found.iter().any(|f| f.id == *id && f.usable.is_err());
440 known = readers_in(&found, path);
441 known.sort_by_key(|(id, _)| (cannot_run(id), *id));
442 return known;
443 }
444 known
445 }
446
447 fn known_readers(&self, path: &Path) -> Vec<(RuntimeId, Format)> {
448 let mut known: Vec<(RuntimeId, Format)> = self
449 .usable
450 .lock()
451 .expect("runtime catalog")
452 .values()
453 .filter(|r| r.id.install().is_none())
454 .filter_map(|r| Some((r.id, r.info.format_of(path)?.clone())))
455 .collect();
456 known.sort_by_key(|(id, _)| *id);
457 known
458 }
459
460 pub fn reader_of(&self, path: &Path) -> Result<RuntimeId, String> {
461 if let Some((id, _)) = self.known_readers(path).first() {
462 return Ok(*id);
463 }
464 let mut cannot_run = None;
465 for id in self.ids() {
466 let found = self.inspect(id);
467 if found.info.as_ref().and_then(|info| info.format_of(path)).is_none() {
468 continue;
469 }
470 match found.usable {
471 Ok(runtime) => {
472 self.usable.lock().expect("runtime catalog").insert(id, runtime);
473 return Ok(id);
474 }
475 Err(_) => {
476 cannot_run.get_or_insert(id);
477 }
478 }
479 }
480 if let Some(id) = cannot_run {
481 return Ok(id);
482 }
483 Err(format!(
484 "no runtime here reads {} ({}); `superfluid runtimes {}` says more, and `superfluid runtime install <id>` adds a runtime",
485 path.display(),
486 self.here_described(),
487 path.display()
488 ))
489 }
490
491 pub fn not_here(&self, name: &str, path: &Path, why: &str) -> String {
492 let mut msg = format!("{why} to serve {} ({})", path.display(), self.here_described());
493 if let Some((other, format)) = self.readers(path).first() {
494 msg.push_str(&format!("; it is {}, which {other} here reads: pass --runtime {other}", format.describe));
495 }
496 let runtime = name.split('@').next().unwrap_or(name);
497 msg.push_str(&format!("; `superfluid runtime install {runtime}` installs {runtime}"));
498 msg
499 }
500
501 pub fn here_described(&self) -> String {
502 let all = self.survey();
503 if all.is_empty() {
504 return "no runtime is installed".to_string();
505 }
506 let parts: Vec<String> = all
507 .iter()
508 .map(|f| {
509 let state = if f.usable.is_ok() { "" } else { " (not usable)" };
510 match &f.info {
511 Some(info) => format!("{}{state} reads {}", f.id, info.reads_described()),
512 None => format!("{}{state}", f.id),
513 }
514 })
515 .collect();
516 format!("runtimes here: {}", parts.join("; "))
517 }
518}
519
520fn repair_command(id: RuntimeId) -> String {
521 match id.install() {
522 Some(install) => format!("superfluid runtime repair {} {install}", id.base()),
523 None => format!("superfluid runtime repair {id}"),
524 }
525}
526
527pub fn readers_in(found: &[Found], path: &Path) -> Vec<(RuntimeId, Format)> {
528 found
529 .iter()
530 .filter_map(|f| {
531 let format = f.info.as_ref()?.format_of(path)?.clone();
532 Some((f.id, format))
533 })
534 .collect()
535}
536
537fn workers_in(dir: &Path) -> Vec<RuntimeId> {
538 std::fs::read_dir(dir)
539 .map(|rd| {
540 rd.flatten()
541 .filter(|e| is_executable(&e.path()))
542 .filter_map(|e| e.file_name().to_str().and_then(|n| n.strip_prefix("superfluid-worker-")).and_then(RuntimeId::parse))
543 .collect()
544 })
545 .unwrap_or_default()
546}
547
548fn is_executable(p: &Path) -> bool {
549 use std::os::unix::fs::PermissionsExt;
550 std::fs::metadata(p).is_ok_and(|m| m.is_file() && m.permissions().mode() & 0o111 != 0)
551}
552
553pub fn check_worker(id: RuntimeId, worker: &Worker) -> Result<Runtime, String> {
554 let report = run_check(worker)?;
555 runtime_from_check(id, worker.clone(), &report)
556}
557
558fn run_check(w: &Worker) -> Result<Value, String> {
559 run_check_model(w, None)
560}
561
562pub fn run_check_model(w: &Worker, model: Option<&Path>) -> Result<Value, String> {
563 let mut cmd = Command::new(&w.bin);
564 crate::exec::without_secrets(&mut cmd).arg("check").args(&w.prefix);
565 if let Some(m) = model {
566 cmd.arg("--model").arg(m);
567 }
568 let out = crate::exec::output_within(&mut cmd, crate::exec::ANSWER_WITHIN)
569 .map_err(|e| format!("{} could not start: {e}", w.bin.display()))?
570 .ok_or_else(|| format!("{} check did not answer within {}s", w.bin.display(), crate::exec::ANSWER_WITHIN.as_secs()))?;
571 serde_json::from_slice::<Value>(&out.stdout)
572 .map_err(|_| format!("{} check failed ({}){}", w.bin.display(), out.status, crate::exec::stderr_tail(&out.stderr)))
573}
574
575pub fn sizing_of(rt: &Runtime, model: &Path) -> Result<superfluid_adapter_kit::Sizing, String> {
576 let report = run_check_model(&rt.worker, Some(model))?;
577 match &report["model"]["sizing"] {
578 Value::Null => Err(format!("the {} runtime sizes no context window here", rt.id.base().name())),
579 Value::String(why) => Err(why.clone()),
580 said => superfluid_adapter_kit::Sizing::from_json(said)
581 .ok_or_else(|| format!("{} check reported a sizing this superfluid does not read: {said}", rt.worker.bin.display())),
582 }
583}
584
585fn beside_this_executable() -> Option<PathBuf> {
587 let exe = std::env::current_exe().ok()?;
588 let exe = std::fs::canonicalize(&exe).unwrap_or(exe);
589 exe.parent().map(Path::to_path_buf)
590}
591
592fn runtime_from_check(id: RuntimeId, worker: Worker, report: &Value) -> Result<Runtime, String> {
593 let reported = report["runtime"]["id"].as_str().unwrap_or_default();
594 if reported != id.base().name() {
595 return Err(format!("{} is not the {id} runtime's worker (it reports '{reported}')", worker.bin.display()));
596 }
597 let speaks: Vec<u64> = report["link_w"].as_array().map(|a| a.iter().filter_map(Value::as_u64).collect()).unwrap_or_default();
598 let ours = u64::from(superfluid_agent::client::PROTO_VERSION);
599 if !speaks.contains(&ours) {
600 let fix = if worker.source == Source::Installed && speaks.iter().all(|v| *v < ours) {
601 format!("`{}` installs it again with this superfluid's worker", repair_command(id))
602 } else {
603 "update the one that is older".to_string()
604 };
605 return Err(format!(
606 "the {id} runtime at {} speaks Link W {speaks:?} and this superfluid speaks {ours}: {fix}",
607 worker.bin.display()
608 ));
609 }
610 match &report["available"] {
611 Value::Bool(true) => {}
612 Value::String(why) if worker.source == Source::Shipped => {
613 return Err(format!("the {id} runtime is not installed: {why}"));
614 }
615 Value::String(why) => {
616 return Err(format!(
617 "the {id} runtime at {} cannot run here: {why}{}",
618 worker.bin.display(),
619 if worker.source == Source::Installed {
620 format!(" (`{}` reinstalls it)", repair_command(id))
621 } else {
622 String::new()
623 }
624 ))
625 }
626 other => return Err(format!("{} check reported availability {other}", worker.bin.display())),
627 }
628 Ok(Runtime {
629 id,
630 version: report["runtime"]["version"].as_str().map(str::to_string),
631 abi: report["runtime"]["abi"].as_u64(),
632 capabilities: report.get("capabilities").filter(|c| c.as_object().is_some_and(|o| !o.is_empty())).map(Value::to_string),
633 info: Info::from_report(report),
634 devices: superfluid_worker::check::devices_from(&report["devices"]),
635 tokenizer: None,
636 pull: report.get("pull").map(|p| {
637 p["options"]
638 .as_array()
639 .map(|a| a.iter().filter_map(|o| Some((o["name"].as_str()?.to_string(), o["value"].as_bool().unwrap_or(false)))).collect())
640 .unwrap_or_default()
641 }),
642 options: superfluid_worker::check::options_from(&report["options"]),
643 worker,
644 })
645}
646
647#[cfg(test)]
648pub(crate) mod tests {
649 use super::*;
650 use std::os::unix::fs::PermissionsExt;
651
652 fn scratch(tag: &str) -> PathBuf {
653 let d = std::env::temp_dir().join(format!("superfluid-runtimes-{tag}-{}", std::process::id()));
654 let _ = std::fs::remove_dir_all(&d);
655 std::fs::create_dir_all(&d).unwrap();
656 d
657 }
658
659 pub(crate) fn fake_worker(dir: &Path, name: &str, report: &str, exit: i32) -> PathBuf {
660 let p = dir.join(name);
661 std::fs::write(&p, format!("#!/bin/sh\ncat <<'EOF'\n{report}\nEOF\nexit {exit}\n")).unwrap();
662 std::fs::set_permissions(&p, std::fs::Permissions::from_mode(0o755)).unwrap();
663 p
664 }
665
666 pub(crate) fn report(id: &str, link_w: u16, available: &str) -> String {
667 let (aliases, formats, tokenizer) = match id {
668 "llamacpp" => (
669 r#"["llama.cpp"]"#,
670 r#"[{"id":"gguf","describe":"a GGUF file","file":{"extensions":["gguf"],"magic":"GGUF"}}]"#,
671 r#"{"from":"library","name":"superfluid_tokenizer_llamacpp"}"#,
672 ),
673 "mlx" => (
674 "[]",
675 r#"[{"id":"mlx","describe":"an MLX model directory","directory":{"files":["config.json"],"extensions":["safetensors"]}}]"#,
676 r#"{"from":"huggingface"}"#,
677 ),
678 _ => (
679 r#"["native"]"#,
680 r#"[{"id":"base","describe":"a .base bundle","file":{"extensions":["base"],"magic":"BASE"}}]"#,
681 r#"{"from":"engine"}"#,
682 ),
683 };
684 format!(
685 r#"{{"runtime":{{"id":"{id}","version":"v1","aliases":{aliases}}},"link_w":[{link_w}],"available":{available},"formats":{formats},"tokenizer":{tokenizer},"devices":[{{"backend":"Metal","name":"Apple M5 Pro","memory":36000000000}}],"capabilities":{{"descriptor_version":1,"load":{{"kv_bits":"no such knob"}},"serving":{{"park_lossy":"no lossy encoding"}}}}}}"#
686 )
687 }
688
689 const V: u16 = superfluid_agent::client::PROTO_VERSION;
690
691 #[test]
692 fn a_worker_is_started_with_its_runtime_options_from_the_first_probe_on() {
693 crate::runtime_options::set(vec![(RuntimeId::new("optrt"), vec![("--lib".to_string(), "/custom/lib".to_string())])]);
695 let root = std::env::temp_dir().join(format!("superfluid-runtime-options-probe-{}", std::process::id()));
696 let _ = std::fs::remove_dir_all(&root);
697 let (beside, libexec) = (root.join("bin"), root.join("libexec").join("superfluid"));
698 std::fs::create_dir_all(&beside).unwrap();
699 std::fs::create_dir_all(&libexec).unwrap();
700 let toy = libexec.join("superfluid-worker-optrt");
701 std::fs::write(&toy, "#!/bin/sh\nprintf '{\"runtime\":{\"id\":\"optrt\",\"version\":\"v1\"},\"received\":\"%s\"}\n' \"$*\"\n").unwrap();
702 std::fs::set_permissions(&toy, std::fs::Permissions::from_mode(0o755)).unwrap();
703 let cat = Catalog::new(root.join("home"), Some(beside.clone()), beside.join("superfluid-workerd"));
704 let id = RuntimeId::new("optrt");
705 let w = cat.locate(id).unwrap();
706 assert_eq!(w.prefix, ["--lib", "/custom/lib"], "the options ride in the prefix");
707 assert!(cat.locate_plain(id).unwrap().prefix.is_empty());
708 let report = run_check_model(&w, None).unwrap();
709 assert_eq!(report["received"], "check --lib /custom/lib", "the first probe already carries them");
710 let rt = Runtime {
711 id,
712 worker: w,
713 version: None,
714 abi: None,
715 capabilities: None,
716 info: Info::default(),
717 devices: Vec::new(),
718 tokenizer: None,
719 pull: None,
720 options: Vec::new(),
721 };
722 let args = rt.serve_args(Path::new("/m"), 4096, 8, 0);
723 assert_eq!(args.iter().filter(|a| *a == "--lib").count(), 1, "once, from the prefix: {args:?}");
724 assert!(cat.locate(RuntimeId::new("otherrt")).is_none_or(|w| w.prefix.is_empty()), "another runtime's worker gets nothing");
725 let _ = std::fs::remove_dir_all(&root);
726 }
727
728 pub(crate) fn toy_report(id: &str, available: &str) -> String {
729 format!(
730 r#"{{"runtime":{{"id":"{id}","version":"v1"}},"link_w":[{V}],"available":{available},"formats":[{{"id":"toy","describe":"a toy file","file":{{"extensions":["toy"]}}}}],"tokenizer":{{"from":"huggingface"}}}}"#
731 )
732 }
733
734 fn catalog(home: &Path) -> Catalog {
735 Catalog::new(home.to_path_buf(), None, home.join("superfluid-workerd"))
736 }
737
738 fn install_fake(home: &Path, id: &str, report_text: &str, exit: i32) -> PathBuf {
739 let bin_dir = home.join("runtimes").join(id).join("current/bin");
740 std::fs::create_dir_all(&bin_dir).unwrap();
741 fake_worker(&bin_dir, &format!("superfluid-worker-{id}"), report_text, exit)
742 }
743
744 #[test]
745 fn a_models_sizing_is_read_from_its_runtimes_check() {
746 let dir = scratch("sizing");
747 let with_model = |model: &str| {
748 let r = report("llamacpp", V, "true");
749 format!("{},\"model\":{model}}}", &r[..r.len() - 1])
750 };
751 let rt = |name: &str, text: &str| Runtime {
752 id: RuntimeId::new("llamacpp"),
753 worker: Worker { bin: fake_worker(&dir, name, text, 0), prefix: Vec::new(), source: Source::Env },
754 version: None,
755 abi: None,
756 capabilities: None,
757 info: Info::default(),
758 devices: Vec::new(),
759 tokenizer: None,
760 pull: None,
761 options: Vec::new(),
762 };
763 let model = Path::new("/m.gguf");
764 let figures = r#"{"budget_bytes":34000000000,"weight_bytes":600000000,"kv_bytes_per_token":114688,"trained_context":40960}"#;
765 let sized = rt("sized", &with_model(&format!(r#"{{"path":"/m.gguf","reads":true,"sizing":{figures}}}"#)));
766 assert_eq!(
767 sizing_of(&sized, model),
768 Ok(superfluid_adapter_kit::Sizing {
769 budget_bytes: 34_000_000_000,
770 weight_bytes: 600_000_000,
771 kv_bytes_per_token: 114_688,
772 trained_context: 40_960
773 })
774 );
775 let declined = rt(
776 "declined",
777 &with_model(r#"{"path":"/m.gguf","reads":true,"sizing":"the llamacpp runtime sizes no window on Vulkan yet"}"#),
778 );
779 assert_eq!(sizing_of(&declined, model), Err("the llamacpp runtime sizes no window on Vulkan yet".to_string()));
780 let silent = rt("silent", &with_model(r#"{"path":"/m.gguf","reads":true}"#));
781 assert_eq!(sizing_of(&silent, model), Err("the llamacpp runtime sizes no context window here".to_string()));
782 let garbled = rt("garbled", &with_model(r#"{"path":"/m.gguf","reads":true,"sizing":{"budget_bytes":1}}"#));
783 assert!(sizing_of(&garbled, model).unwrap_err().contains("reported a sizing this superfluid does not read"));
784 }
785
786 #[test]
787 fn an_installed_package_is_found_checked_and_remembered() {
788 let llamacpp = RuntimeId::new("llamacpp");
789 if crate::linked::get(llamacpp).is_some() {
790 return;
791 }
792 let home = scratch("installed");
793 let w = install_fake(&home, "llamacpp", &report("llamacpp", V, "true"), 0);
794 let cat = catalog(&home);
795 let found: Vec<RuntimeId> = cat.ids().into_iter().filter(|i| crate::linked::get(*i).is_none()).collect();
796 assert_eq!(found, vec![llamacpp]);
797 let e = cat.require(llamacpp).unwrap_err();
798 assert!(e.ends_with("ships no tokenizer library (libsuperfluid_tokenizer_llamacpp.dylib beside it or in ../lib)")
799 || e.ends_with("ships no tokenizer library (libsuperfluid_tokenizer_llamacpp.so beside it or in ../lib)"), "{e}");
800 let lib_dir = home.join("runtimes/llamacpp/current/lib");
801 std::fs::create_dir_all(&lib_dir).unwrap();
802 let lib = lib_dir.join(crate::dylib_tokenizer::library_file("superfluid_tokenizer_llamacpp"));
803 std::fs::write(&lib, b"").unwrap();
804 let rt = cat.require(llamacpp).unwrap();
805 let pinned = w.canonicalize().unwrap();
806 assert_eq!(rt.worker, Worker { bin: pinned, prefix: vec![], source: Source::Installed });
807 assert_eq!(rt.version.as_deref(), Some("v1"));
808 assert_eq!(rt.info.aliases, ["llama.cpp"]);
809 assert_eq!(rt.device().unwrap().summary(), "Metal: Apple M5 Pro, 36.0 GB");
810 assert_eq!(rt.tokenizer.as_deref().map(|p| p.canonicalize().unwrap()), Some(lib.canonicalize().unwrap()));
811 assert_eq!(rt.static_capabilities().check_startup_flags(true, None, None).unwrap_err(), "--park-lossy: no lossy encoding");
812 let args = rt.serve_args(Path::new("/m.gguf"), 4096, 4, 8);
813 assert_eq!(args, ["--model", "/m.gguf", "--max-context", "4096", "--max-batch", "4"], "its record refuses --kv-bits");
814 }
815
816 #[test]
817 fn the_home_is_never_relative_to_the_working_directory() {
818 assert_eq!(home_from(Some("/srv/superfluid".into()), Some("/home/u".into())), PathBuf::from("/srv/superfluid"));
819 assert_eq!(home_from(None, Some("/home/u".into())), PathBuf::from("/home/u/.superfluid"));
820 assert_eq!(home_from(Some("".into()), Some("/home/u".into())), PathBuf::from("/home/u/.superfluid"), "an empty variable is unset");
821 assert_eq!(home_from(None, None), PathBuf::from("/.superfluid"));
822 assert_eq!(home_from(None, Some("".into())), PathBuf::from("/.superfluid"));
823 assert_eq!(home_from(None, Some(".".into())), PathBuf::from("/.superfluid"));
824 }
825
826 fn counting_worker(dir: &Path, name: &str, report: &str, tally: &Path) -> PathBuf {
827 std::fs::create_dir_all(dir).unwrap();
828 let p = dir.join(name);
829 std::fs::write(&p, format!("#!/bin/sh\necho run >> '{}'\ncat <<'EOF'\n{report}\nEOF\n", tally.display())).unwrap();
830 std::fs::set_permissions(&p, std::fs::Permissions::from_mode(0o755)).unwrap();
831 p
832 }
833
834 fn runs(tally: &Path) -> usize {
835 std::fs::read_to_string(tally).map(|t| t.lines().count()).unwrap_or(0)
836 }
837
838 #[test]
839 fn a_remembered_runtime_whose_worker_is_gone_is_looked_for_again() {
840 let home = scratch("regone");
841 let toyrt = RuntimeId::new("toyrt");
842 let tally = home.join("tally");
843 let pkg = home.join("runtimes/toyrt");
844 counting_worker(&pkg.join("b1/bin"), "superfluid-worker-toyrt", &toy_report("toyrt", "true"), &tally);
845 std::os::unix::fs::symlink("b1", pkg.join("current")).unwrap();
846 let cat = catalog(&home);
847 let first = cat.require(toyrt).unwrap();
848 assert!(cat.require(toyrt).is_ok());
849 assert_eq!(runs(&tally), 1, "a usable runtime is checked once");
850 counting_worker(&pkg.join("b2/bin"), "superfluid-worker-toyrt", &toy_report("toyrt", "true"), &tally);
851 std::fs::remove_file(pkg.join("current")).unwrap();
852 std::os::unix::fs::symlink("b2", pkg.join("current")).unwrap();
853 assert_eq!(cat.require(toyrt).unwrap().worker, first.worker);
854 assert_eq!(runs(&tally), 1);
855 std::fs::remove_dir_all(pkg.join("b1")).unwrap();
856 let again = cat.require(toyrt).unwrap();
857 assert_eq!(again.worker.bin, pkg.join("b2/bin/superfluid-worker-toyrt").canonicalize().unwrap());
858 assert_eq!(runs(&tally), 2);
859 std::fs::remove_dir_all(pkg.join("b2")).unwrap();
860 let e = cat.require(toyrt).unwrap_err();
861 assert!(e.starts_with("the toyrt runtime is not installed"), "{e}");
862 }
863
864 #[test]
865 fn a_model_asks_no_runtime_past_the_first_that_serves_it() {
866 let home = scratch("lazy");
867 let (aart, zzrt) = (RuntimeId::new("aart"), RuntimeId::new("zzrt"));
868 let (asked_a, asked_z) = (home.join("asked-a"), home.join("asked-z"));
869 counting_worker(&home.join("runtimes/aart/current/bin"), "superfluid-worker-aart", &toy_report("aart", "true"), &asked_a);
870 let reads_zz = toy_report("zzrt", "true").replace(r#""extensions":["toy"]"#, r#""extensions":["zz"]"#);
871 counting_worker(&home.join("runtimes/zzrt/current/bin"), "superfluid-worker-zzrt", &reads_zz, &asked_z);
872 let cat = catalog(&home);
873 let toy = home.join("m.toy");
874 std::fs::write(&toy, b"toy").unwrap();
875 assert_eq!(cat.reader_of(&toy).unwrap(), aart);
876 assert_eq!((runs(&asked_a), runs(&asked_z)), (1, 0), "the runtime after the reader was not run");
877 assert!(cat.require(aart).is_ok());
878 assert_eq!(runs(&asked_a), 1, "and the reader was not checked a second time");
879 let zz = home.join("m.zz");
880 std::fs::write(&zz, b"zz").unwrap();
881 assert_eq!(cat.reader_of(&zz).unwrap(), zzrt);
882 assert_eq!(runs(&asked_z), 1);
883 }
884
885 #[test]
886 fn a_pick_of_one_install_leaves_later_models_on_the_default() {
887 let home = scratch("pinned-reader");
888 let toyrt = RuntimeId::new("toyrt");
889 let pkg = home.join("runtimes/toyrt");
890 for b in ["b1", "b2"] {
891 let bin = pkg.join(b).join("bin");
892 std::fs::create_dir_all(&bin).unwrap();
893 fake_worker(&bin, "superfluid-worker-toyrt", &toy_report("toyrt", "true"), 0);
894 }
895 std::os::unix::fs::symlink("b2", pkg.join("current")).unwrap();
896 let cat = catalog(&home);
897 let pinned = cat.require(RuntimeId::parse("toyrt@b1").unwrap()).unwrap();
898 assert_eq!(pinned.worker.bin, pkg.join("b1/bin/superfluid-worker-toyrt").canonicalize().unwrap());
899 let model = home.join("m.toy");
900 std::fs::write(&model, b"toy").unwrap();
901 assert_eq!(cat.reader_of(&model).unwrap(), toyrt, "the runtime, not the install another model picked");
902 assert_eq!(cat.readers(&model).into_iter().map(|(id, _)| id).collect::<Vec<_>>(), [toyrt]);
903 let served = cat.require(toyrt).unwrap();
904 assert_eq!(served.worker.bin, pkg.join("b2/bin/superfluid-worker-toyrt").canonicalize().unwrap());
905 }
906
907 #[test]
908 fn an_adapter_a_release_ships_is_known_before_its_runtime_is_installed() {
909 for flat in [false, true] {
910 let root = scratch(if flat { "shipped-flat" } else { "shipped-sdk" });
911 let beside = if flat { root.clone() } else { root.join("bin") };
912 let libexec = root.join("libexec").join("superfluid");
913 std::fs::create_dir_all(&beside).unwrap();
914 std::fs::create_dir_all(&libexec).unwrap();
915 let not_found = r#""toyrt not found: install it with `superfluid runtime install toyrt`""#;
916 let adapter = fake_worker(&libexec, "superfluid-worker-toyrt", &toy_report("toyrt", not_found), 1).canonicalize().unwrap();
917 std::fs::write(libexec.join("libsuperfluid_tokenizer_toyrt.dylib"), b"").unwrap();
918 let home = root.join("home");
919 let catalog = || Catalog::new(home.clone(), Some(beside.clone()), beside.join("superfluid-workerd"));
920 let (toyrt, vllm) = (RuntimeId::new("toyrt"), RuntimeId::new("vllm"));
921
922 let cat = catalog();
923 assert_eq!(cat.shipped_ids(), vec![toyrt], "flat: {flat}");
924 assert!(cat.ids().contains(&toyrt));
925 assert_eq!(cat.named("toyrt").unwrap(), toyrt);
926 assert_eq!(cat.locate(toyrt).unwrap(), Worker { bin: adapter.clone(), prefix: vec![], source: Source::Shipped });
927 assert_eq!(
928 cat.require(toyrt).unwrap_err(),
929 "the toyrt runtime is not installed: toyrt not found: install it with `superfluid runtime install toyrt`"
930 );
931 let model = root.join("m.toy");
932 std::fs::write(&model, b"toy").unwrap();
933 assert_eq!(cat.reader_of(&model).unwrap(), toyrt);
934 assert_eq!(cat.reads(toyrt, &model), Ok(()));
935 assert_eq!(crate::installs::installer(&cat, toyrt).unwrap(), adapter);
936 let e = cat.require(vllm).unwrap_err();
937 assert!(e.starts_with("the vllm runtime is not here: this superfluid ships no adapter for it (it ships: toyrt)"), "{e}");
938 assert_eq!(
939 crate::installs::installer(&cat, vllm).unwrap_err(),
940 "this superfluid ships no adapter to install the vllm runtime with (it ships: toyrt)"
941 );
942
943 let installed = install_fake(&home, "toyrt", &toy_report("toyrt", "true"), 0).canonicalize().unwrap();
944 let cat = catalog();
945 assert_eq!(cat.locate(toyrt).unwrap(), Worker { bin: installed, prefix: vec![], source: Source::Installed });
946 assert!(cat.require(toyrt).is_ok());
947 assert_eq!(crate::installs::installer(&cat, toyrt).unwrap(), adapter);
948 }
949 }
950
951 #[test]
952 fn a_source_build_ships_no_adapter() {
953 let beside = scratch("no-libexec");
954 let cat = Catalog::new(scratch("no-libexec-home"), Some(beside), PathBuf::from("/nonexistent/superfluid-workerd"));
955 let vllm = RuntimeId::new("vllm");
956 assert!(cat.shipped_ids().is_empty());
957 assert_eq!(cat.shipped(vllm), None);
958 let e = cat.require(vllm).unwrap_err();
959 assert!(e.contains("cargo build -p superfluid-adapter-vllm"), "{e}");
960 let e = crate::installs::installer(&cat, vllm).unwrap_err();
961 assert!(e.starts_with("no superfluid-worker-vllm to install the vllm runtime with") && e.contains("cargo build"), "{e}");
962 }
963
964 #[test]
965 fn a_worker_beside_superfluid_wins_over_an_installed_one() {
966 let vllm = RuntimeId::new("vllm");
967 let home = scratch("beside-home");
968 let beside = scratch("beside-exe");
969 install_fake(&home, "vllm", &report("vllm", V, "true"), 0);
970 let mine = fake_worker(&beside, "superfluid-worker-vllm", &report("vllm", V, "true"), 0);
971 std::fs::write(beside.join("superfluid-worker-vllm.d"), b"").unwrap();
972 let cat = Catalog::new(home, Some(beside), PathBuf::from("/nonexistent/superfluid-workerd"));
973 assert_eq!(cat.locate(vllm).unwrap(), Worker { bin: mine, prefix: vec![], source: Source::BesideDaemon });
974 assert!(cat.ids().contains(&vllm) && !cat.ids().iter().any(|i| i.name().ends_with(".d")));
975 }
976
977 #[test]
978 fn a_runtime_this_build_links_is_served_by_this_build() {
979 let beside = scratch("linked-beside");
980 let workerd = beside.join("superfluid-workerd");
981 for id in crate::linked::ids() {
982 fake_worker(&beside, &worker_name(id), &report(id.name(), V, "true"), 0);
983 let cat = Catalog::new(scratch("linked-home"), Some(beside.clone()), workerd.clone());
984 let worker = cat.locate(id).unwrap();
985 assert_eq!(worker, Worker { bin: workerd.clone(), prefix: vec!["--engine".into(), id.name().into()], source: Source::BuiltIn });
986 }
987 }
988
989 #[test]
990 fn a_program_named_as_the_workerd_is_started_as_one() {
991 let program = scratch("embedder").join("embedding-program");
992 let cat = Catalog::with_workerd(program.clone());
993 assert_eq!(cat.workerd(), program.as_path());
994 for id in crate::linked::ids() {
995 let worker = cat.locate(id).unwrap();
996 assert_eq!(worker.bin, program);
997 let serve: Vec<String> = worker.prefix.iter().cloned().chain(["--model".into(), "m".into()]).collect();
1001 assert!(crate::workerd::is_invocation(&serve), "{serve:?}");
1002 let check: Vec<String> = std::iter::once("check".to_string()).chain(worker.prefix.iter().cloned()).collect();
1003 assert!(crate::workerd::is_invocation(&check), "{check:?}");
1004 }
1005 }
1006
1007 #[test]
1008 fn what_is_missing_or_broken_says_why_and_how_to_fix_it() {
1009 let mlx = RuntimeId::new("mlx");
1010 if crate::linked::get(mlx).is_some() {
1011 return;
1012 }
1013 let home = scratch("broken");
1014 let cat = catalog(&home);
1015 let e = cat.require(mlx).unwrap_err();
1016 assert!(e.starts_with("the mlx runtime is not installed: no superfluid-worker-mlx in "), "{e}");
1017 assert!(e.contains("`superfluid runtime install mlx`") && e.contains("cargo build -p superfluid-adapter-mlx"), "{e}");
1018
1019 let w = install_fake(&home, "mlx", &report("mlx", V, r#""ModuleNotFoundError: No module named 'mlx'""#), 1);
1020 let e = cat.require(mlx).unwrap_err();
1021 let pinned = w.canonicalize().unwrap();
1022 assert_eq!(
1023 e,
1024 format!(
1025 "the mlx runtime at {} cannot run here: ModuleNotFoundError: No module named 'mlx' (`superfluid runtime repair mlx` reinstalls it)",
1026 pinned.display()
1027 )
1028 );
1029 let found = cat.inspect(mlx);
1030 assert_eq!(found.info.unwrap().formats[0].id, "mlx");
1031
1032 install_fake(&home, "mlx", &report("mlx", V + 1, "true"), 0);
1033 let e = cat.require(mlx).unwrap_err();
1034 assert!(e.contains(&format!("speaks Link W [{}] and this superfluid speaks {V}", V + 1)), "{e}");
1035 assert!(e.ends_with("update the one that is older"), "a newer worker: superfluid is the older one: {e}");
1036 install_fake(&home, "mlx", &report("mlx", V - 1, "true"), 0);
1037 let e = cat.require(mlx).unwrap_err();
1038 assert!(e.contains(&format!("speaks Link W [{}] and this superfluid speaks {V}", V - 1)), "{e}");
1039 assert!(e.ends_with("`superfluid runtime repair mlx` installs it again with this superfluid's worker"), "{e}");
1040 let old = home.join("runtimes/mlx/old/bin");
1041 std::fs::create_dir_all(&old).unwrap();
1042 fake_worker(&old, "superfluid-worker-mlx", &report("mlx", V - 1, "true"), 0);
1043 let e = cat.require(RuntimeId::parse("mlx@old").unwrap()).unwrap_err();
1044 assert!(e.ends_with("`superfluid runtime repair mlx old` installs it again with this superfluid's worker"), "{e}");
1045 fake_worker(&old, "superfluid-worker-mlx", &report("mlx", V, r#""no Metal device""#), 1);
1046 let e = cat.require(RuntimeId::parse("mlx@old").unwrap()).unwrap_err();
1047 assert!(e.ends_with("cannot run here: no Metal device (`superfluid runtime repair mlx old` reinstalls it)"), "{e}");
1048 let e = cat.not_here("mlx@gone", Path::new("/m"), "mlx has no install gone here");
1049 assert!(e.ends_with("`superfluid runtime install mlx` installs mlx"), "{e}");
1050
1051 install_fake(&home, "mlx", &report("llamacpp", V, "true"), 0);
1052 assert!(cat.require(mlx).unwrap_err().contains("is not the mlx runtime's worker"));
1053
1054 std::fs::write(&w, "#!/bin/sh\necho 'dyld: Library not loaded: libpython3.12.dylib' >&2\nexit 134\n").unwrap();
1055 let e = cat.require(mlx).unwrap_err();
1056 assert!(e.contains("check failed") && e.ends_with("dyld: Library not loaded: libpython3.12.dylib"), "{e}");
1057
1058 install_fake(&home, "mlx", &report("mlx", V, "true"), 0);
1059 assert_eq!(cat.require(mlx).unwrap().version.as_deref(), Some("v1"));
1060 }
1061
1062 #[test]
1063 fn a_worker_that_declares_no_formats_is_named_as_older() {
1064 let old = RuntimeId::new("oldrt");
1065 let home = scratch("old");
1066 install_fake(&home, "oldrt", &format!(r#"{{"runtime":{{"id":"oldrt","version":"v0"}},"link_w":[{V}],"available":true}}"#), 0);
1067 let cat = catalog(&home);
1068 assert!(cat.inspect(old).info.unwrap().formats.is_empty());
1069 let file = scratch("old-model").join("m.weights");
1070 std::fs::write(&file, b"????").unwrap();
1071 let e = cat.reader_of(&file).unwrap_err();
1072 assert!(e.contains("oldrt reads no format: its worker declares none, so it is older than this superfluid (rebuild or update it)"), "{e}");
1073 }
1074
1075 #[test]
1076 fn a_model_two_runtimes_read_goes_to_the_one_that_can_run() {
1077 let (broken, working) = (RuntimeId::new("abroken"), RuntimeId::new("zworking"));
1078 let toy = |id: &str, available: &str| {
1079 format!(
1080 r#"{{"runtime":{{"id":"{id}","version":"v1"}},"link_w":[{V}],"available":{available},"formats":[{{"id":"toy","describe":"a toy file","file":{{"extensions":["toy"]}}}}],"tokenizer":{{"from":"huggingface"}}}}"#
1081 )
1082 };
1083 let home = scratch("two-readers");
1084 install_fake(&home, "abroken", &toy("abroken", r#""library missing""#), 1);
1085 install_fake(&home, "zworking", &toy("zworking", "true"), 0);
1086 let file = scratch("two-readers-model").join("m.toy");
1087 std::fs::write(&file, b"toy").unwrap();
1088
1089 let cat = catalog(&home);
1090 let listed: Vec<RuntimeId> = cat.readers(&file).into_iter().map(|(id, _)| id).collect();
1091 assert_eq!(listed, vec![working, broken], "the one that cannot run stays listed, after the one that can");
1092 assert_eq!(cat.reader_of(&file).unwrap(), working, "the reader that can run, not the first by name");
1093 assert_eq!(crate::runtime_pick::RuntimePick::default().resolve(&file, &cat).unwrap(), working);
1094 assert!(cat.require(working).is_ok());
1095 let fresh = catalog(&home);
1096 let e = fresh.not_here("vllm", &file, "no runtime 'vllm' here");
1097 assert!(e.contains("which zworking here reads: pass --runtime zworking"), "{e}");
1098
1099 let alone = scratch("one-broken-reader");
1100 install_fake(&alone, "abroken", &toy("abroken", r#""library missing""#), 1);
1101 let cat = catalog(&alone);
1102 assert_eq!(cat.reader_of(&file).unwrap(), broken);
1103 let e = cat.require(broken).unwrap_err();
1104 assert!(e.contains("cannot run here: library missing"), "{e}");
1105 }
1106
1107 #[test]
1108 fn a_runtime_is_named_by_its_id_or_an_alias_it_declares() {
1109 if crate::linked::get(RuntimeId::new("llamacpp")).is_some() {
1110 return;
1111 }
1112 let home = scratch("named");
1113 install_fake(&home, "llamacpp", &report("llamacpp", V, "true"), 0);
1114 let cat = catalog(&home);
1115 assert_eq!(cat.named("llamacpp").unwrap(), RuntimeId::new("llamacpp"));
1116 assert_eq!(cat.named("llama.cpp").unwrap(), RuntimeId::new("llamacpp"), "an alias the runtime declares");
1117 assert_eq!(cat.named("vllm").unwrap_err(), "no runtime 'vllm' here");
1118 }
1119
1120 #[test]
1121 fn the_runtime_for_a_model_is_the_one_whose_format_it_is() {
1122 let (llamacpp, mlx) = (RuntimeId::new("llamacpp"), RuntimeId::new("mlx"));
1123 if crate::linked::get(llamacpp).is_some() || crate::linked::get(mlx).is_some() {
1124 return;
1125 }
1126 let home = scratch("formats");
1127 install_fake(&home, "llamacpp", &report("llamacpp", V, "true"), 0);
1128 let lib = home.join("runtimes/llamacpp/current/lib");
1129 std::fs::create_dir_all(&lib).unwrap();
1130 std::fs::write(lib.join(crate::dylib_tokenizer::library_file("superfluid_tokenizer_llamacpp")), b"").unwrap();
1131 install_fake(&home, "mlx", &report("mlx", V, "true"), 0);
1132 let cat = catalog(&home);
1133 let models = scratch("formats-models");
1134 let gguf = models.join("weights.bin");
1135 std::fs::write(&gguf, b"GGUF\x03\x00").unwrap();
1136 let dir = models.join("qwen-mlx");
1137 std::fs::create_dir_all(&dir).unwrap();
1138 std::fs::write(dir.join("config.json"), b"{}").unwrap();
1139 std::fs::write(dir.join("model.safetensors"), b"").unwrap();
1140 let notes = models.join("notes.txt");
1141 std::fs::write(¬es, b"hello").unwrap();
1142
1143 assert_eq!(cat.reader_of(&gguf).unwrap(), llamacpp, "by the magic its format declares");
1144 assert_eq!(cat.reader_of(&dir).unwrap(), mlx);
1145 let e = cat.reader_of(¬es).unwrap_err();
1146 assert!(e.starts_with(&format!("no runtime here reads {}", notes.display())), "{e}");
1147 assert!(e.contains("llamacpp reads a GGUF file; mlx reads an MLX model directory"), "{e}");
1148 assert!(e.contains("`superfluid runtime install <id>`"), "{e}");
1149
1150 let e = cat.reads(mlx, &gguf).unwrap_err();
1151 assert_eq!(
1152 e,
1153 format!(
1154 "runtime mlx cannot serve {}: it reads an MLX model directory, and this is a GGUF file (pass --runtime llamacpp, or convert the model)",
1155 gguf.display()
1156 )
1157 );
1158 let mut pick = crate::runtime_pick::RuntimePick::default();
1159 pick.add("vllm").unwrap();
1160 let e = pick.resolve(&gguf, &cat).unwrap_err();
1161 assert!(e.starts_with(&format!("no runtime 'vllm' here to serve {}", gguf.display())), "{e}");
1162 assert!(e.contains("it is a GGUF file, which llamacpp here reads: pass --runtime llamacpp"), "{e}");
1163 assert!(e.ends_with("`superfluid runtime install vllm` installs vllm"), "{e}");
1164 assert_eq!(crate::runtime_pick::RuntimePick::default().resolve(&dir, &cat).unwrap(), mlx);
1165 let mut pick = crate::runtime_pick::RuntimePick::default();
1166 pick.add("llama.cpp").unwrap();
1167 assert_eq!(pick.resolve(&gguf, &cat).unwrap(), llamacpp);
1168 }
1169}