Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 9 additions & 1 deletion langfuse/_utils/prompt_cache.py
Original file line number Diff line number Diff line change
Expand Up @@ -178,9 +178,17 @@ def delete(self, key: str) -> None:

def invalidate(self, prompt_name: str) -> None:
"""Invalidate all cached prompts with the given prompt name."""
if not prompt_name:
return
version_prefix = f"{prompt_name}-version:"
label_prefix = f"{prompt_name}-label:"
with self._lock:
for key in list(self._cache):
if key.startswith(prompt_name):
if (
key == prompt_name
or key.startswith(version_prefix)
or key.startswith(label_prefix)
):
del self._cache[key]

def add_refresh_prompt_task(self, key: str, fetch_func: Callable[[], None]) -> None:
Expand Down
38 changes: 38 additions & 0 deletions tests/unit/test_prompt.py
Original file line number Diff line number Diff line change
Expand Up @@ -748,3 +748,41 @@ def test_get_fresh_prompt_when_version_changes(langfuse: Langfuse):
result_call_2 = langfuse.get_prompt(prompt_name, version=2)
assert mock_server_call.call_count == 2
assert result_call_2 == version_changed_prompt_client


def test_prompt_cache_invalidate_exact_prefix_match(langfuse: Langfuse):
cache = PromptCache()
prompt1 = Prompt_Text(
name="summary",
version=1,
prompt="Summarize this",
labels=[],
type="text",
config={},
tags=[],
)
prompt2 = Prompt_Text(
name="summary-detailed",
version=1,
prompt="Summarize in detail",
labels=[],
type="text",
config={},
tags=[],
)

key1 = PromptCache.generate_cache_key("summary", version=1, label=None)
key2 = PromptCache.generate_cache_key("summary-detailed", version=1, label=None)

cache.set(key1, TextPromptClient(prompt1), ttl_seconds=60)
cache.set(key2, TextPromptClient(prompt2), ttl_seconds=60)

assert cache.get(key1) is not None
assert cache.get(key2) is not None

cache.invalidate("summary")

# summary should be invalidated, but summary-detailed must be preserved
assert cache.get(key1) is None
assert cache.get(key2) is not None