lean_ctx/tools/
ctx_feedback.rs1use crate::core::adaptive_mode_policy::AdaptiveModePolicyStore;
2use crate::core::llm_feedback::{LlmFeedbackEvent, LlmFeedbackStore};
3
4pub fn record(event: LlmFeedbackEvent) -> Result<String, String> {
5 LlmFeedbackStore::record(event.clone())?;
6 let mut policy = AdaptiveModePolicyStore::load();
7 policy.update_from_feedback(&event);
8 policy.save()?;
9 Ok("feedback recorded".to_string())
10}
11
12pub fn status() -> String {
13 let s = LlmFeedbackStore::status();
14 format!(
15 "ctx_feedback status\n path: {}\n bytes: {}\n retention: max_events={} max_bytes={}",
16 s.path.display(),
17 s.bytes,
18 s.max_events,
19 s.max_bytes
20 )
21}
22
23pub fn report(limit: usize) -> String {
24 let s = LlmFeedbackStore::summarize(limit);
25 if s.total_events == 0 {
26 return "No LLM feedback recorded yet.".to_string();
27 }
28
29 let mut lines = vec![
30 format!("LLM Feedback Report (last {limit} events)"),
31 format!(" total_events: {}", s.total_events),
32 format!(" avg_output_ratio: {:.2}", s.avg_output_ratio),
33 format!(" max_output_tokens: {}", s.max_output_tokens),
34 format!(" max_output_ratio: {:.2}", s.max_output_ratio),
35 ];
36 if let Some(ms) = s.avg_latency_ms {
37 lines.push(format!(" avg_latency_ms: {:.0}", ms));
38 }
39
40 if !s.by_model.is_empty() {
41 lines.push(" by_model:".to_string());
42 for (model, m) in s.by_model.iter().take(10) {
43 let mut row = format!(
44 " {model}: n={} avg_ratio={:.2} max_out={}",
45 m.events, m.avg_output_ratio, m.max_output_tokens
46 );
47 if let Some(ms) = m.avg_latency_ms {
48 row.push_str(&format!(" avg_ms={:.0}", ms));
49 }
50 lines.push(row);
51 }
52 }
53
54 lines.join("\n")
55}
56
57pub fn json(limit: usize) -> String {
58 let status = LlmFeedbackStore::status();
59 let summary = LlmFeedbackStore::summarize(limit);
60 let recent = LlmFeedbackStore::recent(limit.min(200));
61 serde_json::json!({
62 "status": status,
63 "summary": summary,
64 "recent": recent,
65 })
66 .to_string()
67}
68
69pub fn reset() -> String {
70 match (LlmFeedbackStore::reset(), AdaptiveModePolicyStore::reset()) {
71 (Ok(()), Ok(())) => "LLM feedback has been reset.".to_string(),
72 (a, b) => {
73 let mut errs = Vec::new();
74 if let Err(e) = a {
75 errs.push(format!("feedback: {e}"));
76 }
77 if let Err(e) = b {
78 errs.push(format!("policy: {e}"));
79 }
80 format!("Error resetting feedback: {}", errs.join("; "))
81 }
82 }
83}