1use serde::{Deserialize, Serialize};
6use std::fmt;
7use std::path::PathBuf;
8
9#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
15pub struct ToolId(pub String);
16
17impl ToolId {
18 pub fn new(name: &str) -> Self {
19 Self(name.to_string())
20 }
21}
22
23impl fmt::Display for ToolId {
24 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
25 write!(f, "{}", self.0)
26 }
27}
28
29impl From<&str> for ToolId {
30 fn from(s: &str) -> Self {
31 Self::new(s)
32 }
33}
34
35#[derive(Debug, Clone, Serialize, Deserialize)]
37pub struct ToolRequest {
38 pub call_id: String,
40 pub name: String,
42 pub arguments: serde_json::Value,
44}
45
46#[derive(Debug, Clone, Serialize, Deserialize)]
48pub struct ToolResponse {
49 pub call_id: String,
51 pub name: String,
53 pub content: String,
55 pub is_error: bool,
57 pub duration_ms: u64,
59}
60
61impl ToolResponse {
62 pub fn success(
63 call_id: impl Into<String>,
64 name: impl Into<String>,
65 content: impl Into<String>,
66 ) -> Self {
67 Self {
68 call_id: call_id.into(),
69 name: name.into(),
70 content: content.into(),
71 is_error: false,
72 duration_ms: 0,
73 }
74 }
75
76 pub fn error(
77 call_id: impl Into<String>,
78 name: impl Into<String>,
79 error: impl Into<String>,
80 ) -> Self {
81 Self {
82 call_id: call_id.into(),
83 name: name.into(),
84 content: error.into(),
85 is_error: true,
86 duration_ms: 0,
87 }
88 }
89}
90
91#[derive(Debug, Clone, Serialize, Deserialize)]
93pub struct ToolMeta {
94 pub name: String,
96 pub description: String,
98 pub parameters: serde_json::Value,
100 #[serde(default)]
102 pub requires_confirmation: bool,
103 #[serde(default)]
105 pub is_dangerous: bool,
106 pub category: ToolCategory,
108}
109
110#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
112#[serde(rename_all = "snake_case")]
113pub enum ToolCategory {
114 FileOps,
116 Search,
118 Shell,
120 Network,
122 CodeAnalysis,
124 Memory,
126 Workflow,
128 System,
130 DataProcessing,
132 TextProcessing,
134 VersionControl,
136 Other,
138}
139
140#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize, Default)]
146#[serde(rename_all = "snake_case")]
147pub enum MemoryTier {
148 #[default]
150 Working,
151 Session,
153 Project,
155 LongTerm,
157}
158
159#[derive(Debug, Clone, Serialize, Deserialize)]
161pub struct MemoryEntry {
162 pub id: String,
164 pub tier: MemoryTier,
166 pub content: String,
168 #[serde(default)]
170 pub metadata: serde_json::Map<String, serde_json::Value>,
171 pub created_at: chrono::DateTime<chrono::Utc>,
173 pub last_accessed: chrono::DateTime<chrono::Utc>,
175 #[serde(default)]
177 pub access_count: u32,
178 #[serde(default)]
180 pub importance: f32,
181}
182
183#[derive(Debug, Clone, Default)]
185pub struct MemoryQuery {
186 pub query: String,
188 pub tier: Option<MemoryTier>,
190 pub limit: Option<usize>,
192 pub time_range: Option<(chrono::DateTime<chrono::Utc>, chrono::DateTime<chrono::Utc>)>,
194}
195
196#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
202#[serde(rename_all = "snake_case")]
203pub enum QueryType {
204 Definition,
206 References,
208 Implementations,
210 TypeDefinition,
212 DocumentSymbols,
214 WorkspaceSymbols,
216 Hover,
218}
219
220#[derive(Debug, Clone, Serialize, Deserialize)]
222pub struct CodeLocation {
223 pub file: PathBuf,
225 pub line: u32,
227 pub column: u32,
229}
230
231impl fmt::Display for CodeLocation {
232 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
233 write!(f, "{}:{}:{}", self.file.display(), self.line, self.column)
234 }
235}
236
237#[derive(Debug, Clone, Serialize, Deserialize)]
239pub struct CodeRange {
240 pub start: CodeLocation,
241 pub end: CodeLocation,
242}
243
244#[derive(Debug, Clone, Serialize, Deserialize)]
246pub struct QueryResult {
247 pub query_type: QueryType,
249 pub location: CodeLocation,
251 pub range: Option<CodeRange>,
253 pub display_text: String,
255 pub snippet: Option<String>,
257}
258
259#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
265#[serde(rename_all = "snake_case")]
266pub enum ProcessState {
267 Running,
268 Stopped,
269 Exited,
270 Killed,
271}
272
273#[derive(Debug, Clone, Serialize, Deserialize)]
275pub struct ProcessInfo {
276 pub pid: u32,
278 pub name: String,
280 pub state: ProcessState,
282 pub started_at: chrono::DateTime<chrono::Utc>,
284 pub command: String,
286 pub working_dir: PathBuf,
288}
289
290#[derive(Debug, thiserror::Error)]
296pub enum Layer3Error {
297 #[error("Tool not found: {0}")]
298 ToolNotFound(String),
299
300 #[error("Tool execution failed: {0}")]
301 ToolExecutionFailed(String),
302
303 #[error("Tool validation failed: {0}")]
304 ToolValidationFailed(String),
305
306 #[error("Memory not found: {0}")]
307 MemoryNotFound(String),
308
309 #[error("Memory query failed: {0}")]
310 MemoryQueryFailed(String),
311
312 #[error("Query failed: {0}")]
313 QueryFailed(String),
314
315 #[error("Process error: {0}")]
316 ProcessError(String),
317
318 #[error("LSP error: {0}")]
319 LspError(String),
320
321 #[error("Sandbox error: {0}")]
322 SandboxError(String),
323
324 #[error("IO error: {0}")]
325 Io(#[from] std::io::Error),
326
327 #[error("Serialization error: {0}")]
328 Serialization(#[from] serde_json::Error),
329
330 #[error("Lock error: {0}")]
331 LockError(String),
332
333 #[error("Vector store error: {0}")]
334 VectorStoreError(String),
335
336 #[error("Vector dimension mismatch: expected {expected}, got {actual}")]
337 VectorDimensionMismatch { expected: usize, actual: usize },
338
339 #[error("Vector not found: {0}")]
340 VectorNotFound(String),
341
342 #[error("Vector operation failed: {operation} - {reason}")]
343 VectorOperationFailed { operation: String, reason: String },
344
345 #[error("Persistence error: {0}")]
346 PersistenceError(String),
347
348 #[error("Invalid vector: {0}")]
349 InvalidVector(String),
350
351 #[error("Index error: {0}")]
352 IndexError(String),
353
354 #[error("Configuration error: {0}")]
355 ConfigError(String),
356}
357
358pub type Layer3Result<T> = anyhow::Result<T>;
360
361#[cfg(test)]
362mod tests {
363 use super::*;
364
365 #[test]
366 fn test_tool_response_creation() {
367 let resp = ToolResponse::success("call_1", "test_tool", "result");
368 assert!(!resp.is_error);
369 assert_eq!(resp.name, "test_tool");
370
371 let err_resp = ToolResponse::error("call_2", "test_tool", "error");
372 assert!(err_resp.is_error);
373 }
374
375 #[test]
376 fn test_memory_tier_default() {
377 let tier = MemoryTier::default();
378 assert_eq!(tier, MemoryTier::Working);
379 }
380
381 #[test]
382 fn test_code_location_display() {
383 let loc = CodeLocation {
384 file: PathBuf::from("src/main.rs"),
385 line: 10,
386 column: 5,
387 };
388 assert!(loc.to_string().contains("main.rs"));
389 }
390}