lean_ctx/core/
protocol.rs1use std::path::Path;
2
3pub fn shorten_path(path: &str) -> String {
4 let p = Path::new(path);
5 if let Some(name) = p.file_name() {
6 return name.to_string_lossy().to_string();
7 }
8 path.to_string()
9}
10
11pub fn format_savings(original: usize, compressed: usize) -> String {
12 let saved = original.saturating_sub(compressed);
13 if original == 0 {
14 return "0 tok saved".to_string();
15 }
16 let pct = (saved as f64 / original as f64 * 100.0).round() as usize;
17 format!("[{saved} tok saved ({pct}%)]")
18}
19
20pub struct InstructionTemplate {
21 pub code: &'static str,
22 pub full: &'static str,
23}
24
25const TEMPLATES: &[InstructionTemplate] = &[
26 InstructionTemplate {
27 code: "ACT1",
28 full: "Act immediately, report result in one line",
29 },
30 InstructionTemplate {
31 code: "BRIEF",
32 full: "Summarize approach in 1-2 lines, then act",
33 },
34 InstructionTemplate {
35 code: "FULL",
36 full: "Outline approach, consider edge cases, then act",
37 },
38 InstructionTemplate {
39 code: "DELTA",
40 full: "Only show changed lines, not full files",
41 },
42 InstructionTemplate {
43 code: "NOREPEAT",
44 full: "Never repeat known context. Reference cached files by Fn ID",
45 },
46 InstructionTemplate {
47 code: "STRUCT",
48 full: "Use notation, not sentences. Changes: +line/-line/~line",
49 },
50 InstructionTemplate {
51 code: "1LINE",
52 full: "One line per action. Summarize, don't explain",
53 },
54 InstructionTemplate {
55 code: "NODOC",
56 full: "Don't add comments that narrate what code does",
57 },
58 InstructionTemplate {
59 code: "ACTFIRST",
60 full: "Execute tool calls immediately. Never narrate before acting",
61 },
62 InstructionTemplate {
63 code: "QUALITY",
64 full: "Never skip edge case analysis or error handling to save tokens",
65 },
66 InstructionTemplate {
67 code: "NOMOCK",
68 full: "Never use mock data, fake values, or placeholder code",
69 },
70 InstructionTemplate {
71 code: "FREF",
72 full: "Reference files by Fn refs only, never full paths",
73 },
74 InstructionTemplate {
75 code: "DIFF",
76 full: "For code changes: show only diff lines, not full files",
77 },
78 InstructionTemplate {
79 code: "ABBREV",
80 full: "Use abbreviations: fn, cfg, impl, deps, req, res, ctx, err",
81 },
82 InstructionTemplate {
83 code: "SYMBOLS",
84 full: "Use TDD notation: +=add -=remove ~=modify ->=returns ok/fail for status",
85 },
86];
87
88pub fn instruction_decoder_block() -> String {
90 let mut lines = vec!["INSTRUCTION CODES:".to_string()];
91 for t in TEMPLATES {
92 lines.push(format!(" {} = {}", t.code, t.full));
93 }
94 lines.join("\n")
95}
96
97pub fn encode_instructions(complexity: &str) -> String {
100 match complexity {
101 "mechanical" => "MODE: ACT1 DELTA 1LINE | BUDGET: <=50 tokens, 1 line answer".to_string(),
102 "simple" => "MODE: BRIEF DELTA 1LINE | BUDGET: <=100 tokens, structured".to_string(),
103 "standard" => "MODE: BRIEF DELTA NOREPEAT STRUCT | BUDGET: <=200 tokens".to_string(),
104 "complex" => {
105 "MODE: FULL QUALITY NOREPEAT STRUCT FREF DIFF | BUDGET: <=500 tokens".to_string()
106 }
107 "architectural" => {
108 "MODE: FULL QUALITY NOREPEAT STRUCT FREF | BUDGET: unlimited".to_string()
109 }
110 _ => "MODE: BRIEF | BUDGET: <=200 tokens".to_string(),
111 }
112}
113
114pub fn encode_instructions_with_snr(complexity: &str, compression_pct: f64) -> String {
116 let snr = if compression_pct > 0.0 {
117 1.0 - (compression_pct / 100.0)
118 } else {
119 1.0
120 };
121 let base = encode_instructions(complexity);
122 format!("{base} | SNR: {snr:.2}")
123}
124
125#[cfg(test)]
126mod tests {
127 use super::*;
128
129 #[test]
130 fn decoder_block_contains_all_codes() {
131 let block = instruction_decoder_block();
132 for t in TEMPLATES {
133 assert!(
134 block.contains(t.code),
135 "decoder should contain code {}",
136 t.code
137 );
138 }
139 }
140
141 #[test]
142 fn encoded_instructions_are_compact() {
143 use super::super::tokens::count_tokens;
144 let full = "TASK COMPLEXITY: mechanical\nMinimal reasoning needed. Act immediately, report result in one line. Show only changed lines, not full files.";
145 let encoded = encode_instructions("mechanical");
146 assert!(
147 count_tokens(&encoded) <= count_tokens(full),
148 "encoded ({}) should be <= full ({})",
149 count_tokens(&encoded),
150 count_tokens(full)
151 );
152 }
153
154 #[test]
155 fn all_complexity_levels_encode() {
156 for level in &["mechanical", "standard", "architectural"] {
157 let encoded = encode_instructions(level);
158 assert!(encoded.starts_with("MODE:"), "should start with MODE:");
159 }
160 }
161}