Skip to content

fix(mem0): build v2-compatible search filters for mixed entity IDs#835

Open
liuxiaopai-ai wants to merge 1 commit intoagentscope-ai:mainfrom
liuxiaopai-ai:fix/mem0-filter-logical-823
Open

fix(mem0): build v2-compatible search filters for mixed entity IDs#835
liuxiaopai-ai wants to merge 1 commit intoagentscope-ai:mainfrom
liuxiaopai-ai:fix/mem0-filter-logical-823

Conversation

@liuxiaopai-ai
Copy link

@liuxiaopai-ai liuxiaopai-ai commented Feb 26, 2026

Summary

Fixes #823 by generating Mem0 search filters that match v2 syntax and expected matching semantics:

  • Use OR when multiple entity IDs are present (user_id, agent_id, run_id) instead of implicit top-level AND.
  • Nest custom metadata under the supported metadata field (instead of flattening metadata keys at filter root).
  • Combine entity expression and metadata expression with AND to preserve retrieval narrowing by metadata.

Why

Issue #823 reported two problems in current request building:

  1. user_id + agent_id were serialized as sibling filter keys (implicit AND), which can miss records when memory belongs to only one entity dimension.
  2. Custom metadata keys were flattened into the top-level filter object, which is incompatible with Mem0 v2 filter syntax (allowed roots are logical operators + known fields).

Implementation notes

  • Updated Mem0LongTermMemory.buildSearchRequest to build filters through a dedicated helper:
    • Entity filters -> single clause or OR expression.
    • Metadata -> { "metadata": { ... } }.
    • Final filter -> AND(entityExpr, metadataExpr) when both exist.
  • Kept changes scoped to Mem0 long-term memory request construction to minimize blast radius.

Tests

Added request-shape assertions in Mem0LongTermMemoryTest:

  • testRetrieveUsesOrForMultipleEntityFilters
  • testRetrieveNestsMetadataUnderMetadataFilterField

Validation performed:

  • New tests fail against old implementation (verified locally).
  • Full targeted suite passes after fix:
mvn -pl agentscope-extensions/agentscope-extensions-mem0 -am \
  -DskipITs -DskipIntegrationTests \
  test -Dtest=Mem0LongTermMemoryTest,Mem0SearchRequestTest,Mem0ClientTest

Result: Tests run: 74, Failures: 0, Errors: 0, Skipped: 0

@liuxiaopai-ai liuxiaopai-ai requested a review from a team February 26, 2026 18:50
@cla-assistant
Copy link

cla-assistant bot commented Feb 26, 2026

CLA assistant check
Thank you for your submission! We really appreciate it. Like many open source projects, we ask that you sign our Contributor License Agreement before we can accept your contribution.


root seems not to be a GitHub user. You need a GitHub account to be able to sign the CLA. If you have already a GitHub account, please add the email address used for this commit to your account.
You have signed the CLA already but the status is still pending? Let us recheck it.

@gemini-code-assist
Copy link

Summary of Changes

Hello @liuxiaopai-ai, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed!

This pull request addresses compatibility issues with Mem0 v2 API search filters by refactoring the filter construction logic within Mem0LongTermMemory. The changes ensure that search requests correctly handle multiple entity IDs with OR conditions and properly nest custom metadata under a dedicated metadata field, aligning with the v2 API specification. This resolves issues where records might be missed or filters were incorrectly applied, and new tests have been added to validate the updated filter generation.

Highlights

  • Entity ID Filtering Logic: Modified the Mem0LongTermMemory to use OR logic when multiple entity IDs (userId, agentId, runId) are present in search filters, preventing missed records due to implicit AND behavior.
  • Custom Metadata Handling: Ensured custom metadata is correctly nested under a dedicated "metadata" field in Mem0 v2 search filters, aligning with the new API syntax and preventing flattening at the filter root.
  • Combined Filter Logic: Implemented an AND combination for entity expressions and metadata expressions when both are present, preserving the intended retrieval narrowing by metadata.
Changelog
  • agentscope-extensions/agentscope-extensions-mem0/src/main/java/io/agentscope/core/memory/mem0/Mem0LongTermMemory.java
    • Imported ArrayList and HashMap for new filter construction logic.
    • Refactored buildSearchRequest to delegate filter construction to a new buildSearchFilters method.
    • Introduced buildSearchFilters to create v2-compatible filters, handling OR for multiple entity IDs and nesting metadata under a metadata field.
    • Added addEntityFilter helper method to conditionally add entity filters.
  • agentscope-extensions/agentscope-extensions-mem0/src/test/java/io/agentscope/core/memory/mem0/Mem0LongTermMemoryTest.java
    • Added imports for assertFalse, assertTrue, TypeReference, JsonUtils, Map, and RecordedRequest for new test assertions.
    • Added testRetrieveUsesOrForMultipleEntityFilters to verify the OR logic for multiple entity IDs in the generated search filters.
    • Added testRetrieveNestsMetadataUnderMetadataFilterField to verify correct metadata nesting and AND combination in search filters.
