cognee 0.5.0.dev0__py3-none-any.whl → 0.5.0.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.
Files changed (131) hide show
  1. cognee/api/client.py +1 -5
  2. cognee/api/v1/add/add.py +2 -1
  3. cognee/api/v1/cognify/cognify.py +24 -16
  4. cognee/api/v1/cognify/routers/__init__.py +0 -1
  5. cognee/api/v1/cognify/routers/get_cognify_router.py +3 -1
  6. cognee/api/v1/datasets/routers/get_datasets_router.py +3 -3
  7. cognee/api/v1/ontologies/ontologies.py +12 -37
  8. cognee/api/v1/ontologies/routers/get_ontology_router.py +27 -25
  9. cognee/api/v1/search/search.py +4 -0
  10. cognee/api/v1/ui/node_setup.py +360 -0
  11. cognee/api/v1/ui/npm_utils.py +50 -0
  12. cognee/api/v1/ui/ui.py +38 -68
  13. cognee/context_global_variables.py +61 -16
  14. cognee/eval_framework/Dockerfile +29 -0
  15. cognee/eval_framework/answer_generation/answer_generation_executor.py +10 -0
  16. cognee/eval_framework/answer_generation/run_question_answering_module.py +1 -1
  17. cognee/eval_framework/corpus_builder/task_getters/get_cascade_graph_tasks.py +0 -2
  18. cognee/eval_framework/corpus_builder/task_getters/get_default_tasks_by_indices.py +4 -4
  19. cognee/eval_framework/eval_config.py +2 -2
  20. cognee/eval_framework/modal_run_eval.py +16 -28
  21. cognee/infrastructure/databases/dataset_database_handler/__init__.py +3 -0
  22. cognee/infrastructure/databases/dataset_database_handler/dataset_database_handler_interface.py +80 -0
  23. cognee/infrastructure/databases/dataset_database_handler/supported_dataset_database_handlers.py +18 -0
  24. cognee/infrastructure/databases/dataset_database_handler/use_dataset_database_handler.py +10 -0
  25. cognee/infrastructure/databases/graph/config.py +3 -0
  26. cognee/infrastructure/databases/graph/get_graph_engine.py +1 -0
  27. cognee/infrastructure/databases/graph/graph_db_interface.py +15 -0
  28. cognee/infrastructure/databases/graph/kuzu/KuzuDatasetDatabaseHandler.py +81 -0
  29. cognee/infrastructure/databases/graph/kuzu/adapter.py +228 -0
  30. cognee/infrastructure/databases/graph/neo4j_driver/Neo4jAuraDevDatasetDatabaseHandler.py +168 -0
  31. cognee/infrastructure/databases/graph/neo4j_driver/adapter.py +80 -1
  32. cognee/infrastructure/databases/utils/__init__.py +3 -0
  33. cognee/infrastructure/databases/utils/get_graph_dataset_database_handler.py +10 -0
  34. cognee/infrastructure/databases/utils/get_or_create_dataset_database.py +62 -48
  35. cognee/infrastructure/databases/utils/get_vector_dataset_database_handler.py +10 -0
  36. cognee/infrastructure/databases/utils/resolve_dataset_database_connection_info.py +30 -0
  37. cognee/infrastructure/databases/vector/config.py +2 -0
  38. cognee/infrastructure/databases/vector/create_vector_engine.py +1 -0
  39. cognee/infrastructure/databases/vector/embeddings/FastembedEmbeddingEngine.py +8 -6
  40. cognee/infrastructure/databases/vector/embeddings/LiteLLMEmbeddingEngine.py +9 -7
  41. cognee/infrastructure/databases/vector/embeddings/OllamaEmbeddingEngine.py +11 -10
  42. cognee/infrastructure/databases/vector/lancedb/LanceDBAdapter.py +2 -0
  43. cognee/infrastructure/databases/vector/lancedb/LanceDBDatasetDatabaseHandler.py +50 -0
  44. cognee/infrastructure/databases/vector/vector_db_interface.py +35 -0
  45. cognee/infrastructure/files/storage/s3_config.py +2 -0
  46. cognee/infrastructure/llm/LLMGateway.py +5 -2
  47. cognee/infrastructure/llm/config.py +35 -0
  48. cognee/infrastructure/llm/extraction/knowledge_graph/extract_content_graph.py +2 -2
  49. cognee/infrastructure/llm/structured_output_framework/baml/baml_src/extraction/acreate_structured_output.py +23 -8
  50. cognee/infrastructure/llm/structured_output_framework/litellm_instructor/llm/anthropic/adapter.py +17 -16
  51. cognee/infrastructure/llm/structured_output_framework/litellm_instructor/llm/bedrock/__init__.py +5 -0
  52. cognee/infrastructure/llm/structured_output_framework/litellm_instructor/llm/bedrock/adapter.py +153 -0
  53. cognee/infrastructure/llm/structured_output_framework/litellm_instructor/llm/gemini/adapter.py +40 -37
  54. cognee/infrastructure/llm/structured_output_framework/litellm_instructor/llm/generic_llm_api/adapter.py +39 -36
  55. cognee/infrastructure/llm/structured_output_framework/litellm_instructor/llm/get_llm_client.py +19 -1
  56. cognee/infrastructure/llm/structured_output_framework/litellm_instructor/llm/mistral/adapter.py +11 -9
  57. cognee/infrastructure/llm/structured_output_framework/litellm_instructor/llm/ollama/adapter.py +23 -21
  58. cognee/infrastructure/llm/structured_output_framework/litellm_instructor/llm/openai/adapter.py +42 -34
  59. cognee/memify_pipelines/create_triplet_embeddings.py +53 -0
  60. cognee/modules/cognify/config.py +2 -0
  61. cognee/modules/data/deletion/prune_system.py +52 -2
  62. cognee/modules/data/methods/delete_dataset.py +26 -0
  63. cognee/modules/engine/models/Triplet.py +9 -0
  64. cognee/modules/engine/models/__init__.py +1 -0
  65. cognee/modules/graph/cognee_graph/CogneeGraph.py +85 -37
  66. cognee/modules/graph/cognee_graph/CogneeGraphElements.py +8 -3
  67. cognee/modules/memify/memify.py +1 -7
  68. cognee/modules/pipelines/operations/pipeline.py +18 -2
  69. cognee/modules/retrieval/__init__.py +1 -1
  70. cognee/modules/retrieval/graph_completion_context_extension_retriever.py +4 -0
  71. cognee/modules/retrieval/graph_completion_cot_retriever.py +4 -0
  72. cognee/modules/retrieval/graph_completion_retriever.py +10 -0
  73. cognee/modules/retrieval/graph_summary_completion_retriever.py +4 -0
  74. cognee/modules/retrieval/register_retriever.py +10 -0
  75. cognee/modules/retrieval/registered_community_retrievers.py +1 -0
  76. cognee/modules/retrieval/temporal_retriever.py +4 -0
  77. cognee/modules/retrieval/triplet_retriever.py +182 -0
  78. cognee/modules/retrieval/utils/brute_force_triplet_search.py +42 -10
  79. cognee/modules/run_custom_pipeline/run_custom_pipeline.py +8 -1
  80. cognee/modules/search/methods/get_search_type_tools.py +54 -8
  81. cognee/modules/search/methods/no_access_control_search.py +4 -0
  82. cognee/modules/search/methods/search.py +21 -0
  83. cognee/modules/search/types/SearchType.py +1 -1
  84. cognee/modules/settings/get_settings.py +19 -0
  85. cognee/modules/users/methods/get_authenticated_user.py +2 -2
  86. cognee/modules/users/models/DatasetDatabase.py +15 -3
  87. cognee/shared/logging_utils.py +4 -0
  88. cognee/shared/rate_limiting.py +30 -0
  89. cognee/tasks/documents/__init__.py +0 -1
  90. cognee/tasks/graph/extract_graph_from_data.py +9 -10
  91. cognee/tasks/memify/get_triplet_datapoints.py +289 -0
  92. cognee/tasks/storage/add_data_points.py +142 -2
  93. cognee/tests/integration/retrieval/test_triplet_retriever.py +84 -0
  94. cognee/tests/integration/tasks/test_add_data_points.py +139 -0
  95. cognee/tests/integration/tasks/test_get_triplet_datapoints.py +69 -0
  96. cognee/tests/test_cognee_server_start.py +2 -4
  97. cognee/tests/test_conversation_history.py +23 -1
  98. cognee/tests/test_dataset_database_handler.py +137 -0
  99. cognee/tests/test_dataset_delete.py +76 -0
  100. cognee/tests/test_edge_centered_payload.py +170 -0
  101. cognee/tests/test_pipeline_cache.py +164 -0
  102. cognee/tests/test_search_db.py +37 -1
  103. cognee/tests/unit/api/test_ontology_endpoint.py +77 -89
  104. cognee/tests/unit/infrastructure/llm/test_llm_config.py +46 -0
  105. cognee/tests/unit/infrastructure/mock_embedding_engine.py +3 -7
  106. cognee/tests/unit/infrastructure/test_embedding_rate_limiting_realistic.py +0 -5
  107. cognee/tests/unit/modules/graph/cognee_graph_elements_test.py +2 -2
  108. cognee/tests/unit/modules/graph/cognee_graph_test.py +406 -0
  109. cognee/tests/unit/modules/memify_tasks/test_get_triplet_datapoints.py +214 -0
  110. cognee/tests/unit/modules/retrieval/test_brute_force_triplet_search.py +608 -0
  111. cognee/tests/unit/modules/retrieval/triplet_retriever_test.py +83 -0
  112. cognee/tests/unit/tasks/storage/test_add_data_points.py +288 -0
  113. {cognee-0.5.0.dev0.dist-info → cognee-0.5.0.dev1.dist-info}/METADATA +76 -89
  114. {cognee-0.5.0.dev0.dist-info → cognee-0.5.0.dev1.dist-info}/RECORD +118 -97
  115. {cognee-0.5.0.dev0.dist-info → cognee-0.5.0.dev1.dist-info}/WHEEL +1 -1
  116. cognee/api/v1/cognify/code_graph_pipeline.py +0 -119
  117. cognee/api/v1/cognify/routers/get_code_pipeline_router.py +0 -90
  118. cognee/infrastructure/databases/vector/embeddings/embedding_rate_limiter.py +0 -544
  119. cognee/modules/retrieval/code_retriever.py +0 -232
  120. cognee/tasks/code/enrich_dependency_graph_checker.py +0 -35
  121. cognee/tasks/code/get_local_dependencies_checker.py +0 -20
  122. cognee/tasks/code/get_repo_dependency_graph_checker.py +0 -35
  123. cognee/tasks/documents/check_permissions_on_dataset.py +0 -26
  124. cognee/tasks/repo_processor/__init__.py +0 -2
  125. cognee/tasks/repo_processor/get_local_dependencies.py +0 -335
  126. cognee/tasks/repo_processor/get_non_code_files.py +0 -158
  127. cognee/tasks/repo_processor/get_repo_file_dependencies.py +0 -243
  128. cognee/tests/test_delete_bmw_example.py +0 -60
  129. {cognee-0.5.0.dev0.dist-info → cognee-0.5.0.dev1.dist-info}/entry_points.txt +0 -0
  130. {cognee-0.5.0.dev0.dist-info → cognee-0.5.0.dev1.dist-info}/licenses/LICENSE +0 -0
  131. {cognee-0.5.0.dev0.dist-info → cognee-0.5.0.dev1.dist-info}/licenses/NOTICE.md +0 -0
