Skip to content

Python: fix(mem0): support mem0ai 2.x in Mem0ContextProvider - #6129

Closed
youneshima wants to merge 2 commits into
microsoft:mainfrom
youneshima:fix/mem0ai-2x
Closed

Python: fix(mem0): support mem0ai 2.x in Mem0ContextProvider#6129
youneshima wants to merge 2 commits into
microsoft:mainfrom
youneshima:fix/mem0ai-2x

Conversation

@youneshima

Copy link
Copy Markdown

Motivation and Context

agent-framework-mem0 pins mem0ai>=1.0.0,<2, so every install resolves to the legacy mem0ai==1.0.11 rather than the current 2.x line. This bumps the pin to mem0ai>=2.0.0,<3 and adapts Mem0ContextProvider to the mem0 2.x API so new installs land on current mem0.

Description

In mem0 >=2.0, search() rejects top-level entity params (user_id/agent_id/run_id) and requires them in a filters={...} dict — for both the OSS AsyncMemory and Platform AsyncMemoryClient clients. The previous OSS path passed entity IDs as top-level kwargs, which now raises ValueError: Top-level entity parameters ... are not supported in search().

Changes:

  • before_run now passes filters= for both client types (the OSS/Platform branch collapses to the shared 2.x convention).
  • app_id is dropped from the OSS filters: OSS recognizes only user_id/agent_id/run_id as entities, so an app_id filter would be treated as a non-matching metadata filter and silently exclude all results. The Platform client keeps app_id (a recognized Platform entity).
  • add() is unchanged — it still accepts top-level entity kwargs in 2.x.

No change to Mem0ContextProvider's public API (constructor and hook signatures are identical). Not a breaking change for consumers.

Verified end to end against real mem0ai==2.0.4 with an OSS AsyncMemory: the store (after_run) → search (before_run) round trip succeeds, where it raised ValueError before the fix.

Contribution Checklist

  • The code builds clean without any errors or warnings
  • The PR follows the Contribution Guidelines
  • All unit tests pass, and I have added new tests where possible
  • Is this a breaking change? No.

Copilot AI review requested due to automatic review settings May 28, 2026 01:56

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Note

Copilot was unable to run its full agentic suite in this review.

Updates the Mem0 integration to work with mem0ai v2 semantics by passing entity IDs via a filters dict and adjusting behavior around app_id depending on whether the client is OSS or Platform.

Changes:

  • Bump mem0ai dependency from >=1,<2 to >=2,<3.
  • Update Mem0ContextProvider.before_run() to always call search(query=..., filters=...), dropping app_id for OSS AsyncMemory.
  • Update/add tests to assert filter handling for OSS vs Platform clients, including app_id behavior.

Reviewed changes

Copilot reviewed 3 out of 4 changed files in this pull request and generated 3 comments.

File Description
python/packages/mem0/agent_framework_mem0/_context_provider.py Switches Mem0 search to v2-style filters dict; drops app_id for OSS client.
python/packages/mem0/tests/test_mem0_context_provider.py Updates/extends tests to validate new filters behavior for OSS and Platform clients.
python/packages/mem0/pyproject.toml Bumps mem0ai major version constraint to v2.

Comment thread python/packages/mem0/agent_framework_mem0/_context_provider.py
Comment thread python/packages/mem0/tests/test_mem0_context_provider.py Outdated
Comment thread python/packages/mem0/agent_framework_mem0/_context_provider.py
@moonbox3 Evan Mattson (moonbox3) added the python Usage: [Issues, PRs], Target: Python label May 28, 2026
@github-actions github-actions Bot changed the title fix(mem0): support mem0ai 2.x in Mem0ContextProvider Python: fix(mem0): support mem0ai 2.x in Mem0ContextProvider May 28, 2026
@youneshima

Copy link
Copy Markdown
Author

@microsoft-github-policy-service agree company="Mem0"

should_close_client = True

self.api_key = api_key
self.application_id = application_id

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We can throw in an error in case client is OSS client i.e AsyncMemory and application_id is passed as well.

Ideally should be done once we know what type of client is being initialized

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

or the surface can remain application_id but internally we can route it to run_id if this is passed for oss client

from agent_framework._agents import SupportsAgentRun


class _MemorySearchResponse_v1_1(TypedDict):

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We can deprecate this as now search is always a list now.

search_kwargs["filters"] = filters
filters = {key: value for key, value in filters.items() if key != "app_id"}

search_response: _MemorySearchResponse_v1_1 | _MemorySearchResponse_v2 = await self.mem0_client.search( # type: ignore[misc]

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As mentioned above _MemorySearchResponse_v1_1 can be deprecated

"""Validates that at least one usable filter is provided for the configured client."""
if not self.agent_id and not self.user_id and not self.application_id:
raise ValueError("At least one of the filters: agent_id, user_id, or application_id is required.")
if isinstance(self.mem0_client, AsyncMemory) and not self.user_id and not self.agent_id:

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I see the intent but messaging can be improved, right now even if users are sending application_id (in OSS client) it would seem as if it matters but actually it doesn't

messages=messages,
user_id=self.user_id,
agent_id=self.agent_id,
metadata={"application_id": self.application_id},

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If we're passing the application_id in metadata then criticism of it not being supported on OSS client becomes invalid.

Metadata are handled by both SDKs, and also it would break the filters, as direct filter={application_id: "app123"} cannot be used to filter metadata directly on Platform Client

filters["user_id"] = self.user_id
if self.agent_id:
filters["agent_id"] = self.agent_id
if self.application_id:

@whysosaket Saket Aryan (whysosaket) May 30, 2026

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Application ID as mentioned above when passed as metadata cannot directly be used in filter like this

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The Key we're using is application_id on R170 while saving, then while searching how can it be app_id???

filters: dict[str, Any] = {}
if self.user_id:
filters["user_id"] = self.user_id
if self.agent_id:

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

agent_id and user_id are mutually exclusive and tend to break when used together when in same filter group

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is not a major blocker but still an issue

@eavanvalkenburg

Copy link
Copy Markdown
Member

youneshima can you catch up to main and fix the merge conflicts?

search_kwargs.update(filters)
else:
search_kwargs["filters"] = filters
filters = {key: value for key, value in filters.items() if key != "app_id"}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could we update the corresponding platform add path to use this same 2.x filters shape before bumping the dependency? before_run() now searches with filters={...}, but after_run() still calls AsyncMemoryClient.add() with top-level user_id/agent_id and metadata={"application_id": ...}; in mem0ai 2.0.4, that becomes a /v3/memories/add/ payload whose identity fields are not under filters. That can reject platform stores or write memories under a scope this new search path will not read back, and the existing store test still asserts the old payload shape.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Addressed in replacement PR #7004, commit 5018e46: Platform AsyncMemoryClient.add now sends user_id, agent_id, and app_id under filters, while OSS AsyncMemory.add keeps its top-level user_id/agent_id signature.

@eavanvalkenburg

Copy link
Copy Markdown
Member

Superseded by #7004, which applies the mem0ai 2.x compatibility update on the current branch and keeps the Python checks passing.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

python Usage: [Issues, PRs], Target: Python

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants