From 32b97bee87700cb5a6d7cfadda7e2824fa0ca71a Mon Sep 17 00:00:00 2001 From: ARIA Date: Wed, 15 Apr 2026 18:19:52 +0200 Subject: [PATCH] Add configurable case-insensitive search - Add MEM0_CASE_INSENSITIVE config option (default: false) - When enabled, searches with both original and lowercase query - Merges results, keeping highest score for each memory - Fixes case sensitivity issues with Qdrant embeddings - Generalize after-install.md with placeholders instead of personal values --- __init__.py | 15 +++++++++++++++ after-install.md | 35 ++++++++++++++++++----------------- client.py | 39 +++++++++++++++++++++++++++++++++++++++ 3 files changed, 72 insertions(+), 17 deletions(-) diff --git a/__init__.py b/__init__.py index 21e582a..cfb0604 100644 --- a/__init__.py +++ b/__init__.py @@ -8,6 +8,7 @@ Config via environment variables: MEM0_AGENT_ID — Agent identifier (default: hermes) MEM0_PREFETCH_LIMIT — Max memories to prefetch (default: 3) MEM0_PREFETCH_SCORE_THRESHOLD — Min similarity score % to include memory (default: 60) + MEM0_CASE_INSENSITIVE — Enable case-insensitive search (default: false) Or via $HERMES_HOME/mem0-local.json. """ @@ -52,6 +53,8 @@ def _load_config() -> dict: "prefetch_score_threshold": int( os.environ.get("MEM0_PREFETCH_SCORE_THRESHOLD", "60") ), + "case_insensitive": os.environ.get("MEM0_CASE_INSENSITIVE", "false").lower() + == "true", } config_path = get_hermes_home() / "mem0-local.json" @@ -154,6 +157,7 @@ class Mem0LocalMemoryProvider(MemoryProvider): self._rerank = True self._prefetch_limit = 3 self._prefetch_score_threshold = 60 + self._case_insensitive = False self._prefetch_result = "" self._prefetch_lock = threading.Lock() self._prefetch_thread = None @@ -224,6 +228,12 @@ class Mem0LocalMemoryProvider(MemoryProvider): "description": "Min similarity score % to include memory (0-100)", "default": "60", }, + { + "key": "case_insensitive", + "description": "Enable case-insensitive search (uses 2x API calls)", + "default": False, + "type": "boolean", + }, ] def _get_client(self) -> LocalMem0Client: @@ -241,6 +251,7 @@ class Mem0LocalMemoryProvider(MemoryProvider): self._prefetch_score_threshold = int( self._config.get("prefetch_score_threshold", 60) ) + self._case_insensitive = self._config.get("case_insensitive", False) base_url = self._config.get("base_url", "http://localhost:8000") timeout = float(self._config.get("timeout", 10.0)) self._client = LocalMem0Client(base_url, timeout=timeout) @@ -293,6 +304,7 @@ class Mem0LocalMemoryProvider(MemoryProvider): self._prefetch_score_threshold = int( self._config.get("prefetch_score_threshold", 60) ) + self._case_insensitive = self._config.get("case_insensitive", False) def system_prompt_block(self) -> str: return ( @@ -333,6 +345,7 @@ class Mem0LocalMemoryProvider(MemoryProvider): query=query, user_id=self._user_id, limit=self._prefetch_limit, + case_insensitive=self._case_insensitive, ) # Filter by score threshold threshold = self._prefetch_score_threshold / 100.0 @@ -370,6 +383,7 @@ class Mem0LocalMemoryProvider(MemoryProvider): query=query, user_id=self._user_id, limit=self._prefetch_limit, + case_insensitive=self._case_insensitive, ) # Filter by score threshold threshold = self._prefetch_score_threshold / 100.0 @@ -466,6 +480,7 @@ class Mem0LocalMemoryProvider(MemoryProvider): query=query, user_id=self._user_id, limit=top_k, + case_insensitive=self._case_insensitive, ) self._record_success() if not results: diff --git a/after-install.md b/after-install.md index 7b02c39..26a15c9 100644 --- a/after-install.md +++ b/after-install.md @@ -13,9 +13,9 @@ If not running: docker run -d -p 8000:8000 mem0ai/mem0:latest ``` -For your setup on 10.0.0.150:8889: +For your setup: ```bash -curl http://10.0.0.150:8889/health +curl http://:/health ``` ### 2. Configure the Plugin @@ -28,8 +28,8 @@ nano ~/.hermes/.env Add or update: ```env -MEM0_BASE_URL=http://10.0.0.150:8889 -MEM0_USER_ID=henry_hofmann +MEM0_BASE_URL=http://: +MEM0_USER_ID= MEM0_AGENT_ID=hermes ``` @@ -37,8 +37,8 @@ Or create a config file: ```bash cat > ~/.hermes/mem0-local.json << 'EOF' { - "base_url": "http://10.0.0.150:8889", - "user_id": "henry_hofmann", + "base_url": "http://:", + "user_id": "", "agent_id": "hermes", "rerank": true, "timeout": 10.0 @@ -71,8 +71,8 @@ The plugin supports two configuration methods that work together: Edit `~/.hermes/.env`: ```env -MEM0_BASE_URL=http://10.0.0.150:8889 -MEM0_USER_ID=henry_hofmann +MEM0_BASE_URL=http://: +MEM0_USER_ID= MEM0_AGENT_ID=hermes ``` @@ -81,8 +81,8 @@ MEM0_AGENT_ID=hermes Create `~/.hermes/mem0-local.json` to override specific settings: ```json { - "base_url": "http://10.0.0.150:8889", - "user_id": "henry_hofmann", + "base_url": "http://:", + "user_id": "", "agent_id": "hermes", "rerank": true, "timeout": 10.0 @@ -92,9 +92,10 @@ Create `~/.hermes/mem0-local.json` to override specific settings: **Note**: Config file values override environment variables. Use `.env` for defaults and JSON for overrides. Key variables: -- `MEM0_BASE_URL` — Local server URL (your setup: `http://10.0.0.150:8889`) -- `MEM0_USER_ID` — User identifier for memory scoping (your setup: `henry_hofmann`) +- `MEM0_BASE_URL` — Local server URL (default: `http://localhost:8000`) +- `MEM0_USER_ID` — User identifier for memory scoping (default: `hermes-user`) - `MEM0_AGENT_ID` — Agent identifier (default: `hermes`) +- `MEM0_CASE_INSENSITIVE` — Enable case-insensitive search (default: `false`) - `rerank` — Enable reranking for higher precision (default: `true`) - `timeout` — Request timeout in seconds (default: `10.0`) @@ -120,12 +121,12 @@ No tool call needed — instant context! ## Migration from Hardcoded Config -Your previous hardcoded configuration: +If you had a previous hardcoded configuration like: ```yaml mem0: enabled: true api_url: http://localhost:8889 - user_id: henry_hofmann + user_id: collection_name: hermes_memory mode: local transparent: @@ -155,9 +156,9 @@ Is now replaced by the plugin with: If memory doesn't work: 1. **Check server connectivity**: - ```bash - curl http://10.0.0.150:8889/health - ``` + ```bash + curl http://:/health + ``` 2. **Check gateway logs**: ```bash diff --git a/client.py b/client.py index cde4c10..38fdf59 100644 --- a/client.py +++ b/client.py @@ -65,13 +65,52 @@ class LocalMem0Client: query: str, user_id: Optional[str] = None, limit: int = 5, + case_insensitive: bool = False, ) -> List[Dict]: """Search memories by semantic similarity. API: POST /search Request: {query, user_id, limit} Response: {results: [{id, text, user_id, score, metadata}]} + + Args: + query: Search query + user_id: User identifier + limit: Max results + case_insensitive: If True, search with both original and lowercase query """ + if not case_insensitive: + payload = {"query": query, "limit": limit} + if user_id: + payload["user_id"] = user_id + result = self._request("POST", "/search", json=payload) + return result.get("results", []) + + # Case-insensitive mode: search with both original and lowercase + # Fetch 2x limit to ensure we get top N after merging + results_original = self._search_with_query(query, user_id, limit * 2) + results_lower = self._search_with_query(query.lower(), user_id, limit * 2) + + # Merge and deduplicate, keeping highest score + merged = {} + for result in results_original + results_lower: + mem_id = result.get("id") + if mem_id not in merged or result.get("score", 0) > merged[mem_id].get( + "score", 0 + ): + merged[mem_id] = result + + return sorted(merged.values(), key=lambda x: x.get("score", 0), reverse=True)[ + :limit + ] + + def _search_with_query( + self, + query: str, + user_id: Optional[str] = None, + limit: int = 5, + ) -> List[Dict]: + """Internal search helper for case-insensitive mode.""" payload = {"query": query, "limit": limit} if user_id: payload["user_id"] = user_id -- 2.52.0