Activity
  • The author identified and fixed two problems in the current request building: implicit AND for entity IDs and flattened custom metadata keys.
  • The author updated Mem0LongTermMemory to build filters through dedicated helper methods.
  • The author added request-shape assertions in Mem0LongTermMemoryTest to validate the new filter logic.
  • The author validated that new tests fail against the old implementation and pass after the fix.
Using Gemini Code Assist

The full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips.

Invoking Gemini

You can request assistance from Gemini at any point by creating a comment using either /gemini <command> or @gemini-code-assist <command>. Below is a summary of the supported commands on the current page.

Feature Command Description
Code Review /gemini review Performs a code review for the current pull request in its current state.
Pull Request Summary /gemini summary Provides a summary of the current pull request in its current state.
Comment @gemini-code-assist Responds in comments when explicitly tagged, both in pull request comments and review comments.
Help /gemini help Displays a list of available commands.

Customization

To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a .gemini/ folder in the base of the repository. Detailed instructions can be found here.

Limitations & Feedback

Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for Github and other Google products, sign up here.

You can also get AI-powered code generation, chat, as well as code reviews directly in the IDE at no cost with the Gemini Code Assist IDE Extension.

Footnotes

  1. Review the Privacy Notices, Generative AI Prohibited Use Policy, Terms of Service, and learn how to configure Gemini Code Assist in GitHub here. Gemini can make mistakes, so double check it and use code with caution.

Copy link

@gemini-code-assist gemini-code-assist bot left a comment

Choose a reason for hiding this comment

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

Code Review

This pull request correctly addresses an issue with Mem0 search filter generation by implementing OR logic for multiple entity IDs and properly nesting custom metadata. The logic is sound and well-tested. I've provided a couple of suggestions to further improve code clarity and remove a minor redundancy.

Comment on lines +240 to +241
Mem0SearchRequest request =
Mem0SearchRequest.builder().query(query).userId(userId).topK(5).build();

Choose a reason for hiding this comment

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

medium

The .userId(userId) call here is redundant. The Mem0SearchRequest.Builder::userId method does modify the request's filters, but this is immediately overwritten by the request.setFilters(buildSearchFilters()) call on the next line. The new buildSearchFilters() method already handles the userId correctly. Removing this redundant call will make the code cleaner and prevent potential confusion.

Suggested change
Mem0SearchRequest request =
Mem0SearchRequest.builder().query(query).userId(userId).topK(5).build();
Mem0SearchRequest request =
Mem0SearchRequest.builder().query(query).topK(5).build();

Comment on lines +262 to +277
if (entityExpression != null && metadataExpression != null) {
List<Map<String, Object>> andExpressions = new ArrayList<>();
andExpressions.add(entityExpression);
andExpressions.add(metadataExpression);
return Map.of("AND", andExpressions);
}

if (entityExpression != null) {
return entityExpression;
}

if (metadataExpression != null) {
return metadataExpression;
}

return builder.build();
return new HashMap<>();

Choose a reason for hiding this comment

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

medium

The logic for combining entityExpression and metadataExpression can be simplified for better readability and maintainability. Instead of multiple if statements to handle the different combinations, you can collect all non-null expressions into a list and then decide how to combine them. This approach is more concise and easier to extend if more filter expressions are added in the future.

        List<Map<String, Object>> finalExpressions = new ArrayList<>();
        if (entityExpression != null) {
            finalExpressions.add(entityExpression);
        }
        if (metadataExpression != null) {
            finalExpressions.add(metadataExpression);
        }

        if (finalExpressions.isEmpty()) {
            return new HashMap<>();
        }

        if (finalExpressions.size() == 1) {
            return finalExpressions.get(0);
        }

        return Map.of("AND", finalExpressions);

@codecov
Copy link

codecov bot commented Feb 26, 2026

Codecov Report

❌ Patch coverage is 72.00000% with 7 lines in your changes missing coverage. Please review.

Files with missing lines Patch % Lines
...gentscope/core/memory/mem0/Mem0LongTermMemory.java 72.00% 3 Missing and 4 partials ⚠️

📢 Thoughts on this report? Let us know!

@LearningGp
Copy link
Collaborator

image

@LearningGp
Copy link
Collaborator

PTAL @shiyiyue1102

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Bug]:mem0 filter for metadata has syntax error; user_id, agent_id in filter is OR not AND logic

2 participants