1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
//! `/reload` — reload settings, theme, and extensions. Migrated off the legacy
//! `handle_slash_command` match.
use super::super::registry::SlashCommand;
use crate::tui::app::NotificationKind;
use crate::tui::slash::{SlashCtx, SlashOutcome};
/// `/reload` — reload settings, theme, and extensions.
pub(crate) struct ReloadCommand;
impl SlashCommand for ReloadCommand {
fn name(&self) -> &str {
"reload"
}
fn description(&self) -> &str {
"Reload settings, theme, and extensions"
}
fn execute(&self, _args: &str, ctx: &mut SlashCtx<'_>) -> SlashOutcome {
let state = &mut *ctx.state;
let session = ctx.session;
let reloaded = crate::store::settings::Settings::load().unwrap_or_default();
// Flag the render loop to rebuild the live theme (theme name + glyph
// set) from the freshly-loaded settings. The overlay's Esc handler
// sets the same flag; `/reload` mirrors it so hand-edited
// `settings.toml` theme changes are picked up without a restart.
state.appearance_needs_reload = true;
session.set_thinking_level(reloaded.thinking_level);
// Rebuild the system prompt to pick up the latest TUI language
// policy (`output_languages`). The App-side `set_thinking_level`
// above handles the thinking-level half; the language policy is
// a separate concern (see `Settings::output_languages` docs and
// `AgentSession::rebuild_system_prompt`).
session.rebuild_system_prompt();
// Apply model change to the active agent session
if let Some(m) = reloaded.effective_model(None)
&& !m.is_empty()
{
let full_id = if m.contains('/') {
m
} else {
let p = reloaded.effective_provider(None).unwrap_or_default();
format!("{}/{}", p, m)
};
match session.set_model(&full_id) {
Ok(()) => {
let parts: Vec<&str> = full_id.splitn(2, '/').collect();
state.footer_state.data.model_name = full_id.clone();
if parts.len() == 2 {
state.footer_state.data.provider_name = parts[0].to_string();
}
}
Err(e) => {
state.add_notification(
format!("Warning: Could not apply model: {}", e),
NotificationKind::Warning,
);
}
}
}
// Reload WASM extensions (shared with the /settings overlay).
crate::tui::overlay::settings::sync_wasm_extensions(
state,
session,
reloaded.extensions_enabled,
);
// Reload skills
{
let new_mgr = crate::skills::SkillManager::discover_all(
&std::env::current_dir().unwrap_or_else(|_| std::path::PathBuf::from(".")),
&[],
)
.unwrap_or_else(|_| crate::skills::SkillManager::new());
let count = new_mgr.len();
*state.skills.write() = new_mgr;
if count > 0 {
state
.add_notification(format!("{} skill(s) loaded", count), NotificationKind::Info);
}
}
state.add_notification("Settings reloaded".to_string(), NotificationKind::Success);
SlashOutcome::Handled
}
}