Skip to main content

llm_manager/config/
profiles.rs

1use std::collections::HashMap;
2use std::path::PathBuf;
3
4use serde::{Deserialize, Serialize};
5
6use crate::config::Profile;
7use crate::config::builtin_profiles;
8use crate::config::config_base_dir;
9use crate::config::store::{load_all_from_dir, move_to_unused, save_yaml};
10
11/// Directory for per-profile YAML configs.
12pub fn profiles_config_dir() -> PathBuf {
13    config_base_dir().join("llm-manager").join("profiles")
14}
15
16/// Directory for unused (deleted) profile configs.
17pub fn unused_profiles_dir() -> PathBuf {
18    config_base_dir()
19        .join("llm-manager")
20        .join("unused_profiles")
21}
22
23/// Profile store — manages per-profile YAML configs.
24#[derive(Debug, Clone, Serialize, Deserialize)]
25pub struct ProfileStore {
26    profiles_dir: PathBuf,
27    unused_dir: PathBuf,
28    cache: HashMap<String, Profile>,
29}
30
31impl ProfileStore {
32    pub fn new() -> Self {
33        let profiles_dir = profiles_config_dir();
34        let unused_dir = unused_profiles_dir();
35        let cache = load_all_from_dir(&profiles_dir);
36        Self {
37            profiles_dir,
38            unused_dir,
39            cache,
40        }
41    }
42
43    /// Save (or update) a profile.
44    pub fn save(&mut self, profile: &Profile) {
45        save_yaml(&profile.name, profile, &self.profiles_dir, &self.unused_dir);
46        self.cache.insert(profile.name.clone(), profile.clone());
47    }
48
49    /// Insert a built-in profile into the in-memory cache only (no disk I/O).
50    pub fn insert_builtin(&mut self, profile: Profile) {
51        self.cache.insert(profile.name.clone(), profile);
52    }
53
54    /// Delete a profile by moving it to the unused directory.
55    pub fn delete(&mut self, name: &str) -> bool {
56        let builtin = builtin_profiles();
57        if builtin.iter().any(|b| b.name == name) {
58            return false;
59        }
60        move_to_unused(name, &self.profiles_dir, &self.unused_dir);
61        self.cache.remove(name);
62        true
63    }
64
65    /// Get a profile by name.
66    pub fn get(&self, name: &str) -> Option<&Profile> {
67        self.cache.get(name)
68    }
69
70    /// Get all user-defined profiles (excluding built-ins).
71    pub fn user_profiles(&self) -> Vec<Profile> {
72        let builtin = builtin_profiles();
73        self.cache
74            .values()
75            .filter(|p| !builtin.iter().any(|b| b.name == p.name))
76            .cloned()
77            .collect()
78    }
79
80    /// Get all profiles (built-in + user).
81    pub fn all(&self) -> Vec<Profile> {
82        let builtin = builtin_profiles();
83        let mut all: Vec<Profile> = builtin.clone();
84        for p in self.cache.values() {
85            if !builtin.iter().any(|b| b.name == p.name) {
86                all.push(p.clone());
87            }
88        }
89        all
90    }
91}
92
93impl Default for ProfileStore {
94    fn default() -> Self {
95        Self::new()
96    }
97}