1use std::{collections::HashMap, sync::Arc};
2
3use async_trait::async_trait;
4use tokio::sync::RwLock;
5
6use crate::{
7 budget::IterationBudget,
8 config::AgentConfig,
9 error::{AgentError, ToolError},
10 memory::MemoryStore,
11 types::{ToolResult, ToolSchema},
12};
13
14#[derive(Debug, Default, Clone)]
19pub struct SkillPermissions(pub HashMap<String, bool>);
20
21impl SkillPermissions {
22 pub fn merge(&mut self, other: &HashMap<String, bool>) {
24 for (tool, allowed) in other {
25 let entry = self.0.entry(tool.clone()).or_insert(false);
26 if *allowed {
27 *entry = true;
28 }
29 }
30 }
31
32 pub fn check(&self, tool_name: &str) -> Option<bool> {
35 self.0.get(tool_name).copied()
36 }
37}
38
39#[async_trait]
40pub trait Tool: Send + Sync + 'static {
41 fn name(&self) -> &str;
42 fn description(&self) -> &str;
43 fn schema(&self) -> serde_json::Value;
44 fn toolset(&self) -> &str;
45
46 fn is_destructive(&self) -> bool {
51 false
52 }
53
54 fn is_destructive_for(&self, _params: &serde_json::Value) -> bool {
59 self.is_destructive()
60 }
61
62 fn bypass_dispatch_timeout(&self) -> bool {
65 false
66 }
67
68 async fn execute(
69 &self,
70 params: serde_json::Value,
71 ctx: &ToolContext,
72 ) -> Result<ToolResult, ToolError>;
73
74 fn to_schema(&self) -> ToolSchema {
75 ToolSchema {
76 name: self.name().to_string(),
77 description: self.description().to_string(),
78 parameters: self.schema(),
79 }
80 }
81}
82
83#[async_trait]
84pub trait SubAgentRunner: Send + Sync + 'static {
85 async fn run_task(&self, task: &str, session_id: &str) -> Result<String, AgentError>;
86}
87
88pub struct ToolContext {
89 pub session_id: String,
90 pub agent_id: String,
91 pub iteration: u32,
92 pub budget: Arc<IterationBudget>,
93 pub memory: Arc<dyn MemoryStore>,
94 pub config: Arc<AgentConfig>,
95 pub approver: Arc<dyn CommandApprover>,
96 pub sub_agent: Option<Arc<dyn SubAgentRunner>>,
97 pub skill_permissions: Arc<RwLock<SkillPermissions>>,
100 pub required_tools: Arc<RwLock<Vec<String>>>,
103}
104
105#[async_trait]
106pub trait CommandApprover: Send + Sync + 'static {
107 async fn approve(&self, tool_name: &str, params: &str) -> ApprovalDecision;
111}
112
113#[derive(Debug, Clone, PartialEq)]
114pub enum ApprovalDecision {
115 Approved,
116 ApprovedAlways,
117 Denied,
118 Yolo,
119}