1use crate::agent::AgentContext;
2use crate::error::{Error, Result};
3use async_trait::async_trait;
4use serde::{Deserialize, Serialize};
5use serde_json::Value;
6use std::collections::HashMap;
7
8#[derive(Debug, Clone, Serialize, Deserialize)]
10pub struct ActionMetadata {
11 pub name: String,
13
14 pub description: String,
16
17 pub input_schema: Value,
19
20 pub output_schema: Option<Value>,
22}
23
24#[async_trait]
26pub trait ActionInvoker: Send + Sync {
27 async fn execute(&self, ctx: &mut AgentContext, inputs: Value) -> Result<Value>;
29
30 fn metadata(&self) -> &ActionMetadata;
32}
33
34pub struct ToolInvoker {
36 actions: HashMap<String, Box<dyn ActionInvoker>>,
37}
38
39impl ToolInvoker {
40 pub fn new() -> Self {
42 Self {
43 actions: HashMap::new(),
44 }
45 }
46
47 pub fn register(&mut self, action: Box<dyn ActionInvoker>) {
49 let name = action.metadata().name.clone();
50 self.actions.insert(name, action);
51 }
52
53 pub fn list_actions(&self) -> Vec<ActionMetadata> {
55 self.actions
56 .values()
57 .map(|a| a.metadata().clone())
58 .collect()
59 }
60
61 pub async fn invoke(&self, name: &str, ctx: &mut AgentContext, inputs: Value) -> Result<Value> {
63 let action = self
64 .actions
65 .get(name)
66 .ok_or_else(|| Error::ActionNotFound(name.to_string()))?;
67
68 action.execute(ctx, inputs).await
69 }
70}
71
72impl Default for ToolInvoker {
73 fn default() -> Self {
74 Self::new()
75 }
76}