Merge branch 'dev' into fix_issue_with_base_config

This commit is contained in:
Igor Ilic 2025-10-29 11:42:25 +01:00
commit 0cb334c9ae
15 changed files with 4398 additions and 4225 deletions

View file

@ -1,4 +1,5 @@
import os import os
from pathlib import Path
from typing import Optional from typing import Optional
from functools import lru_cache from functools import lru_cache
from cognee.root_dir import get_absolute_path, ensure_absolute_path from cognee.root_dir import get_absolute_path, ensure_absolute_path
@ -11,7 +12,9 @@ class BaseConfig(BaseSettings):
data_root_directory: str = get_absolute_path(".data_storage") data_root_directory: str = get_absolute_path(".data_storage")
system_root_directory: str = get_absolute_path(".cognee_system") system_root_directory: str = get_absolute_path(".cognee_system")
cache_root_directory: str = get_absolute_path(".cognee_cache") cache_root_directory: str = get_absolute_path(".cognee_cache")
logs_root_directory: str = os.getenv("COGNEE_LOGS_DIR", "/tmp/cognee_logs") logs_root_directory: str = os.getenv(
"COGNEE_LOGS_DIR", str(os.path.join(os.path.dirname(os.path.dirname(__file__)), "logs"))
)
monitoring_tool: object = Observer.NONE monitoring_tool: object = Observer.NONE
@pydantic.model_validator(mode="after") @pydantic.model_validator(mode="after")
@ -31,14 +34,8 @@ class BaseConfig(BaseSettings):
# Require absolute paths for root directories # Require absolute paths for root directories
self.data_root_directory = ensure_absolute_path(self.data_root_directory) self.data_root_directory = ensure_absolute_path(self.data_root_directory)
self.system_root_directory = ensure_absolute_path(self.system_root_directory) self.system_root_directory = ensure_absolute_path(self.system_root_directory)
# logs_root_directory may be outside project root; keep as-is if absolute or make absolute if relative self.logs_root_directory = ensure_absolute_path(self.logs_root_directory)
try:
if not os.path.isabs(self.logs_root_directory):
# If relative, place under current working directory
self.logs_root_directory = os.path.abspath(self.logs_root_directory)
except Exception:
# If anything goes wrong, fall back to /tmp/cognee_logs
self.logs_root_directory = "/tmp/cognee_logs"
# Set monitoring tool based on available keys # Set monitoring tool based on available keys
if self.langfuse_public_key and self.langfuse_secret_key: if self.langfuse_public_key and self.langfuse_secret_key:
self.monitoring_tool = Observer.LANGFUSE self.monitoring_tool = Observer.LANGFUSE

View file

@ -1,15 +1,13 @@
For the purposes of identifying timestamps in a query, you are tasked with extracting relevant timestamps from the query. You are tasked with identifying relevant time periods where the answer to a given query should be searched.
## Timestamp requirements Current date is: `{{ time_now }}`. Determine relevant period(s) and return structured intervals.
- If the query contains interval extrack both starts_at and ends_at properties
- If the query contains an instantaneous timestamp, starts_at and ends_at should be the same Extraction rules:
- If the query its open-ended (before 2009 or after 2009), the corresponding non defined end of the time should be none
-For example: "before 2009" -- starts_at: None, ends_at: 2009 or "after 2009" -- starts_at: 2009, ends_at: None 1. Query without specific timestamp: use the time period with starts_at set to None and ends_at set to now.
- Put always the data that comes first in time as starts_at and the timestamps that comes second in time as ends_at 2. Explicit time intervals: If the query specifies a range (e.g., from 2010 to 2020, between January and March 2023), extract both start and end dates. Always assign the earlier date to starts_at and the later date to ends_at.
- If starts_at or ends_at cannot be extracted both of them has to be None 3. Single timestamp: If the query refers to one specific moment (e.g., in 2015, on March 5, 2022), set starts_at and ends_at to that same timestamp.
## Output Format 4. Open-ended time references: For phrases such as "before X" or "after X", represent the unspecified side as None. For example: before 2009 → starts_at: None, ends_at: 2009; after 2009 → starts_at: 2009, ends_at: None.
Your reply should be a JSON: list of dictionaries with the following structure: 5. Current-time references ("now", "current", "today"): If the query explicitly refers to the present, set both starts_at and ends_at to now (the ingestion timestamp).
```python 6. "Who is" and "Who was" questions: These imply a general identity or biographical inquiry without a specific temporal scope. Set both starts_at and ends_at to None.
class QueryInterval(BaseModel): 7. Ordering rule: Always ensure the earlier date is assigned to starts_at and the later date to ends_at.
starts_at: Optional[Timestamp] = None 8. No temporal information: If no valid or inferable time reference is found, set both starts_at and ends_at to None.
ends_at: Optional[Timestamp] = None
```

