1use crate::ingest::SemanticKind;
7use serde::{Deserialize, Serialize};
8
9#[derive(Debug, Clone, Copy, PartialEq, Eq)]
11pub enum ToolHintOperation {
12 DeleteBody,
14 ChangeSignature,
16 ChangeType,
18 ReplaceBody,
20 Query,
22 Get,
24}
25
26#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
30pub struct ToolHints {
31 pub requires_full_context: bool,
33
34 pub apply_atomically: bool,
36
37 pub may_break_tests: bool,
39
40 pub requires_compilation: bool,
42}
43
44impl Default for ToolHints {
45 fn default() -> Self {
46 Self {
47 requires_full_context: false,
48 apply_atomically: true, may_break_tests: false,
50 requires_compilation: false,
51 }
52 }
53}
54
55impl ToolHints {
56 pub fn new() -> Self {
58 Self::default()
59 }
60
61 pub fn with_requires_full_context(mut self, value: bool) -> Self {
63 self.requires_full_context = value;
64 self
65 }
66
67 pub fn with_may_break_tests(mut self, value: bool) -> Self {
69 self.may_break_tests = value;
70 self
71 }
72
73 pub fn with_requires_compilation(mut self, value: bool) -> Self {
75 self.requires_compilation = value;
76 self
77 }
78
79 pub fn for_function_delete(is_public: bool) -> Self {
85 Self {
86 requires_full_context: false,
87 apply_atomically: true,
88 may_break_tests: is_public,
89 requires_compilation: true,
90 }
91 }
92
93 pub fn for_struct_modify(is_public: bool) -> Self {
99 Self {
100 requires_full_context: false,
101 apply_atomically: true,
102 may_break_tests: is_public,
103 requires_compilation: true,
104 }
105 }
106
107 pub fn for_body_replace() -> Self {
112 Self {
113 requires_full_context: false,
114 apply_atomically: true,
115 may_break_tests: false,
116 requires_compilation: false,
117 }
118 }
119}
120
121pub fn derive_tool_hints(
136 semantic_kind: SemanticKind,
137 is_public: bool,
138 operation: ToolHintOperation,
139) -> ToolHints {
140 let requires_full_context = matches!(
143 (semantic_kind, operation),
144 (SemanticKind::Function, ToolHintOperation::DeleteBody)
145 | (SemanticKind::Function, ToolHintOperation::ReplaceBody)
146 | (SemanticKind::Trait, _)
147 );
148
149 let apply_atomically = true;
151
152 let may_break_tests = match (semantic_kind, is_public) {
155 (SemanticKind::Function, true) => true,
156 (SemanticKind::Trait, true) => true,
157 (SemanticKind::Type, true) => true,
158 _ => false,
159 };
160
161 let requires_compilation = match operation {
164 ToolHintOperation::ChangeType => true,
165 ToolHintOperation::ChangeSignature if is_public => true,
166 ToolHintOperation::DeleteBody if is_public => true,
167 _ => false,
168 };
169
170 ToolHints {
171 requires_full_context,
172 apply_atomically,
173 may_break_tests,
174 requires_compilation,
175 }
176}
177
178#[cfg(test)]
179mod tests {
180 use super::*;
181
182 #[test]
183 fn test_tool_hints_default() {
184 let hints = ToolHints::default();
185 assert_eq!(hints.requires_full_context, false);
186 assert_eq!(hints.apply_atomically, true);
187 assert_eq!(hints.may_break_tests, false);
188 assert_eq!(hints.requires_compilation, false);
189 }
190
191 #[test]
192 fn test_tool_hints_builder() {
193 let hints = ToolHints::new()
194 .with_requires_full_context(true)
195 .with_may_break_tests(true)
196 .with_requires_compilation(true);
197
198 assert_eq!(hints.requires_full_context, true);
199 assert_eq!(hints.apply_atomically, true); assert_eq!(hints.may_break_tests, true);
201 assert_eq!(hints.requires_compilation, true);
202 }
203
204 #[test]
205 fn test_tool_hints_serialization() {
206 let hints = ToolHints::new()
207 .with_requires_full_context(true)
208 .with_may_break_tests(false);
209
210 let json = serde_json::to_string(&hints).unwrap();
211 assert!(json.contains("\"requires_full_context\":true"));
212 assert!(json.contains("\"apply_atomically\":true"));
213 assert!(json.contains("\"may_break_tests\":false"));
214 }
215
216 #[test]
217 fn test_for_function_delete() {
218 let hints = ToolHints::for_function_delete(true);
219 assert_eq!(hints.requires_full_context, false);
220 assert_eq!(hints.apply_atomically, true);
221 assert_eq!(hints.may_break_tests, true); assert_eq!(hints.requires_compilation, true);
223
224 let hints_private = ToolHints::for_function_delete(false);
225 assert_eq!(hints_private.may_break_tests, false); }
227
228 #[test]
229 fn test_for_struct_modify() {
230 let hints = ToolHints::for_struct_modify(true);
231 assert_eq!(hints.requires_full_context, false);
232 assert_eq!(hints.apply_atomically, true);
233 assert_eq!(hints.may_break_tests, true); assert_eq!(hints.requires_compilation, true);
235
236 let hints_private = ToolHints::for_struct_modify(false);
237 assert_eq!(hints_private.may_break_tests, false); }
239
240 #[test]
241 fn test_for_body_replace() {
242 let hints = ToolHints::for_body_replace();
243 assert_eq!(hints.requires_full_context, false);
244 assert_eq!(hints.apply_atomically, true);
245 assert_eq!(hints.may_break_tests, false); assert_eq!(hints.requires_compilation, false); }
248}