fix(prompts): stop compile() crashing on literal $ in templates - #772
fix(prompts): stop compile() crashing on literal $ in templates#772DevMello wants to merge 1 commit into
Conversation
string.Template treats every $ as a placeholder marker, so any stored
prompt containing a dollar sign ("costs $5", JS ${...} snippets)
raised ValueError('Invalid placeholder') at compile time in production
rather than at authoring time. Spaced placeholders like {{ name }} hit
the same crash because the rewrite preserved the whitespace, producing
an invalid placeholder. Escape literal dollars before the {{var}} ->
$var rewrite and let the placeholder regex absorb surrounding
whitespace.
| template_str = re.sub( | ||
| r"\{\{\s*([^}]+?)\s*\}\}", r"$\1", self.prompt.replace("$", "$$") | ||
| ) |
There was a problem hiding this comment.
🟡 Prompts whose placeholder is immediately followed by letters or digits fail to fill in
A placeholder is rewritten into a bare marker without delimiting braces (r"$\1" at src/judgeval/prompts/prompt.py:46), so when a placeholder is directly followed by letters, digits or an underscore the name runs into the following text and filling in the prompt fails with a "missing variable" error.
Impact: Prompts like "Hello {{name}}san" or "{{count}}x" can never be compiled, even when every variable is supplied.
Mechanism: bare $name placeholder swallows adjacent identifier characters
re.sub(r"\{\{\s*([^}]+?)\s*\}\}", r"$\1", ...) turns Hello {{name}}san into Hello $namesan. string.Template parses the identifier greedily, so substitute(name="Ada") raises KeyError('namesan'), which compile() converts to ValueError: Missing required variable: namesan (src/judgeval/prompts/prompt.py:70-74).
Now that literal dollars are escaped up front (self.prompt.replace("$", "$$")), emitting the braced form ${name} is safe and fixes the adjacency case; ${name} is unambiguous to Template.
| template_str = re.sub( | |
| r"\{\{\s*([^}]+?)\s*\}\}", r"$\1", self.prompt.replace("$", "$$") | |
| ) | |
| template_str = re.sub( | |
| r"\{\{\s*([^}]+?)\s*\}\}", r"${\1}", self.prompt.replace("$", "$$") | |
| ) |
Was this helpful? React with 👍 or 👎 to provide feedback.
Prompt.compile()raisedValueError('Invalid placeholder in string')for any prompt containing a literal dollar sign (for example"costs $5") or a spaced placeholder like{{ name }}, because the{{var}}to$varrewrite feedsstring.Templateunescaped. This change escapes literal dollars before the rewrite and lets the placeholder regex absorb surrounding whitespace, so those templates now compile instead of crashing, while templates that already compiled produce identical output. Adds unit tests covering literal$,$$,${x},${{amount}}, spaced placeholders, and the existing missing-variable error.Example: