@@ -11,8 +11,8 @@ use serde::Deserialize;
11
11
use serde_trim:: * ;
12
12
13
13
use super :: { variables:: interpolate_variables, Task } ;
14
- use crate :: agent:: get_user_input;
15
14
use crate :: agent:: task:: robopages;
15
+ use crate :: agent:: { get_user_input, namespaces} ;
16
16
use crate :: agent:: {
17
17
namespaces:: { Action , Namespace } ,
18
18
state:: SharedState ,
@@ -41,8 +41,12 @@ pub struct TaskletAction {
41
41
args : Option < HashMap < String , String > > ,
42
42
example_payload : Option < String > ,
43
43
timeout : Option < String > ,
44
- #[ serde( deserialize_with = "string_trim" ) ]
45
- tool : String ,
44
+
45
+ tool : Option < String > ,
46
+ alias : Option < String > ,
47
+
48
+ #[ serde( skip_deserializing, skip_serializing) ]
49
+ aliased_to : Option < Box < dyn Action > > ,
46
50
}
47
51
48
52
#[ async_trait]
@@ -56,10 +60,18 @@ impl Action for TaskletAction {
56
60
}
57
61
58
62
fn example_payload ( & self ) -> Option < & str > {
63
+ if let Some ( aliased_to) = & self . aliased_to {
64
+ return aliased_to. example_payload ( ) ;
65
+ }
66
+
59
67
self . example_payload . as_deref ( )
60
68
}
61
69
62
70
fn example_attributes ( & self ) -> Option < HashMap < String , String > > {
71
+ if let Some ( aliased_to) = & self . aliased_to {
72
+ return aliased_to. example_attributes ( ) ;
73
+ }
74
+
63
75
self . args . clone ( )
64
76
}
65
77
@@ -88,9 +100,16 @@ impl Action for TaskletAction {
88
100
return Ok ( Some ( result) ) ;
89
101
}
90
102
103
+ // run as alias of a builtin namespace.action, here we can unwrap as everything is validated earlier
104
+ if let Some ( aliased_to) = & self . aliased_to {
105
+ return aliased_to. run ( state, attributes, payload) . await ;
106
+ }
107
+
91
108
// run as local tool
92
109
let parts: Vec < String > = self
93
110
. tool
111
+ . as_ref ( )
112
+ . ok_or_else ( || anyhow ! ( "tool not set" ) ) ?
94
113
. split_whitespace ( )
95
114
. map ( |x| x. trim ( ) )
96
115
. filter ( |x| !x. is_empty ( ) )
@@ -314,12 +333,14 @@ impl Tasklet {
314
333
let yaml = std:: fs:: read_to_string ( & canon) ?;
315
334
let mut tasklet: Self = serde_yaml:: from_str ( & yaml) ?;
316
335
336
+ // used to set the working directory while running the task
317
337
tasklet. folder = if let Some ( folder) = tasklet_parent_folder. to_str ( ) {
318
338
folder. to_string ( )
319
339
} else {
320
340
return Err ( anyhow ! ( "can't get string of {:?}" , tasklet_parent_folder) ) ;
321
341
} ;
322
342
343
+ // set unique task name from the folder or yaml file itself
323
344
tasklet. name = if canon. ends_with ( "task.yaml" ) || canon. ends_with ( "task.yml" ) {
324
345
tasklet_parent_folder
325
346
. file_name ( )
@@ -331,6 +352,51 @@ impl Tasklet {
331
352
canon. file_stem ( ) . unwrap ( ) . to_str ( ) . unwrap ( ) . to_owned ( )
332
353
} ;
333
354
355
+ // check any tool definied as alias of a builtin namespace and perform some validation
356
+ if let Some ( functions) = tasklet. functions . as_mut ( ) {
357
+ for group in functions {
358
+ for action in & mut group. actions {
359
+ if let Some ( alias) = & action. alias {
360
+ if action. tool . is_some ( ) {
361
+ return Err ( anyhow ! ( "can't define both tool and alias" ) ) ;
362
+ }
363
+
364
+ let ( namespace_name, action_name) = alias
365
+ . split_once ( '.' )
366
+ . ok_or_else ( || anyhow ! ( "invalid alias format '{}', aliases must be provided as 'namespace.action'" , alias) ) ?;
367
+
368
+ if let Some ( get_namespace_fn) =
369
+ namespaces:: NAMESPACES . get ( namespace_name)
370
+ {
371
+ let le_namespace = get_namespace_fn ( ) ;
372
+ let le_action = le_namespace
373
+ . actions
374
+ . iter ( )
375
+ . find ( |a| a. name ( ) == action_name) ;
376
+
377
+ if let Some ( le_action) = le_action {
378
+ log:: info!(
379
+ "aliased {}.{} to {}" ,
380
+ group. name,
381
+ action. name,
382
+ le_action. name( )
383
+ ) ;
384
+ action. aliased_to = Some ( le_action. clone ( ) ) ;
385
+ } else {
386
+ return Err ( anyhow ! (
387
+ "action '{}' not found in namespace '{}'" ,
388
+ action_name,
389
+ namespace_name
390
+ ) ) ;
391
+ }
392
+ } else {
393
+ return Err ( anyhow ! ( "namespace '{}' not found" , namespace_name) ) ;
394
+ }
395
+ }
396
+ }
397
+ }
398
+ }
399
+
334
400
log:: debug!( "tasklet = {:?}" , & tasklet) ;
335
401
336
402
Ok ( tasklet)
0 commit comments