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 #[allow(unused_mut)]
44 let mut names = vec![
45 "read",
47 "write",
48 "edit",
49 "grep",
50 "find",
51 "ls",
52 "web_search",
53 "get_search_results",
54 "exec",
56 "memory_read",
57 "memory_write",
58 "memory_search",
59 "subagent",
60 "project",
61 "mount",
62 "kernel_agent",
63 "persona",
64 "cron",
65 "security",
66 "budget",
67 "resource",
68 "a2a_delegate",
69 "a2a_send",
70 "a2a_query",
71 "knowledge",
72 "ask_user",
73 "marketplace",
74 "skill_forge",
75 "calendar", "send_email",
77 ];
80
81 #[cfg(feature = "native-browser")]
83 names.extend([
84 "browse",
85 "browse_extract",
86 "browse_session",
87 "browse_script",
88 ]);
89
90 names
91 }
92
93 fn register_tools(&self, registry: &ToolRegistry, context: &SdkKernelToolContext) {
94 register_always_on(registry, Arc::clone(&self.search_cache));
96
97 crate::tools::builtin::register_all_kernel_tools(
99 registry,
100 &self.kernel_handle,
101 &context.agent_id,
102 );
103 }
104}
105
106#[cfg(test)]
107mod tests {
108 use super::*;
109
110 #[tokio::test]
112 async fn test_tool_names_length() {
113 let tmp = tempfile::tempdir().unwrap();
114 let base = tmp.path().to_path_buf();
115
116 let state_store =
118 Arc::new(crate::state_store::StateStore::new(base.join("workspace")).unwrap());
119
120 let kernel = Arc::new(crate::KernelHandle::new(
121 crate::StateApi::new(state_store.clone()),
122 crate::AgentApi::new(
123 Arc::new(crate::supervisor::NoOpSupervisor),
124 Arc::new(crate::budget::BudgetManager::new()),
125 Arc::new(crate::memory::MemoryManager::new(state_store.clone())),
126 None,
127 ),
128 crate::SecurityApi::new(
129 Arc::new(parking_lot::Mutex::new(crate::auth::AuthManager::new())),
130 Arc::new(oxi_sdk::observability::AuditTrail::new(100)),
131 Arc::new(parking_lot::Mutex::new(
132 crate::access_manager::AccessManager::new(),
133 )),
134 state_store.clone(),
135 ),
136 crate::PersonaApi::new(Arc::new(crate::persona::PersonaManager::new())),
137 crate::ExtensionApi::new(Arc::new(crate::skill::SkillManager::new(
138 base.join("skills"),
139 base.join("share/skills"),
140 ))),
141 crate::McpApi::new(Arc::new(crate::mcp::McpBridge::new())),
142 crate::InfraApi::new(
143 Arc::new(crate::git_layer::GitLayer::new(base.join("git"), false).unwrap()),
144 Arc::new(crate::cron::CronScheduler::new(state_store.clone(), 60)),
145 Arc::new(crate::resource_monitor::ResourceMonitor::new(60, 60)),
146 crate::event_bus::EventBus::new(256),
147 crate::OxiosConfig::default(),
148 std::time::Instant::now(),
149 std::sync::Arc::new(crate::tools::PendingToolApprovals::new()),
150 std::sync::Arc::new(crate::tools::PendingAskUser::new()),
151 std::sync::Arc::new(parking_lot::RwLock::new(
152 crate::approval::ApprovalConfig::default(),
153 )),
154 std::sync::Arc::new(crate::tools::PendingPathAccess::new()),
155 ),
156 None,
157 crate::ExecApi::new(
158 Arc::new(parking_lot::RwLock::new(
159 crate::config::ExecConfig::default(),
160 )),
161 Arc::new(parking_lot::Mutex::new(
162 crate::access_manager::AccessManager::new(),
163 )),
164 ),
165 crate::A2aApi::new(Arc::new(crate::a2a::A2AProtocol::new(
166 crate::event_bus::EventBus::new(256),
167 ))),
168 crate::EngineApi::new(
169 Arc::new(parking_lot::RwLock::new(crate::OxiosConfig::default())),
170 base.join("config.toml"),
171 Arc::new(crate::RoutingStats::new()),
172 Arc::new(crate::engine::EngineHandle::new(Arc::new(
173 crate::OxiosEngine::new("anthropic/claude-sonnet-4-20250514"),
174 ))),
175 ),
176 Arc::new(oxios_markdown::KnowledgeBase::new(base.join("knowledge")).unwrap()),
177 Arc::new(
178 crate::kernel_handle::KnowledgeLens::new(
179 Arc::new(
180 oxios_markdown::KnowledgeBase::new(base.join("knowledge_lens")).unwrap(),
181 ),
182 Arc::new(crate::memory::MemoryManager::new(state_store.clone())),
183 )
184 .unwrap(),
185 ),
186 crate::MarketplaceApi::new(
187 Arc::new(crate::skill::clawhub::ClawHubInstaller::new(
188 base.join("skills"),
189 base.join("workspace"),
190 None,
191 )),
192 Arc::new(
193 crate::skill::clawhub::ClawHubClient::new(None).expect("valid ClawHub client"),
194 ),
195 Arc::new(crate::skill::skills_sh::SkillsShInstaller::new(
196 base.join("skills"),
197 None,
198 None,
199 )),
200 Arc::new(
201 crate::skill::skills_sh::SkillsShClient::new(None, None)
202 .expect("valid Skills.sh client"),
203 ),
204 ),
205 None, Arc::new(parking_lot::RwLock::new(None)), ));
208
209 let bridge = OxiosKernelBridge::new(kernel);
210
211 let names = bridge.tool_names();
212 #[allow(unused_mut)]
219 let mut expected = 30_usize;
220 #[cfg(feature = "native-browser")]
221 {
222 expected += 4; }
224 assert_eq!(
225 names.len(),
226 expected,
227 "expected {expected} tools, got {:?}",
228 names
229 );
230 }
231}