Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 6 additions & 1 deletion langfuse/model.py
Original file line number Diff line number Diff line change
Expand Up @@ -163,7 +163,12 @@ def get_langchain_prompt(self) -> Any:
def _get_langchain_prompt_string(content: str) -> str:
json_escaped_content = BasePromptClient._escape_json_for_langchain(content)

return re.sub(r"{{\s*(\w+)\s*}}", r"{\g<1>}", json_escaped_content)
# Match any Langfuse variable name between {{ }} (Langfuse allows names
# with hyphens, spaces, unicode, etc.), not just \w+. The character class
# excludes braces and both quote styles so already-escaped JSON (which
# _escape_json_for_langchain doubles to {{"...}} or {{'...}}) is left
# untouched.
return re.sub(r"{{\s*([^{}\"']+?)\s*}}", r"{\g<1>}", json_escaped_content)

@staticmethod
def _escape_json_for_langchain(text: str) -> str:
Expand Down
42 changes: 42 additions & 0 deletions tests/unit/test_prompt_compilation.py
Original file line number Diff line number Diff line change
Expand Up @@ -255,6 +255,48 @@ def test_normal_variables_with_nested_json(self):

assert formatted_prompt == expected

def test_get_langchain_prompt_preserves_special_variable_names(self):
"""Variable names with hyphens/spaces/unicode must convert to langchain
single-brace placeholders instead of being left as unusable {{...}}."""
prompt = TextPromptClient(
Prompt_Text(
type="text",
name="special_var_names",
version=1,
config={},
tags=[],
labels=[],
prompt="Hello {{user-name}}!",
)
)

langchain_prompt_string = prompt.get_langchain_prompt()

assert langchain_prompt_string == "Hello {user-name}!"

langchain_prompt = PromptTemplate.from_template(langchain_prompt_string)
assert langchain_prompt.input_variables == ["user-name"]
assert langchain_prompt.format(**{"user-name": "Ada"}) == "Hello Ada!"

def test_get_langchain_prompt_leaves_quoted_json_escaped(self):
"""Brace-pairs wrapping JSON (single- or double-quoted) must stay doubled
for langchain, not be converted as if they were variables."""
prompt = TextPromptClient(
Prompt_Text(
type="text",
name="json_braces",
version=1,
config={},
tags=[],
labels=[],
prompt="Reply with {'key': 'value'} and {{name}}",
)
)

result = prompt.get_langchain_prompt()

assert result == "Reply with {{'key': 'value'}} and {name}"

def test_mixed_variables_with_nested_json(self):
"""Test normal variables (double braces) and Langchain variables (single braces) with nested JSON."""
prompt_string = """Normal variable: {{user_name}}
Expand Down