1515logger = get_logger (__name__ )
1616
1717
18- class LangCacheWrapper (BaseLLMCache ):
18+ class LangCacheSemanticCache (BaseLLMCache ):
1919 """LLM Cache implementation using the LangCache managed service.
2020
2121 This cache uses the LangCache API service for semantic caching of LLM
@@ -24,9 +24,9 @@ class LangCacheWrapper(BaseLLMCache):
2424 Example:
2525 .. code-block:: python
2626
27- from redisvl.extensions.cache.llm import LangCacheWrapper
27+ from redisvl.extensions.cache.llm import LangCacheSemanticCache
2828
29- cache = LangCacheWrapper (
29+ cache = LangCacheSemanticCache (
3030 name="my_cache",
3131 server_url="https://api.langcache.com",
3232 cache_id="your-cache-id",
@@ -47,7 +47,7 @@ class LangCacheWrapper(BaseLLMCache):
4747 def __init__ (
4848 self ,
4949 name : str = "langcache" ,
50- server_url : str = "https://api .langcache.com " ,
50+ server_url : str = "https://aws-us-east-1 .langcache.redis.io " ,
5151 cache_id : str = "" ,
5252 api_key : str = "" ,
5353 ttl : Optional [int ] = None ,
@@ -56,7 +56,7 @@ def __init__(
5656 distance_scale : Literal ["normalized" , "redis" ] = "normalized" ,
5757 ** kwargs ,
5858 ):
59- """Initialize a LangCache wrapper .
59+ """Initialize a LangCache semantic cache .
6060
6161 Args:
6262 name (str): The name of the cache. Defaults to "langcache".
@@ -79,9 +79,9 @@ def __init__(
7979 self ._distance_scale = distance_scale
8080
8181 if not cache_id :
82- raise ValueError ("cache_id is required for LangCacheWrapper " )
82+ raise ValueError ("cache_id is required for LangCacheSemanticCache " )
8383 if not api_key :
84- raise ValueError ("api_key is required for LangCacheWrapper " )
84+ raise ValueError ("api_key is required for LangCacheSemanticCache " )
8585
8686 super ().__init__ (name = name , ttl = ttl , ** kwargs )
8787
@@ -108,20 +108,20 @@ def _create_client(self):
108108 Initialize the LangCache client.
109109
110110 Returns:
111- LangCacheClient : The LangCache client.
111+ LangCache : The LangCache client.
112112
113113 Raises:
114114 ImportError: If the langcache package is not installed.
115115 """
116116 try :
117- from langcache import LangCacheClient
117+ from langcache import LangCache
118118 except ImportError as e :
119119 raise ImportError (
120- "The langcache package is required to use LangCacheWrapper . "
120+ "The langcache package is required to use LangCacheSemanticCache . "
121121 "Install it with: pip install langcache"
122122 ) from e
123123
124- return LangCacheClient (
124+ return LangCache (
125125 server_url = self ._server_url ,
126126 cache_id = self ._cache_id ,
127127 api_key = self ._api_key ,
@@ -155,6 +155,8 @@ def _build_search_kwargs(
155155 SearchStrategy .EXACT if "exact" in self ._search_strategies else None ,
156156 SearchStrategy .SEMANTIC if "semantic" in self ._search_strategies else None ,
157157 ]
158+ # Filter out Nones to avoid sending invalid enum values
159+ search_strategies = [s for s in search_strategies if s is not None ]
158160 kwargs : Dict [str , Any ] = {
159161 "prompt" : prompt ,
160162 "search_strategies" : search_strategies ,
@@ -253,15 +255,31 @@ def check(
253255 if distance_threshold is not None :
254256 similarity_threshold = self ._similarity_threshold (distance_threshold )
255257
256- # Search using the LangCache client
257- # The client itself is the context manager
258+ # Build kwargs
258259 search_kwargs = self ._build_search_kwargs (
259260 prompt = prompt ,
260261 similarity_threshold = similarity_threshold ,
261262 attributes = attributes ,
262263 )
263264
264- response = self ._client .search (** search_kwargs )
265+ try :
266+ response = self ._client .search (** search_kwargs )
267+ except Exception as e :
268+ try :
269+ from langcache .errors import BadRequestErrorResponseContent
270+ except Exception :
271+ raise
272+ if (
273+ isinstance (e , BadRequestErrorResponseContent )
274+ and "no attributes are configured" in str (e ).lower ()
275+ and attributes
276+ ):
277+ raise RuntimeError (
278+ "LangCache reported attributes are not configured for this cache, "
279+ "but attributes were provided to check(). Remove attributes or configure them on the cache."
280+ ) from e
281+ else :
282+ raise
265283
266284 # Convert results to cache hits
267285 return self ._hits_from_response (response , num_results )
@@ -321,7 +339,24 @@ async def acheck(
321339
322340 # Add attributes if provided (already handled by builder)
323341
324- response = await self ._client .search_async (** search_kwargs )
342+ try :
343+ response = await self ._client .search_async (** search_kwargs )
344+ except Exception as e :
345+ try :
346+ from langcache .errors import BadRequestErrorResponseContent
347+ except Exception :
348+ raise
349+ if (
350+ isinstance (e , BadRequestErrorResponseContent )
351+ and "no attributes are configured" in str (e ).lower ()
352+ and attributes
353+ ):
354+ raise RuntimeError (
355+ "LangCache reported attributes are not configured for this cache, "
356+ "but attributes were provided to acheck(). Remove attributes or configure them on the cache."
357+ ) from e
358+ else :
359+ raise
325360
326361 # Convert results to cache hits
327362 return self ._hits_from_response (response , num_results )
@@ -365,16 +400,30 @@ def store(
365400 if ttl is not None :
366401 logger .warning ("LangCache does not support per-entry TTL" )
367402
368- # Store using the LangCache client
369- # The client itself is the context manager
370- # Only pass attributes if metadata is provided
371- # Some caches may not have attributes configured
372- if metadata :
373- result = self ._client .set (
374- prompt = prompt , response = response , attributes = metadata
375- )
376- else :
377- result = self ._client .set (prompt = prompt , response = response )
403+ # Store using the LangCache client; only send attributes if provided (non-empty)
404+ try :
405+ if metadata :
406+ result = self ._client .set (
407+ prompt = prompt , response = response , attributes = metadata
408+ )
409+ else :
410+ result = self ._client .set (prompt = prompt , response = response )
411+ except Exception as e : # narrow for known SDK error when possible
412+ try :
413+ from langcache .errors import BadRequestErrorResponseContent
414+ except Exception :
415+ raise
416+ if (
417+ isinstance (e , BadRequestErrorResponseContent )
418+ and "no attributes are configured" in str (e ).lower ()
419+ and metadata
420+ ):
421+ raise RuntimeError (
422+ "LangCache reported attributes are not configured for this cache, "
423+ "but metadata was provided to store(). Remove metadata or configure attributes on the cache."
424+ ) from e
425+ else :
426+ raise
378427
379428 # Return the entry ID
380429 # Result is a SetResponse Pydantic model with entry_id attribute
@@ -419,16 +468,30 @@ async def astore(
419468 if ttl is not None :
420469 logger .warning ("LangCache does not support per-entry TTL" )
421470
422- # Store using the LangCache client (async)
423- # The client itself is the context manager
424- # Only pass attributes if metadata is provided
425- # Some caches may not have attributes configured
426- if metadata :
427- result = await self ._client .set_async (
428- prompt = prompt , response = response , attributes = metadata
429- )
430- else :
431- result = await self ._client .set_async (prompt = prompt , response = response )
471+ # Store using the LangCache client (async); only send attributes if provided (non-empty)
472+ try :
473+ if metadata :
474+ result = await self ._client .set_async (
475+ prompt = prompt , response = response , attributes = metadata
476+ )
477+ else :
478+ result = await self ._client .set_async (prompt = prompt , response = response )
479+ except Exception as e :
480+ try :
481+ from langcache .errors import BadRequestErrorResponseContent
482+ except Exception :
483+ raise
484+ if (
485+ isinstance (e , BadRequestErrorResponseContent )
486+ and "no attributes are configured" in str (e ).lower ()
487+ and metadata
488+ ):
489+ raise RuntimeError (
490+ "LangCache reported attributes are not configured for this cache, "
491+ "but metadata was provided to astore(). Remove metadata or configure attributes on the cache."
492+ ) from e
493+ else :
494+ raise
432495
433496 # Return the entry ID
434497 # Result is a SetResponse Pydantic model with entry_id attribute
0 commit comments