Skip to content

Commit 0a463cb

Browse files
authored
feat: update prompts and invalidate cache (#1082)
1 parent 7e46014 commit 0a463cb

File tree

13 files changed

+386
-19
lines changed

13 files changed

+386
-19
lines changed

langfuse/api/__init__.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -147,6 +147,7 @@
147147
models,
148148
observations,
149149
projects,
150+
prompt_version,
150151
prompts,
151152
score,
152153
score_configs,
@@ -302,6 +303,7 @@
302303
"models",
303304
"observations",
304305
"projects",
306+
"prompt_version",
305307
"prompts",
306308
"score",
307309
"score_configs",

langfuse/api/client.py

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,10 @@
1919
from .resources.models.client import AsyncModelsClient, ModelsClient
2020
from .resources.observations.client import AsyncObservationsClient, ObservationsClient
2121
from .resources.projects.client import AsyncProjectsClient, ProjectsClient
22+
from .resources.prompt_version.client import (
23+
AsyncPromptVersionClient,
24+
PromptVersionClient,
25+
)
2226
from .resources.prompts.client import AsyncPromptsClient, PromptsClient
2327
from .resources.score.client import AsyncScoreClient, ScoreClient
2428
from .resources.score_configs.client import AsyncScoreConfigsClient, ScoreConfigsClient
@@ -108,6 +112,7 @@ def __init__(
108112
self.models = ModelsClient(client_wrapper=self._client_wrapper)
109113
self.observations = ObservationsClient(client_wrapper=self._client_wrapper)
110114
self.projects = ProjectsClient(client_wrapper=self._client_wrapper)
115+
self.prompt_version = PromptVersionClient(client_wrapper=self._client_wrapper)
111116
self.prompts = PromptsClient(client_wrapper=self._client_wrapper)
112117
self.score_configs = ScoreConfigsClient(client_wrapper=self._client_wrapper)
113118
self.score = ScoreClient(client_wrapper=self._client_wrapper)
@@ -199,6 +204,9 @@ def __init__(
199204
self.models = AsyncModelsClient(client_wrapper=self._client_wrapper)
200205
self.observations = AsyncObservationsClient(client_wrapper=self._client_wrapper)
201206
self.projects = AsyncProjectsClient(client_wrapper=self._client_wrapper)
207+
self.prompt_version = AsyncPromptVersionClient(
208+
client_wrapper=self._client_wrapper
209+
)
202210
self.prompts = AsyncPromptsClient(client_wrapper=self._client_wrapper)
203211
self.score_configs = AsyncScoreConfigsClient(
204212
client_wrapper=self._client_wrapper

langfuse/api/reference.md

Lines changed: 96 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2237,6 +2237,100 @@ client.projects.get()
22372237
</dl>
22382238

22392239

2240+
</dd>
2241+
</dl>
2242+
</details>
2243+
2244+
## PromptVersion
2245+
<details><summary><code>client.prompt_version.<a href="src/langfuse/resources/prompt_version/client.py">update</a>(...)</code></summary>
2246+
<dl>
2247+
<dd>
2248+
2249+
#### 📝 Description
2250+
2251+
<dl>
2252+
<dd>
2253+
2254+
<dl>
2255+
<dd>
2256+
2257+
Update labels for a specific prompt version
2258+
</dd>
2259+
</dl>
2260+
</dd>
2261+
</dl>
2262+
2263+
#### 🔌 Usage
2264+
2265+
<dl>
2266+
<dd>
2267+
2268+
<dl>
2269+
<dd>
2270+
2271+
```python
2272+
from langfuse.client import FernLangfuse
2273+
2274+
client = FernLangfuse(
2275+
x_langfuse_sdk_name="YOUR_X_LANGFUSE_SDK_NAME",
2276+
x_langfuse_sdk_version="YOUR_X_LANGFUSE_SDK_VERSION",
2277+
x_langfuse_public_key="YOUR_X_LANGFUSE_PUBLIC_KEY",
2278+
username="YOUR_USERNAME",
2279+
password="YOUR_PASSWORD",
2280+
base_url="https://yourhost.com/path/to/api",
2281+
)
2282+
client.prompt_version.update(
2283+
name="string",
2284+
version=1,
2285+
new_labels=["string"],
2286+
)
2287+
2288+
```
2289+
</dd>
2290+
</dl>
2291+
</dd>
2292+
</dl>
2293+
2294+
#### ⚙️ Parameters
2295+
2296+
<dl>
2297+
<dd>
2298+
2299+
<dl>
2300+
<dd>
2301+
2302+
**name:** `str` — The name of the prompt
2303+
2304+
</dd>
2305+
</dl>
2306+
2307+
<dl>
2308+
<dd>
2309+
2310+
**version:** `int` — Version of the prompt to update
2311+
2312+
</dd>
2313+
</dl>
2314+
2315+
<dl>
2316+
<dd>
2317+
2318+
**new_labels:** `typing.Sequence[str]` — New labels for the prompt version. Labels are unique across versions. The "latest" label is reserved and managed by Langfuse.
2319+
2320+
</dd>
2321+
</dl>
2322+
2323+
<dl>
2324+
<dd>
2325+
2326+
**request_options:** `typing.Optional[RequestOptions]` — Request-specific configuration.
2327+
2328+
</dd>
2329+
</dl>
2330+
</dd>
2331+
</dl>
2332+
2333+
22402334
</dd>
22412335
</dl>
22422336
</details>
@@ -2944,7 +3038,7 @@ client.score.get(
29443038
config_id="string",
29453039
queue_id="string",
29463040
data_type=ScoreDataType.NUMERIC,
2947-
trace_tags=["string"],
3041+
trace_tags="string",
29483042
)
29493043

29503044
```
@@ -3065,9 +3159,7 @@ client.score.get(
30653159
<dl>
30663160
<dd>
30673161

3068-
**trace_tags:** `typing.Optional[
3069-
typing.Union[typing.Sequence[str], typing.Sequence[typing.Sequence[str]]]
3070-
]` — Only scores linked to traces that include all of these tags will be returned.
3162+
**trace_tags:** `typing.Optional[typing.Union[str, typing.Sequence[str]]]` — Only scores linked to traces that include all of these tags will be returned.
30713163

30723164
</dd>
30733165
</dl>

langfuse/api/resources/__init__.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
models,
1414
observations,
1515
projects,
16+
prompt_version,
1617
prompts,
1718
score,
1819
score_configs,
@@ -299,6 +300,7 @@
299300
"models",
300301
"observations",
301302
"projects",
303+
"prompt_version",
302304
"prompts",
303305
"score",
304306
"score_configs",
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
# This file was auto-generated by Fern from our API Definition.
2+
Lines changed: 197 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,197 @@
1+
# This file was auto-generated by Fern from our API Definition.
2+
3+
import typing
4+
from json.decoder import JSONDecodeError
5+
6+
from ...core.api_error import ApiError
7+
from ...core.client_wrapper import AsyncClientWrapper, SyncClientWrapper
8+
from ...core.jsonable_encoder import jsonable_encoder
9+
from ...core.pydantic_utilities import pydantic_v1
10+
from ...core.request_options import RequestOptions
11+
from ..commons.errors.access_denied_error import AccessDeniedError
12+
from ..commons.errors.error import Error
13+
from ..commons.errors.method_not_allowed_error import MethodNotAllowedError
14+
from ..commons.errors.not_found_error import NotFoundError
15+
from ..commons.errors.unauthorized_error import UnauthorizedError
16+
from ..prompts.types.prompt import Prompt
17+
18+
# this is used as the default value for optional parameters
19+
OMIT = typing.cast(typing.Any, ...)
20+
21+
22+
class PromptVersionClient:
23+
def __init__(self, *, client_wrapper: SyncClientWrapper):
24+
self._client_wrapper = client_wrapper
25+
26+
def update(
27+
self,
28+
name: str,
29+
version: int,
30+
*,
31+
new_labels: typing.Sequence[str],
32+
request_options: typing.Optional[RequestOptions] = None,
33+
) -> Prompt:
34+
"""
35+
Update labels for a specific prompt version
36+
37+
Parameters
38+
----------
39+
name : str
40+
The name of the prompt
41+
42+
version : int
43+
Version of the prompt to update
44+
45+
new_labels : typing.Sequence[str]
46+
New labels for the prompt version. Labels are unique across versions. The "latest" label is reserved and managed by Langfuse.
47+
48+
request_options : typing.Optional[RequestOptions]
49+
Request-specific configuration.
50+
51+
Returns
52+
-------
53+
Prompt
54+
55+
Examples
56+
--------
57+
from langfuse.client import FernLangfuse
58+
59+
client = FernLangfuse(
60+
x_langfuse_sdk_name="YOUR_X_LANGFUSE_SDK_NAME",
61+
x_langfuse_sdk_version="YOUR_X_LANGFUSE_SDK_VERSION",
62+
x_langfuse_public_key="YOUR_X_LANGFUSE_PUBLIC_KEY",
63+
username="YOUR_USERNAME",
64+
password="YOUR_PASSWORD",
65+
base_url="https://yourhost.com/path/to/api",
66+
)
67+
client.prompt_version.update(
68+
name="string",
69+
version=1,
70+
new_labels=["string"],
71+
)
72+
"""
73+
_response = self._client_wrapper.httpx_client.request(
74+
f"api/public/v2/prompts/{jsonable_encoder(name)}/versions/{jsonable_encoder(version)}",
75+
method="PATCH",
76+
json={"newLabels": new_labels},
77+
request_options=request_options,
78+
omit=OMIT,
79+
)
80+
try:
81+
if 200 <= _response.status_code < 300:
82+
return pydantic_v1.parse_obj_as(Prompt, _response.json()) # type: ignore
83+
if _response.status_code == 400:
84+
raise Error(pydantic_v1.parse_obj_as(typing.Any, _response.json())) # type: ignore
85+
if _response.status_code == 401:
86+
raise UnauthorizedError(
87+
pydantic_v1.parse_obj_as(typing.Any, _response.json())
88+
) # type: ignore
89+
if _response.status_code == 403:
90+
raise AccessDeniedError(
91+
pydantic_v1.parse_obj_as(typing.Any, _response.json())
92+
) # type: ignore
93+
if _response.status_code == 405:
94+
raise MethodNotAllowedError(
95+
pydantic_v1.parse_obj_as(typing.Any, _response.json())
96+
) # type: ignore
97+
if _response.status_code == 404:
98+
raise NotFoundError(
99+
pydantic_v1.parse_obj_as(typing.Any, _response.json())
100+
) # type: ignore
101+
_response_json = _response.json()
102+
except JSONDecodeError:
103+
raise ApiError(status_code=_response.status_code, body=_response.text)
104+
raise ApiError(status_code=_response.status_code, body=_response_json)
105+
106+
107+
class AsyncPromptVersionClient:
108+
def __init__(self, *, client_wrapper: AsyncClientWrapper):
109+
self._client_wrapper = client_wrapper
110+
111+
async def update(
112+
self,
113+
name: str,
114+
version: int,
115+
*,
116+
new_labels: typing.Sequence[str],
117+
request_options: typing.Optional[RequestOptions] = None,
118+
) -> Prompt:
119+
"""
120+
Update labels for a specific prompt version
121+
122+
Parameters
123+
----------
124+
name : str
125+
The name of the prompt
126+
127+
version : int
128+
Version of the prompt to update
129+
130+
new_labels : typing.Sequence[str]
131+
New labels for the prompt version. Labels are unique across versions. The "latest" label is reserved and managed by Langfuse.
132+
133+
request_options : typing.Optional[RequestOptions]
134+
Request-specific configuration.
135+
136+
Returns
137+
-------
138+
Prompt
139+
140+
Examples
141+
--------
142+
import asyncio
143+
144+
from langfuse.client import AsyncFernLangfuse
145+
146+
client = AsyncFernLangfuse(
147+
x_langfuse_sdk_name="YOUR_X_LANGFUSE_SDK_NAME",
148+
x_langfuse_sdk_version="YOUR_X_LANGFUSE_SDK_VERSION",
149+
x_langfuse_public_key="YOUR_X_LANGFUSE_PUBLIC_KEY",
150+
username="YOUR_USERNAME",
151+
password="YOUR_PASSWORD",
152+
base_url="https://yourhost.com/path/to/api",
153+
)
154+
155+
156+
async def main() -> None:
157+
await client.prompt_version.update(
158+
name="string",
159+
version=1,
160+
new_labels=["string"],
161+
)
162+
163+
164+
asyncio.run(main())
165+
"""
166+
_response = await self._client_wrapper.httpx_client.request(
167+
f"api/public/v2/prompts/{jsonable_encoder(name)}/versions/{jsonable_encoder(version)}",
168+
method="PATCH",
169+
json={"newLabels": new_labels},
170+
request_options=request_options,
171+
omit=OMIT,
172+
)
173+
try:
174+
if 200 <= _response.status_code < 300:
175+
return pydantic_v1.parse_obj_as(Prompt, _response.json()) # type: ignore
176+
if _response.status_code == 400:
177+
raise Error(pydantic_v1.parse_obj_as(typing.Any, _response.json())) # type: ignore
178+
if _response.status_code == 401:
179+
raise UnauthorizedError(
180+
pydantic_v1.parse_obj_as(typing.Any, _response.json())
181+
) # type: ignore
182+
if _response.status_code == 403:
183+
raise AccessDeniedError(
184+
pydantic_v1.parse_obj_as(typing.Any, _response.json())
185+
) # type: ignore
186+
if _response.status_code == 405:
187+
raise MethodNotAllowedError(
188+
pydantic_v1.parse_obj_as(typing.Any, _response.json())
189+
) # type: ignore
190+
if _response.status_code == 404:
191+
raise NotFoundError(
192+
pydantic_v1.parse_obj_as(typing.Any, _response.json())
193+
) # type: ignore
194+
_response_json = _response.json()
195+
except JSONDecodeError:
196+
raise ApiError(status_code=_response.status_code, body=_response.text)
197+
raise ApiError(status_code=_response.status_code, body=_response_json)

0 commit comments

Comments
 (0)