llm_kernel/provider/
capability.rs1use super::catalog::ServiceDescriptor;
2
3#[derive(Debug, Clone, Copy, PartialEq, Eq)]
5pub enum AuthStrategy {
6 None,
8 Literal,
10 Secret,
12 Unknown,
14}
15
16pub trait CapabilityProfile {
18 fn auth_strategy(&self) -> AuthStrategy;
19 fn clears_anthropic_api_key(&self) -> bool;
20 fn supports_model_tiers(&self) -> bool;
21}
22
23fn auth_mode_to_strategy(value: &str) -> AuthStrategy {
24 match value {
25 "none" => AuthStrategy::None,
26 "literal" => AuthStrategy::Literal,
27 "secret" => AuthStrategy::Secret,
28 _ => AuthStrategy::Unknown,
29 }
30}
31
32fn clears_api_key_for_family(family: &str) -> bool {
33 matches!(family, "openrouter" | "local" | "custom_unknown")
34}
35
36fn supports_tiers_for_family(family: &str) -> bool {
37 !matches!(family, "claude_strict")
38}
39
40impl CapabilityProfile for ServiceDescriptor {
41 fn auth_strategy(&self) -> AuthStrategy {
42 auth_mode_to_strategy(&self.auth_mode)
43 }
44
45 fn clears_anthropic_api_key(&self) -> bool {
46 clears_api_key_for_family(&self.family)
47 }
48
49 fn supports_model_tiers(&self) -> bool {
50 supports_tiers_for_family(&self.family)
51 }
52}
53
54#[cfg(test)]
55mod tests {
56 use super::*;
57 use std::collections::HashMap;
58
59 fn make_descriptor(auth_mode: &str, family: &str) -> ServiceDescriptor {
60 ServiceDescriptor {
61 id: "test".to_string(),
62 display_name: "Test".to_string(),
63 description: String::new(),
64 category: "test".to_string(),
65 family: family.to_string(),
66 auth_mode: auth_mode.to_string(),
67 key_var: String::new(),
68 literal_auth_token: String::new(),
69 base_url: String::new(),
70 default_model: String::new(),
71 model_tiers: HashMap::new(),
72 model_choices: vec![],
73 test_url: String::new(),
74 setup: vec![],
75 usage: vec![],
76 api_base_url: None,
77 npm_package: None,
78 doc_url: None,
79 models: vec![],
80 }
81 }
82
83 #[test]
84 fn test_auth_mode_mapping() {
85 assert_eq!(auth_mode_to_strategy("none"), AuthStrategy::None);
86 assert_eq!(auth_mode_to_strategy("literal"), AuthStrategy::Literal);
87 assert_eq!(auth_mode_to_strategy("secret"), AuthStrategy::Secret);
88 assert_eq!(auth_mode_to_strategy("other"), AuthStrategy::Unknown);
89 }
90
91 #[test]
92 fn test_secret_provider_capability() {
93 let desc = make_descriptor("secret", "openrouter");
94 assert_eq!(desc.auth_strategy(), AuthStrategy::Secret);
95 assert!(desc.clears_anthropic_api_key());
96 assert!(desc.supports_model_tiers());
97 }
98
99 #[test]
100 fn test_claude_strict_invariants() {
101 assert!(!clears_api_key_for_family("claude_strict"));
102 assert!(!supports_tiers_for_family("claude_strict"));
103 }
104
105 #[test]
106 fn test_openrouter_invariants() {
107 assert!(clears_api_key_for_family("openrouter"));
108 assert!(supports_tiers_for_family("openrouter"));
109 }
110
111 #[test]
112 fn test_local_family_clears_api_key() {
113 assert!(clears_api_key_for_family("local"));
114 }
115
116 #[test]
117 fn test_none_auth_strategy() {
118 let desc = make_descriptor("none", "local");
119 assert_eq!(desc.auth_strategy(), AuthStrategy::None);
120 }
121}