use anyhow::{Result, bail};
use rlx_runtime::{Device, is_available};
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct OrpheusRuntimeDevice {
pub lm: Device,
pub snac_coreml: bool,
}
impl OrpheusRuntimeDevice {
pub fn snac_load_options(self) -> crate::decoder::SnacLoadOptions {
crate::decoder::SnacLoadOptions {
coreml: self.snac_coreml,
}
}
}
fn env_flag(name: &str) -> Option<bool> {
match std::env::var(name).ok().as_deref() {
Some("1") | Some("true") | Some("TRUE") => Some(true),
Some("0") | Some("false") | Some("FALSE") => Some(false),
_ => None,
}
}
pub fn lm_kv_decode_supported(device: Device) -> bool {
match device {
Device::Mlx => env_flag("ORPHEUS_MLX_KV") == Some(true),
Device::Metal | Device::Cuda | Device::Rocm | Device::Gpu | Device::Vulkan => true,
Device::Cpu => env_flag("ORPHEUS_FAST_LM") == Some(true),
_ => false,
}
}
pub fn preferred_synth_device() -> Device {
if is_available(Device::Metal) {
Device::Metal
} else if is_available(Device::Mlx) && lm_kv_decode_supported(Device::Mlx) {
Device::Mlx
} else if is_available(Device::Cuda) {
Device::Cuda
} else if is_available(Device::Rocm) {
Device::Rocm
} else if is_available(Device::Gpu) {
Device::Gpu
} else if is_available(Device::Vulkan) {
Device::Vulkan
} else {
Device::Cpu
}
}
#[cfg(feature = "llama")]
pub fn synth_device_for_tests() -> Device {
if let Ok(s) = std::env::var("ORPHEUS_SYNTH_DEVICE") {
if let Ok(d) = rlx_cli::parse_device(s.trim()) {
return d;
}
}
preferred_synth_device()
}
#[cfg(feature = "llama")]
pub fn parse_orpheus_device(s: &str) -> Result<OrpheusRuntimeDevice> {
resolve_orpheus_device(s)
}
#[cfg(feature = "llama")]
pub fn resolve_orpheus_device(s: &str) -> Result<OrpheusRuntimeDevice> {
let s = s.trim();
if s.eq_ignore_ascii_case("auto") {
return Ok(OrpheusRuntimeDevice {
lm: preferred_synth_device(),
snac_coreml: false,
});
}
if s.eq_ignore_ascii_case("coreml") {
let lm = preferred_synth_device();
if !matches!(lm, Device::Metal | Device::Mlx | Device::Cpu) {
bail!("coreml SNAC path expects an Apple host with Metal or MLX; got lm={lm:?}");
}
return Ok(OrpheusRuntimeDevice {
lm,
snac_coreml: true,
});
}
Ok(OrpheusRuntimeDevice {
lm: rlx_cli::parse_device(s)?,
snac_coreml: false,
})
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn mlx_kv_off_by_default() {
assert!(!lm_kv_decode_supported(Device::Mlx));
}
#[test]
fn metal_kv_on_by_default() {
assert!(lm_kv_decode_supported(Device::Metal));
}
#[test]
fn wgpu_kv_on_by_default() {
assert!(lm_kv_decode_supported(Device::Gpu));
assert!(lm_kv_decode_supported(Device::Vulkan));
}
#[test]
fn resolve_coreml_sets_snac_flag() {
let rt = resolve_orpheus_device("coreml").unwrap();
assert!(rt.snac_coreml);
}
}