Skip to main content

lash_core/runtime/
config_ops.rs

1//! `LashRuntime` configuration mutators: provider, model, context-window,
2//! session id, and tool-surface refresh.
3//!
4//! Extracted from `runtime/mod.rs`. This file re-opens `impl LashRuntime`;
5//! no types live here and no public API is changed.
6
7use crate::SessionError;
8use crate::provider::ProviderHandle;
9
10use super::LashRuntime;
11
12impl LashRuntime {
13    /// Update model on the runtime config.
14    pub fn set_model(&mut self, model: String) {
15        self.policy.model = model;
16        self.state.policy.model = self.policy.model.clone();
17    }
18
19    /// Update model variant on the runtime config.
20    pub fn set_model_variant(&mut self, model_variant: Option<String>) {
21        self.policy.model_variant = model_variant;
22        self.state.policy.model_variant = self.policy.model_variant.clone();
23    }
24
25    /// Update explicit model context metadata on the runtime config.
26    pub fn set_max_context_tokens(&mut self, max_context_tokens: usize) {
27        self.policy.max_context_tokens = Some(max_context_tokens);
28        self.state.policy.max_context_tokens = self.policy.max_context_tokens;
29    }
30
31    /// Update provider on the runtime config.
32    pub fn set_provider(&mut self, provider: ProviderHandle) {
33        self.policy.provider = provider;
34        self.state.policy.provider = self.policy.provider.clone();
35    }
36
37    /// Update session ID metadata on the runtime config.
38    pub fn set_session_id(&mut self, session_id: Option<String>) {
39        self.policy.session_id = session_id;
40        self.state.policy.session_id = self.policy.session_id.clone();
41    }
42
43    pub async fn update_session_config(
44        &mut self,
45        provider: Option<ProviderHandle>,
46        model: Option<String>,
47        model_variant: Option<Option<String>>,
48        max_context_tokens: Option<usize>,
49        prompt: Option<crate::PromptLayer>,
50    ) {
51        let previous = self.session_policy();
52        if let Some(provider) = provider {
53            self.policy.provider = provider;
54        }
55        if let Some(model) = model {
56            self.policy.model = model;
57        }
58        if let Some(model_variant) = model_variant {
59            self.policy.model_variant = model_variant;
60        }
61        if let Some(max_context_tokens) = max_context_tokens {
62            self.policy.max_context_tokens = Some(max_context_tokens);
63        }
64        if let Some(prompt) = prompt {
65            self.policy.prompt = prompt;
66        }
67        self.state.policy = self.policy.clone();
68        // Eagerly compact messages if the context window shrunk.
69        let new_max = self.policy.max_context_tokens;
70        let old_max = previous.max_context_tokens;
71        if new_max < old_max || (new_max.is_some() && old_max.is_none()) {
72            let _ = self
73                .rewrite_history(crate::RewriteTrigger::WindowShrink { old_max, new_max })
74                .await;
75        }
76        self.apply_session_config_mutations(previous.clone()).await;
77        self.notify_session_config_changed(previous).await;
78    }
79
80    pub async fn set_prompt_template(&mut self, template: crate::PromptTemplate) {
81        let mut prompt = self.policy.prompt.clone();
82        prompt.template = Some(template);
83        self.update_session_config(None, None, None, None, Some(prompt))
84            .await;
85    }
86
87    pub async fn clear_prompt_template(&mut self) {
88        let mut prompt = self.policy.prompt.clone();
89        prompt.template = None;
90        self.update_session_config(None, None, None, None, Some(prompt))
91            .await;
92    }
93
94    pub async fn add_prompt_contribution(&mut self, contribution: crate::PromptContribution) {
95        let mut prompt = self.policy.prompt.clone();
96        prompt.add_contribution(contribution);
97        self.update_session_config(None, None, None, None, Some(prompt))
98            .await;
99    }
100
101    pub async fn replace_prompt_slot(
102        &mut self,
103        slot: crate::PromptSlot,
104        contributions: impl IntoIterator<Item = crate::PromptContribution>,
105    ) {
106        let mut prompt = self.policy.prompt.clone();
107        prompt.replace_slot(slot, contributions);
108        self.update_session_config(None, None, None, None, Some(prompt))
109            .await;
110    }
111
112    pub async fn clear_prompt_slot(&mut self, slot: crate::PromptSlot) {
113        let mut prompt = self.policy.prompt.clone();
114        prompt.clear_slot(slot);
115        self.update_session_config(None, None, None, None, Some(prompt))
116            .await;
117    }
118
119    /// Re-register the current tool surface in the live RLM session.
120    pub async fn refresh_session_tool_surface(&mut self) -> Result<(), SessionError> {
121        let Some(session) = self.session.as_mut() else {
122            return Err(SessionError::Protocol(
123                "runtime session not available".to_string(),
124            ));
125        };
126        session.refresh_tool_surface().await?;
127        self.stamp_live_plugin_state();
128        Ok(())
129    }
130
131    pub async fn apply_tool_state(
132        &mut self,
133        snapshot: crate::ToolState,
134    ) -> Result<u64, SessionError> {
135        let Some(session) = self.session.as_mut() else {
136            return Err(SessionError::Protocol(
137                "runtime session not available".to_string(),
138            ));
139        };
140        let generation = session
141            .plugins()
142            .tool_registry()
143            .apply_state(snapshot)
144            .map_err(|err| SessionError::Protocol(format!("tool reconfigure failed: {err}")))?;
145        self.stamp_live_plugin_state();
146        Ok(generation)
147    }
148}