From 5b001e726525ff383404aae4b2efb93f72bac9cf Mon Sep 17 00:00:00 2001 From: "google-labs-jules[bot]" <161369871+google-labs-jules[bot]@users.noreply.github.com> Date: Fri, 13 Feb 2026 07:46:13 +0000 Subject: [PATCH 1/3] Fix CLI errors and Postgres persistence - Ensure events are persisted before entity state in SDK to fix FK violation. - Add `sentence-transformers` to requirements.txt. - Implement slash command support in CLI chat loop. Co-authored-by: badalraj9 <128183727+badalraj9@users.noreply.github.com> --- memory_thread/cli.py | 20 ++++++++++++++++++++ memory_thread/sdk.py | 3 +++ requirements.txt | 1 + 3 files changed, 24 insertions(+) diff --git a/memory_thread/cli.py b/memory_thread/cli.py index 1a6ba1f..65dea2c 100644 --- a/memory_thread/cli.py +++ b/memory_thread/cli.py @@ -216,6 +216,26 @@ def _enter_chat(): console.print("[dim]Goodbye.[/dim]") break + # Slash commands (e.g., /provider use groq) + if raw.startswith("/"): + import shlex + import subprocess + try: + args = shlex.split(raw[1:]) + if not args: + continue + + # Construct command to invoke same entry point + cmd_args = [sys.executable, sys.argv[0]] if sys.argv[0].endswith(".py") else [sys.argv[0]] + cmd_args.extend(args) + + subprocess.run(cmd_args) + console.print() + continue + except Exception as e: + console.print(f"[red]Command failed: {e}[/red]") + continue + # Chat handles EVERYTHING: remember, extract, contradict, respond try: response = client.chat(raw) diff --git a/memory_thread/sdk.py b/memory_thread/sdk.py index 35e61de..98eb5cf 100644 --- a/memory_thread/sdk.py +++ b/memory_thread/sdk.py @@ -439,6 +439,9 @@ def remember( def _persist_to_postgres(self, entity_id: uuid.UUID, content: str, memory_type: str, state: EntityState, event: Event): """Persist memory to PostgreSQL.""" + # Ensure event is persisted first to satisfy foreign key constraint + self.tms.persist_event(event) + with self._pg.get_cursor() as cur: # Upsert into memories table (or entity_state) cur.execute(""" diff --git a/requirements.txt b/requirements.txt index bfddf4c..17bd09b 100644 --- a/requirements.txt +++ b/requirements.txt @@ -20,3 +20,4 @@ prometheus-client fastapi uvicorn zmq +sentence-transformers From 352f3ec946d0f1f351ecdbd7e14adec360019139 Mon Sep 17 00:00:00 2001 From: "google-labs-jules[bot]" <161369871+google-labs-jules[bot]@users.noreply.github.com> Date: Fri, 13 Feb 2026 08:20:48 +0000 Subject: [PATCH 2/3] Fix CLI/DB errors: persistence order, slash commands, Qdrant compat, deps - Fix FK violation by persisting event before entity state in SDK. - Add `sentence-transformers` to requirements.txt. - Implement slash command support (`/provider ...`) in CLI chat loop. - Add Qdrant client compatibility for `.search()` vs `.query_points()`. - Improve logging for embeddings/NER import errors to aid debugging. - Add logging to provider selection logic. Co-authored-by: badalraj9 <128183727+badalraj9@users.noreply.github.com> --- memory_thread/db/qdrant_client.py | 20 +++++++++++++++----- memory_thread/sdk.py | 4 +++- memory_thread/services/hybrid_ner_service.py | 13 +++++++++++-- memory_thread/utils/embeddings.py | 2 +- 4 files changed, 30 insertions(+), 9 deletions(-) diff --git a/memory_thread/db/qdrant_client.py b/memory_thread/db/qdrant_client.py index 05ee65e..e9bbdc2 100644 --- a/memory_thread/db/qdrant_client.py +++ b/memory_thread/db/qdrant_client.py @@ -48,11 +48,21 @@ def upsert(self, collection_name: str, points: List[Dict[str, Any]]): def search(self, collection_name: str, query_vector: List[float], limit: int = 5) -> List[Any]: """Search for similar vectors.""" try: - return self.client.search( - collection_name=collection_name, - query_vector=query_vector, - limit=limit - ) + # Fallback for deprecated 'search' if needed, or use 'query_points' for future compat + if hasattr(self.client, "search"): + return self.client.search( + collection_name=collection_name, + query_vector=query_vector, + limit=limit + ) + elif hasattr(self.client, "query_points"): + return self.client.query_points( + collection_name=collection_name, + query=query_vector, + limit=limit + ).points + else: + raise AttributeError("QdrantClient has no search method") except Exception as e: from memory_thread.utils.logger import get_logger log = get_logger(__name__) diff --git a/memory_thread/sdk.py b/memory_thread/sdk.py index 98eb5cf..17fca6d 100644 --- a/memory_thread/sdk.py +++ b/memory_thread/sdk.py @@ -1133,11 +1133,13 @@ def chat( # Check explicit env override first env_provider = os.environ.get("MT_PROVIDER") - if env_provider: + if env_provider and env_provider != "auto": active_provider = env_provider.lower() + log.info(f"Using provider from ENV: {active_provider}") else: # Ensure we respect the vault's setting (which includes env vars now) active_provider = vault.get_active_provider(user_id) + log.info(f"Using provider from Vault: {active_provider}") log.debug(f"Chat request - Provider: {active_provider}, User: {user_id}") diff --git a/memory_thread/services/hybrid_ner_service.py b/memory_thread/services/hybrid_ner_service.py index 47dd4ce..0e2a47c 100644 --- a/memory_thread/services/hybrid_ner_service.py +++ b/memory_thread/services/hybrid_ner_service.py @@ -48,8 +48,17 @@ def extract_entities(text: str): return ner_cache.get(text_hash) # Run all stages - regex_entities = regex_ner(text) - spacy_entities, confidence = spacy_ner(text) + try: + regex_entities = regex_ner(text) + except Exception as e: + print(f"Regex NER failed: {e}") + regex_entities = [] + + try: + spacy_entities, confidence = spacy_ner(text) + except Exception as e: + print(f"Spacy NER failed: {e}") + spacy_entities, confidence = [], 0.0 final_entities = regex_entities + spacy_entities diff --git a/memory_thread/utils/embeddings.py b/memory_thread/utils/embeddings.py index cd8611b..b0f8940 100644 --- a/memory_thread/utils/embeddings.py +++ b/memory_thread/utils/embeddings.py @@ -38,7 +38,7 @@ def _get_local_model(): log.warning("sentence-transformers not installed. pip install sentence-transformers") return None except Exception as e: - log.warning(f"Failed to load embedding model: {e}") + log.warning(f"Failed to load embedding model: {e}", exc_info=True) return None From 70b2eea45092821044f84364a970f76784333f72 Mon Sep 17 00:00:00 2001 From: "google-labs-jules[bot]" <161369871+google-labs-jules[bot]@users.noreply.github.com> Date: Fri, 13 Feb 2026 08:46:13 +0000 Subject: [PATCH 3/3] Fix CLI errors: DB constraints, missing deps, Qdrant API, and env loading - Fix Postgres FK violation by persisting events before state. - Add `sentence-transformers` to requirements.txt. - Implement slash command support (`/provider ...`) in CLI chat. - Add Qdrant client compatibility for `.search()` vs `.query_points()`. - Add `load_dotenv()` to CLI entry point to fix missing API keys. - Improve logging for embeddings/NER import errors. - Unmask swallowed ImportError in `sdk.py`. Co-authored-by: badalraj9 <128183727+badalraj9@users.noreply.github.com> --- memory_thread/cli.py | 3 +++ memory_thread/sdk.py | 10 ++++++---- 2 files changed, 9 insertions(+), 4 deletions(-) diff --git a/memory_thread/cli.py b/memory_thread/cli.py index 65dea2c..51a5e4e 100644 --- a/memory_thread/cli.py +++ b/memory_thread/cli.py @@ -33,6 +33,9 @@ from rich.panel import Panel from rich.text import Text from rich import print as rprint +from dotenv import load_dotenv + +load_dotenv() # ═══════════════════════════════════════════════════════════════════════════════ # WINDOWS UTF-8 FIX — no more Wakandan runes diff --git a/memory_thread/sdk.py b/memory_thread/sdk.py index 17fca6d..afedb73 100644 --- a/memory_thread/sdk.py +++ b/memory_thread/sdk.py @@ -170,9 +170,9 @@ def _generate_embedding(self, text: str) -> List[float]: try: from memory_thread.utils.embeddings import generate_embeddings return generate_embeddings(tuple([text]))[0] - except ImportError: + except ImportError as e: # sentence-transformers not installed - log.debug("sentence-transformers not installed, using zero vector") + log.warning(f"sentence-transformers failed: {e}") return [0.0] * settings.EMBEDDING_DIMENSION except Exception as e: # Return zeros if embedding fails @@ -188,8 +188,8 @@ def _extract_entities(self, text: str) -> List[Dict]: try: from memory_thread.services.hybrid_ner_service import extract_entities return extract_entities(text) - except ImportError: - log.warning("hybrid_ner_service not available, skipping entity extraction") + except ImportError as e: + log.warning(f"hybrid_ner_service not available (ImportError: {e}), skipping entity extraction") return [] except Exception as e: log.warning(f"Entity extraction failed: {e}") @@ -1301,6 +1301,8 @@ def _generate_cloud(self, prompt: str, provider: str = "auto") -> str: key = creds.get("api_key") if creds else os.environ.get("GROQ_API_KEY") model = creds.get("model") if creds else os.environ.get("GROQ_MODEL", "llama-3.3-70b-versatile") + log.info(f"Groq API Key Check: Vault={'Found' if creds else 'Missing'}, Env={'Found' if os.environ.get('GROQ_API_KEY') else 'Missing'}") + if key: log.info(f"Using Groq ({model})") response = requests.post(