Python: Remove unsupported memory scoping params from mem0/redis samples and docs (#4367)

* Python: Remove unsupported memory scoping params from samples and docs

Fixes #4353

The `Mem0ContextProvider` and `RedisContextProvider` no longer support
`thread_id` or `scope_to_per_operation_thread_id` parameters. This commit
updates the affected samples and READMEs to use only the currently
supported API (`user_id`, `agent_id`, `application_id`).

Changes:
- mem0_sessions.py: Remove `thread_id` and
  `scope_to_per_operation_thread_id` from examples 1 and 2, rewrite to
  demonstrate user-scoped and agent-scoped memory patterns
- redis_sessions.py: Update module docstring to remove references to
  removed thread scoping params
- mem0/README.md: Update Memory Scoping docs to reflect current API
- redis/README.md: Remove `thread_id` and
  `scope_to_per_operation_thread_id` references from docs

* Address Copilot review: rename thread_scope functions, fix docstring

- Rename `example_global_thread_scope` -> `example_global_memory_scope`
- Rename `example_per_operation_thread_scope` -> `example_agent_scoped_memory`
- Update example 2 docstring to mention `application_id` alongside
  `user_id` and `agent_id` since it's set in the provider config
- Update module docstring scenario 2 to include `application_id`

* fix: rebase onto main, address giles17 review feedback

- Resolve merge conflicts by rebasing all 4 original files onto current main
- Address giles17's agent review suggestions:
  - mem0_basic.py: update comment to remove thread_id from scoping list
  - mem0_oss.py: update comment to remove thread_id from scoping list
  - redis_sessions.py: rename Example 2 from "Agent-Scoped Memory" to
    "Hybrid Vector Search" to accurately describe what it demonstrates
  - redis/README.md: update Example 2 description to match renamed example

---------

Co-authored-by: Tao Chen <taochen@microsoft.com>
Co-authored-by: Giles Odigwe <79032838+giles17@users.noreply.github.com>
This commit is contained in:
L. Elaine Dazzio
2026-03-31 17:57:23 -04:00
committed by GitHub
Unverified
parent 3a49b1d6dd
commit 1e527a328c
6 changed files with 81 additions and 99 deletions
@@ -9,7 +9,7 @@ This folder contains examples demonstrating how to use the Mem0 context provider
| File | Description |
|------|-------------|
| [`mem0_basic.py`](mem0_basic.py) | Basic example of using Mem0 context provider to store and retrieve user preferences across different conversation threads. |
| [`mem0_sessions.py`](mem0_sessions.py) | Advanced example demonstrating different thread scoping strategies with Mem0. Covers global thread scope (memories shared across all operations), per-operation thread scope (memories isolated per thread), and multiple agents with different memory configurations for personal vs. work contexts. |
| [`mem0_sessions.py`](mem0_sessions.py) | Example demonstrating different memory scoping strategies with Mem0. Covers user-scoped memory (memories shared across all sessions for the same user), agent-scoped memory (memories isolated per agent), and multiple agents with different memory configurations for personal vs. work contexts. |
| [`mem0_oss.py`](mem0_oss.py) | Example of using the Mem0 Open Source self-hosted version as the context provider. Demonstrates setup and configuration for local deployment. |
## Prerequisites
@@ -40,16 +40,8 @@ Set the following environment variables:
### Memory Scoping
The Mem0 context provider supports different scoping strategies:
The Mem0 context provider supports scoping via identifiers:
- **Global Scope** (`scope_to_per_operation_thread_id=False`): Memories are shared across all conversation threads
- **Thread Scope** (`scope_to_per_operation_thread_id=True`): Memories are isolated per conversation thread
### Memory Association
Mem0 records can be associated with different identifiers:
- `user_id`: Associate memories with a specific user
- `agent_id`: Associate memories with a specific agent
- `thread_id`: Associate memories with a specific conversation thread
- `application_id`: Associate memories with an application context
- **User scope** (`user_id`): Associate memories with a specific user, shared across all sessions
- **Agent scope** (`agent_id`): Isolate memories per agent persona
- **Application scope** (`application_id`): Associate memories with an application context
@@ -31,7 +31,7 @@ def retrieve_company_report(company_code: str, detailed: bool) -> str:
async def main() -> None:
"""Example of memory usage with Mem0 context provider."""
print("=== Mem0 Context Provider Example ===")
# Each record in Mem0 should be associated with agent_id or user_id or application_id or thread_id.
# Each record in Mem0 should be associated with agent_id or user_id or application_id.
# In this example, we associate Mem0 records with user_id.
user_id = str(uuid.uuid4())
# For Azure authentication, run `az login` command in terminal or replace AzureCliCredential with preferred
@@ -32,7 +32,7 @@ def retrieve_company_report(company_code: str, detailed: bool) -> str:
async def main() -> None:
"""Example of memory usage with local Mem0 OSS context provider."""
print("=== Mem0 Context Provider Example ===")
# Each record in Mem0 should be associated with agent_id or user_id or application_id or thread_id.
# Each record in Mem0 should be associated with agent_id or user_id or application_id.
# In this example, we associate Mem0 records with user_id.
user_id = str(uuid.uuid4())
# For Azure authentication, run `az login` command in terminal or replace AzureCliCredential with preferred
@@ -1,7 +1,6 @@
# Copyright (c) Microsoft. All rights reserved.
import asyncio
import uuid
from agent_framework import Agent, tool
from agent_framework.foundry import FoundryChatClient
@@ -27,52 +26,49 @@ def get_user_preferences(user_id: str) -> str:
return preferences.get(user_id, "No specific preferences found")
async def example_global_thread_scope() -> None:
"""Example 1: Global thread_id scope (memories shared across all operations)."""
print("1. Global Thread Scope Example:")
async def example_user_scoped_memory() -> None:
"""Example 1: User-scoped memory (memories shared across all sessions for the same user)."""
print("1. User-Scoped Memory Example:")
print("-" * 40)
global_thread_id = str(uuid.uuid4())
user_id = "user123"
async with (
AzureCliCredential() as credential,
Agent(
client=FoundryChatClient(credential=credential),
name="GlobalMemoryAssistant",
name="UserMemoryAssistant",
instructions="You are an assistant that remembers user preferences across conversations.",
tools=get_user_preferences,
context_providers=[
Mem0ContextProvider(
source_id="mem0",
user_id=user_id,
thread_id=global_thread_id,
scope_to_per_operation_thread_id=False, # Share memories across all sessions
)
],
) as global_agent,
) as user_agent,
):
# Store some preferences in the global scope
# Store some preferences
query = "Remember that I prefer technical responses with code examples when discussing programming."
print(f"User: {query}")
result = await global_agent.run(query)
result = await user_agent.run(query)
print(f"Agent: {result}\n")
# Create a new session - but memories should still be accessible due to global scope
new_session = global_agent.create_session()
# Create a new session - memories should still be accessible via user_id scoping
new_session = user_agent.create_session()
query = "What do you know about my preferences?"
print(f"User (new session): {query}")
result = await global_agent.run(query, session=new_session)
result = await user_agent.run(query, session=new_session)
print(f"Agent: {result}\n")
async def example_per_operation_thread_scope() -> None:
"""Example 2: Per-operation thread scope (memories isolated per session).
async def example_agent_scoped_memory() -> None:
"""Example 2: Agent-scoped memory (memories isolated per agent_id).
Note: When scope_to_per_operation_thread_id=True, the provider is bound to a single session
throughout its lifetime. Use the same session object for all operations with that provider.
Note: Use different agent_id values to isolate memories between different
agent personas, even when the user_id is the same.
"""
print("2. Per-Operation Thread Scope Example:")
print("2. Agent-Scoped Memory Example:")
print("-" * 40)
user_id = "user123"
@@ -82,48 +78,45 @@ async def example_per_operation_thread_scope() -> None:
Agent(
client=FoundryChatClient(credential=credential),
name="ScopedMemoryAssistant",
instructions="You are an assistant with thread-scoped memory.",
instructions="You are an assistant with agent-scoped memory.",
tools=get_user_preferences,
context_providers=[
Mem0ContextProvider(
source_id="mem0",
user_id=user_id,
scope_to_per_operation_thread_id=True, # Isolate memories per session
agent_id="scoped_assistant",
)
],
) as scoped_agent,
):
# Create a specific session for this scoped provider
dedicated_session = scoped_agent.create_session()
# Store some information in the dedicated session
# Store some information
query = "Remember that for this conversation, I'm working on a Python project about data analysis."
print(f"User (dedicated session): {query}")
result = await scoped_agent.run(query, session=dedicated_session)
print(f"User: {query}")
result = await scoped_agent.run(query)
print(f"Agent: {result}\n")
# Test memory retrieval in the same dedicated session
# Test memory retrieval
query = "What project am I working on?"
print(f"User (same dedicated session): {query}")
result = await scoped_agent.run(query, session=dedicated_session)
print(f"User: {query}")
result = await scoped_agent.run(query)
print(f"Agent: {result}\n")
# Store more information in the same session
# Store more information
query = "Also remember that I prefer using pandas and matplotlib for this project."
print(f"User (same dedicated session): {query}")
result = await scoped_agent.run(query, session=dedicated_session)
print(f"User: {query}")
result = await scoped_agent.run(query)
print(f"Agent: {result}\n")
# Test comprehensive memory retrieval
query = "What do you know about my current project and preferences?"
print(f"User (same dedicated session): {query}")
result = await scoped_agent.run(query, session=dedicated_session)
print(f"User: {query}")
result = await scoped_agent.run(query)
print(f"Agent: {result}\n")
async def example_multiple_agents() -> None:
"""Example 3: Multiple agents with different thread configurations."""
print("3. Multiple Agents with Different Thread Configurations:")
"""Example 3: Multiple agents with different memory configurations."""
print("3. Multiple Agents with Different Memory Configurations:")
print("-" * 40)
agent_id_1 = "agent_personal"
@@ -178,11 +171,11 @@ async def example_multiple_agents() -> None:
async def main() -> None:
"""Run all Mem0 thread management examples."""
print("=== Mem0 Thread Management Example ===\n")
"""Run all Mem0 memory management examples."""
print("=== Mem0 Memory Management Example ===\n")
await example_global_thread_scope()
await example_per_operation_thread_scope()
await example_user_scoped_memory()
await example_agent_scoped_memory()
await example_multiple_agents()
@@ -11,7 +11,7 @@ This folder contains an example demonstrating how to use the Redis context provi
| [`azure_redis_conversation.py`](azure_redis_conversation.py) | Demonstrates conversation persistence with RedisHistoryProvider and Azure Redis with Azure AD (Entra ID) authentication using credential provider. |
| [`redis_basics.py`](redis_basics.py) | Shows standalone provider usage and agent integration. Demonstrates writing messages to Redis, retrieving context via fulltext or hybrid vector search, and persisting preferences across threads. Also includes a simple tool example whose outputs are remembered. |
| [`redis_conversation.py`](redis_conversation.py) | Simple example showing conversation persistence with RedisContextProvider using traditional connection string authentication. |
| [`redis_sessions.py`](redis_sessions.py) | Demonstrates thread scoping. Includes: (1) global thread scope with a fixed `thread_id` shared across operations; (2) peroperation thread scope where `scope_to_per_operation_thread_id=True` binds memory to a single thread for the provider's lifetime; and (3) multiple agents with isolated memory via different `agent_id` values. |
| [`redis_sessions.py`](redis_sessions.py) | Demonstrates memory scoping strategies. Includes: (1) global memory scope with `application_id`, `agent_id`, and `user_id` shared across operations; (2) hybrid vector search using a custom OpenAI vectorizer for richer context retrieval; and (3) multiple agents with isolated memory via different `agent_id` values. |
## Prerequisites
@@ -61,8 +61,7 @@ The provider supports both fulltext only and hybrid vector search:
- Set `vectorizer_choice` to `"openai"` or `"hf"` to enable embeddings and hybrid search.
- When using a vectorizer, also set `vector_field_name` (e.g., `"vector"`).
- Partition fields for scoping memory: `application_id`, `agent_id`, `user_id`, `thread_id`.
- Thread scoping: `scope_to_per_operation_thread_id=True` isolates memory per operation thread.
- Partition fields for scoping memory: `application_id`, `agent_id`, `user_id`.
- Index management: `index_name`, `overwrite_redis_index`, `drop_redis_index`.
## What the example does
@@ -104,8 +103,8 @@ You should see the agent responses and, when using embeddings, context retrieved
### Memory scoping
- Global scope: set `application_id`, `agent_id`, `user_id`, or `thread_id` on the provider to filter memory.
- Peroperation thread scope: set `scope_to_per_operation_thread_id=True` to isolate memory to the current thread created by the framework.
- Global scope: set `application_id`, `agent_id`, or `user_id` on the provider to filter memory.
- Agent isolation: use different `agent_id` values to keep memories separated for different agent personas.
### Hybrid vector search (optional)
@@ -118,7 +117,7 @@ You should see the agent responses and, when using embeddings, context retrieved
## Troubleshooting
- Ensure at least one of `application_id`, `agent_id`, `user_id`, or `thread_id` is set; the provider requires a scope.
- Ensure at least one of `application_id`, `agent_id`, or `user_id` is set; the provider requires a scope.
- Verify `FOUNDRY_PROJECT_ENDPOINT` and `FOUNDRY_MODEL` are set for the chat client.
- If using embeddings, verify `OPENAI_API_KEY` is set and reachable.
- Make sure Redis exposes RediSearch (Redis Stack image or managed service with search enabled).
@@ -1,17 +1,18 @@
# Copyright (c) Microsoft. All rights reserved.
"""Redis Context Provider: Thread scoping examples
"""Redis Context Provider: Memory scoping examples
This sample demonstrates how conversational memory can be scoped when using the
Redis context provider. It covers three scenarios:
1) Global thread scope
- Provide a fixed thread_id to share memories across operations/threads.
1) Global memory scope
- Use application_id, agent_id, and user_id to share memories across
all operations/sessions.
2) Per-operation thread scope
- Enable scope_to_per_operation_thread_id to bind the provider to a single
thread for the lifetime of that provider instance. Use the same thread
object for reads/writes with that provider.
2) Hybrid vector search
- Use a custom OpenAI vectorizer with the provider for hybrid vector search.
Demonstrates combining full-text and semantic search for richer context
retrieval.
3) Multiple agents with isolated memory
- Use different agent_id values to keep memories separated for different
@@ -23,7 +24,7 @@ Requirements:
- Optionally an OpenAI API key for the chat client in this demo
Run:
python redis_threads.py
python redis_sessions.py
"""
import asyncio
@@ -55,9 +56,9 @@ def create_chat_client() -> FoundryChatClient:
)
async def example_global_thread_scope() -> None:
"""Example 1: Global thread_id scope (memories shared across all operations)."""
print("1. Global Thread Scope Example:")
async def example_global_memory_scope() -> None:
"""Example 1: Global memory scope (memories shared across all operations)."""
print("1. Global Memory Scope Example:")
print("-" * 40)
client = create_chat_client()
@@ -99,13 +100,13 @@ async def example_global_thread_scope() -> None:
await provider.redis_index.delete()
async def example_per_operation_thread_scope() -> None:
"""Example 2: Per-operation thread scope (memories isolated per session).
async def example_hybrid_vector_search() -> None:
"""Example 2: Hybrid vector search with custom vectorizer.
Note: When scope_to_per_operation_thread_id=True, the provider is bound to a single session
throughout its lifetime. Use the same session object for all operations with that provider.
Demonstrates using a custom OpenAI vectorizer for hybrid vector search,
combining full-text and semantic search for richer context retrieval.
"""
print("2. Per-Operation Thread Scope Example:")
print("2. Hybrid Vector Search Example:")
print("-" * 40)
client = create_chat_client()
@@ -131,36 +132,33 @@ async def example_per_operation_thread_scope() -> None:
agent = Agent(
client=client,
name="ScopedMemoryAssistant",
instructions="You are an assistant with thread-scoped memory.",
name="HybridSearchAssistant",
instructions="You are an assistant with hybrid vector search for richer context retrieval.",
context_providers=[provider],
)
# Create a specific session for this scoped provider
dedicated_session = agent.create_session()
# Store some information in the dedicated session
# Store some information
query = "Remember that for this conversation, I'm working on a Python project about data analysis."
print(f"User (dedicated session): {query}")
result = await agent.run(query, session=dedicated_session)
print(f"User: {query}")
result = await agent.run(query)
print(f"Agent: {result}\n")
# Test memory retrieval in the same dedicated session
# Test memory retrieval via hybrid search
query = "What project am I working on?"
print(f"User (same dedicated session): {query}")
result = await agent.run(query, session=dedicated_session)
print(f"User: {query}")
result = await agent.run(query)
print(f"Agent: {result}\n")
# Store more information in the same session
# Store more information
query = "Also remember that I prefer using pandas and matplotlib for this project."
print(f"User (same dedicated session): {query}")
result = await agent.run(query, session=dedicated_session)
print(f"User: {query}")
result = await agent.run(query)
print(f"Agent: {result}\n")
# Test comprehensive memory retrieval
query = "What do you know about my current project and preferences?"
print(f"User (same dedicated session): {query}")
result = await agent.run(query, session=dedicated_session)
print(f"User: {query}")
result = await agent.run(query)
print(f"Agent: {result}\n")
# Clean up the Redis index
@@ -168,8 +166,8 @@ async def example_per_operation_thread_scope() -> None:
async def example_multiple_agents() -> None:
"""Example 3: Multiple agents with different thread configurations (isolated via agent_id) but within 1 index."""
print("3. Multiple Agents with Different Thread Configurations:")
"""Example 3: Multiple agents with different memory configurations (isolated via agent_id) but within 1 index."""
print("3. Multiple Agents with Different Memory Configurations:")
print("-" * 40)
client = create_chat_client()
@@ -247,9 +245,9 @@ async def example_multiple_agents() -> None:
async def main() -> None:
print("=== Redis Thread Scoping Examples ===\n")
await example_global_thread_scope()
await example_per_operation_thread_scope()
print("=== Redis Memory Scoping Examples ===\n")
await example_global_memory_scope()
await example_hybrid_vector_search()
await example_multiple_agents()