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#[derive(Debug, Clone, Serialize, Deserialize)]
58pub struct AgentSpec {
59 #[serde(skip_serializing_if = "String::is_empty", default)]
60 pub id: String,
61
62 #[serde(skip_serializing_if = "String::is_empty", default)]
64 pub def_name: String,
65
66 #[serde(skip_serializing_if = "Option::is_none", default)]
68 pub inputs: Option<Vec<String>>,
69
70 #[serde(skip_serializing_if = "Option::is_none", default)]
72 pub outputs: Option<Vec<String>>,
73
74 #[serde(skip_serializing_if = "Option::is_none")]
76 pub configs: Option<AgentConfigs>,
77
78 #[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 self.extensions.insert(k.clone(), v.clone());
144 }
145 }
146 }
147
148 Ok(())
149 }
150}
151
152#[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}