1use async_trait::async_trait;
3use lean_ctx_protocol::CapabilityManifestV1;
4
5use crate::types::{
6 AgentEnvelope, AgentMessageRequest, CompressionRequest, CompressionResult, ConfigProposal,
7 ConfigTuningRequest, ConnectorJob, DeliveryEntry, DeliveryRecord, DeliveryRecordResult,
8 DeliveryStats, EfficiencyAnalysis, EfficiencySample, ExperimentRequest, ExperimentResult,
9 IntentDecision, IntentRequest, MetricPoint, Observation, OclaCapability, OclaResult, Outcome,
10 ResponseOptimizationRequest, ResponseOptimizationResult, SavingsEvidence, ScheduledJob,
11 UsageRecord,
12};
13
14pub trait OclaService: Send + Sync {
16 fn capability(&self) -> OclaCapability;
17
18 fn manifest(&self) -> OclaResult<CapabilityManifestV1> {
20 Err(crate::types::OclaError::Unavailable(self.capability().kind))
21 }
22}
23
24#[async_trait]
25pub trait ObservationHook: OclaService {
26 async fn observe(&self, observation: Observation) -> OclaResult<()>;
27}
28
29#[async_trait]
30pub trait UsageSink: OclaService {
31 async fn record_usage(&self, usage: UsageRecord) -> OclaResult<()>;
32}
33
34#[async_trait]
35pub trait MetricsExporter: OclaService {
36 async fn export_metrics(&self, metrics: Vec<MetricPoint>) -> OclaResult<()>;
37}
38
39pub trait SavingsLedger: OclaService {
40 fn record_savings(&self, evidence: SavingsEvidence) -> OclaResult<String>;
41
42 fn project_savings(&self, evidence: SavingsEvidence) -> OclaResult<String>;
45}
46
47pub trait IntentClassifier: OclaService {
48 fn classify_intent(&self, request: IntentRequest) -> OclaResult<IntentDecision>;
49}
50
51pub trait OutcomeTracker: OclaService {
52 fn record_outcome(&self, outcome: Outcome) -> OclaResult<()>;
53}
54
55pub trait CompressionProvider: OclaService {
56 fn compress(&self, request: CompressionRequest) -> OclaResult<CompressionResult>;
57}
58
59#[async_trait]
60pub trait ResponseOptimizer: OclaService {
61 async fn optimize_response(
62 &self,
63 request: ResponseOptimizationRequest,
64 ) -> OclaResult<ResponseOptimizationResult>;
65}
66
67pub trait EfficiencyAnalyzer: OclaService {
68 fn analyze_efficiency(&self, sample: EfficiencySample) -> OclaResult<EfficiencyAnalysis>;
69}
70
71pub trait ConfigTuner: OclaService {
72 fn propose_tuning(&self, request: ConfigTuningRequest) -> OclaResult<ConfigProposal>;
73}
74
75pub trait ExperimentRunner: OclaService {
76 fn run_experiment(&self, request: ExperimentRequest) -> OclaResult<ExperimentResult>;
77}
78
79pub trait ConnectorScheduler: OclaService {
80 fn schedule_connector(&self, job: ConnectorJob) -> OclaResult<ScheduledJob>;
81}
82
83pub trait AgentGateway: OclaService {
84 fn relay_agent(&self, envelope: AgentEnvelope) -> OclaResult<AgentEnvelope>;
85 fn route_message(&self, request: &AgentMessageRequest) -> OclaResult<String>;
86}
87
88pub trait DeliveryRegistry: OclaService {
89 fn check_scoped_delivery(
91 &self,
92 blake3: &[u8; 12],
93 path: &str,
94 scope: &crate::delivery_scope::DeliveryScopeV1,
95 requester_agent_id: &str,
96 requester_conversation_id: Option<&str>,
97 ) -> Option<DeliveryRecord>;
98
99 fn check_delivery(
100 &self,
101 blake3: &[u8; 12],
102 mtime: u64,
103 path: &str,
104 requester_agent_id: Option<&str>,
105 requester_conversation_id: Option<&str>,
106 ) -> Option<DeliveryRecord>;
107 fn record_stub_served(&self, record: &DeliveryRecord, stub_tokens: u64);
108 fn record_delivery(&self, entry: DeliveryEntry) -> DeliveryRecordResult;
109 fn delivery_stats(&self) -> DeliveryStats;
110}
111
112#[cfg(test)]
113mod tests {
114 use super::*;
115 use crate::types::OclaCapabilityKind;
116
117 struct UndeclaredService {
118 kind: OclaCapabilityKind,
119 }
120
121 impl OclaService for UndeclaredService {
122 fn capability(&self) -> OclaCapability {
123 OclaCapability::available(self.kind)
124 }
125 }
126
127 #[test]
128 fn missing_manifest_is_unavailable_for_every_capability_kind() {
129 for kind in OclaCapabilityKind::ALL {
130 assert!(matches!(
131 UndeclaredService { kind }.manifest(),
132 Err(crate::types::OclaError::Unavailable(actual)) if actual == kind
133 ));
134 }
135 }
136
137 #[test]
138 fn every_public_trait_is_object_safe() {
139 fn assert_object_safe<T: ?Sized>() {}
140 assert_object_safe::<dyn ObservationHook>();
141 assert_object_safe::<dyn UsageSink>();
142 assert_object_safe::<dyn MetricsExporter>();
143 assert_object_safe::<dyn SavingsLedger>();
144 assert_object_safe::<dyn IntentClassifier>();
145 assert_object_safe::<dyn OutcomeTracker>();
146 assert_object_safe::<dyn CompressionProvider>();
147 assert_object_safe::<dyn ResponseOptimizer>();
148 assert_object_safe::<dyn EfficiencyAnalyzer>();
149 assert_object_safe::<dyn ConfigTuner>();
150 assert_object_safe::<dyn ExperimentRunner>();
151 assert_object_safe::<dyn ConnectorScheduler>();
152 assert_object_safe::<dyn AgentGateway>();
153 assert_object_safe::<dyn DeliveryRegistry>();
154 }
155}