cognee 0.2.3.dev1__py3-none-any.whl → 0.3.0__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 (252) hide show
  1. cognee/__init__.py +2 -0
  2. cognee/__main__.py +4 -0
  3. cognee/api/client.py +28 -3
  4. cognee/api/health.py +10 -13
  5. cognee/api/v1/add/add.py +20 -6
  6. cognee/api/v1/add/routers/get_add_router.py +12 -37
  7. cognee/api/v1/cloud/routers/__init__.py +1 -0
  8. cognee/api/v1/cloud/routers/get_checks_router.py +23 -0
  9. cognee/api/v1/cognify/code_graph_pipeline.py +14 -3
  10. cognee/api/v1/cognify/cognify.py +67 -105
  11. cognee/api/v1/cognify/routers/get_cognify_router.py +11 -3
  12. cognee/api/v1/datasets/routers/get_datasets_router.py +16 -5
  13. cognee/api/v1/memify/routers/__init__.py +1 -0
  14. cognee/api/v1/memify/routers/get_memify_router.py +100 -0
  15. cognee/api/v1/notebooks/routers/__init__.py +1 -0
  16. cognee/api/v1/notebooks/routers/get_notebooks_router.py +96 -0
  17. cognee/api/v1/responses/default_tools.py +4 -0
  18. cognee/api/v1/responses/dispatch_function.py +6 -1
  19. cognee/api/v1/responses/models.py +1 -1
  20. cognee/api/v1/search/routers/get_search_router.py +20 -1
  21. cognee/api/v1/search/search.py +17 -4
  22. cognee/api/v1/sync/__init__.py +17 -0
  23. cognee/api/v1/sync/routers/__init__.py +3 -0
  24. cognee/api/v1/sync/routers/get_sync_router.py +241 -0
  25. cognee/api/v1/sync/sync.py +877 -0
  26. cognee/api/v1/ui/__init__.py +1 -0
  27. cognee/api/v1/ui/ui.py +529 -0
  28. cognee/api/v1/users/routers/get_auth_router.py +13 -1
  29. cognee/base_config.py +10 -1
  30. cognee/cli/__init__.py +10 -0
  31. cognee/cli/_cognee.py +273 -0
  32. cognee/cli/commands/__init__.py +1 -0
  33. cognee/cli/commands/add_command.py +80 -0
  34. cognee/cli/commands/cognify_command.py +128 -0
  35. cognee/cli/commands/config_command.py +225 -0
  36. cognee/cli/commands/delete_command.py +80 -0
  37. cognee/cli/commands/search_command.py +149 -0
  38. cognee/cli/config.py +33 -0
  39. cognee/cli/debug.py +21 -0
  40. cognee/cli/echo.py +45 -0
  41. cognee/cli/exceptions.py +23 -0
  42. cognee/cli/minimal_cli.py +97 -0
  43. cognee/cli/reference.py +26 -0
  44. cognee/cli/suppress_logging.py +12 -0
  45. cognee/eval_framework/corpus_builder/corpus_builder_executor.py +2 -2
  46. cognee/eval_framework/eval_config.py +1 -1
  47. cognee/infrastructure/databases/graph/config.py +10 -4
  48. cognee/infrastructure/databases/graph/get_graph_engine.py +4 -9
  49. cognee/infrastructure/databases/graph/kuzu/adapter.py +199 -2
  50. cognee/infrastructure/databases/graph/neo4j_driver/adapter.py +138 -0
  51. cognee/infrastructure/databases/relational/__init__.py +2 -0
  52. cognee/infrastructure/databases/relational/get_async_session.py +15 -0
  53. cognee/infrastructure/databases/relational/sqlalchemy/SqlAlchemyAdapter.py +6 -1
  54. cognee/infrastructure/databases/relational/with_async_session.py +25 -0
  55. cognee/infrastructure/databases/vector/chromadb/ChromaDBAdapter.py +1 -1
  56. cognee/infrastructure/databases/vector/config.py +13 -6
  57. cognee/infrastructure/databases/vector/embeddings/FastembedEmbeddingEngine.py +6 -4
  58. cognee/infrastructure/databases/vector/embeddings/LiteLLMEmbeddingEngine.py +16 -7
  59. cognee/infrastructure/databases/vector/embeddings/OllamaEmbeddingEngine.py +5 -5
  60. cognee/infrastructure/databases/vector/embeddings/config.py +2 -2
  61. cognee/infrastructure/databases/vector/embeddings/embedding_rate_limiter.py +2 -6
  62. cognee/infrastructure/databases/vector/embeddings/get_embedding_engine.py +10 -7
  63. cognee/infrastructure/files/storage/LocalFileStorage.py +9 -0
  64. cognee/infrastructure/files/storage/S3FileStorage.py +5 -0
  65. cognee/infrastructure/files/storage/StorageManager.py +7 -1
  66. cognee/infrastructure/files/storage/storage.py +16 -0
  67. cognee/infrastructure/files/utils/get_data_file_path.py +14 -9
  68. cognee/infrastructure/files/utils/get_file_metadata.py +2 -1
  69. cognee/infrastructure/llm/LLMGateway.py +32 -5
  70. cognee/infrastructure/llm/config.py +6 -4
  71. cognee/infrastructure/llm/prompts/extract_query_time.txt +15 -0
  72. cognee/infrastructure/llm/prompts/generate_event_entity_prompt.txt +25 -0
  73. cognee/infrastructure/llm/prompts/generate_event_graph_prompt.txt +30 -0
  74. cognee/infrastructure/llm/structured_output_framework/baml/baml_src/extraction/knowledge_graph/extract_content_graph.py +16 -5
  75. cognee/infrastructure/llm/structured_output_framework/litellm_instructor/extraction/__init__.py +2 -0
  76. cognee/infrastructure/llm/structured_output_framework/litellm_instructor/extraction/extract_event_entities.py +44 -0
  77. cognee/infrastructure/llm/structured_output_framework/litellm_instructor/extraction/knowledge_graph/__init__.py +1 -0
  78. cognee/infrastructure/llm/structured_output_framework/litellm_instructor/extraction/knowledge_graph/extract_content_graph.py +19 -15
  79. cognee/infrastructure/llm/structured_output_framework/litellm_instructor/extraction/knowledge_graph/extract_event_graph.py +46 -0
  80. cognee/infrastructure/llm/structured_output_framework/litellm_instructor/llm/anthropic/adapter.py +3 -3
  81. cognee/infrastructure/llm/structured_output_framework/litellm_instructor/llm/gemini/adapter.py +3 -3
  82. cognee/infrastructure/llm/structured_output_framework/litellm_instructor/llm/generic_llm_api/adapter.py +2 -2
  83. cognee/infrastructure/llm/structured_output_framework/litellm_instructor/llm/get_llm_client.py +14 -8
  84. cognee/infrastructure/llm/structured_output_framework/litellm_instructor/llm/ollama/adapter.py +6 -4
  85. cognee/infrastructure/llm/structured_output_framework/litellm_instructor/llm/openai/adapter.py +28 -4
  86. cognee/infrastructure/llm/tokenizer/Gemini/adapter.py +2 -2
  87. cognee/infrastructure/llm/tokenizer/HuggingFace/adapter.py +3 -3
  88. cognee/infrastructure/llm/tokenizer/Mistral/adapter.py +3 -3
  89. cognee/infrastructure/llm/tokenizer/TikToken/adapter.py +6 -6
  90. cognee/infrastructure/llm/utils.py +7 -7
  91. cognee/infrastructure/utils/run_sync.py +8 -1
  92. cognee/modules/chunking/models/DocumentChunk.py +4 -3
  93. cognee/modules/cloud/exceptions/CloudApiKeyMissingError.py +15 -0
  94. cognee/modules/cloud/exceptions/CloudConnectionError.py +15 -0
  95. cognee/modules/cloud/exceptions/__init__.py +2 -0
  96. cognee/modules/cloud/operations/__init__.py +1 -0
  97. cognee/modules/cloud/operations/check_api_key.py +25 -0
  98. cognee/modules/data/deletion/prune_system.py +1 -1
  99. cognee/modules/data/methods/__init__.py +2 -0
  100. cognee/modules/data/methods/check_dataset_name.py +1 -1
  101. cognee/modules/data/methods/create_authorized_dataset.py +19 -0
  102. cognee/modules/data/methods/get_authorized_dataset.py +11 -5
  103. cognee/modules/data/methods/get_authorized_dataset_by_name.py +16 -0
  104. cognee/modules/data/methods/get_dataset_data.py +1 -1
  105. cognee/modules/data/methods/load_or_create_datasets.py +2 -20
  106. cognee/modules/engine/models/Event.py +16 -0
  107. cognee/modules/engine/models/Interval.py +8 -0
  108. cognee/modules/engine/models/Timestamp.py +13 -0
  109. cognee/modules/engine/models/__init__.py +3 -0
  110. cognee/modules/engine/utils/__init__.py +2 -0
  111. cognee/modules/engine/utils/generate_event_datapoint.py +46 -0
  112. cognee/modules/engine/utils/generate_timestamp_datapoint.py +51 -0
  113. cognee/modules/graph/cognee_graph/CogneeGraph.py +2 -2
  114. cognee/modules/graph/methods/get_formatted_graph_data.py +3 -2
  115. cognee/modules/graph/utils/__init__.py +1 -0
  116. cognee/modules/graph/utils/resolve_edges_to_text.py +71 -0
  117. cognee/modules/memify/__init__.py +1 -0
  118. cognee/modules/memify/memify.py +118 -0
  119. cognee/modules/notebooks/methods/__init__.py +5 -0
  120. cognee/modules/notebooks/methods/create_notebook.py +26 -0
  121. cognee/modules/notebooks/methods/delete_notebook.py +13 -0
  122. cognee/modules/notebooks/methods/get_notebook.py +21 -0
  123. cognee/modules/notebooks/methods/get_notebooks.py +18 -0
  124. cognee/modules/notebooks/methods/update_notebook.py +17 -0
  125. cognee/modules/notebooks/models/Notebook.py +53 -0
  126. cognee/modules/notebooks/models/__init__.py +1 -0
  127. cognee/modules/notebooks/operations/__init__.py +1 -0
  128. cognee/modules/notebooks/operations/run_in_local_sandbox.py +55 -0
  129. cognee/modules/pipelines/__init__.py +1 -1
  130. cognee/modules/pipelines/exceptions/tasks.py +18 -0
  131. cognee/modules/pipelines/layers/__init__.py +1 -0
  132. cognee/modules/pipelines/layers/check_pipeline_run_qualification.py +59 -0
  133. cognee/modules/pipelines/layers/pipeline_execution_mode.py +127 -0
  134. cognee/modules/pipelines/layers/reset_dataset_pipeline_run_status.py +28 -0
  135. cognee/modules/pipelines/layers/resolve_authorized_user_dataset.py +34 -0
  136. cognee/modules/pipelines/layers/resolve_authorized_user_datasets.py +55 -0
  137. cognee/modules/pipelines/layers/setup_and_check_environment.py +41 -0
  138. cognee/modules/pipelines/layers/validate_pipeline_tasks.py +20 -0
  139. cognee/modules/pipelines/methods/__init__.py +2 -0
  140. cognee/modules/pipelines/methods/get_pipeline_runs_by_dataset.py +34 -0
  141. cognee/modules/pipelines/methods/reset_pipeline_run_status.py +16 -0
  142. cognee/modules/pipelines/operations/__init__.py +0 -1
  143. cognee/modules/pipelines/operations/log_pipeline_run_initiated.py +1 -1
  144. cognee/modules/pipelines/operations/pipeline.py +24 -138
  145. cognee/modules/pipelines/operations/run_tasks.py +17 -41
  146. cognee/modules/retrieval/base_feedback.py +11 -0
  147. cognee/modules/retrieval/base_graph_retriever.py +18 -0
  148. cognee/modules/retrieval/base_retriever.py +1 -1
  149. cognee/modules/retrieval/code_retriever.py +8 -0
  150. cognee/modules/retrieval/coding_rules_retriever.py +31 -0
  151. cognee/modules/retrieval/completion_retriever.py +9 -3
  152. cognee/modules/retrieval/context_providers/TripletSearchContextProvider.py +1 -0
  153. cognee/modules/retrieval/cypher_search_retriever.py +1 -9
  154. cognee/modules/retrieval/graph_completion_context_extension_retriever.py +29 -13
  155. cognee/modules/retrieval/graph_completion_cot_retriever.py +30 -13
  156. cognee/modules/retrieval/graph_completion_retriever.py +107 -56
  157. cognee/modules/retrieval/graph_summary_completion_retriever.py +5 -1
  158. cognee/modules/retrieval/insights_retriever.py +14 -3
  159. cognee/modules/retrieval/natural_language_retriever.py +0 -4
  160. cognee/modules/retrieval/summaries_retriever.py +1 -1
  161. cognee/modules/retrieval/temporal_retriever.py +152 -0
  162. cognee/modules/retrieval/user_qa_feedback.py +83 -0
  163. cognee/modules/retrieval/utils/brute_force_triplet_search.py +7 -32
  164. cognee/modules/retrieval/utils/completion.py +10 -3
  165. cognee/modules/retrieval/utils/extract_uuid_from_node.py +18 -0
  166. cognee/modules/retrieval/utils/models.py +40 -0
  167. cognee/modules/search/methods/get_search_type_tools.py +168 -0
  168. cognee/modules/search/methods/no_access_control_search.py +47 -0
  169. cognee/modules/search/methods/search.py +239 -118
  170. cognee/modules/search/types/SearchResult.py +21 -0
  171. cognee/modules/search/types/SearchType.py +3 -0
  172. cognee/modules/search/types/__init__.py +1 -0
  173. cognee/modules/search/utils/__init__.py +2 -0
  174. cognee/modules/search/utils/prepare_search_result.py +41 -0
  175. cognee/modules/search/utils/transform_context_to_graph.py +38 -0
  176. cognee/modules/settings/get_settings.py +2 -2
  177. cognee/modules/sync/__init__.py +1 -0
  178. cognee/modules/sync/methods/__init__.py +23 -0
  179. cognee/modules/sync/methods/create_sync_operation.py +53 -0
  180. cognee/modules/sync/methods/get_sync_operation.py +107 -0
  181. cognee/modules/sync/methods/update_sync_operation.py +248 -0
  182. cognee/modules/sync/models/SyncOperation.py +142 -0
  183. cognee/modules/sync/models/__init__.py +3 -0
  184. cognee/modules/users/__init__.py +0 -1
  185. cognee/modules/users/methods/__init__.py +4 -1
  186. cognee/modules/users/methods/create_user.py +26 -1
  187. cognee/modules/users/methods/get_authenticated_user.py +36 -42
  188. cognee/modules/users/methods/get_default_user.py +3 -1
  189. cognee/modules/users/permissions/methods/get_specific_user_permission_datasets.py +2 -1
  190. cognee/root_dir.py +19 -0
  191. cognee/shared/CodeGraphEntities.py +1 -0
  192. cognee/shared/logging_utils.py +143 -32
  193. cognee/shared/utils.py +0 -1
  194. cognee/tasks/codingagents/coding_rule_associations.py +127 -0
  195. cognee/tasks/graph/extract_graph_from_data.py +6 -2
  196. cognee/tasks/ingestion/save_data_item_to_storage.py +23 -0
  197. cognee/tasks/memify/__init__.py +2 -0
  198. cognee/tasks/memify/extract_subgraph.py +7 -0
  199. cognee/tasks/memify/extract_subgraph_chunks.py +11 -0
  200. cognee/tasks/repo_processor/get_local_dependencies.py +2 -0
  201. cognee/tasks/repo_processor/get_repo_file_dependencies.py +144 -47
  202. cognee/tasks/storage/add_data_points.py +33 -3
  203. cognee/tasks/temporal_graph/__init__.py +1 -0
  204. cognee/tasks/temporal_graph/add_entities_to_event.py +85 -0
  205. cognee/tasks/temporal_graph/enrich_events.py +34 -0
  206. cognee/tasks/temporal_graph/extract_events_and_entities.py +32 -0
  207. cognee/tasks/temporal_graph/extract_knowledge_graph_from_events.py +41 -0
  208. cognee/tasks/temporal_graph/models.py +49 -0
  209. cognee/tests/integration/cli/__init__.py +3 -0
  210. cognee/tests/integration/cli/test_cli_integration.py +331 -0
  211. cognee/tests/integration/documents/PdfDocument_test.py +2 -2
  212. cognee/tests/integration/documents/TextDocument_test.py +2 -4
  213. cognee/tests/integration/documents/UnstructuredDocument_test.py +5 -8
  214. cognee/tests/{test_deletion.py → test_delete_hard.py} +0 -37
  215. cognee/tests/test_delete_soft.py +85 -0
  216. cognee/tests/test_kuzu.py +2 -2
  217. cognee/tests/test_neo4j.py +2 -2
  218. cognee/tests/test_permissions.py +3 -3
  219. cognee/tests/test_relational_db_migration.py +7 -5
  220. cognee/tests/test_search_db.py +136 -23
  221. cognee/tests/test_temporal_graph.py +167 -0
  222. cognee/tests/unit/api/__init__.py +1 -0
  223. cognee/tests/unit/api/test_conditional_authentication_endpoints.py +246 -0
  224. cognee/tests/unit/cli/__init__.py +3 -0
  225. cognee/tests/unit/cli/test_cli_commands.py +483 -0
  226. cognee/tests/unit/cli/test_cli_edge_cases.py +625 -0
  227. cognee/tests/unit/cli/test_cli_main.py +173 -0
  228. cognee/tests/unit/cli/test_cli_runner.py +62 -0
  229. cognee/tests/unit/cli/test_cli_utils.py +127 -0
  230. cognee/tests/unit/modules/retrieval/chunks_retriever_test.py +18 -2
  231. cognee/tests/unit/modules/retrieval/graph_completion_retriever_context_extension_test.py +12 -15
  232. cognee/tests/unit/modules/retrieval/graph_completion_retriever_cot_test.py +10 -15
  233. cognee/tests/unit/modules/retrieval/graph_completion_retriever_test.py +4 -3
  234. cognee/tests/unit/modules/retrieval/insights_retriever_test.py +4 -2
  235. cognee/tests/unit/modules/retrieval/rag_completion_retriever_test.py +18 -2
  236. cognee/tests/unit/modules/retrieval/temporal_retriever_test.py +225 -0
  237. cognee/tests/unit/modules/users/__init__.py +1 -0
  238. cognee/tests/unit/modules/users/test_conditional_authentication.py +277 -0
  239. cognee/tests/unit/processing/utils/utils_test.py +20 -1
  240. {cognee-0.2.3.dev1.dist-info → cognee-0.3.0.dist-info}/METADATA +13 -9
  241. {cognee-0.2.3.dev1.dist-info → cognee-0.3.0.dist-info}/RECORD +247 -135
  242. cognee-0.3.0.dist-info/entry_points.txt +2 -0
  243. cognee/infrastructure/databases/graph/networkx/adapter.py +0 -1017
  244. cognee/infrastructure/pipeline/models/Operation.py +0 -60
  245. cognee/notebooks/github_analysis_step_by_step.ipynb +0 -37
  246. cognee/tests/tasks/descriptive_metrics/networkx_metrics_test.py +0 -7
  247. cognee/tests/unit/modules/search/search_methods_test.py +0 -223
  248. /cognee/{infrastructure/databases/graph/networkx → api/v1/memify}/__init__.py +0 -0
  249. /cognee/{infrastructure/pipeline/models → tasks/codingagents}/__init__.py +0 -0
  250. {cognee-0.2.3.dev1.dist-info → cognee-0.3.0.dist-info}/WHEEL +0 -0
  251. {cognee-0.2.3.dev1.dist-info → cognee-0.3.0.dist-info}/licenses/LICENSE +0 -0
  252. {cognee-0.2.3.dev1.dist-info → cognee-0.3.0.dist-info}/licenses/NOTICE.md +0 -0
