use agent_core::reasoning::ReasoningLevel;
use serde::Deserialize;
use super::{
capability_cache, CatalogModel, CatalogProviderKind, CatalogSource, Modality, PricingSummary,
ReasoningSupport,
};
pub const MUSE_PROVIDER_KEY: &str = "muse";
pub const MUSE_PROVIDER_NAME: &str = "Meta Muse";
pub const MUSE_MODELS_PATH: &str = "/muse-code/models";
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct MuseModelDescriptor {
pub id: &'static str,
pub label: &'static str,
}
pub const MUSE_TEXT_MODELS: &[MuseModelDescriptor] = &[MuseModelDescriptor {
id: "muse-wonder-1.0",
label: "Muse Wonder 1.0",
}];
pub fn muse_static_model(id: &str) -> Option<&'static MuseModelDescriptor> {
MUSE_TEXT_MODELS.iter().find(|model| model.id == id)
}
fn valid_muse_id(id: &str) -> bool {
let bytes = id.as_bytes();
!bytes.is_empty()
&& bytes.len() <= 128
&& bytes[0].is_ascii_alphanumeric()
&& bytes.iter().all(|b| {
b.is_ascii_lowercase() || b.is_ascii_digit() || matches!(b, b'.' | b'-' | b'_')
})
}
#[cfg(test)]
pub(crate) static TEST_CACHE_LOCK: std::sync::Mutex<()> = std::sync::Mutex::new(());
#[cfg(test)]
pub(crate) fn test_cache_guard() -> std::sync::MutexGuard<'static, ()> {
TEST_CACHE_LOCK
.lock()
.unwrap_or_else(|poisoned| poisoned.into_inner())
}
pub fn muse_routable_id(id: &str) -> bool {
valid_muse_id(id)
}
pub fn muse_runtime_model(id: &str) -> bool {
muse_static_model(id).is_some()
|| capability_cache::get(&format!("{MUSE_PROVIDER_KEY}/{id}"))
.is_some_and(|row| row.provider_key == MUSE_PROVIDER_KEY && row.id == id)
}
pub fn muse_supported_levels(id: &str) -> Option<Vec<ReasoningLevel>> {
match capability_cache::get(&format!("{MUSE_PROVIDER_KEY}/{id}"))?.reasoning {
ReasoningSupport::NamedEffort { supported, .. } if !supported.is_empty() => Some(supported),
_ => None,
}
}
pub fn muse_default_level(id: &str) -> Option<ReasoningLevel> {
match capability_cache::get(&format!("{MUSE_PROVIDER_KEY}/{id}"))?.reasoning {
ReasoningSupport::NamedEffort {
supported,
default_level: Some(level),
} if supported.contains(&level) => Some(level),
_ => None,
}
}
pub fn muse_effort_label(level: ReasoningLevel) -> Option<&'static str> {
match level {
ReasoningLevel::Off => Some("none"),
ReasoningLevel::Low => Some("low"),
ReasoningLevel::Medium => Some("medium"),
ReasoningLevel::High => Some("high"),
ReasoningLevel::XHigh => Some("xhigh"),
ReasoningLevel::Max => Some("max"),
ReasoningLevel::Ultra => Some("ultra"),
ReasoningLevel::Adaptive | ReasoningLevel::UltraCode => None,
}
}
fn parse_muse_effort(effort: &str) -> Option<ReasoningLevel> {
match effort {
"none" => Some(ReasoningLevel::Off),
"low" => Some(ReasoningLevel::Low),
"medium" => Some(ReasoningLevel::Medium),
"high" => Some(ReasoningLevel::High),
"xhigh" => Some(ReasoningLevel::XHigh),
"max" => Some(ReasoningLevel::Max),
"ultra" => Some(ReasoningLevel::Ultra),
_ => None,
}
}
fn muse_row(id: &str, label: Option<String>) -> CatalogModel {
CatalogModel {
provider_key: MUSE_PROVIDER_KEY.into(),
provider_name: MUSE_PROVIDER_NAME.into(),
provider_kind: CatalogProviderKind::Generic {
key: MUSE_PROVIDER_KEY.into(),
},
id: id.into(),
label,
context_tokens: None,
max_output_tokens: None,
input_modalities: vec![Modality::Text],
pricing: PricingSummary::default(),
reasoning: ReasoningSupport::Unknown,
source: CatalogSource::Live,
}
}
pub fn muse_static_catalog_models() -> Vec<CatalogModel> {
MUSE_TEXT_MODELS
.iter()
.map(|descriptor| {
let mut row = muse_row(descriptor.id, Some(descriptor.label.into()));
row.source = CatalogSource::StaticFallback;
row
})
.collect()
}
#[derive(Deserialize)]
struct MuseCatalogBody {
#[serde(default)]
models: Option<Vec<serde_json::Value>>,
#[serde(default)]
data: Option<Vec<serde_json::Value>>,
}
#[derive(Deserialize)]
struct MuseCatalogRow {
id: String,
#[serde(default)]
display_label: Option<String>,
#[serde(default)]
visibility: Option<String>,
#[serde(default)]
display_order: Option<i64>,
#[serde(default)]
context_limit: Option<u64>,
#[serde(default)]
output_limit: Option<u64>,
#[serde(default)]
reasoning_effort_variants: Option<Vec<MuseEffortVariant>>,
#[serde(default)]
metadata: Option<serde_json::Value>,
}
#[derive(Deserialize)]
struct MuseEffortVariant {
#[serde(default)]
effort: Option<String>,
}
#[derive(Deserialize, Default)]
struct MuseCodeMeta {
#[serde(default)]
is_hidden: Option<bool>,
#[serde(default)]
limit: Option<MuseLimit>,
#[serde(default)]
modalities: Option<MuseModalities>,
#[serde(default)]
options: Option<MuseOptions>,
#[serde(default)]
variants: Option<serde_json::Map<String, serde_json::Value>>,
}
#[derive(Deserialize, Default)]
struct MuseLimit {
#[serde(default)]
context: Option<u64>,
#[serde(default)]
output: Option<u64>,
}
#[derive(Deserialize, Default)]
struct MuseModalities {
#[serde(default)]
input: Option<Vec<String>>,
#[serde(default)]
output: Option<Vec<String>>,
}
#[derive(Deserialize, Default)]
#[serde(rename_all = "camelCase")]
struct MuseOptions {
#[serde(default)]
reasoning_effort: Option<String>,
}
fn effort_rank(level: ReasoningLevel) -> u8 {
match level {
ReasoningLevel::Off => 0,
ReasoningLevel::Low => 1,
ReasoningLevel::Medium => 2,
ReasoningLevel::High => 3,
ReasoningLevel::XHigh => 4,
ReasoningLevel::Max => 5,
ReasoningLevel::Ultra => 6,
ReasoningLevel::Adaptive | ReasoningLevel::UltraCode => u8::MAX,
}
}
fn push_unique(supported: &mut Vec<ReasoningLevel>, level: ReasoningLevel) {
if !supported.contains(&level) {
supported.push(level);
}
}
pub fn parse_muse_catalog_models(body: &str) -> Result<Vec<CatalogModel>, String> {
let parsed: MuseCatalogBody =
serde_json::from_str(body).map_err(|e| format!("invalid Muse catalog JSON: {e}"))?;
let rows = parsed
.models
.or(parsed.data)
.ok_or_else(|| "Muse catalog has no models array".to_string())?;
let mut ordered: Vec<(i64, usize, CatalogModel)> = Vec::new();
for (index, value) in rows.into_iter().enumerate() {
let Ok(row) = serde_json::from_value::<MuseCatalogRow>(value) else {
continue;
};
let meta: MuseCodeMeta = row
.metadata
.as_ref()
.and_then(|m| m.get("muse-code"))
.and_then(|m| serde_json::from_value(m.clone()).ok())
.unwrap_or_default();
let modalities = meta.modalities.unwrap_or_default();
let text_output = modalities
.output
.as_ref()
.is_none_or(|out| out.iter().any(|m| m == "text"));
if row.visibility.as_deref() == Some("hidden")
|| meta.is_hidden == Some(true)
|| !text_output
|| !valid_muse_id(&row.id)
{
continue;
}
if ordered.iter().any(|(_, _, existing)| existing.id == row.id) {
continue;
}
let label = row
.display_label
.map(|l| l.trim().to_string())
.filter(|l| !l.is_empty());
let mut model = muse_row(&row.id, label);
let limit = meta.limit.unwrap_or_default();
model.context_tokens = row.context_limit.or(limit.context).filter(|n| *n > 0);
model.max_output_tokens = row.output_limit.or(limit.output).filter(|n| *n > 0);
if let Some(input) = modalities.input.filter(|i| !i.is_empty()) {
let mut parsed = vec![Modality::Text];
for m in input.iter().map(|m| Modality::from_str(m.trim())) {
if !parsed.contains(&m) {
parsed.push(m);
}
}
model.input_modalities = parsed;
}
let mut supported = Vec::new();
for effort in row
.reasoning_effort_variants
.unwrap_or_default()
.into_iter()
.filter_map(|v| v.effort)
.filter_map(|e| parse_muse_effort(e.trim()))
{
push_unique(&mut supported, effort);
}
let mut variant_levels = Vec::new();
for variant in meta.variants.unwrap_or_default().into_values() {
let Some(effort) = variant.get("reasoningEffort").and_then(|e| e.as_str()) else {
continue;
};
if let Some(level) = parse_muse_effort(effort.trim()) {
push_unique(&mut variant_levels, level);
}
}
variant_levels.sort_by_key(|l| effort_rank(*l));
for level in variant_levels {
push_unique(&mut supported, level);
}
if !supported.is_empty() {
let default_level = meta
.options
.and_then(|o| o.reasoning_effort)
.and_then(|e| parse_muse_effort(e.trim()))
.filter(|level| supported.contains(level));
model.reasoning = ReasoningSupport::NamedEffort {
supported,
default_level,
};
}
ordered.push((row.display_order.unwrap_or(i64::MAX), index, model));
}
ordered.sort_by_key(|(order, index, _)| (*order, *index));
Ok(ordered.into_iter().map(|(_, _, model)| model).collect())
}
#[cfg(test)]
mod tests {
use super::*;
const LIVE: &str = r#"{"schema_version":1,"provider_id":"meta","source":"network","models":[
{"id":"muse-spark-1.3","display_label":"Muse Spark 1.3","visibility":"visible",
"display_order":2,"is_default":false,"context_limit":262144,"output_limit":128000,
"reasoning_effort_variants":[{"effort":"low","description":"l"},{"effort":"minimal"},
{"effort":"high"},{"effort":"high"},{"effort":"bogus"}]},
{"id":"muse-wonder-1.0","display_label":"Muse Wonder 1.0","visibility":"visible",
"display_order":1,"is_default":true,"context_limit":1000000,"output_limit":0,
"reasoning_effort_variants":[]},
{"id":"muse-internal-x","visibility":"hidden","display_order":0},
{"id":"Bad Id/../x","display_order":0},
{"display_label":"no id"},
{"id":"muse-novel-row","display_order":"not-a-number"}
]}"#;
#[test]
fn effort_labels_round_trip_and_adaptive_omits() {
for level in [
ReasoningLevel::Off,
ReasoningLevel::Low,
ReasoningLevel::Medium,
ReasoningLevel::High,
ReasoningLevel::XHigh,
ReasoningLevel::Max,
ReasoningLevel::Ultra,
] {
let label = muse_effort_label(level).unwrap();
assert_eq!(parse_muse_effort(label), Some(level), "{label}");
}
assert_eq!(muse_effort_label(ReasoningLevel::Adaptive), None);
assert_eq!(muse_effort_label(ReasoningLevel::UltraCode), None);
assert_eq!(parse_muse_effort("minimal"), None);
}
#[test]
fn live_catalog_parse_orders_filters_and_reads_exact_efforts() {
let models = parse_muse_catalog_models(LIVE).unwrap();
let ids: Vec<_> = models.iter().map(|m| m.id.as_str()).collect();
assert_eq!(ids, ["muse-wonder-1.0", "muse-spark-1.3"]);
let wonder = &models[0];
assert_eq!(wonder.runtime_id(), "muse/muse-wonder-1.0");
assert_eq!(wonder.context_tokens, Some(1_000_000));
assert_eq!(wonder.max_output_tokens, None, "0 is not a limit");
assert_eq!(wonder.reasoning, ReasoningSupport::Unknown);
let spark = &models[1];
assert_eq!(spark.label.as_deref(), Some("Muse Spark 1.3"));
assert_eq!(
spark.reasoning,
ReasoningSupport::NamedEffort {
supported: vec![ReasoningLevel::Low, ReasoningLevel::High],
default_level: None,
}
);
assert!(parse_muse_catalog_models(r#"{"data":[{"id":"m-1"}]}"#)
.unwrap()
.iter()
.any(|m| m.id == "m-1"));
assert!(parse_muse_catalog_models("{}").is_err());
assert!(parse_muse_catalog_models("nope").is_err());
}
const WIRE: &str = r#"{"object":"list","data":[
{"id":"muse-wonder-1.0","object":"model","created":1,"owned_by":"meta","metadata":{"muse-code":{
"attachment":true,"description":null,"family":"avocado","is_hidden":false,
"limit":{"context":1007997,"output":128000},
"modalities":{"input":["text","image"],"output":["text"]},
"name":"muse-wonder-1.0",
"options":{"forceReasoning":true,"include":["reasoning.encrypted_content"],
"reasoningEffort":"high","temperature":0.9,"top_p":0.9},
"reasoning":true,"tool_call":true,
"variants":{"high":{"reasoningEffort":"high"},"low":{"reasoningEffort":"low"},
"max":{"reasoningEffort":"max"},"medium":{"reasoningEffort":"medium"},
"minimal":{"reasoningEffort":"minimal"},
"xhigh":{"reasoningEffort":"xhigh","selector":{"description":"d"}}}}}},
{"id":"muse-image-1.0","object":"model","owned_by":"meta","metadata":{"muse-code":{
"is_hidden":true,"modalities":{"input":["text","image"],"output":["image"]},
"options":{},"tool_call":false}}},
{"id":"muse-visible-imagegen-zz7","object":"model","metadata":{"muse-code":{
"is_hidden":false,"modalities":{"input":["text"],"output":["image"]}}}},
{"id":"muse-odd-default-zz8","object":"model","metadata":{"muse-code":{
"options":{"reasoningEffort":"ultra"},"variants":{"fast":{"reasoningEffort":"low"}}}}},
{"id":"muse-bad-meta-zz9","object":"model","metadata":{"muse-code":{"limit":"nope"}}}
]}"#;
#[test]
fn wire_catalog_reads_muse_code_metadata() {
let models = parse_muse_catalog_models(WIRE).unwrap();
let ids: Vec<_> = models.iter().map(|m| m.id.as_str()).collect();
assert_eq!(
ids,
[
"muse-wonder-1.0",
"muse-odd-default-zz8",
"muse-bad-meta-zz9"
]
);
let wonder = &models[0];
assert_eq!(wonder.source, CatalogSource::Live);
assert_eq!(wonder.context_tokens, Some(1_007_997));
assert_eq!(wonder.max_output_tokens, Some(128_000));
assert_eq!(
wonder.input_modalities,
vec![Modality::Text, Modality::Image]
);
assert_eq!(
wonder.reasoning,
ReasoningSupport::NamedEffort {
supported: vec![
ReasoningLevel::Low,
ReasoningLevel::Medium,
ReasoningLevel::High,
ReasoningLevel::XHigh,
ReasoningLevel::Max,
],
default_level: Some(ReasoningLevel::High),
}
);
assert_eq!(
models[1].reasoning,
ReasoningSupport::NamedEffort {
supported: vec![ReasoningLevel::Low],
default_level: None,
}
);
let bad = &models[2];
assert_eq!(bad.reasoning, ReasoningSupport::Unknown);
assert_eq!(bad.input_modalities, vec![Modality::Text]);
assert_eq!(bad.context_tokens, None);
}
#[test]
fn variant_name_without_reasoning_effort_is_not_an_effort() {
let wire = r#"{"object":"list","data":[
{"id":"muse-preset-zz1","object":"model","metadata":{"muse-code":{
"variants":{"max":{"speed":"fast"},"high":{"tools":"minimal"},
"careful":{"reasoningEffort":"medium"}}}}},
{"id":"muse-preset-zz2","object":"model","metadata":{"muse-code":{
"variants":{"high":{},"low":{"temperature":0.1}}}}}
]}"#;
let models = parse_muse_catalog_models(wire).unwrap();
assert_eq!(
models[0].reasoning,
ReasoningSupport::NamedEffort {
supported: vec![ReasoningLevel::Medium],
default_level: None,
}
);
assert_eq!(models[1].reasoning, ReasoningSupport::Unknown);
}
#[test]
fn wire_catalog_default_drives_default_level_for_model() {
use crate::runtime::openai::catalog::validation::{
default_level_for_model, validate_reasoning_mutation,
};
let _guard = test_cache_guard();
capability_cache::replace_provider(MUSE_PROVIDER_KEY, &[]);
assert_eq!(
default_level_for_model("muse/muse-wonder-1.0"),
Some(ReasoningLevel::Adaptive),
"no live evidence → provider default"
);
capability_cache::replace_provider(
MUSE_PROVIDER_KEY,
&parse_muse_catalog_models(WIRE).unwrap(),
);
assert_eq!(
muse_default_level("muse-wonder-1.0"),
Some(ReasoningLevel::High)
);
assert_eq!(
default_level_for_model("muse/muse-wonder-1.0"),
Some(ReasoningLevel::High)
);
assert!(validate_reasoning_mutation("muse/muse-wonder-1.0", ReasoningLevel::XHigh).is_ok());
assert!(
validate_reasoning_mutation("muse/muse-wonder-1.0", ReasoningLevel::Ultra).is_err()
);
assert_eq!(muse_default_level("muse-odd-default-zz8"), None);
assert_eq!(
default_level_for_model("muse/muse-odd-default-zz8"),
Some(ReasoningLevel::Adaptive)
);
capability_cache::replace_provider(MUSE_PROVIDER_KEY, &[]);
}
#[test]
fn static_seed_is_documented_id_only_and_ids_fail_closed() {
assert!(muse_static_model("muse-wonder-1.0").is_some());
assert!(muse_static_model("muse-wonder").is_none());
let seeds = muse_static_catalog_models();
assert_eq!(seeds.len(), 1);
assert_eq!(seeds[0].source, CatalogSource::StaticFallback);
assert_eq!(seeds[0].reasoning, ReasoningSupport::Unknown);
assert!(muse_runtime_model("muse-wonder-1.0"));
assert!(!muse_runtime_model("never-cataloged-zz9"));
assert!(muse_routable_id("never-cataloged-zz9"));
assert!(!muse_routable_id("Bad Id"));
assert_eq!(muse_supported_levels("muse-wonder-1.0"), None);
}
#[test]
fn id_shape_guard() {
for ok in ["muse-wonder-1.0", "muse_spark.1", "a"] {
assert!(valid_muse_id(ok), "{ok}");
}
for bad in ["", "Muse", "-x", "a/b", "a b", "../x", &"a".repeat(129)] {
assert!(!valid_muse_id(bad), "{bad}");
}
}
}