Skip to content

Commit d7fb969

Browse files
committed
placeholer compile
1 parent d349c38 commit d7fb969

1 file changed

Lines changed: 86 additions & 4 deletions

File tree

langfuse/model.py

Lines changed: 86 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
import re
44
from abc import ABC, abstractmethod
5-
from typing import Any, Dict, List, Optional, Tuple, TypedDict, Union
5+
from typing import Any, Dict, List, Literal, Optional, Tuple, TypedDict, Union
66

77
from langfuse.api.resources.commons.types.dataset import (
88
Dataset, # noqa: F401
@@ -54,6 +54,26 @@ class ChatMessageDict(TypedDict):
5454
content: str
5555

5656

57+
class ChatMessageWithPlaceholdersDict_Message(TypedDict):
58+
type: Literal["message"]
59+
role: str
60+
content: str
61+
name: None
62+
63+
64+
class ChatMessageWithPlaceholdersDict_Placeholder(TypedDict):
65+
type: Literal["placeholder"]
66+
role: None
67+
content: None
68+
name: str
69+
70+
71+
ChatMessageWithPlaceholdersDict = Union[
72+
ChatMessageWithPlaceholdersDict_Message,
73+
ChatMessageWithPlaceholdersDict_Placeholder,
74+
]
75+
76+
5777
class TemplateParser:
5878
OPENING = "{{"
5979
CLOSING = "}}"
@@ -208,9 +228,27 @@ def get_langchain_prompt(self, **kwargs) -> str:
208228
class ChatPromptClient(BasePromptClient):
209229
def __init__(self, prompt: Prompt_Chat, is_fallback: bool = False):
210230
super().__init__(prompt, is_fallback)
211-
self.prompt = [
212-
ChatMessageDict(role=p.role, content=p.content) for p in prompt.prompt
213-
]
231+
self.prompt: List[ChatMessageWithPlaceholdersDict] = []
232+
233+
for p in prompt.prompt:
234+
if hasattr(p, "type") and p.type == "placeholder":
235+
self.prompt.append(
236+
ChatMessageWithPlaceholdersDict_Placeholder(
237+
type="placeholder",
238+
role=None,
239+
content=None,
240+
name=p.name,
241+
)
242+
)
243+
elif hasattr(p, "type") and p.type == "message":
244+
self.prompt.append(
245+
ChatMessageWithPlaceholdersDict_Message(
246+
type="message",
247+
role=p.role,
248+
content=p.content,
249+
name=None,
250+
)
251+
)
214252

215253
def compile(self, **kwargs) -> List[ChatMessageDict]:
216254
return [
@@ -221,6 +259,7 @@ def compile(self, **kwargs) -> List[ChatMessageDict]:
221259
role=chat_message["role"],
222260
)
223261
for chat_message in self.prompt
262+
if chat_message["type"] == "message"
224263
]
225264

226265
@property
@@ -229,6 +268,7 @@ def variables(self) -> List[str]:
229268
return [
230269
variable
231270
for chat_message in self.prompt
271+
if chat_message["type"] == "message"
232272
for variable in TemplateParser.find_variable_names(chat_message["content"])
233273
]
234274

@@ -246,6 +286,47 @@ def __eq__(self, other):
246286

247287
return False
248288

289+
def compileWithPlaceholders(
290+
self,
291+
variables: Dict[str, Any],
292+
placeholders: Dict[str, List[ChatMessage]],
293+
) -> List[ChatMessageDict]:
294+
"""Compile chat prompt by first replacing placeholders, then expanding variables.
295+
296+
Args:
297+
variables: Dictionary of variable names to values for template substitution
298+
placeholders: Dictionary of placeholder names to lists of ChatMessage objects
299+
300+
Returns:
301+
List[ChatMessageDict]: Compiled chat messages
302+
"""
303+
messages_with_placeholders_replaced: List[ChatMessage] = []
304+
305+
# Subsitute the placeholders for their supplied ChatMessages
306+
for item in self.prompt:
307+
if item["type"] == "placeholder" and item["name"] in placeholders:
308+
messages_with_placeholders_replaced.extend(placeholders[item["name"]])
309+
elif item["type"] == "message":
310+
messages_with_placeholders_replaced.append(
311+
ChatMessage(
312+
role=item["role"],
313+
content=item["content"],
314+
)
315+
)
316+
317+
# Then, replace the variables in the ChatMessage content.
318+
return [
319+
ChatMessageDict(
320+
content=TemplateParser.compile_template(
321+
chat_message.content, variables,
322+
),
323+
role=chat_message.role,
324+
)
325+
for chat_message in messages_with_placeholders_replaced
326+
if hasattr(chat_message, "role") and hasattr(chat_message, "content")
327+
]
328+
329+
249330
def get_langchain_prompt(self, **kwargs):
250331
"""Convert Langfuse prompt into string compatible with Langchain ChatPromptTemplate.
251332
@@ -269,6 +350,7 @@ def get_langchain_prompt(self, **kwargs):
269350
),
270351
)
271352
for msg in self.prompt
353+
if msg["type"] == "message"
272354
]
273355

274356

0 commit comments

Comments
 (0)