askit_std_agents/
sequence.rs1use agent_stream_kit::{
2 ASKit, AgentContext, AgentData, AgentError, AgentOutput, AgentSpec, AgentValue, AsAgent,
3 askit_agent, async_trait,
4};
5
6static CATEGORY: &str = "Std/Sequence";
7
8static PIN_IN: &str = "in";
9static PIN_IN1: &str = "in1";
10static PIN_IN2: &str = "in2";
11static PIN_OUT1: &str = "out1";
12static PIN_OUT2: &str = "out2";
13
14#[askit_agent(
16 title = "Sequence",
17 category = CATEGORY,
18 inputs = [PIN_IN],
19 outputs = [PIN_OUT1, PIN_OUT2],
20 integer_config(name = "n", default = 2),
21)]
22struct SequenceAgent {
23 data: AgentData,
24 n: usize,
25}
26
27#[async_trait]
28impl AsAgent for SequenceAgent {
29 fn new(askit: ASKit, id: String, spec: AgentSpec) -> Result<Self, AgentError> {
30 let n = spec
31 .configs
32 .as_ref()
33 .map(|cfg| cfg.get_integer_or("n", 2))
34 .unwrap_or(2) as usize;
35 let mut spec = spec;
36 spec.outputs = Some((1..=n).map(|i| format!("out{}", i)).collect());
37 let data = AgentData::new(askit, id, spec);
38 Ok(Self { data, n })
39 }
40
41 fn configs_changed(&mut self) -> Result<(), AgentError> {
42 let cfg_n = self
43 .data
44 .spec
45 .configs
46 .as_ref()
47 .map(|cfg| cfg.get_integer_or("n", 2))
48 .unwrap_or(2) as usize;
49 if cfg_n != self.n {
50 self.n = cfg_n;
51 self.data.spec.outputs = Some((1..=self.n).map(|i| format!("out{}", i)).collect());
52 self.emit_agent_spec_updated();
53 }
54 Ok(())
55 }
56
57 async fn process(
58 &mut self,
59 ctx: AgentContext,
60 _pin: String,
61 value: AgentValue,
62 ) -> Result<(), AgentError> {
63 for i in 0..self.n {
64 let out_pin = format!("out{}", i + 1);
65 self.try_output(ctx.clone(), out_pin, value.clone())?;
66 }
67 Ok(())
68 }
69}
70
71#[askit_agent(
73 title = "Sync",
74 category = CATEGORY,
75 inputs = [PIN_IN1, PIN_IN2],
76 outputs = [PIN_OUT1, PIN_OUT2],
77 integer_config(name = "n", default = 2),
78)]
79struct SyncAgent {
80 data: AgentData,
81 n: usize,
82 input_values: Vec<Option<AgentValue>>,
83 current_id: usize,
84}
85
86#[async_trait]
87impl AsAgent for SyncAgent {
88 fn new(askit: ASKit, id: String, spec: AgentSpec) -> Result<Self, AgentError> {
89 let n = spec
90 .configs
91 .as_ref()
92 .map(|cfg| cfg.get_integer_or("n", 2))
93 .unwrap_or(2) as usize;
94 let mut spec = spec;
95 spec.inputs = Some((1..=n).map(|i| format!("in{}", i)).collect());
96 spec.outputs = Some((1..=n).map(|i| format!("out{}", i)).collect());
97 let data = AgentData::new(askit, id, spec);
98 Ok(Self {
99 data,
100 n,
101 input_values: vec![None; n],
102 current_id: 0,
103 })
104 }
105
106 fn configs_changed(&mut self) -> Result<(), AgentError> {
107 let cfg_n = self
108 .data
109 .spec
110 .configs
111 .as_ref()
112 .map(|cfg| cfg.get_integer_or("n", 2))
113 .unwrap_or(2) as usize;
114 if cfg_n < 1 {
115 return Err(AgentError::InvalidConfig("n must be at least 1".into()));
116 }
117 if cfg_n != self.n {
118 self.n = cfg_n;
119 self.data.spec.inputs = Some((1..=self.n).map(|i| format!("in{}", i)).collect());
120 self.data.spec.outputs = Some((1..=self.n).map(|i| format!("out{}", i)).collect());
121 self.input_values = vec![None; self.n];
122 self.current_id = 0;
123 self.emit_agent_spec_updated();
124 }
125 Ok(())
126 }
127
128 async fn process(
129 &mut self,
130 ctx: AgentContext,
131 pin: String,
132 value: AgentValue,
133 ) -> Result<(), AgentError> {
134 let ctx_id = ctx.id();
136 if ctx_id != self.current_id {
137 self.current_id = ctx_id;
138 self.input_values = vec![None; self.n];
139 }
140
141 let Some(i) = pin
143 .strip_prefix("in")
144 .and_then(|s| s.parse::<usize>().ok())
145 .and_then(|idx| {
146 if idx >= 1 && idx <= self.n {
147 Some(idx - 1)
148 } else {
149 None
150 }
151 })
152 else {
153 return Err(AgentError::InvalidValue(format!(
154 "Invalid input pin: {}",
155 pin
156 )));
157 };
158
159 self.input_values[i] = Some(value);
160
161 if self.input_values.iter().any(|v| v.is_none()) {
163 return Ok(());
164 }
165
166 for i in 0..self.n {
168 let out_value = self.input_values[i].take().unwrap();
169 self.try_output(
170 ctx.clone(),
171 self.data.spec.outputs.as_ref().unwrap()[i].clone(),
172 out_value,
173 )?;
174 }
175
176 Ok(())
177 }
178}