diff --git a/langfuse/model.py b/langfuse/model.py index 8618b548..20ab4397 100644 --- a/langfuse/model.py +++ b/langfuse/model.py @@ -83,7 +83,20 @@ def get_langchain_prompt(self): @staticmethod def _get_langchain_prompt_string(content: str): - return re.sub(r"{{\s*(\w+)\s*}}", r"{\g<1>}", content) + # replace single `{` with the temporary replacement content + content = re.sub(r'(?', content) + + # replace single `}` with the temporary replacement content + content = re.sub(r'(?', content) + + # replace all double braces with single braces for langchain vars + content = re.sub(r"{{\s*(\w+)\s*}}", r"{\g<1>}", content) + + # replace temporary replacements with double braces + content = re.sub('', '{{', content) + content = re.sub('', '}}', content) + + return content @staticmethod def _compile_template_string(content: str, data: Dict[str, Any] = {}) -> str: diff --git a/tests/test_langchain.py b/tests/test_langchain.py index e92fcb10..9407ecff 100644 --- a/tests/test_langchain.py +++ b/tests/test_langchain.py @@ -1659,7 +1659,23 @@ def test_get_langchain_prompt_with_jinja2(): langfuse_prompt.get_langchain_prompt() == 'this is a {template} template that should remain unchanged: {{ handle_text(payload["Name"], "Name is") }}' ) + +def test_get_langchain_prompt_with_braces(): + langfuse = Langfuse() + + prompt = 'This is a {{test}} with another {{test} that leads to {this}' + langfuse.create_prompt( + name="test_braces", + prompt=prompt, + labels=["production"], + ) + + langfuse_prompt = langfuse.get_prompt("test_braces") + assert ( + langfuse_prompt.get_langchain_prompt() + == 'This is a {test} with another {{test}} that leads to {{this}}' + ) def test_get_langchain_prompt(): langfuse = Langfuse()