@@ -0,0 +1,360 @@
1
+ import os
2
+ import platform
3
+ import subprocess
4
+ import tempfile
5
+ from pathlib import Path
6
+
7
+ import requests
8
+
9
+ from cognee.shared.logging_utils import get_logger
10
+
11
+ logger = get_logger()
12
+
13
+
14
+ def get_nvm_dir() -> Path:
15
+ """
16
+ Get the nvm directory path following standard nvm installation logic.
17
+ Uses XDG_CONFIG_HOME if set, otherwise falls back to ~/.nvm.
18
+ """
19
+ xdg_config_home = os.environ.get("XDG_CONFIG_HOME")
20
+ if xdg_config_home:
21
+ return Path(xdg_config_home) / "nvm"
22
+ return Path.home() / ".nvm"
23
+
24
+
25
+ def get_nvm_sh_path() -> Path:
26
+ """
27
+ Get the path to nvm.sh following standard nvm installation logic.
28
+ """
29
+ return get_nvm_dir() / "nvm.sh"
30
+
31
+
32
+ def check_nvm_installed() -> bool:
33
+ """
34
+ Check if nvm (Node Version Manager) is installed.
35
+ """
36
+ try:
37
+ # Check if nvm is available in the shell
38
+ # nvm is typically sourced in shell config files, so we need to check via shell
39
+ if platform.system() == "Windows":
40
+ # On Windows, nvm-windows uses a different approach
41
+ result = subprocess.run(
42
+ ["nvm", "version"],
43
+ capture_output=True,
44
+ text=True,
45
+ timeout=10,
46
+ shell=True,
47
+ )
48
+ else:
49
+ # On Unix-like systems, nvm is a shell function, so we need to source it
50
+ # First check if nvm.sh exists
51
+ nvm_path = get_nvm_sh_path()
52
+ if not nvm_path.exists():
53
+ logger.debug(f"nvm.sh not found at {nvm_path}")
54
+ return False
55
+
56
+ # Try to source nvm and check version, capturing errors
57
+ result = subprocess.run(
58
+ ["bash", "-c", f"source {nvm_path} && nvm --version"],
59
+ capture_output=True,
60
+ text=True,
61
+ timeout=10,
62
+ )
63
+
64
+ if result.returncode != 0:
65
+ # Log the error to help diagnose configuration issues
66
+ if result.stderr:
67
+ logger.debug(f"nvm check failed: {result.stderr.strip()}")
68
+ return False
69
+
70
+ return result.returncode == 0
71
+ except Exception as e:
72
+ logger.debug(f"Exception checking nvm: {str(e)}")
73
+ return False
74
+
75
+
76
+ def install_nvm() -> bool:
77
+ """
78
+ Install nvm (Node Version Manager) on Unix-like systems.
79
+ """
80
+ if platform.system() == "Windows":
81
+ logger.error("nvm installation on Windows requires nvm-windows.")
82
+ logger.error(
83
+ "Please install nvm-windows manually from: https://github.com/coreybutler/nvm-windows"
84
+ )
85
+ return False
86
+
87
+ logger.info("Installing nvm (Node Version Manager)...")
88
+
89
+ try:
90
+ # Download and install nvm
91
+ nvm_install_script = "https://raw.githubusercontent.com/nvm-sh/nvm/v0.40.3/install.sh"
92
+ logger.info(f"Downloading nvm installer from {nvm_install_script}...")
93
+
94
+ response = requests.get(nvm_install_script, timeout=60)
95
+ response.raise_for_status()
96
+
97
+ # Create a temporary script file
98
+ with tempfile.NamedTemporaryFile(mode="w", suffix=".sh", delete=False) as f:
99
+ f.write(response.text)
100
+ install_script_path = f.name
101
+
102
+ try:
103
+ # Make the script executable and run it
104
+ os.chmod(install_script_path, 0o755)
105
+ result = subprocess.run(
106
+ ["bash", install_script_path],
107
+ capture_output=True,
108
+ text=True,
109
+ timeout=120,
110
+ )
111
+
112
+ if result.returncode == 0:
113
+ logger.info("✓ nvm installed successfully")
114
+ # Source nvm in current shell session
115
+ nvm_dir = get_nvm_dir()
116
+ if nvm_dir.exists():
117
+ return True
118
+ else:
119
+ logger.warning(
120
+ f"nvm installation completed but nvm directory not found at {nvm_dir}"
121
+ )
122
+ return False
123
+ else:
124
+ logger.error(f"nvm installation failed: {result.stderr}")
125
+ return False
126
+ finally:
127
+ # Clean up temporary script
128
+ try:
129
+ os.unlink(install_script_path)
130
+ except Exception:
131
+ pass
132
+
133
+ except requests.exceptions.RequestException as e:
134
+ logger.error(f"Failed to download nvm installer: {str(e)}")
135
+ return False
136
+ except Exception as e:
137
+ logger.error(f"Failed to install nvm: {str(e)}")
138
+ return False
139
+
140
+
141
+ def install_node_with_nvm() -> bool:
142
+ """
143
+ Install the latest Node.js version using nvm.
144
+ Returns True if installation succeeds, False otherwise.
145
+ """
146
+ if platform.system() == "Windows":
147
+ logger.error("Node.js installation via nvm on Windows requires nvm-windows.")
148
+ logger.error("Please install Node.js manually from: https://nodejs.org/")
149
+ return False
150
+
151
+ logger.info("Installing latest Node.js version using nvm...")
152
+
153
+ try:
154
+ # Source nvm and install latest Node.js
155
+ nvm_path = get_nvm_sh_path()
156
+ if not nvm_path.exists():
157
+ logger.error(f"nvm.sh not found at {nvm_path}. nvm may not be properly installed.")
158
+ return False
159
+
160
+ nvm_source_cmd = f"source {nvm_path}"
161
+ install_cmd = f"{nvm_source_cmd} && nvm install node"
162
+
163
+ result = subprocess.run(
164
+ ["bash", "-c", install_cmd],
165
+ capture_output=True,
166
+ text=True,
167
+ timeout=300, # 5 minutes timeout for Node.js installation
168
+ )
169
+
170
+ if result.returncode == 0:
171
+ logger.info("✓ Node.js installed successfully via nvm")
172
+
173
+ # Set as default version
174
+ use_cmd = f"{nvm_source_cmd} && nvm alias default node"
175
+ subprocess.run(
176
+ ["bash", "-c", use_cmd],
177
+ capture_output=True,
178
+ text=True,
179
+ timeout=30,
180
+ )
181
+
182
+ # Add nvm to PATH for current session
183
+ # This ensures node/npm are available in subsequent commands
184
+ nvm_dir = get_nvm_dir()
185
+ if nvm_dir.exists():
186
+ # Update PATH for current process
187
+ nvm_bin = nvm_dir / "versions" / "node"
188
+ # Find the latest installed version
189
+ if nvm_bin.exists():
190
+ versions = sorted(nvm_bin.iterdir(), reverse=True)
191
+ if versions:
192
+ latest_node_bin = versions[0] / "bin"
193
+ if latest_node_bin.exists():
194
+ current_path = os.environ.get("PATH", "")
195
+ os.environ["PATH"] = f"{latest_node_bin}:{current_path}"
196
+
197
+ return True
198
+ else:
199
+ logger.error(f"Failed to install Node.js: {result.stderr}")
200
+ return False
201
+
202
+ except subprocess.TimeoutExpired:
203
+ logger.error("Timeout installing Node.js (this can take several minutes)")
204
+ return False
205
+ except Exception as e:
206
+ logger.error(f"Error installing Node.js: {str(e)}")
207
+ return False
208
+
209
+
210
+ def check_node_npm() -> tuple[bool, str]: # (is_available, error_message)
211
+ """
212
+ Check if Node.js and npm are available.
213
+ If not available, attempts to install nvm and Node.js automatically.
214
+ """
215
+
216
+ try:
217
+ # Check Node.js - try direct command first, then with nvm if needed
218
+ result = subprocess.run(["node", "--version"], capture_output=True, text=True, timeout=10)
219
+ if result.returncode != 0:
220
+ # If direct command fails, try with nvm sourced (in case nvm is installed but not in PATH)
221
+ nvm_path = get_nvm_sh_path()
222
+ if nvm_path.exists():
223
+ result = subprocess.run(
224
+ ["bash", "-c", f"source {nvm_path} && node --version"],
225
+ capture_output=True,
226
+ text=True,
227
+ timeout=10,
228
+ )
229
+ if result.returncode != 0 and result.stderr:
230
+ logger.debug(f"Failed to source nvm or run node: {result.stderr.strip()}")
231
+ if result.returncode != 0:
232
+ # Node.js is not installed, try to install it
233
+ logger.info("Node.js is not installed. Attempting to install automatically...")
234
+
235
+ # Check if nvm is installed
236
+ if not check_nvm_installed():
237
+ logger.info("nvm is not installed. Installing nvm first...")
238
+ if not install_nvm():
239
+ return (
240
+ False,
241
+ "Failed to install nvm. Please install Node.js manually from https://nodejs.org/",
242
+ )
243
+
244
+ # Install Node.js using nvm
245
+ if not install_node_with_nvm():
246
+ return (
247
+ False,
248
+ "Failed to install Node.js. Please install Node.js manually from https://nodejs.org/",
249
+ )
250
+
251
+ # Verify installation after automatic setup
252
+ # Try with nvm sourced first
253
+ nvm_path = get_nvm_sh_path()
254
+ if nvm_path.exists():
255
+ result = subprocess.run(
256
+ ["bash", "-c", f"source {nvm_path} && node --version"],
257
+ capture_output=True,
258
+ text=True,
259
+ timeout=10,
260
+ )
261
+ if result.returncode != 0 and result.stderr:
262
+ logger.debug(
263
+ f"Failed to verify node after installation: {result.stderr.strip()}"
264
+ )
265
+ else:
266
+ result = subprocess.run(
267
+ ["node", "--version"], capture_output=True, text=True, timeout=10
268
+ )
269
+ if result.returncode != 0:
270
+ nvm_path = get_nvm_sh_path()
271
+ return (
272
+ False,
273
+ f"Node.js installation completed but node command is not available. Please restart your terminal or source {nvm_path}",
274
+ )
275
+
276
+ node_version = result.stdout.strip()
277
+ logger.debug(f"Found Node.js version: {node_version}")
278
+
279
+ # Check npm - handle Windows PowerShell scripts
280
+ if platform.system() == "Windows":
281
+ # On Windows, npm might be a PowerShell script, so we need to use shell=True
282
+ result = subprocess.run(
283
+ ["npm", "--version"], capture_output=True, text=True, timeout=10, shell=True
284
+ )
285
+ else:
286
+ # On Unix-like systems, if we just installed via nvm, we may need to source nvm
287
+ # Try direct command first
288
+ result = subprocess.run(
289
+ ["npm", "--version"], capture_output=True, text=True, timeout=10
290
+ )
291
+ if result.returncode != 0:
292
+ # Try with nvm sourced
293
+ nvm_path = get_nvm_sh_path()
294
+ if nvm_path.exists():
295
+ result = subprocess.run(
296
+ ["bash", "-c", f"source {nvm_path} && npm --version"],
297
+ capture_output=True,
298
+ text=True,
299
+ timeout=10,
300
+ )
301
+ if result.returncode != 0 and result.stderr:
302
+ logger.debug(f"Failed to source nvm or run npm: {result.stderr.strip()}")
303
+
304
+ if result.returncode != 0:
305
+ return False, "npm is not installed or not in PATH"
306
+
307
+ npm_version = result.stdout.strip()
308
+ logger.debug(f"Found npm version: {npm_version}")
309
+
310
+ return True, f"Node.js {node_version}, npm {npm_version}"
311
+
312
+ except subprocess.TimeoutExpired:
313
+ return False, "Timeout checking Node.js/npm installation"
314
+ except FileNotFoundError:
315
+ # Node.js is not installed, try to install it
316
+ logger.info("Node.js is not found. Attempting to install automatically...")
317
+
318
+ # Check if nvm is installed
319
+ if not check_nvm_installed():
320
+ logger.info("nvm is not installed. Installing nvm first...")
321
+ if not install_nvm():
322
+ return (
323
+ False,
324
+ "Failed to install nvm. Please install Node.js manually from https://nodejs.org/",
325
+ )
326
+
327
+ # Install Node.js using nvm
328
+ if not install_node_with_nvm():
329
+ return (
330
+ False,
331
+ "Failed to install Node.js. Please install Node.js manually from https://nodejs.org/",
332
+ )
333
+
334
+ # Retry checking Node.js after installation
335
+ try:
336
+ result = subprocess.run(
337
+ ["node", "--version"], capture_output=True, text=True, timeout=10
338
+ )
339
+ if result.returncode == 0:
340
+ node_version = result.stdout.strip()
341
+ # Check npm
342
+ nvm_path = get_nvm_sh_path()
343
+ if nvm_path.exists():
344
+ result = subprocess.run(
345
+ ["bash", "-c", f"source {nvm_path} && npm --version"],
346
+ capture_output=True,
347
+ text=True,
348
+ timeout=10,
349
+ )
350
+ if result.returncode == 0:
351
+ npm_version = result.stdout.strip()
352
+ return True, f"Node.js {node_version}, npm {npm_version}"
353
+ elif result.stderr:
354
+ logger.debug(f"Failed to source nvm or run npm: {result.stderr.strip()}")
355
+ except Exception as e:
356
+ logger.debug(f"Exception retrying node/npm check: {str(e)}")
357
+
358
+ return False, "Node.js/npm not found. Please install Node.js from https://nodejs.org/"
359
+ except Exception as e:
360
+ return False, f"Error checking Node.js/npm: {str(e)}"
@@ -0,0 +1,50 @@
1
+ import platform
2
+ import subprocess
3
+ from pathlib import Path
4
+ from typing import List
5
+
6
+ from cognee.shared.logging_utils import get_logger
7
+ from .node_setup import get_nvm_sh_path
8
+
9
+ logger = get_logger()
10
+
11
+
12
+ def run_npm_command(cmd: List[str], cwd: Path, timeout: int = 300) -> subprocess.CompletedProcess:
13
+ """
14
+ Run an npm command, ensuring nvm is sourced if needed (Unix-like systems only).
15
+ Returns the CompletedProcess result.
16
+ """
17
+ if platform.system() == "Windows":
18
+ # On Windows, use shell=True for npm commands
19
+ return subprocess.run(
20
+ cmd,
21
+ cwd=cwd,
22
+ capture_output=True,
23
+ text=True,
24
+ timeout=timeout,
25
+ shell=True,
26
+ )
27
+ else:
28
+ # On Unix-like systems, try direct command first
29
+ result = subprocess.run(
30
+ cmd,
31
+ cwd=cwd,
32
+ capture_output=True,
33
+ text=True,
34
+ timeout=timeout,
35
+ )
36
+ # If it fails and nvm might be installed, try with nvm sourced
37
+ if result.returncode != 0:
38
+ nvm_path = get_nvm_sh_path()
39
+ if nvm_path.exists():
40
+ nvm_cmd = f"source {nvm_path} && {' '.join(cmd)}"
41
+ result = subprocess.run(
42
+ ["bash", "-c", nvm_cmd],
43
+ cwd=cwd,
44
+ capture_output=True,
45
+ text=True,
46
+ timeout=timeout,
47
+ )
48
+ if result.returncode != 0 and result.stderr:
49
+ logger.debug(f"npm command failed with nvm: {result.stderr.strip()}")
50
+ return result
cognee/api/v1/ui/ui.py CHANGED
@@ -15,6 +15,8 @@ import shutil
15
15
 