@@ -0,0 +1,225 @@
1
+ import asyncio
2
+ from types import SimpleNamespace
3
+ import pytest
4
+
5
+ from cognee.modules.retrieval.temporal_retriever import TemporalRetriever
6
+
7
+
8
+ # Test TemporalRetriever initialization defaults and overrides
9
+ def test_init_defaults_and_overrides():
10
+ tr = TemporalRetriever()
11
+ assert tr.top_k == 5
12
+ assert tr.user_prompt_path == "graph_context_for_question.txt"
13
+ assert tr.system_prompt_path == "answer_simple_question.txt"
14
+ assert tr.time_extraction_prompt_path == "extract_query_time.txt"
15
+
16
+ tr2 = TemporalRetriever(
17
+ top_k=3,
18
+ user_prompt_path="u.txt",
19
+ system_prompt_path="s.txt",
20
+ time_extraction_prompt_path="t.txt",
21
+ )
22
+ assert tr2.top_k == 3
23
+ assert tr2.user_prompt_path == "u.txt"
24
+ assert tr2.system_prompt_path == "s.txt"
25
+ assert tr2.time_extraction_prompt_path == "t.txt"
26
+
27
+
28
+ # Test descriptions_to_string with basic and empty results
29
+ def test_descriptions_to_string_basic_and_empty():
30
+ tr = TemporalRetriever()
31
+
32
+ results = [
33
+ {"description": " First "},
34
+ {"nope": "no description"},
35
+ {"description": "Second"},
36
+ {"description": ""},
37
+ {"description": " Third line "},
38
+ ]
39
+
40
+ s = tr.descriptions_to_string(results)
41
+ assert s == "First\n#####################\nSecond\n#####################\nThird line"
42
+
43
+ assert tr.descriptions_to_string([]) == ""
44
+
45
+
46
+ # Test filter_top_k_events sorts and limits correctly
47
+ @pytest.mark.asyncio
48
+ async def test_filter_top_k_events_sorts_and_limits():
49
+ tr = TemporalRetriever(top_k=2)
50
+
51
+ relevant_events = [
52
+ {
53
+ "events": [
54
+ {"id": "e1", "description": "E1"},
55
+ {"id": "e2", "description": "E2"},
56
+ {"id": "e3", "description": "E3 - not in vector results"},
57
+ ]
58
+ }
59
+ ]
60
+
61
+ scored_results = [
62
+ SimpleNamespace(payload={"id": "e2"}, score=0.10),
63
+ SimpleNamespace(payload={"id": "e1"}, score=0.20),
64
+ ]
65
+
66
+ top = await tr.filter_top_k_events(relevant_events, scored_results)
67
+
68
+ assert [e["id"] for e in top] == ["e2", "e1"]
69
+ assert all("score" in e for e in top)
70
+ assert top[0]["score"] == 0.10
71
+ assert top[1]["score"] == 0.20
72
+
73
+
74
+ # Test filter_top_k_events handles unknown ids as infinite scores
75
+ @pytest.mark.asyncio
76
+ async def test_filter_top_k_events_includes_unknown_as_infinite_but_not_in_top_k():
77
+ tr = TemporalRetriever(top_k=2)
78
+
79
+ relevant_events = [
80
+ {
81
+ "events": [
82
+ {"id": "known1", "description": "Known 1"},
83
+ {"id": "unknown", "description": "Unknown"},
84
+ {"id": "known2", "description": "Known 2"},
85
+ ]
86
+ }
87
+ ]
88
+
89
+ scored_results = [
90
+ SimpleNamespace(payload={"id": "known2"}, score=0.05),
91
+ SimpleNamespace(payload={"id": "known1"}, score=0.50),
92
+ ]
93
+
94
+ top = await tr.filter_top_k_events(relevant_events, scored_results)
95
+ assert [e["id"] for e in top] == ["known2", "known1"]
96
+ assert all(e["score"] != float("inf") for e in top)
97
+
98
+
99
+ # Test descriptions_to_string with unicode and newlines
100
+ def test_descriptions_to_string_unicode_and_newlines():
101
+ tr = TemporalRetriever()
102
+ results = [
103
+ {"description": "Line A\nwith newline"},
104
+ {"description": "This is a description"},
105
+ ]
106
+ s = tr.descriptions_to_string(results)
107
+ assert "Line A\nwith newline" in s
108
+ assert "This is a description" in s
109
+ assert s.count("#####################") == 1
110
+
111
+
112
+ # Test filter_top_k_events when top_k is larger than available events
113
+ @pytest.mark.asyncio
114
+ async def test_filter_top_k_events_limits_when_top_k_exceeds_events():
115
+ tr = TemporalRetriever(top_k=10)
116
+ relevant_events = [{"events": [{"id": "a"}, {"id": "b"}]}]
117
+ scored_results = [
118
+ SimpleNamespace(payload={"id": "a"}, score=0.1),
119
+ SimpleNamespace(payload={"id": "b"}, score=0.2),
120
+ ]
121
+ out = await tr.filter_top_k_events(relevant_events, scored_results)
122
+ assert [e["id"] for e in out] == ["a", "b"]
123
+
124
+
125
+ # Test filter_top_k_events when scored_results is empty
126
+ @pytest.mark.asyncio
127
+ async def test_filter_top_k_events_handles_empty_scored_results():
128
+ tr = TemporalRetriever(top_k=2)
129
+ relevant_events = [{"events": [{"id": "x"}, {"id": "y"}]}]
130
+ scored_results = []
131
+ out = await tr.filter_top_k_events(relevant_events, scored_results)
132
+ assert [e["id"] for e in out] == ["x", "y"]
133
+ assert all(e["score"] == float("inf") for e in out)
134
+
135
+
136
+ # Test filter_top_k_events error handling for missing structure
137
+ @pytest.mark.asyncio
138
+ async def test_filter_top_k_events_error_handling():
139
+ tr = TemporalRetriever(top_k=2)
140
+ with pytest.raises((KeyError, TypeError)):
141
+ await tr.filter_top_k_events([{}], [])
142
+
143
+
144
+ class _FakeRetriever(TemporalRetriever):
145
+ def __init__(self, *args, **kwargs):
146
+ super().__init__(*args, **kwargs)
147
+ self._calls = []
148
+
149
+ async def extract_time_from_query(self, query: str):
150
+ if "both" in query:
151
+ return "2024-01-01", "2024-12-31"
152
+ if "from_only" in query:
153
+ return "2024-01-01", None
154
+ if "to_only" in query:
155
+ return None, "2024-12-31"
156
+ return None, None
157
+
158
+ async def get_triplets(self, query: str):
159
+ self._calls.append(("get_triplets", query))
160
+ return [{"s": "a", "p": "b", "o": "c"}]
161
+
162
+ async def resolve_edges_to_text(self, triplets):
163
+ self._calls.append(("resolve_edges_to_text", len(triplets)))
164
+ return "edges->text"
165
+
166
+ async def _fake_graph_collect_ids(self, **kwargs):
167
+ return ["e1", "e2"]
168
+
169
+ async def _fake_graph_collect_events(self, ids):
170
+ return [
171
+ {
172
+ "events": [
173
+ {"id": "e1", "description": "E1"},
174
+ {"id": "e2", "description": "E2"},
175
+ {"id": "e3", "description": "E3"},
176
+ ]
177
+ }
178
+ ]
179
+
180
+ async def _fake_vector_embed(self, texts):
181
+ assert isinstance(texts, list) and texts
182
+ return [[0.0, 1.0, 2.0]]
183
+
184
+ async def _fake_vector_search(self, **kwargs):
185
+ return [
186
+ SimpleNamespace(payload={"id": "e2"}, score=0.05),
187
+ SimpleNamespace(payload={"id": "e1"}, score=0.10),
188
+ ]
189
+
190
+ async def get_context(self, query: str):
191
+ time_from, time_to = await self.extract_time_from_query(query)
192
+
193
+ if not (time_from or time_to):
194
+ triplets = await self.get_triplets(query)
195
+ return await self.resolve_edges_to_text(triplets)
196
+
197
+ ids = await self._fake_graph_collect_ids(time_from=time_from, time_to=time_to)
198
+ relevant_events = await self._fake_graph_collect_events(ids)
199
+
200
+ _ = await self._fake_vector_embed([query])
201
+ vector_search_results = await self._fake_vector_search(
202
+ collection_name="Event_name", query_vector=[0.0], limit=0
203
+ )
204
+ top_k_events = await self.filter_top_k_events(relevant_events, vector_search_results)
205
+ return self.descriptions_to_string(top_k_events)
206
+
207
+
208
+ # Test get_context fallback to triplets when no time is extracted
209
+ @pytest.mark.asyncio
210
+ async def test_fake_get_context_falls_back_to_triplets_when_no_time():
211
+ tr = _FakeRetriever(top_k=2)
212
+ ctx = await tr.get_context("no_time")
213
+ assert ctx == "edges->text"
214
+ assert tr._calls[0][0] == "get_triplets"
215
+ assert tr._calls[1][0] == "resolve_edges_to_text"
216
+
217
+
218
+ # Test get_context when time is extracted and vector ranking is applied
219
+ @pytest.mark.asyncio
220
+ async def test_fake_get_context_with_time_filters_and_vector_ranking():
221
+ tr = _FakeRetriever(top_k=2)
222
+ ctx = await tr.get_context("both time")
223
+ assert ctx.startswith("E2")
224
+ assert "#####################" in ctx
225
+ assert "E1" in ctx and "E3" not in ctx
@@ -0,0 +1 @@
1
+ # Test package for user module tests
@@ -0,0 +1,277 @@
1
+ import os
2
+ import sys
3
+ import pytest
4
+ from unittest.mock import AsyncMock, patch
5
+ from uuid import uuid4
6
+ from types import SimpleNamespace
7
+ import importlib
8
+
9
+
10
+ from cognee.modules.users.models import User
11
+
12
+
13
+ gau_mod = importlib.import_module("cognee.modules.users.methods.get_authenticated_user")
14
+
15
+
16
+ class TestConditionalAuthentication:
17
+ """Test cases for conditional authentication functionality."""
18
+
19
+ @pytest.mark.asyncio
20
+ @patch.object(gau_mod, "get_default_user", new_callable=AsyncMock)
21
+ async def test_require_authentication_false_no_token_returns_default_user(
22
+ self, mock_get_default
23
+ ):
24
+ """Test that when REQUIRE_AUTHENTICATION=false and no token, returns default user."""
25
+ # Mock the default user
26
+ mock_default_user = SimpleNamespace(id=uuid4(), email="default@example.com", is_active=True)
27
+ mock_get_default.return_value = mock_default_user
28
+
29
+ # Use gau_mod.get_authenticated_user instead
30
+
31
+ # Test with None user (no authentication)
32
+ result = await gau_mod.get_authenticated_user(user=None)
33
+
34
+ assert result == mock_default_user
35
+ mock_get_default.assert_called_once()
36
+
37
+ @pytest.mark.asyncio
38
+ @patch.object(gau_mod, "get_default_user", new_callable=AsyncMock)
39
+ async def test_require_authentication_false_with_valid_user_returns_user(
40
+ self, mock_get_default
41
+ ):
42
+ """Test that when REQUIRE_AUTHENTICATION=false and valid user, returns that user."""
43
+ mock_authenticated_user = User(
44
+ id=uuid4(),
45
+ email="user@example.com",
46
+ hashed_password="hashed",
47
+ is_active=True,
48
+ is_verified=True,
49
+ )
50
+
51
+ # Use gau_mod.get_authenticated_user instead
52
+
53
+ # Test with authenticated user
54
+ result = await gau_mod.get_authenticated_user(user=mock_authenticated_user)
55
+
56
+ assert result == mock_authenticated_user
57
+ mock_get_default.assert_not_called()
58
+
59
+ @pytest.mark.asyncio
60
+ @patch.object(gau_mod, "get_default_user", new_callable=AsyncMock)
61
+ async def test_require_authentication_true_with_user_returns_user(self, mock_get_default):
62
+ """Test that when REQUIRE_AUTHENTICATION=true and user present, returns user."""
63
+ mock_authenticated_user = User(
64
+ id=uuid4(),
65
+ email="user@example.com",
66
+ hashed_password="hashed",
67
+ is_active=True,
68
+ is_verified=True,
69
+ )
70
+
71
+ # Use gau_mod.get_authenticated_user instead
72
+
73
+ result = await gau_mod.get_authenticated_user(user=mock_authenticated_user)
74
+
75
+ assert result == mock_authenticated_user
76
+
77
+
78
+ class TestConditionalAuthenticationIntegration:
79
+ """Integration tests that test the full authentication flow."""
80
+
81
+ @pytest.mark.asyncio
82
+ async def test_fastapi_users_dependency_creation(self):
83
+ """Test that FastAPI Users dependency can be created correctly."""
84
+ from cognee.modules.users.get_fastapi_users import get_fastapi_users
85
+
86
+ fastapi_users = get_fastapi_users()
87
+
88
+ # Test that we can create optional dependency
89
+ optional_dependency = fastapi_users.current_user(optional=True, active=True)
90
+ assert callable(optional_dependency)
91
+
92
+ # Test that we can create required dependency
93
+ required_dependency = fastapi_users.current_user(active=True) # optional=False by default
94
+ assert callable(required_dependency)
95
+
96
+ @pytest.mark.asyncio
97
+ async def test_conditional_authentication_function_exists(self):
98
+ """Test that the conditional authentication function can be imported and used."""
99
+ from cognee.modules.users.methods.get_authenticated_user import (
100
+ get_authenticated_user,
101
+ REQUIRE_AUTHENTICATION,
102
+ )
103
+
104
+ # Should be callable
105
+ assert callable(get_authenticated_user)
106
+
107
+ # REQUIRE_AUTHENTICATION should be a boolean
108
+ assert isinstance(REQUIRE_AUTHENTICATION, bool)
109
+
110
+ # Currently should be False (optional authentication)
111
+ assert not REQUIRE_AUTHENTICATION
112
+
113
+
114
+ class TestConditionalAuthenticationEnvironmentVariables:
115
+ """Test environment variable handling."""
116
+
117
+ def test_require_authentication_default_false(self):
118
+ """Test that REQUIRE_AUTHENTICATION defaults to false when imported with no env vars."""
119
+ with patch.dict(os.environ, {}, clear=True):
120
+ # Remove module from cache to force fresh import
121
+ module_name = "cognee.modules.users.methods.get_authenticated_user"
122
+ if module_name in sys.modules:
123
+ del sys.modules[module_name]
124
+
125
+ # Import after patching environment - module will see empty environment
126
+ from cognee.modules.users.methods.get_authenticated_user import (
127
+ REQUIRE_AUTHENTICATION,
128
+ )
129
+
130
+ importlib.invalidate_caches()
131
+ assert not REQUIRE_AUTHENTICATION
132
+
133
+ def test_require_authentication_true(self):
134
+ """Test that REQUIRE_AUTHENTICATION=true is parsed correctly when imported."""
135
+ with patch.dict(os.environ, {"REQUIRE_AUTHENTICATION": "true"}):
136
+ # Remove module from cache to force fresh import
137
+ module_name = "cognee.modules.users.methods.get_authenticated_user"
138
+ if module_name in sys.modules:
139
+ del sys.modules[module_name]
140
+
141
+ # Import after patching environment - module will see REQUIRE_AUTHENTICATION=true
142
+ from cognee.modules.users.methods.get_authenticated_user import (
143
+ REQUIRE_AUTHENTICATION,
144
+ )
145
+
146
+ assert REQUIRE_AUTHENTICATION
147
+
148
+ def test_require_authentication_false_explicit(self):
149
+ """Test that REQUIRE_AUTHENTICATION=false is parsed correctly when imported."""
150
+ with patch.dict(os.environ, {"REQUIRE_AUTHENTICATION": "false"}):
151
+ # Remove module from cache to force fresh import
152
+ module_name = "cognee.modules.users.methods.get_authenticated_user"
153
+ if module_name in sys.modules:
154
+ del sys.modules[module_name]
155
+
156
+ # Import after patching environment - module will see REQUIRE_AUTHENTICATION=false
157
+ from cognee.modules.users.methods.get_authenticated_user import (
158
+ REQUIRE_AUTHENTICATION,
159
+ )
160
+
161
+ assert not REQUIRE_AUTHENTICATION
162
+
163
+ def test_require_authentication_case_insensitive(self):
164
+ """Test that environment variable parsing is case insensitive when imported."""
165
+ test_cases = ["TRUE", "True", "tRuE", "FALSE", "False", "fAlSe"]
166
+
167
+ for case in test_cases:
168
+ with patch.dict(os.environ, {"REQUIRE_AUTHENTICATION": case}):
169
+ # Remove module from cache to force fresh import
170
+ module_name = "cognee.modules.users.methods.get_authenticated_user"
171
+ if module_name in sys.modules:
172
+ del sys.modules[module_name]
173
+
174
+ # Import after patching environment
175
+ from cognee.modules.users.methods.get_authenticated_user import (
176
+ REQUIRE_AUTHENTICATION,
177
+ )
178
+
179
+ expected = case.lower() == "true"
180
+ assert REQUIRE_AUTHENTICATION == expected, f"Failed for case: {case}"
181
+
182
+ def test_current_require_authentication_value(self):
183
+ """Test that the current REQUIRE_AUTHENTICATION module value is as expected."""
184
+ from cognee.modules.users.methods.get_authenticated_user import (
185
+ REQUIRE_AUTHENTICATION,
186
+ )
187
+
188
+ # The module-level variable should currently be False (set at import time)
189
+ assert isinstance(REQUIRE_AUTHENTICATION, bool)
190
+ assert not REQUIRE_AUTHENTICATION
191
+
192
+
193
+ class TestConditionalAuthenticationEdgeCases:
194
+ """Test edge cases and error scenarios."""
195
+
196
+ @pytest.mark.asyncio
197
+ @patch.object(gau_mod, "get_default_user", new_callable=AsyncMock)
198
+ async def test_get_default_user_raises_exception(self, mock_get_default):
199
+ """Test behavior when get_default_user raises an exception."""
200
+ mock_get_default.side_effect = Exception("Database error")
201
+
202
+ # This should propagate the exception
203
+ with pytest.raises(Exception, match="Database error"):
204
+ await gau_mod.get_authenticated_user(user=None)
205
+
206
+ @pytest.mark.asyncio
207
+ @patch.object(gau_mod, "get_default_user", new_callable=AsyncMock)
208
+ async def test_user_type_consistency(self, mock_get_default):
209
+ """Test that the function always returns the same type."""
210
+ mock_user = User(
211
+ id=uuid4(),
212
+ email="test@example.com",
213
+ hashed_password="hashed",
214
+ is_active=True,
215
+ is_verified=True,
216
+ )
217
+
218
+ mock_default_user = SimpleNamespace(id=uuid4(), email="default@example.com", is_active=True)
219
+ mock_get_default.return_value = mock_default_user
220
+
221
+ # Test with user
222
+ result1 = await gau_mod.get_authenticated_user(user=mock_user)
223
+ assert result1 == mock_user
224
+
225
+ # Test with None
226
+ result2 = await gau_mod.get_authenticated_user(user=None)
227
+ assert result2 == mock_default_user
228
+
229
+ # Both should have user-like interface
230
+ assert hasattr(result1, "id")
231
+ assert hasattr(result1, "email")
232
+ assert result1.id == mock_user.id
233
+ assert result1.email == mock_user.email
234
+ assert hasattr(result2, "id")
235
+ assert hasattr(result2, "email")
236
+ assert result2.id == mock_default_user.id
237
+ assert result2.email == mock_default_user.email
238
+
239
+
240
+ @pytest.mark.asyncio
241
+ class TestAuthenticationScenarios:
242
+ """Test specific authentication scenarios that could occur in FastAPI Users."""
243
+
244
+ @patch.object(gau_mod, "get_default_user", new_callable=AsyncMock)
245
+ async def test_fallback_to_default_user_scenarios(self, mock_get_default):
246
+ """
247
+ Test fallback to default user for all scenarios where FastAPI Users returns None:
248
+ - No JWT/Cookie present
249
+ - Invalid JWT/Cookie
250
+ - Valid JWT but user doesn't exist in database
251
+ - Valid JWT but user is inactive (active=True requirement)
252
+
253
+ All these scenarios result in FastAPI Users returning None when optional=True,
254
+ which should trigger fallback to default user.
255
+ """
256
+ mock_default_user = SimpleNamespace(id=uuid4(), email="default@example.com")
257
+ mock_get_default.return_value = mock_default_user
258
+
259
+ # All the above scenarios result in user=None being passed to our function
260
+ result = await gau_mod.get_authenticated_user(user=None)
261
+ assert result == mock_default_user
262
+ mock_get_default.assert_called_once()
263
+
264
+ async def test_scenario_valid_active_user(self):
265
+ """Scenario: Valid JWT and user exists and is active → returns the user."""
266
+ mock_user = User(
267
+ id=uuid4(),
268
+ email="active@example.com",
269
+ hashed_password="hashed",
270
+ is_active=True,
271
+ is_verified=True,
272
+ )
273
+
274
+ # Use gau_mod.get_authenticated_user instead
275
+
276
+ result = await gau_mod.get_authenticated_user(user=mock_user)
277
+ assert result == mock_user
@@ -4,8 +4,9 @@ import pytest
4
4
  from unittest.mock import patch, mock_open
