Skip to content

fix: update mem0 and qdrant dependencies#13292

Merged
erichare merged 2 commits into
release-1.10.0from
fix/mem0-2-qdrant-cve
May 22, 2026
Merged

fix: update mem0 and qdrant dependencies#13292
erichare merged 2 commits into
release-1.10.0from
fix/mem0-2-qdrant-cve

Conversation

@erichare

@erichare erichare commented May 22, 2026

Copy link
Copy Markdown
Collaborator

Summary

  • Upgrade the mem0 optional extra to mem0ai 2.0.2+ and qdrant-client 1.12.0+
  • Update Mem0 read paths to use filters for user scoping with the mem0 2.x API
  • Add regression coverage for search and get_all using filters

Validation

  • uv run pytest src/backend/tests/unit/components/bundles/mem0/test_mem0_component.py
  • uv run ruff check src/lfx/src/lfx/components/mem0/mem0_chat_memory.py src/backend/tests/unit/components/bundles/mem0/test_mem0_component.py
  • uv lock --check
  • git diff --check

Summary by CodeRabbit

  • Chores
    • Updated Mem0 AI dependency to version 2.0.2+
    • Updated Qdrant client dependency to version 1.12.0+
    • Enhanced memory component compatibility with Mem0 2.x API

Review Change Stack

@coderabbitai

coderabbitai Bot commented May 22, 2026

Copy link
Copy Markdown
Contributor

Walkthrough

This PR upgrades mem0ai from 0.1.34 to 2.0.2+, updates qdrant-client to 1.12.0–1.x, and migrates Mem0MemoryComponent.build_search_results() to use Mem0 2.x's filter-based user scoping API. Test coverage validates the new filter-based search() and get_all() calls.

Changes

Mem0 2.x library upgrade

Layer / File(s) Summary
Dependency version updates
src/backend/base/pyproject.toml, src/lfx/src/lfx/_assets/component_index.json
mem0ai upgraded to >=2.0.2,<3.0.0 and qdrant-client to >=1.12.0,<2.0.0; component index metadata reflects new versions and updates file hash.
Mem0 2.x filter-based API migration
src/lfx/src/lfx/components/mem0/mem0_chat_memory.py, src/lfx/src/lfx/_assets/component_index.json
build_search_results() now passes user scoping via filters={"user_id": user_id} to both memory.search() and memory.get_all() instead of as direct arguments; embedded component code in index mirrors this change.
Mem0 2.x API test coverage
src/backend/tests/unit/components/bundles/mem0/test_mem0_component.py
Imports Mock and adds two new unit tests validating that build_search_results() invokes Mem0 APIs with the correct filter parameter and metadata structure.

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~12 minutes

Possibly related PRs

  • langflow-ai/langflow#13053: Updates src/backend/base/pyproject.toml optional dependency versions for qdrant and mem0 extras with similar version constraints.

Suggested labels

lgtm

Suggested reviewers

  • Adam-Aghili
  • ogabrielluiz
🚥 Pre-merge checks | ✅ 7 | ❌ 2

❌ Failed checks (2 warnings)

