use oxi_agent::ToolRegistry;
use std::collections::HashMap;
use std::path::PathBuf;
#[derive(Debug, Clone)]
pub struct KernelToolContext {
pub workspace_dir: PathBuf,
pub agent_id: String,
pub session_id: Option<String>,
pub permissions: Vec<String>,
pub metadata: HashMap<String, serde_json::Value>,
}
impl KernelToolContext {
pub fn new(workspace_dir: impl Into<PathBuf>, agent_id: impl Into<String>) -> Self {
Self {
workspace_dir: workspace_dir.into(),
agent_id: agent_id.into(),
session_id: None,
permissions: Vec::new(),
metadata: HashMap::new(),
}
}
pub fn with_session(mut self, session_id: impl Into<String>) -> Self {
self.session_id = Some(session_id.into());
self
}
pub fn with_permissions(mut self, permissions: Vec<String>) -> Self {
self.permissions = permissions;
self
}
pub fn with_meta(mut self, key: impl Into<String>, value: serde_json::Value) -> Self {
self.metadata.insert(key.into(), value);
self
}
pub fn get_meta(&self, key: &str) -> Option<&serde_json::Value> {
self.metadata.get(key)
}
pub fn get_meta_str(&self, key: &str) -> Option<&str> {
self.metadata.get(key).and_then(|v| v.as_str())
}
}
pub trait KernelToolProvider: Send + Sync {
fn tool_names(&self) -> Vec<&str>;
fn register_tools(&self, registry: &ToolRegistry, context: &KernelToolContext);
}
#[cfg(test)]
mod tests {
use super::*;
use async_trait::async_trait;
use oxi_agent::{AgentTool, AgentToolResult, ToolContext, ToolError};
use serde_json::Value;
struct MockKernelTool {
name: String,
}
#[async_trait]
impl AgentTool for MockKernelTool {
fn name(&self) -> &str {
&self.name
}
fn label(&self) -> &str {
"mock"
}
fn description(&self) -> &str {
"A mock kernel tool"
}
fn parameters_schema(&self) -> Value {
serde_json::json!({"type": "object", "properties": {}})
}
async fn execute(
&self,
_tool_call_id: &str,
_params: Value,
_signal: Option<tokio::sync::oneshot::Receiver<()>>,
_ctx: &ToolContext,
) -> Result<AgentToolResult, ToolError> {
Ok(AgentToolResult::success("mock result"))
}
}
struct MockKernelBridge;
impl KernelToolProvider for MockKernelBridge {
fn tool_names(&self) -> Vec<&str> {
vec!["exec", "memory"]
}
fn register_tools(&self, registry: &ToolRegistry, ctx: &KernelToolContext) {
registry.register(MockKernelTool {
name: format!("exec_{}", ctx.agent_id),
});
registry.register(MockKernelTool {
name: format!("memory_{}", ctx.agent_id),
});
}
}
#[test]
fn test_kernel_tool_context_builder() {
let ctx = KernelToolContext::new("/workspace", "agent-001")
.with_session("sess-123")
.with_permissions(vec!["read".into(), "write".into()]);
assert_eq!(ctx.workspace_dir, PathBuf::from("/workspace"));
assert_eq!(ctx.agent_id, "agent-001");
assert_eq!(ctx.session_id, Some("sess-123".to_string()));
assert_eq!(ctx.permissions, vec!["read", "write"]);
}
#[test]
fn test_kernel_bridge_registers_tools() {
let bridge = MockKernelBridge;
let registry = ToolRegistry::new();
let ctx = KernelToolContext::new("/workspace", "agent-001");
bridge.register_tools(®istry, &ctx);
let names = registry.names();
assert!(names.contains(&"exec_agent-001".to_string()));
assert!(names.contains(&"memory_agent-001".to_string()));
}
}