use serde_json::Value;
use std::time::Duration;
use crate::checkpoint::ToolIdempotency;
use crate::tools::{
ToolApprovalRule, ToolEnablementContext, ToolEnablementRule, ToolHandler, ToolSpec,
};
use crate::types::ToolExecutionResult;
pub trait Tool: Send + Sync {
fn name(&self) -> &str;
fn description(&self) -> &str;
fn parameters_schema(&self) -> &Value;
fn strict_schema(&self) -> bool {
true
}
fn exposure(&self) -> crate::tools::ToolExposure {
crate::tools::ToolExposure::Direct
}
fn timeout(&self) -> Option<Duration> {
None
}
fn approval_rule(&self) -> ToolApprovalRule {
ToolApprovalRule::default()
}
fn idempotency(&self) -> ToolIdempotency {
ToolIdempotency::Unknown
}
fn is_enabled(&self, _context: &ToolEnablementContext) -> bool {
true
}
fn as_tool_spec(&self) -> ToolSpec;
}
#[derive(Clone)]
pub struct StaticTool {
name: String,
description: String,
parameters_schema: Value,
handler: ToolHandler,
enablement: ToolEnablementRule,
idempotency: ToolIdempotency,
}
impl StaticTool {
pub fn new(
name: impl Into<String>,
description: impl Into<String>,
parameters_schema: Value,
handler: ToolHandler,
) -> Self {
Self {
name: name.into(),
description: description.into(),
parameters_schema,
handler,
enablement: ToolEnablementRule::default(),
idempotency: ToolIdempotency::Unknown,
}
}
pub fn with_enabled(mut self, enabled: bool) -> Self {
self.enablement = ToolEnablementRule::Static(enabled);
self
}
pub fn with_enabled_if<F>(mut self, predicate: F) -> Self
where
F: Fn(&ToolEnablementContext) -> bool + Send + Sync + 'static,
{
self.enablement = ToolEnablementRule::predicate(predicate);
self
}
pub fn with_idempotency(mut self, idempotency: ToolIdempotency) -> Self {
self.idempotency = idempotency;
self
}
}
impl Tool for StaticTool {
fn name(&self) -> &str {
&self.name
}
fn description(&self) -> &str {
&self.description
}
fn parameters_schema(&self) -> &Value {
&self.parameters_schema
}
fn is_enabled(&self, context: &ToolEnablementContext) -> bool {
self.enablement.is_enabled(context)
}
fn idempotency(&self) -> ToolIdempotency {
self.idempotency
}
fn as_tool_spec(&self) -> ToolSpec {
let mut spec = ToolSpec::new(
self.name.clone(),
self.description.clone(),
self.handler.clone(),
);
spec.schema = serde_json::json!({
"type": "function",
"function": {
"name": self.name,
"description": self.description,
"parameters": self.parameters_schema,
"strict": self.strict_schema(),
}
});
spec.strict_schema = self.strict_schema();
spec.exposure = self.exposure();
spec.timeout = self.timeout();
spec.approval = self.approval_rule();
spec.idempotency = self.idempotency();
spec
}
}
impl<F> From<(String, String, Value, F)> for StaticTool
where
F: Fn(&mut crate::tools::ToolContext, &crate::types::ToolArguments) -> ToolExecutionResult
+ Send
+ Sync
+ 'static,
{
fn from(value: (String, String, Value, F)) -> Self {
Self::new(value.0, value.1, value.2, std::sync::Arc::new(value.3))
}
}