Check name Status Explanation Resolution
Test Quality And Coverage ⚠️ Warning Tests validate the new filter behavior but lack critical edge case coverage: no tests for None/empty user_id (flagged in review), exception handling, or error conditions. Add tests for falsy user_id, exception handling in build_search_results, and error conditions when memory operations fail.
Test File Naming And Structure ⚠️ Warning Test file follows naming and pytest structure correctly but lacks edge case coverage. Missing tests for None/empty user_id (flagged in review), exception handling, and empty results. Add tests for None/empty user_id scenarios, exception handling in search/get_all, and empty result sets to provide comprehensive coverage as required by custom check.
✅ Passed checks (7 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title concisely and clearly identifies the main change: updating mem0 and qdrant dependencies to newer versions, which aligns with all the modifications across the changeset.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Test Coverage For New Implementations ✅ Passed PR includes two new regression tests for mem0 2.x filter-based user scoping, follows test_*.py convention, uses proper mocks, and test assertions match implementation code precisely.
Excessive Mock Usage Warning ✅ Passed Mock usage is minimal and appropriate: 1 Mock per test for external mem0.Memory dependency. Tests verify API signature changes in Mem0 2.x integration, not excessive or obscuring core logic.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/mem0-2-qdrant-cve

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@github-actions github-actions Bot added the bug Something isn't working label May 22, 2026
@erichare erichare marked this pull request as ready for review May 22, 2026 17:34
@erichare erichare requested review from Adam-Aghili and Jkavia May 22, 2026 17:34
@github-actions github-actions Bot added bug Something isn't working and removed bug Something isn't working labels May 22, 2026
@github-actions

Copy link
Copy Markdown
Contributor

✅ Test Coverage Advisor

No source changes detected without accompanying tests. Thanks for keeping coverage up! 🎉

Advisory check only — never blocks merge.

@github-actions github-actions Bot added the lgtm This PR has been approved by a maintainer label May 22, 2026
@erichare erichare enabled auto-merge May 22, 2026 17:37
@github-actions github-actions Bot added bug Something isn't working and removed bug Something isn't working labels May 22, 2026
@codecov

codecov Bot commented May 22, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 55.61%. Comparing base (dd87310) to head (cda213f).
⚠️ Report is 1 commits behind head on release-1.10.0.

Additional details and impacted files

Impacted file tree graph

@@                Coverage Diff                 @@
##           release-1.10.0   #13292      +/-   ##
==================================================
+ Coverage           55.57%   55.61%   +0.04%     
==================================================
  Files                2178     2178              
  Lines              205682   205657      -25     
  Branches            31089    29436    -1653     
==================================================
+ Hits               114309   114384      +75     
+ Misses              90053    89954      -99     
+ Partials             1320     1319       -1     
Flag Coverage Δ
backend 60.28% <ø> (+1.25%) ⬆️
frontend 55.48% <ø> (-0.23%) ⬇️
lfx 51.71% <ø> (+<0.01%) ⬆️

Flags with carried forward coverage won't be shown. Click here to find out more.
see 214 files with indirect coverage changes

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@coderabbitai coderabbitai Bot 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.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@src/lfx/src/lfx/_assets/component_index.json`:
- Line 92004: In build_search_results, add an early guard that checks if
self.user_id is falsy and avoid calling mem0_memory.search or get_all with
filters containing a null user_id; instead log a warning (using logger.warning)
and return an empty/neutral Data result appropriate for build_search_results (so
callers don’t get null-scoped Mem0 results). Update build_search_results (and
its interaction with ingest_data if needed) to perform this check before
constructing filters or calling mem0_memory.search/get_all.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 19db78ef-e630-4008-9b55-4c3d86760d2c

📥 Commits

Reviewing files that changed from the base of the PR and between cf3c2d3 and cda213f.

⛔ Files ignored due to path filters (2)
  • src/backend/base/uv.lock is excluded by !**/*.lock
  • uv.lock is excluded by !**/*.lock
📒 Files selected for processing (4)
  • src/backend/base/pyproject.toml
  • src/backend/tests/unit/components/bundles/mem0/test_mem0_component.py
  • src/lfx/src/lfx/_assets/component_index.json
  • src/lfx/src/lfx/components/mem0/mem0_chat_memory.py

"title_case": false,
"type": "code",
"value": "import os\n\nfrom mem0 import Memory, MemoryClient\n\nfrom lfx.base.memory.model import LCChatMemoryComponent\nfrom lfx.inputs.inputs import DictInput, HandleInput, MessageTextInput, NestedDictInput, SecretStrInput\nfrom lfx.io import Output\nfrom lfx.log.logger import logger\nfrom lfx.schema.data import Data\nfrom lfx.utils.validate_cloud import raise_error_if_astra_cloud_disable_component\n\ndisable_component_in_astra_cloud_msg = (\n \"Mem0 chat memory is not supported in Astra cloud environment. Please use local storage mode or mem0 cloud.\"\n)\n\n\nclass Mem0MemoryComponent(LCChatMemoryComponent):\n display_name = \"Mem0 Chat Memory\"\n description = \"Retrieves and stores chat messages using Mem0 memory storage.\"\n name = \"mem0_chat_memory\"\n icon: str = \"Mem0\"\n inputs = [\n NestedDictInput(\n name=\"mem0_config\",\n display_name=\"Mem0 Configuration\",\n info=\"\"\"Configuration dictionary for initializing Mem0 memory instance.\n Example:\n {\n \"graph_store\": {\n \"provider\": \"neo4j\",\n \"config\": {\n \"url\": \"neo4j+s://your-neo4j-url\",\n \"username\": \"neo4j\",\n \"password\": \"your-password\"\n }\n },\n \"version\": \"v1.1\"\n }\"\"\",\n input_types=[\"Data\", \"JSON\"],\n ),\n MessageTextInput(\n name=\"ingest_message\",\n display_name=\"Message to Ingest\",\n info=\"The message content to be ingested into Mem0 memory.\",\n ),\n HandleInput(\n name=\"existing_memory\",\n display_name=\"Existing Memory Instance\",\n input_types=[\"Memory\"],\n info=\"Optional existing Mem0 memory instance. If not provided, a new instance will be created.\",\n ),\n MessageTextInput(\n name=\"user_id\", display_name=\"User ID\", info=\"Identifier for the user associated with the messages.\"\n ),\n MessageTextInput(\n name=\"search_query\", display_name=\"Search Query\", info=\"Input text for searching related memories in Mem0.\"\n ),\n SecretStrInput(\n name=\"mem0_api_key\",\n display_name=\"Mem0 API Key\",\n info=\"API key for Mem0 platform. Leave empty to use the local version.\",\n ),\n DictInput(\n name=\"metadata\",\n display_name=\"Metadata\",\n info=\"Additional metadata to associate with the ingested message.\",\n advanced=True,\n ),\n SecretStrInput(\n name=\"openai_api_key\",\n display_name=\"OpenAI API Key\",\n required=False,\n info=\"API key for OpenAI. Required if using OpenAI Embeddings without a provided configuration.\",\n ),\n ]\n\n outputs = [\n Output(name=\"memory\", display_name=\"Mem0 Memory\", method=\"ingest_data\"),\n Output(\n name=\"search_results\",\n display_name=\"Search Results\",\n method=\"build_search_results\",\n ),\n ]\n\n def build_mem0(self) -> Memory:\n \"\"\"Initializes a Mem0 memory instance based on provided configuration and API keys.\"\"\"\n # Check if we're in Astra cloud environment and raise an error if we are.\n raise_error_if_astra_cloud_disable_component(disable_component_in_astra_cloud_msg)\n if self.openai_api_key:\n os.environ[\"OPENAI_API_KEY\"] = self.openai_api_key\n\n try:\n if not self.mem0_api_key:\n return Memory.from_config(config_dict=dict(self.mem0_config)) if self.mem0_config else Memory()\n if self.mem0_config:\n return MemoryClient.from_config(api_key=self.mem0_api_key, config_dict=dict(self.mem0_config))\n return MemoryClient(api_key=self.mem0_api_key)\n except ImportError as e:\n msg = \"Mem0 is not properly installed. Please install it with 'pip install -U mem0ai'.\"\n raise ImportError(msg) from e\n\n def ingest_data(self) -> Memory:\n \"\"\"Ingests a new message into Mem0 memory and returns the updated memory instance.\"\"\"\n # Check if we're in Astra cloud environment and raise an error if we are.\n raise_error_if_astra_cloud_disable_component(disable_component_in_astra_cloud_msg)\n mem0_memory = self.existing_memory or self.build_mem0()\n\n if not self.ingest_message or not self.user_id:\n logger.warning(\"Missing 'ingest_message' or 'user_id'; cannot ingest data.\")\n return mem0_memory\n\n metadata = self.metadata or {}\n\n logger.info(\"Ingesting message for user_id: %s\", self.user_id)\n\n try:\n mem0_memory.add(self.ingest_message, user_id=self.user_id, metadata=metadata)\n except Exception:\n logger.exception(\"Failed to add message to Mem0 memory.\")\n raise\n\n return mem0_memory\n\n def build_search_results(self) -> Data:\n \"\"\"Searches the Mem0 memory for related messages based on the search query and returns the results.\"\"\"\n # Check if we're in Astra cloud environment and raise an error if we are.\n raise_error_if_astra_cloud_disable_component(disable_component_in_astra_cloud_msg)\n mem0_memory = self.ingest_data()\n search_query = self.search_query\n user_id = self.user_id\n\n logger.info(\"Search query: %s\", search_query)\n\n try:\n if search_query:\n logger.info(\"Performing search with query.\")\n related_memories = mem0_memory.search(query=search_query, user_id=user_id)\n else:\n logger.info(\"Retrieving all memories for user_id: %s\", user_id)\n related_memories = mem0_memory.get_all(user_id=user_id)\n except Exception:\n logger.exception(\"Failed to retrieve related memories from Mem0.\")\n raise\n\n logger.info(\"Related memories retrieved: %s\", related_memories)\n return related_memories\n"
"value": "import os\n\nfrom mem0 import Memory, MemoryClient\n\nfrom lfx.base.memory.model import LCChatMemoryComponent\nfrom lfx.inputs.inputs import DictInput, HandleInput, MessageTextInput, NestedDictInput, SecretStrInput\nfrom lfx.io import Output\nfrom lfx.log.logger import logger\nfrom lfx.schema.data import Data\nfrom lfx.utils.validate_cloud import raise_error_if_astra_cloud_disable_component\n\ndisable_component_in_astra_cloud_msg = (\n \"Mem0 chat memory is not supported in Astra cloud environment. Please use local storage mode or mem0 cloud.\"\n)\n\n\nclass Mem0MemoryComponent(LCChatMemoryComponent):\n display_name = \"Mem0 Chat Memory\"\n description = \"Retrieves and stores chat messages using Mem0 memory storage.\"\n name = \"mem0_chat_memory\"\n icon: str = \"Mem0\"\n inputs = [\n NestedDictInput(\n name=\"mem0_config\",\n display_name=\"Mem0 Configuration\",\n info=\"\"\"Configuration dictionary for initializing Mem0 memory instance.\n Example:\n {\n \"graph_store\": {\n \"provider\": \"neo4j\",\n \"config\": {\n \"url\": \"neo4j+s://your-neo4j-url\",\n \"username\": \"neo4j\",\n \"password\": \"your-password\"\n }\n },\n \"version\": \"v1.1\"\n }\"\"\",\n input_types=[\"Data\", \"JSON\"],\n ),\n MessageTextInput(\n name=\"ingest_message\",\n display_name=\"Message to Ingest\",\n info=\"The message content to be ingested into Mem0 memory.\",\n ),\n HandleInput(\n name=\"existing_memory\",\n display_name=\"Existing Memory Instance\",\n input_types=[\"Memory\"],\n info=\"Optional existing Mem0 memory instance. If not provided, a new instance will be created.\",\n ),\n MessageTextInput(\n name=\"user_id\", display_name=\"User ID\", info=\"Identifier for the user associated with the messages.\"\n ),\n MessageTextInput(\n name=\"search_query\", display_name=\"Search Query\", info=\"Input text for searching related memories in Mem0.\"\n ),\n SecretStrInput(\n name=\"mem0_api_key\",\n display_name=\"Mem0 API Key\",\n info=\"API key for Mem0 platform. Leave empty to use the local version.\",\n ),\n DictInput(\n name=\"metadata\",\n display_name=\"Metadata\",\n info=\"Additional metadata to associate with the ingested message.\",\n advanced=True,\n ),\n SecretStrInput(\n name=\"openai_api_key\",\n display_name=\"OpenAI API Key\",\n required=False,\n info=\"API key for OpenAI. Required if using OpenAI Embeddings without a provided configuration.\",\n ),\n ]\n\n outputs = [\n Output(name=\"memory\", display_name=\"Mem0 Memory\", method=\"ingest_data\"),\n Output(\n name=\"search_results\",\n display_name=\"Search Results\",\n method=\"build_search_results\",\n ),\n ]\n\n def build_mem0(self) -> Memory:\n \"\"\"Initializes a Mem0 memory instance based on provided configuration and API keys.\"\"\"\n # Check if we're in Astra cloud environment and raise an error if we are.\n raise_error_if_astra_cloud_disable_component(disable_component_in_astra_cloud_msg)\n if self.openai_api_key:\n os.environ[\"OPENAI_API_KEY\"] = self.openai_api_key\n\n try:\n if not self.mem0_api_key:\n return Memory.from_config(config_dict=dict(self.mem0_config)) if self.mem0_config else Memory()\n if self.mem0_config:\n return MemoryClient.from_config(api_key=self.mem0_api_key, config_dict=dict(self.mem0_config))\n return MemoryClient(api_key=self.mem0_api_key)\n except ImportError as e:\n msg = \"Mem0 is not properly installed. Please install it with 'pip install -U mem0ai'.\"\n raise ImportError(msg) from e\n\n def ingest_data(self) -> Memory:\n \"\"\"Ingests a new message into Mem0 memory and returns the updated memory instance.\"\"\"\n # Check if we're in Astra cloud environment and raise an error if we are.\n raise_error_if_astra_cloud_disable_component(disable_component_in_astra_cloud_msg)\n mem0_memory = self.existing_memory or self.build_mem0()\n\n if not self.ingest_message or not self.user_id:\n logger.warning(\"Missing 'ingest_message' or 'user_id'; cannot ingest data.\")\n return mem0_memory\n\n metadata = self.metadata or {}\n\n logger.info(\"Ingesting message for user_id: %s\", self.user_id)\n\n try:\n mem0_memory.add(self.ingest_message, user_id=self.user_id, metadata=metadata)\n except Exception:\n logger.exception(\"Failed to add message to Mem0 memory.\")\n raise\n\n return mem0_memory\n\n def build_search_results(self) -> Data:\n \"\"\"Searches the Mem0 memory for related messages based on the search query and returns the results.\"\"\"\n # Check if we're in Astra cloud environment and raise an error if we are.\n raise_error_if_astra_cloud_disable_component(disable_component_in_astra_cloud_msg)\n mem0_memory = self.ingest_data()\n search_query = self.search_query\n user_id = self.user_id\n\n logger.info(\"Search query: %s\", search_query)\n\n try:\n if search_query:\n logger.info(\"Performing search with query.\")\n related_memories = mem0_memory.search(query=search_query, filters={\"user_id\": user_id})\n else:\n logger.info(\"Retrieving all memories for user_id: %s\", user_id)\n related_memories = mem0_memory.get_all(filters={\"user_id\": user_id})\n except Exception:\n logger.exception(\"Failed to retrieve related memories from Mem0.\")\n raise\n\n logger.info(\"Related memories retrieved: %s\", related_memories)\n return related_memories\n"

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.

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

🧩 Analysis chain

🌐 Web query:

For mem0ai 2.x, what is the behavior of Memory.search() and Memory.get_all() when filters={"user_id": None} (or when user_id is omitted)? Does it return unscoped/all-user memories?

💡 Result:

In mem0ai 2.x (OSS “Memory” SDK), the documented behavior is that entity scoping is done via the filters object; passing entity IDs as top-level kwargs is rejected, and reads are “scoped by filters”.[1][2][3] 1) If filters={"user_id": None} - The docs state that entity IDs must be passed inside filters and reads return memories “scoped by filters”.[1][2][3] - However, the specific case of filters with user_id=None (or JSON null) is not explicitly documented as returning “all-user/unscoped” memories. The platform feature page instead describes “implicit null scoping”: records where other primary entities are null are treated specially, and wildcards behave differently than null-only values.[3] - Therefore, based on the documented entity-scoping model, filters={"user_id": None} should not be interpreted as “unscoped/all users”; it would target the null-valued user scope (i.e., records created with user_id null / absent), not every user.[3] 2) If user_id is omitted from filters - The docs describe filters-based scoping but do not say that omitting user_id means “return all users”.[2][3] - The entity-scoped-memory feature page explains that records are partitioned by primary entity and that “wildcards” ("") are required to include broader sets; it contrasts wildcard behavior with null-only scoping and gives examples of constructing broader joins using OR and wildcards.[3] - So, omitting user_id is best treated as “use the default scoping behavior for your entity identifiers”, which is not equivalent to all-user retrieval; to retrieve broader sets you’d need explicit wildcard logic (e.g., user_id="") as described by the feature docs.[3] Practical conclusion - No: filters={"user_id": None} is not documented to return unscoped/all-user memories; it aligns with “null scoping” rather than “no scope”.[3] - Also not: omitting user_id is not documented to automatically mean “all-user”; if you want all users, you should use the documented wildcard mechanism in the filters (e.g., "user_id": "*") or an OR-based broadening pattern, rather than relying on null/omitted behavior.[3]

Citations:


Avoid querying Mem0 when user_id is missing in build_search_results.

build_search_results always calls mem0_memory.search/get_all with filters={"user_id": user_id}; when self.user_id is empty/None, Mem0’s “entity scoping” via filters will apply “null scoping” (targeting only null/absent user_id records, not all users), leading to incorrect/unexpected results. Add an early guard before calling search()/get_all() when user_id is falsy.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/lfx/src/lfx/_assets/component_index.json` at line 92004, In
build_search_results, add an early guard that checks if self.user_id is falsy
and avoid calling mem0_memory.search or get_all with filters containing a null
user_id; instead log a warning (using logger.warning) and return an
empty/neutral Data result appropriate for build_search_results (so callers don’t
get null-scoped Mem0 results). Update build_search_results (and its interaction
with ingest_data if needed) to perform this check before constructing filters or
calling mem0_memory.search/get_all.

@github-actions

Copy link
Copy Markdown
Contributor

Frontend Unit Test Coverage Report

Coverage Summary

Lines Statements Branches Functions
Coverage: 39%
39.73% (50433/126937) 68.37% (6868/10044) 39.13% (1140/2913)

Unit Test Results

Tests Skipped Failures Errors Time
4404 0 💤 0 ❌ 0 🔥 11m 32s ⏱️

@erichare erichare added this pull request to the merge queue May 22, 2026
Merged via the queue into release-1.10.0 with commit 68d4e84 May 22, 2026
131 of 132 checks passed
@erichare erichare deleted the fix/mem0-2-qdrant-cve branch May 22, 2026 18:36
Adam-Aghili added a commit that referenced this pull request May 25, 2026
Adam-Aghili added a commit that referenced this pull request May 26, 2026
erichare pushed a commit that referenced this pull request May 27, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bug Something isn't working lgtm This PR has been approved by a maintainer

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants