1use superfluid_abi::{encoding, MAX_TOP_LOGPROBS};
4use serde_json::{json, Map, Value};
5
6use crate::primitives::{RuntimeDescriptor, SamplingDefaults};
7
8fn cap(reason: Option<String>) -> Value {
9 reason.map(Value::String).unwrap_or(Value::Bool(true))
10}
11
12fn no(reason: impl Into<String>) -> Value {
13 Value::String(reason.into())
14}
15
16fn sampling_defaults(sd: &SamplingDefaults) -> Option<Value> {
17 let mut m = Map::new();
18 let mut put = |k: &str, v: Option<Value>| {
19 if let Some(v) = v {
20 m.insert(k.to_string(), v);
21 }
22 };
23 put("temperature", sd.temperature.map(|x| json!(x)));
24 put("top_p", sd.top_p.map(|x| json!(x)));
25 put("top_k", sd.top_k.map(|x| json!(x)));
26 put("min_p", sd.min_p.map(|x| json!(x)));
27 put("repetition_penalty", sd.repetition_penalty.map(|x| json!(x)));
28 if let Some(d) = sd.do_sample {
29 m.insert("do_sample".to_string(), Value::Bool(d));
30 }
31 (!m.is_empty()).then_some(Value::Object(m))
32}
33
34pub fn static_descriptor(id: &str, export_encodings: &[u8], verify_rows: bool) -> serde_json::Value {
37 let lossy = export_encodings.iter().any(|e| *e != encoding::LOSSLESS);
38 let media = || no(format!("the {id} runtime has no media path"));
39 let lora = || no(format!("the {id} runtime loads no LoRA"));
40 json!({
41 "descriptor_version": 1,
42 "runtime": {"id": id},
43 "load": {
44 "paged_kv": false,
45 "prefix_cache": true,
46 "kv_bits": no(format!("the {id} runtime keeps its KV type per context and exposes no such knob")),
47 },
48 "workload": {
49 "causal_generation": true,
50 "embedding": no(format!("the {id} runtime serves generation; it has no embedding path")),
51 "speech_to_text": no("not a speech model"),
52 },
53 "modalities": {
54 "image_encode": media(),
55 "gemma_audio_encode": media(),
56 "whisper_transcribe": no("not a Whisper model"),
57 "whisper_translate": no("not a Whisper model"),
58 },
59 "serving": {
60 "sequences": true,
61 "host_logits": true,
62 "multi_row_verification": if verify_rows {
63 Value::Bool(true)
64 } else {
65 no(format!("the {id} runtime registers no speculation strategy"))
66 },
67 "speculation_strategies": if verify_rows { json!([crate::speculate::STRATEGY_ID]) } else { json!([]) },
68 "prefix_seed": true,
69 "park_lossless": export_encodings.contains(&encoding::LOSSLESS),
70 "park_lossy": cap((!lossy).then(|| format!("the {id} runtime exports no lossy encoding"))),
71 "round_granular": true,
72 },
73 "state": {"legacy_save_load": no("the native engine's state-file API")},
74 "adaptation": {"lora_load": lora(), "lora_active_on_inference": lora()},
75 "ops": {
76 "snapshot_restore": true,
77 "seq_fork": true,
78 "space_promote": no("no demoted tier: parks are lossless exports"),
79 "cache_evict_entries": true,
80 },
81 "sampling": {"logit_bias": true, "penalties": true, "top_logprobs_max": MAX_TOP_LOGPROBS},
82 "determinism": {
83 "seed_reproducible": true,
84 "batch_invariant": no("a batched round or another prefill chunking moves logits by rounding"),
85 },
86 })
87}
88
89pub fn model_facts(architecture: &str, sd: &SamplingDefaults) -> Value {
90 let mut v = json!({"architecture": architecture});
91 if let Some(s) = sampling_defaults(sd) {
92 v["sampling_defaults"] = s;
93 }
94 v
95}
96
97pub(crate) fn descriptor(d: &RuntimeDescriptor, grammar: bool) -> String {
98 let id = d.runtime_id.as_str();
99 let mut v = static_descriptor(id, &d.export_encodings, d.verify_rows);
100 if d.verify_rows && !d.truncate_partial {
101 v["serving"]["multi_row_verification"] = json!(format!(
102 "prompt-lookup cuts a rejected draft off, and this model's {} state cuts only at its head",
103 if d.recurrent { "recurrent" } else { "sliding-window" }
104 ));
105 v["serving"]["speculation_strategies"] = json!([]);
106 }
107 v["architecture"] = json!(d.architecture);
108 v["backend"] = json!(d.backend);
109 v["runtime"]["version"] = json!(d.runtime_version);
110 v["load"]["max_batch_size"] = json!(d.max_batch);
111 v["serving"]["tick_yield"] =
112 cap((d.prefill_step_tokens == 0).then(|| format!("the {id} runtime prefills a tick as one step")));
113 v["state"]["rollback"] = cap((!d.truncate_partial).then(|| "recurrent state cuts only at its head".to_string()));
114 v["state"]["shared_prefix_seed"] = cap((!d.truncate_partial).then(|| {
115 "a cached state seeds only a prompt that holds all of it: recurrent state cuts only at its head".to_string()
116 }));
117 v["state"]["recurrent_snapshot"] = cap((!d.recurrent).then(|| "no recurrent state in this architecture".to_string()));
118 v["sampling"]["grammar"] =
119 cap((!grammar).then(|| format!("the {id} runtime lists no vocabulary to compile grammars against")));
120 v["sampling"]["engine_argmax"] = json!(d.engine_sampling);
121 v["sampling"]["engine_draws"] = json!(d.engine_draws);
122 v["limits"] = json!({
123 "max_seq_len": d.max_seq_len,
124 "max_seqs": d.max_seqs,
125 "page_size_tokens": d.page_size_tokens,
126 "cells_total": d.cells_total,
127 "cache_resident_cells": d.cache_resident_cells,
128 "cache_exported_cells": d.cache_exported_cells,
129 });
130 if let Some(sd) = sampling_defaults(&d.sampling_defaults) {
131 v["sampling_defaults"] = sd;
132 }
133 v.to_string()
134}
135
136#[cfg(test)]
137mod tests {
138 use super::*;
139
140 fn desc() -> RuntimeDescriptor {
141 crate::fake::FakePrimitives::default().describe()
142 }
143
144 use crate::primitives::RuntimePrimitives;
145
146 #[test]
147 fn a_runtime_reports_what_it_lacks_in_its_own_words() {
148 let v: Value = serde_json::from_str(&descriptor(&desc(), false)).unwrap();
149 assert_eq!(v["descriptor_version"], 1);
150 assert_eq!(v["runtime"], json!({"id": "fake", "version": "1"}));
151 assert_eq!(v["serving"]["park_lossy"], "the fake runtime exports no lossy encoding");
152 assert_eq!(v["serving"]["park_lossless"], true);
153 assert_eq!(v["modalities"]["image_encode"], "the fake runtime has no media path");
154 assert_eq!(v["sampling"]["grammar"], "the fake runtime lists no vocabulary to compile grammars against");
155 assert_eq!(v["state"]["rollback"], true, "the fake cuts anywhere by default");
156 assert_eq!(v["state"]["shared_prefix_seed"], true);
157 assert!(v.get("sampling_defaults").is_none(), "a checkpoint that claims none carries none");
158 }
159
160 #[test]
161 fn a_models_facts_are_the_records_artifact_fields() {
162 let sd = SamplingDefaults { top_p: Some(0.95), ..Default::default() };
163 assert_eq!(model_facts("qwen3", &sd), json!({"architecture": "qwen3", "sampling_defaults": {"top_p": 0.95}}));
164 assert_eq!(model_facts("llama", &SamplingDefaults::default()), json!({"architecture": "llama"}));
165 }
166
167 #[test]
168 fn the_checkpoints_sampling_defaults_ride_along_and_only_what_it_claims() {
169 let mut d = desc();
170 d.sampling_defaults = SamplingDefaults { temperature: Some(0.6), top_k: Some(20), ..Default::default() };
171 d.truncate_partial = false;
172 let v: Value = serde_json::from_str(&descriptor(&d, true)).unwrap();
173 assert_eq!(v["sampling_defaults"], json!({"temperature": 0.6, "top_k": 20}));
174 assert_eq!(v["sampling"]["grammar"], true);
175 assert_eq!(v["state"]["rollback"], "recurrent state cuts only at its head");
176 assert!(v["state"]["shared_prefix_seed"].is_string(), "a burst on one prefix needs a kept copy");
177 }
178
179 #[test]
180 fn the_static_part_is_what_every_load_reports() {
181 let s = static_descriptor("fake", &[encoding::LOSSLESS], false);
182 let full: Value = serde_json::from_str(&descriptor(&desc(), false)).unwrap();
183 for (section, keys) in s.as_object().unwrap() {
184 let Some(keys) = keys.as_object() else { continue };
185 for (k, v) in keys {
186 if section == "runtime" {
187 continue;
188 }
189 assert_eq!(&full[section][k], v, "{section}.{k}");
190 }
191 }
192 }
193}