jeevesagent.memory.redis
========================

.. py:module:: jeevesagent.memory.redis

.. autoapi-nested-parse::

   Redis-backed :class:`Memory`.

   Two flavours, picked at construction time:

   * **vector mode** (default when RediSearch is available) — episodes
     are stored as Redis hashes; a RediSearch ``FT.CREATE`` index with
     ``HNSW`` provides cosine-similarity recall.
   * **brute-force mode** (when RediSearch isn't available, e.g. plain
     Redis) — episodes still go to hashes but recall scans every
     episode in process. Fine for small corpora; switch to the vector
     mode (RedisStack) for production scale.

   Both modes use the ``redis.asyncio`` client. Working blocks live in
   process memory; the redundancy of putting them in Redis isn't worth
   the extra round-trip for the small payloads we have.



Attributes
----------

.. autoapisummary::

   jeevesagent.memory.redis.DEFAULT_INDEX_NAME
   jeevesagent.memory.redis.DEFAULT_KEY_PREFIX


Classes
-------

.. autoapisummary::

   jeevesagent.memory.redis.RedisMemory


Module Contents
---------------

.. py:class:: RedisMemory(client: Any, *, embedder: jeevesagent.core.protocols.Embedder | None = None, key_prefix: str = DEFAULT_KEY_PREFIX, index_name: str = DEFAULT_INDEX_NAME, use_vector_index: bool = True, fact_store: Any | None = None)

   Redis-backed :class:`Memory`. Use :meth:`connect` to construct.


   .. py:method:: aclose() -> None
      :async:



   .. py:method:: append_block(name: str, content: str) -> None
      :async:



   .. py:method:: connect(url: str = 'redis://localhost:6379/0', *, embedder: jeevesagent.core.protocols.Embedder | None = None, key_prefix: str = DEFAULT_KEY_PREFIX, index_name: str = DEFAULT_INDEX_NAME, use_vector_index: bool = True, with_facts: bool = False, fact_key_prefix: str = 'jeeves:fact:') -> RedisMemory
      :classmethod:

      :async:


      Open an async Redis connection.

      ``with_facts=True`` attaches a :class:`RedisFactStore` sharing
      the same client; facts go to ``{fact_key_prefix}*`` keys so
      they don't collide with episode keys.



   .. py:method:: consolidate() -> None
      :async:



   .. py:method:: ensure_index() -> None
      :async:


      Create the RediSearch HNSW index, if not already present.

      Skipped silently when ``use_vector_index=False`` or when
      RediSearch isn't available on the server.



   .. py:method:: recall(query: str, *, kind: str = 'episodic', limit: int = 5, time_range: tuple[datetime.datetime, datetime.datetime] | None = None, user_id: str | None = None) -> list[jeevesagent.core.types.Episode]
      :async:



   .. py:method:: recall_facts(query: str, *, limit: int = 5, valid_at: datetime.datetime | None = None, user_id: str | None = None) -> list[jeevesagent.core.types.Fact]
      :async:



   .. py:method:: remember(episode: jeevesagent.core.types.Episode) -> str
      :async:



   .. py:method:: session_messages(session_id: str, *, user_id: str | None = None, limit: int = 20) -> list[jeevesagent.core.types.Message]
      :async:



   .. py:method:: update_block(name: str, content: str) -> None
      :async:



   .. py:method:: working() -> list[jeevesagent.core.types.MemoryBlock]
      :async:



   .. py:attribute:: facts
      :type:  Any | None
      :value: None



.. py:data:: DEFAULT_INDEX_NAME
   :value: 'jeeves_idx'


.. py:data:: DEFAULT_KEY_PREFIX
   :value: 'jeeves:episode:'


