ecommerce-support-agent / cache /redis_cache.py
Naren-007's picture
Feature: tool-level Redis caching with duration logging (120s TTL)
d59f526
import redis
import hashlib
import json
import os
from logger import get_logger
logger = get_logger("cache")
def get_redis_client():
url = os.environ.get("REDIS_URL")
if not url:
return None
try:
client = redis.from_url(url, decode_responses=True, socket_timeout=2)
client.ping()
return client
except Exception as e:
logger.warning("Redis unavailable", extra={"event": "cache_unavailable", "error": str(e)})
return None
r = get_redis_client()
CACHE_TTL = 3600
def make_cache_key(message: str, thread_id: str = "global") -> str:
normalized = message.lower().strip()
return "agent:v1:" + hashlib.sha256(f"{thread_id}:{normalized}".encode()).hexdigest()
def get_cached_response(message: str, thread_id: str = "global") -> dict | None:
if r is None:
return None
try:
key = make_cache_key(message, thread_id)
value = r.get(key)
if value:
logger.info("Cache hit", extra={"event": "cache_hit"})
return json.loads(value)
return None
except Exception as e:
logger.warning("Cache get failed", extra={"event": "cache_error", "error": str(e)})
return None
def set_cached_response(message: str, response: dict, thread_id: str = "global") -> None:
if r is None:
return
try:
key = make_cache_key(message, thread_id)
r.setex(key, CACHE_TTL, json.dumps(response))
logger.info("Cache set", extra={"event": "cache_set"})
except Exception as e:
logger.warning("Cache set failed", extra={"event": "cache_error", "error": str(e)})
# --- Tool-level caching ---
TOOL_CACHE_TTL = 120 # 2 minutes — short TTL for data freshness
def make_tool_cache_key(tool_name: str, args: dict) -> str:
"""Create a cache key from tool name + sorted args."""
args_str = json.dumps(args, sort_keys=True).lower().strip()
return "tool:v1:" + hashlib.sha256(f"{tool_name}:{args_str}".encode()).hexdigest()
def get_cached_tool_result(tool_name: str, args: dict) -> str | None:
if r is None:
return None
try:
key = make_tool_cache_key(tool_name, args)
value = r.get(key)
if value:
logger.info("Tool cache hit", extra={
"event": "tool_cache_hit", "tool": tool_name
})
return value
return None
except Exception as e:
logger.warning("Tool cache get failed", extra={"event": "tool_cache_error", "error": str(e)})
return None
def set_cached_tool_result(tool_name: str, args: dict, result: str) -> None:
if r is None:
return
try:
key = make_tool_cache_key(tool_name, args)
r.setex(key, TOOL_CACHE_TTL, result)
logger.info("Tool cache set", extra={
"event": "tool_cache_set", "tool": tool_name
})
except Exception as e:
logger.warning("Tool cache set failed", extra={"event": "tool_cache_error", "error": str(e)})