use std::sync::Arc;
pub mod harmony;
pub mod native;
pub mod xml_regex;
pub use crate::llms::{ChatStrategy, RequestOverrides};
pub struct StrategyResolver;
impl StrategyResolver {
pub fn resolve(engine: Option<&str>) -> Arc<dyn ChatStrategy> {
match engine {
Some("vllm") => Arc::new(xml_regex::XmlRegexStrategy::new(Some("vllm".to_string()))),
Some("vllm_xml_responses") => Arc::new(xml_regex::XmlRegexStrategy::new(Some(
"vllm_responses".to_string(),
))),
Some("gpt-oss") | Some("harmony") => Arc::new(harmony::HarmonyStrategy),
Some(other) => Arc::new(native::NativeStrategy::new(other)),
None => Arc::new(native::NativeStrategy::default()),
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_strategy_resolution() {
let strategy = StrategyResolver::resolve(Some("vllm"));
assert!(!strategy.supports_streaming());
let strategy = StrategyResolver::resolve(Some("gpt-oss"));
assert!(!strategy.supports_streaming()); assert_eq!(strategy.endpoint_suffix(), "/completions");
let strategy = StrategyResolver::resolve(Some("harmony"));
assert_eq!(strategy.endpoint_suffix(), "/completions");
let strategy = StrategyResolver::resolve(Some("native"));
assert!(strategy.supports_streaming()); assert_eq!(strategy.endpoint_suffix(), "/chat/completions");
let strategy = StrategyResolver::resolve(None);
assert!(strategy.supports_streaming());
}
#[test]
fn test_strategy_resolution_unknown_engine_falls_back_to_native() {
let strategy = StrategyResolver::resolve(Some("cloudflare"));
assert!(strategy.supports_streaming());
assert_eq!(strategy.endpoint_suffix(), "/chat/completions");
let strategy = StrategyResolver::resolve(Some("together"));
assert!(strategy.supports_streaming());
assert_eq!(strategy.endpoint_suffix(), "/chat/completions");
let strategy = StrategyResolver::resolve(Some("vllm_xml_responses"));
assert!(!strategy.supports_streaming());
assert_eq!(
strategy.endpoint_suffix(),
"/responses",
"vllm_xml_responses should resolve to XmlRegexStrategy (/responses), not HarmonyStrategy (/completions)"
);
}
}