Move preferences from the database to a YAML config file
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
101
src/settings.rs
101
src/settings.rs
@@ -1,4 +1,5 @@
|
||||
use crate::model::{self, EngineArtifacts, ModelChoice};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::fmt;
|
||||
use std::path::Path;
|
||||
|
||||
@@ -17,7 +18,8 @@ const DEFAULT_KV_MIN_TOKENS: u32 = 512;
|
||||
const DEFAULT_KV_COLD_MAX_TOKENS: u32 = 30_000;
|
||||
const DEFAULT_KV_CONTINUED_INTERVAL_TOKENS: u32 = 10_000;
|
||||
|
||||
#[derive(Clone, Debug, PartialEq)]
|
||||
#[derive(Clone, Debug, Deserialize, PartialEq, Serialize)]
|
||||
#[serde(default, deny_unknown_fields)]
|
||||
pub(crate) struct SpeculativePreferences {
|
||||
pub(crate) mtp_draft_tokens: i32,
|
||||
pub(crate) mtp_margin: f32,
|
||||
@@ -94,13 +96,70 @@ pub(crate) struct EngineSpeculativeSettings {
|
||||
pub(crate) dspark_strict: bool,
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
|
||||
/// An expert count, or a whole GiB budget. Written as `4` or `64GB`, the same
|
||||
/// spelling the preferences window accepts.
|
||||
#[derive(Clone, Copy, Debug, Deserialize, Eq, PartialEq, Serialize)]
|
||||
#[serde(into = "String", try_from = "String")]
|
||||
pub(crate) enum StreamingCacheBudget {
|
||||
Experts(u32),
|
||||
Gib(u64),
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Default, Eq, PartialEq)]
|
||||
impl fmt::Display for StreamingCacheBudget {
|
||||
fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
match self {
|
||||
Self::Experts(experts) => write!(formatter, "{experts}"),
|
||||
Self::Gib(gib) => write!(formatter, "{gib}GB"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<StreamingCacheBudget> for String {
|
||||
fn from(budget: StreamingCacheBudget) -> Self {
|
||||
budget.to_string()
|
||||
}
|
||||
}
|
||||
|
||||
impl TryFrom<String> for StreamingCacheBudget {
|
||||
type Error = String;
|
||||
|
||||
fn try_from(value: String) -> Result<Self, Self::Error> {
|
||||
value.parse()
|
||||
}
|
||||
}
|
||||
|
||||
impl std::str::FromStr for StreamingCacheBudget {
|
||||
type Err = String;
|
||||
|
||||
fn from_str(value: &str) -> Result<Self, Self::Err> {
|
||||
let value = value.trim();
|
||||
let gib = value
|
||||
.get(value.len().saturating_sub(2)..)
|
||||
.is_some_and(|suffix| suffix.eq_ignore_ascii_case("gb"));
|
||||
let digits = if gib {
|
||||
&value[..value.len() - 2]
|
||||
} else {
|
||||
value
|
||||
};
|
||||
let number = (!digits.is_empty() && digits.bytes().all(|byte| byte.is_ascii_digit()))
|
||||
.then(|| digits.parse::<u64>().ok())
|
||||
.flatten()
|
||||
.filter(|number| *number > 0);
|
||||
match number {
|
||||
Some(number) if gib && number <= u64::MAX / GIB => Ok(Self::Gib(number)),
|
||||
Some(number) if !gib && number <= u64::from(u32::MAX) => {
|
||||
Ok(Self::Experts(number as u32))
|
||||
}
|
||||
_ => Err(
|
||||
"SSD cache budget must be a positive expert count or whole GiB value such as 64GB."
|
||||
.into(),
|
||||
),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Default, Deserialize, Eq, PartialEq, Serialize)]
|
||||
#[serde(default, deny_unknown_fields)]
|
||||
pub(crate) struct SsdPreferences {
|
||||
pub(crate) enabled: bool,
|
||||
pub(crate) cold: bool,
|
||||
@@ -166,7 +225,8 @@ pub(crate) struct EngineSsdSettings {
|
||||
|
||||
/// Disk KV cache management, mirroring ds4's `--kv-disk-space-mb` budget and
|
||||
/// its store-side gates. Unset values keep the DS4 defaults.
|
||||
#[derive(Clone, Copy, Debug, Default, Eq, PartialEq)]
|
||||
#[derive(Clone, Copy, Debug, Default, Deserialize, Eq, PartialEq, Serialize)]
|
||||
#[serde(default, deny_unknown_fields)]
|
||||
pub(crate) struct KvCachePreferences {
|
||||
pub(crate) budget_gib: Option<u64>,
|
||||
pub(crate) min_tokens: Option<u32>,
|
||||
@@ -219,7 +279,8 @@ impl KvCacheSettings {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Default, PartialEq)]
|
||||
#[derive(Clone, Debug, Default, Deserialize, PartialEq, Serialize)]
|
||||
#[serde(default, deny_unknown_fields)]
|
||||
pub(crate) struct SteeringPreferences {
|
||||
pub(crate) file: Option<String>,
|
||||
pub(crate) ffn_scale: Option<f32>,
|
||||
@@ -270,7 +331,8 @@ pub(crate) struct EngineSteeringSettings {
|
||||
pub(crate) attention_scale: f32,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Default, Eq, PartialEq)]
|
||||
#[derive(Clone, Debug, Default, Deserialize, Eq, PartialEq, Serialize)]
|
||||
#[serde(default, deny_unknown_fields)]
|
||||
pub(crate) struct DiagnosticPreferences {
|
||||
pub(crate) simulated_used_memory_gib: Option<u64>,
|
||||
pub(crate) expert_profile_path: Option<String>,
|
||||
@@ -298,7 +360,8 @@ pub(crate) struct EngineDiagnosticSettings {
|
||||
pub(crate) expert_profile_path: Option<String>,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Default, PartialEq)]
|
||||
#[derive(Clone, Debug, Default, Deserialize, PartialEq, Serialize)]
|
||||
#[serde(default, deny_unknown_fields)]
|
||||
pub(crate) struct RuntimePreferences {
|
||||
pub(crate) execution: ExecutionPreferences,
|
||||
pub(crate) speculative: SpeculativePreferences,
|
||||
@@ -354,7 +417,8 @@ pub(crate) struct EngineSettings {
|
||||
pub(crate) diagnostics: EngineDiagnosticSettings,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Default, Eq, PartialEq)]
|
||||
#[derive(Clone, Debug, Default, Deserialize, Eq, PartialEq, Serialize)]
|
||||
#[serde(default, deny_unknown_fields)]
|
||||
pub(crate) struct ExecutionPreferences {
|
||||
pub(crate) cpu_threads: Option<u32>,
|
||||
pub(crate) power_percent: Option<u8>,
|
||||
@@ -420,28 +484,16 @@ pub(crate) struct EngineExecutionSettings {
|
||||
pub(crate) warm_weights: bool,
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Debug, Default, Eq, PartialEq)]
|
||||
#[derive(Clone, Copy, Debug, Default, Deserialize, Eq, PartialEq, Serialize)]
|
||||
#[serde(rename_all = "lowercase")]
|
||||
pub(crate) enum ReasoningMode {
|
||||
#[serde(rename = "none")]
|
||||
Direct,
|
||||
#[default]
|
||||
High,
|
||||
Max,
|
||||
}
|
||||
|
||||
impl ReasoningMode {
|
||||
pub(crate) fn id(self) -> &'static str {
|
||||
match self {
|
||||
Self::Direct => "none",
|
||||
Self::High => "high",
|
||||
Self::Max => "max",
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn from_id(id: &str) -> Option<Self> {
|
||||
REASONING_MODES.into_iter().find(|mode| mode.id() == id)
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Display for ReasoningMode {
|
||||
fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
formatter.write_str(match self {
|
||||
@@ -452,7 +504,8 @@ impl fmt::Display for ReasoningMode {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, PartialEq)]
|
||||
#[derive(Clone, Debug, Deserialize, PartialEq, Serialize)]
|
||||
#[serde(default, deny_unknown_fields)]
|
||||
pub(crate) struct GenerationPreferences {
|
||||
pub(crate) context_tokens: i32,
|
||||
pub(crate) max_generated_tokens: i32,
|
||||
|
||||
Reference in New Issue
Block a user