Skip to main content

ai_agents_core/traits/
tool.rs

1//! Tool trait for external capabilities
2
3use async_trait::async_trait;
4use serde::{Deserialize, Serialize};
5use serde_json::Value;
6use std::collections::HashMap;
7
8use crate::Result;
9use crate::types::{
10    ToolCallClassification, ToolExecutionContext, ToolExecutionRecord, ToolExecutionRequest,
11    ToolPolicyBindings, ToolSafetyMetadata,
12};
13
14#[derive(Debug, Clone, Serialize, Deserialize)]
15pub struct ToolResult {
16    pub success: bool,
17    pub output: String,
18    #[serde(skip_serializing_if = "Option::is_none")]
19    pub metadata: Option<HashMap<String, Value>>,
20}
21
22impl ToolResult {
23    pub fn ok(output: impl Into<String>) -> Self {
24        Self {
25            success: true,
26            output: output.into(),
27            metadata: None,
28        }
29    }
30
31    pub fn ok_with_metadata(output: impl Into<String>, metadata: HashMap<String, Value>) -> Self {
32        Self {
33            success: true,
34            output: output.into(),
35            metadata: Some(metadata),
36        }
37    }
38
39    pub fn error(error: impl Into<String>) -> Self {
40        Self {
41            success: false,
42            output: error.into(),
43            metadata: None,
44        }
45    }
46}
47
48/// Public descriptor for a registered tool.
49#[derive(Debug, Clone, Serialize, Deserialize)]
50pub struct ToolInfo {
51    /// Canonical tool ID used by YAML, policy, HITL, and eval.
52    pub id: String,
53    /// Display name shown to the model.
54    pub name: String,
55    /// Description shown to the model for tool selection.
56    pub description: String,
57    /// JSON schema for tool arguments.
58    pub input_schema: Value,
59    /// Safety metadata used by the runtime executor.
60    #[serde(default)]
61    pub safety: ToolSafetyMetadata,
62    /// Policy bindings declared by the tool.
63    #[serde(default)]
64    pub policy_bindings: ToolPolicyBindings,
65}
66
67/// Core tool trait for external capabilities.
68///
69/// Implement this to add custom tools that the agent can invoke during conversation.
70/// Built-in tools use `generate_schema::<T>()` from `ai-agents-tools` with
71/// `schemars::JsonSchema` to derive input schemas automatically.
72#[async_trait]
73pub trait Tool: Send + Sync {
74    /// Unique identifier for this tool (e.g. `"calculator"`).
75    fn id(&self) -> &str;
76    /// Human-readable display name.
77    fn name(&self) -> &str;
78    /// Description shown to the LLM for tool selection.
79    fn description(&self) -> &str;
80    /// JSON Schema describing expected input arguments.
81    fn input_schema(&self) -> Value;
82
83    /// Execute the tool with arguments and executor context.
84    async fn execute(&self, args: Value, ctx: ToolExecutionContext) -> ToolResult;
85
86    /// Policy bindings used by the shared executor to apply configured policy.
87    fn policy_bindings(&self) -> ToolPolicyBindings {
88        ToolPolicyBindings::default()
89    }
90
91    /// Safety metadata used by runtime policy, scheduling, and observability.
92    fn safety_metadata(&self) -> ToolSafetyMetadata {
93        ToolSafetyMetadata::conservative_unknown()
94    }
95
96    /// Classify a specific call when risk depends on arguments.
97    fn classify_call(&self, _args: &Value) -> ToolCallClassification {
98        ToolCallClassification::from_metadata(&self.safety_metadata())
99    }
100
101    /// Returns a [`ToolInfo`] struct from the above methods.
102    fn info(&self) -> ToolInfo {
103        ToolInfo {
104            id: self.id().to_string(),
105            name: self.name().to_string(),
106            description: self.description().to_string(),
107            input_schema: self.input_schema(),
108            safety: self.safety_metadata(),
109            policy_bindings: self.policy_bindings(),
110        }
111    }
112}
113
114/// Runtime boundary for invoking tools through shared policy and evidence handling.
115#[async_trait]
116pub trait ToolInvoker: Send + Sync {
117    /// Invokes a tool request and returns a structured execution record.
118    async fn invoke_tool(&self, request: ToolExecutionRequest) -> Result<ToolExecutionRecord>;
119}