Skip to content

Commit c48ed76

Browse files
author
Zvi Fried
committed
feat/general-refinement - refactor: move prompts to Markdown files with Jinja2 templating
✨ MAJOR REFACTORING: Externalized Prompts for Better Maintainability 🎯 **What Changed:** - **Extracted all hardcoded prompts** to separate Markdown files in src/prompts/ - **Added Jinja2 templating** for dynamic variable substitution - **Created PromptLoader utility** for loading and rendering templates - **Comprehensive test coverage** for prompt loading functionality 📁 **New Structure:** - src/prompts/judge_coding_plan.md - Main evaluation prompt - src/prompts/judge_code_change.md - Code review prompt - src/prompts/research_validation.md - Research quality validation - src/mcp_as_a_judge/prompt_loader.py - Template loading utility - tests/test_prompt_loader.py - Full test coverage 🚀 **Benefits:** - **Easy editing**: Prompts now in readable Markdown format - **Version control**: Track prompt changes separately from code - **Maintainability**: No more giant f-strings in Python code - **Flexibility**: Jinja2 templating for dynamic content - **Testability**: Isolated prompt testing and validation - **Collaboration**: Non-developers can edit prompts easily ✅ **Quality Assurance:** - All existing tests pass (28/28) - New comprehensive prompt loader tests - Backward compatibility maintained - No functional changes to evaluation logic This refactoring makes the codebase much more maintainable and allows for easier prompt iteration and improvement! 🎉
1 parent 8ba53d6 commit c48ed76

File tree

9 files changed

+665
-271
lines changed

9 files changed

+665
-271
lines changed

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@
2626
- 🔍 **Enforcing research and best practices** before implementation
2727
- ⚖️ **Creating a collaborative AI-human workflow** for better software quality
2828

29-
## 🚀 **This MCP Will Change Many Developers' Lives!**
29+
## 🚀 **Vibe Coding doesn't have to be frustrating**
3030

3131
### **What It Prevents:**
3232

pyproject.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ classifiers = [
2828
]
2929
requires-python = ">=3.12"
3030
dependencies = [
31+
"jinja2>=3.1.6",
3132
"mcp[cli]>=1.13.0",
3233
"pydantic>=2.0.0",
3334
]
Lines changed: 153 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,153 @@
1+
"""Prompt loader utility for loading and rendering Jinja2 templates."""
2+
3+
from pathlib import Path
4+
from typing import Any, Dict
5+
6+
from jinja2 import Environment, FileSystemLoader, Template
7+
8+
9+
class PromptLoader:
10+
"""Loads and renders prompt templates using Jinja2."""
11+
12+
def __init__(self, prompts_dir: Path | None = None):
13+
"""Initialize the prompt loader.
14+
15+
Args:
16+
prompts_dir: Directory containing prompt templates.
17+
Defaults to src/prompts relative to this file.
18+
"""
19+
if prompts_dir is None:
20+
# Default to src/prompts directory
21+
current_dir = Path(__file__).parent
22+
prompts_dir = current_dir.parent / "prompts"
23+
24+
self.prompts_dir = prompts_dir
25+
self.env = Environment(
26+
loader=FileSystemLoader(str(prompts_dir)),
27+
trim_blocks=True,
28+
lstrip_blocks=True,
29+
)
30+
31+
def load_template(self, template_name: str) -> Template:
32+
"""Load a Jinja2 template by name.
33+
34+
Args:
35+
template_name: Name of the template file (e.g., 'judge_coding_plan.md')
36+
37+
Returns:
38+
Jinja2 Template object
39+
40+
Raises:
41+
FileNotFoundError: If template file doesn't exist
42+
"""
43+
try:
44+
return self.env.get_template(template_name)
45+
except Exception as e:
46+
raise FileNotFoundError(f"Template '{template_name}' not found in {self.prompts_dir}") from e
47+
48+
def render_prompt(self, template_name: str, **kwargs: Any) -> str:
49+
"""Load and render a prompt template with the given variables.
50+
51+
Args:
52+
template_name: Name of the template file
53+
**kwargs: Variables to pass to the template
54+
55+
Returns:
56+
Rendered prompt string
57+
58+
Raises:
59+
FileNotFoundError: If template file doesn't exist
60+
"""
61+
template = self.load_template(template_name)
62+
return template.render(**kwargs)
63+
64+
def render_judge_coding_plan(
65+
self,
66+
user_requirements: str,
67+
plan: str,
68+
design: str,
69+
research: str,
70+
context: str = "",
71+
response_schema: str = "",
72+
) -> str:
73+
"""Render the judge coding plan prompt.
74+
75+
Args:
76+
user_requirements: User's requirements
77+
plan: Coding plan to evaluate
78+
design: System design
79+
research: Research findings
80+
context: Additional context
81+
response_schema: JSON schema for response format
82+
83+
Returns:
84+
Rendered prompt string
85+
"""
86+
return self.render_prompt(
87+
"judge_coding_plan.md",
88+
user_requirements=user_requirements,
89+
plan=plan,
90+
design=design,
91+
research=research,
92+
context=context,
93+
response_schema=response_schema,
94+
)
95+
96+
def render_judge_code_change(
97+
self,
98+
user_requirements: str,
99+
code_change: str,
100+
file_path: str,
101+
change_description: str,
102+
response_schema: str = "",
103+
) -> str:
104+
"""Render the judge code change prompt.
105+
106+
Args:
107+
user_requirements: User's requirements
108+
code_change: Code content to review
109+
file_path: Path to the file
110+
change_description: Description of the change
111+
response_schema: JSON schema for response format
112+
113+
Returns:
114+
Rendered prompt string
115+
"""
116+
return self.render_prompt(
117+
"judge_code_change.md",
118+
user_requirements=user_requirements,
119+
code_change=code_change,
120+
file_path=file_path,
121+
change_description=change_description,
122+
response_schema=response_schema,
123+
)
124+
125+
def render_research_validation(
126+
self,
127+
user_requirements: str,
128+
plan: str,
129+
design: str,
130+
research: str,
131+
) -> str:
132+
"""Render the research validation prompt.
133+
134+
Args:
135+
user_requirements: User's requirements
136+
plan: Coding plan
137+
design: System design
138+
research: Research to validate
139+
140+
Returns:
141+
Rendered prompt string
142+
"""
143+
return self.render_prompt(
144+
"research_validation.md",
145+
user_requirements=user_requirements,
146+
plan=plan,
147+
design=design,
148+
research=research,
149+
)
150+
151+
152+
# Global instance for easy access
153+
prompt_loader = PromptLoader()

0 commit comments

Comments
 (0)