View file

@ -21,7 +21,8 @@ def get_ontology_resolver_from_env(
Supported value: "rdflib". Supported value: "rdflib".
matching_strategy (str): The matching strategy to apply. matching_strategy (str): The matching strategy to apply.
Supported value: "fuzzy". Supported value: "fuzzy".
ontology_file_path (str): Path to the ontology file required for the resolver. ontology_file_path (str): Path to the ontology file(s) required for the resolver.
Can be a single path or comma-separated paths for multiple files.
Returns: Returns:
BaseOntologyResolver: An instance of the requested ontology resolver. BaseOntologyResolver: An instance of the requested ontology resolver.
@ -31,8 +32,13 @@ def get_ontology_resolver_from_env(
or if required parameters are missing. or if required parameters are missing.
""" """
if ontology_resolver == "rdflib" and matching_strategy == "fuzzy" and ontology_file_path: if ontology_resolver == "rdflib" and matching_strategy == "fuzzy" and ontology_file_path:
if "," in ontology_file_path:
file_paths = [path.strip() for path in ontology_file_path.split(",")]
else:
file_paths = ontology_file_path
return RDFLibOntologyResolver( return RDFLibOntologyResolver(
matching_strategy=FuzzyMatchingStrategy(), ontology_file=ontology_file_path matching_strategy=FuzzyMatchingStrategy(), ontology_file=file_paths
) )
else: else:
raise EnvironmentError( raise EnvironmentError(

View file

@ -2,7 +2,7 @@ import os
import difflib import difflib
from cognee.shared.logging_utils import get_logger from cognee.shared.logging_utils import get_logger
from collections import deque from collections import deque
from typing import List, Tuple, Dict, Optional, Any from typing import List, Tuple, Dict, Optional, Any, Union
from rdflib import Graph, URIRef, RDF, RDFS, OWL from rdflib import Graph, URIRef, RDF, RDFS, OWL
from cognee.modules.ontology.exceptions import ( from cognee.modules.ontology.exceptions import (
@ -26,22 +26,50 @@ class RDFLibOntologyResolver(BaseOntologyResolver):
def __init__( def __init__(
self, self,
ontology_file: Optional[str] = None, ontology_file: Optional[Union[str, List[str]]] = None,
matching_strategy: Optional[MatchingStrategy] = None, matching_strategy: Optional[MatchingStrategy] = None,
) -> None: ) -> None:
super().__init__(matching_strategy) super().__init__(matching_strategy)
self.ontology_file = ontology_file self.ontology_file = ontology_file
try: try:
if ontology_file and os.path.exists(ontology_file): files_to_load = []
if ontology_file is not None:
if isinstance(ontology_file, str):
files_to_load = [ontology_file]
elif isinstance(ontology_file, list):
files_to_load = ontology_file
else:
raise ValueError(
f"ontology_file must be a string, list of strings, or None. Got: {type(ontology_file)}"
)
if files_to_load:
self.graph = Graph() self.graph = Graph()
self.graph.parse(ontology_file) loaded_files = []
logger.info("Ontology loaded successfully from file: %s", ontology_file) for file_path in files_to_load:
if os.path.exists(file_path):
self.graph.parse(file_path)
loaded_files.append(file_path)
logger.info("Ontology loaded successfully from file: %s", file_path)
else:
logger.warning(
"Ontology file '%s' not found. Skipping this file.",
file_path,
)
if not loaded_files:
logger.info(
"No valid ontology files found. No owl ontology will be attached to the graph."
)
self.graph = None
else:
logger.info("Total ontology files loaded: %d", len(loaded_files))
else: else:
logger.info( logger.info(
"Ontology file '%s' not found. No owl ontology will be attached to the graph.", "No ontology file provided. No owl ontology will be attached to the graph."
ontology_file,
) )
self.graph = None self.graph = None
self.build_lookup() self.build_lookup()
except Exception as e: except Exception as e:
logger.error("Failed to load ontology", exc_info=e) logger.error("Failed to load ontology", exc_info=e)

View file

@ -27,6 +27,7 @@ async def handle_task(
additional_properties={ additional_properties={
"task_name": running_task.executable.__name__, "task_name": running_task.executable.__name__,
"cognee_version": cognee_version, "cognee_version": cognee_version,
"tenant_id": str(user.tenant_id) if user.tenant_id else "Single User Tenant",
}, },
) )
@ -49,6 +50,7 @@ async def handle_task(
additional_properties={ additional_properties={
"task_name": running_task.executable.__name__, "task_name": running_task.executable.__name__,
"cognee_version": cognee_version, "cognee_version": cognee_version,
"tenant_id": str(user.tenant_id) if user.tenant_id else "Single User Tenant",
}, },
) )
except Exception as error: except Exception as error:
@ -62,6 +64,7 @@ async def handle_task(
additional_properties={ additional_properties={
"task_name": running_task.executable.__name__, "task_name": running_task.executable.__name__,
"cognee_version": cognee_version, "cognee_version": cognee_version,
"tenant_id": str(user.tenant_id) if user.tenant_id else "Single User Tenant",
}, },
) )
raise error raise error

View file

@ -28,6 +28,7 @@ async def run_tasks_with_telemetry(
additional_properties={ additional_properties={
"pipeline_name": str(pipeline_name), "pipeline_name": str(pipeline_name),
"cognee_version": cognee_version, "cognee_version": cognee_version,
"tenant_id": str(user.tenant_id) if user.tenant_id else "Single User Tenant",
} }
| config, | config,
) )
@ -42,6 +43,7 @@ async def run_tasks_with_telemetry(
additional_properties={ additional_properties={
"pipeline_name": str(pipeline_name), "pipeline_name": str(pipeline_name),
"cognee_version": cognee_version, "cognee_version": cognee_version,
"tenant_id": str(user.tenant_id) if user.tenant_id else "Single User Tenant",
} }
| config, | config,
) )
@ -58,6 +60,7 @@ async def run_tasks_with_telemetry(
additional_properties={ additional_properties={
"pipeline_name": str(pipeline_name), "pipeline_name": str(pipeline_name),
"cognee_version": cognee_version, "cognee_version": cognee_version,
"tenant_id": str(user.tenant_id) if user.tenant_id else "Single User Tenant",
} }
| config, | config,
) )

