From 7aa921a0898fd7aea18f3649b91bf352d0872411 Mon Sep 17 00:00:00 2001 From: Xayar145 <1029229393@qq.com> Date: Sat, 22 Aug 2026 09:25:19 +0800 Subject: [PATCH 1/4] fix(cache): prevent over-invalidation of similarly named prompt prefixes in PromptCache --- langfuse/_utils/prompt_cache.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/langfuse/_utils/prompt_cache.py b/langfuse/_utils/prompt_cache.py index 7d9c2298b..ecbec5cc1 100644 --- a/langfuse/_utils/prompt_cache.py +++ b/langfuse/_utils/prompt_cache.py @@ -178,9 +178,12 @@ 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 + prefix = f"{prompt_name}-" with self._lock: for key in list(self._cache): - if key.startswith(prompt_name): + if key == prompt_name or key.startswith(prefix): del self._cache[key] def add_refresh_prompt_task(self, key: str, fetch_func: Callable[[], None]) -> None: From 686e392c66da8c82bb6773924396954d17c2d2b4 Mon Sep 17 00:00:00 2001 From: Xayar145 <1029229393@qq.com> Date: Sat, 22 Aug 2026 09:25:22 +0800 Subject: [PATCH 2/4] test(prompt): add unit test for exact prompt name matching during cache invalidation --- tests/unit/test_prompt.py | 38 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 38 insertions(+) diff --git a/tests/unit/test_prompt.py b/tests/unit/test_prompt.py index eadfb8221..77405ab0d 100644 --- a/tests/unit/test_prompt.py +++ b/tests/unit/test_prompt.py @@ -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 + From 7a2219dab87e2a510c100158677f6b1c069e107d Mon Sep 17 00:00:00 2001 From: Xayar145 <1029229393@qq.com> Date: Sat, 22 Aug 2026 10:48:27 +0800 Subject: [PATCH 3/4] fix(cache): match exact version and label prefixes in PromptCache.invalidate --- langfuse/_utils/prompt_cache.py | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/langfuse/_utils/prompt_cache.py b/langfuse/_utils/prompt_cache.py index ecbec5cc1..c2e8d4629 100644 --- a/langfuse/_utils/prompt_cache.py +++ b/langfuse/_utils/prompt_cache.py @@ -180,10 +180,15 @@ def invalidate(self, prompt_name: str) -> None: """Invalidate all cached prompts with the given prompt name.""" if not prompt_name: return - prefix = f"{prompt_name}-" + version_prefix = f"{prompt_name}-version:" + label_prefix = f"{prompt_name}-label:" with self._lock: for key in list(self._cache): - if key == prompt_name or key.startswith(prefix): + 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: From a23c9ea44ab694280349984d99ab3ace48557196 Mon Sep 17 00:00:00 2001 From: Xayar145 <1029229393@qq.com> Date: Sat, 22 Aug 2026 10:48:32 +0800 Subject: [PATCH 4/4] test(cache): assert hyphenated sibling prompts are preserved during invalidation --- tests/unit/test_prompt.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tests/unit/test_prompt.py b/tests/unit/test_prompt.py index 77405ab0d..ea000ca53 100644 --- a/tests/unit/test_prompt.py +++ b/tests/unit/test_prompt.py @@ -762,7 +762,7 @@ def test_prompt_cache_invalidate_exact_prefix_match(langfuse: Langfuse): tags=[], ) prompt2 = Prompt_Text( - name="summary_detailed", + name="summary-detailed", version=1, prompt="Summarize in detail", labels=[], @@ -772,7 +772,7 @@ def test_prompt_cache_invalidate_exact_prefix_match(langfuse: Langfuse): ) key1 = PromptCache.generate_cache_key("summary", version=1, label=None) - key2 = PromptCache.generate_cache_key("summary_detailed", 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) @@ -782,7 +782,7 @@ def test_prompt_cache_invalidate_exact_prefix_match(langfuse: Langfuse): cache.invalidate("summary") - # summary should be invalidated, but summary_detailed must be preserved + # summary should be invalidated, but summary-detailed must be preserved assert cache.get(key1) is None assert cache.get(key2) is not None