ai_agent/constants/
output_styles.rs1use std::collections::HashMap;
6
7#[derive(Debug, Clone, PartialEq)]
9pub enum OutputStyleSource {
10 BuiltIn,
11 Plugin,
12 PolicySettings,
13 UserSettings,
14 ProjectSettings,
15}
16
17impl OutputStyleSource {
18 pub fn as_str(&self) -> &str {
19 match self {
20 OutputStyleSource::BuiltIn => "built-in",
21 OutputStyleSource::Plugin => "plugin",
22 OutputStyleSource::PolicySettings => "policySettings",
23 OutputStyleSource::UserSettings => "userSettings",
24 OutputStyleSource::ProjectSettings => "projectSettings",
25 }
26 }
27}
28
29#[derive(Debug, Clone)]
31pub struct OutputStyleConfig {
32 pub name: String,
33 pub description: String,
34 pub prompt: String,
35 pub source: OutputStyleSource,
36 pub keep_coding_instructions: Option<bool>,
37 pub force_for_plugin: Option<bool>,
38}
39
40impl OutputStyleConfig {
41 pub fn new(name: &str, description: &str, prompt: &str) -> Self {
42 Self {
43 name: name.to_string(),
44 description: description.to_string(),
45 prompt: prompt.to_string(),
46 source: OutputStyleSource::BuiltIn,
47 keep_coding_instructions: None,
48 force_for_plugin: None,
49 }
50 }
51
52 pub fn with_keep_coding_instructions(mut self, keep: bool) -> Self {
53 self.keep_coding_instructions = Some(keep);
54 self
55 }
56
57 pub fn with_source(mut self, source: OutputStyleSource) -> Self {
58 self.source = source;
59 self
60 }
61}
62
63pub const DEFAULT_OUTPUT_STYLE_NAME: &str = "default";
65
66pub const EXPLANATORY_FEATURE_PROMPT: &str = r#"## Insights
68In order to encourage learning, before and after writing code, always provide brief educational explanations about implementation choices using (with backticks):
69"`* Insight ─────────────────────────────────────`
70[2-3 key educational points]
71`─────────────────────────────────────────────────`"
72
73These insights should be included in the conversation, not in the codebase. You should generally focus on interesting insights that are specific to the codebase or the code you just wrote, rather than general programming concepts."#;
74
75pub fn get_output_style_config() -> HashMap<String, Option<OutputStyleConfig>> {
77 let mut styles = HashMap::new();
78
79 styles.insert(DEFAULT_OUTPUT_STYLE_NAME.to_string(), None);
81
82 let explanatory_prompt = format!(
84 "You are an interactive CLI tool that helps users with software engineering tasks. In addition to software engineering tasks, you should provide educational insights about the codebase along the way.\n\nYou should be clear and educational, providing helpful explanations while remaining focused on the task. Balance educational content with task completion. When providing insights, you may exceed typical length constraints, but remain focused and relevant.\n\n# Explanatory Style Active\n{}",
85 EXPLANATORY_FEATURE_PROMPT
86 );
87
88 styles.insert(
89 "Explanatory".to_string(),
90 Some(
91 OutputStyleConfig::new(
92 "Explanatory",
93 "Claude explains its implementation choices and codebase patterns",
94 &explanatory_prompt,
95 )
96 .with_keep_coding_instructions(true),
97 ),
98 );
99
100 let learning_prompt = format!(
102 "You are an interactive CLI tool that helps users with software engineering tasks. In addition to software engineering tasks, you should help users learn more about the codebase through hands-on practice and educational insights.\n\nYou should be collaborative and encouraging. Balance task completion with learning by requesting user input for meaningful design decisions while handling routine implementation yourself.\n\n# Learning Style Active\n## Requesting Human Contributions\nIn order to encourage learning, ask the human to contribute 2-10 line code pieces when generating 20+ lines involving:\n- Design decisions (error handling, data structures)\n- Business logic with multiple valid approaches\n- Key algorithms or interface definitions\n\n## Insights\n{}",
103 EXPLANATORY_FEATURE_PROMPT
104 );
105
106 styles.insert(
107 "Learning".to_string(),
108 Some(
109 OutputStyleConfig::new(
110 "Learning",
111 "Claude pauses and asks you to write small pieces of code for hands-on practice",
112 &learning_prompt,
113 )
114 .with_keep_coding_instructions(true),
115 ),
116 );
117
118 styles
119}
120
121pub fn get_builtin_style_names() -> Vec<&'static str> {
123 vec![DEFAULT_OUTPUT_STYLE_NAME, "Explanatory", "Learning"]
124}
125
126pub fn is_valid_style_name(name: &str) -> bool {
128 get_builtin_style_names().contains(&name) || name == DEFAULT_OUTPUT_STYLE_NAME
129}
130
131#[cfg(test)]
132mod tests {
133 use super::*;
134
135 #[test]
136 fn test_default_style() {
137 let styles = get_output_style_config();
138 assert!(styles.get(DEFAULT_OUTPUT_STYLE_NAME).is_some());
139 assert!(styles.get(DEFAULT_OUTPUT_STYLE_NAME).unwrap().is_none());
140 }
141
142 #[test]
143 fn test_explanatory_style() {
144 let styles = get_output_style_config();
145 let explanatory = styles.get("Explanatory").unwrap();
146 assert!(explanatory.is_some());
147 let config = explanatory.as_ref().unwrap();
148 assert_eq!(config.name, "Explanatory");
149 assert!(config.keep_coding_instructions.unwrap_or(false));
150 }
151
152 #[test]
153 fn test_learning_style() {
154 let styles = get_output_style_config();
155 let learning = styles.get("Learning").unwrap();
156 assert!(learning.is_some());
157 let config = learning.as_ref().unwrap();
158 assert_eq!(config.name, "Learning");
159 }
160
161 #[test]
162 fn test_valid_style_names() {
163 assert!(is_valid_style_name("default"));
164 assert!(is_valid_style_name("Explanatory"));
165 assert!(is_valid_style_name("Learning"));
166 assert!(!is_valid_style_name("Invalid"));
167 }
168}