|
| 1 | +# prompt_utils.py |
| 2 | +import os |
| 3 | +import re |
| 4 | +import sys |
| 5 | +from functools import lru_cache |
| 6 | + |
| 7 | +from jinja2 import Environment, FileSystemBytecodeCache, FileSystemLoader, Template |
| 8 | + |
| 9 | + |
| 10 | +def refine(text: str) -> str: |
| 11 | + if sys.platform == "win32": |
| 12 | + text = re.sub(r"\bexecute_bash\b", "execute_powershell", text, flags=re.IGNORECASE) |
| 13 | + text = re.sub(r"(?<!execute_)(?<!_)\bbash\b", "powershell", text, flags=re.IGNORECASE) |
| 14 | + return text |
| 15 | + |
| 16 | +@lru_cache(maxsize=64) |
| 17 | +def _get_env(prompt_dir: str) -> Environment: |
| 18 | + if not prompt_dir: |
| 19 | + raise ValueError("prompt_dir is required") |
| 20 | + # BytecodeCache avoids reparsing templates across processes |
| 21 | + cache_folder = os.path.join(prompt_dir, ".jinja_cache") |
| 22 | + os.makedirs(cache_folder, exist_ok=True) |
| 23 | + bcc = FileSystemBytecodeCache(directory=cache_folder) |
| 24 | + env = Environment( |
| 25 | + loader=FileSystemLoader(prompt_dir), |
| 26 | + bytecode_cache=bcc, |
| 27 | + autoescape=False, |
| 28 | + ) |
| 29 | + # Optional: expose refine as a filter so templates can use {{ text|refine }} |
| 30 | + env.filters["refine"] = refine |
| 31 | + return env |
| 32 | + |
| 33 | +@lru_cache(maxsize=256) |
| 34 | +def _get_template(prompt_dir: str, template_name: str) -> Template: |
| 35 | + env = _get_env(prompt_dir) |
| 36 | + try: |
| 37 | + return env.get_template(template_name) |
| 38 | + except Exception: |
| 39 | + raise FileNotFoundError(f"Prompt file {os.path.join(prompt_dir, template_name)} not found") |
| 40 | + |
| 41 | +def render_template(prompt_dir: str, template_name: str, **ctx) -> str: |
| 42 | + tpl = _get_template(prompt_dir, template_name) |
| 43 | + return refine(tpl.render(**ctx).strip()) |
| 44 | + |
| 45 | +# Convenience wrappers keeping old names/semantics |
| 46 | +def render_system_message(prompt_dir: str, system_prompt_filename: str = "system_prompt.j2", **ctx) -> str: |
| 47 | + return render_template(prompt_dir, system_prompt_filename, **ctx) |
| 48 | + |
| 49 | +def render_initial_user_message(prompt_dir: str, **ctx) -> str: |
| 50 | + return render_template(prompt_dir, "user_prompt.j2", **ctx) |
| 51 | + |
| 52 | +def render_additional_info(prompt_dir: str, **ctx) -> str: |
| 53 | + return render_template(prompt_dir, "additional_info.j2", **ctx) |
| 54 | + |
| 55 | +def render_microagent_info(prompt_dir: str, **ctx) -> str: |
| 56 | + return render_template(prompt_dir, "microagent_info.j2", **ctx) |
0 commit comments