| use crate::a2a_protocol::{A2AProtocolHandler, ReasoningPartition};
|
| use crate::streaming::ReasoningStreamManager;
|
| use crate::trace::{ReasoningStep, ReasoningTrace};
|
| use std::sync::Arc;
|
|
|
|
|
| pub struct L1KernelIntegration {
|
| protocol_handler: Arc<A2AProtocolHandler>,
|
| }
|
|
|
| impl L1KernelIntegration {
|
| pub fn new(agent_id: String) -> Self {
|
| L1KernelIntegration {
|
| protocol_handler: Arc::new(A2AProtocolHandler::new(agent_id)),
|
| }
|
| }
|
|
|
|
|
|
|
| pub async fn on_kernel_append(&self, offset: u64, event_hash: &str) {
|
| let mut trace = ReasoningTrace::new(
|
| "kernel_001".into(),
|
| "append".into(),
|
| 1,
|
| );
|
|
|
| trace.set_query(format!("append offset {}", offset));
|
| trace.add_step(ReasoningStep::Retrieve {
|
| source: "L1::WAL".into(),
|
| symbol: format!("offset_{}", offset),
|
| result: serde_json::json!({
|
| "offset": offset,
|
| "hash": event_hash,
|
| "timestamp": std::time::SystemTime::now()
|
| .duration_since(std::time::UNIX_EPOCH)
|
| .unwrap()
|
| .as_nanos()
|
| }),
|
| });
|
|
|
| let trace_id = trace.finalize();
|
| self.protocol_handler
|
| .emit_trace_start(
|
| "append".into(),
|
| trace_id,
|
| trace.initiating_query.clone(),
|
| )
|
| .await;
|
| }
|
|
|
|
|
|
|
| pub async fn on_kernel_commit(&self, offset: u64, _tip_hash: &str) {
|
| let mut trace = ReasoningTrace::new(
|
| "kernel_001".into(),
|
| "commit".into(),
|
| 2,
|
| );
|
|
|
| trace.add_step(ReasoningStep::CheckAuthorization {
|
| principal: "kernel".into(),
|
| action: "commit_offset".into(),
|
| resource: format!("offset_{}", offset),
|
| allowed: true,
|
| reason: "monotonic_and_valid".into(),
|
| });
|
|
|
| let trace_id = trace.finalize();
|
| self.protocol_handler
|
| .emit_trace_complete(trace_id, 5, 1, Some(0.99))
|
| .await;
|
| }
|
|
|
|
|
|
|
| pub async fn on_kernel_rotate(&self, segment_id: u64, _prev_hash: &str) {
|
| let mut trace = ReasoningTrace::new(
|
| "kernel_001".into(),
|
| "rotate".into(),
|
| 3,
|
| );
|
|
|
| trace.add_step(ReasoningStep::Verify {
|
| target: format!("segment_{}", segment_id),
|
| method: "prev_hash_chain".into(),
|
| valid: true,
|
| error: None,
|
| });
|
|
|
| trace.add_step(ReasoningStep::Conclude {
|
| conclusion: "Segment rotated successfully".into(),
|
| confidence: 1.0,
|
| });
|
|
|
| let trace_id = trace.finalize();
|
| self.protocol_handler
|
| .emit_trace_complete(trace_id, 10, 2, Some(1.0))
|
| .await;
|
| }
|
| }
|
|
|
|
|
| pub struct L3PolicyIntegration {
|
| protocol_handler: Arc<A2AProtocolHandler>,
|
| }
|
|
|
| impl L3PolicyIntegration {
|
| pub fn new(agent_id: String) -> Self {
|
| L3PolicyIntegration {
|
| protocol_handler: Arc::new(A2AProtocolHandler::new(agent_id)),
|
| }
|
| }
|
|
|
|
|
|
|
| pub async fn on_policy_authorize(
|
| &self,
|
| principal: &str,
|
| action: &str,
|
| resource: &str,
|
| allowed: bool,
|
| reason: &str,
|
| ) {
|
| let mut trace = ReasoningTrace::new(
|
| "policy_001".into(),
|
| "authorize".into(),
|
| 1,
|
| );
|
|
|
| trace.set_query(format!(
|
| "authorize {} {} {}",
|
| principal, action, resource
|
| ));
|
|
|
| trace.add_step(ReasoningStep::Retrieve {
|
| source: "L3::Datalog".into(),
|
| symbol: format!("policy_{}", action),
|
| result: serde_json::json!({
|
| "principal": principal,
|
| "action": action,
|
| "allowed": allowed
|
| }),
|
| });
|
|
|
| trace.add_step(ReasoningStep::CheckAuthorization {
|
| principal: principal.into(),
|
| action: action.into(),
|
| resource: resource.into(),
|
| allowed,
|
| reason: reason.into(),
|
| });
|
|
|
| trace.add_step(ReasoningStep::Conclude {
|
| conclusion: format!("Authorization: {}", if allowed { "ALLOW" } else { "DENY" }),
|
| confidence: 0.95,
|
| });
|
|
|
| let trace_id = trace.finalize();
|
| self.protocol_handler
|
| .emit_trace_start(
|
| "authorize".into(),
|
| trace_id,
|
| trace.initiating_query.clone(),
|
| )
|
| .await;
|
| }
|
|
|
|
|
| pub async fn on_policy_anomaly(&self, anomaly_type: &str, details: serde_json::Value) {
|
| let mut trace = ReasoningTrace::new(
|
| "policy_001".into(),
|
| "anomaly".into(),
|
| 2,
|
| );
|
|
|
| trace.add_step(ReasoningStep::Retrieve {
|
| source: "L3::Anomaly".into(),
|
| symbol: anomaly_type.into(),
|
| result: details,
|
| });
|
|
|
| trace.add_step(ReasoningStep::Conclude {
|
| conclusion: format!("Anomaly detected: {}", anomaly_type),
|
| confidence: 0.85,
|
| });
|
|
|
| let trace_id = trace.finalize();
|
| self.protocol_handler
|
| .emit_trace_complete(trace_id, 15, 2, Some(0.85))
|
| .await;
|
| }
|
| }
|
|
|
|
|
| pub struct L5KnowledgeIntegration {
|
| stream_manager: Arc<ReasoningStreamManager>,
|
| }
|
|
|
| impl L5KnowledgeIntegration {
|
| pub fn new() -> Self {
|
| L5KnowledgeIntegration {
|
| stream_manager: Arc::new(ReasoningStreamManager::new()),
|
| }
|
| }
|
|
|
|
|
|
|
| pub async fn store_reasoning_trace(&self, trace: ReasoningTrace) {
|
|
|
| let symbols = trace.extract_symbols();
|
|
|
|
|
| self.stream_manager.store_trace(trace.clone()).await;
|
|
|
|
|
| for symbol in symbols {
|
| tracing::info!("Indexed symbol '{}' from trace {}", symbol, &trace.trace_id[0..16]);
|
| }
|
| }
|
|
|
|
|
|
|
| pub async fn link_traces(&self, source_id: &str, target_id: &str, relation: &str) {
|
| tracing::info!(
|
| "Linking traces: {} --[{}]--> {}",
|
| &source_id[0..16],
|
| relation,
|
| &target_id[0..16]
|
| );
|
|
|
|
|
| }
|
|
|
|
|
| pub async fn query_related_traces(&self, symbol: &str) -> Vec<String> {
|
| let traces = self.stream_manager.get_traces().await;
|
| traces
|
| .iter()
|
| .filter(|t| t.extract_symbols().contains(&symbol.to_string()))
|
| .map(|t| t.trace_id.clone())
|
| .collect()
|
| }
|
|
|
|
|
| pub async fn get_trace_timeline(&self, trace_id: &str) -> Option<String> {
|
| self.stream_manager
|
| .get_timeline(trace_id)
|
| .await
|
| .map(|tl| tl.render_ascii())
|
| }
|
| }
|
|
|
| impl Default for L5KnowledgeIntegration {
|
| fn default() -> Self {
|
| Self::new()
|
| }
|
| }
|
|
|
|
|
|
|
| pub mod erlang_nif {
|
| use super::*;
|
|
|
|
|
|
|
|
|
| pub fn seb_reasoning_subscribe(partition_path: &str, _mode: &str) -> String {
|
| let partition = ReasoningPartition::from_path(partition_path)
|
| .map(|p| p.path())
|
| .unwrap_or_else(|| partition_path.to_string());
|
| format!("subscription:{}", partition)
|
| }
|
|
|
|
|
|
|
| pub fn seb_reasoning_emit_step(_trace_id: &str, _step_index: usize, _step_json: serde_json::Value) -> bool {
|
| true
|
| }
|
|
|
|
|
|
|
| pub fn seb_reasoning_challenge(
|
| target_trace_id: &str,
|
| counter_evidence: &str,
|
| step_index: Option<usize>,
|
| ) -> String {
|
| format!(
|
| "challenge:{}:{}:{}",
|
| target_trace_id,
|
| counter_evidence.len(),
|
| step_index.unwrap_or(0)
|
| )
|
| }
|
|
|
|
|
|
|
| pub fn seb_reasoning_compose(sub_trace_ids: Vec<String>, composition_rule: &str) -> String {
|
| format!(
|
| "composition:{}:{}",
|
| sub_trace_ids.len(),
|
| composition_rule
|
| )
|
| }
|
|
|
|
|
|
|
|
|
| pub fn seb_reasoning_query(_query_type: &str, _query_data: serde_json::Value) -> Vec<String> {
|
| vec![]
|
| }
|
| }
|
|
|
| #[cfg(test)]
|
| mod tests {
|
| use super::*;
|
|
|
| #[tokio::test]
|
| async fn test_l1_kernel_integration() {
|
| let l1 = L1KernelIntegration::new("kernel_001".into());
|
|
|
| l1.on_kernel_append(101, "abc123def").await;
|
| l1.on_kernel_commit(101, "xyz789").await;
|
| l1.on_kernel_rotate(1, "prev_hash").await;
|
|
|
| let events = l1.protocol_handler.get_events().await;
|
| assert!(!events.is_empty());
|
| }
|
|
|
| #[tokio::test]
|
| async fn test_l3_policy_integration() {
|
| let l3 = L3PolicyIntegration::new("policy_001".into());
|
|
|
| l3.on_policy_authorize("user_1", "read", "doc_1", true, "owned")
|
| .await;
|
|
|
| let events = l3.protocol_handler.get_events().await;
|
| assert!(!events.is_empty());
|
| }
|
|
|
| #[tokio::test]
|
| async fn test_l5_knowledge_integration() {
|
| let l5 = L5KnowledgeIntegration::new();
|
|
|
| let mut trace = ReasoningTrace::new("agent_001".into(), "verify".into(), 1);
|
| trace.add_step(ReasoningStep::Retrieve {
|
| source: "L1".into(),
|
| symbol: "test_symbol".into(),
|
| result: serde_json::json!({}),
|
| });
|
| trace.finalize();
|
|
|
| l5.store_reasoning_trace(trace).await;
|
|
|
| let related = l5.query_related_traces("test_symbol").await;
|
| assert!(!related.is_empty());
|
| }
|
|
|
| #[test]
|
| fn test_erlang_nif_subscribe() {
|
| let result = erlang_nif::seb_reasoning_subscribe("reasoning/agent_001", "live");
|
| assert!(result.contains("subscription"));
|
| }
|
|
|
| #[test]
|
| fn test_erlang_nif_challenge() {
|
| let result = erlang_nif::seb_reasoning_challenge("trace_001", "counter_evidence", Some(2));
|
| assert!(result.contains("challenge"));
|
| assert!(result.contains("trace_001"));
|
| }
|
| }
|
|
|