atman_runtime/
settings_catalog.rs1use std::fmt;
2
3#[derive(Debug, Clone, Copy, PartialEq, Eq)]
4pub enum SettingSource {
5 Default,
6 Global,
7 Project,
8 Session,
9}
10
11#[derive(Debug, Clone, Copy, PartialEq, Eq)]
12pub enum Activation {
13 Immediate,
14 NextSession,
15 RestartRequired,
16}
17
18#[derive(Debug, Clone, PartialEq, Eq)]
19pub struct SettingDescriptor {
20 pub key: &'static str,
21 pub title: &'static str,
22 pub description: &'static str,
23 pub source: SettingSource,
24 pub activation: Activation,
25 pub sensitive: bool,
26}
27
28#[derive(Debug, Clone, PartialEq, Eq)]
29pub struct SettingValue {
30 pub descriptor: SettingDescriptor,
31 pub value: String,
32}
33
34#[derive(Debug, Clone, PartialEq, Eq)]
35pub enum SettingMutationError {
36 EmptyValue,
37 UnsupportedKey(String),
38}
39
40impl fmt::Display for SettingMutationError {
41 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
42 match self {
43 Self::EmptyValue => write!(f, "setting value cannot be empty"),
44 Self::UnsupportedKey(key) => write!(f, "unsupported setting: {key}"),
45 }
46 }
47}
48
49impl std::error::Error for SettingMutationError {}
50
51pub fn catalog() -> Vec<SettingDescriptor> {
52 vec![
53 SettingDescriptor {
54 key: "session.context_budget",
55 title: "Context budget",
56 description: "Maximum provider context window budget.",
57 source: SettingSource::Global,
58 activation: Activation::NextSession,
59 sensitive: false,
60 },
61 SettingDescriptor {
62 key: "tools.output.max_bytes",
63 title: "Tool output bytes",
64 description: "Maximum inline tool output before continuation is offered.",
65 source: SettingSource::Global,
66 activation: Activation::Immediate,
67 sensitive: false,
68 },
69 SettingDescriptor {
70 key: "trust.mode",
71 title: "Trust mode",
72 description: "Controls approval behavior for tool execution.",
73 source: SettingSource::Project,
74 activation: Activation::NextSession,
75 sensitive: false,
76 },
77 SettingDescriptor {
78 key: "provider.api_key",
79 title: "Provider API key",
80 description: "Credential used by the selected provider.",
81 source: SettingSource::Global,
82 activation: Activation::Immediate,
83 sensitive: true,
84 },
85 ]
86}
87
88pub fn descriptor(key: &str) -> Option<SettingDescriptor> {
89 catalog().into_iter().find(|item| item.key == key)
90}
91
92pub fn validate_mutation(key: &str, value: &str) -> Result<(), SettingMutationError> {
93 if descriptor(key).is_none() {
94 return Err(SettingMutationError::UnsupportedKey(key.to_owned()));
95 }
96 if value.trim().is_empty() {
97 return Err(SettingMutationError::EmptyValue);
98 }
99 Ok(())
100}
101
102#[cfg(test)]
103mod tests {
104 use super::*;
105
106 #[test]
107 fn catalog_exposes_source_activation_and_sensitive_metadata() {
108 let item = descriptor("provider.api_key").unwrap();
109 assert_eq!(item.source, SettingSource::Global);
110 assert_eq!(item.activation, Activation::Immediate);
111 assert!(item.sensitive);
112 }
113
114 #[test]
115 fn mutation_validation_rejects_unknown_and_empty_values() {
116 assert_eq!(
117 validate_mutation("unknown", "x"),
118 Err(SettingMutationError::UnsupportedKey("unknown".into()))
119 );
120 assert_eq!(
121 validate_mutation("trust.mode", " "),
122 Err(SettingMutationError::EmptyValue)
123 );
124 }
125}