diff --git a/CHANGELOG.md b/CHANGELOG.md index f9b07883..ad5a066c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -20,6 +20,17 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Fixes `VectorStore.update_vectors`/`delete_vectors` to delegate to the active backend store instead of only mutating in-memory state, correcting existing behavior for all non-`inmemory` backends - 25 unit and integration tests in `tests/vector_store/test_sqlite_vec_store.py` covering init, add, search, get, update, delete, read-only mode, and stats +### Fixed + +- **Missing `shacl` optional-dependency extra** (#736) by @Sameer6305 + - `pip install semantica[shacl]` referenced no matching extra in `pyproject.toml`, so `pyshacl` was never installed despite being documented as the fix in `ontology_validator.py`'s `ImportError` message, the Explorer API, the healthcare cookbook notebook, and the changelog + - Added `shacl = ["pyshacl>=0.25.0"]` to `[project.optional-dependencies]` and folded `shacl` into the `all` extra + +- **`NodeEmbedder` `AttributeError` masked in `ContextGraph.analyze_graph_with_kg`** (#734) by @Sameer6305 + - `analyze_graph_with_kg()` called a non-existent `NodeEmbedder.generate_embeddings()`, and the surrounding broad `except Exception` swallowed the resulting `AttributeError`, silently returning `{"error": "Graph analysis failed due to an internal error"}` from `get_causal_chain()`'s supporting analytics and `get_decision_insights()` + - Rewired the call site to the real `NodeEmbedder.compute_embeddings(graph_store, node_labels, relationship_types)` API, deriving `node_labels`/`relationship_types` from `self.node_type_index`/`self.edge_type_index` + - Added a dedicated `except AttributeError` branch that logs distinctly and re-raises, so a broken internal method call surfaces as a diagnosable error instead of being indistinguishable from a legitimately empty analysis result + --- ## [0.5.1] - 2026-06-29 diff --git a/pyproject.toml b/pyproject.toml index ee025067..2a289ec2 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -116,6 +116,9 @@ llm-all = [ # ---- Document Parsing ---- parse-docling = ["docling>=2.107.0"] +# ---- SHACL Validation ---- +shacl = ["pyshacl>=0.25.0"] + # ---- Database Connectors ---- db-snowflake = ["snowflake-connector-python>=4.6.0", "cryptography>=49.0.0"] db-arrow = ["pyarrow>=24.0.0"] @@ -234,8 +237,8 @@ explorer-lite = [ # Everything (cross-platform — gpu excluded; install semantica[gpu] separately on Linux) all = [ - "semantica[dev,viz,infra,cloud,monitoring,watch,llm-all,models-huggingface,split-all,graph-all,vectorstore-all,parse-docling,ingest-parquet,ingest-arrow,explorer]", - "semantica[dev,viz,infra,cloud,monitoring,watch,llm-all,models-huggingface,split-all,graph-all,vectorstore-all,parse-docling,ingest-parquet,ingest-arrow,agno]" + "semantica[dev,viz,infra,cloud,monitoring,watch,llm-all,models-huggingface,split-all,graph-all,vectorstore-all,parse-docling,ingest-parquet,ingest-arrow,shacl,explorer]", + "semantica[dev,viz,infra,cloud,monitoring,watch,llm-all,models-huggingface,split-all,graph-all,vectorstore-all,parse-docling,ingest-parquet,ingest-arrow,shacl,agno]" ] # ---------------- ENTRYPOINTS ---------------- diff --git a/semantica/context/context_graph.py b/semantica/context/context_graph.py index 4f84acf5..ac1b9b59 100644 --- a/semantica/context/context_graph.py +++ b/semantica/context/context_graph.py @@ -2214,12 +2214,26 @@ class ContextGraph: # Node embeddings if "node_embedder" in self.kg_components: - embeddings = self.kg_components["node_embedder"].generate_embeddings(kg_graph) - analysis["node_embeddings"] = embeddings + node_labels = list(self.node_type_index.keys()) + relationship_types = list(self.edge_type_index.keys()) + if node_labels: + embeddings = self.kg_components["node_embedder"].compute_embeddings( + graph_store=self, + node_labels=node_labels, + relationship_types=relationship_types, + ) + analysis["node_embeddings"] = embeddings self.logger.info("Completed comprehensive graph analysis") return analysis + except AttributeError as e: + # A broken internal method call (e.g. calling a method that doesn't + # exist on one of the kg_components) is a programming error, not a + # legitimate empty-analysis result. Log it distinctly and re-raise + # rather than masking it under the generic message below. + self.logger.error(f"Graph analysis failed due to a broken internal method call: {e}") + raise except Exception as e: self.logger.error(f"Failed to analyze graph with KG: {e}") return {"error": "Graph analysis failed due to an internal error"}