Add typed generation preferences
This commit is contained in:
@@ -5,6 +5,7 @@ use std::fs;
|
||||
use std::path::Path;
|
||||
|
||||
use crate::schema::{preferences, projects, sessions};
|
||||
use crate::settings::{GenerationPreferences, ReasoningMode};
|
||||
|
||||
pub const MIGRATIONS: EmbeddedMigrations = embed_migrations!("migrations");
|
||||
|
||||
@@ -16,6 +17,14 @@ pub struct AppPreferences {
|
||||
pub selected_model: String,
|
||||
pub dspark_enabled: bool,
|
||||
pub idle_timeout_minutes: i32,
|
||||
pub context_tokens: i32,
|
||||
pub max_generated_tokens: i32,
|
||||
pub system_prompt: String,
|
||||
pub temperature: Option<f32>,
|
||||
pub top_p: Option<f32>,
|
||||
pub min_p: Option<f32>,
|
||||
pub seed: Option<String>,
|
||||
pub reasoning_mode: String,
|
||||
}
|
||||
|
||||
impl Default for AppPreferences {
|
||||
@@ -25,16 +34,55 @@ impl Default for AppPreferences {
|
||||
selected_model: "deepseek-v4-flash".into(),
|
||||
dspark_enabled: false,
|
||||
idle_timeout_minutes: 10,
|
||||
context_tokens: 32_768,
|
||||
max_generated_tokens: 50_000,
|
||||
system_prompt: "You are a helpful assistant".into(),
|
||||
temperature: None,
|
||||
top_p: None,
|
||||
min_p: None,
|
||||
seed: None,
|
||||
reasoning_mode: "high".into(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl AppPreferences {
|
||||
pub(crate) fn generation(&self) -> Result<GenerationPreferences, String> {
|
||||
let preferences = GenerationPreferences {
|
||||
context_tokens: self.context_tokens,
|
||||
max_generated_tokens: self.max_generated_tokens,
|
||||
system_prompt: self.system_prompt.clone(),
|
||||
temperature: self.temperature,
|
||||
top_p: self.top_p,
|
||||
min_p: self.min_p,
|
||||
seed: self
|
||||
.seed
|
||||
.as_deref()
|
||||
.map(str::parse)
|
||||
.transpose()
|
||||
.map_err(|_| "Saved seed is not a valid positive whole number.".to_owned())?,
|
||||
reasoning_mode: ReasoningMode::from_id(&self.reasoning_mode)
|
||||
.ok_or_else(|| format!("Unsupported reasoning mode: {}", self.reasoning_mode))?,
|
||||
};
|
||||
preferences.validate()?;
|
||||
Ok(preferences)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(AsChangeset)]
|
||||
#[diesel(table_name = preferences)]
|
||||
struct PreferenceChanges<'a> {
|
||||
selected_model: &'a str,
|
||||
dspark_enabled: bool,
|
||||
idle_timeout_minutes: i32,
|
||||
context_tokens: i32,
|
||||
max_generated_tokens: i32,
|
||||
system_prompt: &'a str,
|
||||
temperature: Option<f32>,
|
||||
top_p: Option<f32>,
|
||||
min_p: Option<f32>,
|
||||
seed: Option<&'a str>,
|
||||
reasoning_mode: &'a str,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Identifiable, Queryable, Selectable)]
|
||||
@@ -137,12 +185,23 @@ impl Database {
|
||||
selected_model: &str,
|
||||
dspark_enabled: bool,
|
||||
idle_timeout_minutes: i32,
|
||||
generation: &GenerationPreferences,
|
||||
) -> Result<AppPreferences, String> {
|
||||
generation.validate()?;
|
||||
let seed = generation.seed.map(|seed| seed.to_string());
|
||||
diesel::update(preferences::table.find(1))
|
||||
.set(PreferenceChanges {
|
||||
selected_model,
|
||||
dspark_enabled,
|
||||
idle_timeout_minutes,
|
||||
context_tokens: generation.context_tokens,
|
||||
max_generated_tokens: generation.max_generated_tokens,
|
||||
system_prompt: &generation.system_prompt,
|
||||
temperature: generation.temperature,
|
||||
top_p: generation.top_p,
|
||||
min_p: generation.min_p,
|
||||
seed: seed.as_deref(),
|
||||
reasoning_mode: generation.reasoning_mode.id(),
|
||||
})
|
||||
.returning(AppPreferences::as_returning())
|
||||
.get_result(&mut self.connection)
|
||||
@@ -202,13 +261,26 @@ mod tests {
|
||||
assert_eq!(preferences.selected_model, "deepseek-v4-flash");
|
||||
assert!(!preferences.dspark_enabled);
|
||||
assert_eq!(preferences.idle_timeout_minutes, 10);
|
||||
assert!(database.update_preferences("glm-5.2", true, 30).is_err());
|
||||
let generation = GenerationPreferences::default();
|
||||
assert!(
|
||||
database
|
||||
.update_preferences("deepseek-v4-flash", false, 0)
|
||||
.update_preferences("glm-5.2", true, 30, &generation)
|
||||
.is_err()
|
||||
);
|
||||
database.update_preferences("glm-5.2", false, 30).unwrap();
|
||||
assert!(
|
||||
database
|
||||
.update_preferences("deepseek-v4-flash", false, 0, &generation)
|
||||
.is_err()
|
||||
);
|
||||
let generation = GenerationPreferences {
|
||||
top_p: Some(0.7),
|
||||
seed: Some(u64::MAX),
|
||||
reasoning_mode: ReasoningMode::Max,
|
||||
..generation
|
||||
};
|
||||
database
|
||||
.update_preferences("glm-5.2", false, 30, &generation)
|
||||
.unwrap();
|
||||
|
||||
let project = database.create_project("DS4", "/tmp/ds4").unwrap();
|
||||
let first = database
|
||||
@@ -229,6 +301,7 @@ mod tests {
|
||||
let preferences = reopened.load_preferences().unwrap();
|
||||
assert_eq!(preferences.selected_model, "glm-5.2");
|
||||
assert_eq!(preferences.idle_timeout_minutes, 30);
|
||||
assert_eq!(preferences.generation().unwrap(), generation);
|
||||
drop(reopened);
|
||||
fs::remove_file(path).unwrap();
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user