5
5
  from io import BytesIO
6
6
  from uuid import uuid4
7
+ from pathlib import Path
7
8
 
8
-
9
+ from cognee.root_dir import ensure_absolute_path
9
10
  from cognee.infrastructure.files.utils.get_file_content_hash import get_file_content_hash
10
11
  from cognee.shared.utils import get_anonymous_id
11
12
 
@@ -52,3 +53,21 @@ async def test_get_file_content_hash_stream():
52
53
  expected_hash = hashlib.md5(b"test_data").hexdigest()
53
54
  result = await get_file_content_hash(stream)
54
55
  assert result == expected_hash
56
+
57
+
58
+ @pytest.mark.asyncio
59
+ async def test_root_dir_absolute_paths():
60
+ """Test absolute path handling in root_dir.py"""
61
+ # Test with absolute path
62
+ abs_path = "C:/absolute/path" if os.name == "nt" else "/absolute/path"
63
+ result = ensure_absolute_path(abs_path)
64
+ assert result == str(Path(abs_path).resolve())
65
+
66
+ # Test with relative path (should fail)
67
+ rel_path = "relative/path"
68
+ with pytest.raises(ValueError, match="must be absolute"):
69
+ ensure_absolute_path(rel_path)
70
+
71
+ # Test with None path
72
+ with pytest.raises(ValueError, match="cannot be None"):
73
+ ensure_absolute_path(None)
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: cognee
3
- Version: 0.2.3.dev1
3
+ Version: 0.3.0
4
4
  Summary: Cognee - is a library for enriching LLM context with a semantic layer for better understanding and reasoning.
