1use std::sync::{Arc, RwLock, Weak};
7use uuid::Uuid;
8
9pub struct RuntimeRef {
17 runtime_weak: Weak<RwLock<crate::AgentRuntime>>,
19
20 agent_id: Uuid,
22
23 agent_name: String,
25}
26
27impl RuntimeRef {
28 pub fn new(runtime: &Arc<RwLock<crate::AgentRuntime>>) -> Self {
30 let rt = runtime.read().unwrap();
31 Self {
32 runtime_weak: Arc::downgrade(runtime),
33 agent_id: rt.agent_id,
34 agent_name: rt.character.name.clone(),
35 }
36 }
37
38 pub fn agent_id(&self) -> Uuid {
40 self.agent_id
41 }
42
43 pub fn agent_name(&self) -> &str {
45 &self.agent_name
46 }
47
48 pub fn try_upgrade(&self) -> Option<Arc<RwLock<crate::AgentRuntime>>> {
51 self.runtime_weak.upgrade()
52 }
53
54 pub fn get_setting(&self, key: &str) -> Option<serde_json::Value> {
56 self.try_upgrade().and_then(|rt| {
57 let runtime = rt.read().unwrap();
58 runtime.get_setting(key)
59 })
60 }
61}
62
63unsafe impl Send for RuntimeRef {}
65unsafe impl Sync for RuntimeRef {}
66
67impl std::fmt::Debug for RuntimeRef {
68 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
69 f.debug_struct("RuntimeRef")
70 .field("agent_id", &self.agent_id)
71 .field("agent_name", &self.agent_name)
72 .field("runtime_available", &self.runtime_weak.strong_count())
73 .finish()
74 }
75}
76
77impl RuntimeRef {
79 pub fn as_any_arc(self: &Arc<Self>) -> Arc<dyn std::any::Any + Send + Sync> {
81 Arc::clone(self) as Arc<dyn std::any::Any + Send + Sync>
82 }
83}
84
85pub fn downcast_runtime_ref(any: &Arc<dyn std::any::Any + Send + Sync>) -> Option<Arc<RuntimeRef>> {
87 any.clone().downcast::<RuntimeRef>().ok()
88}
89
90#[cfg(test)]
91mod tests {
92 use super::*;
93 use crate::{Character, RuntimeOpts};
94
95 #[tokio::test]
96 async fn test_runtime_ref() {
97 let runtime = crate::AgentRuntime::new(RuntimeOpts {
98 character: Some(Character {
99 name: "TestBot".to_string(),
100 ..Default::default()
101 }),
102 ..Default::default()
103 })
104 .await
105 .unwrap();
106
107 let runtime_ref = Arc::new(RuntimeRef::new(&runtime));
108
109 assert_eq!(runtime_ref.agent_name(), "TestBot");
110 assert!(runtime_ref.try_upgrade().is_some());
111 }
112
113 #[tokio::test]
114 async fn test_runtime_ref_weak() {
115 let runtime = crate::AgentRuntime::new(RuntimeOpts {
116 character: Some(Character {
117 name: "TestBot".to_string(),
118 ..Default::default()
119 }),
120 ..Default::default()
121 })
122 .await
123 .unwrap();
124
125 let runtime_ref = Arc::new(RuntimeRef::new(&runtime));
126
127 assert!(runtime_ref.try_upgrade().is_some());
129
130 drop(runtime);
132
133 assert!(runtime_ref.try_upgrade().is_none());
135 }
136
137 #[tokio::test]
138 async fn test_downcast() {
139 let runtime = crate::AgentRuntime::new(RuntimeOpts {
140 character: Some(Character {
141 name: "TestBot".to_string(),
142 ..Default::default()
143 }),
144 ..Default::default()
145 })
146 .await
147 .unwrap();
148
149 let runtime_ref = Arc::new(RuntimeRef::new(&runtime));
150 let any_arc = runtime_ref.as_any_arc();
151
152 let downcasted = downcast_runtime_ref(&any_arc);
153 assert!(downcasted.is_some());
154 assert_eq!(downcasted.unwrap().agent_name(), "TestBot");
155 }
156}