1use std::collections::HashMap;
2
3use crate::error::ZigError;
4
5pub mod templates {
12 use std::sync::LazyLock;
13
14 pub fn create() -> &'static str {
16 static STRIPPED: LazyLock<&'static str> =
17 LazyLock::new(|| super::strip_front_matter(include_str!("../prompts/create/1_4.md")));
18 *STRIPPED
19 }
20
21 pub fn update() -> &'static str {
23 static STRIPPED: LazyLock<&'static str> =
24 LazyLock::new(|| super::strip_front_matter(include_str!("../prompts/update/1_0.md")));
25 *STRIPPED
26 }
27
28 pub fn config_sidecar() -> &'static str {
31 static STRIPPED: LazyLock<&'static str> = LazyLock::new(|| {
32 super::strip_front_matter(include_str!("../prompts/config-sidecar/1_3.md"))
33 });
34 *STRIPPED
35 }
36
37 pub mod examples {
40 pub const SEQUENTIAL: &str = include_str!("../prompts/examples/sequential.zwf");
41 pub const FAN_OUT: &str = include_str!("../prompts/examples/fan-out.zwf");
42 pub const GENERATOR_CRITIC: &str = include_str!("../prompts/examples/generator-critic.zwf");
43 pub const COORDINATOR_DISPATCHER: &str =
44 include_str!("../prompts/examples/coordinator-dispatcher.zwf");
45 pub const HIERARCHICAL_DECOMPOSITION: &str =
46 include_str!("../prompts/examples/hierarchical-decomposition.zwf");
47 pub const HUMAN_IN_THE_LOOP: &str =
48 include_str!("../prompts/examples/human-in-the-loop.zwf");
49 pub const INTER_AGENT_COMMUNICATION: &str =
50 include_str!("../prompts/examples/inter-agent-communication.zwf");
51 }
52}
53
54const EXAMPLE_DESCRIPTIONS: &[(&str, &str)] = &[
57 (
58 "sequential.zwf",
59 "Sequential Pipeline — blog post workflow (research → draft → edit → SEO)",
60 ),
61 (
62 "fan-out.zwf",
63 "Fan-Out / Gather — PR review with parallel security/performance/design reviewers and synthesis",
64 ),
65 (
66 "generator-critic.zwf",
67 "Generator / Critic — landing page copy with iterative quality scoring loop",
68 ),
69 (
70 "coordinator-dispatcher.zwf",
71 "Coordinator / Dispatcher — support ticket classification routed to specialist handlers",
72 ),
73 (
74 "hierarchical-decomposition.zwf",
75 "Hierarchical Decomposition — feature spec broken into parallel analysis tracks",
76 ),
77 (
78 "human-in-the-loop.zwf",
79 "Human-in-the-Loop — database migration plan with approval gates",
80 ),
81 (
82 "inter-agent-communication.zwf",
83 "Inter-Agent Communication — RFC review with advocate/skeptic/moderator roles",
84 ),
85];
86
87pub fn example_for_pattern(pattern: &str) -> Option<&'static str> {
89 match pattern {
90 "sequential" => Some(templates::examples::SEQUENTIAL),
91 "fan-out" => Some(templates::examples::FAN_OUT),
92 "generator-critic" => Some(templates::examples::GENERATOR_CRITIC),
93 "coordinator-dispatcher" => Some(templates::examples::COORDINATOR_DISPATCHER),
94 "hierarchical-decomposition" => Some(templates::examples::HIERARCHICAL_DECOMPOSITION),
95 "human-in-the-loop" => Some(templates::examples::HUMAN_IN_THE_LOOP),
96 "inter-agent-communication" => Some(templates::examples::INTER_AGENT_COMMUNICATION),
97 _ => None,
98 }
99}
100
101pub fn all_examples() -> Vec<(&'static str, &'static str)> {
103 vec![
104 ("sequential.zwf", templates::examples::SEQUENTIAL),
105 ("fan-out.zwf", templates::examples::FAN_OUT),
106 (
107 "generator-critic.zwf",
108 templates::examples::GENERATOR_CRITIC,
109 ),
110 (
111 "coordinator-dispatcher.zwf",
112 templates::examples::COORDINATOR_DISPATCHER,
113 ),
114 (
115 "hierarchical-decomposition.zwf",
116 templates::examples::HIERARCHICAL_DECOMPOSITION,
117 ),
118 (
119 "human-in-the-loop.zwf",
120 templates::examples::HUMAN_IN_THE_LOOP,
121 ),
122 (
123 "inter-agent-communication.zwf",
124 templates::examples::INTER_AGENT_COMMUNICATION,
125 ),
126 ]
127}
128
129pub fn strip_front_matter(content: &str) -> &str {
150 let rest = if let Some(r) = content.strip_prefix("---\n") {
152 r
153 } else if let Some(r) = content.strip_prefix("---\r\n") {
154 r
155 } else {
156 return content;
157 };
158
159 let mut offset = 0;
162 while offset <= rest.len() {
163 let remainder = &rest[offset..];
164 let (line, advance) = match remainder.find('\n') {
165 Some(nl) => (&remainder[..nl], nl + 1),
166 None => (remainder, remainder.len()),
167 };
168 let trimmed = line.strip_suffix('\r').unwrap_or(line);
169 if trimmed == "---" {
170 let body_start = offset + advance;
171 let body = &rest[body_start..];
172 return body
175 .strip_prefix("\r\n")
176 .or_else(|| body.strip_prefix('\n'))
177 .unwrap_or(body);
178 }
179 if advance == 0 {
180 break;
181 }
182 offset += advance;
183 }
184
185 content
188}
189
190pub fn examples_reference_block() -> String {
195 let mut out = String::new();
196 out.push_str(
197 "Here are examples of agent orchestration patterns, for reference. \
198 Read the relevant file(s) before designing or editing a workflow so \
199 the structure matches a proven pattern:\n\n",
200 );
201 for (filename, description) in EXAMPLE_DESCRIPTIONS {
202 out.push_str("- `~/.zig/examples/");
203 out.push_str(filename);
204 out.push_str("` — ");
205 out.push_str(description);
206 out.push('\n');
207 }
208 out
209}
210
211pub fn write_examples_to_global_dir() -> Result<(), ZigError> {
214 let dir = crate::paths::ensure_global_examples_dir()?;
215 for (filename, content) in all_examples() {
216 let path = dir.join(filename);
217 std::fs::write(&path, content)
218 .map_err(|e| ZigError::Io(format!("failed to write {}: {e}", path.display())))?;
219 }
220 Ok(())
221}
222
223pub fn render(template: &str, vars: &HashMap<&str, &str>) -> String {
228 let mut result = template.to_string();
229 for (&key, &value) in vars {
230 let placeholder = format!("{{{{{key}}}}}");
231 result = result.replace(&placeholder, value);
232 }
233 result
234}
235
236#[cfg(test)]
237#[path = "prompt_tests.rs"]
238mod tests;