agent_stream_kit/
spec.rs

1use std::ops::Not;
2
3use serde::{Deserialize, Serialize};
4use serde_json::Value;
5
6use crate::FnvIndexMap;
7use crate::config::AgentConfigs;
8use crate::definition::AgentConfigSpecs;
9use crate::error::AgentError;
10
11pub type AgentStreamSpecs = FnvIndexMap<String, AgentStreamSpec>;
12
13#[derive(Clone, Debug, Default, Deserialize, Serialize)]
14pub struct AgentStreamSpec {
15    pub agents: Vec<AgentSpec>,
16
17    pub channels: Vec<ChannelSpec>,
18
19    #[serde(flatten)]
20    pub extensions: FnvIndexMap<String, Value>,
21}
22
23impl AgentStreamSpec {
24    pub fn add_agent(&mut self, agent: AgentSpec) {
25        self.agents.push(agent);
26    }
27
28    pub fn remove_agent(&mut self, agent_id: &str) {
29        self.agents.retain(|agent| agent.id != agent_id);
30    }
31
32    pub fn add_channel(&mut self, channel: ChannelSpec) {
33        self.channels.push(channel);
34    }
35
36    pub fn remove_channel(&mut self, channel: &ChannelSpec) -> Option<ChannelSpec> {
37        let Some(index) = self.channels.iter().position(|c| c == channel) else {
38            return None;
39        };
40        Some(self.channels.remove(index))
41    }
42
43    pub fn to_json(&self) -> Result<String, AgentError> {
44        let json = serde_json::to_string_pretty(self)
45            .map_err(|e| AgentError::SerializationError(e.to_string()))?;
46        Ok(json)
47    }
48
49    pub fn from_json(json_str: &str) -> Result<Self, AgentError> {
50        let stream: AgentStreamSpec = serde_json::from_str(json_str)
51            .map_err(|e| AgentError::SerializationError(e.to_string()))?;
52        Ok(stream)
53    }
54}
55
56/// Information held by each agent.
57#[derive(Debug, Clone, Serialize, Deserialize)]
58pub struct AgentSpec {
59    #[serde(skip_serializing_if = "String::is_empty", default)]
60    pub id: String,
61
62    /// Name of the AgentDefinition.
63    #[serde(skip_serializing_if = "String::is_empty", default)]
64    pub def_name: String,
65
66    /// List of input pin names.
67    #[serde(skip_serializing_if = "Option::is_none", default)]
68    pub inputs: Option<Vec<String>>,
69
70    /// List of output pin names.
71    #[serde(skip_serializing_if = "Option::is_none", default)]
72    pub outputs: Option<Vec<String>>,
73
74    /// Config values.
75    #[serde(skip_serializing_if = "Option::is_none")]
76    pub configs: Option<AgentConfigs>,
77
78    /// Config specs.
79    #[serde(skip_serializing_if = "Option::is_none")]
80    pub config_specs: Option<AgentConfigSpecs>,
81
82    #[deprecated(note = "Use `disabled` instead")]
83    #[serde(default, skip_serializing_if = "<&bool>::not")]
84    pub enabled: bool,
85
86    #[serde(default, skip_serializing_if = "<&bool>::not")]
87    pub disabled: bool,
88
89    #[serde(flatten)]
90    pub extensions: FnvIndexMap<String, serde_json::Value>,
91}
92
93impl AgentSpec {
94    pub fn update(&mut self, value: &Value) -> Result<(), AgentError> {
95        let update_map = value
96            .as_object()
97            .ok_or_else(|| AgentError::SerializationError("Expected JSON object".to_string()))?;
98
99        for (k, v) in update_map {
100            match k.as_str() {
101                "id" => {
102                    if let Some(id_str) = v.as_str() {
103                        self.id = id_str.to_string();
104                    }
105                }
106                "def_name" => {
107                    if let Some(def_name_str) = v.as_str() {
108                        self.def_name = def_name_str.to_string();
109                    }
110                }
111                "inputs" => {
112                    if let Some(inputs_array) = v.as_array() {
113                        self.inputs = Some(
114                            inputs_array
115                                .iter()
116                                .filter_map(|v| v.as_str().map(|s| s.to_string()))
117                                .collect(),
118                        );
119                    }
120                }
121                "outputs" => {
122                    if let Some(outputs_array) = v.as_array() {
123                        self.outputs = Some(
124                            outputs_array
125                                .iter()
126                                .filter_map(|v| v.as_str().map(|s| s.to_string()))
127                                .collect(),
128                        );
129                    }
130                }
131                "configs" => {
132                    let configs: AgentConfigs = serde_json::from_value(v.clone())
133                        .map_err(|e| AgentError::SerializationError(e.to_string()))?;
134                    self.configs = Some(configs);
135                }
136                "disabled" => {
137                    if let Some(disabled_bool) = v.as_bool() {
138                        self.disabled = disabled_bool;
139                    }
140                }
141                _ => {
142                    // Update extensions
143                    self.extensions.insert(k.clone(), v.clone());
144                }
145            }
146        }
147
148        Ok(())
149    }
150}
151
152// ChannelSpec
153
154#[derive(Clone, Debug, Default, Eq, PartialEq, Serialize, Deserialize)]
155pub struct ChannelSpec {
156    pub source: String,
157    pub source_handle: String,
158    pub target: String,
159    pub target_handle: String,
160}