Context KV Memory
Context KV memory answers "what is my current session state?" It is a fast, schema-free key-value store for working state that belongs to one agent session: user preferences, task progress, scratch notes, tool-call counters.
It is backed by Redis hashes. Each (agent_id, session_id) pair is one hash, keyed <agent_id>__<session_id>, so:
- all keys of a session can be listed, exported or wiped together;
- a TTL applies to the whole session at once.
Values must be JSON-serializable. They are stored as JSON and returned as Python objects.
Access
from agentic_memory import AgentMemory
with AgentMemory(config) as mem:
kv = mem.context_kv # ContextKVMemory bound to the configured Redis
Or standalone, without the other databases:
from agentic_memory.backends.redis_client import RedisClient
from agentic_memory.config import RedisConfig
from agentic_memory.memory_types.context_kv import ContextKVMemory
redis = RedisClient(RedisConfig(host="localhost", port=6379, password=""))
kv = ContextKVMemory(
redis,
on_set=lambda agent, session, key, value: print("SET", agent, session, key),
on_get=lambda agent, session, key, value: print("GET", agent, session, key),
)
on_get and on_set are optional observability hooks. on_get fires only for values that exist.
Usage
agent, session = "planner-agent", "session-99"
# set / get (a TTL applies to the whole session hash)
kv.set(agent, session, "user_prefs", {"language": "en", "theme": "dark"}, ttl_seconds=600)
kv.set(agent, session, "task_state", {"current_step": 2, "total_steps": 5})
kv.get(agent, session, "user_prefs") # {"language": "en", "theme": "dark"}
kv.get(agent, session, "missing") # None
# discoverability
kv.exists(agent, session, "task_state") # True
kv.keys(agent, session) # ["user_prefs", "task_state"]
# bulk
kv.set_many(agent, session, {"scratch": {"notes": []}, "tool_calls": {"count": 0}})
kv.get_many(agent, session, ["user_prefs", "ghost"]) # {"user_prefs": {...}, "ghost": None}
# atomic initialise-once
state = kv.get_or_set(agent, session, "init_flag", lambda: {"initialized": True})
# snapshot / restore
snapshot = kv.dump(agent, session) # {key: value, ...}
kv.clear(agent, session) # delete the whole session
kv.restore(agent, session, snapshot, ttl_seconds=300)
# delete one key
kv.delete(agent, session, "scratch")
Through AgentMemory
mem.set_context("status", {"ready": True}, agent_id=agent, session_id=session, ttl_seconds=600)
mem.get_context("status", agent_id=agent, session_id=session)
mem.recall("step", agent_id=agent, session_id=session)["context"]
# context entries whose key or value contains "step" (case-insensitive)
Semantics
- TTL —
ttl_secondssets the expiry of the whole session hash (RedisEXPIRE). A latersetwithout a TTL keeps the existing expiry. get_or_set— if the key exists, its value is returned. Otherwise the factory is called and the value is written withHSETNX. If another writer wins the race, their value is returned instead.restore— the same asset_many; it does not clear existing keys first.
API Reference
| Method | Description |
|---|---|
get(agent_id, session_id, key) |
Value or None |
set(agent_id, session_id, key, data, *, ttl_seconds=None) |
Write a value |
delete(agent_id, session_id, key) |
Remove one key |
clear(agent_id, session_id) |
Delete the whole session hash |
exists(agent_id, session_id, key) |
True if present |
keys(agent_id, session_id) |
All keys in the session |
get_many(agent_id, session_id, keys) |
Dict of key → value (or None) in one round-trip |
set_many(agent_id, session_id, mapping, *, ttl_seconds=None) |
Write several keys in one call |
dump(agent_id, session_id) |
Export the session as a dict |
restore(agent_id, session_id, snapshot, *, ttl_seconds=None) |
Bulk-write a snapshot |
get_or_set(agent_id, session_id, key, default_factory, *, ttl_seconds=None) |
Atomic initialise-once |