diff --git a/langfuse/api/reference.md b/langfuse/api/reference.md index 41d43849a..c0dc254f4 100644 --- a/langfuse/api/reference.md +++ b/langfuse/api/reference.md @@ -2614,6 +2614,7 @@ client.prompts.create( config={"key": "value"}, labels=["string"], tags=["string"], + commit_message="string", ), ) diff --git a/langfuse/api/resources/prompts/client.py b/langfuse/api/resources/prompts/client.py index ebaa07909..5ca4c4aa5 100644 --- a/langfuse/api/resources/prompts/client.py +++ b/langfuse/api/resources/prompts/client.py @@ -267,6 +267,7 @@ def create( config={"key": "value"}, labels=["string"], tags=["string"], + commit_message="string", ), ) """ @@ -568,6 +569,7 @@ async def main() -> None: config={"key": "value"}, labels=["string"], tags=["string"], + commit_message="string", ), ) diff --git a/langfuse/api/resources/prompts/types/base_prompt.py b/langfuse/api/resources/prompts/types/base_prompt.py index 82934fbe6..576110b75 100644 --- a/langfuse/api/resources/prompts/types/base_prompt.py +++ b/langfuse/api/resources/prompts/types/base_prompt.py @@ -21,6 +21,13 @@ class BasePrompt(pydantic_v1.BaseModel): List of tags. Used to filter via UI and API. The same across versions of a prompt. """ + commit_message: typing.Optional[str] = pydantic_v1.Field( + alias="commitMessage", default=None + ) + """ + Commit message for this prompt version. + """ + def json(self, **kwargs: typing.Any) -> str: kwargs_with_defaults: typing.Any = { "by_alias": True, @@ -49,5 +56,7 @@ def dict(self, **kwargs: typing.Any) -> typing.Dict[str, typing.Any]: class Config: frozen = True smart_union = True + allow_population_by_field_name = True + populate_by_name = True extra = pydantic_v1.Extra.allow json_encoders = {dt.datetime: serialize_datetime} diff --git a/langfuse/api/resources/prompts/types/create_chat_prompt_request.py b/langfuse/api/resources/prompts/types/create_chat_prompt_request.py index a7c9f113b..95d55c88a 100644 --- a/langfuse/api/resources/prompts/types/create_chat_prompt_request.py +++ b/langfuse/api/resources/prompts/types/create_chat_prompt_request.py @@ -22,6 +22,13 @@ class CreateChatPromptRequest(pydantic_v1.BaseModel): List of tags to apply to all versions of this prompt. """ + commit_message: typing.Optional[str] = pydantic_v1.Field( + alias="commitMessage", default=None + ) + """ + Commit message for this prompt version. + """ + def json(self, **kwargs: typing.Any) -> str: kwargs_with_defaults: typing.Any = { "by_alias": True, @@ -50,5 +57,7 @@ def dict(self, **kwargs: typing.Any) -> typing.Dict[str, typing.Any]: class Config: frozen = True smart_union = True + allow_population_by_field_name = True + populate_by_name = True extra = pydantic_v1.Extra.allow json_encoders = {dt.datetime: serialize_datetime} diff --git a/langfuse/api/resources/prompts/types/create_prompt_request.py b/langfuse/api/resources/prompts/types/create_prompt_request.py index 9b23bd12d..76cba7ff9 100644 --- a/langfuse/api/resources/prompts/types/create_prompt_request.py +++ b/langfuse/api/resources/prompts/types/create_prompt_request.py @@ -16,6 +16,9 @@ class CreatePromptRequest_Chat(pydantic_v1.BaseModel): config: typing.Optional[typing.Any] = None labels: typing.Optional[typing.List[str]] = None tags: typing.Optional[typing.List[str]] = None + commit_message: typing.Optional[str] = pydantic_v1.Field( + alias="commitMessage", default=None + ) type: typing.Literal["chat"] = "chat" def json(self, **kwargs: typing.Any) -> str: @@ -46,6 +49,8 @@ def dict(self, **kwargs: typing.Any) -> typing.Dict[str, typing.Any]: class Config: frozen = True smart_union = True + allow_population_by_field_name = True + populate_by_name = True extra = pydantic_v1.Extra.allow json_encoders = {dt.datetime: serialize_datetime} @@ -56,6 +61,9 @@ class CreatePromptRequest_Text(pydantic_v1.BaseModel): config: typing.Optional[typing.Any] = None labels: typing.Optional[typing.List[str]] = None tags: typing.Optional[typing.List[str]] = None + commit_message: typing.Optional[str] = pydantic_v1.Field( + alias="commitMessage", default=None + ) type: typing.Literal["text"] = "text" def json(self, **kwargs: typing.Any) -> str: @@ -86,6 +94,8 @@ def dict(self, **kwargs: typing.Any) -> typing.Dict[str, typing.Any]: class Config: frozen = True smart_union = True + allow_population_by_field_name = True + populate_by_name = True extra = pydantic_v1.Extra.allow json_encoders = {dt.datetime: serialize_datetime} diff --git a/langfuse/api/resources/prompts/types/create_text_prompt_request.py b/langfuse/api/resources/prompts/types/create_text_prompt_request.py index 31b1c0eee..d35fbb24d 100644 --- a/langfuse/api/resources/prompts/types/create_text_prompt_request.py +++ b/langfuse/api/resources/prompts/types/create_text_prompt_request.py @@ -21,6 +21,13 @@ class CreateTextPromptRequest(pydantic_v1.BaseModel): List of tags to apply to all versions of this prompt. """ + commit_message: typing.Optional[str] = pydantic_v1.Field( + alias="commitMessage", default=None + ) + """ + Commit message for this prompt version. + """ + def json(self, **kwargs: typing.Any) -> str: kwargs_with_defaults: typing.Any = { "by_alias": True, @@ -49,5 +56,7 @@ def dict(self, **kwargs: typing.Any) -> typing.Dict[str, typing.Any]: class Config: frozen = True smart_union = True + allow_population_by_field_name = True + populate_by_name = True extra = pydantic_v1.Extra.allow json_encoders = {dt.datetime: serialize_datetime} diff --git a/langfuse/api/resources/prompts/types/prompt.py b/langfuse/api/resources/prompts/types/prompt.py index 90ba3447f..9c91b85d8 100644 --- a/langfuse/api/resources/prompts/types/prompt.py +++ b/langfuse/api/resources/prompts/types/prompt.py @@ -17,6 +17,9 @@ class Prompt_Chat(pydantic_v1.BaseModel): config: typing.Any labels: typing.List[str] tags: typing.List[str] + commit_message: typing.Optional[str] = pydantic_v1.Field( + alias="commitMessage", default=None + ) type: typing.Literal["chat"] = "chat" def json(self, **kwargs: typing.Any) -> str: @@ -47,6 +50,8 @@ def dict(self, **kwargs: typing.Any) -> typing.Dict[str, typing.Any]: class Config: frozen = True smart_union = True + allow_population_by_field_name = True + populate_by_name = True extra = pydantic_v1.Extra.allow json_encoders = {dt.datetime: serialize_datetime} @@ -58,6 +63,9 @@ class Prompt_Text(pydantic_v1.BaseModel): config: typing.Any labels: typing.List[str] tags: typing.List[str] + commit_message: typing.Optional[str] = pydantic_v1.Field( + alias="commitMessage", default=None + ) type: typing.Literal["text"] = "text" def json(self, **kwargs: typing.Any) -> str: @@ -88,6 +96,8 @@ def dict(self, **kwargs: typing.Any) -> typing.Dict[str, typing.Any]: class Config: frozen = True smart_union = True + allow_population_by_field_name = True + populate_by_name = True extra = pydantic_v1.Extra.allow json_encoders = {dt.datetime: serialize_datetime} diff --git a/langfuse/client.py b/langfuse/client.py index d1d4f516c..6f1ba5eef 100644 --- a/langfuse/client.py +++ b/langfuse/client.py @@ -1282,6 +1282,7 @@ def create_prompt( tags: Optional[List[str]] = None, type: Optional[Literal["chat"]], config: Optional[Any] = None, + commit_message: Optional[str] = None, ) -> ChatPromptClient: ... @overload @@ -1295,6 +1296,7 @@ def create_prompt( tags: Optional[List[str]] = None, type: Optional[Literal["text"]] = "text", config: Optional[Any] = None, + commit_message: Optional[str] = None, ) -> TextPromptClient: ... def create_prompt( @@ -1307,6 +1309,7 @@ def create_prompt( tags: Optional[List[str]] = None, type: Optional[Literal["chat", "text"]] = "text", config: Optional[Any] = None, + commit_message: Optional[str] = None, ) -> PromptClient: """Create a new prompt in Langfuse. @@ -1318,6 +1321,7 @@ def create_prompt( tags: The tags of the prompt. Defaults to None. Will be applied to all versions of the prompt. config: Additional structured data to be saved with the prompt. Defaults to None. type: The type of the prompt to be created. "chat" vs. "text". Defaults to "text". + commit_message: Optional string describing the change. Returns: TextPromptClient: The prompt if type argument is 'text'. @@ -1345,6 +1349,7 @@ def create_prompt( labels=labels, tags=tags, config=config or {}, + commitMessage=commit_message, type="chat", ) server_prompt = self.client.prompts.create(request=request) @@ -1360,6 +1365,7 @@ def create_prompt( labels=labels, tags=tags, config=config or {}, + commitMessage=commit_message, type="text", ) diff --git a/langfuse/model.py b/langfuse/model.py index 712a4ea2a..6380bf5f2 100644 --- a/langfuse/model.py +++ b/langfuse/model.py @@ -1,8 +1,8 @@ """@private""" -from abc import ABC, abstractmethod -from typing import Optional, TypedDict, Any, Dict, Union, List, Tuple import re +from abc import ABC, abstractmethod +from typing import Any, Dict, List, Optional, Tuple, TypedDict, Union from langfuse.api.resources.commons.types.dataset import ( Dataset, # noqa: F401 @@ -36,7 +36,7 @@ from langfuse.api.resources.datasets.types.create_dataset_request import ( # noqa: F401 CreateDatasetRequest, ) -from langfuse.api.resources.prompts import Prompt, ChatMessage, Prompt_Chat, Prompt_Text +from langfuse.api.resources.prompts import ChatMessage, Prompt, Prompt_Chat, Prompt_Text class ModelUsage(TypedDict): @@ -126,6 +126,7 @@ class BasePromptClient(ABC): config: Dict[str, Any] labels: List[str] tags: List[str] + commit_message: Optional[str] def __init__(self, prompt: Prompt, is_fallback: bool = False): self.name = prompt.name @@ -133,6 +134,7 @@ def __init__(self, prompt: Prompt, is_fallback: bool = False): self.config = prompt.config self.labels = prompt.labels self.tags = prompt.tags + self.commit_message = prompt.commit_message self.is_fallback = is_fallback @abstractmethod diff --git a/tests/test_prompt.py b/tests/test_prompt.py index ad7cf9a92..8c6660f57 100644 --- a/tests/test_prompt.py +++ b/tests/test_prompt.py @@ -1,13 +1,14 @@ from time import sleep -import pytest from unittest.mock import Mock, patch import openai +import pytest + +from langfuse.api.resources.prompts import Prompt_Chat, Prompt_Text from langfuse.client import Langfuse -from langfuse.prompt_cache import PromptCacheItem, DEFAULT_PROMPT_CACHE_TTL_SECONDS +from langfuse.model import ChatPromptClient, TextPromptClient +from langfuse.prompt_cache import DEFAULT_PROMPT_CACHE_TTL_SECONDS, PromptCacheItem from tests.utils import create_uuid, get_api -from langfuse.api.resources.prompts import Prompt_Text, Prompt_Chat -from langfuse.model import TextPromptClient, ChatPromptClient def test_create_prompt(): @@ -17,6 +18,7 @@ def test_create_prompt(): name=prompt_name, prompt="test prompt", labels=["production"], + commit_message="initial commit", ) second_prompt_client = langfuse.get_prompt(prompt_name) @@ -25,6 +27,7 @@ def test_create_prompt(): assert prompt_client.version == second_prompt_client.version assert prompt_client.prompt == second_prompt_client.prompt assert prompt_client.config == second_prompt_client.config + assert prompt_client.commit_message == second_prompt_client.commit_message assert prompt_client.config == {} @@ -79,6 +82,7 @@ def test_create_chat_prompt(): labels=["production"], tags=["test"], type="chat", + commit_message="initial commit", ) second_prompt_client = langfuse.get_prompt(prompt_name, type="chat") @@ -97,6 +101,7 @@ def test_create_chat_prompt(): assert prompt_client.config == second_prompt_client.config assert prompt_client.labels == ["production", "latest"] assert prompt_client.tags == second_prompt_client.tags + assert prompt_client.commit_message == second_prompt_client.commit_message assert prompt_client.config == {}