View file

@ -1,7 +1,7 @@
import os import os
import asyncio import asyncio
from typing import Any, Optional, List, Type from typing import Any, Optional, List, Type
from datetime import datetime
from operator import itemgetter from operator import itemgetter
from cognee.infrastructure.databases.vector import get_vector_engine from cognee.infrastructure.databases.vector import get_vector_engine
@ -79,7 +79,11 @@ class TemporalRetriever(GraphCompletionRetriever):
else: else:
base_directory = None base_directory = None
system_prompt = render_prompt(prompt_path, {}, base_directory=base_directory) time_now = datetime.now().strftime("%d-%m-%Y")
system_prompt = render_prompt(
prompt_path, {"time_now": time_now}, base_directory=base_directory
)
interval = await LLMGateway.acreate_structured_output(query, system_prompt, QueryInterval) interval = await LLMGateway.acreate_structured_output(query, system_prompt, QueryInterval)
@ -108,8 +112,6 @@ class TemporalRetriever(GraphCompletionRetriever):
graph_engine = await get_graph_engine() graph_engine = await get_graph_engine()
triplets = []
if time_from and time_to: if time_from and time_to:
ids = await graph_engine.collect_time_ids(time_from=time_from, time_to=time_to) ids = await graph_engine.collect_time_ids(time_from=time_from, time_to=time_to)
elif time_from: elif time_from:

View file

@ -67,7 +67,10 @@ async def search(
send_telemetry( send_telemetry(
"cognee.search EXECUTION STARTED", "cognee.search EXECUTION STARTED",
user.id, user.id,
additional_properties={"cognee_version": cognee_version}, additional_properties={
"cognee_version": cognee_version,
"tenant_id": str(user.tenant_id) if user.tenant_id else "Single User Tenant",
},
) )
# Use search function filtered by permissions if access control is enabled # Use search function filtered by permissions if access control is enabled
@ -108,7 +111,10 @@ async def search(
send_telemetry( send_telemetry(
"cognee.search EXECUTION COMPLETED", "cognee.search EXECUTION COMPLETED",
user.id, user.id,
additional_properties={"cognee_version": cognee_version}, additional_properties={
"cognee_version": cognee_version,
"tenant_id": str(user.tenant_id) if user.tenant_id else "Single User Tenant",
},
) )
await log_result( await log_result(

View file

@ -1,6 +1,7 @@
import os import os
import sys import sys
import logging import logging
import tempfile
import structlog import structlog
import traceback import traceback
import platform import platform
@ -76,12 +77,8 @@ log_levels = {
# Track if structlog logging has been configured # Track if structlog logging has been configured
_is_structlog_configured = False _is_structlog_configured = False
# Logging directory resolution
# Default writable location for most Unix-based systems
DEFAULT_LOGS_DIR = "/tmp/cognee_logs"
def resolve_logs_dir():
def _resolve_logs_dir():
"""Resolve a writable logs directory. """Resolve a writable logs directory.
Priority: Priority:
@ -93,20 +90,13 @@ def _resolve_logs_dir():
""" """
candidate_paths = [] candidate_paths = []
# Prefer configuration from BaseConfig from cognee.base_config import get_base_config
try:
from cognee.base_config import get_base_config
base_config = get_base_config() base_config = get_base_config()
if getattr(base_config, "logs_root_directory", None): candidate_paths.append(Path(base_config.logs_root_directory))
candidate_paths.append(Path(base_config.logs_root_directory))
except Exception: tmp_candidate_path = os.path.join(tempfile.gettempdir(), "cognee_logs")
# If base config is unavailable during early imports, fall back to env candidate_paths.append(tmp_candidate_path)
env_dir = os.environ.get("COGNEE_LOGS_DIR")
if env_dir:
candidate_paths.append(Path(env_dir))
candidate_paths.append(Path(DEFAULT_LOGS_DIR))
candidate_paths.append(Path.cwd() / "logs")
for candidate in candidate_paths: for candidate in candidate_paths:
try: try:
@ -470,8 +460,17 @@ def setup_logging(log_level=None, name=None):
stream_handler.setFormatter(console_formatter) stream_handler.setFormatter(console_formatter)
stream_handler.setLevel(log_level) stream_handler.setLevel(log_level)
root_logger = logging.getLogger()
if root_logger.hasHandlers():
root_logger.handlers.clear()
root_logger.addHandler(stream_handler)
# Note: root logger needs to be set at NOTSET to allow all messages through and specific stream and file handlers
# can define their own levels.
root_logger.setLevel(logging.NOTSET)
# Resolve logs directory with env and safe fallbacks # Resolve logs directory with env and safe fallbacks
logs_dir = _resolve_logs_dir() logs_dir = resolve_logs_dir()
# Check if we already have a log file path from the environment # Check if we already have a log file path from the environment
# NOTE: environment variable must be used here as it allows us to # NOTE: environment variable must be used here as it allows us to
@ -484,24 +483,15 @@ def setup_logging(log_level=None, name=None):
log_file_path = str((logs_dir / f"{start_time}.log").resolve()) log_file_path = str((logs_dir / f"{start_time}.log").resolve())
os.environ["LOG_FILE_NAME"] = log_file_path os.environ["LOG_FILE_NAME"] = log_file_path
# Create a file handler that uses our custom PlainFileHandler if possible try:
file_handler = None # Create a file handler that uses our custom PlainFileHandler
if log_file_path: file_handler = PlainFileHandler(log_file_path, encoding="utf-8")
try: file_handler.setLevel(DEBUG)
file_handler = PlainFileHandler(log_file_path, encoding="utf-8")
file_handler.setLevel(DEBUG)
except Exception:
# If file handler cannot be created, fall back to console-only logging
file_handler = None
# Configure root logger
root_logger = logging.getLogger()
if root_logger.hasHandlers():
root_logger.handlers.clear()
root_logger.addHandler(stream_handler)
if file_handler is not None:
root_logger.addHandler(file_handler) root_logger.addHandler(file_handler)
root_logger.setLevel(log_level) except Exception as e:
# Note: Exceptions happen in case of read only file systems or log file path poiting to location where it does
# not have write permission. Logging to file is not mandatory so we just log a warning to console.
root_logger.warning(f"Warning: Could not create log file handler at {log_file_path}: {e}")
if log_level > logging.DEBUG: if log_level > logging.DEBUG:
import warnings import warnings
@ -541,6 +531,10 @@ def setup_logging(log_level=None, name=None):
# Get a configured logger and log system information # Get a configured logger and log system information
logger = structlog.get_logger(name if name else __name__) logger = structlog.get_logger(name if name else __name__)
if logs_dir is not None:
logger.info(f"Log file created at: {log_file_path}", log_file=log_file_path)
# Detailed initialization for regular usage # Detailed initialization for regular usage
logger.info( logger.info(
"Logging initialized", "Logging initialized",

View file

@ -239,7 +239,7 @@ async def complete_database_ingestion(schema, migrate_column_data):
id=uuid5(NAMESPACE_OID, name=column_node_id), id=uuid5(NAMESPACE_OID, name=column_node_id),
name=column_node_id, name=column_node_id,
properties=f"{key} {value} {table_name}", properties=f"{key} {value} {table_name}",
description=f"column from relational database table={table_name}. Column name={key} and value={value}. The value of the column is related to the following row with this id: {row_node.id}. This column has the following ID: {column_node_id}", description=f"column from relational database table={table_name}. Column name={key} and value={value}. This column has the following ID: {column_node_id}",
) )
node_mapping[column_node_id] = column_node node_mapping[column_node_id] = column_node

View file

@ -489,3 +489,154 @@ def test_get_ontology_resolver_from_env_resolver_functionality():
assert nodes == [] assert nodes == []
assert relationships == [] assert relationships == []
assert start_node is None assert start_node is None
def test_multifile_ontology_loading_success():
"""Test successful loading of multiple ontology files."""
ns1 = Namespace("http://example.org/cars#")
ns2 = Namespace("http://example.org/tech#")
g1 = Graph()
g1.add((ns1.Vehicle, RDF.type, OWL.Class))
g1.add((ns1.Car, RDF.type, OWL.Class))
g1.add((ns1.Car, RDFS.subClassOf, ns1.Vehicle))
g1.add((ns1.Audi, RDF.type, ns1.Car))
g1.add((ns1.BMW, RDF.type, ns1.Car))
g2 = Graph()
g2.add((ns2.Company, RDF.type, OWL.Class))
g2.add((ns2.TechCompany, RDF.type, OWL.Class))
g2.add((ns2.TechCompany, RDFS.subClassOf, ns2.Company))
g2.add((ns2.Apple, RDF.type, ns2.TechCompany))
g2.add((ns2.Google, RDF.type, ns2.TechCompany))
import tempfile
with tempfile.NamedTemporaryFile(mode="w", suffix=".owl", delete=False) as f1:
g1.serialize(f1.name, format="xml")
file1_path = f1.name
with tempfile.NamedTemporaryFile(mode="w", suffix=".owl", delete=False) as f2:
g2.serialize(f2.name, format="xml")
file2_path = f2.name
try:
resolver = RDFLibOntologyResolver(ontology_file=[file1_path, file2_path])
assert resolver.graph is not None
assert "car" in resolver.lookup["classes"]
assert "vehicle" in resolver.lookup["classes"]
assert "company" in resolver.lookup["classes"]
assert "techcompany" in resolver.lookup["classes"]
assert "audi" in resolver.lookup["individuals"]
assert "bmw" in resolver.lookup["individuals"]
assert "apple" in resolver.lookup["individuals"]
assert "google" in resolver.lookup["individuals"]
car_match = resolver.find_closest_match("Audi", "individuals")
assert car_match == "audi"
tech_match = resolver.find_closest_match("Google", "individuals")
assert tech_match == "google"
finally:
import os
os.unlink(file1_path)
os.unlink(file2_path)
def test_multifile_ontology_with_missing_files():
"""Test loading multiple ontology files where some don't exist."""
ns = Namespace("http://example.org/test#")
g = Graph()
g.add((ns.Car, RDF.type, OWL.Class))
g.add((ns.Audi, RDF.type, ns.Car))
import tempfile
with tempfile.NamedTemporaryFile(mode="w", suffix=".owl", delete=False) as f:
g.serialize(f.name, format="xml")
valid_file = f.name
try:
resolver = RDFLibOntologyResolver(
ontology_file=["nonexistent_file_1.owl", valid_file, "nonexistent_file_2.owl"]
)
assert resolver.graph is not None
assert "car" in resolver.lookup["classes"]
assert "audi" in resolver.lookup["individuals"]
match = resolver.find_closest_match("Audi", "individuals")
assert match == "audi"
finally:
import os
os.unlink(valid_file)
def test_multifile_ontology_all_files_missing():
"""Test loading multiple ontology files where all files are missing."""
resolver = RDFLibOntologyResolver(
ontology_file=["nonexistent_file_1.owl", "nonexistent_file_2.owl", "nonexistent_file_3.owl"]
)
assert resolver.graph is None
assert resolver.lookup["classes"] == {}
assert resolver.lookup["individuals"] == {}
def test_multifile_ontology_with_overlapping_entities():
"""Test loading multiple ontology files with overlapping/related entities."""
ns = Namespace("http://example.org/automotive#")
g1 = Graph()
g1.add((ns.Vehicle, RDF.type, OWL.Class))
g1.add((ns.Car, RDF.type, OWL.Class))
g1.add((ns.Car, RDFS.subClassOf, ns.Vehicle))
g2 = Graph()
g2.add((ns.LuxuryCar, RDF.type, OWL.Class))
g2.add((ns.LuxuryCar, RDFS.subClassOf, ns.Car))
g2.add((ns.Mercedes, RDF.type, ns.LuxuryCar))
g2.add((ns.BMW, RDF.type, ns.LuxuryCar))
import tempfile
with tempfile.NamedTemporaryFile(mode="w", suffix=".owl", delete=False) as f1:
g1.serialize(f1.name, format="xml")
file1_path = f1.name
with tempfile.NamedTemporaryFile(mode="w", suffix=".owl", delete=False) as f2:
g2.serialize(f2.name, format="xml")
file2_path = f2.name
try:
resolver = RDFLibOntologyResolver(ontology_file=[file1_path, file2_path])
assert "vehicle" in resolver.lookup["classes"]
assert "car" in resolver.lookup["classes"]
assert "luxurycar" in resolver.lookup["classes"]
assert "mercedes" in resolver.lookup["individuals"]
assert "bmw" in resolver.lookup["individuals"]
nodes, relationships, start_node = resolver.get_subgraph("Mercedes", "individuals")
uri_labels = {resolver._uri_to_key(n.uri) for n in nodes}
assert "mercedes" in uri_labels
assert "luxurycar" in uri_labels
assert "car" in uri_labels
assert "vehicle" in uri_labels
finally:
import os
os.unlink(file1_path)
os.unlink(file2_path)

View file

@ -77,6 +77,7 @@ async def main():
"What happened between 2000 and 2006?", "What happened between 2000 and 2006?",
"What happened between 1903 and 1995, I am interested in the Selected Works of Arnulf Øverland Ole Peter Arnulf Øverland?", "What happened between 1903 and 1995, I am interested in the Selected Works of Arnulf Øverland Ole Peter Arnulf Øverland?",
"Who is Attaphol Buspakom Attaphol Buspakom?", "Who is Attaphol Buspakom Attaphol Buspakom?",
"Who was Arnulf Øverland?",
] ]
for query_text in queries: for query_text in queries:

6
poetry.lock generated
View file

@ -1,4 +1,4 @@
# This file is automatically @generated by Poetry 2.1.2 and should not be changed by hand. # This file is automatically @generated by Poetry 2.1.3 and should not be changed by hand.
[[package]] [[package]]
name = "accelerate" name = "accelerate"
@ -2543,7 +2543,6 @@ files = [
{file = "fastuuid-0.12.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b9b31dd488d0778c36f8279b306dc92a42f16904cba54acca71e107d65b60b0c"}, {file = "fastuuid-0.12.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b9b31dd488d0778c36f8279b306dc92a42f16904cba54acca71e107d65b60b0c"},
{file = "fastuuid-0.12.0-cp313-cp313-manylinux_2_34_x86_64.whl", hash = "sha256:b19361ee649365eefc717ec08005972d3d1eb9ee39908022d98e3bfa9da59e37"}, {file = "fastuuid-0.12.0-cp313-cp313-manylinux_2_34_x86_64.whl", hash = "sha256:b19361ee649365eefc717ec08005972d3d1eb9ee39908022d98e3bfa9da59e37"},
{file = "fastuuid-0.12.0-cp313-cp313-win_amd64.whl", hash = "sha256:8fc66b11423e6f3e1937385f655bedd67aebe56a3dcec0cb835351cfe7d358c9"}, {file = "fastuuid-0.12.0-cp313-cp313-win_amd64.whl", hash = "sha256:8fc66b11423e6f3e1937385f655bedd67aebe56a3dcec0cb835351cfe7d358c9"},
{file = "fastuuid-0.12.0-cp38-cp38-macosx_10_12_x86_64.whl", hash = "sha256:2925f67b88d47cb16aa3eb1ab20fdcf21b94d74490e0818c91ea41434b987493"},
{file = "fastuuid-0.12.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:7b15c54d300279ab20a9cc0579ada9c9f80d1bc92997fc61fb7bf3103d7cb26b"}, {file = "fastuuid-0.12.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:7b15c54d300279ab20a9cc0579ada9c9f80d1bc92997fc61fb7bf3103d7cb26b"},
{file = "fastuuid-0.12.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:458f1bc3ebbd76fdb89ad83e6b81ccd3b2a99fa6707cd3650b27606745cfb170"}, {file = "fastuuid-0.12.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:458f1bc3ebbd76fdb89ad83e6b81ccd3b2a99fa6707cd3650b27606745cfb170"},
{file = "fastuuid-0.12.0-cp38-cp38-manylinux_2_34_x86_64.whl", hash = "sha256:a8f0f83fbba6dc44271a11b22e15838641b8c45612cdf541b4822a5930f6893c"}, {file = "fastuuid-0.12.0-cp38-cp38-manylinux_2_34_x86_64.whl", hash = "sha256:a8f0f83fbba6dc44271a11b22e15838641b8c45612cdf541b4822a5930f6893c"},
@ -4170,8 +4169,6 @@ groups = ["main"]
markers = "extra == \"dlt\"" markers = "extra == \"dlt\""
files = [ files = [
{file = "jsonpath-ng-1.7.0.tar.gz", hash = "sha256:f6f5f7fd4e5ff79c785f1573b394043b39849fb2bb47bcead935d12b00beab3c"}, {file = "jsonpath-ng-1.7.0.tar.gz", hash = "sha256:f6f5f7fd4e5ff79c785f1573b394043b39849fb2bb47bcead935d12b00beab3c"},
{file = "jsonpath_ng-1.7.0-py2-none-any.whl", hash = "sha256:898c93fc173f0c336784a3fa63d7434297544b7198124a68f9a3ef9597b0ae6e"},
{file = "jsonpath_ng-1.7.0-py3-none-any.whl", hash = "sha256:f3d7f9e848cba1b6da28c55b1c26ff915dc9e0b1ba7e752a53d6da8d5cbd00b6"},
] ]
[package.dependencies] [package.dependencies]
@ -8593,7 +8590,6 @@ files = [
{file = "psycopg2_binary-2.9.10-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:bb89f0a835bcfc1d42ccd5f41f04870c1b936d8507c6df12b7737febc40f0909"}, {file = "psycopg2_binary-2.9.10-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:bb89f0a835bcfc1d42ccd5f41f04870c1b936d8507c6df12b7737febc40f0909"},
{file = "psycopg2_binary-2.9.10-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:f0c2d907a1e102526dd2986df638343388b94c33860ff3bbe1384130828714b1"}, {file = "psycopg2_binary-2.9.10-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:f0c2d907a1e102526dd2986df638343388b94c33860ff3bbe1384130828714b1"},
{file = "psycopg2_binary-2.9.10-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:f8157bed2f51db683f31306aa497311b560f2265998122abe1dce6428bd86567"}, {file = "psycopg2_binary-2.9.10-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:f8157bed2f51db683f31306aa497311b560f2265998122abe1dce6428bd86567"},
{file = "psycopg2_binary-2.9.10-cp313-cp313-win_amd64.whl", hash = "sha256:27422aa5f11fbcd9b18da48373eb67081243662f9b46e6fd07c3eb46e4535142"},
{file = "psycopg2_binary-2.9.10-cp38-cp38-macosx_12_0_x86_64.whl", hash = "sha256:eb09aa7f9cecb45027683bb55aebaaf45a0df8bf6de68801a6afdc7947bb09d4"}, {file = "psycopg2_binary-2.9.10-cp38-cp38-macosx_12_0_x86_64.whl", hash = "sha256:eb09aa7f9cecb45027683bb55aebaaf45a0df8bf6de68801a6afdc7947bb09d4"},
{file = "psycopg2_binary-2.9.10-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b73d6d7f0ccdad7bc43e6d34273f70d587ef62f824d7261c4ae9b8b1b6af90e8"}, {file = "psycopg2_binary-2.9.10-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b73d6d7f0ccdad7bc43e6d34273f70d587ef62f824d7261c4ae9b8b1b6af90e8"},
{file = "psycopg2_binary-2.9.10-cp38-cp38-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ce5ab4bf46a211a8e924d307c1b1fcda82368586a19d0a24f8ae166f5c784864"}, {file = "psycopg2_binary-2.9.10-cp38-cp38-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ce5ab4bf46a211a8e924d307c1b1fcda82368586a19d0a24f8ae166f5c784864"},

View file

@ -1,7 +1,7 @@
[project] [project]
name = "cognee" name = "cognee"
version = "0.3.7" version = "0.3.7.dev1"
description = "Cognee - is a library for enriching LLM context with a semantic layer for better understanding and reasoning." description = "Cognee - is a library for enriching LLM context with a semantic layer for better understanding and reasoning."
authors = [ authors = [
{ name = "Vasilije Markovic" }, { name = "Vasilije Markovic" },

8274
uv.lock generated

File diff suppressed because it is too large Load diff