@@ -65,7 +65,17 @@ pub struct Usage {
6565#[ async_trait]
6666pub trait LLMAdapter : Send + Sync {
6767 async fn complete ( & self , request : LLMRequest ) -> Result < LLMResponse > ;
68- fn _model_name ( & self ) -> & str ;
68+ #[ allow( dead_code) ]
69+ fn model_name ( & self ) -> & str ;
70+ }
71+
72+ /// Check if a base URL points to an Ollama instance by parsing the port.
73+ fn is_ollama_url ( base_url : & Option < String > ) -> bool {
74+ base_url. as_ref ( ) . is_some_and ( |u| {
75+ url:: Url :: parse ( u)
76+ . map ( |parsed| parsed. port ( ) == Some ( 11434 ) )
77+ . unwrap_or ( false )
78+ } )
6979}
7080
7181pub fn create_adapter ( config : & ModelConfig ) -> Result < Box < dyn LLMAdapter > > {
@@ -118,12 +128,7 @@ pub fn create_adapter(config: &ModelConfig) -> Result<Box<dyn LLMAdapter>> {
118128 name if name. starts_with ( "ollama:" ) => {
119129 Ok ( Box :: new ( crate :: adapters:: OllamaAdapter :: new ( config) ?) )
120130 }
121- _name
122- if config
123- . base_url
124- . as_ref ( )
125- . is_some_and ( |u| u. contains ( "11434" ) ) =>
126- {
131+ _name if is_ollama_url ( & config. base_url ) => {
127132 Ok ( Box :: new ( crate :: adapters:: OllamaAdapter :: new ( config) ?) )
128133 }
129134 // Default to OpenAI for unknown models
@@ -149,42 +154,42 @@ mod tests {
149154 fn test_create_adapter_claude_dash_prefix ( ) {
150155 let config = local_config ( "claude-3-5-sonnet-20241022" ) ;
151156 let adapter = create_adapter ( & config) . unwrap ( ) ;
152- assert_eq ! ( adapter. _model_name ( ) , "claude-3-5-sonnet-20241022" ) ;
157+ assert_eq ! ( adapter. model_name ( ) , "claude-3-5-sonnet-20241022" ) ;
153158 }
154159
155160 #[ test]
156161 fn test_create_adapter_claude_legacy_prefix ( ) {
157162 let config = local_config ( "claude3sonnet" ) ;
158163 let adapter = create_adapter ( & config) . unwrap ( ) ;
159- assert_eq ! ( adapter. _model_name ( ) , "claude3sonnet" ) ;
164+ assert_eq ! ( adapter. model_name ( ) , "claude3sonnet" ) ;
160165 }
161166
162167 #[ test]
163168 fn test_create_adapter_gpt ( ) {
164169 let config = local_config ( "gpt-4o" ) ;
165170 let adapter = create_adapter ( & config) . unwrap ( ) ;
166- assert_eq ! ( adapter. _model_name ( ) , "gpt-4o" ) ;
171+ assert_eq ! ( adapter. model_name ( ) , "gpt-4o" ) ;
167172 }
168173
169174 #[ test]
170175 fn test_create_adapter_gpt35 ( ) {
171176 let config = local_config ( "gpt-3.5-turbo" ) ;
172177 let adapter = create_adapter ( & config) . unwrap ( ) ;
173- assert_eq ! ( adapter. _model_name ( ) , "gpt-3.5-turbo" ) ;
178+ assert_eq ! ( adapter. model_name ( ) , "gpt-3.5-turbo" ) ;
174179 }
175180
176181 #[ test]
177182 fn test_create_adapter_o1 ( ) {
178183 let config = local_config ( "o1-preview" ) ;
179184 let adapter = create_adapter ( & config) . unwrap ( ) ;
180- assert_eq ! ( adapter. _model_name ( ) , "o1-preview" ) ;
185+ assert_eq ! ( adapter. model_name ( ) , "o1-preview" ) ;
181186 }
182187
183188 #[ test]
184189 fn test_create_adapter_ollama_prefix ( ) {
185190 let config = local_config ( "ollama:codellama" ) ;
186191 let adapter = create_adapter ( & config) . unwrap ( ) ;
187- assert_eq ! ( adapter. _model_name ( ) , "ollama:codellama" ) ;
192+ assert_eq ! ( adapter. model_name ( ) , "ollama:codellama" ) ;
188193 }
189194
190195 #[ test]
@@ -196,15 +201,15 @@ mod tests {
196201 ..Default :: default ( )
197202 } ;
198203 let adapter = create_adapter ( & config) . unwrap ( ) ;
199- assert_eq ! ( adapter. _model_name ( ) , "codellama" ) ;
204+ assert_eq ! ( adapter. model_name ( ) , "codellama" ) ;
200205 }
201206
202207 #[ test]
203208 fn test_create_adapter_default_unknown_model ( ) {
204209 // Unknown model name with a local base_url should default to OpenAI adapter
205210 let config = local_config ( "some-custom-model" ) ;
206211 let adapter = create_adapter ( & config) . unwrap ( ) ;
207- assert_eq ! ( adapter. _model_name ( ) , "some-custom-model" ) ;
212+ assert_eq ! ( adapter. model_name ( ) , "some-custom-model" ) ;
208213 }
209214
210215 #[ test]
@@ -218,7 +223,7 @@ mod tests {
218223 } ;
219224 // Even though model_name says "gpt-4o", the override should pick Anthropic
220225 let adapter = create_adapter ( & config) . unwrap ( ) ;
221- assert_eq ! ( adapter. _model_name ( ) , "gpt-4o" ) ;
226+ assert_eq ! ( adapter. model_name ( ) , "gpt-4o" ) ;
222227 }
223228
224229 #[ test]
@@ -231,7 +236,7 @@ mod tests {
231236 ..Default :: default ( )
232237 } ;
233238 let adapter = create_adapter ( & config) . unwrap ( ) ;
234- assert_eq ! ( adapter. _model_name ( ) , "my-model" ) ;
239+ assert_eq ! ( adapter. model_name ( ) , "my-model" ) ;
235240 }
236241
237242 #[ test]
@@ -245,7 +250,7 @@ mod tests {
245250 } ;
246251 // Even though model_name says "claude-*", the override should pick OpenAI
247252 let adapter = create_adapter ( & config) . unwrap ( ) ;
248- assert_eq ! ( adapter. _model_name ( ) , "claude-3-5-sonnet-20241022" ) ;
253+ assert_eq ! ( adapter. model_name ( ) , "claude-3-5-sonnet-20241022" ) ;
249254 }
250255
251256 #[ test]
@@ -259,7 +264,46 @@ mod tests {
259264 } ;
260265 // Unknown adapter override should default to OpenAI
261266 let adapter = create_adapter ( & config) . unwrap ( ) ;
262- assert_eq ! ( adapter. _model_name( ) , "my-model" ) ;
267+ assert_eq ! ( adapter. model_name( ) , "my-model" ) ;
268+ }
269+
270+ #[ test]
271+ fn test_create_adapter_ollama_by_standard_url ( ) {
272+ // Should detect Ollama from standard localhost:11434 URL
273+ let config = ModelConfig {
274+ model_name : "codellama" . to_string ( ) ,
275+ api_key : None ,
276+ base_url : Some ( "http://localhost:11434" . to_string ( ) ) ,
277+ ..Default :: default ( )
278+ } ;
279+ let adapter = create_adapter ( & config) . unwrap ( ) ;
280+ assert_eq ! ( adapter. model_name( ) , "codellama" ) ;
281+ }
282+
283+ #[ test]
284+ fn test_create_adapter_ollama_by_url_with_path ( ) {
285+ // Should detect Ollama even with trailing path
286+ let config = ModelConfig {
287+ model_name : "codellama" . to_string ( ) ,
288+ api_key : None ,
289+ base_url : Some ( "http://my-server:11434/api" . to_string ( ) ) ,
290+ ..Default :: default ( )
291+ } ;
292+ let adapter = create_adapter ( & config) . unwrap ( ) ;
293+ assert_eq ! ( adapter. model_name( ) , "codellama" ) ;
294+ }
295+
296+ #[ test]
297+ fn test_create_adapter_port_in_path_not_detected_as_ollama ( ) {
298+ // A URL like http://proxy.example.com/service/11434 should NOT trigger Ollama
299+ let config = ModelConfig {
300+ model_name : "my-model" . to_string ( ) ,
301+ api_key : Some ( "test-key" . to_string ( ) ) ,
302+ base_url : Some ( "http://proxy.example.com/service/11434" . to_string ( ) ) ,
303+ ..Default :: default ( )
304+ } ;
305+ // Should default to OpenAI, not Ollama
306+ let _adapter = create_adapter ( & config) . unwrap ( ) ;
263307 }
264308
265309 #[ test]
0 commit comments