16
16
  from cognee.shared.logging_utils import get_logger
17
17
  from cognee.version import get_cognee_version
18
+ from .node_setup import check_node_npm, get_nvm_dir, get_nvm_sh_path
19
+ from .npm_utils import run_npm_command
18
20
 
19
21
  logger = get_logger()
20
22
 
@@ -285,48 +287,6 @@ def find_frontend_path() -> Optional[Path]:
285
287
  return None
286
288
 
287
289
 
288
- def check_node_npm() -> tuple[bool, str]:
289
- """
290
- Check if Node.js and npm are available.
291
- Returns (is_available, error_message)
292
- """
293
-
294
- try:
295
- # Check Node.js
296
- result = subprocess.run(["node", "--version"], capture_output=True, text=True, timeout=10)
297
- if result.returncode != 0:
298
- return False, "Node.js is not installed or not in PATH"
299
-
300
- node_version = result.stdout.strip()
301
- logger.debug(f"Found Node.js version: {node_version}")
302
-
303
- # Check npm - handle Windows PowerShell scripts
304
- if platform.system() == "Windows":
305
- # On Windows, npm might be a PowerShell script, so we need to use shell=True
306
- result = subprocess.run(
307
- ["npm", "--version"], capture_output=True, text=True, timeout=10, shell=True
308
- )
309
- else:
310
- result = subprocess.run(
311
- ["npm", "--version"], capture_output=True, text=True, timeout=10
312
- )
313
-
314
- if result.returncode != 0:
315
- return False, "npm is not installed or not in PATH"
316
-
317
- npm_version = result.stdout.strip()
318
- logger.debug(f"Found npm version: {npm_version}")
319
-
320
- return True, f"Node.js {node_version}, npm {npm_version}"
321
-
322
- except subprocess.TimeoutExpired:
323
- return False, "Timeout checking Node.js/npm installation"
324
- except FileNotFoundError:
325
- return False, "Node.js/npm not found. Please install Node.js from https://nodejs.org/"
326
- except Exception as e:
327
- return False, f"Error checking Node.js/npm: {str(e)}"
328
-
329
-
330
290
  def install_frontend_dependencies(frontend_path: Path) -> bool:
