1use std::sync::Arc;
7
8use oxi_sdk::SearchCache;
9use oxi_sdk::ToolRegistry;
10use oxi_sdk::{
11 KernelToolContext as SdkKernelToolContext, KernelToolProvider as SdkKernelToolProvider,
12};
13
14use crate::KernelHandle;
15use crate::tools::registration::register_always_on;
16
17pub struct OxiosKernelBridge {
19 kernel_handle: Arc<KernelHandle>,
20 search_cache: Arc<SearchCache>,
21}
22
23impl OxiosKernelBridge {
24 pub fn new(kernel_handle: Arc<KernelHandle>) -> Self {
26 Self {
27 kernel_handle,
28 search_cache: Arc::new(SearchCache::new()),
29 }
30 }
31
32 pub fn with_cache(kernel_handle: Arc<KernelHandle>, search_cache: Arc<SearchCache>) -> Self {
34 Self {
35 kernel_handle,
36 search_cache,
37 }
38 }
39}
40
41impl SdkKernelToolProvider for OxiosKernelBridge {
42 fn tool_names(&self) -> Vec<&str> {
43 vec![
44 "read",
46 "write",
47 "edit",
48 "grep",
49 "find",
50 "ls",
51 "web_search",
52 "get_search_results",
53 "exec",
55 "memory_read",
56 "memory_write",
57 "memory_search",
58 "subagent",
59 "project",
60 "mount",
61 "kernel_agent",
62 "persona",
63 "cron",
64 "security",
65 "budget",
66 "resource",
67 "a2a_delegate",
68 "a2a_send",
69 "a2a_query",
70 "knowledge",
71 "ask_user",
72 "marketplace",
73 "skill_forge",
74 "calendar", "send_email",
76 ]
79 }
80
81 fn register_tools(&self, registry: &ToolRegistry, context: &SdkKernelToolContext) {
82 register_always_on(registry, Arc::clone(&self.search_cache));
84
85 crate::tools::builtin::register_all_kernel_tools(
87 registry,
88 &self.kernel_handle,
89 &context.agent_id,
90 );
91 }
92}
93
94#[cfg(test)]
95mod tests {
96 use super::*;
97
98 #[tokio::test]
100 async fn test_tool_names_length() {
101 let tmp = tempfile::tempdir().unwrap();
102 let base = tmp.path().to_path_buf();
103
104 let state_store =
106 Arc::new(crate::state_store::StateStore::new(base.join("workspace")).unwrap());
107
108 let kernel = Arc::new(crate::KernelHandle::new(
109 crate::StateApi::new(state_store.clone()),
110 crate::AgentApi::new(
111 Arc::new(crate::supervisor::NoOpSupervisor),
112 Arc::new(crate::budget::BudgetManager::new()),
113 Arc::new(crate::memory::MemoryManager::new(state_store.clone())),
114 None,
115 ),
116 crate::SecurityApi::new(
117 Arc::new(parking_lot::Mutex::new(crate::auth::AuthManager::new())),
118 Arc::new(oxi_sdk::observability::AuditTrail::new(100)),
119 Arc::new(parking_lot::Mutex::new(
120 crate::access_manager::AccessManager::new(),
121 )),
122 state_store.clone(),
123 ),
124 crate::PersonaApi::new(Arc::new(crate::persona::PersonaManager::new())),
125 crate::ExtensionApi::new(Arc::new(crate::skill::SkillManager::new(
126 base.join("skills"),
127 base.join("share/skills"),
128 ))),
129 crate::McpApi::new(Arc::new(crate::mcp::McpBridge::new())),
130 crate::InfraApi::new(
131 Arc::new(crate::git_layer::GitLayer::new(base.join("git"), false).unwrap()),
132 Arc::new(crate::cron::CronScheduler::new(state_store.clone(), 60)),
133 Arc::new(crate::resource_monitor::ResourceMonitor::new(60, 60)),
134 crate::event_bus::EventBus::new(256),
135 crate::OxiosConfig::default(),
136 std::time::Instant::now(),
137 std::sync::Arc::new(crate::tools::PendingToolApprovals::new()),
138 std::sync::Arc::new(crate::tools::PendingAskUser::new()),
139 std::sync::Arc::new(parking_lot::RwLock::new(
140 crate::approval::ApprovalConfig::default(),
141 )),
142 std::sync::Arc::new(crate::tools::PendingPathAccess::new()),
143 ),
144 None,
145 crate::ExecApi::new(
146 Arc::new(parking_lot::RwLock::new(
147 crate::config::ExecConfig::default(),
148 )),
149 Arc::new(parking_lot::Mutex::new(
150 crate::access_manager::AccessManager::new(),
151 )),
152 ),
153 crate::A2aApi::new(Arc::new(crate::a2a::A2AProtocol::new(
154 crate::event_bus::EventBus::new(256),
155 ))),
156 crate::EngineApi::new(
157 Arc::new(parking_lot::RwLock::new(crate::OxiosConfig::default())),
158 base.join("config.toml"),
159 Arc::new(crate::RoutingStats::new()),
160 Arc::new(crate::engine::EngineHandle::new(Arc::new(
161 crate::OxiosEngine::new("anthropic/claude-sonnet-4-20250514"),
162 ))),
163 ),
164 Arc::new(oxios_markdown::KnowledgeBase::new(base.join("knowledge")).unwrap()),
165 Arc::new(
166 crate::kernel_handle::KnowledgeLens::new(
167 Arc::new(
168 oxios_markdown::KnowledgeBase::new(base.join("knowledge_lens")).unwrap(),
169 ),
170 Arc::new(crate::memory::MemoryManager::new(state_store.clone())),
171 )
172 .unwrap(),
173 ),
174 crate::MarketplaceApi::new(
175 Arc::new(crate::skill::clawhub::ClawHubInstaller::new(
176 base.join("skills"),
177 base.join("workspace"),
178 None,
179 )),
180 Arc::new(
181 crate::skill::clawhub::ClawHubClient::new(None).expect("valid ClawHub client"),
182 ),
183 Arc::new(crate::skill::skills_sh::SkillsShInstaller::new(
184 base.join("skills"),
185 None,
186 None,
187 )),
188 Arc::new(
189 crate::skill::skills_sh::SkillsShClient::new(None, None)
190 .expect("valid Skills.sh client"),
191 ),
192 ),
193 None, Arc::new(parking_lot::RwLock::new(None)), ));
196
197 let bridge = OxiosKernelBridge::new(kernel);
198
199 let names = bridge.tool_names();
200 assert_eq!(names.len(), 30, "expected 30 tools, got {:?}", names);
206 }
207}