fix: preserve requested model ID casing in registry resolution (#733)
Previously, ModelRegistry::resolve() lowercased the requested model name before looking it up in the alias map, and always returned the registry's canonical (lowercase) model ID. This broke third-party API providers that enforce case-sensitive model name matching. Now when the resolved model ID differs from the requested name only in case (eq_ignore_ascii_case), the requested casing is preserved. Closes #729 Co-authored-by: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
+46
-2
@@ -227,7 +227,7 @@ impl ModelRegistry {
|
||||
{
|
||||
return ModelResolution {
|
||||
requested: Some(name.to_string()),
|
||||
resolved: model,
|
||||
resolved: preserve_requested_model_id_case(model, name),
|
||||
used_fallback: false,
|
||||
fallback_chain,
|
||||
};
|
||||
@@ -235,7 +235,7 @@ impl ModelRegistry {
|
||||
if let Some(idx) = self.alias_map.get(&normalize(name)) {
|
||||
return ModelResolution {
|
||||
requested: Some(name.to_string()),
|
||||
resolved: self.models[*idx].clone(),
|
||||
resolved: preserve_requested_model_id_case(self.models[*idx].clone(), name),
|
||||
used_fallback: false,
|
||||
fallback_chain,
|
||||
};
|
||||
@@ -283,6 +283,14 @@ fn model_matches(model: &ModelInfo, requested: &str) -> bool {
|
||||
.any(|alias| normalize(alias) == requested)
|
||||
}
|
||||
|
||||
fn preserve_requested_model_id_case(mut model: ModelInfo, requested: &str) -> ModelInfo {
|
||||
let requested = requested.trim();
|
||||
if model.id.eq_ignore_ascii_case(requested) {
|
||||
model.id = requested.to_string();
|
||||
}
|
||||
model
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
@@ -406,4 +414,40 @@ mod tests {
|
||||
assert_eq!(resolved.resolved.provider, ProviderKind::Vllm);
|
||||
assert_eq!(resolved.resolved.id, "deepseek-ai/DeepSeek-V4-Flash");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn preserves_requested_model_casing_for_third_party_providers() {
|
||||
let registry = ModelRegistry::default();
|
||||
let resolved = registry.resolve(Some("DeepSeek-V4-Pro"), None);
|
||||
|
||||
assert_eq!(resolved.resolved.provider, ProviderKind::Deepseek);
|
||||
assert_eq!(resolved.resolved.id, "DeepSeek-V4-Pro");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn preserves_requested_model_casing_with_provider_hint() {
|
||||
let registry = ModelRegistry::default();
|
||||
let resolved = registry.resolve(Some("DeepSeek-V4-Pro"), Some(ProviderKind::Deepseek));
|
||||
|
||||
assert_eq!(resolved.resolved.provider, ProviderKind::Deepseek);
|
||||
assert_eq!(resolved.resolved.id, "DeepSeek-V4-Pro");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn preserves_requested_model_casing_without_surrounding_whitespace() {
|
||||
let registry = ModelRegistry::default();
|
||||
let resolved = registry.resolve(Some(" DeepSeek-V4-Pro "), None);
|
||||
|
||||
assert_eq!(resolved.resolved.provider, ProviderKind::Deepseek);
|
||||
assert_eq!(resolved.resolved.id, "DeepSeek-V4-Pro");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn alias_match_does_not_override_requested_casing() {
|
||||
let registry = ModelRegistry::default();
|
||||
let resolved = registry.resolve(Some("deepseek-reasoner"), None);
|
||||
|
||||
assert_eq!(resolved.resolved.provider, ProviderKind::Deepseek);
|
||||
assert_eq!(resolved.resolved.id, "deepseek-v4-flash");
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user