From be868ec90b2f9c8222c2ccb2ecbabc15a4a31a68 Mon Sep 17 00:00:00 2001 From: Hande <159312713+hande-k@users.noreply.github.com> Date: Wed, 18 Mar 2026 13:04:22 +0100 Subject: [PATCH 01/10] initial commit --- integrations/cognee/README.md | 114 ++++++++++++ integrations/cognee/examples/README.md | 33 ++++ .../cognee/examples/demo_memory_agent.py | 75 ++++++++ integrations/cognee/examples/demo_pipeline.py | 99 ++++++++++ integrations/cognee/pyproject.toml | 55 ++++++ .../components/connectors/cognee/__init__.py | 15 ++ .../components/connectors/cognee/_utils.py | 25 +++ .../components/connectors/cognee/cognifier.py | 50 +++++ .../connectors/cognee/memory_store.py | 173 ++++++++++++++++++ .../components/connectors/cognee/retriever.py | 129 +++++++++++++ .../components/connectors/cognee/writer.py | 78 ++++++++ integrations/cognee/tests/__init__.py | 0 .../cognee/tests/test_memory_store.py | 94 ++++++++++ integrations/cognee/tests/test_retriever.py | 98 ++++++++++ integrations/cognee/tests/test_writer.py | 94 ++++++++++ 15 files changed, 1132 insertions(+) create mode 100644 integrations/cognee/README.md create mode 100644 integrations/cognee/examples/README.md create mode 100644 integrations/cognee/examples/demo_memory_agent.py create mode 100644 integrations/cognee/examples/demo_pipeline.py create mode 100644 integrations/cognee/pyproject.toml create mode 100644 integrations/cognee/src/haystack_integrations/components/connectors/cognee/__init__.py create mode 100644 integrations/cognee/src/haystack_integrations/components/connectors/cognee/_utils.py create mode 100644 integrations/cognee/src/haystack_integrations/components/connectors/cognee/cognifier.py create mode 100644 integrations/cognee/src/haystack_integrations/components/connectors/cognee/memory_store.py create mode 100644 integrations/cognee/src/haystack_integrations/components/connectors/cognee/retriever.py create mode 100644 integrations/cognee/src/haystack_integrations/components/connectors/cognee/writer.py create mode 100644 integrations/cognee/tests/__init__.py create mode 100644 integrations/cognee/tests/test_memory_store.py create mode 100644 integrations/cognee/tests/test_retriever.py create mode 100644 integrations/cognee/tests/test_writer.py diff --git a/integrations/cognee/README.md b/integrations/cognee/README.md new file mode 100644 index 0000000000..c3212e192c --- /dev/null +++ b/integrations/cognee/README.md @@ -0,0 +1,114 @@ +# cognee-haystack + +[![PyPI](https://img.shields.io/pypi/v/cognee-haystack.svg)](https://pypi.org/project/cognee-haystack/) +[![License](https://img.shields.io/badge/license-Apache%202.0-blue.svg)](LICENSE) + +A [Haystack](https://haystack.deepset.ai/) integration for [Cognee](https://github.com/topoteretes/cognee) — memory for AI agents. + +## Installation + +```bash +pip install cognee-haystack +``` + +To use the `CogneeMemoryStore` with Haystack's experimental Agent: + +```bash +pip install "cognee-haystack[memory]" +``` + +## Components + +### CogneeWriter + +Adds Haystack Documents to Cognee's knowledge engine via `cognee.add()`, with optional automatic `cognee.cognify()`. + +```python +from haystack import Document, Pipeline +from haystack_integrations.components.connectors.cognee import CogneeWriter + +pipeline = Pipeline() +pipeline.add_component("writer", CogneeWriter(dataset_name="my_data", auto_cognify=True)) + +docs = [Document(content="Cognee builds a structured memory from unstructured data.")] +pipeline.run({"writer": {"documents": docs}}) +``` + +### CogneeCognifier + +Standalone `cognee.cognify()` step — useful when you want to separate adding and processing. + +```python +from haystack_integrations.components.connectors.cognee import CogneeCognifier + +cognifier = CogneeCognifier() +cognifier.run() # {"cognified": True} +``` + +### CogneeRetriever + +Searches Cognee's memory and returns Haystack `Document` objects. + +```python +from haystack import Pipeline +from haystack_integrations.components.connectors.cognee import CogneeRetriever + +pipeline = Pipeline() +pipeline.add_component("retriever", CogneeRetriever(search_type="GRAPH_COMPLETION", top_k=5)) + +result = pipeline.run({"retriever": {"query": "What is Cognee?"}}) +for doc in result["retriever"]["documents"]: + print(doc.content) +``` + +**Supported search types:** `GRAPH_COMPLETION`, `CHUNKS`, `SUMMARIES`, `INSIGHTS`, and others from Cognee's `SearchType` enum. + +### CogneeMemoryStore + +Memory backend for Haystack's experimental Agent, backed by Cognee. + +```python +from haystack.dataclasses import ChatMessage +from haystack_integrations.components.connectors.cognee import CogneeMemoryStore + +store = CogneeMemoryStore(search_type="GRAPH_COMPLETION", top_k=5) + +# Store memories +store.add_memories(messages=[ + ChatMessage.from_user("The project deadline is next Friday.") +]) + +# Recall memories +results = store.search_memories(query="When is the deadline?") +``` + +## Configuration + +Cognee uses environment variables for its LLM and storage configuration: + +```bash +export OPENAI_API_KEY="sk-..." +``` + +See the [Cognee documentation](https://docs.cognee.ai/) for additional configuration options. + +## Examples + +See the [`examples/`](examples/) directory for runnable demos: + +- **`demo_pipeline.py`** — Index documents and search with CogneeWriter + CogneeRetriever +- **`demo_memory_agent.py`** — Use CogneeMemoryStore as a conversational memory backend + +## Development + +```bash +# Install in dev mode +pip install -e "integrations/cognee[memory]" + +# Run tests +pytest integrations/cognee/tests/ +``` + +## License + +Apache 2.0 — see [LICENSE](../../LICENSE) for details. diff --git a/integrations/cognee/examples/README.md b/integrations/cognee/examples/README.md new file mode 100644 index 0000000000..a65a51c45f --- /dev/null +++ b/integrations/cognee/examples/README.md @@ -0,0 +1,33 @@ +# Cognee-Haystack Examples + +## Prerequisites + +Install the integration from the repository root: + +```bash +pip install -e "integrations/cognee[memory]" +``` + +Set your LLM API key (required by cognee): + +```bash +export LLM_API_KEY="sk-..." +``` + +## Examples + +### Pipeline Demo (`demo_pipeline.py`) + +Demonstrates `CogneeWriter` and `CogneeRetriever` in a Haystack pipeline: + +```bash +python integrations/cognee/examples/demo_pipeline.py +``` + +### Memory Agent Demo (`demo_memory_agent.py`) + +Demonstrates `CogneeMemoryStore` as a conversational memory backend: + +```bash +python integrations/cognee/examples/demo_memory_agent.py +``` diff --git a/integrations/cognee/examples/demo_memory_agent.py b/integrations/cognee/examples/demo_memory_agent.py new file mode 100644 index 0000000000..7e223e1022 --- /dev/null +++ b/integrations/cognee/examples/demo_memory_agent.py @@ -0,0 +1,75 @@ +#!/usr/bin/env python +""" +Demo: Cognee as a Memory Backend for Haystack's Agent + +Shows how to use CogneeMemoryStore with Haystack's experimental Agent +to give conversational memory backed by Cognee's knowledge engine. + +Prerequisites: + pip install -e "integrations/cognee[memory]" + +Set your LLM API key: + export LLM_API_KEY="sk-..." +""" + +from haystack.dataclasses import ChatMessage + +from haystack_integrations.components.connectors.cognee import CogneeMemoryStore +from cognee.api.v1.visualize.visualize import visualize_graph +import asyncio +import os + +async def main(): + print("=== Cognee Memory Store Demo ===\n") + + store = CogneeMemoryStore(search_type="GRAPH_COMPLETION", top_k=5, dataset_name="agent_memory") + + # --- Step 1: Clear any previous memories --- + print("1. Clearing previous memories...") + store.delete_all_memories() + print(" Done.\n") + + # --- Step 2: Add some memories --- + print("2. Adding memories...") + messages = [ + ChatMessage.from_user( + "My name is Alice and I'm working on the Cognee-Haystack integration. " + "The deadline is next Friday." + ), + ChatMessage.from_user( + "We decided to use GRAPH_COMPLETION as the default search type " + "because it retrieves the most relevant memories by graph traversal and vector search" + ), + ChatMessage.from_assistant( + "I'll remember that the deadline is next Friday and that GRAPH_COMPLETION " + "is the preferred search type for this project." + ), + ] + store.add_memories(messages=messages) + print(f" Added {len(messages)} messages as memories.\n") + + visualization_path = os.path.join( + os.path.dirname(__file__), ".artifacts", "demo_memory_agent.html" + ) + await visualize_graph(visualization_path) + + # --- Step 3: Search memories --- + queries = [ + "What is the project deadline?", + "Which search type should we use?", + "Who is working on the integration?", + ] + + for query in queries: + print(f"3. Searching memories: '{query}'") + results = store.search_memories(query=query, top_k=3) + print(f" Found {len(results)} memory(ies):") + for i, msg in enumerate(results, 1): + print(f" [{i}] {msg.text}") + print() + + print("=== Done ===") + + +if __name__ == "__main__": + asyncio.run(main()) diff --git a/integrations/cognee/examples/demo_pipeline.py b/integrations/cognee/examples/demo_pipeline.py new file mode 100644 index 0000000000..4c59ea4026 --- /dev/null +++ b/integrations/cognee/examples/demo_pipeline.py @@ -0,0 +1,99 @@ +#!/usr/bin/env python +""" +Demo: Cognee + Haystack Pipeline + +Shows how to use CogneeWriter and CogneeRetriever in a Haystack pipeline +to ingest documents into Cognee's memory and search them. + +Prerequisites: + pip install -e "integrations/cognee" + +Set your LLM API key (Cognee uses it internally): + export LLM_API_KEY="sk-..." +""" + +from haystack import Document, Pipeline +from cognee.api.v1.visualize.visualize import visualize_graph + +from haystack_integrations.components.connectors.cognee import CogneeRetriever, CogneeWriter +import asyncio +import os + +SAMPLE_DOCUMENTS = [ + Document( + content=( + "Cognee is an open-source memory for AI agents. Cognee builts a knowledge engine" + "that transforms raw data (e.g., unstructured documents, relational databases, etc.)" + "into a persistent, rich, and traceable memory that is searchable by meaning and relationships." + ), + meta={"topic": "cognee"}, + ), + Document( + content=( + "Haystack is an open-source LLM framework by deepset for building production-ready " + "RAG pipelines, agents, and search systems. It uses a component-based architecture " + "where each step (retrieval, generation, etc.) is a composable building block." + ), + meta={"topic": "haystack"}, + ), + Document( + content=( + "Knowledge graphs represent information as nodes (entities) and edges (relationships). " + "They enable semantic search, reasoning, and discovery of hidden connections across " + "large document collections." + ), + meta={"topic": "knowledge_graphs"}, + ), + Document( + content=( + "The engineering team at Acme Corp consists of Alice (backend lead), Bob (ML engineer), " + "and Carol (infrastructure). They are building a next-generation search platform " + "powered by knowledge graphs and LLMs." + ), + meta={"topic": "team"}, + ), +] + + +async def main(): + print("=== Cognee + Haystack Pipeline Demo ===\n") + + # --- Indexing pipeline --- + print("1. Building indexing pipeline...") + indexing = Pipeline() + indexing.add_component("writer", CogneeWriter(dataset_name="demo", auto_cognify=True)) + + print(f"2. Indexing {len(SAMPLE_DOCUMENTS)} documents...") + result = indexing.run({"writer": {"documents": SAMPLE_DOCUMENTS}}) + print(f" Written: {result['writer']['documents_written']} documents\n") + + visualization_path = os.path.join( + os.path.dirname(__file__), ".artifacts", "demo_pipeline.html" + ) + await visualize_graph(visualization_path) + + # --- Query pipeline --- + print("3. Building query pipeline...") + querying = Pipeline() + querying.add_component("retriever", CogneeRetriever(search_type="GRAPH_COMPLETION", top_k=5)) + + queries = [ + "What is Cognee and what does it do?", + "Who is on the engineering team at Acme Corp?", + "How do knowledge graphs work?", + ] + + for query in queries: + print(f"4. Searching: '{query}'") + result = querying.run({"retriever": {"query": query}}) + docs = result["retriever"]["documents"] + print(f" Found {len(docs)} result(s):") + for i, doc in enumerate(docs, 1): + print(f" [{i}] {doc.content}...") + print() + + print("=== Done ===") + + +if __name__ == "__main__": + asyncio.run(main()) diff --git a/integrations/cognee/pyproject.toml b/integrations/cognee/pyproject.toml new file mode 100644 index 0000000000..dc5316d427 --- /dev/null +++ b/integrations/cognee/pyproject.toml @@ -0,0 +1,55 @@ +[build-system] +requires = ["hatchling", "hatch-vcs"] +build-backend = "hatchling.build" + +[project] +name = "cognee-haystack" +dynamic = ["version"] +description = "Haystack integration for Cognee — memory for AI agents" +readme = "README.md" +requires-python = ">=3.10" +license = "Apache-2.0" +authors = [{ name = "deepset GmbH", email = "info@deepset.ai" }] +classifiers = [ + "Development Status :: 3 - Alpha", + "License :: OSI Approved :: Apache Software License", + "Programming Language :: Python :: 3", + "Programming Language :: Python :: 3.10", + "Programming Language :: Python :: 3.11", + "Programming Language :: Python :: 3.12", +] +dependencies = [ + "haystack-ai>=2.0", + "cognee==0.5.4", + "mistralai>=1.0,<2.0", +] + +[project.optional-dependencies] +memory = ["haystack-experimental"] + +[tool.hatch.build.targets.wheel] +packages = ["src/haystack_integrations"] + +[tool.hatch.version] +source = "vcs" +tag-pattern = 'integrations\/cognee-v(?P.*)' + +[tool.hatch.version.raw-options] +root = "../.." +git_describe_command = 'git describe --tags --match="integrations/cognee-v[0-9]*"' + +[tool.hatch.envs.test] +dependencies = [ + "pytest", + "pytest-asyncio", + "haystack-experimental", +] + +[tool.hatch.envs.test.scripts] +unit = "pytest {args:tests}" + +[tool.hatch.envs.types] +dependencies = ["mypy"] + +[tool.hatch.envs.types.scripts] +types = "mypy -p haystack_integrations.components.connectors.cognee {args}" diff --git a/integrations/cognee/src/haystack_integrations/components/connectors/cognee/__init__.py b/integrations/cognee/src/haystack_integrations/components/connectors/cognee/__init__.py new file mode 100644 index 0000000000..2698fcbc21 --- /dev/null +++ b/integrations/cognee/src/haystack_integrations/components/connectors/cognee/__init__.py @@ -0,0 +1,15 @@ +# SPDX-FileCopyrightText: 2022-present deepset GmbH +# +# SPDX-License-Identifier: Apache-2.0 + +from .cognifier import CogneeCognifier +from .memory_store import CogneeMemoryStore +from .retriever import CogneeRetriever +from .writer import CogneeWriter + +__all__ = [ + "CogneeCognifier", + "CogneeMemoryStore", + "CogneeRetriever", + "CogneeWriter", +] diff --git a/integrations/cognee/src/haystack_integrations/components/connectors/cognee/_utils.py b/integrations/cognee/src/haystack_integrations/components/connectors/cognee/_utils.py new file mode 100644 index 0000000000..6b75033b3d --- /dev/null +++ b/integrations/cognee/src/haystack_integrations/components/connectors/cognee/_utils.py @@ -0,0 +1,25 @@ +# SPDX-FileCopyrightText: 2022-present deepset GmbH +# +# SPDX-License-Identifier: Apache-2.0 + +import asyncio +from concurrent.futures import ThreadPoolExecutor + + +def run_sync(coro): + """ + Run an async coroutine from a synchronous context. + + If no event loop is running, uses asyncio.run() directly. + If already inside an async context, runs the coroutine in a separate thread + to avoid blocking the existing event loop. + """ + try: + asyncio.get_running_loop() + except RuntimeError: + return asyncio.run(coro) + + # Already in an async context — run in a thread to avoid nested loop issues + with ThreadPoolExecutor(max_workers=1) as pool: + future = pool.submit(asyncio.run, coro) + return future.result() diff --git a/integrations/cognee/src/haystack_integrations/components/connectors/cognee/cognifier.py b/integrations/cognee/src/haystack_integrations/components/connectors/cognee/cognifier.py new file mode 100644 index 0000000000..9f900b7955 --- /dev/null +++ b/integrations/cognee/src/haystack_integrations/components/connectors/cognee/cognifier.py @@ -0,0 +1,50 @@ +# SPDX-FileCopyrightText: 2022-present deepset GmbH +# +# SPDX-License-Identifier: Apache-2.0 + +from typing import Any + +import cognee +from haystack import component, default_from_dict, default_to_dict, logging + +from ._utils import run_sync + +logger = logging.getLogger(__name__) + + +@component +class CogneeCognifier: + """ + Processes previously added data in Cognee's knowledge engine. + + Wraps `cognee.cognify()` as a standalone pipeline step, useful when you + want to separate the add and cognify phases (e.g., batch-add first, then + cognify once). + + Usage: + ```python + from haystack_integrations.components.connectors.cognee import CogneeCognifier + + cognifier = CogneeCognifier() + result = cognifier.run() + assert result["cognified"] is True + ``` + """ + + @component.output_types(cognified=bool) + def run(self) -> dict[str, Any]: + """ + Run cognee.cognify() to process added data into the memory. + + :returns: Dictionary with key `cognified` set to True on success. + """ + logger.info("Running cognee.cognify()") + run_sync(cognee.cognify()) + return {"cognified": True} + + def to_dict(self) -> dict[str, Any]: + return default_to_dict(self) + + @classmethod + def from_dict(cls, data: dict[str, Any]) -> "CogneeCognifier": + return default_from_dict(cls, data) diff --git a/integrations/cognee/src/haystack_integrations/components/connectors/cognee/memory_store.py b/integrations/cognee/src/haystack_integrations/components/connectors/cognee/memory_store.py new file mode 100644 index 0000000000..95ac50c279 --- /dev/null +++ b/integrations/cognee/src/haystack_integrations/components/connectors/cognee/memory_store.py @@ -0,0 +1,173 @@ +# SPDX-FileCopyrightText: 2022-present deepset GmbH +# +# SPDX-License-Identifier: Apache-2.0 + +from typing import Any + +import cognee +from haystack import default_from_dict, default_to_dict, logging +from haystack.dataclasses import ChatMessage + +from ._utils import run_sync + +logger = logging.getLogger(__name__) + + +class CogneeMemoryStore: + """ + A memory store backed by Cognee memory. + + Implements the `MemoryStore` protocol from haystack-experimental, allowing + Cognee to serve as the memory backend for Haystack's experimental Agent. + + Usage: + ```python + from haystack_integrations.components.connectors.cognee import CogneeMemoryStore + + store = CogneeMemoryStore(search_type="GRAPH_COMPLETION", top_k=5) + store.add_memories(messages=[ChatMessage.from_user("Remember: the project deadline is Friday.")]) + results = store.search_memories(query="When is the project deadline?") + ``` + """ + + def __init__(self, search_type: str = "GRAPH_COMPLETION", top_k: int = 5, dataset_name: str = "haystack_memory"): + """ + :param search_type: Cognee search type for memory retrieval. + :param top_k: Default number of results for memory search. + :param dataset_name: Cognee dataset name for storing memories. + """ + self.search_type = search_type + self.top_k = top_k + self.dataset_name = dataset_name + + def add_memories( + self, + *, + messages: list[ChatMessage], + user_id: str | None = None, + agent_id: str | None = None, + run_id: str | None = None, + **kwargs: Any, + ) -> None: + """ + Add chat messages to Cognee as memories and cognify them. + + :param messages: List of ChatMessages to store. + :param user_id: Optional user identifier (reserved for future use). + :param agent_id: Optional agent identifier (reserved for future use). + :param run_id: Optional run identifier (reserved for future use). + """ + for msg in messages: + text = msg.text + if not text: + continue + run_sync(cognee.add(text, dataset_name=self.dataset_name)) + + run_sync(cognee.cognify()) + logger.info("Added and cognified {count} messages as memories", count=len(messages)) + + def search_memories( + self, + *, + query: str | None = None, + top_k: int = 5, + user_id: str | None = None, + agent_id: str | None = None, + run_id: str | None = None, + **kwargs: Any, + ) -> list[ChatMessage]: + """ + Search Cognee's knowledge engine for relevant memories. + + :param query: The search query. + :param top_k: Maximum number of memories to return. + :param user_id: Optional user identifier (reserved for future use). + :param agent_id: Optional agent identifier (reserved for future use). + :param run_id: Optional run identifier (reserved for future use). + :returns: List of ChatMessages containing memory content as system messages. + """ + if not query: + return [] + + from cognee.api.v1.search import SearchType + + search_type_enum = SearchType[self.search_type] + effective_top_k = top_k or self.top_k + + raw_results = run_sync( + cognee.search(query_text=query, query_type=search_type_enum) + ) + + memories: list[ChatMessage] = [] + if not raw_results: + return memories + + for item in raw_results[:effective_top_k]: + text = _extract_memory_text(item) + if text: + memories.append(ChatMessage.from_system(text)) + + logger.info("Found {count} memories for query '{query}'", count=len(memories), query=query[:80]) + return memories + + def delete_all_memories( + self, + *, + user_id: str | None = None, + agent_id: str | None = None, + run_id: str | None = None, + **kwargs: Any, + ) -> None: + """ + Delete all memories by pruning Cognee's data and system state. + + :param user_id: Optional user identifier (reserved for future use). + :param agent_id: Optional agent identifier (reserved for future use). + :param run_id: Optional run identifier (reserved for future use). + """ + run_sync(cognee.prune.prune_data()) + run_sync(cognee.prune.prune_system(metadata=True)) + logger.info("All Cognee memories pruned") + + def delete_memory(self, memory_id: str, **kwargs: Any) -> None: + """ + Delete a single memory by ID. + + Not supported in V1 — Cognee's SDK does not expose fine-grained deletion. + + :param memory_id: The ID of the memory to delete. + :raises NotImplementedError: Always, as single-item deletion is not yet supported. + """ + msg = "CogneeMemoryStore does not support deleting individual memories in V1." + raise NotImplementedError(msg) + + def to_dict(self) -> dict[str, Any]: + return default_to_dict( + self, + search_type=self.search_type, + top_k=self.top_k, + dataset_name=self.dataset_name, + ) + + @classmethod + def from_dict(cls, data: dict[str, Any]) -> "CogneeMemoryStore": + return default_from_dict(cls, data) + + +def _extract_memory_text(item: Any) -> str: + """Best-effort text extraction from a Cognee search result item.""" + if isinstance(item, str): + return item + + for attr in ("content", "text", "description", "name"): + if hasattr(item, attr): + val = getattr(item, attr) + if val and isinstance(val, str): + return val + + if isinstance(item, dict): + for key in ("content", "text", "description", "name"): + if key in item and isinstance(item[key], str): + return item[key] + + return str(item) diff --git a/integrations/cognee/src/haystack_integrations/components/connectors/cognee/retriever.py b/integrations/cognee/src/haystack_integrations/components/connectors/cognee/retriever.py new file mode 100644 index 0000000000..bf05f9d571 --- /dev/null +++ b/integrations/cognee/src/haystack_integrations/components/connectors/cognee/retriever.py @@ -0,0 +1,129 @@ +# SPDX-FileCopyrightText: 2022-present deepset GmbH +# +# SPDX-License-Identifier: Apache-2.0 + +from typing import Any + +import cognee +from cognee.api.v1.search import SearchType +from haystack import Document, component, default_from_dict, default_to_dict, logging + +from ._utils import run_sync + +logger = logging.getLogger(__name__) + +_VALID_SEARCH_TYPES = {member.name for member in SearchType} + + +@component +class CogneeRetriever: + """ + Retrieves documents from Cognee's memory. + + Wraps `cognee.search()` and converts results into Haystack `Document` objects. + + Usage: + ```python + from haystack_integrations.components.connectors.cognee import CogneeRetriever + + retriever = CogneeRetriever(search_type="GRAPH_COMPLETION", top_k=5) + results = retriever.run(query="What is Cognee?") + for doc in results["documents"]: + print(doc.content) + ``` + """ + + def __init__(self, search_type: str = "GRAPH_COMPLETION", top_k: int = 10, dataset_name: str | None = None): + """ + :param search_type: Cognee search type. One of: GRAPH_COMPLETION, CHUNKS, + SUMMARIES, INSIGHTS, etc. + :param top_k: Maximum number of results to return. + :param dataset_name: Optional dataset name to restrict search scope. + """ + if search_type not in _VALID_SEARCH_TYPES: + msg = f"Invalid search_type '{search_type}'. Must be one of: {sorted(_VALID_SEARCH_TYPES)}" + raise ValueError(msg) + + self.search_type = search_type + self.top_k = top_k + self.dataset_name = dataset_name + + @component.output_types(documents=list[Document]) + def run(self, query: str, top_k: int | None = None) -> dict[str, Any]: + """ + Search Cognee's memory and return matching documents. + + :param query: The search query. + :param top_k: Override the default maximum number of results. + :returns: Dictionary with key `documents` containing the search results + as Haystack Document objects. + """ + effective_top_k = top_k if top_k is not None else self.top_k + search_type_enum = SearchType[self.search_type] + + search_kwargs: dict[str, Any] = { + "query_text": query, + "query_type": search_type_enum, + } + if self.dataset_name: + search_kwargs["datasets"] = [self.dataset_name] + + raw_results = run_sync(cognee.search(**search_kwargs)) + + documents = _convert_results(raw_results, effective_top_k) + + logger.info( + "Cognee search returned {count} documents for query '{query}'", + count=len(documents), + query=query[:80], + ) + return {"documents": documents} + + def to_dict(self) -> dict[str, Any]: + return default_to_dict( + self, + search_type=self.search_type, + top_k=self.top_k, + dataset_name=self.dataset_name, + ) + + @classmethod + def from_dict(cls, data: dict[str, Any]) -> "CogneeRetriever": + return default_from_dict(cls, data) + + +def _convert_results(raw_results: list[Any], top_k: int) -> list[Document]: + """Convert Cognee search results to Haystack Documents.""" + documents: list[Document] = [] + if not raw_results: + return documents + + for item in raw_results[:top_k]: + text = _extract_text(item) + if text: + documents.append( + Document( + content=text, + meta={"source": "cognee", "search_result_type": type(item).__name__}, + ) + ) + return documents + + +def _extract_text(item: Any) -> str: + """Best-effort text extraction from a Cognee search result item.""" + if isinstance(item, str): + return item + + for attr in ("content", "text", "description", "name"): + if hasattr(item, attr): + val = getattr(item, attr) + if val and isinstance(val, str): + return val + + if isinstance(item, dict): + for key in ("content", "text", "description", "name"): + if key in item and isinstance(item[key], str): + return item[key] + + return str(item) diff --git a/integrations/cognee/src/haystack_integrations/components/connectors/cognee/writer.py b/integrations/cognee/src/haystack_integrations/components/connectors/cognee/writer.py new file mode 100644 index 0000000000..723d8e2644 --- /dev/null +++ b/integrations/cognee/src/haystack_integrations/components/connectors/cognee/writer.py @@ -0,0 +1,78 @@ +# SPDX-FileCopyrightText: 2022-present deepset GmbH +# +# SPDX-License-Identifier: Apache-2.0 + +from typing import Any + +import cognee +from haystack import Document, component, default_from_dict, default_to_dict, logging + +from ._utils import run_sync + +logger = logging.getLogger(__name__) + + +@component +class CogneeWriter: + """ + Adds Haystack Documents to Cognee's memory. + + Wraps `cognee.add()` and optionally `cognee.cognify()` to ingest documents + and build a knowledge engine in a single pipeline step. + + Usage: + ```python + from haystack import Document + from haystack_integrations.components.connectors.cognee import CogneeWriter + + writer = CogneeWriter(dataset_name="my_dataset", auto_cognify=True) + writer.run(documents=[Document(content="Cognee builds AI memory.")]) + ``` + """ + + def __init__(self, dataset_name: str = "haystack", auto_cognify: bool = True): + """ + :param dataset_name: Name of the Cognee dataset to add documents to. + :param auto_cognify: If True, automatically runs `cognee.cognify()` after adding + documents to process them into the knowledge engine. + """ + self.dataset_name = dataset_name + self.auto_cognify = auto_cognify + + @component.output_types(documents_written=int) + def run(self, documents: list[Document]) -> dict[str, Any]: + """ + Add documents to Cognee and optionally cognify them. + + :param documents: List of Haystack Documents to add. + :returns: Dictionary with key `documents_written` indicating how many + documents were successfully added. + """ + written = 0 + for doc in documents: + if not doc.content: + logger.warning("Skipping document with empty content: {doc_id}", doc_id=doc.id) + continue + run_sync(cognee.add(doc.content, dataset_name=self.dataset_name)) + written += 1 + + if self.auto_cognify and written > 0: + logger.info( + "Cognifying {count} documents in dataset '{dataset}'", + count=written, + dataset=self.dataset_name, + ) + run_sync(cognee.cognify()) + + return {"documents_written": written} + + def to_dict(self) -> dict[str, Any]: + return default_to_dict( + self, + dataset_name=self.dataset_name, + auto_cognify=self.auto_cognify, + ) + + @classmethod + def from_dict(cls, data: dict[str, Any]) -> "CogneeWriter": + return default_from_dict(cls, data) diff --git a/integrations/cognee/tests/__init__.py b/integrations/cognee/tests/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/integrations/cognee/tests/test_memory_store.py b/integrations/cognee/tests/test_memory_store.py new file mode 100644 index 0000000000..08f068e8ca --- /dev/null +++ b/integrations/cognee/tests/test_memory_store.py @@ -0,0 +1,94 @@ +# SPDX-FileCopyrightText: 2022-present deepset GmbH +# +# SPDX-License-Identifier: Apache-2.0 + +from unittest.mock import AsyncMock, patch + +import pytest +from haystack.dataclasses import ChatMessage + +from haystack_integrations.components.connectors.cognee import CogneeMemoryStore + + +class TestCogneeMemoryStore: + def test_init_defaults(self): + store = CogneeMemoryStore() + assert store.search_type == "GRAPH_COMPLETION" + assert store.top_k == 5 + assert store.dataset_name == "haystack_memory" + + def test_init_custom(self): + store = CogneeMemoryStore(search_type="CHUNKS", top_k=10, dataset_name="custom") + assert store.search_type == "CHUNKS" + assert store.top_k == 10 + assert store.dataset_name == "custom" + + def test_to_dict(self): + store = CogneeMemoryStore(search_type="SUMMARIES", top_k=3, dataset_name="mem") + data = store.to_dict() + assert data["type"] == "haystack_integrations.components.connectors.cognee.memory_store.CogneeMemoryStore" + assert data["init_parameters"]["search_type"] == "SUMMARIES" + assert data["init_parameters"]["top_k"] == 3 + assert data["init_parameters"]["dataset_name"] == "mem" + + def test_from_dict(self): + data = { + "type": "haystack_integrations.components.connectors.cognee.memory_store.CogneeMemoryStore", + "init_parameters": {"search_type": "CHUNKS", "top_k": 8, "dataset_name": "restored"}, + } + store = CogneeMemoryStore.from_dict(data) + assert store.search_type == "CHUNKS" + assert store.top_k == 8 + assert store.dataset_name == "restored" + + @patch("haystack_integrations.components.connectors.cognee.memory_store.cognee") + def test_add_memories(self, mock_cognee): + mock_cognee.add = AsyncMock() + mock_cognee.cognify = AsyncMock() + + store = CogneeMemoryStore() + messages = [ + ChatMessage.from_user("Remember: the deadline is Friday."), + ChatMessage.from_assistant("Got it, I'll remember Friday."), + ] + store.add_memories(messages=messages) + + assert mock_cognee.add.await_count == 2 + mock_cognee.cognify.assert_awaited_once() + + @patch("haystack_integrations.components.connectors.cognee.memory_store.cognee") + def test_search_memories(self, mock_cognee): + mock_cognee.search = AsyncMock(return_value=["Memory about deadline"]) + + store = CogneeMemoryStore() + results = store.search_memories(query="What is the deadline?") + + assert len(results) == 1 + assert isinstance(results[0], ChatMessage) + assert results[0].text == "Memory about deadline" + + def test_search_memories_empty_query(self): + store = CogneeMemoryStore() + results = store.search_memories(query=None) + assert results == [] + + results = store.search_memories(query="") + assert results == [] + + @patch("haystack_integrations.components.connectors.cognee.memory_store.cognee") + def test_delete_all_memories(self, mock_cognee): + mock_cognee.prune = type("Prune", (), { + "prune_data": AsyncMock(), + "prune_system": AsyncMock(), + })() + + store = CogneeMemoryStore() + store.delete_all_memories() + + mock_cognee.prune.prune_data.assert_awaited_once() + mock_cognee.prune.prune_system.assert_awaited_once() + + def test_delete_memory_raises(self): + store = CogneeMemoryStore() + with pytest.raises(NotImplementedError): + store.delete_memory("some-id") diff --git a/integrations/cognee/tests/test_retriever.py b/integrations/cognee/tests/test_retriever.py new file mode 100644 index 0000000000..ed5f1d8726 --- /dev/null +++ b/integrations/cognee/tests/test_retriever.py @@ -0,0 +1,98 @@ +# SPDX-FileCopyrightText: 2022-present deepset GmbH +# +# SPDX-License-Identifier: Apache-2.0 + +from unittest.mock import AsyncMock, patch + +import pytest + +from haystack_integrations.components.connectors.cognee import CogneeRetriever + + +class TestCogneeRetriever: + def test_init_defaults(self): + retriever = CogneeRetriever() + assert retriever.search_type == "GRAPH_COMPLETION" + assert retriever.top_k == 10 + assert retriever.dataset_name is None + + def test_init_custom(self): + retriever = CogneeRetriever(search_type="CHUNKS", top_k=5, dataset_name="my_data") + assert retriever.search_type == "CHUNKS" + assert retriever.top_k == 5 + assert retriever.dataset_name == "my_data" + + def test_init_invalid_search_type(self): + with pytest.raises(ValueError, match="Invalid search_type"): + CogneeRetriever(search_type="INVALID_TYPE") + + def test_to_dict(self): + retriever = CogneeRetriever(search_type="SUMMARIES", top_k=3, dataset_name="ds") + data = retriever.to_dict() + assert data["type"] == "haystack_integrations.components.connectors.cognee.retriever.CogneeRetriever" + assert data["init_parameters"]["search_type"] == "SUMMARIES" + assert data["init_parameters"]["top_k"] == 3 + assert data["init_parameters"]["dataset_name"] == "ds" + + def test_from_dict(self): + data = { + "type": "haystack_integrations.components.connectors.cognee.retriever.CogneeRetriever", + "init_parameters": {"search_type": "CHUNKS", "top_k": 7, "dataset_name": None}, + } + retriever = CogneeRetriever.from_dict(data) + assert retriever.search_type == "CHUNKS" + assert retriever.top_k == 7 + + @patch("haystack_integrations.components.connectors.cognee.retriever.cognee") + def test_run_returns_documents(self, mock_cognee): + mock_cognee.search = AsyncMock(return_value=["result one", "result two"]) + + retriever = CogneeRetriever(search_type="GRAPH_COMPLETION", top_k=5) + result = retriever.run(query="What is Cognee?") + + docs = result["documents"] + assert len(docs) == 2 + assert docs[0].content == "result one" + assert docs[0].meta["source"] == "cognee" + + @patch("haystack_integrations.components.connectors.cognee.retriever.cognee") + def test_run_empty_results(self, mock_cognee): + mock_cognee.search = AsyncMock(return_value=[]) + + retriever = CogneeRetriever() + result = retriever.run(query="nonexistent query") + + assert result["documents"] == [] + + @patch("haystack_integrations.components.connectors.cognee.retriever.cognee") + def test_run_respects_top_k_override(self, mock_cognee): + mock_cognee.search = AsyncMock(return_value=["a", "b", "c", "d", "e"]) + + retriever = CogneeRetriever(top_k=10) + result = retriever.run(query="test", top_k=2) + + assert len(result["documents"]) == 2 + + @patch("haystack_integrations.components.connectors.cognee.retriever.cognee") + def test_run_handles_dict_results(self, mock_cognee): + mock_cognee.search = AsyncMock( + return_value=[ + {"content": "Dict content", "score": 0.9}, + {"text": "Alt text field"}, + ] + ) + + retriever = CogneeRetriever() + result = retriever.run(query="test") + + assert len(result["documents"]) == 2 + assert result["documents"][0].content == "Dict content" + assert result["documents"][1].content == "Alt text field" + + @patch("haystack_integrations.components.connectors.cognee.retriever.cognee") + def test_run_handles_none_results(self, mock_cognee): + mock_cognee.search = AsyncMock(return_value=None) + + retriever = CogneeRetriever() + result = retriever.run(query="test") + assert result["documents"] == [] diff --git a/integrations/cognee/tests/test_writer.py b/integrations/cognee/tests/test_writer.py new file mode 100644 index 0000000000..597224b761 --- /dev/null +++ b/integrations/cognee/tests/test_writer.py @@ -0,0 +1,94 @@ +# SPDX-FileCopyrightText: 2022-present deepset GmbH +# +# SPDX-License-Identifier: Apache-2.0 + +from unittest.mock import AsyncMock, patch + +from haystack import Document + +from haystack_integrations.components.connectors.cognee import CogneeWriter + + +class TestCogneeWriter: + def test_init_defaults(self): + writer = CogneeWriter() + assert writer.dataset_name == "haystack" + assert writer.auto_cognify is True + + def test_init_custom(self): + writer = CogneeWriter(dataset_name="custom", auto_cognify=False) + assert writer.dataset_name == "custom" + assert writer.auto_cognify is False + + def test_to_dict(self): + writer = CogneeWriter(dataset_name="test_ds", auto_cognify=False) + data = writer.to_dict() + assert data["type"] == "haystack_integrations.components.connectors.cognee.writer.CogneeWriter" + assert data["init_parameters"]["dataset_name"] == "test_ds" + assert data["init_parameters"]["auto_cognify"] is False + + def test_from_dict(self): + data = { + "type": "haystack_integrations.components.connectors.cognee.writer.CogneeWriter", + "init_parameters": {"dataset_name": "restored", "auto_cognify": True}, + } + writer = CogneeWriter.from_dict(data) + assert writer.dataset_name == "restored" + assert writer.auto_cognify is True + + @patch("haystack_integrations.components.connectors.cognee.writer.cognee") + def test_run_with_auto_cognify(self, mock_cognee): + mock_cognee.add = AsyncMock() + mock_cognee.cognify = AsyncMock() + + writer = CogneeWriter(dataset_name="test", auto_cognify=True) + docs = [ + Document(content="First document"), + Document(content="Second document"), + ] + result = writer.run(documents=docs) + + assert result == {"documents_written": 2} + assert mock_cognee.add.await_count == 2 + mock_cognee.cognify.assert_awaited_once() + + @patch("haystack_integrations.components.connectors.cognee.writer.cognee") + def test_run_without_auto_cognify(self, mock_cognee): + mock_cognee.add = AsyncMock() + mock_cognee.cognify = AsyncMock() + + writer = CogneeWriter(dataset_name="test", auto_cognify=False) + docs = [Document(content="A document")] + result = writer.run(documents=docs) + + assert result == {"documents_written": 1} + mock_cognee.add.assert_awaited_once() + mock_cognee.cognify.assert_not_awaited() + + @patch("haystack_integrations.components.connectors.cognee.writer.cognee") + def test_run_skips_empty_content(self, mock_cognee): + mock_cognee.add = AsyncMock() + mock_cognee.cognify = AsyncMock() + + writer = CogneeWriter(auto_cognify=True) + docs = [ + Document(content="Valid document"), + Document(content=""), + Document(content=None), + ] + result = writer.run(documents=docs) + + assert result == {"documents_written": 1} + assert mock_cognee.add.await_count == 1 + + @patch("haystack_integrations.components.connectors.cognee.writer.cognee") + def test_run_empty_list(self, mock_cognee): + mock_cognee.add = AsyncMock() + mock_cognee.cognify = AsyncMock() + + writer = CogneeWriter(auto_cognify=True) + result = writer.run(documents=[]) + + assert result == {"documents_written": 0} + mock_cognee.add.assert_not_awaited() + mock_cognee.cognify.assert_not_awaited() From 59c8443a121ff7200760e33f5993e4eb497a542e Mon Sep 17 00:00:00 2001 From: Hande <159312713+hande-k@users.noreply.github.com> Date: Wed, 18 Mar 2026 13:26:52 +0100 Subject: [PATCH 02/10] add fix --- .github/labeler.yml | 5 + .github/workflows/cognee.yml | 79 + README.md | 1 + integrations/cognee/.gitignore | 163 ++ integrations/cognee/CHANGELOG.md | 3 + integrations/cognee/LICENSE | 201 +++ .../.artifacts/demo_memory_agent.html | 1450 +++++++++++++++++ .../examples/.artifacts/demo_pipeline.html | 1450 +++++++++++++++++ .../cognee/examples/demo_memory_agent.py | 15 +- integrations/cognee/examples/demo_pipeline.py | 11 +- .../cognee/pydoc/config_docusaurus.yml | 16 + integrations/cognee/pyproject.toml | 133 +- .../components/connectors/cognee/_utils.py | 6 +- .../components/connectors/cognee/cognifier.py | 3 +- .../connectors/cognee/memory_store.py | 10 +- .../components/connectors/cognee/py.typed | 0 .../components/connectors/cognee/retriever.py | 5 +- .../components/connectors/cognee/writer.py | 5 +- .../cognee/tests/test_memory_store.py | 12 +- 19 files changed, 3524 insertions(+), 44 deletions(-) create mode 100644 .github/workflows/cognee.yml create mode 100644 integrations/cognee/.gitignore create mode 100644 integrations/cognee/CHANGELOG.md create mode 100644 integrations/cognee/LICENSE create mode 100644 integrations/cognee/examples/.artifacts/demo_memory_agent.html create mode 100644 integrations/cognee/examples/.artifacts/demo_pipeline.html create mode 100644 integrations/cognee/pydoc/config_docusaurus.yml create mode 100644 integrations/cognee/src/haystack_integrations/components/connectors/cognee/py.typed diff --git a/.github/labeler.yml b/.github/labeler.yml index 0929acebe7..2a952a3977 100644 --- a/.github/labeler.yml +++ b/.github/labeler.yml @@ -39,6 +39,11 @@ integration:azure-doc-intelligence: - any-glob-to-any-file: "integrations/azure_doc_intelligence/**/*" - any-glob-to-any-file: ".github/workflows/azure_doc_intelligence.yml" +integration:cognee: + - changed-files: + - any-glob-to-any-file: "integrations/cognee/**/*" + - any-glob-to-any-file: ".github/workflows/cognee.yml" + integration:chroma: - changed-files: - any-glob-to-any-file: "integrations/chroma/**/*" diff --git a/.github/workflows/cognee.yml b/.github/workflows/cognee.yml new file mode 100644 index 0000000000..158009d21e --- /dev/null +++ b/.github/workflows/cognee.yml @@ -0,0 +1,79 @@ +# This workflow comes from https://github.com/ofek/hatch-mypyc +# https://github.com/ofek/hatch-mypyc/blob/5a198c0ba8660494d02716cfc9d79ce4adfb1442/.github/workflows/test.yml +name: Test / cognee + +on: + schedule: + - cron: "0 0 * * *" + pull_request: + paths: + - "integrations/cognee/**" + - "!integrations/cognee/*.md" + - ".github/workflows/cognee.yml" + +defaults: + run: + working-directory: integrations/cognee + +concurrency: + group: cognee-${{ github.head_ref }} + cancel-in-progress: true + +env: + PYTHONUNBUFFERED: "1" + FORCE_COLOR: "1" + +jobs: + run: + name: Python ${{ matrix.python-version }} on ${{ startsWith(matrix.os, 'macos-') && 'macOS' || startsWith(matrix.os, 'windows-') && 'Windows' || 'Linux' }} + runs-on: ${{ matrix.os }} + strategy: + fail-fast: false + matrix: + os: [ubuntu-latest, windows-latest, macos-latest] + python-version: ["3.10", "3.13"] + + steps: + - name: Support longpaths + if: matrix.os == 'windows-latest' + working-directory: . + run: git config --system core.longpaths true + + - uses: actions/checkout@v6 + + - name: Set up Python ${{ matrix.python-version }} + uses: actions/setup-python@v6 + with: + python-version: ${{ matrix.python-version }} + + - name: Install Hatch + run: pip install --upgrade hatch + - name: Lint + if: matrix.python-version == '3.10' && runner.os == 'Linux' + run: hatch run fmt-check && hatch run test:types + + - name: Run tests + run: hatch run test:cov-retry + + - name: Run unit tests with lowest direct dependencies + run: | + hatch run uv pip compile pyproject.toml --resolution lowest-direct --output-file requirements_lowest_direct.txt + hatch -e test env run -- uv pip install -r requirements_lowest_direct.txt + hatch run test:unit + + - name: Nightly - run tests with Haystack main branch + if: github.event_name == 'schedule' + run: | + hatch env prune + hatch -e test env run -- uv pip install git+https://github.com/deepset-ai/haystack.git@main + hatch run test:cov-retry + + + notify-slack-on-failure: + needs: run + if: failure() && github.event_name == 'schedule' + runs-on: ubuntu-slim + steps: + - uses: deepset-ai/notify-slack-action@v1 + with: + slack-webhook-url: ${{ secrets.SLACK_WEBHOOK_URL_NOTIFICATIONS }} diff --git a/README.md b/README.md index 7319a7bde8..fd9a08efb0 100644 --- a/README.md +++ b/README.md @@ -34,6 +34,7 @@ Please check out our [Contribution Guidelines](CONTRIBUTING.md) for all the deta | [azure-ai-search-haystack](integrations/azure_ai_search/) | Document Store | [![PyPI - Version](https://img.shields.io/pypi/v/azure-ai-search-haystack.svg)](https://pypi.org/project/azure-ai-search-haystack) | [![Test / azure-ai-search](https://github.com/deepset-ai/haystack-core-integrations/actions/workflows/azure_ai_search.yml/badge.svg)](https://github.com/deepset-ai/haystack-core-integrations/actions/workflows/azure_ai_search.yml) | | [azure-doc-intelligence-haystack](integrations/azure_doc_intelligence/) | Converter | [![PyPI - Version](https://img.shields.io/pypi/v/azure-doc-intelligence-haystack.svg)](https://pypi.org/project/azure-doc-intelligence-haystack) | [![Test / azure_doc_intelligence](https://github.com/deepset-ai/haystack-core-integrations/actions/workflows/azure_doc_intelligence.yml/badge.svg)](https://github.com/deepset-ai/haystack-core-integrations/actions/workflows/azure_doc_intelligence.yml) | | [chroma-haystack](integrations/chroma/) | Document Store | [![PyPI - Version](https://img.shields.io/pypi/v/chroma-haystack.svg)](https://pypi.org/project/chroma-haystack) | [![Test / chroma](https://github.com/deepset-ai/haystack-core-integrations/actions/workflows/chroma.yml/badge.svg)](https://github.com/deepset-ai/haystack-core-integrations/actions/workflows/chroma.yml) | +| [cognee-haystack](integrations/cognee/) | Connector | [![PyPI - Version](https://img.shields.io/pypi/v/cognee-haystack.svg)](https://pypi.org/project/cognee-haystack) | [![Test / cognee](https://github.com/deepset-ai/haystack-core-integrations/actions/workflows/cognee.yml/badge.svg)](https://github.com/deepset-ai/haystack-core-integrations/actions/workflows/cognee.yml) | | [cohere-haystack](integrations/cohere/) | Embedder, Generator, Ranker | [![PyPI - Version](https://img.shields.io/pypi/v/cohere-haystack.svg)](https://pypi.org/project/cohere-haystack) | [![Test / cohere](https://github.com/deepset-ai/haystack-core-integrations/actions/workflows/cohere.yml/badge.svg)](https://github.com/deepset-ai/haystack-core-integrations/actions/workflows/cohere.yml) | | [cometapi-haystack](integrations/cometapi/) | Generator | [![PyPI - Version](https://img.shields.io/pypi/v/cometapi-haystack.svg)](https://pypi.org/project/cometapi-haystack) | [![Test / cometapi](https://github.com/deepset-ai/haystack-core-integrations/actions/workflows/cometapi.yml/badge.svg)](https://github.com/deepset-ai/haystack-core-integrations/actions/workflows/cometapi.yml) | | [deepeval-haystack](integrations/deepeval/) | Evaluator | [![PyPI - Version](https://img.shields.io/pypi/v/deepeval-haystack.svg)](https://pypi.org/project/deepeval-haystack) | [![Test / deepeval](https://github.com/deepset-ai/haystack-core-integrations/actions/workflows/deepeval.yml/badge.svg)](https://github.com/deepset-ai/haystack-core-integrations/actions/workflows/deepeval.yml) | diff --git a/integrations/cognee/.gitignore b/integrations/cognee/.gitignore new file mode 100644 index 0000000000..a3d827e06b --- /dev/null +++ b/integrations/cognee/.gitignore @@ -0,0 +1,163 @@ +# Byte-compiled / optimized / DLL files +__pycache__/ +*.py[cod] +*$py.class + +# C extensions +*.so + +# Distribution / packaging +.Python +build/ +develop-eggs/ +dist/ +downloads/ +eggs/ +.eggs/ +lib/ +lib64/ +parts/ +sdist/ +var/ +wheels/ +share/python-wheels/ +*.egg-info/ +.installed.cfg +*.egg +MANIFEST + +# PyInstaller +# Usually these files are written by a python script from a template +# before PyInstaller builds the exe, so as to inject date/other infos into it. +*.manifest +*.spec + +# Installer logs +pip-log.txt +pip-delete-this-directory.txt + +# Unit test / coverage reports +htmlcov/ +.tox/ +.nox/ +.coverage +.coverage.* +.cache +nosetests.xml +coverage.xml +*.cover +*.py,cover +.hypothesis/ +.pytest_cache/ +cover/ + +# Translations +*.mo +*.pot + +# Django stuff: +*.log +local_settings.py +*.sqlite3 +*.sqlite3-journal + +# Flask stuff: +instance/ +.webassets-cache + +# Scrapy stuff: +.scrapy + +# Sphinx documentation +docs/_build/ + +# PyBuilder +.pybuilder/ +target/ + +# Jupyter Notebook +.ipynb_checkpoints + +# IPython +profile_default/ +ipython_config.py + +# pyenv +# For a library or package, you might want to ignore these files since the code is +# intended to run in multiple environments; otherwise, check them in: +# .python-version + +# pipenv +# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control. +# However, in case of collaboration, if having platform-specific dependencies or dependencies +# having no cross-platform support, pipenv may install dependencies that don't work, or not +# install all needed dependencies. +#Pipfile.lock + +# poetry +# Similar to Pipfile.lock, it is generally recommended to include poetry.lock in version control. +# This is especially recommended for binary packages to ensure reproducibility, and is more +# commonly ignored for libraries. +# https://python-poetry.org/docs/basic-usage/#commit-your-poetrylock-file-to-version-control +#poetry.lock + +# pdm +# Similar to Pipfile.lock, it is generally recommended to include pdm.lock in version control. +#pdm.lock +# pdm stores project-wide configurations in .pdm.toml, but it is recommended to not include it +# in version control. +# https://pdm.fming.dev/#use-with-ide +.pdm.toml + +# PEP 582; used by e.g. github.com/David-OConnor/pyflow and github.com/pdm-project/pdm +__pypackages__/ + +# Celery stuff +celerybeat-schedule +celerybeat.pid + +# SageMath parsed files +*.sage.py + +# Environments +.env +.venv +env/ +venv/ +ENV/ +env.bak/ +venv.bak/ + +# Spyder project settings +.spyderproject +.spyproject + +# Rope project settings +.ropeproject + +# mkdocs documentation +/site + +# mypy +.mypy_cache/ +.dmypy.json +dmypy.json + +# Pyre type checker +.pyre/ + +# pytype static type analyzer +.pytype/ + +# Cython debug symbols +cython_debug/ + +# PyCharm +# JetBrains specific template is maintained in a separate JetBrains.gitignore that can +# be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore +# and can be added to the global gitignore or merged into this file. For a more nuclear +# option (not recommended) you can uncomment the following to ignore the entire idea folder. +#.idea/ + +# VS Code +.vscode diff --git a/integrations/cognee/CHANGELOG.md b/integrations/cognee/CHANGELOG.md new file mode 100644 index 0000000000..f39c90b2b7 --- /dev/null +++ b/integrations/cognee/CHANGELOG.md @@ -0,0 +1,3 @@ +# Changelog + + diff --git a/integrations/cognee/LICENSE b/integrations/cognee/LICENSE new file mode 100644 index 0000000000..de4c7f39f1 --- /dev/null +++ b/integrations/cognee/LICENSE @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright 2023 deepset GmbH + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/integrations/cognee/examples/.artifacts/demo_memory_agent.html b/integrations/cognee/examples/.artifacts/demo_memory_agent.html new file mode 100644 index 0000000000..67aeeef2e0 --- /dev/null +++ b/integrations/cognee/examples/.artifacts/demo_memory_agent.html @@ -0,0 +1,1450 @@ + + + + + +Cognee Knowledge Graph + + + + + + + + + +
+ + + + + +
+ Color: + + + + + +
+ + + +
+ +
+
+ +
+
Laying out graph...
+
+
+
+ +
+
+ + + + + + \ No newline at end of file diff --git a/integrations/cognee/examples/.artifacts/demo_pipeline.html b/integrations/cognee/examples/.artifacts/demo_pipeline.html new file mode 100644 index 0000000000..059439d05b --- /dev/null +++ b/integrations/cognee/examples/.artifacts/demo_pipeline.html @@ -0,0 +1,1450 @@ + + + + + +Cognee Knowledge Graph + + + + + + + + + +
+ + + + + +
+ Color: + + + + + +
+ + + +
+ +
+
+ +
+
Laying out graph...
+
+
+
+ +
+
+ + + + + + \ No newline at end of file diff --git a/integrations/cognee/examples/demo_memory_agent.py b/integrations/cognee/examples/demo_memory_agent.py index 7e223e1022..cf7c5e8b76 100644 --- a/integrations/cognee/examples/demo_memory_agent.py +++ b/integrations/cognee/examples/demo_memory_agent.py @@ -12,12 +12,14 @@ export LLM_API_KEY="sk-..." """ +import asyncio +import os + +from cognee.api.v1.visualize.visualize import visualize_graph from haystack.dataclasses import ChatMessage from haystack_integrations.components.connectors.cognee import CogneeMemoryStore -from cognee.api.v1.visualize.visualize import visualize_graph -import asyncio -import os + async def main(): print("=== Cognee Memory Store Demo ===\n") @@ -33,8 +35,7 @@ async def main(): print("2. Adding memories...") messages = [ ChatMessage.from_user( - "My name is Alice and I'm working on the Cognee-Haystack integration. " - "The deadline is next Friday." + "My name is Alice and I'm working on the Cognee-Haystack integration. The deadline is next Friday." ), ChatMessage.from_user( "We decided to use GRAPH_COMPLETION as the default search type " @@ -48,9 +49,7 @@ async def main(): store.add_memories(messages=messages) print(f" Added {len(messages)} messages as memories.\n") - visualization_path = os.path.join( - os.path.dirname(__file__), ".artifacts", "demo_memory_agent.html" - ) + visualization_path = os.path.join(os.path.dirname(__file__), ".artifacts", "demo_memory_agent.html") await visualize_graph(visualization_path) # --- Step 3: Search memories --- diff --git a/integrations/cognee/examples/demo_pipeline.py b/integrations/cognee/examples/demo_pipeline.py index 4c59ea4026..72ffe630f6 100644 --- a/integrations/cognee/examples/demo_pipeline.py +++ b/integrations/cognee/examples/demo_pipeline.py @@ -12,12 +12,13 @@ export LLM_API_KEY="sk-..." """ -from haystack import Document, Pipeline +import asyncio +import os + from cognee.api.v1.visualize.visualize import visualize_graph +from haystack import Document, Pipeline from haystack_integrations.components.connectors.cognee import CogneeRetriever, CogneeWriter -import asyncio -import os SAMPLE_DOCUMENTS = [ Document( @@ -67,9 +68,7 @@ async def main(): result = indexing.run({"writer": {"documents": SAMPLE_DOCUMENTS}}) print(f" Written: {result['writer']['documents_written']} documents\n") - visualization_path = os.path.join( - os.path.dirname(__file__), ".artifacts", "demo_pipeline.html" - ) + visualization_path = os.path.join(os.path.dirname(__file__), ".artifacts", "demo_pipeline.html") await visualize_graph(visualization_path) # --- Query pipeline --- diff --git a/integrations/cognee/pydoc/config_docusaurus.yml b/integrations/cognee/pydoc/config_docusaurus.yml new file mode 100644 index 0000000000..7804b76fb8 --- /dev/null +++ b/integrations/cognee/pydoc/config_docusaurus.yml @@ -0,0 +1,16 @@ +loaders: + - modules: + - haystack_integrations.components.connectors.cognee.writer + - haystack_integrations.components.connectors.cognee.retriever + - haystack_integrations.components.connectors.cognee.cognifier + - haystack_integrations.components.connectors.cognee.memory_store + search_path: [../src] +processors: + - type: filter + documented_only: true + skip_empty_modules: true +renderer: + description: Cognee integration for Haystack + id: integrations-cognee + filename: cognee.md + title: Cognee diff --git a/integrations/cognee/pyproject.toml b/integrations/cognee/pyproject.toml index dc5316d427..2f0e6a5c4d 100644 --- a/integrations/cognee/pyproject.toml +++ b/integrations/cognee/pyproject.toml @@ -9,24 +9,33 @@ description = "Haystack integration for Cognee — memory for AI agents" readme = "README.md" requires-python = ">=3.10" license = "Apache-2.0" +keywords = [] authors = [{ name = "deepset GmbH", email = "info@deepset.ai" }] classifiers = [ - "Development Status :: 3 - Alpha", - "License :: OSI Approved :: Apache Software License", - "Programming Language :: Python :: 3", - "Programming Language :: Python :: 3.10", - "Programming Language :: Python :: 3.11", - "Programming Language :: Python :: 3.12", + "License :: OSI Approved :: Apache Software License", + "Development Status :: 3 - Alpha", + "Programming Language :: Python", + "Programming Language :: Python :: 3.10", + "Programming Language :: Python :: 3.11", + "Programming Language :: Python :: 3.12", + "Programming Language :: Python :: 3.13", + "Programming Language :: Python :: Implementation :: CPython", + "Programming Language :: Python :: Implementation :: PyPy", ] dependencies = [ - "haystack-ai>=2.0", - "cognee==0.5.4", - "mistralai>=1.0,<2.0", + "haystack-ai>=2.24.0", + "cognee==0.5.4", + "mistralai>=1.0,<2.0", ] [project.optional-dependencies] memory = ["haystack-experimental"] +[project.urls] +Documentation = "https://github.com/deepset-ai/haystack-core-integrations/tree/main/integrations/cognee#readme" +Issues = "https://github.com/deepset-ai/haystack-core-integrations/issues" +Source = "https://github.com/deepset-ai/haystack-core-integrations/tree/main/integrations/cognee" + [tool.hatch.build.targets.wheel] packages = ["src/haystack_integrations"] @@ -38,18 +47,114 @@ tag-pattern = 'integrations\/cognee-v(?P.*)' root = "../.." git_describe_command = 'git describe --tags --match="integrations/cognee-v[0-9]*"' +[tool.hatch.envs.default] +installer = "uv" +dependencies = ["haystack-pydoc-tools", "ruff"] + +[tool.hatch.envs.default.scripts] +docs = ["haystack-pydoc pydoc/config_docusaurus.yml"] +fmt = "ruff check --fix {args}; ruff format {args}" +fmt-check = "ruff check {args} && ruff format --check {args}" + [tool.hatch.envs.test] dependencies = [ "pytest", "pytest-asyncio", + "pytest-cov", + "pytest-rerunfailures", + "mypy", + "pip", "haystack-experimental", ] [tool.hatch.envs.test.scripts] -unit = "pytest {args:tests}" - -[tool.hatch.envs.types] -dependencies = ["mypy"] +unit = 'pytest -m "not integration" {args:tests}' +integration = 'pytest -m "integration" {args:tests}' +all = 'pytest {args:tests}' +cov-retry = 'pytest --cov=haystack_integrations --reruns 3 --reruns-delay 30 -x {args:tests}' -[tool.hatch.envs.types.scripts] types = "mypy -p haystack_integrations.components.connectors.cognee {args}" + +[tool.mypy] +install_types = true +non_interactive = true +check_untyped_defs = true +disallow_incomplete_defs = true + +[tool.ruff] +line-length = 120 + +[tool.ruff.lint] +select = [ + "A", + "ARG", + "B", + "C", + "DTZ", + "E", + "EM", + "F", + "FBT", + "I", + "ICN", + "ISC", + "N", + "PLC", + "PLE", + "PLR", + "PLW", + "Q", + "RUF", + "S", + "T", + "TID", + "UP", + "W", + "YTT", +] +ignore = [ + # Allow non-abstract empty methods in abstract base classes + "B027", + # Allow boolean positional values in function calls, like `dict.get(... True)` + "FBT003", + # Ignore checks for possible passwords + "S105", + "S106", + "S107", + # Ignore complexity + "C901", + "PLR0911", + "PLR0912", + "PLR0913", + "PLR0915", + # Ignore unused params + "ARG002", + # Allow assertions + "S101", +] +exclude = ["examples"] + +[tool.ruff.lint.isort] +known-first-party = ["haystack_integrations"] + +[tool.ruff.lint.flake8-tidy-imports] +ban-relative-imports = "parents" + +[tool.ruff.lint.per-file-ignores] +# Tests can use magic values, assertions, and relative imports +"tests/**/*" = ["PLR2004", "S101", "TID252"] +"examples/**/*" = ["T201"] + +[tool.coverage.run] +source = ["haystack_integrations"] +branch = true +parallel = false + +[tool.coverage.report] +omit = ["*/tests/*", "*/__init__.py"] +show_missing = true +exclude_lines = ["no cov", "if __name__ == .__main__.:", "if TYPE_CHECKING:"] + +[tool.pytest.ini_options] +minversion = "6.0" +markers = ["integration: integration tests"] diff --git a/integrations/cognee/src/haystack_integrations/components/connectors/cognee/_utils.py b/integrations/cognee/src/haystack_integrations/components/connectors/cognee/_utils.py index 6b75033b3d..49638e81b0 100644 --- a/integrations/cognee/src/haystack_integrations/components/connectors/cognee/_utils.py +++ b/integrations/cognee/src/haystack_integrations/components/connectors/cognee/_utils.py @@ -3,10 +3,14 @@ # SPDX-License-Identifier: Apache-2.0 import asyncio +from collections.abc import Coroutine from concurrent.futures import ThreadPoolExecutor +from typing import Any, TypeVar +T = TypeVar("T") -def run_sync(coro): + +def run_sync(coro: Coroutine[Any, Any, T]) -> T: """ Run an async coroutine from a synchronous context. diff --git a/integrations/cognee/src/haystack_integrations/components/connectors/cognee/cognifier.py b/integrations/cognee/src/haystack_integrations/components/connectors/cognee/cognifier.py index 9f900b7955..09fa6c9c97 100644 --- a/integrations/cognee/src/haystack_integrations/components/connectors/cognee/cognifier.py +++ b/integrations/cognee/src/haystack_integrations/components/connectors/cognee/cognifier.py @@ -4,9 +4,10 @@ from typing import Any -import cognee from haystack import component, default_from_dict, default_to_dict, logging +import cognee # type: ignore[import-untyped] + from ._utils import run_sync logger = logging.getLogger(__name__) diff --git a/integrations/cognee/src/haystack_integrations/components/connectors/cognee/memory_store.py b/integrations/cognee/src/haystack_integrations/components/connectors/cognee/memory_store.py index 95ac50c279..452c16be9c 100644 --- a/integrations/cognee/src/haystack_integrations/components/connectors/cognee/memory_store.py +++ b/integrations/cognee/src/haystack_integrations/components/connectors/cognee/memory_store.py @@ -4,10 +4,12 @@ from typing import Any -import cognee from haystack import default_from_dict, default_to_dict, logging from haystack.dataclasses import ChatMessage +import cognee # type: ignore[import-untyped] +from cognee.api.v1.search import SearchType # type: ignore[import-untyped] + from ._utils import run_sync logger = logging.getLogger(__name__) @@ -89,14 +91,10 @@ def search_memories( if not query: return [] - from cognee.api.v1.search import SearchType - search_type_enum = SearchType[self.search_type] effective_top_k = top_k or self.top_k - raw_results = run_sync( - cognee.search(query_text=query, query_type=search_type_enum) - ) + raw_results = run_sync(cognee.search(query_text=query, query_type=search_type_enum)) memories: list[ChatMessage] = [] if not raw_results: diff --git a/integrations/cognee/src/haystack_integrations/components/connectors/cognee/py.typed b/integrations/cognee/src/haystack_integrations/components/connectors/cognee/py.typed new file mode 100644 index 0000000000..e69de29bb2 diff --git a/integrations/cognee/src/haystack_integrations/components/connectors/cognee/retriever.py b/integrations/cognee/src/haystack_integrations/components/connectors/cognee/retriever.py index bf05f9d571..5c369dfcfd 100644 --- a/integrations/cognee/src/haystack_integrations/components/connectors/cognee/retriever.py +++ b/integrations/cognee/src/haystack_integrations/components/connectors/cognee/retriever.py @@ -4,10 +4,11 @@ from typing import Any -import cognee -from cognee.api.v1.search import SearchType from haystack import Document, component, default_from_dict, default_to_dict, logging +import cognee # type: ignore[import-untyped] +from cognee.api.v1.search import SearchType # type: ignore[import-untyped] + from ._utils import run_sync logger = logging.getLogger(__name__) diff --git a/integrations/cognee/src/haystack_integrations/components/connectors/cognee/writer.py b/integrations/cognee/src/haystack_integrations/components/connectors/cognee/writer.py index 723d8e2644..1c504ee31a 100644 --- a/integrations/cognee/src/haystack_integrations/components/connectors/cognee/writer.py +++ b/integrations/cognee/src/haystack_integrations/components/connectors/cognee/writer.py @@ -4,9 +4,10 @@ from typing import Any -import cognee from haystack import Document, component, default_from_dict, default_to_dict, logging +import cognee # type: ignore[import-untyped] + from ._utils import run_sync logger = logging.getLogger(__name__) @@ -30,7 +31,7 @@ class CogneeWriter: ``` """ - def __init__(self, dataset_name: str = "haystack", auto_cognify: bool = True): + def __init__(self, *, dataset_name: str = "haystack", auto_cognify: bool = True): """ :param dataset_name: Name of the Cognee dataset to add documents to. :param auto_cognify: If True, automatically runs `cognee.cognify()` after adding diff --git a/integrations/cognee/tests/test_memory_store.py b/integrations/cognee/tests/test_memory_store.py index 08f068e8ca..937c8eb24e 100644 --- a/integrations/cognee/tests/test_memory_store.py +++ b/integrations/cognee/tests/test_memory_store.py @@ -77,10 +77,14 @@ def test_search_memories_empty_query(self): @patch("haystack_integrations.components.connectors.cognee.memory_store.cognee") def test_delete_all_memories(self, mock_cognee): - mock_cognee.prune = type("Prune", (), { - "prune_data": AsyncMock(), - "prune_system": AsyncMock(), - })() + mock_cognee.prune = type( + "Prune", + (), + { + "prune_data": AsyncMock(), + "prune_system": AsyncMock(), + }, + )() store = CogneeMemoryStore() store.delete_all_memories() From 657b7cc797b65396de1c638861c790cd5e5c7132 Mon Sep 17 00:00:00 2001 From: Hande <159312713+hande-k@users.noreply.github.com> Date: Wed, 18 Mar 2026 13:40:58 +0100 Subject: [PATCH 03/10] update readmes --- integrations/cognee/README.md | 23 +++++++++++++++++------ integrations/cognee/examples/README.md | 8 ++++++-- 2 files changed, 23 insertions(+), 8 deletions(-) diff --git a/integrations/cognee/README.md b/integrations/cognee/README.md index c3212e192c..eafc9e0bad 100644 --- a/integrations/cognee/README.md +++ b/integrations/cognee/README.md @@ -3,7 +3,12 @@ [![PyPI](https://img.shields.io/pypi/v/cognee-haystack.svg)](https://pypi.org/project/cognee-haystack/) [![License](https://img.shields.io/badge/license-Apache%202.0-blue.svg)](LICENSE) -A [Haystack](https://haystack.deepset.ai/) integration for [Cognee](https://github.com/topoteretes/cognee) — memory for AI agents. +A [Haystack](https://haystack.deepset.ai/) integration for [Cognee](https://github.com/topoteretes/cognee) — open-source memory for AI agents. + +[Cognee](https://www.cognee.ai/) gives agents persistent, traceable memory by transforming raw data (e.g., unstructured documents, relational databases, etc.) into a knowledge engine that is both searchable by meaning and connected by relationships. Cognee uses an ECL (Extract, Cognify, Load) pipeline: vector search, knowledge graphs, with support for ontology-based entity grounding (e.g. OWL) and Pydantic-defined graph schemas. + +Cognee serves developers and teams building agentic systems where agents need to retain context across sessions, learn from user feedback, and operate in multi-tenant, data-isolated environments. Cognee is available as an open-source Python library (Apache 2.0), a self-hosted/on-prem subscription tier, and a managed cloud service (Cognee Cloud at platform.cognee.ai). + ## Installation @@ -87,7 +92,7 @@ results = store.search_memories(query="When is the deadline?") Cognee uses environment variables for its LLM and storage configuration: ```bash -export OPENAI_API_KEY="sk-..." +export LLM_API_KEY="sk-..." ``` See the [Cognee documentation](https://docs.cognee.ai/) for additional configuration options. @@ -102,13 +107,19 @@ See the [`examples/`](examples/) directory for runnable demos: ## Development ```bash -# Install in dev mode -pip install -e "integrations/cognee[memory]" +cd integrations/cognee + +# Format and lint +hatch run fmt +hatch run fmt-check + +# Type checking +hatch run test:types # Run tests -pytest integrations/cognee/tests/ +hatch run test:unit ``` ## License -Apache 2.0 — see [LICENSE](../../LICENSE) for details. +Apache 2.0 — see [LICENSE](LICENSE) for details. diff --git a/integrations/cognee/examples/README.md b/integrations/cognee/examples/README.md index a65a51c45f..b5210b64e5 100644 --- a/integrations/cognee/examples/README.md +++ b/integrations/cognee/examples/README.md @@ -8,10 +8,14 @@ Install the integration from the repository root: pip install -e "integrations/cognee[memory]" ``` -Set your LLM API key (required by cognee): +Set your LLM API key (required by cognee, default OpenAI API key) and ENABLE_BACKEND_ACCESS_CONTROL=False for simplicity: + +To integrate other LLM providers and other configuration options, see [Cognee Documentation](https://docs.cognee.ai/getting-started/installation#environment-configuration). + ```bash -export LLM_API_KEY="sk-..." +export LLM_API_KEY="sk-your-openai-api-key" +export ENABLE_BACKEND_ACCESS_CONTROL="False" ``` ## Examples From 2bd6bc2266fe1fafe49ea79465a8f8823cd90e4d Mon Sep 17 00:00:00 2001 From: Hande <159312713+hande-k@users.noreply.github.com> Date: Sat, 21 Mar 2026 01:35:51 +0100 Subject: [PATCH 04/10] Address PR review feedback --- integrations/cognee/.gitignore | 163 ------------------ integrations/cognee/CHANGELOG.md | 3 - integrations/cognee/README.md | 125 +------------- .../.artifacts/demo_memory_agent.html | 4 +- .../examples/.artifacts/demo_pipeline.html | 4 +- .../cognee/examples/demo_memory_agent.py | 2 +- integrations/cognee/examples/demo_pipeline.py | 3 +- integrations/cognee/pyproject.toml | 3 +- .../components/connectors/cognee/__init__.py | 6 - .../components/connectors/cognee/_utils.py | 38 +++- .../components/connectors/cognee/cognifier.py | 56 ++++-- .../connectors/{cognee => }/py.typed | 0 .../components/retrievers/cognee/__init__.py | 9 + .../cognee/memory_retriever.py} | 36 +--- .../components/writers/cognee/__init__.py | 9 + .../cognee/memory_writer.py} | 23 +-- .../memory_stores/cognee/__init__.py | 9 + .../cognee/memory_store.py | 76 ++------ .../cognee/tests/test_memory_store.py | 25 ++- integrations/cognee/tests/test_retriever.py | 22 +-- integrations/cognee/tests/test_writer.py | 26 ++- 21 files changed, 198 insertions(+), 444 deletions(-) delete mode 100644 integrations/cognee/.gitignore delete mode 100644 integrations/cognee/CHANGELOG.md rename integrations/cognee/src/haystack_integrations/components/connectors/{cognee => }/py.typed (100%) create mode 100644 integrations/cognee/src/haystack_integrations/components/retrievers/cognee/__init__.py rename integrations/cognee/src/haystack_integrations/components/{connectors/cognee/retriever.py => retrievers/cognee/memory_retriever.py} (74%) create mode 100644 integrations/cognee/src/haystack_integrations/components/writers/cognee/__init__.py rename integrations/cognee/src/haystack_integrations/components/{connectors/cognee/writer.py => writers/cognee/memory_writer.py} (79%) create mode 100644 integrations/cognee/src/haystack_integrations/memory_stores/cognee/__init__.py rename integrations/cognee/src/haystack_integrations/{components/connectors => memory_stores}/cognee/memory_store.py (59%) diff --git a/integrations/cognee/.gitignore b/integrations/cognee/.gitignore deleted file mode 100644 index a3d827e06b..0000000000 --- a/integrations/cognee/.gitignore +++ /dev/null @@ -1,163 +0,0 @@ -# Byte-compiled / optimized / DLL files -__pycache__/ -*.py[cod] -*$py.class - -# C extensions -*.so - -# Distribution / packaging -.Python -build/ -develop-eggs/ -dist/ -downloads/ -eggs/ -.eggs/ -lib/ -lib64/ -parts/ -sdist/ -var/ -wheels/ -share/python-wheels/ -*.egg-info/ -.installed.cfg -*.egg -MANIFEST - -# PyInstaller -# Usually these files are written by a python script from a template -# before PyInstaller builds the exe, so as to inject date/other infos into it. -*.manifest -*.spec - -# Installer logs -pip-log.txt -pip-delete-this-directory.txt - -# Unit test / coverage reports -htmlcov/ -.tox/ -.nox/ -.coverage -.coverage.* -.cache -nosetests.xml -coverage.xml -*.cover -*.py,cover -.hypothesis/ -.pytest_cache/ -cover/ - -# Translations -*.mo -*.pot - -# Django stuff: -*.log -local_settings.py -*.sqlite3 -*.sqlite3-journal - -# Flask stuff: -instance/ -.webassets-cache - -# Scrapy stuff: -.scrapy - -# Sphinx documentation -docs/_build/ - -# PyBuilder -.pybuilder/ -target/ - -# Jupyter Notebook -.ipynb_checkpoints - -# IPython -profile_default/ -ipython_config.py - -# pyenv -# For a library or package, you might want to ignore these files since the code is -# intended to run in multiple environments; otherwise, check them in: -# .python-version - -# pipenv -# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control. -# However, in case of collaboration, if having platform-specific dependencies or dependencies -# having no cross-platform support, pipenv may install dependencies that don't work, or not -# install all needed dependencies. -#Pipfile.lock - -# poetry -# Similar to Pipfile.lock, it is generally recommended to include poetry.lock in version control. -# This is especially recommended for binary packages to ensure reproducibility, and is more -# commonly ignored for libraries. -# https://python-poetry.org/docs/basic-usage/#commit-your-poetrylock-file-to-version-control -#poetry.lock - -# pdm -# Similar to Pipfile.lock, it is generally recommended to include pdm.lock in version control. -#pdm.lock -# pdm stores project-wide configurations in .pdm.toml, but it is recommended to not include it -# in version control. -# https://pdm.fming.dev/#use-with-ide -.pdm.toml - -# PEP 582; used by e.g. github.com/David-OConnor/pyflow and github.com/pdm-project/pdm -__pypackages__/ - -# Celery stuff -celerybeat-schedule -celerybeat.pid - -# SageMath parsed files -*.sage.py - -# Environments -.env -.venv -env/ -venv/ -ENV/ -env.bak/ -venv.bak/ - -# Spyder project settings -.spyderproject -.spyproject - -# Rope project settings -.ropeproject - -# mkdocs documentation -/site - -# mypy -.mypy_cache/ -.dmypy.json -dmypy.json - -# Pyre type checker -.pyre/ - -# pytype static type analyzer -.pytype/ - -# Cython debug symbols -cython_debug/ - -# PyCharm -# JetBrains specific template is maintained in a separate JetBrains.gitignore that can -# be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore -# and can be added to the global gitignore or merged into this file. For a more nuclear -# option (not recommended) you can uncomment the following to ignore the entire idea folder. -#.idea/ - -# VS Code -.vscode diff --git a/integrations/cognee/CHANGELOG.md b/integrations/cognee/CHANGELOG.md deleted file mode 100644 index f39c90b2b7..0000000000 --- a/integrations/cognee/CHANGELOG.md +++ /dev/null @@ -1,3 +0,0 @@ -# Changelog - - diff --git a/integrations/cognee/README.md b/integrations/cognee/README.md index eafc9e0bad..049f783ee4 100644 --- a/integrations/cognee/README.md +++ b/integrations/cognee/README.md @@ -1,125 +1,14 @@ # cognee-haystack -[![PyPI](https://img.shields.io/pypi/v/cognee-haystack.svg)](https://pypi.org/project/cognee-haystack/) -[![License](https://img.shields.io/badge/license-Apache%202.0-blue.svg)](LICENSE) +[![PyPI - Version](https://img.shields.io/pypi/v/cognee-haystack.svg)](https://pypi.org/project/cognee-haystack) +[![PyPI - Python Version](https://img.shields.io/pypi/pyversions/cognee-haystack.svg)](https://pypi.org/project/cognee-haystack) -A [Haystack](https://haystack.deepset.ai/) integration for [Cognee](https://github.com/topoteretes/cognee) — open-source memory for AI agents. +[Cognee](https://www.cognee.ai/) integration for [Haystack](https://haystack.deepset.ai/) — open-source memory for AI agents. -[Cognee](https://www.cognee.ai/) gives agents persistent, traceable memory by transforming raw data (e.g., unstructured documents, relational databases, etc.) into a knowledge engine that is both searchable by meaning and connected by relationships. Cognee uses an ECL (Extract, Cognify, Load) pipeline: vector search, knowledge graphs, with support for ontology-based entity grounding (e.g. OWL) and Pydantic-defined graph schemas. +- [Changelog](https://github.com/deepset-ai/haystack-core-integrations/blob/main/integrations/cognee/CHANGELOG.md) -Cognee serves developers and teams building agentic systems where agents need to retain context across sessions, learn from user feedback, and operate in multi-tenant, data-isolated environments. Cognee is available as an open-source Python library (Apache 2.0), a self-hosted/on-prem subscription tier, and a managed cloud service (Cognee Cloud at platform.cognee.ai). +--- +## Contributing -## Installation - -```bash -pip install cognee-haystack -``` - -To use the `CogneeMemoryStore` with Haystack's experimental Agent: - -```bash -pip install "cognee-haystack[memory]" -``` - -## Components - -### CogneeWriter - -Adds Haystack Documents to Cognee's knowledge engine via `cognee.add()`, with optional automatic `cognee.cognify()`. - -```python -from haystack import Document, Pipeline -from haystack_integrations.components.connectors.cognee import CogneeWriter - -pipeline = Pipeline() -pipeline.add_component("writer", CogneeWriter(dataset_name="my_data", auto_cognify=True)) - -docs = [Document(content="Cognee builds a structured memory from unstructured data.")] -pipeline.run({"writer": {"documents": docs}}) -``` - -### CogneeCognifier - -Standalone `cognee.cognify()` step — useful when you want to separate adding and processing. - -```python -from haystack_integrations.components.connectors.cognee import CogneeCognifier - -cognifier = CogneeCognifier() -cognifier.run() # {"cognified": True} -``` - -### CogneeRetriever - -Searches Cognee's memory and returns Haystack `Document` objects. - -```python -from haystack import Pipeline -from haystack_integrations.components.connectors.cognee import CogneeRetriever - -pipeline = Pipeline() -pipeline.add_component("retriever", CogneeRetriever(search_type="GRAPH_COMPLETION", top_k=5)) - -result = pipeline.run({"retriever": {"query": "What is Cognee?"}}) -for doc in result["retriever"]["documents"]: - print(doc.content) -``` - -**Supported search types:** `GRAPH_COMPLETION`, `CHUNKS`, `SUMMARIES`, `INSIGHTS`, and others from Cognee's `SearchType` enum. - -### CogneeMemoryStore - -Memory backend for Haystack's experimental Agent, backed by Cognee. - -```python -from haystack.dataclasses import ChatMessage -from haystack_integrations.components.connectors.cognee import CogneeMemoryStore - -store = CogneeMemoryStore(search_type="GRAPH_COMPLETION", top_k=5) - -# Store memories -store.add_memories(messages=[ - ChatMessage.from_user("The project deadline is next Friday.") -]) - -# Recall memories -results = store.search_memories(query="When is the deadline?") -``` - -## Configuration - -Cognee uses environment variables for its LLM and storage configuration: - -```bash -export LLM_API_KEY="sk-..." -``` - -See the [Cognee documentation](https://docs.cognee.ai/) for additional configuration options. - -## Examples - -See the [`examples/`](examples/) directory for runnable demos: - -- **`demo_pipeline.py`** — Index documents and search with CogneeWriter + CogneeRetriever -- **`demo_memory_agent.py`** — Use CogneeMemoryStore as a conversational memory backend - -## Development - -```bash -cd integrations/cognee - -# Format and lint -hatch run fmt -hatch run fmt-check - -# Type checking -hatch run test:types - -# Run tests -hatch run test:unit -``` - -## License - -Apache 2.0 — see [LICENSE](LICENSE) for details. +Refer to the general [Contribution Guidelines](https://github.com/deepset-ai/haystack-core-integrations/blob/main/CONTRIBUTING.md). diff --git a/integrations/cognee/examples/.artifacts/demo_memory_agent.html b/integrations/cognee/examples/.artifacts/demo_memory_agent.html index 67aeeef2e0..39992f1aec 100644 --- a/integrations/cognee/examples/.artifacts/demo_memory_agent.html +++ b/integrations/cognee/examples/.artifacts/demo_memory_agent.html @@ -171,8 +171,8 @@ (function(){ "use strict"; -var nodes = [{"name": "", "type": "DocumentChunk", "ontology_valid": false, "version": 1, "topological_rank": 0, "metadata": {"index_fields": ["text"]}, "belongs_to_set": null, "source_pipeline": "cognify_pipeline", "source_task": "extract_chunks_from_documents", "source_node_set": null, "source_user": "default_user@example.com", "text": "My name is Alice and I'm working on the Cognee-Haystack integration. The deadline is next Friday.", "chunk_size": 38, "chunk_index": 0, "cut_type": "sentence_end", "id": "c83fca99-61d3-55e2-b49b-6a8585b35f1b", "color": "#0DFF00"}, {"name": "alice", "type": "Entity", "ontology_valid": false, "version": 1, "topological_rank": 0, "metadata": {"index_fields": ["name"]}, "belongs_to_set": null, "source_pipeline": "cognify_pipeline", "source_task": "extract_graph_from_data", "source_node_set": null, "source_user": "default_user@example.com", "description": "User who stated they are working on the Cognee-Haystack integration", "id": "f7d8be13-2a72-5104-bd02-7a5964737a91", "color": "#6510F4"}, {"name": "person", "type": "EntityType", "ontology_valid": false, "version": 1, "topological_rank": 0, "metadata": {"index_fields": ["name"]}, "belongs_to_set": null, "source_pipeline": "cognify_pipeline", "source_task": "extract_graph_from_data", "source_node_set": null, "source_user": "default_user@example.com", "description": "person", "id": "d072ba0f-e1a9-58bf-9974-e1802adc8134", "color": "#A550FF"}, {"name": "cognee-haystack integration", "type": "Entity", "ontology_valid": false, "version": 1, "topological_rank": 0, "metadata": {"index_fields": ["name"]}, "belongs_to_set": null, "source_pipeline": "cognify_pipeline", "source_task": "extract_graph_from_data", "source_node_set": null, "source_user": "default_user@example.com", "description": "Integration project between Cognee and Haystack", "id": "37f4562e-675f-5309-9cf3-82fc46dfd7bf", "color": "#6510F4"}, {"name": "this project", "type": "Entity", "ontology_valid": false, "version": 1, "topological_rank": 0, "metadata": {"index_fields": ["name"]}, "belongs_to_set": null, "source_pipeline": "cognify_pipeline", "source_task": "extract_graph_from_data", "source_node_set": null, "source_user": "default_user@example.com", "description": "Project referred to in the message.", "id": "29c0d211-0d39-579f-bf45-c7a78394c9aa", "color": "#6510F4"}, {"name": "2026-03-20", "type": "Entity", "ontology_valid": false, "version": 1, "topological_rank": 0, "metadata": {"index_fields": ["name"]}, "belongs_to_set": null, "source_pipeline": "cognify_pipeline", "source_task": "extract_graph_from_data", "source_node_set": null, "source_user": "default_user@example.com", "description": "Deadline parsed as 2026-03-20", "id": "e995ad45-cb4a-5114-9b09-5c9c90335852", "color": "#6510F4"}, {"name": "date", "type": "EntityType", "ontology_valid": false, "version": 1, "topological_rank": 0, "metadata": {"index_fields": ["name"]}, "belongs_to_set": null, "source_pipeline": "cognify_pipeline", "source_task": "extract_graph_from_data", "source_node_set": null, "source_user": "default_user@example.com", "description": "date", "id": "d61d99ac-b291-5666-9748-3e80e1c8b56a", "color": "#A550FF"}, {"name": "text_e922928a64b61a3d616873a46f313bfa", "type": "TextDocument", "ontology_valid": false, "version": 1, "topological_rank": 0, "metadata": {"index_fields": ["name"]}, "belongs_to_set": null, "source_pipeline": "cognify_pipeline", "source_task": "classify_documents", "source_node_set": null, "source_user": "default_user@example.com", "raw_data_location": "file:///Users/handekafkas/Documents/local-code/haystack-core-integrations/.venv/lib/python3.12/site-packages/cognee/.data_storage/text_e922928a64b61a3d616873a46f313bfa.txt", "external_metadata": "{}", "mime_type": "text/plain", "id": "94f09a91-d044-5ac4-a7db-64babeead462", "color": "#DBD8D8"}, {"name": "", "type": "TextSummary", "ontology_valid": false, "version": 1, "topological_rank": 0, "metadata": {"index_fields": ["text"]}, "belongs_to_set": null, "source_pipeline": "cognify_pipeline", "source_task": "summarize_text", "source_node_set": null, "source_user": "default_user@example.com", "text": "Alice is handling the Cognee\u2013Haystack integration; the deliverable is due next Friday.", "id": "c79d366f-8a6e-52ca-942d-144582464470", "color": "#6510F4"}, {"name": "", "type": "DocumentChunk", "ontology_valid": false, "version": 1, "topological_rank": 0, "metadata": {"index_fields": ["text"]}, "belongs_to_set": null, "source_pipeline": "cognify_pipeline", "source_task": "extract_chunks_from_documents", "source_node_set": null, "source_user": "default_user@example.com", "text": "I'll remember that the deadline is next Friday and that GRAPH_COMPLETION is the preferred search type for this project.", "chunk_size": 42, "chunk_index": 0, "cut_type": "sentence_end", "id": "5642d955-1590-5d2d-91ba-c31918ce6b24", "color": "#0DFF00"}, {"name": "2026-03-20", "type": "Entity", "ontology_valid": false, "version": 1, "topological_rank": 0, "metadata": {"index_fields": ["name"]}, "belongs_to_set": null, "source_pipeline": "cognify_pipeline", "source_task": "extract_graph_from_data", "source_node_set": null, "source_user": "default_user@example.com", "description": "Deadline computed as next Friday relative to 2026-03-18.", "id": "8d3409aa-1c56-50b7-883b-834f419902b0", "color": "#6510F4"}, {"name": "graph_completion", "type": "Entity", "ontology_valid": false, "version": 1, "topological_rank": 0, "metadata": {"index_fields": ["name"]}, "belongs_to_set": null, "source_pipeline": "cognify_pipeline", "source_task": "extract_graph_from_data", "source_node_set": null, "source_user": "default_user@example.com", "description": "The search type chosen as default; retrieves relevant memories using graph traversal and vector search.", "id": "90ed6132-7732-572f-b798-d833662c4a18", "color": "#6510F4"}, {"name": "searchtype", "type": "EntityType", "ontology_valid": false, "version": 1, "topological_rank": 0, "metadata": {"index_fields": ["name"]}, "belongs_to_set": null, "source_pipeline": "cognify_pipeline", "source_task": "extract_graph_from_data", "source_node_set": null, "source_user": "default_user@example.com", "description": "searchtype", "id": "26ec8442-0b57-5727-a4b1-8208eee3a7c7", "color": "#A550FF"}, {"name": "text_88278ad547fc9e31ef4ffbbe793d8bb0", "type": "TextDocument", "ontology_valid": false, "version": 1, "topological_rank": 0, "metadata": {"index_fields": ["name"]}, "belongs_to_set": null, "source_pipeline": "cognify_pipeline", "source_task": "classify_documents", "source_node_set": null, "source_user": "default_user@example.com", "raw_data_location": "file:///Users/handekafkas/Documents/local-code/haystack-core-integrations/.venv/lib/python3.12/site-packages/cognee/.data_storage/text_88278ad547fc9e31ef4ffbbe793d8bb0.txt", "external_metadata": "{}", "mime_type": "text/plain", "id": "c678854f-b883-5723-bd8e-e0eb930dc214", "color": "#DBD8D8"}, {"name": "", "type": "DocumentChunk", "ontology_valid": false, "version": 1, "topological_rank": 0, "metadata": {"index_fields": ["text"]}, "belongs_to_set": null, "source_pipeline": "cognify_pipeline", "source_task": "extract_chunks_from_documents", "source_node_set": null, "source_user": "default_user@example.com", "text": "We decided to use GRAPH_COMPLETION as the default search type because it retrieves the most relevant memories by graph traversal and vector search", "chunk_size": 53, "chunk_index": 0, "cut_type": "sentence_cut", "id": "62339b20-3811-539a-aec2-897640252895", "color": "#0DFF00"}, {"name": "we", "type": "Entity", "ontology_valid": false, "version": 1, "topological_rank": 0, "metadata": {"index_fields": ["name"]}, "belongs_to_set": null, "source_pipeline": "cognify_pipeline", "source_task": "extract_graph_from_data", "source_node_set": null, "source_user": "default_user@example.com", "description": "The decision-making group that selected the search type.", "id": "230442fc-409d-588e-9c41-7b0a04309608", "color": "#6510F4"}, {"name": "group", "type": "EntityType", "ontology_valid": false, "version": 1, "topological_rank": 0, "metadata": {"index_fields": ["name"]}, "belongs_to_set": null, "source_pipeline": "cognify_pipeline", "source_task": "extract_graph_from_data", "source_node_set": null, "source_user": "default_user@example.com", "description": "group", "id": "902952aa-01e0-50f7-b732-bbb74b318b53", "color": "#A550FF"}, {"name": "default search type", "type": "Entity", "ontology_valid": false, "version": 1, "topological_rank": 0, "metadata": {"index_fields": ["name"]}, "belongs_to_set": null, "source_pipeline": "cognify_pipeline", "source_task": "extract_graph_from_data", "source_node_set": null, "source_user": "default_user@example.com", "description": "Designation indicating the selected default configuration for search.", "id": "8cff9083-49b8-5471-9922-00b224258949", "color": "#6510F4"}, {"name": "concept", "type": "EntityType", "ontology_valid": false, "version": 1, "topological_rank": 0, "metadata": {"index_fields": ["name"]}, "belongs_to_set": null, "source_pipeline": "cognify_pipeline", "source_task": "extract_graph_from_data", "source_node_set": null, "source_user": "default_user@example.com", "description": "concept", "id": "dd9713b7-dc20-5101-aad0-1c4216811147", "color": "#A550FF"}, {"name": "most relevant memories", "type": "Entity", "ontology_valid": false, "version": 1, "topological_rank": 0, "metadata": {"index_fields": ["name"]}, "belongs_to_set": null, "source_pipeline": "cognify_pipeline", "source_task": "extract_graph_from_data", "source_node_set": null, "source_user": "default_user@example.com", "description": "Memories or items considered most relevant by the search process.", "id": "9aaff686-abbb-54c1-b70c-8f6de27b9444", "color": "#6510F4"}, {"name": "data", "type": "EntityType", "ontology_valid": false, "version": 1, "topological_rank": 0, "metadata": {"index_fields": ["name"]}, "belongs_to_set": null, "source_pipeline": "cognify_pipeline", "source_task": "extract_graph_from_data", "source_node_set": null, "source_user": "default_user@example.com", "description": "data", "id": "4ed5a0c7-2efb-52d1-9734-06a8ba225c94", "color": "#A550FF"}, {"name": "graph traversal", "type": "Entity", "ontology_valid": false, "version": 1, "topological_rank": 0, "metadata": {"index_fields": ["name"]}, "belongs_to_set": null, "source_pipeline": "cognify_pipeline", "source_task": "extract_graph_from_data", "source_node_set": null, "source_user": "default_user@example.com", "description": "Graph traversal technique used to retrieve relevant memories.", "id": "3d0c908a-35fd-5370-953e-8952648f0900", "color": "#6510F4"}, {"name": "method", "type": "EntityType", "ontology_valid": false, "version": 1, "topological_rank": 0, "metadata": {"index_fields": ["name"]}, "belongs_to_set": null, "source_pipeline": "cognify_pipeline", "source_task": "extract_graph_from_data", "source_node_set": null, "source_user": "default_user@example.com", "description": "method", "id": "00f29df1-cee8-544f-87d6-60761845f00b", "color": "#A550FF"}, {"name": "vector search", "type": "Entity", "ontology_valid": false, "version": 1, "topological_rank": 0, "metadata": {"index_fields": ["name"]}, "belongs_to_set": null, "source_pipeline": "cognify_pipeline", "source_task": "extract_graph_from_data", "source_node_set": null, "source_user": "default_user@example.com", "description": "Vector search technique used to retrieve relevant memories.", "id": "b3c5ff56-7122-56d1-b27b-de4ebe59395b", "color": "#6510F4"}, {"name": "text_eb05286518d418a42800eef8456af922", "type": "TextDocument", "ontology_valid": false, "version": 1, "topological_rank": 0, "metadata": {"index_fields": ["name"]}, "belongs_to_set": null, "source_pipeline": "cognify_pipeline", "source_task": "classify_documents", "source_node_set": null, "source_user": "default_user@example.com", "raw_data_location": "file:///Users/handekafkas/Documents/local-code/haystack-core-integrations/.venv/lib/python3.12/site-packages/cognee/.data_storage/text_eb05286518d418a42800eef8456af922.txt", "external_metadata": "{}", "mime_type": "text/plain", "id": "7fac9ee0-d493-5fc0-b679-1b6946dfbcde", "color": "#DBD8D8"}, {"name": "", "type": "TextSummary", "ontology_valid": false, "version": 1, "topological_rank": 0, "metadata": {"index_fields": ["text"]}, "belongs_to_set": null, "source_pipeline": "cognify_pipeline", "source_task": "summarize_text", "source_node_set": null, "source_user": "default_user@example.com", "text": "Deadline set for next Friday; preferred search method: GRAPH_COMPLETION.", "id": "74327ced-5eb8-5f08-b661-4730548acfcc", "color": "#6510F4"}, {"name": "", "type": "TextSummary", "ontology_valid": false, "version": 1, "topological_rank": 0, "metadata": {"index_fields": ["text"]}, "belongs_to_set": null, "source_pipeline": "cognify_pipeline", "source_task": "summarize_text", "source_node_set": null, "source_user": "default_user@example.com", "text": "GRAPH_COMPLETION chosen as default search type", "id": "88ada940-fd05-52cc-94c0-8d99caf9ca9a", "color": "#6510F4"}]; -var links = [{"source": "c83fca99-61d3-55e2-b49b-6a8585b35f1b", "target": "f7d8be13-2a72-5104-bd02-7a5964737a91", "relation": "contains", "weight": null, "all_weights": {}, "relationship_type": "contains", "edge_info": {"source_node_id": "c83fca99-61d3-55e2-b49b-6a8585b35f1b", "target_node_id": "f7d8be13-2a72-5104-bd02-7a5964737a91", "relationship_name": "contains", "updated_at": "2026-03-18 12:22:36", "relationship_type": "contains", "edge_text": "relationship_name: contains; entity_name: alice; entity_description: User who stated they are working on the Cognee-Haystack integration"}}, {"source": "c83fca99-61d3-55e2-b49b-6a8585b35f1b", "target": "37f4562e-675f-5309-9cf3-82fc46dfd7bf", "relation": "contains", "weight": null, "all_weights": {}, "relationship_type": "contains", "edge_info": {"source_node_id": "c83fca99-61d3-55e2-b49b-6a8585b35f1b", "target_node_id": "37f4562e-675f-5309-9cf3-82fc46dfd7bf", "relationship_name": "contains", "updated_at": "2026-03-18 12:22:36", "relationship_type": "contains", "edge_text": "relationship_name: contains; entity_name: cognee-haystack integration; entity_description: Integration project between Cognee and Haystack"}}, {"source": "c83fca99-61d3-55e2-b49b-6a8585b35f1b", "target": "e995ad45-cb4a-5114-9b09-5c9c90335852", "relation": "contains", "weight": null, "all_weights": {}, "relationship_type": "contains", "edge_info": {"source_node_id": "c83fca99-61d3-55e2-b49b-6a8585b35f1b", "target_node_id": "e995ad45-cb4a-5114-9b09-5c9c90335852", "relationship_name": "contains", "updated_at": "2026-03-18 12:22:36", "relationship_type": "contains", "edge_text": "relationship_name: contains; entity_name: 2026-03-20; entity_description: Deadline parsed as 2026-03-20"}}, {"source": "c83fca99-61d3-55e2-b49b-6a8585b35f1b", "target": "94f09a91-d044-5ac4-a7db-64babeead462", "relation": "is_part_of", "weight": null, "all_weights": {}, "relationship_type": null, "edge_info": {"source_node_id": "c83fca99-61d3-55e2-b49b-6a8585b35f1b", "target_node_id": "94f09a91-d044-5ac4-a7db-64babeead462", "relationship_name": "is_part_of", "updated_at": "2026-03-18 12:22:36"}}, {"source": "f7d8be13-2a72-5104-bd02-7a5964737a91", "target": "d072ba0f-e1a9-58bf-9974-e1802adc8134", "relation": "is_a", "weight": null, "all_weights": {}, "relationship_type": null, "edge_info": {"source_node_id": "f7d8be13-2a72-5104-bd02-7a5964737a91", "target_node_id": "d072ba0f-e1a9-58bf-9974-e1802adc8134", "relationship_name": "is_a", "updated_at": "2026-03-18 12:22:36"}}, {"source": "f7d8be13-2a72-5104-bd02-7a5964737a91", "target": "37f4562e-675f-5309-9cf3-82fc46dfd7bf", "relation": "working_on", "weight": null, "all_weights": {}, "relationship_type": null, "edge_info": {"relationship_name": "working_on", "source_node_id": "f7d8be13-2a72-5104-bd02-7a5964737a91", "target_node_id": "37f4562e-675f-5309-9cf3-82fc46dfd7bf", "ontology_valid": false}}, {"source": "37f4562e-675f-5309-9cf3-82fc46dfd7bf", "target": "29c0d211-0d39-579f-bf45-c7a78394c9aa", "relation": "is_a", "weight": null, "all_weights": {}, "relationship_type": null, "edge_info": {"source_node_id": "37f4562e-675f-5309-9cf3-82fc46dfd7bf", "target_node_id": "29c0d211-0d39-579f-bf45-c7a78394c9aa", "relationship_name": "is_a", "updated_at": "2026-03-18 12:22:36"}}, {"source": "37f4562e-675f-5309-9cf3-82fc46dfd7bf", "target": "e995ad45-cb4a-5114-9b09-5c9c90335852", "relation": "deadline_on", "weight": null, "all_weights": {}, "relationship_type": null, "edge_info": {"relationship_name": "deadline_on", "source_node_id": "37f4562e-675f-5309-9cf3-82fc46dfd7bf", "target_node_id": "e995ad45-cb4a-5114-9b09-5c9c90335852", "ontology_valid": false}}, {"source": "29c0d211-0d39-579f-bf45-c7a78394c9aa", "target": "29c0d211-0d39-579f-bf45-c7a78394c9aa", "relation": "is_a", "weight": null, "all_weights": {}, "relationship_type": null, "edge_info": {"source_node_id": "29c0d211-0d39-579f-bf45-c7a78394c9aa", "target_node_id": "29c0d211-0d39-579f-bf45-c7a78394c9aa", "relationship_name": "is_a", "updated_at": "2026-03-18 12:22:46"}}, {"source": "29c0d211-0d39-579f-bf45-c7a78394c9aa", "target": "8d3409aa-1c56-50b7-883b-834f419902b0", "relation": "has_deadline", "weight": null, "all_weights": {}, "relationship_type": null, "edge_info": {"relationship_name": "has_deadline", "source_node_id": "29c0d211-0d39-579f-bf45-c7a78394c9aa", "target_node_id": "8d3409aa-1c56-50b7-883b-834f419902b0", "ontology_valid": false}}, {"source": "29c0d211-0d39-579f-bf45-c7a78394c9aa", "target": "90ed6132-7732-572f-b798-d833662c4a18", "relation": "preferred_search_type", "weight": null, "all_weights": {}, "relationship_type": null, "edge_info": {"relationship_name": "preferred_search_type", "source_node_id": "29c0d211-0d39-579f-bf45-c7a78394c9aa", "target_node_id": "90ed6132-7732-572f-b798-d833662c4a18", "ontology_valid": false}}, {"source": "e995ad45-cb4a-5114-9b09-5c9c90335852", "target": "d61d99ac-b291-5666-9748-3e80e1c8b56a", "relation": "is_a", "weight": null, "all_weights": {}, "relationship_type": null, "edge_info": {"source_node_id": "e995ad45-cb4a-5114-9b09-5c9c90335852", "target_node_id": "d61d99ac-b291-5666-9748-3e80e1c8b56a", "relationship_name": "is_a", "updated_at": "2026-03-18 12:22:36"}}, {"source": "c79d366f-8a6e-52ca-942d-144582464470", "target": "c83fca99-61d3-55e2-b49b-6a8585b35f1b", "relation": "made_from", "weight": null, "all_weights": {}, "relationship_type": null, "edge_info": {"source_node_id": "c79d366f-8a6e-52ca-942d-144582464470", "target_node_id": "c83fca99-61d3-55e2-b49b-6a8585b35f1b", "relationship_name": "made_from", "updated_at": "2026-03-18 12:22:36"}}, {"source": "5642d955-1590-5d2d-91ba-c31918ce6b24", "target": "29c0d211-0d39-579f-bf45-c7a78394c9aa", "relation": "contains", "weight": null, "all_weights": {}, "relationship_type": "contains", "edge_info": {"source_node_id": "5642d955-1590-5d2d-91ba-c31918ce6b24", "target_node_id": "29c0d211-0d39-579f-bf45-c7a78394c9aa", "relationship_name": "contains", "updated_at": "2026-03-18 12:22:46", "relationship_type": "contains", "edge_text": "relationship_name: contains; entity_name: this project; entity_description: Project referred to in the message."}}, {"source": "5642d955-1590-5d2d-91ba-c31918ce6b24", "target": "8d3409aa-1c56-50b7-883b-834f419902b0", "relation": "contains", "weight": null, "all_weights": {}, "relationship_type": "contains", "edge_info": {"source_node_id": "5642d955-1590-5d2d-91ba-c31918ce6b24", "target_node_id": "8d3409aa-1c56-50b7-883b-834f419902b0", "relationship_name": "contains", "updated_at": "2026-03-18 12:22:46", "relationship_type": "contains", "edge_text": "relationship_name: contains; entity_name: 2026-03-20; entity_description: Deadline computed as next Friday relative to 2026-03-18."}}, {"source": "5642d955-1590-5d2d-91ba-c31918ce6b24", "target": "90ed6132-7732-572f-b798-d833662c4a18", "relation": "contains", "weight": null, "all_weights": {}, "relationship_type": "contains", "edge_info": {"source_node_id": "5642d955-1590-5d2d-91ba-c31918ce6b24", "target_node_id": "90ed6132-7732-572f-b798-d833662c4a18", "relationship_name": "contains", "updated_at": "2026-03-18 12:22:46", "relationship_type": "contains", "edge_text": "relationship_name: contains; entity_name: graph_completion; entity_description: Preferred search type specified for the project."}}, {"source": "5642d955-1590-5d2d-91ba-c31918ce6b24", "target": "c678854f-b883-5723-bd8e-e0eb930dc214", "relation": "is_part_of", "weight": null, "all_weights": {}, "relationship_type": null, "edge_info": {"source_node_id": "5642d955-1590-5d2d-91ba-c31918ce6b24", "target_node_id": "c678854f-b883-5723-bd8e-e0eb930dc214", "relationship_name": "is_part_of", "updated_at": "2026-03-18 12:22:46"}}, {"source": "8d3409aa-1c56-50b7-883b-834f419902b0", "target": "d61d99ac-b291-5666-9748-3e80e1c8b56a", "relation": "is_a", "weight": null, "all_weights": {}, "relationship_type": null, "edge_info": {"source_node_id": "8d3409aa-1c56-50b7-883b-834f419902b0", "target_node_id": "d61d99ac-b291-5666-9748-3e80e1c8b56a", "relationship_name": "is_a", "updated_at": "2026-03-18 12:22:46"}}, {"source": "90ed6132-7732-572f-b798-d833662c4a18", "target": "26ec8442-0b57-5727-a4b1-8208eee3a7c7", "relation": "is_a", "weight": null, "all_weights": {}, "relationship_type": null, "edge_info": {"source_node_id": "90ed6132-7732-572f-b798-d833662c4a18", "target_node_id": "26ec8442-0b57-5727-a4b1-8208eee3a7c7", "relationship_name": "is_a", "updated_at": "2026-03-18 12:22:47"}}, {"source": "90ed6132-7732-572f-b798-d833662c4a18", "target": "8cff9083-49b8-5471-9922-00b224258949", "relation": "assigned_as_default", "weight": null, "all_weights": {}, "relationship_type": null, "edge_info": {"relationship_name": "assigned_as_default", "source_node_id": "90ed6132-7732-572f-b798-d833662c4a18", "target_node_id": "8cff9083-49b8-5471-9922-00b224258949", "ontology_valid": false}}, {"source": "90ed6132-7732-572f-b798-d833662c4a18", "target": "9aaff686-abbb-54c1-b70c-8f6de27b9444", "relation": "retrieves_most_relevant", "weight": null, "all_weights": {}, "relationship_type": null, "edge_info": {"relationship_name": "retrieves_most_relevant", "source_node_id": "90ed6132-7732-572f-b798-d833662c4a18", "target_node_id": "9aaff686-abbb-54c1-b70c-8f6de27b9444", "ontology_valid": false}}, {"source": "90ed6132-7732-572f-b798-d833662c4a18", "target": "3d0c908a-35fd-5370-953e-8952648f0900", "relation": "uses_method", "weight": null, "all_weights": {}, "relationship_type": null, "edge_info": {"relationship_name": "uses_method", "source_node_id": "90ed6132-7732-572f-b798-d833662c4a18", "target_node_id": "3d0c908a-35fd-5370-953e-8952648f0900", "ontology_valid": false}}, {"source": "90ed6132-7732-572f-b798-d833662c4a18", "target": "b3c5ff56-7122-56d1-b27b-de4ebe59395b", "relation": "uses_method", "weight": null, "all_weights": {}, "relationship_type": null, "edge_info": {"relationship_name": "uses_method", "source_node_id": "90ed6132-7732-572f-b798-d833662c4a18", "target_node_id": "b3c5ff56-7122-56d1-b27b-de4ebe59395b", "ontology_valid": false}}, {"source": "62339b20-3811-539a-aec2-897640252895", "target": "230442fc-409d-588e-9c41-7b0a04309608", "relation": "contains", "weight": null, "all_weights": {}, "relationship_type": "contains", "edge_info": {"source_node_id": "62339b20-3811-539a-aec2-897640252895", "target_node_id": "230442fc-409d-588e-9c41-7b0a04309608", "relationship_name": "contains", "updated_at": "2026-03-18 12:22:47", "relationship_type": "contains", "edge_text": "relationship_name: contains; entity_name: we; entity_description: The decision-making group that selected the search type."}}, {"source": "62339b20-3811-539a-aec2-897640252895", "target": "90ed6132-7732-572f-b798-d833662c4a18", "relation": "contains", "weight": null, "all_weights": {}, "relationship_type": "contains", "edge_info": {"source_node_id": "62339b20-3811-539a-aec2-897640252895", "target_node_id": "90ed6132-7732-572f-b798-d833662c4a18", "relationship_name": "contains", "updated_at": "2026-03-18 12:22:47", "relationship_type": "contains", "edge_text": "relationship_name: contains; entity_name: graph_completion; entity_description: The search type chosen as default; retrieves relevant memories using graph traversal and vector search."}}, {"source": "62339b20-3811-539a-aec2-897640252895", "target": "8cff9083-49b8-5471-9922-00b224258949", "relation": "contains", "weight": null, "all_weights": {}, "relationship_type": "contains", "edge_info": {"source_node_id": "62339b20-3811-539a-aec2-897640252895", "target_node_id": "8cff9083-49b8-5471-9922-00b224258949", "relationship_name": "contains", "updated_at": "2026-03-18 12:22:47", "relationship_type": "contains", "edge_text": "relationship_name: contains; entity_name: default search type; entity_description: Designation indicating the selected default configuration for search."}}, {"source": "62339b20-3811-539a-aec2-897640252895", "target": "9aaff686-abbb-54c1-b70c-8f6de27b9444", "relation": "contains", "weight": null, "all_weights": {}, "relationship_type": "contains", "edge_info": {"source_node_id": "62339b20-3811-539a-aec2-897640252895", "target_node_id": "9aaff686-abbb-54c1-b70c-8f6de27b9444", "relationship_name": "contains", "updated_at": "2026-03-18 12:22:47", "relationship_type": "contains", "edge_text": "relationship_name: contains; entity_name: most relevant memories; entity_description: Memories or items considered most relevant by the search process."}}, {"source": "62339b20-3811-539a-aec2-897640252895", "target": "3d0c908a-35fd-5370-953e-8952648f0900", "relation": "contains", "weight": null, "all_weights": {}, "relationship_type": "contains", "edge_info": {"source_node_id": "62339b20-3811-539a-aec2-897640252895", "target_node_id": "3d0c908a-35fd-5370-953e-8952648f0900", "relationship_name": "contains", "updated_at": "2026-03-18 12:22:47", "relationship_type": "contains", "edge_text": "relationship_name: contains; entity_name: graph traversal; entity_description: Graph traversal technique used to retrieve relevant memories."}}, {"source": "62339b20-3811-539a-aec2-897640252895", "target": "b3c5ff56-7122-56d1-b27b-de4ebe59395b", "relation": "contains", "weight": null, "all_weights": {}, "relationship_type": "contains", "edge_info": {"source_node_id": "62339b20-3811-539a-aec2-897640252895", "target_node_id": "b3c5ff56-7122-56d1-b27b-de4ebe59395b", "relationship_name": "contains", "updated_at": "2026-03-18 12:22:47", "relationship_type": "contains", "edge_text": "relationship_name: contains; entity_name: vector search; entity_description: Vector search technique used to retrieve relevant memories."}}, {"source": "62339b20-3811-539a-aec2-897640252895", "target": "7fac9ee0-d493-5fc0-b679-1b6946dfbcde", "relation": "is_part_of", "weight": null, "all_weights": {}, "relationship_type": null, "edge_info": {"source_node_id": "62339b20-3811-539a-aec2-897640252895", "target_node_id": "7fac9ee0-d493-5fc0-b679-1b6946dfbcde", "relationship_name": "is_part_of", "updated_at": "2026-03-18 12:22:47"}}, {"source": "230442fc-409d-588e-9c41-7b0a04309608", "target": "902952aa-01e0-50f7-b732-bbb74b318b53", "relation": "is_a", "weight": null, "all_weights": {}, "relationship_type": null, "edge_info": {"source_node_id": "230442fc-409d-588e-9c41-7b0a04309608", "target_node_id": "902952aa-01e0-50f7-b732-bbb74b318b53", "relationship_name": "is_a", "updated_at": "2026-03-18 12:22:47"}}, {"source": "230442fc-409d-588e-9c41-7b0a04309608", "target": "90ed6132-7732-572f-b798-d833662c4a18", "relation": "decided_to_use", "weight": null, "all_weights": {}, "relationship_type": null, "edge_info": {"relationship_name": "decided_to_use", "source_node_id": "230442fc-409d-588e-9c41-7b0a04309608", "target_node_id": "90ed6132-7732-572f-b798-d833662c4a18", "ontology_valid": false}}, {"source": "8cff9083-49b8-5471-9922-00b224258949", "target": "dd9713b7-dc20-5101-aad0-1c4216811147", "relation": "is_a", "weight": null, "all_weights": {}, "relationship_type": null, "edge_info": {"source_node_id": "8cff9083-49b8-5471-9922-00b224258949", "target_node_id": "dd9713b7-dc20-5101-aad0-1c4216811147", "relationship_name": "is_a", "updated_at": "2026-03-18 12:22:47"}}, {"source": "9aaff686-abbb-54c1-b70c-8f6de27b9444", "target": "4ed5a0c7-2efb-52d1-9734-06a8ba225c94", "relation": "is_a", "weight": null, "all_weights": {}, "relationship_type": null, "edge_info": {"source_node_id": "9aaff686-abbb-54c1-b70c-8f6de27b9444", "target_node_id": "4ed5a0c7-2efb-52d1-9734-06a8ba225c94", "relationship_name": "is_a", "updated_at": "2026-03-18 12:22:47"}}, {"source": "3d0c908a-35fd-5370-953e-8952648f0900", "target": "00f29df1-cee8-544f-87d6-60761845f00b", "relation": "is_a", "weight": null, "all_weights": {}, "relationship_type": null, "edge_info": {"source_node_id": "3d0c908a-35fd-5370-953e-8952648f0900", "target_node_id": "00f29df1-cee8-544f-87d6-60761845f00b", "relationship_name": "is_a", "updated_at": "2026-03-18 12:22:47"}}, {"source": "b3c5ff56-7122-56d1-b27b-de4ebe59395b", "target": "00f29df1-cee8-544f-87d6-60761845f00b", "relation": "is_a", "weight": null, "all_weights": {}, "relationship_type": null, "edge_info": {"source_node_id": "b3c5ff56-7122-56d1-b27b-de4ebe59395b", "target_node_id": "00f29df1-cee8-544f-87d6-60761845f00b", "relationship_name": "is_a", "updated_at": "2026-03-18 12:22:47"}}, {"source": "74327ced-5eb8-5f08-b661-4730548acfcc", "target": "5642d955-1590-5d2d-91ba-c31918ce6b24", "relation": "made_from", "weight": null, "all_weights": {}, "relationship_type": null, "edge_info": {"source_node_id": "74327ced-5eb8-5f08-b661-4730548acfcc", "target_node_id": "5642d955-1590-5d2d-91ba-c31918ce6b24", "relationship_name": "made_from", "updated_at": "2026-03-18 12:22:46"}}, {"source": "88ada940-fd05-52cc-94c0-8d99caf9ca9a", "target": "62339b20-3811-539a-aec2-897640252895", "relation": "made_from", "weight": null, "all_weights": {}, "relationship_type": null, "edge_info": {"source_node_id": "88ada940-fd05-52cc-94c0-8d99caf9ca9a", "target_node_id": "62339b20-3811-539a-aec2-897640252895", "relationship_name": "made_from", "updated_at": "2026-03-18 12:22:47"}}]; +var nodes = [{"name": "", "type": "DocumentChunk", "ontology_valid": false, "version": 1, "topological_rank": 0, "metadata": {"index_fields": ["text"]}, "belongs_to_set": null, "source_pipeline": "cognify_pipeline", "source_task": "extract_chunks_from_documents", "source_node_set": null, "source_user": "default_user@example.com", "text": "My name is Alice and I'm working on the Cognee-Haystack integration. The deadline is next Friday.", "chunk_size": 38, "chunk_index": 0, "cut_type": "sentence_end", "id": "f000c910-dcd8-5b37-8d79-efa87848fa9e", "color": "#0DFF00"}, {"name": "alice", "type": "Entity", "ontology_valid": false, "version": 1, "topological_rank": 0, "metadata": {"index_fields": ["name"]}, "belongs_to_set": null, "source_pipeline": "cognify_pipeline", "source_task": "extract_graph_from_data", "source_node_set": null, "source_user": "default_user@example.com", "description": "Person who stated they are working on the integration", "id": "f7d8be13-2a72-5104-bd02-7a5964737a91", "color": "#6510F4"}, {"name": "person", "type": "EntityType", "ontology_valid": false, "version": 1, "topological_rank": 0, "metadata": {"index_fields": ["name"]}, "belongs_to_set": null, "source_pipeline": "cognify_pipeline", "source_task": "extract_graph_from_data", "source_node_set": null, "source_user": "default_user@example.com", "description": "person", "id": "d072ba0f-e1a9-58bf-9974-e1802adc8134", "color": "#A550FF"}, {"name": "cognee-haystack integration", "type": "Entity", "ontology_valid": false, "version": 1, "topological_rank": 0, "metadata": {"index_fields": ["name"]}, "belongs_to_set": null, "source_pipeline": "cognify_pipeline", "source_task": "extract_graph_from_data", "source_node_set": null, "source_user": "default_user@example.com", "description": "Integration project between Cognee and Haystack mentioned by Alice", "id": "37f4562e-675f-5309-9cf3-82fc46dfd7bf", "color": "#6510F4"}, {"name": "project", "type": "EntityType", "ontology_valid": false, "version": 1, "topological_rank": 0, "metadata": {"index_fields": ["name"]}, "belongs_to_set": null, "source_pipeline": "cognify_pipeline", "source_task": "extract_graph_from_data", "source_node_set": null, "source_user": "default_user@example.com", "description": "project", "id": "29c0d211-0d39-579f-bf45-c7a78394c9aa", "color": "#A550FF"}, {"name": "2026-03-27", "type": "Entity", "ontology_valid": false, "version": 1, "topological_rank": 0, "metadata": {"index_fields": ["name"]}, "belongs_to_set": null, "source_pipeline": "cognify_pipeline", "source_task": "extract_graph_from_data", "source_node_set": null, "source_user": "default_user@example.com", "description": "Deadline 'next Friday' resolved relative to 2026-03-20", "id": "aae7dfac-596e-5895-be75-8c7eef4ea6e4", "color": "#6510F4"}, {"name": "date", "type": "EntityType", "ontology_valid": false, "version": 1, "topological_rank": 0, "metadata": {"index_fields": ["name"]}, "belongs_to_set": null, "source_pipeline": "cognify_pipeline", "source_task": "extract_graph_from_data", "source_node_set": null, "source_user": "default_user@example.com", "description": "date", "id": "d61d99ac-b291-5666-9748-3e80e1c8b56a", "color": "#A550FF"}, {"name": "text_e922928a64b61a3d616873a46f313bfa", "type": "TextDocument", "ontology_valid": false, "version": 1, "topological_rank": 0, "metadata": {"index_fields": ["name"]}, "belongs_to_set": null, "source_pipeline": "cognify_pipeline", "source_task": "classify_documents", "source_node_set": null, "source_user": "default_user@example.com", "raw_data_location": "file:///Users/handekafkas/Documents/local-code/haystack-core-integrations/integrations/cognee/.venv/lib/python3.13/site-packages/cognee/.data_storage/text_e922928a64b61a3d616873a46f313bfa.txt", "external_metadata": "{}", "mime_type": "text/plain", "id": "240fa574-4bd5-5daf-b2d3-63c970827398", "color": "#DBD8D8"}, {"name": "", "type": "DocumentChunk", "ontology_valid": false, "version": 1, "topological_rank": 0, "metadata": {"index_fields": ["text"]}, "belongs_to_set": null, "source_pipeline": "cognify_pipeline", "source_task": "extract_chunks_from_documents", "source_node_set": null, "source_user": "default_user@example.com", "text": "We decided to use GRAPH_COMPLETION as the default search type because it retrieves the most relevant memories by graph traversal and vector search", "chunk_size": 53, "chunk_index": 0, "cut_type": "sentence_cut", "id": "c868d3a2-41b8-544c-94ec-533be08724a2", "color": "#0DFF00"}, {"name": "graph_completion", "type": "Entity", "ontology_valid": false, "version": 1, "topological_rank": 0, "metadata": {"index_fields": ["name"]}, "belongs_to_set": null, "source_pipeline": "cognify_pipeline", "source_task": "extract_graph_from_data", "source_node_set": null, "source_user": "default_user@example.com", "description": "preferred search type for the project", "id": "90ed6132-7732-572f-b798-d833662c4a18", "color": "#6510F4"}, {"name": "concept", "type": "EntityType", "ontology_valid": false, "version": 1, "topological_rank": 0, "metadata": {"index_fields": ["name"]}, "belongs_to_set": null, "source_pipeline": "cognify_pipeline", "source_task": "extract_graph_from_data", "source_node_set": null, "source_user": "default_user@example.com", "description": "concept", "id": "dd9713b7-dc20-5101-aad0-1c4216811147", "color": "#A550FF"}, {"name": "default search type", "type": "Entity", "ontology_valid": false, "version": 1, "topological_rank": 0, "metadata": {"index_fields": ["name"]}, "belongs_to_set": null, "source_pipeline": "cognify_pipeline", "source_task": "extract_graph_from_data", "source_node_set": null, "source_user": "default_user@example.com", "description": "Role indicating the search type selected as the default.", "id": "8cff9083-49b8-5471-9922-00b224258949", "color": "#6510F4"}, {"name": "relevant memories", "type": "Entity", "ontology_valid": false, "version": 1, "topological_rank": 0, "metadata": {"index_fields": ["name"]}, "belongs_to_set": null, "source_pipeline": "cognify_pipeline", "source_task": "extract_graph_from_data", "source_node_set": null, "source_user": "default_user@example.com", "description": "Memories that are most pertinent to a query.", "id": "ab1f07c0-fd77-5ad6-a164-6721213d5a29", "color": "#6510F4"}, {"name": "graph traversal", "type": "Entity", "ontology_valid": false, "version": 1, "topological_rank": 0, "metadata": {"index_fields": ["name"]}, "belongs_to_set": null, "source_pipeline": "cognify_pipeline", "source_task": "extract_graph_from_data", "source_node_set": null, "source_user": "default_user@example.com", "description": "Technique of traversing graph connections to find related memories.", "id": "3d0c908a-35fd-5370-953e-8952648f0900", "color": "#6510F4"}, {"name": "vector search", "type": "Entity", "ontology_valid": false, "version": 1, "topological_rank": 0, "metadata": {"index_fields": ["name"]}, "belongs_to_set": null, "source_pipeline": "cognify_pipeline", "source_task": "extract_graph_from_data", "source_node_set": null, "source_user": "default_user@example.com", "description": "Embedding-based similarity search method used to find related items.", "id": "b3c5ff56-7122-56d1-b27b-de4ebe59395b", "color": "#6510F4"}, {"name": "text_eb05286518d418a42800eef8456af922", "type": "TextDocument", "ontology_valid": false, "version": 1, "topological_rank": 0, "metadata": {"index_fields": ["name"]}, "belongs_to_set": null, "source_pipeline": "cognify_pipeline", "source_task": "classify_documents", "source_node_set": null, "source_user": "default_user@example.com", "raw_data_location": "file:///Users/handekafkas/Documents/local-code/haystack-core-integrations/integrations/cognee/.venv/lib/python3.13/site-packages/cognee/.data_storage/text_eb05286518d418a42800eef8456af922.txt", "external_metadata": "{}", "mime_type": "text/plain", "id": "fcd8a6b3-d97f-5d1a-8ccc-cb63a3344f71", "color": "#DBD8D8"}, {"name": "", "type": "DocumentChunk", "ontology_valid": false, "version": 1, "topological_rank": 0, "metadata": {"index_fields": ["text"]}, "belongs_to_set": null, "source_pipeline": "cognify_pipeline", "source_task": "extract_chunks_from_documents", "source_node_set": null, "source_user": "default_user@example.com", "text": "I'll remember that the deadline is next Friday and that GRAPH_COMPLETION is the preferred search type for this project.", "chunk_size": 42, "chunk_index": 0, "cut_type": "sentence_end", "id": "2df00f77-1358-55a9-aab3-5b62b961bdf3", "color": "#0DFF00"}, {"name": "this project", "type": "Entity", "ontology_valid": false, "version": 1, "topological_rank": 0, "metadata": {"index_fields": ["name"]}, "belongs_to_set": null, "source_pipeline": "cognify_pipeline", "source_task": "extract_graph_from_data", "source_node_set": null, "source_user": "default_user@example.com", "description": "Referenced project for which preferences and deadlines apply", "id": "9591ae32-57d8-591f-bb04-3077530bea6a", "color": "#6510F4"}, {"name": "next friday", "type": "Entity", "ontology_valid": false, "version": 1, "topological_rank": 0, "metadata": {"index_fields": ["name"]}, "belongs_to_set": null, "source_pipeline": "cognify_pipeline", "source_task": "extract_graph_from_data", "source_node_set": null, "source_user": "default_user@example.com", "description": "date: 2026-03-27", "id": "e995ad45-cb4a-5114-9b09-5c9c90335852", "color": "#6510F4"}, {"name": "text_88278ad547fc9e31ef4ffbbe793d8bb0", "type": "TextDocument", "ontology_valid": false, "version": 1, "topological_rank": 0, "metadata": {"index_fields": ["name"]}, "belongs_to_set": null, "source_pipeline": "cognify_pipeline", "source_task": "classify_documents", "source_node_set": null, "source_user": "default_user@example.com", "raw_data_location": "file:///Users/handekafkas/Documents/local-code/haystack-core-integrations/integrations/cognee/.venv/lib/python3.13/site-packages/cognee/.data_storage/text_88278ad547fc9e31ef4ffbbe793d8bb0.txt", "external_metadata": "{}", "mime_type": "text/plain", "id": "c730c8d1-a271-515b-8c78-f12e194d6b25", "color": "#DBD8D8"}, {"name": "", "type": "TextSummary", "ontology_valid": false, "version": 1, "topological_rank": 0, "metadata": {"index_fields": ["text"]}, "belongs_to_set": null, "source_pipeline": "cognify_pipeline", "source_task": "summarize_text", "source_node_set": null, "source_user": "default_user@example.com", "text": "Alice is working on the Cognee\u2013Haystack integration, with a deadline next Friday.", "id": "81efbad3-0d84-572b-9d08-f3a7d742a65a", "color": "#6510F4"}, {"name": "", "type": "TextSummary", "ontology_valid": false, "version": 1, "topological_rank": 0, "metadata": {"index_fields": ["text"]}, "belongs_to_set": null, "source_pipeline": "cognify_pipeline", "source_task": "summarize_text", "source_node_set": null, "source_user": "default_user@example.com", "text": "Adopted GRAPH_COMPLETION as the default search for retrieving the most relevant memories.", "id": "c10ec5f1-9b16-57d8-8a25-572f091fb28c", "color": "#6510F4"}, {"name": "", "type": "TextSummary", "ontology_valid": false, "version": 1, "topological_rank": 0, "metadata": {"index_fields": ["text"]}, "belongs_to_set": null, "source_pipeline": "cognify_pipeline", "source_task": "summarize_text", "source_node_set": null, "source_user": "default_user@example.com", "text": "Due date: next Friday; preferred search method: GRAPH_COMPLETION.", "id": "6275c695-1310-53a5-be99-b0b45e01197a", "color": "#6510F4"}]; +var links = [{"source": "f000c910-dcd8-5b37-8d79-efa87848fa9e", "target": "f7d8be13-2a72-5104-bd02-7a5964737a91", "relation": "contains", "weight": null, "all_weights": {}, "relationship_type": "contains", "edge_info": {"source_node_id": "f000c910-dcd8-5b37-8d79-efa87848fa9e", "target_node_id": "f7d8be13-2a72-5104-bd02-7a5964737a91", "relationship_name": "contains", "updated_at": "2026-03-20 23:29:32", "relationship_type": "contains", "edge_text": "relationship_name: contains; entity_name: alice; entity_description: Person who stated they are working on the integration"}}, {"source": "f000c910-dcd8-5b37-8d79-efa87848fa9e", "target": "37f4562e-675f-5309-9cf3-82fc46dfd7bf", "relation": "contains", "weight": null, "all_weights": {}, "relationship_type": "contains", "edge_info": {"source_node_id": "f000c910-dcd8-5b37-8d79-efa87848fa9e", "target_node_id": "37f4562e-675f-5309-9cf3-82fc46dfd7bf", "relationship_name": "contains", "updated_at": "2026-03-20 23:29:32", "relationship_type": "contains", "edge_text": "relationship_name: contains; entity_name: cognee-haystack integration; entity_description: Integration project between Cognee and Haystack mentioned by Alice"}}, {"source": "f000c910-dcd8-5b37-8d79-efa87848fa9e", "target": "aae7dfac-596e-5895-be75-8c7eef4ea6e4", "relation": "contains", "weight": null, "all_weights": {}, "relationship_type": "contains", "edge_info": {"source_node_id": "f000c910-dcd8-5b37-8d79-efa87848fa9e", "target_node_id": "aae7dfac-596e-5895-be75-8c7eef4ea6e4", "relationship_name": "contains", "updated_at": "2026-03-20 23:29:32", "relationship_type": "contains", "edge_text": "relationship_name: contains; entity_name: 2026-03-27; entity_description: Deadline 'next Friday' resolved relative to 2026-03-20"}}, {"source": "f000c910-dcd8-5b37-8d79-efa87848fa9e", "target": "240fa574-4bd5-5daf-b2d3-63c970827398", "relation": "is_part_of", "weight": null, "all_weights": {}, "relationship_type": null, "edge_info": {"source_node_id": "f000c910-dcd8-5b37-8d79-efa87848fa9e", "target_node_id": "240fa574-4bd5-5daf-b2d3-63c970827398", "relationship_name": "is_part_of", "updated_at": "2026-03-20 23:29:32"}}, {"source": "f7d8be13-2a72-5104-bd02-7a5964737a91", "target": "d072ba0f-e1a9-58bf-9974-e1802adc8134", "relation": "is_a", "weight": null, "all_weights": {}, "relationship_type": null, "edge_info": {"source_node_id": "f7d8be13-2a72-5104-bd02-7a5964737a91", "target_node_id": "d072ba0f-e1a9-58bf-9974-e1802adc8134", "relationship_name": "is_a", "updated_at": "2026-03-20 23:29:32"}}, {"source": "f7d8be13-2a72-5104-bd02-7a5964737a91", "target": "37f4562e-675f-5309-9cf3-82fc46dfd7bf", "relation": "working_on", "weight": null, "all_weights": {}, "relationship_type": null, "edge_info": {"relationship_name": "working_on", "source_node_id": "f7d8be13-2a72-5104-bd02-7a5964737a91", "target_node_id": "37f4562e-675f-5309-9cf3-82fc46dfd7bf", "ontology_valid": false}}, {"source": "37f4562e-675f-5309-9cf3-82fc46dfd7bf", "target": "29c0d211-0d39-579f-bf45-c7a78394c9aa", "relation": "is_a", "weight": null, "all_weights": {}, "relationship_type": null, "edge_info": {"source_node_id": "37f4562e-675f-5309-9cf3-82fc46dfd7bf", "target_node_id": "29c0d211-0d39-579f-bf45-c7a78394c9aa", "relationship_name": "is_a", "updated_at": "2026-03-20 23:29:32"}}, {"source": "37f4562e-675f-5309-9cf3-82fc46dfd7bf", "target": "aae7dfac-596e-5895-be75-8c7eef4ea6e4", "relation": "has_deadline", "weight": null, "all_weights": {}, "relationship_type": null, "edge_info": {"relationship_name": "has_deadline", "source_node_id": "37f4562e-675f-5309-9cf3-82fc46dfd7bf", "target_node_id": "aae7dfac-596e-5895-be75-8c7eef4ea6e4", "ontology_valid": false}}, {"source": "aae7dfac-596e-5895-be75-8c7eef4ea6e4", "target": "d61d99ac-b291-5666-9748-3e80e1c8b56a", "relation": "is_a", "weight": null, "all_weights": {}, "relationship_type": null, "edge_info": {"source_node_id": "aae7dfac-596e-5895-be75-8c7eef4ea6e4", "target_node_id": "d61d99ac-b291-5666-9748-3e80e1c8b56a", "relationship_name": "is_a", "updated_at": "2026-03-20 23:29:32"}}, {"source": "c868d3a2-41b8-544c-94ec-533be08724a2", "target": "90ed6132-7732-572f-b798-d833662c4a18", "relation": "contains", "weight": null, "all_weights": {}, "relationship_type": "contains", "edge_info": {"source_node_id": "c868d3a2-41b8-544c-94ec-533be08724a2", "target_node_id": "90ed6132-7732-572f-b798-d833662c4a18", "relationship_name": "contains", "updated_at": "2026-03-20 23:29:34", "relationship_type": "contains", "edge_text": "relationship_name: contains; entity_name: graph_completion; entity_description: Search type that combines graph traversal and vector search to retrieve memories."}}, {"source": "c868d3a2-41b8-544c-94ec-533be08724a2", "target": "8cff9083-49b8-5471-9922-00b224258949", "relation": "contains", "weight": null, "all_weights": {}, "relationship_type": "contains", "edge_info": {"source_node_id": "c868d3a2-41b8-544c-94ec-533be08724a2", "target_node_id": "8cff9083-49b8-5471-9922-00b224258949", "relationship_name": "contains", "updated_at": "2026-03-20 23:29:34", "relationship_type": "contains", "edge_text": "relationship_name: contains; entity_name: default search type; entity_description: Role indicating the search type selected as the default."}}, {"source": "c868d3a2-41b8-544c-94ec-533be08724a2", "target": "ab1f07c0-fd77-5ad6-a164-6721213d5a29", "relation": "contains", "weight": null, "all_weights": {}, "relationship_type": "contains", "edge_info": {"source_node_id": "c868d3a2-41b8-544c-94ec-533be08724a2", "target_node_id": "ab1f07c0-fd77-5ad6-a164-6721213d5a29", "relationship_name": "contains", "updated_at": "2026-03-20 23:29:34", "relationship_type": "contains", "edge_text": "relationship_name: contains; entity_name: relevant memories; entity_description: Memories that are most pertinent to a query."}}, {"source": "c868d3a2-41b8-544c-94ec-533be08724a2", "target": "3d0c908a-35fd-5370-953e-8952648f0900", "relation": "contains", "weight": null, "all_weights": {}, "relationship_type": "contains", "edge_info": {"source_node_id": "c868d3a2-41b8-544c-94ec-533be08724a2", "target_node_id": "3d0c908a-35fd-5370-953e-8952648f0900", "relationship_name": "contains", "updated_at": "2026-03-20 23:29:34", "relationship_type": "contains", "edge_text": "relationship_name: contains; entity_name: graph traversal; entity_description: Technique of traversing graph connections to find related memories."}}, {"source": "c868d3a2-41b8-544c-94ec-533be08724a2", "target": "b3c5ff56-7122-56d1-b27b-de4ebe59395b", "relation": "contains", "weight": null, "all_weights": {}, "relationship_type": "contains", "edge_info": {"source_node_id": "c868d3a2-41b8-544c-94ec-533be08724a2", "target_node_id": "b3c5ff56-7122-56d1-b27b-de4ebe59395b", "relationship_name": "contains", "updated_at": "2026-03-20 23:29:34", "relationship_type": "contains", "edge_text": "relationship_name: contains; entity_name: vector search; entity_description: Embedding-based similarity search method used to find related items."}}, {"source": "c868d3a2-41b8-544c-94ec-533be08724a2", "target": "fcd8a6b3-d97f-5d1a-8ccc-cb63a3344f71", "relation": "is_part_of", "weight": null, "all_weights": {}, "relationship_type": null, "edge_info": {"source_node_id": "c868d3a2-41b8-544c-94ec-533be08724a2", "target_node_id": "fcd8a6b3-d97f-5d1a-8ccc-cb63a3344f71", "relationship_name": "is_part_of", "updated_at": "2026-03-20 23:29:34"}}, {"source": "90ed6132-7732-572f-b798-d833662c4a18", "target": "dd9713b7-dc20-5101-aad0-1c4216811147", "relation": "is_a", "weight": null, "all_weights": {}, "relationship_type": null, "edge_info": {"source_node_id": "90ed6132-7732-572f-b798-d833662c4a18", "target_node_id": "dd9713b7-dc20-5101-aad0-1c4216811147", "relationship_name": "is_a", "updated_at": "2026-03-20 23:29:37"}}, {"source": "90ed6132-7732-572f-b798-d833662c4a18", "target": "8cff9083-49b8-5471-9922-00b224258949", "relation": "is_default_search_type", "weight": null, "all_weights": {}, "relationship_type": null, "edge_info": {"relationship_name": "is_default_search_type", "source_node_id": "90ed6132-7732-572f-b798-d833662c4a18", "target_node_id": "8cff9083-49b8-5471-9922-00b224258949", "ontology_valid": false}}, {"source": "90ed6132-7732-572f-b798-d833662c4a18", "target": "ab1f07c0-fd77-5ad6-a164-6721213d5a29", "relation": "retrieves_most_relevant_memories", "weight": null, "all_weights": {}, "relationship_type": null, "edge_info": {"relationship_name": "retrieves_most_relevant_memories", "source_node_id": "90ed6132-7732-572f-b798-d833662c4a18", "target_node_id": "ab1f07c0-fd77-5ad6-a164-6721213d5a29", "ontology_valid": false}}, {"source": "90ed6132-7732-572f-b798-d833662c4a18", "target": "3d0c908a-35fd-5370-953e-8952648f0900", "relation": "uses_graph_traversal", "weight": null, "all_weights": {}, "relationship_type": null, "edge_info": {"relationship_name": "uses_graph_traversal", "source_node_id": "90ed6132-7732-572f-b798-d833662c4a18", "target_node_id": "3d0c908a-35fd-5370-953e-8952648f0900", "ontology_valid": false}}, {"source": "90ed6132-7732-572f-b798-d833662c4a18", "target": "b3c5ff56-7122-56d1-b27b-de4ebe59395b", "relation": "uses_vector_search", "weight": null, "all_weights": {}, "relationship_type": null, "edge_info": {"relationship_name": "uses_vector_search", "source_node_id": "90ed6132-7732-572f-b798-d833662c4a18", "target_node_id": "b3c5ff56-7122-56d1-b27b-de4ebe59395b", "ontology_valid": false}}, {"source": "8cff9083-49b8-5471-9922-00b224258949", "target": "dd9713b7-dc20-5101-aad0-1c4216811147", "relation": "is_a", "weight": null, "all_weights": {}, "relationship_type": null, "edge_info": {"source_node_id": "8cff9083-49b8-5471-9922-00b224258949", "target_node_id": "dd9713b7-dc20-5101-aad0-1c4216811147", "relationship_name": "is_a", "updated_at": "2026-03-20 23:29:34"}}, {"source": "ab1f07c0-fd77-5ad6-a164-6721213d5a29", "target": "dd9713b7-dc20-5101-aad0-1c4216811147", "relation": "is_a", "weight": null, "all_weights": {}, "relationship_type": null, "edge_info": {"source_node_id": "ab1f07c0-fd77-5ad6-a164-6721213d5a29", "target_node_id": "dd9713b7-dc20-5101-aad0-1c4216811147", "relationship_name": "is_a", "updated_at": "2026-03-20 23:29:34"}}, {"source": "3d0c908a-35fd-5370-953e-8952648f0900", "target": "dd9713b7-dc20-5101-aad0-1c4216811147", "relation": "is_a", "weight": null, "all_weights": {}, "relationship_type": null, "edge_info": {"source_node_id": "3d0c908a-35fd-5370-953e-8952648f0900", "target_node_id": "dd9713b7-dc20-5101-aad0-1c4216811147", "relationship_name": "is_a", "updated_at": "2026-03-20 23:29:34"}}, {"source": "3d0c908a-35fd-5370-953e-8952648f0900", "target": "ab1f07c0-fd77-5ad6-a164-6721213d5a29", "relation": "contributes_to_retrieval_of", "weight": null, "all_weights": {}, "relationship_type": null, "edge_info": {"relationship_name": "contributes_to_retrieval_of", "source_node_id": "3d0c908a-35fd-5370-953e-8952648f0900", "target_node_id": "ab1f07c0-fd77-5ad6-a164-6721213d5a29", "ontology_valid": false}}, {"source": "b3c5ff56-7122-56d1-b27b-de4ebe59395b", "target": "dd9713b7-dc20-5101-aad0-1c4216811147", "relation": "is_a", "weight": null, "all_weights": {}, "relationship_type": null, "edge_info": {"source_node_id": "b3c5ff56-7122-56d1-b27b-de4ebe59395b", "target_node_id": "dd9713b7-dc20-5101-aad0-1c4216811147", "relationship_name": "is_a", "updated_at": "2026-03-20 23:29:34"}}, {"source": "b3c5ff56-7122-56d1-b27b-de4ebe59395b", "target": "ab1f07c0-fd77-5ad6-a164-6721213d5a29", "relation": "contributes_to_retrieval_of", "weight": null, "all_weights": {}, "relationship_type": null, "edge_info": {"relationship_name": "contributes_to_retrieval_of", "source_node_id": "b3c5ff56-7122-56d1-b27b-de4ebe59395b", "target_node_id": "ab1f07c0-fd77-5ad6-a164-6721213d5a29", "ontology_valid": false}}, {"source": "2df00f77-1358-55a9-aab3-5b62b961bdf3", "target": "9591ae32-57d8-591f-bb04-3077530bea6a", "relation": "contains", "weight": null, "all_weights": {}, "relationship_type": "contains", "edge_info": {"source_node_id": "2df00f77-1358-55a9-aab3-5b62b961bdf3", "target_node_id": "9591ae32-57d8-591f-bb04-3077530bea6a", "relationship_name": "contains", "updated_at": "2026-03-20 23:29:37", "relationship_type": "contains", "edge_text": "relationship_name: contains; entity_name: this project; entity_description: Referenced project for which preferences and deadlines apply"}}, {"source": "2df00f77-1358-55a9-aab3-5b62b961bdf3", "target": "e995ad45-cb4a-5114-9b09-5c9c90335852", "relation": "contains", "weight": null, "all_weights": {}, "relationship_type": "contains", "edge_info": {"source_node_id": "2df00f77-1358-55a9-aab3-5b62b961bdf3", "target_node_id": "e995ad45-cb4a-5114-9b09-5c9c90335852", "relationship_name": "contains", "updated_at": "2026-03-20 23:29:37", "relationship_type": "contains", "edge_text": "relationship_name: contains; entity_name: next friday; entity_description: date: 2026-03-27"}}, {"source": "2df00f77-1358-55a9-aab3-5b62b961bdf3", "target": "90ed6132-7732-572f-b798-d833662c4a18", "relation": "contains", "weight": null, "all_weights": {}, "relationship_type": "contains", "edge_info": {"source_node_id": "2df00f77-1358-55a9-aab3-5b62b961bdf3", "target_node_id": "90ed6132-7732-572f-b798-d833662c4a18", "relationship_name": "contains", "updated_at": "2026-03-20 23:29:37", "relationship_type": "contains", "edge_text": "relationship_name: contains; entity_name: graph_completion; entity_description: preferred search type for the project"}}, {"source": "2df00f77-1358-55a9-aab3-5b62b961bdf3", "target": "c730c8d1-a271-515b-8c78-f12e194d6b25", "relation": "is_part_of", "weight": null, "all_weights": {}, "relationship_type": null, "edge_info": {"source_node_id": "2df00f77-1358-55a9-aab3-5b62b961bdf3", "target_node_id": "c730c8d1-a271-515b-8c78-f12e194d6b25", "relationship_name": "is_part_of", "updated_at": "2026-03-20 23:29:37"}}, {"source": "9591ae32-57d8-591f-bb04-3077530bea6a", "target": "29c0d211-0d39-579f-bf45-c7a78394c9aa", "relation": "is_a", "weight": null, "all_weights": {}, "relationship_type": null, "edge_info": {"source_node_id": "9591ae32-57d8-591f-bb04-3077530bea6a", "target_node_id": "29c0d211-0d39-579f-bf45-c7a78394c9aa", "relationship_name": "is_a", "updated_at": "2026-03-20 23:29:37"}}, {"source": "9591ae32-57d8-591f-bb04-3077530bea6a", "target": "e995ad45-cb4a-5114-9b09-5c9c90335852", "relation": "has_deadline", "weight": null, "all_weights": {}, "relationship_type": null, "edge_info": {"relationship_name": "has_deadline", "source_node_id": "9591ae32-57d8-591f-bb04-3077530bea6a", "target_node_id": "e995ad45-cb4a-5114-9b09-5c9c90335852", "ontology_valid": false}}, {"source": "9591ae32-57d8-591f-bb04-3077530bea6a", "target": "90ed6132-7732-572f-b798-d833662c4a18", "relation": "preferred_search_type", "weight": null, "all_weights": {}, "relationship_type": null, "edge_info": {"relationship_name": "preferred_search_type", "source_node_id": "9591ae32-57d8-591f-bb04-3077530bea6a", "target_node_id": "90ed6132-7732-572f-b798-d833662c4a18", "ontology_valid": false}}, {"source": "e995ad45-cb4a-5114-9b09-5c9c90335852", "target": "d61d99ac-b291-5666-9748-3e80e1c8b56a", "relation": "is_a", "weight": null, "all_weights": {}, "relationship_type": null, "edge_info": {"source_node_id": "e995ad45-cb4a-5114-9b09-5c9c90335852", "target_node_id": "d61d99ac-b291-5666-9748-3e80e1c8b56a", "relationship_name": "is_a", "updated_at": "2026-03-20 23:29:37"}}, {"source": "81efbad3-0d84-572b-9d08-f3a7d742a65a", "target": "f000c910-dcd8-5b37-8d79-efa87848fa9e", "relation": "made_from", "weight": null, "all_weights": {}, "relationship_type": null, "edge_info": {"source_node_id": "81efbad3-0d84-572b-9d08-f3a7d742a65a", "target_node_id": "f000c910-dcd8-5b37-8d79-efa87848fa9e", "relationship_name": "made_from", "updated_at": "2026-03-20 23:29:32"}}, {"source": "c10ec5f1-9b16-57d8-8a25-572f091fb28c", "target": "c868d3a2-41b8-544c-94ec-533be08724a2", "relation": "made_from", "weight": null, "all_weights": {}, "relationship_type": null, "edge_info": {"source_node_id": "c10ec5f1-9b16-57d8-8a25-572f091fb28c", "target_node_id": "c868d3a2-41b8-544c-94ec-533be08724a2", "relationship_name": "made_from", "updated_at": "2026-03-20 23:29:34"}}, {"source": "6275c695-1310-53a5-be99-b0b45e01197a", "target": "2df00f77-1358-55a9-aab3-5b62b961bdf3", "relation": "made_from", "weight": null, "all_weights": {}, "relationship_type": null, "edge_info": {"source_node_id": "6275c695-1310-53a5-be99-b0b45e01197a", "target_node_id": "2df00f77-1358-55a9-aab3-5b62b961bdf3", "relationship_name": "made_from", "updated_at": "2026-03-20 23:29:37"}}]; var taskColors = {"classify_documents": "#db5656", "extract_chunks_from_documents": "#56db7d", "extract_graph_from_data": "#a456db", "summarize_text": "#dbca56"}; var pipelineColors = {"cognify_pipeline": "#db5656"}; var nodesetColors = {}; diff --git a/integrations/cognee/examples/.artifacts/demo_pipeline.html b/integrations/cognee/examples/.artifacts/demo_pipeline.html index 059439d05b..b87f7f42d7 100644 --- a/integrations/cognee/examples/.artifacts/demo_pipeline.html +++ b/integrations/cognee/examples/.artifacts/demo_pipeline.html @@ -171,8 +171,8 @@ (function(){ "use strict"; -var nodes = [{"name": "", "type": "DocumentChunk", "ontology_valid": false, "version": 1, "topological_rank": 0, "metadata": {"index_fields": ["text"]}, "belongs_to_set": null, "source_pipeline": "cognify_pipeline", "source_task": "extract_chunks_from_documents", "source_node_set": null, "source_user": "default_user@example.com", "text": "Haystack is an open-source LLM framework by deepset for building production-ready RAG pipelines, agents, and search systems. It uses a component-based architecture where each step (retrieval, generation, etc.) is a composable building block.", "chunk_size": 84, "chunk_index": 0, "cut_type": "sentence_end", "id": "c2a2a0b9-6fdf-5035-aedf-d1f4fa3d0fa8", "color": "#0DFF00"}, {"name": "text_62f45b114bbc9894497442c0588694a9", "type": "TextDocument", "ontology_valid": false, "version": 1, "topological_rank": 0, "metadata": {"index_fields": ["name"]}, "belongs_to_set": null, "source_pipeline": "cognify_pipeline", "source_task": "classify_documents", "source_node_set": null, "source_user": "default_user@example.com", "raw_data_location": "file:///Users/handekafkas/Documents/local-code/haystack-core-integrations/.venv/lib/python3.12/site-packages/cognee/.data_storage/text_62f45b114bbc9894497442c0588694a9.txt", "external_metadata": "{}", "mime_type": "text/plain", "id": "d1a887a7-2ced-54ec-8359-b5b619b259a3", "color": "#DBD8D8"}, {"name": "haystack", "type": "Entity", "ontology_valid": false, "version": 1, "topological_rank": 0, "metadata": {"index_fields": ["name"]}, "belongs_to_set": null, "source_pipeline": "cognify_pipeline", "source_task": "extract_graph_from_data", "source_node_set": null, "source_user": "default_user@example.com", "description": "Open-source LLM framework by deepset for building production-ready RAG pipelines, agents, and search systems.", "id": "2bdd3deb-07d8-5413-a56d-1643e3ceb48b", "color": "#6510F4"}, {"name": "software", "type": "EntityType", "ontology_valid": false, "version": 1, "topological_rank": 0, "metadata": {"index_fields": ["name"]}, "belongs_to_set": null, "source_pipeline": "cognify_pipeline", "source_task": "extract_graph_from_data", "source_node_set": null, "source_user": "default_user@example.com", "description": "software", "id": "2d66edc2-1e14-55ab-8304-680b514a597a", "color": "#A550FF"}, {"name": "deepset", "type": "Entity", "ontology_valid": false, "version": 1, "topological_rank": 0, "metadata": {"index_fields": ["name"]}, "belongs_to_set": null, "source_pipeline": "cognify_pipeline", "source_task": "extract_graph_from_data", "source_node_set": null, "source_user": "default_user@example.com", "description": "Organization that developed Haystack.", "id": "126df7ec-d0db-53ea-bc88-1bafd84c8646", "color": "#6510F4"}, {"name": "organization", "type": "EntityType", "ontology_valid": false, "version": 1, "topological_rank": 0, "metadata": {"index_fields": ["name"]}, "belongs_to_set": null, "source_pipeline": "cognify_pipeline", "source_task": "extract_graph_from_data", "source_node_set": null, "source_user": "default_user@example.com", "description": "organization", "id": "d3d7b6b4-9b0d-52e8-9e09-a9e9cf4b5a4d", "color": "#A550FF"}, {"name": "rag pipelines", "type": "Entity", "ontology_valid": false, "version": 1, "topological_rank": 0, "metadata": {"index_fields": ["name"]}, "belongs_to_set": null, "source_pipeline": "cognify_pipeline", "source_task": "extract_graph_from_data", "source_node_set": null, "source_user": "default_user@example.com", "description": "Retrieval-Augmented Generation (RAG) pipelines.", "id": "7594343c-5532-5896-b0aa-be5c1a74bd92", "color": "#6510F4"}, {"name": "concept", "type": "EntityType", "ontology_valid": false, "version": 1, "topological_rank": 0, "metadata": {"index_fields": ["name"]}, "belongs_to_set": null, "source_pipeline": "cognify_pipeline", "source_task": "extract_graph_from_data", "source_node_set": null, "source_user": "default_user@example.com", "description": "concept", "id": "dd9713b7-dc20-5101-aad0-1c4216811147", "color": "#A550FF"}, {"name": "agents", "type": "Entity", "ontology_valid": false, "version": 1, "topological_rank": 0, "metadata": {"index_fields": ["name"]}, "belongs_to_set": null, "source_pipeline": "cognify_pipeline", "source_task": "extract_graph_from_data", "source_node_set": null, "source_user": "default_user@example.com", "description": "Agents built using Haystack.", "id": "ba1f1dac-e2fb-5464-914d-ff54b9b19787", "color": "#6510F4"}, {"name": "search systems", "type": "Entity", "ontology_valid": false, "version": 1, "topological_rank": 0, "metadata": {"index_fields": ["name"]}, "belongs_to_set": null, "source_pipeline": "cognify_pipeline", "source_task": "extract_graph_from_data", "source_node_set": null, "source_user": "default_user@example.com", "description": "Search systems built using Haystack.", "id": "a1a666e4-2070-59fd-95f7-c4c6178e89ba", "color": "#6510F4"}, {"name": "component-based architecture", "type": "Entity", "ontology_valid": false, "version": 1, "topological_rank": 0, "metadata": {"index_fields": ["name"]}, "belongs_to_set": null, "source_pipeline": "cognify_pipeline", "source_task": "extract_graph_from_data", "source_node_set": null, "source_user": "default_user@example.com", "description": "Architecture where each step (retrieval, generation, etc.) is a composable building block.", "id": "865e92ac-5a4f-5ba9-910f-d28ce255c4a2", "color": "#6510F4"}, {"name": "retrieval", "type": "Entity", "ontology_valid": false, "version": 1, "topological_rank": 0, "metadata": {"index_fields": ["name"]}, "belongs_to_set": null, "source_pipeline": "cognify_pipeline", "source_task": "extract_graph_from_data", "source_node_set": null, "source_user": "default_user@example.com", "description": "A retrieval step in Haystack pipelines.", "id": "f010bf52-6eb5-511f-bbed-cd5237545edd", "color": "#6510F4"}, {"name": "generation", "type": "Entity", "ontology_valid": false, "version": 1, "topological_rank": 0, "metadata": {"index_fields": ["name"]}, "belongs_to_set": null, "source_pipeline": "cognify_pipeline", "source_task": "extract_graph_from_data", "source_node_set": null, "source_user": "default_user@example.com", "description": "A generation step in Haystack pipelines.", "id": "dba0457b-9aff-5eb6-8ccd-19f7c9ae4dfa", "color": "#6510F4"}, {"name": "composable building block", "type": "Entity", "ontology_valid": false, "version": 1, "topological_rank": 0, "metadata": {"index_fields": ["name"]}, "belongs_to_set": null, "source_pipeline": "cognify_pipeline", "source_task": "extract_graph_from_data", "source_node_set": null, "source_user": "default_user@example.com", "description": "Modular component that can be composed into pipeline steps.", "id": "59cf88c0-cb09-5f96-9252-5f5810981bcc", "color": "#6510F4"}, {"name": "", "type": "TextSummary", "ontology_valid": false, "version": 1, "topological_rank": 0, "metadata": {"index_fields": ["text"]}, "belongs_to_set": null, "source_pipeline": "cognify_pipeline", "source_task": "summarize_text", "source_node_set": null, "source_user": "default_user@example.com", "text": "Haystack is an open-source LLM framework from deepset for building production-ready RAG pipelines, agents, and search solutions.", "id": "2bcd4862-2b66-5cfd-bdc0-92605a426502", "color": "#6510F4"}, {"name": "", "type": "DocumentChunk", "ontology_valid": false, "version": 1, "topological_rank": 0, "metadata": {"index_fields": ["text"]}, "belongs_to_set": null, "source_pipeline": "cognify_pipeline", "source_task": "extract_chunks_from_documents", "source_node_set": null, "source_user": "default_user@example.com", "text": "The engineering team at Acme Corp consists of Alice (backend lead), Bob (ML engineer), and Carol (infrastructure). They are building a next-generation search platform powered by knowledge graphs and LLMs.", "chunk_size": 72, "chunk_index": 0, "cut_type": "sentence_end", "id": "8d133f76-c22c-5758-bdc6-73bf5da4576a", "color": "#0DFF00"}, {"name": "text_fe5096366b6f10a6766dc51cbac9058c", "type": "TextDocument", "ontology_valid": false, "version": 1, "topological_rank": 0, "metadata": {"index_fields": ["name"]}, "belongs_to_set": null, "source_pipeline": "cognify_pipeline", "source_task": "classify_documents", "source_node_set": null, "source_user": "default_user@example.com", "raw_data_location": "file:///Users/handekafkas/Documents/local-code/haystack-core-integrations/.venv/lib/python3.12/site-packages/cognee/.data_storage/text_fe5096366b6f10a6766dc51cbac9058c.txt", "external_metadata": "{}", "mime_type": "text/plain", "id": "9e533e24-badc-5824-90d7-fac3a10dbe20", "color": "#DBD8D8"}, {"name": "acme corp", "type": "Entity", "ontology_valid": false, "version": 1, "topological_rank": 0, "metadata": {"index_fields": ["name"]}, "belongs_to_set": null, "source_pipeline": "cognify_pipeline", "source_task": "extract_graph_from_data", "source_node_set": null, "source_user": "default_user@example.com", "description": "organization: Acme Corp", "id": "7f5a651e-56c1-574f-aa54-cd0a0b7dbc38", "color": "#6510F4"}, {"name": "engineering team at acme corp", "type": "Entity", "ontology_valid": false, "version": 1, "topological_rank": 0, "metadata": {"index_fields": ["name"]}, "belongs_to_set": null, "source_pipeline": "cognify_pipeline", "source_task": "extract_graph_from_data", "source_node_set": null, "source_user": "default_user@example.com", "description": "team: engineering team at Acme Corp", "id": "7fa8891b-a426-5d42-b011-6851ef945793", "color": "#6510F4"}, {"name": "team", "type": "EntityType", "ontology_valid": false, "version": 1, "topological_rank": 0, "metadata": {"index_fields": ["name"]}, "belongs_to_set": null, "source_pipeline": "cognify_pipeline", "source_task": "extract_graph_from_data", "source_node_set": null, "source_user": "default_user@example.com", "description": "team", "id": "e308d782-2a18-5ace-b0e8-236c7c3b4db4", "color": "#A550FF"}, {"name": "alice", "type": "Entity", "ontology_valid": false, "version": 1, "topological_rank": 0, "metadata": {"index_fields": ["name"]}, "belongs_to_set": null, "source_pipeline": "cognify_pipeline", "source_task": "extract_graph_from_data", "source_node_set": null, "source_user": "default_user@example.com", "description": "profession: backend lead", "id": "f7d8be13-2a72-5104-bd02-7a5964737a91", "color": "#6510F4"}, {"name": "person", "type": "EntityType", "ontology_valid": false, "version": 1, "topological_rank": 0, "metadata": {"index_fields": ["name"]}, "belongs_to_set": null, "source_pipeline": "cognify_pipeline", "source_task": "extract_graph_from_data", "source_node_set": null, "source_user": "default_user@example.com", "description": "person", "id": "d072ba0f-e1a9-58bf-9974-e1802adc8134", "color": "#A550FF"}, {"name": "bob", "type": "Entity", "ontology_valid": false, "version": 1, "topological_rank": 0, "metadata": {"index_fields": ["name"]}, "belongs_to_set": null, "source_pipeline": "cognify_pipeline", "source_task": "extract_graph_from_data", "source_node_set": null, "source_user": "default_user@example.com", "description": "profession: ML engineer", "id": "515e93c6-3782-59db-96be-ad5b8cf872a5", "color": "#6510F4"}, {"name": "carol", "type": "Entity", "ontology_valid": false, "version": 1, "topological_rank": 0, "metadata": {"index_fields": ["name"]}, "belongs_to_set": null, "source_pipeline": "cognify_pipeline", "source_task": "extract_graph_from_data", "source_node_set": null, "source_user": "default_user@example.com", "description": "profession: infrastructure", "id": "80370ebb-d9b5-5f12-a3fb-db3631157840", "color": "#6510F4"}, {"name": "next-generation search platform", "type": "Entity", "ontology_valid": false, "version": 1, "topological_rank": 0, "metadata": {"index_fields": ["name"]}, "belongs_to_set": null, "source_pipeline": "cognify_pipeline", "source_task": "extract_graph_from_data", "source_node_set": null, "source_user": "default_user@example.com", "description": "description: next-generation search platform built by the engineering team at Acme Corp", "id": "6fdb37d4-ae27-5a1a-9f7a-03f5036247ca", "color": "#6510F4"}, {"name": "project", "type": "EntityType", "ontology_valid": false, "version": 1, "topological_rank": 0, "metadata": {"index_fields": ["name"]}, "belongs_to_set": null, "source_pipeline": "cognify_pipeline", "source_task": "extract_graph_from_data", "source_node_set": null, "source_user": "default_user@example.com", "description": "project", "id": "29c0d211-0d39-579f-bf45-c7a78394c9aa", "color": "#A550FF"}, {"name": "knowledge graphs", "type": "Entity", "ontology_valid": false, "version": 1, "topological_rank": 0, "metadata": {"index_fields": ["name"]}, "belongs_to_set": null, "source_pipeline": "cognify_pipeline", "source_task": "extract_graph_from_data", "source_node_set": null, "source_user": "default_user@example.com", "description": "technology: knowledge graphs", "id": "df20c394-b710-5b2c-9256-ce5f5fe36397", "color": "#6510F4"}, {"name": "technology", "type": "EntityType", "ontology_valid": false, "version": 1, "topological_rank": 0, "metadata": {"index_fields": ["name"]}, "belongs_to_set": null, "source_pipeline": "cognify_pipeline", "source_task": "extract_graph_from_data", "source_node_set": null, "source_user": "default_user@example.com", "description": "technology", "id": "65c71de3-4c23-5f28-8e07-fc7428d1e0c4", "color": "#A550FF"}, {"name": "llms", "type": "Entity", "ontology_valid": false, "version": 1, "topological_rank": 0, "metadata": {"index_fields": ["name"]}, "belongs_to_set": null, "source_pipeline": "cognify_pipeline", "source_task": "extract_graph_from_data", "source_node_set": null, "source_user": "default_user@example.com", "description": "technology: LLMs", "id": "f7dc5ef7-3d2d-50c7-9edc-475862a15d4b", "color": "#6510F4"}, {"name": "", "type": "DocumentChunk", "ontology_valid": false, "version": 1, "topological_rank": 0, "metadata": {"index_fields": ["text"]}, "belongs_to_set": null, "source_pipeline": "cognify_pipeline", "source_task": "extract_chunks_from_documents", "source_node_set": null, "source_user": "default_user@example.com", "text": "Cognee is an open-source memory for AI agents. Cognee builts a knowledge enginethat transforms raw data (e.g., unstructured documents, relational databases, etc.)into a persistent, rich, and traceable memory that is searchable by meaning and relationships.", "chunk_size": 95, "chunk_index": 0, "cut_type": "sentence_end", "id": "b68768b0-b073-5307-b138-92e625e09f87", "color": "#0DFF00"}, {"name": "text_d1622b5a4ae1e31ed9d352ea3d2cbc20", "type": "TextDocument", "ontology_valid": false, "version": 1, "topological_rank": 0, "metadata": {"index_fields": ["name"]}, "belongs_to_set": null, "source_pipeline": "cognify_pipeline", "source_task": "classify_documents", "source_node_set": null, "source_user": "default_user@example.com", "raw_data_location": "file:///Users/handekafkas/Documents/local-code/haystack-core-integrations/.venv/lib/python3.12/site-packages/cognee/.data_storage/text_d1622b5a4ae1e31ed9d352ea3d2cbc20.txt", "external_metadata": "{}", "mime_type": "text/plain", "id": "46e1332c-9459-5206-b192-bcf6afebf362", "color": "#DBD8D8"}, {"name": "cognee", "type": "Entity", "ontology_valid": false, "version": 1, "topological_rank": 0, "metadata": {"index_fields": ["name"]}, "belongs_to_set": null, "source_pipeline": "cognify_pipeline", "source_task": "extract_graph_from_data", "source_node_set": null, "source_user": "default_user@example.com", "description": "Open-source memory for AI agents that builds a knowledge engine transforming raw data into persistent, rich, and traceable memory searchable by meaning and relationships.", "id": "2d09f34b-aee1-5d32-a2f9-23eb7ed48b24", "color": "#6510F4"}, {"name": "ai agents", "type": "Entity", "ontology_valid": false, "version": 1, "topological_rank": 0, "metadata": {"index_fields": ["name"]}, "belongs_to_set": null, "source_pipeline": "cognify_pipeline", "source_task": "extract_graph_from_data", "source_node_set": null, "source_user": "default_user@example.com", "description": "Artificial intelligence agents that use Cognee's memory.", "id": "968213f1-6ddc-5155-89d4-6df7c144a4a1", "color": "#6510F4"}, {"name": "agent", "type": "EntityType", "ontology_valid": false, "version": 1, "topological_rank": 0, "metadata": {"index_fields": ["name"]}, "belongs_to_set": null, "source_pipeline": "cognify_pipeline", "source_task": "extract_graph_from_data", "source_node_set": null, "source_user": "default_user@example.com", "description": "agent", "id": "5f6d6fc0-e6aa-5365-a4a0-98d6fa3af190", "color": "#A550FF"}, {"name": "knowledge engine", "type": "Entity", "ontology_valid": false, "version": 1, "topological_rank": 0, "metadata": {"index_fields": ["name"]}, "belongs_to_set": null, "source_pipeline": "cognify_pipeline", "source_task": "extract_graph_from_data", "source_node_set": null, "source_user": "default_user@example.com", "description": "Engine built by Cognee to transform raw data into a persistent, rich, and traceable memory.", "id": "d8b992b3-ebdc-52a4-9913-9e1aea9a47f8", "color": "#6510F4"}, {"name": "raw data", "type": "Entity", "ontology_valid": false, "version": 1, "topological_rank": 0, "metadata": {"index_fields": ["name"]}, "belongs_to_set": null, "source_pipeline": "cognify_pipeline", "source_task": "extract_graph_from_data", "source_node_set": null, "source_user": "default_user@example.com", "description": "Input data (examples include unstructured documents and relational databases) processed by the knowledge engine.", "id": "0a6f4624-d50e-5989-ba18-ddab839f5554", "color": "#6510F4"}, {"name": "data", "type": "EntityType", "ontology_valid": false, "version": 1, "topological_rank": 0, "metadata": {"index_fields": ["name"]}, "belongs_to_set": null, "source_pipeline": "cognify_pipeline", "source_task": "extract_graph_from_data", "source_node_set": null, "source_user": "default_user@example.com", "description": "data", "id": "4ed5a0c7-2efb-52d1-9734-06a8ba225c94", "color": "#A550FF"}, {"name": "unstructured documents", "type": "Entity", "ontology_valid": false, "version": 1, "topological_rank": 0, "metadata": {"index_fields": ["name"]}, "belongs_to_set": null, "source_pipeline": "cognify_pipeline", "source_task": "extract_graph_from_data", "source_node_set": null, "source_user": "default_user@example.com", "description": "Example of raw data processed by Cognee (unstructured documents).", "id": "f89d185b-5df9-5fc6-84a7-35931b380405", "color": "#6510F4"}, {"name": "document", "type": "EntityType", "ontology_valid": false, "version": 1, "topological_rank": 0, "metadata": {"index_fields": ["name"]}, "belongs_to_set": null, "source_pipeline": "cognify_pipeline", "source_task": "extract_graph_from_data", "source_node_set": null, "source_user": "default_user@example.com", "description": "document", "id": "7391ab9a-d827-5471-9b04-8cfd1994f783", "color": "#A550FF"}, {"name": "relational databases", "type": "Entity", "ontology_valid": false, "version": 1, "topological_rank": 0, "metadata": {"index_fields": ["name"]}, "belongs_to_set": null, "source_pipeline": "cognify_pipeline", "source_task": "extract_graph_from_data", "source_node_set": null, "source_user": "default_user@example.com", "description": "Example of raw data processed by Cognee (relational databases).", "id": "9d84ec4f-0968-52d0-bd6d-2a4c1b07490d", "color": "#6510F4"}, {"name": "database", "type": "EntityType", "ontology_valid": false, "version": 1, "topological_rank": 0, "metadata": {"index_fields": ["name"]}, "belongs_to_set": null, "source_pipeline": "cognify_pipeline", "source_task": "extract_graph_from_data", "source_node_set": null, "source_user": "default_user@example.com", "description": "database", "id": "90cb1fed-d3a3-51c4-bf2d-467bce3d40a3", "color": "#A550FF"}, {"name": "persistent, rich, and traceable memory", "type": "Entity", "ontology_valid": false, "version": 1, "topological_rank": 0, "metadata": {"index_fields": ["name"]}, "belongs_to_set": null, "source_pipeline": "cognify_pipeline", "source_task": "extract_graph_from_data", "source_node_set": null, "source_user": "default_user@example.com", "description": "The persistent, rich, and traceable memory produced by Cognee's knowledge engine.", "id": "dce5dd84-ed4d-5666-8908-c4c523b804c8", "color": "#6510F4"}, {"name": "memory", "type": "EntityType", "ontology_valid": false, "version": 1, "topological_rank": 0, "metadata": {"index_fields": ["name"]}, "belongs_to_set": null, "source_pipeline": "cognify_pipeline", "source_task": "extract_graph_from_data", "source_node_set": null, "source_user": "default_user@example.com", "description": "memory", "id": "d7624ee3-0f87-5c82-a4a6-562baf3f835b", "color": "#A550FF"}, {"name": "searchable by meaning", "type": "Entity", "ontology_valid": false, "version": 1, "topological_rank": 0, "metadata": {"index_fields": ["name"]}, "belongs_to_set": null, "source_pipeline": "cognify_pipeline", "source_task": "extract_graph_from_data", "source_node_set": null, "source_user": "default_user@example.com", "description": "Characteristic indicating the memory can be searched by semantic meaning.", "id": "d9548bb8-6a7d-50c2-8c88-4412ea76b0b7", "color": "#6510F4"}, {"name": "searchable by relationships", "type": "Entity", "ontology_valid": false, "version": 1, "topological_rank": 0, "metadata": {"index_fields": ["name"]}, "belongs_to_set": null, "source_pipeline": "cognify_pipeline", "source_task": "extract_graph_from_data", "source_node_set": null, "source_user": "default_user@example.com", "description": "Characteristic indicating the memory can be searched by relationships between items.", "id": "797d0cee-f7dd-50cc-a2ac-5fd900797e9a", "color": "#6510F4"}, {"name": "open-source", "type": "Entity", "ontology_valid": false, "version": 1, "topological_rank": 0, "metadata": {"index_fields": ["name"]}, "belongs_to_set": null, "source_pipeline": "cognify_pipeline", "source_task": "extract_graph_from_data", "source_node_set": null, "source_user": "default_user@example.com", "description": "Indicates the software is open-source.", "id": "835749c8-bbaf-503f-8587-cc44589473c9", "color": "#6510F4"}, {"name": "", "type": "DocumentChunk", "ontology_valid": false, "version": 1, "topological_rank": 0, "metadata": {"index_fields": ["text"]}, "belongs_to_set": null, "source_pipeline": "cognify_pipeline", "source_task": "extract_chunks_from_documents", "source_node_set": null, "source_user": "default_user@example.com", "text": "Knowledge graphs represent information as nodes (entities) and edges (relationships). They enable semantic search, reasoning, and discovery of hidden connections across large document collections.", "chunk_size": 56, "chunk_index": 0, "cut_type": "sentence_end", "id": "8a198b04-631a-5fc3-8bb9-87034f79b1cc", "color": "#0DFF00"}, {"name": "text_41edf18cf1a9cb76a5e2eb8429cb9a29", "type": "TextDocument", "ontology_valid": false, "version": 1, "topological_rank": 0, "metadata": {"index_fields": ["name"]}, "belongs_to_set": null, "source_pipeline": "cognify_pipeline", "source_task": "classify_documents", "source_node_set": null, "source_user": "default_user@example.com", "raw_data_location": "file:///Users/handekafkas/Documents/local-code/haystack-core-integrations/.venv/lib/python3.12/site-packages/cognee/.data_storage/text_41edf18cf1a9cb76a5e2eb8429cb9a29.txt", "external_metadata": "{}", "mime_type": "text/plain", "id": "84bba00b-b72d-5340-a260-e47635da331b", "color": "#DBD8D8"}, {"name": "nodes", "type": "Entity", "ontology_valid": false, "version": 1, "topological_rank": 0, "metadata": {"index_fields": ["name"]}, "belongs_to_set": null, "source_pipeline": "cognify_pipeline", "source_task": "extract_graph_from_data", "source_node_set": null, "source_user": "default_user@example.com", "description": "Elements in a knowledge graph that represent entities or concepts.", "id": "bd3f3aa5-5df4-54a0-af4e-78aa5a54e8f3", "color": "#6510F4"}, {"name": "edges", "type": "Entity", "ontology_valid": false, "version": 1, "topological_rank": 0, "metadata": {"index_fields": ["name"]}, "belongs_to_set": null, "source_pipeline": "cognify_pipeline", "source_task": "extract_graph_from_data", "source_node_set": null, "source_user": "default_user@example.com", "description": "Connections in a knowledge graph that represent relationships between nodes.", "id": "e4f1a343-1dd6-5191-ab16-4901f6eccf51", "color": "#6510F4"}, {"name": "entities", "type": "Entity", "ontology_valid": false, "version": 1, "topological_rank": 0, "metadata": {"index_fields": ["name"]}, "belongs_to_set": null, "source_pipeline": "cognify_pipeline", "source_task": "extract_graph_from_data", "source_node_set": null, "source_user": "default_user@example.com", "description": "Real-world things or concepts represented by nodes in a knowledge graph.", "id": "e4e6f950-4621-53ae-8af0-8920799b4853", "color": "#6510F4"}, {"name": "relationships", "type": "Entity", "ontology_valid": false, "version": 1, "topological_rank": 0, "metadata": {"index_fields": ["name"]}, "belongs_to_set": null, "source_pipeline": "cognify_pipeline", "source_task": "extract_graph_from_data", "source_node_set": null, "source_user": "default_user@example.com", "description": "Semantic links between entities represented by edges in a knowledge graph.", "id": "f42a6141-42ac-5973-8b4d-8a1e6f944a12", "color": "#6510F4"}, {"name": "semantic search", "type": "Entity", "ontology_valid": false, "version": 1, "topological_rank": 0, "metadata": {"index_fields": ["name"]}, "belongs_to_set": null, "source_pipeline": "cognify_pipeline", "source_task": "extract_graph_from_data", "source_node_set": null, "source_user": "default_user@example.com", "description": "Search approach that leverages meaning and connections rather than simple keyword matching.", "id": "9d6360d4-504a-5f7f-b618-c2ea457a1a4d", "color": "#6510F4"}, {"name": "reasoning", "type": "Entity", "ontology_valid": false, "version": 1, "topological_rank": 0, "metadata": {"index_fields": ["name"]}, "belongs_to_set": null, "source_pipeline": "cognify_pipeline", "source_task": "extract_graph_from_data", "source_node_set": null, "source_user": "default_user@example.com", "description": "Inference and logical processes enabled by structured knowledge in a graph.", "id": "ba802be9-50b2-58a6-a46d-031e30a780a8", "color": "#6510F4"}, {"name": "discovery of hidden connections", "type": "Entity", "ontology_valid": false, "version": 1, "topological_rank": 0, "metadata": {"index_fields": ["name"]}, "belongs_to_set": null, "source_pipeline": "cognify_pipeline", "source_task": "extract_graph_from_data", "source_node_set": null, "source_user": "default_user@example.com", "description": "Finding non-obvious links between items using the structure and semantics of a knowledge graph.", "id": "e0c5c99c-74a8-5d09-8e8a-05cb2e5bcf6b", "color": "#6510F4"}, {"name": "large document collections", "type": "Entity", "ontology_valid": false, "version": 1, "topological_rank": 0, "metadata": {"index_fields": ["name"]}, "belongs_to_set": null, "source_pipeline": "cognify_pipeline", "source_task": "extract_graph_from_data", "source_node_set": null, "source_user": "default_user@example.com", "description": "Extensive sets of documents across which knowledge graphs can reveal relationships and insights.", "id": "838f4a46-e459-58e4-a40b-ab30cd21da5c", "color": "#6510F4"}, {"name": "", "type": "TextSummary", "ontology_valid": false, "version": 1, "topological_rank": 0, "metadata": {"index_fields": ["text"]}, "belongs_to_set": null, "source_pipeline": "cognify_pipeline", "source_task": "summarize_text", "source_node_set": null, "source_user": "default_user@example.com", "text": "Cognee is an open-source memory system for AI agents that converts raw inputs into a durable, enriched, and traceable knowledge store searchable by semantics and relationships.", "id": "4dfc885b-eac1-5dd6-9276-d129394d7c6d", "color": "#6510F4"}, {"name": "", "type": "TextSummary", "ontology_valid": false, "version": 1, "topological_rank": 0, "metadata": {"index_fields": ["text"]}, "belongs_to_set": null, "source_pipeline": "cognify_pipeline", "source_task": "summarize_text", "source_node_set": null, "source_user": "default_user@example.com", "text": "Knowledge graphs model information as nodes (entities) and edges (relations), enabling semantic search, inferencing, and discovery of latent links across large document corpora.", "id": "a778650e-2acb-5f70-8bea-ce50fd5f2d68", "color": "#6510F4"}, {"name": "", "type": "TextSummary", "ontology_valid": false, "version": 1, "topological_rank": 0, "metadata": {"index_fields": ["text"]}, "belongs_to_set": null, "source_pipeline": "cognify_pipeline", "source_task": "summarize_text", "source_node_set": null, "source_user": "default_user@example.com", "text": "Acme Corp's engineering team\u2014Alice (backend lead), Bob (ML engineer), and Carol (infrastructure)\u2014is building an advanced search platform powered by knowledge graphs and large language models.", "id": "ee59fe9f-e651-5cd1-bb28-14c4155deaad", "color": "#6510F4"}]; -var links = [{"source": "c2a2a0b9-6fdf-5035-aedf-d1f4fa3d0fa8", "target": "d1a887a7-2ced-54ec-8359-b5b619b259a3", "relation": "is_part_of", "weight": null, "all_weights": {}, "relationship_type": null, "edge_info": {"source_node_id": "c2a2a0b9-6fdf-5035-aedf-d1f4fa3d0fa8", "target_node_id": "d1a887a7-2ced-54ec-8359-b5b619b259a3", "relationship_name": "is_part_of", "updated_at": "2026-03-18 12:19:48"}}, {"source": "c2a2a0b9-6fdf-5035-aedf-d1f4fa3d0fa8", "target": "2bdd3deb-07d8-5413-a56d-1643e3ceb48b", "relation": "contains", "weight": null, "all_weights": {}, "relationship_type": "contains", "edge_info": {"source_node_id": "c2a2a0b9-6fdf-5035-aedf-d1f4fa3d0fa8", "target_node_id": "2bdd3deb-07d8-5413-a56d-1643e3ceb48b", "relationship_name": "contains", "updated_at": "2026-03-18 12:19:48", "relationship_type": "contains", "edge_text": "relationship_name: contains; entity_name: haystack; entity_description: Open-source LLM framework by deepset for building production-ready RAG pipelines, agents, and search systems."}}, {"source": "c2a2a0b9-6fdf-5035-aedf-d1f4fa3d0fa8", "target": "126df7ec-d0db-53ea-bc88-1bafd84c8646", "relation": "contains", "weight": null, "all_weights": {}, "relationship_type": "contains", "edge_info": {"source_node_id": "c2a2a0b9-6fdf-5035-aedf-d1f4fa3d0fa8", "target_node_id": "126df7ec-d0db-53ea-bc88-1bafd84c8646", "relationship_name": "contains", "updated_at": "2026-03-18 12:19:48", "relationship_type": "contains", "edge_text": "relationship_name: contains; entity_name: deepset; entity_description: Organization that developed Haystack."}}, {"source": "c2a2a0b9-6fdf-5035-aedf-d1f4fa3d0fa8", "target": "7594343c-5532-5896-b0aa-be5c1a74bd92", "relation": "contains", "weight": null, "all_weights": {}, "relationship_type": "contains", "edge_info": {"source_node_id": "c2a2a0b9-6fdf-5035-aedf-d1f4fa3d0fa8", "target_node_id": "7594343c-5532-5896-b0aa-be5c1a74bd92", "relationship_name": "contains", "updated_at": "2026-03-18 12:19:48", "relationship_type": "contains", "edge_text": "relationship_name: contains; entity_name: rag pipelines; entity_description: Retrieval-Augmented Generation (RAG) pipelines."}}, {"source": "c2a2a0b9-6fdf-5035-aedf-d1f4fa3d0fa8", "target": "ba1f1dac-e2fb-5464-914d-ff54b9b19787", "relation": "contains", "weight": null, "all_weights": {}, "relationship_type": "contains", "edge_info": {"source_node_id": "c2a2a0b9-6fdf-5035-aedf-d1f4fa3d0fa8", "target_node_id": "ba1f1dac-e2fb-5464-914d-ff54b9b19787", "relationship_name": "contains", "updated_at": "2026-03-18 12:19:48", "relationship_type": "contains", "edge_text": "relationship_name: contains; entity_name: agents; entity_description: Agents built using Haystack."}}, {"source": "c2a2a0b9-6fdf-5035-aedf-d1f4fa3d0fa8", "target": "a1a666e4-2070-59fd-95f7-c4c6178e89ba", "relation": "contains", "weight": null, "all_weights": {}, "relationship_type": "contains", "edge_info": {"source_node_id": "c2a2a0b9-6fdf-5035-aedf-d1f4fa3d0fa8", "target_node_id": "a1a666e4-2070-59fd-95f7-c4c6178e89ba", "relationship_name": "contains", "updated_at": "2026-03-18 12:19:48", "relationship_type": "contains", "edge_text": "relationship_name: contains; entity_name: search systems; entity_description: Search systems built using Haystack."}}, {"source": "c2a2a0b9-6fdf-5035-aedf-d1f4fa3d0fa8", "target": "865e92ac-5a4f-5ba9-910f-d28ce255c4a2", "relation": "contains", "weight": null, "all_weights": {}, "relationship_type": "contains", "edge_info": {"source_node_id": "c2a2a0b9-6fdf-5035-aedf-d1f4fa3d0fa8", "target_node_id": "865e92ac-5a4f-5ba9-910f-d28ce255c4a2", "relationship_name": "contains", "updated_at": "2026-03-18 12:19:48", "relationship_type": "contains", "edge_text": "relationship_name: contains; entity_name: component-based architecture; entity_description: Architecture where each step (retrieval, generation, etc.) is a composable building block."}}, {"source": "c2a2a0b9-6fdf-5035-aedf-d1f4fa3d0fa8", "target": "f010bf52-6eb5-511f-bbed-cd5237545edd", "relation": "contains", "weight": null, "all_weights": {}, "relationship_type": "contains", "edge_info": {"source_node_id": "c2a2a0b9-6fdf-5035-aedf-d1f4fa3d0fa8", "target_node_id": "f010bf52-6eb5-511f-bbed-cd5237545edd", "relationship_name": "contains", "updated_at": "2026-03-18 12:19:48", "relationship_type": "contains", "edge_text": "relationship_name: contains; entity_name: retrieval; entity_description: A retrieval step in Haystack pipelines."}}, {"source": "c2a2a0b9-6fdf-5035-aedf-d1f4fa3d0fa8", "target": "dba0457b-9aff-5eb6-8ccd-19f7c9ae4dfa", "relation": "contains", "weight": null, "all_weights": {}, "relationship_type": "contains", "edge_info": {"source_node_id": "c2a2a0b9-6fdf-5035-aedf-d1f4fa3d0fa8", "target_node_id": "dba0457b-9aff-5eb6-8ccd-19f7c9ae4dfa", "relationship_name": "contains", "updated_at": "2026-03-18 12:19:48", "relationship_type": "contains", "edge_text": "relationship_name: contains; entity_name: generation; entity_description: A generation step in Haystack pipelines."}}, {"source": "c2a2a0b9-6fdf-5035-aedf-d1f4fa3d0fa8", "target": "59cf88c0-cb09-5f96-9252-5f5810981bcc", "relation": "contains", "weight": null, "all_weights": {}, "relationship_type": "contains", "edge_info": {"source_node_id": "c2a2a0b9-6fdf-5035-aedf-d1f4fa3d0fa8", "target_node_id": "59cf88c0-cb09-5f96-9252-5f5810981bcc", "relationship_name": "contains", "updated_at": "2026-03-18 12:19:48", "relationship_type": "contains", "edge_text": "relationship_name: contains; entity_name: composable building block; entity_description: Modular component that can be composed into pipeline steps."}}, {"source": "2bdd3deb-07d8-5413-a56d-1643e3ceb48b", "target": "2d66edc2-1e14-55ab-8304-680b514a597a", "relation": "is_a", "weight": null, "all_weights": {}, "relationship_type": null, "edge_info": {"source_node_id": "2bdd3deb-07d8-5413-a56d-1643e3ceb48b", "target_node_id": "2d66edc2-1e14-55ab-8304-680b514a597a", "relationship_name": "is_a", "updated_at": "2026-03-18 12:19:48"}}, {"source": "2bdd3deb-07d8-5413-a56d-1643e3ceb48b", "target": "126df7ec-d0db-53ea-bc88-1bafd84c8646", "relation": "developed_by", "weight": null, "all_weights": {}, "relationship_type": null, "edge_info": {"relationship_name": "developed_by", "source_node_id": "2bdd3deb-07d8-5413-a56d-1643e3ceb48b", "target_node_id": "126df7ec-d0db-53ea-bc88-1bafd84c8646", "ontology_valid": false}}, {"source": "2bdd3deb-07d8-5413-a56d-1643e3ceb48b", "target": "7594343c-5532-5896-b0aa-be5c1a74bd92", "relation": "used_for_building", "weight": null, "all_weights": {}, "relationship_type": null, "edge_info": {"relationship_name": "used_for_building", "source_node_id": "2bdd3deb-07d8-5413-a56d-1643e3ceb48b", "target_node_id": "7594343c-5532-5896-b0aa-be5c1a74bd92", "ontology_valid": false}}, {"source": "2bdd3deb-07d8-5413-a56d-1643e3ceb48b", "target": "ba1f1dac-e2fb-5464-914d-ff54b9b19787", "relation": "used_for_building", "weight": null, "all_weights": {}, "relationship_type": null, "edge_info": {"relationship_name": "used_for_building", "source_node_id": "2bdd3deb-07d8-5413-a56d-1643e3ceb48b", "target_node_id": "ba1f1dac-e2fb-5464-914d-ff54b9b19787", "ontology_valid": false}}, {"source": "2bdd3deb-07d8-5413-a56d-1643e3ceb48b", "target": "a1a666e4-2070-59fd-95f7-c4c6178e89ba", "relation": "used_for_building", "weight": null, "all_weights": {}, "relationship_type": null, "edge_info": {"relationship_name": "used_for_building", "source_node_id": "2bdd3deb-07d8-5413-a56d-1643e3ceb48b", "target_node_id": "a1a666e4-2070-59fd-95f7-c4c6178e89ba", "ontology_valid": false}}, {"source": "2bdd3deb-07d8-5413-a56d-1643e3ceb48b", "target": "865e92ac-5a4f-5ba9-910f-d28ce255c4a2", "relation": "uses_architecture", "weight": null, "all_weights": {}, "relationship_type": null, "edge_info": {"relationship_name": "uses_architecture", "source_node_id": "2bdd3deb-07d8-5413-a56d-1643e3ceb48b", "target_node_id": "865e92ac-5a4f-5ba9-910f-d28ce255c4a2", "ontology_valid": false}}, {"source": "126df7ec-d0db-53ea-bc88-1bafd84c8646", "target": "d3d7b6b4-9b0d-52e8-9e09-a9e9cf4b5a4d", "relation": "is_a", "weight": null, "all_weights": {}, "relationship_type": null, "edge_info": {"source_node_id": "126df7ec-d0db-53ea-bc88-1bafd84c8646", "target_node_id": "d3d7b6b4-9b0d-52e8-9e09-a9e9cf4b5a4d", "relationship_name": "is_a", "updated_at": "2026-03-18 12:19:48"}}, {"source": "7594343c-5532-5896-b0aa-be5c1a74bd92", "target": "dd9713b7-dc20-5101-aad0-1c4216811147", "relation": "is_a", "weight": null, "all_weights": {}, "relationship_type": null, "edge_info": {"source_node_id": "7594343c-5532-5896-b0aa-be5c1a74bd92", "target_node_id": "dd9713b7-dc20-5101-aad0-1c4216811147", "relationship_name": "is_a", "updated_at": "2026-03-18 12:19:48"}}, {"source": "ba1f1dac-e2fb-5464-914d-ff54b9b19787", "target": "dd9713b7-dc20-5101-aad0-1c4216811147", "relation": "is_a", "weight": null, "all_weights": {}, "relationship_type": null, "edge_info": {"source_node_id": "ba1f1dac-e2fb-5464-914d-ff54b9b19787", "target_node_id": "dd9713b7-dc20-5101-aad0-1c4216811147", "relationship_name": "is_a", "updated_at": "2026-03-18 12:19:48"}}, {"source": "a1a666e4-2070-59fd-95f7-c4c6178e89ba", "target": "dd9713b7-dc20-5101-aad0-1c4216811147", "relation": "is_a", "weight": null, "all_weights": {}, "relationship_type": null, "edge_info": {"source_node_id": "a1a666e4-2070-59fd-95f7-c4c6178e89ba", "target_node_id": "dd9713b7-dc20-5101-aad0-1c4216811147", "relationship_name": "is_a", "updated_at": "2026-03-18 12:19:48"}}, {"source": "865e92ac-5a4f-5ba9-910f-d28ce255c4a2", "target": "dd9713b7-dc20-5101-aad0-1c4216811147", "relation": "is_a", "weight": null, "all_weights": {}, "relationship_type": null, "edge_info": {"source_node_id": "865e92ac-5a4f-5ba9-910f-d28ce255c4a2", "target_node_id": "dd9713b7-dc20-5101-aad0-1c4216811147", "relationship_name": "is_a", "updated_at": "2026-03-18 12:19:48"}}, {"source": "865e92ac-5a4f-5ba9-910f-d28ce255c4a2", "target": "f010bf52-6eb5-511f-bbed-cd5237545edd", "relation": "includes_step", "weight": null, "all_weights": {}, "relationship_type": null, "edge_info": {"relationship_name": "includes_step", "source_node_id": "865e92ac-5a4f-5ba9-910f-d28ce255c4a2", "target_node_id": "f010bf52-6eb5-511f-bbed-cd5237545edd", "ontology_valid": false}}, {"source": "865e92ac-5a4f-5ba9-910f-d28ce255c4a2", "target": "dba0457b-9aff-5eb6-8ccd-19f7c9ae4dfa", "relation": "includes_step", "weight": null, "all_weights": {}, "relationship_type": null, "edge_info": {"relationship_name": "includes_step", "source_node_id": "865e92ac-5a4f-5ba9-910f-d28ce255c4a2", "target_node_id": "dba0457b-9aff-5eb6-8ccd-19f7c9ae4dfa", "ontology_valid": false}}, {"source": "f010bf52-6eb5-511f-bbed-cd5237545edd", "target": "dd9713b7-dc20-5101-aad0-1c4216811147", "relation": "is_a", "weight": null, "all_weights": {}, "relationship_type": null, "edge_info": {"source_node_id": "f010bf52-6eb5-511f-bbed-cd5237545edd", "target_node_id": "dd9713b7-dc20-5101-aad0-1c4216811147", "relationship_name": "is_a", "updated_at": "2026-03-18 12:19:48"}}, {"source": "f010bf52-6eb5-511f-bbed-cd5237545edd", "target": "59cf88c0-cb09-5f96-9252-5f5810981bcc", "relation": "is_a", "weight": null, "all_weights": {}, "relationship_type": null, "edge_info": {"relationship_name": "is_a", "source_node_id": "f010bf52-6eb5-511f-bbed-cd5237545edd", "target_node_id": "59cf88c0-cb09-5f96-9252-5f5810981bcc", "ontology_valid": false}}, {"source": "dba0457b-9aff-5eb6-8ccd-19f7c9ae4dfa", "target": "dd9713b7-dc20-5101-aad0-1c4216811147", "relation": "is_a", "weight": null, "all_weights": {}, "relationship_type": null, "edge_info": {"source_node_id": "dba0457b-9aff-5eb6-8ccd-19f7c9ae4dfa", "target_node_id": "dd9713b7-dc20-5101-aad0-1c4216811147", "relationship_name": "is_a", "updated_at": "2026-03-18 12:19:48"}}, {"source": "dba0457b-9aff-5eb6-8ccd-19f7c9ae4dfa", "target": "59cf88c0-cb09-5f96-9252-5f5810981bcc", "relation": "is_a", "weight": null, "all_weights": {}, "relationship_type": null, "edge_info": {"relationship_name": "is_a", "source_node_id": "dba0457b-9aff-5eb6-8ccd-19f7c9ae4dfa", "target_node_id": "59cf88c0-cb09-5f96-9252-5f5810981bcc", "ontology_valid": false}}, {"source": "59cf88c0-cb09-5f96-9252-5f5810981bcc", "target": "dd9713b7-dc20-5101-aad0-1c4216811147", "relation": "is_a", "weight": null, "all_weights": {}, "relationship_type": null, "edge_info": {"source_node_id": "59cf88c0-cb09-5f96-9252-5f5810981bcc", "target_node_id": "dd9713b7-dc20-5101-aad0-1c4216811147", "relationship_name": "is_a", "updated_at": "2026-03-18 12:19:48"}}, {"source": "2bcd4862-2b66-5cfd-bdc0-92605a426502", "target": "c2a2a0b9-6fdf-5035-aedf-d1f4fa3d0fa8", "relation": "made_from", "weight": null, "all_weights": {}, "relationship_type": null, "edge_info": {"source_node_id": "2bcd4862-2b66-5cfd-bdc0-92605a426502", "target_node_id": "c2a2a0b9-6fdf-5035-aedf-d1f4fa3d0fa8", "relationship_name": "made_from", "updated_at": "2026-03-18 12:19:48"}}, {"source": "8d133f76-c22c-5758-bdc6-73bf5da4576a", "target": "9e533e24-badc-5824-90d7-fac3a10dbe20", "relation": "is_part_of", "weight": null, "all_weights": {}, "relationship_type": null, "edge_info": {"source_node_id": "8d133f76-c22c-5758-bdc6-73bf5da4576a", "target_node_id": "9e533e24-badc-5824-90d7-fac3a10dbe20", "relationship_name": "is_part_of", "updated_at": "2026-03-18 12:19:58"}}, {"source": "8d133f76-c22c-5758-bdc6-73bf5da4576a", "target": "7f5a651e-56c1-574f-aa54-cd0a0b7dbc38", "relation": "contains", "weight": null, "all_weights": {}, "relationship_type": "contains", "edge_info": {"source_node_id": "8d133f76-c22c-5758-bdc6-73bf5da4576a", "target_node_id": "7f5a651e-56c1-574f-aa54-cd0a0b7dbc38", "relationship_name": "contains", "updated_at": "2026-03-18 12:19:58", "relationship_type": "contains", "edge_text": "relationship_name: contains; entity_name: acme corp; entity_description: organization: Acme Corp"}}, {"source": "8d133f76-c22c-5758-bdc6-73bf5da4576a", "target": "7fa8891b-a426-5d42-b011-6851ef945793", "relation": "contains", "weight": null, "all_weights": {}, "relationship_type": "contains", "edge_info": {"source_node_id": "8d133f76-c22c-5758-bdc6-73bf5da4576a", "target_node_id": "7fa8891b-a426-5d42-b011-6851ef945793", "relationship_name": "contains", "updated_at": "2026-03-18 12:19:58", "relationship_type": "contains", "edge_text": "relationship_name: contains; entity_name: engineering team at acme corp; entity_description: team: engineering team at Acme Corp"}}, {"source": "8d133f76-c22c-5758-bdc6-73bf5da4576a", "target": "f7d8be13-2a72-5104-bd02-7a5964737a91", "relation": "contains", "weight": null, "all_weights": {}, "relationship_type": "contains", "edge_info": {"source_node_id": "8d133f76-c22c-5758-bdc6-73bf5da4576a", "target_node_id": "f7d8be13-2a72-5104-bd02-7a5964737a91", "relationship_name": "contains", "updated_at": "2026-03-18 12:19:58", "relationship_type": "contains", "edge_text": "relationship_name: contains; entity_name: alice; entity_description: profession: backend lead"}}, {"source": "8d133f76-c22c-5758-bdc6-73bf5da4576a", "target": "515e93c6-3782-59db-96be-ad5b8cf872a5", "relation": "contains", "weight": null, "all_weights": {}, "relationship_type": "contains", "edge_info": {"source_node_id": "8d133f76-c22c-5758-bdc6-73bf5da4576a", "target_node_id": "515e93c6-3782-59db-96be-ad5b8cf872a5", "relationship_name": "contains", "updated_at": "2026-03-18 12:19:58", "relationship_type": "contains", "edge_text": "relationship_name: contains; entity_name: bob; entity_description: profession: ML engineer"}}, {"source": "8d133f76-c22c-5758-bdc6-73bf5da4576a", "target": "80370ebb-d9b5-5f12-a3fb-db3631157840", "relation": "contains", "weight": null, "all_weights": {}, "relationship_type": "contains", "edge_info": {"source_node_id": "8d133f76-c22c-5758-bdc6-73bf5da4576a", "target_node_id": "80370ebb-d9b5-5f12-a3fb-db3631157840", "relationship_name": "contains", "updated_at": "2026-03-18 12:19:58", "relationship_type": "contains", "edge_text": "relationship_name: contains; entity_name: carol; entity_description: profession: infrastructure"}}, {"source": "8d133f76-c22c-5758-bdc6-73bf5da4576a", "target": "6fdb37d4-ae27-5a1a-9f7a-03f5036247ca", "relation": "contains", "weight": null, "all_weights": {}, "relationship_type": "contains", "edge_info": {"source_node_id": "8d133f76-c22c-5758-bdc6-73bf5da4576a", "target_node_id": "6fdb37d4-ae27-5a1a-9f7a-03f5036247ca", "relationship_name": "contains", "updated_at": "2026-03-18 12:19:58", "relationship_type": "contains", "edge_text": "relationship_name: contains; entity_name: next-generation search platform; entity_description: description: next-generation search platform built by the engineering team at Acme Corp"}}, {"source": "8d133f76-c22c-5758-bdc6-73bf5da4576a", "target": "df20c394-b710-5b2c-9256-ce5f5fe36397", "relation": "contains", "weight": null, "all_weights": {}, "relationship_type": "contains", "edge_info": {"source_node_id": "8d133f76-c22c-5758-bdc6-73bf5da4576a", "target_node_id": "df20c394-b710-5b2c-9256-ce5f5fe36397", "relationship_name": "contains", "updated_at": "2026-03-18 12:19:58", "relationship_type": "contains", "edge_text": "relationship_name: contains; entity_name: knowledge graphs; entity_description: technology: knowledge graphs"}}, {"source": "8d133f76-c22c-5758-bdc6-73bf5da4576a", "target": "f7dc5ef7-3d2d-50c7-9edc-475862a15d4b", "relation": "contains", "weight": null, "all_weights": {}, "relationship_type": "contains", "edge_info": {"source_node_id": "8d133f76-c22c-5758-bdc6-73bf5da4576a", "target_node_id": "f7dc5ef7-3d2d-50c7-9edc-475862a15d4b", "relationship_name": "contains", "updated_at": "2026-03-18 12:19:58", "relationship_type": "contains", "edge_text": "relationship_name: contains; entity_name: llms; entity_description: technology: LLMs"}}, {"source": "7f5a651e-56c1-574f-aa54-cd0a0b7dbc38", "target": "d3d7b6b4-9b0d-52e8-9e09-a9e9cf4b5a4d", "relation": "is_a", "weight": null, "all_weights": {}, "relationship_type": null, "edge_info": {"source_node_id": "7f5a651e-56c1-574f-aa54-cd0a0b7dbc38", "target_node_id": "d3d7b6b4-9b0d-52e8-9e09-a9e9cf4b5a4d", "relationship_name": "is_a", "updated_at": "2026-03-18 12:19:58"}}, {"source": "7fa8891b-a426-5d42-b011-6851ef945793", "target": "e308d782-2a18-5ace-b0e8-236c7c3b4db4", "relation": "is_a", "weight": null, "all_weights": {}, "relationship_type": null, "edge_info": {"source_node_id": "7fa8891b-a426-5d42-b011-6851ef945793", "target_node_id": "e308d782-2a18-5ace-b0e8-236c7c3b4db4", "relationship_name": "is_a", "updated_at": "2026-03-18 12:19:58"}}, {"source": "7fa8891b-a426-5d42-b011-6851ef945793", "target": "7f5a651e-56c1-574f-aa54-cd0a0b7dbc38", "relation": "part_of", "weight": null, "all_weights": {}, "relationship_type": null, "edge_info": {"relationship_name": "part_of", "source_node_id": "7fa8891b-a426-5d42-b011-6851ef945793", "target_node_id": "7f5a651e-56c1-574f-aa54-cd0a0b7dbc38", "ontology_valid": false}}, {"source": "7fa8891b-a426-5d42-b011-6851ef945793", "target": "6fdb37d4-ae27-5a1a-9f7a-03f5036247ca", "relation": "builds", "weight": null, "all_weights": {}, "relationship_type": null, "edge_info": {"relationship_name": "builds", "source_node_id": "7fa8891b-a426-5d42-b011-6851ef945793", "target_node_id": "6fdb37d4-ae27-5a1a-9f7a-03f5036247ca", "ontology_valid": false}}, {"source": "f7d8be13-2a72-5104-bd02-7a5964737a91", "target": "d072ba0f-e1a9-58bf-9974-e1802adc8134", "relation": "is_a", "weight": null, "all_weights": {}, "relationship_type": null, "edge_info": {"source_node_id": "f7d8be13-2a72-5104-bd02-7a5964737a91", "target_node_id": "d072ba0f-e1a9-58bf-9974-e1802adc8134", "relationship_name": "is_a", "updated_at": "2026-03-18 12:19:58"}}, {"source": "f7d8be13-2a72-5104-bd02-7a5964737a91", "target": "7fa8891b-a426-5d42-b011-6851ef945793", "relation": "member_of", "weight": null, "all_weights": {}, "relationship_type": null, "edge_info": {"relationship_name": "member_of", "source_node_id": "f7d8be13-2a72-5104-bd02-7a5964737a91", "target_node_id": "7fa8891b-a426-5d42-b011-6851ef945793", "ontology_valid": false}}, {"source": "515e93c6-3782-59db-96be-ad5b8cf872a5", "target": "d072ba0f-e1a9-58bf-9974-e1802adc8134", "relation": "is_a", "weight": null, "all_weights": {}, "relationship_type": null, "edge_info": {"source_node_id": "515e93c6-3782-59db-96be-ad5b8cf872a5", "target_node_id": "d072ba0f-e1a9-58bf-9974-e1802adc8134", "relationship_name": "is_a", "updated_at": "2026-03-18 12:19:58"}}, {"source": "515e93c6-3782-59db-96be-ad5b8cf872a5", "target": "7fa8891b-a426-5d42-b011-6851ef945793", "relation": "member_of", "weight": null, "all_weights": {}, "relationship_type": null, "edge_info": {"relationship_name": "member_of", "source_node_id": "515e93c6-3782-59db-96be-ad5b8cf872a5", "target_node_id": "7fa8891b-a426-5d42-b011-6851ef945793", "ontology_valid": false}}, {"source": "80370ebb-d9b5-5f12-a3fb-db3631157840", "target": "d072ba0f-e1a9-58bf-9974-e1802adc8134", "relation": "is_a", "weight": null, "all_weights": {}, "relationship_type": null, "edge_info": {"source_node_id": "80370ebb-d9b5-5f12-a3fb-db3631157840", "target_node_id": "d072ba0f-e1a9-58bf-9974-e1802adc8134", "relationship_name": "is_a", "updated_at": "2026-03-18 12:19:58"}}, {"source": "80370ebb-d9b5-5f12-a3fb-db3631157840", "target": "7fa8891b-a426-5d42-b011-6851ef945793", "relation": "member_of", "weight": null, "all_weights": {}, "relationship_type": null, "edge_info": {"relationship_name": "member_of", "source_node_id": "80370ebb-d9b5-5f12-a3fb-db3631157840", "target_node_id": "7fa8891b-a426-5d42-b011-6851ef945793", "ontology_valid": false}}, {"source": "6fdb37d4-ae27-5a1a-9f7a-03f5036247ca", "target": "29c0d211-0d39-579f-bf45-c7a78394c9aa", "relation": "is_a", "weight": null, "all_weights": {}, "relationship_type": null, "edge_info": {"source_node_id": "6fdb37d4-ae27-5a1a-9f7a-03f5036247ca", "target_node_id": "29c0d211-0d39-579f-bf45-c7a78394c9aa", "relationship_name": "is_a", "updated_at": "2026-03-18 12:19:58"}}, {"source": "6fdb37d4-ae27-5a1a-9f7a-03f5036247ca", "target": "df20c394-b710-5b2c-9256-ce5f5fe36397", "relation": "powered_by", "weight": null, "all_weights": {}, "relationship_type": null, "edge_info": {"relationship_name": "powered_by", "source_node_id": "6fdb37d4-ae27-5a1a-9f7a-03f5036247ca", "target_node_id": "df20c394-b710-5b2c-9256-ce5f5fe36397", "ontology_valid": false}}, {"source": "6fdb37d4-ae27-5a1a-9f7a-03f5036247ca", "target": "f7dc5ef7-3d2d-50c7-9edc-475862a15d4b", "relation": "powered_by", "weight": null, "all_weights": {}, "relationship_type": null, "edge_info": {"relationship_name": "powered_by", "source_node_id": "6fdb37d4-ae27-5a1a-9f7a-03f5036247ca", "target_node_id": "f7dc5ef7-3d2d-50c7-9edc-475862a15d4b", "ontology_valid": false}}, {"source": "df20c394-b710-5b2c-9256-ce5f5fe36397", "target": "65c71de3-4c23-5f28-8e07-fc7428d1e0c4", "relation": "is_a", "weight": null, "all_weights": {}, "relationship_type": null, "edge_info": {"source_node_id": "df20c394-b710-5b2c-9256-ce5f5fe36397", "target_node_id": "65c71de3-4c23-5f28-8e07-fc7428d1e0c4", "relationship_name": "is_a", "updated_at": "2026-03-18 12:19:58"}}, {"source": "df20c394-b710-5b2c-9256-ce5f5fe36397", "target": "dd9713b7-dc20-5101-aad0-1c4216811147", "relation": "is_a", "weight": null, "all_weights": {}, "relationship_type": null, "edge_info": {"source_node_id": "df20c394-b710-5b2c-9256-ce5f5fe36397", "target_node_id": "dd9713b7-dc20-5101-aad0-1c4216811147", "relationship_name": "is_a", "updated_at": "2026-03-18 12:19:57"}}, {"source": "df20c394-b710-5b2c-9256-ce5f5fe36397", "target": "bd3f3aa5-5df4-54a0-af4e-78aa5a54e8f3", "relation": "represent_information_as", "weight": null, "all_weights": {}, "relationship_type": null, "edge_info": {"relationship_name": "represent_information_as", "source_node_id": "df20c394-b710-5b2c-9256-ce5f5fe36397", "target_node_id": "bd3f3aa5-5df4-54a0-af4e-78aa5a54e8f3", "ontology_valid": false}}, {"source": "df20c394-b710-5b2c-9256-ce5f5fe36397", "target": "e4f1a343-1dd6-5191-ab16-4901f6eccf51", "relation": "represent_information_as", "weight": null, "all_weights": {}, "relationship_type": null, "edge_info": {"relationship_name": "represent_information_as", "source_node_id": "df20c394-b710-5b2c-9256-ce5f5fe36397", "target_node_id": "e4f1a343-1dd6-5191-ab16-4901f6eccf51", "ontology_valid": false}}, {"source": "df20c394-b710-5b2c-9256-ce5f5fe36397", "target": "9d6360d4-504a-5f7f-b618-c2ea457a1a4d", "relation": "enable", "weight": null, "all_weights": {}, "relationship_type": null, "edge_info": {"relationship_name": "enable", "source_node_id": "df20c394-b710-5b2c-9256-ce5f5fe36397", "target_node_id": "9d6360d4-504a-5f7f-b618-c2ea457a1a4d", "ontology_valid": false}}, {"source": "df20c394-b710-5b2c-9256-ce5f5fe36397", "target": "ba802be9-50b2-58a6-a46d-031e30a780a8", "relation": "enable", "weight": null, "all_weights": {}, "relationship_type": null, "edge_info": {"relationship_name": "enable", "source_node_id": "df20c394-b710-5b2c-9256-ce5f5fe36397", "target_node_id": "ba802be9-50b2-58a6-a46d-031e30a780a8", "ontology_valid": false}}, {"source": "df20c394-b710-5b2c-9256-ce5f5fe36397", "target": "e0c5c99c-74a8-5d09-8e8a-05cb2e5bcf6b", "relation": "enable", "weight": null, "all_weights": {}, "relationship_type": null, "edge_info": {"relationship_name": "enable", "source_node_id": "df20c394-b710-5b2c-9256-ce5f5fe36397", "target_node_id": "e0c5c99c-74a8-5d09-8e8a-05cb2e5bcf6b", "ontology_valid": false}}, {"source": "f7dc5ef7-3d2d-50c7-9edc-475862a15d4b", "target": "65c71de3-4c23-5f28-8e07-fc7428d1e0c4", "relation": "is_a", "weight": null, "all_weights": {}, "relationship_type": null, "edge_info": {"source_node_id": "f7dc5ef7-3d2d-50c7-9edc-475862a15d4b", "target_node_id": "65c71de3-4c23-5f28-8e07-fc7428d1e0c4", "relationship_name": "is_a", "updated_at": "2026-03-18 12:19:58"}}, {"source": "b68768b0-b073-5307-b138-92e625e09f87", "target": "46e1332c-9459-5206-b192-bcf6afebf362", "relation": "is_part_of", "weight": null, "all_weights": {}, "relationship_type": null, "edge_info": {"source_node_id": "b68768b0-b073-5307-b138-92e625e09f87", "target_node_id": "46e1332c-9459-5206-b192-bcf6afebf362", "relationship_name": "is_part_of", "updated_at": "2026-03-18 12:19:57"}}, {"source": "b68768b0-b073-5307-b138-92e625e09f87", "target": "2d09f34b-aee1-5d32-a2f9-23eb7ed48b24", "relation": "contains", "weight": null, "all_weights": {}, "relationship_type": "contains", "edge_info": {"source_node_id": "b68768b0-b073-5307-b138-92e625e09f87", "target_node_id": "2d09f34b-aee1-5d32-a2f9-23eb7ed48b24", "relationship_name": "contains", "updated_at": "2026-03-18 12:19:57", "relationship_type": "contains", "edge_text": "relationship_name: contains; entity_name: cognee; entity_description: Open-source memory for AI agents that builds a knowledge engine transforming raw data into persistent, rich, and traceable memory searchable by meaning and relationships."}}, {"source": "b68768b0-b073-5307-b138-92e625e09f87", "target": "968213f1-6ddc-5155-89d4-6df7c144a4a1", "relation": "contains", "weight": null, "all_weights": {}, "relationship_type": "contains", "edge_info": {"source_node_id": "b68768b0-b073-5307-b138-92e625e09f87", "target_node_id": "968213f1-6ddc-5155-89d4-6df7c144a4a1", "relationship_name": "contains", "updated_at": "2026-03-18 12:19:57", "relationship_type": "contains", "edge_text": "relationship_name: contains; entity_name: ai agents; entity_description: Artificial intelligence agents that use Cognee's memory."}}, {"source": "b68768b0-b073-5307-b138-92e625e09f87", "target": "d8b992b3-ebdc-52a4-9913-9e1aea9a47f8", "relation": "contains", "weight": null, "all_weights": {}, "relationship_type": "contains", "edge_info": {"source_node_id": "b68768b0-b073-5307-b138-92e625e09f87", "target_node_id": "d8b992b3-ebdc-52a4-9913-9e1aea9a47f8", "relationship_name": "contains", "updated_at": "2026-03-18 12:19:57", "relationship_type": "contains", "edge_text": "relationship_name: contains; entity_name: knowledge engine; entity_description: Engine built by Cognee to transform raw data into a persistent, rich, and traceable memory."}}, {"source": "b68768b0-b073-5307-b138-92e625e09f87", "target": "0a6f4624-d50e-5989-ba18-ddab839f5554", "relation": "contains", "weight": null, "all_weights": {}, "relationship_type": "contains", "edge_info": {"source_node_id": "b68768b0-b073-5307-b138-92e625e09f87", "target_node_id": "0a6f4624-d50e-5989-ba18-ddab839f5554", "relationship_name": "contains", "updated_at": "2026-03-18 12:19:57", "relationship_type": "contains", "edge_text": "relationship_name: contains; entity_name: raw data; entity_description: Input data (examples include unstructured documents and relational databases) processed by the knowledge engine."}}, {"source": "b68768b0-b073-5307-b138-92e625e09f87", "target": "f89d185b-5df9-5fc6-84a7-35931b380405", "relation": "contains", "weight": null, "all_weights": {}, "relationship_type": "contains", "edge_info": {"source_node_id": "b68768b0-b073-5307-b138-92e625e09f87", "target_node_id": "f89d185b-5df9-5fc6-84a7-35931b380405", "relationship_name": "contains", "updated_at": "2026-03-18 12:19:57", "relationship_type": "contains", "edge_text": "relationship_name: contains; entity_name: unstructured documents; entity_description: Example of raw data processed by Cognee (unstructured documents)."}}, {"source": "b68768b0-b073-5307-b138-92e625e09f87", "target": "9d84ec4f-0968-52d0-bd6d-2a4c1b07490d", "relation": "contains", "weight": null, "all_weights": {}, "relationship_type": "contains", "edge_info": {"source_node_id": "b68768b0-b073-5307-b138-92e625e09f87", "target_node_id": "9d84ec4f-0968-52d0-bd6d-2a4c1b07490d", "relationship_name": "contains", "updated_at": "2026-03-18 12:19:57", "relationship_type": "contains", "edge_text": "relationship_name: contains; entity_name: relational databases; entity_description: Example of raw data processed by Cognee (relational databases)."}}, {"source": "b68768b0-b073-5307-b138-92e625e09f87", "target": "dce5dd84-ed4d-5666-8908-c4c523b804c8", "relation": "contains", "weight": null, "all_weights": {}, "relationship_type": "contains", "edge_info": {"source_node_id": "b68768b0-b073-5307-b138-92e625e09f87", "target_node_id": "dce5dd84-ed4d-5666-8908-c4c523b804c8", "relationship_name": "contains", "updated_at": "2026-03-18 12:19:57", "relationship_type": "contains", "edge_text": "relationship_name: contains; entity_name: persistent, rich, and traceable memory; entity_description: The persistent, rich, and traceable memory produced by Cognee's knowledge engine."}}, {"source": "b68768b0-b073-5307-b138-92e625e09f87", "target": "d9548bb8-6a7d-50c2-8c88-4412ea76b0b7", "relation": "contains", "weight": null, "all_weights": {}, "relationship_type": "contains", "edge_info": {"source_node_id": "b68768b0-b073-5307-b138-92e625e09f87", "target_node_id": "d9548bb8-6a7d-50c2-8c88-4412ea76b0b7", "relationship_name": "contains", "updated_at": "2026-03-18 12:19:57", "relationship_type": "contains", "edge_text": "relationship_name: contains; entity_name: searchable by meaning; entity_description: Characteristic indicating the memory can be searched by semantic meaning."}}, {"source": "b68768b0-b073-5307-b138-92e625e09f87", "target": "797d0cee-f7dd-50cc-a2ac-5fd900797e9a", "relation": "contains", "weight": null, "all_weights": {}, "relationship_type": "contains", "edge_info": {"source_node_id": "b68768b0-b073-5307-b138-92e625e09f87", "target_node_id": "797d0cee-f7dd-50cc-a2ac-5fd900797e9a", "relationship_name": "contains", "updated_at": "2026-03-18 12:19:57", "relationship_type": "contains", "edge_text": "relationship_name: contains; entity_name: searchable by relationships; entity_description: Characteristic indicating the memory can be searched by relationships between items."}}, {"source": "b68768b0-b073-5307-b138-92e625e09f87", "target": "835749c8-bbaf-503f-8587-cc44589473c9", "relation": "contains", "weight": null, "all_weights": {}, "relationship_type": "contains", "edge_info": {"source_node_id": "b68768b0-b073-5307-b138-92e625e09f87", "target_node_id": "835749c8-bbaf-503f-8587-cc44589473c9", "relationship_name": "contains", "updated_at": "2026-03-18 12:19:57", "relationship_type": "contains", "edge_text": "relationship_name: contains; entity_name: open-source; entity_description: Indicates the software is open-source."}}, {"source": "2d09f34b-aee1-5d32-a2f9-23eb7ed48b24", "target": "2d66edc2-1e14-55ab-8304-680b514a597a", "relation": "is_a", "weight": null, "all_weights": {}, "relationship_type": null, "edge_info": {"source_node_id": "2d09f34b-aee1-5d32-a2f9-23eb7ed48b24", "target_node_id": "2d66edc2-1e14-55ab-8304-680b514a597a", "relationship_name": "is_a", "updated_at": "2026-03-18 12:19:57"}}, {"source": "2d09f34b-aee1-5d32-a2f9-23eb7ed48b24", "target": "835749c8-bbaf-503f-8587-cc44589473c9", "relation": "is_open_source", "weight": null, "all_weights": {}, "relationship_type": null, "edge_info": {"relationship_name": "is_open_source", "source_node_id": "2d09f34b-aee1-5d32-a2f9-23eb7ed48b24", "target_node_id": "835749c8-bbaf-503f-8587-cc44589473c9", "ontology_valid": false}}, {"source": "2d09f34b-aee1-5d32-a2f9-23eb7ed48b24", "target": "d8b992b3-ebdc-52a4-9913-9e1aea9a47f8", "relation": "builds_knowledge_engine", "weight": null, "all_weights": {}, "relationship_type": null, "edge_info": {"relationship_name": "builds_knowledge_engine", "source_node_id": "2d09f34b-aee1-5d32-a2f9-23eb7ed48b24", "target_node_id": "d8b992b3-ebdc-52a4-9913-9e1aea9a47f8", "ontology_valid": false}}, {"source": "2d09f34b-aee1-5d32-a2f9-23eb7ed48b24", "target": "968213f1-6ddc-5155-89d4-6df7c144a4a1", "relation": "built_for_agents", "weight": null, "all_weights": {}, "relationship_type": null, "edge_info": {"relationship_name": "built_for_agents", "source_node_id": "2d09f34b-aee1-5d32-a2f9-23eb7ed48b24", "target_node_id": "968213f1-6ddc-5155-89d4-6df7c144a4a1", "ontology_valid": false}}, {"source": "968213f1-6ddc-5155-89d4-6df7c144a4a1", "target": "5f6d6fc0-e6aa-5365-a4a0-98d6fa3af190", "relation": "is_a", "weight": null, "all_weights": {}, "relationship_type": null, "edge_info": {"source_node_id": "968213f1-6ddc-5155-89d4-6df7c144a4a1", "target_node_id": "5f6d6fc0-e6aa-5365-a4a0-98d6fa3af190", "relationship_name": "is_a", "updated_at": "2026-03-18 12:19:57"}}, {"source": "d8b992b3-ebdc-52a4-9913-9e1aea9a47f8", "target": "dd9713b7-dc20-5101-aad0-1c4216811147", "relation": "is_a", "weight": null, "all_weights": {}, "relationship_type": null, "edge_info": {"source_node_id": "d8b992b3-ebdc-52a4-9913-9e1aea9a47f8", "target_node_id": "dd9713b7-dc20-5101-aad0-1c4216811147", "relationship_name": "is_a", "updated_at": "2026-03-18 12:19:57"}}, {"source": "d8b992b3-ebdc-52a4-9913-9e1aea9a47f8", "target": "0a6f4624-d50e-5989-ba18-ddab839f5554", "relation": "transforms_raw_data", "weight": null, "all_weights": {}, "relationship_type": null, "edge_info": {"relationship_name": "transforms_raw_data", "source_node_id": "d8b992b3-ebdc-52a4-9913-9e1aea9a47f8", "target_node_id": "0a6f4624-d50e-5989-ba18-ddab839f5554", "ontology_valid": false}}, {"source": "d8b992b3-ebdc-52a4-9913-9e1aea9a47f8", "target": "dce5dd84-ed4d-5666-8908-c4c523b804c8", "relation": "produces_memory", "weight": null, "all_weights": {}, "relationship_type": null, "edge_info": {"relationship_name": "produces_memory", "source_node_id": "d8b992b3-ebdc-52a4-9913-9e1aea9a47f8", "target_node_id": "dce5dd84-ed4d-5666-8908-c4c523b804c8", "ontology_valid": false}}, {"source": "0a6f4624-d50e-5989-ba18-ddab839f5554", "target": "4ed5a0c7-2efb-52d1-9734-06a8ba225c94", "relation": "is_a", "weight": null, "all_weights": {}, "relationship_type": null, "edge_info": {"source_node_id": "0a6f4624-d50e-5989-ba18-ddab839f5554", "target_node_id": "4ed5a0c7-2efb-52d1-9734-06a8ba225c94", "relationship_name": "is_a", "updated_at": "2026-03-18 12:19:57"}}, {"source": "0a6f4624-d50e-5989-ba18-ddab839f5554", "target": "f89d185b-5df9-5fc6-84a7-35931b380405", "relation": "includes_data_type", "weight": null, "all_weights": {}, "relationship_type": null, "edge_info": {"relationship_name": "includes_data_type", "source_node_id": "0a6f4624-d50e-5989-ba18-ddab839f5554", "target_node_id": "f89d185b-5df9-5fc6-84a7-35931b380405", "ontology_valid": false}}, {"source": "0a6f4624-d50e-5989-ba18-ddab839f5554", "target": "9d84ec4f-0968-52d0-bd6d-2a4c1b07490d", "relation": "includes_data_type", "weight": null, "all_weights": {}, "relationship_type": null, "edge_info": {"relationship_name": "includes_data_type", "source_node_id": "0a6f4624-d50e-5989-ba18-ddab839f5554", "target_node_id": "9d84ec4f-0968-52d0-bd6d-2a4c1b07490d", "ontology_valid": false}}, {"source": "f89d185b-5df9-5fc6-84a7-35931b380405", "target": "7391ab9a-d827-5471-9b04-8cfd1994f783", "relation": "is_a", "weight": null, "all_weights": {}, "relationship_type": null, "edge_info": {"source_node_id": "f89d185b-5df9-5fc6-84a7-35931b380405", "target_node_id": "7391ab9a-d827-5471-9b04-8cfd1994f783", "relationship_name": "is_a", "updated_at": "2026-03-18 12:19:57"}}, {"source": "9d84ec4f-0968-52d0-bd6d-2a4c1b07490d", "target": "90cb1fed-d3a3-51c4-bf2d-467bce3d40a3", "relation": "is_a", "weight": null, "all_weights": {}, "relationship_type": null, "edge_info": {"source_node_id": "9d84ec4f-0968-52d0-bd6d-2a4c1b07490d", "target_node_id": "90cb1fed-d3a3-51c4-bf2d-467bce3d40a3", "relationship_name": "is_a", "updated_at": "2026-03-18 12:19:57"}}, {"source": "dce5dd84-ed4d-5666-8908-c4c523b804c8", "target": "d7624ee3-0f87-5c82-a4a6-562baf3f835b", "relation": "is_a", "weight": null, "all_weights": {}, "relationship_type": null, "edge_info": {"source_node_id": "dce5dd84-ed4d-5666-8908-c4c523b804c8", "target_node_id": "d7624ee3-0f87-5c82-a4a6-562baf3f835b", "relationship_name": "is_a", "updated_at": "2026-03-18 12:19:57"}}, {"source": "dce5dd84-ed4d-5666-8908-c4c523b804c8", "target": "d9548bb8-6a7d-50c2-8c88-4412ea76b0b7", "relation": "is_searchable_by_meaning", "weight": null, "all_weights": {}, "relationship_type": null, "edge_info": {"relationship_name": "is_searchable_by_meaning", "source_node_id": "dce5dd84-ed4d-5666-8908-c4c523b804c8", "target_node_id": "d9548bb8-6a7d-50c2-8c88-4412ea76b0b7", "ontology_valid": false}}, {"source": "dce5dd84-ed4d-5666-8908-c4c523b804c8", "target": "797d0cee-f7dd-50cc-a2ac-5fd900797e9a", "relation": "is_searchable_by_relationships", "weight": null, "all_weights": {}, "relationship_type": null, "edge_info": {"relationship_name": "is_searchable_by_relationships", "source_node_id": "dce5dd84-ed4d-5666-8908-c4c523b804c8", "target_node_id": "797d0cee-f7dd-50cc-a2ac-5fd900797e9a", "ontology_valid": false}}, {"source": "d9548bb8-6a7d-50c2-8c88-4412ea76b0b7", "target": "dd9713b7-dc20-5101-aad0-1c4216811147", "relation": "is_a", "weight": null, "all_weights": {}, "relationship_type": null, "edge_info": {"source_node_id": "d9548bb8-6a7d-50c2-8c88-4412ea76b0b7", "target_node_id": "dd9713b7-dc20-5101-aad0-1c4216811147", "relationship_name": "is_a", "updated_at": "2026-03-18 12:19:57"}}, {"source": "797d0cee-f7dd-50cc-a2ac-5fd900797e9a", "target": "dd9713b7-dc20-5101-aad0-1c4216811147", "relation": "is_a", "weight": null, "all_weights": {}, "relationship_type": null, "edge_info": {"source_node_id": "797d0cee-f7dd-50cc-a2ac-5fd900797e9a", "target_node_id": "dd9713b7-dc20-5101-aad0-1c4216811147", "relationship_name": "is_a", "updated_at": "2026-03-18 12:19:57"}}, {"source": "835749c8-bbaf-503f-8587-cc44589473c9", "target": "dd9713b7-dc20-5101-aad0-1c4216811147", "relation": "is_a", "weight": null, "all_weights": {}, "relationship_type": null, "edge_info": {"source_node_id": "835749c8-bbaf-503f-8587-cc44589473c9", "target_node_id": "dd9713b7-dc20-5101-aad0-1c4216811147", "relationship_name": "is_a", "updated_at": "2026-03-18 12:19:57"}}, {"source": "8a198b04-631a-5fc3-8bb9-87034f79b1cc", "target": "84bba00b-b72d-5340-a260-e47635da331b", "relation": "is_part_of", "weight": null, "all_weights": {}, "relationship_type": null, "edge_info": {"source_node_id": "8a198b04-631a-5fc3-8bb9-87034f79b1cc", "target_node_id": "84bba00b-b72d-5340-a260-e47635da331b", "relationship_name": "is_part_of", "updated_at": "2026-03-18 12:19:57"}}, {"source": "8a198b04-631a-5fc3-8bb9-87034f79b1cc", "target": "df20c394-b710-5b2c-9256-ce5f5fe36397", "relation": "contains", "weight": null, "all_weights": {}, "relationship_type": "contains", "edge_info": {"source_node_id": "8a198b04-631a-5fc3-8bb9-87034f79b1cc", "target_node_id": "df20c394-b710-5b2c-9256-ce5f5fe36397", "relationship_name": "contains", "updated_at": "2026-03-18 12:19:57", "relationship_type": "contains", "edge_text": "relationship_name: contains; entity_name: knowledge graphs; entity_description: Data structures that represent information using nodes and edges to capture entities and relationships."}}, {"source": "8a198b04-631a-5fc3-8bb9-87034f79b1cc", "target": "bd3f3aa5-5df4-54a0-af4e-78aa5a54e8f3", "relation": "contains", "weight": null, "all_weights": {}, "relationship_type": "contains", "edge_info": {"source_node_id": "8a198b04-631a-5fc3-8bb9-87034f79b1cc", "target_node_id": "bd3f3aa5-5df4-54a0-af4e-78aa5a54e8f3", "relationship_name": "contains", "updated_at": "2026-03-18 12:19:57", "relationship_type": "contains", "edge_text": "relationship_name: contains; entity_name: nodes; entity_description: Elements in a knowledge graph that represent entities or concepts."}}, {"source": "8a198b04-631a-5fc3-8bb9-87034f79b1cc", "target": "e4f1a343-1dd6-5191-ab16-4901f6eccf51", "relation": "contains", "weight": null, "all_weights": {}, "relationship_type": "contains", "edge_info": {"source_node_id": "8a198b04-631a-5fc3-8bb9-87034f79b1cc", "target_node_id": "e4f1a343-1dd6-5191-ab16-4901f6eccf51", "relationship_name": "contains", "updated_at": "2026-03-18 12:19:57", "relationship_type": "contains", "edge_text": "relationship_name: contains; entity_name: edges; entity_description: Connections in a knowledge graph that represent relationships between nodes."}}, {"source": "8a198b04-631a-5fc3-8bb9-87034f79b1cc", "target": "e4e6f950-4621-53ae-8af0-8920799b4853", "relation": "contains", "weight": null, "all_weights": {}, "relationship_type": "contains", "edge_info": {"source_node_id": "8a198b04-631a-5fc3-8bb9-87034f79b1cc", "target_node_id": "e4e6f950-4621-53ae-8af0-8920799b4853", "relationship_name": "contains", "updated_at": "2026-03-18 12:19:57", "relationship_type": "contains", "edge_text": "relationship_name: contains; entity_name: entities; entity_description: Real-world things or concepts represented by nodes in a knowledge graph."}}, {"source": "8a198b04-631a-5fc3-8bb9-87034f79b1cc", "target": "f42a6141-42ac-5973-8b4d-8a1e6f944a12", "relation": "contains", "weight": null, "all_weights": {}, "relationship_type": "contains", "edge_info": {"source_node_id": "8a198b04-631a-5fc3-8bb9-87034f79b1cc", "target_node_id": "f42a6141-42ac-5973-8b4d-8a1e6f944a12", "relationship_name": "contains", "updated_at": "2026-03-18 12:19:57", "relationship_type": "contains", "edge_text": "relationship_name: contains; entity_name: relationships; entity_description: Semantic links between entities represented by edges in a knowledge graph."}}, {"source": "8a198b04-631a-5fc3-8bb9-87034f79b1cc", "target": "9d6360d4-504a-5f7f-b618-c2ea457a1a4d", "relation": "contains", "weight": null, "all_weights": {}, "relationship_type": "contains", "edge_info": {"source_node_id": "8a198b04-631a-5fc3-8bb9-87034f79b1cc", "target_node_id": "9d6360d4-504a-5f7f-b618-c2ea457a1a4d", "relationship_name": "contains", "updated_at": "2026-03-18 12:19:57", "relationship_type": "contains", "edge_text": "relationship_name: contains; entity_name: semantic search; entity_description: Search approach that leverages meaning and connections rather than simple keyword matching."}}, {"source": "8a198b04-631a-5fc3-8bb9-87034f79b1cc", "target": "ba802be9-50b2-58a6-a46d-031e30a780a8", "relation": "contains", "weight": null, "all_weights": {}, "relationship_type": "contains", "edge_info": {"source_node_id": "8a198b04-631a-5fc3-8bb9-87034f79b1cc", "target_node_id": "ba802be9-50b2-58a6-a46d-031e30a780a8", "relationship_name": "contains", "updated_at": "2026-03-18 12:19:57", "relationship_type": "contains", "edge_text": "relationship_name: contains; entity_name: reasoning; entity_description: Inference and logical processes enabled by structured knowledge in a graph."}}, {"source": "8a198b04-631a-5fc3-8bb9-87034f79b1cc", "target": "e0c5c99c-74a8-5d09-8e8a-05cb2e5bcf6b", "relation": "contains", "weight": null, "all_weights": {}, "relationship_type": "contains", "edge_info": {"source_node_id": "8a198b04-631a-5fc3-8bb9-87034f79b1cc", "target_node_id": "e0c5c99c-74a8-5d09-8e8a-05cb2e5bcf6b", "relationship_name": "contains", "updated_at": "2026-03-18 12:19:57", "relationship_type": "contains", "edge_text": "relationship_name: contains; entity_name: discovery of hidden connections; entity_description: Finding non-obvious links between items using the structure and semantics of a knowledge graph."}}, {"source": "8a198b04-631a-5fc3-8bb9-87034f79b1cc", "target": "838f4a46-e459-58e4-a40b-ab30cd21da5c", "relation": "contains", "weight": null, "all_weights": {}, "relationship_type": "contains", "edge_info": {"source_node_id": "8a198b04-631a-5fc3-8bb9-87034f79b1cc", "target_node_id": "838f4a46-e459-58e4-a40b-ab30cd21da5c", "relationship_name": "contains", "updated_at": "2026-03-18 12:19:57", "relationship_type": "contains", "edge_text": "relationship_name: contains; entity_name: large document collections; entity_description: Extensive sets of documents across which knowledge graphs can reveal relationships and insights."}}, {"source": "bd3f3aa5-5df4-54a0-af4e-78aa5a54e8f3", "target": "dd9713b7-dc20-5101-aad0-1c4216811147", "relation": "is_a", "weight": null, "all_weights": {}, "relationship_type": null, "edge_info": {"source_node_id": "bd3f3aa5-5df4-54a0-af4e-78aa5a54e8f3", "target_node_id": "dd9713b7-dc20-5101-aad0-1c4216811147", "relationship_name": "is_a", "updated_at": "2026-03-18 12:19:57"}}, {"source": "bd3f3aa5-5df4-54a0-af4e-78aa5a54e8f3", "target": "e4e6f950-4621-53ae-8af0-8920799b4853", "relation": "represent_entities", "weight": null, "all_weights": {}, "relationship_type": null, "edge_info": {"relationship_name": "represent_entities", "source_node_id": "bd3f3aa5-5df4-54a0-af4e-78aa5a54e8f3", "target_node_id": "e4e6f950-4621-53ae-8af0-8920799b4853", "ontology_valid": false}}, {"source": "e4f1a343-1dd6-5191-ab16-4901f6eccf51", "target": "dd9713b7-dc20-5101-aad0-1c4216811147", "relation": "is_a", "weight": null, "all_weights": {}, "relationship_type": null, "edge_info": {"source_node_id": "e4f1a343-1dd6-5191-ab16-4901f6eccf51", "target_node_id": "dd9713b7-dc20-5101-aad0-1c4216811147", "relationship_name": "is_a", "updated_at": "2026-03-18 12:19:57"}}, {"source": "e4f1a343-1dd6-5191-ab16-4901f6eccf51", "target": "f42a6141-42ac-5973-8b4d-8a1e6f944a12", "relation": "represent_relationships", "weight": null, "all_weights": {}, "relationship_type": null, "edge_info": {"relationship_name": "represent_relationships", "source_node_id": "e4f1a343-1dd6-5191-ab16-4901f6eccf51", "target_node_id": "f42a6141-42ac-5973-8b4d-8a1e6f944a12", "ontology_valid": false}}, {"source": "e4e6f950-4621-53ae-8af0-8920799b4853", "target": "dd9713b7-dc20-5101-aad0-1c4216811147", "relation": "is_a", "weight": null, "all_weights": {}, "relationship_type": null, "edge_info": {"source_node_id": "e4e6f950-4621-53ae-8af0-8920799b4853", "target_node_id": "dd9713b7-dc20-5101-aad0-1c4216811147", "relationship_name": "is_a", "updated_at": "2026-03-18 12:19:57"}}, {"source": "f42a6141-42ac-5973-8b4d-8a1e6f944a12", "target": "dd9713b7-dc20-5101-aad0-1c4216811147", "relation": "is_a", "weight": null, "all_weights": {}, "relationship_type": null, "edge_info": {"source_node_id": "f42a6141-42ac-5973-8b4d-8a1e6f944a12", "target_node_id": "dd9713b7-dc20-5101-aad0-1c4216811147", "relationship_name": "is_a", "updated_at": "2026-03-18 12:19:57"}}, {"source": "9d6360d4-504a-5f7f-b618-c2ea457a1a4d", "target": "dd9713b7-dc20-5101-aad0-1c4216811147", "relation": "is_a", "weight": null, "all_weights": {}, "relationship_type": null, "edge_info": {"source_node_id": "9d6360d4-504a-5f7f-b618-c2ea457a1a4d", "target_node_id": "dd9713b7-dc20-5101-aad0-1c4216811147", "relationship_name": "is_a", "updated_at": "2026-03-18 12:19:57"}}, {"source": "ba802be9-50b2-58a6-a46d-031e30a780a8", "target": "dd9713b7-dc20-5101-aad0-1c4216811147", "relation": "is_a", "weight": null, "all_weights": {}, "relationship_type": null, "edge_info": {"source_node_id": "ba802be9-50b2-58a6-a46d-031e30a780a8", "target_node_id": "dd9713b7-dc20-5101-aad0-1c4216811147", "relationship_name": "is_a", "updated_at": "2026-03-18 12:19:57"}}, {"source": "e0c5c99c-74a8-5d09-8e8a-05cb2e5bcf6b", "target": "dd9713b7-dc20-5101-aad0-1c4216811147", "relation": "is_a", "weight": null, "all_weights": {}, "relationship_type": null, "edge_info": {"source_node_id": "e0c5c99c-74a8-5d09-8e8a-05cb2e5bcf6b", "target_node_id": "dd9713b7-dc20-5101-aad0-1c4216811147", "relationship_name": "is_a", "updated_at": "2026-03-18 12:19:57"}}, {"source": "e0c5c99c-74a8-5d09-8e8a-05cb2e5bcf6b", "target": "838f4a46-e459-58e4-a40b-ab30cd21da5c", "relation": "across_collections", "weight": null, "all_weights": {}, "relationship_type": null, "edge_info": {"relationship_name": "across_collections", "source_node_id": "e0c5c99c-74a8-5d09-8e8a-05cb2e5bcf6b", "target_node_id": "838f4a46-e459-58e4-a40b-ab30cd21da5c", "ontology_valid": false}}, {"source": "838f4a46-e459-58e4-a40b-ab30cd21da5c", "target": "dd9713b7-dc20-5101-aad0-1c4216811147", "relation": "is_a", "weight": null, "all_weights": {}, "relationship_type": null, "edge_info": {"source_node_id": "838f4a46-e459-58e4-a40b-ab30cd21da5c", "target_node_id": "dd9713b7-dc20-5101-aad0-1c4216811147", "relationship_name": "is_a", "updated_at": "2026-03-18 12:19:57"}}, {"source": "4dfc885b-eac1-5dd6-9276-d129394d7c6d", "target": "b68768b0-b073-5307-b138-92e625e09f87", "relation": "made_from", "weight": null, "all_weights": {}, "relationship_type": null, "edge_info": {"source_node_id": "4dfc885b-eac1-5dd6-9276-d129394d7c6d", "target_node_id": "b68768b0-b073-5307-b138-92e625e09f87", "relationship_name": "made_from", "updated_at": "2026-03-18 12:19:57"}}, {"source": "a778650e-2acb-5f70-8bea-ce50fd5f2d68", "target": "8a198b04-631a-5fc3-8bb9-87034f79b1cc", "relation": "made_from", "weight": null, "all_weights": {}, "relationship_type": null, "edge_info": {"source_node_id": "a778650e-2acb-5f70-8bea-ce50fd5f2d68", "target_node_id": "8a198b04-631a-5fc3-8bb9-87034f79b1cc", "relationship_name": "made_from", "updated_at": "2026-03-18 12:19:57"}}, {"source": "ee59fe9f-e651-5cd1-bb28-14c4155deaad", "target": "8d133f76-c22c-5758-bdc6-73bf5da4576a", "relation": "made_from", "weight": null, "all_weights": {}, "relationship_type": null, "edge_info": {"source_node_id": "ee59fe9f-e651-5cd1-bb28-14c4155deaad", "target_node_id": "8d133f76-c22c-5758-bdc6-73bf5da4576a", "relationship_name": "made_from", "updated_at": "2026-03-18 12:19:58"}}]; +var nodes = [{"name": "", "type": "DocumentChunk", "ontology_valid": false, "version": 1, "topological_rank": 0, "metadata": {"index_fields": ["text"]}, "belongs_to_set": null, "source_pipeline": "cognify_pipeline", "source_task": "extract_chunks_from_documents", "source_node_set": null, "source_user": "default_user@example.com", "text": "Knowledge graphs represent information as nodes (entities) and edges (relationships). They enable semantic search, reasoning, and discovery of hidden connections across large document collections.", "chunk_size": 56, "chunk_index": 0, "cut_type": "sentence_end", "id": "601f27c0-4582-5a13-89d3-64a8c0f15cc1", "color": "#0DFF00"}, {"name": "knowledge graphs", "type": "Entity", "ontology_valid": false, "version": 1, "topological_rank": 0, "metadata": {"index_fields": ["name"]}, "belongs_to_set": null, "source_pipeline": "cognify_pipeline", "source_task": "extract_graph_from_data", "source_node_set": null, "source_user": "default_user@example.com", "description": "Knowledge graph technologies used to power the search platform.", "id": "df20c394-b710-5b2c-9256-ce5f5fe36397", "color": "#6510F4"}, {"name": "concept", "type": "EntityType", "ontology_valid": false, "version": 1, "topological_rank": 0, "metadata": {"index_fields": ["name"]}, "belongs_to_set": null, "source_pipeline": "cognify_pipeline", "source_task": "extract_graph_from_data", "source_node_set": null, "source_user": "default_user@example.com", "description": "concept", "id": "dd9713b7-dc20-5101-aad0-1c4216811147", "color": "#A550FF"}, {"name": "nodes", "type": "Entity", "ontology_valid": false, "version": 1, "topological_rank": 0, "metadata": {"index_fields": ["name"]}, "belongs_to_set": null, "source_pipeline": "cognify_pipeline", "source_task": "extract_graph_from_data", "source_node_set": null, "source_user": "default_user@example.com", "description": "Elements in a knowledge graph that represent entities.", "id": "bd3f3aa5-5df4-54a0-af4e-78aa5a54e8f3", "color": "#6510F4"}, {"name": "edges", "type": "Entity", "ontology_valid": false, "version": 1, "topological_rank": 0, "metadata": {"index_fields": ["name"]}, "belongs_to_set": null, "source_pipeline": "cognify_pipeline", "source_task": "extract_graph_from_data", "source_node_set": null, "source_user": "default_user@example.com", "description": "Relationships that connect nodes in a knowledge graph.", "id": "e4f1a343-1dd6-5191-ab16-4901f6eccf51", "color": "#6510F4"}, {"name": "information", "type": "Entity", "ontology_valid": false, "version": 1, "topological_rank": 0, "metadata": {"index_fields": ["name"]}, "belongs_to_set": null, "source_pipeline": "cognify_pipeline", "source_task": "extract_graph_from_data", "source_node_set": null, "source_user": "default_user@example.com", "description": "Data or knowledge represented within a knowledge graph.", "id": "3fb76a7a-fbf5-57ce-afb0-dcabb13cddeb", "color": "#6510F4"}, {"name": "semantic search", "type": "Entity", "ontology_valid": false, "version": 1, "topological_rank": 0, "metadata": {"index_fields": ["name"]}, "belongs_to_set": null, "source_pipeline": "cognify_pipeline", "source_task": "extract_graph_from_data", "source_node_set": null, "source_user": "default_user@example.com", "description": "Search that uses meaning and relationships rather than simple keyword matching.", "id": "9d6360d4-504a-5f7f-b618-c2ea457a1a4d", "color": "#6510F4"}, {"name": "reasoning", "type": "Entity", "ontology_valid": false, "version": 1, "topological_rank": 0, "metadata": {"index_fields": ["name"]}, "belongs_to_set": null, "source_pipeline": "cognify_pipeline", "source_task": "extract_graph_from_data", "source_node_set": null, "source_user": "default_user@example.com", "description": "Inference and logical processes enabled by structured knowledge representations.", "id": "ba802be9-50b2-58a6-a46d-031e30a780a8", "color": "#6510F4"}, {"name": "discovery of hidden connections", "type": "Entity", "ontology_valid": false, "version": 1, "topological_rank": 0, "metadata": {"index_fields": ["name"]}, "belongs_to_set": null, "source_pipeline": "cognify_pipeline", "source_task": "extract_graph_from_data", "source_node_set": null, "source_user": "default_user@example.com", "description": "Identification of non-obvious relationships across data using a knowledge graph.", "id": "e0c5c99c-74a8-5d09-8e8a-05cb2e5bcf6b", "color": "#6510F4"}, {"name": "large document collections", "type": "Entity", "ontology_valid": false, "version": 1, "topological_rank": 0, "metadata": {"index_fields": ["name"]}, "belongs_to_set": null, "source_pipeline": "cognify_pipeline", "source_task": "extract_graph_from_data", "source_node_set": null, "source_user": "default_user@example.com", "description": "Extensive corpora of documents across which knowledge graphs can reveal connections.", "id": "838f4a46-e459-58e4-a40b-ab30cd21da5c", "color": "#6510F4"}, {"name": "text_41edf18cf1a9cb76a5e2eb8429cb9a29", "type": "TextDocument", "ontology_valid": false, "version": 1, "topological_rank": 0, "metadata": {"index_fields": ["name"]}, "belongs_to_set": null, "source_pipeline": "cognify_pipeline", "source_task": "classify_documents", "source_node_set": null, "source_user": "default_user@example.com", "raw_data_location": "file:///Users/handekafkas/Documents/local-code/haystack-core-integrations/integrations/cognee/.venv/lib/python3.13/site-packages/cognee/.data_storage/text_41edf18cf1a9cb76a5e2eb8429cb9a29.txt", "external_metadata": "{}", "mime_type": "text/plain", "id": "86c075e6-5852-5d80-8327-4e9691a71f62", "color": "#DBD8D8"}, {"name": "", "type": "DocumentChunk", "ontology_valid": false, "version": 1, "topological_rank": 0, "metadata": {"index_fields": ["text"]}, "belongs_to_set": null, "source_pipeline": "cognify_pipeline", "source_task": "extract_chunks_from_documents", "source_node_set": null, "source_user": "default_user@example.com", "text": "Cognee is an open-source memory for AI agents. Cognee builts a knowledge enginethat transforms raw data (e.g., unstructured documents, relational databases, etc.)into a persistent, rich, and traceable memory that is searchable by meaning and relationships.", "chunk_size": 95, "chunk_index": 0, "cut_type": "sentence_end", "id": "bc815248-f743-5faa-b176-a216cf9e908e", "color": "#0DFF00"}, {"name": "cognee", "type": "Entity", "ontology_valid": false, "version": 1, "topological_rank": 0, "metadata": {"index_fields": ["name"]}, "belongs_to_set": null, "source_pipeline": "cognify_pipeline", "source_task": "extract_graph_from_data", "source_node_set": null, "source_user": "default_user@example.com", "description": "Open-source memory for AI agents; builds a knowledge engine that transforms raw data into a persistent, rich, and traceable memory searchable by meaning and relationships.", "id": "2d09f34b-aee1-5d32-a2f9-23eb7ed48b24", "color": "#6510F4"}, {"name": "software", "type": "EntityType", "ontology_valid": false, "version": 1, "topological_rank": 0, "metadata": {"index_fields": ["name"]}, "belongs_to_set": null, "source_pipeline": "cognify_pipeline", "source_task": "extract_graph_from_data", "source_node_set": null, "source_user": "default_user@example.com", "description": "software", "id": "2d66edc2-1e14-55ab-8304-680b514a597a", "color": "#A550FF"}, {"name": "ai agents", "type": "Entity", "ontology_valid": false, "version": 1, "topological_rank": 0, "metadata": {"index_fields": ["name"]}, "belongs_to_set": null, "source_pipeline": "cognify_pipeline", "source_task": "extract_graph_from_data", "source_node_set": null, "source_user": "default_user@example.com", "description": "Autonomous or semi-autonomous software agents that use memory systems.", "id": "968213f1-6ddc-5155-89d4-6df7c144a4a1", "color": "#6510F4"}, {"name": "agent", "type": "EntityType", "ontology_valid": false, "version": 1, "topological_rank": 0, "metadata": {"index_fields": ["name"]}, "belongs_to_set": null, "source_pipeline": "cognify_pipeline", "source_task": "extract_graph_from_data", "source_node_set": null, "source_user": "default_user@example.com", "description": "agent", "id": "5f6d6fc0-e6aa-5365-a4a0-98d6fa3af190", "color": "#A550FF"}, {"name": "knowledge engine", "type": "Entity", "ontology_valid": false, "version": 1, "topological_rank": 0, "metadata": {"index_fields": ["name"]}, "belongs_to_set": null, "source_pipeline": "cognify_pipeline", "source_task": "extract_graph_from_data", "source_node_set": null, "source_user": "default_user@example.com", "description": "A system that processes and structures raw data into persistent, rich, and traceable memory.", "id": "d8b992b3-ebdc-52a4-9913-9e1aea9a47f8", "color": "#6510F4"}, {"name": "raw data", "type": "Entity", "ontology_valid": false, "version": 1, "topological_rank": 0, "metadata": {"index_fields": ["name"]}, "belongs_to_set": null, "source_pipeline": "cognify_pipeline", "source_task": "extract_graph_from_data", "source_node_set": null, "source_user": "default_user@example.com", "description": "Unprocessed input such as unstructured documents, relational databases, and other data sources.", "id": "0a6f4624-d50e-5989-ba18-ddab839f5554", "color": "#6510F4"}, {"name": "data", "type": "EntityType", "ontology_valid": false, "version": 1, "topological_rank": 0, "metadata": {"index_fields": ["name"]}, "belongs_to_set": null, "source_pipeline": "cognify_pipeline", "source_task": "extract_graph_from_data", "source_node_set": null, "source_user": "default_user@example.com", "description": "data", "id": "4ed5a0c7-2efb-52d1-9734-06a8ba225c94", "color": "#A550FF"}, {"name": "unstructured documents", "type": "Entity", "ontology_valid": false, "version": 1, "topological_rank": 0, "metadata": {"index_fields": ["name"]}, "belongs_to_set": null, "source_pipeline": "cognify_pipeline", "source_task": "extract_graph_from_data", "source_node_set": null, "source_user": "default_user@example.com", "description": "Example raw data format (e.g., text files, reports, articles) mentioned as an input to the knowledge engine.", "id": "f89d185b-5df9-5fc6-84a7-35931b380405", "color": "#6510F4"}, {"name": "relational databases", "type": "Entity", "ontology_valid": false, "version": 1, "topological_rank": 0, "metadata": {"index_fields": ["name"]}, "belongs_to_set": null, "source_pipeline": "cognify_pipeline", "source_task": "extract_graph_from_data", "source_node_set": null, "source_user": "default_user@example.com", "description": "Example raw data format (structured tables) mentioned as an input to the knowledge engine.", "id": "9d84ec4f-0968-52d0-bd6d-2a4c1b07490d", "color": "#6510F4"}, {"name": "persistent rich traceable memory", "type": "Entity", "ontology_valid": false, "version": 1, "topological_rank": 0, "metadata": {"index_fields": ["name"]}, "belongs_to_set": null, "source_pipeline": "cognify_pipeline", "source_task": "extract_graph_from_data", "source_node_set": null, "source_user": "default_user@example.com", "description": "Memory produced by the knowledge engine that is persistent, rich in structure and metadata, traceable, and searchable by meaning and relationships.", "id": "dce5dd84-ed4d-5666-8908-c4c523b804c8", "color": "#6510F4"}, {"name": "text_d1622b5a4ae1e31ed9d352ea3d2cbc20", "type": "TextDocument", "ontology_valid": false, "version": 1, "topological_rank": 0, "metadata": {"index_fields": ["name"]}, "belongs_to_set": null, "source_pipeline": "cognify_pipeline", "source_task": "classify_documents", "source_node_set": null, "source_user": "default_user@example.com", "raw_data_location": "file:///Users/handekafkas/Documents/local-code/haystack-core-integrations/integrations/cognee/.venv/lib/python3.13/site-packages/cognee/.data_storage/text_d1622b5a4ae1e31ed9d352ea3d2cbc20.txt", "external_metadata": "{}", "mime_type": "text/plain", "id": "0700b84c-e4eb-5462-be56-0d7d97d0009e", "color": "#DBD8D8"}, {"name": "", "type": "DocumentChunk", "ontology_valid": false, "version": 1, "topological_rank": 0, "metadata": {"index_fields": ["text"]}, "belongs_to_set": null, "source_pipeline": "cognify_pipeline", "source_task": "extract_chunks_from_documents", "source_node_set": null, "source_user": "default_user@example.com", "text": "The engineering team at Acme Corp consists of Alice (backend lead), Bob (ML engineer), and Carol (infrastructure). They are building a next-generation search platform powered by knowledge graphs and LLMs.", "chunk_size": 72, "chunk_index": 0, "cut_type": "sentence_end", "id": "c569abe9-16f1-54e0-ab9c-a4223e1088e1", "color": "#0DFF00"}, {"name": "alice", "type": "Entity", "ontology_valid": false, "version": 1, "topological_rank": 0, "metadata": {"index_fields": ["name"]}, "belongs_to_set": null, "source_pipeline": "cognify_pipeline", "source_task": "extract_graph_from_data", "source_node_set": null, "source_user": "default_user@example.com", "description": "Backend lead on Acme Corp's engineering team.", "id": "f7d8be13-2a72-5104-bd02-7a5964737a91", "color": "#6510F4"}, {"name": "person", "type": "EntityType", "ontology_valid": false, "version": 1, "topological_rank": 0, "metadata": {"index_fields": ["name"]}, "belongs_to_set": null, "source_pipeline": "cognify_pipeline", "source_task": "extract_graph_from_data", "source_node_set": null, "source_user": "default_user@example.com", "description": "person", "id": "d072ba0f-e1a9-58bf-9974-e1802adc8134", "color": "#A550FF"}, {"name": "bob", "type": "Entity", "ontology_valid": false, "version": 1, "topological_rank": 0, "metadata": {"index_fields": ["name"]}, "belongs_to_set": null, "source_pipeline": "cognify_pipeline", "source_task": "extract_graph_from_data", "source_node_set": null, "source_user": "default_user@example.com", "description": "ML engineer on Acme Corp's engineering team.", "id": "515e93c6-3782-59db-96be-ad5b8cf872a5", "color": "#6510F4"}, {"name": "carol", "type": "Entity", "ontology_valid": false, "version": 1, "topological_rank": 0, "metadata": {"index_fields": ["name"]}, "belongs_to_set": null, "source_pipeline": "cognify_pipeline", "source_task": "extract_graph_from_data", "source_node_set": null, "source_user": "default_user@example.com", "description": "Infrastructure engineer on Acme Corp's engineering team.", "id": "80370ebb-d9b5-5f12-a3fb-db3631157840", "color": "#6510F4"}, {"name": "acme corp", "type": "Entity", "ontology_valid": false, "version": 1, "topological_rank": 0, "metadata": {"index_fields": ["name"]}, "belongs_to_set": null, "source_pipeline": "cognify_pipeline", "source_task": "extract_graph_from_data", "source_node_set": null, "source_user": "default_user@example.com", "description": "Company employing the engineering team.", "id": "7f5a651e-56c1-574f-aa54-cd0a0b7dbc38", "color": "#6510F4"}, {"name": "organization", "type": "EntityType", "ontology_valid": false, "version": 1, "topological_rank": 0, "metadata": {"index_fields": ["name"]}, "belongs_to_set": null, "source_pipeline": "cognify_pipeline", "source_task": "extract_graph_from_data", "source_node_set": null, "source_user": "default_user@example.com", "description": "organization", "id": "d3d7b6b4-9b0d-52e8-9e09-a9e9cf4b5a4d", "color": "#A550FF"}, {"name": "engineering team at acme corp", "type": "Entity", "ontology_valid": false, "version": 1, "topological_rank": 0, "metadata": {"index_fields": ["name"]}, "belongs_to_set": null, "source_pipeline": "cognify_pipeline", "source_task": "extract_graph_from_data", "source_node_set": null, "source_user": "default_user@example.com", "description": "Engineering team at Acme Corp consisting of Alice, Bob, and Carol.", "id": "7fa8891b-a426-5d42-b011-6851ef945793", "color": "#6510F4"}, {"name": "team", "type": "EntityType", "ontology_valid": false, "version": 1, "topological_rank": 0, "metadata": {"index_fields": ["name"]}, "belongs_to_set": null, "source_pipeline": "cognify_pipeline", "source_task": "extract_graph_from_data", "source_node_set": null, "source_user": "default_user@example.com", "description": "team", "id": "e308d782-2a18-5ace-b0e8-236c7c3b4db4", "color": "#A550FF"}, {"name": "next-generation search platform", "type": "Entity", "ontology_valid": false, "version": 1, "topological_rank": 0, "metadata": {"index_fields": ["name"]}, "belongs_to_set": null, "source_pipeline": "cognify_pipeline", "source_task": "extract_graph_from_data", "source_node_set": null, "source_user": "default_user@example.com", "description": "Next-generation search platform being built by the engineering team.", "id": "6fdb37d4-ae27-5a1a-9f7a-03f5036247ca", "color": "#6510F4"}, {"name": "project", "type": "EntityType", "ontology_valid": false, "version": 1, "topological_rank": 0, "metadata": {"index_fields": ["name"]}, "belongs_to_set": null, "source_pipeline": "cognify_pipeline", "source_task": "extract_graph_from_data", "source_node_set": null, "source_user": "default_user@example.com", "description": "project", "id": "29c0d211-0d39-579f-bf45-c7a78394c9aa", "color": "#A550FF"}, {"name": "technology", "type": "EntityType", "ontology_valid": false, "version": 1, "topological_rank": 0, "metadata": {"index_fields": ["name"]}, "belongs_to_set": null, "source_pipeline": "cognify_pipeline", "source_task": "extract_graph_from_data", "source_node_set": null, "source_user": "default_user@example.com", "description": "technology", "id": "65c71de3-4c23-5f28-8e07-fc7428d1e0c4", "color": "#A550FF"}, {"name": "llms", "type": "Entity", "ontology_valid": false, "version": 1, "topological_rank": 0, "metadata": {"index_fields": ["name"]}, "belongs_to_set": null, "source_pipeline": "cognify_pipeline", "source_task": "extract_graph_from_data", "source_node_set": null, "source_user": "default_user@example.com", "description": "Large language models used to power the search platform.", "id": "f7dc5ef7-3d2d-50c7-9edc-475862a15d4b", "color": "#6510F4"}, {"name": "text_fe5096366b6f10a6766dc51cbac9058c", "type": "TextDocument", "ontology_valid": false, "version": 1, "topological_rank": 0, "metadata": {"index_fields": ["name"]}, "belongs_to_set": null, "source_pipeline": "cognify_pipeline", "source_task": "classify_documents", "source_node_set": null, "source_user": "default_user@example.com", "raw_data_location": "file:///Users/handekafkas/Documents/local-code/haystack-core-integrations/integrations/cognee/.venv/lib/python3.13/site-packages/cognee/.data_storage/text_fe5096366b6f10a6766dc51cbac9058c.txt", "external_metadata": "{}", "mime_type": "text/plain", "id": "7706f53e-49ac-582a-8cf4-59b9c6e64bfb", "color": "#DBD8D8"}, {"name": "", "type": "DocumentChunk", "ontology_valid": false, "version": 1, "topological_rank": 0, "metadata": {"index_fields": ["text"]}, "belongs_to_set": null, "source_pipeline": "cognify_pipeline", "source_task": "extract_chunks_from_documents", "source_node_set": null, "source_user": "default_user@example.com", "text": "Haystack is an open-source LLM framework by deepset for building production-ready RAG pipelines, agents, and search systems. It uses a component-based architecture where each step (retrieval, generation, etc.) is a composable building block.", "chunk_size": 84, "chunk_index": 0, "cut_type": "sentence_end", "id": "ee7307f2-cba9-5003-9dc0-0780c50591a6", "color": "#0DFF00"}, {"name": "haystack", "type": "Entity", "ontology_valid": false, "version": 1, "topological_rank": 0, "metadata": {"index_fields": ["name"]}, "belongs_to_set": null, "source_pipeline": "cognify_pipeline", "source_task": "extract_graph_from_data", "source_node_set": null, "source_user": "default_user@example.com", "description": "Open-source LLM framework by deepset for building production-ready RAG pipelines, agents, and search systems.", "id": "2bdd3deb-07d8-5413-a56d-1643e3ceb48b", "color": "#6510F4"}, {"name": "deepset", "type": "Entity", "ontology_valid": false, "version": 1, "topological_rank": 0, "metadata": {"index_fields": ["name"]}, "belongs_to_set": null, "source_pipeline": "cognify_pipeline", "source_task": "extract_graph_from_data", "source_node_set": null, "source_user": "default_user@example.com", "description": "Company that develops Haystack.", "id": "126df7ec-d0db-53ea-bc88-1bafd84c8646", "color": "#6510F4"}, {"name": "rag pipelines", "type": "Entity", "ontology_valid": false, "version": 1, "topological_rank": 0, "metadata": {"index_fields": ["name"]}, "belongs_to_set": null, "source_pipeline": "cognify_pipeline", "source_task": "extract_graph_from_data", "source_node_set": null, "source_user": "default_user@example.com", "description": "Retrieval-Augmented Generation pipelines combining retrieval with LLM generation.", "id": "7594343c-5532-5896-b0aa-be5c1a74bd92", "color": "#6510F4"}, {"name": "agents", "type": "Entity", "ontology_valid": false, "version": 1, "topological_rank": 0, "metadata": {"index_fields": ["name"]}, "belongs_to_set": null, "source_pipeline": "cognify_pipeline", "source_task": "extract_graph_from_data", "source_node_set": null, "source_user": "default_user@example.com", "description": "Agent systems that orchestrate actions and LLM calls.", "id": "ba1f1dac-e2fb-5464-914d-ff54b9b19787", "color": "#6510F4"}, {"name": "search systems", "type": "Entity", "ontology_valid": false, "version": 1, "topological_rank": 0, "metadata": {"index_fields": ["name"]}, "belongs_to_set": null, "source_pipeline": "cognify_pipeline", "source_task": "extract_graph_from_data", "source_node_set": null, "source_user": "default_user@example.com", "description": "Systems for information retrieval and search.", "id": "a1a666e4-2070-59fd-95f7-c4c6178e89ba", "color": "#6510F4"}, {"name": "component-based architecture", "type": "Entity", "ontology_valid": false, "version": 1, "topological_rank": 0, "metadata": {"index_fields": ["name"]}, "belongs_to_set": null, "source_pipeline": "cognify_pipeline", "source_task": "extract_graph_from_data", "source_node_set": null, "source_user": "default_user@example.com", "description": "Architecture composed of modular components where each step is a building block.", "id": "30f5dcb9-d238-5c7d-8d2a-b9da0b854f98", "color": "#6510F4"}, {"name": "retrieval", "type": "Entity", "ontology_valid": false, "version": 1, "topological_rank": 0, "metadata": {"index_fields": ["name"]}, "belongs_to_set": null, "source_pipeline": "cognify_pipeline", "source_task": "extract_graph_from_data", "source_node_set": null, "source_user": "default_user@example.com", "description": "A retrieval step/component in the pipeline.", "id": "f010bf52-6eb5-511f-bbed-cd5237545edd", "color": "#6510F4"}, {"name": "component", "type": "EntityType", "ontology_valid": false, "version": 1, "topological_rank": 0, "metadata": {"index_fields": ["name"]}, "belongs_to_set": null, "source_pipeline": "cognify_pipeline", "source_task": "extract_graph_from_data", "source_node_set": null, "source_user": "default_user@example.com", "description": "component", "id": "b283358b-c288-5ca1-a6e8-05bac88f7a6f", "color": "#A550FF"}, {"name": "generation", "type": "Entity", "ontology_valid": false, "version": 1, "topological_rank": 0, "metadata": {"index_fields": ["name"]}, "belongs_to_set": null, "source_pipeline": "cognify_pipeline", "source_task": "extract_graph_from_data", "source_node_set": null, "source_user": "default_user@example.com", "description": "A generation (LLM) step/component in the pipeline.", "id": "dba0457b-9aff-5eb6-8ccd-19f7c9ae4dfa", "color": "#6510F4"}, {"name": "composable building block", "type": "Entity", "ontology_valid": false, "version": 1, "topological_rank": 0, "metadata": {"index_fields": ["name"]}, "belongs_to_set": null, "source_pipeline": "cognify_pipeline", "source_task": "extract_graph_from_data", "source_node_set": null, "source_user": "default_user@example.com", "description": "A modular, composable building block representing an individual step in the architecture.", "id": "59cf88c0-cb09-5f96-9252-5f5810981bcc", "color": "#6510F4"}, {"name": "text_62f45b114bbc9894497442c0588694a9", "type": "TextDocument", "ontology_valid": false, "version": 1, "topological_rank": 0, "metadata": {"index_fields": ["name"]}, "belongs_to_set": null, "source_pipeline": "cognify_pipeline", "source_task": "classify_documents", "source_node_set": null, "source_user": "default_user@example.com", "raw_data_location": "file:///Users/handekafkas/Documents/local-code/haystack-core-integrations/integrations/cognee/.venv/lib/python3.13/site-packages/cognee/.data_storage/text_62f45b114bbc9894497442c0588694a9.txt", "external_metadata": "{}", "mime_type": "text/plain", "id": "1a7434a3-3266-5111-9501-4fe093f36076", "color": "#DBD8D8"}, {"name": "", "type": "TextSummary", "ontology_valid": false, "version": 1, "topological_rank": 0, "metadata": {"index_fields": ["text"]}, "belongs_to_set": null, "source_pipeline": "cognify_pipeline", "source_task": "summarize_text", "source_node_set": null, "source_user": "default_user@example.com", "text": "Knowledge graphs model information as nodes (entities) and edges (relationships), enabling semantic search, inference, and discovery of hidden connections across large document collections.", "id": "8a75198a-6b32-5a14-926f-ae42589088af", "color": "#6510F4"}, {"name": "", "type": "TextSummary", "ontology_valid": false, "version": 1, "topological_rank": 0, "metadata": {"index_fields": ["text"]}, "belongs_to_set": null, "source_pipeline": "cognify_pipeline", "source_task": "summarize_text", "source_node_set": null, "source_user": "default_user@example.com", "text": "Acme Corp\u2019s engineering team \u2014 Alice (backend lead), Bob (ML engineer), and Carol (infrastructure) \u2014 is developing a next\u2011generation search platform.", "id": "349bab63-8b60-5d59-a1f2-a4413b6377f2", "color": "#6510F4"}, {"name": "", "type": "TextSummary", "ontology_valid": false, "version": 1, "topological_rank": 0, "metadata": {"index_fields": ["text"]}, "belongs_to_set": null, "source_pipeline": "cognify_pipeline", "source_task": "summarize_text", "source_node_set": null, "source_user": "default_user@example.com", "text": "Cognee is an open-source memory system for AI agents that builds a knowledge engine to convert raw data (e.g., unstructured documents, relational databases) into a persistent, enriched, and traceable memory searchable by semantic meaning and relationships.", "id": "16c06ddd-c7f6-5d74-9ed4-a4520ffde7ca", "color": "#6510F4"}, {"name": "", "type": "TextSummary", "ontology_valid": false, "version": 1, "topological_rank": 0, "metadata": {"index_fields": ["text"]}, "belongs_to_set": null, "source_pipeline": "cognify_pipeline", "source_task": "summarize_text", "source_node_set": null, "source_user": "default_user@example.com", "text": "Haystack is an open-source LLM framework by deepset for building production-ready RAG pipelines, agents, and search applications using modular, composable components.", "id": "208e9fa9-a281-5f67-8f8f-4b78c917c467", "color": "#6510F4"}]; +var links = [{"source": "601f27c0-4582-5a13-89d3-64a8c0f15cc1", "target": "df20c394-b710-5b2c-9256-ce5f5fe36397", "relation": "contains", "weight": null, "all_weights": {}, "relationship_type": "contains", "edge_info": {"source_node_id": "601f27c0-4582-5a13-89d3-64a8c0f15cc1", "target_node_id": "df20c394-b710-5b2c-9256-ce5f5fe36397", "relationship_name": "contains", "updated_at": "2026-03-20 23:21:01", "relationship_type": "contains", "edge_text": "relationship_name: contains; entity_name: knowledge graphs; entity_description: Structures that represent information as nodes (entities) and edges (relationships)."}}, {"source": "601f27c0-4582-5a13-89d3-64a8c0f15cc1", "target": "bd3f3aa5-5df4-54a0-af4e-78aa5a54e8f3", "relation": "contains", "weight": null, "all_weights": {}, "relationship_type": "contains", "edge_info": {"source_node_id": "601f27c0-4582-5a13-89d3-64a8c0f15cc1", "target_node_id": "bd3f3aa5-5df4-54a0-af4e-78aa5a54e8f3", "relationship_name": "contains", "updated_at": "2026-03-20 23:21:01", "relationship_type": "contains", "edge_text": "relationship_name: contains; entity_name: nodes; entity_description: Elements in a knowledge graph that represent entities."}}, {"source": "601f27c0-4582-5a13-89d3-64a8c0f15cc1", "target": "e4f1a343-1dd6-5191-ab16-4901f6eccf51", "relation": "contains", "weight": null, "all_weights": {}, "relationship_type": "contains", "edge_info": {"source_node_id": "601f27c0-4582-5a13-89d3-64a8c0f15cc1", "target_node_id": "e4f1a343-1dd6-5191-ab16-4901f6eccf51", "relationship_name": "contains", "updated_at": "2026-03-20 23:21:01", "relationship_type": "contains", "edge_text": "relationship_name: contains; entity_name: edges; entity_description: Relationships that connect nodes in a knowledge graph."}}, {"source": "601f27c0-4582-5a13-89d3-64a8c0f15cc1", "target": "3fb76a7a-fbf5-57ce-afb0-dcabb13cddeb", "relation": "contains", "weight": null, "all_weights": {}, "relationship_type": "contains", "edge_info": {"source_node_id": "601f27c0-4582-5a13-89d3-64a8c0f15cc1", "target_node_id": "3fb76a7a-fbf5-57ce-afb0-dcabb13cddeb", "relationship_name": "contains", "updated_at": "2026-03-20 23:21:01", "relationship_type": "contains", "edge_text": "relationship_name: contains; entity_name: information; entity_description: Data or knowledge represented within a knowledge graph."}}, {"source": "601f27c0-4582-5a13-89d3-64a8c0f15cc1", "target": "9d6360d4-504a-5f7f-b618-c2ea457a1a4d", "relation": "contains", "weight": null, "all_weights": {}, "relationship_type": "contains", "edge_info": {"source_node_id": "601f27c0-4582-5a13-89d3-64a8c0f15cc1", "target_node_id": "9d6360d4-504a-5f7f-b618-c2ea457a1a4d", "relationship_name": "contains", "updated_at": "2026-03-20 23:21:01", "relationship_type": "contains", "edge_text": "relationship_name: contains; entity_name: semantic search; entity_description: Search that uses meaning and relationships rather than simple keyword matching."}}, {"source": "601f27c0-4582-5a13-89d3-64a8c0f15cc1", "target": "ba802be9-50b2-58a6-a46d-031e30a780a8", "relation": "contains", "weight": null, "all_weights": {}, "relationship_type": "contains", "edge_info": {"source_node_id": "601f27c0-4582-5a13-89d3-64a8c0f15cc1", "target_node_id": "ba802be9-50b2-58a6-a46d-031e30a780a8", "relationship_name": "contains", "updated_at": "2026-03-20 23:21:01", "relationship_type": "contains", "edge_text": "relationship_name: contains; entity_name: reasoning; entity_description: Inference and logical processes enabled by structured knowledge representations."}}, {"source": "601f27c0-4582-5a13-89d3-64a8c0f15cc1", "target": "e0c5c99c-74a8-5d09-8e8a-05cb2e5bcf6b", "relation": "contains", "weight": null, "all_weights": {}, "relationship_type": "contains", "edge_info": {"source_node_id": "601f27c0-4582-5a13-89d3-64a8c0f15cc1", "target_node_id": "e0c5c99c-74a8-5d09-8e8a-05cb2e5bcf6b", "relationship_name": "contains", "updated_at": "2026-03-20 23:21:01", "relationship_type": "contains", "edge_text": "relationship_name: contains; entity_name: discovery of hidden connections; entity_description: Identification of non-obvious relationships across data using a knowledge graph."}}, {"source": "601f27c0-4582-5a13-89d3-64a8c0f15cc1", "target": "838f4a46-e459-58e4-a40b-ab30cd21da5c", "relation": "contains", "weight": null, "all_weights": {}, "relationship_type": "contains", "edge_info": {"source_node_id": "601f27c0-4582-5a13-89d3-64a8c0f15cc1", "target_node_id": "838f4a46-e459-58e4-a40b-ab30cd21da5c", "relationship_name": "contains", "updated_at": "2026-03-20 23:21:01", "relationship_type": "contains", "edge_text": "relationship_name: contains; entity_name: large document collections; entity_description: Extensive corpora of documents across which knowledge graphs can reveal connections."}}, {"source": "601f27c0-4582-5a13-89d3-64a8c0f15cc1", "target": "86c075e6-5852-5d80-8327-4e9691a71f62", "relation": "is_part_of", "weight": null, "all_weights": {}, "relationship_type": null, "edge_info": {"source_node_id": "601f27c0-4582-5a13-89d3-64a8c0f15cc1", "target_node_id": "86c075e6-5852-5d80-8327-4e9691a71f62", "relationship_name": "is_part_of", "updated_at": "2026-03-20 23:21:01"}}, {"source": "df20c394-b710-5b2c-9256-ce5f5fe36397", "target": "dd9713b7-dc20-5101-aad0-1c4216811147", "relation": "is_a", "weight": null, "all_weights": {}, "relationship_type": null, "edge_info": {"source_node_id": "df20c394-b710-5b2c-9256-ce5f5fe36397", "target_node_id": "dd9713b7-dc20-5101-aad0-1c4216811147", "relationship_name": "is_a", "updated_at": "2026-03-20 23:21:01"}}, {"source": "df20c394-b710-5b2c-9256-ce5f5fe36397", "target": "3fb76a7a-fbf5-57ce-afb0-dcabb13cddeb", "relation": "represents_information", "weight": null, "all_weights": {}, "relationship_type": null, "edge_info": {"relationship_name": "represents_information", "source_node_id": "df20c394-b710-5b2c-9256-ce5f5fe36397", "target_node_id": "3fb76a7a-fbf5-57ce-afb0-dcabb13cddeb", "ontology_valid": false}}, {"source": "df20c394-b710-5b2c-9256-ce5f5fe36397", "target": "bd3f3aa5-5df4-54a0-af4e-78aa5a54e8f3", "relation": "has_nodes", "weight": null, "all_weights": {}, "relationship_type": null, "edge_info": {"relationship_name": "has_nodes", "source_node_id": "df20c394-b710-5b2c-9256-ce5f5fe36397", "target_node_id": "bd3f3aa5-5df4-54a0-af4e-78aa5a54e8f3", "ontology_valid": false}}, {"source": "df20c394-b710-5b2c-9256-ce5f5fe36397", "target": "e4f1a343-1dd6-5191-ab16-4901f6eccf51", "relation": "has_edges", "weight": null, "all_weights": {}, "relationship_type": null, "edge_info": {"relationship_name": "has_edges", "source_node_id": "df20c394-b710-5b2c-9256-ce5f5fe36397", "target_node_id": "e4f1a343-1dd6-5191-ab16-4901f6eccf51", "ontology_valid": false}}, {"source": "df20c394-b710-5b2c-9256-ce5f5fe36397", "target": "9d6360d4-504a-5f7f-b618-c2ea457a1a4d", "relation": "enables_semantic_search", "weight": null, "all_weights": {}, "relationship_type": null, "edge_info": {"relationship_name": "enables_semantic_search", "source_node_id": "df20c394-b710-5b2c-9256-ce5f5fe36397", "target_node_id": "9d6360d4-504a-5f7f-b618-c2ea457a1a4d", "ontology_valid": false}}, {"source": "df20c394-b710-5b2c-9256-ce5f5fe36397", "target": "ba802be9-50b2-58a6-a46d-031e30a780a8", "relation": "enables_reasoning", "weight": null, "all_weights": {}, "relationship_type": null, "edge_info": {"relationship_name": "enables_reasoning", "source_node_id": "df20c394-b710-5b2c-9256-ce5f5fe36397", "target_node_id": "ba802be9-50b2-58a6-a46d-031e30a780a8", "ontology_valid": false}}, {"source": "df20c394-b710-5b2c-9256-ce5f5fe36397", "target": "e0c5c99c-74a8-5d09-8e8a-05cb2e5bcf6b", "relation": "enables_discovery_of_hidden_connections", "weight": null, "all_weights": {}, "relationship_type": null, "edge_info": {"relationship_name": "enables_discovery_of_hidden_connections", "source_node_id": "df20c394-b710-5b2c-9256-ce5f5fe36397", "target_node_id": "e0c5c99c-74a8-5d09-8e8a-05cb2e5bcf6b", "ontology_valid": false}}, {"source": "df20c394-b710-5b2c-9256-ce5f5fe36397", "target": "65c71de3-4c23-5f28-8e07-fc7428d1e0c4", "relation": "is_a", "weight": null, "all_weights": {}, "relationship_type": null, "edge_info": {"source_node_id": "df20c394-b710-5b2c-9256-ce5f5fe36397", "target_node_id": "65c71de3-4c23-5f28-8e07-fc7428d1e0c4", "relationship_name": "is_a", "updated_at": "2026-03-20 23:21:03"}}, {"source": "bd3f3aa5-5df4-54a0-af4e-78aa5a54e8f3", "target": "dd9713b7-dc20-5101-aad0-1c4216811147", "relation": "is_a", "weight": null, "all_weights": {}, "relationship_type": null, "edge_info": {"source_node_id": "bd3f3aa5-5df4-54a0-af4e-78aa5a54e8f3", "target_node_id": "dd9713b7-dc20-5101-aad0-1c4216811147", "relationship_name": "is_a", "updated_at": "2026-03-20 23:21:01"}}, {"source": "e4f1a343-1dd6-5191-ab16-4901f6eccf51", "target": "dd9713b7-dc20-5101-aad0-1c4216811147", "relation": "is_a", "weight": null, "all_weights": {}, "relationship_type": null, "edge_info": {"source_node_id": "e4f1a343-1dd6-5191-ab16-4901f6eccf51", "target_node_id": "dd9713b7-dc20-5101-aad0-1c4216811147", "relationship_name": "is_a", "updated_at": "2026-03-20 23:21:01"}}, {"source": "3fb76a7a-fbf5-57ce-afb0-dcabb13cddeb", "target": "dd9713b7-dc20-5101-aad0-1c4216811147", "relation": "is_a", "weight": null, "all_weights": {}, "relationship_type": null, "edge_info": {"source_node_id": "3fb76a7a-fbf5-57ce-afb0-dcabb13cddeb", "target_node_id": "dd9713b7-dc20-5101-aad0-1c4216811147", "relationship_name": "is_a", "updated_at": "2026-03-20 23:21:01"}}, {"source": "9d6360d4-504a-5f7f-b618-c2ea457a1a4d", "target": "dd9713b7-dc20-5101-aad0-1c4216811147", "relation": "is_a", "weight": null, "all_weights": {}, "relationship_type": null, "edge_info": {"source_node_id": "9d6360d4-504a-5f7f-b618-c2ea457a1a4d", "target_node_id": "dd9713b7-dc20-5101-aad0-1c4216811147", "relationship_name": "is_a", "updated_at": "2026-03-20 23:21:01"}}, {"source": "ba802be9-50b2-58a6-a46d-031e30a780a8", "target": "dd9713b7-dc20-5101-aad0-1c4216811147", "relation": "is_a", "weight": null, "all_weights": {}, "relationship_type": null, "edge_info": {"source_node_id": "ba802be9-50b2-58a6-a46d-031e30a780a8", "target_node_id": "dd9713b7-dc20-5101-aad0-1c4216811147", "relationship_name": "is_a", "updated_at": "2026-03-20 23:21:01"}}, {"source": "e0c5c99c-74a8-5d09-8e8a-05cb2e5bcf6b", "target": "dd9713b7-dc20-5101-aad0-1c4216811147", "relation": "is_a", "weight": null, "all_weights": {}, "relationship_type": null, "edge_info": {"source_node_id": "e0c5c99c-74a8-5d09-8e8a-05cb2e5bcf6b", "target_node_id": "dd9713b7-dc20-5101-aad0-1c4216811147", "relationship_name": "is_a", "updated_at": "2026-03-20 23:21:01"}}, {"source": "e0c5c99c-74a8-5d09-8e8a-05cb2e5bcf6b", "target": "838f4a46-e459-58e4-a40b-ab30cd21da5c", "relation": "across_large_document_collections", "weight": null, "all_weights": {}, "relationship_type": null, "edge_info": {"relationship_name": "across_large_document_collections", "source_node_id": "e0c5c99c-74a8-5d09-8e8a-05cb2e5bcf6b", "target_node_id": "838f4a46-e459-58e4-a40b-ab30cd21da5c", "ontology_valid": false}}, {"source": "838f4a46-e459-58e4-a40b-ab30cd21da5c", "target": "dd9713b7-dc20-5101-aad0-1c4216811147", "relation": "is_a", "weight": null, "all_weights": {}, "relationship_type": null, "edge_info": {"source_node_id": "838f4a46-e459-58e4-a40b-ab30cd21da5c", "target_node_id": "dd9713b7-dc20-5101-aad0-1c4216811147", "relationship_name": "is_a", "updated_at": "2026-03-20 23:21:01"}}, {"source": "bc815248-f743-5faa-b176-a216cf9e908e", "target": "2d09f34b-aee1-5d32-a2f9-23eb7ed48b24", "relation": "contains", "weight": null, "all_weights": {}, "relationship_type": "contains", "edge_info": {"source_node_id": "bc815248-f743-5faa-b176-a216cf9e908e", "target_node_id": "2d09f34b-aee1-5d32-a2f9-23eb7ed48b24", "relationship_name": "contains", "updated_at": "2026-03-20 23:21:04", "relationship_type": "contains", "edge_text": "relationship_name: contains; entity_name: cognee; entity_description: Open-source memory for AI agents; builds a knowledge engine that transforms raw data into a persistent, rich, and traceable memory searchable by meaning and relationships."}}, {"source": "bc815248-f743-5faa-b176-a216cf9e908e", "target": "968213f1-6ddc-5155-89d4-6df7c144a4a1", "relation": "contains", "weight": null, "all_weights": {}, "relationship_type": "contains", "edge_info": {"source_node_id": "bc815248-f743-5faa-b176-a216cf9e908e", "target_node_id": "968213f1-6ddc-5155-89d4-6df7c144a4a1", "relationship_name": "contains", "updated_at": "2026-03-20 23:21:04", "relationship_type": "contains", "edge_text": "relationship_name: contains; entity_name: ai agents; entity_description: Autonomous or semi-autonomous software agents that use memory systems."}}, {"source": "bc815248-f743-5faa-b176-a216cf9e908e", "target": "d8b992b3-ebdc-52a4-9913-9e1aea9a47f8", "relation": "contains", "weight": null, "all_weights": {}, "relationship_type": "contains", "edge_info": {"source_node_id": "bc815248-f743-5faa-b176-a216cf9e908e", "target_node_id": "d8b992b3-ebdc-52a4-9913-9e1aea9a47f8", "relationship_name": "contains", "updated_at": "2026-03-20 23:21:04", "relationship_type": "contains", "edge_text": "relationship_name: contains; entity_name: knowledge engine; entity_description: A system that processes and structures raw data into persistent, rich, and traceable memory."}}, {"source": "bc815248-f743-5faa-b176-a216cf9e908e", "target": "0a6f4624-d50e-5989-ba18-ddab839f5554", "relation": "contains", "weight": null, "all_weights": {}, "relationship_type": "contains", "edge_info": {"source_node_id": "bc815248-f743-5faa-b176-a216cf9e908e", "target_node_id": "0a6f4624-d50e-5989-ba18-ddab839f5554", "relationship_name": "contains", "updated_at": "2026-03-20 23:21:04", "relationship_type": "contains", "edge_text": "relationship_name: contains; entity_name: raw data; entity_description: Unprocessed input such as unstructured documents, relational databases, and other data sources."}}, {"source": "bc815248-f743-5faa-b176-a216cf9e908e", "target": "f89d185b-5df9-5fc6-84a7-35931b380405", "relation": "contains", "weight": null, "all_weights": {}, "relationship_type": "contains", "edge_info": {"source_node_id": "bc815248-f743-5faa-b176-a216cf9e908e", "target_node_id": "f89d185b-5df9-5fc6-84a7-35931b380405", "relationship_name": "contains", "updated_at": "2026-03-20 23:21:04", "relationship_type": "contains", "edge_text": "relationship_name: contains; entity_name: unstructured documents; entity_description: Example raw data format (e.g., text files, reports, articles) mentioned as an input to the knowledge engine."}}, {"source": "bc815248-f743-5faa-b176-a216cf9e908e", "target": "9d84ec4f-0968-52d0-bd6d-2a4c1b07490d", "relation": "contains", "weight": null, "all_weights": {}, "relationship_type": "contains", "edge_info": {"source_node_id": "bc815248-f743-5faa-b176-a216cf9e908e", "target_node_id": "9d84ec4f-0968-52d0-bd6d-2a4c1b07490d", "relationship_name": "contains", "updated_at": "2026-03-20 23:21:04", "relationship_type": "contains", "edge_text": "relationship_name: contains; entity_name: relational databases; entity_description: Example raw data format (structured tables) mentioned as an input to the knowledge engine."}}, {"source": "bc815248-f743-5faa-b176-a216cf9e908e", "target": "dce5dd84-ed4d-5666-8908-c4c523b804c8", "relation": "contains", "weight": null, "all_weights": {}, "relationship_type": "contains", "edge_info": {"source_node_id": "bc815248-f743-5faa-b176-a216cf9e908e", "target_node_id": "dce5dd84-ed4d-5666-8908-c4c523b804c8", "relationship_name": "contains", "updated_at": "2026-03-20 23:21:04", "relationship_type": "contains", "edge_text": "relationship_name: contains; entity_name: persistent rich traceable memory; entity_description: Memory produced by the knowledge engine that is persistent, rich in structure and metadata, traceable, and searchable by meaning and relationships."}}, {"source": "bc815248-f743-5faa-b176-a216cf9e908e", "target": "0700b84c-e4eb-5462-be56-0d7d97d0009e", "relation": "is_part_of", "weight": null, "all_weights": {}, "relationship_type": null, "edge_info": {"source_node_id": "bc815248-f743-5faa-b176-a216cf9e908e", "target_node_id": "0700b84c-e4eb-5462-be56-0d7d97d0009e", "relationship_name": "is_part_of", "updated_at": "2026-03-20 23:21:04"}}, {"source": "2d09f34b-aee1-5d32-a2f9-23eb7ed48b24", "target": "2d66edc2-1e14-55ab-8304-680b514a597a", "relation": "is_a", "weight": null, "all_weights": {}, "relationship_type": null, "edge_info": {"source_node_id": "2d09f34b-aee1-5d32-a2f9-23eb7ed48b24", "target_node_id": "2d66edc2-1e14-55ab-8304-680b514a597a", "relationship_name": "is_a", "updated_at": "2026-03-20 23:21:04"}}, {"source": "2d09f34b-aee1-5d32-a2f9-23eb7ed48b24", "target": "dce5dd84-ed4d-5666-8908-c4c523b804c8", "relation": "is_a", "weight": null, "all_weights": {}, "relationship_type": null, "edge_info": {"relationship_name": "is_a", "source_node_id": "2d09f34b-aee1-5d32-a2f9-23eb7ed48b24", "target_node_id": "dce5dd84-ed4d-5666-8908-c4c523b804c8", "ontology_valid": false}}, {"source": "2d09f34b-aee1-5d32-a2f9-23eb7ed48b24", "target": "968213f1-6ddc-5155-89d4-6df7c144a4a1", "relation": "for_agents", "weight": null, "all_weights": {}, "relationship_type": null, "edge_info": {"relationship_name": "for_agents", "source_node_id": "2d09f34b-aee1-5d32-a2f9-23eb7ed48b24", "target_node_id": "968213f1-6ddc-5155-89d4-6df7c144a4a1", "ontology_valid": false}}, {"source": "2d09f34b-aee1-5d32-a2f9-23eb7ed48b24", "target": "d8b992b3-ebdc-52a4-9913-9e1aea9a47f8", "relation": "builds_knowledge_engine", "weight": null, "all_weights": {}, "relationship_type": null, "edge_info": {"relationship_name": "builds_knowledge_engine", "source_node_id": "2d09f34b-aee1-5d32-a2f9-23eb7ed48b24", "target_node_id": "d8b992b3-ebdc-52a4-9913-9e1aea9a47f8", "ontology_valid": false}}, {"source": "968213f1-6ddc-5155-89d4-6df7c144a4a1", "target": "5f6d6fc0-e6aa-5365-a4a0-98d6fa3af190", "relation": "is_a", "weight": null, "all_weights": {}, "relationship_type": null, "edge_info": {"source_node_id": "968213f1-6ddc-5155-89d4-6df7c144a4a1", "target_node_id": "5f6d6fc0-e6aa-5365-a4a0-98d6fa3af190", "relationship_name": "is_a", "updated_at": "2026-03-20 23:21:04"}}, {"source": "d8b992b3-ebdc-52a4-9913-9e1aea9a47f8", "target": "dd9713b7-dc20-5101-aad0-1c4216811147", "relation": "is_a", "weight": null, "all_weights": {}, "relationship_type": null, "edge_info": {"source_node_id": "d8b992b3-ebdc-52a4-9913-9e1aea9a47f8", "target_node_id": "dd9713b7-dc20-5101-aad0-1c4216811147", "relationship_name": "is_a", "updated_at": "2026-03-20 23:21:04"}}, {"source": "d8b992b3-ebdc-52a4-9913-9e1aea9a47f8", "target": "0a6f4624-d50e-5989-ba18-ddab839f5554", "relation": "transforms_raw_data", "weight": null, "all_weights": {}, "relationship_type": null, "edge_info": {"relationship_name": "transforms_raw_data", "source_node_id": "d8b992b3-ebdc-52a4-9913-9e1aea9a47f8", "target_node_id": "0a6f4624-d50e-5989-ba18-ddab839f5554", "ontology_valid": false}}, {"source": "d8b992b3-ebdc-52a4-9913-9e1aea9a47f8", "target": "dce5dd84-ed4d-5666-8908-c4c523b804c8", "relation": "creates_memory", "weight": null, "all_weights": {}, "relationship_type": null, "edge_info": {"relationship_name": "creates_memory", "source_node_id": "d8b992b3-ebdc-52a4-9913-9e1aea9a47f8", "target_node_id": "dce5dd84-ed4d-5666-8908-c4c523b804c8", "ontology_valid": false}}, {"source": "0a6f4624-d50e-5989-ba18-ddab839f5554", "target": "4ed5a0c7-2efb-52d1-9734-06a8ba225c94", "relation": "is_a", "weight": null, "all_weights": {}, "relationship_type": null, "edge_info": {"source_node_id": "0a6f4624-d50e-5989-ba18-ddab839f5554", "target_node_id": "4ed5a0c7-2efb-52d1-9734-06a8ba225c94", "relationship_name": "is_a", "updated_at": "2026-03-20 23:21:04"}}, {"source": "0a6f4624-d50e-5989-ba18-ddab839f5554", "target": "f89d185b-5df9-5fc6-84a7-35931b380405", "relation": "includes", "weight": null, "all_weights": {}, "relationship_type": null, "edge_info": {"relationship_name": "includes", "source_node_id": "0a6f4624-d50e-5989-ba18-ddab839f5554", "target_node_id": "f89d185b-5df9-5fc6-84a7-35931b380405", "ontology_valid": false}}, {"source": "0a6f4624-d50e-5989-ba18-ddab839f5554", "target": "9d84ec4f-0968-52d0-bd6d-2a4c1b07490d", "relation": "includes", "weight": null, "all_weights": {}, "relationship_type": null, "edge_info": {"relationship_name": "includes", "source_node_id": "0a6f4624-d50e-5989-ba18-ddab839f5554", "target_node_id": "9d84ec4f-0968-52d0-bd6d-2a4c1b07490d", "ontology_valid": false}}, {"source": "f89d185b-5df9-5fc6-84a7-35931b380405", "target": "4ed5a0c7-2efb-52d1-9734-06a8ba225c94", "relation": "is_a", "weight": null, "all_weights": {}, "relationship_type": null, "edge_info": {"source_node_id": "f89d185b-5df9-5fc6-84a7-35931b380405", "target_node_id": "4ed5a0c7-2efb-52d1-9734-06a8ba225c94", "relationship_name": "is_a", "updated_at": "2026-03-20 23:21:04"}}, {"source": "9d84ec4f-0968-52d0-bd6d-2a4c1b07490d", "target": "4ed5a0c7-2efb-52d1-9734-06a8ba225c94", "relation": "is_a", "weight": null, "all_weights": {}, "relationship_type": null, "edge_info": {"source_node_id": "9d84ec4f-0968-52d0-bd6d-2a4c1b07490d", "target_node_id": "4ed5a0c7-2efb-52d1-9734-06a8ba225c94", "relationship_name": "is_a", "updated_at": "2026-03-20 23:21:04"}}, {"source": "dce5dd84-ed4d-5666-8908-c4c523b804c8", "target": "dd9713b7-dc20-5101-aad0-1c4216811147", "relation": "is_a", "weight": null, "all_weights": {}, "relationship_type": null, "edge_info": {"source_node_id": "dce5dd84-ed4d-5666-8908-c4c523b804c8", "target_node_id": "dd9713b7-dc20-5101-aad0-1c4216811147", "relationship_name": "is_a", "updated_at": "2026-03-20 23:21:04"}}, {"source": "c569abe9-16f1-54e0-ab9c-a4223e1088e1", "target": "f7d8be13-2a72-5104-bd02-7a5964737a91", "relation": "contains", "weight": null, "all_weights": {}, "relationship_type": "contains", "edge_info": {"source_node_id": "c569abe9-16f1-54e0-ab9c-a4223e1088e1", "target_node_id": "f7d8be13-2a72-5104-bd02-7a5964737a91", "relationship_name": "contains", "updated_at": "2026-03-20 23:21:03", "relationship_type": "contains", "edge_text": "relationship_name: contains; entity_name: alice; entity_description: Backend lead on Acme Corp's engineering team."}}, {"source": "c569abe9-16f1-54e0-ab9c-a4223e1088e1", "target": "515e93c6-3782-59db-96be-ad5b8cf872a5", "relation": "contains", "weight": null, "all_weights": {}, "relationship_type": "contains", "edge_info": {"source_node_id": "c569abe9-16f1-54e0-ab9c-a4223e1088e1", "target_node_id": "515e93c6-3782-59db-96be-ad5b8cf872a5", "relationship_name": "contains", "updated_at": "2026-03-20 23:21:03", "relationship_type": "contains", "edge_text": "relationship_name: contains; entity_name: bob; entity_description: ML engineer on Acme Corp's engineering team."}}, {"source": "c569abe9-16f1-54e0-ab9c-a4223e1088e1", "target": "80370ebb-d9b5-5f12-a3fb-db3631157840", "relation": "contains", "weight": null, "all_weights": {}, "relationship_type": "contains", "edge_info": {"source_node_id": "c569abe9-16f1-54e0-ab9c-a4223e1088e1", "target_node_id": "80370ebb-d9b5-5f12-a3fb-db3631157840", "relationship_name": "contains", "updated_at": "2026-03-20 23:21:03", "relationship_type": "contains", "edge_text": "relationship_name: contains; entity_name: carol; entity_description: Infrastructure engineer on Acme Corp's engineering team."}}, {"source": "c569abe9-16f1-54e0-ab9c-a4223e1088e1", "target": "7f5a651e-56c1-574f-aa54-cd0a0b7dbc38", "relation": "contains", "weight": null, "all_weights": {}, "relationship_type": "contains", "edge_info": {"source_node_id": "c569abe9-16f1-54e0-ab9c-a4223e1088e1", "target_node_id": "7f5a651e-56c1-574f-aa54-cd0a0b7dbc38", "relationship_name": "contains", "updated_at": "2026-03-20 23:21:03", "relationship_type": "contains", "edge_text": "relationship_name: contains; entity_name: acme corp; entity_description: Company employing the engineering team."}}, {"source": "c569abe9-16f1-54e0-ab9c-a4223e1088e1", "target": "7fa8891b-a426-5d42-b011-6851ef945793", "relation": "contains", "weight": null, "all_weights": {}, "relationship_type": "contains", "edge_info": {"source_node_id": "c569abe9-16f1-54e0-ab9c-a4223e1088e1", "target_node_id": "7fa8891b-a426-5d42-b011-6851ef945793", "relationship_name": "contains", "updated_at": "2026-03-20 23:21:03", "relationship_type": "contains", "edge_text": "relationship_name: contains; entity_name: engineering team at acme corp; entity_description: Engineering team at Acme Corp consisting of Alice, Bob, and Carol."}}, {"source": "c569abe9-16f1-54e0-ab9c-a4223e1088e1", "target": "6fdb37d4-ae27-5a1a-9f7a-03f5036247ca", "relation": "contains", "weight": null, "all_weights": {}, "relationship_type": "contains", "edge_info": {"source_node_id": "c569abe9-16f1-54e0-ab9c-a4223e1088e1", "target_node_id": "6fdb37d4-ae27-5a1a-9f7a-03f5036247ca", "relationship_name": "contains", "updated_at": "2026-03-20 23:21:03", "relationship_type": "contains", "edge_text": "relationship_name: contains; entity_name: next-generation search platform; entity_description: Next-generation search platform being built by the engineering team."}}, {"source": "c569abe9-16f1-54e0-ab9c-a4223e1088e1", "target": "df20c394-b710-5b2c-9256-ce5f5fe36397", "relation": "contains", "weight": null, "all_weights": {}, "relationship_type": "contains", "edge_info": {"source_node_id": "c569abe9-16f1-54e0-ab9c-a4223e1088e1", "target_node_id": "df20c394-b710-5b2c-9256-ce5f5fe36397", "relationship_name": "contains", "updated_at": "2026-03-20 23:21:03", "relationship_type": "contains", "edge_text": "relationship_name: contains; entity_name: knowledge graphs; entity_description: Knowledge graph technologies used to power the search platform."}}, {"source": "c569abe9-16f1-54e0-ab9c-a4223e1088e1", "target": "f7dc5ef7-3d2d-50c7-9edc-475862a15d4b", "relation": "contains", "weight": null, "all_weights": {}, "relationship_type": "contains", "edge_info": {"source_node_id": "c569abe9-16f1-54e0-ab9c-a4223e1088e1", "target_node_id": "f7dc5ef7-3d2d-50c7-9edc-475862a15d4b", "relationship_name": "contains", "updated_at": "2026-03-20 23:21:03", "relationship_type": "contains", "edge_text": "relationship_name: contains; entity_name: llms; entity_description: Large language models used to power the search platform."}}, {"source": "c569abe9-16f1-54e0-ab9c-a4223e1088e1", "target": "7706f53e-49ac-582a-8cf4-59b9c6e64bfb", "relation": "is_part_of", "weight": null, "all_weights": {}, "relationship_type": null, "edge_info": {"source_node_id": "c569abe9-16f1-54e0-ab9c-a4223e1088e1", "target_node_id": "7706f53e-49ac-582a-8cf4-59b9c6e64bfb", "relationship_name": "is_part_of", "updated_at": "2026-03-20 23:21:03"}}, {"source": "f7d8be13-2a72-5104-bd02-7a5964737a91", "target": "d072ba0f-e1a9-58bf-9974-e1802adc8134", "relation": "is_a", "weight": null, "all_weights": {}, "relationship_type": null, "edge_info": {"source_node_id": "f7d8be13-2a72-5104-bd02-7a5964737a91", "target_node_id": "d072ba0f-e1a9-58bf-9974-e1802adc8134", "relationship_name": "is_a", "updated_at": "2026-03-20 23:21:03"}}, {"source": "f7d8be13-2a72-5104-bd02-7a5964737a91", "target": "7fa8891b-a426-5d42-b011-6851ef945793", "relation": "member_of", "weight": null, "all_weights": {}, "relationship_type": null, "edge_info": {"relationship_name": "member_of", "source_node_id": "f7d8be13-2a72-5104-bd02-7a5964737a91", "target_node_id": "7fa8891b-a426-5d42-b011-6851ef945793", "ontology_valid": false}}, {"source": "515e93c6-3782-59db-96be-ad5b8cf872a5", "target": "d072ba0f-e1a9-58bf-9974-e1802adc8134", "relation": "is_a", "weight": null, "all_weights": {}, "relationship_type": null, "edge_info": {"source_node_id": "515e93c6-3782-59db-96be-ad5b8cf872a5", "target_node_id": "d072ba0f-e1a9-58bf-9974-e1802adc8134", "relationship_name": "is_a", "updated_at": "2026-03-20 23:21:03"}}, {"source": "515e93c6-3782-59db-96be-ad5b8cf872a5", "target": "7fa8891b-a426-5d42-b011-6851ef945793", "relation": "member_of", "weight": null, "all_weights": {}, "relationship_type": null, "edge_info": {"relationship_name": "member_of", "source_node_id": "515e93c6-3782-59db-96be-ad5b8cf872a5", "target_node_id": "7fa8891b-a426-5d42-b011-6851ef945793", "ontology_valid": false}}, {"source": "80370ebb-d9b5-5f12-a3fb-db3631157840", "target": "d072ba0f-e1a9-58bf-9974-e1802adc8134", "relation": "is_a", "weight": null, "all_weights": {}, "relationship_type": null, "edge_info": {"source_node_id": "80370ebb-d9b5-5f12-a3fb-db3631157840", "target_node_id": "d072ba0f-e1a9-58bf-9974-e1802adc8134", "relationship_name": "is_a", "updated_at": "2026-03-20 23:21:03"}}, {"source": "80370ebb-d9b5-5f12-a3fb-db3631157840", "target": "7fa8891b-a426-5d42-b011-6851ef945793", "relation": "member_of", "weight": null, "all_weights": {}, "relationship_type": null, "edge_info": {"relationship_name": "member_of", "source_node_id": "80370ebb-d9b5-5f12-a3fb-db3631157840", "target_node_id": "7fa8891b-a426-5d42-b011-6851ef945793", "ontology_valid": false}}, {"source": "7f5a651e-56c1-574f-aa54-cd0a0b7dbc38", "target": "d3d7b6b4-9b0d-52e8-9e09-a9e9cf4b5a4d", "relation": "is_a", "weight": null, "all_weights": {}, "relationship_type": null, "edge_info": {"source_node_id": "7f5a651e-56c1-574f-aa54-cd0a0b7dbc38", "target_node_id": "d3d7b6b4-9b0d-52e8-9e09-a9e9cf4b5a4d", "relationship_name": "is_a", "updated_at": "2026-03-20 23:21:03"}}, {"source": "7fa8891b-a426-5d42-b011-6851ef945793", "target": "e308d782-2a18-5ace-b0e8-236c7c3b4db4", "relation": "is_a", "weight": null, "all_weights": {}, "relationship_type": null, "edge_info": {"source_node_id": "7fa8891b-a426-5d42-b011-6851ef945793", "target_node_id": "e308d782-2a18-5ace-b0e8-236c7c3b4db4", "relationship_name": "is_a", "updated_at": "2026-03-20 23:21:03"}}, {"source": "7fa8891b-a426-5d42-b011-6851ef945793", "target": "7f5a651e-56c1-574f-aa54-cd0a0b7dbc38", "relation": "part_of", "weight": null, "all_weights": {}, "relationship_type": null, "edge_info": {"relationship_name": "part_of", "source_node_id": "7fa8891b-a426-5d42-b011-6851ef945793", "target_node_id": "7f5a651e-56c1-574f-aa54-cd0a0b7dbc38", "ontology_valid": false}}, {"source": "7fa8891b-a426-5d42-b011-6851ef945793", "target": "6fdb37d4-ae27-5a1a-9f7a-03f5036247ca", "relation": "building", "weight": null, "all_weights": {}, "relationship_type": null, "edge_info": {"relationship_name": "building", "source_node_id": "7fa8891b-a426-5d42-b011-6851ef945793", "target_node_id": "6fdb37d4-ae27-5a1a-9f7a-03f5036247ca", "ontology_valid": false}}, {"source": "6fdb37d4-ae27-5a1a-9f7a-03f5036247ca", "target": "29c0d211-0d39-579f-bf45-c7a78394c9aa", "relation": "is_a", "weight": null, "all_weights": {}, "relationship_type": null, "edge_info": {"source_node_id": "6fdb37d4-ae27-5a1a-9f7a-03f5036247ca", "target_node_id": "29c0d211-0d39-579f-bf45-c7a78394c9aa", "relationship_name": "is_a", "updated_at": "2026-03-20 23:21:03"}}, {"source": "6fdb37d4-ae27-5a1a-9f7a-03f5036247ca", "target": "df20c394-b710-5b2c-9256-ce5f5fe36397", "relation": "powered_by", "weight": null, "all_weights": {}, "relationship_type": null, "edge_info": {"relationship_name": "powered_by", "source_node_id": "6fdb37d4-ae27-5a1a-9f7a-03f5036247ca", "target_node_id": "df20c394-b710-5b2c-9256-ce5f5fe36397", "ontology_valid": false}}, {"source": "6fdb37d4-ae27-5a1a-9f7a-03f5036247ca", "target": "f7dc5ef7-3d2d-50c7-9edc-475862a15d4b", "relation": "powered_by", "weight": null, "all_weights": {}, "relationship_type": null, "edge_info": {"relationship_name": "powered_by", "source_node_id": "6fdb37d4-ae27-5a1a-9f7a-03f5036247ca", "target_node_id": "f7dc5ef7-3d2d-50c7-9edc-475862a15d4b", "ontology_valid": false}}, {"source": "f7dc5ef7-3d2d-50c7-9edc-475862a15d4b", "target": "65c71de3-4c23-5f28-8e07-fc7428d1e0c4", "relation": "is_a", "weight": null, "all_weights": {}, "relationship_type": null, "edge_info": {"source_node_id": "f7dc5ef7-3d2d-50c7-9edc-475862a15d4b", "target_node_id": "65c71de3-4c23-5f28-8e07-fc7428d1e0c4", "relationship_name": "is_a", "updated_at": "2026-03-20 23:21:03"}}, {"source": "ee7307f2-cba9-5003-9dc0-0780c50591a6", "target": "2bdd3deb-07d8-5413-a56d-1643e3ceb48b", "relation": "contains", "weight": null, "all_weights": {}, "relationship_type": "contains", "edge_info": {"source_node_id": "ee7307f2-cba9-5003-9dc0-0780c50591a6", "target_node_id": "2bdd3deb-07d8-5413-a56d-1643e3ceb48b", "relationship_name": "contains", "updated_at": "2026-03-20 23:21:04", "relationship_type": "contains", "edge_text": "relationship_name: contains; entity_name: haystack; entity_description: Open-source LLM framework by deepset for building production-ready RAG pipelines, agents, and search systems."}}, {"source": "ee7307f2-cba9-5003-9dc0-0780c50591a6", "target": "126df7ec-d0db-53ea-bc88-1bafd84c8646", "relation": "contains", "weight": null, "all_weights": {}, "relationship_type": "contains", "edge_info": {"source_node_id": "ee7307f2-cba9-5003-9dc0-0780c50591a6", "target_node_id": "126df7ec-d0db-53ea-bc88-1bafd84c8646", "relationship_name": "contains", "updated_at": "2026-03-20 23:21:04", "relationship_type": "contains", "edge_text": "relationship_name: contains; entity_name: deepset; entity_description: Company that develops Haystack."}}, {"source": "ee7307f2-cba9-5003-9dc0-0780c50591a6", "target": "7594343c-5532-5896-b0aa-be5c1a74bd92", "relation": "contains", "weight": null, "all_weights": {}, "relationship_type": "contains", "edge_info": {"source_node_id": "ee7307f2-cba9-5003-9dc0-0780c50591a6", "target_node_id": "7594343c-5532-5896-b0aa-be5c1a74bd92", "relationship_name": "contains", "updated_at": "2026-03-20 23:21:04", "relationship_type": "contains", "edge_text": "relationship_name: contains; entity_name: rag pipelines; entity_description: Retrieval-Augmented Generation pipelines combining retrieval with LLM generation."}}, {"source": "ee7307f2-cba9-5003-9dc0-0780c50591a6", "target": "ba1f1dac-e2fb-5464-914d-ff54b9b19787", "relation": "contains", "weight": null, "all_weights": {}, "relationship_type": "contains", "edge_info": {"source_node_id": "ee7307f2-cba9-5003-9dc0-0780c50591a6", "target_node_id": "ba1f1dac-e2fb-5464-914d-ff54b9b19787", "relationship_name": "contains", "updated_at": "2026-03-20 23:21:04", "relationship_type": "contains", "edge_text": "relationship_name: contains; entity_name: agents; entity_description: Agent systems that orchestrate actions and LLM calls."}}, {"source": "ee7307f2-cba9-5003-9dc0-0780c50591a6", "target": "a1a666e4-2070-59fd-95f7-c4c6178e89ba", "relation": "contains", "weight": null, "all_weights": {}, "relationship_type": "contains", "edge_info": {"source_node_id": "ee7307f2-cba9-5003-9dc0-0780c50591a6", "target_node_id": "a1a666e4-2070-59fd-95f7-c4c6178e89ba", "relationship_name": "contains", "updated_at": "2026-03-20 23:21:04", "relationship_type": "contains", "edge_text": "relationship_name: contains; entity_name: search systems; entity_description: Systems for information retrieval and search."}}, {"source": "ee7307f2-cba9-5003-9dc0-0780c50591a6", "target": "30f5dcb9-d238-5c7d-8d2a-b9da0b854f98", "relation": "contains", "weight": null, "all_weights": {}, "relationship_type": "contains", "edge_info": {"source_node_id": "ee7307f2-cba9-5003-9dc0-0780c50591a6", "target_node_id": "30f5dcb9-d238-5c7d-8d2a-b9da0b854f98", "relationship_name": "contains", "updated_at": "2026-03-20 23:21:04", "relationship_type": "contains", "edge_text": "relationship_name: contains; entity_name: component-based architecture; entity_description: Architecture composed of modular components where each step is a building block."}}, {"source": "ee7307f2-cba9-5003-9dc0-0780c50591a6", "target": "f010bf52-6eb5-511f-bbed-cd5237545edd", "relation": "contains", "weight": null, "all_weights": {}, "relationship_type": "contains", "edge_info": {"source_node_id": "ee7307f2-cba9-5003-9dc0-0780c50591a6", "target_node_id": "f010bf52-6eb5-511f-bbed-cd5237545edd", "relationship_name": "contains", "updated_at": "2026-03-20 23:21:04", "relationship_type": "contains", "edge_text": "relationship_name: contains; entity_name: retrieval; entity_description: A retrieval step/component in the pipeline."}}, {"source": "ee7307f2-cba9-5003-9dc0-0780c50591a6", "target": "dba0457b-9aff-5eb6-8ccd-19f7c9ae4dfa", "relation": "contains", "weight": null, "all_weights": {}, "relationship_type": "contains", "edge_info": {"source_node_id": "ee7307f2-cba9-5003-9dc0-0780c50591a6", "target_node_id": "dba0457b-9aff-5eb6-8ccd-19f7c9ae4dfa", "relationship_name": "contains", "updated_at": "2026-03-20 23:21:04", "relationship_type": "contains", "edge_text": "relationship_name: contains; entity_name: generation; entity_description: A generation (LLM) step/component in the pipeline."}}, {"source": "ee7307f2-cba9-5003-9dc0-0780c50591a6", "target": "59cf88c0-cb09-5f96-9252-5f5810981bcc", "relation": "contains", "weight": null, "all_weights": {}, "relationship_type": "contains", "edge_info": {"source_node_id": "ee7307f2-cba9-5003-9dc0-0780c50591a6", "target_node_id": "59cf88c0-cb09-5f96-9252-5f5810981bcc", "relationship_name": "contains", "updated_at": "2026-03-20 23:21:04", "relationship_type": "contains", "edge_text": "relationship_name: contains; entity_name: composable building block; entity_description: A modular, composable building block representing an individual step in the architecture."}}, {"source": "ee7307f2-cba9-5003-9dc0-0780c50591a6", "target": "1a7434a3-3266-5111-9501-4fe093f36076", "relation": "is_part_of", "weight": null, "all_weights": {}, "relationship_type": null, "edge_info": {"source_node_id": "ee7307f2-cba9-5003-9dc0-0780c50591a6", "target_node_id": "1a7434a3-3266-5111-9501-4fe093f36076", "relationship_name": "is_part_of", "updated_at": "2026-03-20 23:21:04"}}, {"source": "2bdd3deb-07d8-5413-a56d-1643e3ceb48b", "target": "2d66edc2-1e14-55ab-8304-680b514a597a", "relation": "is_a", "weight": null, "all_weights": {}, "relationship_type": null, "edge_info": {"source_node_id": "2bdd3deb-07d8-5413-a56d-1643e3ceb48b", "target_node_id": "2d66edc2-1e14-55ab-8304-680b514a597a", "relationship_name": "is_a", "updated_at": "2026-03-20 23:21:04"}}, {"source": "2bdd3deb-07d8-5413-a56d-1643e3ceb48b", "target": "126df7ec-d0db-53ea-bc88-1bafd84c8646", "relation": "developed_by", "weight": null, "all_weights": {}, "relationship_type": null, "edge_info": {"relationship_name": "developed_by", "source_node_id": "2bdd3deb-07d8-5413-a56d-1643e3ceb48b", "target_node_id": "126df7ec-d0db-53ea-bc88-1bafd84c8646", "ontology_valid": false}}, {"source": "2bdd3deb-07d8-5413-a56d-1643e3ceb48b", "target": "7594343c-5532-5896-b0aa-be5c1a74bd92", "relation": "used_to_build", "weight": null, "all_weights": {}, "relationship_type": null, "edge_info": {"relationship_name": "used_to_build", "source_node_id": "2bdd3deb-07d8-5413-a56d-1643e3ceb48b", "target_node_id": "7594343c-5532-5896-b0aa-be5c1a74bd92", "ontology_valid": false}}, {"source": "2bdd3deb-07d8-5413-a56d-1643e3ceb48b", "target": "ba1f1dac-e2fb-5464-914d-ff54b9b19787", "relation": "used_to_build", "weight": null, "all_weights": {}, "relationship_type": null, "edge_info": {"relationship_name": "used_to_build", "source_node_id": "2bdd3deb-07d8-5413-a56d-1643e3ceb48b", "target_node_id": "ba1f1dac-e2fb-5464-914d-ff54b9b19787", "ontology_valid": false}}, {"source": "2bdd3deb-07d8-5413-a56d-1643e3ceb48b", "target": "a1a666e4-2070-59fd-95f7-c4c6178e89ba", "relation": "used_to_build", "weight": null, "all_weights": {}, "relationship_type": null, "edge_info": {"relationship_name": "used_to_build", "source_node_id": "2bdd3deb-07d8-5413-a56d-1643e3ceb48b", "target_node_id": "a1a666e4-2070-59fd-95f7-c4c6178e89ba", "ontology_valid": false}}, {"source": "2bdd3deb-07d8-5413-a56d-1643e3ceb48b", "target": "30f5dcb9-d238-5c7d-8d2a-b9da0b854f98", "relation": "uses_architecture", "weight": null, "all_weights": {}, "relationship_type": null, "edge_info": {"relationship_name": "uses_architecture", "source_node_id": "2bdd3deb-07d8-5413-a56d-1643e3ceb48b", "target_node_id": "30f5dcb9-d238-5c7d-8d2a-b9da0b854f98", "ontology_valid": false}}, {"source": "126df7ec-d0db-53ea-bc88-1bafd84c8646", "target": "d3d7b6b4-9b0d-52e8-9e09-a9e9cf4b5a4d", "relation": "is_a", "weight": null, "all_weights": {}, "relationship_type": null, "edge_info": {"source_node_id": "126df7ec-d0db-53ea-bc88-1bafd84c8646", "target_node_id": "d3d7b6b4-9b0d-52e8-9e09-a9e9cf4b5a4d", "relationship_name": "is_a", "updated_at": "2026-03-20 23:21:04"}}, {"source": "7594343c-5532-5896-b0aa-be5c1a74bd92", "target": "dd9713b7-dc20-5101-aad0-1c4216811147", "relation": "is_a", "weight": null, "all_weights": {}, "relationship_type": null, "edge_info": {"source_node_id": "7594343c-5532-5896-b0aa-be5c1a74bd92", "target_node_id": "dd9713b7-dc20-5101-aad0-1c4216811147", "relationship_name": "is_a", "updated_at": "2026-03-20 23:21:04"}}, {"source": "ba1f1dac-e2fb-5464-914d-ff54b9b19787", "target": "dd9713b7-dc20-5101-aad0-1c4216811147", "relation": "is_a", "weight": null, "all_weights": {}, "relationship_type": null, "edge_info": {"source_node_id": "ba1f1dac-e2fb-5464-914d-ff54b9b19787", "target_node_id": "dd9713b7-dc20-5101-aad0-1c4216811147", "relationship_name": "is_a", "updated_at": "2026-03-20 23:21:04"}}, {"source": "a1a666e4-2070-59fd-95f7-c4c6178e89ba", "target": "dd9713b7-dc20-5101-aad0-1c4216811147", "relation": "is_a", "weight": null, "all_weights": {}, "relationship_type": null, "edge_info": {"source_node_id": "a1a666e4-2070-59fd-95f7-c4c6178e89ba", "target_node_id": "dd9713b7-dc20-5101-aad0-1c4216811147", "relationship_name": "is_a", "updated_at": "2026-03-20 23:21:04"}}, {"source": "30f5dcb9-d238-5c7d-8d2a-b9da0b854f98", "target": "dd9713b7-dc20-5101-aad0-1c4216811147", "relation": "is_a", "weight": null, "all_weights": {}, "relationship_type": null, "edge_info": {"source_node_id": "30f5dcb9-d238-5c7d-8d2a-b9da0b854f98", "target_node_id": "dd9713b7-dc20-5101-aad0-1c4216811147", "relationship_name": "is_a", "updated_at": "2026-03-20 23:21:04"}}, {"source": "30f5dcb9-d238-5c7d-8d2a-b9da0b854f98", "target": "f010bf52-6eb5-511f-bbed-cd5237545edd", "relation": "includes_component", "weight": null, "all_weights": {}, "relationship_type": null, "edge_info": {"relationship_name": "includes_component", "source_node_id": "30f5dcb9-d238-5c7d-8d2a-b9da0b854f98", "target_node_id": "f010bf52-6eb5-511f-bbed-cd5237545edd", "ontology_valid": false}}, {"source": "30f5dcb9-d238-5c7d-8d2a-b9da0b854f98", "target": "dba0457b-9aff-5eb6-8ccd-19f7c9ae4dfa", "relation": "includes_component", "weight": null, "all_weights": {}, "relationship_type": null, "edge_info": {"relationship_name": "includes_component", "source_node_id": "30f5dcb9-d238-5c7d-8d2a-b9da0b854f98", "target_node_id": "dba0457b-9aff-5eb6-8ccd-19f7c9ae4dfa", "ontology_valid": false}}, {"source": "f010bf52-6eb5-511f-bbed-cd5237545edd", "target": "b283358b-c288-5ca1-a6e8-05bac88f7a6f", "relation": "is_a", "weight": null, "all_weights": {}, "relationship_type": null, "edge_info": {"source_node_id": "f010bf52-6eb5-511f-bbed-cd5237545edd", "target_node_id": "b283358b-c288-5ca1-a6e8-05bac88f7a6f", "relationship_name": "is_a", "updated_at": "2026-03-20 23:21:04"}}, {"source": "f010bf52-6eb5-511f-bbed-cd5237545edd", "target": "59cf88c0-cb09-5f96-9252-5f5810981bcc", "relation": "is_composable_building_block", "weight": null, "all_weights": {}, "relationship_type": null, "edge_info": {"relationship_name": "is_composable_building_block", "source_node_id": "f010bf52-6eb5-511f-bbed-cd5237545edd", "target_node_id": "59cf88c0-cb09-5f96-9252-5f5810981bcc", "ontology_valid": false}}, {"source": "dba0457b-9aff-5eb6-8ccd-19f7c9ae4dfa", "target": "b283358b-c288-5ca1-a6e8-05bac88f7a6f", "relation": "is_a", "weight": null, "all_weights": {}, "relationship_type": null, "edge_info": {"source_node_id": "dba0457b-9aff-5eb6-8ccd-19f7c9ae4dfa", "target_node_id": "b283358b-c288-5ca1-a6e8-05bac88f7a6f", "relationship_name": "is_a", "updated_at": "2026-03-20 23:21:04"}}, {"source": "dba0457b-9aff-5eb6-8ccd-19f7c9ae4dfa", "target": "59cf88c0-cb09-5f96-9252-5f5810981bcc", "relation": "is_composable_building_block", "weight": null, "all_weights": {}, "relationship_type": null, "edge_info": {"relationship_name": "is_composable_building_block", "source_node_id": "dba0457b-9aff-5eb6-8ccd-19f7c9ae4dfa", "target_node_id": "59cf88c0-cb09-5f96-9252-5f5810981bcc", "ontology_valid": false}}, {"source": "59cf88c0-cb09-5f96-9252-5f5810981bcc", "target": "dd9713b7-dc20-5101-aad0-1c4216811147", "relation": "is_a", "weight": null, "all_weights": {}, "relationship_type": null, "edge_info": {"source_node_id": "59cf88c0-cb09-5f96-9252-5f5810981bcc", "target_node_id": "dd9713b7-dc20-5101-aad0-1c4216811147", "relationship_name": "is_a", "updated_at": "2026-03-20 23:21:04"}}, {"source": "8a75198a-6b32-5a14-926f-ae42589088af", "target": "601f27c0-4582-5a13-89d3-64a8c0f15cc1", "relation": "made_from", "weight": null, "all_weights": {}, "relationship_type": null, "edge_info": {"source_node_id": "8a75198a-6b32-5a14-926f-ae42589088af", "target_node_id": "601f27c0-4582-5a13-89d3-64a8c0f15cc1", "relationship_name": "made_from", "updated_at": "2026-03-20 23:21:01"}}, {"source": "349bab63-8b60-5d59-a1f2-a4413b6377f2", "target": "c569abe9-16f1-54e0-ab9c-a4223e1088e1", "relation": "made_from", "weight": null, "all_weights": {}, "relationship_type": null, "edge_info": {"source_node_id": "349bab63-8b60-5d59-a1f2-a4413b6377f2", "target_node_id": "c569abe9-16f1-54e0-ab9c-a4223e1088e1", "relationship_name": "made_from", "updated_at": "2026-03-20 23:21:03"}}, {"source": "16c06ddd-c7f6-5d74-9ed4-a4520ffde7ca", "target": "bc815248-f743-5faa-b176-a216cf9e908e", "relation": "made_from", "weight": null, "all_weights": {}, "relationship_type": null, "edge_info": {"source_node_id": "16c06ddd-c7f6-5d74-9ed4-a4520ffde7ca", "target_node_id": "bc815248-f743-5faa-b176-a216cf9e908e", "relationship_name": "made_from", "updated_at": "2026-03-20 23:21:04"}}, {"source": "208e9fa9-a281-5f67-8f8f-4b78c917c467", "target": "ee7307f2-cba9-5003-9dc0-0780c50591a6", "relation": "made_from", "weight": null, "all_weights": {}, "relationship_type": null, "edge_info": {"source_node_id": "208e9fa9-a281-5f67-8f8f-4b78c917c467", "target_node_id": "ee7307f2-cba9-5003-9dc0-0780c50591a6", "relationship_name": "made_from", "updated_at": "2026-03-20 23:21:04"}}]; var taskColors = {"classify_documents": "#db5656", "extract_chunks_from_documents": "#56db7d", "extract_graph_from_data": "#a456db", "summarize_text": "#dbca56"}; var pipelineColors = {"cognify_pipeline": "#db5656"}; var nodesetColors = {}; diff --git a/integrations/cognee/examples/demo_memory_agent.py b/integrations/cognee/examples/demo_memory_agent.py index cf7c5e8b76..783b520b29 100644 --- a/integrations/cognee/examples/demo_memory_agent.py +++ b/integrations/cognee/examples/demo_memory_agent.py @@ -18,7 +18,7 @@ from cognee.api.v1.visualize.visualize import visualize_graph from haystack.dataclasses import ChatMessage -from haystack_integrations.components.connectors.cognee import CogneeMemoryStore +from haystack_integrations.memory_stores.cognee import CogneeMemoryStore async def main(): diff --git a/integrations/cognee/examples/demo_pipeline.py b/integrations/cognee/examples/demo_pipeline.py index 72ffe630f6..edd4fd75e6 100644 --- a/integrations/cognee/examples/demo_pipeline.py +++ b/integrations/cognee/examples/demo_pipeline.py @@ -18,7 +18,8 @@ from cognee.api.v1.visualize.visualize import visualize_graph from haystack import Document, Pipeline -from haystack_integrations.components.connectors.cognee import CogneeRetriever, CogneeWriter +from haystack_integrations.components.retrievers.cognee import CogneeRetriever +from haystack_integrations.components.writers.cognee import CogneeWriter SAMPLE_DOCUMENTS = [ Document( diff --git a/integrations/cognee/pyproject.toml b/integrations/cognee/pyproject.toml index 2f0e6a5c4d..e96928e3b8 100644 --- a/integrations/cognee/pyproject.toml +++ b/integrations/cognee/pyproject.toml @@ -25,7 +25,6 @@ classifiers = [ dependencies = [ "haystack-ai>=2.24.0", "cognee==0.5.4", - "mistralai>=1.0,<2.0", ] [project.optional-dependencies] @@ -73,7 +72,7 @@ integration = 'pytest -m "integration" {args:tests}' all = 'pytest {args:tests}' cov-retry = 'pytest --cov=haystack_integrations --reruns 3 --reruns-delay 30 -x {args:tests}' -types = "mypy -p haystack_integrations.components.connectors.cognee {args}" +types = "mypy -p haystack_integrations.components.connectors.cognee -p haystack_integrations.components.retrievers.cognee -p haystack_integrations.components.writers.cognee -p haystack_integrations.memory_stores.cognee {args}" [tool.mypy] install_types = true diff --git a/integrations/cognee/src/haystack_integrations/components/connectors/cognee/__init__.py b/integrations/cognee/src/haystack_integrations/components/connectors/cognee/__init__.py index 2698fcbc21..775c5a35e4 100644 --- a/integrations/cognee/src/haystack_integrations/components/connectors/cognee/__init__.py +++ b/integrations/cognee/src/haystack_integrations/components/connectors/cognee/__init__.py @@ -3,13 +3,7 @@ # SPDX-License-Identifier: Apache-2.0 from .cognifier import CogneeCognifier -from .memory_store import CogneeMemoryStore -from .retriever import CogneeRetriever -from .writer import CogneeWriter __all__ = [ "CogneeCognifier", - "CogneeMemoryStore", - "CogneeRetriever", - "CogneeWriter", ] diff --git a/integrations/cognee/src/haystack_integrations/components/connectors/cognee/_utils.py b/integrations/cognee/src/haystack_integrations/components/connectors/cognee/_utils.py index 49638e81b0..c704bca6c9 100644 --- a/integrations/cognee/src/haystack_integrations/components/connectors/cognee/_utils.py +++ b/integrations/cognee/src/haystack_integrations/components/connectors/cognee/_utils.py @@ -5,10 +5,27 @@ import asyncio from collections.abc import Coroutine from concurrent.futures import ThreadPoolExecutor -from typing import Any, TypeVar +from typing import Any, Literal, TypeVar T = TypeVar("T") +CogneeSearchType = Literal[ + "GRAPH_COMPLETION", + "RAG_COMPLETION", + "CHUNKS", + "CHUNKS_LEXICAL", + "SUMMARIES", + "TRIPLET_COMPLETION", + "GRAPH_SUMMARY_COMPLETION", + "GRAPH_COMPLETION_COT", + "GRAPH_COMPLETION_CONTEXT_EXTENSION", + "CYPHER", + "NATURAL_LANGUAGE", + "TEMPORAL", + "CODING_RULES", + "FEELING_LUCKY", +] + def run_sync(coro: Coroutine[Any, Any, T]) -> T: """ @@ -27,3 +44,22 @@ def run_sync(coro: Coroutine[Any, Any, T]) -> T: with ThreadPoolExecutor(max_workers=1) as pool: future = pool.submit(asyncio.run, coro) return future.result() + + +def extract_text(item: Any) -> str: + """Best-effort text extraction from a Cognee search result item.""" + if isinstance(item, str): + return item + + for attr in ("content", "text", "description", "name"): + if hasattr(item, attr): + val = getattr(item, attr) + if val and isinstance(val, str): + return val + + if isinstance(item, dict): + for key in ("content", "text", "description", "name"): + if key in item and isinstance(item[key], str): + return item[key] + + return str(item) diff --git a/integrations/cognee/src/haystack_integrations/components/connectors/cognee/cognifier.py b/integrations/cognee/src/haystack_integrations/components/connectors/cognee/cognifier.py index 09fa6c9c97..8f983314c7 100644 --- a/integrations/cognee/src/haystack_integrations/components/connectors/cognee/cognifier.py +++ b/integrations/cognee/src/haystack_integrations/components/connectors/cognee/cognifier.py @@ -16,35 +16,69 @@ @component class CogneeCognifier: """ - Processes previously added data in Cognee's knowledge engine. + Processes previously added data through Cognee's knowledge engine. - Wraps `cognee.cognify()` as a standalone pipeline step, useful when you - want to separate the add and cognify phases (e.g., batch-add first, then - cognify once). + Wraps `cognee.cognify()` as a standalone pipeline step. Cognify takes raw data + that was previously added via `cognee.add()` and transforms it into a structured + knowledge graph. The process includes: + + 1. **Document classification** — identifies the type and structure of the input data. + 2. **Text chunking** — splits documents into semantically meaningful segments. + 3. **Entity extraction** — uses an LLM to identify entities and their properties. + 4. **Relationship detection** — discovers connections between extracted entities. + 5. **Graph construction** — builds a knowledge graph with embeddings for vector search. + 6. **Summarization** — generates hierarchical summaries of the processed content. + + After cognification, the data becomes searchable via `cognee.search()` using various + strategies (graph traversal, vector similarity, summaries, etc.). + + This component is useful when you want to separate the add and cognify phases — + for example, batch-add documents first with `CogneeWriter(auto_cognify=False)`, + then cognify once. Usage: ```python + from haystack import Pipeline + from haystack_integrations.components.writers.cognee import CogneeWriter from haystack_integrations.components.connectors.cognee import CogneeCognifier - cognifier = CogneeCognifier() - result = cognifier.run() - assert result["cognified"] is True + pipeline = Pipeline() + pipeline.add_component("writer", CogneeWriter(dataset_name="my_data", auto_cognify=False)) + pipeline.add_component("cognifier", CogneeCognifier(dataset_name="my_data")) + pipeline.connect("writer.documents_written", "cognifier.documents_written") + + result = pipeline.run({"writer": {"documents": docs}}) ``` """ + def __init__(self, dataset_name: str | list[str] | None = None): + """ + :param dataset_name: Optional Cognee dataset name(s) to cognify. Accepts a single + name, a list of names, or None to cognify all pending datasets. + """ + self.dataset_name = dataset_name + @component.output_types(cognified=bool) - def run(self) -> dict[str, Any]: + def run(self, documents_written: int | None = None) -> dict[str, Any]: """ - Run cognee.cognify() to process added data into the memory. + Run cognee.cognify() to process added data into the knowledge graph. + :param documents_written: Optional number of documents written by a preceding + CogneeWriter. Used as a pipeline connection point; cognify runs regardless + of the value, as long as data has been previously added. :returns: Dictionary with key `cognified` set to True on success. """ + cognify_kwargs: dict[str, Any] = {} + if self.dataset_name: + datasets = [self.dataset_name] if isinstance(self.dataset_name, str) else self.dataset_name + cognify_kwargs["datasets"] = datasets + logger.info("Running cognee.cognify()") - run_sync(cognee.cognify()) + run_sync(cognee.cognify(**cognify_kwargs)) return {"cognified": True} def to_dict(self) -> dict[str, Any]: - return default_to_dict(self) + return default_to_dict(self, dataset_name=self.dataset_name) @classmethod def from_dict(cls, data: dict[str, Any]) -> "CogneeCognifier": diff --git a/integrations/cognee/src/haystack_integrations/components/connectors/cognee/py.typed b/integrations/cognee/src/haystack_integrations/components/connectors/py.typed similarity index 100% rename from integrations/cognee/src/haystack_integrations/components/connectors/cognee/py.typed rename to integrations/cognee/src/haystack_integrations/components/connectors/py.typed diff --git a/integrations/cognee/src/haystack_integrations/components/retrievers/cognee/__init__.py b/integrations/cognee/src/haystack_integrations/components/retrievers/cognee/__init__.py new file mode 100644 index 0000000000..90cf73038c --- /dev/null +++ b/integrations/cognee/src/haystack_integrations/components/retrievers/cognee/__init__.py @@ -0,0 +1,9 @@ +# SPDX-FileCopyrightText: 2022-present deepset GmbH +# +# SPDX-License-Identifier: Apache-2.0 + +from .memory_retriever import CogneeRetriever + +__all__ = [ + "CogneeRetriever", +] diff --git a/integrations/cognee/src/haystack_integrations/components/connectors/cognee/retriever.py b/integrations/cognee/src/haystack_integrations/components/retrievers/cognee/memory_retriever.py similarity index 74% rename from integrations/cognee/src/haystack_integrations/components/connectors/cognee/retriever.py rename to integrations/cognee/src/haystack_integrations/components/retrievers/cognee/memory_retriever.py index 5c369dfcfd..a5aca52d33 100644 --- a/integrations/cognee/src/haystack_integrations/components/connectors/cognee/retriever.py +++ b/integrations/cognee/src/haystack_integrations/components/retrievers/cognee/memory_retriever.py @@ -8,13 +8,10 @@ import cognee # type: ignore[import-untyped] from cognee.api.v1.search import SearchType # type: ignore[import-untyped] - -from ._utils import run_sync +from haystack_integrations.components.connectors.cognee._utils import CogneeSearchType, extract_text, run_sync logger = logging.getLogger(__name__) -_VALID_SEARCH_TYPES = {member.name for member in SearchType} - @component class CogneeRetriever: @@ -25,7 +22,7 @@ class CogneeRetriever: Usage: ```python - from haystack_integrations.components.connectors.cognee import CogneeRetriever + from haystack_integrations.components.retrievers.cognee import CogneeRetriever retriever = CogneeRetriever(search_type="GRAPH_COMPLETION", top_k=5) results = retriever.run(query="What is Cognee?") @@ -34,17 +31,15 @@ class CogneeRetriever: ``` """ - def __init__(self, search_type: str = "GRAPH_COMPLETION", top_k: int = 10, dataset_name: str | None = None): + def __init__( + self, search_type: CogneeSearchType = "GRAPH_COMPLETION", top_k: int = 10, dataset_name: str | None = None + ): """ :param search_type: Cognee search type. One of: GRAPH_COMPLETION, CHUNKS, SUMMARIES, INSIGHTS, etc. :param top_k: Maximum number of results to return. :param dataset_name: Optional dataset name to restrict search scope. """ - if search_type not in _VALID_SEARCH_TYPES: - msg = f"Invalid search_type '{search_type}'. Must be one of: {sorted(_VALID_SEARCH_TYPES)}" - raise ValueError(msg) - self.search_type = search_type self.top_k = top_k self.dataset_name = dataset_name @@ -100,7 +95,7 @@ def _convert_results(raw_results: list[Any], top_k: int) -> list[Document]: return documents for item in raw_results[:top_k]: - text = _extract_text(item) + text = extract_text(item) if text: documents.append( Document( @@ -109,22 +104,3 @@ def _convert_results(raw_results: list[Any], top_k: int) -> list[Document]: ) ) return documents - - -def _extract_text(item: Any) -> str: - """Best-effort text extraction from a Cognee search result item.""" - if isinstance(item, str): - return item - - for attr in ("content", "text", "description", "name"): - if hasattr(item, attr): - val = getattr(item, attr) - if val and isinstance(val, str): - return val - - if isinstance(item, dict): - for key in ("content", "text", "description", "name"): - if key in item and isinstance(item[key], str): - return item[key] - - return str(item) diff --git a/integrations/cognee/src/haystack_integrations/components/writers/cognee/__init__.py b/integrations/cognee/src/haystack_integrations/components/writers/cognee/__init__.py new file mode 100644 index 0000000000..7d88e60c29 --- /dev/null +++ b/integrations/cognee/src/haystack_integrations/components/writers/cognee/__init__.py @@ -0,0 +1,9 @@ +# SPDX-FileCopyrightText: 2022-present deepset GmbH +# +# SPDX-License-Identifier: Apache-2.0 + +from .memory_writer import CogneeWriter + +__all__ = [ + "CogneeWriter", +] diff --git a/integrations/cognee/src/haystack_integrations/components/connectors/cognee/writer.py b/integrations/cognee/src/haystack_integrations/components/writers/cognee/memory_writer.py similarity index 79% rename from integrations/cognee/src/haystack_integrations/components/connectors/cognee/writer.py rename to integrations/cognee/src/haystack_integrations/components/writers/cognee/memory_writer.py index 1c504ee31a..a61f0577bb 100644 --- a/integrations/cognee/src/haystack_integrations/components/connectors/cognee/writer.py +++ b/integrations/cognee/src/haystack_integrations/components/writers/cognee/memory_writer.py @@ -7,8 +7,7 @@ from haystack import Document, component, default_from_dict, default_to_dict, logging import cognee # type: ignore[import-untyped] - -from ._utils import run_sync +from haystack_integrations.components.connectors.cognee._utils import run_sync logger = logging.getLogger(__name__) @@ -24,7 +23,7 @@ class CogneeWriter: Usage: ```python from haystack import Document - from haystack_integrations.components.connectors.cognee import CogneeWriter + from haystack_integrations.components.writers.cognee import CogneeWriter writer = CogneeWriter(dataset_name="my_dataset", auto_cognify=True) writer.run(documents=[Document(content="Cognee builds AI memory.")]) @@ -49,13 +48,15 @@ def run(self, documents: list[Document]) -> dict[str, Any]: :returns: Dictionary with key `documents_written` indicating how many documents were successfully added. """ - written = 0 - for doc in documents: - if not doc.content: - logger.warning("Skipping document with empty content: {doc_id}", doc_id=doc.id) - continue - run_sync(cognee.add(doc.content, dataset_name=self.dataset_name)) - written += 1 + texts = [doc.content for doc in documents if doc.content] + skipped = len(documents) - len(texts) + if skipped > 0: + logger.warning("Skipping {count} document(s) with empty content", count=skipped) + + if texts: + run_sync(cognee.add(texts, dataset_name=self.dataset_name)) + + written = len(texts) if self.auto_cognify and written > 0: logger.info( @@ -63,7 +64,7 @@ def run(self, documents: list[Document]) -> dict[str, Any]: count=written, dataset=self.dataset_name, ) - run_sync(cognee.cognify()) + run_sync(cognee.cognify(datasets=[self.dataset_name])) return {"documents_written": written} diff --git a/integrations/cognee/src/haystack_integrations/memory_stores/cognee/__init__.py b/integrations/cognee/src/haystack_integrations/memory_stores/cognee/__init__.py new file mode 100644 index 0000000000..eb9a6b81a8 --- /dev/null +++ b/integrations/cognee/src/haystack_integrations/memory_stores/cognee/__init__.py @@ -0,0 +1,9 @@ +# SPDX-FileCopyrightText: 2022-present deepset GmbH +# +# SPDX-License-Identifier: Apache-2.0 + +from .memory_store import CogneeMemoryStore + +__all__ = [ + "CogneeMemoryStore", +] diff --git a/integrations/cognee/src/haystack_integrations/components/connectors/cognee/memory_store.py b/integrations/cognee/src/haystack_integrations/memory_stores/cognee/memory_store.py similarity index 59% rename from integrations/cognee/src/haystack_integrations/components/connectors/cognee/memory_store.py rename to integrations/cognee/src/haystack_integrations/memory_stores/cognee/memory_store.py index 452c16be9c..4479edaf9b 100644 --- a/integrations/cognee/src/haystack_integrations/components/connectors/cognee/memory_store.py +++ b/integrations/cognee/src/haystack_integrations/memory_stores/cognee/memory_store.py @@ -9,8 +9,7 @@ import cognee # type: ignore[import-untyped] from cognee.api.v1.search import SearchType # type: ignore[import-untyped] - -from ._utils import run_sync +from haystack_integrations.components.connectors.cognee._utils import CogneeSearchType, extract_text, run_sync logger = logging.getLogger(__name__) @@ -24,7 +23,7 @@ class CogneeMemoryStore: Usage: ```python - from haystack_integrations.components.connectors.cognee import CogneeMemoryStore + from haystack_integrations.memory_stores.cognee import CogneeMemoryStore store = CogneeMemoryStore(search_type="GRAPH_COMPLETION", top_k=5) store.add_memories(messages=[ChatMessage.from_user("Remember: the project deadline is Friday.")]) @@ -32,7 +31,9 @@ class CogneeMemoryStore: ``` """ - def __init__(self, search_type: str = "GRAPH_COMPLETION", top_k: int = 5, dataset_name: str = "haystack_memory"): + def __init__( + self, search_type: CogneeSearchType = "GRAPH_COMPLETION", top_k: int = 5, dataset_name: str = "haystack_memory" + ): """ :param search_type: Cognee search type for memory retrieval. :param top_k: Default number of results for memory search. @@ -42,22 +43,11 @@ def __init__(self, search_type: str = "GRAPH_COMPLETION", top_k: int = 5, datase self.top_k = top_k self.dataset_name = dataset_name - def add_memories( - self, - *, - messages: list[ChatMessage], - user_id: str | None = None, - agent_id: str | None = None, - run_id: str | None = None, - **kwargs: Any, - ) -> None: + def add_memories(self, *, messages: list[ChatMessage]) -> None: """ - Add chat messages to Cognee as memories and cognify them. + Add chat messages to Cognee as memories. :param messages: List of ChatMessages to store. - :param user_id: Optional user identifier (reserved for future use). - :param agent_id: Optional agent identifier (reserved for future use). - :param run_id: Optional run identifier (reserved for future use). """ for msg in messages: text = msg.text @@ -65,27 +55,15 @@ def add_memories( continue run_sync(cognee.add(text, dataset_name=self.dataset_name)) - run_sync(cognee.cognify()) + run_sync(cognee.cognify(datasets=[self.dataset_name])) logger.info("Added and cognified {count} messages as memories", count=len(messages)) - def search_memories( - self, - *, - query: str | None = None, - top_k: int = 5, - user_id: str | None = None, - agent_id: str | None = None, - run_id: str | None = None, - **kwargs: Any, - ) -> list[ChatMessage]: + def search_memories(self, *, query: str | None = None, top_k: int = 5) -> list[ChatMessage]: """ Search Cognee's knowledge engine for relevant memories. :param query: The search query. :param top_k: Maximum number of memories to return. - :param user_id: Optional user identifier (reserved for future use). - :param agent_id: Optional agent identifier (reserved for future use). - :param run_id: Optional run identifier (reserved for future use). :returns: List of ChatMessages containing memory content as system messages. """ if not query: @@ -101,33 +79,22 @@ def search_memories( return memories for item in raw_results[:effective_top_k]: - text = _extract_memory_text(item) + text = extract_text(item) if text: memories.append(ChatMessage.from_system(text)) logger.info("Found {count} memories for query '{query}'", count=len(memories), query=query[:80]) return memories - def delete_all_memories( - self, - *, - user_id: str | None = None, - agent_id: str | None = None, - run_id: str | None = None, - **kwargs: Any, - ) -> None: + def delete_all_memories(self) -> None: """ Delete all memories by pruning Cognee's data and system state. - - :param user_id: Optional user identifier (reserved for future use). - :param agent_id: Optional agent identifier (reserved for future use). - :param run_id: Optional run identifier (reserved for future use). """ run_sync(cognee.prune.prune_data()) run_sync(cognee.prune.prune_system(metadata=True)) logger.info("All Cognee memories pruned") - def delete_memory(self, memory_id: str, **kwargs: Any) -> None: + def delete_memory(self, memory_id: str) -> None: """ Delete a single memory by ID. @@ -150,22 +117,3 @@ def to_dict(self) -> dict[str, Any]: @classmethod def from_dict(cls, data: dict[str, Any]) -> "CogneeMemoryStore": return default_from_dict(cls, data) - - -def _extract_memory_text(item: Any) -> str: - """Best-effort text extraction from a Cognee search result item.""" - if isinstance(item, str): - return item - - for attr in ("content", "text", "description", "name"): - if hasattr(item, attr): - val = getattr(item, attr) - if val and isinstance(val, str): - return val - - if isinstance(item, dict): - for key in ("content", "text", "description", "name"): - if key in item and isinstance(item[key], str): - return item[key] - - return str(item) diff --git a/integrations/cognee/tests/test_memory_store.py b/integrations/cognee/tests/test_memory_store.py index 937c8eb24e..91ec58b371 100644 --- a/integrations/cognee/tests/test_memory_store.py +++ b/integrations/cognee/tests/test_memory_store.py @@ -7,7 +7,7 @@ import pytest from haystack.dataclasses import ChatMessage -from haystack_integrations.components.connectors.cognee import CogneeMemoryStore +from haystack_integrations.memory_stores.cognee import CogneeMemoryStore class TestCogneeMemoryStore: @@ -26,14 +26,14 @@ def test_init_custom(self): def test_to_dict(self): store = CogneeMemoryStore(search_type="SUMMARIES", top_k=3, dataset_name="mem") data = store.to_dict() - assert data["type"] == "haystack_integrations.components.connectors.cognee.memory_store.CogneeMemoryStore" + assert data["type"] == "haystack_integrations.memory_stores.cognee.memory_store.CogneeMemoryStore" assert data["init_parameters"]["search_type"] == "SUMMARIES" assert data["init_parameters"]["top_k"] == 3 assert data["init_parameters"]["dataset_name"] == "mem" def test_from_dict(self): data = { - "type": "haystack_integrations.components.connectors.cognee.memory_store.CogneeMemoryStore", + "type": "haystack_integrations.memory_stores.cognee.memory_store.CogneeMemoryStore", "init_parameters": {"search_type": "CHUNKS", "top_k": 8, "dataset_name": "restored"}, } store = CogneeMemoryStore.from_dict(data) @@ -41,7 +41,7 @@ def test_from_dict(self): assert store.top_k == 8 assert store.dataset_name == "restored" - @patch("haystack_integrations.components.connectors.cognee.memory_store.cognee") + @patch("haystack_integrations.memory_stores.cognee.memory_store.cognee") def test_add_memories(self, mock_cognee): mock_cognee.add = AsyncMock() mock_cognee.cognify = AsyncMock() @@ -56,7 +56,20 @@ def test_add_memories(self, mock_cognee): assert mock_cognee.add.await_count == 2 mock_cognee.cognify.assert_awaited_once() - @patch("haystack_integrations.components.connectors.cognee.memory_store.cognee") + @patch("haystack_integrations.memory_stores.cognee.memory_store.cognee") + def test_add_memories_cognify_uses_dataset(self, mock_cognee): + mock_cognee.add = AsyncMock() + mock_cognee.cognify = AsyncMock() + + store = CogneeMemoryStore(dataset_name="my_ds") + messages = [ChatMessage.from_user("Remember this.")] + store.add_memories(messages=messages) + + mock_cognee.cognify.assert_awaited_once() + cognify_kwargs = mock_cognee.cognify.call_args[1] + assert cognify_kwargs["datasets"] == ["my_ds"] + + @patch("haystack_integrations.memory_stores.cognee.memory_store.cognee") def test_search_memories(self, mock_cognee): mock_cognee.search = AsyncMock(return_value=["Memory about deadline"]) @@ -75,7 +88,7 @@ def test_search_memories_empty_query(self): results = store.search_memories(query="") assert results == [] - @patch("haystack_integrations.components.connectors.cognee.memory_store.cognee") + @patch("haystack_integrations.memory_stores.cognee.memory_store.cognee") def test_delete_all_memories(self, mock_cognee): mock_cognee.prune = type( "Prune", diff --git a/integrations/cognee/tests/test_retriever.py b/integrations/cognee/tests/test_retriever.py index ed5f1d8726..6494861db9 100644 --- a/integrations/cognee/tests/test_retriever.py +++ b/integrations/cognee/tests/test_retriever.py @@ -4,9 +4,7 @@ from unittest.mock import AsyncMock, patch -import pytest - -from haystack_integrations.components.connectors.cognee import CogneeRetriever +from haystack_integrations.components.retrievers.cognee import CogneeRetriever class TestCogneeRetriever: @@ -22,28 +20,24 @@ def test_init_custom(self): assert retriever.top_k == 5 assert retriever.dataset_name == "my_data" - def test_init_invalid_search_type(self): - with pytest.raises(ValueError, match="Invalid search_type"): - CogneeRetriever(search_type="INVALID_TYPE") - def test_to_dict(self): retriever = CogneeRetriever(search_type="SUMMARIES", top_k=3, dataset_name="ds") data = retriever.to_dict() - assert data["type"] == "haystack_integrations.components.connectors.cognee.retriever.CogneeRetriever" + assert data["type"] == "haystack_integrations.components.retrievers.cognee.memory_retriever.CogneeRetriever" assert data["init_parameters"]["search_type"] == "SUMMARIES" assert data["init_parameters"]["top_k"] == 3 assert data["init_parameters"]["dataset_name"] == "ds" def test_from_dict(self): data = { - "type": "haystack_integrations.components.connectors.cognee.retriever.CogneeRetriever", + "type": "haystack_integrations.components.retrievers.cognee.memory_retriever.CogneeRetriever", "init_parameters": {"search_type": "CHUNKS", "top_k": 7, "dataset_name": None}, } retriever = CogneeRetriever.from_dict(data) assert retriever.search_type == "CHUNKS" assert retriever.top_k == 7 - @patch("haystack_integrations.components.connectors.cognee.retriever.cognee") + @patch("haystack_integrations.components.retrievers.cognee.memory_retriever.cognee") def test_run_returns_documents(self, mock_cognee): mock_cognee.search = AsyncMock(return_value=["result one", "result two"]) @@ -55,7 +49,7 @@ def test_run_returns_documents(self, mock_cognee): assert docs[0].content == "result one" assert docs[0].meta["source"] == "cognee" - @patch("haystack_integrations.components.connectors.cognee.retriever.cognee") + @patch("haystack_integrations.components.retrievers.cognee.memory_retriever.cognee") def test_run_empty_results(self, mock_cognee): mock_cognee.search = AsyncMock(return_value=[]) @@ -64,7 +58,7 @@ def test_run_empty_results(self, mock_cognee): assert result["documents"] == [] - @patch("haystack_integrations.components.connectors.cognee.retriever.cognee") + @patch("haystack_integrations.components.retrievers.cognee.memory_retriever.cognee") def test_run_respects_top_k_override(self, mock_cognee): mock_cognee.search = AsyncMock(return_value=["a", "b", "c", "d", "e"]) @@ -73,7 +67,7 @@ def test_run_respects_top_k_override(self, mock_cognee): assert len(result["documents"]) == 2 - @patch("haystack_integrations.components.connectors.cognee.retriever.cognee") + @patch("haystack_integrations.components.retrievers.cognee.memory_retriever.cognee") def test_run_handles_dict_results(self, mock_cognee): mock_cognee.search = AsyncMock( return_value=[ @@ -89,7 +83,7 @@ def test_run_handles_dict_results(self, mock_cognee): assert result["documents"][0].content == "Dict content" assert result["documents"][1].content == "Alt text field" - @patch("haystack_integrations.components.connectors.cognee.retriever.cognee") + @patch("haystack_integrations.components.retrievers.cognee.memory_retriever.cognee") def test_run_handles_none_results(self, mock_cognee): mock_cognee.search = AsyncMock(return_value=None) diff --git a/integrations/cognee/tests/test_writer.py b/integrations/cognee/tests/test_writer.py index 597224b761..c8acc499af 100644 --- a/integrations/cognee/tests/test_writer.py +++ b/integrations/cognee/tests/test_writer.py @@ -6,7 +6,7 @@ from haystack import Document -from haystack_integrations.components.connectors.cognee import CogneeWriter +from haystack_integrations.components.writers.cognee import CogneeWriter class TestCogneeWriter: @@ -23,20 +23,20 @@ def test_init_custom(self): def test_to_dict(self): writer = CogneeWriter(dataset_name="test_ds", auto_cognify=False) data = writer.to_dict() - assert data["type"] == "haystack_integrations.components.connectors.cognee.writer.CogneeWriter" + assert data["type"] == "haystack_integrations.components.writers.cognee.memory_writer.CogneeWriter" assert data["init_parameters"]["dataset_name"] == "test_ds" assert data["init_parameters"]["auto_cognify"] is False def test_from_dict(self): data = { - "type": "haystack_integrations.components.connectors.cognee.writer.CogneeWriter", + "type": "haystack_integrations.components.writers.cognee.memory_writer.CogneeWriter", "init_parameters": {"dataset_name": "restored", "auto_cognify": True}, } writer = CogneeWriter.from_dict(data) assert writer.dataset_name == "restored" assert writer.auto_cognify is True - @patch("haystack_integrations.components.connectors.cognee.writer.cognee") + @patch("haystack_integrations.components.writers.cognee.memory_writer.cognee") def test_run_with_auto_cognify(self, mock_cognee): mock_cognee.add = AsyncMock() mock_cognee.cognify = AsyncMock() @@ -49,10 +49,16 @@ def test_run_with_auto_cognify(self, mock_cognee): result = writer.run(documents=docs) assert result == {"documents_written": 2} - assert mock_cognee.add.await_count == 2 + # Verify batch call: single add() with list of texts + mock_cognee.add.assert_awaited_once() + call_args = mock_cognee.add.call_args + assert call_args[0][0] == ["First document", "Second document"] + # Verify cognify uses specific dataset mock_cognee.cognify.assert_awaited_once() + cognify_kwargs = mock_cognee.cognify.call_args[1] + assert cognify_kwargs["datasets"] == ["test"] - @patch("haystack_integrations.components.connectors.cognee.writer.cognee") + @patch("haystack_integrations.components.writers.cognee.memory_writer.cognee") def test_run_without_auto_cognify(self, mock_cognee): mock_cognee.add = AsyncMock() mock_cognee.cognify = AsyncMock() @@ -65,7 +71,7 @@ def test_run_without_auto_cognify(self, mock_cognee): mock_cognee.add.assert_awaited_once() mock_cognee.cognify.assert_not_awaited() - @patch("haystack_integrations.components.connectors.cognee.writer.cognee") + @patch("haystack_integrations.components.writers.cognee.memory_writer.cognee") def test_run_skips_empty_content(self, mock_cognee): mock_cognee.add = AsyncMock() mock_cognee.cognify = AsyncMock() @@ -79,9 +85,11 @@ def test_run_skips_empty_content(self, mock_cognee): result = writer.run(documents=docs) assert result == {"documents_written": 1} - assert mock_cognee.add.await_count == 1 + mock_cognee.add.assert_awaited_once() + call_args = mock_cognee.add.call_args + assert call_args[0][0] == ["Valid document"] - @patch("haystack_integrations.components.connectors.cognee.writer.cognee") + @patch("haystack_integrations.components.writers.cognee.memory_writer.cognee") def test_run_empty_list(self, mock_cognee): mock_cognee.add = AsyncMock() mock_cognee.cognify = AsyncMock() From f93fc2121685cbc08ed39089987e1b1c953ee64f Mon Sep 17 00:00:00 2001 From: Hande <159312713+hande-k@users.noreply.github.com> Date: Sat, 21 Mar 2026 02:01:37 +0100 Subject: [PATCH 05/10] fix ci --- integrations/cognee/pydoc/config_docusaurus.yml | 6 +++--- .../haystack_integrations/components/retrievers/py.typed | 0 .../src/haystack_integrations/components/writers/py.typed | 0 .../memory_stores/cognee/memory_store.py | 8 ++++++-- .../src/haystack_integrations/memory_stores/py.typed | 0 5 files changed, 9 insertions(+), 5 deletions(-) create mode 100644 integrations/cognee/src/haystack_integrations/components/retrievers/py.typed create mode 100644 integrations/cognee/src/haystack_integrations/components/writers/py.typed create mode 100644 integrations/cognee/src/haystack_integrations/memory_stores/py.typed diff --git a/integrations/cognee/pydoc/config_docusaurus.yml b/integrations/cognee/pydoc/config_docusaurus.yml index 7804b76fb8..662b1f342e 100644 --- a/integrations/cognee/pydoc/config_docusaurus.yml +++ b/integrations/cognee/pydoc/config_docusaurus.yml @@ -1,9 +1,9 @@ loaders: - modules: - - haystack_integrations.components.connectors.cognee.writer - - haystack_integrations.components.connectors.cognee.retriever - haystack_integrations.components.connectors.cognee.cognifier - - haystack_integrations.components.connectors.cognee.memory_store + - haystack_integrations.components.retrievers.cognee.memory_retriever + - haystack_integrations.components.writers.cognee.memory_writer + - haystack_integrations.memory_stores.cognee.memory_store search_path: [../src] processors: - type: filter diff --git a/integrations/cognee/src/haystack_integrations/components/retrievers/py.typed b/integrations/cognee/src/haystack_integrations/components/retrievers/py.typed new file mode 100644 index 0000000000..e69de29bb2 diff --git a/integrations/cognee/src/haystack_integrations/components/writers/py.typed b/integrations/cognee/src/haystack_integrations/components/writers/py.typed new file mode 100644 index 0000000000..e69de29bb2 diff --git a/integrations/cognee/src/haystack_integrations/memory_stores/cognee/memory_store.py b/integrations/cognee/src/haystack_integrations/memory_stores/cognee/memory_store.py index 4479edaf9b..3979e03c6d 100644 --- a/integrations/cognee/src/haystack_integrations/memory_stores/cognee/memory_store.py +++ b/integrations/cognee/src/haystack_integrations/memory_stores/cognee/memory_store.py @@ -49,14 +49,18 @@ def add_memories(self, *, messages: list[ChatMessage]) -> None: :param messages: List of ChatMessages to store. """ + added = 0 for msg in messages: text = msg.text if not text: continue run_sync(cognee.add(text, dataset_name=self.dataset_name)) + added += 1 - run_sync(cognee.cognify(datasets=[self.dataset_name])) - logger.info("Added and cognified {count} messages as memories", count=len(messages)) + if added > 0: + run_sync(cognee.cognify(datasets=[self.dataset_name])) + + logger.info("Added and cognified {count} messages as memories", count=added) def search_memories(self, *, query: str | None = None, top_k: int = 5) -> list[ChatMessage]: """ diff --git a/integrations/cognee/src/haystack_integrations/memory_stores/py.typed b/integrations/cognee/src/haystack_integrations/memory_stores/py.typed new file mode 100644 index 0000000000..e69de29bb2 From 6ea4f130eab97f95a6ef1543ea89d4b12b97f2b5 Mon Sep 17 00:00:00 2001 From: Hande <159312713+hande-k@users.noreply.github.com> Date: Thu, 2 Apr 2026 13:56:01 +0200 Subject: [PATCH 06/10] address comments --- .github/workflows/cognee.yml | 8 +- .../.artifacts/demo_memory_agent.html | 4 +- .../examples/.artifacts/demo_pipeline.html | 4 +- integrations/cognee/examples/README.md | 13 +- .../cognee/examples/demo_memory_agent.py | 175 +++++++++++++----- integrations/cognee/examples/demo_pipeline.py | 161 +++++++++++----- integrations/cognee/pyproject.toml | 15 +- .../components/connectors/cognee/_utils.py | 65 ++++++- .../components/connectors/cognee/cognifier.py | 4 + .../retrievers/cognee/memory_retriever.py | 6 +- .../writers/cognee/memory_writer.py | 4 + .../memory_stores/cognee/memory_store.py | 88 ++++++++- integrations/cognee/tests/test_cognifier.py | 80 ++++++++ integrations/cognee/tests/test_integration.py | 99 ++++++++++ .../cognee/tests/test_memory_store.py | 58 +++++- integrations/cognee/tests/test_utils.py | 99 ++++++++++ 16 files changed, 754 insertions(+), 129 deletions(-) create mode 100644 integrations/cognee/tests/test_cognifier.py create mode 100644 integrations/cognee/tests/test_integration.py create mode 100644 integrations/cognee/tests/test_utils.py diff --git a/.github/workflows/cognee.yml b/.github/workflows/cognee.yml index 158009d21e..d4441fb7b1 100644 --- a/.github/workflows/cognee.yml +++ b/.github/workflows/cognee.yml @@ -31,7 +31,7 @@ jobs: fail-fast: false matrix: os: [ubuntu-latest, windows-latest, macos-latest] - python-version: ["3.10", "3.13"] + python-version: ["3.10", "3.14"] steps: - name: Support longpaths @@ -39,10 +39,10 @@ jobs: working-directory: . run: git config --system core.longpaths true - - uses: actions/checkout@v6 + - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 - name: Set up Python ${{ matrix.python-version }} - uses: actions/setup-python@v6 + uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6.2.0 with: python-version: ${{ matrix.python-version }} @@ -74,6 +74,6 @@ jobs: if: failure() && github.event_name == 'schedule' runs-on: ubuntu-slim steps: - - uses: deepset-ai/notify-slack-action@v1 + - uses: deepset-ai/notify-slack-action@3cda73b77a148f16f703274198e7771340cf862b # v1 with: slack-webhook-url: ${{ secrets.SLACK_WEBHOOK_URL_NOTIFICATIONS }} diff --git a/integrations/cognee/examples/.artifacts/demo_memory_agent.html b/integrations/cognee/examples/.artifacts/demo_memory_agent.html index 39992f1aec..1a31dda784 100644 --- a/integrations/cognee/examples/.artifacts/demo_memory_agent.html +++ b/integrations/cognee/examples/.artifacts/demo_memory_agent.html @@ -171,8 +171,8 @@ (function(){ "use strict"; -var nodes = [{"name": "", "type": "DocumentChunk", "ontology_valid": false, "version": 1, "topological_rank": 0, "metadata": {"index_fields": ["text"]}, "belongs_to_set": null, "source_pipeline": "cognify_pipeline", "source_task": "extract_chunks_from_documents", "source_node_set": null, "source_user": "default_user@example.com", "text": "My name is Alice and I'm working on the Cognee-Haystack integration. The deadline is next Friday.", "chunk_size": 38, "chunk_index": 0, "cut_type": "sentence_end", "id": "f000c910-dcd8-5b37-8d79-efa87848fa9e", "color": "#0DFF00"}, {"name": "alice", "type": "Entity", "ontology_valid": false, "version": 1, "topological_rank": 0, "metadata": {"index_fields": ["name"]}, "belongs_to_set": null, "source_pipeline": "cognify_pipeline", "source_task": "extract_graph_from_data", "source_node_set": null, "source_user": "default_user@example.com", "description": "Person who stated they are working on the integration", "id": "f7d8be13-2a72-5104-bd02-7a5964737a91", "color": "#6510F4"}, {"name": "person", "type": "EntityType", "ontology_valid": false, "version": 1, "topological_rank": 0, "metadata": {"index_fields": ["name"]}, "belongs_to_set": null, "source_pipeline": "cognify_pipeline", "source_task": "extract_graph_from_data", "source_node_set": null, "source_user": "default_user@example.com", "description": "person", "id": "d072ba0f-e1a9-58bf-9974-e1802adc8134", "color": "#A550FF"}, {"name": "cognee-haystack integration", "type": "Entity", "ontology_valid": false, "version": 1, "topological_rank": 0, "metadata": {"index_fields": ["name"]}, "belongs_to_set": null, "source_pipeline": "cognify_pipeline", "source_task": "extract_graph_from_data", "source_node_set": null, "source_user": "default_user@example.com", "description": "Integration project between Cognee and Haystack mentioned by Alice", "id": "37f4562e-675f-5309-9cf3-82fc46dfd7bf", "color": "#6510F4"}, {"name": "project", "type": "EntityType", "ontology_valid": false, "version": 1, "topological_rank": 0, "metadata": {"index_fields": ["name"]}, "belongs_to_set": null, "source_pipeline": "cognify_pipeline", "source_task": "extract_graph_from_data", "source_node_set": null, "source_user": "default_user@example.com", "description": "project", "id": "29c0d211-0d39-579f-bf45-c7a78394c9aa", "color": "#A550FF"}, {"name": "2026-03-27", "type": "Entity", "ontology_valid": false, "version": 1, "topological_rank": 0, "metadata": {"index_fields": ["name"]}, "belongs_to_set": null, "source_pipeline": "cognify_pipeline", "source_task": "extract_graph_from_data", "source_node_set": null, "source_user": "default_user@example.com", "description": "Deadline 'next Friday' resolved relative to 2026-03-20", "id": "aae7dfac-596e-5895-be75-8c7eef4ea6e4", "color": "#6510F4"}, {"name": "date", "type": "EntityType", "ontology_valid": false, "version": 1, "topological_rank": 0, "metadata": {"index_fields": ["name"]}, "belongs_to_set": null, "source_pipeline": "cognify_pipeline", "source_task": "extract_graph_from_data", "source_node_set": null, "source_user": "default_user@example.com", "description": "date", "id": "d61d99ac-b291-5666-9748-3e80e1c8b56a", "color": "#A550FF"}, {"name": "text_e922928a64b61a3d616873a46f313bfa", "type": "TextDocument", "ontology_valid": false, "version": 1, "topological_rank": 0, "metadata": {"index_fields": ["name"]}, "belongs_to_set": null, "source_pipeline": "cognify_pipeline", "source_task": "classify_documents", "source_node_set": null, "source_user": "default_user@example.com", "raw_data_location": "file:///Users/handekafkas/Documents/local-code/haystack-core-integrations/integrations/cognee/.venv/lib/python3.13/site-packages/cognee/.data_storage/text_e922928a64b61a3d616873a46f313bfa.txt", "external_metadata": "{}", "mime_type": "text/plain", "id": "240fa574-4bd5-5daf-b2d3-63c970827398", "color": "#DBD8D8"}, {"name": "", "type": "DocumentChunk", "ontology_valid": false, "version": 1, "topological_rank": 0, "metadata": {"index_fields": ["text"]}, "belongs_to_set": null, "source_pipeline": "cognify_pipeline", "source_task": "extract_chunks_from_documents", "source_node_set": null, "source_user": "default_user@example.com", "text": "We decided to use GRAPH_COMPLETION as the default search type because it retrieves the most relevant memories by graph traversal and vector search", "chunk_size": 53, "chunk_index": 0, "cut_type": "sentence_cut", "id": "c868d3a2-41b8-544c-94ec-533be08724a2", "color": "#0DFF00"}, {"name": "graph_completion", "type": "Entity", "ontology_valid": false, "version": 1, "topological_rank": 0, "metadata": {"index_fields": ["name"]}, "belongs_to_set": null, "source_pipeline": "cognify_pipeline", "source_task": "extract_graph_from_data", "source_node_set": null, "source_user": "default_user@example.com", "description": "preferred search type for the project", "id": "90ed6132-7732-572f-b798-d833662c4a18", "color": "#6510F4"}, {"name": "concept", "type": "EntityType", "ontology_valid": false, "version": 1, "topological_rank": 0, "metadata": {"index_fields": ["name"]}, "belongs_to_set": null, "source_pipeline": "cognify_pipeline", "source_task": "extract_graph_from_data", "source_node_set": null, "source_user": "default_user@example.com", "description": "concept", "id": "dd9713b7-dc20-5101-aad0-1c4216811147", "color": "#A550FF"}, {"name": "default search type", "type": "Entity", "ontology_valid": false, "version": 1, "topological_rank": 0, "metadata": {"index_fields": ["name"]}, "belongs_to_set": null, "source_pipeline": "cognify_pipeline", "source_task": "extract_graph_from_data", "source_node_set": null, "source_user": "default_user@example.com", "description": "Role indicating the search type selected as the default.", "id": "8cff9083-49b8-5471-9922-00b224258949", "color": "#6510F4"}, {"name": "relevant memories", "type": "Entity", "ontology_valid": false, "version": 1, "topological_rank": 0, "metadata": {"index_fields": ["name"]}, "belongs_to_set": null, "source_pipeline": "cognify_pipeline", "source_task": "extract_graph_from_data", "source_node_set": null, "source_user": "default_user@example.com", "description": "Memories that are most pertinent to a query.", "id": "ab1f07c0-fd77-5ad6-a164-6721213d5a29", "color": "#6510F4"}, {"name": "graph traversal", "type": "Entity", "ontology_valid": false, "version": 1, "topological_rank": 0, "metadata": {"index_fields": ["name"]}, "belongs_to_set": null, "source_pipeline": "cognify_pipeline", "source_task": "extract_graph_from_data", "source_node_set": null, "source_user": "default_user@example.com", "description": "Technique of traversing graph connections to find related memories.", "id": "3d0c908a-35fd-5370-953e-8952648f0900", "color": "#6510F4"}, {"name": "vector search", "type": "Entity", "ontology_valid": false, "version": 1, "topological_rank": 0, "metadata": {"index_fields": ["name"]}, "belongs_to_set": null, "source_pipeline": "cognify_pipeline", "source_task": "extract_graph_from_data", "source_node_set": null, "source_user": "default_user@example.com", "description": "Embedding-based similarity search method used to find related items.", "id": "b3c5ff56-7122-56d1-b27b-de4ebe59395b", "color": "#6510F4"}, {"name": "text_eb05286518d418a42800eef8456af922", "type": "TextDocument", "ontology_valid": false, "version": 1, "topological_rank": 0, "metadata": {"index_fields": ["name"]}, "belongs_to_set": null, "source_pipeline": "cognify_pipeline", "source_task": "classify_documents", "source_node_set": null, "source_user": "default_user@example.com", "raw_data_location": "file:///Users/handekafkas/Documents/local-code/haystack-core-integrations/integrations/cognee/.venv/lib/python3.13/site-packages/cognee/.data_storage/text_eb05286518d418a42800eef8456af922.txt", "external_metadata": "{}", "mime_type": "text/plain", "id": "fcd8a6b3-d97f-5d1a-8ccc-cb63a3344f71", "color": "#DBD8D8"}, {"name": "", "type": "DocumentChunk", "ontology_valid": false, "version": 1, "topological_rank": 0, "metadata": {"index_fields": ["text"]}, "belongs_to_set": null, "source_pipeline": "cognify_pipeline", "source_task": "extract_chunks_from_documents", "source_node_set": null, "source_user": "default_user@example.com", "text": "I'll remember that the deadline is next Friday and that GRAPH_COMPLETION is the preferred search type for this project.", "chunk_size": 42, "chunk_index": 0, "cut_type": "sentence_end", "id": "2df00f77-1358-55a9-aab3-5b62b961bdf3", "color": "#0DFF00"}, {"name": "this project", "type": "Entity", "ontology_valid": false, "version": 1, "topological_rank": 0, "metadata": {"index_fields": ["name"]}, "belongs_to_set": null, "source_pipeline": "cognify_pipeline", "source_task": "extract_graph_from_data", "source_node_set": null, "source_user": "default_user@example.com", "description": "Referenced project for which preferences and deadlines apply", "id": "9591ae32-57d8-591f-bb04-3077530bea6a", "color": "#6510F4"}, {"name": "next friday", "type": "Entity", "ontology_valid": false, "version": 1, "topological_rank": 0, "metadata": {"index_fields": ["name"]}, "belongs_to_set": null, "source_pipeline": "cognify_pipeline", "source_task": "extract_graph_from_data", "source_node_set": null, "source_user": "default_user@example.com", "description": "date: 2026-03-27", "id": "e995ad45-cb4a-5114-9b09-5c9c90335852", "color": "#6510F4"}, {"name": "text_88278ad547fc9e31ef4ffbbe793d8bb0", "type": "TextDocument", "ontology_valid": false, "version": 1, "topological_rank": 0, "metadata": {"index_fields": ["name"]}, "belongs_to_set": null, "source_pipeline": "cognify_pipeline", "source_task": "classify_documents", "source_node_set": null, "source_user": "default_user@example.com", "raw_data_location": "file:///Users/handekafkas/Documents/local-code/haystack-core-integrations/integrations/cognee/.venv/lib/python3.13/site-packages/cognee/.data_storage/text_88278ad547fc9e31ef4ffbbe793d8bb0.txt", "external_metadata": "{}", "mime_type": "text/plain", "id": "c730c8d1-a271-515b-8c78-f12e194d6b25", "color": "#DBD8D8"}, {"name": "", "type": "TextSummary", "ontology_valid": false, "version": 1, "topological_rank": 0, "metadata": {"index_fields": ["text"]}, "belongs_to_set": null, "source_pipeline": "cognify_pipeline", "source_task": "summarize_text", "source_node_set": null, "source_user": "default_user@example.com", "text": "Alice is working on the Cognee\u2013Haystack integration, with a deadline next Friday.", "id": "81efbad3-0d84-572b-9d08-f3a7d742a65a", "color": "#6510F4"}, {"name": "", "type": "TextSummary", "ontology_valid": false, "version": 1, "topological_rank": 0, "metadata": {"index_fields": ["text"]}, "belongs_to_set": null, "source_pipeline": "cognify_pipeline", "source_task": "summarize_text", "source_node_set": null, "source_user": "default_user@example.com", "text": "Adopted GRAPH_COMPLETION as the default search for retrieving the most relevant memories.", "id": "c10ec5f1-9b16-57d8-8a25-572f091fb28c", "color": "#6510F4"}, {"name": "", "type": "TextSummary", "ontology_valid": false, "version": 1, "topological_rank": 0, "metadata": {"index_fields": ["text"]}, "belongs_to_set": null, "source_pipeline": "cognify_pipeline", "source_task": "summarize_text", "source_node_set": null, "source_user": "default_user@example.com", "text": "Due date: next Friday; preferred search method: GRAPH_COMPLETION.", "id": "6275c695-1310-53a5-be99-b0b45e01197a", "color": "#6510F4"}]; -var links = [{"source": "f000c910-dcd8-5b37-8d79-efa87848fa9e", "target": "f7d8be13-2a72-5104-bd02-7a5964737a91", "relation": "contains", "weight": null, "all_weights": {}, "relationship_type": "contains", "edge_info": {"source_node_id": "f000c910-dcd8-5b37-8d79-efa87848fa9e", "target_node_id": "f7d8be13-2a72-5104-bd02-7a5964737a91", "relationship_name": "contains", "updated_at": "2026-03-20 23:29:32", "relationship_type": "contains", "edge_text": "relationship_name: contains; entity_name: alice; entity_description: Person who stated they are working on the integration"}}, {"source": "f000c910-dcd8-5b37-8d79-efa87848fa9e", "target": "37f4562e-675f-5309-9cf3-82fc46dfd7bf", "relation": "contains", "weight": null, "all_weights": {}, "relationship_type": "contains", "edge_info": {"source_node_id": "f000c910-dcd8-5b37-8d79-efa87848fa9e", "target_node_id": "37f4562e-675f-5309-9cf3-82fc46dfd7bf", "relationship_name": "contains", "updated_at": "2026-03-20 23:29:32", "relationship_type": "contains", "edge_text": "relationship_name: contains; entity_name: cognee-haystack integration; entity_description: Integration project between Cognee and Haystack mentioned by Alice"}}, {"source": "f000c910-dcd8-5b37-8d79-efa87848fa9e", "target": "aae7dfac-596e-5895-be75-8c7eef4ea6e4", "relation": "contains", "weight": null, "all_weights": {}, "relationship_type": "contains", "edge_info": {"source_node_id": "f000c910-dcd8-5b37-8d79-efa87848fa9e", "target_node_id": "aae7dfac-596e-5895-be75-8c7eef4ea6e4", "relationship_name": "contains", "updated_at": "2026-03-20 23:29:32", "relationship_type": "contains", "edge_text": "relationship_name: contains; entity_name: 2026-03-27; entity_description: Deadline 'next Friday' resolved relative to 2026-03-20"}}, {"source": "f000c910-dcd8-5b37-8d79-efa87848fa9e", "target": "240fa574-4bd5-5daf-b2d3-63c970827398", "relation": "is_part_of", "weight": null, "all_weights": {}, "relationship_type": null, "edge_info": {"source_node_id": "f000c910-dcd8-5b37-8d79-efa87848fa9e", "target_node_id": "240fa574-4bd5-5daf-b2d3-63c970827398", "relationship_name": "is_part_of", "updated_at": "2026-03-20 23:29:32"}}, {"source": "f7d8be13-2a72-5104-bd02-7a5964737a91", "target": "d072ba0f-e1a9-58bf-9974-e1802adc8134", "relation": "is_a", "weight": null, "all_weights": {}, "relationship_type": null, "edge_info": {"source_node_id": "f7d8be13-2a72-5104-bd02-7a5964737a91", "target_node_id": "d072ba0f-e1a9-58bf-9974-e1802adc8134", "relationship_name": "is_a", "updated_at": "2026-03-20 23:29:32"}}, {"source": "f7d8be13-2a72-5104-bd02-7a5964737a91", "target": "37f4562e-675f-5309-9cf3-82fc46dfd7bf", "relation": "working_on", "weight": null, "all_weights": {}, "relationship_type": null, "edge_info": {"relationship_name": "working_on", "source_node_id": "f7d8be13-2a72-5104-bd02-7a5964737a91", "target_node_id": "37f4562e-675f-5309-9cf3-82fc46dfd7bf", "ontology_valid": false}}, {"source": "37f4562e-675f-5309-9cf3-82fc46dfd7bf", "target": "29c0d211-0d39-579f-bf45-c7a78394c9aa", "relation": "is_a", "weight": null, "all_weights": {}, "relationship_type": null, "edge_info": {"source_node_id": "37f4562e-675f-5309-9cf3-82fc46dfd7bf", "target_node_id": "29c0d211-0d39-579f-bf45-c7a78394c9aa", "relationship_name": "is_a", "updated_at": "2026-03-20 23:29:32"}}, {"source": "37f4562e-675f-5309-9cf3-82fc46dfd7bf", "target": "aae7dfac-596e-5895-be75-8c7eef4ea6e4", "relation": "has_deadline", "weight": null, "all_weights": {}, "relationship_type": null, "edge_info": {"relationship_name": "has_deadline", "source_node_id": "37f4562e-675f-5309-9cf3-82fc46dfd7bf", "target_node_id": "aae7dfac-596e-5895-be75-8c7eef4ea6e4", "ontology_valid": false}}, {"source": "aae7dfac-596e-5895-be75-8c7eef4ea6e4", "target": "d61d99ac-b291-5666-9748-3e80e1c8b56a", "relation": "is_a", "weight": null, "all_weights": {}, "relationship_type": null, "edge_info": {"source_node_id": "aae7dfac-596e-5895-be75-8c7eef4ea6e4", "target_node_id": "d61d99ac-b291-5666-9748-3e80e1c8b56a", "relationship_name": "is_a", "updated_at": "2026-03-20 23:29:32"}}, {"source": "c868d3a2-41b8-544c-94ec-533be08724a2", "target": "90ed6132-7732-572f-b798-d833662c4a18", "relation": "contains", "weight": null, "all_weights": {}, "relationship_type": "contains", "edge_info": {"source_node_id": "c868d3a2-41b8-544c-94ec-533be08724a2", "target_node_id": "90ed6132-7732-572f-b798-d833662c4a18", "relationship_name": "contains", "updated_at": "2026-03-20 23:29:34", "relationship_type": "contains", "edge_text": "relationship_name: contains; entity_name: graph_completion; entity_description: Search type that combines graph traversal and vector search to retrieve memories."}}, {"source": "c868d3a2-41b8-544c-94ec-533be08724a2", "target": "8cff9083-49b8-5471-9922-00b224258949", "relation": "contains", "weight": null, "all_weights": {}, "relationship_type": "contains", "edge_info": {"source_node_id": "c868d3a2-41b8-544c-94ec-533be08724a2", "target_node_id": "8cff9083-49b8-5471-9922-00b224258949", "relationship_name": "contains", "updated_at": "2026-03-20 23:29:34", "relationship_type": "contains", "edge_text": "relationship_name: contains; entity_name: default search type; entity_description: Role indicating the search type selected as the default."}}, {"source": "c868d3a2-41b8-544c-94ec-533be08724a2", "target": "ab1f07c0-fd77-5ad6-a164-6721213d5a29", "relation": "contains", "weight": null, "all_weights": {}, "relationship_type": "contains", "edge_info": {"source_node_id": "c868d3a2-41b8-544c-94ec-533be08724a2", "target_node_id": "ab1f07c0-fd77-5ad6-a164-6721213d5a29", "relationship_name": "contains", "updated_at": "2026-03-20 23:29:34", "relationship_type": "contains", "edge_text": "relationship_name: contains; entity_name: relevant memories; entity_description: Memories that are most pertinent to a query."}}, {"source": "c868d3a2-41b8-544c-94ec-533be08724a2", "target": "3d0c908a-35fd-5370-953e-8952648f0900", "relation": "contains", "weight": null, "all_weights": {}, "relationship_type": "contains", "edge_info": {"source_node_id": "c868d3a2-41b8-544c-94ec-533be08724a2", "target_node_id": "3d0c908a-35fd-5370-953e-8952648f0900", "relationship_name": "contains", "updated_at": "2026-03-20 23:29:34", "relationship_type": "contains", "edge_text": "relationship_name: contains; entity_name: graph traversal; entity_description: Technique of traversing graph connections to find related memories."}}, {"source": "c868d3a2-41b8-544c-94ec-533be08724a2", "target": "b3c5ff56-7122-56d1-b27b-de4ebe59395b", "relation": "contains", "weight": null, "all_weights": {}, "relationship_type": "contains", "edge_info": {"source_node_id": "c868d3a2-41b8-544c-94ec-533be08724a2", "target_node_id": "b3c5ff56-7122-56d1-b27b-de4ebe59395b", "relationship_name": "contains", "updated_at": "2026-03-20 23:29:34", "relationship_type": "contains", "edge_text": "relationship_name: contains; entity_name: vector search; entity_description: Embedding-based similarity search method used to find related items."}}, {"source": "c868d3a2-41b8-544c-94ec-533be08724a2", "target": "fcd8a6b3-d97f-5d1a-8ccc-cb63a3344f71", "relation": "is_part_of", "weight": null, "all_weights": {}, "relationship_type": null, "edge_info": {"source_node_id": "c868d3a2-41b8-544c-94ec-533be08724a2", "target_node_id": "fcd8a6b3-d97f-5d1a-8ccc-cb63a3344f71", "relationship_name": "is_part_of", "updated_at": "2026-03-20 23:29:34"}}, {"source": "90ed6132-7732-572f-b798-d833662c4a18", "target": "dd9713b7-dc20-5101-aad0-1c4216811147", "relation": "is_a", "weight": null, "all_weights": {}, "relationship_type": null, "edge_info": {"source_node_id": "90ed6132-7732-572f-b798-d833662c4a18", "target_node_id": "dd9713b7-dc20-5101-aad0-1c4216811147", "relationship_name": "is_a", "updated_at": "2026-03-20 23:29:37"}}, {"source": "90ed6132-7732-572f-b798-d833662c4a18", "target": "8cff9083-49b8-5471-9922-00b224258949", "relation": "is_default_search_type", "weight": null, "all_weights": {}, "relationship_type": null, "edge_info": {"relationship_name": "is_default_search_type", "source_node_id": "90ed6132-7732-572f-b798-d833662c4a18", "target_node_id": "8cff9083-49b8-5471-9922-00b224258949", "ontology_valid": false}}, {"source": "90ed6132-7732-572f-b798-d833662c4a18", "target": "ab1f07c0-fd77-5ad6-a164-6721213d5a29", "relation": "retrieves_most_relevant_memories", "weight": null, "all_weights": {}, "relationship_type": null, "edge_info": {"relationship_name": "retrieves_most_relevant_memories", "source_node_id": "90ed6132-7732-572f-b798-d833662c4a18", "target_node_id": "ab1f07c0-fd77-5ad6-a164-6721213d5a29", "ontology_valid": false}}, {"source": "90ed6132-7732-572f-b798-d833662c4a18", "target": "3d0c908a-35fd-5370-953e-8952648f0900", "relation": "uses_graph_traversal", "weight": null, "all_weights": {}, "relationship_type": null, "edge_info": {"relationship_name": "uses_graph_traversal", "source_node_id": "90ed6132-7732-572f-b798-d833662c4a18", "target_node_id": "3d0c908a-35fd-5370-953e-8952648f0900", "ontology_valid": false}}, {"source": "90ed6132-7732-572f-b798-d833662c4a18", "target": "b3c5ff56-7122-56d1-b27b-de4ebe59395b", "relation": "uses_vector_search", "weight": null, "all_weights": {}, "relationship_type": null, "edge_info": {"relationship_name": "uses_vector_search", "source_node_id": "90ed6132-7732-572f-b798-d833662c4a18", "target_node_id": "b3c5ff56-7122-56d1-b27b-de4ebe59395b", "ontology_valid": false}}, {"source": "8cff9083-49b8-5471-9922-00b224258949", "target": "dd9713b7-dc20-5101-aad0-1c4216811147", "relation": "is_a", "weight": null, "all_weights": {}, "relationship_type": null, "edge_info": {"source_node_id": "8cff9083-49b8-5471-9922-00b224258949", "target_node_id": "dd9713b7-dc20-5101-aad0-1c4216811147", "relationship_name": "is_a", "updated_at": "2026-03-20 23:29:34"}}, {"source": "ab1f07c0-fd77-5ad6-a164-6721213d5a29", "target": "dd9713b7-dc20-5101-aad0-1c4216811147", "relation": "is_a", "weight": null, "all_weights": {}, "relationship_type": null, "edge_info": {"source_node_id": "ab1f07c0-fd77-5ad6-a164-6721213d5a29", "target_node_id": "dd9713b7-dc20-5101-aad0-1c4216811147", "relationship_name": "is_a", "updated_at": "2026-03-20 23:29:34"}}, {"source": "3d0c908a-35fd-5370-953e-8952648f0900", "target": "dd9713b7-dc20-5101-aad0-1c4216811147", "relation": "is_a", "weight": null, "all_weights": {}, "relationship_type": null, "edge_info": {"source_node_id": "3d0c908a-35fd-5370-953e-8952648f0900", "target_node_id": "dd9713b7-dc20-5101-aad0-1c4216811147", "relationship_name": "is_a", "updated_at": "2026-03-20 23:29:34"}}, {"source": "3d0c908a-35fd-5370-953e-8952648f0900", "target": "ab1f07c0-fd77-5ad6-a164-6721213d5a29", "relation": "contributes_to_retrieval_of", "weight": null, "all_weights": {}, "relationship_type": null, "edge_info": {"relationship_name": "contributes_to_retrieval_of", "source_node_id": "3d0c908a-35fd-5370-953e-8952648f0900", "target_node_id": "ab1f07c0-fd77-5ad6-a164-6721213d5a29", "ontology_valid": false}}, {"source": "b3c5ff56-7122-56d1-b27b-de4ebe59395b", "target": "dd9713b7-dc20-5101-aad0-1c4216811147", "relation": "is_a", "weight": null, "all_weights": {}, "relationship_type": null, "edge_info": {"source_node_id": "b3c5ff56-7122-56d1-b27b-de4ebe59395b", "target_node_id": "dd9713b7-dc20-5101-aad0-1c4216811147", "relationship_name": "is_a", "updated_at": "2026-03-20 23:29:34"}}, {"source": "b3c5ff56-7122-56d1-b27b-de4ebe59395b", "target": "ab1f07c0-fd77-5ad6-a164-6721213d5a29", "relation": "contributes_to_retrieval_of", "weight": null, "all_weights": {}, "relationship_type": null, "edge_info": {"relationship_name": "contributes_to_retrieval_of", "source_node_id": "b3c5ff56-7122-56d1-b27b-de4ebe59395b", "target_node_id": "ab1f07c0-fd77-5ad6-a164-6721213d5a29", "ontology_valid": false}}, {"source": "2df00f77-1358-55a9-aab3-5b62b961bdf3", "target": "9591ae32-57d8-591f-bb04-3077530bea6a", "relation": "contains", "weight": null, "all_weights": {}, "relationship_type": "contains", "edge_info": {"source_node_id": "2df00f77-1358-55a9-aab3-5b62b961bdf3", "target_node_id": "9591ae32-57d8-591f-bb04-3077530bea6a", "relationship_name": "contains", "updated_at": "2026-03-20 23:29:37", "relationship_type": "contains", "edge_text": "relationship_name: contains; entity_name: this project; entity_description: Referenced project for which preferences and deadlines apply"}}, {"source": "2df00f77-1358-55a9-aab3-5b62b961bdf3", "target": "e995ad45-cb4a-5114-9b09-5c9c90335852", "relation": "contains", "weight": null, "all_weights": {}, "relationship_type": "contains", "edge_info": {"source_node_id": "2df00f77-1358-55a9-aab3-5b62b961bdf3", "target_node_id": "e995ad45-cb4a-5114-9b09-5c9c90335852", "relationship_name": "contains", "updated_at": "2026-03-20 23:29:37", "relationship_type": "contains", "edge_text": "relationship_name: contains; entity_name: next friday; entity_description: date: 2026-03-27"}}, {"source": "2df00f77-1358-55a9-aab3-5b62b961bdf3", "target": "90ed6132-7732-572f-b798-d833662c4a18", "relation": "contains", "weight": null, "all_weights": {}, "relationship_type": "contains", "edge_info": {"source_node_id": "2df00f77-1358-55a9-aab3-5b62b961bdf3", "target_node_id": "90ed6132-7732-572f-b798-d833662c4a18", "relationship_name": "contains", "updated_at": "2026-03-20 23:29:37", "relationship_type": "contains", "edge_text": "relationship_name: contains; entity_name: graph_completion; entity_description: preferred search type for the project"}}, {"source": "2df00f77-1358-55a9-aab3-5b62b961bdf3", "target": "c730c8d1-a271-515b-8c78-f12e194d6b25", "relation": "is_part_of", "weight": null, "all_weights": {}, "relationship_type": null, "edge_info": {"source_node_id": "2df00f77-1358-55a9-aab3-5b62b961bdf3", "target_node_id": "c730c8d1-a271-515b-8c78-f12e194d6b25", "relationship_name": "is_part_of", "updated_at": "2026-03-20 23:29:37"}}, {"source": "9591ae32-57d8-591f-bb04-3077530bea6a", "target": "29c0d211-0d39-579f-bf45-c7a78394c9aa", "relation": "is_a", "weight": null, "all_weights": {}, "relationship_type": null, "edge_info": {"source_node_id": "9591ae32-57d8-591f-bb04-3077530bea6a", "target_node_id": "29c0d211-0d39-579f-bf45-c7a78394c9aa", "relationship_name": "is_a", "updated_at": "2026-03-20 23:29:37"}}, {"source": "9591ae32-57d8-591f-bb04-3077530bea6a", "target": "e995ad45-cb4a-5114-9b09-5c9c90335852", "relation": "has_deadline", "weight": null, "all_weights": {}, "relationship_type": null, "edge_info": {"relationship_name": "has_deadline", "source_node_id": "9591ae32-57d8-591f-bb04-3077530bea6a", "target_node_id": "e995ad45-cb4a-5114-9b09-5c9c90335852", "ontology_valid": false}}, {"source": "9591ae32-57d8-591f-bb04-3077530bea6a", "target": "90ed6132-7732-572f-b798-d833662c4a18", "relation": "preferred_search_type", "weight": null, "all_weights": {}, "relationship_type": null, "edge_info": {"relationship_name": "preferred_search_type", "source_node_id": "9591ae32-57d8-591f-bb04-3077530bea6a", "target_node_id": "90ed6132-7732-572f-b798-d833662c4a18", "ontology_valid": false}}, {"source": "e995ad45-cb4a-5114-9b09-5c9c90335852", "target": "d61d99ac-b291-5666-9748-3e80e1c8b56a", "relation": "is_a", "weight": null, "all_weights": {}, "relationship_type": null, "edge_info": {"source_node_id": "e995ad45-cb4a-5114-9b09-5c9c90335852", "target_node_id": "d61d99ac-b291-5666-9748-3e80e1c8b56a", "relationship_name": "is_a", "updated_at": "2026-03-20 23:29:37"}}, {"source": "81efbad3-0d84-572b-9d08-f3a7d742a65a", "target": "f000c910-dcd8-5b37-8d79-efa87848fa9e", "relation": "made_from", "weight": null, "all_weights": {}, "relationship_type": null, "edge_info": {"source_node_id": "81efbad3-0d84-572b-9d08-f3a7d742a65a", "target_node_id": "f000c910-dcd8-5b37-8d79-efa87848fa9e", "relationship_name": "made_from", "updated_at": "2026-03-20 23:29:32"}}, {"source": "c10ec5f1-9b16-57d8-8a25-572f091fb28c", "target": "c868d3a2-41b8-544c-94ec-533be08724a2", "relation": "made_from", "weight": null, "all_weights": {}, "relationship_type": null, "edge_info": {"source_node_id": "c10ec5f1-9b16-57d8-8a25-572f091fb28c", "target_node_id": "c868d3a2-41b8-544c-94ec-533be08724a2", "relationship_name": "made_from", "updated_at": "2026-03-20 23:29:34"}}, {"source": "6275c695-1310-53a5-be99-b0b45e01197a", "target": "2df00f77-1358-55a9-aab3-5b62b961bdf3", "relation": "made_from", "weight": null, "all_weights": {}, "relationship_type": null, "edge_info": {"source_node_id": "6275c695-1310-53a5-be99-b0b45e01197a", "target_node_id": "2df00f77-1358-55a9-aab3-5b62b961bdf3", "relationship_name": "made_from", "updated_at": "2026-03-20 23:29:37"}}]; +var nodes = [{"name": "", "type": "TextSummary", "ontology_valid": false, "version": 1, "topological_rank": 0, "metadata": {"index_fields": ["text"]}, "belongs_to_set": null, "source_pipeline": "cognify_pipeline", "source_task": "summarize_text", "source_node_set": null, "source_user": "default_user@example.com", "feedback_weight": 0.5, "text": "Due next Friday; favored search type is GRAPH_COMPLETION.", "id": "f945057e-79ec-5d9e-b7e7-81eb7d1d52d7", "color": "#6510F4"}, {"name": "", "type": "DocumentChunk", "ontology_valid": false, "version": 1, "topological_rank": 0, "metadata": {"index_fields": ["text"]}, "belongs_to_set": null, "source_pipeline": "cognify_pipeline", "source_task": "extract_chunks_from_documents", "source_node_set": null, "source_user": "default_user@example.com", "feedback_weight": 0.5, "text": "I'll remember that the deadline is next Friday and that GRAPH_COMPLETION is the preferred search type for this project.", "chunk_size": 42, "chunk_index": 0, "cut_type": "sentence_end", "id": "3a7ffaaf-7d94-5b1f-b039-c1a6893bc2ae", "color": "#0DFF00"}, {"name": "this project", "type": "Entity", "ontology_valid": false, "version": 1, "topological_rank": 0, "metadata": {"index_fields": ["name"]}, "belongs_to_set": null, "source_pipeline": "cognify_pipeline", "source_task": "extract_graph_from_data", "source_node_set": null, "source_user": "default_user@example.com", "feedback_weight": 0.5, "description": "Project referred to in the user's message.", "id": "9591ae32-57d8-591f-bb04-3077530bea6a", "color": "#6510F4"}, {"name": "project", "type": "EntityType", "ontology_valid": false, "version": 1, "topological_rank": 0, "metadata": {"index_fields": ["name"]}, "belongs_to_set": null, "source_pipeline": "cognify_pipeline", "source_task": "extract_graph_from_data", "source_node_set": null, "source_user": "default_user@example.com", "feedback_weight": 0.5, "description": "project", "relations": [], "id": "29c0d211-0d39-579f-bf45-c7a78394c9aa", "color": "#A550FF"}, {"name": "2026-04-03", "type": "Entity", "ontology_valid": false, "version": 1, "topological_rank": 0, "metadata": {"index_fields": ["name"]}, "belongs_to_set": null, "source_pipeline": "cognify_pipeline", "source_task": "extract_graph_from_data", "source_node_set": null, "source_user": "default_user@example.com", "feedback_weight": 0.5, "description": "Next Friday relative to 2026-04-02 (interpreted from 'next Friday').", "relations": [], "id": "bd261130-9c89-5df6-b834-f841adda8252", "color": "#6510F4"}, {"name": "date", "type": "EntityType", "ontology_valid": false, "version": 1, "topological_rank": 0, "metadata": {"index_fields": ["name"]}, "belongs_to_set": null, "source_pipeline": "cognify_pipeline", "source_task": "extract_graph_from_data", "source_node_set": null, "source_user": "default_user@example.com", "feedback_weight": 0.5, "description": "date", "relations": [], "id": "d61d99ac-b291-5666-9748-3e80e1c8b56a", "color": "#A550FF"}, {"name": "graph_completion", "type": "Entity", "ontology_valid": false, "version": 1, "topological_rank": 0, "metadata": {"index_fields": ["name"]}, "belongs_to_set": null, "source_pipeline": "cognify_pipeline", "source_task": "extract_graph_from_data", "source_node_set": null, "source_user": "default_user@example.com", "feedback_weight": 0.5, "description": "Search type that retrieves the most relevant memories by graph traversal and vector search", "id": "90ed6132-7732-572f-b798-d833662c4a18", "color": "#6510F4"}, {"name": "searchtype", "type": "EntityType", "ontology_valid": false, "version": 1, "topological_rank": 0, "metadata": {"index_fields": ["name"]}, "belongs_to_set": null, "source_pipeline": "cognify_pipeline", "source_task": "extract_graph_from_data", "source_node_set": null, "source_user": "default_user@example.com", "feedback_weight": 0.5, "description": "searchtype", "relations": [], "id": "26ec8442-0b57-5727-a4b1-8208eee3a7c7", "color": "#A550FF"}, {"name": "text_88278ad547fc9e31ef4ffbbe793d8bb0", "type": "TextDocument", "ontology_valid": false, "version": 1, "topological_rank": 0, "metadata": {"index_fields": ["name"]}, "belongs_to_set": null, "source_pipeline": "cognify_pipeline", "source_task": "classify_documents", "source_node_set": null, "source_user": "default_user@example.com", "feedback_weight": 0.5, "raw_data_location": "file:///Users/handekafkas/Documents/local-code/haystack-core-integrations/integrations/cognee/.venv/lib/python3.13/site-packages/cognee/.data_storage/437c2538-ad95-42da-bbe9-2bde9790d147/text_88278ad547fc9e31ef4ffbbe793d8bb0.txt", "external_metadata": "{}", "mime_type": "text/plain", "id": "e78a62e4-43c4-53e8-958c-dff882d08f6a", "color": "#DBD8D8"}, {"name": "", "type": "TextSummary", "ontology_valid": false, "version": 1, "topological_rank": 0, "metadata": {"index_fields": ["text"]}, "belongs_to_set": null, "source_pipeline": "cognify_pipeline", "source_task": "summarize_text", "source_node_set": null, "source_user": "default_user@example.com", "feedback_weight": 0.5, "text": "Alice is managing the Cognee\u2013Haystack integration, with a due date next Friday.", "id": "59e47787-7802-5d87-a7f4-0de053bbd421", "color": "#6510F4"}, {"name": "", "type": "DocumentChunk", "ontology_valid": false, "version": 1, "topological_rank": 0, "metadata": {"index_fields": ["text"]}, "belongs_to_set": null, "source_pipeline": "cognify_pipeline", "source_task": "extract_chunks_from_documents", "source_node_set": null, "source_user": "default_user@example.com", "feedback_weight": 0.5, "text": "My name is Alice and I'm working on the Cognee-Haystack integration. The deadline is next Friday.", "chunk_size": 38, "chunk_index": 0, "cut_type": "sentence_end", "id": "01195d51-08f7-59fc-a461-7396bdc7ee27", "color": "#0DFF00"}, {"name": "alice", "type": "Entity", "ontology_valid": false, "version": 1, "topological_rank": 0, "metadata": {"index_fields": ["name"]}, "belongs_to_set": null, "source_pipeline": "cognify_pipeline", "source_task": "extract_graph_from_data", "source_node_set": null, "source_user": "default_user@example.com", "feedback_weight": 0.5, "description": "Person who is working on the Cognee-Haystack integration.", "id": "f7d8be13-2a72-5104-bd02-7a5964737a91", "color": "#6510F4"}, {"name": "person", "type": "EntityType", "ontology_valid": false, "version": 1, "topological_rank": 0, "metadata": {"index_fields": ["name"]}, "belongs_to_set": null, "source_pipeline": "cognify_pipeline", "source_task": "extract_graph_from_data", "source_node_set": null, "source_user": "default_user@example.com", "feedback_weight": 0.5, "description": "person", "relations": [], "id": "d072ba0f-e1a9-58bf-9974-e1802adc8134", "color": "#A550FF"}, {"name": "cognee-haystack integration", "type": "Entity", "ontology_valid": false, "version": 1, "topological_rank": 0, "metadata": {"index_fields": ["name"]}, "belongs_to_set": null, "source_pipeline": "cognify_pipeline", "source_task": "extract_graph_from_data", "source_node_set": null, "source_user": "default_user@example.com", "feedback_weight": 0.5, "description": "Integration project between Cognee and Haystack.", "id": "37f4562e-675f-5309-9cf3-82fc46dfd7bf", "color": "#6510F4"}, {"name": "next friday", "type": "Entity", "ontology_valid": false, "version": 1, "topological_rank": 0, "metadata": {"index_fields": ["name"]}, "belongs_to_set": null, "source_pipeline": "cognify_pipeline", "source_task": "extract_graph_from_data", "source_node_set": null, "source_user": "default_user@example.com", "feedback_weight": 0.5, "description": "date: 2026-04-03", "relations": [], "id": "e995ad45-cb4a-5114-9b09-5c9c90335852", "color": "#6510F4"}, {"name": "text_e922928a64b61a3d616873a46f313bfa", "type": "TextDocument", "ontology_valid": false, "version": 1, "topological_rank": 0, "metadata": {"index_fields": ["name"]}, "belongs_to_set": null, "source_pipeline": "cognify_pipeline", "source_task": "classify_documents", "source_node_set": null, "source_user": "default_user@example.com", "feedback_weight": 0.5, "raw_data_location": "file:///Users/handekafkas/Documents/local-code/haystack-core-integrations/integrations/cognee/.venv/lib/python3.13/site-packages/cognee/.data_storage/437c2538-ad95-42da-bbe9-2bde9790d147/text_e922928a64b61a3d616873a46f313bfa.txt", "external_metadata": "{}", "mime_type": "text/plain", "id": "8d7a6715-a090-5d3c-b55e-bcd4d7a93b6d", "color": "#DBD8D8"}, {"name": "", "type": "TextSummary", "ontology_valid": false, "version": 1, "topological_rank": 0, "metadata": {"index_fields": ["text"]}, "belongs_to_set": null, "source_pipeline": "cognify_pipeline", "source_task": "summarize_text", "source_node_set": null, "source_user": "default_user@example.com", "feedback_weight": 0.5, "text": "GRAPH_COMPLETION chosen as the default search method to retrieve the most relevant memories via graph traversal and vector search.", "id": "23cf773a-d442-5ba8-9353-465db0f5b477", "color": "#6510F4"}, {"name": "", "type": "DocumentChunk", "ontology_valid": false, "version": 1, "topological_rank": 0, "metadata": {"index_fields": ["text"]}, "belongs_to_set": null, "source_pipeline": "cognify_pipeline", "source_task": "extract_chunks_from_documents", "source_node_set": null, "source_user": "default_user@example.com", "feedback_weight": 0.5, "text": "We decided to use GRAPH_COMPLETION as the default search type because it retrieves the most relevant memories by graph traversal and vector search", "chunk_size": 53, "chunk_index": 0, "cut_type": "sentence_cut", "id": "94d0c5eb-1260-59bd-917f-bd50dc31b1ed", "color": "#0DFF00"}, {"name": "method", "type": "EntityType", "ontology_valid": false, "version": 1, "topological_rank": 0, "metadata": {"index_fields": ["name"]}, "belongs_to_set": null, "source_pipeline": "cognify_pipeline", "source_task": "extract_graph_from_data", "source_node_set": null, "source_user": "default_user@example.com", "feedback_weight": 0.5, "description": "method", "relations": [], "id": "00f29df1-cee8-544f-87d6-60761845f00b", "color": "#A550FF"}, {"name": "graph traversal", "type": "Entity", "ontology_valid": false, "version": 1, "topological_rank": 0, "metadata": {"index_fields": ["name"]}, "belongs_to_set": null, "source_pipeline": "cognify_pipeline", "source_task": "extract_graph_from_data", "source_node_set": null, "source_user": "default_user@example.com", "feedback_weight": 0.5, "description": "Technique used to traverse a knowledge graph to locate related memories", "id": "3d0c908a-35fd-5370-953e-8952648f0900", "color": "#6510F4"}, {"name": "technique", "type": "EntityType", "ontology_valid": false, "version": 1, "topological_rank": 0, "metadata": {"index_fields": ["name"]}, "belongs_to_set": null, "source_pipeline": "cognify_pipeline", "source_task": "extract_graph_from_data", "source_node_set": null, "source_user": "default_user@example.com", "feedback_weight": 0.5, "description": "technique", "relations": [], "id": "acc8fc74-4097-5175-b5aa-17349d51dd22", "color": "#A550FF"}, {"name": "most relevant memories", "type": "Entity", "ontology_valid": false, "version": 1, "topological_rank": 0, "metadata": {"index_fields": ["name"]}, "belongs_to_set": null, "source_pipeline": "cognify_pipeline", "source_task": "extract_graph_from_data", "source_node_set": null, "source_user": "default_user@example.com", "feedback_weight": 0.5, "description": "Memories ranked as most relevant to a query", "relations": [], "id": "9aaff686-abbb-54c1-b70c-8f6de27b9444", "color": "#6510F4"}, {"name": "concept", "type": "EntityType", "ontology_valid": false, "version": 1, "topological_rank": 0, "metadata": {"index_fields": ["name"]}, "belongs_to_set": null, "source_pipeline": "cognify_pipeline", "source_task": "extract_graph_from_data", "source_node_set": null, "source_user": "default_user@example.com", "feedback_weight": 0.5, "description": "concept", "relations": [], "id": "dd9713b7-dc20-5101-aad0-1c4216811147", "color": "#A550FF"}, {"name": "vector search", "type": "Entity", "ontology_valid": false, "version": 1, "topological_rank": 0, "metadata": {"index_fields": ["name"]}, "belongs_to_set": null, "source_pipeline": "cognify_pipeline", "source_task": "extract_graph_from_data", "source_node_set": null, "source_user": "default_user@example.com", "feedback_weight": 0.5, "description": "Technique that retrieves items based on vector similarity", "id": "b3c5ff56-7122-56d1-b27b-de4ebe59395b", "color": "#6510F4"}, {"name": "decision: use graph_completion as default search type", "type": "Entity", "ontology_valid": false, "version": 1, "topological_rank": 0, "metadata": {"index_fields": ["name"]}, "belongs_to_set": null, "source_pipeline": "cognify_pipeline", "source_task": "extract_graph_from_data", "source_node_set": null, "source_user": "default_user@example.com", "feedback_weight": 0.5, "description": "Decision to use GRAPH_COMPLETION as the default search type", "id": "342c6c16-c468-55b1-87b5-ea3a7eda5316", "color": "#6510F4"}, {"name": "decision", "type": "EntityType", "ontology_valid": false, "version": 1, "topological_rank": 0, "metadata": {"index_fields": ["name"]}, "belongs_to_set": null, "source_pipeline": "cognify_pipeline", "source_task": "extract_graph_from_data", "source_node_set": null, "source_user": "default_user@example.com", "feedback_weight": 0.5, "description": "decision", "relations": [], "id": "edef54f2-1ca8-5e4f-bef7-422a7005120f", "color": "#A550FF"}, {"name": "text_eb05286518d418a42800eef8456af922", "type": "TextDocument", "ontology_valid": false, "version": 1, "topological_rank": 0, "metadata": {"index_fields": ["name"]}, "belongs_to_set": null, "source_pipeline": "cognify_pipeline", "source_task": "classify_documents", "source_node_set": null, "source_user": "default_user@example.com", "feedback_weight": 0.5, "raw_data_location": "file:///Users/handekafkas/Documents/local-code/haystack-core-integrations/integrations/cognee/.venv/lib/python3.13/site-packages/cognee/.data_storage/437c2538-ad95-42da-bbe9-2bde9790d147/text_eb05286518d418a42800eef8456af922.txt", "external_metadata": "{}", "mime_type": "text/plain", "id": "1e350c7d-a14b-5f5d-b9c1-793d20b9cd89", "color": "#DBD8D8"}]; +var links = [{"source": "f945057e-79ec-5d9e-b7e7-81eb7d1d52d7", "target": "3a7ffaaf-7d94-5b1f-b039-c1a6893bc2ae", "relation": "made_from", "weight": null, "all_weights": {}, "relationship_type": null, "edge_info": {"source_node_id": "f945057e-79ec-5d9e-b7e7-81eb7d1d52d7", "target_node_id": "3a7ffaaf-7d94-5b1f-b039-c1a6893bc2ae", "relationship_name": "made_from", "updated_at": "2026-04-02 09:10:48", "edge_object_id": "bafd2686-b07d-5d95-958f-ea0162141494", "feedback_weight": 0.5}}, {"source": "3a7ffaaf-7d94-5b1f-b039-c1a6893bc2ae", "target": "9591ae32-57d8-591f-bb04-3077530bea6a", "relation": "contains", "weight": null, "all_weights": {}, "relationship_type": "contains", "edge_info": {"source_node_id": "3a7ffaaf-7d94-5b1f-b039-c1a6893bc2ae", "target_node_id": "9591ae32-57d8-591f-bb04-3077530bea6a", "relationship_name": "contains", "updated_at": "2026-04-02 09:10:48", "relationship_type": "contains", "edge_text": "relationship_name: contains; entity_name: this project; entity_description: Project referred to in the user's message.", "edge_object_id": "735762d6-f720-56e7-9e16-f4e2e04abd6e", "feedback_weight": 0.5}}, {"source": "3a7ffaaf-7d94-5b1f-b039-c1a6893bc2ae", "target": "bd261130-9c89-5df6-b834-f841adda8252", "relation": "contains", "weight": null, "all_weights": {}, "relationship_type": "contains", "edge_info": {"source_node_id": "3a7ffaaf-7d94-5b1f-b039-c1a6893bc2ae", "target_node_id": "bd261130-9c89-5df6-b834-f841adda8252", "relationship_name": "contains", "updated_at": "2026-04-02 09:10:48", "relationship_type": "contains", "edge_text": "relationship_name: contains; entity_name: 2026-04-03; entity_description: Next Friday relative to 2026-04-02 (interpreted from 'next Friday').", "edge_object_id": "dc9e50fd-043a-5287-a9c8-002d71d76de2", "feedback_weight": 0.5}}, {"source": "3a7ffaaf-7d94-5b1f-b039-c1a6893bc2ae", "target": "90ed6132-7732-572f-b798-d833662c4a18", "relation": "contains", "weight": null, "all_weights": {}, "relationship_type": "contains", "edge_info": {"source_node_id": "3a7ffaaf-7d94-5b1f-b039-c1a6893bc2ae", "target_node_id": "90ed6132-7732-572f-b798-d833662c4a18", "relationship_name": "contains", "updated_at": "2026-04-02 09:10:48", "relationship_type": "contains", "edge_text": "relationship_name: contains; entity_name: graph_completion; entity_description: Preferred search type specified for the project.", "edge_object_id": "1b0a2a25-0257-5d67-852c-9f609e20b408", "feedback_weight": 0.5}}, {"source": "3a7ffaaf-7d94-5b1f-b039-c1a6893bc2ae", "target": "e78a62e4-43c4-53e8-958c-dff882d08f6a", "relation": "is_part_of", "weight": null, "all_weights": {}, "relationship_type": null, "edge_info": {"source_node_id": "3a7ffaaf-7d94-5b1f-b039-c1a6893bc2ae", "target_node_id": "e78a62e4-43c4-53e8-958c-dff882d08f6a", "relationship_name": "is_part_of", "updated_at": "2026-04-02 09:10:48", "edge_object_id": "0db2781d-2a3b-57f9-a2ba-7950c6c2d888", "feedback_weight": 0.5}}, {"source": "9591ae32-57d8-591f-bb04-3077530bea6a", "target": "29c0d211-0d39-579f-bf45-c7a78394c9aa", "relation": "is_a", "weight": null, "all_weights": {}, "relationship_type": null, "edge_info": {"source_node_id": "9591ae32-57d8-591f-bb04-3077530bea6a", "target_node_id": "29c0d211-0d39-579f-bf45-c7a78394c9aa", "relationship_name": "is_a", "updated_at": "2026-04-02 09:10:48", "edge_object_id": "34bb5ddb-d2b9-5efb-b8a0-89fbaf353942", "feedback_weight": 0.5}}, {"source": "9591ae32-57d8-591f-bb04-3077530bea6a", "target": "bd261130-9c89-5df6-b834-f841adda8252", "relation": "has_deadline", "weight": null, "all_weights": {}, "relationship_type": "has_deadline", "edge_info": {"source_node_id": "9591ae32-57d8-591f-bb04-3077530bea6a", "target_node_id": "bd261130-9c89-5df6-b834-f841adda8252", "relationship_name": "has_deadline", "updated_at": "2026-04-02 09:10:48", "relationship_type": "has_deadline", "edge_object_id": "2eae2c70-582c-5517-81a4-0cdf1c2721ba", "feedback_weight": 0.5}}, {"source": "9591ae32-57d8-591f-bb04-3077530bea6a", "target": "90ed6132-7732-572f-b798-d833662c4a18", "relation": "preferred_search_type", "weight": null, "all_weights": {}, "relationship_type": "preferred_search_type", "edge_info": {"source_node_id": "9591ae32-57d8-591f-bb04-3077530bea6a", "target_node_id": "90ed6132-7732-572f-b798-d833662c4a18", "relationship_name": "preferred_search_type", "updated_at": "2026-04-02 09:10:48", "relationship_type": "preferred_search_type", "edge_object_id": "94e60e8b-2dca-508e-9867-a1443d37f72b", "feedback_weight": 0.5}}, {"source": "bd261130-9c89-5df6-b834-f841adda8252", "target": "d61d99ac-b291-5666-9748-3e80e1c8b56a", "relation": "is_a", "weight": null, "all_weights": {}, "relationship_type": null, "edge_info": {"source_node_id": "bd261130-9c89-5df6-b834-f841adda8252", "target_node_id": "d61d99ac-b291-5666-9748-3e80e1c8b56a", "relationship_name": "is_a", "updated_at": "2026-04-02 09:10:48", "edge_object_id": "fe2aeb82-c624-5d29-a8c6-9daf5a89138e", "feedback_weight": 0.5}}, {"source": "90ed6132-7732-572f-b798-d833662c4a18", "target": "26ec8442-0b57-5727-a4b1-8208eee3a7c7", "relation": "is_a", "weight": null, "all_weights": {}, "relationship_type": null, "edge_info": {"source_node_id": "90ed6132-7732-572f-b798-d833662c4a18", "target_node_id": "26ec8442-0b57-5727-a4b1-8208eee3a7c7", "relationship_name": "is_a", "updated_at": "2026-04-02 09:10:48", "edge_object_id": "a48a5fe6-a071-572f-af1f-625fbcf0df67", "feedback_weight": 0.5}}, {"source": "90ed6132-7732-572f-b798-d833662c4a18", "target": "00f29df1-cee8-544f-87d6-60761845f00b", "relation": "is_a", "weight": null, "all_weights": {}, "relationship_type": null, "edge_info": {"source_node_id": "90ed6132-7732-572f-b798-d833662c4a18", "target_node_id": "00f29df1-cee8-544f-87d6-60761845f00b", "relationship_name": "is_a", "updated_at": "2026-04-02 09:10:53", "edge_object_id": "3b589b47-088b-5d82-9834-79b95c063d16", "feedback_weight": 0.5}}, {"source": "90ed6132-7732-572f-b798-d833662c4a18", "target": "3d0c908a-35fd-5370-953e-8952648f0900", "relation": "uses", "weight": null, "all_weights": {}, "relationship_type": "uses", "edge_info": {"source_node_id": "90ed6132-7732-572f-b798-d833662c4a18", "target_node_id": "3d0c908a-35fd-5370-953e-8952648f0900", "relationship_name": "uses", "updated_at": "2026-04-02 09:10:53", "relationship_type": "uses", "edge_object_id": "17c86f99-fdfa-5780-b06b-19d4b4f74240", "feedback_weight": 0.5}}, {"source": "90ed6132-7732-572f-b798-d833662c4a18", "target": "b3c5ff56-7122-56d1-b27b-de4ebe59395b", "relation": "uses", "weight": null, "all_weights": {}, "relationship_type": "uses", "edge_info": {"source_node_id": "90ed6132-7732-572f-b798-d833662c4a18", "target_node_id": "b3c5ff56-7122-56d1-b27b-de4ebe59395b", "relationship_name": "uses", "updated_at": "2026-04-02 09:10:53", "relationship_type": "uses", "edge_object_id": "ca6e8814-8c04-5da1-a790-66fa75708073", "feedback_weight": 0.5}}, {"source": "90ed6132-7732-572f-b798-d833662c4a18", "target": "9aaff686-abbb-54c1-b70c-8f6de27b9444", "relation": "retrieves", "weight": null, "all_weights": {}, "relationship_type": "retrieves", "edge_info": {"source_node_id": "90ed6132-7732-572f-b798-d833662c4a18", "target_node_id": "9aaff686-abbb-54c1-b70c-8f6de27b9444", "relationship_name": "retrieves", "updated_at": "2026-04-02 09:10:53", "relationship_type": "retrieves", "edge_object_id": "e78bb863-6a9d-5365-9161-cbb8a1ecaa64", "feedback_weight": 0.5}}, {"source": "59e47787-7802-5d87-a7f4-0de053bbd421", "target": "01195d51-08f7-59fc-a461-7396bdc7ee27", "relation": "made_from", "weight": null, "all_weights": {}, "relationship_type": null, "edge_info": {"source_node_id": "59e47787-7802-5d87-a7f4-0de053bbd421", "target_node_id": "01195d51-08f7-59fc-a461-7396bdc7ee27", "relationship_name": "made_from", "updated_at": "2026-04-02 09:10:49", "edge_object_id": "78e5324a-4b10-5271-88d2-c0fc5dd417ae", "feedback_weight": 0.5}}, {"source": "01195d51-08f7-59fc-a461-7396bdc7ee27", "target": "f7d8be13-2a72-5104-bd02-7a5964737a91", "relation": "contains", "weight": null, "all_weights": {}, "relationship_type": "contains", "edge_info": {"source_node_id": "01195d51-08f7-59fc-a461-7396bdc7ee27", "target_node_id": "f7d8be13-2a72-5104-bd02-7a5964737a91", "relationship_name": "contains", "updated_at": "2026-04-02 09:10:49", "relationship_type": "contains", "edge_text": "relationship_name: contains; entity_name: alice; entity_description: Person who is working on the Cognee-Haystack integration.", "edge_object_id": "8cadc8e8-bbd1-5e43-ae02-ce9ea86e4f02", "feedback_weight": 0.5}}, {"source": "01195d51-08f7-59fc-a461-7396bdc7ee27", "target": "37f4562e-675f-5309-9cf3-82fc46dfd7bf", "relation": "contains", "weight": null, "all_weights": {}, "relationship_type": "contains", "edge_info": {"source_node_id": "01195d51-08f7-59fc-a461-7396bdc7ee27", "target_node_id": "37f4562e-675f-5309-9cf3-82fc46dfd7bf", "relationship_name": "contains", "updated_at": "2026-04-02 09:10:49", "relationship_type": "contains", "edge_text": "relationship_name: contains; entity_name: cognee-haystack integration; entity_description: Integration project between Cognee and Haystack.", "edge_object_id": "05271794-a693-5e38-8a83-cab3a7ab9e2a", "feedback_weight": 0.5}}, {"source": "01195d51-08f7-59fc-a461-7396bdc7ee27", "target": "e995ad45-cb4a-5114-9b09-5c9c90335852", "relation": "contains", "weight": null, "all_weights": {}, "relationship_type": "contains", "edge_info": {"source_node_id": "01195d51-08f7-59fc-a461-7396bdc7ee27", "target_node_id": "e995ad45-cb4a-5114-9b09-5c9c90335852", "relationship_name": "contains", "updated_at": "2026-04-02 09:10:49", "relationship_type": "contains", "edge_text": "relationship_name: contains; entity_name: next friday; entity_description: date: 2026-04-03", "edge_object_id": "fc2176b8-57d7-5573-adfd-fad53baa46d7", "feedback_weight": 0.5}}, {"source": "01195d51-08f7-59fc-a461-7396bdc7ee27", "target": "8d7a6715-a090-5d3c-b55e-bcd4d7a93b6d", "relation": "is_part_of", "weight": null, "all_weights": {}, "relationship_type": null, "edge_info": {"source_node_id": "01195d51-08f7-59fc-a461-7396bdc7ee27", "target_node_id": "8d7a6715-a090-5d3c-b55e-bcd4d7a93b6d", "relationship_name": "is_part_of", "updated_at": "2026-04-02 09:10:49", "edge_object_id": "aab92aec-f95f-5106-a5ed-7a153903d16b", "feedback_weight": 0.5}}, {"source": "f7d8be13-2a72-5104-bd02-7a5964737a91", "target": "d072ba0f-e1a9-58bf-9974-e1802adc8134", "relation": "is_a", "weight": null, "all_weights": {}, "relationship_type": null, "edge_info": {"source_node_id": "f7d8be13-2a72-5104-bd02-7a5964737a91", "target_node_id": "d072ba0f-e1a9-58bf-9974-e1802adc8134", "relationship_name": "is_a", "updated_at": "2026-04-02 09:10:49", "edge_object_id": "635bbc13-9413-5d22-822b-50c92aa8bdd1", "feedback_weight": 0.5}}, {"source": "f7d8be13-2a72-5104-bd02-7a5964737a91", "target": "37f4562e-675f-5309-9cf3-82fc46dfd7bf", "relation": "works_on", "weight": null, "all_weights": {}, "relationship_type": "works_on", "edge_info": {"source_node_id": "f7d8be13-2a72-5104-bd02-7a5964737a91", "target_node_id": "37f4562e-675f-5309-9cf3-82fc46dfd7bf", "relationship_name": "works_on", "updated_at": "2026-04-02 09:10:49", "relationship_type": "works_on", "edge_object_id": "ba555e36-c351-5234-834b-7ef4904a236d", "feedback_weight": 0.5}}, {"source": "37f4562e-675f-5309-9cf3-82fc46dfd7bf", "target": "29c0d211-0d39-579f-bf45-c7a78394c9aa", "relation": "is_a", "weight": null, "all_weights": {}, "relationship_type": null, "edge_info": {"source_node_id": "37f4562e-675f-5309-9cf3-82fc46dfd7bf", "target_node_id": "29c0d211-0d39-579f-bf45-c7a78394c9aa", "relationship_name": "is_a", "updated_at": "2026-04-02 09:10:49", "edge_object_id": "bab9a45d-d725-51c8-8922-f98d8c18c512", "feedback_weight": 0.5}}, {"source": "37f4562e-675f-5309-9cf3-82fc46dfd7bf", "target": "e995ad45-cb4a-5114-9b09-5c9c90335852", "relation": "has_deadline", "weight": null, "all_weights": {}, "relationship_type": "has_deadline", "edge_info": {"source_node_id": "37f4562e-675f-5309-9cf3-82fc46dfd7bf", "target_node_id": "e995ad45-cb4a-5114-9b09-5c9c90335852", "relationship_name": "has_deadline", "updated_at": "2026-04-02 09:10:49", "relationship_type": "has_deadline", "edge_object_id": "5f2c2d88-c2f2-5cd6-8363-e3ba3de892a7", "feedback_weight": 0.5}}, {"source": "e995ad45-cb4a-5114-9b09-5c9c90335852", "target": "d61d99ac-b291-5666-9748-3e80e1c8b56a", "relation": "is_a", "weight": null, "all_weights": {}, "relationship_type": null, "edge_info": {"source_node_id": "e995ad45-cb4a-5114-9b09-5c9c90335852", "target_node_id": "d61d99ac-b291-5666-9748-3e80e1c8b56a", "relationship_name": "is_a", "updated_at": "2026-04-02 09:10:49", "edge_object_id": "c36522ea-6870-52a5-a26c-14bdde27c362", "feedback_weight": 0.5}}, {"source": "23cf773a-d442-5ba8-9353-465db0f5b477", "target": "94d0c5eb-1260-59bd-917f-bd50dc31b1ed", "relation": "made_from", "weight": null, "all_weights": {}, "relationship_type": null, "edge_info": {"source_node_id": "23cf773a-d442-5ba8-9353-465db0f5b477", "target_node_id": "94d0c5eb-1260-59bd-917f-bd50dc31b1ed", "relationship_name": "made_from", "updated_at": "2026-04-02 09:10:53", "edge_object_id": "a40c0da2-6b7c-5968-8377-e5b6755307e0", "feedback_weight": 0.5}}, {"source": "94d0c5eb-1260-59bd-917f-bd50dc31b1ed", "target": "90ed6132-7732-572f-b798-d833662c4a18", "relation": "contains", "weight": null, "all_weights": {}, "relationship_type": "contains", "edge_info": {"source_node_id": "94d0c5eb-1260-59bd-917f-bd50dc31b1ed", "target_node_id": "90ed6132-7732-572f-b798-d833662c4a18", "relationship_name": "contains", "updated_at": "2026-04-02 09:10:53", "relationship_type": "contains", "edge_text": "relationship_name: contains; entity_name: graph_completion; entity_description: Search type that retrieves the most relevant memories by graph traversal and vector search", "edge_object_id": "5169e2a8-7edb-59b7-b7bb-95d1d21409b3", "feedback_weight": 0.5}}, {"source": "94d0c5eb-1260-59bd-917f-bd50dc31b1ed", "target": "3d0c908a-35fd-5370-953e-8952648f0900", "relation": "contains", "weight": null, "all_weights": {}, "relationship_type": "contains", "edge_info": {"source_node_id": "94d0c5eb-1260-59bd-917f-bd50dc31b1ed", "target_node_id": "3d0c908a-35fd-5370-953e-8952648f0900", "relationship_name": "contains", "updated_at": "2026-04-02 09:10:53", "relationship_type": "contains", "edge_text": "relationship_name: contains; entity_name: graph traversal; entity_description: Technique used to traverse a knowledge graph to locate related memories", "edge_object_id": "4bc7b4b5-21b1-5171-95e8-35b3793c7b27", "feedback_weight": 0.5}}, {"source": "94d0c5eb-1260-59bd-917f-bd50dc31b1ed", "target": "b3c5ff56-7122-56d1-b27b-de4ebe59395b", "relation": "contains", "weight": null, "all_weights": {}, "relationship_type": "contains", "edge_info": {"source_node_id": "94d0c5eb-1260-59bd-917f-bd50dc31b1ed", "target_node_id": "b3c5ff56-7122-56d1-b27b-de4ebe59395b", "relationship_name": "contains", "updated_at": "2026-04-02 09:10:53", "relationship_type": "contains", "edge_text": "relationship_name: contains; entity_name: vector search; entity_description: Technique that retrieves items based on vector similarity", "edge_object_id": "b2d74451-805e-53bb-9d35-e3ae31dfeb62", "feedback_weight": 0.5}}, {"source": "94d0c5eb-1260-59bd-917f-bd50dc31b1ed", "target": "9aaff686-abbb-54c1-b70c-8f6de27b9444", "relation": "contains", "weight": null, "all_weights": {}, "relationship_type": "contains", "edge_info": {"source_node_id": "94d0c5eb-1260-59bd-917f-bd50dc31b1ed", "target_node_id": "9aaff686-abbb-54c1-b70c-8f6de27b9444", "relationship_name": "contains", "updated_at": "2026-04-02 09:10:53", "relationship_type": "contains", "edge_text": "relationship_name: contains; entity_name: most relevant memories; entity_description: Memories ranked as most relevant to a query", "edge_object_id": "b29d1898-c10c-5001-9aa5-72b961367ab1", "feedback_weight": 0.5}}, {"source": "94d0c5eb-1260-59bd-917f-bd50dc31b1ed", "target": "342c6c16-c468-55b1-87b5-ea3a7eda5316", "relation": "contains", "weight": null, "all_weights": {}, "relationship_type": "contains", "edge_info": {"source_node_id": "94d0c5eb-1260-59bd-917f-bd50dc31b1ed", "target_node_id": "342c6c16-c468-55b1-87b5-ea3a7eda5316", "relationship_name": "contains", "updated_at": "2026-04-02 09:10:53", "relationship_type": "contains", "edge_text": "relationship_name: contains; entity_name: decision: use graph_completion as default search type; entity_description: Decision to use GRAPH_COMPLETION as the default search type", "edge_object_id": "430a78f2-2a98-5f2b-9d0a-44454f363f66", "feedback_weight": 0.5}}, {"source": "94d0c5eb-1260-59bd-917f-bd50dc31b1ed", "target": "1e350c7d-a14b-5f5d-b9c1-793d20b9cd89", "relation": "is_part_of", "weight": null, "all_weights": {}, "relationship_type": null, "edge_info": {"source_node_id": "94d0c5eb-1260-59bd-917f-bd50dc31b1ed", "target_node_id": "1e350c7d-a14b-5f5d-b9c1-793d20b9cd89", "relationship_name": "is_part_of", "updated_at": "2026-04-02 09:10:53", "edge_object_id": "0c9c16dc-70d0-5306-b4b2-3682a2724905", "feedback_weight": 0.5}}, {"source": "3d0c908a-35fd-5370-953e-8952648f0900", "target": "acc8fc74-4097-5175-b5aa-17349d51dd22", "relation": "is_a", "weight": null, "all_weights": {}, "relationship_type": null, "edge_info": {"source_node_id": "3d0c908a-35fd-5370-953e-8952648f0900", "target_node_id": "acc8fc74-4097-5175-b5aa-17349d51dd22", "relationship_name": "is_a", "updated_at": "2026-04-02 09:10:53", "edge_object_id": "60cf88fa-e23e-5748-b733-a96e63b2d4f5", "feedback_weight": 0.5}}, {"source": "3d0c908a-35fd-5370-953e-8952648f0900", "target": "9aaff686-abbb-54c1-b70c-8f6de27b9444", "relation": "enables_retrieval_of", "weight": null, "all_weights": {}, "relationship_type": "enables_retrieval_of", "edge_info": {"source_node_id": "3d0c908a-35fd-5370-953e-8952648f0900", "target_node_id": "9aaff686-abbb-54c1-b70c-8f6de27b9444", "relationship_name": "enables_retrieval_of", "updated_at": "2026-04-02 09:10:53", "relationship_type": "enables_retrieval_of", "edge_object_id": "2255f48d-71aa-5c8b-be7f-04800f15c19f", "feedback_weight": 0.5}}, {"source": "9aaff686-abbb-54c1-b70c-8f6de27b9444", "target": "dd9713b7-dc20-5101-aad0-1c4216811147", "relation": "is_a", "weight": null, "all_weights": {}, "relationship_type": null, "edge_info": {"source_node_id": "9aaff686-abbb-54c1-b70c-8f6de27b9444", "target_node_id": "dd9713b7-dc20-5101-aad0-1c4216811147", "relationship_name": "is_a", "updated_at": "2026-04-02 09:10:53", "edge_object_id": "222f5529-1a8d-52b3-8d4f-ec3b9d88d42c", "feedback_weight": 0.5}}, {"source": "b3c5ff56-7122-56d1-b27b-de4ebe59395b", "target": "acc8fc74-4097-5175-b5aa-17349d51dd22", "relation": "is_a", "weight": null, "all_weights": {}, "relationship_type": null, "edge_info": {"source_node_id": "b3c5ff56-7122-56d1-b27b-de4ebe59395b", "target_node_id": "acc8fc74-4097-5175-b5aa-17349d51dd22", "relationship_name": "is_a", "updated_at": "2026-04-02 09:10:53", "edge_object_id": "7f705ab4-0a55-5a29-b74c-eb04eaea082c", "feedback_weight": 0.5}}, {"source": "b3c5ff56-7122-56d1-b27b-de4ebe59395b", "target": "9aaff686-abbb-54c1-b70c-8f6de27b9444", "relation": "enables_retrieval_of", "weight": null, "all_weights": {}, "relationship_type": "enables_retrieval_of", "edge_info": {"source_node_id": "b3c5ff56-7122-56d1-b27b-de4ebe59395b", "target_node_id": "9aaff686-abbb-54c1-b70c-8f6de27b9444", "relationship_name": "enables_retrieval_of", "updated_at": "2026-04-02 09:10:53", "relationship_type": "enables_retrieval_of", "edge_object_id": "f2624661-6556-559b-8707-27097299d9e0", "feedback_weight": 0.5}}, {"source": "342c6c16-c468-55b1-87b5-ea3a7eda5316", "target": "edef54f2-1ca8-5e4f-bef7-422a7005120f", "relation": "is_a", "weight": null, "all_weights": {}, "relationship_type": null, "edge_info": {"source_node_id": "342c6c16-c468-55b1-87b5-ea3a7eda5316", "target_node_id": "edef54f2-1ca8-5e4f-bef7-422a7005120f", "relationship_name": "is_a", "updated_at": "2026-04-02 09:10:53", "edge_object_id": "c66df5ba-3130-5b13-bef8-506b82bd7629", "feedback_weight": 0.5}}, {"source": "342c6c16-c468-55b1-87b5-ea3a7eda5316", "target": "90ed6132-7732-572f-b798-d833662c4a18", "relation": "sets_default_to", "weight": null, "all_weights": {}, "relationship_type": "sets_default_to", "edge_info": {"source_node_id": "342c6c16-c468-55b1-87b5-ea3a7eda5316", "target_node_id": "90ed6132-7732-572f-b798-d833662c4a18", "relationship_name": "sets_default_to", "updated_at": "2026-04-02 09:10:53", "relationship_type": "sets_default_to", "edge_object_id": "2f655453-b566-511b-b7ea-1e9658ab5e1b", "feedback_weight": 0.5}}]; var taskColors = {"classify_documents": "#db5656", "extract_chunks_from_documents": "#56db7d", "extract_graph_from_data": "#a456db", "summarize_text": "#dbca56"}; var pipelineColors = {"cognify_pipeline": "#db5656"}; var nodesetColors = {}; diff --git a/integrations/cognee/examples/.artifacts/demo_pipeline.html b/integrations/cognee/examples/.artifacts/demo_pipeline.html index b87f7f42d7..cf72ecd59c 100644 --- a/integrations/cognee/examples/.artifacts/demo_pipeline.html +++ b/integrations/cognee/examples/.artifacts/demo_pipeline.html @@ -171,8 +171,8 @@ (function(){ "use strict"; -var nodes = [{"name": "", "type": "DocumentChunk", "ontology_valid": false, "version": 1, "topological_rank": 0, "metadata": {"index_fields": ["text"]}, "belongs_to_set": null, "source_pipeline": "cognify_pipeline", "source_task": "extract_chunks_from_documents", "source_node_set": null, "source_user": "default_user@example.com", "text": "Knowledge graphs represent information as nodes (entities) and edges (relationships). They enable semantic search, reasoning, and discovery of hidden connections across large document collections.", "chunk_size": 56, "chunk_index": 0, "cut_type": "sentence_end", "id": "601f27c0-4582-5a13-89d3-64a8c0f15cc1", "color": "#0DFF00"}, {"name": "knowledge graphs", "type": "Entity", "ontology_valid": false, "version": 1, "topological_rank": 0, "metadata": {"index_fields": ["name"]}, "belongs_to_set": null, "source_pipeline": "cognify_pipeline", "source_task": "extract_graph_from_data", "source_node_set": null, "source_user": "default_user@example.com", "description": "Knowledge graph technologies used to power the search platform.", "id": "df20c394-b710-5b2c-9256-ce5f5fe36397", "color": "#6510F4"}, {"name": "concept", "type": "EntityType", "ontology_valid": false, "version": 1, "topological_rank": 0, "metadata": {"index_fields": ["name"]}, "belongs_to_set": null, "source_pipeline": "cognify_pipeline", "source_task": "extract_graph_from_data", "source_node_set": null, "source_user": "default_user@example.com", "description": "concept", "id": "dd9713b7-dc20-5101-aad0-1c4216811147", "color": "#A550FF"}, {"name": "nodes", "type": "Entity", "ontology_valid": false, "version": 1, "topological_rank": 0, "metadata": {"index_fields": ["name"]}, "belongs_to_set": null, "source_pipeline": "cognify_pipeline", "source_task": "extract_graph_from_data", "source_node_set": null, "source_user": "default_user@example.com", "description": "Elements in a knowledge graph that represent entities.", "id": "bd3f3aa5-5df4-54a0-af4e-78aa5a54e8f3", "color": "#6510F4"}, {"name": "edges", "type": "Entity", "ontology_valid": false, "version": 1, "topological_rank": 0, "metadata": {"index_fields": ["name"]}, "belongs_to_set": null, "source_pipeline": "cognify_pipeline", "source_task": "extract_graph_from_data", "source_node_set": null, "source_user": "default_user@example.com", "description": "Relationships that connect nodes in a knowledge graph.", "id": "e4f1a343-1dd6-5191-ab16-4901f6eccf51", "color": "#6510F4"}, {"name": "information", "type": "Entity", "ontology_valid": false, "version": 1, "topological_rank": 0, "metadata": {"index_fields": ["name"]}, "belongs_to_set": null, "source_pipeline": "cognify_pipeline", "source_task": "extract_graph_from_data", "source_node_set": null, "source_user": "default_user@example.com", "description": "Data or knowledge represented within a knowledge graph.", "id": "3fb76a7a-fbf5-57ce-afb0-dcabb13cddeb", "color": "#6510F4"}, {"name": "semantic search", "type": "Entity", "ontology_valid": false, "version": 1, "topological_rank": 0, "metadata": {"index_fields": ["name"]}, "belongs_to_set": null, "source_pipeline": "cognify_pipeline", "source_task": "extract_graph_from_data", "source_node_set": null, "source_user": "default_user@example.com", "description": "Search that uses meaning and relationships rather than simple keyword matching.", "id": "9d6360d4-504a-5f7f-b618-c2ea457a1a4d", "color": "#6510F4"}, {"name": "reasoning", "type": "Entity", "ontology_valid": false, "version": 1, "topological_rank": 0, "metadata": {"index_fields": ["name"]}, "belongs_to_set": null, "source_pipeline": "cognify_pipeline", "source_task": "extract_graph_from_data", "source_node_set": null, "source_user": "default_user@example.com", "description": "Inference and logical processes enabled by structured knowledge representations.", "id": "ba802be9-50b2-58a6-a46d-031e30a780a8", "color": "#6510F4"}, {"name": "discovery of hidden connections", "type": "Entity", "ontology_valid": false, "version": 1, "topological_rank": 0, "metadata": {"index_fields": ["name"]}, "belongs_to_set": null, "source_pipeline": "cognify_pipeline", "source_task": "extract_graph_from_data", "source_node_set": null, "source_user": "default_user@example.com", "description": "Identification of non-obvious relationships across data using a knowledge graph.", "id": "e0c5c99c-74a8-5d09-8e8a-05cb2e5bcf6b", "color": "#6510F4"}, {"name": "large document collections", "type": "Entity", "ontology_valid": false, "version": 1, "topological_rank": 0, "metadata": {"index_fields": ["name"]}, "belongs_to_set": null, "source_pipeline": "cognify_pipeline", "source_task": "extract_graph_from_data", "source_node_set": null, "source_user": "default_user@example.com", "description": "Extensive corpora of documents across which knowledge graphs can reveal connections.", "id": "838f4a46-e459-58e4-a40b-ab30cd21da5c", "color": "#6510F4"}, {"name": "text_41edf18cf1a9cb76a5e2eb8429cb9a29", "type": "TextDocument", "ontology_valid": false, "version": 1, "topological_rank": 0, "metadata": {"index_fields": ["name"]}, "belongs_to_set": null, "source_pipeline": "cognify_pipeline", "source_task": "classify_documents", "source_node_set": null, "source_user": "default_user@example.com", "raw_data_location": "file:///Users/handekafkas/Documents/local-code/haystack-core-integrations/integrations/cognee/.venv/lib/python3.13/site-packages/cognee/.data_storage/text_41edf18cf1a9cb76a5e2eb8429cb9a29.txt", "external_metadata": "{}", "mime_type": "text/plain", "id": "86c075e6-5852-5d80-8327-4e9691a71f62", "color": "#DBD8D8"}, {"name": "", "type": "DocumentChunk", "ontology_valid": false, "version": 1, "topological_rank": 0, "metadata": {"index_fields": ["text"]}, "belongs_to_set": null, "source_pipeline": "cognify_pipeline", "source_task": "extract_chunks_from_documents", "source_node_set": null, "source_user": "default_user@example.com", "text": "Cognee is an open-source memory for AI agents. Cognee builts a knowledge enginethat transforms raw data (e.g., unstructured documents, relational databases, etc.)into a persistent, rich, and traceable memory that is searchable by meaning and relationships.", "chunk_size": 95, "chunk_index": 0, "cut_type": "sentence_end", "id": "bc815248-f743-5faa-b176-a216cf9e908e", "color": "#0DFF00"}, {"name": "cognee", "type": "Entity", "ontology_valid": false, "version": 1, "topological_rank": 0, "metadata": {"index_fields": ["name"]}, "belongs_to_set": null, "source_pipeline": "cognify_pipeline", "source_task": "extract_graph_from_data", "source_node_set": null, "source_user": "default_user@example.com", "description": "Open-source memory for AI agents; builds a knowledge engine that transforms raw data into a persistent, rich, and traceable memory searchable by meaning and relationships.", "id": "2d09f34b-aee1-5d32-a2f9-23eb7ed48b24", "color": "#6510F4"}, {"name": "software", "type": "EntityType", "ontology_valid": false, "version": 1, "topological_rank": 0, "metadata": {"index_fields": ["name"]}, "belongs_to_set": null, "source_pipeline": "cognify_pipeline", "source_task": "extract_graph_from_data", "source_node_set": null, "source_user": "default_user@example.com", "description": "software", "id": "2d66edc2-1e14-55ab-8304-680b514a597a", "color": "#A550FF"}, {"name": "ai agents", "type": "Entity", "ontology_valid": false, "version": 1, "topological_rank": 0, "metadata": {"index_fields": ["name"]}, "belongs_to_set": null, "source_pipeline": "cognify_pipeline", "source_task": "extract_graph_from_data", "source_node_set": null, "source_user": "default_user@example.com", "description": "Autonomous or semi-autonomous software agents that use memory systems.", "id": "968213f1-6ddc-5155-89d4-6df7c144a4a1", "color": "#6510F4"}, {"name": "agent", "type": "EntityType", "ontology_valid": false, "version": 1, "topological_rank": 0, "metadata": {"index_fields": ["name"]}, "belongs_to_set": null, "source_pipeline": "cognify_pipeline", "source_task": "extract_graph_from_data", "source_node_set": null, "source_user": "default_user@example.com", "description": "agent", "id": "5f6d6fc0-e6aa-5365-a4a0-98d6fa3af190", "color": "#A550FF"}, {"name": "knowledge engine", "type": "Entity", "ontology_valid": false, "version": 1, "topological_rank": 0, "metadata": {"index_fields": ["name"]}, "belongs_to_set": null, "source_pipeline": "cognify_pipeline", "source_task": "extract_graph_from_data", "source_node_set": null, "source_user": "default_user@example.com", "description": "A system that processes and structures raw data into persistent, rich, and traceable memory.", "id": "d8b992b3-ebdc-52a4-9913-9e1aea9a47f8", "color": "#6510F4"}, {"name": "raw data", "type": "Entity", "ontology_valid": false, "version": 1, "topological_rank": 0, "metadata": {"index_fields": ["name"]}, "belongs_to_set": null, "source_pipeline": "cognify_pipeline", "source_task": "extract_graph_from_data", "source_node_set": null, "source_user": "default_user@example.com", "description": "Unprocessed input such as unstructured documents, relational databases, and other data sources.", "id": "0a6f4624-d50e-5989-ba18-ddab839f5554", "color": "#6510F4"}, {"name": "data", "type": "EntityType", "ontology_valid": false, "version": 1, "topological_rank": 0, "metadata": {"index_fields": ["name"]}, "belongs_to_set": null, "source_pipeline": "cognify_pipeline", "source_task": "extract_graph_from_data", "source_node_set": null, "source_user": "default_user@example.com", "description": "data", "id": "4ed5a0c7-2efb-52d1-9734-06a8ba225c94", "color": "#A550FF"}, {"name": "unstructured documents", "type": "Entity", "ontology_valid": false, "version": 1, "topological_rank": 0, "metadata": {"index_fields": ["name"]}, "belongs_to_set": null, "source_pipeline": "cognify_pipeline", "source_task": "extract_graph_from_data", "source_node_set": null, "source_user": "default_user@example.com", "description": "Example raw data format (e.g., text files, reports, articles) mentioned as an input to the knowledge engine.", "id": "f89d185b-5df9-5fc6-84a7-35931b380405", "color": "#6510F4"}, {"name": "relational databases", "type": "Entity", "ontology_valid": false, "version": 1, "topological_rank": 0, "metadata": {"index_fields": ["name"]}, "belongs_to_set": null, "source_pipeline": "cognify_pipeline", "source_task": "extract_graph_from_data", "source_node_set": null, "source_user": "default_user@example.com", "description": "Example raw data format (structured tables) mentioned as an input to the knowledge engine.", "id": "9d84ec4f-0968-52d0-bd6d-2a4c1b07490d", "color": "#6510F4"}, {"name": "persistent rich traceable memory", "type": "Entity", "ontology_valid": false, "version": 1, "topological_rank": 0, "metadata": {"index_fields": ["name"]}, "belongs_to_set": null, "source_pipeline": "cognify_pipeline", "source_task": "extract_graph_from_data", "source_node_set": null, "source_user": "default_user@example.com", "description": "Memory produced by the knowledge engine that is persistent, rich in structure and metadata, traceable, and searchable by meaning and relationships.", "id": "dce5dd84-ed4d-5666-8908-c4c523b804c8", "color": "#6510F4"}, {"name": "text_d1622b5a4ae1e31ed9d352ea3d2cbc20", "type": "TextDocument", "ontology_valid": false, "version": 1, "topological_rank": 0, "metadata": {"index_fields": ["name"]}, "belongs_to_set": null, "source_pipeline": "cognify_pipeline", "source_task": "classify_documents", "source_node_set": null, "source_user": "default_user@example.com", "raw_data_location": "file:///Users/handekafkas/Documents/local-code/haystack-core-integrations/integrations/cognee/.venv/lib/python3.13/site-packages/cognee/.data_storage/text_d1622b5a4ae1e31ed9d352ea3d2cbc20.txt", "external_metadata": "{}", "mime_type": "text/plain", "id": "0700b84c-e4eb-5462-be56-0d7d97d0009e", "color": "#DBD8D8"}, {"name": "", "type": "DocumentChunk", "ontology_valid": false, "version": 1, "topological_rank": 0, "metadata": {"index_fields": ["text"]}, "belongs_to_set": null, "source_pipeline": "cognify_pipeline", "source_task": "extract_chunks_from_documents", "source_node_set": null, "source_user": "default_user@example.com", "text": "The engineering team at Acme Corp consists of Alice (backend lead), Bob (ML engineer), and Carol (infrastructure). They are building a next-generation search platform powered by knowledge graphs and LLMs.", "chunk_size": 72, "chunk_index": 0, "cut_type": "sentence_end", "id": "c569abe9-16f1-54e0-ab9c-a4223e1088e1", "color": "#0DFF00"}, {"name": "alice", "type": "Entity", "ontology_valid": false, "version": 1, "topological_rank": 0, "metadata": {"index_fields": ["name"]}, "belongs_to_set": null, "source_pipeline": "cognify_pipeline", "source_task": "extract_graph_from_data", "source_node_set": null, "source_user": "default_user@example.com", "description": "Backend lead on Acme Corp's engineering team.", "id": "f7d8be13-2a72-5104-bd02-7a5964737a91", "color": "#6510F4"}, {"name": "person", "type": "EntityType", "ontology_valid": false, "version": 1, "topological_rank": 0, "metadata": {"index_fields": ["name"]}, "belongs_to_set": null, "source_pipeline": "cognify_pipeline", "source_task": "extract_graph_from_data", "source_node_set": null, "source_user": "default_user@example.com", "description": "person", "id": "d072ba0f-e1a9-58bf-9974-e1802adc8134", "color": "#A550FF"}, {"name": "bob", "type": "Entity", "ontology_valid": false, "version": 1, "topological_rank": 0, "metadata": {"index_fields": ["name"]}, "belongs_to_set": null, "source_pipeline": "cognify_pipeline", "source_task": "extract_graph_from_data", "source_node_set": null, "source_user": "default_user@example.com", "description": "ML engineer on Acme Corp's engineering team.", "id": "515e93c6-3782-59db-96be-ad5b8cf872a5", "color": "#6510F4"}, {"name": "carol", "type": "Entity", "ontology_valid": false, "version": 1, "topological_rank": 0, "metadata": {"index_fields": ["name"]}, "belongs_to_set": null, "source_pipeline": "cognify_pipeline", "source_task": "extract_graph_from_data", "source_node_set": null, "source_user": "default_user@example.com", "description": "Infrastructure engineer on Acme Corp's engineering team.", "id": "80370ebb-d9b5-5f12-a3fb-db3631157840", "color": "#6510F4"}, {"name": "acme corp", "type": "Entity", "ontology_valid": false, "version": 1, "topological_rank": 0, "metadata": {"index_fields": ["name"]}, "belongs_to_set": null, "source_pipeline": "cognify_pipeline", "source_task": "extract_graph_from_data", "source_node_set": null, "source_user": "default_user@example.com", "description": "Company employing the engineering team.", "id": "7f5a651e-56c1-574f-aa54-cd0a0b7dbc38", "color": "#6510F4"}, {"name": "organization", "type": "EntityType", "ontology_valid": false, "version": 1, "topological_rank": 0, "metadata": {"index_fields": ["name"]}, "belongs_to_set": null, "source_pipeline": "cognify_pipeline", "source_task": "extract_graph_from_data", "source_node_set": null, "source_user": "default_user@example.com", "description": "organization", "id": "d3d7b6b4-9b0d-52e8-9e09-a9e9cf4b5a4d", "color": "#A550FF"}, {"name": "engineering team at acme corp", "type": "Entity", "ontology_valid": false, "version": 1, "topological_rank": 0, "metadata": {"index_fields": ["name"]}, "belongs_to_set": null, "source_pipeline": "cognify_pipeline", "source_task": "extract_graph_from_data", "source_node_set": null, "source_user": "default_user@example.com", "description": "Engineering team at Acme Corp consisting of Alice, Bob, and Carol.", "id": "7fa8891b-a426-5d42-b011-6851ef945793", "color": "#6510F4"}, {"name": "team", "type": "EntityType", "ontology_valid": false, "version": 1, "topological_rank": 0, "metadata": {"index_fields": ["name"]}, "belongs_to_set": null, "source_pipeline": "cognify_pipeline", "source_task": "extract_graph_from_data", "source_node_set": null, "source_user": "default_user@example.com", "description": "team", "id": "e308d782-2a18-5ace-b0e8-236c7c3b4db4", "color": "#A550FF"}, {"name": "next-generation search platform", "type": "Entity", "ontology_valid": false, "version": 1, "topological_rank": 0, "metadata": {"index_fields": ["name"]}, "belongs_to_set": null, "source_pipeline": "cognify_pipeline", "source_task": "extract_graph_from_data", "source_node_set": null, "source_user": "default_user@example.com", "description": "Next-generation search platform being built by the engineering team.", "id": "6fdb37d4-ae27-5a1a-9f7a-03f5036247ca", "color": "#6510F4"}, {"name": "project", "type": "EntityType", "ontology_valid": false, "version": 1, "topological_rank": 0, "metadata": {"index_fields": ["name"]}, "belongs_to_set": null, "source_pipeline": "cognify_pipeline", "source_task": "extract_graph_from_data", "source_node_set": null, "source_user": "default_user@example.com", "description": "project", "id": "29c0d211-0d39-579f-bf45-c7a78394c9aa", "color": "#A550FF"}, {"name": "technology", "type": "EntityType", "ontology_valid": false, "version": 1, "topological_rank": 0, "metadata": {"index_fields": ["name"]}, "belongs_to_set": null, "source_pipeline": "cognify_pipeline", "source_task": "extract_graph_from_data", "source_node_set": null, "source_user": "default_user@example.com", "description": "technology", "id": "65c71de3-4c23-5f28-8e07-fc7428d1e0c4", "color": "#A550FF"}, {"name": "llms", "type": "Entity", "ontology_valid": false, "version": 1, "topological_rank": 0, "metadata": {"index_fields": ["name"]}, "belongs_to_set": null, "source_pipeline": "cognify_pipeline", "source_task": "extract_graph_from_data", "source_node_set": null, "source_user": "default_user@example.com", "description": "Large language models used to power the search platform.", "id": "f7dc5ef7-3d2d-50c7-9edc-475862a15d4b", "color": "#6510F4"}, {"name": "text_fe5096366b6f10a6766dc51cbac9058c", "type": "TextDocument", "ontology_valid": false, "version": 1, "topological_rank": 0, "metadata": {"index_fields": ["name"]}, "belongs_to_set": null, "source_pipeline": "cognify_pipeline", "source_task": "classify_documents", "source_node_set": null, "source_user": "default_user@example.com", "raw_data_location": "file:///Users/handekafkas/Documents/local-code/haystack-core-integrations/integrations/cognee/.venv/lib/python3.13/site-packages/cognee/.data_storage/text_fe5096366b6f10a6766dc51cbac9058c.txt", "external_metadata": "{}", "mime_type": "text/plain", "id": "7706f53e-49ac-582a-8cf4-59b9c6e64bfb", "color": "#DBD8D8"}, {"name": "", "type": "DocumentChunk", "ontology_valid": false, "version": 1, "topological_rank": 0, "metadata": {"index_fields": ["text"]}, "belongs_to_set": null, "source_pipeline": "cognify_pipeline", "source_task": "extract_chunks_from_documents", "source_node_set": null, "source_user": "default_user@example.com", "text": "Haystack is an open-source LLM framework by deepset for building production-ready RAG pipelines, agents, and search systems. It uses a component-based architecture where each step (retrieval, generation, etc.) is a composable building block.", "chunk_size": 84, "chunk_index": 0, "cut_type": "sentence_end", "id": "ee7307f2-cba9-5003-9dc0-0780c50591a6", "color": "#0DFF00"}, {"name": "haystack", "type": "Entity", "ontology_valid": false, "version": 1, "topological_rank": 0, "metadata": {"index_fields": ["name"]}, "belongs_to_set": null, "source_pipeline": "cognify_pipeline", "source_task": "extract_graph_from_data", "source_node_set": null, "source_user": "default_user@example.com", "description": "Open-source LLM framework by deepset for building production-ready RAG pipelines, agents, and search systems.", "id": "2bdd3deb-07d8-5413-a56d-1643e3ceb48b", "color": "#6510F4"}, {"name": "deepset", "type": "Entity", "ontology_valid": false, "version": 1, "topological_rank": 0, "metadata": {"index_fields": ["name"]}, "belongs_to_set": null, "source_pipeline": "cognify_pipeline", "source_task": "extract_graph_from_data", "source_node_set": null, "source_user": "default_user@example.com", "description": "Company that develops Haystack.", "id": "126df7ec-d0db-53ea-bc88-1bafd84c8646", "color": "#6510F4"}, {"name": "rag pipelines", "type": "Entity", "ontology_valid": false, "version": 1, "topological_rank": 0, "metadata": {"index_fields": ["name"]}, "belongs_to_set": null, "source_pipeline": "cognify_pipeline", "source_task": "extract_graph_from_data", "source_node_set": null, "source_user": "default_user@example.com", "description": "Retrieval-Augmented Generation pipelines combining retrieval with LLM generation.", "id": "7594343c-5532-5896-b0aa-be5c1a74bd92", "color": "#6510F4"}, {"name": "agents", "type": "Entity", "ontology_valid": false, "version": 1, "topological_rank": 0, "metadata": {"index_fields": ["name"]}, "belongs_to_set": null, "source_pipeline": "cognify_pipeline", "source_task": "extract_graph_from_data", "source_node_set": null, "source_user": "default_user@example.com", "description": "Agent systems that orchestrate actions and LLM calls.", "id": "ba1f1dac-e2fb-5464-914d-ff54b9b19787", "color": "#6510F4"}, {"name": "search systems", "type": "Entity", "ontology_valid": false, "version": 1, "topological_rank": 0, "metadata": {"index_fields": ["name"]}, "belongs_to_set": null, "source_pipeline": "cognify_pipeline", "source_task": "extract_graph_from_data", "source_node_set": null, "source_user": "default_user@example.com", "description": "Systems for information retrieval and search.", "id": "a1a666e4-2070-59fd-95f7-c4c6178e89ba", "color": "#6510F4"}, {"name": "component-based architecture", "type": "Entity", "ontology_valid": false, "version": 1, "topological_rank": 0, "metadata": {"index_fields": ["name"]}, "belongs_to_set": null, "source_pipeline": "cognify_pipeline", "source_task": "extract_graph_from_data", "source_node_set": null, "source_user": "default_user@example.com", "description": "Architecture composed of modular components where each step is a building block.", "id": "30f5dcb9-d238-5c7d-8d2a-b9da0b854f98", "color": "#6510F4"}, {"name": "retrieval", "type": "Entity", "ontology_valid": false, "version": 1, "topological_rank": 0, "metadata": {"index_fields": ["name"]}, "belongs_to_set": null, "source_pipeline": "cognify_pipeline", "source_task": "extract_graph_from_data", "source_node_set": null, "source_user": "default_user@example.com", "description": "A retrieval step/component in the pipeline.", "id": "f010bf52-6eb5-511f-bbed-cd5237545edd", "color": "#6510F4"}, {"name": "component", "type": "EntityType", "ontology_valid": false, "version": 1, "topological_rank": 0, "metadata": {"index_fields": ["name"]}, "belongs_to_set": null, "source_pipeline": "cognify_pipeline", "source_task": "extract_graph_from_data", "source_node_set": null, "source_user": "default_user@example.com", "description": "component", "id": "b283358b-c288-5ca1-a6e8-05bac88f7a6f", "color": "#A550FF"}, {"name": "generation", "type": "Entity", "ontology_valid": false, "version": 1, "topological_rank": 0, "metadata": {"index_fields": ["name"]}, "belongs_to_set": null, "source_pipeline": "cognify_pipeline", "source_task": "extract_graph_from_data", "source_node_set": null, "source_user": "default_user@example.com", "description": "A generation (LLM) step/component in the pipeline.", "id": "dba0457b-9aff-5eb6-8ccd-19f7c9ae4dfa", "color": "#6510F4"}, {"name": "composable building block", "type": "Entity", "ontology_valid": false, "version": 1, "topological_rank": 0, "metadata": {"index_fields": ["name"]}, "belongs_to_set": null, "source_pipeline": "cognify_pipeline", "source_task": "extract_graph_from_data", "source_node_set": null, "source_user": "default_user@example.com", "description": "A modular, composable building block representing an individual step in the architecture.", "id": "59cf88c0-cb09-5f96-9252-5f5810981bcc", "color": "#6510F4"}, {"name": "text_62f45b114bbc9894497442c0588694a9", "type": "TextDocument", "ontology_valid": false, "version": 1, "topological_rank": 0, "metadata": {"index_fields": ["name"]}, "belongs_to_set": null, "source_pipeline": "cognify_pipeline", "source_task": "classify_documents", "source_node_set": null, "source_user": "default_user@example.com", "raw_data_location": "file:///Users/handekafkas/Documents/local-code/haystack-core-integrations/integrations/cognee/.venv/lib/python3.13/site-packages/cognee/.data_storage/text_62f45b114bbc9894497442c0588694a9.txt", "external_metadata": "{}", "mime_type": "text/plain", "id": "1a7434a3-3266-5111-9501-4fe093f36076", "color": "#DBD8D8"}, {"name": "", "type": "TextSummary", "ontology_valid": false, "version": 1, "topological_rank": 0, "metadata": {"index_fields": ["text"]}, "belongs_to_set": null, "source_pipeline": "cognify_pipeline", "source_task": "summarize_text", "source_node_set": null, "source_user": "default_user@example.com", "text": "Knowledge graphs model information as nodes (entities) and edges (relationships), enabling semantic search, inference, and discovery of hidden connections across large document collections.", "id": "8a75198a-6b32-5a14-926f-ae42589088af", "color": "#6510F4"}, {"name": "", "type": "TextSummary", "ontology_valid": false, "version": 1, "topological_rank": 0, "metadata": {"index_fields": ["text"]}, "belongs_to_set": null, "source_pipeline": "cognify_pipeline", "source_task": "summarize_text", "source_node_set": null, "source_user": "default_user@example.com", "text": "Acme Corp\u2019s engineering team \u2014 Alice (backend lead), Bob (ML engineer), and Carol (infrastructure) \u2014 is developing a next\u2011generation search platform.", "id": "349bab63-8b60-5d59-a1f2-a4413b6377f2", "color": "#6510F4"}, {"name": "", "type": "TextSummary", "ontology_valid": false, "version": 1, "topological_rank": 0, "metadata": {"index_fields": ["text"]}, "belongs_to_set": null, "source_pipeline": "cognify_pipeline", "source_task": "summarize_text", "source_node_set": null, "source_user": "default_user@example.com", "text": "Cognee is an open-source memory system for AI agents that builds a knowledge engine to convert raw data (e.g., unstructured documents, relational databases) into a persistent, enriched, and traceable memory searchable by semantic meaning and relationships.", "id": "16c06ddd-c7f6-5d74-9ed4-a4520ffde7ca", "color": "#6510F4"}, {"name": "", "type": "TextSummary", "ontology_valid": false, "version": 1, "topological_rank": 0, "metadata": {"index_fields": ["text"]}, "belongs_to_set": null, "source_pipeline": "cognify_pipeline", "source_task": "summarize_text", "source_node_set": null, "source_user": "default_user@example.com", "text": "Haystack is an open-source LLM framework by deepset for building production-ready RAG pipelines, agents, and search applications using modular, composable components.", "id": "208e9fa9-a281-5f67-8f8f-4b78c917c467", "color": "#6510F4"}]; -var links = [{"source": "601f27c0-4582-5a13-89d3-64a8c0f15cc1", "target": "df20c394-b710-5b2c-9256-ce5f5fe36397", "relation": "contains", "weight": null, "all_weights": {}, "relationship_type": "contains", "edge_info": {"source_node_id": "601f27c0-4582-5a13-89d3-64a8c0f15cc1", "target_node_id": "df20c394-b710-5b2c-9256-ce5f5fe36397", "relationship_name": "contains", "updated_at": "2026-03-20 23:21:01", "relationship_type": "contains", "edge_text": "relationship_name: contains; entity_name: knowledge graphs; entity_description: Structures that represent information as nodes (entities) and edges (relationships)."}}, {"source": "601f27c0-4582-5a13-89d3-64a8c0f15cc1", "target": "bd3f3aa5-5df4-54a0-af4e-78aa5a54e8f3", "relation": "contains", "weight": null, "all_weights": {}, "relationship_type": "contains", "edge_info": {"source_node_id": "601f27c0-4582-5a13-89d3-64a8c0f15cc1", "target_node_id": "bd3f3aa5-5df4-54a0-af4e-78aa5a54e8f3", "relationship_name": "contains", "updated_at": "2026-03-20 23:21:01", "relationship_type": "contains", "edge_text": "relationship_name: contains; entity_name: nodes; entity_description: Elements in a knowledge graph that represent entities."}}, {"source": "601f27c0-4582-5a13-89d3-64a8c0f15cc1", "target": "e4f1a343-1dd6-5191-ab16-4901f6eccf51", "relation": "contains", "weight": null, "all_weights": {}, "relationship_type": "contains", "edge_info": {"source_node_id": "601f27c0-4582-5a13-89d3-64a8c0f15cc1", "target_node_id": "e4f1a343-1dd6-5191-ab16-4901f6eccf51", "relationship_name": "contains", "updated_at": "2026-03-20 23:21:01", "relationship_type": "contains", "edge_text": "relationship_name: contains; entity_name: edges; entity_description: Relationships that connect nodes in a knowledge graph."}}, {"source": "601f27c0-4582-5a13-89d3-64a8c0f15cc1", "target": "3fb76a7a-fbf5-57ce-afb0-dcabb13cddeb", "relation": "contains", "weight": null, "all_weights": {}, "relationship_type": "contains", "edge_info": {"source_node_id": "601f27c0-4582-5a13-89d3-64a8c0f15cc1", "target_node_id": "3fb76a7a-fbf5-57ce-afb0-dcabb13cddeb", "relationship_name": "contains", "updated_at": "2026-03-20 23:21:01", "relationship_type": "contains", "edge_text": "relationship_name: contains; entity_name: information; entity_description: Data or knowledge represented within a knowledge graph."}}, {"source": "601f27c0-4582-5a13-89d3-64a8c0f15cc1", "target": "9d6360d4-504a-5f7f-b618-c2ea457a1a4d", "relation": "contains", "weight": null, "all_weights": {}, "relationship_type": "contains", "edge_info": {"source_node_id": "601f27c0-4582-5a13-89d3-64a8c0f15cc1", "target_node_id": "9d6360d4-504a-5f7f-b618-c2ea457a1a4d", "relationship_name": "contains", "updated_at": "2026-03-20 23:21:01", "relationship_type": "contains", "edge_text": "relationship_name: contains; entity_name: semantic search; entity_description: Search that uses meaning and relationships rather than simple keyword matching."}}, {"source": "601f27c0-4582-5a13-89d3-64a8c0f15cc1", "target": "ba802be9-50b2-58a6-a46d-031e30a780a8", "relation": "contains", "weight": null, "all_weights": {}, "relationship_type": "contains", "edge_info": {"source_node_id": "601f27c0-4582-5a13-89d3-64a8c0f15cc1", "target_node_id": "ba802be9-50b2-58a6-a46d-031e30a780a8", "relationship_name": "contains", "updated_at": "2026-03-20 23:21:01", "relationship_type": "contains", "edge_text": "relationship_name: contains; entity_name: reasoning; entity_description: Inference and logical processes enabled by structured knowledge representations."}}, {"source": "601f27c0-4582-5a13-89d3-64a8c0f15cc1", "target": "e0c5c99c-74a8-5d09-8e8a-05cb2e5bcf6b", "relation": "contains", "weight": null, "all_weights": {}, "relationship_type": "contains", "edge_info": {"source_node_id": "601f27c0-4582-5a13-89d3-64a8c0f15cc1", "target_node_id": "e0c5c99c-74a8-5d09-8e8a-05cb2e5bcf6b", "relationship_name": "contains", "updated_at": "2026-03-20 23:21:01", "relationship_type": "contains", "edge_text": "relationship_name: contains; entity_name: discovery of hidden connections; entity_description: Identification of non-obvious relationships across data using a knowledge graph."}}, {"source": "601f27c0-4582-5a13-89d3-64a8c0f15cc1", "target": "838f4a46-e459-58e4-a40b-ab30cd21da5c", "relation": "contains", "weight": null, "all_weights": {}, "relationship_type": "contains", "edge_info": {"source_node_id": "601f27c0-4582-5a13-89d3-64a8c0f15cc1", "target_node_id": "838f4a46-e459-58e4-a40b-ab30cd21da5c", "relationship_name": "contains", "updated_at": "2026-03-20 23:21:01", "relationship_type": "contains", "edge_text": "relationship_name: contains; entity_name: large document collections; entity_description: Extensive corpora of documents across which knowledge graphs can reveal connections."}}, {"source": "601f27c0-4582-5a13-89d3-64a8c0f15cc1", "target": "86c075e6-5852-5d80-8327-4e9691a71f62", "relation": "is_part_of", "weight": null, "all_weights": {}, "relationship_type": null, "edge_info": {"source_node_id": "601f27c0-4582-5a13-89d3-64a8c0f15cc1", "target_node_id": "86c075e6-5852-5d80-8327-4e9691a71f62", "relationship_name": "is_part_of", "updated_at": "2026-03-20 23:21:01"}}, {"source": "df20c394-b710-5b2c-9256-ce5f5fe36397", "target": "dd9713b7-dc20-5101-aad0-1c4216811147", "relation": "is_a", "weight": null, "all_weights": {}, "relationship_type": null, "edge_info": {"source_node_id": "df20c394-b710-5b2c-9256-ce5f5fe36397", "target_node_id": "dd9713b7-dc20-5101-aad0-1c4216811147", "relationship_name": "is_a", "updated_at": "2026-03-20 23:21:01"}}, {"source": "df20c394-b710-5b2c-9256-ce5f5fe36397", "target": "3fb76a7a-fbf5-57ce-afb0-dcabb13cddeb", "relation": "represents_information", "weight": null, "all_weights": {}, "relationship_type": null, "edge_info": {"relationship_name": "represents_information", "source_node_id": "df20c394-b710-5b2c-9256-ce5f5fe36397", "target_node_id": "3fb76a7a-fbf5-57ce-afb0-dcabb13cddeb", "ontology_valid": false}}, {"source": "df20c394-b710-5b2c-9256-ce5f5fe36397", "target": "bd3f3aa5-5df4-54a0-af4e-78aa5a54e8f3", "relation": "has_nodes", "weight": null, "all_weights": {}, "relationship_type": null, "edge_info": {"relationship_name": "has_nodes", "source_node_id": "df20c394-b710-5b2c-9256-ce5f5fe36397", "target_node_id": "bd3f3aa5-5df4-54a0-af4e-78aa5a54e8f3", "ontology_valid": false}}, {"source": "df20c394-b710-5b2c-9256-ce5f5fe36397", "target": "e4f1a343-1dd6-5191-ab16-4901f6eccf51", "relation": "has_edges", "weight": null, "all_weights": {}, "relationship_type": null, "edge_info": {"relationship_name": "has_edges", "source_node_id": "df20c394-b710-5b2c-9256-ce5f5fe36397", "target_node_id": "e4f1a343-1dd6-5191-ab16-4901f6eccf51", "ontology_valid": false}}, {"source": "df20c394-b710-5b2c-9256-ce5f5fe36397", "target": "9d6360d4-504a-5f7f-b618-c2ea457a1a4d", "relation": "enables_semantic_search", "weight": null, "all_weights": {}, "relationship_type": null, "edge_info": {"relationship_name": "enables_semantic_search", "source_node_id": "df20c394-b710-5b2c-9256-ce5f5fe36397", "target_node_id": "9d6360d4-504a-5f7f-b618-c2ea457a1a4d", "ontology_valid": false}}, {"source": "df20c394-b710-5b2c-9256-ce5f5fe36397", "target": "ba802be9-50b2-58a6-a46d-031e30a780a8", "relation": "enables_reasoning", "weight": null, "all_weights": {}, "relationship_type": null, "edge_info": {"relationship_name": "enables_reasoning", "source_node_id": "df20c394-b710-5b2c-9256-ce5f5fe36397", "target_node_id": "ba802be9-50b2-58a6-a46d-031e30a780a8", "ontology_valid": false}}, {"source": "df20c394-b710-5b2c-9256-ce5f5fe36397", "target": "e0c5c99c-74a8-5d09-8e8a-05cb2e5bcf6b", "relation": "enables_discovery_of_hidden_connections", "weight": null, "all_weights": {}, "relationship_type": null, "edge_info": {"relationship_name": "enables_discovery_of_hidden_connections", "source_node_id": "df20c394-b710-5b2c-9256-ce5f5fe36397", "target_node_id": "e0c5c99c-74a8-5d09-8e8a-05cb2e5bcf6b", "ontology_valid": false}}, {"source": "df20c394-b710-5b2c-9256-ce5f5fe36397", "target": "65c71de3-4c23-5f28-8e07-fc7428d1e0c4", "relation": "is_a", "weight": null, "all_weights": {}, "relationship_type": null, "edge_info": {"source_node_id": "df20c394-b710-5b2c-9256-ce5f5fe36397", "target_node_id": "65c71de3-4c23-5f28-8e07-fc7428d1e0c4", "relationship_name": "is_a", "updated_at": "2026-03-20 23:21:03"}}, {"source": "bd3f3aa5-5df4-54a0-af4e-78aa5a54e8f3", "target": "dd9713b7-dc20-5101-aad0-1c4216811147", "relation": "is_a", "weight": null, "all_weights": {}, "relationship_type": null, "edge_info": {"source_node_id": "bd3f3aa5-5df4-54a0-af4e-78aa5a54e8f3", "target_node_id": "dd9713b7-dc20-5101-aad0-1c4216811147", "relationship_name": "is_a", "updated_at": "2026-03-20 23:21:01"}}, {"source": "e4f1a343-1dd6-5191-ab16-4901f6eccf51", "target": "dd9713b7-dc20-5101-aad0-1c4216811147", "relation": "is_a", "weight": null, "all_weights": {}, "relationship_type": null, "edge_info": {"source_node_id": "e4f1a343-1dd6-5191-ab16-4901f6eccf51", "target_node_id": "dd9713b7-dc20-5101-aad0-1c4216811147", "relationship_name": "is_a", "updated_at": "2026-03-20 23:21:01"}}, {"source": "3fb76a7a-fbf5-57ce-afb0-dcabb13cddeb", "target": "dd9713b7-dc20-5101-aad0-1c4216811147", "relation": "is_a", "weight": null, "all_weights": {}, "relationship_type": null, "edge_info": {"source_node_id": "3fb76a7a-fbf5-57ce-afb0-dcabb13cddeb", "target_node_id": "dd9713b7-dc20-5101-aad0-1c4216811147", "relationship_name": "is_a", "updated_at": "2026-03-20 23:21:01"}}, {"source": "9d6360d4-504a-5f7f-b618-c2ea457a1a4d", "target": "dd9713b7-dc20-5101-aad0-1c4216811147", "relation": "is_a", "weight": null, "all_weights": {}, "relationship_type": null, "edge_info": {"source_node_id": "9d6360d4-504a-5f7f-b618-c2ea457a1a4d", "target_node_id": "dd9713b7-dc20-5101-aad0-1c4216811147", "relationship_name": "is_a", "updated_at": "2026-03-20 23:21:01"}}, {"source": "ba802be9-50b2-58a6-a46d-031e30a780a8", "target": "dd9713b7-dc20-5101-aad0-1c4216811147", "relation": "is_a", "weight": null, "all_weights": {}, "relationship_type": null, "edge_info": {"source_node_id": "ba802be9-50b2-58a6-a46d-031e30a780a8", "target_node_id": "dd9713b7-dc20-5101-aad0-1c4216811147", "relationship_name": "is_a", "updated_at": "2026-03-20 23:21:01"}}, {"source": "e0c5c99c-74a8-5d09-8e8a-05cb2e5bcf6b", "target": "dd9713b7-dc20-5101-aad0-1c4216811147", "relation": "is_a", "weight": null, "all_weights": {}, "relationship_type": null, "edge_info": {"source_node_id": "e0c5c99c-74a8-5d09-8e8a-05cb2e5bcf6b", "target_node_id": "dd9713b7-dc20-5101-aad0-1c4216811147", "relationship_name": "is_a", "updated_at": "2026-03-20 23:21:01"}}, {"source": "e0c5c99c-74a8-5d09-8e8a-05cb2e5bcf6b", "target": "838f4a46-e459-58e4-a40b-ab30cd21da5c", "relation": "across_large_document_collections", "weight": null, "all_weights": {}, "relationship_type": null, "edge_info": {"relationship_name": "across_large_document_collections", "source_node_id": "e0c5c99c-74a8-5d09-8e8a-05cb2e5bcf6b", "target_node_id": "838f4a46-e459-58e4-a40b-ab30cd21da5c", "ontology_valid": false}}, {"source": "838f4a46-e459-58e4-a40b-ab30cd21da5c", "target": "dd9713b7-dc20-5101-aad0-1c4216811147", "relation": "is_a", "weight": null, "all_weights": {}, "relationship_type": null, "edge_info": {"source_node_id": "838f4a46-e459-58e4-a40b-ab30cd21da5c", "target_node_id": "dd9713b7-dc20-5101-aad0-1c4216811147", "relationship_name": "is_a", "updated_at": "2026-03-20 23:21:01"}}, {"source": "bc815248-f743-5faa-b176-a216cf9e908e", "target": "2d09f34b-aee1-5d32-a2f9-23eb7ed48b24", "relation": "contains", "weight": null, "all_weights": {}, "relationship_type": "contains", "edge_info": {"source_node_id": "bc815248-f743-5faa-b176-a216cf9e908e", "target_node_id": "2d09f34b-aee1-5d32-a2f9-23eb7ed48b24", "relationship_name": "contains", "updated_at": "2026-03-20 23:21:04", "relationship_type": "contains", "edge_text": "relationship_name: contains; entity_name: cognee; entity_description: Open-source memory for AI agents; builds a knowledge engine that transforms raw data into a persistent, rich, and traceable memory searchable by meaning and relationships."}}, {"source": "bc815248-f743-5faa-b176-a216cf9e908e", "target": "968213f1-6ddc-5155-89d4-6df7c144a4a1", "relation": "contains", "weight": null, "all_weights": {}, "relationship_type": "contains", "edge_info": {"source_node_id": "bc815248-f743-5faa-b176-a216cf9e908e", "target_node_id": "968213f1-6ddc-5155-89d4-6df7c144a4a1", "relationship_name": "contains", "updated_at": "2026-03-20 23:21:04", "relationship_type": "contains", "edge_text": "relationship_name: contains; entity_name: ai agents; entity_description: Autonomous or semi-autonomous software agents that use memory systems."}}, {"source": "bc815248-f743-5faa-b176-a216cf9e908e", "target": "d8b992b3-ebdc-52a4-9913-9e1aea9a47f8", "relation": "contains", "weight": null, "all_weights": {}, "relationship_type": "contains", "edge_info": {"source_node_id": "bc815248-f743-5faa-b176-a216cf9e908e", "target_node_id": "d8b992b3-ebdc-52a4-9913-9e1aea9a47f8", "relationship_name": "contains", "updated_at": "2026-03-20 23:21:04", "relationship_type": "contains", "edge_text": "relationship_name: contains; entity_name: knowledge engine; entity_description: A system that processes and structures raw data into persistent, rich, and traceable memory."}}, {"source": "bc815248-f743-5faa-b176-a216cf9e908e", "target": "0a6f4624-d50e-5989-ba18-ddab839f5554", "relation": "contains", "weight": null, "all_weights": {}, "relationship_type": "contains", "edge_info": {"source_node_id": "bc815248-f743-5faa-b176-a216cf9e908e", "target_node_id": "0a6f4624-d50e-5989-ba18-ddab839f5554", "relationship_name": "contains", "updated_at": "2026-03-20 23:21:04", "relationship_type": "contains", "edge_text": "relationship_name: contains; entity_name: raw data; entity_description: Unprocessed input such as unstructured documents, relational databases, and other data sources."}}, {"source": "bc815248-f743-5faa-b176-a216cf9e908e", "target": "f89d185b-5df9-5fc6-84a7-35931b380405", "relation": "contains", "weight": null, "all_weights": {}, "relationship_type": "contains", "edge_info": {"source_node_id": "bc815248-f743-5faa-b176-a216cf9e908e", "target_node_id": "f89d185b-5df9-5fc6-84a7-35931b380405", "relationship_name": "contains", "updated_at": "2026-03-20 23:21:04", "relationship_type": "contains", "edge_text": "relationship_name: contains; entity_name: unstructured documents; entity_description: Example raw data format (e.g., text files, reports, articles) mentioned as an input to the knowledge engine."}}, {"source": "bc815248-f743-5faa-b176-a216cf9e908e", "target": "9d84ec4f-0968-52d0-bd6d-2a4c1b07490d", "relation": "contains", "weight": null, "all_weights": {}, "relationship_type": "contains", "edge_info": {"source_node_id": "bc815248-f743-5faa-b176-a216cf9e908e", "target_node_id": "9d84ec4f-0968-52d0-bd6d-2a4c1b07490d", "relationship_name": "contains", "updated_at": "2026-03-20 23:21:04", "relationship_type": "contains", "edge_text": "relationship_name: contains; entity_name: relational databases; entity_description: Example raw data format (structured tables) mentioned as an input to the knowledge engine."}}, {"source": "bc815248-f743-5faa-b176-a216cf9e908e", "target": "dce5dd84-ed4d-5666-8908-c4c523b804c8", "relation": "contains", "weight": null, "all_weights": {}, "relationship_type": "contains", "edge_info": {"source_node_id": "bc815248-f743-5faa-b176-a216cf9e908e", "target_node_id": "dce5dd84-ed4d-5666-8908-c4c523b804c8", "relationship_name": "contains", "updated_at": "2026-03-20 23:21:04", "relationship_type": "contains", "edge_text": "relationship_name: contains; entity_name: persistent rich traceable memory; entity_description: Memory produced by the knowledge engine that is persistent, rich in structure and metadata, traceable, and searchable by meaning and relationships."}}, {"source": "bc815248-f743-5faa-b176-a216cf9e908e", "target": "0700b84c-e4eb-5462-be56-0d7d97d0009e", "relation": "is_part_of", "weight": null, "all_weights": {}, "relationship_type": null, "edge_info": {"source_node_id": "bc815248-f743-5faa-b176-a216cf9e908e", "target_node_id": "0700b84c-e4eb-5462-be56-0d7d97d0009e", "relationship_name": "is_part_of", "updated_at": "2026-03-20 23:21:04"}}, {"source": "2d09f34b-aee1-5d32-a2f9-23eb7ed48b24", "target": "2d66edc2-1e14-55ab-8304-680b514a597a", "relation": "is_a", "weight": null, "all_weights": {}, "relationship_type": null, "edge_info": {"source_node_id": "2d09f34b-aee1-5d32-a2f9-23eb7ed48b24", "target_node_id": "2d66edc2-1e14-55ab-8304-680b514a597a", "relationship_name": "is_a", "updated_at": "2026-03-20 23:21:04"}}, {"source": "2d09f34b-aee1-5d32-a2f9-23eb7ed48b24", "target": "dce5dd84-ed4d-5666-8908-c4c523b804c8", "relation": "is_a", "weight": null, "all_weights": {}, "relationship_type": null, "edge_info": {"relationship_name": "is_a", "source_node_id": "2d09f34b-aee1-5d32-a2f9-23eb7ed48b24", "target_node_id": "dce5dd84-ed4d-5666-8908-c4c523b804c8", "ontology_valid": false}}, {"source": "2d09f34b-aee1-5d32-a2f9-23eb7ed48b24", "target": "968213f1-6ddc-5155-89d4-6df7c144a4a1", "relation": "for_agents", "weight": null, "all_weights": {}, "relationship_type": null, "edge_info": {"relationship_name": "for_agents", "source_node_id": "2d09f34b-aee1-5d32-a2f9-23eb7ed48b24", "target_node_id": "968213f1-6ddc-5155-89d4-6df7c144a4a1", "ontology_valid": false}}, {"source": "2d09f34b-aee1-5d32-a2f9-23eb7ed48b24", "target": "d8b992b3-ebdc-52a4-9913-9e1aea9a47f8", "relation": "builds_knowledge_engine", "weight": null, "all_weights": {}, "relationship_type": null, "edge_info": {"relationship_name": "builds_knowledge_engine", "source_node_id": "2d09f34b-aee1-5d32-a2f9-23eb7ed48b24", "target_node_id": "d8b992b3-ebdc-52a4-9913-9e1aea9a47f8", "ontology_valid": false}}, {"source": "968213f1-6ddc-5155-89d4-6df7c144a4a1", "target": "5f6d6fc0-e6aa-5365-a4a0-98d6fa3af190", "relation": "is_a", "weight": null, "all_weights": {}, "relationship_type": null, "edge_info": {"source_node_id": "968213f1-6ddc-5155-89d4-6df7c144a4a1", "target_node_id": "5f6d6fc0-e6aa-5365-a4a0-98d6fa3af190", "relationship_name": "is_a", "updated_at": "2026-03-20 23:21:04"}}, {"source": "d8b992b3-ebdc-52a4-9913-9e1aea9a47f8", "target": "dd9713b7-dc20-5101-aad0-1c4216811147", "relation": "is_a", "weight": null, "all_weights": {}, "relationship_type": null, "edge_info": {"source_node_id": "d8b992b3-ebdc-52a4-9913-9e1aea9a47f8", "target_node_id": "dd9713b7-dc20-5101-aad0-1c4216811147", "relationship_name": "is_a", "updated_at": "2026-03-20 23:21:04"}}, {"source": "d8b992b3-ebdc-52a4-9913-9e1aea9a47f8", "target": "0a6f4624-d50e-5989-ba18-ddab839f5554", "relation": "transforms_raw_data", "weight": null, "all_weights": {}, "relationship_type": null, "edge_info": {"relationship_name": "transforms_raw_data", "source_node_id": "d8b992b3-ebdc-52a4-9913-9e1aea9a47f8", "target_node_id": "0a6f4624-d50e-5989-ba18-ddab839f5554", "ontology_valid": false}}, {"source": "d8b992b3-ebdc-52a4-9913-9e1aea9a47f8", "target": "dce5dd84-ed4d-5666-8908-c4c523b804c8", "relation": "creates_memory", "weight": null, "all_weights": {}, "relationship_type": null, "edge_info": {"relationship_name": "creates_memory", "source_node_id": "d8b992b3-ebdc-52a4-9913-9e1aea9a47f8", "target_node_id": "dce5dd84-ed4d-5666-8908-c4c523b804c8", "ontology_valid": false}}, {"source": "0a6f4624-d50e-5989-ba18-ddab839f5554", "target": "4ed5a0c7-2efb-52d1-9734-06a8ba225c94", "relation": "is_a", "weight": null, "all_weights": {}, "relationship_type": null, "edge_info": {"source_node_id": "0a6f4624-d50e-5989-ba18-ddab839f5554", "target_node_id": "4ed5a0c7-2efb-52d1-9734-06a8ba225c94", "relationship_name": "is_a", "updated_at": "2026-03-20 23:21:04"}}, {"source": "0a6f4624-d50e-5989-ba18-ddab839f5554", "target": "f89d185b-5df9-5fc6-84a7-35931b380405", "relation": "includes", "weight": null, "all_weights": {}, "relationship_type": null, "edge_info": {"relationship_name": "includes", "source_node_id": "0a6f4624-d50e-5989-ba18-ddab839f5554", "target_node_id": "f89d185b-5df9-5fc6-84a7-35931b380405", "ontology_valid": false}}, {"source": "0a6f4624-d50e-5989-ba18-ddab839f5554", "target": "9d84ec4f-0968-52d0-bd6d-2a4c1b07490d", "relation": "includes", "weight": null, "all_weights": {}, "relationship_type": null, "edge_info": {"relationship_name": "includes", "source_node_id": "0a6f4624-d50e-5989-ba18-ddab839f5554", "target_node_id": "9d84ec4f-0968-52d0-bd6d-2a4c1b07490d", "ontology_valid": false}}, {"source": "f89d185b-5df9-5fc6-84a7-35931b380405", "target": "4ed5a0c7-2efb-52d1-9734-06a8ba225c94", "relation": "is_a", "weight": null, "all_weights": {}, "relationship_type": null, "edge_info": {"source_node_id": "f89d185b-5df9-5fc6-84a7-35931b380405", "target_node_id": "4ed5a0c7-2efb-52d1-9734-06a8ba225c94", "relationship_name": "is_a", "updated_at": "2026-03-20 23:21:04"}}, {"source": "9d84ec4f-0968-52d0-bd6d-2a4c1b07490d", "target": "4ed5a0c7-2efb-52d1-9734-06a8ba225c94", "relation": "is_a", "weight": null, "all_weights": {}, "relationship_type": null, "edge_info": {"source_node_id": "9d84ec4f-0968-52d0-bd6d-2a4c1b07490d", "target_node_id": "4ed5a0c7-2efb-52d1-9734-06a8ba225c94", "relationship_name": "is_a", "updated_at": "2026-03-20 23:21:04"}}, {"source": "dce5dd84-ed4d-5666-8908-c4c523b804c8", "target": "dd9713b7-dc20-5101-aad0-1c4216811147", "relation": "is_a", "weight": null, "all_weights": {}, "relationship_type": null, "edge_info": {"source_node_id": "dce5dd84-ed4d-5666-8908-c4c523b804c8", "target_node_id": "dd9713b7-dc20-5101-aad0-1c4216811147", "relationship_name": "is_a", "updated_at": "2026-03-20 23:21:04"}}, {"source": "c569abe9-16f1-54e0-ab9c-a4223e1088e1", "target": "f7d8be13-2a72-5104-bd02-7a5964737a91", "relation": "contains", "weight": null, "all_weights": {}, "relationship_type": "contains", "edge_info": {"source_node_id": "c569abe9-16f1-54e0-ab9c-a4223e1088e1", "target_node_id": "f7d8be13-2a72-5104-bd02-7a5964737a91", "relationship_name": "contains", "updated_at": "2026-03-20 23:21:03", "relationship_type": "contains", "edge_text": "relationship_name: contains; entity_name: alice; entity_description: Backend lead on Acme Corp's engineering team."}}, {"source": "c569abe9-16f1-54e0-ab9c-a4223e1088e1", "target": "515e93c6-3782-59db-96be-ad5b8cf872a5", "relation": "contains", "weight": null, "all_weights": {}, "relationship_type": "contains", "edge_info": {"source_node_id": "c569abe9-16f1-54e0-ab9c-a4223e1088e1", "target_node_id": "515e93c6-3782-59db-96be-ad5b8cf872a5", "relationship_name": "contains", "updated_at": "2026-03-20 23:21:03", "relationship_type": "contains", "edge_text": "relationship_name: contains; entity_name: bob; entity_description: ML engineer on Acme Corp's engineering team."}}, {"source": "c569abe9-16f1-54e0-ab9c-a4223e1088e1", "target": "80370ebb-d9b5-5f12-a3fb-db3631157840", "relation": "contains", "weight": null, "all_weights": {}, "relationship_type": "contains", "edge_info": {"source_node_id": "c569abe9-16f1-54e0-ab9c-a4223e1088e1", "target_node_id": "80370ebb-d9b5-5f12-a3fb-db3631157840", "relationship_name": "contains", "updated_at": "2026-03-20 23:21:03", "relationship_type": "contains", "edge_text": "relationship_name: contains; entity_name: carol; entity_description: Infrastructure engineer on Acme Corp's engineering team."}}, {"source": "c569abe9-16f1-54e0-ab9c-a4223e1088e1", "target": "7f5a651e-56c1-574f-aa54-cd0a0b7dbc38", "relation": "contains", "weight": null, "all_weights": {}, "relationship_type": "contains", "edge_info": {"source_node_id": "c569abe9-16f1-54e0-ab9c-a4223e1088e1", "target_node_id": "7f5a651e-56c1-574f-aa54-cd0a0b7dbc38", "relationship_name": "contains", "updated_at": "2026-03-20 23:21:03", "relationship_type": "contains", "edge_text": "relationship_name: contains; entity_name: acme corp; entity_description: Company employing the engineering team."}}, {"source": "c569abe9-16f1-54e0-ab9c-a4223e1088e1", "target": "7fa8891b-a426-5d42-b011-6851ef945793", "relation": "contains", "weight": null, "all_weights": {}, "relationship_type": "contains", "edge_info": {"source_node_id": "c569abe9-16f1-54e0-ab9c-a4223e1088e1", "target_node_id": "7fa8891b-a426-5d42-b011-6851ef945793", "relationship_name": "contains", "updated_at": "2026-03-20 23:21:03", "relationship_type": "contains", "edge_text": "relationship_name: contains; entity_name: engineering team at acme corp; entity_description: Engineering team at Acme Corp consisting of Alice, Bob, and Carol."}}, {"source": "c569abe9-16f1-54e0-ab9c-a4223e1088e1", "target": "6fdb37d4-ae27-5a1a-9f7a-03f5036247ca", "relation": "contains", "weight": null, "all_weights": {}, "relationship_type": "contains", "edge_info": {"source_node_id": "c569abe9-16f1-54e0-ab9c-a4223e1088e1", "target_node_id": "6fdb37d4-ae27-5a1a-9f7a-03f5036247ca", "relationship_name": "contains", "updated_at": "2026-03-20 23:21:03", "relationship_type": "contains", "edge_text": "relationship_name: contains; entity_name: next-generation search platform; entity_description: Next-generation search platform being built by the engineering team."}}, {"source": "c569abe9-16f1-54e0-ab9c-a4223e1088e1", "target": "df20c394-b710-5b2c-9256-ce5f5fe36397", "relation": "contains", "weight": null, "all_weights": {}, "relationship_type": "contains", "edge_info": {"source_node_id": "c569abe9-16f1-54e0-ab9c-a4223e1088e1", "target_node_id": "df20c394-b710-5b2c-9256-ce5f5fe36397", "relationship_name": "contains", "updated_at": "2026-03-20 23:21:03", "relationship_type": "contains", "edge_text": "relationship_name: contains; entity_name: knowledge graphs; entity_description: Knowledge graph technologies used to power the search platform."}}, {"source": "c569abe9-16f1-54e0-ab9c-a4223e1088e1", "target": "f7dc5ef7-3d2d-50c7-9edc-475862a15d4b", "relation": "contains", "weight": null, "all_weights": {}, "relationship_type": "contains", "edge_info": {"source_node_id": "c569abe9-16f1-54e0-ab9c-a4223e1088e1", "target_node_id": "f7dc5ef7-3d2d-50c7-9edc-475862a15d4b", "relationship_name": "contains", "updated_at": "2026-03-20 23:21:03", "relationship_type": "contains", "edge_text": "relationship_name: contains; entity_name: llms; entity_description: Large language models used to power the search platform."}}, {"source": "c569abe9-16f1-54e0-ab9c-a4223e1088e1", "target": "7706f53e-49ac-582a-8cf4-59b9c6e64bfb", "relation": "is_part_of", "weight": null, "all_weights": {}, "relationship_type": null, "edge_info": {"source_node_id": "c569abe9-16f1-54e0-ab9c-a4223e1088e1", "target_node_id": "7706f53e-49ac-582a-8cf4-59b9c6e64bfb", "relationship_name": "is_part_of", "updated_at": "2026-03-20 23:21:03"}}, {"source": "f7d8be13-2a72-5104-bd02-7a5964737a91", "target": "d072ba0f-e1a9-58bf-9974-e1802adc8134", "relation": "is_a", "weight": null, "all_weights": {}, "relationship_type": null, "edge_info": {"source_node_id": "f7d8be13-2a72-5104-bd02-7a5964737a91", "target_node_id": "d072ba0f-e1a9-58bf-9974-e1802adc8134", "relationship_name": "is_a", "updated_at": "2026-03-20 23:21:03"}}, {"source": "f7d8be13-2a72-5104-bd02-7a5964737a91", "target": "7fa8891b-a426-5d42-b011-6851ef945793", "relation": "member_of", "weight": null, "all_weights": {}, "relationship_type": null, "edge_info": {"relationship_name": "member_of", "source_node_id": "f7d8be13-2a72-5104-bd02-7a5964737a91", "target_node_id": "7fa8891b-a426-5d42-b011-6851ef945793", "ontology_valid": false}}, {"source": "515e93c6-3782-59db-96be-ad5b8cf872a5", "target": "d072ba0f-e1a9-58bf-9974-e1802adc8134", "relation": "is_a", "weight": null, "all_weights": {}, "relationship_type": null, "edge_info": {"source_node_id": "515e93c6-3782-59db-96be-ad5b8cf872a5", "target_node_id": "d072ba0f-e1a9-58bf-9974-e1802adc8134", "relationship_name": "is_a", "updated_at": "2026-03-20 23:21:03"}}, {"source": "515e93c6-3782-59db-96be-ad5b8cf872a5", "target": "7fa8891b-a426-5d42-b011-6851ef945793", "relation": "member_of", "weight": null, "all_weights": {}, "relationship_type": null, "edge_info": {"relationship_name": "member_of", "source_node_id": "515e93c6-3782-59db-96be-ad5b8cf872a5", "target_node_id": "7fa8891b-a426-5d42-b011-6851ef945793", "ontology_valid": false}}, {"source": "80370ebb-d9b5-5f12-a3fb-db3631157840", "target": "d072ba0f-e1a9-58bf-9974-e1802adc8134", "relation": "is_a", "weight": null, "all_weights": {}, "relationship_type": null, "edge_info": {"source_node_id": "80370ebb-d9b5-5f12-a3fb-db3631157840", "target_node_id": "d072ba0f-e1a9-58bf-9974-e1802adc8134", "relationship_name": "is_a", "updated_at": "2026-03-20 23:21:03"}}, {"source": "80370ebb-d9b5-5f12-a3fb-db3631157840", "target": "7fa8891b-a426-5d42-b011-6851ef945793", "relation": "member_of", "weight": null, "all_weights": {}, "relationship_type": null, "edge_info": {"relationship_name": "member_of", "source_node_id": "80370ebb-d9b5-5f12-a3fb-db3631157840", "target_node_id": "7fa8891b-a426-5d42-b011-6851ef945793", "ontology_valid": false}}, {"source": "7f5a651e-56c1-574f-aa54-cd0a0b7dbc38", "target": "d3d7b6b4-9b0d-52e8-9e09-a9e9cf4b5a4d", "relation": "is_a", "weight": null, "all_weights": {}, "relationship_type": null, "edge_info": {"source_node_id": "7f5a651e-56c1-574f-aa54-cd0a0b7dbc38", "target_node_id": "d3d7b6b4-9b0d-52e8-9e09-a9e9cf4b5a4d", "relationship_name": "is_a", "updated_at": "2026-03-20 23:21:03"}}, {"source": "7fa8891b-a426-5d42-b011-6851ef945793", "target": "e308d782-2a18-5ace-b0e8-236c7c3b4db4", "relation": "is_a", "weight": null, "all_weights": {}, "relationship_type": null, "edge_info": {"source_node_id": "7fa8891b-a426-5d42-b011-6851ef945793", "target_node_id": "e308d782-2a18-5ace-b0e8-236c7c3b4db4", "relationship_name": "is_a", "updated_at": "2026-03-20 23:21:03"}}, {"source": "7fa8891b-a426-5d42-b011-6851ef945793", "target": "7f5a651e-56c1-574f-aa54-cd0a0b7dbc38", "relation": "part_of", "weight": null, "all_weights": {}, "relationship_type": null, "edge_info": {"relationship_name": "part_of", "source_node_id": "7fa8891b-a426-5d42-b011-6851ef945793", "target_node_id": "7f5a651e-56c1-574f-aa54-cd0a0b7dbc38", "ontology_valid": false}}, {"source": "7fa8891b-a426-5d42-b011-6851ef945793", "target": "6fdb37d4-ae27-5a1a-9f7a-03f5036247ca", "relation": "building", "weight": null, "all_weights": {}, "relationship_type": null, "edge_info": {"relationship_name": "building", "source_node_id": "7fa8891b-a426-5d42-b011-6851ef945793", "target_node_id": "6fdb37d4-ae27-5a1a-9f7a-03f5036247ca", "ontology_valid": false}}, {"source": "6fdb37d4-ae27-5a1a-9f7a-03f5036247ca", "target": "29c0d211-0d39-579f-bf45-c7a78394c9aa", "relation": "is_a", "weight": null, "all_weights": {}, "relationship_type": null, "edge_info": {"source_node_id": "6fdb37d4-ae27-5a1a-9f7a-03f5036247ca", "target_node_id": "29c0d211-0d39-579f-bf45-c7a78394c9aa", "relationship_name": "is_a", "updated_at": "2026-03-20 23:21:03"}}, {"source": "6fdb37d4-ae27-5a1a-9f7a-03f5036247ca", "target": "df20c394-b710-5b2c-9256-ce5f5fe36397", "relation": "powered_by", "weight": null, "all_weights": {}, "relationship_type": null, "edge_info": {"relationship_name": "powered_by", "source_node_id": "6fdb37d4-ae27-5a1a-9f7a-03f5036247ca", "target_node_id": "df20c394-b710-5b2c-9256-ce5f5fe36397", "ontology_valid": false}}, {"source": "6fdb37d4-ae27-5a1a-9f7a-03f5036247ca", "target": "f7dc5ef7-3d2d-50c7-9edc-475862a15d4b", "relation": "powered_by", "weight": null, "all_weights": {}, "relationship_type": null, "edge_info": {"relationship_name": "powered_by", "source_node_id": "6fdb37d4-ae27-5a1a-9f7a-03f5036247ca", "target_node_id": "f7dc5ef7-3d2d-50c7-9edc-475862a15d4b", "ontology_valid": false}}, {"source": "f7dc5ef7-3d2d-50c7-9edc-475862a15d4b", "target": "65c71de3-4c23-5f28-8e07-fc7428d1e0c4", "relation": "is_a", "weight": null, "all_weights": {}, "relationship_type": null, "edge_info": {"source_node_id": "f7dc5ef7-3d2d-50c7-9edc-475862a15d4b", "target_node_id": "65c71de3-4c23-5f28-8e07-fc7428d1e0c4", "relationship_name": "is_a", "updated_at": "2026-03-20 23:21:03"}}, {"source": "ee7307f2-cba9-5003-9dc0-0780c50591a6", "target": "2bdd3deb-07d8-5413-a56d-1643e3ceb48b", "relation": "contains", "weight": null, "all_weights": {}, "relationship_type": "contains", "edge_info": {"source_node_id": "ee7307f2-cba9-5003-9dc0-0780c50591a6", "target_node_id": "2bdd3deb-07d8-5413-a56d-1643e3ceb48b", "relationship_name": "contains", "updated_at": "2026-03-20 23:21:04", "relationship_type": "contains", "edge_text": "relationship_name: contains; entity_name: haystack; entity_description: Open-source LLM framework by deepset for building production-ready RAG pipelines, agents, and search systems."}}, {"source": "ee7307f2-cba9-5003-9dc0-0780c50591a6", "target": "126df7ec-d0db-53ea-bc88-1bafd84c8646", "relation": "contains", "weight": null, "all_weights": {}, "relationship_type": "contains", "edge_info": {"source_node_id": "ee7307f2-cba9-5003-9dc0-0780c50591a6", "target_node_id": "126df7ec-d0db-53ea-bc88-1bafd84c8646", "relationship_name": "contains", "updated_at": "2026-03-20 23:21:04", "relationship_type": "contains", "edge_text": "relationship_name: contains; entity_name: deepset; entity_description: Company that develops Haystack."}}, {"source": "ee7307f2-cba9-5003-9dc0-0780c50591a6", "target": "7594343c-5532-5896-b0aa-be5c1a74bd92", "relation": "contains", "weight": null, "all_weights": {}, "relationship_type": "contains", "edge_info": {"source_node_id": "ee7307f2-cba9-5003-9dc0-0780c50591a6", "target_node_id": "7594343c-5532-5896-b0aa-be5c1a74bd92", "relationship_name": "contains", "updated_at": "2026-03-20 23:21:04", "relationship_type": "contains", "edge_text": "relationship_name: contains; entity_name: rag pipelines; entity_description: Retrieval-Augmented Generation pipelines combining retrieval with LLM generation."}}, {"source": "ee7307f2-cba9-5003-9dc0-0780c50591a6", "target": "ba1f1dac-e2fb-5464-914d-ff54b9b19787", "relation": "contains", "weight": null, "all_weights": {}, "relationship_type": "contains", "edge_info": {"source_node_id": "ee7307f2-cba9-5003-9dc0-0780c50591a6", "target_node_id": "ba1f1dac-e2fb-5464-914d-ff54b9b19787", "relationship_name": "contains", "updated_at": "2026-03-20 23:21:04", "relationship_type": "contains", "edge_text": "relationship_name: contains; entity_name: agents; entity_description: Agent systems that orchestrate actions and LLM calls."}}, {"source": "ee7307f2-cba9-5003-9dc0-0780c50591a6", "target": "a1a666e4-2070-59fd-95f7-c4c6178e89ba", "relation": "contains", "weight": null, "all_weights": {}, "relationship_type": "contains", "edge_info": {"source_node_id": "ee7307f2-cba9-5003-9dc0-0780c50591a6", "target_node_id": "a1a666e4-2070-59fd-95f7-c4c6178e89ba", "relationship_name": "contains", "updated_at": "2026-03-20 23:21:04", "relationship_type": "contains", "edge_text": "relationship_name: contains; entity_name: search systems; entity_description: Systems for information retrieval and search."}}, {"source": "ee7307f2-cba9-5003-9dc0-0780c50591a6", "target": "30f5dcb9-d238-5c7d-8d2a-b9da0b854f98", "relation": "contains", "weight": null, "all_weights": {}, "relationship_type": "contains", "edge_info": {"source_node_id": "ee7307f2-cba9-5003-9dc0-0780c50591a6", "target_node_id": "30f5dcb9-d238-5c7d-8d2a-b9da0b854f98", "relationship_name": "contains", "updated_at": "2026-03-20 23:21:04", "relationship_type": "contains", "edge_text": "relationship_name: contains; entity_name: component-based architecture; entity_description: Architecture composed of modular components where each step is a building block."}}, {"source": "ee7307f2-cba9-5003-9dc0-0780c50591a6", "target": "f010bf52-6eb5-511f-bbed-cd5237545edd", "relation": "contains", "weight": null, "all_weights": {}, "relationship_type": "contains", "edge_info": {"source_node_id": "ee7307f2-cba9-5003-9dc0-0780c50591a6", "target_node_id": "f010bf52-6eb5-511f-bbed-cd5237545edd", "relationship_name": "contains", "updated_at": "2026-03-20 23:21:04", "relationship_type": "contains", "edge_text": "relationship_name: contains; entity_name: retrieval; entity_description: A retrieval step/component in the pipeline."}}, {"source": "ee7307f2-cba9-5003-9dc0-0780c50591a6", "target": "dba0457b-9aff-5eb6-8ccd-19f7c9ae4dfa", "relation": "contains", "weight": null, "all_weights": {}, "relationship_type": "contains", "edge_info": {"source_node_id": "ee7307f2-cba9-5003-9dc0-0780c50591a6", "target_node_id": "dba0457b-9aff-5eb6-8ccd-19f7c9ae4dfa", "relationship_name": "contains", "updated_at": "2026-03-20 23:21:04", "relationship_type": "contains", "edge_text": "relationship_name: contains; entity_name: generation; entity_description: A generation (LLM) step/component in the pipeline."}}, {"source": "ee7307f2-cba9-5003-9dc0-0780c50591a6", "target": "59cf88c0-cb09-5f96-9252-5f5810981bcc", "relation": "contains", "weight": null, "all_weights": {}, "relationship_type": "contains", "edge_info": {"source_node_id": "ee7307f2-cba9-5003-9dc0-0780c50591a6", "target_node_id": "59cf88c0-cb09-5f96-9252-5f5810981bcc", "relationship_name": "contains", "updated_at": "2026-03-20 23:21:04", "relationship_type": "contains", "edge_text": "relationship_name: contains; entity_name: composable building block; entity_description: A modular, composable building block representing an individual step in the architecture."}}, {"source": "ee7307f2-cba9-5003-9dc0-0780c50591a6", "target": "1a7434a3-3266-5111-9501-4fe093f36076", "relation": "is_part_of", "weight": null, "all_weights": {}, "relationship_type": null, "edge_info": {"source_node_id": "ee7307f2-cba9-5003-9dc0-0780c50591a6", "target_node_id": "1a7434a3-3266-5111-9501-4fe093f36076", "relationship_name": "is_part_of", "updated_at": "2026-03-20 23:21:04"}}, {"source": "2bdd3deb-07d8-5413-a56d-1643e3ceb48b", "target": "2d66edc2-1e14-55ab-8304-680b514a597a", "relation": "is_a", "weight": null, "all_weights": {}, "relationship_type": null, "edge_info": {"source_node_id": "2bdd3deb-07d8-5413-a56d-1643e3ceb48b", "target_node_id": "2d66edc2-1e14-55ab-8304-680b514a597a", "relationship_name": "is_a", "updated_at": "2026-03-20 23:21:04"}}, {"source": "2bdd3deb-07d8-5413-a56d-1643e3ceb48b", "target": "126df7ec-d0db-53ea-bc88-1bafd84c8646", "relation": "developed_by", "weight": null, "all_weights": {}, "relationship_type": null, "edge_info": {"relationship_name": "developed_by", "source_node_id": "2bdd3deb-07d8-5413-a56d-1643e3ceb48b", "target_node_id": "126df7ec-d0db-53ea-bc88-1bafd84c8646", "ontology_valid": false}}, {"source": "2bdd3deb-07d8-5413-a56d-1643e3ceb48b", "target": "7594343c-5532-5896-b0aa-be5c1a74bd92", "relation": "used_to_build", "weight": null, "all_weights": {}, "relationship_type": null, "edge_info": {"relationship_name": "used_to_build", "source_node_id": "2bdd3deb-07d8-5413-a56d-1643e3ceb48b", "target_node_id": "7594343c-5532-5896-b0aa-be5c1a74bd92", "ontology_valid": false}}, {"source": "2bdd3deb-07d8-5413-a56d-1643e3ceb48b", "target": "ba1f1dac-e2fb-5464-914d-ff54b9b19787", "relation": "used_to_build", "weight": null, "all_weights": {}, "relationship_type": null, "edge_info": {"relationship_name": "used_to_build", "source_node_id": "2bdd3deb-07d8-5413-a56d-1643e3ceb48b", "target_node_id": "ba1f1dac-e2fb-5464-914d-ff54b9b19787", "ontology_valid": false}}, {"source": "2bdd3deb-07d8-5413-a56d-1643e3ceb48b", "target": "a1a666e4-2070-59fd-95f7-c4c6178e89ba", "relation": "used_to_build", "weight": null, "all_weights": {}, "relationship_type": null, "edge_info": {"relationship_name": "used_to_build", "source_node_id": "2bdd3deb-07d8-5413-a56d-1643e3ceb48b", "target_node_id": "a1a666e4-2070-59fd-95f7-c4c6178e89ba", "ontology_valid": false}}, {"source": "2bdd3deb-07d8-5413-a56d-1643e3ceb48b", "target": "30f5dcb9-d238-5c7d-8d2a-b9da0b854f98", "relation": "uses_architecture", "weight": null, "all_weights": {}, "relationship_type": null, "edge_info": {"relationship_name": "uses_architecture", "source_node_id": "2bdd3deb-07d8-5413-a56d-1643e3ceb48b", "target_node_id": "30f5dcb9-d238-5c7d-8d2a-b9da0b854f98", "ontology_valid": false}}, {"source": "126df7ec-d0db-53ea-bc88-1bafd84c8646", "target": "d3d7b6b4-9b0d-52e8-9e09-a9e9cf4b5a4d", "relation": "is_a", "weight": null, "all_weights": {}, "relationship_type": null, "edge_info": {"source_node_id": "126df7ec-d0db-53ea-bc88-1bafd84c8646", "target_node_id": "d3d7b6b4-9b0d-52e8-9e09-a9e9cf4b5a4d", "relationship_name": "is_a", "updated_at": "2026-03-20 23:21:04"}}, {"source": "7594343c-5532-5896-b0aa-be5c1a74bd92", "target": "dd9713b7-dc20-5101-aad0-1c4216811147", "relation": "is_a", "weight": null, "all_weights": {}, "relationship_type": null, "edge_info": {"source_node_id": "7594343c-5532-5896-b0aa-be5c1a74bd92", "target_node_id": "dd9713b7-dc20-5101-aad0-1c4216811147", "relationship_name": "is_a", "updated_at": "2026-03-20 23:21:04"}}, {"source": "ba1f1dac-e2fb-5464-914d-ff54b9b19787", "target": "dd9713b7-dc20-5101-aad0-1c4216811147", "relation": "is_a", "weight": null, "all_weights": {}, "relationship_type": null, "edge_info": {"source_node_id": "ba1f1dac-e2fb-5464-914d-ff54b9b19787", "target_node_id": "dd9713b7-dc20-5101-aad0-1c4216811147", "relationship_name": "is_a", "updated_at": "2026-03-20 23:21:04"}}, {"source": "a1a666e4-2070-59fd-95f7-c4c6178e89ba", "target": "dd9713b7-dc20-5101-aad0-1c4216811147", "relation": "is_a", "weight": null, "all_weights": {}, "relationship_type": null, "edge_info": {"source_node_id": "a1a666e4-2070-59fd-95f7-c4c6178e89ba", "target_node_id": "dd9713b7-dc20-5101-aad0-1c4216811147", "relationship_name": "is_a", "updated_at": "2026-03-20 23:21:04"}}, {"source": "30f5dcb9-d238-5c7d-8d2a-b9da0b854f98", "target": "dd9713b7-dc20-5101-aad0-1c4216811147", "relation": "is_a", "weight": null, "all_weights": {}, "relationship_type": null, "edge_info": {"source_node_id": "30f5dcb9-d238-5c7d-8d2a-b9da0b854f98", "target_node_id": "dd9713b7-dc20-5101-aad0-1c4216811147", "relationship_name": "is_a", "updated_at": "2026-03-20 23:21:04"}}, {"source": "30f5dcb9-d238-5c7d-8d2a-b9da0b854f98", "target": "f010bf52-6eb5-511f-bbed-cd5237545edd", "relation": "includes_component", "weight": null, "all_weights": {}, "relationship_type": null, "edge_info": {"relationship_name": "includes_component", "source_node_id": "30f5dcb9-d238-5c7d-8d2a-b9da0b854f98", "target_node_id": "f010bf52-6eb5-511f-bbed-cd5237545edd", "ontology_valid": false}}, {"source": "30f5dcb9-d238-5c7d-8d2a-b9da0b854f98", "target": "dba0457b-9aff-5eb6-8ccd-19f7c9ae4dfa", "relation": "includes_component", "weight": null, "all_weights": {}, "relationship_type": null, "edge_info": {"relationship_name": "includes_component", "source_node_id": "30f5dcb9-d238-5c7d-8d2a-b9da0b854f98", "target_node_id": "dba0457b-9aff-5eb6-8ccd-19f7c9ae4dfa", "ontology_valid": false}}, {"source": "f010bf52-6eb5-511f-bbed-cd5237545edd", "target": "b283358b-c288-5ca1-a6e8-05bac88f7a6f", "relation": "is_a", "weight": null, "all_weights": {}, "relationship_type": null, "edge_info": {"source_node_id": "f010bf52-6eb5-511f-bbed-cd5237545edd", "target_node_id": "b283358b-c288-5ca1-a6e8-05bac88f7a6f", "relationship_name": "is_a", "updated_at": "2026-03-20 23:21:04"}}, {"source": "f010bf52-6eb5-511f-bbed-cd5237545edd", "target": "59cf88c0-cb09-5f96-9252-5f5810981bcc", "relation": "is_composable_building_block", "weight": null, "all_weights": {}, "relationship_type": null, "edge_info": {"relationship_name": "is_composable_building_block", "source_node_id": "f010bf52-6eb5-511f-bbed-cd5237545edd", "target_node_id": "59cf88c0-cb09-5f96-9252-5f5810981bcc", "ontology_valid": false}}, {"source": "dba0457b-9aff-5eb6-8ccd-19f7c9ae4dfa", "target": "b283358b-c288-5ca1-a6e8-05bac88f7a6f", "relation": "is_a", "weight": null, "all_weights": {}, "relationship_type": null, "edge_info": {"source_node_id": "dba0457b-9aff-5eb6-8ccd-19f7c9ae4dfa", "target_node_id": "b283358b-c288-5ca1-a6e8-05bac88f7a6f", "relationship_name": "is_a", "updated_at": "2026-03-20 23:21:04"}}, {"source": "dba0457b-9aff-5eb6-8ccd-19f7c9ae4dfa", "target": "59cf88c0-cb09-5f96-9252-5f5810981bcc", "relation": "is_composable_building_block", "weight": null, "all_weights": {}, "relationship_type": null, "edge_info": {"relationship_name": "is_composable_building_block", "source_node_id": "dba0457b-9aff-5eb6-8ccd-19f7c9ae4dfa", "target_node_id": "59cf88c0-cb09-5f96-9252-5f5810981bcc", "ontology_valid": false}}, {"source": "59cf88c0-cb09-5f96-9252-5f5810981bcc", "target": "dd9713b7-dc20-5101-aad0-1c4216811147", "relation": "is_a", "weight": null, "all_weights": {}, "relationship_type": null, "edge_info": {"source_node_id": "59cf88c0-cb09-5f96-9252-5f5810981bcc", "target_node_id": "dd9713b7-dc20-5101-aad0-1c4216811147", "relationship_name": "is_a", "updated_at": "2026-03-20 23:21:04"}}, {"source": "8a75198a-6b32-5a14-926f-ae42589088af", "target": "601f27c0-4582-5a13-89d3-64a8c0f15cc1", "relation": "made_from", "weight": null, "all_weights": {}, "relationship_type": null, "edge_info": {"source_node_id": "8a75198a-6b32-5a14-926f-ae42589088af", "target_node_id": "601f27c0-4582-5a13-89d3-64a8c0f15cc1", "relationship_name": "made_from", "updated_at": "2026-03-20 23:21:01"}}, {"source": "349bab63-8b60-5d59-a1f2-a4413b6377f2", "target": "c569abe9-16f1-54e0-ab9c-a4223e1088e1", "relation": "made_from", "weight": null, "all_weights": {}, "relationship_type": null, "edge_info": {"source_node_id": "349bab63-8b60-5d59-a1f2-a4413b6377f2", "target_node_id": "c569abe9-16f1-54e0-ab9c-a4223e1088e1", "relationship_name": "made_from", "updated_at": "2026-03-20 23:21:03"}}, {"source": "16c06ddd-c7f6-5d74-9ed4-a4520ffde7ca", "target": "bc815248-f743-5faa-b176-a216cf9e908e", "relation": "made_from", "weight": null, "all_weights": {}, "relationship_type": null, "edge_info": {"source_node_id": "16c06ddd-c7f6-5d74-9ed4-a4520ffde7ca", "target_node_id": "bc815248-f743-5faa-b176-a216cf9e908e", "relationship_name": "made_from", "updated_at": "2026-03-20 23:21:04"}}, {"source": "208e9fa9-a281-5f67-8f8f-4b78c917c467", "target": "ee7307f2-cba9-5003-9dc0-0780c50591a6", "relation": "made_from", "weight": null, "all_weights": {}, "relationship_type": null, "edge_info": {"source_node_id": "208e9fa9-a281-5f67-8f8f-4b78c917c467", "target_node_id": "ee7307f2-cba9-5003-9dc0-0780c50591a6", "relationship_name": "made_from", "updated_at": "2026-03-20 23:21:04"}}]; +var nodes = [{"name": "", "type": "TextSummary", "ontology_valid": false, "version": 1, "topological_rank": 0, "metadata": {"index_fields": ["text"]}, "belongs_to_set": null, "source_pipeline": "cognify_pipeline", "source_task": "summarize_text", "source_node_set": null, "source_user": "default_user@example.com", "feedback_weight": 0.5, "text": "Knowledge graphs encode information as nodes (entities) and links (relationships).", "id": "69451bda-0a8c-55cc-a5c6-1f2f3d4a384d", "color": "#6510F4"}, {"name": "", "type": "DocumentChunk", "ontology_valid": false, "version": 1, "topological_rank": 0, "metadata": {"index_fields": ["text"]}, "belongs_to_set": null, "source_pipeline": "cognify_pipeline", "source_task": "extract_chunks_from_documents", "source_node_set": null, "source_user": "default_user@example.com", "feedback_weight": 0.5, "text": "Knowledge graphs represent information as nodes (entities) and edges (relationships). They enable semantic search, reasoning, and discovery of hidden connections across large document collections.", "chunk_size": 56, "chunk_index": 0, "cut_type": "sentence_end", "id": "5a24f9a6-a52e-5239-b6cf-76364cac7ff0", "color": "#0DFF00"}, {"name": "text_41edf18cf1a9cb76a5e2eb8429cb9a29", "type": "TextDocument", "ontology_valid": false, "version": 1, "topological_rank": 0, "metadata": {"index_fields": ["name"]}, "belongs_to_set": null, "source_pipeline": "cognify_pipeline", "source_task": "classify_documents", "source_node_set": null, "source_user": "default_user@example.com", "feedback_weight": 0.5, "raw_data_location": "file:///Users/handekafkas/Documents/local-code/haystack-core-integrations/integrations/cognee/.venv/lib/python3.13/site-packages/cognee/.data_storage/7cea2662-fd6a-49be-a2c6-aeefcb51fc76/text_41edf18cf1a9cb76a5e2eb8429cb9a29.txt", "external_metadata": "{}", "mime_type": "text/plain", "id": "aa2e81bf-0c3e-599f-9de3-0bc8e97c644f", "color": "#DBD8D8"}, {"name": "knowledge graphs", "type": "Entity", "ontology_valid": false, "version": 1, "topological_rank": 0, "metadata": {"index_fields": ["name"]}, "belongs_to_set": null, "source_pipeline": "cognify_pipeline", "source_task": "extract_graph_from_data", "source_node_set": null, "source_user": "default_user@example.com", "feedback_weight": 0.5, "description": "technology used to structure and represent knowledge for the search platform", "relations": [], "id": "df20c394-b710-5b2c-9256-ce5f5fe36397", "color": "#6510F4"}, {"name": "concept", "type": "EntityType", "ontology_valid": false, "version": 1, "topological_rank": 0, "metadata": {"index_fields": ["name"]}, "belongs_to_set": null, "source_pipeline": "cognify_pipeline", "source_task": "extract_graph_from_data", "source_node_set": null, "source_user": "default_user@example.com", "feedback_weight": 0.5, "description": "concept", "relations": [], "id": "dd9713b7-dc20-5101-aad0-1c4216811147", "color": "#A550FF"}, {"name": "nodes (entities)", "type": "Entity", "ontology_valid": false, "version": 1, "topological_rank": 0, "metadata": {"index_fields": ["name"]}, "belongs_to_set": null, "source_pipeline": "cognify_pipeline", "source_task": "extract_graph_from_data", "source_node_set": null, "source_user": "default_user@example.com", "feedback_weight": 0.5, "description": "Graph elements representing real-world entities or concepts", "relations": [], "id": "05be7eb9-fd46-5fc0-aa0b-1e82ac5985d1", "color": "#6510F4"}, {"name": "edges (relationships)", "type": "Entity", "ontology_valid": false, "version": 1, "topological_rank": 0, "metadata": {"index_fields": ["name"]}, "belongs_to_set": null, "source_pipeline": "cognify_pipeline", "source_task": "extract_graph_from_data", "source_node_set": null, "source_user": "default_user@example.com", "feedback_weight": 0.5, "description": "Graph elements representing relationships between nodes", "relations": [], "id": "749d1b20-55d7-5992-a930-b6ab13974f8d", "color": "#6510F4"}, {"name": "semantic search", "type": "Entity", "ontology_valid": false, "version": 1, "topological_rank": 0, "metadata": {"index_fields": ["name"]}, "belongs_to_set": null, "source_pipeline": "cognify_pipeline", "source_task": "extract_graph_from_data", "source_node_set": null, "source_user": "default_user@example.com", "feedback_weight": 0.5, "description": "Search technique that uses meaning and relationships to improve relevance", "relations": [], "id": "9d6360d4-504a-5f7f-b618-c2ea457a1a4d", "color": "#6510F4"}, {"name": "reasoning", "type": "Entity", "ontology_valid": false, "version": 1, "topological_rank": 0, "metadata": {"index_fields": ["name"]}, "belongs_to_set": null, "source_pipeline": "cognify_pipeline", "source_task": "extract_graph_from_data", "source_node_set": null, "source_user": "default_user@example.com", "feedback_weight": 0.5, "description": "Inference processes that derive new knowledge from existing facts and relations", "relations": [], "id": "ba802be9-50b2-58a6-a46d-031e30a780a8", "color": "#6510F4"}, {"name": "discovery of hidden connections", "type": "Entity", "ontology_valid": false, "version": 1, "topological_rank": 0, "metadata": {"index_fields": ["name"]}, "belongs_to_set": null, "source_pipeline": "cognify_pipeline", "source_task": "extract_graph_from_data", "source_node_set": null, "source_user": "default_user@example.com", "feedback_weight": 0.5, "description": "Finding non-obvious relationships across data that reveal new insights", "id": "e0c5c99c-74a8-5d09-8e8a-05cb2e5bcf6b", "color": "#6510F4"}, {"name": "large document collections", "type": "Entity", "ontology_valid": false, "version": 1, "topological_rank": 0, "metadata": {"index_fields": ["name"]}, "belongs_to_set": null, "source_pipeline": "cognify_pipeline", "source_task": "extract_graph_from_data", "source_node_set": null, "source_user": "default_user@example.com", "feedback_weight": 0.5, "description": "Extensive corpora of documents across which knowledge graphs can reveal connections", "relations": [], "id": "838f4a46-e459-58e4-a40b-ab30cd21da5c", "color": "#6510F4"}, {"name": "", "type": "TextSummary", "ontology_valid": false, "version": 1, "topological_rank": 0, "metadata": {"index_fields": ["text"]}, "belongs_to_set": null, "source_pipeline": "cognify_pipeline", "source_task": "summarize_text", "source_node_set": null, "source_user": "default_user@example.com", "feedback_weight": 0.5, "text": "Acme Corp\u2019s engineering trio\u2014Alice (backend lead), Bob (ML engineer), and Carol (infrastructure)\u2014is building a next\u2011generation search platform using knowledge graphs and large language models.", "id": "5920fa1a-48b2-503a-858a-df9cb18e710d", "color": "#6510F4"}, {"name": "", "type": "DocumentChunk", "ontology_valid": false, "version": 1, "topological_rank": 0, "metadata": {"index_fields": ["text"]}, "belongs_to_set": null, "source_pipeline": "cognify_pipeline", "source_task": "extract_chunks_from_documents", "source_node_set": null, "source_user": "default_user@example.com", "feedback_weight": 0.5, "text": "The engineering team at Acme Corp consists of Alice (backend lead), Bob (ML engineer), and Carol (infrastructure). They are building a next-generation search platform powered by knowledge graphs and LLMs.", "chunk_size": 72, "chunk_index": 0, "cut_type": "sentence_end", "id": "d44e16f2-55c2-5bb6-a1c1-cfd39ad2b1b1", "color": "#0DFF00"}, {"name": "text_fe5096366b6f10a6766dc51cbac9058c", "type": "TextDocument", "ontology_valid": false, "version": 1, "topological_rank": 0, "metadata": {"index_fields": ["name"]}, "belongs_to_set": null, "source_pipeline": "cognify_pipeline", "source_task": "classify_documents", "source_node_set": null, "source_user": "default_user@example.com", "feedback_weight": 0.5, "raw_data_location": "file:///Users/handekafkas/Documents/local-code/haystack-core-integrations/integrations/cognee/.venv/lib/python3.13/site-packages/cognee/.data_storage/7cea2662-fd6a-49be-a2c6-aeefcb51fc76/text_fe5096366b6f10a6766dc51cbac9058c.txt", "external_metadata": "{}", "mime_type": "text/plain", "id": "6834c0c9-68ce-56f7-8829-86bc13026ca2", "color": "#DBD8D8"}, {"name": "alice", "type": "Entity", "ontology_valid": false, "version": 1, "topological_rank": 0, "metadata": {"index_fields": ["name"]}, "belongs_to_set": null, "source_pipeline": "cognify_pipeline", "source_task": "extract_graph_from_data", "source_node_set": null, "source_user": "default_user@example.com", "feedback_weight": 0.5, "description": "backend lead on the engineering team at Acme Corp", "id": "f7d8be13-2a72-5104-bd02-7a5964737a91", "color": "#6510F4"}, {"name": "person", "type": "EntityType", "ontology_valid": false, "version": 1, "topological_rank": 0, "metadata": {"index_fields": ["name"]}, "belongs_to_set": null, "source_pipeline": "cognify_pipeline", "source_task": "extract_graph_from_data", "source_node_set": null, "source_user": "default_user@example.com", "feedback_weight": 0.5, "description": "person", "relations": [], "id": "d072ba0f-e1a9-58bf-9974-e1802adc8134", "color": "#A550FF"}, {"name": "backend lead", "type": "Entity", "ontology_valid": false, "version": 1, "topological_rank": 0, "metadata": {"index_fields": ["name"]}, "belongs_to_set": null, "source_pipeline": "cognify_pipeline", "source_task": "extract_graph_from_data", "source_node_set": null, "source_user": "default_user@example.com", "feedback_weight": 0.5, "description": "role focused on backend architecture and implementation", "relations": [], "id": "4d00d1ec-e3a5-5b42-b970-1926ddca1a75", "color": "#6510F4"}, {"name": "role", "type": "EntityType", "ontology_valid": false, "version": 1, "topological_rank": 0, "metadata": {"index_fields": ["name"]}, "belongs_to_set": null, "source_pipeline": "cognify_pipeline", "source_task": "extract_graph_from_data", "source_node_set": null, "source_user": "default_user@example.com", "feedback_weight": 0.5, "description": "role", "relations": [], "id": "09451c3f-999a-5c73-94d3-0d9dd38a58b1", "color": "#A550FF"}, {"name": "engineering team", "type": "Entity", "ontology_valid": false, "version": 1, "topological_rank": 0, "metadata": {"index_fields": ["name"]}, "belongs_to_set": null, "source_pipeline": "cognify_pipeline", "source_task": "extract_graph_from_data", "source_node_set": null, "source_user": "default_user@example.com", "feedback_weight": 0.5, "description": "engineering team at Acme Corp consisting of Alice, Bob, and Carol", "id": "346f1ce4-0869-56a1-891a-a99af46c348a", "color": "#6510F4"}, {"name": "team", "type": "EntityType", "ontology_valid": false, "version": 1, "topological_rank": 0, "metadata": {"index_fields": ["name"]}, "belongs_to_set": null, "source_pipeline": "cognify_pipeline", "source_task": "extract_graph_from_data", "source_node_set": null, "source_user": "default_user@example.com", "feedback_weight": 0.5, "description": "team", "relations": [], "id": "e308d782-2a18-5ace-b0e8-236c7c3b4db4", "color": "#A550FF"}, {"name": "acme corp", "type": "Entity", "ontology_valid": false, "version": 1, "topological_rank": 0, "metadata": {"index_fields": ["name"]}, "belongs_to_set": null, "source_pipeline": "cognify_pipeline", "source_task": "extract_graph_from_data", "source_node_set": null, "source_user": "default_user@example.com", "feedback_weight": 0.5, "description": "organization employing the engineering team", "relations": [], "id": "7f5a651e-56c1-574f-aa54-cd0a0b7dbc38", "color": "#6510F4"}, {"name": "organization", "type": "EntityType", "ontology_valid": false, "version": 1, "topological_rank": 0, "metadata": {"index_fields": ["name"]}, "belongs_to_set": null, "source_pipeline": "cognify_pipeline", "source_task": "extract_graph_from_data", "source_node_set": null, "source_user": "default_user@example.com", "feedback_weight": 0.5, "description": "organization", "relations": [], "id": "d3d7b6b4-9b0d-52e8-9e09-a9e9cf4b5a4d", "color": "#A550FF"}, {"name": "next-generation search platform", "type": "Entity", "ontology_valid": false, "version": 1, "topological_rank": 0, "metadata": {"index_fields": ["name"]}, "belongs_to_set": null, "source_pipeline": "cognify_pipeline", "source_task": "extract_graph_from_data", "source_node_set": null, "source_user": "default_user@example.com", "feedback_weight": 0.5, "description": "search platform being built by the engineering team, powered by knowledge graphs and LLMs", "id": "6fdb37d4-ae27-5a1a-9f7a-03f5036247ca", "color": "#6510F4"}, {"name": "project", "type": "EntityType", "ontology_valid": false, "version": 1, "topological_rank": 0, "metadata": {"index_fields": ["name"]}, "belongs_to_set": null, "source_pipeline": "cognify_pipeline", "source_task": "extract_graph_from_data", "source_node_set": null, "source_user": "default_user@example.com", "feedback_weight": 0.5, "description": "project", "relations": [], "id": "29c0d211-0d39-579f-bf45-c7a78394c9aa", "color": "#A550FF"}, {"name": "technology", "type": "EntityType", "ontology_valid": false, "version": 1, "topological_rank": 0, "metadata": {"index_fields": ["name"]}, "belongs_to_set": null, "source_pipeline": "cognify_pipeline", "source_task": "extract_graph_from_data", "source_node_set": null, "source_user": "default_user@example.com", "feedback_weight": 0.5, "description": "technology", "relations": [], "id": "65c71de3-4c23-5f28-8e07-fc7428d1e0c4", "color": "#A550FF"}, {"name": "llms", "type": "Entity", "ontology_valid": false, "version": 1, "topological_rank": 0, "metadata": {"index_fields": ["name"]}, "belongs_to_set": null, "source_pipeline": "cognify_pipeline", "source_task": "extract_graph_from_data", "source_node_set": null, "source_user": "default_user@example.com", "feedback_weight": 0.5, "description": "large language models used as part of the search platform", "relations": [], "id": "f7dc5ef7-3d2d-50c7-9edc-475862a15d4b", "color": "#6510F4"}, {"name": "bob", "type": "Entity", "ontology_valid": false, "version": 1, "topological_rank": 0, "metadata": {"index_fields": ["name"]}, "belongs_to_set": null, "source_pipeline": "cognify_pipeline", "source_task": "extract_graph_from_data", "source_node_set": null, "source_user": "default_user@example.com", "feedback_weight": 0.5, "description": "ML engineer on the engineering team at Acme Corp", "id": "515e93c6-3782-59db-96be-ad5b8cf872a5", "color": "#6510F4"}, {"name": "ml engineer", "type": "Entity", "ontology_valid": false, "version": 1, "topological_rank": 0, "metadata": {"index_fields": ["name"]}, "belongs_to_set": null, "source_pipeline": "cognify_pipeline", "source_task": "extract_graph_from_data", "source_node_set": null, "source_user": "default_user@example.com", "feedback_weight": 0.5, "description": "role focused on machine learning model development and integration", "relations": [], "id": "fe01cac2-faf3-51b4-8e43-19979f276efa", "color": "#6510F4"}, {"name": "carol", "type": "Entity", "ontology_valid": false, "version": 1, "topological_rank": 0, "metadata": {"index_fields": ["name"]}, "belongs_to_set": null, "source_pipeline": "cognify_pipeline", "source_task": "extract_graph_from_data", "source_node_set": null, "source_user": "default_user@example.com", "feedback_weight": 0.5, "description": "infrastructure engineer on the engineering team at Acme Corp", "id": "80370ebb-d9b5-5f12-a3fb-db3631157840", "color": "#6510F4"}, {"name": "infrastructure engineer", "type": "Entity", "ontology_valid": false, "version": 1, "topological_rank": 0, "metadata": {"index_fields": ["name"]}, "belongs_to_set": null, "source_pipeline": "cognify_pipeline", "source_task": "extract_graph_from_data", "source_node_set": null, "source_user": "default_user@example.com", "feedback_weight": 0.5, "description": "role focused on infrastructure and deployment", "relations": [], "id": "7df9e2f4-b48b-57ae-96d0-df86968624b8", "color": "#6510F4"}, {"name": "", "type": "TextSummary", "ontology_valid": false, "version": 1, "topological_rank": 0, "metadata": {"index_fields": ["text"]}, "belongs_to_set": null, "source_pipeline": "cognify_pipeline", "source_task": "summarize_text", "source_node_set": null, "source_user": "default_user@example.com", "feedback_weight": 0.5, "text": "Cognee is an open-source memory system for AI agents that converts raw data (e.g., unstructured documents, relational databases) into a persistent, rich, and traceable knowledge store searchable by meaning and relationships.", "id": "d39e745b-8b1b-5196-a9bd-529792880b24", "color": "#6510F4"}, {"name": "", "type": "DocumentChunk", "ontology_valid": false, "version": 1, "topological_rank": 0, "metadata": {"index_fields": ["text"]}, "belongs_to_set": null, "source_pipeline": "cognify_pipeline", "source_task": "extract_chunks_from_documents", "source_node_set": null, "source_user": "default_user@example.com", "feedback_weight": 0.5, "text": "Cognee is an open-source memory for AI agents. Cognee builts a knowledge enginethat transforms raw data (e.g., unstructured documents, relational databases, etc.)into a persistent, rich, and traceable memory that is searchable by meaning and relationships.", "chunk_size": 95, "chunk_index": 0, "cut_type": "sentence_end", "id": "37e1b646-e036-5954-b73d-73391dbe03f9", "color": "#0DFF00"}, {"name": "text_d1622b5a4ae1e31ed9d352ea3d2cbc20", "type": "TextDocument", "ontology_valid": false, "version": 1, "topological_rank": 0, "metadata": {"index_fields": ["name"]}, "belongs_to_set": null, "source_pipeline": "cognify_pipeline", "source_task": "classify_documents", "source_node_set": null, "source_user": "default_user@example.com", "feedback_weight": 0.5, "raw_data_location": "file:///Users/handekafkas/Documents/local-code/haystack-core-integrations/integrations/cognee/.venv/lib/python3.13/site-packages/cognee/.data_storage/7cea2662-fd6a-49be-a2c6-aeefcb51fc76/text_d1622b5a4ae1e31ed9d352ea3d2cbc20.txt", "external_metadata": "{}", "mime_type": "text/plain", "id": "d4211405-855c-5dec-84bd-7209d88a5766", "color": "#DBD8D8"}, {"name": "cognee", "type": "Entity", "ontology_valid": false, "version": 1, "topological_rank": 0, "metadata": {"index_fields": ["name"]}, "belongs_to_set": null, "source_pipeline": "cognify_pipeline", "source_task": "extract_graph_from_data", "source_node_set": null, "source_user": "default_user@example.com", "feedback_weight": 0.5, "description": "An open-source memory for AI agents that builds a knowledge engine to transform raw data into a persistent, rich, and traceable memory searchable by meaning and relationships.", "id": "2d09f34b-aee1-5d32-a2f9-23eb7ed48b24", "color": "#6510F4"}, {"name": "software", "type": "EntityType", "ontology_valid": false, "version": 1, "topological_rank": 0, "metadata": {"index_fields": ["name"]}, "belongs_to_set": null, "source_pipeline": "cognify_pipeline", "source_task": "extract_graph_from_data", "source_node_set": null, "source_user": "default_user@example.com", "feedback_weight": 0.5, "description": "software", "relations": [], "id": "2d66edc2-1e14-55ab-8304-680b514a597a", "color": "#A550FF"}, {"name": "knowledge engine", "type": "Entity", "ontology_valid": false, "version": 1, "topological_rank": 0, "metadata": {"index_fields": ["name"]}, "belongs_to_set": null, "source_pipeline": "cognify_pipeline", "source_task": "extract_graph_from_data", "source_node_set": null, "source_user": "default_user@example.com", "feedback_weight": 0.5, "description": "A system that transforms raw data (for example, unstructured documents and relational databases) into persistent, rich, and traceable memory.", "id": "d8b992b3-ebdc-52a4-9913-9e1aea9a47f8", "color": "#6510F4"}, {"name": "raw data", "type": "Entity", "ontology_valid": false, "version": 1, "topological_rank": 0, "metadata": {"index_fields": ["name"]}, "belongs_to_set": null, "source_pipeline": "cognify_pipeline", "source_task": "extract_graph_from_data", "source_node_set": null, "source_user": "default_user@example.com", "feedback_weight": 0.5, "description": "Source inputs such as unstructured documents and relational databases that are transformed by the knowledge engine.", "id": "0a6f4624-d50e-5989-ba18-ddab839f5554", "color": "#6510F4"}, {"name": "data", "type": "EntityType", "ontology_valid": false, "version": 1, "topological_rank": 0, "metadata": {"index_fields": ["name"]}, "belongs_to_set": null, "source_pipeline": "cognify_pipeline", "source_task": "extract_graph_from_data", "source_node_set": null, "source_user": "default_user@example.com", "feedback_weight": 0.5, "description": "data", "relations": [], "id": "4ed5a0c7-2efb-52d1-9734-06a8ba225c94", "color": "#A550FF"}, {"name": "unstructured documents", "type": "Entity", "ontology_valid": false, "version": 1, "topological_rank": 0, "metadata": {"index_fields": ["name"]}, "belongs_to_set": null, "source_pipeline": "cognify_pipeline", "source_task": "extract_graph_from_data", "source_node_set": null, "source_user": "default_user@example.com", "feedback_weight": 0.5, "description": "An example of raw data, e.g., free-form text documents, articles, and reports.", "relations": [], "id": "f89d185b-5df9-5fc6-84a7-35931b380405", "color": "#6510F4"}, {"name": "relational databases", "type": "Entity", "ontology_valid": false, "version": 1, "topological_rank": 0, "metadata": {"index_fields": ["name"]}, "belongs_to_set": null, "source_pipeline": "cognify_pipeline", "source_task": "extract_graph_from_data", "source_node_set": null, "source_user": "default_user@example.com", "feedback_weight": 0.5, "description": "An example of raw data stored in structured database systems.", "relations": [], "id": "9d84ec4f-0968-52d0-bd6d-2a4c1b07490d", "color": "#6510F4"}, {"name": "persistent memory", "type": "Entity", "ontology_valid": false, "version": 1, "topological_rank": 0, "metadata": {"index_fields": ["name"]}, "belongs_to_set": null, "source_pipeline": "cognify_pipeline", "source_task": "extract_graph_from_data", "source_node_set": null, "source_user": "default_user@example.com", "feedback_weight": 0.5, "description": "Stored memory that endures across sessions and retains rich, traceable information.", "id": "55d2ac3c-0027-5294-b45f-272dddc1a8ad", "color": "#6510F4"}, {"name": "meaning and relationships", "type": "Entity", "ontology_valid": false, "version": 1, "topological_rank": 0, "metadata": {"index_fields": ["name"]}, "belongs_to_set": null, "source_pipeline": "cognify_pipeline", "source_task": "extract_graph_from_data", "source_node_set": null, "source_user": "default_user@example.com", "feedback_weight": 0.5, "description": "Semantic and relational aspects used to search and retrieve information from the persistent memory.", "relations": [], "id": "470d1242-e936-549e-bb35-2fe0188857dd", "color": "#6510F4"}, {"name": "ai agents", "type": "Entity", "ontology_valid": false, "version": 1, "topological_rank": 0, "metadata": {"index_fields": ["name"]}, "belongs_to_set": null, "source_pipeline": "cognify_pipeline", "source_task": "extract_graph_from_data", "source_node_set": null, "source_user": "default_user@example.com", "feedback_weight": 0.5, "description": "Autonomous systems or programs that use persistent memory like Cognee.", "relations": [], "id": "968213f1-6ddc-5155-89d4-6df7c144a4a1", "color": "#6510F4"}, {"name": "agent", "type": "EntityType", "ontology_valid": false, "version": 1, "topological_rank": 0, "metadata": {"index_fields": ["name"]}, "belongs_to_set": null, "source_pipeline": "cognify_pipeline", "source_task": "extract_graph_from_data", "source_node_set": null, "source_user": "default_user@example.com", "feedback_weight": 0.5, "description": "agent", "relations": [], "id": "5f6d6fc0-e6aa-5365-a4a0-98d6fa3af190", "color": "#A550FF"}, {"name": "open-source", "type": "Entity", "ontology_valid": false, "version": 1, "topological_rank": 0, "metadata": {"index_fields": ["name"]}, "belongs_to_set": null, "source_pipeline": "cognify_pipeline", "source_task": "extract_graph_from_data", "source_node_set": null, "source_user": "default_user@example.com", "feedback_weight": 0.5, "description": "Software with source code that is publicly available.", "relations": [], "id": "2cee890e-bebd-5809-94ae-ad0f2f9774c8", "color": "#6510F4"}, {"name": "", "type": "TextSummary", "ontology_valid": false, "version": 1, "topological_rank": 0, "metadata": {"index_fields": ["text"]}, "belongs_to_set": null, "source_pipeline": "cognify_pipeline", "source_task": "summarize_text", "source_node_set": null, "source_user": "default_user@example.com", "feedback_weight": 0.5, "text": "Haystack is an open-source LLM framework developed by deepset for building production-ready retrieval-augmented generation (RAG) pipelines, agents, and search applications.", "id": "025d8100-e0af-509a-a6fe-64e37e8200fd", "color": "#6510F4"}, {"name": "", "type": "DocumentChunk", "ontology_valid": false, "version": 1, "topological_rank": 0, "metadata": {"index_fields": ["text"]}, "belongs_to_set": null, "source_pipeline": "cognify_pipeline", "source_task": "extract_chunks_from_documents", "source_node_set": null, "source_user": "default_user@example.com", "feedback_weight": 0.5, "text": "Haystack is an open-source LLM framework by deepset for building production-ready RAG pipelines, agents, and search systems. It uses a component-based architecture where each step (retrieval, generation, etc.) is a composable building block.", "chunk_size": 84, "chunk_index": 0, "cut_type": "sentence_end", "id": "7404fe0d-4620-594d-b9f7-bf0cb143e7c0", "color": "#0DFF00"}, {"name": "text_62f45b114bbc9894497442c0588694a9", "type": "TextDocument", "ontology_valid": false, "version": 1, "topological_rank": 0, "metadata": {"index_fields": ["name"]}, "belongs_to_set": null, "source_pipeline": "cognify_pipeline", "source_task": "classify_documents", "source_node_set": null, "source_user": "default_user@example.com", "feedback_weight": 0.5, "raw_data_location": "file:///Users/handekafkas/Documents/local-code/haystack-core-integrations/integrations/cognee/.venv/lib/python3.13/site-packages/cognee/.data_storage/7cea2662-fd6a-49be-a2c6-aeefcb51fc76/text_62f45b114bbc9894497442c0588694a9.txt", "external_metadata": "{}", "mime_type": "text/plain", "id": "e116f5f3-7f9d-5c06-8159-096f75a892fc", "color": "#DBD8D8"}, {"name": "haystack", "type": "Entity", "ontology_valid": false, "version": 1, "topological_rank": 0, "metadata": {"index_fields": ["name"]}, "belongs_to_set": null, "source_pipeline": "cognify_pipeline", "source_task": "extract_graph_from_data", "source_node_set": null, "source_user": "default_user@example.com", "feedback_weight": 0.5, "description": "Open-source LLM framework by deepset for building production-ready RAG pipelines, agents, and search systems.", "id": "2bdd3deb-07d8-5413-a56d-1643e3ceb48b", "color": "#6510F4"}, {"name": "framework", "type": "EntityType", "ontology_valid": false, "version": 1, "topological_rank": 0, "metadata": {"index_fields": ["name"]}, "belongs_to_set": null, "source_pipeline": "cognify_pipeline", "source_task": "extract_graph_from_data", "source_node_set": null, "source_user": "default_user@example.com", "feedback_weight": 0.5, "description": "framework", "relations": [], "id": "36a32bd3-8880-547a-949b-8447477d1ef5", "color": "#A550FF"}, {"name": "deepset", "type": "Entity", "ontology_valid": false, "version": 1, "topological_rank": 0, "metadata": {"index_fields": ["name"]}, "belongs_to_set": null, "source_pipeline": "cognify_pipeline", "source_task": "extract_graph_from_data", "source_node_set": null, "source_user": "default_user@example.com", "feedback_weight": 0.5, "description": "Organization that created Haystack.", "relations": [], "id": "126df7ec-d0db-53ea-bc88-1bafd84c8646", "color": "#6510F4"}, {"name": "llm framework", "type": "Entity", "ontology_valid": false, "version": 1, "topological_rank": 0, "metadata": {"index_fields": ["name"]}, "belongs_to_set": null, "source_pipeline": "cognify_pipeline", "source_task": "extract_graph_from_data", "source_node_set": null, "source_user": "default_user@example.com", "feedback_weight": 0.5, "description": "A framework for working with large language models.", "relations": [], "id": "827e1c0c-0b6e-5e84-a5a6-fd221d3314dd", "color": "#6510F4"}, {"name": "component-based architecture", "type": "Entity", "ontology_valid": false, "version": 1, "topological_rank": 0, "metadata": {"index_fields": ["name"]}, "belongs_to_set": null, "source_pipeline": "cognify_pipeline", "source_task": "extract_graph_from_data", "source_node_set": null, "source_user": "default_user@example.com", "feedback_weight": 0.5, "description": "Architecture where each step is a composable building block.", "id": "865e92ac-5a4f-5ba9-910f-d28ce255c4a2", "color": "#6510F4"}, {"name": "architecture", "type": "EntityType", "ontology_valid": false, "version": 1, "topological_rank": 0, "metadata": {"index_fields": ["name"]}, "belongs_to_set": null, "source_pipeline": "cognify_pipeline", "source_task": "extract_graph_from_data", "source_node_set": null, "source_user": "default_user@example.com", "feedback_weight": 0.5, "description": "architecture", "relations": [], "id": "b581ee28-cf45-5ad5-813f-014e7e2d2312", "color": "#A550FF"}, {"name": "composable building block", "type": "Entity", "ontology_valid": false, "version": 1, "topological_rank": 0, "metadata": {"index_fields": ["name"]}, "belongs_to_set": null, "source_pipeline": "cognify_pipeline", "source_task": "extract_graph_from_data", "source_node_set": null, "source_user": "default_user@example.com", "feedback_weight": 0.5, "description": "Modular unit representing a pipeline step that can be composed with others.", "id": "59cf88c0-cb09-5f96-9252-5f5810981bcc", "color": "#6510F4"}, {"name": "retrieval", "type": "Entity", "ontology_valid": false, "version": 1, "topological_rank": 0, "metadata": {"index_fields": ["name"]}, "belongs_to_set": null, "source_pipeline": "cognify_pipeline", "source_task": "extract_graph_from_data", "source_node_set": null, "source_user": "default_user@example.com", "feedback_weight": 0.5, "description": "Retrieval step component used in Haystack pipelines.", "relations": [], "id": "f010bf52-6eb5-511f-bbed-cd5237545edd", "color": "#6510F4"}, {"name": "component", "type": "EntityType", "ontology_valid": false, "version": 1, "topological_rank": 0, "metadata": {"index_fields": ["name"]}, "belongs_to_set": null, "source_pipeline": "cognify_pipeline", "source_task": "extract_graph_from_data", "source_node_set": null, "source_user": "default_user@example.com", "feedback_weight": 0.5, "description": "component", "relations": [], "id": "b283358b-c288-5ca1-a6e8-05bac88f7a6f", "color": "#A550FF"}, {"name": "generation", "type": "Entity", "ontology_valid": false, "version": 1, "topological_rank": 0, "metadata": {"index_fields": ["name"]}, "belongs_to_set": null, "source_pipeline": "cognify_pipeline", "source_task": "extract_graph_from_data", "source_node_set": null, "source_user": "default_user@example.com", "feedback_weight": 0.5, "description": "Generation step component used in Haystack pipelines.", "relations": [], "id": "dba0457b-9aff-5eb6-8ccd-19f7c9ae4dfa", "color": "#6510F4"}, {"name": "pipeline", "type": "Entity", "ontology_valid": false, "version": 1, "topological_rank": 0, "metadata": {"index_fields": ["name"]}, "belongs_to_set": null, "source_pipeline": "cognify_pipeline", "source_task": "extract_graph_from_data", "source_node_set": null, "source_user": "default_user@example.com", "feedback_weight": 0.5, "description": "Sequence of steps (for example retrieval and generation) used to process inputs and produce outputs.", "id": "31777e8a-6d26-5454-9da8-766d9e049857", "color": "#6510F4"}, {"name": "rag", "type": "Entity", "ontology_valid": false, "version": 1, "topological_rank": 0, "metadata": {"index_fields": ["name"]}, "belongs_to_set": null, "source_pipeline": "cognify_pipeline", "source_task": "extract_graph_from_data", "source_node_set": null, "source_user": "default_user@example.com", "feedback_weight": 0.5, "description": "Retrieval-Augmented Generation pipelines.", "relations": [], "id": "1ff6e485-672b-5976-8bea-f809f67fe245", "color": "#6510F4"}, {"name": "agents", "type": "Entity", "ontology_valid": false, "version": 1, "topological_rank": 0, "metadata": {"index_fields": ["name"]}, "belongs_to_set": null, "source_pipeline": "cognify_pipeline", "source_task": "extract_graph_from_data", "source_node_set": null, "source_user": "default_user@example.com", "feedback_weight": 0.5, "description": "Agent systems that perform tasks using LLMs.", "relations": [], "id": "ba1f1dac-e2fb-5464-914d-ff54b9b19787", "color": "#6510F4"}, {"name": "search systems", "type": "Entity", "ontology_valid": false, "version": 1, "topological_rank": 0, "metadata": {"index_fields": ["name"]}, "belongs_to_set": null, "source_pipeline": "cognify_pipeline", "source_task": "extract_graph_from_data", "source_node_set": null, "source_user": "default_user@example.com", "feedback_weight": 0.5, "description": "Search systems built using LLMs and retrieval techniques.", "relations": [], "id": "a1a666e4-2070-59fd-95f7-c4c6178e89ba", "color": "#6510F4"}]; +var links = [{"source": "69451bda-0a8c-55cc-a5c6-1f2f3d4a384d", "target": "5a24f9a6-a52e-5239-b6cf-76364cac7ff0", "relation": "made_from", "weight": null, "all_weights": {}, "relationship_type": null, "edge_info": {"source_node_id": "69451bda-0a8c-55cc-a5c6-1f2f3d4a384d", "target_node_id": "5a24f9a6-a52e-5239-b6cf-76364cac7ff0", "relationship_name": "made_from", "updated_at": "2026-04-02 09:04:27", "edge_object_id": "e192dc40-031f-5f60-8a8e-f03e8baa0880", "feedback_weight": 0.5}}, {"source": "5a24f9a6-a52e-5239-b6cf-76364cac7ff0", "target": "aa2e81bf-0c3e-599f-9de3-0bc8e97c644f", "relation": "is_part_of", "weight": null, "all_weights": {}, "relationship_type": null, "edge_info": {"source_node_id": "5a24f9a6-a52e-5239-b6cf-76364cac7ff0", "target_node_id": "aa2e81bf-0c3e-599f-9de3-0bc8e97c644f", "relationship_name": "is_part_of", "updated_at": "2026-04-02 09:04:27", "edge_object_id": "b55bf8c5-d7ac-5c6b-860e-627c6c389174", "feedback_weight": 0.5}}, {"source": "5a24f9a6-a52e-5239-b6cf-76364cac7ff0", "target": "df20c394-b710-5b2c-9256-ce5f5fe36397", "relation": "contains", "weight": null, "all_weights": {}, "relationship_type": "contains", "edge_info": {"source_node_id": "5a24f9a6-a52e-5239-b6cf-76364cac7ff0", "target_node_id": "df20c394-b710-5b2c-9256-ce5f5fe36397", "relationship_name": "contains", "updated_at": "2026-04-02 09:04:27", "relationship_type": "contains", "edge_text": "relationship_name: contains; entity_name: knowledge graphs; entity_description: Graph-based representation of information using nodes and edges to capture entities and relationships", "edge_object_id": "82ab5ab7-9d21-57a3-a279-b6a91fa9ada0", "feedback_weight": 0.5}}, {"source": "5a24f9a6-a52e-5239-b6cf-76364cac7ff0", "target": "05be7eb9-fd46-5fc0-aa0b-1e82ac5985d1", "relation": "contains", "weight": null, "all_weights": {}, "relationship_type": "contains", "edge_info": {"source_node_id": "5a24f9a6-a52e-5239-b6cf-76364cac7ff0", "target_node_id": "05be7eb9-fd46-5fc0-aa0b-1e82ac5985d1", "relationship_name": "contains", "updated_at": "2026-04-02 09:04:27", "relationship_type": "contains", "edge_text": "relationship_name: contains; entity_name: nodes (entities); entity_description: Graph elements representing real-world entities or concepts", "edge_object_id": "f47c9d18-c8ce-532d-8695-65d0523a76f5", "feedback_weight": 0.5}}, {"source": "5a24f9a6-a52e-5239-b6cf-76364cac7ff0", "target": "749d1b20-55d7-5992-a930-b6ab13974f8d", "relation": "contains", "weight": null, "all_weights": {}, "relationship_type": "contains", "edge_info": {"source_node_id": "5a24f9a6-a52e-5239-b6cf-76364cac7ff0", "target_node_id": "749d1b20-55d7-5992-a930-b6ab13974f8d", "relationship_name": "contains", "updated_at": "2026-04-02 09:04:27", "relationship_type": "contains", "edge_text": "relationship_name: contains; entity_name: edges (relationships); entity_description: Graph elements representing relationships between nodes", "edge_object_id": "a6f3fb8f-a0d8-5125-9cf3-fe73253dd0d8", "feedback_weight": 0.5}}, {"source": "5a24f9a6-a52e-5239-b6cf-76364cac7ff0", "target": "9d6360d4-504a-5f7f-b618-c2ea457a1a4d", "relation": "contains", "weight": null, "all_weights": {}, "relationship_type": "contains", "edge_info": {"source_node_id": "5a24f9a6-a52e-5239-b6cf-76364cac7ff0", "target_node_id": "9d6360d4-504a-5f7f-b618-c2ea457a1a4d", "relationship_name": "contains", "updated_at": "2026-04-02 09:04:27", "relationship_type": "contains", "edge_text": "relationship_name: contains; entity_name: semantic search; entity_description: Search technique that uses meaning and relationships to improve relevance", "edge_object_id": "37e8a4b0-c959-59fe-92f4-86d9c06074a4", "feedback_weight": 0.5}}, {"source": "5a24f9a6-a52e-5239-b6cf-76364cac7ff0", "target": "ba802be9-50b2-58a6-a46d-031e30a780a8", "relation": "contains", "weight": null, "all_weights": {}, "relationship_type": "contains", "edge_info": {"source_node_id": "5a24f9a6-a52e-5239-b6cf-76364cac7ff0", "target_node_id": "ba802be9-50b2-58a6-a46d-031e30a780a8", "relationship_name": "contains", "updated_at": "2026-04-02 09:04:27", "relationship_type": "contains", "edge_text": "relationship_name: contains; entity_name: reasoning; entity_description: Inference processes that derive new knowledge from existing facts and relations", "edge_object_id": "edd04d7d-d25d-5acd-accb-dc143eb6f9d4", "feedback_weight": 0.5}}, {"source": "5a24f9a6-a52e-5239-b6cf-76364cac7ff0", "target": "e0c5c99c-74a8-5d09-8e8a-05cb2e5bcf6b", "relation": "contains", "weight": null, "all_weights": {}, "relationship_type": "contains", "edge_info": {"source_node_id": "5a24f9a6-a52e-5239-b6cf-76364cac7ff0", "target_node_id": "e0c5c99c-74a8-5d09-8e8a-05cb2e5bcf6b", "relationship_name": "contains", "updated_at": "2026-04-02 09:04:27", "relationship_type": "contains", "edge_text": "relationship_name: contains; entity_name: discovery of hidden connections; entity_description: Finding non-obvious relationships across data that reveal new insights", "edge_object_id": "92d39e1a-7fd3-5376-803d-3f459d93930e", "feedback_weight": 0.5}}, {"source": "5a24f9a6-a52e-5239-b6cf-76364cac7ff0", "target": "838f4a46-e459-58e4-a40b-ab30cd21da5c", "relation": "contains", "weight": null, "all_weights": {}, "relationship_type": "contains", "edge_info": {"source_node_id": "5a24f9a6-a52e-5239-b6cf-76364cac7ff0", "target_node_id": "838f4a46-e459-58e4-a40b-ab30cd21da5c", "relationship_name": "contains", "updated_at": "2026-04-02 09:04:27", "relationship_type": "contains", "edge_text": "relationship_name: contains; entity_name: large document collections; entity_description: Extensive corpora of documents across which knowledge graphs can reveal connections", "edge_object_id": "2ed536ad-e3ea-55a5-8d3f-5004aac39c46", "feedback_weight": 0.5}}, {"source": "df20c394-b710-5b2c-9256-ce5f5fe36397", "target": "dd9713b7-dc20-5101-aad0-1c4216811147", "relation": "is_a", "weight": null, "all_weights": {}, "relationship_type": null, "edge_info": {"source_node_id": "df20c394-b710-5b2c-9256-ce5f5fe36397", "target_node_id": "dd9713b7-dc20-5101-aad0-1c4216811147", "relationship_name": "is_a", "updated_at": "2026-04-02 09:04:27", "edge_object_id": "97ce6ccc-f858-54d7-9cb9-8ea424f72608", "feedback_weight": 0.5}}, {"source": "df20c394-b710-5b2c-9256-ce5f5fe36397", "target": "05be7eb9-fd46-5fc0-aa0b-1e82ac5985d1", "relation": "represent_as", "weight": null, "all_weights": {}, "relationship_type": "represent_as", "edge_info": {"source_node_id": "df20c394-b710-5b2c-9256-ce5f5fe36397", "target_node_id": "05be7eb9-fd46-5fc0-aa0b-1e82ac5985d1", "relationship_name": "represent_as", "updated_at": "2026-04-02 09:04:27", "relationship_type": "represent_as", "edge_object_id": "f1e99bd0-801c-5b87-806e-d3cf53bd76f9", "feedback_weight": 0.5}}, {"source": "df20c394-b710-5b2c-9256-ce5f5fe36397", "target": "749d1b20-55d7-5992-a930-b6ab13974f8d", "relation": "represent_as", "weight": null, "all_weights": {}, "relationship_type": "represent_as", "edge_info": {"source_node_id": "df20c394-b710-5b2c-9256-ce5f5fe36397", "target_node_id": "749d1b20-55d7-5992-a930-b6ab13974f8d", "relationship_name": "represent_as", "updated_at": "2026-04-02 09:04:27", "relationship_type": "represent_as", "edge_object_id": "b6630b43-4425-5448-b452-6bbc7bf8bb04", "feedback_weight": 0.5}}, {"source": "df20c394-b710-5b2c-9256-ce5f5fe36397", "target": "9d6360d4-504a-5f7f-b618-c2ea457a1a4d", "relation": "enable", "weight": null, "all_weights": {}, "relationship_type": "enable", "edge_info": {"source_node_id": "df20c394-b710-5b2c-9256-ce5f5fe36397", "target_node_id": "9d6360d4-504a-5f7f-b618-c2ea457a1a4d", "relationship_name": "enable", "updated_at": "2026-04-02 09:04:27", "relationship_type": "enable", "edge_object_id": "3b30315e-7384-54db-b7e2-6f1b98aaf46d", "feedback_weight": 0.5}}, {"source": "df20c394-b710-5b2c-9256-ce5f5fe36397", "target": "ba802be9-50b2-58a6-a46d-031e30a780a8", "relation": "enable", "weight": null, "all_weights": {}, "relationship_type": "enable", "edge_info": {"source_node_id": "df20c394-b710-5b2c-9256-ce5f5fe36397", "target_node_id": "ba802be9-50b2-58a6-a46d-031e30a780a8", "relationship_name": "enable", "updated_at": "2026-04-02 09:04:27", "relationship_type": "enable", "edge_object_id": "db285d61-76e2-5097-bf8c-8494349b984e", "feedback_weight": 0.5}}, {"source": "df20c394-b710-5b2c-9256-ce5f5fe36397", "target": "e0c5c99c-74a8-5d09-8e8a-05cb2e5bcf6b", "relation": "enable", "weight": null, "all_weights": {}, "relationship_type": "enable", "edge_info": {"source_node_id": "df20c394-b710-5b2c-9256-ce5f5fe36397", "target_node_id": "e0c5c99c-74a8-5d09-8e8a-05cb2e5bcf6b", "relationship_name": "enable", "updated_at": "2026-04-02 09:04:27", "relationship_type": "enable", "edge_object_id": "7e93de66-ae6e-56e5-981d-c988f94a19c8", "feedback_weight": 0.5}}, {"source": "df20c394-b710-5b2c-9256-ce5f5fe36397", "target": "65c71de3-4c23-5f28-8e07-fc7428d1e0c4", "relation": "is_a", "weight": null, "all_weights": {}, "relationship_type": null, "edge_info": {"source_node_id": "df20c394-b710-5b2c-9256-ce5f5fe36397", "target_node_id": "65c71de3-4c23-5f28-8e07-fc7428d1e0c4", "relationship_name": "is_a", "updated_at": "2026-04-02 09:04:34", "edge_object_id": "18a6fde1-4f10-576b-b9aa-4524c095fb8e", "feedback_weight": 0.5}}, {"source": "05be7eb9-fd46-5fc0-aa0b-1e82ac5985d1", "target": "dd9713b7-dc20-5101-aad0-1c4216811147", "relation": "is_a", "weight": null, "all_weights": {}, "relationship_type": null, "edge_info": {"source_node_id": "05be7eb9-fd46-5fc0-aa0b-1e82ac5985d1", "target_node_id": "dd9713b7-dc20-5101-aad0-1c4216811147", "relationship_name": "is_a", "updated_at": "2026-04-02 09:04:27", "edge_object_id": "25dbeefe-3109-5e0f-bf65-5a05a5738491", "feedback_weight": 0.5}}, {"source": "749d1b20-55d7-5992-a930-b6ab13974f8d", "target": "dd9713b7-dc20-5101-aad0-1c4216811147", "relation": "is_a", "weight": null, "all_weights": {}, "relationship_type": null, "edge_info": {"source_node_id": "749d1b20-55d7-5992-a930-b6ab13974f8d", "target_node_id": "dd9713b7-dc20-5101-aad0-1c4216811147", "relationship_name": "is_a", "updated_at": "2026-04-02 09:04:27", "edge_object_id": "1f4d5d1f-ce80-56c6-a2d0-d573e0508b04", "feedback_weight": 0.5}}, {"source": "9d6360d4-504a-5f7f-b618-c2ea457a1a4d", "target": "dd9713b7-dc20-5101-aad0-1c4216811147", "relation": "is_a", "weight": null, "all_weights": {}, "relationship_type": null, "edge_info": {"source_node_id": "9d6360d4-504a-5f7f-b618-c2ea457a1a4d", "target_node_id": "dd9713b7-dc20-5101-aad0-1c4216811147", "relationship_name": "is_a", "updated_at": "2026-04-02 09:04:27", "edge_object_id": "db3ea78c-b272-5385-9049-0a3ec143a352", "feedback_weight": 0.5}}, {"source": "ba802be9-50b2-58a6-a46d-031e30a780a8", "target": "dd9713b7-dc20-5101-aad0-1c4216811147", "relation": "is_a", "weight": null, "all_weights": {}, "relationship_type": null, "edge_info": {"source_node_id": "ba802be9-50b2-58a6-a46d-031e30a780a8", "target_node_id": "dd9713b7-dc20-5101-aad0-1c4216811147", "relationship_name": "is_a", "updated_at": "2026-04-02 09:04:27", "edge_object_id": "8df3fefe-4d4d-552e-aa75-7f777a851e75", "feedback_weight": 0.5}}, {"source": "e0c5c99c-74a8-5d09-8e8a-05cb2e5bcf6b", "target": "dd9713b7-dc20-5101-aad0-1c4216811147", "relation": "is_a", "weight": null, "all_weights": {}, "relationship_type": null, "edge_info": {"source_node_id": "e0c5c99c-74a8-5d09-8e8a-05cb2e5bcf6b", "target_node_id": "dd9713b7-dc20-5101-aad0-1c4216811147", "relationship_name": "is_a", "updated_at": "2026-04-02 09:04:27", "edge_object_id": "1e05af6b-81c4-5266-85b5-0739dd1e9a0d", "feedback_weight": 0.5}}, {"source": "e0c5c99c-74a8-5d09-8e8a-05cb2e5bcf6b", "target": "838f4a46-e459-58e4-a40b-ab30cd21da5c", "relation": "occur_across", "weight": null, "all_weights": {}, "relationship_type": "occur_across", "edge_info": {"source_node_id": "e0c5c99c-74a8-5d09-8e8a-05cb2e5bcf6b", "target_node_id": "838f4a46-e459-58e4-a40b-ab30cd21da5c", "relationship_name": "occur_across", "updated_at": "2026-04-02 09:04:27", "relationship_type": "occur_across", "edge_object_id": "c8796d45-fd73-505e-852e-1fa98ec69991", "feedback_weight": 0.5}}, {"source": "838f4a46-e459-58e4-a40b-ab30cd21da5c", "target": "dd9713b7-dc20-5101-aad0-1c4216811147", "relation": "is_a", "weight": null, "all_weights": {}, "relationship_type": null, "edge_info": {"source_node_id": "838f4a46-e459-58e4-a40b-ab30cd21da5c", "target_node_id": "dd9713b7-dc20-5101-aad0-1c4216811147", "relationship_name": "is_a", "updated_at": "2026-04-02 09:04:27", "edge_object_id": "38fdcb07-6e5d-5b86-9f32-a34b031c0139", "feedback_weight": 0.5}}, {"source": "5920fa1a-48b2-503a-858a-df9cb18e710d", "target": "d44e16f2-55c2-5bb6-a1c1-cfd39ad2b1b1", "relation": "made_from", "weight": null, "all_weights": {}, "relationship_type": null, "edge_info": {"source_node_id": "5920fa1a-48b2-503a-858a-df9cb18e710d", "target_node_id": "d44e16f2-55c2-5bb6-a1c1-cfd39ad2b1b1", "relationship_name": "made_from", "updated_at": "2026-04-02 09:04:34", "edge_object_id": "796d3f5f-26ae-5256-b5d7-16a96e32e133", "feedback_weight": 0.5}}, {"source": "d44e16f2-55c2-5bb6-a1c1-cfd39ad2b1b1", "target": "6834c0c9-68ce-56f7-8829-86bc13026ca2", "relation": "is_part_of", "weight": null, "all_weights": {}, "relationship_type": null, "edge_info": {"source_node_id": "d44e16f2-55c2-5bb6-a1c1-cfd39ad2b1b1", "target_node_id": "6834c0c9-68ce-56f7-8829-86bc13026ca2", "relationship_name": "is_part_of", "updated_at": "2026-04-02 09:04:34", "edge_object_id": "662499d0-12c9-5ffb-a15b-050c7bccfe0a", "feedback_weight": 0.5}}, {"source": "d44e16f2-55c2-5bb6-a1c1-cfd39ad2b1b1", "target": "f7d8be13-2a72-5104-bd02-7a5964737a91", "relation": "contains", "weight": null, "all_weights": {}, "relationship_type": "contains", "edge_info": {"source_node_id": "d44e16f2-55c2-5bb6-a1c1-cfd39ad2b1b1", "target_node_id": "f7d8be13-2a72-5104-bd02-7a5964737a91", "relationship_name": "contains", "updated_at": "2026-04-02 09:04:34", "relationship_type": "contains", "edge_text": "relationship_name: contains; entity_name: alice; entity_description: backend lead on the engineering team at Acme Corp", "edge_object_id": "91f7a645-936a-5220-8517-c7c6914159aa", "feedback_weight": 0.5}}, {"source": "d44e16f2-55c2-5bb6-a1c1-cfd39ad2b1b1", "target": "515e93c6-3782-59db-96be-ad5b8cf872a5", "relation": "contains", "weight": null, "all_weights": {}, "relationship_type": "contains", "edge_info": {"source_node_id": "d44e16f2-55c2-5bb6-a1c1-cfd39ad2b1b1", "target_node_id": "515e93c6-3782-59db-96be-ad5b8cf872a5", "relationship_name": "contains", "updated_at": "2026-04-02 09:04:34", "relationship_type": "contains", "edge_text": "relationship_name: contains; entity_name: bob; entity_description: ML engineer on the engineering team at Acme Corp", "edge_object_id": "46cc97d7-438c-566d-aade-875204bbbeed", "feedback_weight": 0.5}}, {"source": "d44e16f2-55c2-5bb6-a1c1-cfd39ad2b1b1", "target": "80370ebb-d9b5-5f12-a3fb-db3631157840", "relation": "contains", "weight": null, "all_weights": {}, "relationship_type": "contains", "edge_info": {"source_node_id": "d44e16f2-55c2-5bb6-a1c1-cfd39ad2b1b1", "target_node_id": "80370ebb-d9b5-5f12-a3fb-db3631157840", "relationship_name": "contains", "updated_at": "2026-04-02 09:04:34", "relationship_type": "contains", "edge_text": "relationship_name: contains; entity_name: carol; entity_description: infrastructure engineer on the engineering team at Acme Corp", "edge_object_id": "be809b86-b009-57c1-a2d9-7b1148355bb7", "feedback_weight": 0.5}}, {"source": "d44e16f2-55c2-5bb6-a1c1-cfd39ad2b1b1", "target": "346f1ce4-0869-56a1-891a-a99af46c348a", "relation": "contains", "weight": null, "all_weights": {}, "relationship_type": "contains", "edge_info": {"source_node_id": "d44e16f2-55c2-5bb6-a1c1-cfd39ad2b1b1", "target_node_id": "346f1ce4-0869-56a1-891a-a99af46c348a", "relationship_name": "contains", "updated_at": "2026-04-02 09:04:34", "relationship_type": "contains", "edge_text": "relationship_name: contains; entity_name: engineering team; entity_description: engineering team at Acme Corp consisting of Alice, Bob, and Carol", "edge_object_id": "61495c98-b2b9-5b09-a4f4-7f0b20fd45f6", "feedback_weight": 0.5}}, {"source": "d44e16f2-55c2-5bb6-a1c1-cfd39ad2b1b1", "target": "7f5a651e-56c1-574f-aa54-cd0a0b7dbc38", "relation": "contains", "weight": null, "all_weights": {}, "relationship_type": "contains", "edge_info": {"source_node_id": "d44e16f2-55c2-5bb6-a1c1-cfd39ad2b1b1", "target_node_id": "7f5a651e-56c1-574f-aa54-cd0a0b7dbc38", "relationship_name": "contains", "updated_at": "2026-04-02 09:04:34", "relationship_type": "contains", "edge_text": "relationship_name: contains; entity_name: acme corp; entity_description: organization employing the engineering team", "edge_object_id": "7ad8d3ad-d8b9-50c8-adb0-c6f243c03255", "feedback_weight": 0.5}}, {"source": "d44e16f2-55c2-5bb6-a1c1-cfd39ad2b1b1", "target": "6fdb37d4-ae27-5a1a-9f7a-03f5036247ca", "relation": "contains", "weight": null, "all_weights": {}, "relationship_type": "contains", "edge_info": {"source_node_id": "d44e16f2-55c2-5bb6-a1c1-cfd39ad2b1b1", "target_node_id": "6fdb37d4-ae27-5a1a-9f7a-03f5036247ca", "relationship_name": "contains", "updated_at": "2026-04-02 09:04:34", "relationship_type": "contains", "edge_text": "relationship_name: contains; entity_name: next-generation search platform; entity_description: search platform being built by the engineering team, powered by knowledge graphs and LLMs", "edge_object_id": "08c5f4c5-ee33-59e4-8d20-7dd56c682e91", "feedback_weight": 0.5}}, {"source": "d44e16f2-55c2-5bb6-a1c1-cfd39ad2b1b1", "target": "df20c394-b710-5b2c-9256-ce5f5fe36397", "relation": "contains", "weight": null, "all_weights": {}, "relationship_type": "contains", "edge_info": {"source_node_id": "d44e16f2-55c2-5bb6-a1c1-cfd39ad2b1b1", "target_node_id": "df20c394-b710-5b2c-9256-ce5f5fe36397", "relationship_name": "contains", "updated_at": "2026-04-02 09:04:34", "relationship_type": "contains", "edge_text": "relationship_name: contains; entity_name: knowledge graphs; entity_description: technology used to structure and represent knowledge for the search platform", "edge_object_id": "7d826f1f-0988-5058-ba58-14d757667493", "feedback_weight": 0.5}}, {"source": "d44e16f2-55c2-5bb6-a1c1-cfd39ad2b1b1", "target": "f7dc5ef7-3d2d-50c7-9edc-475862a15d4b", "relation": "contains", "weight": null, "all_weights": {}, "relationship_type": "contains", "edge_info": {"source_node_id": "d44e16f2-55c2-5bb6-a1c1-cfd39ad2b1b1", "target_node_id": "f7dc5ef7-3d2d-50c7-9edc-475862a15d4b", "relationship_name": "contains", "updated_at": "2026-04-02 09:04:34", "relationship_type": "contains", "edge_text": "relationship_name: contains; entity_name: llms; entity_description: large language models used as part of the search platform", "edge_object_id": "59de6091-c89e-503c-9ea5-eedbe64d71da", "feedback_weight": 0.5}}, {"source": "d44e16f2-55c2-5bb6-a1c1-cfd39ad2b1b1", "target": "4d00d1ec-e3a5-5b42-b970-1926ddca1a75", "relation": "contains", "weight": null, "all_weights": {}, "relationship_type": "contains", "edge_info": {"source_node_id": "d44e16f2-55c2-5bb6-a1c1-cfd39ad2b1b1", "target_node_id": "4d00d1ec-e3a5-5b42-b970-1926ddca1a75", "relationship_name": "contains", "updated_at": "2026-04-02 09:04:34", "relationship_type": "contains", "edge_text": "relationship_name: contains; entity_name: backend lead; entity_description: role focused on backend architecture and implementation", "edge_object_id": "c328d0cd-509a-505a-8cae-5733fbd5a5fc", "feedback_weight": 0.5}}, {"source": "d44e16f2-55c2-5bb6-a1c1-cfd39ad2b1b1", "target": "fe01cac2-faf3-51b4-8e43-19979f276efa", "relation": "contains", "weight": null, "all_weights": {}, "relationship_type": "contains", "edge_info": {"source_node_id": "d44e16f2-55c2-5bb6-a1c1-cfd39ad2b1b1", "target_node_id": "fe01cac2-faf3-51b4-8e43-19979f276efa", "relationship_name": "contains", "updated_at": "2026-04-02 09:04:34", "relationship_type": "contains", "edge_text": "relationship_name: contains; entity_name: ml engineer; entity_description: role focused on machine learning model development and integration", "edge_object_id": "7da7b1b4-8721-58a9-b04d-b77ed2747239", "feedback_weight": 0.5}}, {"source": "d44e16f2-55c2-5bb6-a1c1-cfd39ad2b1b1", "target": "7df9e2f4-b48b-57ae-96d0-df86968624b8", "relation": "contains", "weight": null, "all_weights": {}, "relationship_type": "contains", "edge_info": {"source_node_id": "d44e16f2-55c2-5bb6-a1c1-cfd39ad2b1b1", "target_node_id": "7df9e2f4-b48b-57ae-96d0-df86968624b8", "relationship_name": "contains", "updated_at": "2026-04-02 09:04:34", "relationship_type": "contains", "edge_text": "relationship_name: contains; entity_name: infrastructure engineer; entity_description: role focused on infrastructure and deployment", "edge_object_id": "571d0f13-11c3-5a1c-bb52-4c1b2c430b07", "feedback_weight": 0.5}}, {"source": "f7d8be13-2a72-5104-bd02-7a5964737a91", "target": "d072ba0f-e1a9-58bf-9974-e1802adc8134", "relation": "is_a", "weight": null, "all_weights": {}, "relationship_type": null, "edge_info": {"source_node_id": "f7d8be13-2a72-5104-bd02-7a5964737a91", "target_node_id": "d072ba0f-e1a9-58bf-9974-e1802adc8134", "relationship_name": "is_a", "updated_at": "2026-04-02 09:04:34", "edge_object_id": "635bbc13-9413-5d22-822b-50c92aa8bdd1", "feedback_weight": 0.5}}, {"source": "f7d8be13-2a72-5104-bd02-7a5964737a91", "target": "4d00d1ec-e3a5-5b42-b970-1926ddca1a75", "relation": "has_role", "weight": null, "all_weights": {}, "relationship_type": "has_role", "edge_info": {"source_node_id": "f7d8be13-2a72-5104-bd02-7a5964737a91", "target_node_id": "4d00d1ec-e3a5-5b42-b970-1926ddca1a75", "relationship_name": "has_role", "updated_at": "2026-04-02 09:04:34", "relationship_type": "has_role", "edge_object_id": "9e1356c8-4801-53b1-8776-c8eb00e87d36", "feedback_weight": 0.5}}, {"source": "f7d8be13-2a72-5104-bd02-7a5964737a91", "target": "346f1ce4-0869-56a1-891a-a99af46c348a", "relation": "member_of", "weight": null, "all_weights": {}, "relationship_type": "member_of", "edge_info": {"source_node_id": "f7d8be13-2a72-5104-bd02-7a5964737a91", "target_node_id": "346f1ce4-0869-56a1-891a-a99af46c348a", "relationship_name": "member_of", "updated_at": "2026-04-02 09:04:34", "relationship_type": "member_of", "edge_object_id": "38de6121-a9d8-5811-b0db-4be4c185e62a", "feedback_weight": 0.5}}, {"source": "f7d8be13-2a72-5104-bd02-7a5964737a91", "target": "6fdb37d4-ae27-5a1a-9f7a-03f5036247ca", "relation": "works_on", "weight": null, "all_weights": {}, "relationship_type": "works_on", "edge_info": {"source_node_id": "f7d8be13-2a72-5104-bd02-7a5964737a91", "target_node_id": "6fdb37d4-ae27-5a1a-9f7a-03f5036247ca", "relationship_name": "works_on", "updated_at": "2026-04-02 09:04:34", "relationship_type": "works_on", "edge_object_id": "3374b3c5-8322-51aa-945a-1276704fc723", "feedback_weight": 0.5}}, {"source": "4d00d1ec-e3a5-5b42-b970-1926ddca1a75", "target": "09451c3f-999a-5c73-94d3-0d9dd38a58b1", "relation": "is_a", "weight": null, "all_weights": {}, "relationship_type": null, "edge_info": {"source_node_id": "4d00d1ec-e3a5-5b42-b970-1926ddca1a75", "target_node_id": "09451c3f-999a-5c73-94d3-0d9dd38a58b1", "relationship_name": "is_a", "updated_at": "2026-04-02 09:04:34", "edge_object_id": "44c1a3c9-ac2d-5750-89fd-a2246fbc6c42", "feedback_weight": 0.5}}, {"source": "346f1ce4-0869-56a1-891a-a99af46c348a", "target": "e308d782-2a18-5ace-b0e8-236c7c3b4db4", "relation": "is_a", "weight": null, "all_weights": {}, "relationship_type": null, "edge_info": {"source_node_id": "346f1ce4-0869-56a1-891a-a99af46c348a", "target_node_id": "e308d782-2a18-5ace-b0e8-236c7c3b4db4", "relationship_name": "is_a", "updated_at": "2026-04-02 09:04:34", "edge_object_id": "2ca5ec3d-ab08-592e-ae82-b70d9a71ea78", "feedback_weight": 0.5}}, {"source": "346f1ce4-0869-56a1-891a-a99af46c348a", "target": "7f5a651e-56c1-574f-aa54-cd0a0b7dbc38", "relation": "part_of", "weight": null, "all_weights": {}, "relationship_type": "part_of", "edge_info": {"source_node_id": "346f1ce4-0869-56a1-891a-a99af46c348a", "target_node_id": "7f5a651e-56c1-574f-aa54-cd0a0b7dbc38", "relationship_name": "part_of", "updated_at": "2026-04-02 09:04:34", "relationship_type": "part_of", "edge_object_id": "8aae2f68-c02e-5254-8b4f-fe8162a62adc", "feedback_weight": 0.5}}, {"source": "346f1ce4-0869-56a1-891a-a99af46c348a", "target": "6fdb37d4-ae27-5a1a-9f7a-03f5036247ca", "relation": "is_building", "weight": null, "all_weights": {}, "relationship_type": "is_building", "edge_info": {"source_node_id": "346f1ce4-0869-56a1-891a-a99af46c348a", "target_node_id": "6fdb37d4-ae27-5a1a-9f7a-03f5036247ca", "relationship_name": "is_building", "updated_at": "2026-04-02 09:04:34", "relationship_type": "is_building", "edge_object_id": "4a1b05b7-f54f-5780-8678-11d60c516114", "feedback_weight": 0.5}}, {"source": "7f5a651e-56c1-574f-aa54-cd0a0b7dbc38", "target": "d3d7b6b4-9b0d-52e8-9e09-a9e9cf4b5a4d", "relation": "is_a", "weight": null, "all_weights": {}, "relationship_type": null, "edge_info": {"source_node_id": "7f5a651e-56c1-574f-aa54-cd0a0b7dbc38", "target_node_id": "d3d7b6b4-9b0d-52e8-9e09-a9e9cf4b5a4d", "relationship_name": "is_a", "updated_at": "2026-04-02 09:04:34", "edge_object_id": "d56bce51-4259-5dcc-a27f-2f41e423b351", "feedback_weight": 0.5}}, {"source": "6fdb37d4-ae27-5a1a-9f7a-03f5036247ca", "target": "29c0d211-0d39-579f-bf45-c7a78394c9aa", "relation": "is_a", "weight": null, "all_weights": {}, "relationship_type": null, "edge_info": {"source_node_id": "6fdb37d4-ae27-5a1a-9f7a-03f5036247ca", "target_node_id": "29c0d211-0d39-579f-bf45-c7a78394c9aa", "relationship_name": "is_a", "updated_at": "2026-04-02 09:04:34", "edge_object_id": "272d82d6-86f4-58c0-b6df-9e208a73a2b5", "feedback_weight": 0.5}}, {"source": "6fdb37d4-ae27-5a1a-9f7a-03f5036247ca", "target": "df20c394-b710-5b2c-9256-ce5f5fe36397", "relation": "powered_by", "weight": null, "all_weights": {}, "relationship_type": "powered_by", "edge_info": {"source_node_id": "6fdb37d4-ae27-5a1a-9f7a-03f5036247ca", "target_node_id": "df20c394-b710-5b2c-9256-ce5f5fe36397", "relationship_name": "powered_by", "updated_at": "2026-04-02 09:04:34", "relationship_type": "powered_by", "edge_object_id": "4d0375cc-23ec-5ae0-a762-4d8b85b53cef", "feedback_weight": 0.5}}, {"source": "6fdb37d4-ae27-5a1a-9f7a-03f5036247ca", "target": "f7dc5ef7-3d2d-50c7-9edc-475862a15d4b", "relation": "powered_by", "weight": null, "all_weights": {}, "relationship_type": "powered_by", "edge_info": {"source_node_id": "6fdb37d4-ae27-5a1a-9f7a-03f5036247ca", "target_node_id": "f7dc5ef7-3d2d-50c7-9edc-475862a15d4b", "relationship_name": "powered_by", "updated_at": "2026-04-02 09:04:34", "relationship_type": "powered_by", "edge_object_id": "6022fba6-4ddb-52b5-828a-1e6732ac3c38", "feedback_weight": 0.5}}, {"source": "f7dc5ef7-3d2d-50c7-9edc-475862a15d4b", "target": "65c71de3-4c23-5f28-8e07-fc7428d1e0c4", "relation": "is_a", "weight": null, "all_weights": {}, "relationship_type": null, "edge_info": {"source_node_id": "f7dc5ef7-3d2d-50c7-9edc-475862a15d4b", "target_node_id": "65c71de3-4c23-5f28-8e07-fc7428d1e0c4", "relationship_name": "is_a", "updated_at": "2026-04-02 09:04:34", "edge_object_id": "f7e85267-fe05-5afe-85d7-c785e0d11ada", "feedback_weight": 0.5}}, {"source": "515e93c6-3782-59db-96be-ad5b8cf872a5", "target": "d072ba0f-e1a9-58bf-9974-e1802adc8134", "relation": "is_a", "weight": null, "all_weights": {}, "relationship_type": null, "edge_info": {"source_node_id": "515e93c6-3782-59db-96be-ad5b8cf872a5", "target_node_id": "d072ba0f-e1a9-58bf-9974-e1802adc8134", "relationship_name": "is_a", "updated_at": "2026-04-02 09:04:34", "edge_object_id": "15f9348a-53eb-5b38-bab9-ec95ef9ab29e", "feedback_weight": 0.5}}, {"source": "515e93c6-3782-59db-96be-ad5b8cf872a5", "target": "fe01cac2-faf3-51b4-8e43-19979f276efa", "relation": "has_role", "weight": null, "all_weights": {}, "relationship_type": "has_role", "edge_info": {"source_node_id": "515e93c6-3782-59db-96be-ad5b8cf872a5", "target_node_id": "fe01cac2-faf3-51b4-8e43-19979f276efa", "relationship_name": "has_role", "updated_at": "2026-04-02 09:04:34", "relationship_type": "has_role", "edge_object_id": "479a0d72-4d76-5c8c-b1b4-eb75d96f18b2", "feedback_weight": 0.5}}, {"source": "515e93c6-3782-59db-96be-ad5b8cf872a5", "target": "346f1ce4-0869-56a1-891a-a99af46c348a", "relation": "member_of", "weight": null, "all_weights": {}, "relationship_type": "member_of", "edge_info": {"source_node_id": "515e93c6-3782-59db-96be-ad5b8cf872a5", "target_node_id": "346f1ce4-0869-56a1-891a-a99af46c348a", "relationship_name": "member_of", "updated_at": "2026-04-02 09:04:34", "relationship_type": "member_of", "edge_object_id": "96bbb871-f24b-5cab-af5d-235c635263e6", "feedback_weight": 0.5}}, {"source": "515e93c6-3782-59db-96be-ad5b8cf872a5", "target": "6fdb37d4-ae27-5a1a-9f7a-03f5036247ca", "relation": "works_on", "weight": null, "all_weights": {}, "relationship_type": "works_on", "edge_info": {"source_node_id": "515e93c6-3782-59db-96be-ad5b8cf872a5", "target_node_id": "6fdb37d4-ae27-5a1a-9f7a-03f5036247ca", "relationship_name": "works_on", "updated_at": "2026-04-02 09:04:34", "relationship_type": "works_on", "edge_object_id": "d6a1028d-105e-5e03-91dc-bf92056ca54f", "feedback_weight": 0.5}}, {"source": "fe01cac2-faf3-51b4-8e43-19979f276efa", "target": "09451c3f-999a-5c73-94d3-0d9dd38a58b1", "relation": "is_a", "weight": null, "all_weights": {}, "relationship_type": null, "edge_info": {"source_node_id": "fe01cac2-faf3-51b4-8e43-19979f276efa", "target_node_id": "09451c3f-999a-5c73-94d3-0d9dd38a58b1", "relationship_name": "is_a", "updated_at": "2026-04-02 09:04:34", "edge_object_id": "23543964-459b-5b7a-81da-9c350037d17a", "feedback_weight": 0.5}}, {"source": "80370ebb-d9b5-5f12-a3fb-db3631157840", "target": "d072ba0f-e1a9-58bf-9974-e1802adc8134", "relation": "is_a", "weight": null, "all_weights": {}, "relationship_type": null, "edge_info": {"source_node_id": "80370ebb-d9b5-5f12-a3fb-db3631157840", "target_node_id": "d072ba0f-e1a9-58bf-9974-e1802adc8134", "relationship_name": "is_a", "updated_at": "2026-04-02 09:04:34", "edge_object_id": "4b6899b3-7bcb-50ff-a94c-644ea92b4bae", "feedback_weight": 0.5}}, {"source": "80370ebb-d9b5-5f12-a3fb-db3631157840", "target": "7df9e2f4-b48b-57ae-96d0-df86968624b8", "relation": "has_role", "weight": null, "all_weights": {}, "relationship_type": "has_role", "edge_info": {"source_node_id": "80370ebb-d9b5-5f12-a3fb-db3631157840", "target_node_id": "7df9e2f4-b48b-57ae-96d0-df86968624b8", "relationship_name": "has_role", "updated_at": "2026-04-02 09:04:34", "relationship_type": "has_role", "edge_object_id": "e502ba55-29b0-5f89-93b8-35ec72ed2df0", "feedback_weight": 0.5}}, {"source": "80370ebb-d9b5-5f12-a3fb-db3631157840", "target": "346f1ce4-0869-56a1-891a-a99af46c348a", "relation": "member_of", "weight": null, "all_weights": {}, "relationship_type": "member_of", "edge_info": {"source_node_id": "80370ebb-d9b5-5f12-a3fb-db3631157840", "target_node_id": "346f1ce4-0869-56a1-891a-a99af46c348a", "relationship_name": "member_of", "updated_at": "2026-04-02 09:04:34", "relationship_type": "member_of", "edge_object_id": "e09f88bd-3ea6-5f93-8105-08cbf40a7230", "feedback_weight": 0.5}}, {"source": "80370ebb-d9b5-5f12-a3fb-db3631157840", "target": "6fdb37d4-ae27-5a1a-9f7a-03f5036247ca", "relation": "works_on", "weight": null, "all_weights": {}, "relationship_type": "works_on", "edge_info": {"source_node_id": "80370ebb-d9b5-5f12-a3fb-db3631157840", "target_node_id": "6fdb37d4-ae27-5a1a-9f7a-03f5036247ca", "relationship_name": "works_on", "updated_at": "2026-04-02 09:04:34", "relationship_type": "works_on", "edge_object_id": "745624d7-ca77-5e24-9722-2ab00dc43b4e", "feedback_weight": 0.5}}, {"source": "7df9e2f4-b48b-57ae-96d0-df86968624b8", "target": "09451c3f-999a-5c73-94d3-0d9dd38a58b1", "relation": "is_a", "weight": null, "all_weights": {}, "relationship_type": null, "edge_info": {"source_node_id": "7df9e2f4-b48b-57ae-96d0-df86968624b8", "target_node_id": "09451c3f-999a-5c73-94d3-0d9dd38a58b1", "relationship_name": "is_a", "updated_at": "2026-04-02 09:04:34", "edge_object_id": "a9782d8f-5a71-599d-9e26-8615e794ef1e", "feedback_weight": 0.5}}, {"source": "d39e745b-8b1b-5196-a9bd-529792880b24", "target": "37e1b646-e036-5954-b73d-73391dbe03f9", "relation": "made_from", "weight": null, "all_weights": {}, "relationship_type": null, "edge_info": {"source_node_id": "d39e745b-8b1b-5196-a9bd-529792880b24", "target_node_id": "37e1b646-e036-5954-b73d-73391dbe03f9", "relationship_name": "made_from", "updated_at": "2026-04-02 09:04:34", "edge_object_id": "d690dea4-b8f1-544b-804a-a29c69193f00", "feedback_weight": 0.5}}, {"source": "37e1b646-e036-5954-b73d-73391dbe03f9", "target": "d4211405-855c-5dec-84bd-7209d88a5766", "relation": "is_part_of", "weight": null, "all_weights": {}, "relationship_type": null, "edge_info": {"source_node_id": "37e1b646-e036-5954-b73d-73391dbe03f9", "target_node_id": "d4211405-855c-5dec-84bd-7209d88a5766", "relationship_name": "is_part_of", "updated_at": "2026-04-02 09:04:34", "edge_object_id": "bfd43129-3b87-521c-aafc-1b8ba55771ea", "feedback_weight": 0.5}}, {"source": "37e1b646-e036-5954-b73d-73391dbe03f9", "target": "2d09f34b-aee1-5d32-a2f9-23eb7ed48b24", "relation": "contains", "weight": null, "all_weights": {}, "relationship_type": "contains", "edge_info": {"source_node_id": "37e1b646-e036-5954-b73d-73391dbe03f9", "target_node_id": "2d09f34b-aee1-5d32-a2f9-23eb7ed48b24", "relationship_name": "contains", "updated_at": "2026-04-02 09:04:34", "relationship_type": "contains", "edge_text": "relationship_name: contains; entity_name: cognee; entity_description: An open-source memory for AI agents that builds a knowledge engine to transform raw data into a persistent, rich, and traceable memory searchable by meaning and relationships.", "edge_object_id": "2c69eb6e-73dd-5df2-9ec2-8f9d20e316eb", "feedback_weight": 0.5}}, {"source": "37e1b646-e036-5954-b73d-73391dbe03f9", "target": "d8b992b3-ebdc-52a4-9913-9e1aea9a47f8", "relation": "contains", "weight": null, "all_weights": {}, "relationship_type": "contains", "edge_info": {"source_node_id": "37e1b646-e036-5954-b73d-73391dbe03f9", "target_node_id": "d8b992b3-ebdc-52a4-9913-9e1aea9a47f8", "relationship_name": "contains", "updated_at": "2026-04-02 09:04:34", "relationship_type": "contains", "edge_text": "relationship_name: contains; entity_name: knowledge engine; entity_description: A system that transforms raw data (for example, unstructured documents and relational databases) into persistent, rich, and traceable memory.", "edge_object_id": "b9e891b2-8617-56dc-a1a1-ceb8c3d07fe3", "feedback_weight": 0.5}}, {"source": "37e1b646-e036-5954-b73d-73391dbe03f9", "target": "0a6f4624-d50e-5989-ba18-ddab839f5554", "relation": "contains", "weight": null, "all_weights": {}, "relationship_type": "contains", "edge_info": {"source_node_id": "37e1b646-e036-5954-b73d-73391dbe03f9", "target_node_id": "0a6f4624-d50e-5989-ba18-ddab839f5554", "relationship_name": "contains", "updated_at": "2026-04-02 09:04:34", "relationship_type": "contains", "edge_text": "relationship_name: contains; entity_name: raw data; entity_description: Source inputs such as unstructured documents and relational databases that are transformed by the knowledge engine.", "edge_object_id": "97187fbd-bffe-5df1-9ef4-c24273bee9f8", "feedback_weight": 0.5}}, {"source": "37e1b646-e036-5954-b73d-73391dbe03f9", "target": "f89d185b-5df9-5fc6-84a7-35931b380405", "relation": "contains", "weight": null, "all_weights": {}, "relationship_type": "contains", "edge_info": {"source_node_id": "37e1b646-e036-5954-b73d-73391dbe03f9", "target_node_id": "f89d185b-5df9-5fc6-84a7-35931b380405", "relationship_name": "contains", "updated_at": "2026-04-02 09:04:34", "relationship_type": "contains", "edge_text": "relationship_name: contains; entity_name: unstructured documents; entity_description: An example of raw data, e.g., free-form text documents, articles, and reports.", "edge_object_id": "14eca5ba-27a4-5aa3-9bc4-421f6333a38d", "feedback_weight": 0.5}}, {"source": "37e1b646-e036-5954-b73d-73391dbe03f9", "target": "9d84ec4f-0968-52d0-bd6d-2a4c1b07490d", "relation": "contains", "weight": null, "all_weights": {}, "relationship_type": "contains", "edge_info": {"source_node_id": "37e1b646-e036-5954-b73d-73391dbe03f9", "target_node_id": "9d84ec4f-0968-52d0-bd6d-2a4c1b07490d", "relationship_name": "contains", "updated_at": "2026-04-02 09:04:34", "relationship_type": "contains", "edge_text": "relationship_name: contains; entity_name: relational databases; entity_description: An example of raw data stored in structured database systems.", "edge_object_id": "e06ba8b5-720e-5f7d-ad54-3e895e29ad34", "feedback_weight": 0.5}}, {"source": "37e1b646-e036-5954-b73d-73391dbe03f9", "target": "55d2ac3c-0027-5294-b45f-272dddc1a8ad", "relation": "contains", "weight": null, "all_weights": {}, "relationship_type": "contains", "edge_info": {"source_node_id": "37e1b646-e036-5954-b73d-73391dbe03f9", "target_node_id": "55d2ac3c-0027-5294-b45f-272dddc1a8ad", "relationship_name": "contains", "updated_at": "2026-04-02 09:04:34", "relationship_type": "contains", "edge_text": "relationship_name: contains; entity_name: persistent memory; entity_description: Stored memory that endures across sessions and retains rich, traceable information.", "edge_object_id": "9dd3dc06-2a6d-5374-aa79-0f2d8705b7e5", "feedback_weight": 0.5}}, {"source": "37e1b646-e036-5954-b73d-73391dbe03f9", "target": "470d1242-e936-549e-bb35-2fe0188857dd", "relation": "contains", "weight": null, "all_weights": {}, "relationship_type": "contains", "edge_info": {"source_node_id": "37e1b646-e036-5954-b73d-73391dbe03f9", "target_node_id": "470d1242-e936-549e-bb35-2fe0188857dd", "relationship_name": "contains", "updated_at": "2026-04-02 09:04:34", "relationship_type": "contains", "edge_text": "relationship_name: contains; entity_name: meaning and relationships; entity_description: Semantic and relational aspects used to search and retrieve information from the persistent memory.", "edge_object_id": "be709b79-e440-5cf6-bd5e-95d27e579699", "feedback_weight": 0.5}}, {"source": "37e1b646-e036-5954-b73d-73391dbe03f9", "target": "968213f1-6ddc-5155-89d4-6df7c144a4a1", "relation": "contains", "weight": null, "all_weights": {}, "relationship_type": "contains", "edge_info": {"source_node_id": "37e1b646-e036-5954-b73d-73391dbe03f9", "target_node_id": "968213f1-6ddc-5155-89d4-6df7c144a4a1", "relationship_name": "contains", "updated_at": "2026-04-02 09:04:34", "relationship_type": "contains", "edge_text": "relationship_name: contains; entity_name: ai agents; entity_description: Autonomous systems or programs that use persistent memory like Cognee.", "edge_object_id": "97151938-0e2d-5e3c-a9c4-6350b51cc25a", "feedback_weight": 0.5}}, {"source": "37e1b646-e036-5954-b73d-73391dbe03f9", "target": "2cee890e-bebd-5809-94ae-ad0f2f9774c8", "relation": "contains", "weight": null, "all_weights": {}, "relationship_type": "contains", "edge_info": {"source_node_id": "37e1b646-e036-5954-b73d-73391dbe03f9", "target_node_id": "2cee890e-bebd-5809-94ae-ad0f2f9774c8", "relationship_name": "contains", "updated_at": "2026-04-02 09:04:34", "relationship_type": "contains", "edge_text": "relationship_name: contains; entity_name: open-source; entity_description: Software with source code that is publicly available.", "edge_object_id": "60ddaf51-de70-516b-807e-9e5981e60c1c", "feedback_weight": 0.5}}, {"source": "2d09f34b-aee1-5d32-a2f9-23eb7ed48b24", "target": "2d66edc2-1e14-55ab-8304-680b514a597a", "relation": "is_a", "weight": null, "all_weights": {}, "relationship_type": null, "edge_info": {"source_node_id": "2d09f34b-aee1-5d32-a2f9-23eb7ed48b24", "target_node_id": "2d66edc2-1e14-55ab-8304-680b514a597a", "relationship_name": "is_a", "updated_at": "2026-04-02 09:04:34", "edge_object_id": "811370df-e803-5ca1-9bb3-91585f9b4f74", "feedback_weight": 0.5}}, {"source": "2d09f34b-aee1-5d32-a2f9-23eb7ed48b24", "target": "d8b992b3-ebdc-52a4-9913-9e1aea9a47f8", "relation": "builds", "weight": null, "all_weights": {}, "relationship_type": "builds", "edge_info": {"source_node_id": "2d09f34b-aee1-5d32-a2f9-23eb7ed48b24", "target_node_id": "d8b992b3-ebdc-52a4-9913-9e1aea9a47f8", "relationship_name": "builds", "updated_at": "2026-04-02 09:04:34", "relationship_type": "builds", "edge_object_id": "9edf1ba4-25c9-5440-ba59-d9c5f4c586e2", "feedback_weight": 0.5}}, {"source": "2d09f34b-aee1-5d32-a2f9-23eb7ed48b24", "target": "968213f1-6ddc-5155-89d4-6df7c144a4a1", "relation": "for_agents", "weight": null, "all_weights": {}, "relationship_type": "for_agents", "edge_info": {"source_node_id": "2d09f34b-aee1-5d32-a2f9-23eb7ed48b24", "target_node_id": "968213f1-6ddc-5155-89d4-6df7c144a4a1", "relationship_name": "for_agents", "updated_at": "2026-04-02 09:04:34", "relationship_type": "for_agents", "edge_object_id": "e182aedd-ae73-5179-99bc-80e6d43c6a34", "feedback_weight": 0.5}}, {"source": "2d09f34b-aee1-5d32-a2f9-23eb7ed48b24", "target": "2cee890e-bebd-5809-94ae-ad0f2f9774c8", "relation": "is_open_source", "weight": null, "all_weights": {}, "relationship_type": "is_open_source", "edge_info": {"source_node_id": "2d09f34b-aee1-5d32-a2f9-23eb7ed48b24", "target_node_id": "2cee890e-bebd-5809-94ae-ad0f2f9774c8", "relationship_name": "is_open_source", "updated_at": "2026-04-02 09:04:34", "relationship_type": "is_open_source", "edge_object_id": "bb27a228-e4d5-594d-a7b3-99f87e9e12ac", "feedback_weight": 0.5}}, {"source": "d8b992b3-ebdc-52a4-9913-9e1aea9a47f8", "target": "dd9713b7-dc20-5101-aad0-1c4216811147", "relation": "is_a", "weight": null, "all_weights": {}, "relationship_type": null, "edge_info": {"source_node_id": "d8b992b3-ebdc-52a4-9913-9e1aea9a47f8", "target_node_id": "dd9713b7-dc20-5101-aad0-1c4216811147", "relationship_name": "is_a", "updated_at": "2026-04-02 09:04:34", "edge_object_id": "aca49d40-4330-571e-9184-25c5c261240b", "feedback_weight": 0.5}}, {"source": "d8b992b3-ebdc-52a4-9913-9e1aea9a47f8", "target": "0a6f4624-d50e-5989-ba18-ddab839f5554", "relation": "transforms", "weight": null, "all_weights": {}, "relationship_type": "transforms", "edge_info": {"source_node_id": "d8b992b3-ebdc-52a4-9913-9e1aea9a47f8", "target_node_id": "0a6f4624-d50e-5989-ba18-ddab839f5554", "relationship_name": "transforms", "updated_at": "2026-04-02 09:04:34", "relationship_type": "transforms", "edge_object_id": "78722202-d0b0-5939-9795-3984560c8bbe", "feedback_weight": 0.5}}, {"source": "d8b992b3-ebdc-52a4-9913-9e1aea9a47f8", "target": "55d2ac3c-0027-5294-b45f-272dddc1a8ad", "relation": "produces", "weight": null, "all_weights": {}, "relationship_type": "produces", "edge_info": {"source_node_id": "d8b992b3-ebdc-52a4-9913-9e1aea9a47f8", "target_node_id": "55d2ac3c-0027-5294-b45f-272dddc1a8ad", "relationship_name": "produces", "updated_at": "2026-04-02 09:04:34", "relationship_type": "produces", "edge_object_id": "1942a476-17ab-523c-aa2f-0f537c4c4a80", "feedback_weight": 0.5}}, {"source": "0a6f4624-d50e-5989-ba18-ddab839f5554", "target": "4ed5a0c7-2efb-52d1-9734-06a8ba225c94", "relation": "is_a", "weight": null, "all_weights": {}, "relationship_type": null, "edge_info": {"source_node_id": "0a6f4624-d50e-5989-ba18-ddab839f5554", "target_node_id": "4ed5a0c7-2efb-52d1-9734-06a8ba225c94", "relationship_name": "is_a", "updated_at": "2026-04-02 09:04:34", "edge_object_id": "11d47d94-e85b-584c-ae9d-93fe9ab47f08", "feedback_weight": 0.5}}, {"source": "0a6f4624-d50e-5989-ba18-ddab839f5554", "target": "f89d185b-5df9-5fc6-84a7-35931b380405", "relation": "includes", "weight": null, "all_weights": {}, "relationship_type": "includes", "edge_info": {"source_node_id": "0a6f4624-d50e-5989-ba18-ddab839f5554", "target_node_id": "f89d185b-5df9-5fc6-84a7-35931b380405", "relationship_name": "includes", "updated_at": "2026-04-02 09:04:34", "relationship_type": "includes", "edge_object_id": "9cf3a4b4-cb17-54cc-9373-cb1515d62f9e", "feedback_weight": 0.5}}, {"source": "0a6f4624-d50e-5989-ba18-ddab839f5554", "target": "9d84ec4f-0968-52d0-bd6d-2a4c1b07490d", "relation": "includes", "weight": null, "all_weights": {}, "relationship_type": "includes", "edge_info": {"source_node_id": "0a6f4624-d50e-5989-ba18-ddab839f5554", "target_node_id": "9d84ec4f-0968-52d0-bd6d-2a4c1b07490d", "relationship_name": "includes", "updated_at": "2026-04-02 09:04:34", "relationship_type": "includes", "edge_object_id": "579a3648-4b1a-541e-bb05-55a2f0662da2", "feedback_weight": 0.5}}, {"source": "f89d185b-5df9-5fc6-84a7-35931b380405", "target": "4ed5a0c7-2efb-52d1-9734-06a8ba225c94", "relation": "is_a", "weight": null, "all_weights": {}, "relationship_type": null, "edge_info": {"source_node_id": "f89d185b-5df9-5fc6-84a7-35931b380405", "target_node_id": "4ed5a0c7-2efb-52d1-9734-06a8ba225c94", "relationship_name": "is_a", "updated_at": "2026-04-02 09:04:34", "edge_object_id": "ac803953-5ad6-5305-af10-7f717bb2f8db", "feedback_weight": 0.5}}, {"source": "9d84ec4f-0968-52d0-bd6d-2a4c1b07490d", "target": "4ed5a0c7-2efb-52d1-9734-06a8ba225c94", "relation": "is_a", "weight": null, "all_weights": {}, "relationship_type": null, "edge_info": {"source_node_id": "9d84ec4f-0968-52d0-bd6d-2a4c1b07490d", "target_node_id": "4ed5a0c7-2efb-52d1-9734-06a8ba225c94", "relationship_name": "is_a", "updated_at": "2026-04-02 09:04:34", "edge_object_id": "5bb10fbf-fd98-5ac4-be03-39e739eed872", "feedback_weight": 0.5}}, {"source": "55d2ac3c-0027-5294-b45f-272dddc1a8ad", "target": "dd9713b7-dc20-5101-aad0-1c4216811147", "relation": "is_a", "weight": null, "all_weights": {}, "relationship_type": null, "edge_info": {"source_node_id": "55d2ac3c-0027-5294-b45f-272dddc1a8ad", "target_node_id": "dd9713b7-dc20-5101-aad0-1c4216811147", "relationship_name": "is_a", "updated_at": "2026-04-02 09:04:34", "edge_object_id": "2458218d-c688-501e-8506-a8573a18684b", "feedback_weight": 0.5}}, {"source": "55d2ac3c-0027-5294-b45f-272dddc1a8ad", "target": "470d1242-e936-549e-bb35-2fe0188857dd", "relation": "searchable_by", "weight": null, "all_weights": {}, "relationship_type": "searchable_by", "edge_info": {"source_node_id": "55d2ac3c-0027-5294-b45f-272dddc1a8ad", "target_node_id": "470d1242-e936-549e-bb35-2fe0188857dd", "relationship_name": "searchable_by", "updated_at": "2026-04-02 09:04:34", "relationship_type": "searchable_by", "edge_object_id": "3756ef80-68ad-52bb-ae3a-aafe070f6b86", "feedback_weight": 0.5}}, {"source": "470d1242-e936-549e-bb35-2fe0188857dd", "target": "dd9713b7-dc20-5101-aad0-1c4216811147", "relation": "is_a", "weight": null, "all_weights": {}, "relationship_type": null, "edge_info": {"source_node_id": "470d1242-e936-549e-bb35-2fe0188857dd", "target_node_id": "dd9713b7-dc20-5101-aad0-1c4216811147", "relationship_name": "is_a", "updated_at": "2026-04-02 09:04:34", "edge_object_id": "1897daba-2734-5a03-9cc3-882588a8bf19", "feedback_weight": 0.5}}, {"source": "968213f1-6ddc-5155-89d4-6df7c144a4a1", "target": "5f6d6fc0-e6aa-5365-a4a0-98d6fa3af190", "relation": "is_a", "weight": null, "all_weights": {}, "relationship_type": null, "edge_info": {"source_node_id": "968213f1-6ddc-5155-89d4-6df7c144a4a1", "target_node_id": "5f6d6fc0-e6aa-5365-a4a0-98d6fa3af190", "relationship_name": "is_a", "updated_at": "2026-04-02 09:04:34", "edge_object_id": "e6b24dcc-ad47-529e-980e-803082e57a65", "feedback_weight": 0.5}}, {"source": "2cee890e-bebd-5809-94ae-ad0f2f9774c8", "target": "dd9713b7-dc20-5101-aad0-1c4216811147", "relation": "is_a", "weight": null, "all_weights": {}, "relationship_type": null, "edge_info": {"source_node_id": "2cee890e-bebd-5809-94ae-ad0f2f9774c8", "target_node_id": "dd9713b7-dc20-5101-aad0-1c4216811147", "relationship_name": "is_a", "updated_at": "2026-04-02 09:04:34", "edge_object_id": "a8cbc957-7152-5bf3-ab73-1fef5470e909", "feedback_weight": 0.5}}, {"source": "025d8100-e0af-509a-a6fe-64e37e8200fd", "target": "7404fe0d-4620-594d-b9f7-bf0cb143e7c0", "relation": "made_from", "weight": null, "all_weights": {}, "relationship_type": null, "edge_info": {"source_node_id": "025d8100-e0af-509a-a6fe-64e37e8200fd", "target_node_id": "7404fe0d-4620-594d-b9f7-bf0cb143e7c0", "relationship_name": "made_from", "updated_at": "2026-04-02 09:04:44", "edge_object_id": "35c6a651-073a-5eef-8b3f-24b127003d54", "feedback_weight": 0.5}}, {"source": "7404fe0d-4620-594d-b9f7-bf0cb143e7c0", "target": "e116f5f3-7f9d-5c06-8159-096f75a892fc", "relation": "is_part_of", "weight": null, "all_weights": {}, "relationship_type": null, "edge_info": {"source_node_id": "7404fe0d-4620-594d-b9f7-bf0cb143e7c0", "target_node_id": "e116f5f3-7f9d-5c06-8159-096f75a892fc", "relationship_name": "is_part_of", "updated_at": "2026-04-02 09:04:44", "edge_object_id": "9bf6ce00-f0f3-5e23-b384-d229b5e21bf8", "feedback_weight": 0.5}}, {"source": "7404fe0d-4620-594d-b9f7-bf0cb143e7c0", "target": "2bdd3deb-07d8-5413-a56d-1643e3ceb48b", "relation": "contains", "weight": null, "all_weights": {}, "relationship_type": "contains", "edge_info": {"source_node_id": "7404fe0d-4620-594d-b9f7-bf0cb143e7c0", "target_node_id": "2bdd3deb-07d8-5413-a56d-1643e3ceb48b", "relationship_name": "contains", "updated_at": "2026-04-02 09:04:44", "relationship_type": "contains", "edge_text": "relationship_name: contains; entity_name: haystack; entity_description: Open-source LLM framework by deepset for building production-ready RAG pipelines, agents, and search systems.", "edge_object_id": "fc2f01d3-0c26-5d39-bdcd-1dc28305e6dd", "feedback_weight": 0.5}}, {"source": "7404fe0d-4620-594d-b9f7-bf0cb143e7c0", "target": "126df7ec-d0db-53ea-bc88-1bafd84c8646", "relation": "contains", "weight": null, "all_weights": {}, "relationship_type": "contains", "edge_info": {"source_node_id": "7404fe0d-4620-594d-b9f7-bf0cb143e7c0", "target_node_id": "126df7ec-d0db-53ea-bc88-1bafd84c8646", "relationship_name": "contains", "updated_at": "2026-04-02 09:04:44", "relationship_type": "contains", "edge_text": "relationship_name: contains; entity_name: deepset; entity_description: Organization that created Haystack.", "edge_object_id": "01ccba12-cb8c-570e-b5e7-5387f942ee54", "feedback_weight": 0.5}}, {"source": "7404fe0d-4620-594d-b9f7-bf0cb143e7c0", "target": "827e1c0c-0b6e-5e84-a5a6-fd221d3314dd", "relation": "contains", "weight": null, "all_weights": {}, "relationship_type": "contains", "edge_info": {"source_node_id": "7404fe0d-4620-594d-b9f7-bf0cb143e7c0", "target_node_id": "827e1c0c-0b6e-5e84-a5a6-fd221d3314dd", "relationship_name": "contains", "updated_at": "2026-04-02 09:04:44", "relationship_type": "contains", "edge_text": "relationship_name: contains; entity_name: llm framework; entity_description: A framework for working with large language models.", "edge_object_id": "a1227c81-00d3-5297-a328-aa7c6983adaf", "feedback_weight": 0.5}}, {"source": "7404fe0d-4620-594d-b9f7-bf0cb143e7c0", "target": "1ff6e485-672b-5976-8bea-f809f67fe245", "relation": "contains", "weight": null, "all_weights": {}, "relationship_type": "contains", "edge_info": {"source_node_id": "7404fe0d-4620-594d-b9f7-bf0cb143e7c0", "target_node_id": "1ff6e485-672b-5976-8bea-f809f67fe245", "relationship_name": "contains", "updated_at": "2026-04-02 09:04:44", "relationship_type": "contains", "edge_text": "relationship_name: contains; entity_name: rag; entity_description: Retrieval-Augmented Generation pipelines.", "edge_object_id": "7e1deb31-6909-5399-b48d-c32117ab076e", "feedback_weight": 0.5}}, {"source": "7404fe0d-4620-594d-b9f7-bf0cb143e7c0", "target": "ba1f1dac-e2fb-5464-914d-ff54b9b19787", "relation": "contains", "weight": null, "all_weights": {}, "relationship_type": "contains", "edge_info": {"source_node_id": "7404fe0d-4620-594d-b9f7-bf0cb143e7c0", "target_node_id": "ba1f1dac-e2fb-5464-914d-ff54b9b19787", "relationship_name": "contains", "updated_at": "2026-04-02 09:04:44", "relationship_type": "contains", "edge_text": "relationship_name: contains; entity_name: agents; entity_description: Agent systems that perform tasks using LLMs.", "edge_object_id": "13504968-446a-5106-8219-fb9a1c4d3b04", "feedback_weight": 0.5}}, {"source": "7404fe0d-4620-594d-b9f7-bf0cb143e7c0", "target": "a1a666e4-2070-59fd-95f7-c4c6178e89ba", "relation": "contains", "weight": null, "all_weights": {}, "relationship_type": "contains", "edge_info": {"source_node_id": "7404fe0d-4620-594d-b9f7-bf0cb143e7c0", "target_node_id": "a1a666e4-2070-59fd-95f7-c4c6178e89ba", "relationship_name": "contains", "updated_at": "2026-04-02 09:04:44", "relationship_type": "contains", "edge_text": "relationship_name: contains; entity_name: search systems; entity_description: Search systems built using LLMs and retrieval techniques.", "edge_object_id": "471ecb0e-5692-5825-a498-6ba6c6a2d101", "feedback_weight": 0.5}}, {"source": "7404fe0d-4620-594d-b9f7-bf0cb143e7c0", "target": "865e92ac-5a4f-5ba9-910f-d28ce255c4a2", "relation": "contains", "weight": null, "all_weights": {}, "relationship_type": "contains", "edge_info": {"source_node_id": "7404fe0d-4620-594d-b9f7-bf0cb143e7c0", "target_node_id": "865e92ac-5a4f-5ba9-910f-d28ce255c4a2", "relationship_name": "contains", "updated_at": "2026-04-02 09:04:44", "relationship_type": "contains", "edge_text": "relationship_name: contains; entity_name: component-based architecture; entity_description: Architecture where each step is a composable building block.", "edge_object_id": "603d5d9d-3af9-5e88-b5c1-76011e3f1a50", "feedback_weight": 0.5}}, {"source": "7404fe0d-4620-594d-b9f7-bf0cb143e7c0", "target": "59cf88c0-cb09-5f96-9252-5f5810981bcc", "relation": "contains", "weight": null, "all_weights": {}, "relationship_type": "contains", "edge_info": {"source_node_id": "7404fe0d-4620-594d-b9f7-bf0cb143e7c0", "target_node_id": "59cf88c0-cb09-5f96-9252-5f5810981bcc", "relationship_name": "contains", "updated_at": "2026-04-02 09:04:44", "relationship_type": "contains", "edge_text": "relationship_name: contains; entity_name: composable building block; entity_description: Modular unit representing a pipeline step that can be composed with others.", "edge_object_id": "715a0af0-d02d-533f-8f9d-196f598b8783", "feedback_weight": 0.5}}, {"source": "7404fe0d-4620-594d-b9f7-bf0cb143e7c0", "target": "f010bf52-6eb5-511f-bbed-cd5237545edd", "relation": "contains", "weight": null, "all_weights": {}, "relationship_type": "contains", "edge_info": {"source_node_id": "7404fe0d-4620-594d-b9f7-bf0cb143e7c0", "target_node_id": "f010bf52-6eb5-511f-bbed-cd5237545edd", "relationship_name": "contains", "updated_at": "2026-04-02 09:04:44", "relationship_type": "contains", "edge_text": "relationship_name: contains; entity_name: retrieval; entity_description: Retrieval step component used in Haystack pipelines.", "edge_object_id": "9e973f10-8dce-579d-afe3-f2e477e28651", "feedback_weight": 0.5}}, {"source": "7404fe0d-4620-594d-b9f7-bf0cb143e7c0", "target": "dba0457b-9aff-5eb6-8ccd-19f7c9ae4dfa", "relation": "contains", "weight": null, "all_weights": {}, "relationship_type": "contains", "edge_info": {"source_node_id": "7404fe0d-4620-594d-b9f7-bf0cb143e7c0", "target_node_id": "dba0457b-9aff-5eb6-8ccd-19f7c9ae4dfa", "relationship_name": "contains", "updated_at": "2026-04-02 09:04:44", "relationship_type": "contains", "edge_text": "relationship_name: contains; entity_name: generation; entity_description: Generation step component used in Haystack pipelines.", "edge_object_id": "ba58533c-8eff-57f9-8e16-9ab69cb3159f", "feedback_weight": 0.5}}, {"source": "7404fe0d-4620-594d-b9f7-bf0cb143e7c0", "target": "31777e8a-6d26-5454-9da8-766d9e049857", "relation": "contains", "weight": null, "all_weights": {}, "relationship_type": "contains", "edge_info": {"source_node_id": "7404fe0d-4620-594d-b9f7-bf0cb143e7c0", "target_node_id": "31777e8a-6d26-5454-9da8-766d9e049857", "relationship_name": "contains", "updated_at": "2026-04-02 09:04:44", "relationship_type": "contains", "edge_text": "relationship_name: contains; entity_name: pipeline; entity_description: Sequence of steps (for example retrieval and generation) used to process inputs and produce outputs.", "edge_object_id": "2cf04a88-fae6-5eea-bd05-40564cd98921", "feedback_weight": 0.5}}, {"source": "2bdd3deb-07d8-5413-a56d-1643e3ceb48b", "target": "36a32bd3-8880-547a-949b-8447477d1ef5", "relation": "is_a", "weight": null, "all_weights": {}, "relationship_type": null, "edge_info": {"source_node_id": "2bdd3deb-07d8-5413-a56d-1643e3ceb48b", "target_node_id": "36a32bd3-8880-547a-949b-8447477d1ef5", "relationship_name": "is_a", "updated_at": "2026-04-02 09:04:44", "edge_object_id": "af655100-33d0-5781-b50d-78c32087e2c1", "feedback_weight": 0.5}}, {"source": "2bdd3deb-07d8-5413-a56d-1643e3ceb48b", "target": "126df7ec-d0db-53ea-bc88-1bafd84c8646", "relation": "developed_by", "weight": null, "all_weights": {}, "relationship_type": "developed_by", "edge_info": {"source_node_id": "2bdd3deb-07d8-5413-a56d-1643e3ceb48b", "target_node_id": "126df7ec-d0db-53ea-bc88-1bafd84c8646", "relationship_name": "developed_by", "updated_at": "2026-04-02 09:04:44", "relationship_type": "developed_by", "edge_object_id": "ea5c2b01-f116-586f-b8ec-050aed54d274", "feedback_weight": 0.5}}, {"source": "2bdd3deb-07d8-5413-a56d-1643e3ceb48b", "target": "827e1c0c-0b6e-5e84-a5a6-fd221d3314dd", "relation": "is_a", "weight": null, "all_weights": {}, "relationship_type": "is_a", "edge_info": {"source_node_id": "2bdd3deb-07d8-5413-a56d-1643e3ceb48b", "target_node_id": "827e1c0c-0b6e-5e84-a5a6-fd221d3314dd", "relationship_name": "is_a", "updated_at": "2026-04-02 09:04:44", "relationship_type": "is_a", "edge_object_id": "df266f0d-566f-5160-99bc-38dd64b6aa87", "feedback_weight": 0.5}}, {"source": "2bdd3deb-07d8-5413-a56d-1643e3ceb48b", "target": "865e92ac-5a4f-5ba9-910f-d28ce255c4a2", "relation": "has_architecture", "weight": null, "all_weights": {}, "relationship_type": "has_architecture", "edge_info": {"source_node_id": "2bdd3deb-07d8-5413-a56d-1643e3ceb48b", "target_node_id": "865e92ac-5a4f-5ba9-910f-d28ce255c4a2", "relationship_name": "has_architecture", "updated_at": "2026-04-02 09:04:44", "relationship_type": "has_architecture", "edge_object_id": "6b3bf95c-1d54-521c-b618-9d250a1fcfa3", "feedback_weight": 0.5}}, {"source": "2bdd3deb-07d8-5413-a56d-1643e3ceb48b", "target": "1ff6e485-672b-5976-8bea-f809f67fe245", "relation": "used_for", "weight": null, "all_weights": {}, "relationship_type": "used_for", "edge_info": {"source_node_id": "2bdd3deb-07d8-5413-a56d-1643e3ceb48b", "target_node_id": "1ff6e485-672b-5976-8bea-f809f67fe245", "relationship_name": "used_for", "updated_at": "2026-04-02 09:04:44", "relationship_type": "used_for", "edge_object_id": "1c060aef-8b82-573e-a73e-ee7f6ff2513e", "feedback_weight": 0.5}}, {"source": "2bdd3deb-07d8-5413-a56d-1643e3ceb48b", "target": "ba1f1dac-e2fb-5464-914d-ff54b9b19787", "relation": "used_for", "weight": null, "all_weights": {}, "relationship_type": "used_for", "edge_info": {"source_node_id": "2bdd3deb-07d8-5413-a56d-1643e3ceb48b", "target_node_id": "ba1f1dac-e2fb-5464-914d-ff54b9b19787", "relationship_name": "used_for", "updated_at": "2026-04-02 09:04:44", "relationship_type": "used_for", "edge_object_id": "0d1bcb3a-dd29-576a-b468-7c38beb00179", "feedback_weight": 0.5}}, {"source": "2bdd3deb-07d8-5413-a56d-1643e3ceb48b", "target": "a1a666e4-2070-59fd-95f7-c4c6178e89ba", "relation": "used_for", "weight": null, "all_weights": {}, "relationship_type": "used_for", "edge_info": {"source_node_id": "2bdd3deb-07d8-5413-a56d-1643e3ceb48b", "target_node_id": "a1a666e4-2070-59fd-95f7-c4c6178e89ba", "relationship_name": "used_for", "updated_at": "2026-04-02 09:04:44", "relationship_type": "used_for", "edge_object_id": "ccd69904-f605-57a4-9eda-9f975012a9ef", "feedback_weight": 0.5}}, {"source": "126df7ec-d0db-53ea-bc88-1bafd84c8646", "target": "d3d7b6b4-9b0d-52e8-9e09-a9e9cf4b5a4d", "relation": "is_a", "weight": null, "all_weights": {}, "relationship_type": null, "edge_info": {"source_node_id": "126df7ec-d0db-53ea-bc88-1bafd84c8646", "target_node_id": "d3d7b6b4-9b0d-52e8-9e09-a9e9cf4b5a4d", "relationship_name": "is_a", "updated_at": "2026-04-02 09:04:44", "edge_object_id": "6625b79a-2dcc-5010-ba18-030b3753e856", "feedback_weight": 0.5}}, {"source": "827e1c0c-0b6e-5e84-a5a6-fd221d3314dd", "target": "dd9713b7-dc20-5101-aad0-1c4216811147", "relation": "is_a", "weight": null, "all_weights": {}, "relationship_type": null, "edge_info": {"source_node_id": "827e1c0c-0b6e-5e84-a5a6-fd221d3314dd", "target_node_id": "dd9713b7-dc20-5101-aad0-1c4216811147", "relationship_name": "is_a", "updated_at": "2026-04-02 09:04:44", "edge_object_id": "43d07cdb-3aa6-556a-bc78-40d1bf581ebd", "feedback_weight": 0.5}}, {"source": "865e92ac-5a4f-5ba9-910f-d28ce255c4a2", "target": "b581ee28-cf45-5ad5-813f-014e7e2d2312", "relation": "is_a", "weight": null, "all_weights": {}, "relationship_type": null, "edge_info": {"source_node_id": "865e92ac-5a4f-5ba9-910f-d28ce255c4a2", "target_node_id": "b581ee28-cf45-5ad5-813f-014e7e2d2312", "relationship_name": "is_a", "updated_at": "2026-04-02 09:04:44", "edge_object_id": "ff9a1084-ba1d-55a1-bf6f-6b70996da9e5", "feedback_weight": 0.5}}, {"source": "865e92ac-5a4f-5ba9-910f-d28ce255c4a2", "target": "59cf88c0-cb09-5f96-9252-5f5810981bcc", "relation": "emphasizes", "weight": null, "all_weights": {}, "relationship_type": "emphasizes", "edge_info": {"source_node_id": "865e92ac-5a4f-5ba9-910f-d28ce255c4a2", "target_node_id": "59cf88c0-cb09-5f96-9252-5f5810981bcc", "relationship_name": "emphasizes", "updated_at": "2026-04-02 09:04:44", "relationship_type": "emphasizes", "edge_object_id": "5d21670b-3b61-555e-a8aa-3f33b152ba14", "feedback_weight": 0.5}}, {"source": "865e92ac-5a4f-5ba9-910f-d28ce255c4a2", "target": "31777e8a-6d26-5454-9da8-766d9e049857", "relation": "used_to_build", "weight": null, "all_weights": {}, "relationship_type": "used_to_build", "edge_info": {"source_node_id": "865e92ac-5a4f-5ba9-910f-d28ce255c4a2", "target_node_id": "31777e8a-6d26-5454-9da8-766d9e049857", "relationship_name": "used_to_build", "updated_at": "2026-04-02 09:04:44", "relationship_type": "used_to_build", "edge_object_id": "049ce2da-d807-51bf-b393-182e5c39b50f", "feedback_weight": 0.5}}, {"source": "59cf88c0-cb09-5f96-9252-5f5810981bcc", "target": "dd9713b7-dc20-5101-aad0-1c4216811147", "relation": "is_a", "weight": null, "all_weights": {}, "relationship_type": null, "edge_info": {"source_node_id": "59cf88c0-cb09-5f96-9252-5f5810981bcc", "target_node_id": "dd9713b7-dc20-5101-aad0-1c4216811147", "relationship_name": "is_a", "updated_at": "2026-04-02 09:04:44", "edge_object_id": "2e6a26d1-6f71-5e0a-9da7-31fd26cdf107", "feedback_weight": 0.5}}, {"source": "59cf88c0-cb09-5f96-9252-5f5810981bcc", "target": "f010bf52-6eb5-511f-bbed-cd5237545edd", "relation": "includes_component", "weight": null, "all_weights": {}, "relationship_type": "includes_component", "edge_info": {"source_node_id": "59cf88c0-cb09-5f96-9252-5f5810981bcc", "target_node_id": "f010bf52-6eb5-511f-bbed-cd5237545edd", "relationship_name": "includes_component", "updated_at": "2026-04-02 09:04:44", "relationship_type": "includes_component", "edge_object_id": "aecc6168-47d0-5b69-aea5-f258659870e8", "feedback_weight": 0.5}}, {"source": "59cf88c0-cb09-5f96-9252-5f5810981bcc", "target": "dba0457b-9aff-5eb6-8ccd-19f7c9ae4dfa", "relation": "includes_component", "weight": null, "all_weights": {}, "relationship_type": "includes_component", "edge_info": {"source_node_id": "59cf88c0-cb09-5f96-9252-5f5810981bcc", "target_node_id": "dba0457b-9aff-5eb6-8ccd-19f7c9ae4dfa", "relationship_name": "includes_component", "updated_at": "2026-04-02 09:04:44", "relationship_type": "includes_component", "edge_object_id": "3f3c8620-5575-5b83-8b77-4e8aef41de7b", "feedback_weight": 0.5}}, {"source": "f010bf52-6eb5-511f-bbed-cd5237545edd", "target": "b283358b-c288-5ca1-a6e8-05bac88f7a6f", "relation": "is_a", "weight": null, "all_weights": {}, "relationship_type": null, "edge_info": {"source_node_id": "f010bf52-6eb5-511f-bbed-cd5237545edd", "target_node_id": "b283358b-c288-5ca1-a6e8-05bac88f7a6f", "relationship_name": "is_a", "updated_at": "2026-04-02 09:04:44", "edge_object_id": "838cd42b-13c4-57f7-b768-b229a019143a", "feedback_weight": 0.5}}, {"source": "dba0457b-9aff-5eb6-8ccd-19f7c9ae4dfa", "target": "b283358b-c288-5ca1-a6e8-05bac88f7a6f", "relation": "is_a", "weight": null, "all_weights": {}, "relationship_type": null, "edge_info": {"source_node_id": "dba0457b-9aff-5eb6-8ccd-19f7c9ae4dfa", "target_node_id": "b283358b-c288-5ca1-a6e8-05bac88f7a6f", "relationship_name": "is_a", "updated_at": "2026-04-02 09:04:44", "edge_object_id": "82c23f93-280c-5377-86f6-d48a3fdf4531", "feedback_weight": 0.5}}, {"source": "31777e8a-6d26-5454-9da8-766d9e049857", "target": "dd9713b7-dc20-5101-aad0-1c4216811147", "relation": "is_a", "weight": null, "all_weights": {}, "relationship_type": null, "edge_info": {"source_node_id": "31777e8a-6d26-5454-9da8-766d9e049857", "target_node_id": "dd9713b7-dc20-5101-aad0-1c4216811147", "relationship_name": "is_a", "updated_at": "2026-04-02 09:04:44", "edge_object_id": "6e91b59f-9e54-5cf2-bac5-328c460c0284", "feedback_weight": 0.5}}, {"source": "31777e8a-6d26-5454-9da8-766d9e049857", "target": "f010bf52-6eb5-511f-bbed-cd5237545edd", "relation": "includes_step", "weight": null, "all_weights": {}, "relationship_type": "includes_step", "edge_info": {"source_node_id": "31777e8a-6d26-5454-9da8-766d9e049857", "target_node_id": "f010bf52-6eb5-511f-bbed-cd5237545edd", "relationship_name": "includes_step", "updated_at": "2026-04-02 09:04:44", "relationship_type": "includes_step", "edge_object_id": "dddc6cd2-5f0c-5957-987f-a5b0ede7379c", "feedback_weight": 0.5}}, {"source": "31777e8a-6d26-5454-9da8-766d9e049857", "target": "dba0457b-9aff-5eb6-8ccd-19f7c9ae4dfa", "relation": "includes_step", "weight": null, "all_weights": {}, "relationship_type": "includes_step", "edge_info": {"source_node_id": "31777e8a-6d26-5454-9da8-766d9e049857", "target_node_id": "dba0457b-9aff-5eb6-8ccd-19f7c9ae4dfa", "relationship_name": "includes_step", "updated_at": "2026-04-02 09:04:44", "relationship_type": "includes_step", "edge_object_id": "e882e735-33f7-5a08-9b62-b98544bfd985", "feedback_weight": 0.5}}, {"source": "1ff6e485-672b-5976-8bea-f809f67fe245", "target": "dd9713b7-dc20-5101-aad0-1c4216811147", "relation": "is_a", "weight": null, "all_weights": {}, "relationship_type": null, "edge_info": {"source_node_id": "1ff6e485-672b-5976-8bea-f809f67fe245", "target_node_id": "dd9713b7-dc20-5101-aad0-1c4216811147", "relationship_name": "is_a", "updated_at": "2026-04-02 09:04:44", "edge_object_id": "e0ed68b9-add2-5ea0-ae17-48e4ddf92137", "feedback_weight": 0.5}}, {"source": "ba1f1dac-e2fb-5464-914d-ff54b9b19787", "target": "dd9713b7-dc20-5101-aad0-1c4216811147", "relation": "is_a", "weight": null, "all_weights": {}, "relationship_type": null, "edge_info": {"source_node_id": "ba1f1dac-e2fb-5464-914d-ff54b9b19787", "target_node_id": "dd9713b7-dc20-5101-aad0-1c4216811147", "relationship_name": "is_a", "updated_at": "2026-04-02 09:04:44", "edge_object_id": "de9289c4-841f-5edf-94e4-1ac522d1e270", "feedback_weight": 0.5}}, {"source": "a1a666e4-2070-59fd-95f7-c4c6178e89ba", "target": "dd9713b7-dc20-5101-aad0-1c4216811147", "relation": "is_a", "weight": null, "all_weights": {}, "relationship_type": null, "edge_info": {"source_node_id": "a1a666e4-2070-59fd-95f7-c4c6178e89ba", "target_node_id": "dd9713b7-dc20-5101-aad0-1c4216811147", "relationship_name": "is_a", "updated_at": "2026-04-02 09:04:44", "edge_object_id": "0dc1c5f6-0466-5dde-99df-dd25da19bf3a", "feedback_weight": 0.5}}]; var taskColors = {"classify_documents": "#db5656", "extract_chunks_from_documents": "#56db7d", "extract_graph_from_data": "#a456db", "summarize_text": "#dbca56"}; var pipelineColors = {"cognify_pipeline": "#db5656"}; var nodesetColors = {}; diff --git a/integrations/cognee/examples/README.md b/integrations/cognee/examples/README.md index b5210b64e5..d4ef44805b 100644 --- a/integrations/cognee/examples/README.md +++ b/integrations/cognee/examples/README.md @@ -5,24 +5,25 @@ Install the integration from the repository root: ```bash -pip install -e "integrations/cognee[memory]" +pip install -e "integrations/cognee" ``` -Set your LLM API key (required by cognee, default OpenAI API key) and ENABLE_BACKEND_ACCESS_CONTROL=False for simplicity: +Set your LLM API key (required by cognee, default OpenAI API key): To integrate other LLM providers and other configuration options, see [Cognee Documentation](https://docs.cognee.ai/getting-started/installation#environment-configuration). ```bash export LLM_API_KEY="sk-your-openai-api-key" -export ENABLE_BACKEND_ACCESS_CONTROL="False" ``` ## Examples ### Pipeline Demo (`demo_pipeline.py`) -Demonstrates `CogneeWriter` and `CogneeRetriever` in a Haystack pipeline: +Demonstrates batch document ingestion with `CogneeWriter` (auto_cognify disabled), +followed by a single `CogneeCognifier` pass, then retrieval with `CogneeRetriever`. +Also shows the same flow wired as a connected Haystack Pipeline. ```bash python integrations/cognee/examples/demo_pipeline.py @@ -30,7 +31,9 @@ python integrations/cognee/examples/demo_pipeline.py ### Memory Agent Demo (`demo_memory_agent.py`) -Demonstrates `CogneeMemoryStore` as a conversational memory backend: +Demonstrates `CogneeMemoryStore` with per-user memory scoping via `user_id`: +- Two users store private memories that are isolated from each other. +- A shared dataset is created and read access is granted across users. ```bash python integrations/cognee/examples/demo_memory_agent.py diff --git a/integrations/cognee/examples/demo_memory_agent.py b/integrations/cognee/examples/demo_memory_agent.py index 783b520b29..04b009a71f 100644 --- a/integrations/cognee/examples/demo_memory_agent.py +++ b/integrations/cognee/examples/demo_memory_agent.py @@ -1,71 +1,146 @@ #!/usr/bin/env python """ -Demo: Cognee as a Memory Backend for Haystack's Agent +Demo: Cognee as a Memory Backend with User-Scoped Access -Shows how to use CogneeMemoryStore with Haystack's experimental Agent -to give conversational memory backed by Cognee's knowledge engine. +Shows how CogneeMemoryStore supports per-user memory isolation via user_id, +matching the MemoryStore protocol pattern used by Haystack's experimental Agent. + +Two users (Alice and Bob) each store private memories. Then Alice creates a +shared dataset and grants Bob read access, demonstrating cross-user sharing. + +Note: This demo uses cognee's user management APIs directly for setup (creating +users, granting permissions). These are admin operations outside the Haystack +integration's scope. In production, user management would typically be handled +by the application layer or cognee's API server. Prerequisites: - pip install -e "integrations/cognee[memory]" + pip install -e "integrations/cognee" Set your LLM API key: export LLM_API_KEY="sk-..." """ import asyncio -import os -from cognee.api.v1.visualize.visualize import visualize_graph +import cognee +from cognee.modules.data.methods import get_authorized_existing_datasets +from cognee.modules.engine.operations.setup import setup +from cognee.modules.users.methods import create_user +from cognee.modules.users.permissions.methods import give_permission_on_dataset from haystack.dataclasses import ChatMessage from haystack_integrations.memory_stores.cognee import CogneeMemoryStore async def main(): - print("=== Cognee Memory Store Demo ===\n") - - store = CogneeMemoryStore(search_type="GRAPH_COMPLETION", top_k=5, dataset_name="agent_memory") - - # --- Step 1: Clear any previous memories --- - print("1. Clearing previous memories...") - store.delete_all_memories() - print(" Done.\n") - - # --- Step 2: Add some memories --- - print("2. Adding memories...") - messages = [ - ChatMessage.from_user( - "My name is Alice and I'm working on the Cognee-Haystack integration. The deadline is next Friday." - ), - ChatMessage.from_user( - "We decided to use GRAPH_COMPLETION as the default search type " - "because it retrieves the most relevant memories by graph traversal and vector search" - ), - ChatMessage.from_assistant( - "I'll remember that the deadline is next Friday and that GRAPH_COMPLETION " - "is the preferred search type for this project." - ), - ] - store.add_memories(messages=messages) - print(f" Added {len(messages)} messages as memories.\n") - - visualization_path = os.path.join(os.path.dirname(__file__), ".artifacts", "demo_memory_agent.html") - await visualize_graph(visualization_path) - - # --- Step 3: Search memories --- - queries = [ - "What is the project deadline?", - "Which search type should we use?", - "Who is working on the integration?", - ] - - for query in queries: - print(f"3. Searching memories: '{query}'") - results = store.search_memories(query=query, top_k=3) - print(f" Found {len(results)} memory(ies):") - for i, msg in enumerate(results, 1): - print(f" [{i}] {msg.text}") - print() + print("=== Cognee Memory Store — User Scoping Demo ===\n") + + # --- Setup: clean slate and create two users --- + print("Setup: Pruning all data and creating users...") + await cognee.prune.prune_data() + await cognee.prune.prune_system(metadata=True) + + # Re-create the database schema after pruning (prune_system drops all tables) + await setup() + + alice = await create_user("alice@example.com", "password", is_verified=True) + bob = await create_user("bob@example.com", "password", is_verified=True) + alice_id = str(alice.id) + bob_id = str(bob.id) + print(f" Created Alice (id={alice_id[:8]}...) and Bob (id={bob_id[:8]}...)\n") + + # ========================================================================= + # Part 1: Private memories — each user can only see their own + # ========================================================================= + print("--- Part 1: Private memories (user isolation) ---\n") + + alice_store = CogneeMemoryStore(search_type="GRAPH_COMPLETION", dataset_name="alice_notes") + bob_store = CogneeMemoryStore(search_type="GRAPH_COMPLETION", dataset_name="bob_notes") + + # Alice adds her private memories + print("Alice adds memories to 'alice_notes'...") + alice_store.add_memories( + messages=[ + ChatMessage.from_user("The project deadline is next Friday."), + ], + user_id=alice_id, + ) + print(" Done.\n") + + # Bob adds his private memories + print("Bob adds memories to 'bob_notes'...") + bob_store.add_memories( + messages=[ + ChatMessage.from_user("The client meeting is on Wednesday at 2pm."), + ChatMessage.from_user("The new API endpoint needs authentication."), + ], + user_id=bob_id, + ) + print(" Done.\n") + + # Alice searches her own store — should find results + print("Alice searches her own store for 'project deadline':") + results = alice_store.search_memories(query="What is the project deadline?", user_id=alice_id) + print(f" Found {len(results)} result(s)") + for i, msg in enumerate(results, 1): + print(f" [{i}] {msg.text}") + print() + + # Bob searches his own store — should find results + print("Bob searches his own store for 'client meeting':") + results = bob_store.search_memories(query="When is the client meeting?", user_id=bob_id) + print(f" Found {len(results)} result(s)") + for i, msg in enumerate(results, 1): + print(f" [{i}] {msg.text}") + print() + + # Alice searches Bob's store — should find nothing (no permission) + print("Alice tries to search Bob's store (no permission):") + results = bob_store.search_memories(query="When is the client meeting?", user_id=alice_id) + print(f" Found {len(results)} result(s) — access is isolated!\n") + + # Bob searches Alice's store — should find nothing (no permission) + print("Bob tries to search Alice's store (no permission):") + results = alice_store.search_memories(query="What is the project deadline?", user_id=bob_id) + print(f" Found {len(results)} result(s) — access is isolated!\n") + + # ========================================================================= + # Part 2: Shared dataset — Alice creates it, grants Bob read access + # ========================================================================= + print("--- Part 2: Shared dataset ---\n") + + shared_store = CogneeMemoryStore(search_type="GRAPH_COMPLETION", dataset_name="team_shared") + + # Alice adds to the shared dataset (she becomes the owner) + print("Alice adds memories to 'team_shared'...") + shared_store.add_memories( + messages=[ + ChatMessage.from_user("The team standup is every morning at 9am."), + ChatMessage.from_user("Our tech stack is Python, Haystack, and Cognee."), + ], + user_id=alice_id, + ) + print(" Done.\n") + + # Bob tries to search the shared store BEFORE getting permission — should find nothing + print("Bob tries to search 'team_shared' BEFORE permission:") + results = shared_store.search_memories(query="When is the team standup?", user_id=bob_id) + print(f" Found {len(results)} result(s) — no access yet.\n") + + # Grant Bob read permission on the shared dataset + print("Alice grants Bob read access to 'team_shared'...") + shared_datasets = await get_authorized_existing_datasets(["team_shared"], "read", alice) + shared_dataset_id = shared_datasets[0].id + await give_permission_on_dataset(bob, shared_dataset_id, "read") + print(" Done.\n") + + # Bob searches via the MemoryStore — the store automatically resolves shared datasets + print("Bob searches 'team_shared' AFTER getting read permission:") + results = shared_store.search_memories(query="When is the team standup?", user_id=bob_id) + print(f" Found {len(results)} result(s)") + for i, msg in enumerate(results, 1): + print(f" [{i}] {msg.text}") + print() print("=== Done ===") diff --git a/integrations/cognee/examples/demo_pipeline.py b/integrations/cognee/examples/demo_pipeline.py index edd4fd75e6..0a73053618 100644 --- a/integrations/cognee/examples/demo_pipeline.py +++ b/integrations/cognee/examples/demo_pipeline.py @@ -1,9 +1,19 @@ #!/usr/bin/env python """ -Demo: Cognee + Haystack Pipeline +Demo: Cognee + Haystack Pipeline — Writer, Cognifier, Retriever -Shows how to use CogneeWriter and CogneeRetriever in a Haystack pipeline -to ingest documents into Cognee's memory and search them. +Demonstrates two ingestion strategies with CogneeWriter: + +1. auto_cognify=True (default) — each writer.run() call adds documents AND + immediately cognifies them into the knowledge graph. Simple but slower + when ingesting many batches, because cognify runs after every add. + +2. auto_cognify=False + CogneeCognifier — documents are added quickly in + multiple batches without building the knowledge graph. Then CogneeCognifier + processes the entire dataset once. This is faster for bulk ingestion. + +Both strategies produce the same result: a searchable knowledge graph that +CogneeRetriever can query. Prerequisites: pip install -e "integrations/cognee" @@ -13,38 +23,38 @@ """ import asyncio -import os -from cognee.api.v1.visualize.visualize import visualize_graph +import cognee from haystack import Document, Pipeline +from haystack_integrations.components.connectors.cognee import CogneeCognifier from haystack_integrations.components.retrievers.cognee import CogneeRetriever from haystack_integrations.components.writers.cognee import CogneeWriter -SAMPLE_DOCUMENTS = [ +DOCS_BATCH_1 = [ Document( content=( - "Cognee is an open-source memory for AI agents. Cognee builts a knowledge engine" - "that transforms raw data (e.g., unstructured documents, relational databases, etc.)" - "into a persistent, rich, and traceable memory that is searchable by meaning and relationships." + "Cognee is an open-source memory for AI agents. It builds a knowledge engine " + "that transforms raw data into a persistent, rich, and traceable memory that is " + "searchable by meaning and relationships." ), - meta={"topic": "cognee"}, ), Document( content=( "Haystack is an open-source LLM framework by deepset for building production-ready " "RAG pipelines, agents, and search systems. It uses a component-based architecture " - "where each step (retrieval, generation, etc.) is a composable building block." + "where each step is a composable building block." ), - meta={"topic": "haystack"}, ), +] + +DOCS_BATCH_2 = [ Document( content=( "Knowledge graphs represent information as nodes (entities) and edges (relationships). " "They enable semantic search, reasoning, and discovery of hidden connections across " "large document collections." ), - meta={"topic": "knowledge_graphs"}, ), Document( content=( @@ -52,46 +62,113 @@ "and Carol (infrastructure). They are building a next-generation search platform " "powered by knowledge graphs and LLMs." ), - meta={"topic": "team"}, ), ] +SEARCH_QUERIES = [ + "What is Cognee and what does it do?", + "Who is on the engineering team at Acme Corp?", + "How do knowledge graphs work?", +] -async def main(): - print("=== Cognee + Haystack Pipeline Demo ===\n") - - # --- Indexing pipeline --- - print("1. Building indexing pipeline...") - indexing = Pipeline() - indexing.add_component("writer", CogneeWriter(dataset_name="demo", auto_cognify=True)) - - print(f"2. Indexing {len(SAMPLE_DOCUMENTS)} documents...") - result = indexing.run({"writer": {"documents": SAMPLE_DOCUMENTS}}) - print(f" Written: {result['writer']['documents_written']} documents\n") - - visualization_path = os.path.join(os.path.dirname(__file__), ".artifacts", "demo_pipeline.html") - await visualize_graph(visualization_path) - - # --- Query pipeline --- - print("3. Building query pipeline...") - querying = Pipeline() - querying.add_component("retriever", CogneeRetriever(search_type="GRAPH_COMPLETION", top_k=5)) - - queries = [ - "What is Cognee and what does it do?", - "Who is on the engineering team at Acme Corp?", - "How do knowledge graphs work?", - ] +def search_and_print(retriever, queries): for query in queries: - print(f"4. Searching: '{query}'") - result = querying.run({"retriever": {"query": query}}) - docs = result["retriever"]["documents"] + print(f" Query: '{query}'") + result = retriever.run(query=query) + docs = result["documents"] print(f" Found {len(docs)} result(s):") for i, doc in enumerate(docs, 1): print(f" [{i}] {doc.content}...") print() + +async def main(): + print("=== Cognee + Haystack Pipeline Demo ===\n") + + # ========================================================================= + # Part 1: auto_cognify=True — add + cognify on every call + # + # Each writer.run() both adds the documents AND cognifies the dataset. + # Simple for small ingestion, but cognify is the expensive step (calls + # the LLM to extract entities, build the graph, generate summaries). + # With N batches, cognify runs N times. + # ========================================================================= + print("--- Part 1: auto_cognify=True (add + cognify each batch) ---\n") + + await cognee.prune.prune_data() + await cognee.prune.prune_system(metadata=True) + + writer_auto = CogneeWriter(dataset_name="demo_auto", auto_cognify=True) + + print(f"1. Writing batch 1 ({len(DOCS_BATCH_1)} docs) — adds + cognifies...") + result = writer_auto.run(documents=DOCS_BATCH_1) + print(f" Written: {result['documents_written']} (cognify ran)\n") + + print(f"2. Writing batch 2 ({len(DOCS_BATCH_2)} docs) — adds + cognifies again...") + result = writer_auto.run(documents=DOCS_BATCH_2) + print(f" Written: {result['documents_written']} (cognify ran again)\n") + + print("3. Searching...\n") + retriever = CogneeRetriever(search_type="GRAPH_COMPLETION", dataset_name="demo_auto") + search_and_print(retriever, SEARCH_QUERIES) + + # ========================================================================= + # Part 2: auto_cognify=False + CogneeCognifier — batch add, cognify once + # + # Documents are added quickly without cognifying. Then CogneeCognifier + # processes everything in one pass. With N batches, cognify runs only once. + # ========================================================================= + print("--- Part 2: auto_cognify=False + CogneeCognifier (batch add, cognify once) ---\n") + + await cognee.prune.prune_data() + await cognee.prune.prune_system(metadata=True) + + writer_batch = CogneeWriter(dataset_name="demo_batch", auto_cognify=False) + + print(f"4. Writing batch 1 ({len(DOCS_BATCH_1)} docs) — add only, no cognify...") + result = writer_batch.run(documents=DOCS_BATCH_1) + print(f" Written: {result['documents_written']}\n") + + print(f"5. Writing batch 2 ({len(DOCS_BATCH_2)} docs) — add only, no cognify...") + result = writer_batch.run(documents=DOCS_BATCH_2) + print(f" Written: {result['documents_written']}\n") + + print("6. Cognifying the entire dataset in one pass...") + cognifier = CogneeCognifier(dataset_name="demo_batch") + result = cognifier.run() + print(f" Cognified: {result['cognified']}\n") + + print("7. Searching...\n") + retriever = CogneeRetriever(search_type="GRAPH_COMPLETION", dataset_name="demo_batch") + search_and_print(retriever, SEARCH_QUERIES) + + # ========================================================================= + # Part 3: Same batch flow wired as a Haystack Pipeline + # + # CogneeWriter(auto_cognify=False) outputs documents_written, which + # connects to CogneeCognifier's input — so cognify triggers automatically + # after the writer finishes. + # ========================================================================= + print("--- Part 3: Writer + Cognifier as a connected Pipeline ---\n") + + await cognee.prune.prune_data() + await cognee.prune.prune_system(metadata=True) + + pipeline = Pipeline() + pipeline.add_component("writer", CogneeWriter(dataset_name="demo_pipeline", auto_cognify=False)) + pipeline.add_component("cognifier", CogneeCognifier(dataset_name="demo_pipeline")) + pipeline.connect("writer.documents_written", "cognifier.documents_written") + + all_docs = DOCS_BATCH_1 + DOCS_BATCH_2 + print(f"8. Running pipeline with {len(all_docs)} documents...") + result = pipeline.run({"writer": {"documents": all_docs}}) + print(f" Cognified: {result['cognifier']['cognified']}\n") + + print("9. Searching...\n") + retriever = CogneeRetriever(search_type="GRAPH_COMPLETION", dataset_name="demo_pipeline") + search_and_print(retriever, SEARCH_QUERIES) + print("=== Done ===") diff --git a/integrations/cognee/pyproject.toml b/integrations/cognee/pyproject.toml index e96928e3b8..cb871c1253 100644 --- a/integrations/cognee/pyproject.toml +++ b/integrations/cognee/pyproject.toml @@ -24,12 +24,9 @@ classifiers = [ ] dependencies = [ "haystack-ai>=2.24.0", - "cognee==0.5.4", + "cognee>=0.5.4,<1.0", ] -[project.optional-dependencies] -memory = ["haystack-experimental"] - [project.urls] Documentation = "https://github.com/deepset-ai/haystack-core-integrations/tree/main/integrations/cognee#readme" Issues = "https://github.com/deepset-ai/haystack-core-integrations/issues" @@ -63,7 +60,6 @@ dependencies = [ "pytest-rerunfailures", "mypy", "pip", - "haystack-experimental", ] [tool.hatch.envs.test.scripts] @@ -89,6 +85,11 @@ select = [ "ARG", "B", "C", + "D102", # Missing docstring in public method + "D103", # Missing docstring in public function + "D205", # 1 blank line required between summary line and description + "D209", # Closing triple quotes go to new line + "D213", # summary lines must be positioned on the second physical line of the docstring "DTZ", "E", "EM", @@ -141,8 +142,8 @@ ban-relative-imports = "parents" [tool.ruff.lint.per-file-ignores] # Tests can use magic values, assertions, and relative imports -"tests/**/*" = ["PLR2004", "S101", "TID252"] -"examples/**/*" = ["T201"] +"tests/**/*" = ["D", "PLR2004", "S101", "TID252"] +"examples/**/*" = ["D", "T201"] [tool.coverage.run] source = ["haystack_integrations"] diff --git a/integrations/cognee/src/haystack_integrations/components/connectors/cognee/_utils.py b/integrations/cognee/src/haystack_integrations/components/connectors/cognee/_utils.py index c704bca6c9..d2eb383107 100644 --- a/integrations/cognee/src/haystack_integrations/components/connectors/cognee/_utils.py +++ b/integrations/cognee/src/haystack_integrations/components/connectors/cognee/_utils.py @@ -3,12 +3,22 @@ # SPDX-License-Identifier: Apache-2.0 import asyncio +import threading from collections.abc import Coroutine -from concurrent.futures import ThreadPoolExecutor from typing import Any, Literal, TypeVar +from uuid import UUID + +from cognee.modules.users.methods import get_user # type: ignore[import-untyped] T = TypeVar("T") +# Persistent background event loop for run_sync when called from an async context. +# A single loop is reused so that cognee's internal asyncio.Lock objects stay bound +# to one event loop across multiple run_sync calls. +_background_loop: asyncio.AbstractEventLoop | None = None +_background_thread: threading.Thread | None = None +_lock = threading.Lock() + CogneeSearchType = Literal[ "GRAPH_COMPLETION", "RAG_COMPLETION", @@ -27,27 +37,47 @@ ] +def _get_background_loop() -> asyncio.AbstractEventLoop: + """Return a persistent background event loop running in a daemon thread.""" + global _background_loop, _background_thread # noqa: PLW0603 + + with _lock: + if _background_loop is None or _background_loop.is_closed(): + _background_loop = asyncio.new_event_loop() + _background_thread = threading.Thread(target=_background_loop.run_forever, daemon=True) + _background_thread.start() + return _background_loop + + def run_sync(coro: Coroutine[Any, Any, T]) -> T: """ Run an async coroutine from a synchronous context. If no event loop is running, uses asyncio.run() directly. - If already inside an async context, runs the coroutine in a separate thread - to avoid blocking the existing event loop. + If already inside an async context, submits the coroutine to a persistent + background event loop so that cognee's internal asyncio.Lock objects remain + bound to a single loop across calls. """ try: asyncio.get_running_loop() except RuntimeError: return asyncio.run(coro) - # Already in an async context — run in a thread to avoid nested loop issues - with ThreadPoolExecutor(max_workers=1) as pool: - future = pool.submit(asyncio.run, coro) - return future.result() + # Already in an async context — submit to the persistent background loop + loop = _get_background_loop() + future = asyncio.run_coroutine_threadsafe(coro, loop) + return future.result() def extract_text(item: Any) -> str: - """Best-effort text extraction from a Cognee search result item.""" + """ + Best-effort text extraction from a Cognee search result item. + + Cognee search results may contain items of various types depending on the + search strategy: plain ``str`` for LLM completions, ``dict`` with keys like + *content*/*text*/*description*/*name*, or cognee model objects (e.g. + ``DataPoint`` subclasses) carrying the same attributes. + """ if isinstance(item, str): return item @@ -63,3 +93,22 @@ def extract_text(item: Any) -> str: return item[key] return str(item) + + +async def _get_cognee_user(user_id: str) -> Any: + """ + Resolve a user_id string to a cognee User object. + + Converts the given UUID string to a cognee User via ``cognee.modules.users.methods.get_user``. + + :param user_id: UUID string identifying the cognee user. + :returns: A cognee ``User`` object. + :raises ValueError: If user_id is not a valid UUID or the user is not found. + """ + try: + uid = UUID(user_id) + except ValueError as e: + msg = f"Invalid user_id: '{user_id}' is not a valid UUID." + raise ValueError(msg) from e + + return await get_user(uid) diff --git a/integrations/cognee/src/haystack_integrations/components/connectors/cognee/cognifier.py b/integrations/cognee/src/haystack_integrations/components/connectors/cognee/cognifier.py index 8f983314c7..d862f442e4 100644 --- a/integrations/cognee/src/haystack_integrations/components/connectors/cognee/cognifier.py +++ b/integrations/cognee/src/haystack_integrations/components/connectors/cognee/cognifier.py @@ -53,6 +53,8 @@ class CogneeCognifier: def __init__(self, dataset_name: str | list[str] | None = None): """ + Initialize the CogneeCognifier. + :param dataset_name: Optional Cognee dataset name(s) to cognify. Accepts a single name, a list of names, or None to cognify all pending datasets. """ @@ -78,8 +80,10 @@ def run(self, documents_written: int | None = None) -> dict[str, Any]: return {"cognified": True} def to_dict(self) -> dict[str, Any]: + """Serialize this component to a dictionary.""" return default_to_dict(self, dataset_name=self.dataset_name) @classmethod def from_dict(cls, data: dict[str, Any]) -> "CogneeCognifier": + """Deserialize a component from a dictionary.""" return default_from_dict(cls, data) diff --git a/integrations/cognee/src/haystack_integrations/components/retrievers/cognee/memory_retriever.py b/integrations/cognee/src/haystack_integrations/components/retrievers/cognee/memory_retriever.py index a5aca52d33..3be8186b76 100644 --- a/integrations/cognee/src/haystack_integrations/components/retrievers/cognee/memory_retriever.py +++ b/integrations/cognee/src/haystack_integrations/components/retrievers/cognee/memory_retriever.py @@ -35,6 +35,8 @@ def __init__( self, search_type: CogneeSearchType = "GRAPH_COMPLETION", top_k: int = 10, dataset_name: str | None = None ): """ + Initialize the CogneeRetriever. + :param search_type: Cognee search type. One of: GRAPH_COMPLETION, CHUNKS, SUMMARIES, INSIGHTS, etc. :param top_k: Maximum number of results to return. @@ -45,7 +47,7 @@ def __init__( self.dataset_name = dataset_name @component.output_types(documents=list[Document]) - def run(self, query: str, top_k: int | None = None) -> dict[str, Any]: + def run(self, query: str, top_k: int | None = None) -> dict[str, list[Document]]: """ Search Cognee's memory and return matching documents. @@ -76,6 +78,7 @@ def run(self, query: str, top_k: int | None = None) -> dict[str, Any]: return {"documents": documents} def to_dict(self) -> dict[str, Any]: + """Serialize this component to a dictionary.""" return default_to_dict( self, search_type=self.search_type, @@ -85,6 +88,7 @@ def to_dict(self) -> dict[str, Any]: @classmethod def from_dict(cls, data: dict[str, Any]) -> "CogneeRetriever": + """Deserialize a component from a dictionary.""" return default_from_dict(cls, data) diff --git a/integrations/cognee/src/haystack_integrations/components/writers/cognee/memory_writer.py b/integrations/cognee/src/haystack_integrations/components/writers/cognee/memory_writer.py index a61f0577bb..b358a7c5ba 100644 --- a/integrations/cognee/src/haystack_integrations/components/writers/cognee/memory_writer.py +++ b/integrations/cognee/src/haystack_integrations/components/writers/cognee/memory_writer.py @@ -32,6 +32,8 @@ class CogneeWriter: def __init__(self, *, dataset_name: str = "haystack", auto_cognify: bool = True): """ + Initialize the CogneeWriter. + :param dataset_name: Name of the Cognee dataset to add documents to. :param auto_cognify: If True, automatically runs `cognee.cognify()` after adding documents to process them into the knowledge engine. @@ -69,6 +71,7 @@ def run(self, documents: list[Document]) -> dict[str, Any]: return {"documents_written": written} def to_dict(self) -> dict[str, Any]: + """Serialize this component to a dictionary.""" return default_to_dict( self, dataset_name=self.dataset_name, @@ -77,4 +80,5 @@ def to_dict(self) -> dict[str, Any]: @classmethod def from_dict(cls, data: dict[str, Any]) -> "CogneeWriter": + """Deserialize a component from a dictionary.""" return default_from_dict(cls, data) diff --git a/integrations/cognee/src/haystack_integrations/memory_stores/cognee/memory_store.py b/integrations/cognee/src/haystack_integrations/memory_stores/cognee/memory_store.py index 3979e03c6d..92c43cc3bb 100644 --- a/integrations/cognee/src/haystack_integrations/memory_stores/cognee/memory_store.py +++ b/integrations/cognee/src/haystack_integrations/memory_stores/cognee/memory_store.py @@ -9,7 +9,14 @@ import cognee # type: ignore[import-untyped] from cognee.api.v1.search import SearchType # type: ignore[import-untyped] -from haystack_integrations.components.connectors.cognee._utils import CogneeSearchType, extract_text, run_sync +from cognee.modules.data.exceptions import DatasetNotFoundError # type: ignore[import-untyped] +from cognee.modules.users.permissions.methods import get_all_user_permission_datasets # type: ignore[import-untyped] +from haystack_integrations.components.connectors.cognee._utils import ( + CogneeSearchType, + _get_cognee_user, + extract_text, + run_sync, +) logger = logging.getLogger(__name__) @@ -35,6 +42,8 @@ def __init__( self, search_type: CogneeSearchType = "GRAPH_COMPLETION", top_k: int = 5, dataset_name: str = "haystack_memory" ): """ + Initialize the CogneeMemoryStore. + :param search_type: Cognee search type for memory retrieval. :param top_k: Default number of results for memory search. :param dataset_name: Cognee dataset name for storing memories. @@ -43,40 +52,81 @@ def __init__( self.top_k = top_k self.dataset_name = dataset_name - def add_memories(self, *, messages: list[ChatMessage]) -> None: + def add_memories( + self, + *, + messages: list[ChatMessage], + user_id: str | None = None, + **kwargs: Any, + ) -> None: """ Add chat messages to Cognee as memories. :param messages: List of ChatMessages to store. + :param user_id: Optional cognee user UUID to scope memories to a specific user. + When provided, the data is stored under that user's permissions. + When ``None``, cognee's default user is used. + :param kwargs: Additional keyword arguments (unused, accepted for protocol + compatibility). """ + user = run_sync(_get_cognee_user(user_id)) if user_id else None + added = 0 for msg in messages: text = msg.text if not text: continue - run_sync(cognee.add(text, dataset_name=self.dataset_name)) + run_sync(cognee.add(text, dataset_name=self.dataset_name, user=user)) added += 1 if added > 0: - run_sync(cognee.cognify(datasets=[self.dataset_name])) + run_sync(cognee.cognify(datasets=[self.dataset_name], user=user)) logger.info("Added and cognified {count} messages as memories", count=added) - def search_memories(self, *, query: str | None = None, top_k: int = 5) -> list[ChatMessage]: + def search_memories( + self, + *, + query: str | None = None, + top_k: int = 5, + user_id: str | None = None, + **kwargs: Any, + ) -> list[ChatMessage]: """ Search Cognee's knowledge engine for relevant memories. :param query: The search query. :param top_k: Maximum number of memories to return. + :param user_id: Optional cognee user UUID to scope the search to a specific user. + Search is restricted to the store's ``dataset_name``. If the user owns the + dataset it is resolved by name; otherwise the store checks whether the user + has been granted read access (e.g. via shared permissions) and searches by + dataset UUID. + When ``None``, cognee's default user is used. + :param kwargs: Additional keyword arguments (unused, accepted for protocol + compatibility). :returns: List of ChatMessages containing memory content as system messages. """ if not query: return [] + user = run_sync(_get_cognee_user(user_id)) if user_id else None search_type_enum = SearchType[self.search_type] effective_top_k = top_k or self.top_k - raw_results = run_sync(cognee.search(query_text=query, query_type=search_type_enum)) + try: + raw_results = run_sync( + cognee.search( + query_text=query, + query_type=search_type_enum, + user=user, + datasets=[self.dataset_name], + ) + ) + except DatasetNotFoundError: + # The user doesn't own a dataset with this name. + # Fall back to checking shared datasets the user has read access to. + raw_results = self._search_shared_dataset(query, search_type_enum, user) memories: list[ChatMessage] = [] if not raw_results: @@ -90,9 +140,31 @@ def search_memories(self, *, query: str | None = None, top_k: int = 5) -> list[C logger.info("Found {count} memories for query '{query}'", count=len(memories), query=query[:80]) return memories - def delete_all_memories(self) -> None: + def _search_shared_dataset(self, query: str, search_type_enum: SearchType, user: Any) -> list[Any]: + """Search for the dataset by name among all datasets the user has read access to.""" + if user is None: + return [] + all_readable = run_sync(get_all_user_permission_datasets(user, "read")) + matching = [ds for ds in all_readable if ds.name == self.dataset_name] + if not matching: + return [] + return run_sync( + cognee.search(query_text=query, query_type=search_type_enum, user=user, dataset_ids=[matching[0].id]) + ) + + def delete_all_memories( + self, + *, + user_id: str | None = None, + **kwargs: Any, + ) -> None: """ Delete all memories by pruning Cognee's data and system state. + + :param user_id: Optional cognee user UUID (accepted for protocol compatibility). + Note: Cognee's prune operations are global and not scoped to a specific user. + :param kwargs: Additional keyword arguments (unused, accepted for protocol + compatibility). """ run_sync(cognee.prune.prune_data()) run_sync(cognee.prune.prune_system(metadata=True)) @@ -111,6 +183,7 @@ def delete_memory(self, memory_id: str) -> None: raise NotImplementedError(msg) def to_dict(self) -> dict[str, Any]: + """Serialize this component to a dictionary.""" return default_to_dict( self, search_type=self.search_type, @@ -120,4 +193,5 @@ def to_dict(self) -> dict[str, Any]: @classmethod def from_dict(cls, data: dict[str, Any]) -> "CogneeMemoryStore": + """Deserialize a component from a dictionary.""" return default_from_dict(cls, data) diff --git a/integrations/cognee/tests/test_cognifier.py b/integrations/cognee/tests/test_cognifier.py new file mode 100644 index 0000000000..4b6eea9ffc --- /dev/null +++ b/integrations/cognee/tests/test_cognifier.py @@ -0,0 +1,80 @@ +# SPDX-FileCopyrightText: 2022-present deepset GmbH +# +# SPDX-License-Identifier: Apache-2.0 + +from unittest.mock import AsyncMock, patch + +from haystack_integrations.components.connectors.cognee import CogneeCognifier + + +class TestCogneeCognifier: + def test_init_defaults(self): + cognifier = CogneeCognifier() + assert cognifier.dataset_name is None + + def test_init_custom_string(self): + cognifier = CogneeCognifier(dataset_name="my_data") + assert cognifier.dataset_name == "my_data" + + def test_init_custom_list(self): + cognifier = CogneeCognifier(dataset_name=["ds1", "ds2"]) + assert cognifier.dataset_name == ["ds1", "ds2"] + + def test_to_dict(self): + cognifier = CogneeCognifier(dataset_name="test_ds") + data = cognifier.to_dict() + assert data["type"] == "haystack_integrations.components.connectors.cognee.cognifier.CogneeCognifier" + assert data["init_parameters"]["dataset_name"] == "test_ds" + + def test_to_dict_defaults(self): + cognifier = CogneeCognifier() + data = cognifier.to_dict() + assert data["init_parameters"]["dataset_name"] is None + + def test_from_dict(self): + data = { + "type": "haystack_integrations.components.connectors.cognee.cognifier.CogneeCognifier", + "init_parameters": {"dataset_name": "restored"}, + } + cognifier = CogneeCognifier.from_dict(data) + assert cognifier.dataset_name == "restored" + + @patch("haystack_integrations.components.connectors.cognee.cognifier.cognee") + def test_run_no_dataset(self, mock_cognee): + mock_cognee.cognify = AsyncMock() + + cognifier = CogneeCognifier() + result = cognifier.run() + + assert result == {"cognified": True} + mock_cognee.cognify.assert_awaited_once_with() + + @patch("haystack_integrations.components.connectors.cognee.cognifier.cognee") + def test_run_with_string_dataset(self, mock_cognee): + mock_cognee.cognify = AsyncMock() + + cognifier = CogneeCognifier(dataset_name="my_data") + result = cognifier.run() + + assert result == {"cognified": True} + mock_cognee.cognify.assert_awaited_once_with(datasets=["my_data"]) + + @patch("haystack_integrations.components.connectors.cognee.cognifier.cognee") + def test_run_with_list_dataset(self, mock_cognee): + mock_cognee.cognify = AsyncMock() + + cognifier = CogneeCognifier(dataset_name=["ds1", "ds2"]) + result = cognifier.run() + + assert result == {"cognified": True} + mock_cognee.cognify.assert_awaited_once_with(datasets=["ds1", "ds2"]) + + @patch("haystack_integrations.components.connectors.cognee.cognifier.cognee") + def test_run_with_documents_written_input(self, mock_cognee): + mock_cognee.cognify = AsyncMock() + + cognifier = CogneeCognifier(dataset_name="my_data") + result = cognifier.run(documents_written=5) + + assert result == {"cognified": True} + mock_cognee.cognify.assert_awaited_once_with(datasets=["my_data"]) diff --git a/integrations/cognee/tests/test_integration.py b/integrations/cognee/tests/test_integration.py new file mode 100644 index 0000000000..2f58d40392 --- /dev/null +++ b/integrations/cognee/tests/test_integration.py @@ -0,0 +1,99 @@ +# SPDX-FileCopyrightText: 2022-present deepset GmbH +# +# SPDX-License-Identifier: Apache-2.0 + +import os + +import cognee +import pytest +from haystack import Document +from haystack.dataclasses import ChatMessage + +from haystack_integrations.components.connectors.cognee import CogneeCognifier +from haystack_integrations.components.connectors.cognee._utils import run_sync +from haystack_integrations.components.retrievers.cognee import CogneeRetriever +from haystack_integrations.components.writers.cognee import CogneeWriter +from haystack_integrations.memory_stores.cognee import CogneeMemoryStore + +SKIP_REASON = "Export an env var called LLM_API_KEY containing the LLM API key to run this test." + + +@pytest.mark.skipif( + not os.environ.get("LLM_API_KEY", None), + reason=SKIP_REASON, +) +@pytest.mark.integration +class TestCogneeMemoryStoreIntegration: + def test_add_search_delete(self): + store = CogneeMemoryStore( + search_type="GRAPH_COMPLETION", + top_k=3, + dataset_name="haystack_integration_test", + ) + + store.delete_all_memories() + + messages = [ + ChatMessage.from_user("The capital of France is Paris."), + ChatMessage.from_user("The Eiffel Tower is located in Paris."), + ] + store.add_memories(messages=messages) + + results = store.search_memories(query="What is the capital of France?", top_k=3) + assert len(results) > 0 + assert all(isinstance(r, ChatMessage) for r in results) + + store.delete_all_memories() + + +@pytest.mark.skipif( + not os.environ.get("LLM_API_KEY", None), + reason=SKIP_REASON, +) +@pytest.mark.integration +class TestCogneeWriterRetrieverIntegration: + def test_write_and_retrieve(self): + run_sync(cognee.prune.prune_data()) + run_sync(cognee.prune.prune_system(metadata=True)) + + writer = CogneeWriter(dataset_name="haystack_integration_test", auto_cognify=True) + docs = [ + Document(content="Python is a programming language created by Guido van Rossum."), + Document(content="Haystack is an open-source framework for building AI applications."), + ] + write_result = writer.run(documents=docs) + assert write_result["documents_written"] == 2 + + retriever = CogneeRetriever( + search_type="GRAPH_COMPLETION", + top_k=3, + dataset_name="haystack_integration_test", + ) + search_result = retriever.run(query="What is Haystack?") + assert len(search_result["documents"]) > 0 + assert all(isinstance(d, Document) for d in search_result["documents"]) + + run_sync(cognee.prune.prune_data()) + run_sync(cognee.prune.prune_system(metadata=True)) + + +@pytest.mark.skipif( + not os.environ.get("LLM_API_KEY", None), + reason=SKIP_REASON, +) +@pytest.mark.integration +class TestCogneeCognifierIntegration: + def test_write_then_cognify(self): + run_sync(cognee.prune.prune_data()) + run_sync(cognee.prune.prune_system(metadata=True)) + + writer = CogneeWriter(dataset_name="haystack_integration_test", auto_cognify=False) + docs = [Document(content="Berlin is the capital of Germany.")] + writer.run(documents=docs) + + cognifier = CogneeCognifier(dataset_name="haystack_integration_test") + result = cognifier.run() + assert result["cognified"] is True + + run_sync(cognee.prune.prune_data()) + run_sync(cognee.prune.prune_system(metadata=True)) diff --git a/integrations/cognee/tests/test_memory_store.py b/integrations/cognee/tests/test_memory_store.py index 91ec58b371..5a48be1eaf 100644 --- a/integrations/cognee/tests/test_memory_store.py +++ b/integrations/cognee/tests/test_memory_store.py @@ -2,7 +2,7 @@ # # SPDX-License-Identifier: Apache-2.0 -from unittest.mock import AsyncMock, patch +from unittest.mock import AsyncMock, MagicMock, patch import pytest from haystack.dataclasses import ChatMessage @@ -105,6 +105,62 @@ def test_delete_all_memories(self, mock_cognee): mock_cognee.prune.prune_data.assert_awaited_once() mock_cognee.prune.prune_system.assert_awaited_once() + @patch("haystack_integrations.memory_stores.cognee.memory_store._get_cognee_user", new_callable=AsyncMock) + @patch("haystack_integrations.memory_stores.cognee.memory_store.cognee") + def test_add_memories_with_user_id(self, mock_cognee, mock_get_user): + mock_user = MagicMock() + mock_get_user.return_value = mock_user + mock_cognee.add = AsyncMock() + mock_cognee.cognify = AsyncMock() + + store = CogneeMemoryStore() + messages = [ChatMessage.from_user("Remember this.")] + store.add_memories(messages=messages, user_id="550e8400-e29b-41d4-a716-446655440000") + + mock_get_user.assert_awaited_once_with("550e8400-e29b-41d4-a716-446655440000") + mock_cognee.add.assert_awaited_once() + add_kwargs = mock_cognee.add.call_args[1] + assert add_kwargs["user"] is mock_user + cognify_kwargs = mock_cognee.cognify.call_args[1] + assert cognify_kwargs["user"] is mock_user + + @patch("haystack_integrations.memory_stores.cognee.memory_store._get_cognee_user", new_callable=AsyncMock) + @patch("haystack_integrations.memory_stores.cognee.memory_store.cognee") + def test_search_memories_with_user_id(self, mock_cognee, mock_get_user): + mock_user = MagicMock() + mock_get_user.return_value = mock_user + mock_cognee.search = AsyncMock(return_value=["result"]) + + store = CogneeMemoryStore() + results = store.search_memories(query="test", user_id="550e8400-e29b-41d4-a716-446655440000") + + mock_get_user.assert_awaited_once_with("550e8400-e29b-41d4-a716-446655440000") + search_kwargs = mock_cognee.search.call_args[1] + assert search_kwargs["user"] is mock_user + assert len(results) == 1 + + @patch("haystack_integrations.memory_stores.cognee.memory_store.cognee") + def test_add_memories_without_user_id(self, mock_cognee): + mock_cognee.add = AsyncMock() + mock_cognee.cognify = AsyncMock() + + store = CogneeMemoryStore() + messages = [ChatMessage.from_user("Remember this.")] + store.add_memories(messages=messages) + + add_kwargs = mock_cognee.add.call_args[1] + assert add_kwargs["user"] is None + + @patch("haystack_integrations.memory_stores.cognee.memory_store.cognee") + def test_search_memories_without_user_id(self, mock_cognee): + mock_cognee.search = AsyncMock(return_value=["result"]) + + store = CogneeMemoryStore() + store.search_memories(query="test") + + search_kwargs = mock_cognee.search.call_args[1] + assert search_kwargs["user"] is None + def test_delete_memory_raises(self): store = CogneeMemoryStore() with pytest.raises(NotImplementedError): diff --git a/integrations/cognee/tests/test_utils.py b/integrations/cognee/tests/test_utils.py new file mode 100644 index 0000000000..13701aea93 --- /dev/null +++ b/integrations/cognee/tests/test_utils.py @@ -0,0 +1,99 @@ +# SPDX-FileCopyrightText: 2022-present deepset GmbH +# +# SPDX-License-Identifier: Apache-2.0 + +import asyncio + +from haystack_integrations.components.connectors.cognee._utils import extract_text, run_sync + + +class TestExtractText: + def test_string_input(self): + assert extract_text("hello world") == "hello world" + + def test_object_with_content_attr(self): + class FakeResult: + content = "object content" + + assert extract_text(FakeResult()) == "object content" + + def test_object_with_text_attr(self): + class FakeResult: + text = "object text" + + assert extract_text(FakeResult()) == "object text" + + def test_object_with_description_attr(self): + class FakeResult: + description = "object description" + + assert extract_text(FakeResult()) == "object description" + + def test_object_with_name_attr(self): + class FakeResult: + name = "object name" + + assert extract_text(FakeResult()) == "object name" + + def test_object_attr_priority(self): + class FakeResult: + content = "first" + text = "second" + + assert extract_text(FakeResult()) == "first" + + def test_object_skips_none_attr(self): + class FakeResult: + content = None + text = "fallback text" + + assert extract_text(FakeResult()) == "fallback text" + + def test_object_skips_non_string_attr(self): + class FakeResult: + content = 123 + text = "string value" + + assert extract_text(FakeResult()) == "string value" + + def test_dict_with_content_key(self): + assert extract_text({"content": "dict content"}) == "dict content" + + def test_dict_with_text_key(self): + assert extract_text({"text": "dict text"}) == "dict text" + + def test_dict_with_description_key(self): + assert extract_text({"description": "dict description"}) == "dict description" + + def test_dict_with_name_key(self): + assert extract_text({"name": "dict name"}) == "dict name" + + def test_dict_key_priority(self): + assert extract_text({"content": "first", "text": "second"}) == "first" + + def test_dict_skips_non_string_value(self): + assert extract_text({"content": 123, "text": "fallback"}) == "fallback" + + def test_fallback_to_str(self): + assert extract_text(42) == "42" + + def test_fallback_dict_no_known_keys(self): + result = extract_text({"unknown": "value"}) + assert "unknown" in result + + +class TestRunSync: + def test_run_simple_coroutine(self): + async def coro(): + return 42 + + result = run_sync(coro()) + assert result == 42 + + def test_run_async_coroutine(self): + async def coro(): + await asyncio.sleep(0) + return "done" + + result = run_sync(coro()) + assert result == "done" From ccba8eee64fe620f19767dfbd78db39684ef8d02 Mon Sep 17 00:00:00 2001 From: Hande <159312713+hande-k@users.noreply.github.com> Date: Wed, 22 Apr 2026 13:15:58 +0200 Subject: [PATCH 07/10] address comments --- integrations/cognee/examples/demo_pipeline.py | 13 +- .../components/connectors/cognee/_utils.py | 20 ++- .../retrievers/cognee/memory_retriever.py | 100 ++++++------ .../writers/cognee/memory_writer.py | 16 +- .../memory_stores/cognee/memory_store.py | 7 +- integrations/cognee/tests/test_integration.py | 8 +- integrations/cognee/tests/test_retriever.py | 143 +++++++++++------- integrations/cognee/tests/test_writer.py | 35 ++++- 8 files changed, 219 insertions(+), 123 deletions(-) diff --git a/integrations/cognee/examples/demo_pipeline.py b/integrations/cognee/examples/demo_pipeline.py index 0a73053618..08d6577179 100644 --- a/integrations/cognee/examples/demo_pipeline.py +++ b/integrations/cognee/examples/demo_pipeline.py @@ -30,6 +30,7 @@ from haystack_integrations.components.connectors.cognee import CogneeCognifier from haystack_integrations.components.retrievers.cognee import CogneeRetriever from haystack_integrations.components.writers.cognee import CogneeWriter +from haystack_integrations.memory_stores.cognee import CogneeMemoryStore DOCS_BATCH_1 = [ Document( @@ -110,7 +111,9 @@ async def main(): print(f" Written: {result['documents_written']} (cognify ran again)\n") print("3. Searching...\n") - retriever = CogneeRetriever(search_type="GRAPH_COMPLETION", dataset_name="demo_auto") + retriever = CogneeRetriever( + memory_store=CogneeMemoryStore(search_type="GRAPH_COMPLETION", dataset_name="demo_auto") + ) search_and_print(retriever, SEARCH_QUERIES) # ========================================================================= @@ -140,7 +143,9 @@ async def main(): print(f" Cognified: {result['cognified']}\n") print("7. Searching...\n") - retriever = CogneeRetriever(search_type="GRAPH_COMPLETION", dataset_name="demo_batch") + retriever = CogneeRetriever( + memory_store=CogneeMemoryStore(search_type="GRAPH_COMPLETION", dataset_name="demo_batch") + ) search_and_print(retriever, SEARCH_QUERIES) # ========================================================================= @@ -166,7 +171,9 @@ async def main(): print(f" Cognified: {result['cognifier']['cognified']}\n") print("9. Searching...\n") - retriever = CogneeRetriever(search_type="GRAPH_COMPLETION", dataset_name="demo_pipeline") + retriever = CogneeRetriever( + memory_store=CogneeMemoryStore(search_type="GRAPH_COMPLETION", dataset_name="demo_pipeline") + ) search_and_print(retriever, SEARCH_QUERIES) print("=== Done ===") diff --git a/integrations/cognee/src/haystack_integrations/components/connectors/cognee/_utils.py b/integrations/cognee/src/haystack_integrations/components/connectors/cognee/_utils.py index d2eb383107..49e8eebb24 100644 --- a/integrations/cognee/src/haystack_integrations/components/connectors/cognee/_utils.py +++ b/integrations/cognee/src/haystack_integrations/components/connectors/cognee/_utils.py @@ -73,10 +73,22 @@ def extract_text(item: Any) -> str: """ Best-effort text extraction from a Cognee search result item. - Cognee search results may contain items of various types depending on the - search strategy: plain ``str`` for LLM completions, ``dict`` with keys like - *content*/*text*/*description*/*name*, or cognee model objects (e.g. - ``DataPoint`` subclasses) carrying the same attributes. + Cognee's search results are not a single public type — depending on the + search strategy, an item can be one of three shapes (all cognee-internal): + + 1. A plain `str` — returned by LLM-completion search types + (e.g. `GRAPH_COMPLETION`, `RAG_COMPLETION`). + 2. A `dict` — returned by structured search types; the text is read from + one of the `content` / `text` / `description` / `name` keys. + 3. A cognee model object — e.g. a `DataPoint` subclass such as + `TextChunk` or `EntityType`, carrying the same attributes. + + Since these types are internal to cognee and not part of its public API, + `item` is typed as `Any` and this function probes for known shapes rather + than narrowing the type. + + :param item: A single element returned by `cognee.search(...)`. + :returns: Best-effort extracted text, falling back to `str(item)`. """ if isinstance(item, str): return item diff --git a/integrations/cognee/src/haystack_integrations/components/retrievers/cognee/memory_retriever.py b/integrations/cognee/src/haystack_integrations/components/retrievers/cognee/memory_retriever.py index 3be8186b76..d80867ba49 100644 --- a/integrations/cognee/src/haystack_integrations/components/retrievers/cognee/memory_retriever.py +++ b/integrations/cognee/src/haystack_integrations/components/retrievers/cognee/memory_retriever.py @@ -6,9 +6,7 @@ from haystack import Document, component, default_from_dict, default_to_dict, logging -import cognee # type: ignore[import-untyped] -from cognee.api.v1.search import SearchType # type: ignore[import-untyped] -from haystack_integrations.components.connectors.cognee._utils import CogneeSearchType, extract_text, run_sync +from haystack_integrations.memory_stores.cognee import CogneeMemoryStore logger = logging.getLogger(__name__) @@ -16,15 +14,19 @@ @component class CogneeRetriever: """ - Retrieves documents from Cognee's memory. + Retrieves memories from a `CogneeMemoryStore` and returns them as Haystack `Document`s. - Wraps `cognee.search()` and converts results into Haystack `Document` objects. + Follows the same pattern as other Haystack retrievers (e.g. `OpenSearchBM25Retriever`): + the store is the source of truth for configuration (`search_type`, `dataset_name`, `top_k`) + and the retriever delegates the actual search call to `CogneeMemoryStore.search_memories`. Usage: ```python + from haystack_integrations.memory_stores.cognee import CogneeMemoryStore from haystack_integrations.components.retrievers.cognee import CogneeRetriever - retriever = CogneeRetriever(search_type="GRAPH_COMPLETION", top_k=5) + store = CogneeMemoryStore(search_type="GRAPH_COMPLETION", top_k=5, dataset_name="my_data") + retriever = CogneeRetriever(memory_store=store) results = retriever.run(query="What is Cognee?") for doc in results["documents"]: print(doc.content) @@ -32,46 +34,58 @@ class CogneeRetriever: """ def __init__( - self, search_type: CogneeSearchType = "GRAPH_COMPLETION", top_k: int = 10, dataset_name: str | None = None + self, + *, + memory_store: CogneeMemoryStore, + top_k: int | None = None, ): """ Initialize the CogneeRetriever. - :param search_type: Cognee search type. One of: GRAPH_COMPLETION, CHUNKS, - SUMMARIES, INSIGHTS, etc. - :param top_k: Maximum number of results to return. - :param dataset_name: Optional dataset name to restrict search scope. + :param memory_store: An instance of `CogneeMemoryStore` to retrieve memories from. + :param top_k: Default maximum number of results to return. When `None`, the + store's own `top_k` is used. Can be overridden at runtime via `run(top_k=...)`. + :raises ValueError: If `memory_store` is not an instance of `CogneeMemoryStore`. """ - self.search_type = search_type - self.top_k = top_k - self.dataset_name = dataset_name + if not isinstance(memory_store, CogneeMemoryStore): + msg = "memory_store must be an instance of CogneeMemoryStore" + raise ValueError(msg) + + self._memory_store = memory_store + self._top_k = top_k @component.output_types(documents=list[Document]) - def run(self, query: str, top_k: int | None = None) -> dict[str, list[Document]]: + def run( + self, + query: str, + top_k: int | None = None, + user_id: str | None = None, + ) -> dict[str, list[Document]]: """ - Search Cognee's memory and return matching documents. + Search the attached `CogneeMemoryStore` and return matching memories as Documents. + + The arguments mirror `CogneeMemoryStore.search_memories` so that pipeline builders + can scope a retrieval call at runtime (e.g. per end-user). :param query: The search query. - :param top_k: Override the default maximum number of results. - :returns: Dictionary with key `documents` containing the search results - as Haystack Document objects. + :param top_k: Maximum number of results to return. Overrides the retriever's + init-time default (if set), which in turn overrides the store's default. + :param user_id: Optional cognee user UUID to scope the search to a specific user. + When `None`, cognee's default user is used. + :returns: Dictionary with key `documents` containing the search results as + Haystack `Document` objects. """ - effective_top_k = top_k if top_k is not None else self.top_k - search_type_enum = SearchType[self.search_type] - - search_kwargs: dict[str, Any] = { - "query_text": query, - "query_type": search_type_enum, - } - if self.dataset_name: - search_kwargs["datasets"] = [self.dataset_name] + effective_top_k = top_k if top_k is not None else self._top_k + search_kwargs: dict[str, Any] = {"query": query, "user_id": user_id} + if effective_top_k is not None: + search_kwargs["top_k"] = effective_top_k - raw_results = run_sync(cognee.search(**search_kwargs)) + memories = self._memory_store.search_memories(**search_kwargs) - documents = _convert_results(raw_results, effective_top_k) + documents = [Document(content=m.text, meta={"source": "cognee"}) for m in memories if m.text] logger.info( - "Cognee search returned {count} documents for query '{query}'", + "Cognee retriever returned {count} documents for query '{query}'", count=len(documents), query=query[:80], ) @@ -81,30 +95,12 @@ def to_dict(self) -> dict[str, Any]: """Serialize this component to a dictionary.""" return default_to_dict( self, - search_type=self.search_type, - top_k=self.top_k, - dataset_name=self.dataset_name, + memory_store=self._memory_store.to_dict(), + top_k=self._top_k, ) @classmethod def from_dict(cls, data: dict[str, Any]) -> "CogneeRetriever": """Deserialize a component from a dictionary.""" + data["init_parameters"]["memory_store"] = CogneeMemoryStore.from_dict(data["init_parameters"]["memory_store"]) return default_from_dict(cls, data) - - -def _convert_results(raw_results: list[Any], top_k: int) -> list[Document]: - """Convert Cognee search results to Haystack Documents.""" - documents: list[Document] = [] - if not raw_results: - return documents - - for item in raw_results[:top_k]: - text = extract_text(item) - if text: - documents.append( - Document( - content=text, - meta={"source": "cognee", "search_result_type": type(item).__name__}, - ) - ) - return documents diff --git a/integrations/cognee/src/haystack_integrations/components/writers/cognee/memory_writer.py b/integrations/cognee/src/haystack_integrations/components/writers/cognee/memory_writer.py index b358a7c5ba..11089c01a1 100644 --- a/integrations/cognee/src/haystack_integrations/components/writers/cognee/memory_writer.py +++ b/integrations/cognee/src/haystack_integrations/components/writers/cognee/memory_writer.py @@ -7,7 +7,7 @@ from haystack import Document, component, default_from_dict, default_to_dict, logging import cognee # type: ignore[import-untyped] -from haystack_integrations.components.connectors.cognee._utils import run_sync +from haystack_integrations.components.connectors.cognee._utils import _get_cognee_user, run_sync logger = logging.getLogger(__name__) @@ -42,11 +42,17 @@ def __init__(self, *, dataset_name: str = "haystack", auto_cognify: bool = True) self.auto_cognify = auto_cognify @component.output_types(documents_written=int) - def run(self, documents: list[Document]) -> dict[str, Any]: + def run(self, documents: list[Document], user_id: str | None = None) -> dict[str, Any]: """ Add documents to Cognee and optionally cognify them. :param documents: List of Haystack Documents to add. + :param user_id: Optional cognee user UUID to scope the ingested data to a + specific user. When provided, the data is stored under that user's + permissions. When `None`, cognee's default user is used. Exposed on + `run()` (rather than only on `__init__`) so that the same writer + instance can be reused in a pipeline for many users by passing + `user_id` at invocation time. :returns: Dictionary with key `documents_written` indicating how many documents were successfully added. """ @@ -55,8 +61,10 @@ def run(self, documents: list[Document]) -> dict[str, Any]: if skipped > 0: logger.warning("Skipping {count} document(s) with empty content", count=skipped) + user = run_sync(_get_cognee_user(user_id)) if user_id else None + if texts: - run_sync(cognee.add(texts, dataset_name=self.dataset_name)) + run_sync(cognee.add(texts, dataset_name=self.dataset_name, user=user)) written = len(texts) @@ -66,7 +74,7 @@ def run(self, documents: list[Document]) -> dict[str, Any]: count=written, dataset=self.dataset_name, ) - run_sync(cognee.cognify(datasets=[self.dataset_name])) + run_sync(cognee.cognify(datasets=[self.dataset_name], user=user)) return {"documents_written": written} diff --git a/integrations/cognee/src/haystack_integrations/memory_stores/cognee/memory_store.py b/integrations/cognee/src/haystack_integrations/memory_stores/cognee/memory_store.py index 92c43cc3bb..a39fcaaa95 100644 --- a/integrations/cognee/src/haystack_integrations/memory_stores/cognee/memory_store.py +++ b/integrations/cognee/src/haystack_integrations/memory_stores/cognee/memory_store.py @@ -65,7 +65,8 @@ def add_memories( :param messages: List of ChatMessages to store. :param user_id: Optional cognee user UUID to scope memories to a specific user. When provided, the data is stored under that user's permissions. - When ``None``, cognee's default user is used. + When `None`, cognee's default user is used (cognee falls back to its + built-in default user account so the call still succeeds). :param kwargs: Additional keyword arguments (unused, accepted for protocol compatibility). """ @@ -98,11 +99,11 @@ def search_memories( :param query: The search query. :param top_k: Maximum number of memories to return. :param user_id: Optional cognee user UUID to scope the search to a specific user. - Search is restricted to the store's ``dataset_name``. If the user owns the + Search is restricted to the store's `dataset_name`. If the user owns the dataset it is resolved by name; otherwise the store checks whether the user has been granted read access (e.g. via shared permissions) and searches by dataset UUID. - When ``None``, cognee's default user is used. + When `None`, cognee's default user is used. :param kwargs: Additional keyword arguments (unused, accepted for protocol compatibility). :returns: List of ChatMessages containing memory content as system messages. diff --git a/integrations/cognee/tests/test_integration.py b/integrations/cognee/tests/test_integration.py index 2f58d40392..91e2d16c38 100644 --- a/integrations/cognee/tests/test_integration.py +++ b/integrations/cognee/tests/test_integration.py @@ -65,9 +65,11 @@ def test_write_and_retrieve(self): assert write_result["documents_written"] == 2 retriever = CogneeRetriever( - search_type="GRAPH_COMPLETION", - top_k=3, - dataset_name="haystack_integration_test", + memory_store=CogneeMemoryStore( + search_type="GRAPH_COMPLETION", + top_k=3, + dataset_name="haystack_integration_test", + ), ) search_result = retriever.run(query="What is Haystack?") assert len(search_result["documents"]) > 0 diff --git a/integrations/cognee/tests/test_retriever.py b/integrations/cognee/tests/test_retriever.py index 6494861db9..343ea3bf01 100644 --- a/integrations/cognee/tests/test_retriever.py +++ b/integrations/cognee/tests/test_retriever.py @@ -2,91 +2,128 @@ # # SPDX-License-Identifier: Apache-2.0 -from unittest.mock import AsyncMock, patch +from unittest.mock import MagicMock + +import pytest +from haystack.dataclasses import ChatMessage from haystack_integrations.components.retrievers.cognee import CogneeRetriever +from haystack_integrations.memory_stores.cognee import CogneeMemoryStore class TestCogneeRetriever: + def test_init_requires_memory_store(self): + with pytest.raises(ValueError, match="memory_store must be an instance of CogneeMemoryStore"): + CogneeRetriever(memory_store="not a store") # type: ignore[arg-type] + def test_init_defaults(self): - retriever = CogneeRetriever() - assert retriever.search_type == "GRAPH_COMPLETION" - assert retriever.top_k == 10 - assert retriever.dataset_name is None + store = CogneeMemoryStore() + retriever = CogneeRetriever(memory_store=store) + assert retriever._memory_store is store + assert retriever._top_k is None - def test_init_custom(self): - retriever = CogneeRetriever(search_type="CHUNKS", top_k=5, dataset_name="my_data") - assert retriever.search_type == "CHUNKS" - assert retriever.top_k == 5 - assert retriever.dataset_name == "my_data" + def test_init_with_top_k(self): + store = CogneeMemoryStore() + retriever = CogneeRetriever(memory_store=store, top_k=3) + assert retriever._top_k == 3 def test_to_dict(self): - retriever = CogneeRetriever(search_type="SUMMARIES", top_k=3, dataset_name="ds") + store = CogneeMemoryStore(search_type="SUMMARIES", top_k=3, dataset_name="ds") + retriever = CogneeRetriever(memory_store=store, top_k=7) data = retriever.to_dict() assert data["type"] == "haystack_integrations.components.retrievers.cognee.memory_retriever.CogneeRetriever" - assert data["init_parameters"]["search_type"] == "SUMMARIES" - assert data["init_parameters"]["top_k"] == 3 - assert data["init_parameters"]["dataset_name"] == "ds" + assert data["init_parameters"]["top_k"] == 7 + assert ( + data["init_parameters"]["memory_store"]["type"] + == "haystack_integrations.memory_stores.cognee.memory_store.CogneeMemoryStore" + ) + assert data["init_parameters"]["memory_store"]["init_parameters"]["dataset_name"] == "ds" def test_from_dict(self): data = { "type": "haystack_integrations.components.retrievers.cognee.memory_retriever.CogneeRetriever", - "init_parameters": {"search_type": "CHUNKS", "top_k": 7, "dataset_name": None}, + "init_parameters": { + "top_k": 5, + "memory_store": { + "type": "haystack_integrations.memory_stores.cognee.memory_store.CogneeMemoryStore", + "init_parameters": { + "search_type": "CHUNKS", + "top_k": 8, + "dataset_name": "restored", + }, + }, + }, } retriever = CogneeRetriever.from_dict(data) - assert retriever.search_type == "CHUNKS" - assert retriever.top_k == 7 - - @patch("haystack_integrations.components.retrievers.cognee.memory_retriever.cognee") - def test_run_returns_documents(self, mock_cognee): - mock_cognee.search = AsyncMock(return_value=["result one", "result two"]) - - retriever = CogneeRetriever(search_type="GRAPH_COMPLETION", top_k=5) + assert retriever._top_k == 5 + assert isinstance(retriever._memory_store, CogneeMemoryStore) + assert retriever._memory_store.search_type == "CHUNKS" + assert retriever._memory_store.dataset_name == "restored" + + def test_run_delegates_to_store(self): + store = MagicMock(spec=CogneeMemoryStore) + store.search_memories.return_value = [ + ChatMessage.from_system("result one"), + ChatMessage.from_system("result two"), + ] + + retriever = CogneeRetriever(memory_store=store) result = retriever.run(query="What is Cognee?") + store.search_memories.assert_called_once_with(query="What is Cognee?", user_id=None) docs = result["documents"] assert len(docs) == 2 assert docs[0].content == "result one" assert docs[0].meta["source"] == "cognee" - @patch("haystack_integrations.components.retrievers.cognee.memory_retriever.cognee") - def test_run_empty_results(self, mock_cognee): - mock_cognee.search = AsyncMock(return_value=[]) + def test_run_forwards_top_k_override(self): + store = MagicMock(spec=CogneeMemoryStore) + store.search_memories.return_value = [] - retriever = CogneeRetriever() - result = retriever.run(query="nonexistent query") + retriever = CogneeRetriever(memory_store=store, top_k=10) + retriever.run(query="q", top_k=2) - assert result["documents"] == [] + store.search_memories.assert_called_once_with(query="q", user_id=None, top_k=2) - @patch("haystack_integrations.components.retrievers.cognee.memory_retriever.cognee") - def test_run_respects_top_k_override(self, mock_cognee): - mock_cognee.search = AsyncMock(return_value=["a", "b", "c", "d", "e"]) + def test_run_uses_retriever_default_top_k(self): + store = MagicMock(spec=CogneeMemoryStore) + store.search_memories.return_value = [] - retriever = CogneeRetriever(top_k=10) - result = retriever.run(query="test", top_k=2) + retriever = CogneeRetriever(memory_store=store, top_k=4) + retriever.run(query="q") - assert len(result["documents"]) == 2 + store.search_memories.assert_called_once_with(query="q", user_id=None, top_k=4) - @patch("haystack_integrations.components.retrievers.cognee.memory_retriever.cognee") - def test_run_handles_dict_results(self, mock_cognee): - mock_cognee.search = AsyncMock( - return_value=[ - {"content": "Dict content", "score": 0.9}, - {"text": "Alt text field"}, - ] - ) + def test_run_forwards_user_id(self): + store = MagicMock(spec=CogneeMemoryStore) + store.search_memories.return_value = [] + + retriever = CogneeRetriever(memory_store=store) + retriever.run(query="q", user_id="550e8400-e29b-41d4-a716-446655440000") - retriever = CogneeRetriever() - result = retriever.run(query="test") + store.search_memories.assert_called_once_with( + query="q", + user_id="550e8400-e29b-41d4-a716-446655440000", + ) - assert len(result["documents"]) == 2 - assert result["documents"][0].content == "Dict content" - assert result["documents"][1].content == "Alt text field" + def test_run_empty_results(self): + store = MagicMock(spec=CogneeMemoryStore) + store.search_memories.return_value = [] - @patch("haystack_integrations.components.retrievers.cognee.memory_retriever.cognee") - def test_run_handles_none_results(self, mock_cognee): - mock_cognee.search = AsyncMock(return_value=None) + retriever = CogneeRetriever(memory_store=store) + result = retriever.run(query="nonexistent query") - retriever = CogneeRetriever() - result = retriever.run(query="test") assert result["documents"] == [] + + def test_run_skips_messages_with_empty_text(self): + store = MagicMock(spec=CogneeMemoryStore) + store.search_memories.return_value = [ + ChatMessage.from_system("valid"), + ChatMessage.from_system(""), + ] + + retriever = CogneeRetriever(memory_store=store) + result = retriever.run(query="q") + + assert len(result["documents"]) == 1 + assert result["documents"][0].content == "valid" diff --git a/integrations/cognee/tests/test_writer.py b/integrations/cognee/tests/test_writer.py index c8acc499af..888f87f7d6 100644 --- a/integrations/cognee/tests/test_writer.py +++ b/integrations/cognee/tests/test_writer.py @@ -2,7 +2,7 @@ # # SPDX-License-Identifier: Apache-2.0 -from unittest.mock import AsyncMock, patch +from unittest.mock import AsyncMock, MagicMock, patch from haystack import Document @@ -100,3 +100,36 @@ def test_run_empty_list(self, mock_cognee): assert result == {"documents_written": 0} mock_cognee.add.assert_not_awaited() mock_cognee.cognify.assert_not_awaited() + + @patch("haystack_integrations.components.writers.cognee.memory_writer._get_cognee_user", new_callable=AsyncMock) + @patch("haystack_integrations.components.writers.cognee.memory_writer.cognee") + def test_run_with_user_id(self, mock_cognee, mock_get_user): + mock_user = MagicMock() + mock_get_user.return_value = mock_user + mock_cognee.add = AsyncMock() + mock_cognee.cognify = AsyncMock() + + writer = CogneeWriter(dataset_name="test", auto_cognify=True) + writer.run( + documents=[Document(content="hello")], + user_id="550e8400-e29b-41d4-a716-446655440000", + ) + + mock_get_user.assert_awaited_once_with("550e8400-e29b-41d4-a716-446655440000") + add_kwargs = mock_cognee.add.call_args[1] + assert add_kwargs["user"] is mock_user + cognify_kwargs = mock_cognee.cognify.call_args[1] + assert cognify_kwargs["user"] is mock_user + + @patch("haystack_integrations.components.writers.cognee.memory_writer.cognee") + def test_run_without_user_id(self, mock_cognee): + mock_cognee.add = AsyncMock() + mock_cognee.cognify = AsyncMock() + + writer = CogneeWriter(dataset_name="test", auto_cognify=True) + writer.run(documents=[Document(content="hello")]) + + add_kwargs = mock_cognee.add.call_args[1] + assert add_kwargs["user"] is None + cognify_kwargs = mock_cognee.cognify.call_args[1] + assert cognify_kwargs["user"] is None From 94c01d17acbb1ff8115750f6fdc1bbdd7c7d4b30 Mon Sep 17 00:00:00 2001 From: Hande <159312713+hande-k@users.noreply.github.com> Date: Tue, 12 May 2026 19:30:35 +0200 Subject: [PATCH 08/10] rework against cognee 1.0 API and agent-memory pattern --- .github/workflows/cognee.yml | 19 +- .../.artifacts/demo_memory_agent.html | 1450 ----------------- .../examples/.artifacts/demo_pipeline.html | 1450 ----------------- integrations/cognee/examples/README.md | 35 +- .../cognee/examples/demo_memory_agent.py | 317 ++-- integrations/cognee/examples/demo_pipeline.py | 183 --- .../cognee/pydoc/config_docusaurus.yml | 1 - integrations/cognee/pyproject.toml | 11 +- .../components/connectors/cognee/__init__.py | 9 - .../components/connectors/cognee/_utils.py | 126 -- .../components/connectors/cognee/cognifier.py | 89 - .../components/connectors/py.typed | 0 .../retrievers/cognee/memory_retriever.py | 82 +- .../writers/cognee/memory_writer.py | 101 +- .../memory_stores/cognee/memory_store.py | 314 ++-- integrations/cognee/tests/test_cognifier.py | 80 - integrations/cognee/tests/test_integration.py | 130 +- .../cognee/tests/test_memory_store.py | 299 ++-- integrations/cognee/tests/test_retriever.py | 71 +- integrations/cognee/tests/test_utils.py | 99 -- integrations/cognee/tests/test_writer.py | 176 +- 21 files changed, 804 insertions(+), 4238 deletions(-) delete mode 100644 integrations/cognee/examples/.artifacts/demo_memory_agent.html delete mode 100644 integrations/cognee/examples/.artifacts/demo_pipeline.html delete mode 100644 integrations/cognee/examples/demo_pipeline.py delete mode 100644 integrations/cognee/src/haystack_integrations/components/connectors/cognee/__init__.py delete mode 100644 integrations/cognee/src/haystack_integrations/components/connectors/cognee/_utils.py delete mode 100644 integrations/cognee/src/haystack_integrations/components/connectors/cognee/cognifier.py delete mode 100644 integrations/cognee/src/haystack_integrations/components/connectors/py.typed delete mode 100644 integrations/cognee/tests/test_cognifier.py delete mode 100644 integrations/cognee/tests/test_utils.py diff --git a/.github/workflows/cognee.yml b/.github/workflows/cognee.yml index d4441fb7b1..d00696263c 100644 --- a/.github/workflows/cognee.yml +++ b/.github/workflows/cognee.yml @@ -10,6 +10,13 @@ on: - "integrations/cognee/**" - "!integrations/cognee/*.md" - ".github/workflows/cognee.yml" + push: + branches: + - main + paths: + - "integrations/cognee/**" + - "!integrations/cognee/*.md" + - ".github/workflows/cognee.yml" defaults: run: @@ -22,6 +29,8 @@ concurrency: env: PYTHONUNBUFFERED: "1" FORCE_COLOR: "1" + # cognee runs an LLM internally for remember/recall/improve; the integration suite needs a key. + LLM_API_KEY: ${{ secrets.OPENAI_API_KEY }} jobs: run: @@ -52,8 +61,11 @@ jobs: if: matrix.python-version == '3.10' && runner.os == 'Linux' run: hatch run fmt-check && hatch run test:types - - name: Run tests - run: hatch run test:cov-retry + - name: Run unit tests + run: hatch run test:unit-cov-retry + + - name: Run integration tests + run: hatch run test:integration-cov-append-retry - name: Run unit tests with lowest direct dependencies run: | @@ -66,7 +78,8 @@ jobs: run: | hatch env prune hatch -e test env run -- uv pip install git+https://github.com/deepset-ai/haystack.git@main - hatch run test:cov-retry + hatch run test:unit-cov-retry + hatch run test:integration-cov-append-retry notify-slack-on-failure: diff --git a/integrations/cognee/examples/.artifacts/demo_memory_agent.html b/integrations/cognee/examples/.artifacts/demo_memory_agent.html deleted file mode 100644 index 1a31dda784..0000000000 --- a/integrations/cognee/examples/.artifacts/demo_memory_agent.html +++ /dev/null @@ -1,1450 +0,0 @@ - - - - - -Cognee Knowledge Graph - - - - - - - - - -
- - - - - -
- Color: - - - - - -
- - - -
- -
-
- -
-
Laying out graph...
-
-
-
- -
-
- - - - - - \ No newline at end of file diff --git a/integrations/cognee/examples/.artifacts/demo_pipeline.html b/integrations/cognee/examples/.artifacts/demo_pipeline.html deleted file mode 100644 index cf72ecd59c..0000000000 --- a/integrations/cognee/examples/.artifacts/demo_pipeline.html +++ /dev/null @@ -1,1450 +0,0 @@ - - - - - -Cognee Knowledge Graph - - - - - - - - - -
- - - - - -
- Color: - - - - - -
- - - -
- -
-
- -
-
Laying out graph...
-
-
-
- -
-
- - - - - - \ No newline at end of file diff --git a/integrations/cognee/examples/README.md b/integrations/cognee/examples/README.md index d4ef44805b..718a4b2b2f 100644 --- a/integrations/cognee/examples/README.md +++ b/integrations/cognee/examples/README.md @@ -8,32 +8,33 @@ Install the integration from the repository root: pip install -e "integrations/cognee" ``` -Set your LLM API key (required by cognee, default OpenAI API key): - -To integrate other LLM providers and other configuration options, see [Cognee Documentation](https://docs.cognee.ai/getting-started/installation#environment-configuration). - +Set the keys used by cognee and by Haystack's `OpenAIChatGenerator`: ```bash -export LLM_API_KEY="sk-your-openai-api-key" +export LLM_API_KEY="sk-your-openai-api-key" # cognee: remember/recall/improve +export EMBEDDING_API_KEY="sk-your-openai-api-key" # cognee: embeddings (often same key) +export OPENAI_API_KEY="sk-your-openai-api-key" # Haystack OpenAIChatGenerator (Agent) ``` -## Examples - -### Pipeline Demo (`demo_pipeline.py`) +In practice all three can point at the same OpenAI key. For other LLM providers and full +configuration options, see [Cognee Documentation](https://docs.cognee.ai/getting-started/installation#environment-configuration). -Demonstrates batch document ingestion with `CogneeWriter` (auto_cognify disabled), -followed by a single `CogneeCognifier` pass, then retrieval with `CogneeRetriever`. -Also shows the same flow wired as a connected Haystack Pipeline. +cognee's session cache is on by default (`CACHING=true`, `CACHE_BACKEND=fs`); set +`CACHE_BACKEND=redis` plus `CACHE_HOST` / `CACHE_PORT` / `CACHE_USERNAME` / +`CACHE_PASSWORD` to point at a Redis instance instead. -```bash -python integrations/cognee/examples/demo_pipeline.py -``` +## Examples ### Memory Agent Demo (`demo_memory_agent.py`) -Demonstrates `CogneeMemoryStore` with per-user memory scoping via `user_id`: -- Two users store private memories that are isolated from each other. -- A shared dataset is created and read access is granted across users. +Wires `CogneeRetriever`, `CogneeMemoryStore`, and `CogneeWriter` around Haystack's +`Agent` to enrich every conversation turn with persistent memory, in four phases: + +1. `persistent_writer` seeds long-lived facts into the permanent graph. +2. `session_writer` seeds session-only context (`session_id=...`). +3. Agent loop: `CogneeRetriever` calls `cognee.recall(query, session_id=...)` which + auto-captures each turn as a QA entry in the session — no writer in the pipeline. +4. `chat_store.improve()` promotes the session into the permanent graph. ```bash python integrations/cognee/examples/demo_memory_agent.py diff --git a/integrations/cognee/examples/demo_memory_agent.py b/integrations/cognee/examples/demo_memory_agent.py index 04b009a71f..e6074eb544 100644 --- a/integrations/cognee/examples/demo_memory_agent.py +++ b/integrations/cognee/examples/demo_memory_agent.py @@ -1,148 +1,203 @@ #!/usr/bin/env python """ -Demo: Cognee as a Memory Backend with User-Scoped Access - -Shows how CogneeMemoryStore supports per-user memory isolation via user_id, -matching the MemoryStore protocol pattern used by Haystack's experimental Agent. +Minimal cognee-haystack demo — persistent vs session memory in four phases. + +Phase 1 — `persistent_writer` (no `session_id`) seeds long-lived facts into + cognee's permanent knowledge graph. +Phase 2 — `session_writer` (`session_id=...`) seeds session-only context into + cognee's session cache. The graph itself doesn't change. +Phase 3 — Agent loop: `CogneeRetriever` calls `cognee.recall(query, session_id=...)` + which auto-captures each turn as a QA entry in the session. **No + CogneeWriter in the pipeline** — cognee's recall is the session-write + path per the docs. +Phase 4 — `chat_store.improve()` promotes the session into the permanent + graph via `cognee.improve(dataset=..., session_ids=[...])`. + +Environment (loaded from repo-root .env): + LLM_API_KEY Required. cognee's LLM provider key. + EMBEDDING_API_KEY Optional; defaults to LLM_API_KEY when unset. + OPENAI_API_KEY Required. Used by Haystack's OpenAIChatGenerator. + +Run: + cd integrations/cognee + .venv/bin/hatch run test:python examples/demo_memory_agent.py +""" -Two users (Alice and Bob) each store private memories. Then Alice creates a -shared dataset and grants Bob read access, demonstrating cross-user sharing. +import asyncio +import logging +import os +from pathlib import Path -Note: This demo uses cognee's user management APIs directly for setup (creating -users, granting permissions). These are admin operations outside the Haystack -integration's scope. In production, user management would typically be handled -by the application layer or cognee's API server. +from dotenv import load_dotenv -Prerequisites: - pip install -e "integrations/cognee" +os.environ.setdefault("LOG_LEVEL", "WARNING") -Set your LLM API key: - export LLM_API_KEY="sk-..." -""" - -import asyncio +# Load .env from the repo root before cognee imports read any config. +load_dotenv(Path(__file__).resolve().parents[3] / ".env", override=True) import cognee -from cognee.modules.data.methods import get_authorized_existing_datasets -from cognee.modules.engine.operations.setup import setup -from cognee.modules.users.methods import create_user -from cognee.modules.users.permissions.methods import give_permission_on_dataset +from cognee.api.v1.visualize import visualize_multi_user_graph +from cognee.modules.users.methods import get_default_user +from haystack import Pipeline +from haystack.components.agents import Agent +from haystack.components.converters import OutputAdapter +from haystack.components.generators.chat import OpenAIChatGenerator from haystack.dataclasses import ChatMessage +from haystack_integrations.components.retrievers.cognee import CogneeRetriever +from haystack_integrations.components.writers.cognee import CogneeWriter from haystack_integrations.memory_stores.cognee import CogneeMemoryStore - -async def main(): - print("=== Cognee Memory Store — User Scoping Demo ===\n") - - # --- Setup: clean slate and create two users --- - print("Setup: Pruning all data and creating users...") - await cognee.prune.prune_data() - await cognee.prune.prune_system(metadata=True) - - # Re-create the database schema after pruning (prune_system drops all tables) - await setup() - - alice = await create_user("alice@example.com", "password", is_verified=True) - bob = await create_user("bob@example.com", "password", is_verified=True) - alice_id = str(alice.id) - bob_id = str(bob.id) - print(f" Created Alice (id={alice_id[:8]}...) and Bob (id={bob_id[:8]}...)\n") - - # ========================================================================= - # Part 1: Private memories — each user can only see their own - # ========================================================================= - print("--- Part 1: Private memories (user isolation) ---\n") - - alice_store = CogneeMemoryStore(search_type="GRAPH_COMPLETION", dataset_name="alice_notes") - bob_store = CogneeMemoryStore(search_type="GRAPH_COMPLETION", dataset_name="bob_notes") - - # Alice adds her private memories - print("Alice adds memories to 'alice_notes'...") - alice_store.add_memories( - messages=[ - ChatMessage.from_user("The project deadline is next Friday."), - ], - user_id=alice_id, - ) - print(" Done.\n") - - # Bob adds his private memories - print("Bob adds memories to 'bob_notes'...") - bob_store.add_memories( - messages=[ - ChatMessage.from_user("The client meeting is on Wednesday at 2pm."), - ChatMessage.from_user("The new API endpoint needs authentication."), - ], - user_id=bob_id, +# cognee binds its graph engine to whichever event loop touches it first. +# Route the demo's direct cognee calls through the integration's background +# loop so reads and writes share state. +from haystack_integrations.memory_stores.cognee.memory_store import _run_sync + +logging.basicConfig(level=logging.WARNING) + +DATASET = "agent_memory_minimal" +SESSION = "alice_chat_42" + +ARTIFACTS = Path(__file__).resolve().parent / "graph_snapshots" +ARTIFACTS.mkdir(exist_ok=True) + +# Long-lived facts +PERSISTENT_MEMORIES = [ + "My name is Alice. I'm a senior data scientist at Acme Corp specialising in NLP and knowledge graphs.", + "My current project is building an internal documentation search system powered by Haystack and Cognee.", + "My team: Bob is the ML engineer and Carol handles infrastructure.", + "I prefer concise answers with Python code examples over long prose explanations.", +] + +# Session-only context +SESSION_MEMORIES = [ + "Bob is having trouble with the new documentation search system.", + "Carol helps Bob troubleshoot the issue.", +] + +SYSTEM_PROMPT = ( + "You are a helpful assistant with access to persistent memory of past conversations. " + "Any system messages at the start of the conversation contain relevant memories. " + "Be concise; prefer short answers and Python code examples." +) + + +async def _visualize_all_datasets(destination_file_path: str) -> None: + """Render a combined graph across every dataset the default user can read. + + Uses `cognee.visualize_multi_user_graph` with explicit `(user, dataset)` pairs + so each dataset's graph is read inside its own database context. Works whether + or not `ENABLE_BACKEND_ACCESS_CONTROL` is enabled. + """ + user = await get_default_user() + datasets = await cognee.datasets.list_datasets(user=user) + pairs = [(user, ds) for ds in datasets] + await visualize_multi_user_graph(pairs, destination_file_path=destination_file_path) + + +def build_pipeline(chat_store: CogneeMemoryStore) -> Pipeline: + """Retriever → injector → agent. No writer: cognee.recall auto-captures the session QA.""" + pipeline = Pipeline() + pipeline.add_component("retriever", CogneeRetriever(memory_store=chat_store)) + pipeline.add_component( + "injector", + OutputAdapter( + template="{{ memories + user_messages }}", + output_type=list[ChatMessage], + unsafe=True, + ), ) - print(" Done.\n") - - # Alice searches her own store — should find results - print("Alice searches her own store for 'project deadline':") - results = alice_store.search_memories(query="What is the project deadline?", user_id=alice_id) - print(f" Found {len(results)} result(s)") - for i, msg in enumerate(results, 1): - print(f" [{i}] {msg.text}") - print() - - # Bob searches his own store — should find results - print("Bob searches his own store for 'client meeting':") - results = bob_store.search_memories(query="When is the client meeting?", user_id=bob_id) - print(f" Found {len(results)} result(s)") - for i, msg in enumerate(results, 1): - print(f" [{i}] {msg.text}") - print() - - # Alice searches Bob's store — should find nothing (no permission) - print("Alice tries to search Bob's store (no permission):") - results = bob_store.search_memories(query="When is the client meeting?", user_id=alice_id) - print(f" Found {len(results)} result(s) — access is isolated!\n") - - # Bob searches Alice's store — should find nothing (no permission) - print("Bob tries to search Alice's store (no permission):") - results = alice_store.search_memories(query="What is the project deadline?", user_id=bob_id) - print(f" Found {len(results)} result(s) — access is isolated!\n") - - # ========================================================================= - # Part 2: Shared dataset — Alice creates it, grants Bob read access - # ========================================================================= - print("--- Part 2: Shared dataset ---\n") - - shared_store = CogneeMemoryStore(search_type="GRAPH_COMPLETION", dataset_name="team_shared") - - # Alice adds to the shared dataset (she becomes the owner) - print("Alice adds memories to 'team_shared'...") - shared_store.add_memories( - messages=[ - ChatMessage.from_user("The team standup is every morning at 9am."), - ChatMessage.from_user("Our tech stack is Python, Haystack, and Cognee."), - ], - user_id=alice_id, + pipeline.add_component( + "agent", + Agent( + chat_generator=OpenAIChatGenerator(model="gpt-4o-mini"), + system_prompt=SYSTEM_PROMPT, + ), ) - print(" Done.\n") - - # Bob tries to search the shared store BEFORE getting permission — should find nothing - print("Bob tries to search 'team_shared' BEFORE permission:") - results = shared_store.search_memories(query="When is the team standup?", user_id=bob_id) - print(f" Found {len(results)} result(s) — no access yet.\n") - - # Grant Bob read permission on the shared dataset - print("Alice grants Bob read access to 'team_shared'...") - shared_datasets = await get_authorized_existing_datasets(["team_shared"], "read", alice) - shared_dataset_id = shared_datasets[0].id - await give_permission_on_dataset(bob, shared_dataset_id, "read") - print(" Done.\n") - - # Bob searches via the MemoryStore — the store automatically resolves shared datasets - print("Bob searches 'team_shared' AFTER getting read permission:") - results = shared_store.search_memories(query="When is the team standup?", user_id=bob_id) - print(f" Found {len(results)} result(s)") - for i, msg in enumerate(results, 1): - print(f" [{i}] {msg.text}") - print() - - print("=== Done ===") + pipeline.connect("retriever.messages", "injector.memories") + pipeline.connect("injector.output", "agent.messages") + return pipeline + + +async def main() -> None: + # Direct `cognee.forget(everything=True)` instead of `store.delete_all_memories()`: + # the protocol method is dataset-scoped and leaves the session cache alone, but at + # demo start we want a global wipe including any leftover session entries. + print("Forgetting previous data for a clean start...") + _run_sync(cognee.forget(everything=True)) + print("Done.\n") + + # One store, two writers — `session_id` on the writer picks the tier. + # `self_improvement=False` keeps Phase 4's `improve()` as the only improve + # trigger; otherwise cognee runs improve per write and we'd see duplicated + # nodes after the explicit improve. + seed_store = CogneeMemoryStore(dataset_name=DATASET, self_improvement=False) + + # ─── Phase 1: persistent seed (writer has no session_id) ─────────────────── + print(f"Phase 1: persistent_writer -> permanent graph ({len(PERSISTENT_MEMORIES)} facts)...") + persistent_writer = CogneeWriter(memory_store=seed_store) + persistent_writer.run(messages=[ChatMessage.from_user(fact) for fact in PERSISTENT_MEMORIES]) + + snapshot_1 = ARTIFACTS / "1_after_persistent_seed.html" + _run_sync(_visualize_all_datasets(str(snapshot_1))) + print(f" Graph snapshot -> {snapshot_1}\n") + + # ─── Phase 2: session seed (writer has session_id set) ───────────────────── + print(f"Phase 2: session_writer -> session cache ({len(SESSION_MEMORIES)} facts)...") + session_writer = CogneeWriter(memory_store=seed_store, session_id=SESSION) + session_writer.run(messages=[ChatMessage.from_user(fact) for fact in SESSION_MEMORIES]) + + snapshot_2 = ARTIFACTS / "2_after_session_seed.html" + _run_sync(_visualize_all_datasets(str(snapshot_2))) + print(f" Graph snapshot -> {snapshot_2}") + print(" (Session writes don't touch the graph — should look like snapshot 1.)\n") + + # ─── Phase 3: agent loop (no writer; cognee.recall auto-captures the session QA) ── + print("Phase 3: agent loop (retriever -> injector -> agent)\n") + # Session-scoped store so the retriever's recall is session-aware. + chat_store = CogneeMemoryStore(dataset_name=DATASET, session_id=SESSION) + pipeline = build_pipeline(chat_store) + + turns = [ + "Hi! Can you remind me what project I'm currently working on?", + "What's the tech stack we're using for it?", + "Who else is on my team, and what are their roles?", + "Based on what you know about me, give me a quick tip for structuring a new Haystack pipeline component.", + ] + for user_text in turns: + print(f"User: {user_text}") + result = pipeline.run( + { + "retriever": {"query": user_text}, + "injector": {"user_messages": [ChatMessage.from_user(user_text)]}, + } + ) + reply = result["agent"]["last_message"].text or "(no reply)" + print(f"Agent: {reply}\n") + + snapshot_3 = ARTIFACTS / "3_after_chat.html" + _run_sync(_visualize_all_datasets(str(snapshot_3))) + print(f" Graph snapshot -> {snapshot_3}") + print(" (Still graph-unchanged: session writes from recall live in the cache.)\n") + + print("--- Session cache contents (cognee.session.get_session) ---") + entries = _run_sync(cognee.session.get_session(session_id=SESSION)) + print(f"{len(entries)} entries in session {SESSION!r}") + for i, e in enumerate(entries, 1): + print(f"\n[{i}] qa_id={e.qa_id} time={e.time}") + print(f" question: {e.question!r}") + print(f" answer : {e.answer!r}") + + # ─── Phase 4: improve session -> permanent graph ────────────────────────── + print(f"\nPhase 4: chat_store.improve() -> cognee.improve(dataset={DATASET!r}, session_ids=[{SESSION!r}])...") + chat_store.improve() + + snapshot_4 = ARTIFACTS / "4_after_improve.html" + _run_sync(_visualize_all_datasets(str(snapshot_4))) + print(f" Graph snapshot -> {snapshot_4}") + print(" (Graph now includes session-derived nodes.)") + + print("\nDone.") if __name__ == "__main__": diff --git a/integrations/cognee/examples/demo_pipeline.py b/integrations/cognee/examples/demo_pipeline.py deleted file mode 100644 index 08d6577179..0000000000 --- a/integrations/cognee/examples/demo_pipeline.py +++ /dev/null @@ -1,183 +0,0 @@ -#!/usr/bin/env python -""" -Demo: Cognee + Haystack Pipeline — Writer, Cognifier, Retriever - -Demonstrates two ingestion strategies with CogneeWriter: - -1. auto_cognify=True (default) — each writer.run() call adds documents AND - immediately cognifies them into the knowledge graph. Simple but slower - when ingesting many batches, because cognify runs after every add. - -2. auto_cognify=False + CogneeCognifier — documents are added quickly in - multiple batches without building the knowledge graph. Then CogneeCognifier - processes the entire dataset once. This is faster for bulk ingestion. - -Both strategies produce the same result: a searchable knowledge graph that -CogneeRetriever can query. - -Prerequisites: - pip install -e "integrations/cognee" - -Set your LLM API key (Cognee uses it internally): - export LLM_API_KEY="sk-..." -""" - -import asyncio - -import cognee -from haystack import Document, Pipeline - -from haystack_integrations.components.connectors.cognee import CogneeCognifier -from haystack_integrations.components.retrievers.cognee import CogneeRetriever -from haystack_integrations.components.writers.cognee import CogneeWriter -from haystack_integrations.memory_stores.cognee import CogneeMemoryStore - -DOCS_BATCH_1 = [ - Document( - content=( - "Cognee is an open-source memory for AI agents. It builds a knowledge engine " - "that transforms raw data into a persistent, rich, and traceable memory that is " - "searchable by meaning and relationships." - ), - ), - Document( - content=( - "Haystack is an open-source LLM framework by deepset for building production-ready " - "RAG pipelines, agents, and search systems. It uses a component-based architecture " - "where each step is a composable building block." - ), - ), -] - -DOCS_BATCH_2 = [ - Document( - content=( - "Knowledge graphs represent information as nodes (entities) and edges (relationships). " - "They enable semantic search, reasoning, and discovery of hidden connections across " - "large document collections." - ), - ), - Document( - content=( - "The engineering team at Acme Corp consists of Alice (backend lead), Bob (ML engineer), " - "and Carol (infrastructure). They are building a next-generation search platform " - "powered by knowledge graphs and LLMs." - ), - ), -] - -SEARCH_QUERIES = [ - "What is Cognee and what does it do?", - "Who is on the engineering team at Acme Corp?", - "How do knowledge graphs work?", -] - - -def search_and_print(retriever, queries): - for query in queries: - print(f" Query: '{query}'") - result = retriever.run(query=query) - docs = result["documents"] - print(f" Found {len(docs)} result(s):") - for i, doc in enumerate(docs, 1): - print(f" [{i}] {doc.content}...") - print() - - -async def main(): - print("=== Cognee + Haystack Pipeline Demo ===\n") - - # ========================================================================= - # Part 1: auto_cognify=True — add + cognify on every call - # - # Each writer.run() both adds the documents AND cognifies the dataset. - # Simple for small ingestion, but cognify is the expensive step (calls - # the LLM to extract entities, build the graph, generate summaries). - # With N batches, cognify runs N times. - # ========================================================================= - print("--- Part 1: auto_cognify=True (add + cognify each batch) ---\n") - - await cognee.prune.prune_data() - await cognee.prune.prune_system(metadata=True) - - writer_auto = CogneeWriter(dataset_name="demo_auto", auto_cognify=True) - - print(f"1. Writing batch 1 ({len(DOCS_BATCH_1)} docs) — adds + cognifies...") - result = writer_auto.run(documents=DOCS_BATCH_1) - print(f" Written: {result['documents_written']} (cognify ran)\n") - - print(f"2. Writing batch 2 ({len(DOCS_BATCH_2)} docs) — adds + cognifies again...") - result = writer_auto.run(documents=DOCS_BATCH_2) - print(f" Written: {result['documents_written']} (cognify ran again)\n") - - print("3. Searching...\n") - retriever = CogneeRetriever( - memory_store=CogneeMemoryStore(search_type="GRAPH_COMPLETION", dataset_name="demo_auto") - ) - search_and_print(retriever, SEARCH_QUERIES) - - # ========================================================================= - # Part 2: auto_cognify=False + CogneeCognifier — batch add, cognify once - # - # Documents are added quickly without cognifying. Then CogneeCognifier - # processes everything in one pass. With N batches, cognify runs only once. - # ========================================================================= - print("--- Part 2: auto_cognify=False + CogneeCognifier (batch add, cognify once) ---\n") - - await cognee.prune.prune_data() - await cognee.prune.prune_system(metadata=True) - - writer_batch = CogneeWriter(dataset_name="demo_batch", auto_cognify=False) - - print(f"4. Writing batch 1 ({len(DOCS_BATCH_1)} docs) — add only, no cognify...") - result = writer_batch.run(documents=DOCS_BATCH_1) - print(f" Written: {result['documents_written']}\n") - - print(f"5. Writing batch 2 ({len(DOCS_BATCH_2)} docs) — add only, no cognify...") - result = writer_batch.run(documents=DOCS_BATCH_2) - print(f" Written: {result['documents_written']}\n") - - print("6. Cognifying the entire dataset in one pass...") - cognifier = CogneeCognifier(dataset_name="demo_batch") - result = cognifier.run() - print(f" Cognified: {result['cognified']}\n") - - print("7. Searching...\n") - retriever = CogneeRetriever( - memory_store=CogneeMemoryStore(search_type="GRAPH_COMPLETION", dataset_name="demo_batch") - ) - search_and_print(retriever, SEARCH_QUERIES) - - # ========================================================================= - # Part 3: Same batch flow wired as a Haystack Pipeline - # - # CogneeWriter(auto_cognify=False) outputs documents_written, which - # connects to CogneeCognifier's input — so cognify triggers automatically - # after the writer finishes. - # ========================================================================= - print("--- Part 3: Writer + Cognifier as a connected Pipeline ---\n") - - await cognee.prune.prune_data() - await cognee.prune.prune_system(metadata=True) - - pipeline = Pipeline() - pipeline.add_component("writer", CogneeWriter(dataset_name="demo_pipeline", auto_cognify=False)) - pipeline.add_component("cognifier", CogneeCognifier(dataset_name="demo_pipeline")) - pipeline.connect("writer.documents_written", "cognifier.documents_written") - - all_docs = DOCS_BATCH_1 + DOCS_BATCH_2 - print(f"8. Running pipeline with {len(all_docs)} documents...") - result = pipeline.run({"writer": {"documents": all_docs}}) - print(f" Cognified: {result['cognifier']['cognified']}\n") - - print("9. Searching...\n") - retriever = CogneeRetriever( - memory_store=CogneeMemoryStore(search_type="GRAPH_COMPLETION", dataset_name="demo_pipeline") - ) - search_and_print(retriever, SEARCH_QUERIES) - - print("=== Done ===") - - -if __name__ == "__main__": - asyncio.run(main()) diff --git a/integrations/cognee/pydoc/config_docusaurus.yml b/integrations/cognee/pydoc/config_docusaurus.yml index 662b1f342e..d0412a6523 100644 --- a/integrations/cognee/pydoc/config_docusaurus.yml +++ b/integrations/cognee/pydoc/config_docusaurus.yml @@ -1,6 +1,5 @@ loaders: - modules: - - haystack_integrations.components.connectors.cognee.cognifier - haystack_integrations.components.retrievers.cognee.memory_retriever - haystack_integrations.components.writers.cognee.memory_writer - haystack_integrations.memory_stores.cognee.memory_store diff --git a/integrations/cognee/pyproject.toml b/integrations/cognee/pyproject.toml index cb871c1253..faee63a1af 100644 --- a/integrations/cognee/pyproject.toml +++ b/integrations/cognee/pyproject.toml @@ -24,7 +24,7 @@ classifiers = [ ] dependencies = [ "haystack-ai>=2.24.0", - "cognee>=0.5.4,<1.0", + "cognee>=1.0.9,<2.0", ] [project.urls] @@ -66,9 +66,10 @@ dependencies = [ unit = 'pytest -m "not integration" {args:tests}' integration = 'pytest -m "integration" {args:tests}' all = 'pytest {args:tests}' -cov-retry = 'pytest --cov=haystack_integrations --reruns 3 --reruns-delay 30 -x {args:tests}' +unit-cov-retry = 'pytest --cov=haystack_integrations --reruns 3 --reruns-delay 30 -x -m "not integration" {args:tests}' +integration-cov-append-retry = 'pytest --cov=haystack_integrations --cov-append --reruns 3 --reruns-delay 30 -x -m "integration" {args:tests}' -types = "mypy -p haystack_integrations.components.connectors.cognee -p haystack_integrations.components.retrievers.cognee -p haystack_integrations.components.writers.cognee -p haystack_integrations.memory_stores.cognee {args}" +types = "mypy -p haystack_integrations.components.retrievers.cognee -p haystack_integrations.components.writers.cognee -p haystack_integrations.memory_stores.cognee {args}" [tool.mypy] install_types = true @@ -90,6 +91,8 @@ select = [ "D205", # 1 blank line required between summary line and description "D209", # Closing triple quotes go to new line "D213", # summary lines must be positioned on the second physical line of the docstring + "D417", # Missing argument descriptions in the docstring + "D419", # Docstring is empty "DTZ", "E", "EM", @@ -143,7 +146,7 @@ ban-relative-imports = "parents" [tool.ruff.lint.per-file-ignores] # Tests can use magic values, assertions, and relative imports "tests/**/*" = ["D", "PLR2004", "S101", "TID252"] -"examples/**/*" = ["D", "T201"] +"examples/**/*" = ["D", "T201", "E402"] [tool.coverage.run] source = ["haystack_integrations"] diff --git a/integrations/cognee/src/haystack_integrations/components/connectors/cognee/__init__.py b/integrations/cognee/src/haystack_integrations/components/connectors/cognee/__init__.py deleted file mode 100644 index 775c5a35e4..0000000000 --- a/integrations/cognee/src/haystack_integrations/components/connectors/cognee/__init__.py +++ /dev/null @@ -1,9 +0,0 @@ -# SPDX-FileCopyrightText: 2022-present deepset GmbH -# -# SPDX-License-Identifier: Apache-2.0 - -from .cognifier import CogneeCognifier - -__all__ = [ - "CogneeCognifier", -] diff --git a/integrations/cognee/src/haystack_integrations/components/connectors/cognee/_utils.py b/integrations/cognee/src/haystack_integrations/components/connectors/cognee/_utils.py deleted file mode 100644 index 49e8eebb24..0000000000 --- a/integrations/cognee/src/haystack_integrations/components/connectors/cognee/_utils.py +++ /dev/null @@ -1,126 +0,0 @@ -# SPDX-FileCopyrightText: 2022-present deepset GmbH -# -# SPDX-License-Identifier: Apache-2.0 - -import asyncio -import threading -from collections.abc import Coroutine -from typing import Any, Literal, TypeVar -from uuid import UUID - -from cognee.modules.users.methods import get_user # type: ignore[import-untyped] - -T = TypeVar("T") - -# Persistent background event loop for run_sync when called from an async context. -# A single loop is reused so that cognee's internal asyncio.Lock objects stay bound -# to one event loop across multiple run_sync calls. -_background_loop: asyncio.AbstractEventLoop | None = None -_background_thread: threading.Thread | None = None -_lock = threading.Lock() - -CogneeSearchType = Literal[ - "GRAPH_COMPLETION", - "RAG_COMPLETION", - "CHUNKS", - "CHUNKS_LEXICAL", - "SUMMARIES", - "TRIPLET_COMPLETION", - "GRAPH_SUMMARY_COMPLETION", - "GRAPH_COMPLETION_COT", - "GRAPH_COMPLETION_CONTEXT_EXTENSION", - "CYPHER", - "NATURAL_LANGUAGE", - "TEMPORAL", - "CODING_RULES", - "FEELING_LUCKY", -] - - -def _get_background_loop() -> asyncio.AbstractEventLoop: - """Return a persistent background event loop running in a daemon thread.""" - global _background_loop, _background_thread # noqa: PLW0603 - - with _lock: - if _background_loop is None or _background_loop.is_closed(): - _background_loop = asyncio.new_event_loop() - _background_thread = threading.Thread(target=_background_loop.run_forever, daemon=True) - _background_thread.start() - return _background_loop - - -def run_sync(coro: Coroutine[Any, Any, T]) -> T: - """ - Run an async coroutine from a synchronous context. - - If no event loop is running, uses asyncio.run() directly. - If already inside an async context, submits the coroutine to a persistent - background event loop so that cognee's internal asyncio.Lock objects remain - bound to a single loop across calls. - """ - try: - asyncio.get_running_loop() - except RuntimeError: - return asyncio.run(coro) - - # Already in an async context — submit to the persistent background loop - loop = _get_background_loop() - future = asyncio.run_coroutine_threadsafe(coro, loop) - return future.result() - - -def extract_text(item: Any) -> str: - """ - Best-effort text extraction from a Cognee search result item. - - Cognee's search results are not a single public type — depending on the - search strategy, an item can be one of three shapes (all cognee-internal): - - 1. A plain `str` — returned by LLM-completion search types - (e.g. `GRAPH_COMPLETION`, `RAG_COMPLETION`). - 2. A `dict` — returned by structured search types; the text is read from - one of the `content` / `text` / `description` / `name` keys. - 3. A cognee model object — e.g. a `DataPoint` subclass such as - `TextChunk` or `EntityType`, carrying the same attributes. - - Since these types are internal to cognee and not part of its public API, - `item` is typed as `Any` and this function probes for known shapes rather - than narrowing the type. - - :param item: A single element returned by `cognee.search(...)`. - :returns: Best-effort extracted text, falling back to `str(item)`. - """ - if isinstance(item, str): - return item - - for attr in ("content", "text", "description", "name"): - if hasattr(item, attr): - val = getattr(item, attr) - if val and isinstance(val, str): - return val - - if isinstance(item, dict): - for key in ("content", "text", "description", "name"): - if key in item and isinstance(item[key], str): - return item[key] - - return str(item) - - -async def _get_cognee_user(user_id: str) -> Any: - """ - Resolve a user_id string to a cognee User object. - - Converts the given UUID string to a cognee User via ``cognee.modules.users.methods.get_user``. - - :param user_id: UUID string identifying the cognee user. - :returns: A cognee ``User`` object. - :raises ValueError: If user_id is not a valid UUID or the user is not found. - """ - try: - uid = UUID(user_id) - except ValueError as e: - msg = f"Invalid user_id: '{user_id}' is not a valid UUID." - raise ValueError(msg) from e - - return await get_user(uid) diff --git a/integrations/cognee/src/haystack_integrations/components/connectors/cognee/cognifier.py b/integrations/cognee/src/haystack_integrations/components/connectors/cognee/cognifier.py deleted file mode 100644 index d862f442e4..0000000000 --- a/integrations/cognee/src/haystack_integrations/components/connectors/cognee/cognifier.py +++ /dev/null @@ -1,89 +0,0 @@ -# SPDX-FileCopyrightText: 2022-present deepset GmbH -# -# SPDX-License-Identifier: Apache-2.0 - -from typing import Any - -from haystack import component, default_from_dict, default_to_dict, logging - -import cognee # type: ignore[import-untyped] - -from ._utils import run_sync - -logger = logging.getLogger(__name__) - - -@component -class CogneeCognifier: - """ - Processes previously added data through Cognee's knowledge engine. - - Wraps `cognee.cognify()` as a standalone pipeline step. Cognify takes raw data - that was previously added via `cognee.add()` and transforms it into a structured - knowledge graph. The process includes: - - 1. **Document classification** — identifies the type and structure of the input data. - 2. **Text chunking** — splits documents into semantically meaningful segments. - 3. **Entity extraction** — uses an LLM to identify entities and their properties. - 4. **Relationship detection** — discovers connections between extracted entities. - 5. **Graph construction** — builds a knowledge graph with embeddings for vector search. - 6. **Summarization** — generates hierarchical summaries of the processed content. - - After cognification, the data becomes searchable via `cognee.search()` using various - strategies (graph traversal, vector similarity, summaries, etc.). - - This component is useful when you want to separate the add and cognify phases — - for example, batch-add documents first with `CogneeWriter(auto_cognify=False)`, - then cognify once. - - Usage: - ```python - from haystack import Pipeline - from haystack_integrations.components.writers.cognee import CogneeWriter - from haystack_integrations.components.connectors.cognee import CogneeCognifier - - pipeline = Pipeline() - pipeline.add_component("writer", CogneeWriter(dataset_name="my_data", auto_cognify=False)) - pipeline.add_component("cognifier", CogneeCognifier(dataset_name="my_data")) - pipeline.connect("writer.documents_written", "cognifier.documents_written") - - result = pipeline.run({"writer": {"documents": docs}}) - ``` - """ - - def __init__(self, dataset_name: str | list[str] | None = None): - """ - Initialize the CogneeCognifier. - - :param dataset_name: Optional Cognee dataset name(s) to cognify. Accepts a single - name, a list of names, or None to cognify all pending datasets. - """ - self.dataset_name = dataset_name - - @component.output_types(cognified=bool) - def run(self, documents_written: int | None = None) -> dict[str, Any]: - """ - Run cognee.cognify() to process added data into the knowledge graph. - - :param documents_written: Optional number of documents written by a preceding - CogneeWriter. Used as a pipeline connection point; cognify runs regardless - of the value, as long as data has been previously added. - :returns: Dictionary with key `cognified` set to True on success. - """ - cognify_kwargs: dict[str, Any] = {} - if self.dataset_name: - datasets = [self.dataset_name] if isinstance(self.dataset_name, str) else self.dataset_name - cognify_kwargs["datasets"] = datasets - - logger.info("Running cognee.cognify()") - run_sync(cognee.cognify(**cognify_kwargs)) - return {"cognified": True} - - def to_dict(self) -> dict[str, Any]: - """Serialize this component to a dictionary.""" - return default_to_dict(self, dataset_name=self.dataset_name) - - @classmethod - def from_dict(cls, data: dict[str, Any]) -> "CogneeCognifier": - """Deserialize a component from a dictionary.""" - return default_from_dict(cls, data) diff --git a/integrations/cognee/src/haystack_integrations/components/connectors/py.typed b/integrations/cognee/src/haystack_integrations/components/connectors/py.typed deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/integrations/cognee/src/haystack_integrations/components/retrievers/cognee/memory_retriever.py b/integrations/cognee/src/haystack_integrations/components/retrievers/cognee/memory_retriever.py index d80867ba49..418666e921 100644 --- a/integrations/cognee/src/haystack_integrations/components/retrievers/cognee/memory_retriever.py +++ b/integrations/cognee/src/haystack_integrations/components/retrievers/cognee/memory_retriever.py @@ -4,100 +4,56 @@ from typing import Any -from haystack import Document, component, default_from_dict, default_to_dict, logging +from haystack import component, default_from_dict, default_to_dict +from haystack.dataclasses import ChatMessage from haystack_integrations.memory_stores.cognee import CogneeMemoryStore -logger = logging.getLogger(__name__) - @component class CogneeRetriever: """ - Retrieves memories from a `CogneeMemoryStore` and returns them as Haystack `Document`s. - - Follows the same pattern as other Haystack retrievers (e.g. `OpenSearchBM25Retriever`): - the store is the source of truth for configuration (`search_type`, `dataset_name`, `top_k`) - and the retriever delegates the actual search call to `CogneeMemoryStore.search_memories`. - - Usage: - ```python - from haystack_integrations.memory_stores.cognee import CogneeMemoryStore - from haystack_integrations.components.retrievers.cognee import CogneeRetriever + Retrieves memories from a `CogneeMemoryStore` as `ChatMessage` instances. - store = CogneeMemoryStore(search_type="GRAPH_COMPLETION", top_k=5, dataset_name="my_data") - retriever = CogneeRetriever(memory_store=store) - results = retriever.run(query="What is Cognee?") - for doc in results["documents"]: - print(doc.content) - ``` + Configuration (`search_type`, `top_k`, `dataset_name`, `session_id`) lives on + the store; this retriever is a thin pipeline adapter over `search_memories`. """ - def __init__( - self, - *, - memory_store: CogneeMemoryStore, - top_k: int | None = None, - ): + def __init__(self, *, memory_store: CogneeMemoryStore, top_k: int | None = None): """ - Initialize the CogneeRetriever. + Initialize the retriever. - :param memory_store: An instance of `CogneeMemoryStore` to retrieve memories from. - :param top_k: Default maximum number of results to return. When `None`, the - store's own `top_k` is used. Can be overridden at runtime via `run(top_k=...)`. - :raises ValueError: If `memory_store` is not an instance of `CogneeMemoryStore`. + :param memory_store: Backing `CogneeMemoryStore` to query. + :param top_k: Default max results; falls back to the store's `top_k` when `None`. + Overridable per-call via `run`. """ if not isinstance(memory_store, CogneeMemoryStore): msg = "memory_store must be an instance of CogneeMemoryStore" raise ValueError(msg) - self._memory_store = memory_store self._top_k = top_k - @component.output_types(documents=list[Document]) + @component.output_types(messages=list[ChatMessage]) def run( self, query: str, top_k: int | None = None, user_id: str | None = None, - ) -> dict[str, list[Document]]: + ) -> dict[str, list[ChatMessage]]: """ - Search the attached `CogneeMemoryStore` and return matching memories as Documents. - - The arguments mirror `CogneeMemoryStore.search_memories` so that pipeline builders - can scope a retrieval call at runtime (e.g. per end-user). + Search the attached store and return matching memories as ChatMessages. - :param query: The search query. - :param top_k: Maximum number of results to return. Overrides the retriever's - init-time default (if set), which in turn overrides the store's default. - :param user_id: Optional cognee user UUID to scope the search to a specific user. - When `None`, cognee's default user is used. - :returns: Dictionary with key `documents` containing the search results as - Haystack `Document` objects. + :param query: Natural-language query. + :param top_k: Per-call override; falls back to init `top_k`, then the store's default. + :param user_id: Cognee user UUID; scopes the search to that user. """ effective_top_k = top_k if top_k is not None else self._top_k - search_kwargs: dict[str, Any] = {"query": query, "user_id": user_id} - if effective_top_k is not None: - search_kwargs["top_k"] = effective_top_k - - memories = self._memory_store.search_memories(**search_kwargs) - - documents = [Document(content=m.text, meta={"source": "cognee"}) for m in memories if m.text] - - logger.info( - "Cognee retriever returned {count} documents for query '{query}'", - count=len(documents), - query=query[:80], - ) - return {"documents": documents} + messages = self._memory_store.search_memories(query=query, top_k=effective_top_k, user_id=user_id) + return {"messages": messages} def to_dict(self) -> dict[str, Any]: """Serialize this component to a dictionary.""" - return default_to_dict( - self, - memory_store=self._memory_store.to_dict(), - top_k=self._top_k, - ) + return default_to_dict(self, memory_store=self._memory_store.to_dict(), top_k=self._top_k) @classmethod def from_dict(cls, data: dict[str, Any]) -> "CogneeRetriever": diff --git a/integrations/cognee/src/haystack_integrations/components/writers/cognee/memory_writer.py b/integrations/cognee/src/haystack_integrations/components/writers/cognee/memory_writer.py index 11089c01a1..f9806a35de 100644 --- a/integrations/cognee/src/haystack_integrations/components/writers/cognee/memory_writer.py +++ b/integrations/cognee/src/haystack_integrations/components/writers/cognee/memory_writer.py @@ -4,89 +4,64 @@ from typing import Any -from haystack import Document, component, default_from_dict, default_to_dict, logging +from haystack import component, default_from_dict, default_to_dict +from haystack.dataclasses import ChatMessage -import cognee # type: ignore[import-untyped] -from haystack_integrations.components.connectors.cognee._utils import _get_cognee_user, run_sync - -logger = logging.getLogger(__name__) +from haystack_integrations.memory_stores.cognee import CogneeMemoryStore @component class CogneeWriter: """ - Adds Haystack Documents to Cognee's memory. - - Wraps `cognee.add()` and optionally `cognee.cognify()` to ingest documents - and build a knowledge engine in a single pipeline step. - - Usage: - ```python - from haystack import Document - from haystack_integrations.components.writers.cognee import CogneeWriter + Persists `ChatMessage`s into a `CogneeMemoryStore`. - writer = CogneeWriter(dataset_name="my_dataset", auto_cognify=True) - writer.run(documents=[Document(content="Cognee builds AI memory.")]) - ``` + Use without `session_id` to write to the permanent graph; pass `session_id` to + target cognee's session cache for that writer's writes. The writer's + `session_id` overrides the store's own `session_id` per call, so one store can + back multiple writers writing to different tiers. """ - def __init__(self, *, dataset_name: str = "haystack", auto_cognify: bool = True): + def __init__( + self, + *, + memory_store: CogneeMemoryStore, + session_id: str | None = None, + ): """ - Initialize the CogneeWriter. + Initialize the writer. - :param dataset_name: Name of the Cognee dataset to add documents to. - :param auto_cognify: If True, automatically runs `cognee.cognify()` after adding - documents to process them into the knowledge engine. + :param memory_store: Backing `CogneeMemoryStore` to write into. + :param session_id: When set, writes go to cognee's session cache under this + id; overrides the store's `session_id` for this writer. When `None`, + falls back to the store's tier. """ - self.dataset_name = dataset_name - self.auto_cognify = auto_cognify - - @component.output_types(documents_written=int) - def run(self, documents: list[Document], user_id: str | None = None) -> dict[str, Any]: + if not isinstance(memory_store, CogneeMemoryStore): + msg = "memory_store must be an instance of CogneeMemoryStore" + raise ValueError(msg) + self._memory_store = memory_store + self._session_id = session_id + + @component.output_types(messages_written=list[ChatMessage]) + def run( + self, + messages: list[ChatMessage], + user_id: str | None = None, + ) -> dict[str, list[ChatMessage]]: """ - Add documents to Cognee and optionally cognify them. + Store `messages` in Cognee memory and pass them through unchanged. - :param documents: List of Haystack Documents to add. - :param user_id: Optional cognee user UUID to scope the ingested data to a - specific user. When provided, the data is stored under that user's - permissions. When `None`, cognee's default user is used. Exposed on - `run()` (rather than only on `__init__`) so that the same writer - instance can be reused in a pipeline for many users by passing - `user_id` at invocation time. - :returns: Dictionary with key `documents_written` indicating how many - documents were successfully added. + :param messages: Messages to persist. + :param user_id: Cognee user UUID; scopes the write to that user. """ - texts = [doc.content for doc in documents if doc.content] - skipped = len(documents) - len(texts) - if skipped > 0: - logger.warning("Skipping {count} document(s) with empty content", count=skipped) - - user = run_sync(_get_cognee_user(user_id)) if user_id else None - - if texts: - run_sync(cognee.add(texts, dataset_name=self.dataset_name, user=user)) - - written = len(texts) - - if self.auto_cognify and written > 0: - logger.info( - "Cognifying {count} documents in dataset '{dataset}'", - count=written, - dataset=self.dataset_name, - ) - run_sync(cognee.cognify(datasets=[self.dataset_name], user=user)) - - return {"documents_written": written} + self._memory_store.add_memories(messages=messages, user_id=user_id, session_id=self._session_id) + return {"messages_written": messages} def to_dict(self) -> dict[str, Any]: """Serialize this component to a dictionary.""" - return default_to_dict( - self, - dataset_name=self.dataset_name, - auto_cognify=self.auto_cognify, - ) + return default_to_dict(self, memory_store=self._memory_store.to_dict(), session_id=self._session_id) @classmethod def from_dict(cls, data: dict[str, Any]) -> "CogneeWriter": """Deserialize a component from a dictionary.""" + data["init_parameters"]["memory_store"] = CogneeMemoryStore.from_dict(data["init_parameters"]["memory_store"]) return default_from_dict(cls, data) diff --git a/integrations/cognee/src/haystack_integrations/memory_stores/cognee/memory_store.py b/integrations/cognee/src/haystack_integrations/memory_stores/cognee/memory_store.py index a39fcaaa95..b9f6b1902d 100644 --- a/integrations/cognee/src/haystack_integrations/memory_stores/cognee/memory_store.py +++ b/integrations/cognee/src/haystack_integrations/memory_stores/cognee/memory_store.py @@ -2,197 +2,269 @@ # # SPDX-License-Identifier: Apache-2.0 -from typing import Any +import asyncio +import threading +from collections.abc import Coroutine +from typing import Any, Literal, TypeVar +from uuid import UUID from haystack import default_from_dict, default_to_dict, logging from haystack.dataclasses import ChatMessage import cognee # type: ignore[import-untyped] -from cognee.api.v1.search import SearchType # type: ignore[import-untyped] -from cognee.modules.data.exceptions import DatasetNotFoundError # type: ignore[import-untyped] -from cognee.modules.users.permissions.methods import get_all_user_permission_datasets # type: ignore[import-untyped] -from haystack_integrations.components.connectors.cognee._utils import ( - CogneeSearchType, - _get_cognee_user, - extract_text, - run_sync, -) +from cognee.modules.users.methods import get_user # type: ignore[import-untyped] logger = logging.getLogger(__name__) +T = TypeVar("T") + +CogneeSearchType = Literal[ + "SUMMARIES", + "CHUNKS", + "RAG_COMPLETION", + "TRIPLET_COMPLETION", + "GRAPH_COMPLETION", + "GRAPH_COMPLETION_DECOMPOSITION", + "GRAPH_SUMMARY_COMPLETION", + "CYPHER", + "NATURAL_LANGUAGE", + "GRAPH_COMPLETION_COT", + "GRAPH_COMPLETION_CONTEXT_EXTENSION", + "FEELING_LUCKY", + "TEMPORAL", + "CODING_RULES", + "CHUNKS_LEXICAL", +] + + +# Persistent background loop reused across calls when the caller is already +# inside an event loop. cognee creates asyncio.Lock objects bound to the loop +# they're first awaited on, so a fresh loop per call would later raise +# "lock bound to a different loop" — hence one shared loop. +_background_loop: asyncio.AbstractEventLoop | None = None +_loop_lock = threading.Lock() + + +def _run_sync(coro: Coroutine[Any, Any, T]) -> T: + try: + asyncio.get_running_loop() + except RuntimeError: + return asyncio.run(coro) + + global _background_loop # noqa: PLW0603 + with _loop_lock: + if _background_loop is None or _background_loop.is_closed(): + _background_loop = asyncio.new_event_loop() + threading.Thread(target=_background_loop.run_forever, daemon=True).start() + return asyncio.run_coroutine_threadsafe(coro, _background_loop).result() + + +async def _resolve_user(user_id: str | None) -> Any: + if user_id is None: + return None + return await get_user(UUID(user_id)) + + +def _render(item: Any) -> str | None: + # cognee.recall returns a discriminated RecallResponse union — pick the right + # text field per source rather than probing attributes. + source = getattr(item, "source", None) + if source == "graph": + return item.text + if source == "session": + return item.answer or item.question or None + if source == "graph_context": + return item.content + if source == "trace": + return item.memory_context or None + return None + class CogneeMemoryStore: """ - A memory store backed by Cognee memory. + Memory backend backed by Cognee, implementing the haystack-experimental `MemoryStore` protocol. - Implements the `MemoryStore` protocol from haystack-experimental, allowing - Cognee to serve as the memory backend for Haystack's experimental Agent. + Wraps cognee's V2 memory API: `add_memories` -> `cognee.remember`, + `search_memories` -> `cognee.recall`, `improve` -> `cognee.improve`, + `delete_all_memories` -> `cognee.forget`. - Usage: - ```python - from haystack_integrations.memory_stores.cognee import CogneeMemoryStore + `session_id` selects the tier — set it to use cognee's session cache (cheap, + no LLM extraction, session-aware recall); leave `None` for the permanent + graph. - store = CogneeMemoryStore(search_type="GRAPH_COMPLETION", top_k=5) - store.add_memories(messages=[ChatMessage.from_user("Remember: the project deadline is Friday.")]) - results = store.search_memories(query="When is the project deadline?") - ``` + `self_improvement` is forwarded to `cognee.remember` and defaults to `True` + (same as cognee). On the permanent tier it awaits `improve` inline; on the + session tier it schedules `improve` as a fire-and-forget background task. + Set to `False` when you want `improve()` to be the only improve trigger + — otherwise an explicit `improve()` runs improve twice and produces + near-duplicate graph nodes. """ def __init__( - self, search_type: CogneeSearchType = "GRAPH_COMPLETION", top_k: int = 5, dataset_name: str = "haystack_memory" + self, + *, + search_type: CogneeSearchType = "GRAPH_COMPLETION", + top_k: int = 5, + dataset_name: str = "haystack_memory", + session_id: str | None = None, + self_improvement: bool = True, ): """ - Initialize the CogneeMemoryStore. + Initialize the store. - :param search_type: Cognee search type for memory retrieval. - :param top_k: Default number of results for memory search. - :param dataset_name: Cognee dataset name for storing memories. + :param search_type: Cognee search strategy used by `search_memories`. + :param top_k: Default max results for `search_memories`. + :param dataset_name: Cognee dataset backing this store. + :param session_id: When set, use the session-cache tier; otherwise the permanent graph. + :param self_improvement: Forwarded to `cognee.remember` (default `True`, matches cognee). + Set to `False` when `improve()` should be the only improve trigger. """ self.search_type = search_type self.top_k = top_k self.dataset_name = dataset_name + self.session_id = session_id + self.self_improvement = self_improvement def add_memories( self, *, messages: list[ChatMessage], user_id: str | None = None, - **kwargs: Any, + session_id: str | None = None, + **_: Any, ) -> None: """ - Add chat messages to Cognee as memories. - - :param messages: List of ChatMessages to store. - :param user_id: Optional cognee user UUID to scope memories to a specific user. - When provided, the data is stored under that user's permissions. - When `None`, cognee's default user is used (cognee falls back to its - built-in default user account so the call still succeeds). - :param kwargs: Additional keyword arguments (unused, accepted for protocol - compatibility). + Persist messages via `cognee.remember`. + + Permanent tier batches all texts into one call; session tier writes one + entry per message (matches cognee's session example). Empty messages + are skipped. + + :param messages: Messages to store. + :param user_id: Cognee user UUID; `None` uses cognee's default user. + :param session_id: Per-call override of the store's `session_id`. """ - user = run_sync(_get_cognee_user(user_id)) if user_id else None + texts = [m.text for m in messages if m.text] + if not texts: + return - added = 0 - for msg in messages: - text = msg.text - if not text: - continue - run_sync(cognee.add(text, dataset_name=self.dataset_name, user=user)) - added += 1 + target_session = session_id if session_id is not None else self.session_id - if added > 0: - run_sync(cognee.cognify(datasets=[self.dataset_name], user=user)) + async def _store() -> None: + user = await _resolve_user(user_id) + if target_session is not None: + for text in texts: + await cognee.remember( + text, + dataset_name=self.dataset_name, + session_id=target_session, + user=user, + self_improvement=self.self_improvement, + ) + else: + await cognee.remember( + texts, + dataset_name=self.dataset_name, + user=user, + self_improvement=self.self_improvement, + ) - logger.info("Added and cognified {count} messages as memories", count=added) + _run_sync(_store()) + logger.info( + "Stored {n} memories in '{ds}' (session={s})", + n=len(texts), + ds=self.dataset_name, + s=target_session, + ) def search_memories( self, *, query: str | None = None, - top_k: int = 5, + top_k: int | None = None, user_id: str | None = None, - **kwargs: Any, + **_: Any, ) -> list[ChatMessage]: """ - Search Cognee's knowledge engine for relevant memories. - - :param query: The search query. - :param top_k: Maximum number of memories to return. - :param user_id: Optional cognee user UUID to scope the search to a specific user. - Search is restricted to the store's `dataset_name`. If the user owns the - dataset it is resolved by name; otherwise the store checks whether the user - has been granted read access (e.g. via shared permissions) and searches by - dataset UUID. - When `None`, cognee's default user is used. - :param kwargs: Additional keyword arguments (unused, accepted for protocol - compatibility). - :returns: List of ChatMessages containing memory content as system messages. + Search via `cognee.recall` and wrap each hit in a system `ChatMessage`. + + :param query: Natural-language query. Empty/`None` returns `[]`. + :param top_k: Per-call override of the store's default. + :param user_id: Cognee user UUID; `None` uses cognee's default user. """ if not query: return [] - user = run_sync(_get_cognee_user(user_id)) if user_id else None - search_type_enum = SearchType[self.search_type] - effective_top_k = top_k or self.top_k - - try: - raw_results = run_sync( - cognee.search( - query_text=query, - query_type=search_type_enum, - user=user, - datasets=[self.dataset_name], - ) + async def _search() -> list[Any]: + user = await _resolve_user(user_id) + return await cognee.recall( + query, + query_type=cognee.SearchType[self.search_type], + datasets=[self.dataset_name], + top_k=top_k if top_k is not None else self.top_k, + session_id=self.session_id, + user=user, ) - except DatasetNotFoundError: - # The user doesn't own a dataset with this name. - # Fall back to checking shared datasets the user has read access to. - raw_results = self._search_shared_dataset(query, search_type_enum, user) - memories: list[ChatMessage] = [] - if not raw_results: - return memories - - for item in raw_results[:effective_top_k]: - text = extract_text(item) - if text: - memories.append(ChatMessage.from_system(text)) - - logger.info("Found {count} memories for query '{query}'", count=len(memories), query=query[:80]) + results = _run_sync(_search()) or [] + memories = [ChatMessage.from_system(text) for item in results if (text := _render(item))] + logger.info("Found {n} memories for '{q}'", n=len(memories), q=query[:80]) return memories - def _search_shared_dataset(self, query: str, search_type_enum: SearchType, user: Any) -> list[Any]: - """Search for the dataset by name among all datasets the user has read access to.""" - if user is None: - return [] - all_readable = run_sync(get_all_user_permission_datasets(user, "read")) - matching = [ds for ds in all_readable if ds.name == self.dataset_name] - if not matching: - return [] - return run_sync( - cognee.search(query_text=query, query_type=search_type_enum, user=user, dataset_ids=[matching[0].id]) - ) + def improve(self, *, session_id: str | None = None, user_id: str | None = None) -> None: + """ + Promote session-cache content into the permanent graph via `cognee.improve`. - def delete_all_memories( - self, - *, - user_id: str | None = None, - **kwargs: Any, - ) -> None: + Without any session_id this is a plain graph-enrichment pass. + + :param session_id: Session to promote; defaults to the store's `session_id`. + :param user_id: Cognee user UUID; `None` uses cognee's default user. """ - Delete all memories by pruning Cognee's data and system state. + target_session = session_id or self.session_id + + async def _improve() -> None: + user = await _resolve_user(user_id) + await cognee.improve( + dataset=self.dataset_name, + session_ids=[target_session] if target_session else None, + user=user, + ) - :param user_id: Optional cognee user UUID (accepted for protocol compatibility). - Note: Cognee's prune operations are global and not scoped to a specific user. - :param kwargs: Additional keyword arguments (unused, accepted for protocol - compatibility). + _run_sync(_improve()) + logger.info("Improved '{ds}' (session={s})", ds=self.dataset_name, s=target_session) + + def delete_all_memories(self, *, user_id: str | None = None, **_: Any) -> None: """ - run_sync(cognee.prune.prune_data()) - run_sync(cognee.prune.prune_system(metadata=True)) - logger.info("All Cognee memories pruned") + Delete this dataset via `cognee.forget(dataset=...)`. - def delete_memory(self, memory_id: str) -> None: + Session cache survives (sessions aren't dataset-scoped) — use + `cognee.forget(everything=True)` for a full wipe. """ - Delete a single memory by ID. - Not supported in V1 — Cognee's SDK does not expose fine-grained deletion. + async def _delete() -> None: + user = await _resolve_user(user_id) + await cognee.forget(dataset=self.dataset_name, user=user) - :param memory_id: The ID of the memory to delete. - :raises NotImplementedError: Always, as single-item deletion is not yet supported. - """ - msg = "CogneeMemoryStore does not support deleting individual memories in V1." + _run_sync(_delete()) + logger.info("Deleted '{ds}'", ds=self.dataset_name) + + def delete_memory(self, memory_id: str) -> None: + """Single-memory deletion is not exposed by cognee's public API yet.""" + msg = "CogneeMemoryStore does not support deleting individual memories." raise NotImplementedError(msg) def to_dict(self) -> dict[str, Any]: - """Serialize this component to a dictionary.""" + """Serialize this store for pipeline persistence.""" return default_to_dict( self, search_type=self.search_type, top_k=self.top_k, dataset_name=self.dataset_name, + session_id=self.session_id, + self_improvement=self.self_improvement, ) @classmethod def from_dict(cls, data: dict[str, Any]) -> "CogneeMemoryStore": - """Deserialize a component from a dictionary.""" + """Deserialize a store from a dict produced by `to_dict`.""" return default_from_dict(cls, data) diff --git a/integrations/cognee/tests/test_cognifier.py b/integrations/cognee/tests/test_cognifier.py deleted file mode 100644 index 4b6eea9ffc..0000000000 --- a/integrations/cognee/tests/test_cognifier.py +++ /dev/null @@ -1,80 +0,0 @@ -# SPDX-FileCopyrightText: 2022-present deepset GmbH -# -# SPDX-License-Identifier: Apache-2.0 - -from unittest.mock import AsyncMock, patch - -from haystack_integrations.components.connectors.cognee import CogneeCognifier - - -class TestCogneeCognifier: - def test_init_defaults(self): - cognifier = CogneeCognifier() - assert cognifier.dataset_name is None - - def test_init_custom_string(self): - cognifier = CogneeCognifier(dataset_name="my_data") - assert cognifier.dataset_name == "my_data" - - def test_init_custom_list(self): - cognifier = CogneeCognifier(dataset_name=["ds1", "ds2"]) - assert cognifier.dataset_name == ["ds1", "ds2"] - - def test_to_dict(self): - cognifier = CogneeCognifier(dataset_name="test_ds") - data = cognifier.to_dict() - assert data["type"] == "haystack_integrations.components.connectors.cognee.cognifier.CogneeCognifier" - assert data["init_parameters"]["dataset_name"] == "test_ds" - - def test_to_dict_defaults(self): - cognifier = CogneeCognifier() - data = cognifier.to_dict() - assert data["init_parameters"]["dataset_name"] is None - - def test_from_dict(self): - data = { - "type": "haystack_integrations.components.connectors.cognee.cognifier.CogneeCognifier", - "init_parameters": {"dataset_name": "restored"}, - } - cognifier = CogneeCognifier.from_dict(data) - assert cognifier.dataset_name == "restored" - - @patch("haystack_integrations.components.connectors.cognee.cognifier.cognee") - def test_run_no_dataset(self, mock_cognee): - mock_cognee.cognify = AsyncMock() - - cognifier = CogneeCognifier() - result = cognifier.run() - - assert result == {"cognified": True} - mock_cognee.cognify.assert_awaited_once_with() - - @patch("haystack_integrations.components.connectors.cognee.cognifier.cognee") - def test_run_with_string_dataset(self, mock_cognee): - mock_cognee.cognify = AsyncMock() - - cognifier = CogneeCognifier(dataset_name="my_data") - result = cognifier.run() - - assert result == {"cognified": True} - mock_cognee.cognify.assert_awaited_once_with(datasets=["my_data"]) - - @patch("haystack_integrations.components.connectors.cognee.cognifier.cognee") - def test_run_with_list_dataset(self, mock_cognee): - mock_cognee.cognify = AsyncMock() - - cognifier = CogneeCognifier(dataset_name=["ds1", "ds2"]) - result = cognifier.run() - - assert result == {"cognified": True} - mock_cognee.cognify.assert_awaited_once_with(datasets=["ds1", "ds2"]) - - @patch("haystack_integrations.components.connectors.cognee.cognifier.cognee") - def test_run_with_documents_written_input(self, mock_cognee): - mock_cognee.cognify = AsyncMock() - - cognifier = CogneeCognifier(dataset_name="my_data") - result = cognifier.run(documents_written=5) - - assert result == {"cognified": True} - mock_cognee.cognify.assert_awaited_once_with(datasets=["my_data"]) diff --git a/integrations/cognee/tests/test_integration.py b/integrations/cognee/tests/test_integration.py index 91e2d16c38..a99c23ca5b 100644 --- a/integrations/cognee/tests/test_integration.py +++ b/integrations/cognee/tests/test_integration.py @@ -2,100 +2,70 @@ # # SPDX-License-Identifier: Apache-2.0 +import asyncio +import contextlib import os +import uuid -import cognee +import cognee # type: ignore[import-untyped] import pytest -from haystack import Document from haystack.dataclasses import ChatMessage -from haystack_integrations.components.connectors.cognee import CogneeCognifier -from haystack_integrations.components.connectors.cognee._utils import run_sync from haystack_integrations.components.retrievers.cognee import CogneeRetriever from haystack_integrations.components.writers.cognee import CogneeWriter from haystack_integrations.memory_stores.cognee import CogneeMemoryStore -SKIP_REASON = "Export an env var called LLM_API_KEY containing the LLM API key to run this test." +pytestmark = [ + pytest.mark.integration, + pytest.mark.skipif( + not os.environ.get("LLM_API_KEY"), + reason="Set LLM_API_KEY (cognee's LLM provider key) to run cognee integration tests.", + ), +] -@pytest.mark.skipif( - not os.environ.get("LLM_API_KEY", None), - reason=SKIP_REASON, -) -@pytest.mark.integration -class TestCogneeMemoryStoreIntegration: - def test_add_search_delete(self): - store = CogneeMemoryStore( - search_type="GRAPH_COMPLETION", - top_k=3, - dataset_name="haystack_integration_test", - ) +@pytest.fixture +def dataset_name() -> str: + # Unique per-run so concurrent CI shards don't collide in the local cognee store. + return f"haystack_it_{uuid.uuid4().hex[:8]}" - store.delete_all_memories() - messages = [ - ChatMessage.from_user("The capital of France is Paris."), - ChatMessage.from_user("The Eiffel Tower is located in Paris."), - ] - store.add_memories(messages=messages) +@pytest.fixture(autouse=True) +def _cleanup(dataset_name: str): + yield + # Best-effort: dataset may already be gone (e.g. after test_improve_and_forget). + with contextlib.suppress(Exception): + asyncio.run(cognee.forget(dataset=dataset_name)) - results = store.search_memories(query="What is the capital of France?", top_k=3) - assert len(results) > 0 - assert all(isinstance(r, ChatMessage) for r in results) - store.delete_all_memories() +class TestCogneeIntegration: + def test_remember_then_recall(self, dataset_name: str): + store = CogneeMemoryStore(dataset_name=dataset_name, search_type="GRAPH_COMPLETION") + store.add_memories(messages=[ChatMessage.from_user("Marie Curie discovered radium in 1898.")]) + + results = store.search_memories(query="Who discovered radium?") + + assert results, "expected at least one memory from cognee" + assert any("curie" in m.text.lower() or "radium" in m.text.lower() for m in results) + + def test_writer_then_retriever_pipeline(self, dataset_name: str): + store = CogneeMemoryStore(dataset_name=dataset_name) + writer = CogneeWriter(memory_store=store) + retriever = CogneeRetriever(memory_store=store, top_k=3) + writer.run(messages=[ChatMessage.from_user("Ada Lovelace wrote the first computer program.")]) + out = retriever.run(query="Who wrote the first computer program?") -@pytest.mark.skipif( - not os.environ.get("LLM_API_KEY", None), - reason=SKIP_REASON, -) -@pytest.mark.integration -class TestCogneeWriterRetrieverIntegration: - def test_write_and_retrieve(self): - run_sync(cognee.prune.prune_data()) - run_sync(cognee.prune.prune_system(metadata=True)) - - writer = CogneeWriter(dataset_name="haystack_integration_test", auto_cognify=True) - docs = [ - Document(content="Python is a programming language created by Guido van Rossum."), - Document(content="Haystack is an open-source framework for building AI applications."), - ] - write_result = writer.run(documents=docs) - assert write_result["documents_written"] == 2 - - retriever = CogneeRetriever( - memory_store=CogneeMemoryStore( - search_type="GRAPH_COMPLETION", - top_k=3, - dataset_name="haystack_integration_test", - ), - ) - search_result = retriever.run(query="What is Haystack?") - assert len(search_result["documents"]) > 0 - assert all(isinstance(d, Document) for d in search_result["documents"]) - - run_sync(cognee.prune.prune_data()) - run_sync(cognee.prune.prune_system(metadata=True)) - - -@pytest.mark.skipif( - not os.environ.get("LLM_API_KEY", None), - reason=SKIP_REASON, -) -@pytest.mark.integration -class TestCogneeCognifierIntegration: - def test_write_then_cognify(self): - run_sync(cognee.prune.prune_data()) - run_sync(cognee.prune.prune_system(metadata=True)) - - writer = CogneeWriter(dataset_name="haystack_integration_test", auto_cognify=False) - docs = [Document(content="Berlin is the capital of Germany.")] - writer.run(documents=docs) - - cognifier = CogneeCognifier(dataset_name="haystack_integration_test") - result = cognifier.run() - assert result["cognified"] is True - - run_sync(cognee.prune.prune_data()) - run_sync(cognee.prune.prune_system(metadata=True)) + assert out["messages"], "retriever returned no messages" + assert any("lovelace" in m.text.lower() or "program" in m.text.lower() for m in out["messages"]) + + def test_improve_and_forget(self, dataset_name: str): + store = CogneeMemoryStore(dataset_name=dataset_name) + store.add_memories(messages=[ChatMessage.from_user("Pluto was reclassified as a dwarf planet in 2006.")]) + + # improve() without session_ids is a graph-enrichment pass — must not raise. + store.improve() + + store.delete_all_memories() + # After forget, recall against this dataset should return nothing. + assert store.search_memories(query="Pluto") == [] diff --git a/integrations/cognee/tests/test_memory_store.py b/integrations/cognee/tests/test_memory_store.py index 5a48be1eaf..38a956768f 100644 --- a/integrations/cognee/tests/test_memory_store.py +++ b/integrations/cognee/tests/test_memory_store.py @@ -2,7 +2,9 @@ # # SPDX-License-Identifier: Apache-2.0 +from types import SimpleNamespace from unittest.mock import AsyncMock, MagicMock, patch +from uuid import uuid4 import pytest from haystack.dataclasses import ChatMessage @@ -10,156 +12,257 @@ from haystack_integrations.memory_stores.cognee import CogneeMemoryStore +def _graph(text: str) -> SimpleNamespace: + return SimpleNamespace(source="graph", text=text) + + +def _session(answer: str, question: str = "") -> SimpleNamespace: + return SimpleNamespace(source="session", answer=answer, question=question) + + class TestCogneeMemoryStore: def test_init_defaults(self): store = CogneeMemoryStore() assert store.search_type == "GRAPH_COMPLETION" assert store.top_k == 5 assert store.dataset_name == "haystack_memory" + assert store.session_id is None def test_init_custom(self): - store = CogneeMemoryStore(search_type="CHUNKS", top_k=10, dataset_name="custom") + store = CogneeMemoryStore(search_type="CHUNKS", top_k=10, dataset_name="custom", session_id="s1") assert store.search_type == "CHUNKS" assert store.top_k == 10 assert store.dataset_name == "custom" - - def test_to_dict(self): - store = CogneeMemoryStore(search_type="SUMMARIES", top_k=3, dataset_name="mem") + assert store.session_id == "s1" + + def test_init_default_self_improvement(self): + """Mirrors cognee.remember's default of self_improvement=True.""" + assert CogneeMemoryStore().self_improvement is True + + def test_to_from_dict_roundtrip(self): + store = CogneeMemoryStore( + search_type="SUMMARIES", + top_k=3, + dataset_name="mem", + session_id="abc", + self_improvement=False, + ) data = store.to_dict() assert data["type"] == "haystack_integrations.memory_stores.cognee.memory_store.CogneeMemoryStore" - assert data["init_parameters"]["search_type"] == "SUMMARIES" - assert data["init_parameters"]["top_k"] == 3 - assert data["init_parameters"]["dataset_name"] == "mem" - - def test_from_dict(self): - data = { - "type": "haystack_integrations.memory_stores.cognee.memory_store.CogneeMemoryStore", - "init_parameters": {"search_type": "CHUNKS", "top_k": 8, "dataset_name": "restored"}, + assert data["init_parameters"] == { + "search_type": "SUMMARIES", + "top_k": 3, + "dataset_name": "mem", + "session_id": "abc", + "self_improvement": False, } - store = CogneeMemoryStore.from_dict(data) - assert store.search_type == "CHUNKS" - assert store.top_k == 8 - assert store.dataset_name == "restored" + restored = CogneeMemoryStore.from_dict(data) + assert restored.search_type == "SUMMARIES" + assert restored.top_k == 3 + assert restored.dataset_name == "mem" + assert restored.session_id == "abc" + assert restored.self_improvement is False + + @patch("haystack_integrations.memory_stores.cognee.memory_store.cognee") + def test_add_memories_batches_permanent_tier(self, mock_cognee): + mock_cognee.remember = AsyncMock() + store = CogneeMemoryStore(dataset_name="my_ds") + + store.add_memories( + messages=[ + ChatMessage.from_user("First fact"), + ChatMessage.from_assistant("Second fact"), + ] + ) + + mock_cognee.remember.assert_awaited_once_with( + ["First fact", "Second fact"], dataset_name="my_ds", user=None, self_improvement=True + ) + + @patch("haystack_integrations.memory_stores.cognee.memory_store.cognee") + def test_add_memories_session_tier_writes_one_per_message(self, mock_cognee): + mock_cognee.remember = AsyncMock() + store = CogneeMemoryStore(dataset_name="ds", session_id="sess1") + + store.add_memories(messages=[ChatMessage.from_user("a"), ChatMessage.from_user("b")]) + + assert mock_cognee.remember.await_count == 2 + first_call = mock_cognee.remember.await_args_list[0] + assert first_call.args == ("a",) + assert first_call.kwargs == { + "dataset_name": "ds", + "session_id": "sess1", + "user": None, + "self_improvement": True, + } + + @patch("haystack_integrations.memory_stores.cognee.memory_store.cognee") + def test_add_memories_self_improvement_false_forwarded(self, mock_cognee): + """`self_improvement=False` flows through to cognee.remember (both tiers).""" + mock_cognee.remember = AsyncMock() + + perm = CogneeMemoryStore(dataset_name="ds", self_improvement=False) + perm.add_memories(messages=[ChatMessage.from_user("a")]) + assert mock_cognee.remember.await_args.kwargs["self_improvement"] is False + + mock_cognee.remember.reset_mock() + sess = CogneeMemoryStore(dataset_name="ds", session_id="s", self_improvement=False) + sess.add_memories(messages=[ChatMessage.from_user("a")]) + assert mock_cognee.remember.await_args.kwargs["self_improvement"] is False + + @patch("haystack_integrations.memory_stores.cognee.memory_store.cognee") + def test_add_memories_session_id_override_writes_to_override(self, mock_cognee): + """`session_id` kwarg routes a permanent-tier store's write into a session.""" + mock_cognee.remember = AsyncMock() + store = CogneeMemoryStore(dataset_name="ds") # no session_id on the store + + store.add_memories(messages=[ChatMessage.from_user("a")], session_id="call_sess") + + mock_cognee.remember.assert_awaited_once_with( + "a", dataset_name="ds", session_id="call_sess", user=None, self_improvement=True + ) @patch("haystack_integrations.memory_stores.cognee.memory_store.cognee") - def test_add_memories(self, mock_cognee): - mock_cognee.add = AsyncMock() - mock_cognee.cognify = AsyncMock() + def test_add_memories_session_id_override_beats_store_session(self, mock_cognee): + """Per-call `session_id` wins over `self.session_id`.""" + mock_cognee.remember = AsyncMock() + store = CogneeMemoryStore(dataset_name="ds", session_id="store_sess") + + store.add_memories(messages=[ChatMessage.from_user("a")], session_id="call_sess") + + assert mock_cognee.remember.await_args.kwargs["session_id"] == "call_sess" + @patch("haystack_integrations.memory_stores.cognee.memory_store.cognee") + def test_add_memories_skips_when_no_text(self, mock_cognee): + mock_cognee.remember = AsyncMock() store = CogneeMemoryStore() - messages = [ - ChatMessage.from_user("Remember: the deadline is Friday."), - ChatMessage.from_assistant("Got it, I'll remember Friday."), - ] - store.add_memories(messages=messages) - assert mock_cognee.add.await_count == 2 - mock_cognee.cognify.assert_awaited_once() + store.add_memories(messages=[]) + store.add_memories(messages=[ChatMessage.from_user("")]) + + mock_cognee.remember.assert_not_called() + @patch("haystack_integrations.memory_stores.cognee.memory_store._resolve_user", new_callable=AsyncMock) @patch("haystack_integrations.memory_stores.cognee.memory_store.cognee") - def test_add_memories_cognify_uses_dataset(self, mock_cognee): - mock_cognee.add = AsyncMock() - mock_cognee.cognify = AsyncMock() + def test_add_memories_resolves_user(self, mock_cognee, mock_resolve): + mock_cognee.remember = AsyncMock() + sentinel_user = object() + mock_resolve.return_value = sentinel_user + uid = str(uuid4()) - store = CogneeMemoryStore(dataset_name="my_ds") - messages = [ChatMessage.from_user("Remember this.")] - store.add_memories(messages=messages) + store = CogneeMemoryStore(dataset_name="ds") + store.add_memories(messages=[ChatMessage.from_user("hi")], user_id=uid) + + mock_resolve.assert_awaited_once_with(uid) + mock_cognee.remember.assert_awaited_once_with( + ["hi"], dataset_name="ds", user=sentinel_user, self_improvement=True + ) - mock_cognee.cognify.assert_awaited_once() - cognify_kwargs = mock_cognee.cognify.call_args[1] - assert cognify_kwargs["datasets"] == ["my_ds"] + @patch("haystack_integrations.memory_stores.cognee.memory_store.cognee") + def test_search_memories_passes_recall_args(self, mock_cognee): + mock_cognee.SearchType = {"GRAPH_COMPLETION": "GRAPH_COMPLETION_ENUM"} + mock_cognee.recall = AsyncMock(return_value=[]) + + store = CogneeMemoryStore(dataset_name="ds", top_k=7, session_id="s") + store.search_memories(query="hello") + + mock_cognee.recall.assert_awaited_once_with( + "hello", + query_type="GRAPH_COMPLETION_ENUM", + datasets=["ds"], + top_k=7, + session_id="s", + user=None, + ) @patch("haystack_integrations.memory_stores.cognee.memory_store.cognee") - def test_search_memories(self, mock_cognee): - mock_cognee.search = AsyncMock(return_value=["Memory about deadline"]) + def test_search_memories_wraps_results_per_source(self, mock_cognee): + mock_cognee.SearchType = {"GRAPH_COMPLETION": MagicMock()} + mock_cognee.recall = AsyncMock( + return_value=[ + _graph("graph hit"), + _session("session answer", "question text"), + SimpleNamespace(source="graph_context", content="ctx blob"), + SimpleNamespace(source="trace", memory_context="trace blob"), + ] + ) store = CogneeMemoryStore() - results = store.search_memories(query="What is the deadline?") + out = store.search_memories(query="q") - assert len(results) == 1 - assert isinstance(results[0], ChatMessage) - assert results[0].text == "Memory about deadline" + assert [m.text for m in out] == [ + "graph hit", + "session answer", + "ctx blob", + "trace blob", + ] + assert all(isinstance(m, ChatMessage) for m in out) + + @patch("haystack_integrations.memory_stores.cognee.memory_store.cognee") + def test_search_memories_top_k_override(self, mock_cognee): + mock_cognee.SearchType = {"GRAPH_COMPLETION": MagicMock()} + mock_cognee.recall = AsyncMock(return_value=[]) + + store = CogneeMemoryStore(top_k=5) + store.search_memories(query="q", top_k=2) + + assert mock_cognee.recall.await_args.kwargs["top_k"] == 2 def test_search_memories_empty_query(self): store = CogneeMemoryStore() - results = store.search_memories(query=None) - assert results == [] - - results = store.search_memories(query="") - assert results == [] + assert store.search_memories(query=None) == [] + assert store.search_memories(query="") == [] + @patch("haystack_integrations.memory_stores.cognee.memory_store._resolve_user", new_callable=AsyncMock) @patch("haystack_integrations.memory_stores.cognee.memory_store.cognee") - def test_delete_all_memories(self, mock_cognee): - mock_cognee.prune = type( - "Prune", - (), - { - "prune_data": AsyncMock(), - "prune_system": AsyncMock(), - }, - )() + def test_search_memories_resolves_user(self, mock_cognee, mock_resolve): + mock_cognee.SearchType = {"GRAPH_COMPLETION": MagicMock()} + mock_cognee.recall = AsyncMock(return_value=[]) + sentinel_user = object() + mock_resolve.return_value = sentinel_user + uid = str(uuid4()) store = CogneeMemoryStore() - store.delete_all_memories() + store.search_memories(query="q", user_id=uid) - mock_cognee.prune.prune_data.assert_awaited_once() - mock_cognee.prune.prune_system.assert_awaited_once() + mock_resolve.assert_awaited_once_with(uid) + assert mock_cognee.recall.await_args.kwargs["user"] is sentinel_user - @patch("haystack_integrations.memory_stores.cognee.memory_store._get_cognee_user", new_callable=AsyncMock) @patch("haystack_integrations.memory_stores.cognee.memory_store.cognee") - def test_add_memories_with_user_id(self, mock_cognee, mock_get_user): - mock_user = MagicMock() - mock_get_user.return_value = mock_user - mock_cognee.add = AsyncMock() - mock_cognee.cognify = AsyncMock() + def test_improve_uses_store_session(self, mock_cognee): + mock_cognee.improve = AsyncMock() - store = CogneeMemoryStore() - messages = [ChatMessage.from_user("Remember this.")] - store.add_memories(messages=messages, user_id="550e8400-e29b-41d4-a716-446655440000") + store = CogneeMemoryStore(dataset_name="ds", session_id="s1") + store.improve() - mock_get_user.assert_awaited_once_with("550e8400-e29b-41d4-a716-446655440000") - mock_cognee.add.assert_awaited_once() - add_kwargs = mock_cognee.add.call_args[1] - assert add_kwargs["user"] is mock_user - cognify_kwargs = mock_cognee.cognify.call_args[1] - assert cognify_kwargs["user"] is mock_user + mock_cognee.improve.assert_awaited_once_with(dataset="ds", session_ids=["s1"], user=None) - @patch("haystack_integrations.memory_stores.cognee.memory_store._get_cognee_user", new_callable=AsyncMock) @patch("haystack_integrations.memory_stores.cognee.memory_store.cognee") - def test_search_memories_with_user_id(self, mock_cognee, mock_get_user): - mock_user = MagicMock() - mock_get_user.return_value = mock_user - mock_cognee.search = AsyncMock(return_value=["result"]) + def test_improve_overrides_session(self, mock_cognee): + mock_cognee.improve = AsyncMock() - store = CogneeMemoryStore() - results = store.search_memories(query="test", user_id="550e8400-e29b-41d4-a716-446655440000") + store = CogneeMemoryStore(dataset_name="ds") + store.improve(session_id="explicit") - mock_get_user.assert_awaited_once_with("550e8400-e29b-41d4-a716-446655440000") - search_kwargs = mock_cognee.search.call_args[1] - assert search_kwargs["user"] is mock_user - assert len(results) == 1 + mock_cognee.improve.assert_awaited_once_with(dataset="ds", session_ids=["explicit"], user=None) @patch("haystack_integrations.memory_stores.cognee.memory_store.cognee") - def test_add_memories_without_user_id(self, mock_cognee): - mock_cognee.add = AsyncMock() - mock_cognee.cognify = AsyncMock() + def test_improve_no_session_runs_graph_enrichment(self, mock_cognee): + mock_cognee.improve = AsyncMock() - store = CogneeMemoryStore() - messages = [ChatMessage.from_user("Remember this.")] - store.add_memories(messages=messages) + store = CogneeMemoryStore(dataset_name="ds") + store.improve() - add_kwargs = mock_cognee.add.call_args[1] - assert add_kwargs["user"] is None + mock_cognee.improve.assert_awaited_once_with(dataset="ds", session_ids=None, user=None) @patch("haystack_integrations.memory_stores.cognee.memory_store.cognee") - def test_search_memories_without_user_id(self, mock_cognee): - mock_cognee.search = AsyncMock(return_value=["result"]) + def test_delete_all_memories_calls_forget_with_dataset(self, mock_cognee): + mock_cognee.forget = AsyncMock() - store = CogneeMemoryStore() - store.search_memories(query="test") + store = CogneeMemoryStore(dataset_name="ds") + store.delete_all_memories() - search_kwargs = mock_cognee.search.call_args[1] - assert search_kwargs["user"] is None + mock_cognee.forget.assert_awaited_once_with(dataset="ds", user=None) def test_delete_memory_raises(self): store = CogneeMemoryStore() diff --git a/integrations/cognee/tests/test_retriever.py b/integrations/cognee/tests/test_retriever.py index 343ea3bf01..33ae9ea3fc 100644 --- a/integrations/cognee/tests/test_retriever.py +++ b/integrations/cognee/tests/test_retriever.py @@ -27,9 +27,10 @@ def test_init_with_top_k(self): retriever = CogneeRetriever(memory_store=store, top_k=3) assert retriever._top_k == 3 - def test_to_dict(self): + def test_to_from_dict_roundtrip(self): store = CogneeMemoryStore(search_type="SUMMARIES", top_k=3, dataset_name="ds") retriever = CogneeRetriever(memory_store=store, top_k=7) + data = retriever.to_dict() assert data["type"] == "haystack_integrations.components.retrievers.cognee.memory_retriever.CogneeRetriever" assert data["init_parameters"]["top_k"] == 7 @@ -39,26 +40,11 @@ def test_to_dict(self): ) assert data["init_parameters"]["memory_store"]["init_parameters"]["dataset_name"] == "ds" - def test_from_dict(self): - data = { - "type": "haystack_integrations.components.retrievers.cognee.memory_retriever.CogneeRetriever", - "init_parameters": { - "top_k": 5, - "memory_store": { - "type": "haystack_integrations.memory_stores.cognee.memory_store.CogneeMemoryStore", - "init_parameters": { - "search_type": "CHUNKS", - "top_k": 8, - "dataset_name": "restored", - }, - }, - }, - } - retriever = CogneeRetriever.from_dict(data) - assert retriever._top_k == 5 - assert isinstance(retriever._memory_store, CogneeMemoryStore) - assert retriever._memory_store.search_type == "CHUNKS" - assert retriever._memory_store.dataset_name == "restored" + restored = CogneeRetriever.from_dict(data) + assert restored._top_k == 7 + assert isinstance(restored._memory_store, CogneeMemoryStore) + assert restored._memory_store.search_type == "SUMMARIES" + assert restored._memory_store.dataset_name == "ds" def test_run_delegates_to_store(self): store = MagicMock(spec=CogneeMemoryStore) @@ -68,62 +54,41 @@ def test_run_delegates_to_store(self): ] retriever = CogneeRetriever(memory_store=store) - result = retriever.run(query="What is Cognee?") + out = retriever.run(query="What is Cognee?") - store.search_memories.assert_called_once_with(query="What is Cognee?", user_id=None) - docs = result["documents"] - assert len(docs) == 2 - assert docs[0].content == "result one" - assert docs[0].meta["source"] == "cognee" + store.search_memories.assert_called_once_with(query="What is Cognee?", top_k=None, user_id=None) + assert out["messages"] == store.search_memories.return_value - def test_run_forwards_top_k_override(self): + def test_run_top_k_override_takes_precedence(self): store = MagicMock(spec=CogneeMemoryStore) store.search_memories.return_value = [] retriever = CogneeRetriever(memory_store=store, top_k=10) retriever.run(query="q", top_k=2) - store.search_memories.assert_called_once_with(query="q", user_id=None, top_k=2) + store.search_memories.assert_called_once_with(query="q", top_k=2, user_id=None) - def test_run_uses_retriever_default_top_k(self): + def test_run_falls_back_to_init_top_k(self): store = MagicMock(spec=CogneeMemoryStore) store.search_memories.return_value = [] retriever = CogneeRetriever(memory_store=store, top_k=4) retriever.run(query="q") - store.search_memories.assert_called_once_with(query="q", user_id=None, top_k=4) + store.search_memories.assert_called_once_with(query="q", top_k=4, user_id=None) - def test_run_forwards_user_id(self): + def test_run_passes_user_id(self): store = MagicMock(spec=CogneeMemoryStore) store.search_memories.return_value = [] retriever = CogneeRetriever(memory_store=store) - retriever.run(query="q", user_id="550e8400-e29b-41d4-a716-446655440000") + retriever.run(query="q", user_id="user-abc") - store.search_memories.assert_called_once_with( - query="q", - user_id="550e8400-e29b-41d4-a716-446655440000", - ) + store.search_memories.assert_called_once_with(query="q", top_k=None, user_id="user-abc") def test_run_empty_results(self): store = MagicMock(spec=CogneeMemoryStore) store.search_memories.return_value = [] retriever = CogneeRetriever(memory_store=store) - result = retriever.run(query="nonexistent query") - - assert result["documents"] == [] - - def test_run_skips_messages_with_empty_text(self): - store = MagicMock(spec=CogneeMemoryStore) - store.search_memories.return_value = [ - ChatMessage.from_system("valid"), - ChatMessage.from_system(""), - ] - - retriever = CogneeRetriever(memory_store=store) - result = retriever.run(query="q") - - assert len(result["documents"]) == 1 - assert result["documents"][0].content == "valid" + assert retriever.run(query="nothing here")["messages"] == [] diff --git a/integrations/cognee/tests/test_utils.py b/integrations/cognee/tests/test_utils.py deleted file mode 100644 index 13701aea93..0000000000 --- a/integrations/cognee/tests/test_utils.py +++ /dev/null @@ -1,99 +0,0 @@ -# SPDX-FileCopyrightText: 2022-present deepset GmbH -# -# SPDX-License-Identifier: Apache-2.0 - -import asyncio - -from haystack_integrations.components.connectors.cognee._utils import extract_text, run_sync - - -class TestExtractText: - def test_string_input(self): - assert extract_text("hello world") == "hello world" - - def test_object_with_content_attr(self): - class FakeResult: - content = "object content" - - assert extract_text(FakeResult()) == "object content" - - def test_object_with_text_attr(self): - class FakeResult: - text = "object text" - - assert extract_text(FakeResult()) == "object text" - - def test_object_with_description_attr(self): - class FakeResult: - description = "object description" - - assert extract_text(FakeResult()) == "object description" - - def test_object_with_name_attr(self): - class FakeResult: - name = "object name" - - assert extract_text(FakeResult()) == "object name" - - def test_object_attr_priority(self): - class FakeResult: - content = "first" - text = "second" - - assert extract_text(FakeResult()) == "first" - - def test_object_skips_none_attr(self): - class FakeResult: - content = None - text = "fallback text" - - assert extract_text(FakeResult()) == "fallback text" - - def test_object_skips_non_string_attr(self): - class FakeResult: - content = 123 - text = "string value" - - assert extract_text(FakeResult()) == "string value" - - def test_dict_with_content_key(self): - assert extract_text({"content": "dict content"}) == "dict content" - - def test_dict_with_text_key(self): - assert extract_text({"text": "dict text"}) == "dict text" - - def test_dict_with_description_key(self): - assert extract_text({"description": "dict description"}) == "dict description" - - def test_dict_with_name_key(self): - assert extract_text({"name": "dict name"}) == "dict name" - - def test_dict_key_priority(self): - assert extract_text({"content": "first", "text": "second"}) == "first" - - def test_dict_skips_non_string_value(self): - assert extract_text({"content": 123, "text": "fallback"}) == "fallback" - - def test_fallback_to_str(self): - assert extract_text(42) == "42" - - def test_fallback_dict_no_known_keys(self): - result = extract_text({"unknown": "value"}) - assert "unknown" in result - - -class TestRunSync: - def test_run_simple_coroutine(self): - async def coro(): - return 42 - - result = run_sync(coro()) - assert result == 42 - - def test_run_async_coroutine(self): - async def coro(): - await asyncio.sleep(0) - return "done" - - result = run_sync(coro()) - assert result == "done" diff --git a/integrations/cognee/tests/test_writer.py b/integrations/cognee/tests/test_writer.py index 888f87f7d6..e1866968dd 100644 --- a/integrations/cognee/tests/test_writer.py +++ b/integrations/cognee/tests/test_writer.py @@ -2,134 +2,74 @@ # # SPDX-License-Identifier: Apache-2.0 -from unittest.mock import AsyncMock, MagicMock, patch +from unittest.mock import MagicMock -from haystack import Document +import pytest +from haystack.dataclasses import ChatMessage from haystack_integrations.components.writers.cognee import CogneeWriter +from haystack_integrations.memory_stores.cognee import CogneeMemoryStore class TestCogneeWriter: - def test_init_defaults(self): - writer = CogneeWriter() - assert writer.dataset_name == "haystack" - assert writer.auto_cognify is True - - def test_init_custom(self): - writer = CogneeWriter(dataset_name="custom", auto_cognify=False) - assert writer.dataset_name == "custom" - assert writer.auto_cognify is False - - def test_to_dict(self): - writer = CogneeWriter(dataset_name="test_ds", auto_cognify=False) + def test_init_requires_memory_store(self): + with pytest.raises(ValueError, match="memory_store must be an instance of CogneeMemoryStore"): + CogneeWriter(memory_store="not a store") # type: ignore[arg-type] + + def test_init_holds_store(self): + store = CogneeMemoryStore(dataset_name="ds", session_id="s") + writer = CogneeWriter(memory_store=store) + assert writer._memory_store is store + assert writer._session_id is None + + def test_init_with_session_id(self): + store = CogneeMemoryStore(dataset_name="ds") + writer = CogneeWriter(memory_store=store, session_id="override") + assert writer._session_id == "override" + + def test_to_from_dict_roundtrip(self): + store = CogneeMemoryStore(dataset_name="ds", session_id="s") + writer = CogneeWriter(memory_store=store, session_id="writer_sess") + data = writer.to_dict() assert data["type"] == "haystack_integrations.components.writers.cognee.memory_writer.CogneeWriter" - assert data["init_parameters"]["dataset_name"] == "test_ds" - assert data["init_parameters"]["auto_cognify"] is False - - def test_from_dict(self): - data = { - "type": "haystack_integrations.components.writers.cognee.memory_writer.CogneeWriter", - "init_parameters": {"dataset_name": "restored", "auto_cognify": True}, - } - writer = CogneeWriter.from_dict(data) - assert writer.dataset_name == "restored" - assert writer.auto_cognify is True - - @patch("haystack_integrations.components.writers.cognee.memory_writer.cognee") - def test_run_with_auto_cognify(self, mock_cognee): - mock_cognee.add = AsyncMock() - mock_cognee.cognify = AsyncMock() - - writer = CogneeWriter(dataset_name="test", auto_cognify=True) - docs = [ - Document(content="First document"), - Document(content="Second document"), - ] - result = writer.run(documents=docs) - - assert result == {"documents_written": 2} - # Verify batch call: single add() with list of texts - mock_cognee.add.assert_awaited_once() - call_args = mock_cognee.add.call_args - assert call_args[0][0] == ["First document", "Second document"] - # Verify cognify uses specific dataset - mock_cognee.cognify.assert_awaited_once() - cognify_kwargs = mock_cognee.cognify.call_args[1] - assert cognify_kwargs["datasets"] == ["test"] - - @patch("haystack_integrations.components.writers.cognee.memory_writer.cognee") - def test_run_without_auto_cognify(self, mock_cognee): - mock_cognee.add = AsyncMock() - mock_cognee.cognify = AsyncMock() - - writer = CogneeWriter(dataset_name="test", auto_cognify=False) - docs = [Document(content="A document")] - result = writer.run(documents=docs) - - assert result == {"documents_written": 1} - mock_cognee.add.assert_awaited_once() - mock_cognee.cognify.assert_not_awaited() - - @patch("haystack_integrations.components.writers.cognee.memory_writer.cognee") - def test_run_skips_empty_content(self, mock_cognee): - mock_cognee.add = AsyncMock() - mock_cognee.cognify = AsyncMock() - - writer = CogneeWriter(auto_cognify=True) - docs = [ - Document(content="Valid document"), - Document(content=""), - Document(content=None), - ] - result = writer.run(documents=docs) - - assert result == {"documents_written": 1} - mock_cognee.add.assert_awaited_once() - call_args = mock_cognee.add.call_args - assert call_args[0][0] == ["Valid document"] - - @patch("haystack_integrations.components.writers.cognee.memory_writer.cognee") - def test_run_empty_list(self, mock_cognee): - mock_cognee.add = AsyncMock() - mock_cognee.cognify = AsyncMock() - - writer = CogneeWriter(auto_cognify=True) - result = writer.run(documents=[]) - - assert result == {"documents_written": 0} - mock_cognee.add.assert_not_awaited() - mock_cognee.cognify.assert_not_awaited() - - @patch("haystack_integrations.components.writers.cognee.memory_writer._get_cognee_user", new_callable=AsyncMock) - @patch("haystack_integrations.components.writers.cognee.memory_writer.cognee") - def test_run_with_user_id(self, mock_cognee, mock_get_user): - mock_user = MagicMock() - mock_get_user.return_value = mock_user - mock_cognee.add = AsyncMock() - mock_cognee.cognify = AsyncMock() - - writer = CogneeWriter(dataset_name="test", auto_cognify=True) - writer.run( - documents=[Document(content="hello")], - user_id="550e8400-e29b-41d4-a716-446655440000", + assert data["init_parameters"]["session_id"] == "writer_sess" + assert ( + data["init_parameters"]["memory_store"]["type"] + == "haystack_integrations.memory_stores.cognee.memory_store.CogneeMemoryStore" ) + assert data["init_parameters"]["memory_store"]["init_parameters"]["dataset_name"] == "ds" + + restored = CogneeWriter.from_dict(data) + assert isinstance(restored._memory_store, CogneeMemoryStore) + assert restored._memory_store.dataset_name == "ds" + assert restored._memory_store.session_id == "s" + assert restored._session_id == "writer_sess" + + def test_run_delegates_to_store_and_echoes_messages(self): + store = MagicMock(spec=CogneeMemoryStore) + writer = CogneeWriter(memory_store=store) + + messages = [ChatMessage.from_user("hi"), ChatMessage.from_assistant("hello")] + out = writer.run(messages=messages) + + store.add_memories.assert_called_once_with(messages=messages, user_id=None, session_id=None) + assert out == {"messages_written": messages} + + def test_run_passes_user_id(self): + store = MagicMock(spec=CogneeMemoryStore) + writer = CogneeWriter(memory_store=store) + + messages = [ChatMessage.from_user("hi")] + writer.run(messages=messages, user_id="user-abc") - mock_get_user.assert_awaited_once_with("550e8400-e29b-41d4-a716-446655440000") - add_kwargs = mock_cognee.add.call_args[1] - assert add_kwargs["user"] is mock_user - cognify_kwargs = mock_cognee.cognify.call_args[1] - assert cognify_kwargs["user"] is mock_user + store.add_memories.assert_called_once_with(messages=messages, user_id="user-abc", session_id=None) - @patch("haystack_integrations.components.writers.cognee.memory_writer.cognee") - def test_run_without_user_id(self, mock_cognee): - mock_cognee.add = AsyncMock() - mock_cognee.cognify = AsyncMock() + def test_run_forwards_writer_session_id(self): + store = MagicMock(spec=CogneeMemoryStore) + writer = CogneeWriter(memory_store=store, session_id="writer_sess") - writer = CogneeWriter(dataset_name="test", auto_cognify=True) - writer.run(documents=[Document(content="hello")]) + messages = [ChatMessage.from_user("hi")] + writer.run(messages=messages) - add_kwargs = mock_cognee.add.call_args[1] - assert add_kwargs["user"] is None - cognify_kwargs = mock_cognee.cognify.call_args[1] - assert cognify_kwargs["user"] is None + store.add_memories.assert_called_once_with(messages=messages, user_id=None, session_id="writer_sess") From f79864a6515c22071edd367793b86b6dd6ea6e51 Mon Sep 17 00:00:00 2001 From: Hande <159312713+hande-k@users.noreply.github.com> Date: Fri, 15 May 2026 12:17:46 +0200 Subject: [PATCH 09/10] address comments --- integrations/cognee/pyproject.toml | 1 + .../retrievers/cognee/memory_retriever.py | 1 - .../writers/cognee/memory_writer.py | 4 +--- .../memory_stores/cognee/memory_store.py | 11 ++--------- integrations/cognee/tests/conftest.py | 19 +++++++++++++++++++ integrations/cognee/tests/test_integration.py | 19 +++++++++---------- .../cognee/tests/test_memory_store.py | 6 ------ 7 files changed, 32 insertions(+), 29 deletions(-) create mode 100644 integrations/cognee/tests/conftest.py diff --git a/integrations/cognee/pyproject.toml b/integrations/cognee/pyproject.toml index faee63a1af..4d3b155b01 100644 --- a/integrations/cognee/pyproject.toml +++ b/integrations/cognee/pyproject.toml @@ -19,6 +19,7 @@ classifiers = [ "Programming Language :: Python :: 3.11", "Programming Language :: Python :: 3.12", "Programming Language :: Python :: 3.13", + "Programming Language :: Python :: 3.14", "Programming Language :: Python :: Implementation :: CPython", "Programming Language :: Python :: Implementation :: PyPy", ] diff --git a/integrations/cognee/src/haystack_integrations/components/retrievers/cognee/memory_retriever.py b/integrations/cognee/src/haystack_integrations/components/retrievers/cognee/memory_retriever.py index 418666e921..f5fd7e65f7 100644 --- a/integrations/cognee/src/haystack_integrations/components/retrievers/cognee/memory_retriever.py +++ b/integrations/cognee/src/haystack_integrations/components/retrievers/cognee/memory_retriever.py @@ -25,7 +25,6 @@ def __init__(self, *, memory_store: CogneeMemoryStore, top_k: int | None = None) :param memory_store: Backing `CogneeMemoryStore` to query. :param top_k: Default max results; falls back to the store's `top_k` when `None`. - Overridable per-call via `run`. """ if not isinstance(memory_store, CogneeMemoryStore): msg = "memory_store must be an instance of CogneeMemoryStore" diff --git a/integrations/cognee/src/haystack_integrations/components/writers/cognee/memory_writer.py b/integrations/cognee/src/haystack_integrations/components/writers/cognee/memory_writer.py index f9806a35de..926c92a82e 100644 --- a/integrations/cognee/src/haystack_integrations/components/writers/cognee/memory_writer.py +++ b/integrations/cognee/src/haystack_integrations/components/writers/cognee/memory_writer.py @@ -31,9 +31,7 @@ def __init__( Initialize the writer. :param memory_store: Backing `CogneeMemoryStore` to write into. - :param session_id: When set, writes go to cognee's session cache under this - id; overrides the store's `session_id` for this writer. When `None`, - falls back to the store's tier. + :param session_id: Overrides the store's `session_id` for this writer's writes. """ if not isinstance(memory_store, CogneeMemoryStore): msg = "memory_store must be an instance of CogneeMemoryStore" diff --git a/integrations/cognee/src/haystack_integrations/memory_stores/cognee/memory_store.py b/integrations/cognee/src/haystack_integrations/memory_stores/cognee/memory_store.py index b9f6b1902d..d424a30298 100644 --- a/integrations/cognee/src/haystack_integrations/memory_stores/cognee/memory_store.py +++ b/integrations/cognee/src/haystack_integrations/memory_stores/cognee/memory_store.py @@ -56,7 +56,7 @@ def _run_sync(coro: Coroutine[Any, Any, T]) -> T: if _background_loop is None or _background_loop.is_closed(): _background_loop = asyncio.new_event_loop() threading.Thread(target=_background_loop.run_forever, daemon=True).start() - return asyncio.run_coroutine_threadsafe(coro, _background_loop).result() + return asyncio.run_coroutine_threadsafe(coro, _background_loop).result(timeout=300) async def _resolve_user(user_id: str | None) -> Any: @@ -131,7 +131,6 @@ def add_memories( messages: list[ChatMessage], user_id: str | None = None, session_id: str | None = None, - **_: Any, ) -> None: """ Persist messages via `cognee.remember`. @@ -183,7 +182,6 @@ def search_memories( query: str | None = None, top_k: int | None = None, user_id: str | None = None, - **_: Any, ) -> list[ChatMessage]: """ Search via `cognee.recall` and wrap each hit in a system `ChatMessage`. @@ -233,7 +231,7 @@ async def _improve() -> None: _run_sync(_improve()) logger.info("Improved '{ds}' (session={s})", ds=self.dataset_name, s=target_session) - def delete_all_memories(self, *, user_id: str | None = None, **_: Any) -> None: + def delete_all_memories(self, *, user_id: str | None = None) -> None: """ Delete this dataset via `cognee.forget(dataset=...)`. @@ -248,11 +246,6 @@ async def _delete() -> None: _run_sync(_delete()) logger.info("Deleted '{ds}'", ds=self.dataset_name) - def delete_memory(self, memory_id: str) -> None: - """Single-memory deletion is not exposed by cognee's public API yet.""" - msg = "CogneeMemoryStore does not support deleting individual memories." - raise NotImplementedError(msg) - def to_dict(self) -> dict[str, Any]: """Serialize this store for pipeline persistence.""" return default_to_dict( diff --git a/integrations/cognee/tests/conftest.py b/integrations/cognee/tests/conftest.py new file mode 100644 index 0000000000..ce1acf514d --- /dev/null +++ b/integrations/cognee/tests/conftest.py @@ -0,0 +1,19 @@ +# SPDX-FileCopyrightText: 2022-present deepset GmbH +# +# SPDX-License-Identifier: Apache-2.0 + +import logging +import os + +# Set before cognee is imported so setup_logging() picks up WARNING level. +os.environ.setdefault("LOG_LEVEL", "WARNING") + +_NOISY_LOGGERS = ("aiosqlite", "sqlalchemy", "sqlalchemy.engine", "alembic") + + +def _silence_noisy_loggers() -> None: + for name in _NOISY_LOGGERS: + logging.getLogger(name).setLevel(logging.WARNING) + + +_silence_noisy_loggers() diff --git a/integrations/cognee/tests/test_integration.py b/integrations/cognee/tests/test_integration.py index a99c23ca5b..6a2c0422b9 100644 --- a/integrations/cognee/tests/test_integration.py +++ b/integrations/cognee/tests/test_integration.py @@ -9,6 +9,7 @@ import cognee # type: ignore[import-untyped] import pytest +from cognee.modules.data.exceptions import DatasetNotFoundError # type: ignore[import-untyped] from haystack.dataclasses import ChatMessage from haystack_integrations.components.retrievers.cognee import CogneeRetriever @@ -26,14 +27,14 @@ @pytest.fixture def dataset_name() -> str: - # Unique per-run so concurrent CI shards don't collide in the local cognee store. + # Unique per-run so concurrent CI shards don't collide. return f"haystack_it_{uuid.uuid4().hex[:8]}" @pytest.fixture(autouse=True) def _cleanup(dataset_name: str): yield - # Best-effort: dataset may already be gone (e.g. after test_improve_and_forget). + # Best-effort — dataset may already be gone. with contextlib.suppress(Exception): asyncio.run(cognee.forget(dataset=dataset_name)) @@ -59,13 +60,11 @@ def test_writer_then_retriever_pipeline(self, dataset_name: str): assert out["messages"], "retriever returned no messages" assert any("lovelace" in m.text.lower() or "program" in m.text.lower() for m in out["messages"]) - def test_improve_and_forget(self, dataset_name: str): + def test_search_after_forget_raises(self, dataset_name: str): + """Forget actually deletes the dataset (recall against it raises DatasetNotFoundError).""" store = CogneeMemoryStore(dataset_name=dataset_name) - store.add_memories(messages=[ChatMessage.from_user("Pluto was reclassified as a dwarf planet in 2006.")]) - - # improve() without session_ids is a graph-enrichment pass — must not raise. - store.improve() - + store.add_memories(messages=[ChatMessage.from_user("Marie Curie discovered radium in 1898.")]) store.delete_all_memories() - # After forget, recall against this dataset should return nothing. - assert store.search_memories(query="Pluto") == [] + + with pytest.raises(DatasetNotFoundError): + store.search_memories(query="radium") diff --git a/integrations/cognee/tests/test_memory_store.py b/integrations/cognee/tests/test_memory_store.py index 38a956768f..223be6172f 100644 --- a/integrations/cognee/tests/test_memory_store.py +++ b/integrations/cognee/tests/test_memory_store.py @@ -6,7 +6,6 @@ from unittest.mock import AsyncMock, MagicMock, patch from uuid import uuid4 -import pytest from haystack.dataclasses import ChatMessage from haystack_integrations.memory_stores.cognee import CogneeMemoryStore @@ -263,8 +262,3 @@ def test_delete_all_memories_calls_forget_with_dataset(self, mock_cognee): store.delete_all_memories() mock_cognee.forget.assert_awaited_once_with(dataset="ds", user=None) - - def test_delete_memory_raises(self): - store = CogneeMemoryStore() - with pytest.raises(NotImplementedError): - store.delete_memory("some-id") From 34c56f5587bf3680f00f5e6b46b1b1057cc5527f Mon Sep 17 00:00:00 2001 From: Hande <159312713+hande-k@users.noreply.github.com> Date: Tue, 26 May 2026 10:18:54 +0200 Subject: [PATCH 10/10] address comment - timeout as init param --- .../memory_stores/cognee/memory_store.py | 22 ++++++++++++++----- .../cognee/tests/test_memory_store.py | 6 +++++ 2 files changed, 22 insertions(+), 6 deletions(-) diff --git a/integrations/cognee/src/haystack_integrations/memory_stores/cognee/memory_store.py b/integrations/cognee/src/haystack_integrations/memory_stores/cognee/memory_store.py index d424a30298..6e8ab6de3c 100644 --- a/integrations/cognee/src/haystack_integrations/memory_stores/cognee/memory_store.py +++ b/integrations/cognee/src/haystack_integrations/memory_stores/cognee/memory_store.py @@ -45,7 +45,7 @@ _loop_lock = threading.Lock() -def _run_sync(coro: Coroutine[Any, Any, T]) -> T: +def _run_sync(coro: Coroutine[Any, Any, T], *, timeout: float = 300) -> T: try: asyncio.get_running_loop() except RuntimeError: @@ -56,7 +56,7 @@ def _run_sync(coro: Coroutine[Any, Any, T]) -> T: if _background_loop is None or _background_loop.is_closed(): _background_loop = asyncio.new_event_loop() threading.Thread(target=_background_loop.run_forever, daemon=True).start() - return asyncio.run_coroutine_threadsafe(coro, _background_loop).result(timeout=300) + return asyncio.run_coroutine_threadsafe(coro, _background_loop).result(timeout=timeout) async def _resolve_user(user_id: str | None) -> Any: @@ -98,6 +98,11 @@ class CogneeMemoryStore: Set to `False` when you want `improve()` to be the only improve trigger — otherwise an explicit `improve()` runs improve twice and produces near-duplicate graph nodes. + + `timeout` (seconds) caps how long any single cognee call may run before + raising `concurrent.futures.TimeoutError`. The default of 300s covers + single-message agent-memory writes comfortably; bulk ingestion of long + documents may need a larger value. """ def __init__( @@ -108,6 +113,7 @@ def __init__( dataset_name: str = "haystack_memory", session_id: str | None = None, self_improvement: bool = True, + timeout: float = 300, ): """ Initialize the store. @@ -118,12 +124,15 @@ def __init__( :param session_id: When set, use the session-cache tier; otherwise the permanent graph. :param self_improvement: Forwarded to `cognee.remember` (default `True`, matches cognee). Set to `False` when `improve()` should be the only improve trigger. + :param timeout: Per-call timeout in seconds for any cognee operation. + Raise this for bulk ingestion workloads that legitimately need >300s. """ self.search_type = search_type self.top_k = top_k self.dataset_name = dataset_name self.session_id = session_id self.self_improvement = self_improvement + self.timeout = timeout def add_memories( self, @@ -168,7 +177,7 @@ async def _store() -> None: self_improvement=self.self_improvement, ) - _run_sync(_store()) + _run_sync(_store(), timeout=self.timeout) logger.info( "Stored {n} memories in '{ds}' (session={s})", n=len(texts), @@ -204,7 +213,7 @@ async def _search() -> list[Any]: user=user, ) - results = _run_sync(_search()) or [] + results = _run_sync(_search(), timeout=self.timeout) or [] memories = [ChatMessage.from_system(text) for item in results if (text := _render(item))] logger.info("Found {n} memories for '{q}'", n=len(memories), q=query[:80]) return memories @@ -228,7 +237,7 @@ async def _improve() -> None: user=user, ) - _run_sync(_improve()) + _run_sync(_improve(), timeout=self.timeout) logger.info("Improved '{ds}' (session={s})", ds=self.dataset_name, s=target_session) def delete_all_memories(self, *, user_id: str | None = None) -> None: @@ -243,7 +252,7 @@ async def _delete() -> None: user = await _resolve_user(user_id) await cognee.forget(dataset=self.dataset_name, user=user) - _run_sync(_delete()) + _run_sync(_delete(), timeout=self.timeout) logger.info("Deleted '{ds}'", ds=self.dataset_name) def to_dict(self) -> dict[str, Any]: @@ -255,6 +264,7 @@ def to_dict(self) -> dict[str, Any]: dataset_name=self.dataset_name, session_id=self.session_id, self_improvement=self.self_improvement, + timeout=self.timeout, ) @classmethod diff --git a/integrations/cognee/tests/test_memory_store.py b/integrations/cognee/tests/test_memory_store.py index 223be6172f..1ac11756a8 100644 --- a/integrations/cognee/tests/test_memory_store.py +++ b/integrations/cognee/tests/test_memory_store.py @@ -38,6 +38,9 @@ def test_init_default_self_improvement(self): """Mirrors cognee.remember's default of self_improvement=True.""" assert CogneeMemoryStore().self_improvement is True + def test_init_default_timeout(self): + assert CogneeMemoryStore().timeout == 300 + def test_to_from_dict_roundtrip(self): store = CogneeMemoryStore( search_type="SUMMARIES", @@ -45,6 +48,7 @@ def test_to_from_dict_roundtrip(self): dataset_name="mem", session_id="abc", self_improvement=False, + timeout=600, ) data = store.to_dict() assert data["type"] == "haystack_integrations.memory_stores.cognee.memory_store.CogneeMemoryStore" @@ -54,6 +58,7 @@ def test_to_from_dict_roundtrip(self): "dataset_name": "mem", "session_id": "abc", "self_improvement": False, + "timeout": 600, } restored = CogneeMemoryStore.from_dict(data) assert restored.search_type == "SUMMARIES" @@ -61,6 +66,7 @@ def test_to_from_dict_roundtrip(self): assert restored.dataset_name == "mem" assert restored.session_id == "abc" assert restored.self_improvement is False + assert restored.timeout == 600 @patch("haystack_integrations.memory_stores.cognee.memory_store.cognee") def test_add_memories_batches_permanent_tier(self, mock_cognee):