5
5
  Project-URL: Homepage, https://www.cognee.ai
6
6
  Project-URL: Repository, https://github.com/topoteretes/cognee
@@ -31,13 +31,13 @@ Requires-Dist: kuzu==0.11.0
31
31
  Requires-Dist: lancedb<1.0.0,>=0.24.0
32
32
  Requires-Dist: langfuse<3,>=2.32.0
33
33
  Requires-Dist: limits<5,>=4.4.1
34
- Requires-Dist: litellm<1.71.0,>=1.57.4
34
+ Requires-Dist: litellm<2.0.0,>=1.71.0
35
35
  Requires-Dist: matplotlib<4,>=3.8.3
36
36
  Requires-Dist: networkx<4,>=3.4.2
37
37
  Requires-Dist: nltk<4.0.0,>=3.9.1
38
38
  Requires-Dist: numpy<=4.0.0,>=1.26.4
39
39
  Requires-Dist: onnxruntime<2.0.0,>=1.0.0
40
- Requires-Dist: openai<2,>=1.80.1
40
+ Requires-Dist: openai<2.0.0,>=1.80.1
41
41
  Requires-Dist: pandas<3.0.0,>=2.2.2
42
42
  Requires-Dist: pre-commit<5,>=4.0.1
43
43
  Requires-Dist: pydantic-settings<3,>=2.2.1
