1use oxi_agent::ToolRegistry;
7use std::collections::HashMap;
8use std::path::PathBuf;
9
10#[derive(Debug, Clone)]
19pub struct KernelToolContext {
20 pub workspace_dir: PathBuf,
22 pub agent_id: String,
24 pub session_id: Option<String>,
26 pub permissions: Vec<String>,
28 pub metadata: HashMap<String, serde_json::Value>,
34}
35
36impl KernelToolContext {
37 pub fn new(workspace_dir: impl Into<PathBuf>, agent_id: impl Into<String>) -> Self {
39 Self {
40 workspace_dir: workspace_dir.into(),
41 agent_id: agent_id.into(),
42 session_id: None,
43 permissions: Vec::new(),
44 metadata: HashMap::new(),
45 }
46 }
47
48 pub fn with_session(mut self, session_id: impl Into<String>) -> Self {
50 self.session_id = Some(session_id.into());
51 self
52 }
53
54 pub fn with_permissions(mut self, permissions: Vec<String>) -> Self {
56 self.permissions = permissions;
57 self
58 }
59
60 pub fn with_meta(mut self, key: impl Into<String>, value: serde_json::Value) -> Self {
70 self.metadata.insert(key.into(), value);
71 self
72 }
73
74 pub fn get_meta(&self, key: &str) -> Option<&serde_json::Value> {
76 self.metadata.get(key)
77 }
78
79 pub fn get_meta_str(&self, key: &str) -> Option<&str> {
81 self.metadata.get(key).and_then(|v| v.as_str())
82 }
83}
84
85pub trait KernelToolProvider: Send + Sync {
110 fn tool_names(&self) -> Vec<&str>;
112
113 fn register_tools(&self, registry: &ToolRegistry, context: &KernelToolContext);
118}
119
120#[cfg(test)]
121mod tests {
122 use super::*;
123 use async_trait::async_trait;
124 use oxi_agent::{AgentTool, AgentToolResult, ToolContext, ToolError};
125 use serde_json::Value;
126
127 struct MockKernelTool {
128 name: String,
129 }
130
131 #[async_trait]
132 impl AgentTool for MockKernelTool {
133 fn name(&self) -> &str {
134 &self.name
135 }
136 fn label(&self) -> &str {
137 "mock"
138 }
139 fn description(&self) -> &str {
140 "A mock kernel tool"
141 }
142 fn parameters_schema(&self) -> Value {
143 serde_json::json!({"type": "object", "properties": {}})
144 }
145
146 async fn execute(
147 &self,
148 _tool_call_id: &str,
149 _params: Value,
150 _signal: Option<tokio::sync::oneshot::Receiver<()>>,
151 _ctx: &ToolContext,
152 ) -> Result<AgentToolResult, ToolError> {
153 Ok(AgentToolResult::success("mock result"))
154 }
155 }
156
157 struct MockKernelBridge;
158
159 impl KernelToolProvider for MockKernelBridge {
160 fn tool_names(&self) -> Vec<&str> {
161 vec!["exec", "memory"]
162 }
163
164 fn register_tools(&self, registry: &ToolRegistry, ctx: &KernelToolContext) {
165 registry.register(MockKernelTool {
166 name: format!("exec_{}", ctx.agent_id),
167 });
168 registry.register(MockKernelTool {
169 name: format!("memory_{}", ctx.agent_id),
170 });
171 }
172 }
173
174 #[test]
175 fn test_kernel_tool_context_builder() {
176 let ctx = KernelToolContext::new("/workspace", "agent-001")
177 .with_session("sess-123")
178 .with_permissions(vec!["read".into(), "write".into()]);
179
180 assert_eq!(ctx.workspace_dir, PathBuf::from("/workspace"));
181 assert_eq!(ctx.agent_id, "agent-001");
182 assert_eq!(ctx.session_id, Some("sess-123".to_string()));
183 assert_eq!(ctx.permissions, vec!["read", "write"]);
184 }
185
186 #[test]
187 fn test_kernel_bridge_registers_tools() {
188 let bridge = MockKernelBridge;
189 let registry = ToolRegistry::new();
190 let ctx = KernelToolContext::new("/workspace", "agent-001");
191
192 bridge.register_tools(®istry, &ctx);
193
194 let names = registry.names();
195 assert!(names.contains(&"exec_agent-001".to_string()));
196 assert!(names.contains(&"memory_agent-001".to_string()));
197 }
198}