331
291
  """
332
292
  Install frontend dependencies if node_modules doesn't exist.
@@ -341,24 +301,7 @@ def install_frontend_dependencies(frontend_path: Path) -> bool:
341
301
  logger.info("Installing frontend dependencies (this may take a few minutes)...")
342
302
 
343
303
  try:
344
- # Use shell=True on Windows for npm commands
345
- if platform.system() == "Windows":
346
- result = subprocess.run(
347
- ["npm", "install"],
348
- cwd=frontend_path,
349
- capture_output=True,
350
- text=True,
351
- timeout=300, # 5 minutes timeout
352
- shell=True,
353
- )
354
- else:
355
- result = subprocess.run(
356
- ["npm", "install"],
357
- cwd=frontend_path,
358
- capture_output=True,
359
- text=True,
360
- timeout=300, # 5 minutes timeout
361
- )
304
+ result = run_npm_command(["npm", "install"], frontend_path, timeout=300)
362
305
 
363
306
  if result.returncode == 0:
364
307
  logger.info("Frontend dependencies installed successfully")
@@ -642,6 +585,21 @@ def start_ui(
642
585
  env["HOST"] = "localhost"
643
586
  env["PORT"] = str(port)
644
587
 
588
+ # If nvm is installed, ensure it's available in the environment
589
+ nvm_path = get_nvm_sh_path()
590
+ if platform.system() != "Windows" and nvm_path.exists():
591
+ # Add nvm to PATH for the subprocess
592
+ nvm_dir = get_nvm_dir()
593
+ # Find the latest Node.js version installed via nvm
594
+ nvm_versions = nvm_dir / "versions" / "node"
595
+ if nvm_versions.exists():
596
+ versions = sorted(nvm_versions.iterdir(), reverse=True)
597
+ if versions:
598
+ latest_node_bin = versions[0] / "bin"
599
+ if latest_node_bin.exists():
600
+ current_path = env.get("PATH", "")
601
+ env["PATH"] = f"{latest_node_bin}:{current_path}"
602
+
645
603
  # Start the development server
646
604
  logger.info(f"Starting frontend server at http://localhost:{port}")
647
605
  logger.info("This may take a moment to compile and start...")
@@ -659,14 +617,26 @@ def start_ui(
659
617
  shell=True,
660
618
  )
661
619
  else:
662
- process = subprocess.Popen(
663
- ["npm", "run", "dev"],
664
- cwd=frontend_path,
665
- env=env,
666
- stdout=subprocess.PIPE,
667
- stderr=subprocess.PIPE,
668
- preexec_fn=os.setsid if hasattr(os, "setsid") else None,
669
- )
620
+ # On Unix-like systems, use bash with nvm sourced if available
621
+ if nvm_path.exists():
622
+ # Use bash to source nvm and run npm
623
+ process = subprocess.Popen(
624
+ ["bash", "-c", f"source {nvm_path} && npm run dev"],
625
+ cwd=frontend_path,
626
+ env=env,
627
+ stdout=subprocess.PIPE,
628
+ stderr=subprocess.PIPE,
629
+ preexec_fn=os.setsid if hasattr(os, "setsid") else None,
630
+ )
631
+ else:
632
+ process = subprocess.Popen(
633
+ ["npm", "run", "dev"],
634
+ cwd=frontend_path,
635
+ env=env,
636
+ stdout=subprocess.PIPE,
637
+ stderr=subprocess.PIPE,
638
+ preexec_fn=os.setsid if hasattr(os, "setsid") else None,
639
+ )
670
640
 
671
641
  # Start threads to stream frontend output with prefix
672
642
  _stream_process_output(process, "stdout", "[FRONTEND]", "\033[33m") # Yellow
@@ -4,9 +4,10 @@ from typing import Union
4
4
  from uuid import UUID
5
5
 
6
6
  from cognee.base_config import get_base_config
7
- from cognee.infrastructure.databases.vector.config import get_vectordb_context_config
8
- from cognee.infrastructure.databases.graph.config import get_graph_context_config
7
+ from cognee.infrastructure.databases.vector.config import get_vectordb_config
8
+ from cognee.infrastructure.databases.graph.config import get_graph_config
9
9
  from cognee.infrastructure.databases.utils import get_or_create_dataset_database
10
+ from cognee.infrastructure.databases.utils import resolve_dataset_database_connection_info
10
11
  from cognee.infrastructure.files.storage.config import file_storage_config
11
12
  from cognee.modules.users.methods import get_user
12
13
 
@@ -16,22 +17,59 @@ vector_db_config = ContextVar("vector_db_config", default=None)
16
17
  graph_db_config = ContextVar("graph_db_config", default=None)
17
18
  session_user = ContextVar("session_user", default=None)
18
19
 
19
- VECTOR_DBS_WITH_MULTI_USER_SUPPORT = ["lancedb", "falkor"]
20
- GRAPH_DBS_WITH_MULTI_USER_SUPPORT = ["kuzu", "falkor"]
21
-
22
20
 
23
21
  async def set_session_user_context_variable(user):
24
22
  session_user.set(user)
25
23
 
26
24
 
27
25
  def multi_user_support_possible():
28
- graph_db_config = get_graph_context_config()
29
- vector_db_config = get_vectordb_context_config()
30
- return (
31
- graph_db_config["graph_database_provider"] in GRAPH_DBS_WITH_MULTI_USER_SUPPORT
32
- and vector_db_config["vector_db_provider"] in VECTOR_DBS_WITH_MULTI_USER_SUPPORT
26
+ graph_db_config = get_graph_config()
27
+ vector_db_config = get_vectordb_config()
28
+
29
+ graph_handler = graph_db_config.graph_dataset_database_handler
30
+ vector_handler = vector_db_config.vector_dataset_database_handler
31
+ from cognee.infrastructure.databases.dataset_database_handler import (
32
+ supported_dataset_database_handlers,
33
33
  )
34
34
 
35
+ if graph_handler not in supported_dataset_database_handlers:
36
+ raise EnvironmentError(
37
+ "Unsupported graph dataset to database handler configured. Cannot add support for multi-user access control mode. Please use a supported graph dataset to database handler or set the environment variables ENABLE_BACKEND_ACCESS_CONTROL to false to switch off multi-user access control mode.\n"
38
+ f"Selected graph dataset to database handler: {graph_handler}\n"
39
+ f"Supported dataset to database handlers: {list(supported_dataset_database_handlers.keys())}\n"
40
+ )
41
+
42
+ if vector_handler not in supported_dataset_database_handlers:
43
+ raise EnvironmentError(
44
+ "Unsupported vector dataset to database handler configured. Cannot add support for multi-user access control mode. Please use a supported vector dataset to database handler or set the environment variables ENABLE_BACKEND_ACCESS_CONTROL to false to switch off multi-user access control mode.\n"
45
+ f"Selected vector dataset to database handler: {vector_handler}\n"
46
+ f"Supported dataset to database handlers: {list(supported_dataset_database_handlers.keys())}\n"
47
+ )
48
+
49
+ if (
50
+ supported_dataset_database_handlers[graph_handler]["handler_provider"]
51
+ != graph_db_config.graph_database_provider
52
+ ):
53
+ raise EnvironmentError(
54
+ "The selected graph dataset to database handler does not work with the configured graph database provider. Cannot add support for multi-user access control mode. Please use a supported graph dataset to database handler or set the environment variables ENABLE_BACKEND_ACCESS_CONTROL to false to switch off multi-user access control mode.\n"
55
+ f"Selected graph database provider: {graph_db_config.graph_database_provider}\n"
56
+ f"Selected graph dataset to database handler: {graph_handler}\n"
57
+ f"Supported dataset to database handlers: {list(supported_dataset_database_handlers.keys())}\n"
58
+ )
59
+
60
+ if (
61
+ supported_dataset_database_handlers[vector_handler]["handler_provider"]
62
+ != vector_db_config.vector_db_provider
63
+ ):
64
+ raise EnvironmentError(
65
+ "The selected vector dataset to database handler does not work with the configured vector database provider. Cannot add support for multi-user access control mode. Please use a supported vector dataset to database handler or set the environment variables ENABLE_BACKEND_ACCESS_CONTROL to false to switch off multi-user access control mode.\n"
66
+ f"Selected vector database provider: {vector_db_config.vector_db_provider}\n"
67
+ f"Selected vector dataset to database handler: {vector_handler}\n"
68
+ f"Supported dataset to database handlers: {list(supported_dataset_database_handlers.keys())}\n"
69
+ )
70
+
71
+ return True
72
+
35
73
 
36
74
  def backend_access_control_enabled():
37
75
  backend_access_control = os.environ.get("ENABLE_BACKEND_ACCESS_CONTROL", None)
@@ -41,12 +79,7 @@ def backend_access_control_enabled():
41
79
  return multi_user_support_possible()
42
80
  elif backend_access_control.lower() == "true":
43
81
  # If enabled, ensure that the current graph and vector DBs can support it
44
- multi_user_support = multi_user_support_possible()
45
- if not multi_user_support:
46
- raise EnvironmentError(
47
- "ENABLE_BACKEND_ACCESS_CONTROL is set to true but the current graph and/or vector databases do not support multi-user access control. Please use supported databases or disable backend access control."
48
- )
49
- return True
82
+ return multi_user_support_possible()
50
83
  return False
51
84
 
52
85
 
@@ -76,6 +109,8 @@ async def set_database_global_context_variables(dataset: Union[str, UUID], user_
76
109
 
77
110
  # To ensure permissions are enforced properly all datasets will have their own databases
78
111
  dataset_database = await get_or_create_dataset_database(dataset, user)
112
+ # Ensure that all connection info is resolved properly
113
+ dataset_database = await resolve_dataset_database_connection_info(dataset_database)
79
114
 
80
115
  base_config = get_base_config()
81
116
  data_root_directory = os.path.join(
@@ -86,6 +121,8 @@ async def set_database_global_context_variables(dataset: Union[str, UUID], user_
86
121
  )
87
122
 
88
123
  # Set vector and graph database configuration based on dataset database information
124
+ # TODO: Add better handling of vector and graph config accross Cognee.
125
+ # LRU_CACHE takes into account order of inputs, if order of inputs is changed it will be registered as a new DB adapter
89
126
  vector_config = {
90
127
  "vector_db_provider": dataset_database.vector_database_provider,
91
128
  "vector_db_url": dataset_database.vector_database_url,
@@ -101,6 +138,14 @@ async def set_database_global_context_variables(dataset: Union[str, UUID], user_
101
138
  "graph_file_path": os.path.join(
102
139
  databases_directory_path, dataset_database.graph_database_name
103
140
  ),
141
+ "graph_database_username": dataset_database.graph_database_connection_info.get(
142
+ "graph_database_username", ""
143
+ ),
144
+ "graph_database_password": dataset_database.graph_database_connection_info.get(
145
+ "graph_database_password", ""
146
+ ),
147
+ "graph_dataset_database_handler": "",
148
+ "graph_database_port": "",
104
149
  }
105
150
 
106
151
  storage_config = {