1use crate::assert_invariant;
2#[cfg(feature = "rag")]
3use crate::rag::RagSystem;
4#[cfg(feature = "sandbox")]
5use crate::sandbox::EnhancedSandbox;
6use chrono::{DateTime, Utc};
7use serde::{Deserialize, Serialize};
8use sha2::{Digest, Sha256};
9use std::collections::HashMap;
10use std::sync::Arc;
11use std::time::Instant;
12use tokio::sync::RwLock;
13use uuid::Uuid;
14
15pub mod error;
17pub mod error_formatting;
18pub use error::*;
19pub use error_formatting::*;
20
21pub mod mission;
23pub use mission::*;
24
25pub mod executor;
27pub use executor::*;
28
29pub mod audit;
31pub use audit::*;
32
33pub mod memory;
35pub use memory::*;
36
37pub mod agent;
39pub use agent::*;
40
41pub mod chain;
43pub use chain::*;
44
45pub mod llm;
47pub use llm::*;
48
49pub mod tools;
51pub use tools::*;
52
53#[cfg(feature = "tools")]
55pub mod web_search_tools;
56
57#[cfg(feature = "tools")]
59pub mod document_loaders;
60#[cfg(feature = "tools")]
61pub use document_loaders::*;
62
63#[cfg(feature = "rag")]
65pub mod pinecone_vector_store;
66
67#[cfg(feature = "rag")]
68pub mod chroma_vector_store;
69
70#[cfg(feature = "tools")]
72pub mod python_interpreter;
73#[cfg(feature = "tools")]
74pub use python_interpreter::*;
75
76#[cfg(feature = "tools")]
78pub mod github_toolkit;
79
80pub mod plugin;
82pub use plugin::*;
83
84pub mod features;
86pub use features::*;
87
88#[derive(Clone)]
90pub struct RuntimeContext {
91 pub config: Arc<RwLock<Config>>,
92 pub audit: Arc<AuditSink>,
93 pub tool_registry: Arc<RwLock<ToolRegistry>>,
94 pub model_manager: Option<Arc<ModelManager>>,
95 pub sandbox: Arc<AgentSandbox>,
96 pub policy_engine: Arc<PolicyEngine>,
97 pub perf_collector: Arc<RwLock<PerfCollector>>,
98 pub plugin_manager: Arc<RwLock<PluginManager>>,
99 pub feature_detector: Arc<FeatureDetector>,
100 #[cfg(feature = "rag")]
101 pub rag_system: Option<Arc<RwLock<RagSystem>>>,
102 #[cfg(feature = "sandbox")]
103 pub enhanced_sandbox: Option<Arc<EnhancedSandbox>>,
104}
105
106impl RuntimeContext {
107 pub fn new() -> Self {
108 assert_invariant!(true, "RuntimeContext created", Some("core"));
109
110 Self {
111 config: Arc::new(RwLock::new(Config::default())),
112 audit: Arc::new(AuditSink::new()),
113 tool_registry: Arc::new(RwLock::new(ToolRegistry::new())),
114 model_manager: None,
115 sandbox: Arc::new(AgentSandbox::new()),
116 policy_engine: Arc::new(PolicyEngine::new()),
117 perf_collector: Arc::new(RwLock::new(PerfCollector::new())),
118 plugin_manager: Arc::new(RwLock::new(PluginManager::new())),
119 feature_detector: Arc::new(FeatureDetector::new()),
120 #[cfg(feature = "rag")]
121 rag_system: None,
122 #[cfg(feature = "sandbox")]
123 enhanced_sandbox: None,
124 }
125 }
126
127 pub async fn audit_action(&self, agent_id: &str, action: &str, outcome: &str) {
128 let entry = AuditEntry {
129 id: Uuid::new_v4(),
130 timestamp: Utc::now(),
131 actor: agent_id.to_string(),
132 action: action.to_string(),
133 outcome: outcome.to_string(),
134 reason: None,
135 };
136 self.audit.log(entry).await;
137 }
138
139 pub async fn has_enterprise_feature(&self, feature: &str) -> bool {
141 if cfg!(feature = "enterprise") {
142 self.plugin_manager.read().await.has_feature(feature)
143 } else {
144 false
145 }
146 }
147
148 pub async fn get_enterprise_features(&self) -> Vec<String> {
150 if cfg!(feature = "enterprise") {
151 self.plugin_manager.read().await.enabled_features()
152 } else {
153 vec![]
154 }
155 }
156
157 pub async fn get_available_features(&self) -> Vec<String> {
159 let mut features = Vec::new();
160
161 features.push("mission_execution".to_string());
163 features.push("safety_validation".to_string());
164 features.push("audit_logging".to_string());
165 features.push("policy_engine".to_string());
166
167 #[cfg(feature = "llm")]
169 features.push("llm_integration".to_string());
170
171 #[cfg(feature = "tools")]
172 features.push("tool_system".to_string());
173
174 #[cfg(feature = "rag")]
175 features.push("rag_system".to_string());
176
177 #[cfg(feature = "sandbox")]
178 features.push("sandbox".to_string());
179
180 #[cfg(feature = "server")]
181 features.push("api_server".to_string());
182
183 #[cfg(feature = "compliance")]
184 features.push("compliance_checking".to_string());
185
186 features
187 }
188
189 pub async fn load_enterprise_plugins(&self) -> crate::core::error::Result<()> {
191 Ok(())
193 }
194
195 pub async fn check_feature_status(&self, feature: &str) -> FeatureStatus {
197 self.feature_detector.is_feature_available(self, feature).await
198 }
199
200 pub async fn require_feature(&self, feature: &str) -> crate::core::error::Result<()> {
202 self.feature_detector.require_feature(self, feature).await
203 }
204
205 pub async fn get_feature_summary(&self) -> FeatureSummary {
207 self.feature_detector.get_feature_summary(self).await
208 }
209
210 pub async fn get_category_status(&self, category: &str) -> Vec<FeatureStatus> {
212 self.feature_detector.get_category_status(self, category).await
213 }
214
215 pub async fn is_enterprise_complete(&self) -> bool {
217 self.get_feature_summary().await.is_enterprise_complete()
218 }
219}
220
221#[derive(Clone, Debug, Serialize, Deserialize)]
222pub struct Config {
223 pub mission_timeout_seconds: u64,
224 pub max_parallel_steps: usize,
225 pub audit_enabled: bool,
226 pub network_policy: NetworkPolicy,
227 pub agent_id: String,
228 pub max_tool_calls: usize,
229}
230
231impl Default for Config {
232 fn default() -> Self {
233 Self {
234 mission_timeout_seconds: 300,
235 max_parallel_steps: 4,
236 audit_enabled: true,
237 network_policy: NetworkPolicy::Offline,
238 agent_id: "rustchain-agent".to_string(),
239 max_tool_calls: 100,
240 }
241 }
242}
243
244#[derive(Clone, Debug, Serialize, Deserialize)]
245pub enum NetworkPolicy {
246 Offline,
247 AllowList(Vec<String>),
248}
249
250pub struct AuditSink {
252 entries: Arc<RwLock<Vec<AuditEntry>>>,
253}
254
255impl AuditSink {
256 pub fn new() -> Self {
257 Self {
258 entries: Arc::new(RwLock::new(Vec::new())),
259 }
260 }
261
262 pub async fn log(&self, entry: AuditEntry) {
263 self.entries.write().await.push(entry);
264 }
265
266 pub async fn get_chain_hash(&self) -> String {
267 let entries = self.entries.read().await;
268 if entries.is_empty() {
269 return "genesis".to_string();
270 }
271
272 let mut hasher = Sha256::new();
273 for entry in entries.iter() {
274 hasher.update(
275 format!(
276 "{}{}{}{}",
277 entry.timestamp.to_rfc3339(),
278 entry.actor,
279 entry.action,
280 entry.outcome
281 )
282 .as_bytes(),
283 );
284 }
285 format!("{:x}", hasher.finalize())
286 }
287}
288
289#[derive(Clone, Debug, Serialize, Deserialize)]
290pub struct AuditEntry {
291 pub id: Uuid,
292 pub timestamp: DateTime<Utc>,
293 pub actor: String,
294 pub action: String,
295 pub outcome: String,
296 pub reason: Option<String>,
297}
298
299pub struct ToolRegistry {
300 tools: HashMap<String, Box<dyn Tool + Send + Sync>>,
301}
302
303impl ToolRegistry {
304 pub fn new() -> Self {
305 Self {
306 tools: HashMap::new(),
307 }
308 }
309
310 pub fn register(&mut self, name: String, tool: Box<dyn Tool + Send + Sync>) {
311 self.tools.insert(name, tool);
312 }
313
314 pub fn get(&self, name: &str) -> Option<&Box<dyn Tool + Send + Sync>> {
315 self.tools.get(name)
316 }
317}
318
319pub trait Tool {
320 fn name(&self) -> &str;
321 fn invoke(&self, args: serde_json::Value) -> anyhow::Result<serde_json::Value>;
322}
323
324#[derive(Debug, Clone)]
326pub struct PerfMetric {
327 pub name: String,
328 pub duration_ms: u128,
329}
330
331pub struct PerfCollector {
332 active: HashMap<String, Instant>,
333 pub completed: Vec<PerfMetric>,
334}
335
336impl PerfCollector {
337 pub fn new() -> Self {
338 Self {
339 active: HashMap::new(),
340 completed: vec![],
341 }
342 }
343
344 pub fn start(&mut self, name: &str) {
345 self.active.insert(name.to_string(), Instant::now());
346 }
347
348 pub fn end(&mut self, name: &str) {
349 if let Some(start) = self.active.remove(name) {
350 let duration = start.elapsed().as_millis();
351 self.completed.push(PerfMetric {
352 name: name.to_string(),
353 duration_ms: duration,
354 });
355 }
356 }
357
358 pub fn summary(&self) -> String {
359 self.completed
360 .iter()
361 .map(|m| format!("{}: {}ms", m.name, m.duration_ms))
362 .collect::<Vec<_>>()
363 .join("\n")
364 }
365}
366
367pub struct ModelManager {
368 #[cfg(feature = "llm")]
370 llm_manager: Option<crate::llm::LLMManager>,
371}
372
373impl ModelManager {
374 pub fn new() -> Self {
375 Self {
376 #[cfg(feature = "llm")]
377 llm_manager: None,
378 }
379 }
380
381 #[cfg(feature = "llm")]
382 pub fn with_llm_manager(mut self, manager: crate::llm::LLMManager) -> Self {
383 self.llm_manager = Some(manager);
384 self
385 }
386
387 #[cfg(feature = "llm")]
388 pub async fn complete(
389 &self,
390 request: crate::llm::LLMRequest,
391 provider: Option<&str>,
392 ) -> anyhow::Result<crate::llm::LLMResponse> {
393 if let Some(ref manager) = self.llm_manager {
394 manager.complete(request, provider).await
395 } else {
396 Err(anyhow::anyhow!("LLM manager not initialized"))
397 }
398 }
399}
400
401pub struct AgentSandbox {
402 #[allow(dead_code)]
403 allowed_paths: Vec<std::path::PathBuf>,
404 #[allow(dead_code)]
405 timeout_seconds: u64,
406}
407
408impl AgentSandbox {
409 pub fn new() -> Self {
410 let current_dir = std::env::current_dir()
412 .unwrap_or_else(|_| std::path::PathBuf::from("."));
413
414 Self {
415 allowed_paths: vec![current_dir],
416 timeout_seconds: 30,
417 }
418 }
419
420 pub fn execute(&self, code: &str) -> std::result::Result<String, String> {
421 Ok(format!("Executed in sandbox: {}", code))
423 }
424}
425
426pub struct PolicyEngine {
427 policies: Vec<String>,
428}
429
430impl PolicyEngine {
431 pub fn new() -> Self {
432 Self {
433 policies: Vec::new(),
434 }
435 }
436
437 pub fn validate(&self, action: &str) -> bool {
438 !self.policies.iter().any(|p| action.contains(p))
440 }
441
442 pub fn add_policy(&mut self, policy: String) {
443 self.policies.push(policy);
444 }
445}