1use super::techniques::{
8 ComplexityLevel, PromptingTechnique, TaskCharacteristic, TechniqueCategory, TechniqueMetadata,
9};
10#[cfg(feature = "knowledge")]
11use crate::knowledge::bks_pks::{BehavioralKnowledgeCache, BehavioralTruth};
12use anyhow::Result;
13use std::collections::HashMap;
14use std::sync::Arc;
15use tokio::sync::Mutex;
16
17pub struct TechniqueLibrary {
19 techniques: HashMap<PromptingTechnique, TechniqueMetadata>,
20 bks_cache: Option<Arc<Mutex<BehavioralKnowledgeCache>>>,
21}
22
23impl TechniqueLibrary {
24 pub fn new() -> Self {
26 let mut techniques = HashMap::new();
27
28 techniques.insert(
30 PromptingTechnique::RolePlaying,
31 TechniqueMetadata::new(
32 PromptingTechnique::RolePlaying,
33 TechniqueCategory::RoleAssignment,
34 "Role Playing",
35 "Assign expert role to elicit domain-specific knowledge",
36 "You are a {role} with expertise in {domain}. ",
37 vec![
38 TaskCharacteristic::MultiStepReasoning,
39 TaskCharacteristic::CodeGeneration,
40 TaskCharacteristic::AlgorithmicProblem,
41 ],
42 0.0, ComplexityLevel::Simple,
44 true,
45 ),
46 );
47
48 techniques.insert(
50 PromptingTechnique::EmotionPrompting,
51 TechniqueMetadata::new(
52 PromptingTechnique::EmotionPrompting,
53 TechniqueCategory::EmotionalStimulus,
54 "Emotion Prompting",
55 "Add emotional cues to increase engagement",
56 "This is an important {task_type} that requires {quality}. ",
57 vec![
58 TaskCharacteristic::MultiStepReasoning,
59 TaskCharacteristic::NumericalCalculation,
60 ],
61 0.0,
62 ComplexityLevel::Simple,
63 true,
64 ),
65 );
66
67 techniques.insert(
68 PromptingTechnique::StressPrompting,
69 TechniqueMetadata::new(
70 PromptingTechnique::StressPrompting,
71 TechniqueCategory::EmotionalStimulus,
72 "Stress Prompting",
73 "Induce moderate stress conditions for focus",
74 "This task requires immediate attention and precision. Time is limited. ",
75 vec![
76 TaskCharacteristic::LogicalDeduction,
77 TaskCharacteristic::AlgorithmicProblem,
78 ],
79 0.0,
80 ComplexityLevel::Simple,
81 true,
82 ),
83 );
84
85 techniques.insert(
87 PromptingTechnique::ChainOfThought,
88 TechniqueMetadata::new(
89 PromptingTechnique::ChainOfThought,
90 TechniqueCategory::Reasoning,
91 "Chain-of-Thought",
92 "Require explicit step-by-step reasoning",
93 "Think step by step. Show your reasoning process clearly. ",
94 vec![
95 TaskCharacteristic::MultiStepReasoning,
96 TaskCharacteristic::LogicalDeduction,
97 TaskCharacteristic::NumericalCalculation,
98 ],
99 0.0, ComplexityLevel::Simple,
101 true,
102 ),
103 );
104
105 techniques.insert(
106 PromptingTechnique::LogicOfThought,
107 TechniqueMetadata::new(
108 PromptingTechnique::LogicOfThought,
109 TechniqueCategory::Reasoning,
110 "Logic-of-Thought",
111 "Embed propositional logic for formal reasoning",
112 "Use propositional logic notation. Let P, Q, R represent propositions. Apply logical inference rules. ",
113 vec![
114 TaskCharacteristic::LogicalDeduction,
115 TaskCharacteristic::MultiStepReasoning,
116 ],
117 0.8, ComplexityLevel::Advanced,
119 true,
120 ),
121 );
122
123 techniques.insert(
124 PromptingTechnique::LeastToMost,
125 TechniqueMetadata::new(
126 PromptingTechnique::LeastToMost,
127 TechniqueCategory::Reasoning,
128 "Least-to-Most",
129 "Decompose into simpler sub-problems progressively",
130 "Break this problem into simpler sub-problems. Solve from simplest to most complex. ",
131 vec![
132 TaskCharacteristic::MultiStepReasoning,
133 TaskCharacteristic::AlgorithmicProblem,
134 ],
135 0.5, ComplexityLevel::Moderate,
137 true,
138 ),
139 );
140
141 techniques.insert(
142 PromptingTechnique::ThreadOfThought,
143 TechniqueMetadata::new(
144 PromptingTechnique::ThreadOfThought,
145 TechniqueCategory::Reasoning,
146 "Thread-of-Thought",
147 "Summarize long contexts progressively",
148 "Summarize the context progressively as you reason through it. Maintain a running summary. ",
149 vec![
150 TaskCharacteristic::LongContextSummarization,
151 TaskCharacteristic::MultiStepReasoning,
152 ],
153 0.7, ComplexityLevel::Advanced,
155 true,
156 ),
157 );
158
159 techniques.insert(
160 PromptingTechnique::PlanAndSolve,
161 TechniqueMetadata::new(
162 PromptingTechnique::PlanAndSolve,
163 TechniqueCategory::Reasoning,
164 "Plan-and-Solve",
165 "Generate execution plan first, then solve step by step",
166 "First, devise a plan. Then, solve the problem step by step according to the plan. ",
167 vec![
168 TaskCharacteristic::MultiStepReasoning,
169 TaskCharacteristic::LogicalDeduction,
170 TaskCharacteristic::AlgorithmicProblem,
171 ],
172 0.5, ComplexityLevel::Moderate,
174 true,
175 ),
176 );
177
178 techniques.insert(
179 PromptingTechnique::SkeletonOfThought,
180 TechniqueMetadata::new(
181 PromptingTechnique::SkeletonOfThought,
182 TechniqueCategory::Reasoning,
183 "Skeleton-of-Thought",
184 "Generate skeleton, then fill details",
185 "First, generate a skeleton outline. Then, fill in the details for each part. ",
186 vec![
187 TaskCharacteristic::CreativeGeneration,
188 TaskCharacteristic::CodeGeneration,
189 ],
190 0.7, ComplexityLevel::Advanced,
192 true,
193 ),
194 );
195
196 techniques.insert(
197 PromptingTechnique::ScratchpadPrompting,
198 TechniqueMetadata::new(
199 PromptingTechnique::ScratchpadPrompting,
200 TechniqueCategory::Reasoning,
201 "Scratchpad Prompting",
202 "Provide draft space for intermediate steps",
203 "Use the following scratchpad format for intermediate calculations:\n\
204 <scratchpad>\n\
205 [Your work here]\n\
206 </scratchpad>\n",
207 vec![
208 TaskCharacteristic::NumericalCalculation,
209 TaskCharacteristic::AlgorithmicProblem,
210 ],
211 0.0,
212 ComplexityLevel::Simple,
213 true,
214 ),
215 );
216
217 techniques.insert(
219 PromptingTechnique::DecomposedPrompting,
220 TechniqueMetadata::new(
221 PromptingTechnique::DecomposedPrompting,
222 TechniqueCategory::Others,
223 "Decomposed Prompting",
224 "Break into sub-tasks explicitly",
225 "Decompose this task into independent sub-tasks. Solve each sub-task separately. ",
226 vec![
227 TaskCharacteristic::MultiStepReasoning,
228 TaskCharacteristic::AlgorithmicProblem,
229 ],
230 0.5,
231 ComplexityLevel::Moderate,
232 true,
233 ),
234 );
235
236 techniques.insert(
237 PromptingTechnique::IgnoreIrrelevantConditions,
238 TechniqueMetadata::new(
239 PromptingTechnique::IgnoreIrrelevantConditions,
240 TechniqueCategory::Others,
241 "Ignore Irrelevant Conditions",
242 "Detect and disregard noise in the problem",
243 "Identify and ignore any irrelevant information. Focus only on what's essential. ",
244 vec![
245 TaskCharacteristic::LogicalDeduction,
246 TaskCharacteristic::MultiStepReasoning,
247 ],
248 0.6,
249 ComplexityLevel::Moderate,
250 true,
251 ),
252 );
253
254 techniques.insert(
255 PromptingTechnique::HighlightedCoT,
256 TechniqueMetadata::new(
257 PromptingTechnique::HighlightedCoT,
258 TechniqueCategory::Others,
259 "Highlighted CoT",
260 "Highlight essential information before reasoning",
261 "First, highlight the essential information. Then, reason step by step based on the highlights. ",
262 vec![
263 TaskCharacteristic::MultiStepReasoning,
264 TaskCharacteristic::LogicalDeduction,
265 ],
266 0.5,
267 ComplexityLevel::Moderate,
268 true,
269 ),
270 );
271
272 techniques.insert(
273 PromptingTechnique::SkillsInContext,
274 TechniqueMetadata::new(
275 PromptingTechnique::SkillsInContext,
276 TechniqueCategory::Others,
277 "Skills-in-Context",
278 "Compose basic skills for complex tasks",
279 "Identify the basic skills required. Compose them systematically to solve the task. ",
280 vec![
281 TaskCharacteristic::AlgorithmicProblem,
282 TaskCharacteristic::CodeGeneration,
283 ],
284 0.7,
285 ComplexityLevel::Advanced,
286 true,
287 ),
288 );
289
290 techniques.insert(
291 PromptingTechnique::AutomaticInformationFiltering,
292 TechniqueMetadata::new(
293 PromptingTechnique::AutomaticInformationFiltering,
294 TechniqueCategory::Others,
295 "Automatic Information Filtering",
296 "Preprocess to remove irrelevant information",
297 "Filter the input to retain only relevant information before processing. ",
298 vec![
299 TaskCharacteristic::LongContextSummarization,
300 TaskCharacteristic::LogicalDeduction,
301 ],
302 0.6,
303 ComplexityLevel::Moderate,
304 true,
305 ),
306 );
307
308 Self {
309 techniques,
310 bks_cache: None,
311 }
312 }
313
314 pub fn with_bks(mut self, bks_cache: Arc<Mutex<BehavioralKnowledgeCache>>) -> Self {
316 self.bks_cache = Some(bks_cache);
317 self
318 }
319
320 pub fn get(&self, technique: &PromptingTechnique) -> Option<&TechniqueMetadata> {
322 self.techniques.get(technique)
323 }
324
325 pub fn get_all(&self) -> Vec<&TechniqueMetadata> {
327 self.techniques.values().collect()
328 }
329
330 pub fn get_by_seal_quality(&self, seal_quality: f32) -> Vec<&TechniqueMetadata> {
332 self.techniques
333 .values()
334 .filter(|t| t.min_seal_quality <= seal_quality)
335 .collect()
336 }
337
338 pub fn get_by_category(&self, category: TechniqueCategory) -> Vec<&TechniqueMetadata> {
340 self.techniques
341 .values()
342 .filter(|t| t.category == category)
343 .collect()
344 }
345
346 pub async fn get_bks_recommended_techniques(
351 &self,
352 cluster_id: &str,
353 ) -> Result<Vec<PromptingTechnique>> {
354 if let Some(ref bks_cache) = self.bks_cache {
355 let bks = bks_cache.lock().await;
356
357 let truths = bks.get_matching_truths(cluster_id);
360
361 let mut recommended = Vec::new();
362 for truth in truths {
363 if let Some(technique) = self.parse_technique_from_truth(truth) {
365 recommended.push(technique);
366 }
367 }
368
369 Ok(recommended)
370 } else {
371 Ok(Vec::new())
372 }
373 }
374
375 fn parse_technique_from_truth(&self, truth: &BehavioralTruth) -> Option<PromptingTechnique> {
377 let text = format!("{} {}", truth.rule, truth.rationale);
380
381 for (technique_enum, metadata) in &self.techniques {
382 if text.contains(&metadata.name) || text.contains(technique_enum.to_str()) {
384 return Some(technique_enum.clone());
385 }
386 }
387
388 None
389 }
390
391 pub fn count_by_complexity(&self, level: ComplexityLevel) -> usize {
393 self.techniques
394 .values()
395 .filter(|t| t.complexity_level == level)
396 .count()
397 }
398}
399
400impl Default for TechniqueLibrary {
401 fn default() -> Self {
402 Self::new()
403 }
404}
405
406#[cfg(test)]
407mod tests {
408 use super::*;
409
410 #[test]
411 fn test_library_contains_all_15_techniques() {
412 let library = TechniqueLibrary::new();
413 assert_eq!(library.techniques.len(), 15);
414 }
415
416 #[test]
417 fn test_library_categories() {
418 let library = TechniqueLibrary::new();
419
420 assert_eq!(
421 library
422 .get_by_category(TechniqueCategory::RoleAssignment)
423 .len(),
424 1
425 );
426 assert_eq!(
427 library
428 .get_by_category(TechniqueCategory::EmotionalStimulus)
429 .len(),
430 2
431 );
432 assert_eq!(
433 library.get_by_category(TechniqueCategory::Reasoning).len(),
434 7
435 );
436 assert_eq!(library.get_by_category(TechniqueCategory::Others).len(), 5);
437 }
438
439 #[test]
440 fn test_seal_quality_filtering() {
441 let library = TechniqueLibrary::new();
442
443 let low_quality = library.get_by_seal_quality(0.3);
445 assert!(low_quality.iter().all(|t| t.min_seal_quality <= 0.3));
446
447 let high_quality = library.get_by_seal_quality(0.9);
449 assert_eq!(high_quality.len(), 15); }
451
452 #[test]
453 fn test_technique_string_conversion() {
454 assert_eq!(
455 PromptingTechnique::parse_id("chain_of_thought").unwrap(),
456 PromptingTechnique::ChainOfThought
457 );
458 assert_eq!(
459 PromptingTechnique::parse_id("CoT").unwrap(),
460 PromptingTechnique::ChainOfThought
461 );
462 assert_eq!(
463 PromptingTechnique::ChainOfThought.to_str(),
464 "chain_of_thought"
465 );
466 }
467}