lean_ctx/core/ocla/builtin/
response_optimizer.rs1use crate::core::ocla::traits::{OclaService, ResponseOptimizer};
8use crate::core::ocla::types::{
9 OclaCapability, OclaCapabilityKind, OclaResult, ResponseOptimizationRequest,
10 ResponseOptimizationResult,
11};
12use crate::core::ocla_bus::{self, OclaEvent};
13
14pub struct BuiltinResponseOptimizer;
15
16impl BuiltinResponseOptimizer {
17 pub fn new() -> Self {
18 Self
19 }
20}
21
22impl Default for BuiltinResponseOptimizer {
23 fn default() -> Self {
24 Self::new()
25 }
26}
27
28impl OclaService for BuiltinResponseOptimizer {
29 fn capability(&self) -> OclaCapability {
30 OclaCapability::available(OclaCapabilityKind::ResponseOptimizer)
31 }
32}
33
34impl ResponseOptimizer for BuiltinResponseOptimizer {
35 fn optimize_response(
36 &self,
37 request: ResponseOptimizationRequest,
38 ) -> OclaResult<ResponseOptimizationResult> {
39 let decision = crate::proxy::response_optimizer::optimize_response(&request);
40
41 ocla_bus::emit(OclaEvent::ResponseOptimized {
42 cache_hit: decision.cache_hit,
43 is_duplicate: decision.is_duplicate,
44 tokens_saved: decision.tokens_saved,
45 });
46
47 Ok(ResponseOptimizationResult {
48 response_ref: request.response_ref.clone(),
49 delivered_tokens: delivered_tokens(&request, &decision),
50 recovery_ref: decision
51 .cache_hit
52 .then(|| format!("cache:{:016x}", decision.cache_key)),
53 })
54 }
55}
56
57fn delivered_tokens(
58 request: &ResponseOptimizationRequest,
59 decision: &crate::proxy::response_optimizer::OptimizationDecision,
60) -> u64 {
61 if decision.cache_hit {
62 return 0;
63 }
64
65 let original = request.original_tokens;
66 let target = request.target_tokens.min(original);
67 if decision.is_duplicate {
68 let dedup_factor = target;
69 return original
70 .saturating_mul(dedup_factor)
71 .checked_div(original.max(1))
72 .unwrap_or(dedup_factor);
73 }
74
75 target
76}
77
78#[cfg(test)]
79mod tests {
80 use super::*;
81 use crate::core::ocla::types::OclaRequestContext;
82
83 fn req(tag: &str, original: u64, target: u64) -> ResponseOptimizationRequest {
89 ResponseOptimizationRequest {
90 context: OclaRequestContext {
91 request_id: "r1".into(),
92 session_id: format!("s1-{tag}"),
93 agent_id: "agent-test".into(),
94 content_ref: "ref:test".into(),
95 tenant_id: None,
96 trace_id: "tr-unit".into(),
97 },
98 response_ref: format!("resp:{tag}"),
99 original_tokens: original,
100 target_tokens: target,
101 }
102 }
103
104 #[test]
105 fn optimization_caps_at_target() {
106 let _iso = crate::core::data_dir::isolated_data_dir();
112 let opt = BuiltinResponseOptimizer::new();
113 let result = opt.optimize_response(req("caps", 1000, 400)).unwrap();
114 assert_eq!(result.delivered_tokens, 400);
115 }
116
117 #[test]
118 fn preserves_response_ref() {
119 let _iso = crate::core::data_dir::isolated_data_dir();
122 let opt = BuiltinResponseOptimizer::new();
123 let result = opt.optimize_response(req("preserves", 500, 300)).unwrap();
124 assert_eq!(result.response_ref, "resp:preserves");
125 }
126
127 #[test]
128 fn registry_path_reports_cache_as_zero_delivery() {
129 let _iso = crate::core::data_dir::isolated_data_dir();
132 let registry = crate::core::ocla::registry::OclaRegistry::with_builtins();
133 let mut request = req("registry", 1000, 400);
134 request.context.session_id = "registry-response-optimizer".into();
135 request.response_ref = "resp:registry-response-optimizer".into();
136 let first = registry
137 .response_optimizer
138 .optimize_response(request.clone())
139 .unwrap();
140 let cached = registry
141 .response_optimizer
142 .optimize_response(request)
143 .unwrap();
144
145 assert_eq!(first.delivered_tokens, 400);
146 assert_eq!(cached.delivered_tokens, 0);
147 }
148
149 #[test]
150 fn duplicate_delivery_uses_target_ratio() {
151 let request = req("duplicate", 1000, 250);
152 let decision = crate::proxy::response_optimizer::OptimizationDecision {
153 cache_hit: false,
154 is_duplicate: true,
155 cache_key: 0,
156 tokens_saved: 750,
157 source: crate::proxy::response_optimizer::OptimizationSource::Dedup,
158 };
159
160 assert_eq!(delivered_tokens(&request, &decision), 250);
161 }
162}