mofa_kernel/workflow/
reducer.rs1use async_trait::async_trait;
7use serde::{Deserialize, Serialize};
8use serde_json::Value;
9
10use crate::agent::error::AgentResult;
11
12#[async_trait]
27pub trait Reducer: Send + Sync {
28 async fn reduce(&self, current: Option<&Value>, update: &Value) -> AgentResult<Value>;
37
38 fn name(&self) -> &str;
40
41 fn reducer_type(&self) -> ReducerType;
43}
44
45#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
47pub enum ReducerType {
48 Overwrite,
50
51 Append,
53
54 Extend,
56
57 Merge {
59 deep: bool,
61 },
62
63 LastN {
65 n: usize,
67 },
68
69 First,
71
72 Last,
74
75 Custom(String),
77}
78
79impl Default for ReducerType {
80 fn default() -> Self {
81 Self::Overwrite
82 }
83}
84
85impl std::fmt::Display for ReducerType {
86 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
87 match self {
88 ReducerType::Overwrite => write!(f, "overwrite"),
89 ReducerType::Append => write!(f, "append"),
90 ReducerType::Extend => write!(f, "extend"),
91 ReducerType::Merge { deep } => write!(f, "merge(deep={})", deep),
92 ReducerType::LastN { n } => write!(f, "last_n({})", n),
93 ReducerType::First => write!(f, "first"),
94 ReducerType::Last => write!(f, "last"),
95 ReducerType::Custom(name) => write!(f, "custom({})", name),
96 }
97 }
98}
99
100#[derive(Debug, Clone, Serialize, Deserialize)]
104pub struct StateUpdate {
105 pub key: String,
107 pub value: Value,
109}
110
111impl StateUpdate {
112 pub fn new(key: impl Into<String>, value: Value) -> Self {
114 Self {
115 key: key.into(),
116 value,
117 }
118 }
119
120 pub fn from_serializable<T: Serialize>(key: impl Into<String>, value: &T) -> AgentResult<Self> {
122 Ok(Self::new(key, serde_json::to_value(value)?))
123 }
124}
125
126impl From<(String, Value)> for StateUpdate {
127 fn from((key, value): (String, Value)) -> Self {
128 Self::new(key, value)
129 }
130}
131
132impl From<(&str, Value)> for StateUpdate {
133 fn from((key, value): (&str, Value)) -> Self {
134 Self::new(key, value)
135 }
136}
137
138#[cfg(test)]
139mod tests {
140 use super::*;
141 use serde_json::json;
142
143 #[test]
144 fn test_state_update_creation() {
145 let update = StateUpdate::new("key", json!("value"));
146 assert_eq!(update.key, "key");
147 assert_eq!(update.value, json!("value"));
148 }
149
150 #[test]
151 fn test_state_update_from_tuple() {
152 let update: StateUpdate = ("message", json!("hello")).into();
153 assert_eq!(update.key, "message");
154 assert_eq!(update.value, json!("hello"));
155 }
156
157 #[test]
158 fn test_reducer_type_display() {
159 assert_eq!(ReducerType::Overwrite.to_string(), "overwrite");
160 assert_eq!(
161 ReducerType::Merge { deep: true }.to_string(),
162 "merge(deep=true)"
163 );
164 assert_eq!(ReducerType::LastN { n: 5 }.to_string(), "last_n(5)");
165 }
166}