Find a model by name. Supports exact match (`org/model`) or suffix match (`model`). Returns `Err` if the suffix match is ambiguous (multiple models match).
(name: &str)
| 97 | /// Find a model by name. Supports exact match (`org/model`) or suffix match (`model`). |
| 98 | /// Returns `Err` if the suffix match is ambiguous (multiple models match). |
| 99 | pub fn find_model(name: &str) -> Result<Option<LocalModel>> { |
| 100 | let models = list_models()?; |
| 101 | |
| 102 | // Exact match first |
| 103 | if let Some(m) = models.iter().find(|m| m.name == name) { |
| 104 | return Ok(Some(m.clone())); |
| 105 | } |
| 106 | |
| 107 | // Suffix match: "Qwen3-0.6B" matches "evilsocket/Qwen3-0.6B" |
| 108 | let suffix = format!("/{name}"); |
| 109 | let matches: Vec<_> = models.iter().filter(|m| m.name.ends_with(&suffix)).collect(); |
| 110 | match matches.len() { |
| 111 | 0 => Ok(None), |
| 112 | 1 => Ok(Some(matches[0].clone())), |
| 113 | _ => anyhow::bail!( |
| 114 | "'{}' is ambiguous, matches: {}", |
| 115 | name, |
| 116 | matches |
| 117 | .iter() |
| 118 | .map(|m| m.name.as_str()) |
| 119 | .collect::<Vec<_>>() |
| 120 | .join(", ") |
| 121 | ), |
| 122 | } |
| 123 | } |
| 124 | |
| 125 | /// Delete a cached model from disk. |
| 126 | /// |