Python: add RedisContextProvider (#716)

* Setting up

* Readme

* Add redis tests path to all-tests

* First pass integration

* Keep provider convention

* First pass integration

* add redis integration tests

* update README.md

* Add basic sample for redis integration

* Add partitioning, add partition-aware tests, improve sample script

* Fix code quality check

* Try to resolve pytest check

* Try to identify if pytest is the cause of failed checks

* Re-enable tests

* Rename redis test file

* Removing some tests to narrow down issue

* Revert, no difference

* Delete temp files

* Starting refactor of RedisProvider

* Build dynamic schema builder, still need to do dynamic embedding model config

* Add scope control

* Complete first pass functionality with OpenAI + HF vectors -> Tests, Samples, Demo to follow

* Fix code quality

* attempt to identify rootcause of failed test

* attempt to identify rootcause of failed test

* Attempt to resolve code quality fail

* Update pyproject.toml for foundry to pin     azure-ai-projects == 1.1.0b3,azure-ai-agents == 1.2.0b3

* Add tests for redisprovider

* Remove invalid tests

* Add API key handling for openai vectorizer

* Update uv.locl

* Use master uv.lock

* Begin sample file, add lazy index creation, fix faulty override

* Index drop and reinit depends on drop_redis_index not overwrite

* Add samples, threading included, escaped queries, verify threading works, sample README.md

* Refactor filters

* Opinionated vars

* Allow filter expression combination

* Try inline stubs for mypy

* Address mypy errors

* Better docstrings, tweaks for feedback

* Tweak example 3 in redis_threads.py sample

* adjust confusing name

* Enrich docstrings

* Add descriptions and comments to samples, externalize vectorizer choice, remove nltk and sentencetransformers dependnecy

* Add descriptions and comments to samples, externalize vectorizer choice, remove nltk and sentencetransformers dependnecy

* Incorporate initial feedback from dmytrostruk

* Fix uv.lock

* Attempt to resolve conflict

* Use remote .tomls

* Sanity check

* fix tests

* Remove hardcoded API key from samples

* Fix incorrect env var

* Make add and redis_search private

* Fix tests relying on private funcs

* Expand tests

* Explainer comments to each test

* Add a 'get_conversation_history' function to RedisProvider - This just returns messages in sequential order. Added 'created_at_*' timestamps to facilitate sequential recovery. function has to be manually invoked by user

* Add agent-framework-redis to  python/pyproject.toml

* Remove get_conversation_history

* improve redis context provider with pydantic techniques and safe index handling patterns

* add RedisChatMessageStore

* remove integration test :(

* fix mypy error

* Remove unused params

* Redo schema validation to be order-invariant, handle attrs (previously throwing errors due to strict ==)

* Expand explanation

* Add ChatMessageStore example

* Fix comments in redis_conversation.py

* Resolving uv.lock conflict, update to match main

* Fix test in redis provider

* Apply suggestion from @ekzhu

* Update python/packages/main/pyproject.toml

---------

Co-authored-by: Tyler Hutcherson <tyler.hutcherson@redis.com>
Co-authored-by: Eric Zhu <ekzhu@users.noreply.github.com>
This commit is contained in:
Han
2025-09-23 08:36:27 +08:00
committed by GitHub
Unverified
parent 1ef24d3e91
commit ca810076e8
23 changed files with 3406 additions and 10 deletions
@@ -2,7 +2,7 @@
import sys
from collections.abc import MutableSequence, Sequence
from typing import Any, Final
from typing import Any
from agent_framework import ChatMessage, Context, ContextProvider, TextContent
from agent_framework.exceptions import ServiceInitializationError
@@ -15,9 +15,6 @@ else:
from typing_extensions import Self # pragma: no cover
DEFAULT_CONTEXT_PROMPT: Final[str] = "## Memories\nConsider the following memories when answering user questions:"
class Mem0Provider(ContextProvider):
mem0_client: AsyncMemoryClient
api_key: str | None = None
@@ -26,7 +23,7 @@ class Mem0Provider(ContextProvider):
thread_id: str | None = None
user_id: str | None = None
scope_to_per_operation_thread_id: bool = False
context_prompt: str = DEFAULT_CONTEXT_PROMPT
context_prompt: str = ContextProvider.DEFAULT_CONTEXT_PROMPT
_should_close_client: bool = PrivateAttr(default=False) # Track whether we should close client connection
@@ -38,7 +35,7 @@ class Mem0Provider(ContextProvider):
thread_id: str | None = None,
user_id: str | None = None,
scope_to_per_operation_thread_id: bool = False,
context_prompt: str = DEFAULT_CONTEXT_PROMPT,
context_prompt: str = ContextProvider.DEFAULT_CONTEXT_PROMPT,
mem0_client: AsyncMemoryClient | None = None,
) -> None:
"""Initializes a new instance of the Mem0Provider class.