1use oxi_agent::ToolRegistry;
7use std::path::PathBuf;
8
9#[derive(Debug, Clone)]
14pub struct KernelToolContext {
15 pub workspace_dir: PathBuf,
17 pub agent_id: String,
19 pub session_id: Option<String>,
21 pub permissions: Vec<String>,
23}
24
25impl KernelToolContext {
26 pub fn new(workspace_dir: impl Into<PathBuf>, agent_id: impl Into<String>) -> Self {
28 Self {
29 workspace_dir: workspace_dir.into(),
30 agent_id: agent_id.into(),
31 session_id: None,
32 permissions: Vec::new(),
33 }
34 }
35
36 pub fn with_session(mut self, session_id: impl Into<String>) -> Self {
38 self.session_id = Some(session_id.into());
39 self
40 }
41
42 pub fn with_permissions(mut self, permissions: Vec<String>) -> Self {
44 self.permissions = permissions;
45 self
46 }
47}
48
49pub trait KernelToolProvider: Send + Sync {
74 fn tool_names(&self) -> Vec<&str>;
76
77 fn register_tools(&self, registry: &ToolRegistry, context: &KernelToolContext);
82}
83
84#[cfg(test)]
85mod tests {
86 use super::*;
87 use async_trait::async_trait;
88 use oxi_agent::{AgentTool, AgentToolResult, ToolContext, ToolError};
89 use serde_json::Value;
90
91 struct MockKernelTool {
92 name: String,
93 }
94
95 #[async_trait]
96 impl AgentTool for MockKernelTool {
97 fn name(&self) -> &str {
98 &self.name
99 }
100 fn label(&self) -> &str {
101 "mock"
102 }
103 fn description(&self) -> &str {
104 "A mock kernel tool"
105 }
106 fn parameters_schema(&self) -> Value {
107 serde_json::json!({"type": "object", "properties": {}})
108 }
109
110 async fn execute(
111 &self,
112 _tool_call_id: &str,
113 _params: Value,
114 _signal: Option<tokio::sync::oneshot::Receiver<()>>,
115 _ctx: &ToolContext,
116 ) -> Result<AgentToolResult, ToolError> {
117 Ok(AgentToolResult::success("mock result"))
118 }
119 }
120
121 struct MockKernelBridge;
122
123 impl KernelToolProvider for MockKernelBridge {
124 fn tool_names(&self) -> Vec<&str> {
125 vec!["exec", "memory"]
126 }
127
128 fn register_tools(&self, registry: &ToolRegistry, ctx: &KernelToolContext) {
129 registry.register(MockKernelTool {
130 name: format!("exec_{}", ctx.agent_id),
131 });
132 registry.register(MockKernelTool {
133 name: format!("memory_{}", ctx.agent_id),
134 });
135 }
136 }
137
138 #[test]
139 fn test_kernel_tool_context_builder() {
140 let ctx = KernelToolContext::new("/workspace", "agent-001")
141 .with_session("sess-123")
142 .with_permissions(vec!["read".into(), "write".into()]);
143
144 assert_eq!(ctx.workspace_dir, PathBuf::from("/workspace"));
145 assert_eq!(ctx.agent_id, "agent-001");
146 assert_eq!(ctx.session_id, Some("sess-123".to_string()));
147 assert_eq!(ctx.permissions, vec!["read", "write"]);
148 }
149
150 #[test]
151 fn test_kernel_bridge_registers_tools() {
152 let bridge = MockKernelBridge;
153 let registry = ToolRegistry::new();
154 let ctx = KernelToolContext::new("/workspace", "agent-001");
155
156 bridge.register_tools(®istry, &ctx);
157
158 let names = registry.names();
159 assert!(names.contains(&"exec_agent-001".to_string()));
160 assert!(names.contains(&"memory_agent-001".to_string()));
161 }
162}