diff --git a/src/agent/context.rs b/src/agent/context.rs index 5b51c24..37dbf48 100644 --- a/src/agent/context.rs +++ b/src/agent/context.rs @@ -374,7 +374,7 @@ impl AstNode { /// Short label for the UI. pub fn label(&self) -> String { - let cfg = crate::config::get(); + let app = crate::config::app(); match self { Self::Branch { role, children, .. } => { let preview = children.first() @@ -383,8 +383,8 @@ impl AstNode { .unwrap_or_default(); match role { Role::System => "system".into(), - Role::User => format!("{}: {}", cfg.user_name, preview), - Role::Assistant => format!("{}: {}", cfg.assistant_name, preview), + Role::User => format!("{}: {}", app.user_name, preview), + Role::Assistant => format!("{}: {}", app.assistant_name, preview), } } Self::Leaf(leaf) => match &leaf.body { diff --git a/src/agent/oneshot.rs b/src/agent/oneshot.rs index 1c5ac90..8bc8b53 100644 --- a/src/agent/oneshot.rs +++ b/src/agent/oneshot.rs @@ -183,8 +183,8 @@ fn resolve_prompt( state: &std::collections::BTreeMap, recently_written: &[String], ) -> String { - let cfg = crate::config::get(); - let template = template.replace("{assistant_name}", &cfg.assistant_name); + let template = template.replace("{assistant_name}", + &crate::config::app().assistant_name); let mut result = String::with_capacity(template.len()); let mut rest = template.as_str(); while let Some(start) = rest.find("{{") { diff --git a/src/cli/node.rs b/src/cli/node.rs index 5472505..c4305a7 100644 --- a/src/cli/node.rs +++ b/src/cli/node.rs @@ -197,7 +197,7 @@ pub async fn cmd_load_context(stats: bool) -> Result<()> { return Ok(()); } - println!("=== MEMORY SYSTEM ({}) ===", cfg.assistant_name); + println!("=== MEMORY SYSTEM ({}) ===", crate::config::app().assistant_name); if !personality.is_empty() { println!("--- personality_nodes ({}) ---", personality.len()); diff --git a/src/config.rs b/src/config.rs index d00d4d7..b7ea597 100644 --- a/src/config.rs +++ b/src/config.rs @@ -40,8 +40,6 @@ fn default_identity_dir() -> PathBuf { #[derive(Debug, Clone, Deserialize)] #[serde(default)] pub struct Config { - pub user_name: String, - pub assistant_name: String, #[serde(deserialize_with = "deserialize_path")] pub data_dir: PathBuf, #[serde(default = "default_identity_dir", deserialize_with = "deserialize_path")] @@ -91,8 +89,6 @@ impl Default for Config { fn default() -> Self { let home = dirs::home_dir().unwrap_or_default(); Self { - user_name: "User".to_string(), - assistant_name: "Assistant".to_string(), data_dir: home.join(".consciousness/memory"), identity_dir: home.join(".consciousness/identity"), projects_dir: home.join(".claude/projects"), @@ -229,6 +225,10 @@ pub fn watch_config(cli: crate::user::CliArgs) { #[derive(Debug, Clone, Serialize, Deserialize)] pub struct AppConfig { + #[serde(default = "default_user_name")] + pub user_name: String, + #[serde(default = "default_assistant_name")] + pub assistant_name: String, /// Named model endpoints — credentials, base URL, and model id bundled /// into one entry per backend. Keyed by name, selected by /// `default_backend` or by `--model ` on the CLI. @@ -315,9 +315,14 @@ impl Default for LearnConfig { } } +fn default_user_name() -> String { "User".into() } +fn default_assistant_name() -> String { "Assistant".into() } + impl Default for AppConfig { fn default() -> Self { Self { + user_name: default_user_name(), + assistant_name: default_assistant_name(), backends: HashMap::new(), default_backend: String::new(), debug: false, @@ -534,7 +539,9 @@ pub fn show_config(app: &AppConfig, figment: &Figment) { } println!("# Effective configuration\n"); - println!("debug: {} ({})", app.debug, src(figment, "debug")); + println!("user_name: {:?} ({})", app.user_name, src(figment, "user_name")); + println!("assistant_name: {:?} ({})", app.assistant_name, src(figment, "assistant_name")); + println!("\ndebug: {} ({})", app.debug, src(figment, "debug")); println!("\ncompaction:"); println!(" hard_threshold_pct: {} ({})", app.compaction.hard_threshold_pct, src(figment, "compaction.hard_threshold_pct")); println!(" soft_threshold_pct: {} ({})", app.compaction.soft_threshold_pct, src(figment, "compaction.soft_threshold_pct")); diff --git a/src/mind/subconscious.rs b/src/mind/subconscious.rs index 15c8b04..21cc549 100644 --- a/src/mind/subconscious.rs +++ b/src/mind/subconscious.rs @@ -92,7 +92,8 @@ impl State { /// Generate the DMN prompt for the current state, informed by /// user presence and error patterns. pub fn prompt(&self, ctx: &DmnContext) -> String { - let user = &crate::config::get().user_name; + let app = crate::config::app(); + let user = &app.user_name; let idle_info = if ctx.user_idle < Duration::from_secs(60) { format!("{} is here (active recently).", user) diff --git a/src/subconscious/defs.rs b/src/subconscious/defs.rs index 8828043..a862c8d 100644 --- a/src/subconscious/defs.rs +++ b/src/subconscious/defs.rs @@ -396,13 +396,14 @@ fn resolve_conversation(budget: Option) -> String { let cfg = crate::config::get(); let max_bytes = budget.unwrap_or_else(|| cfg.surface_conversation_bytes.unwrap_or(100_000)); + let app = crate::config::app(); let mut fragments: Vec = Vec::new(); let mut total_bytes = 0; let mut oldest_ts = String::new(); for (role, content, ts) in iter { if total_bytes >= max_bytes { break; } - let name = if role == "user" { &cfg.user_name } else { &cfg.assistant_name }; + let name = if role == "user" { &app.user_name } else { &app.assistant_name }; let formatted = if !ts.is_empty() { oldest_ts = ts[..ts.floor_char_boundary(ts.len().min(19))].to_string(); format!("**{}** {}: {}", name, &oldest_ts, content) @@ -623,11 +624,13 @@ pub async fn run_agent( let mut all_keys = keys; let mut resolved_steps = Vec::new(); for step in &def.steps { - let cfg = crate::config::get(); - let template = step.prompt - .replace("{agent_name}", &def.agent) - .replace("{user_name}", &cfg.user_name) - .replace("{assistant_name}", &cfg.assistant_name); + let template = { + let app = crate::config::app(); + step.prompt + .replace("{agent_name}", &def.agent) + .replace("{user_name}", &app.user_name) + .replace("{assistant_name}", &app.assistant_name) + }; let (prompt, extra_keys) = resolve_placeholders(&template, &all_keys, count).await; all_keys.extend(extra_keys); resolved_steps.push(super::prompts::ResolvedStep {