1use std::sync::Arc;
12
13use serde::de::DeserializeOwned;
14use serde::{Deserialize, Serialize};
15
16use super::{SessionAppendNode, SessionCreateRequest};
17use crate::runtime::PersistedSessionState;
18use crate::{
19 ExecRequest, ExecResponse, ExecutionMode, LlmRequest, ModeExecutionContext, PromptUsage,
20 SessionReadView, ToolContract, ToolManifest, ToolResult,
21};
22
23#[async_trait::async_trait]
31pub trait ModeSessionPlugin: Send + Sync {
32 async fn initialize_session(
33 &self,
34 _ctx: ModeSessionContext<'_>,
35 ) -> Result<(), crate::SessionError> {
36 Ok(())
37 }
38
39 async fn restore_session(
40 &self,
41 _ctx: ModeSessionContext<'_>,
42 _state: &PersistedSessionState,
43 ) -> Result<(), crate::SessionError> {
44 Ok(())
45 }
46
47 async fn append_session_nodes(
48 &self,
49 _ctx: ModeSessionContext<'_>,
50 _nodes: &[SessionAppendNode],
51 ) -> Result<(), crate::SessionError> {
52 Ok(())
53 }
54
55 async fn apply_session_extension(
56 &self,
57 _extension: crate::ModeSessionExtensionHandle,
58 ) -> Result<(), crate::SessionError> {
59 Err(crate::SessionError::Protocol(
60 "execution mode does not accept session extensions".to_string(),
61 ))
62 }
63
64 async fn validate_turn_extension(
65 &self,
66 _extension: &crate::ModeTurnExtensionHandle,
67 ) -> Result<(), crate::SessionError> {
68 Ok(())
69 }
70
71 async fn execute_code(
72 &self,
73 _ctx: ModeExecutionContext,
74 _request: ExecRequest,
75 ) -> Result<ExecResponse, crate::SessionError> {
76 Err(crate::SessionError::RlmUnavailable)
77 }
78
79 fn execution_state_dirty(&self) -> bool {
80 false
81 }
82
83 async fn snapshot_execution_state(
84 &self,
85 _ctx: ModeSessionContext<'_>,
86 ) -> Result<Option<Vec<u8>>, crate::SessionError> {
87 Ok(None)
88 }
89
90 async fn restore_execution_state(
91 &self,
92 _ctx: ModeSessionContext<'_>,
93 _data: &[u8],
94 ) -> Result<(), crate::SessionError> {
95 Ok(())
96 }
97
98 fn configure_runtime_from_request(
99 &self,
100 _ctx: ModeRuntimeContext<'_>,
101 _request: &SessionCreateRequest,
102 ) {
103 }
104
105 async fn before_llm_call(
106 &self,
107 _ctx: ModeBeforeLlmCallContext,
108 _request: &LlmRequest,
109 ) -> Result<Option<ModeLlmCallAction>, crate::PluginError> {
110 Ok(None)
111 }
112}
113
114pub struct ModeSessionContext<'a> {
123 session_id: &'a str,
124}
125
126impl<'a> ModeSessionContext<'a> {
127 pub(crate) fn new(_session: &'a mut crate::Session, session_id: &'a str) -> Self {
128 Self { session_id }
129 }
130
131 pub fn session_id(&self) -> &str {
134 self.session_id
135 }
136}
137
138pub struct ModeBeforeLlmCallContext {
139 pub session_id: String,
140 pub host: Arc<dyn crate::plugin::RuntimeSessionHost>,
141 pub state: SessionReadView,
142 pub latest_prompt_usage: Option<PromptUsage>,
143}
144
145#[derive(Clone, Debug, PartialEq, Eq)]
146pub enum ModeLlmCallAction {
147 Handoff { session_id: String },
148}
149
150pub struct ModeRuntimeContext<'a> {
157 runtime: &'a mut crate::runtime::LashRuntime,
158}
159
160impl<'a> ModeRuntimeContext<'a> {
161 pub(crate) fn new(runtime: &'a mut crate::runtime::LashRuntime) -> Self {
162 Self { runtime }
163 }
164
165 pub fn set_mode_turn_options(&mut self, options: crate::ModeTurnOptions) {
166 self.runtime.set_mode_turn_options(options);
167 }
168}
169
170#[async_trait::async_trait]
171pub trait ModeNativeToolsPlugin: Send + Sync {
172 fn tool_manifests(&self) -> Vec<ToolManifest>;
173 fn resolve_manifest(&self, name: &str) -> Option<ToolManifest> {
174 self.tool_manifests()
175 .into_iter()
176 .find(|manifest| manifest.name == name)
177 }
178 fn resolve_contract(&self, name: &str) -> Option<Arc<ToolContract>>;
179
180 async fn execute(
181 &self,
182 context: &crate::tool_dispatch::ToolDispatchContext,
183 name: &str,
184 args: &serde_json::Value,
185 progress: Option<&crate::ProgressSender>,
186 ) -> Option<ToolResult>;
187}
188
189pub trait ModeProtocolDriverPlugin: Send + Sync {
197 fn mode_id(&self) -> &str;
201
202 fn build_preamble(&self, input: crate::ModeBuildInput) -> crate::ModePreamble;
205}
206
207#[derive(Clone, Debug, Serialize)]
214pub struct ModeExtras {
215 pub mode_id: ExecutionMode,
216 #[serde(default)]
217 pub payload: serde_json::Value,
218}
219
220impl Default for ModeExtras {
221 fn default() -> Self {
222 Self::empty(ExecutionMode::standard())
223 }
224}
225
226impl ModeExtras {
227 pub fn empty(mode_id: ExecutionMode) -> Self {
228 Self {
229 mode_id,
230 payload: serde_json::Value::Object(serde_json::Map::new()),
231 }
232 }
233
234 pub fn typed<T>(mode_id: ExecutionMode, extras: T) -> Result<Self, serde_json::Error>
235 where
236 T: Serialize,
237 {
238 Ok(Self {
239 mode_id,
240 payload: serde_json::to_value(extras)?,
241 })
242 }
243
244 pub fn decode<T>(&self, expected_mode: &ExecutionMode) -> Result<Option<T>, serde_json::Error>
245 where
246 T: DeserializeOwned,
247 {
248 if &self.mode_id != expected_mode {
249 return Ok(None);
250 }
251 serde_json::from_value(self.payload.clone()).map(Some)
252 }
253}
254
255impl<'de> Deserialize<'de> for ModeExtras {
256 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
257 where
258 D: serde::Deserializer<'de>,
259 {
260 let value = serde_json::Value::deserialize(deserializer)?;
261 if let Some(object) = value.as_object() {
262 if let (Some(mode_id), Some(payload)) = (object.get("mode_id"), object.get("payload")) {
263 let mode_id = ExecutionMode::deserialize(mode_id.clone())
264 .map_err(serde::de::Error::custom)?;
265 return Ok(Self {
266 mode_id,
267 payload: payload.clone(),
268 });
269 }
270 if let Some(mode) = object.get("mode").and_then(serde_json::Value::as_str) {
271 let mut payload = object.clone();
272 payload.remove("mode");
273 return Ok(Self {
274 mode_id: ExecutionMode::new(mode),
275 payload: serde_json::Value::Object(payload),
276 });
277 }
278 }
279 Err(serde::de::Error::custom("invalid mode extras payload"))
280 }
281}
282
283#[derive(Clone, Debug, Default, Serialize, Deserialize)]
284pub struct StandardCreateExtras {}