feat: 重构 agentscope 缓存架构,新增消息和附件缓存

This commit is contained in:
qzl
2026-03-25 17:41:55 +08:00
parent d22ded21f8
commit 599c597e69
25 changed files with 1509 additions and 78 deletions
+4
View File
@@ -0,0 +1,4 @@
from .factory import get_cache_store
from .interfaces import CacheStore
__all__ = ["CacheStore", "get_cache_store"]
+13
View File
@@ -0,0 +1,13 @@
from __future__ import annotations
from .interfaces import CacheStore
from .redis_store import RedisCacheStore
_cache_store: CacheStore | None = None
def get_cache_store() -> CacheStore:
global _cache_store
if _cache_store is None:
_cache_store = RedisCacheStore()
return _cache_store
+19
View File
@@ -0,0 +1,19 @@
from __future__ import annotations
from typing import Protocol
class CacheStore(Protocol):
async def hgetall(self, key: str, /) -> dict[str, str]: ...
async def hset(self, key: str, /, mapping: dict[str, str]) -> int: ...
async def hincrby(self, key: str, field: str, amount: int = 1, /) -> int: ...
async def expire(self, key: str, ttl_seconds: int, /) -> int: ...
async def delete(self, *keys: str) -> int: ...
async def sadd(self, key: str, *members: str) -> int: ...
async def smembers(self, key: str, /) -> set[str]: ...
@@ -0,0 +1,80 @@
from __future__ import annotations
import inspect
from typing import Any
from services.base.redis import get_or_init_redis_client
from .interfaces import CacheStore
def _to_text(value: Any) -> str | None:
if isinstance(value, str):
return value
if isinstance(value, bytes):
try:
return value.decode("utf-8")
except UnicodeDecodeError:
return None
return None
async def _maybe_await(value: Any) -> Any:
if inspect.isawaitable(value):
return await value
return value
class RedisCacheStore(CacheStore):
async def hgetall(self, key: str) -> dict[str, str]:
client = await get_or_init_redis_client()
raw = await _maybe_await(client.hgetall(key))
if not isinstance(raw, dict):
return {}
decoded: dict[str, str] = {}
for raw_key, raw_value in raw.items():
key_text = _to_text(raw_key)
value_text = _to_text(raw_value)
if key_text is None or value_text is None:
continue
decoded[key_text] = value_text
return decoded
async def hset(self, key: str, mapping: dict[str, str]) -> int:
client = await get_or_init_redis_client()
result = await _maybe_await(client.hset(key, mapping=mapping))
return int(result)
async def hincrby(self, key: str, field: str, amount: int = 1) -> int:
client = await get_or_init_redis_client()
result = await _maybe_await(client.hincrby(key, field, amount))
return int(result)
async def expire(self, key: str, ttl_seconds: int) -> int:
client = await get_or_init_redis_client()
result = await _maybe_await(client.expire(key, ttl_seconds))
return int(result)
async def delete(self, *keys: str) -> int:
if not keys:
return 0
client = await get_or_init_redis_client()
result = await _maybe_await(client.delete(*keys))
return int(result)
async def sadd(self, key: str, *members: str) -> int:
if not members:
return 0
client = await get_or_init_redis_client()
result = await _maybe_await(client.sadd(key, *members))
return int(result)
async def smembers(self, key: str) -> set[str]:
client = await get_or_init_redis_client()
raw = await _maybe_await(client.smembers(key))
if isinstance(raw, set):
return {value for item in raw if (value := _to_text(item))}
if isinstance(raw, list | tuple):
return {value for item in raw if (value := _to_text(item))}
return set()