@@ -46,6 +46,7 @@ Requires-Dist: pylance<1.0.0,>=0.22.0
46
46
  Requires-Dist: pympler<2.0.0,>=1.1
47
47
  Requires-Dist: pypdf<6.0.0,>=4.1.0
48
48
  Requires-Dist: python-dotenv<2.0.0,>=1.0.1
49
+ Requires-Dist: python-magic-bin<0.5; platform_system == 'Windows'
49
50
  Requires-Dist: python-multipart<1.0.0,>=0.0.20
50
51
  Requires-Dist: rdflib<7.2.0,>=7.1.4
51
52
  Requires-Dist: s3fs[boto3]==2025.3.2
@@ -74,7 +75,7 @@ Requires-Dist: tree-sitter<0.25,>=0.24.0; extra == 'codegraph'
74
75
  Provides-Extra: debug
75
76
  Requires-Dist: debugpy<2.0.0,>=1.8.9; extra == 'debug'
76
77
  Provides-Extra: deepeval
77
- Requires-Dist: deepeval<3,>=2.0.1; extra == 'deepeval'
78
+ Requires-Dist: deepeval<4,>=3.0.1; extra == 'deepeval'
78
79
  Provides-Extra: dev
79
80
  Requires-Dist: coverage<8,>=7.3.2; extra == 'dev'
