Skip to main content

ralph/
prompts.rs

1//! Prompt template loading, rendering, and validation utilities.
2//!
3//! Responsibilities:
4//! - Expose a minimal public prompt API for integration tests and external callers.
5//! - Keep prompt composition and registry details internal to the crate.
6//!
7//! Not handled:
8//! - CLI argument parsing or queue mutation.
9//! - Direct access to prompt registry internals (see `prompts_internal`).
10//!
11//! Invariants/assumptions:
12//! - Public exports here are intentional and minimal.
13
14use crate::cli::scan::ScanMode;
15use crate::contracts::{Config, ProjectType, ScanPromptVersion};
16use crate::prompts_internal;
17use anyhow::Result;
18use std::path::Path;
19
20pub const REPOPROMPT_REQUIRED_INSTRUCTION: &str =
21    prompts_internal::util::REPOPROMPT_REQUIRED_INSTRUCTION;
22pub const REPOPROMPT_CONTEXT_BUILDER_PLANNING_INSTRUCTION: &str =
23    prompts_internal::util::REPOPROMPT_CONTEXT_BUILDER_PLANNING_INSTRUCTION;
24pub const PHASE3_COMPLETION_GUIDANCE_FINAL: &str =
25    prompts_internal::iteration::PHASE3_COMPLETION_GUIDANCE_FINAL;
26
27pub(crate) const ITERATION_CONTEXT_REFINEMENT: &str =
28    prompts_internal::iteration::ITERATION_CONTEXT_REFINEMENT;
29pub(crate) const ITERATION_COMPLETION_BLOCK: &str =
30    prompts_internal::iteration::ITERATION_COMPLETION_BLOCK;
31pub(crate) const PHASE3_COMPLETION_GUIDANCE_NONFINAL: &str =
32    prompts_internal::iteration::PHASE3_COMPLETION_GUIDANCE_NONFINAL;
33
34pub(crate) fn prompts_reference_readme(repo_root: &Path) -> Result<bool> {
35    prompts_internal::prompts_reference_readme(repo_root)
36}
37
38pub(crate) fn load_scan_prompt(
39    repo_root: &Path,
40    version: ScanPromptVersion,
41    mode: ScanMode,
42) -> Result<String> {
43    prompts_internal::scan::load_scan_prompt(repo_root, version, mode)
44}
45
46pub(crate) fn render_scan_prompt(
47    template: &str,
48    focus: &str,
49    mode: ScanMode,
50    version: ScanPromptVersion,
51    project_type: ProjectType,
52    config: &Config,
53) -> Result<String> {
54    prompts_internal::scan::render_scan_prompt(template, focus, mode, version, project_type, config)
55}
56
57pub(crate) fn load_task_builder_prompt(repo_root: &Path) -> Result<String> {
58    prompts_internal::task_builder::load_task_builder_prompt(repo_root)
59}
60
61pub(crate) fn load_task_decompose_prompt(repo_root: &Path) -> Result<String> {
62    prompts_internal::task_decompose::load_task_decompose_prompt(repo_root)
63}
64
65pub(crate) fn render_task_builder_prompt(
66    template: &str,
67    user_request: &str,
68    hint_tags: &str,
69    hint_scope: &str,
70    project_type: ProjectType,
71    config: &Config,
72) -> Result<String> {
73    prompts_internal::task_builder::render_task_builder_prompt(
74        template,
75        user_request,
76        hint_tags,
77        hint_scope,
78        project_type,
79        config,
80    )
81}
82
83#[allow(clippy::too_many_arguments)]
84pub(crate) fn render_task_decompose_prompt(
85    template: &str,
86    source_mode: &str,
87    source_request: &str,
88    source_task_json: &str,
89    attach_target_json: &str,
90    max_depth: u8,
91    max_children: usize,
92    max_nodes: usize,
93    child_policy: crate::commands::task::DecompositionChildPolicy,
94    with_dependencies: bool,
95    project_type: ProjectType,
96    config: &Config,
97) -> Result<String> {
98    prompts_internal::task_decompose::render_task_decompose_prompt(
99        template,
100        source_mode,
101        source_request,
102        source_task_json,
103        attach_target_json,
104        max_depth,
105        max_children,
106        max_nodes,
107        child_policy,
108        with_dependencies,
109        project_type,
110        config,
111    )
112}
113
114pub(crate) fn load_task_updater_prompt(repo_root: &Path) -> Result<String> {
115    prompts_internal::task_updater::load_task_updater_prompt(repo_root)
116}
117
118pub(crate) fn render_task_updater_prompt(
119    template: &str,
120    task_id: &str,
121    project_type: ProjectType,
122    config: &Config,
123) -> Result<String> {
124    prompts_internal::task_updater::render_task_updater_prompt(
125        template,
126        task_id,
127        project_type,
128        config,
129    )
130}
131
132pub(crate) fn wrap_with_repoprompt_requirement(prompt: &str, required: bool) -> String {
133    prompts_internal::util::wrap_with_repoprompt_requirement(prompt, required)
134}
135
136pub(crate) fn wrap_with_instruction_files(
137    repo_root: &Path,
138    prompt: &str,
139    config: &Config,
140) -> Result<String> {
141    prompts_internal::wrap_with_instruction_files(repo_root, prompt, config)
142}
143
144pub(crate) fn instruction_file_warnings(repo_root: &Path, config: &Config) -> Vec<String> {
145    prompts_internal::instruction_file_warnings(repo_root, config)
146}
147
148pub(crate) fn load_worker_prompt(repo_root: &Path) -> Result<String> {
149    prompts_internal::worker::load_worker_prompt(repo_root)
150}
151
152pub(crate) fn render_worker_prompt(
153    template: &str,
154    task_id: &str,
155    project_type: ProjectType,
156    config: &Config,
157) -> Result<String> {
158    prompts_internal::worker::render_worker_prompt(template, task_id, project_type, config)
159}
160
161pub fn load_worker_phase1_prompt(repo_root: &Path) -> Result<String> {
162    prompts_internal::worker_phases::load_worker_phase1_prompt(repo_root)
163}
164
165pub fn load_worker_phase2_prompt(repo_root: &Path) -> Result<String> {
166    prompts_internal::worker_phases::load_worker_phase2_prompt(repo_root)
167}
168
169pub fn load_worker_phase2_handoff_prompt(repo_root: &Path) -> Result<String> {
170    prompts_internal::worker_phases::load_worker_phase2_handoff_prompt(repo_root)
171}
172
173pub fn load_worker_phase3_prompt(repo_root: &Path) -> Result<String> {
174    prompts_internal::worker_phases::load_worker_phase3_prompt(repo_root)
175}
176
177pub fn load_worker_single_phase_prompt(repo_root: &Path) -> Result<String> {
178    prompts_internal::worker_phases::load_worker_single_phase_prompt(repo_root)
179}
180
181#[allow(clippy::too_many_arguments)]
182pub(crate) fn render_worker_phase1_prompt(
183    template: &str,
184    base_prompt: &str,
185    iteration_context: &str,
186    task_refresh_instruction: &str,
187    task_id: &str,
188    total_phases: u8,
189    plan_path: &str,
190    repoprompt_plan_required: bool,
191    repoprompt_tool_injection: bool,
192    config: &Config,
193) -> Result<String> {
194    prompts_internal::worker_phases::render_worker_phase1_prompt(
195        template,
196        base_prompt,
197        iteration_context,
198        task_refresh_instruction,
199        task_id,
200        total_phases,
201        plan_path,
202        repoprompt_plan_required,
203        repoprompt_tool_injection,
204        config,
205    )
206}
207
208#[allow(clippy::too_many_arguments)]
209pub(crate) fn render_worker_phase2_prompt(
210    template: &str,
211    base_prompt: &str,
212    plan: &str,
213    checklist: &str,
214    iteration_context: &str,
215    iteration_completion_block: &str,
216    task_id: &str,
217    total_phases: u8,
218    repoprompt_tool_injection: bool,
219    config: &Config,
220) -> Result<String> {
221    prompts_internal::worker_phases::render_worker_phase2_prompt(
222        template,
223        base_prompt,
224        plan,
225        checklist,
226        iteration_context,
227        iteration_completion_block,
228        task_id,
229        total_phases,
230        repoprompt_tool_injection,
231        config,
232    )
233}
234
235#[allow(clippy::too_many_arguments)]
236pub(crate) fn render_worker_phase2_handoff_prompt(
237    template: &str,
238    base_prompt: &str,
239    plan: &str,
240    checklist: &str,
241    iteration_context: &str,
242    iteration_completion_block: &str,
243    task_id: &str,
244    total_phases: u8,
245    repoprompt_tool_injection: bool,
246    config: &Config,
247) -> Result<String> {
248    prompts_internal::worker_phases::render_worker_phase2_handoff_prompt(
249        template,
250        base_prompt,
251        plan,
252        checklist,
253        iteration_context,
254        iteration_completion_block,
255        task_id,
256        total_phases,
257        repoprompt_tool_injection,
258        config,
259    )
260}
261
262#[allow(clippy::too_many_arguments)]
263pub(crate) fn render_worker_phase3_prompt(
264    template: &str,
265    base_prompt: &str,
266    review_body: &str,
267    phase2_final: &str,
268    task_id: &str,
269    checklist: &str,
270    iteration_context: &str,
271    iteration_completion_block: &str,
272    phase3_completion_guidance: &str,
273    total_phases: u8,
274    repoprompt_tool_injection: bool,
275    config: &Config,
276) -> Result<String> {
277    prompts_internal::worker_phases::render_worker_phase3_prompt(
278        template,
279        base_prompt,
280        review_body,
281        phase2_final,
282        task_id,
283        checklist,
284        iteration_context,
285        iteration_completion_block,
286        phase3_completion_guidance,
287        total_phases,
288        repoprompt_tool_injection,
289        config,
290    )
291}
292
293#[allow(clippy::too_many_arguments)]
294pub(crate) fn render_worker_single_phase_prompt(
295    template: &str,
296    base_prompt: &str,
297    checklist: &str,
298    iteration_context: &str,
299    iteration_completion_block: &str,
300    task_id: &str,
301    repoprompt_tool_injection: bool,
302    config: &Config,
303) -> Result<String> {
304    prompts_internal::worker_phases::render_worker_single_phase_prompt(
305        template,
306        base_prompt,
307        checklist,
308        iteration_context,
309        iteration_completion_block,
310        task_id,
311        repoprompt_tool_injection,
312        config,
313    )
314}
315
316pub fn load_completion_checklist(repo_root: &Path) -> Result<String> {
317    prompts_internal::review::load_completion_checklist(repo_root)
318}
319
320pub fn load_phase2_handoff_checklist(repo_root: &Path) -> Result<String> {
321    prompts_internal::review::load_phase2_handoff_checklist(repo_root)
322}
323
324pub fn load_iteration_checklist(repo_root: &Path) -> Result<String> {
325    prompts_internal::review::load_iteration_checklist(repo_root)
326}
327
328pub fn render_completion_checklist(
329    template: &str,
330    task_id: &str,
331    config: &Config,
332    parallel_worker_mode: bool,
333) -> Result<String> {
334    prompts_internal::review::render_completion_checklist(
335        template,
336        task_id,
337        config,
338        parallel_worker_mode,
339    )
340}
341
342pub fn render_phase2_handoff_checklist(template: &str, config: &Config) -> Result<String> {
343    prompts_internal::review::render_phase2_handoff_checklist(template, config)
344}
345
346pub fn render_iteration_checklist(
347    template: &str,
348    task_id: &str,
349    config: &Config,
350) -> Result<String> {
351    prompts_internal::review::render_iteration_checklist(template, task_id, config)
352}
353
354pub(crate) fn load_code_review_prompt(repo_root: &Path) -> Result<String> {
355    prompts_internal::review::load_code_review_prompt(repo_root)
356}
357
358pub(crate) fn render_code_review_prompt(
359    template: &str,
360    task_id: &str,
361    project_type: ProjectType,
362    config: &Config,
363) -> Result<String> {
364    prompts_internal::review::render_code_review_prompt(template, task_id, project_type, config)
365}