oxios_kernel/kernel_handle/
mod.rs1pub mod a2a_api;
4pub mod agent_api;
5pub mod browser_api;
6pub mod exec_api;
7pub mod extension_api;
8pub mod infra_api;
9pub mod knowledge_lens;
10pub mod mcp_api;
11pub mod persona_api;
12pub mod security_api;
13pub mod space_api;
14pub mod state_api;
15
16pub use a2a_api::A2aApi;
17pub use agent_api::AgentApi;
18pub use browser_api::BrowserApi;
19pub use exec_api::ExecApi;
20pub use extension_api::ExtensionApi;
21pub use infra_api::InfraApi;
22pub use knowledge_lens::{
23 CopilotResponse, KnowledgeContext, KnowledgeLens, KnowledgeNote, MemoryNote,
24};
25pub use mcp_api::McpApi;
26pub use persona_api::PersonaApi;
27pub use security_api::SecurityApi;
28pub use space_api::SpaceApi;
29pub use state_api::StateApi;
30
31use crate::a2a::A2AProtocol;
32use crate::access_manager::AccessManager;
33use crate::audit_trail::AuditTrail;
34use crate::auth::AuthManager;
35use crate::budget::BudgetManager;
36use crate::config::OxiosConfig;
37use crate::cron::CronScheduler;
38use crate::event_bus::EventBus;
39use crate::git_layer::CommitInfo;
40use crate::git_layer::GitLayer;
41use crate::host_tools::HostToolValidator;
42use crate::mcp::McpBridge;
43use crate::memory::MemoryManager;
44use crate::persona_manager::PersonaManager;
45use crate::program::ProgramManager;
46use crate::resource_monitor::ResourceMonitor;
47use crate::scheduler::AgentScheduler;
48use crate::skill::SkillStore;
49use crate::space::SpaceManager;
50use crate::state_store::StateStore;
51use crate::supervisor::Supervisor;
52use serde::Serialize;
53use std::sync::Arc;
54use std::time::Instant;
55
56pub struct KernelHandle {
71 pub state: StateApi,
73 pub agents: AgentApi,
75 pub security: SecurityApi,
77 pub persona: PersonaApi,
79 pub extensions: ExtensionApi,
81 pub mcp: McpApi,
83 pub infra: InfraApi,
85 pub spaces: SpaceApi,
87 pub exec: ExecApi,
89 pub browser: BrowserApi,
91 pub a2a: A2aApi,
93 pub knowledge: Arc<oxios_markdown::KnowledgeBase>,
95 pub knowledge_lens: Arc<KnowledgeLens>,
97}
98
99impl KernelHandle {
100 #[allow(clippy::too_many_arguments)]
105 pub fn new(
106 state: StateApi,
107 agents: AgentApi,
108 security: SecurityApi,
109 persona: PersonaApi,
110 extensions: ExtensionApi,
111 mcp: McpApi,
112 infra: InfraApi,
113 spaces: SpaceApi,
114 exec: ExecApi,
115 browser: BrowserApi,
116 a2a: A2aApi,
117 knowledge: Arc<oxios_markdown::KnowledgeBase>,
118 knowledge_lens: Arc<KnowledgeLens>,
119 ) -> Self {
120 Self {
121 state,
122 agents,
123 security,
124 persona,
125 extensions,
126 mcp,
127 infra,
128 spaces,
129 exec,
130 browser,
131 a2a,
132 knowledge,
133 knowledge_lens,
134 }
135 }
136
137 #[deprecated(note = "Use KernelHandle::new() with pre-built Facades instead")]
141 #[allow(clippy::too_many_arguments)]
142 pub fn from_subsystems(
143 state_store: Arc<StateStore>,
144 event_bus: EventBus,
145 supervisor: Arc<dyn Supervisor>,
146 scheduler: Arc<AgentScheduler>,
147 memory_manager: Arc<MemoryManager>,
148 git_layer: Arc<GitLayer>,
149 audit_trail: Arc<AuditTrail>,
150 budget_manager: Arc<BudgetManager>,
151 resource_monitor: Arc<ResourceMonitor>,
152 cron_scheduler: Arc<CronScheduler>,
153 program_manager: Arc<ProgramManager>,
154 skill_store: Arc<SkillStore>,
155 persona_manager: Arc<PersonaManager>,
156 mcp_bridge: Arc<McpBridge>,
157 auth_manager: Arc<parking_lot::Mutex<AuthManager>>,
158 access_manager: Arc<parking_lot::Mutex<AccessManager>>,
159 host_tool_validator: Arc<HostToolValidator>,
160 config: OxiosConfig,
161 start_time: Instant,
162 space_manager: Arc<SpaceManager>,
163 ) -> Self {
164 let knowledge_dir = state_store.base_path.join("knowledge");
165 let knowledge = Arc::new(
166 oxios_markdown::KnowledgeBase::new(knowledge_dir)
167 .expect("Failed to create KnowledgeBase"),
168 );
169 let knowledge_lens = Arc::new(
170 KnowledgeLens::new(knowledge.clone(), memory_manager.clone())
171 .expect("Failed to create KnowledgeLens"),
172 );
173 Self {
174 security: SecurityApi::new(
175 auth_manager.clone(),
176 audit_trail,
177 access_manager.clone(),
178 state_store.clone(),
179 ),
180 state: StateApi::new(state_store),
181 agents: AgentApi::new(
182 supervisor,
183 budget_manager,
184 memory_manager,
185 Some(event_bus.clone()),
186 ),
187 persona: PersonaApi::new(persona_manager),
188 extensions: ExtensionApi::new(program_manager, skill_store, host_tool_validator),
189 mcp: McpApi::new(mcp_bridge),
190 infra: InfraApi::new(
191 git_layer,
192 scheduler,
193 cron_scheduler,
194 resource_monitor,
195 event_bus.clone(),
196 config.clone(),
197 start_time,
198 ),
199 spaces: SpaceApi::new(space_manager, event_bus),
200 exec: ExecApi::new(Arc::new(config.exec.clone()), access_manager),
201 #[allow(clippy::default_trait_access)]
202 browser: BrowserApi::default(),
203 a2a: A2aApi::new(Arc::new(A2AProtocol::new(crate::EventBus::new(0)))),
204 knowledge,
205 knowledge_lens,
206 }
207 }
208
209 pub async fn save_and_commit<T: Serialize>(
215 &self,
216 category: &str,
217 name: &str,
218 data: &T,
219 ) -> anyhow::Result<()> {
220 self.state.save(category, name, data).await?;
221 let git = self.infra.git();
222 if git.is_enabled() {
223 let rel_path = format!("{}/{}.json", category, name);
224 let _ = git.commit_file(&rel_path, &format!("save {}/{}", category, name));
225 }
226 Ok(())
227 }
228
229 pub async fn save_markdown_and_commit(
231 &self,
232 category: &str,
233 name: &str,
234 content: &str,
235 ) -> anyhow::Result<()> {
236 self.state.save_markdown(category, name, content).await?;
237 let git = self.infra.git();
238 if git.is_enabled() {
239 let rel_path = format!("{}/{}.md", category, name);
240 let _ = git.commit_file(&rel_path, &format!("save {}/{}", category, name));
241 }
242 Ok(())
243 }
244
245 pub async fn delete_and_commit(&self, category: &str, name: &str) -> anyhow::Result<bool> {
247 let deleted = self.state.delete(category, name).await?;
248 if deleted {
249 let git = self.infra.git();
250 if git.is_enabled() {
251 let rel_path = format!("{}/{}.json", category, name);
252 let _ = git.remove_file(&rel_path, &format!("delete {}/{}", category, name));
253 }
254 }
255 Ok(deleted)
256 }
257
258 pub fn commit_all(&self, message: &str) -> anyhow::Result<Option<CommitInfo>> {
260 self.state.commit_all(self.infra.git(), message)
261 }
262
263 pub fn flush_audit(&self) -> anyhow::Result<()> {
265 self.security.flush(self.infra.git())
266 }
267
268 pub async fn schedule(
270 &self,
271 cron_expr: &str,
272 task: &str,
273 persona: Option<&str>,
274 ) -> anyhow::Result<String> {
275 let _persona = persona.unwrap_or("default");
276 let job = crate::cron::CronJob::new(
277 format!("job_{}", uuid::Uuid::new_v4()),
278 cron_expr.to_string(),
279 task.to_string(),
280 );
281 let job_id = self.infra.add_cron(job).await?;
282 Ok(job_id.to_string())
283 }
284
285 pub async fn unschedule(&self, job_id: &str) -> anyhow::Result<bool> {
287 let uuid =
288 uuid::Uuid::parse_str(job_id).map_err(|e| anyhow::anyhow!("invalid job id: {e}"))?;
289 match self.infra.remove_cron(uuid).await {
290 Ok(()) => Ok(true),
291 Err(_) => Ok(false),
292 }
293 }
294
295 pub fn list_schedules(&self) -> Vec<crate::cron::CronJob> {
297 self.infra.list_crons()
298 }
299
300 pub async fn load_json<T: serde::de::DeserializeOwned>(
302 &self,
303 category: &str,
304 name: &str,
305 ) -> anyhow::Result<Option<T>> {
306 self.state.load(category, name).await
307 }
308
309 pub fn start_time(&self) -> std::time::Instant {
311 self.infra.start_time
312 }
313
314 pub async fn activate_space(&self, id: &str) -> anyhow::Result<()> {
319 self.spaces.activate(id).await?;
320 tracing::info!(space_id = %id, "Space activated (knowledge base is global)");
321 Ok(())
322 }
323}