80
81
  Requires-Dist: deptry<0.21,>=0.20.0; extra == 'dev'
@@ -182,7 +183,7 @@ Description-Content-Type: text/markdown
182
183
 
183
184
 
184
185
 
185
- **🚀 We launched Cogwit beta (Fully-hosted AI Memory): Sign up [here](https://platform.cognee.ai/)! 🚀**
186
+ **🚀 We launched Cogwit beta (Fully-hosted AI Memory): Sign up [here](https://platform.cognee.ai/)! 🚀**
186
187
 
187
188
  Build dynamic memory for Agents and replace RAG using scalable, modular ECL (Extract, Cognify, Load) pipelines.
188
189
 
@@ -218,7 +219,9 @@ More on [use-cases](https://docs.cognee.ai/use-cases) and [evals](https://github
218
219
 
219
220
  ## Get Started
220
221
 
221
- Get started quickly with a Google Colab <a href="https://colab.research.google.com/drive/1jHbWVypDgCLwjE71GSXhRL3YxYhCZzG1?usp=sharing">notebook</a> , <a href="https://deepnote.com/workspace/cognee-382213d0-0444-4c89-8265-13770e333c02/project/cognee-demo-78ffacb9-5832-4611-bb1a-560386068b30/notebook/Notebook-1-75b24cda566d4c24ab348f7150792601?utm_source=share-modal&utm_medium=product-shared-content&utm_campaign=notebook&utm_content=78ffacb9-5832-4611-bb1a-560386068b30">Deepnote notebook</a> or <a href="https://github.com/topoteretes/cognee-starter">starter repo</a>
222
+ Get started quickly with a Google Colab <a href="https://colab.research.google.com/drive/1jHbWVypDgCLwjE71GSXhRL3YxYhCZzG1?usp=sharing">notebook</a> , <a href="https://deepnote.com/workspace/cognee-382213d0-0444-4c89-8265-13770e333c02/project/cognee-demo-78ffacb9-5832-4611-bb1a-560386068b30/notebook/Notebook-1-75b24cda566d4c24ab348f7150792601?utm_source=share-modal&utm_medium=product-shared-content&utm_campaign=notebook&utm_content=78ffacb9-5832-4611-bb1a-560386068b30">Deepnote notebook</a> or <a href="https://github.com/topoteretes/cognee/tree/main/cognee-starter-kit">starter repo</a>
223
+
224
+
222
225
 
223
226
 
224
227
  ## Contributing
@@ -230,7 +233,8 @@ Your contributions are at the core of making this a true open source project. An
230
233
 
231
234
  ## 📦 Installation
232
235
 
233
- You can install Cognee using either **uv**, **pip**, **poetry** or any other python package manager.
236
+ You can install Cognee using either **pip**, **poetry**, **uv** or any other python package manager.
237
+
234
238
  Cognee supports Python 3.10 to 3.13
235
239
 
236
240
  ### With pip
@@ -310,9 +314,9 @@ Example output:
310
314
 
311
315
  You can also cognify your files and query using cognee UI.
312
316
 
313
- <img src="assets/cognee-ui-2.webp" width="100%" alt="Cognee UI 2"></a>
317
+ <img src="assets/cognee-new-ui.webp" width="100%" alt="Cognee UI 2"></a>
314
318
 
315
- Try cognee UI out locally [here](https://docs.cognee.ai/how-to-guides/cognee-ui).
319
+ Try cognee UI by runnning ``` cognee -ui ``` command on your terminal.
316
320
 
317
321
  ## Understand our architecture
318
322