cognee 0.3.6__py3-none-any.whl → 0.3.7.dev1__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- cognee/__init__.py +1 -0
- cognee/api/health.py +2 -12
- cognee/api/v1/add/add.py +46 -6
- cognee/api/v1/add/routers/get_add_router.py +11 -2
- cognee/api/v1/cognify/cognify.py +29 -9
- cognee/api/v1/cognify/routers/get_cognify_router.py +2 -1
- cognee/api/v1/datasets/datasets.py +11 -0
- cognee/api/v1/datasets/routers/get_datasets_router.py +8 -0
- cognee/api/v1/delete/routers/get_delete_router.py +2 -0
- cognee/api/v1/memify/routers/get_memify_router.py +2 -1
- cognee/api/v1/permissions/routers/get_permissions_router.py +6 -0
- cognee/api/v1/responses/default_tools.py +0 -1
- cognee/api/v1/responses/dispatch_function.py +1 -1
- cognee/api/v1/responses/routers/default_tools.py +0 -1
- cognee/api/v1/search/routers/get_search_router.py +3 -3
- cognee/api/v1/search/search.py +11 -9
- cognee/api/v1/settings/routers/get_settings_router.py +7 -1
- cognee/api/v1/sync/routers/get_sync_router.py +3 -0
- cognee/api/v1/ui/ui.py +45 -16
- cognee/api/v1/update/routers/get_update_router.py +3 -1
- cognee/api/v1/update/update.py +3 -3
- cognee/api/v1/users/routers/get_visualize_router.py +2 -0
- cognee/cli/_cognee.py +61 -10
- cognee/cli/commands/add_command.py +3 -3
- cognee/cli/commands/cognify_command.py +3 -3
- cognee/cli/commands/config_command.py +9 -7
- cognee/cli/commands/delete_command.py +3 -3
- cognee/cli/commands/search_command.py +3 -7
- cognee/cli/config.py +0 -1
- cognee/context_global_variables.py +5 -0
- cognee/exceptions/exceptions.py +1 -1
- cognee/infrastructure/databases/cache/__init__.py +2 -0
- cognee/infrastructure/databases/cache/cache_db_interface.py +79 -0
- cognee/infrastructure/databases/cache/config.py +44 -0
- cognee/infrastructure/databases/cache/get_cache_engine.py +67 -0
- cognee/infrastructure/databases/cache/redis/RedisAdapter.py +243 -0
- cognee/infrastructure/databases/exceptions/__init__.py +1 -0
- cognee/infrastructure/databases/exceptions/exceptions.py +18 -2
- cognee/infrastructure/databases/graph/get_graph_engine.py +1 -1
- cognee/infrastructure/databases/graph/graph_db_interface.py +5 -0
- cognee/infrastructure/databases/graph/kuzu/adapter.py +76 -47
- cognee/infrastructure/databases/graph/neo4j_driver/adapter.py +13 -3
- cognee/infrastructure/databases/graph/neo4j_driver/deadlock_retry.py +1 -1
- cognee/infrastructure/databases/graph/neptune_driver/neptune_utils.py +1 -1
- cognee/infrastructure/databases/relational/sqlalchemy/SqlAlchemyAdapter.py +1 -1
- cognee/infrastructure/databases/vector/embeddings/FastembedEmbeddingEngine.py +21 -3
- cognee/infrastructure/databases/vector/embeddings/LiteLLMEmbeddingEngine.py +17 -10
- cognee/infrastructure/databases/vector/embeddings/OllamaEmbeddingEngine.py +17 -4
- cognee/infrastructure/databases/vector/embeddings/config.py +2 -3
- cognee/infrastructure/databases/vector/exceptions/exceptions.py +1 -1
- cognee/infrastructure/databases/vector/lancedb/LanceDBAdapter.py +0 -1
- cognee/infrastructure/files/exceptions.py +1 -1
- cognee/infrastructure/files/storage/LocalFileStorage.py +9 -9
- cognee/infrastructure/files/storage/S3FileStorage.py +11 -11
- cognee/infrastructure/files/utils/guess_file_type.py +6 -0
- cognee/infrastructure/llm/prompts/feedback_reaction_prompt.txt +14 -0
- cognee/infrastructure/llm/prompts/feedback_report_prompt.txt +13 -0
- cognee/infrastructure/llm/prompts/feedback_user_context_prompt.txt +5 -0
- cognee/infrastructure/llm/prompts/search_type_selector_prompt.txt +0 -5
- cognee/infrastructure/llm/structured_output_framework/litellm_instructor/llm/anthropic/adapter.py +19 -9
- cognee/infrastructure/llm/structured_output_framework/litellm_instructor/llm/gemini/adapter.py +17 -5
- cognee/infrastructure/llm/structured_output_framework/litellm_instructor/llm/generic_llm_api/adapter.py +17 -5
- cognee/infrastructure/llm/structured_output_framework/litellm_instructor/llm/get_llm_client.py +32 -0
- cognee/infrastructure/llm/structured_output_framework/litellm_instructor/llm/mistral/__init__.py +0 -0
- cognee/infrastructure/llm/structured_output_framework/litellm_instructor/llm/mistral/adapter.py +109 -0
- cognee/infrastructure/llm/structured_output_framework/litellm_instructor/llm/ollama/adapter.py +33 -8
- cognee/infrastructure/llm/structured_output_framework/litellm_instructor/llm/openai/adapter.py +40 -18
- cognee/infrastructure/loaders/LoaderEngine.py +27 -7
- cognee/infrastructure/loaders/external/__init__.py +7 -0
- cognee/infrastructure/loaders/external/advanced_pdf_loader.py +2 -8
- cognee/infrastructure/loaders/external/beautiful_soup_loader.py +310 -0
- cognee/infrastructure/loaders/supported_loaders.py +7 -0
- cognee/modules/data/exceptions/exceptions.py +1 -1
- cognee/modules/data/methods/__init__.py +3 -0
- cognee/modules/data/methods/get_dataset_data.py +4 -1
- cognee/modules/data/methods/has_dataset_data.py +21 -0
- cognee/modules/engine/models/TableRow.py +0 -1
- cognee/modules/ingestion/save_data_to_file.py +9 -2
- cognee/modules/pipelines/exceptions/exceptions.py +1 -1
- cognee/modules/pipelines/operations/pipeline.py +12 -1
- cognee/modules/pipelines/operations/run_tasks.py +25 -197
- cognee/modules/pipelines/operations/run_tasks_base.py +7 -0
- cognee/modules/pipelines/operations/run_tasks_data_item.py +260 -0
- cognee/modules/pipelines/operations/run_tasks_distributed.py +121 -38
- cognee/modules/pipelines/operations/run_tasks_with_telemetry.py +9 -1
- cognee/modules/retrieval/EntityCompletionRetriever.py +48 -8
- cognee/modules/retrieval/base_graph_retriever.py +3 -1
- cognee/modules/retrieval/base_retriever.py +3 -1
- cognee/modules/retrieval/chunks_retriever.py +5 -1
- cognee/modules/retrieval/code_retriever.py +20 -2
- cognee/modules/retrieval/completion_retriever.py +50 -9
- cognee/modules/retrieval/cypher_search_retriever.py +11 -1
- cognee/modules/retrieval/graph_completion_context_extension_retriever.py +47 -8
- cognee/modules/retrieval/graph_completion_cot_retriever.py +152 -22
- cognee/modules/retrieval/graph_completion_retriever.py +54 -10
- cognee/modules/retrieval/lexical_retriever.py +20 -2
- cognee/modules/retrieval/natural_language_retriever.py +10 -1
- cognee/modules/retrieval/summaries_retriever.py +5 -1
- cognee/modules/retrieval/temporal_retriever.py +62 -10
- cognee/modules/retrieval/user_qa_feedback.py +3 -2
- cognee/modules/retrieval/utils/completion.py +30 -4
- cognee/modules/retrieval/utils/description_to_codepart_search.py +1 -1
- cognee/modules/retrieval/utils/session_cache.py +156 -0
- cognee/modules/search/methods/get_search_type_tools.py +0 -5
- cognee/modules/search/methods/no_access_control_search.py +12 -1
- cognee/modules/search/methods/search.py +51 -5
- cognee/modules/search/types/SearchType.py +0 -1
- cognee/modules/settings/get_settings.py +23 -0
- cognee/modules/users/methods/get_authenticated_user.py +3 -1
- cognee/modules/users/methods/get_default_user.py +1 -6
- cognee/modules/users/roles/methods/create_role.py +2 -2
- cognee/modules/users/tenants/methods/create_tenant.py +2 -2
- cognee/shared/exceptions/exceptions.py +1 -1
- cognee/shared/logging_utils.py +18 -11
- cognee/shared/utils.py +24 -2
- cognee/tasks/codingagents/coding_rule_associations.py +1 -2
- cognee/tasks/documents/exceptions/exceptions.py +1 -1
- cognee/tasks/feedback/__init__.py +13 -0
- cognee/tasks/feedback/create_enrichments.py +84 -0
- cognee/tasks/feedback/extract_feedback_interactions.py +230 -0
- cognee/tasks/feedback/generate_improved_answers.py +130 -0
- cognee/tasks/feedback/link_enrichments_to_feedback.py +67 -0
- cognee/tasks/feedback/models.py +26 -0
- cognee/tasks/graph/extract_graph_from_data.py +2 -0
- cognee/tasks/ingestion/data_item_to_text_file.py +3 -3
- cognee/tasks/ingestion/ingest_data.py +11 -5
- cognee/tasks/ingestion/save_data_item_to_storage.py +12 -1
- cognee/tasks/storage/add_data_points.py +3 -10
- cognee/tasks/storage/index_data_points.py +19 -14
- cognee/tasks/storage/index_graph_edges.py +25 -11
- cognee/tasks/web_scraper/__init__.py +34 -0
- cognee/tasks/web_scraper/config.py +26 -0
- cognee/tasks/web_scraper/default_url_crawler.py +446 -0
- cognee/tasks/web_scraper/models.py +46 -0
- cognee/tasks/web_scraper/types.py +4 -0
- cognee/tasks/web_scraper/utils.py +142 -0
- cognee/tasks/web_scraper/web_scraper_task.py +396 -0
- cognee/tests/cli_tests/cli_unit_tests/test_cli_utils.py +0 -1
- cognee/tests/integration/web_url_crawler/test_default_url_crawler.py +13 -0
- cognee/tests/integration/web_url_crawler/test_tavily_crawler.py +19 -0
- cognee/tests/integration/web_url_crawler/test_url_adding_e2e.py +344 -0
- cognee/tests/subprocesses/reader.py +25 -0
- cognee/tests/subprocesses/simple_cognify_1.py +31 -0
- cognee/tests/subprocesses/simple_cognify_2.py +31 -0
- cognee/tests/subprocesses/writer.py +32 -0
- cognee/tests/tasks/descriptive_metrics/metrics_test_utils.py +0 -2
- cognee/tests/tasks/descriptive_metrics/neo4j_metrics_test.py +8 -3
- cognee/tests/tasks/entity_extraction/entity_extraction_test.py +89 -0
- cognee/tests/tasks/web_scraping/web_scraping_test.py +172 -0
- cognee/tests/test_add_docling_document.py +56 -0
- cognee/tests/test_chromadb.py +7 -11
- cognee/tests/test_concurrent_subprocess_access.py +76 -0
- cognee/tests/test_conversation_history.py +240 -0
- cognee/tests/test_feedback_enrichment.py +174 -0
- cognee/tests/test_kuzu.py +27 -15
- cognee/tests/test_lancedb.py +7 -11
- cognee/tests/test_library.py +32 -2
- cognee/tests/test_neo4j.py +24 -16
- cognee/tests/test_neptune_analytics_vector.py +7 -11
- cognee/tests/test_permissions.py +9 -13
- cognee/tests/test_pgvector.py +4 -4
- cognee/tests/test_remote_kuzu.py +8 -11
- cognee/tests/test_s3_file_storage.py +1 -1
- cognee/tests/test_search_db.py +6 -8
- cognee/tests/unit/infrastructure/databases/cache/test_cache_config.py +89 -0
- cognee/tests/unit/modules/retrieval/conversation_history_test.py +154 -0
- cognee/tests/unit/modules/retrieval/graph_completion_retriever_cot_test.py +51 -0
- {cognee-0.3.6.dist-info → cognee-0.3.7.dev1.dist-info}/METADATA +21 -6
- {cognee-0.3.6.dist-info → cognee-0.3.7.dev1.dist-info}/RECORD +178 -139
- {cognee-0.3.6.dist-info → cognee-0.3.7.dev1.dist-info}/entry_points.txt +1 -0
- distributed/Dockerfile +0 -3
- distributed/entrypoint.py +21 -9
- distributed/signal.py +5 -0
- distributed/workers/data_point_saving_worker.py +64 -34
- distributed/workers/graph_saving_worker.py +71 -47
- cognee/infrastructure/databases/graph/memgraph/memgraph_adapter.py +0 -1116
- cognee/modules/retrieval/insights_retriever.py +0 -133
- cognee/tests/test_memgraph.py +0 -109
- cognee/tests/unit/modules/retrieval/insights_retriever_test.py +0 -251
- {cognee-0.3.6.dist-info → cognee-0.3.7.dev1.dist-info}/WHEEL +0 -0
- {cognee-0.3.6.dist-info → cognee-0.3.7.dev1.dist-info}/licenses/LICENSE +0 -0
- {cognee-0.3.6.dist-info → cognee-0.3.7.dev1.dist-info}/licenses/NOTICE.md +0 -0
|
@@ -12,6 +12,7 @@ from cognee.modules.sync.methods import get_running_sync_operations_for_user, ge
|
|
|
12
12
|
from cognee.shared.utils import send_telemetry
|
|
13
13
|
from cognee.shared.logging_utils import get_logger
|
|
14
14
|
from cognee.api.v1.sync import SyncResponse
|
|
15
|
+
from cognee import __version__ as cognee_version
|
|
15
16
|
from cognee.context_global_variables import set_database_global_context_variables
|
|
16
17
|
|
|
17
18
|
logger = get_logger()
|
|
@@ -99,6 +100,7 @@ def get_sync_router() -> APIRouter:
|
|
|
99
100
|
user.id,
|
|
100
101
|
additional_properties={
|
|
101
102
|
"endpoint": "POST /v1/sync",
|
|
103
|
+
"cognee_version": cognee_version,
|
|
102
104
|
"dataset_ids": [str(id) for id in request.dataset_ids]
|
|
103
105
|
if request.dataset_ids
|
|
104
106
|
else "*",
|
|
@@ -205,6 +207,7 @@ def get_sync_router() -> APIRouter:
|
|
|
205
207
|
user.id,
|
|
206
208
|
additional_properties={
|
|
207
209
|
"endpoint": "GET /v1/sync/status",
|
|
210
|
+
"cognee_version": cognee_version,
|
|
208
211
|
},
|
|
209
212
|
)
|
|
210
213
|
|
cognee/api/v1/ui/ui.py
CHANGED
|
@@ -502,22 +502,46 @@ def start_ui(
|
|
|
502
502
|
|
|
503
503
|
if start_mcp:
|
|
504
504
|
logger.info("Starting Cognee MCP server with Docker...")
|
|
505
|
-
cwd = os.getcwd()
|
|
506
|
-
env_file = os.path.join(cwd, ".env")
|
|
507
505
|
try:
|
|
506
|
+
image = "cognee/cognee-mcp:main"
|
|
507
|
+
subprocess.run(["docker", "pull", image], check=True)
|
|
508
|
+
|
|
509
|
+
import uuid
|
|
510
|
+
|
|
511
|
+
container_name = f"cognee-mcp-{uuid.uuid4().hex[:8]}"
|
|
512
|
+
|
|
513
|
+
docker_cmd = [
|
|
514
|
+
"docker",
|
|
515
|
+
"run",
|
|
516
|
+
"--name",
|
|
517
|
+
container_name,
|
|
518
|
+
"-p",
|
|
519
|
+
f"{mcp_port}:8000",
|
|
520
|
+
"--rm",
|
|
521
|
+
"-e",
|
|
522
|
+
"TRANSPORT_MODE=sse",
|
|
523
|
+
]
|
|
524
|
+
|
|
525
|
+
if start_backend:
|
|
526
|
+
docker_cmd.extend(
|
|
527
|
+
[
|
|
528
|
+
"-e",
|
|
529
|
+
f"API_URL=http://localhost:{backend_port}",
|
|
530
|
+
]
|
|
531
|
+
)
|
|
532
|
+
logger.info(
|
|
533
|
+
f"Configuring MCP to connect to backend API at http://localhost:{backend_port}"
|
|
534
|
+
)
|
|
535
|
+
logger.info("(localhost will be auto-converted to host.docker.internal)")
|
|
536
|
+
else:
|
|
537
|
+
cwd = os.getcwd()
|
|
538
|
+
env_file = os.path.join(cwd, ".env")
|
|
539
|
+
docker_cmd.extend(["--env-file", env_file])
|
|
540
|
+
|
|
541
|
+
docker_cmd.append(image)
|
|
542
|
+
|
|
508
543
|
mcp_process = subprocess.Popen(
|
|
509
|
-
|
|
510
|
-
"docker",
|
|
511
|
-
"run",
|
|
512
|
-
"-p",
|
|
513
|
-
f"{mcp_port}:8000",
|
|
514
|
-
"--rm",
|
|
515
|
-
"--env-file",
|
|
516
|
-
env_file,
|
|
517
|
-
"-e",
|
|
518
|
-
"TRANSPORT_MODE=sse",
|
|
519
|
-
"cognee/cognee-mcp:main",
|
|
520
|
-
],
|
|
544
|
+
docker_cmd,
|
|
521
545
|
stdout=subprocess.PIPE,
|
|
522
546
|
stderr=subprocess.PIPE,
|
|
523
547
|
preexec_fn=os.setsid if hasattr(os, "setsid") else None,
|
|
@@ -526,8 +550,13 @@ def start_ui(
|
|
|
526
550
|
_stream_process_output(mcp_process, "stdout", "[MCP]", "\033[34m") # Blue
|
|
527
551
|
_stream_process_output(mcp_process, "stderr", "[MCP]", "\033[34m") # Blue
|
|
528
552
|
|
|
529
|
-
|
|
530
|
-
|
|
553
|
+
# Pass both PID and container name using a tuple
|
|
554
|
+
pid_callback((mcp_process.pid, container_name))
|
|
555
|
+
|
|
556
|
+
mode_info = "API mode" if start_backend else "direct mode"
|
|
557
|
+
logger.info(
|
|
558
|
+
f"✓ Cognee MCP server starting on http://127.0.0.1:{mcp_port}/sse ({mode_info})"
|
|
559
|
+
)
|
|
531
560
|
except Exception as e:
|
|
532
561
|
logger.error(f"Failed to start MCP server with Docker: {str(e)}")
|
|
533
562
|
# Start backend server if requested
|
|
@@ -9,6 +9,7 @@ from cognee.shared.logging_utils import get_logger
|
|
|
9
9
|
from cognee.modules.users.models import User
|
|
10
10
|
from cognee.modules.users.methods import get_authenticated_user
|
|
11
11
|
from cognee.shared.utils import send_telemetry
|
|
12
|
+
from cognee import __version__ as cognee_version
|
|
12
13
|
from cognee.modules.pipelines.models.PipelineRunInfo import (
|
|
13
14
|
PipelineRunErrored,
|
|
14
15
|
)
|
|
@@ -64,6 +65,7 @@ def get_update_router() -> APIRouter:
|
|
|
64
65
|
"dataset_id": str(dataset_id),
|
|
65
66
|
"data_id": str(data_id),
|
|
66
67
|
"node_set": str(node_set),
|
|
68
|
+
"cognee_version": cognee_version,
|
|
67
69
|
},
|
|
68
70
|
)
|
|
69
71
|
|
|
@@ -75,7 +77,7 @@ def get_update_router() -> APIRouter:
|
|
|
75
77
|
data=data,
|
|
76
78
|
dataset_id=dataset_id,
|
|
77
79
|
user=user,
|
|
78
|
-
node_set=node_set,
|
|
80
|
+
node_set=node_set if node_set else None,
|
|
79
81
|
)
|
|
80
82
|
|
|
81
83
|
# If any cognify run errored return JSONResponse with proper error status code
|
cognee/api/v1/update/update.py
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
from uuid import UUID
|
|
2
|
-
from typing import Union, BinaryIO, List, Optional
|
|
2
|
+
from typing import Union, BinaryIO, List, Optional, Any
|
|
3
3
|
|
|
4
4
|
from cognee.modules.users.models import User
|
|
5
5
|
from cognee.api.v1.delete import delete
|
|
@@ -10,12 +10,12 @@ from cognee.api.v1.cognify import cognify
|
|
|
10
10
|
async def update(
|
|
11
11
|
data_id: UUID,
|
|
12
12
|
data: Union[BinaryIO, list[BinaryIO], str, list[str]],
|
|
13
|
+
dataset_id: UUID,
|
|
13
14
|
user: User = None,
|
|
14
15
|
node_set: Optional[List[str]] = None,
|
|
15
|
-
dataset_id: Optional[UUID] = None,
|
|
16
16
|
vector_db_config: dict = None,
|
|
17
17
|
graph_db_config: dict = None,
|
|
18
|
-
preferred_loaders:
|
|
18
|
+
preferred_loaders: dict[str, dict[str, Any]] = None,
|
|
19
19
|
incremental_loading: bool = True,
|
|
20
20
|
):
|
|
21
21
|
"""
|
|
@@ -8,6 +8,7 @@ from cognee.modules.users.models import User
|
|
|
8
8
|
|
|
9
9
|
from cognee.context_global_variables import set_database_global_context_variables
|
|
10
10
|
from cognee.shared.utils import send_telemetry
|
|
11
|
+
from cognee import __version__ as cognee_version
|
|
11
12
|
|
|
12
13
|
logger = get_logger()
|
|
13
14
|
|
|
@@ -46,6 +47,7 @@ def get_visualize_router() -> APIRouter:
|
|
|
46
47
|
additional_properties={
|
|
47
48
|
"endpoint": "GET /v1/visualize",
|
|
48
49
|
"dataset_id": str(dataset_id),
|
|
50
|
+
"cognee_version": cognee_version,
|
|
49
51
|
},
|
|
50
52
|
)
|
|
51
53
|
|
cognee/cli/_cognee.py
CHANGED
|
@@ -175,19 +175,59 @@ def main() -> int:
|
|
|
175
175
|
# Handle UI flag
|
|
176
176
|
if hasattr(args, "start_ui") and args.start_ui:
|
|
177
177
|
spawned_pids = []
|
|
178
|
+
docker_container = None
|
|
178
179
|
|
|
179
180
|
def signal_handler(signum, frame):
|
|
180
181
|
"""Handle Ctrl+C and other termination signals"""
|
|
181
|
-
nonlocal spawned_pids
|
|
182
|
-
fmt.echo("\nShutting down UI server...")
|
|
182
|
+
nonlocal spawned_pids, docker_container
|
|
183
183
|
|
|
184
|
+
try:
|
|
185
|
+
fmt.echo("\nShutting down UI server...")
|
|
186
|
+
except (BrokenPipeError, OSError):
|
|
187
|
+
pass
|
|
188
|
+
|
|
189
|
+
# First, stop Docker container if running
|
|
190
|
+
if docker_container:
|
|
191
|
+
try:
|
|
192
|
+
result = subprocess.run(
|
|
193
|
+
["docker", "stop", docker_container],
|
|
194
|
+
capture_output=True,
|
|
195
|
+
timeout=10,
|
|
196
|
+
check=False,
|
|
197
|
+
)
|
|
198
|
+
try:
|
|
199
|
+
if result.returncode == 0:
|
|
200
|
+
fmt.success(f"✓ Docker container {docker_container} stopped.")
|
|
201
|
+
else:
|
|
202
|
+
fmt.warning(
|
|
203
|
+
f"Could not stop container {docker_container}: {result.stderr.decode()}"
|
|
204
|
+
)
|
|
205
|
+
except (BrokenPipeError, OSError):
|
|
206
|
+
pass
|
|
207
|
+
except subprocess.TimeoutExpired:
|
|
208
|
+
try:
|
|
209
|
+
fmt.warning(
|
|
210
|
+
f"Timeout stopping container {docker_container}, forcing removal..."
|
|
211
|
+
)
|
|
212
|
+
except (BrokenPipeError, OSError):
|
|
213
|
+
pass
|
|
214
|
+
subprocess.run(
|
|
215
|
+
["docker", "rm", "-f", docker_container], capture_output=True, check=False
|
|
216
|
+
)
|
|
217
|
+
except Exception:
|
|
218
|
+
pass
|
|
219
|
+
|
|
220
|
+
# Then, stop regular processes
|
|
184
221
|
for pid in spawned_pids:
|
|
185
222
|
try:
|
|
186
223
|
if hasattr(os, "killpg"):
|
|
187
224
|
# Unix-like systems: Use process groups
|
|
188
225
|
pgid = os.getpgid(pid)
|
|
189
226
|
os.killpg(pgid, signal.SIGTERM)
|
|
190
|
-
|
|
227
|
+
try:
|
|
228
|
+
fmt.success(f"✓ Process group {pgid} (PID {pid}) terminated.")
|
|
229
|
+
except (BrokenPipeError, OSError):
|
|
230
|
+
pass
|
|
191
231
|
else:
|
|
192
232
|
# Windows: Use taskkill to terminate process and its children
|
|
193
233
|
subprocess.run(
|
|
@@ -195,24 +235,35 @@ def main() -> int:
|
|
|
195
235
|
capture_output=True,
|
|
196
236
|
check=False,
|
|
197
237
|
)
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
238
|
+
try:
|
|
239
|
+
fmt.success(f"✓ Process {pid} and its children terminated.")
|
|
240
|
+
except (BrokenPipeError, OSError):
|
|
241
|
+
pass
|
|
242
|
+
except (OSError, ProcessLookupError, subprocess.SubprocessError):
|
|
243
|
+
pass
|
|
201
244
|
|
|
202
245
|
sys.exit(0)
|
|
203
246
|
|
|
204
247
|
signal.signal(signal.SIGINT, signal_handler) # Ctrl+C
|
|
205
248
|
signal.signal(signal.SIGTERM, signal_handler) # Termination request
|
|
249
|
+
if hasattr(signal, "SIGHUP"):
|
|
250
|
+
signal.signal(signal.SIGHUP, signal_handler)
|
|
206
251
|
|
|
207
252
|
try:
|
|
208
253
|
from cognee import start_ui
|
|
209
254
|
|
|
210
255
|
fmt.echo("Starting cognee UI...")
|
|
211
256
|
|
|
212
|
-
# Callback to capture PIDs of all spawned processes
|
|
213
|
-
def pid_callback(
|
|
214
|
-
nonlocal spawned_pids
|
|
215
|
-
|
|
257
|
+
# Callback to capture PIDs and Docker container of all spawned processes
|
|
258
|
+
def pid_callback(pid_or_tuple):
|
|
259
|
+
nonlocal spawned_pids, docker_container
|
|
260
|
+
# Handle both regular PIDs and (PID, container_name) tuples
|
|
261
|
+
if isinstance(pid_or_tuple, tuple):
|
|
262
|
+
pid, container_name = pid_or_tuple
|
|
263
|
+
spawned_pids.append(pid)
|
|
264
|
+
docker_container = container_name
|
|
265
|
+
else:
|
|
266
|
+
spawned_pids.append(pid_or_tuple)
|
|
216
267
|
|
|
217
268
|
frontend_port = 3000
|
|
218
269
|
start_backend, backend_port = True, 8000
|
|
@@ -70,11 +70,11 @@ After adding data, use `cognee cognify` to process it into knowledge graphs.
|
|
|
70
70
|
await cognee.add(data=data_to_add, dataset_name=args.dataset_name)
|
|
71
71
|
fmt.success(f"Successfully added data to dataset '{args.dataset_name}'")
|
|
72
72
|
except Exception as e:
|
|
73
|
-
raise CliCommandInnerException(f"Failed to add data: {str(e)}")
|
|
73
|
+
raise CliCommandInnerException(f"Failed to add data: {str(e)}") from e
|
|
74
74
|
|
|
75
75
|
asyncio.run(run_add())
|
|
76
76
|
|
|
77
77
|
except Exception as e:
|
|
78
78
|
if isinstance(e, CliCommandInnerException):
|
|
79
|
-
raise CliCommandException(str(e), error_code=1)
|
|
80
|
-
raise CliCommandException(f"
|
|
79
|
+
raise CliCommandException(str(e), error_code=1) from e
|
|
80
|
+
raise CliCommandException(f"Failed to add data: {str(e)}", error_code=1) from e
|
|
@@ -107,7 +107,7 @@ After successful cognify processing, use `cognee search` to query the knowledge
|
|
|
107
107
|
)
|
|
108
108
|
return result
|
|
109
109
|
except Exception as e:
|
|
110
|
-
raise CliCommandInnerException(f"Failed to cognify: {str(e)}")
|
|
110
|
+
raise CliCommandInnerException(f"Failed to cognify: {str(e)}") from e
|
|
111
111
|
|
|
112
112
|
result = asyncio.run(run_cognify())
|
|
113
113
|
|
|
@@ -124,5 +124,5 @@ After successful cognify processing, use `cognee search` to query the knowledge
|
|
|
124
124
|
|
|
125
125
|
except Exception as e:
|
|
126
126
|
if isinstance(e, CliCommandInnerException):
|
|
127
|
-
raise CliCommandException(str(e), error_code=1)
|
|
128
|
-
raise CliCommandException(f"Error during cognification: {str(e)}", error_code=1)
|
|
127
|
+
raise CliCommandException(str(e), error_code=1) from e
|
|
128
|
+
raise CliCommandException(f"Error during cognification: {str(e)}", error_code=1) from e
|
|
@@ -79,8 +79,10 @@ Configuration changes will affect how cognee processes and stores data.
|
|
|
79
79
|
|
|
80
80
|
except Exception as e:
|
|
81
81
|
if isinstance(e, CliCommandInnerException):
|
|
82
|
-
raise CliCommandException(str(e), error_code=1)
|
|
83
|
-
raise CliCommandException(
|
|
82
|
+
raise CliCommandException(str(e), error_code=1) from e
|
|
83
|
+
raise CliCommandException(
|
|
84
|
+
f"Error managing configuration: {str(e)}", error_code=1
|
|
85
|
+
) from e
|
|
84
86
|
|
|
85
87
|
def _handle_get(self, args: argparse.Namespace) -> None:
|
|
86
88
|
try:
|
|
@@ -122,7 +124,7 @@ Configuration changes will affect how cognee processes and stores data.
|
|
|
122
124
|
fmt.note("Configuration viewing not fully implemented yet")
|
|
123
125
|
|
|
124
126
|
except Exception as e:
|
|
125
|
-
raise CliCommandInnerException(f"Failed to get configuration: {str(e)}")
|
|
127
|
+
raise CliCommandInnerException(f"Failed to get configuration: {str(e)}") from e
|
|
126
128
|
|
|
127
129
|
def _handle_set(self, args: argparse.Namespace) -> None:
|
|
128
130
|
try:
|
|
@@ -141,7 +143,7 @@ Configuration changes will affect how cognee processes and stores data.
|
|
|
141
143
|
fmt.error(f"Failed to set configuration key '{args.key}'")
|
|
142
144
|
|
|
143
145
|
except Exception as e:
|
|
144
|
-
raise CliCommandInnerException(f"Failed to set configuration: {str(e)}")
|
|
146
|
+
raise CliCommandInnerException(f"Failed to set configuration: {str(e)}") from e
|
|
145
147
|
|
|
146
148
|
def _handle_unset(self, args: argparse.Namespace) -> None:
|
|
147
149
|
try:
|
|
@@ -189,7 +191,7 @@ Configuration changes will affect how cognee processes and stores data.
|
|
|
189
191
|
fmt.note("Use 'cognee config list' to see all available configuration options")
|
|
190
192
|
|
|
191
193
|
except Exception as e:
|
|
192
|
-
raise CliCommandInnerException(f"Failed to unset configuration: {str(e)}")
|
|
194
|
+
raise CliCommandInnerException(f"Failed to unset configuration: {str(e)}") from e
|
|
193
195
|
|
|
194
196
|
def _handle_list(self, args: argparse.Namespace) -> None:
|
|
195
197
|
try:
|
|
@@ -209,7 +211,7 @@ Configuration changes will affect how cognee processes and stores data.
|
|
|
209
211
|
fmt.echo(" cognee config reset - Reset all to defaults")
|
|
210
212
|
|
|
211
213
|
except Exception as e:
|
|
212
|
-
raise CliCommandInnerException(f"Failed to list configuration: {str(e)}")
|
|
214
|
+
raise CliCommandInnerException(f"Failed to list configuration: {str(e)}") from e
|
|
213
215
|
|
|
214
216
|
def _handle_reset(self, args: argparse.Namespace) -> None:
|
|
215
217
|
try:
|
|
@@ -222,4 +224,4 @@ Configuration changes will affect how cognee processes and stores data.
|
|
|
222
224
|
fmt.echo("This would reset all settings to their default values")
|
|
223
225
|
|
|
224
226
|
except Exception as e:
|
|
225
|
-
raise CliCommandInnerException(f"Failed to reset configuration: {str(e)}")
|
|
227
|
+
raise CliCommandInnerException(f"Failed to reset configuration: {str(e)}") from e
|
|
@@ -100,7 +100,7 @@ Be careful with deletion operations as they are irreversible.
|
|
|
100
100
|
else:
|
|
101
101
|
await cognee.delete(dataset_name=args.dataset_name, user_id=args.user_id)
|
|
102
102
|
except Exception as e:
|
|
103
|
-
raise CliCommandInnerException(f"Failed to delete: {str(e)}")
|
|
103
|
+
raise CliCommandInnerException(f"Failed to delete: {str(e)}") from e
|
|
104
104
|
|
|
105
105
|
asyncio.run(run_delete())
|
|
106
106
|
# This success message may be inaccurate due to the underlying bug, but we leave it for now.
|
|
@@ -108,5 +108,5 @@ Be careful with deletion operations as they are irreversible.
|
|
|
108
108
|
|
|
109
109
|
except Exception as e:
|
|
110
110
|
if isinstance(e, CliCommandInnerException):
|
|
111
|
-
raise CliCommandException(str(e), error_code=1)
|
|
112
|
-
raise CliCommandException(f"Error deleting data: {str(e)}", error_code=1)
|
|
111
|
+
raise CliCommandException(str(e), error_code=1) from e
|
|
112
|
+
raise CliCommandException(f"Error deleting data: {str(e)}", error_code=1) from e
|
|
@@ -31,10 +31,6 @@ Search Types & Use Cases:
|
|
|
31
31
|
Traditional RAG using document chunks without graph structure.
|
|
32
32
|
Best for: Direct document retrieval, specific fact-finding.
|
|
33
33
|
|
|
34
|
-
**INSIGHTS**:
|
|
35
|
-
Structured entity relationships and semantic connections.
|
|
36
|
-
Best for: Understanding concept relationships, knowledge mapping.
|
|
37
|
-
|
|
38
34
|
**CHUNKS**:
|
|
39
35
|
Raw text segments that match the query semantically.
|
|
40
36
|
Best for: Finding specific passages, citations, exact content.
|
|
@@ -108,7 +104,7 @@ Search Types & Use Cases:
|
|
|
108
104
|
)
|
|
109
105
|
return results
|
|
110
106
|
except Exception as e:
|
|
111
|
-
raise CliCommandInnerException(f"Failed to search: {str(e)}")
|
|
107
|
+
raise CliCommandInnerException(f"Failed to search: {str(e)}") from e
|
|
112
108
|
|
|
113
109
|
results = asyncio.run(run_search())
|
|
114
110
|
|
|
@@ -145,5 +141,5 @@ Search Types & Use Cases:
|
|
|
145
141
|
|
|
146
142
|
except Exception as e:
|
|
147
143
|
if isinstance(e, CliCommandInnerException):
|
|
148
|
-
raise CliCommandException(str(e), error_code=1)
|
|
149
|
-
raise CliCommandException(f"Error searching: {str(e)}", error_code=1)
|
|
144
|
+
raise CliCommandException(str(e), error_code=1) from e
|
|
145
|
+
raise CliCommandException(f"Error searching: {str(e)}", error_code=1) from e
|
cognee/cli/config.py
CHANGED
|
@@ -12,6 +12,11 @@ from cognee.modules.users.methods import get_user
|
|
|
12
12
|
# for different async tasks, threads and processes
|
|
13
13
|
vector_db_config = ContextVar("vector_db_config", default=None)
|
|
14
14
|
graph_db_config = ContextVar("graph_db_config", default=None)
|
|
15
|
+
session_user = ContextVar("session_user", default=None)
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
async def set_session_user_context_variable(user):
|
|
19
|
+
session_user.set(user)
|
|
15
20
|
|
|
16
21
|
|
|
17
22
|
async def set_database_global_context_variables(dataset: Union[str, UUID], user_id: UUID):
|
cognee/exceptions/exceptions.py
CHANGED
|
@@ -56,7 +56,7 @@ class CogneeValidationError(CogneeApiError):
|
|
|
56
56
|
self,
|
|
57
57
|
message: str = "A validation error occurred.",
|
|
58
58
|
name: str = "CogneeValidationError",
|
|
59
|
-
status_code=status.
|
|
59
|
+
status_code=status.HTTP_422_UNPROCESSABLE_CONTENT,
|
|
60
60
|
log=True,
|
|
61
61
|
log_level="ERROR",
|
|
62
62
|
):
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
from abc import ABC, abstractmethod
|
|
2
|
+
from contextlib import contextmanager
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
class CacheDBInterface(ABC):
|
|
6
|
+
"""
|
|
7
|
+
Abstract base class for distributed cache coordination systems (e.g., Redis, Memcached).
|
|
8
|
+
Provides a common interface for lock acquisition, release, and context-managed locking.
|
|
9
|
+
"""
|
|
10
|
+
|
|
11
|
+
def __init__(self, host: str, port: int, lock_key: str):
|
|
12
|
+
self.host = host
|
|
13
|
+
self.port = port
|
|
14
|
+
self.lock_key = lock_key
|
|
15
|
+
self.lock = None
|
|
16
|
+
|
|
17
|
+
@abstractmethod
|
|
18
|
+
def acquire_lock(self):
|
|
19
|
+
"""
|
|
20
|
+
Acquire a lock on the given key.
|
|
21
|
+
Must be implemented by subclasses.
|
|
22
|
+
"""
|
|
23
|
+
pass
|
|
24
|
+
|
|
25
|
+
@abstractmethod
|
|
26
|
+
def release_lock(self):
|
|
27
|
+
"""
|
|
28
|
+
Release the lock if it is held.
|
|
29
|
+
Must be implemented by subclasses.
|
|
30
|
+
"""
|
|
31
|
+
pass
|
|
32
|
+
|
|
33
|
+
@contextmanager
|
|
34
|
+
def hold_lock(self):
|
|
35
|
+
"""
|
|
36
|
+
Context manager for safely acquiring and releasing the lock.
|
|
37
|
+
"""
|
|
38
|
+
self.acquire()
|
|
39
|
+
try:
|
|
40
|
+
yield
|
|
41
|
+
finally:
|
|
42
|
+
self.release()
|
|
43
|
+
|
|
44
|
+
@abstractmethod
|
|
45
|
+
async def add_qa(
|
|
46
|
+
self,
|
|
47
|
+
user_id: str,
|
|
48
|
+
session_id: str,
|
|
49
|
+
question: str,
|
|
50
|
+
context: str,
|
|
51
|
+
answer: str,
|
|
52
|
+
ttl: int | None = 86400,
|
|
53
|
+
):
|
|
54
|
+
"""
|
|
55
|
+
Add a Q/A/context triplet to a cache session.
|
|
56
|
+
"""
|
|
57
|
+
|
|
58
|
+
pass
|
|
59
|
+
|
|
60
|
+
@abstractmethod
|
|
61
|
+
async def get_latest_qa(self, user_id: str, session_id: str, last_n: int = 5):
|
|
62
|
+
"""
|
|
63
|
+
Retrieve the most recent Q/A/context triplets for a session.
|
|
64
|
+
"""
|
|
65
|
+
pass
|
|
66
|
+
|
|
67
|
+
@abstractmethod
|
|
68
|
+
async def get_all_qas(self, user_id: str, session_id: str):
|
|
69
|
+
"""
|
|
70
|
+
Retrieve all Q/A/context triplets for the given session.
|
|
71
|
+
"""
|
|
72
|
+
pass
|
|
73
|
+
|
|
74
|
+
@abstractmethod
|
|
75
|
+
async def close(self):
|
|
76
|
+
"""
|
|
77
|
+
Gracefully close any async connections.
|
|
78
|
+
"""
|
|
79
|
+
pass
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
from pydantic_settings import BaseSettings, SettingsConfigDict
|
|
2
|
+
from functools import lru_cache
|
|
3
|
+
from typing import Optional
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
class CacheConfig(BaseSettings):
|
|
7
|
+
"""
|
|
8
|
+
Configuration for distributed cache systems (e.g., Redis), used for locking or coordination.
|
|
9
|
+
|
|
10
|
+
Attributes:
|
|
11
|
+
- shared_kuzu_lock: Shared kuzu lock logic on/off.
|
|
12
|
+
- cache_host: Hostname of the cache service.
|
|
13
|
+
- cache_port: Port number for the cache service.
|
|
14
|
+
- agentic_lock_expire: Automatic lock expiration time (in seconds).
|
|
15
|
+
- agentic_lock_timeout: Maximum time (in seconds) to wait for the lock release.
|
|
16
|
+
"""
|
|
17
|
+
|
|
18
|
+
caching: bool = False
|
|
19
|
+
shared_kuzu_lock: bool = False
|
|
20
|
+
cache_host: str = "localhost"
|
|
21
|
+
cache_port: int = 6379
|
|
22
|
+
cache_username: Optional[str] = None
|
|
23
|
+
cache_password: Optional[str] = None
|
|
24
|
+
agentic_lock_expire: int = 240
|
|
25
|
+
agentic_lock_timeout: int = 300
|
|
26
|
+
|
|
27
|
+
model_config = SettingsConfigDict(env_file=".env", extra="allow")
|
|
28
|
+
|
|
29
|
+
def to_dict(self) -> dict:
|
|
30
|
+
return {
|
|
31
|
+
"caching": self.caching,
|
|
32
|
+
"shared_kuzu_lock": self.shared_kuzu_lock,
|
|
33
|
+
"cache_host": self.cache_host,
|
|
34
|
+
"cache_port": self.cache_port,
|
|
35
|
+
"cache_username": self.cache_username,
|
|
36
|
+
"cache_password": self.cache_password,
|
|
37
|
+
"agentic_lock_expire": self.agentic_lock_expire,
|
|
38
|
+
"agentic_lock_timeout": self.agentic_lock_timeout,
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
@lru_cache
|
|
43
|
+
def get_cache_config():
|
|
44
|
+
return CacheConfig()
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
"""Factory to get the appropriate cache coordination engine (e.g., Redis)."""
|
|
2
|
+
|
|
3
|
+
from functools import lru_cache
|
|
4
|
+
from typing import Optional
|
|
5
|
+
from cognee.infrastructure.databases.cache.config import get_cache_config
|
|
6
|
+
from cognee.infrastructure.databases.cache.cache_db_interface import CacheDBInterface
|
|
7
|
+
|
|
8
|
+
config = get_cache_config()
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
@lru_cache
|
|
12
|
+
def create_cache_engine(
|
|
13
|
+
cache_host: str,
|
|
14
|
+
cache_port: int,
|
|
15
|
+
cache_username: str,
|
|
16
|
+
cache_password: str,
|
|
17
|
+
lock_key: str,
|
|
18
|
+
agentic_lock_expire: int = 240,
|
|
19
|
+
agentic_lock_timeout: int = 300,
|
|
20
|
+
):
|
|
21
|
+
"""
|
|
22
|
+
Factory function to instantiate a cache coordination backend (currently Redis).
|
|
23
|
+
|
|
24
|
+
Parameters:
|
|
25
|
+
-----------
|
|
26
|
+
- cache_host: Hostname or IP of the cache server.
|
|
27
|
+
- cache_port: Port number to connect to.
|
|
28
|
+
- cache_username: Username to authenticate with.
|
|
29
|
+
- cache_password: Password to authenticate with.
|
|
30
|
+
- lock_key: Identifier used for the locking resource.
|
|
31
|
+
- agentic_lock_expire: Duration to hold the lock after acquisition.
|
|
32
|
+
- agentic_lock_timeout: Max time to wait for the lock before failing.
|
|
33
|
+
|
|
34
|
+
Returns:
|
|
35
|
+
--------
|
|
36
|
+
- CacheDBInterface: An instance of the appropriate cache adapter. :TODO: Now we support only Redis. later if we add more here we can split the logic
|
|
37
|
+
"""
|
|
38
|
+
if config.caching:
|
|
39
|
+
from cognee.infrastructure.databases.cache.redis.RedisAdapter import RedisAdapter
|
|
40
|
+
|
|
41
|
+
return RedisAdapter(
|
|
42
|
+
host=cache_host,
|
|
43
|
+
port=cache_port,
|
|
44
|
+
username=cache_username,
|
|
45
|
+
password=cache_password,
|
|
46
|
+
lock_name=lock_key,
|
|
47
|
+
timeout=agentic_lock_expire,
|
|
48
|
+
blocking_timeout=agentic_lock_timeout,
|
|
49
|
+
)
|
|
50
|
+
else:
|
|
51
|
+
return None
|
|
52
|
+
|
|
53
|
+
|
|
54
|
+
def get_cache_engine(lock_key: Optional[str] = None) -> CacheDBInterface:
|
|
55
|
+
"""
|
|
56
|
+
Returns a cache adapter instance using current context configuration.
|
|
57
|
+
"""
|
|
58
|
+
|
|
59
|
+
return create_cache_engine(
|
|
60
|
+
cache_host=config.cache_host,
|
|
61
|
+
cache_port=config.cache_port,
|
|
62
|
+
cache_username=config.cache_username,
|
|
63
|
+
cache_password=config.cache_password,
|
|
64
|
+
lock_key=lock_key,
|
|
65
|
+
agentic_lock_expire=config.agentic_lock_expire,
|
|
66
|
+
agentic_lock_timeout=config.agentic_lock_timeout,
|
|
67
|
+
)
|