Skip to main content

vv_agent/tools/
public_tool.rs

1use serde_json::Value;
2use std::time::Duration;
3
4use crate::checkpoint::ToolIdempotency;
5use crate::tools::{
6    ToolApprovalRule, ToolEnablementContext, ToolEnablementRule, ToolHandler, ToolSpec,
7};
8use crate::types::ToolExecutionResult;
9
10pub trait Tool: Send + Sync {
11    fn name(&self) -> &str;
12    fn description(&self) -> &str;
13    fn parameters_schema(&self) -> &Value;
14
15    fn strict_schema(&self) -> bool {
16        true
17    }
18
19    fn exposure(&self) -> crate::tools::ToolExposure {
20        crate::tools::ToolExposure::Direct
21    }
22
23    fn timeout(&self) -> Option<Duration> {
24        None
25    }
26
27    fn approval_rule(&self) -> ToolApprovalRule {
28        ToolApprovalRule::default()
29    }
30
31    fn idempotency(&self) -> ToolIdempotency {
32        ToolIdempotency::Unknown
33    }
34
35    fn is_enabled(&self, _context: &ToolEnablementContext) -> bool {
36        true
37    }
38
39    fn as_tool_spec(&self) -> ToolSpec;
40}
41
42#[derive(Clone)]
43pub struct StaticTool {
44    name: String,
45    description: String,
46    parameters_schema: Value,
47    handler: ToolHandler,
48    enablement: ToolEnablementRule,
49    idempotency: ToolIdempotency,
50}
51
52impl StaticTool {
53    pub fn new(
54        name: impl Into<String>,
55        description: impl Into<String>,
56        parameters_schema: Value,
57        handler: ToolHandler,
58    ) -> Self {
59        Self {
60            name: name.into(),
61            description: description.into(),
62            parameters_schema,
63            handler,
64            enablement: ToolEnablementRule::default(),
65            idempotency: ToolIdempotency::Unknown,
66        }
67    }
68
69    pub fn with_enabled(mut self, enabled: bool) -> Self {
70        self.enablement = ToolEnablementRule::Static(enabled);
71        self
72    }
73
74    pub fn with_enabled_if<F>(mut self, predicate: F) -> Self
75    where
76        F: Fn(&ToolEnablementContext) -> bool + Send + Sync + 'static,
77    {
78        self.enablement = ToolEnablementRule::predicate(predicate);
79        self
80    }
81
82    pub fn with_idempotency(mut self, idempotency: ToolIdempotency) -> Self {
83        self.idempotency = idempotency;
84        self
85    }
86}
87
88impl Tool for StaticTool {
89    fn name(&self) -> &str {
90        &self.name
91    }
92
93    fn description(&self) -> &str {
94        &self.description
95    }
96
97    fn parameters_schema(&self) -> &Value {
98        &self.parameters_schema
99    }
100
101    fn is_enabled(&self, context: &ToolEnablementContext) -> bool {
102        self.enablement.is_enabled(context)
103    }
104
105    fn idempotency(&self) -> ToolIdempotency {
106        self.idempotency
107    }
108
109    fn as_tool_spec(&self) -> ToolSpec {
110        let mut spec = ToolSpec::new(
111            self.name.clone(),
112            self.description.clone(),
113            self.handler.clone(),
114        );
115        spec.schema = serde_json::json!({
116            "type": "function",
117            "function": {
118                "name": self.name,
119                "description": self.description,
120                "parameters": self.parameters_schema,
121                "strict": self.strict_schema(),
122            }
123        });
124        spec.strict_schema = self.strict_schema();
125        spec.exposure = self.exposure();
126        spec.timeout = self.timeout();
127        spec.approval = self.approval_rule();
128        spec.idempotency = self.idempotency();
129        spec
130    }
131}
132
133impl<F> From<(String, String, Value, F)> for StaticTool
134where
135    F: Fn(&mut crate::tools::ToolContext, &crate::types::ToolArguments) -> ToolExecutionResult
136        + Send
137        + Sync
138        + 'static,
139{
140    fn from(value: (String, String, Value, F)) -> Self {
141        Self::new(value.0, value.1, value.2, std::sync::Arc::new(value.3))
142    }
143}