lash_core/runtime/
observation.rs1use std::sync::Arc;
2
3use arc_swap::ArcSwap;
4use tokio::sync::Mutex;
5
6use super::{BackgroundTaskHost, BackgroundTaskRecord, LashRuntime};
7
8#[derive(Clone)]
9pub struct RuntimeObservation {
10 pub session_id: Arc<str>,
11 pub policy: crate::SessionPolicy,
12 pub read_view: crate::SessionReadView,
13 pub persisted_state: super::PersistedSessionState,
14 pub usage_report: super::SessionUsageReport,
15 pub tool_state: Option<crate::ToolState>,
16 pub tool_catalog: Arc<Vec<serde_json::Value>>,
17 pub runtime_scope_id: Arc<str>,
18 pub background_task_host: Option<Arc<dyn BackgroundTaskHost>>,
19}
20
21impl RuntimeObservation {
22 fn from_runtime(runtime: &LashRuntime) -> Self {
23 Self {
24 session_id: Arc::from(runtime.session_id()),
25 policy: runtime.read_view().policy().clone(),
26 read_view: runtime.read_view(),
27 persisted_state: runtime.export_persisted_state(),
28 usage_report: runtime.usage_report(),
29 tool_state: runtime.tool_state().ok(),
30 tool_catalog: runtime.active_tool_catalog_shared(),
31 runtime_scope_id: Arc::clone(&runtime.runtime_scope_id),
32 background_task_host: runtime.host.background_task_host.clone(),
33 }
34 }
35
36 pub fn session_id(&self) -> &str {
37 &self.session_id
38 }
39
40 pub fn background_scope_key(&self) -> String {
41 format!("{}:{}", self.runtime_scope_id, self.session_id)
42 }
43
44 pub async fn list_background_tasks(&self) -> Vec<BackgroundTaskRecord> {
45 let Some(executor) = self.background_task_host.as_ref() else {
46 return Vec::new();
47 };
48 executor.list_managed(&self.background_scope_key()).await
49 }
50}
51
52#[derive(Clone)]
53pub struct RuntimeHandle {
54 pub(in crate::runtime) runtime: Arc<Mutex<LashRuntime>>,
55 observation: Arc<ArcSwap<RuntimeObservation>>,
56}
57
58impl RuntimeHandle {
59 pub fn new(runtime: LashRuntime) -> Self {
60 let observation = RuntimeObservation::from_runtime(&runtime);
61 Self {
62 runtime: Arc::new(Mutex::new(runtime)),
63 observation: Arc::new(ArcSwap::from_pointee(observation)),
64 }
65 }
66
67 pub fn writer(&self) -> Arc<Mutex<LashRuntime>> {
68 Arc::clone(&self.runtime)
69 }
70
71 pub fn observe(&self) -> Arc<RuntimeObservation> {
72 self.observation.load_full()
73 }
74
75 pub fn publish_from(&self, runtime: &LashRuntime) {
76 self.observation
77 .store(Arc::new(RuntimeObservation::from_runtime(runtime)));
78 }
79
80 pub fn try_into_runtime(self) -> Result<LashRuntime, Self> {
81 match Arc::try_unwrap(self.runtime) {
82 Ok(mutex) => Ok(mutex.into_inner()),
83 Err(runtime) => Err(Self {
84 runtime,
85 observation: self.observation,
86 }),
87 }
88 }
89}