zoey_core/
extensions.rs

1//! # Extension Points for Enterprise Features
2//!
3//! This module defines traits that enterprise plugins can implement to extend
4//! ZoeyOS functionality. The consumer codebase provides default implementations
5//! that work standalone, while enterprise can provide enhanced versions.
6//!
7//! ## Design Principles
8//!
9//! 1. **Consumer Complete**: Consumer features work without enterprise
10//! 2. **Drop-in Replacement**: Enterprise implementations can replace consumer
11//! 3. **Graceful Degradation**: Missing enterprise features don't break consumer
12//! 4. **Type Safety**: Shared types ensure compatibility
13//!
14//! ## Usage
15//!
16//! ```rust
17//! use zoey_core::extensions::{LearningProvider, ComplianceProvider};
18//!
19//! // Consumer provides basic implementations
20//! let basic_compliance = BasicComplianceProvider::new();
21//!
22//! // Enterprise provides enhanced implementations
23//! // let enterprise_compliance = HipaaComplianceProvider::new(); // Enterprise
24//! ```
25
26use crate::types::UUID;
27use crate::Result;
28use async_trait::async_trait;
29use serde::{Deserialize, Serialize};
30use std::collections::HashMap;
31use std::sync::Arc;
32
33// ============================================================================
34// LEARNING PROVIDER - For ML/Training Features
35// ============================================================================
36
37/// Feedback from user or system about agent response quality
38#[derive(Debug, Clone, Serialize, Deserialize)]
39pub struct LearningFeedback {
40    /// ID of the response being rated
41    pub response_id: UUID,
42    /// Score from -1.0 (bad) to 1.0 (good)
43    pub score: f32,
44    /// Optional text feedback
45    pub text: Option<String>,
46    /// Feedback source (user, evaluator, system)
47    pub source: FeedbackSource,
48    /// Timestamp
49    pub timestamp: i64,
50}
51
52/// Source of feedback
53#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
54pub enum FeedbackSource {
55    /// End user feedback
56    User,
57    /// Automated evaluator
58    Evaluator,
59    /// System-generated (quality heuristics)
60    System,
61    /// Expert annotation
62    Expert,
63}
64
65/// Result of a training operation
66#[derive(Debug, Clone, Serialize, Deserialize)]
67pub struct TrainingResult {
68    /// Whether training succeeded
69    pub success: bool,
70    /// Training loss (if applicable)
71    pub loss: Option<f32>,
72    /// Number of examples trained on
73    pub examples_count: usize,
74    /// Training duration in seconds
75    pub duration_secs: f64,
76    /// Error message if failed
77    pub error: Option<String>,
78    /// Additional metrics
79    pub metrics: HashMap<String, f64>,
80}
81
82/// Learning provider trait - allows enterprise to add training capabilities
83///
84/// Consumer implementation: Basic feedback collection, no training
85/// Enterprise implementation: LoRA fine-tuning, continual learning, RLHF
86#[async_trait]
87pub trait LearningProvider: Send + Sync {
88    /// Provider name
89    fn name(&self) -> &str;
90
91    /// Collect feedback for a response (Consumer: stores locally)
92    async fn collect_feedback(&self, feedback: LearningFeedback) -> Result<()>;
93
94    /// Get collected feedback for analysis
95    async fn get_feedback(&self, limit: usize) -> Result<Vec<LearningFeedback>>;
96
97    /// Check if training is available (Consumer: returns false)
98    fn supports_training(&self) -> bool {
99        false
100    }
101
102    /// Train on collected feedback (Enterprise only)
103    /// Consumer implementation returns Ok with success=false
104    async fn train(&self) -> Result<TrainingResult> {
105        Ok(TrainingResult {
106            success: false,
107            loss: None,
108            examples_count: 0,
109            duration_secs: 0.0,
110            error: Some("Training requires enterprise license".to_string()),
111            metrics: HashMap::new(),
112        })
113    }
114
115    /// Enable continual learning mode (Enterprise only)
116    async fn enable_continual_learning(&self) -> Result<bool> {
117        Ok(false)
118    }
119
120    /// Load a trained adapter (Enterprise only)
121    async fn load_adapter(&self, _adapter_name: &str) -> Result<bool> {
122        Ok(false)
123    }
124
125    /// List available adapters (Enterprise only)
126    async fn list_adapters(&self) -> Result<Vec<String>> {
127        Ok(vec![])
128    }
129}
130
131// ============================================================================
132// COMPLIANCE PROVIDER - For Regulatory Features
133// ============================================================================
134
135/// PII finding from compliance scan
136#[derive(Debug, Clone, Serialize, Deserialize)]
137pub struct PiiFinding {
138    /// Type of PII found
139    pub pii_type: PiiType,
140    /// Start position in text
141    pub start: usize,
142    /// End position in text
143    pub end: usize,
144    /// The matched text (may be redacted in logs)
145    pub matched_text: String,
146    /// Severity level
147    pub severity: Severity,
148    /// Confidence score (0.0 - 1.0)
149    pub confidence: f32,
150}
151
152/// Types of PII that can be detected
153#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
154pub enum PiiType {
155    /// Social Security Number
156    Ssn,
157    /// Email address
158    Email,
159    /// Phone number
160    Phone,
161    /// Credit card number
162    CreditCard,
163    /// IP address
164    IpAddress,
165    /// API key or token
166    ApiKey,
167    /// Person name
168    Name,
169    /// Physical address
170    Address,
171    /// Date of birth
172    DateOfBirth,
173    /// Medical record number
174    MedicalId,
175    /// Custom pattern
176    Custom(String),
177}
178
179/// Severity level for findings
180#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Serialize, Deserialize)]
181pub enum Severity {
182    /// Low severity
183    Low,
184    /// Medium severity
185    Medium,
186    /// High severity
187    High,
188    /// Critical severity
189    Critical,
190}
191
192/// Compliance framework
193#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
194pub enum ComplianceFramework {
195    /// HIPAA (healthcare)
196    Hipaa,
197    /// GDPR (EU data protection)
198    Gdpr,
199    /// FDA (medical devices)
200    Fda,
201    /// PCI-DSS (payment cards)
202    PciDss,
203    /// SOC2 (service organizations)
204    Soc2,
205}
206
207/// Compliance check result
208#[derive(Debug, Clone, Serialize, Deserialize)]
209pub struct ComplianceCheckResult {
210    /// Framework checked
211    pub framework: ComplianceFramework,
212    /// Whether compliant
213    pub compliant: bool,
214    /// Findings/violations
215    pub findings: Vec<ComplianceFinding>,
216    /// Recommendations
217    pub recommendations: Vec<String>,
218    /// Timestamp
219    pub checked_at: i64,
220}
221
222/// Individual compliance finding
223#[derive(Debug, Clone, Serialize, Deserialize)]
224pub struct ComplianceFinding {
225    /// Finding code/ID
226    pub code: String,
227    /// Description
228    pub description: String,
229    /// Severity
230    pub severity: Severity,
231    /// Remediation steps
232    pub remediation: Option<String>,
233}
234
235/// Audit log entry
236#[derive(Debug, Clone, Serialize, Deserialize)]
237pub struct AuditEntry {
238    /// Unique ID
239    pub id: UUID,
240    /// Timestamp
241    pub timestamp: i64,
242    /// Actor (user/agent/system)
243    pub actor: String,
244    /// Action performed
245    pub action: String,
246    /// Resource affected
247    pub resource: String,
248    /// Outcome (success/failure)
249    pub outcome: AuditOutcome,
250    /// Additional context
251    pub context: HashMap<String, serde_json::Value>,
252}
253
254/// Audit outcome
255#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
256pub enum AuditOutcome {
257    /// Action succeeded
258    Success,
259    /// Action failed
260    Failure,
261    /// Action was denied
262    Denied,
263}
264
265/// Compliance provider trait - allows enterprise to add compliance features
266///
267/// Consumer implementation: Basic PII detection and redaction
268/// Enterprise implementation: Full HIPAA/GDPR/FDA signals, encrypted audit logs
269#[async_trait]
270pub trait ComplianceProvider: Send + Sync {
271    /// Provider name
272    fn name(&self) -> &str;
273
274    // === Consumer Features (always available) ===
275
276    /// Scan text for PII (Consumer: basic patterns)
277    async fn scan_pii(&self, text: &str) -> Result<Vec<PiiFinding>>;
278
279    /// Redact PII from text (Consumer: basic redaction)
280    fn redact(&self, text: &str) -> String;
281
282    // === Enterprise Features (return None/empty in consumer) ===
283
284    /// Check whether framework compliance is supported
285    fn supports_framework(&self, _framework: ComplianceFramework) -> bool {
286        false
287    }
288
289    /// Check compliance against a framework (Enterprise only)
290    async fn check_compliance(
291        &self,
292        _framework: ComplianceFramework,
293        _context: &str,
294    ) -> Result<Option<ComplianceCheckResult>> {
295        Ok(None)
296    }
297
298    /// Log an audit entry (Enterprise: encrypted, Consumer: no-op)
299    async fn audit_log(&self, _entry: AuditEntry) -> Result<()> {
300        Ok(())
301    }
302
303    /// Get audit logs (Enterprise only)
304    async fn get_audit_logs(
305        &self,
306        _start: i64,
307        _end: i64,
308        _limit: usize,
309    ) -> Result<Vec<AuditEntry>> {
310        Ok(vec![])
311    }
312
313    /// Run full compliance audit (Enterprise only)
314    async fn run_audit(&self, _auditor: &str) -> Result<Option<ComplianceAuditReport>> {
315        Ok(None)
316    }
317}
318
319/// Full compliance audit report (Enterprise)
320#[derive(Debug, Clone, Serialize, Deserialize)]
321pub struct ComplianceAuditReport {
322    /// Audit ID
323    pub id: UUID,
324    /// Auditor name
325    pub auditor: String,
326    /// Frameworks audited
327    pub frameworks: Vec<ComplianceFramework>,
328    /// Overall compliance percentage
329    pub compliance_percentage: f32,
330    /// Findings by framework
331    pub findings: HashMap<String, Vec<ComplianceFinding>>,
332    /// Generated at
333    pub generated_at: i64,
334}
335
336// ============================================================================
337// DISTRIBUTED EXECUTOR - For Distributed Workloads
338// ============================================================================
339
340/// Node information for distributed execution
341#[derive(Debug, Clone, Serialize, Deserialize)]
342pub struct NodeInfo {
343    /// Node ID
344    pub id: String,
345    /// Node address
346    pub address: String,
347    /// Node status
348    pub status: NodeStatus,
349    /// Available resources
350    pub resources: NodeResources,
351    /// Last heartbeat
352    pub last_heartbeat: i64,
353}
354
355/// Node status
356#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
357pub enum NodeStatus {
358    /// Node is healthy and available
359    Healthy,
360    /// Node is overloaded
361    Overloaded,
362    /// Node is unhealthy/unreachable
363    Unhealthy,
364    /// Node is draining (no new work)
365    Draining,
366}
367
368/// Node resources
369#[derive(Debug, Clone, Serialize, Deserialize)]
370pub struct NodeResources {
371    /// CPU cores available
372    pub cpu_cores: f32,
373    /// Memory available (MB)
374    pub memory_mb: u64,
375    /// GPU devices available
376    pub gpu_devices: u32,
377}
378
379/// Distributed task
380#[derive(Debug, Clone, Serialize, Deserialize)]
381pub struct DistributedTask {
382    /// Task ID
383    pub id: UUID,
384    /// Task type
385    pub task_type: String,
386    /// Task payload
387    pub payload: serde_json::Value,
388    /// Resource requirements
389    pub requirements: NodeResources,
390    /// Priority (higher = more important)
391    pub priority: i32,
392}
393
394/// Distributed task result
395#[derive(Debug, Clone, Serialize, Deserialize)]
396pub struct DistributedTaskResult {
397    /// Task ID
398    pub task_id: UUID,
399    /// Node that executed
400    pub executed_by: String,
401    /// Success status
402    pub success: bool,
403    /// Result data
404    pub result: Option<serde_json::Value>,
405    /// Error if failed
406    pub error: Option<String>,
407    /// Execution time (ms)
408    pub duration_ms: u64,
409}
410
411/// Distributed executor trait - allows enterprise to add distributed execution
412///
413/// Consumer implementation: Single-node execution only
414/// Enterprise implementation: Multi-node coordination, load balancing
415#[async_trait]
416pub trait DistributedExecutor: Send + Sync {
417    /// Executor name
418    fn name(&self) -> &str;
419
420    /// Check if distributed execution is available
421    fn is_distributed(&self) -> bool {
422        false
423    }
424
425    /// Get cluster nodes (Consumer: returns self only)
426    async fn get_nodes(&self) -> Result<Vec<NodeInfo>> {
427        Ok(vec![])
428    }
429
430    /// Submit task for distributed execution
431    /// Consumer: executes locally, Enterprise: distributes to cluster
432    async fn submit_task(&self, task: DistributedTask) -> Result<UUID>;
433
434    /// Get task result
435    async fn get_task_result(&self, task_id: UUID) -> Result<Option<DistributedTaskResult>>;
436
437    /// Wait for task completion
438    async fn wait_for_task(
439        &self,
440        task_id: UUID,
441        timeout_ms: u64,
442    ) -> Result<Option<DistributedTaskResult>>;
443
444    // === Enterprise Features ===
445
446    /// Join a cluster (Enterprise only)
447    async fn join_cluster(&self, _coordinator: &str) -> Result<bool> {
448        Ok(false)
449    }
450
451    /// Leave cluster (Enterprise only)
452    async fn leave_cluster(&self) -> Result<bool> {
453        Ok(false)
454    }
455
456    /// Get cluster status (Enterprise only)
457    async fn cluster_status(&self) -> Result<Option<ClusterStatus>> {
458        Ok(None)
459    }
460}
461
462/// Cluster status (Enterprise)
463#[derive(Debug, Clone, Serialize, Deserialize)]
464pub struct ClusterStatus {
465    /// Cluster name
466    pub name: String,
467    /// Number of nodes
468    pub node_count: usize,
469    /// Healthy node count
470    pub healthy_nodes: usize,
471    /// Total available resources
472    pub total_resources: NodeResources,
473    /// Tasks in queue
474    pub queued_tasks: usize,
475    /// Tasks running
476    pub running_tasks: usize,
477}
478
479// ============================================================================
480// POLICY PROVIDER - For Governance Features
481// ============================================================================
482
483/// Policy rule
484#[derive(Debug, Clone, Serialize, Deserialize)]
485pub struct PolicyRule {
486    /// Rule ID
487    pub id: String,
488    /// Rule name
489    pub name: String,
490    /// Rule type
491    pub rule_type: PolicyRuleType,
492    /// Configuration
493    pub config: serde_json::Value,
494    /// Whether rule is enabled
495    pub enabled: bool,
496}
497
498/// Policy rule types
499#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
500pub enum PolicyRuleType {
501    /// Rate limiting
502    RateLimit,
503    /// Cost cap
504    CostCap,
505    /// Content filtering
506    ContentFilter,
507    /// Tool permission
508    ToolPermission,
509    /// Custom rule
510    Custom,
511}
512
513/// Policy decision
514#[derive(Debug, Clone, Serialize, Deserialize)]
515pub struct PolicyDecision {
516    /// Whether action is allowed
517    pub allowed: bool,
518    /// Reason for decision
519    pub reason: String,
520    /// Rules that matched
521    pub matched_rules: Vec<String>,
522}
523
524/// Policy provider trait - allows enterprise to add governance features
525///
526/// Consumer implementation: No policy enforcement
527/// Enterprise implementation: Rate limits, cost caps, content rules
528#[async_trait]
529pub trait PolicyProvider: Send + Sync {
530    /// Provider name
531    fn name(&self) -> &str;
532
533    /// Check if policy engine is enabled
534    fn is_enabled(&self) -> bool {
535        false
536    }
537
538    /// Check policy for an action (Enterprise only)
539    async fn check_policy(
540        &self,
541        _action: &str,
542        _context: &HashMap<String, serde_json::Value>,
543    ) -> Result<PolicyDecision> {
544        Ok(PolicyDecision {
545            allowed: true,
546            reason: "Policy engine not enabled".to_string(),
547            matched_rules: vec![],
548        })
549    }
550
551    /// Get active rules (Enterprise only)
552    async fn get_rules(&self) -> Result<Vec<PolicyRule>> {
553        Ok(vec![])
554    }
555
556    /// Set a rule (Enterprise only)
557    async fn set_rule(&self, _rule: PolicyRule) -> Result<bool> {
558        Ok(false)
559    }
560
561    /// Delete a rule (Enterprise only)
562    async fn delete_rule(&self, _rule_id: &str) -> Result<bool> {
563        Ok(false)
564    }
565}
566
567// ============================================================================
568// IDENTITY PROVIDER - For User Management Features
569// ============================================================================
570
571/// User identity
572#[derive(Debug, Clone, Serialize, Deserialize)]
573pub struct Identity {
574    /// Identity ID
575    pub id: UUID,
576    /// User handle/name
577    pub handle: String,
578    /// Consent scopes granted
579    pub consents: Vec<ConsentScope>,
580    /// Data retention days
581    pub retention_days: i32,
582    /// Created at
583    pub created_at: i64,
584}
585
586/// Consent scope
587#[derive(Debug, Clone, Serialize, Deserialize)]
588pub struct ConsentScope {
589    /// Scope name
590    pub scope: String,
591    /// Whether granted
592    pub granted: bool,
593    /// Granted at
594    pub granted_at: Option<i64>,
595}
596
597/// Data export request
598#[derive(Debug, Clone, Serialize, Deserialize)]
599pub struct DataExportRequest {
600    /// Request ID
601    pub id: UUID,
602    /// Identity ID
603    pub identity_id: UUID,
604    /// Export format
605    pub format: String,
606    /// Status
607    pub status: DataRequestStatus,
608    /// Download URL (when ready)
609    pub download_url: Option<String>,
610}
611
612/// Data deletion request
613#[derive(Debug, Clone, Serialize, Deserialize)]
614pub struct DataDeletionRequest {
615    /// Request ID
616    pub id: UUID,
617    /// Identity ID
618    pub identity_id: UUID,
619    /// Status
620    pub status: DataRequestStatus,
621    /// Completed at
622    pub completed_at: Option<i64>,
623}
624
625/// Status of data request
626#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
627pub enum DataRequestStatus {
628    /// Request pending
629    Pending,
630    /// Request in progress
631    InProgress,
632    /// Request completed
633    Completed,
634    /// Request failed
635    Failed,
636}
637
638/// Identity provider trait - allows enterprise to add identity management
639///
640/// Consumer implementation: No identity management
641/// Enterprise implementation: GDPR data rights, consent management
642#[async_trait]
643pub trait IdentityProvider: Send + Sync {
644    /// Provider name
645    fn name(&self) -> &str;
646
647    /// Check if identity management is enabled
648    fn is_enabled(&self) -> bool {
649        false
650    }
651
652    /// Get identity by ID (Enterprise only)
653    async fn get_identity(&self, _id: UUID) -> Result<Option<Identity>> {
654        Ok(None)
655    }
656
657    /// Update consent (Enterprise only)
658    async fn update_consent(
659        &self,
660        _identity_id: UUID,
661        _scope: &str,
662        _granted: bool,
663    ) -> Result<bool> {
664        Ok(false)
665    }
666
667    /// Request data export (Enterprise only)
668    async fn request_export(&self, _identity_id: UUID, _format: &str) -> Result<Option<UUID>> {
669        Ok(None)
670    }
671
672    /// Request data deletion (Enterprise only)
673    async fn request_deletion(&self, _identity_id: UUID) -> Result<Option<UUID>> {
674        Ok(None)
675    }
676
677    /// Set retention policy (Enterprise only)
678    async fn set_retention(&self, _identity_id: UUID, _days: i32) -> Result<bool> {
679        Ok(false)
680    }
681}
682
683// ============================================================================
684// DEFAULT IMPLEMENTATIONS (Consumer)
685// ============================================================================
686
687/// Basic learning provider (Consumer) - collects feedback but doesn't train
688pub struct BasicLearningProvider {
689    feedback: std::sync::RwLock<Vec<LearningFeedback>>,
690}
691
692impl BasicLearningProvider {
693    /// Create new basic learning provider
694    pub fn new() -> Self {
695        Self {
696            feedback: std::sync::RwLock::new(Vec::new()),
697        }
698    }
699}
700
701impl Default for BasicLearningProvider {
702    fn default() -> Self {
703        Self::new()
704    }
705}
706
707#[async_trait]
708impl LearningProvider for BasicLearningProvider {
709    fn name(&self) -> &str {
710        "basic-learning"
711    }
712
713    async fn collect_feedback(&self, feedback: LearningFeedback) -> Result<()> {
714        let mut store = self.feedback.write().unwrap();
715        store.push(feedback);
716        // Keep only last 1000 feedback items
717        if store.len() > 1000 {
718            store.remove(0);
719        }
720        Ok(())
721    }
722
723    async fn get_feedback(&self, limit: usize) -> Result<Vec<LearningFeedback>> {
724        let store = self.feedback.read().unwrap();
725        Ok(store.iter().rev().take(limit).cloned().collect())
726    }
727}
728
729/// Basic compliance provider (Consumer) - simple PII detection
730pub struct BasicComplianceProvider {
731    patterns: Vec<(PiiType, regex::Regex)>,
732}
733
734impl BasicComplianceProvider {
735    /// Create new basic compliance provider
736    pub fn new() -> Self {
737        let patterns = vec![
738            (
739                PiiType::Ssn,
740                regex::Regex::new(r"\b\d{3}[-\s]?\d{2}[-\s]?\d{4}\b").unwrap(),
741            ),
742            (
743                PiiType::Email,
744                regex::Regex::new(r"\b[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Z|a-z]{2,}\b").unwrap(),
745            ),
746            (
747                PiiType::Phone,
748                regex::Regex::new(r"\b(\+?1[-.\s]?)?(\(?\d{3}\)?[-.\s]?)?\d{3}[-.\s]?\d{4}\b")
749                    .unwrap(),
750            ),
751            (
752                PiiType::CreditCard,
753                regex::Regex::new(r"\b\d{4}[-\s]?\d{4}[-\s]?\d{4}[-\s]?\d{4}\b").unwrap(),
754            ),
755            (
756                PiiType::ApiKey,
757                regex::Regex::new(r"\b(sk-[a-zA-Z0-9]{32,}|api[_-]?key[_-]?[a-zA-Z0-9]{16,})\b")
758                    .unwrap(),
759            ),
760        ];
761        Self { patterns }
762    }
763}
764
765impl Default for BasicComplianceProvider {
766    fn default() -> Self {
767        Self::new()
768    }
769}
770
771#[async_trait]
772impl ComplianceProvider for BasicComplianceProvider {
773    fn name(&self) -> &str {
774        "basic-compliance"
775    }
776
777    async fn scan_pii(&self, text: &str) -> Result<Vec<PiiFinding>> {
778        let mut findings = Vec::new();
779
780        for (pii_type, pattern) in &self.patterns {
781            for m in pattern.find_iter(text) {
782                findings.push(PiiFinding {
783                    pii_type: pii_type.clone(),
784                    start: m.start(),
785                    end: m.end(),
786                    matched_text: m.as_str().to_string(),
787                    severity: match pii_type {
788                        PiiType::Ssn | PiiType::CreditCard | PiiType::ApiKey => Severity::Critical,
789                        PiiType::Email | PiiType::Phone => Severity::Medium,
790                        _ => Severity::Low,
791                    },
792                    confidence: 0.9,
793                });
794            }
795        }
796
797        Ok(findings)
798    }
799
800    fn redact(&self, text: &str) -> String {
801        let mut result = text.to_string();
802
803        for (pii_type, pattern) in &self.patterns {
804            let replacement = match pii_type {
805                PiiType::Ssn => "[SSN]",
806                PiiType::Email => "[EMAIL]",
807                PiiType::Phone => "[PHONE]",
808                PiiType::CreditCard => "[CREDIT_CARD]",
809                PiiType::ApiKey => "[API_KEY]",
810                _ => "[REDACTED]",
811            };
812            result = pattern.replace_all(&result, replacement).to_string();
813        }
814
815        result
816    }
817}
818
819// ============================================================================
820// EXTENSION REGISTRY
821// ============================================================================
822
823/// Registry for extension providers
824pub struct ExtensionRegistry {
825    /// Learning provider
826    pub learning: Option<Arc<dyn LearningProvider>>,
827    /// Compliance provider
828    pub compliance: Option<Arc<dyn ComplianceProvider>>,
829    /// Distributed executor
830    pub distributed: Option<Arc<dyn DistributedExecutor>>,
831    /// Policy provider
832    pub policy: Option<Arc<dyn PolicyProvider>>,
833    /// Identity provider
834    pub identity: Option<Arc<dyn IdentityProvider>>,
835}
836
837impl ExtensionRegistry {
838    /// Create new registry with default (consumer) providers
839    pub fn new() -> Self {
840        Self {
841            learning: Some(Arc::new(BasicLearningProvider::new())),
842            compliance: Some(Arc::new(BasicComplianceProvider::new())),
843            distributed: None,
844            policy: None,
845            identity: None,
846        }
847    }
848
849    /// Create empty registry (no providers)
850    pub fn empty() -> Self {
851        Self {
852            learning: None,
853            compliance: None,
854            distributed: None,
855            policy: None,
856            identity: None,
857        }
858    }
859
860    /// Set learning provider
861    pub fn with_learning(mut self, provider: Arc<dyn LearningProvider>) -> Self {
862        self.learning = Some(provider);
863        self
864    }
865
866    /// Set compliance provider
867    pub fn with_compliance(mut self, provider: Arc<dyn ComplianceProvider>) -> Self {
868        self.compliance = Some(provider);
869        self
870    }
871
872    /// Set distributed executor
873    pub fn with_distributed(mut self, executor: Arc<dyn DistributedExecutor>) -> Self {
874        self.distributed = Some(executor);
875        self
876    }
877
878    /// Set policy provider
879    pub fn with_policy(mut self, provider: Arc<dyn PolicyProvider>) -> Self {
880        self.policy = Some(provider);
881        self
882    }
883
884    /// Set identity provider
885    pub fn with_identity(mut self, provider: Arc<dyn IdentityProvider>) -> Self {
886        self.identity = Some(provider);
887        self
888    }
889
890    /// Check if enterprise features are available
891    pub fn has_enterprise_features(&self) -> bool {
892        self.learning
893            .as_ref()
894            .map(|l| l.supports_training())
895            .unwrap_or(false)
896            || self
897                .compliance
898                .as_ref()
899                .map(|c| c.supports_framework(ComplianceFramework::Hipaa))
900                .unwrap_or(false)
901            || self
902                .distributed
903                .as_ref()
904                .map(|d| d.is_distributed())
905                .unwrap_or(false)
906            || self.policy.as_ref().map(|p| p.is_enabled()).unwrap_or(false)
907            || self
908                .identity
909                .as_ref()
910                .map(|i| i.is_enabled())
911                .unwrap_or(false)
912    }
913}
914
915impl Default for ExtensionRegistry {
916    fn default() -> Self {
917        Self::new()
918    }
919}
920
921#[cfg(test)]
922mod tests {
923    use super::*;
924
925    #[tokio::test]
926    async fn test_basic_learning_provider() {
927        let provider = BasicLearningProvider::new();
928
929        let feedback = LearningFeedback {
930            response_id: uuid::Uuid::new_v4(),
931            score: 0.8,
932            text: Some("Good response".to_string()),
933            source: FeedbackSource::User,
934            timestamp: chrono::Utc::now().timestamp(),
935        };
936
937        provider.collect_feedback(feedback.clone()).await.unwrap();
938
939        let collected = provider.get_feedback(10).await.unwrap();
940        assert_eq!(collected.len(), 1);
941        assert_eq!(collected[0].score, 0.8);
942    }
943
944    #[tokio::test]
945    async fn test_basic_compliance_provider() {
946        let provider = BasicComplianceProvider::new();
947
948        // Test PII detection
949        let text = "My SSN is 123-45-6789 and email is test@example.com";
950        let findings = provider.scan_pii(text).await.unwrap();
951
952        assert!(findings.iter().any(|f| f.pii_type == PiiType::Ssn));
953        assert!(findings.iter().any(|f| f.pii_type == PiiType::Email));
954
955        // Test redaction
956        let redacted = provider.redact(text);
957        assert!(redacted.contains("[SSN]"));
958        assert!(redacted.contains("[EMAIL]"));
959        assert!(!redacted.contains("123-45-6789"));
960    }
961
962    #[tokio::test]
963    async fn test_training_not_available_in_consumer() {
964        let provider = BasicLearningProvider::new();
965
966        assert!(!provider.supports_training());
967
968        let result = provider.train().await.unwrap();
969        assert!(!result.success);
970        assert!(result.error.is_some());
971    }
972
973    #[test]
974    fn test_extension_registry() {
975        let registry = ExtensionRegistry::new();
976
977        assert!(registry.learning.is_some());
978        assert!(registry.compliance.is_some());
979        assert!(!registry.has_enterprise_features());
980    }
981}
982