opendev_repl/handlers/traits.rs
1//! Core traits for tool handler middleware.
2
3use std::collections::HashMap;
4
5use serde_json::Value;
6
7/// Result of a pre-execution check.
8#[derive(Debug, Clone)]
9pub enum PreCheckResult {
10 /// Allow execution to proceed.
11 Allow,
12 /// Deny execution with a reason.
13 Deny(String),
14 /// Modify the arguments before execution.
15 ModifyArgs(HashMap<String, Value>),
16}
17
18/// Metadata attached to a handler result.
19#[derive(Debug, Clone, Default)]
20pub struct HandlerMeta {
21 /// Files that were changed by this tool execution.
22 pub changed_files: Vec<String>,
23 /// Whether this was a background/server command.
24 pub is_background: bool,
25 /// Operation ID for audit/undo tracking.
26 pub operation_id: Option<String>,
27}
28
29/// Result of post-execution processing.
30#[derive(Debug, Clone)]
31pub struct HandlerResult {
32 /// The (potentially modified) tool output.
33 pub output: Option<String>,
34 /// The (potentially modified) error message.
35 pub error: Option<String>,
36 /// Whether the tool succeeded.
37 pub success: bool,
38 /// Handler metadata.
39 pub meta: HandlerMeta,
40}
41
42/// Trait for tool handler middleware.
43///
44/// Handlers sit between the REPL and tool execution, providing
45/// pre-check (approval), post-processing (formatting), and
46/// side-effect management (file tracking, operation logging).
47pub trait ToolHandler: Send + Sync {
48 /// Tool names this handler manages.
49 fn handles(&self) -> &[&str];
50
51 /// Pre-execution check. Called before the tool runs.
52 ///
53 /// Can approve, deny, or modify the tool call arguments.
54 fn pre_check(&self, tool_name: &str, args: &HashMap<String, Value>) -> PreCheckResult {
55 let _ = (tool_name, args);
56 PreCheckResult::Allow
57 }
58
59 /// Post-execution processing. Called after the tool runs.
60 ///
61 /// Can modify the output, attach metadata, or trigger side effects.
62 fn post_process(
63 &self,
64 tool_name: &str,
65 args: &HashMap<String, Value>,
66 output: Option<&str>,
67 error: Option<&str>,
68 success: bool,
69 ) -> HandlerResult {
70 HandlerResult {
71 output: output.map(|s| s.to_string()),
72 error: error.map(|s| s.to_string()),
73 success,
74 meta: HandlerMeta {
75 changed_files: self.extract_changed_files(tool_name, args),
76 ..Default::default()
77 },
78 }
79 }
80
81 /// Extract file paths changed by this tool (for artifact tracking).
82 fn extract_changed_files(
83 &self,
84 _tool_name: &str,
85 _args: &HashMap<String, Value>,
86 ) -> Vec<String> {
87 Vec::new()
88 }
89}
90
91#[cfg(test)]
92#[path = "traits_tests.rs"]
93mod tests;