Skip to content

Commit d6bef40

Browse files
authored
fix(prompts): escape json in get_langchain_prompt (#1226)
1 parent 24a9624 commit d6bef40

File tree

2 files changed

+622
-3
lines changed

2 files changed

+622
-3
lines changed

langfuse/model.py

Lines changed: 69 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -156,7 +156,75 @@ def get_langchain_prompt(self):
156156

157157
@staticmethod
158158
def _get_langchain_prompt_string(content: str):
159-
return re.sub(r"{{\s*(\w+)\s*}}", r"{\g<1>}", content)
159+
json_escaped_content = BasePromptClient._escape_json_for_langchain(content)
160+
161+
return re.sub(r"{{\s*(\w+)\s*}}", r"{\g<1>}", json_escaped_content)
162+
163+
@staticmethod
164+
def _escape_json_for_langchain(text: str) -> str:
165+
"""Escapes every curly-brace that is part of a JSON object by doubling it.
166+
167+
A curly brace is considered “JSON-related” when, after skipping any
168+
immediate whitespace, the next non-whitespace character is a single
169+
or double quote.
170+
171+
Braces that are already doubled (e.g. {{variable}} placeholders) are
172+
left untouched.
173+
174+
Parameters
175+
----------
176+
text : str
177+
The input string that may contain JSON snippets.
178+
179+
Returns:
180+
-------
181+
str
182+
The string with JSON-related braces doubled.
183+
"""
184+
out = [] # collected characters
185+
stack = [] # True = “this { belongs to JSON”, False = normal “{”
186+
i, n = 0, len(text)
187+
188+
while i < n:
189+
ch = text[i]
190+
191+
# ---------- opening brace ----------
192+
if ch == "{":
193+
# leave existing “{{ …” untouched
194+
if i + 1 < n and text[i + 1] == "{":
195+
out.append("{{")
196+
i += 2
197+
continue
198+
199+
# look ahead to find the next non-space character
200+
j = i + 1
201+
while j < n and text[j].isspace():
202+
j += 1
203+
204+
is_json = j < n and text[j] in {"'", '"'}
205+
out.append("{{" if is_json else "{")
206+
stack.append(is_json) # remember how this “{” was treated
207+
i += 1
208+
continue
209+
210+
# ---------- closing brace ----------
211+
elif ch == "}":
212+
# leave existing “… }}” untouched
213+
if i + 1 < n and text[i + 1] == "}":
214+
out.append("}}")
215+
i += 2
216+
continue
217+
218+
is_json = stack.pop() if stack else False
219+
out.append("}}" if is_json else "}")
220+
i += 1
221+
continue
222+
223+
# ---------- any other character ----------
224+
out.append(ch)
225+
i += 1
226+
227+
return "".join(out)
160228

161229

162230
class TextPromptClient(BasePromptClient):

0 commit comments

Comments
 (0)