pub mod anthropic;
pub mod openai;
pub use anthropic::AnthropicTransform;
pub use openai::OpenAITransform;
use crate::layers::TransformLayer;
use std::collections::HashMap;
use std::sync::Arc;
pub struct TransformRegistry {
map: HashMap<String, Arc<dyn TransformLayer>>,
fallback: Arc<dyn TransformLayer>,
}
impl TransformRegistry {
pub fn with_defaults() -> Self {
let openai: Arc<dyn TransformLayer> = Arc::new(OpenAITransform);
let mut map: HashMap<String, Arc<dyn TransformLayer>> = HashMap::new();
map.insert("openai".to_string(), openai.clone());
map.insert("anthropic".to_string(), Arc::new(AnthropicTransform));
Self {
map,
fallback: openai,
}
}
pub fn for_format(&self, format: &str) -> Arc<dyn TransformLayer> {
match self.map.get(format) {
Some(t) => t.clone(),
None => {
tracing::warn!(
format = %format,
"No transform registered for provider format; falling back to OpenAI transform"
);
self.fallback.clone()
}
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn dispatches_distinct_transforms_per_format() {
let reg = TransformRegistry::with_defaults();
let openai = reg.for_format("openai");
let anthropic = reg.for_format("anthropic");
assert!(
!Arc::ptr_eq(&openai, &anthropic),
"anthropic format must not resolve to the OpenAI transform"
);
}
#[test]
fn unknown_format_falls_back_to_openai() {
let reg = TransformRegistry::with_defaults();
let openai = reg.for_format("openai");
let unknown = reg.for_format("some-unregistered-format");
assert!(
Arc::ptr_eq(&openai, &unknown),
"unknown format should fall back to the OpenAI transform"
);
}
}