Skip to main content

nexara_core/
tool.rs

1use crate::policy::{ActionClass, TrustTier};
2use serde::{Deserialize, Serialize};
3use serde_json::Value;
4
5#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
6pub struct ToolGuidance {
7    #[serde(default, skip_serializing_if = "Option::is_none")]
8    pub usage_notes: Option<String>,
9    #[serde(default, skip_serializing_if = "Option::is_none")]
10    pub sequencing_hints: Option<String>,
11    #[serde(default, skip_serializing_if = "Option::is_none")]
12    pub failure_recovery: Option<String>,
13}
14
15#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
16pub struct ToolDescriptor {
17    pub name: String,
18    pub description: String,
19    #[serde(default)]
20    pub tags: Vec<String>,
21    #[serde(default)]
22    pub scopes: Vec<String>,
23    pub trust_tier: TrustTier,
24    pub action_class: ActionClass,
25    pub enabled: bool,
26    #[serde(default, skip_serializing_if = "Option::is_none")]
27    pub input_schema: Option<Value>,
28    #[serde(default, skip_serializing_if = "Option::is_none")]
29    pub guidance: Option<ToolGuidance>,
30    #[serde(default)]
31    pub capabilities: Vec<ToolCapability>,
32    #[serde(default)]
33    pub effects: Vec<ToolEffect>,
34}
35
36#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
37pub struct ToolCapability {
38    pub id: String,
39    #[serde(default, skip_serializing_if = "Option::is_none")]
40    pub display_name: Option<String>,
41    #[serde(default, skip_serializing_if = "Option::is_none")]
42    pub description: Option<String>,
43    pub resource: String,
44    #[serde(default)]
45    pub resource_path: Vec<String>,
46    pub operation: String,
47    pub action_class: ActionClass,
48    pub sensitivity: CapabilitySensitivity,
49    #[serde(default)]
50    pub aliases: Vec<String>,
51}
52
53#[derive(Debug, Clone, Copy, Serialize, Deserialize, PartialEq, Eq)]
54#[serde(rename_all = "snake_case")]
55pub enum CapabilitySensitivity {
56    Public,
57    Internal,
58    Business,
59    Personal,
60    Financial,
61    Secret,
62}
63
64#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
65pub struct ToolEffect {
66    pub resource: String,
67    pub operation: String,
68    pub writes: bool,
69    pub external_side_effect: bool,
70    pub financial_side_effect: bool,
71    pub irreversible: bool,
72}
73
74#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq, PartialOrd, Ord, Hash)]
75pub struct ToolRef {
76    pub name: String,
77}
78
79#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
80pub struct ToolSelectionRequest {
81    pub prompt: String,
82    #[serde(default)]
83    pub scopes: Vec<String>,
84    pub max_tools: usize,
85}
86
87#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
88pub struct ToolCallRequest {
89    pub tool: String,
90    #[serde(default)]
91    pub params: Value,
92}
93
94#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
95pub struct ToolCallResult {
96    #[serde(default)]
97    pub result: Value,
98}
99
100impl ToolCallResult {
101    pub fn new(result: Value) -> Self {
102        Self { result }
103    }
104}
105
106impl ToolDescriptor {
107    pub fn read_only(name: impl Into<String>, description: impl Into<String>) -> Self {
108        Self {
109            name: name.into(),
110            description: description.into(),
111            tags: Vec::new(),
112            scopes: vec!["read".to_string()],
113            trust_tier: TrustTier::Builtin,
114            action_class: ActionClass::Read,
115            enabled: true,
116            input_schema: None,
117            guidance: None,
118            capabilities: Vec::new(),
119            effects: Vec::new(),
120        }
121    }
122
123    pub fn with_capability(mut self, capability: ToolCapability) -> Self {
124        self.capabilities.push(capability);
125        self
126    }
127}
128
129impl ToolCapability {
130    pub fn new(
131        id: impl Into<String>,
132        resource: impl Into<String>,
133        operation: impl Into<String>,
134        action_class: ActionClass,
135    ) -> Self {
136        let id = id.into();
137        let resource = resource.into();
138        let operation = operation.into();
139        Self {
140            id,
141            display_name: None,
142            description: None,
143            resource_path: vec![resource.clone()],
144            resource,
145            operation,
146            action_class,
147            sensitivity: CapabilitySensitivity::Internal,
148            aliases: Vec::new(),
149        }
150    }
151}