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}