Skip to main content

mofa_kernel/agent/secretary/
context.rs

1//! 秘书上下文
2//!
3//! 提供秘书执行过程中的上下文管理
4
5use std::any::Any;
6use std::collections::HashMap;
7use std::sync::Arc;
8use tokio::sync::RwLock;
9
10// =============================================================================
11// 秘书上下文
12// =============================================================================
13
14/// 秘书上下文
15///
16/// 在秘书处理过程中传递状态和共享资源。
17///
18/// # 类型参数
19///
20/// - `State`: 用户定义的状态类型
21///
22/// # 示例
23///
24/// ```rust,ignore
25/// struct MyState {
26///     counter: u32,
27/// }
28///
29/// let mut ctx = SecretaryContext::new(MyState { counter: 0 });
30/// ctx.state_mut().counter += 1;
31/// ctx.set_metadata("key", "value");
32/// ```
33pub struct SecretaryContext<State> {
34    /// 用户定义的状态
35    state: State,
36
37    /// 元数据存储
38    metadata: HashMap<String, Box<dyn Any + Send + Sync>>,
39
40    /// 共享资源
41    resources: HashMap<String, Arc<dyn Any + Send + Sync>>,
42}
43
44impl<State> SecretaryContext<State> {
45    /// 创建新的上下文
46    pub fn new(state: State) -> Self {
47        Self {
48            state,
49            metadata: HashMap::new(),
50            resources: HashMap::new(),
51        }
52    }
53
54    /// 获取状态引用
55    pub fn state(&self) -> &State {
56        &self.state
57    }
58
59    /// 获取状态可变引用
60    pub fn state_mut(&mut self) -> &mut State {
61        &mut self.state
62    }
63
64    /// 替换状态
65    pub fn set_state(&mut self, state: State) {
66        self.state = state;
67    }
68
69    /// 设置元数据
70    pub fn set_metadata<T: Any + Send + Sync>(&mut self, key: impl Into<String>, value: T) {
71        self.metadata.insert(key.into(), Box::new(value));
72    }
73
74    /// 获取元数据
75    pub fn get_metadata<T: Any + Send + Sync>(&self, key: &str) -> Option<&T> {
76        self.metadata.get(key).and_then(|v| v.downcast_ref())
77    }
78
79    /// 移除元数据
80    pub fn remove_metadata(&mut self, key: &str) -> bool {
81        self.metadata.remove(key).is_some()
82    }
83
84    /// 注册共享资源
85    pub fn register_resource<T: Any + Send + Sync>(
86        &mut self,
87        key: impl Into<String>,
88        resource: Arc<T>,
89    ) {
90        self.resources.insert(key.into(), resource);
91    }
92
93    /// 获取共享资源
94    pub fn get_resource<T: Any + Send + Sync>(&self, key: &str) -> Option<Arc<T>> {
95        self.resources
96            .get(key)
97            .and_then(|r| r.clone().downcast::<T>().ok())
98    }
99
100    /// 检查资源是否存在
101    pub fn has_resource(&self, key: &str) -> bool {
102        self.resources.contains_key(key)
103    }
104}
105
106// =============================================================================
107// 共享上下文
108// =============================================================================
109
110/// 共享秘书上下文
111///
112/// 用于在多个任务之间共享上下文
113pub type SharedSecretaryContext<State> = Arc<RwLock<SecretaryContext<State>>>;
114
115// =============================================================================
116// 上下文构建器
117// =============================================================================
118
119/// 上下文构建器
120pub struct SecretaryContextBuilder<State> {
121    state: State,
122    metadata: HashMap<String, Box<dyn Any + Send + Sync>>,
123    resources: HashMap<String, Arc<dyn Any + Send + Sync>>,
124}
125
126impl<State> SecretaryContextBuilder<State> {
127    /// 创建构建器
128    pub fn new(state: State) -> Self {
129        Self {
130            state,
131            metadata: HashMap::new(),
132            resources: HashMap::new(),
133        }
134    }
135
136    /// 添加元数据
137    pub fn with_metadata<T: Any + Send + Sync>(mut self, key: impl Into<String>, value: T) -> Self {
138        self.metadata.insert(key.into(), Box::new(value));
139        self
140    }
141
142    /// 添加资源
143    pub fn with_resource<T: Any + Send + Sync>(
144        mut self,
145        key: impl Into<String>,
146        resource: Arc<T>,
147    ) -> Self {
148        self.resources.insert(key.into(), resource);
149        self
150    }
151
152    /// 构建上下文
153    pub fn build(self) -> SecretaryContext<State> {
154        SecretaryContext {
155            state: self.state,
156            metadata: self.metadata,
157            resources: self.resources,
158        }
159    }
160
161    /// 构建共享上下文
162    pub fn build_shared(self) -> SharedSecretaryContext<State> {
163        Arc::new(RwLock::new(self.build()))
164    }
165}
166
167// =============================================================================
168// 测试
169// =============================================================================
170
171#[cfg(test)]
172mod tests {
173    use super::*;
174
175    struct TestState {
176        value: i32,
177    }
178
179    #[test]
180    fn test_context_state() {
181        let mut ctx = SecretaryContext::new(TestState { value: 42 });
182
183        assert_eq!(ctx.state().value, 42);
184        ctx.state_mut().value = 100;
185        assert_eq!(ctx.state().value, 100);
186    }
187
188    #[test]
189    fn test_context_metadata() {
190        let mut ctx = SecretaryContext::new(TestState { value: 0 });
191
192        ctx.set_metadata("key", "value".to_string());
193        assert_eq!(
194            ctx.get_metadata::<String>("key"),
195            Some(&"value".to_string())
196        );
197
198        ctx.remove_metadata("key");
199        assert!(ctx.get_metadata::<String>("key").is_none());
200    }
201
202    #[test]
203    fn test_context_builder() {
204        let ctx = SecretaryContextBuilder::new(TestState { value: 1 })
205            .with_metadata("name", "test".to_string())
206            .build();
207
208        assert_eq!(ctx.state().value, 1);
209        assert_eq!(
210            ctx.get_metadata::<String>("name"),
211            Some(&"test".to_string())
212        );
213    }
214
215    #[tokio::test]
216    async fn test_shared_context() {
217        let shared = SecretaryContextBuilder::new(TestState { value: 0 }).build_shared();
218
219        {
220            let mut ctx = shared.write().await;
221            ctx.state_mut().value = 42;
222        }
223
224        let ctx = shared.read().await;
225        assert_eq!(ctx.state().value, 42);
226    }
227}