1use std::{pin::Pin, sync::Arc};
16
17use async_trait::async_trait;
18use swiftide_core::{
19 ChatCompletion, Command, CommandError, CommandOutput, SimplePrompt, ToolExecutor,
20 chat_completion::{ChatCompletionRequest, ChatCompletionResponse, errors::LanguageModelError},
21 prompt::Prompt,
22};
23
24use super::{
25 errors::NodeError,
26 node::NodeId,
27 traits::{NodeArg, TaskNode},
28};
29
30pub struct SyncFn<F, I, O, E = NodeError>
34where
35 F: Fn(&I) -> Result<O, E> + Send + Sync + Clone + 'static,
36 E: std::error::Error + Send + Sync + 'static,
37{
38 f: F,
39 _phantom: std::marker::PhantomData<(I, O, E)>,
40}
41
42pub struct AsyncFn<F, I, O, E = NodeError>
44where
45 F: for<'a> Fn(&'a I) -> Pin<Box<dyn Future<Output = Result<O, E>> + Send + 'a>>
46 + Send
47 + Sync
48 + Clone
49 + 'static,
50 E: std::error::Error + Send + Sync + 'static,
51{
52 f: F,
53 _phantom: std::marker::PhantomData<(I, O, E)>,
54}
55
56impl<F, I, O, E> Clone for SyncFn<F, I, O, E>
57where
58 F: Fn(&I) -> Result<O, E> + Send + Sync + Clone + 'static,
59 E: std::error::Error + Send + Sync + 'static,
60{
61 fn clone(&self) -> Self {
62 Self {
63 f: self.f.clone(),
64 _phantom: std::marker::PhantomData,
65 }
66 }
67}
68
69impl<F, I, O, E> Clone for AsyncFn<F, I, O, E>
70where
71 F: for<'a> Fn(&'a I) -> Pin<Box<dyn Future<Output = Result<O, E>> + Send + 'a>>
72 + Send
73 + Sync
74 + Clone
75 + 'static,
76 E: std::error::Error + Send + Sync + 'static,
77{
78 fn clone(&self) -> Self {
79 Self {
80 f: self.f.clone(),
81 _phantom: std::marker::PhantomData,
82 }
83 }
84}
85
86impl<F, I, O, E> SyncFn<F, I, O, E>
87where
88 F: Fn(&I) -> Result<O, E> + Send + Sync + Clone + 'static,
89 I: NodeArg + Clone,
90 O: NodeArg + Clone,
91 E: std::error::Error + Send + Sync + 'static,
92{
93 pub fn new(f: F) -> Self {
95 Self {
96 f,
97 _phantom: std::marker::PhantomData,
98 }
99 }
100}
101
102impl<F, I, O, E> AsyncFn<F, I, O, E>
103where
104 F: for<'a> Fn(&'a I) -> Pin<Box<dyn Future<Output = Result<O, E>> + Send + 'a>>
105 + Send
106 + Sync
107 + Clone
108 + 'static,
109 I: NodeArg + Clone,
110 O: NodeArg + Clone,
111 E: std::error::Error + Send + Sync + 'static,
112{
113 pub fn new(f: F) -> Self {
115 Self {
116 f,
117 _phantom: std::marker::PhantomData,
118 }
119 }
120}
121
122impl<F> From<F> for SyncFn<F, (), ()>
123where
124 F: Fn(&()) -> Result<(), NodeError> + Send + Sync + Clone + 'static,
125{
126 fn from(f: F) -> Self {
127 Self::new(f)
128 }
129}
130
131impl<F> From<F> for AsyncFn<F, (), ()>
132where
133 F: for<'a> Fn(&'a ()) -> Pin<Box<dyn Future<Output = Result<(), NodeError>> + Send + 'a>>
134 + Send
135 + Sync
136 + Clone
137 + 'static,
138{
139 fn from(f: F) -> Self {
140 Self::new(f)
141 }
142}
143
144#[async_trait]
145impl<F, I, O, E> TaskNode for SyncFn<F, I, O, E>
146where
147 F: Fn(&I) -> Result<O, E> + Clone + Send + Sync + 'static,
148 I: NodeArg + Clone,
149 O: NodeArg + Clone,
150 E: std::error::Error + Send + Sync + 'static,
151{
152 type Input = I;
153 type Output = O;
154 type Error = E;
155
156 async fn evaluate(
157 &self,
158 _node_id: &NodeId<
159 dyn TaskNode<Input = Self::Input, Output = Self::Output, Error = Self::Error>,
160 >,
161 input: &Self::Input,
162 ) -> Result<Self::Output, Self::Error> {
163 (self.f)(input)
164 }
165}
166
167#[async_trait]
168impl<F, I, O, E> TaskNode for AsyncFn<F, I, O, E>
169where
170 F: for<'a> Fn(&'a I) -> Pin<Box<dyn Future<Output = Result<O, E>> + Send + 'a>>
171 + Clone
172 + Send
173 + Sync
174 + 'static,
175 I: NodeArg + Clone,
176 O: NodeArg + Clone,
177 E: std::error::Error + Send + Sync + 'static,
178{
179 type Input = I;
180 type Output = O;
181 type Error = E;
182
183 async fn evaluate(
184 &self,
185 _node_id: &NodeId<
186 dyn TaskNode<Input = Self::Input, Output = Self::Output, Error = Self::Error>,
187 >,
188 input: &Self::Input,
189 ) -> Result<Self::Output, Self::Error> {
190 (self.f)(input).await
191 }
192}
193
194macro_rules! impl_task_node_for_prompt_like {
195 ($ty:ty, $input:ty, $output:ty, $error:ty, |$this:ident, $input_value:ident| $body:expr) => {
196 #[async_trait]
197 impl TaskNode for $ty {
198 type Input = $input;
199 type Output = $output;
200 type Error = $error;
201
202 async fn evaluate(
203 &self,
204 _node_id: &NodeId<
205 dyn TaskNode<Input = Self::Input, Output = Self::Output, Error = Self::Error>,
206 >,
207 $input_value: &Self::Input,
208 ) -> Result<Self::Output, Self::Error> {
209 let $this = self;
210 $body
211 }
212 }
213 };
214}
215
216impl_task_node_for_prompt_like!(
217 Box<dyn SimplePrompt>,
218 Prompt,
219 String,
220 LanguageModelError,
221 |this, input| {
222 this.prompt(input.clone()).await
224 }
225);
226
227impl_task_node_for_prompt_like!(
228 Arc<dyn SimplePrompt>,
229 Prompt,
230 String,
231 LanguageModelError,
232 |this, input| {
233 this.prompt(input.clone()).await
235 }
236);
237
238impl_task_node_for_prompt_like!(
239 Box<dyn ChatCompletion>,
240 ChatCompletionRequest<'static>,
241 ChatCompletionResponse,
242 LanguageModelError,
243 |this, input| this.complete(input).await
244);
245
246impl_task_node_for_prompt_like!(
247 Arc<dyn ChatCompletion>,
248 ChatCompletionRequest<'static>,
249 ChatCompletionResponse,
250 LanguageModelError,
251 |this, input| this.complete(input).await
252);
253
254impl_task_node_for_prompt_like!(
255 Box<dyn ToolExecutor>,
256 Command,
257 CommandOutput,
258 CommandError,
259 |this, input| this.exec_cmd(input).await
260);
261
262impl_task_node_for_prompt_like!(
263 Arc<dyn ToolExecutor>,
264 Command,
265 CommandOutput,
266 CommandError,
267 |this, input| this.exec_cmd(input).await
268);