cognee 0.5.1__py3-none-any.whl → 0.5.2__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 (265) hide show
  1. cognee/__init__.py +2 -0
  2. cognee/alembic/README +1 -0
  3. cognee/alembic/env.py +107 -0
  4. cognee/alembic/script.py.mako +26 -0
  5. cognee/alembic/versions/1a58b986e6e1_enable_delete_for_old_tutorial_notebooks.py +52 -0
  6. cognee/alembic/versions/1d0bb7fede17_add_pipeline_run_status.py +33 -0
  7. cognee/alembic/versions/1daae0df1866_incremental_loading.py +48 -0
  8. cognee/alembic/versions/211ab850ef3d_add_sync_operations_table.py +118 -0
  9. cognee/alembic/versions/45957f0a9849_add_notebook_table.py +46 -0
  10. cognee/alembic/versions/46a6ce2bd2b2_expand_dataset_database_with_json_.py +333 -0
  11. cognee/alembic/versions/482cd6517ce4_add_default_user.py +30 -0
  12. cognee/alembic/versions/76625596c5c3_expand_dataset_database_for_multi_user.py +98 -0
  13. cognee/alembic/versions/8057ae7329c2_initial_migration.py +25 -0
  14. cognee/alembic/versions/9e7a3cb85175_loader_separation.py +104 -0
  15. cognee/alembic/versions/a1b2c3d4e5f6_add_label_column_to_data.py +38 -0
  16. cognee/alembic/versions/ab7e313804ae_permission_system_rework.py +236 -0
  17. cognee/alembic/versions/b9274c27a25a_kuzu_11_migration.py +75 -0
  18. cognee/alembic/versions/c946955da633_multi_tenant_support.py +137 -0
  19. cognee/alembic/versions/e1ec1dcb50b6_add_last_accessed_to_data.py +51 -0
  20. cognee/alembic/versions/e4ebee1091e7_expand_data_model_info.py +140 -0
  21. cognee/alembic.ini +117 -0
  22. cognee/api/v1/add/add.py +2 -1
  23. cognee/api/v1/add/routers/get_add_router.py +2 -0
  24. cognee/api/v1/cognify/cognify.py +11 -6
  25. cognee/api/v1/cognify/routers/get_cognify_router.py +8 -0
  26. cognee/api/v1/config/config.py +60 -0
  27. cognee/api/v1/datasets/routers/get_datasets_router.py +46 -3
  28. cognee/api/v1/memify/routers/get_memify_router.py +3 -0
  29. cognee/api/v1/search/routers/get_search_router.py +21 -6
  30. cognee/api/v1/search/search.py +21 -5
  31. cognee/api/v1/sync/routers/get_sync_router.py +3 -3
  32. cognee/cli/commands/add_command.py +1 -1
  33. cognee/cli/commands/cognify_command.py +6 -0
  34. cognee/cli/commands/config_command.py +1 -1
  35. cognee/context_global_variables.py +5 -1
  36. cognee/eval_framework/answer_generation/answer_generation_executor.py +7 -8
  37. cognee/infrastructure/databases/cache/cache_db_interface.py +38 -1
  38. cognee/infrastructure/databases/cache/config.py +6 -0
  39. cognee/infrastructure/databases/cache/fscache/FsCacheAdapter.py +21 -0
  40. cognee/infrastructure/databases/cache/get_cache_engine.py +9 -3
  41. cognee/infrastructure/databases/cache/redis/RedisAdapter.py +60 -1
  42. cognee/infrastructure/databases/dataset_database_handler/supported_dataset_database_handlers.py +7 -0
  43. cognee/infrastructure/databases/graph/get_graph_engine.py +29 -1
  44. cognee/infrastructure/databases/graph/neo4j_driver/Neo4jAuraDevDatasetDatabaseHandler.py +62 -27
  45. cognee/infrastructure/databases/hybrid/neptune_analytics/NeptuneAnalyticsAdapter.py +17 -4
  46. cognee/infrastructure/databases/relational/config.py +16 -1
  47. cognee/infrastructure/databases/relational/create_relational_engine.py +13 -3
  48. cognee/infrastructure/databases/relational/sqlalchemy/SqlAlchemyAdapter.py +26 -3
  49. cognee/infrastructure/databases/vector/chromadb/ChromaDBAdapter.py +2 -0
  50. cognee/infrastructure/databases/vector/config.py +6 -0
  51. cognee/infrastructure/databases/vector/create_vector_engine.py +70 -16
  52. cognee/infrastructure/databases/vector/embeddings/LiteLLMEmbeddingEngine.py +64 -9
  53. cognee/infrastructure/databases/vector/embeddings/OllamaEmbeddingEngine.py +13 -2
  54. cognee/infrastructure/databases/vector/lancedb/LanceDBAdapter.py +16 -3
  55. cognee/infrastructure/databases/vector/models/ScoredResult.py +3 -3
  56. cognee/infrastructure/databases/vector/pgvector/PGVectorAdapter.py +16 -3
  57. cognee/infrastructure/databases/vector/pgvector/PGVectorDatasetDatabaseHandler.py +86 -0
  58. cognee/infrastructure/databases/vector/pgvector/create_db_and_tables.py +81 -2
  59. cognee/infrastructure/databases/vector/vector_db_interface.py +8 -0
  60. cognee/infrastructure/files/utils/get_data_file_path.py +33 -27
  61. cognee/infrastructure/llm/LLMGateway.py +0 -13
  62. cognee/infrastructure/llm/prompts/extract_query_time.txt +1 -1
  63. cognee/infrastructure/llm/prompts/generate_event_entity_prompt.txt +1 -1
  64. cognee/infrastructure/llm/prompts/generate_event_graph_prompt.txt +1 -1
  65. cognee/infrastructure/llm/prompts/generate_graph_prompt.txt +2 -2
  66. cognee/infrastructure/llm/prompts/generate_graph_prompt_guided.txt +1 -1
  67. cognee/infrastructure/llm/prompts/generate_graph_prompt_oneshot.txt +2 -2
  68. cognee/infrastructure/llm/prompts/generate_graph_prompt_simple.txt +1 -1
  69. cognee/infrastructure/llm/prompts/generate_graph_prompt_strict.txt +1 -1
  70. cognee/infrastructure/llm/prompts/search_type_selector_prompt.txt +6 -6
  71. cognee/infrastructure/llm/prompts/test.txt +1 -1
  72. cognee/infrastructure/llm/prompts/translate_content.txt +19 -0
  73. cognee/infrastructure/llm/structured_output_framework/litellm_instructor/llm/anthropic/adapter.py +17 -12
  74. cognee/infrastructure/llm/structured_output_framework/litellm_instructor/llm/gemini/adapter.py +31 -25
  75. cognee/infrastructure/llm/structured_output_framework/litellm_instructor/llm/generic_llm_api/adapter.py +132 -7
  76. cognee/infrastructure/llm/structured_output_framework/litellm_instructor/llm/get_llm_client.py +29 -5
  77. cognee/infrastructure/llm/structured_output_framework/litellm_instructor/llm/llama_cpp/adapter.py +191 -0
  78. cognee/infrastructure/llm/structured_output_framework/litellm_instructor/llm/llm_interface.py +2 -6
  79. cognee/infrastructure/llm/structured_output_framework/litellm_instructor/llm/mistral/adapter.py +58 -13
  80. cognee/infrastructure/llm/structured_output_framework/litellm_instructor/llm/ollama/adapter.py +0 -1
  81. cognee/infrastructure/llm/structured_output_framework/litellm_instructor/llm/openai/adapter.py +25 -131
  82. cognee/infrastructure/llm/structured_output_framework/litellm_instructor/llm/types.py +10 -0
  83. cognee/modules/chunking/models/DocumentChunk.py +0 -1
  84. cognee/modules/cognify/config.py +2 -0
  85. cognee/modules/data/models/Data.py +3 -1
  86. cognee/modules/engine/models/Entity.py +0 -1
  87. cognee/modules/engine/operations/setup.py +6 -0
  88. cognee/modules/graph/cognee_graph/CogneeGraph.py +150 -37
  89. cognee/modules/graph/cognee_graph/CogneeGraphElements.py +48 -2
  90. cognee/modules/graph/utils/__init__.py +1 -0
  91. cognee/modules/graph/utils/get_entity_nodes_from_triplets.py +12 -0
  92. cognee/modules/notebooks/methods/__init__.py +1 -0
  93. cognee/modules/notebooks/methods/create_notebook.py +0 -34
  94. cognee/modules/notebooks/methods/create_tutorial_notebooks.py +191 -0
  95. cognee/modules/notebooks/methods/get_notebooks.py +12 -8
  96. cognee/modules/notebooks/tutorials/cognee-basics/cell-1.md +3 -0
  97. cognee/modules/notebooks/tutorials/cognee-basics/cell-2.md +10 -0
  98. cognee/modules/notebooks/tutorials/cognee-basics/cell-3.md +7 -0
  99. cognee/modules/notebooks/tutorials/cognee-basics/cell-4.py +28 -0
  100. cognee/modules/notebooks/tutorials/cognee-basics/cell-5.py +3 -0
  101. cognee/modules/notebooks/tutorials/cognee-basics/cell-6.py +9 -0
  102. cognee/modules/notebooks/tutorials/cognee-basics/cell-7.py +17 -0
  103. cognee/modules/notebooks/tutorials/cognee-basics/config.json +4 -0
  104. cognee/modules/notebooks/tutorials/python-development-with-cognee/cell-1.md +3 -0
  105. cognee/modules/notebooks/tutorials/python-development-with-cognee/cell-10.md +3 -0
  106. cognee/modules/notebooks/tutorials/python-development-with-cognee/cell-11.md +3 -0
  107. cognee/modules/notebooks/tutorials/python-development-with-cognee/cell-12.py +3 -0
  108. cognee/modules/notebooks/tutorials/python-development-with-cognee/cell-13.md +7 -0
  109. cognee/modules/notebooks/tutorials/python-development-with-cognee/cell-14.py +6 -0
  110. cognee/modules/notebooks/tutorials/python-development-with-cognee/cell-15.md +3 -0
  111. cognee/modules/notebooks/tutorials/python-development-with-cognee/cell-16.py +7 -0
  112. cognee/modules/notebooks/tutorials/python-development-with-cognee/cell-2.md +9 -0
  113. cognee/modules/notebooks/tutorials/python-development-with-cognee/cell-3.md +7 -0
  114. cognee/modules/notebooks/tutorials/python-development-with-cognee/cell-4.md +9 -0
  115. cognee/modules/notebooks/tutorials/python-development-with-cognee/cell-5.md +5 -0
  116. cognee/modules/notebooks/tutorials/python-development-with-cognee/cell-6.py +13 -0
  117. cognee/modules/notebooks/tutorials/python-development-with-cognee/cell-7.md +3 -0
  118. cognee/modules/notebooks/tutorials/python-development-with-cognee/cell-8.md +3 -0
  119. cognee/modules/notebooks/tutorials/python-development-with-cognee/cell-9.py +31 -0
  120. cognee/modules/notebooks/tutorials/python-development-with-cognee/config.json +4 -0
  121. cognee/modules/notebooks/tutorials/python-development-with-cognee/data/copilot_conversations.json +107 -0
  122. cognee/modules/notebooks/tutorials/python-development-with-cognee/data/guido_contributions.json +976 -0
  123. cognee/modules/notebooks/tutorials/python-development-with-cognee/data/my_developer_rules.md +79 -0
  124. cognee/modules/notebooks/tutorials/python-development-with-cognee/data/pep_style_guide.md +74 -0
  125. cognee/modules/notebooks/tutorials/python-development-with-cognee/data/zen_principles.md +74 -0
  126. cognee/modules/retrieval/EntityCompletionRetriever.py +51 -38
  127. cognee/modules/retrieval/__init__.py +0 -1
  128. cognee/modules/retrieval/base_retriever.py +66 -10
  129. cognee/modules/retrieval/chunks_retriever.py +57 -49
  130. cognee/modules/retrieval/coding_rules_retriever.py +12 -5
  131. cognee/modules/retrieval/completion_retriever.py +29 -28
  132. cognee/modules/retrieval/cypher_search_retriever.py +25 -20
  133. cognee/modules/retrieval/graph_completion_context_extension_retriever.py +42 -46
  134. cognee/modules/retrieval/graph_completion_cot_retriever.py +68 -51
  135. cognee/modules/retrieval/graph_completion_retriever.py +78 -63
  136. cognee/modules/retrieval/graph_summary_completion_retriever.py +2 -0
  137. cognee/modules/retrieval/lexical_retriever.py +34 -12
  138. cognee/modules/retrieval/natural_language_retriever.py +18 -15
  139. cognee/modules/retrieval/summaries_retriever.py +51 -34
  140. cognee/modules/retrieval/temporal_retriever.py +59 -49
  141. cognee/modules/retrieval/triplet_retriever.py +32 -33
  142. cognee/modules/retrieval/utils/access_tracking.py +88 -0
  143. cognee/modules/retrieval/utils/brute_force_triplet_search.py +99 -103
  144. cognee/modules/retrieval/utils/node_edge_vector_search.py +174 -0
  145. cognee/modules/search/methods/__init__.py +1 -0
  146. cognee/modules/search/methods/get_retriever_output.py +53 -0
  147. cognee/modules/search/methods/get_search_type_retriever_instance.py +252 -0
  148. cognee/modules/search/methods/search.py +90 -222
  149. cognee/modules/search/models/SearchResultPayload.py +67 -0
  150. cognee/modules/search/types/SearchResult.py +1 -8
  151. cognee/modules/search/types/SearchType.py +1 -2
  152. cognee/modules/search/types/__init__.py +1 -1
  153. cognee/modules/search/utils/__init__.py +1 -2
  154. cognee/modules/search/utils/transform_insights_to_graph.py +2 -2
  155. cognee/modules/search/utils/{transform_context_to_graph.py → transform_triplets_to_graph.py} +2 -2
  156. cognee/modules/users/authentication/default/default_transport.py +11 -1
  157. cognee/modules/users/authentication/get_api_auth_backend.py +2 -1
  158. cognee/modules/users/authentication/get_client_auth_backend.py +2 -1
  159. cognee/modules/users/methods/create_user.py +0 -9
  160. cognee/modules/users/permissions/methods/has_user_management_permission.py +29 -0
  161. cognee/modules/visualization/cognee_network_visualization.py +1 -1
  162. cognee/run_migrations.py +48 -0
  163. cognee/shared/exceptions/__init__.py +1 -3
  164. cognee/shared/exceptions/exceptions.py +11 -1
  165. cognee/shared/usage_logger.py +332 -0
  166. cognee/shared/utils.py +12 -5
  167. cognee/tasks/chunks/__init__.py +9 -0
  168. cognee/tasks/cleanup/cleanup_unused_data.py +172 -0
  169. cognee/tasks/graph/__init__.py +7 -0
  170. cognee/tasks/ingestion/data_item.py +8 -0
  171. cognee/tasks/ingestion/ingest_data.py +12 -1
  172. cognee/tasks/ingestion/save_data_item_to_storage.py +5 -0
  173. cognee/tasks/memify/__init__.py +8 -0
  174. cognee/tasks/memify/extract_usage_frequency.py +613 -0
  175. cognee/tasks/summarization/models.py +0 -2
  176. cognee/tasks/temporal_graph/__init__.py +0 -1
  177. cognee/tasks/translation/__init__.py +96 -0
  178. cognee/tasks/translation/config.py +110 -0
  179. cognee/tasks/translation/detect_language.py +190 -0
  180. cognee/tasks/translation/exceptions.py +62 -0
  181. cognee/tasks/translation/models.py +72 -0
  182. cognee/tasks/translation/providers/__init__.py +44 -0
  183. cognee/tasks/translation/providers/azure_provider.py +192 -0
  184. cognee/tasks/translation/providers/base.py +85 -0
  185. cognee/tasks/translation/providers/google_provider.py +158 -0
  186. cognee/tasks/translation/providers/llm_provider.py +143 -0
  187. cognee/tasks/translation/translate_content.py +282 -0
  188. cognee/tasks/web_scraper/default_url_crawler.py +6 -2
  189. cognee/tests/cli_tests/cli_unit_tests/test_cli_commands.py +1 -0
  190. cognee/tests/cli_tests/cli_unit_tests/test_cli_edge_cases.py +3 -0
  191. cognee/tests/integration/retrieval/test_brute_force_triplet_search_with_cognify.py +62 -0
  192. cognee/tests/integration/retrieval/test_chunks_retriever.py +351 -0
  193. cognee/tests/integration/retrieval/test_graph_completion_retriever.py +276 -0
  194. cognee/tests/integration/retrieval/test_graph_completion_retriever_context_extension.py +228 -0
  195. cognee/tests/integration/retrieval/test_graph_completion_retriever_cot.py +217 -0
  196. cognee/tests/integration/retrieval/test_rag_completion_retriever.py +319 -0
  197. cognee/tests/integration/retrieval/test_structured_output.py +258 -0
  198. cognee/tests/integration/retrieval/test_summaries_retriever.py +195 -0
  199. cognee/tests/integration/retrieval/test_temporal_retriever.py +336 -0
  200. cognee/tests/integration/retrieval/test_triplet_retriever.py +45 -1
  201. cognee/tests/integration/shared/test_usage_logger_integration.py +255 -0
  202. cognee/tests/tasks/translation/README.md +147 -0
  203. cognee/tests/tasks/translation/__init__.py +1 -0
  204. cognee/tests/tasks/translation/config_test.py +93 -0
  205. cognee/tests/tasks/translation/detect_language_test.py +118 -0
  206. cognee/tests/tasks/translation/providers_test.py +151 -0
  207. cognee/tests/tasks/translation/translate_content_test.py +213 -0
  208. cognee/tests/test_chromadb.py +1 -1
  209. cognee/tests/test_cleanup_unused_data.py +165 -0
  210. cognee/tests/test_custom_data_label.py +68 -0
  211. cognee/tests/test_delete_by_id.py +6 -6
  212. cognee/tests/test_extract_usage_frequency.py +308 -0
  213. cognee/tests/test_kuzu.py +17 -7
  214. cognee/tests/test_lancedb.py +3 -1
  215. cognee/tests/test_library.py +1 -1
  216. cognee/tests/test_neo4j.py +17 -7
  217. cognee/tests/test_neptune_analytics_vector.py +3 -1
  218. cognee/tests/test_permissions.py +172 -187
  219. cognee/tests/test_pgvector.py +3 -1
  220. cognee/tests/test_relational_db_migration.py +15 -1
  221. cognee/tests/test_remote_kuzu.py +3 -1
  222. cognee/tests/test_s3_file_storage.py +1 -1
  223. cognee/tests/test_search_db.py +345 -205
  224. cognee/tests/test_usage_logger_e2e.py +268 -0
  225. cognee/tests/unit/api/test_get_raw_data_endpoint.py +206 -0
  226. cognee/tests/unit/eval_framework/answer_generation_test.py +4 -3
  227. cognee/tests/unit/eval_framework/benchmark_adapters_test.py +25 -0
  228. cognee/tests/unit/eval_framework/corpus_builder_test.py +33 -4
  229. cognee/tests/unit/infrastructure/databases/cache/test_cache_config.py +2 -0
  230. cognee/tests/unit/infrastructure/databases/relational/test_RelationalConfig.py +69 -0
  231. cognee/tests/unit/modules/graph/cognee_graph_elements_test.py +42 -2
  232. cognee/tests/unit/modules/graph/cognee_graph_test.py +329 -31
  233. cognee/tests/unit/modules/retrieval/chunks_retriever_test.py +122 -168
  234. cognee/tests/unit/modules/retrieval/conversation_history_test.py +338 -0
  235. cognee/tests/unit/modules/retrieval/graph_completion_retriever_context_extension_test.py +486 -157
  236. cognee/tests/unit/modules/retrieval/graph_completion_retriever_cot_test.py +693 -155
  237. cognee/tests/unit/modules/retrieval/graph_completion_retriever_test.py +619 -200
  238. cognee/tests/unit/modules/retrieval/rag_completion_retriever_test.py +300 -171
  239. cognee/tests/unit/modules/retrieval/summaries_retriever_test.py +184 -155
  240. cognee/tests/unit/modules/retrieval/temporal_retriever_test.py +544 -79
  241. cognee/tests/unit/modules/retrieval/test_brute_force_triplet_search.py +476 -28
  242. cognee/tests/unit/modules/retrieval/test_completion.py +343 -0
  243. cognee/tests/unit/modules/retrieval/test_graph_summary_completion_retriever.py +157 -0
  244. cognee/tests/unit/modules/retrieval/test_node_edge_vector_search.py +273 -0
  245. cognee/tests/unit/modules/retrieval/test_user_qa_feedback.py +312 -0
  246. cognee/tests/unit/modules/retrieval/triplet_retriever_test.py +267 -7
  247. cognee/tests/unit/modules/search/test_get_search_type_retriever_instance.py +125 -0
  248. cognee/tests/unit/modules/search/test_search.py +96 -20
  249. cognee/tests/unit/modules/search/test_search_prepare_search_result_contract.py +190 -0
  250. cognee/tests/unit/modules/users/test_tutorial_notebook_creation.py +511 -297
  251. cognee/tests/unit/shared/test_usage_logger.py +241 -0
  252. cognee/tests/unit/users/permissions/test_has_user_management_permission.py +46 -0
  253. {cognee-0.5.1.dist-info → cognee-0.5.2.dist-info}/METADATA +22 -17
  254. {cognee-0.5.1.dist-info → cognee-0.5.2.dist-info}/RECORD +258 -157
  255. cognee/api/.env.example +0 -5
  256. cognee/modules/retrieval/base_graph_retriever.py +0 -24
  257. cognee/modules/search/methods/get_search_type_tools.py +0 -223
  258. cognee/modules/search/methods/no_access_control_search.py +0 -62
  259. cognee/modules/search/utils/prepare_search_result.py +0 -63
  260. cognee/tests/test_feedback_enrichment.py +0 -174
  261. cognee/tests/unit/modules/retrieval/structured_output_test.py +0 -204
  262. {cognee-0.5.1.dist-info → cognee-0.5.2.dist-info}/WHEEL +0 -0
  263. {cognee-0.5.1.dist-info → cognee-0.5.2.dist-info}/entry_points.txt +0 -0
  264. {cognee-0.5.1.dist-info → cognee-0.5.2.dist-info}/licenses/LICENSE +0 -0
  265. {cognee-0.5.1.dist-info → cognee-0.5.2.dist-info}/licenses/NOTICE.md +0 -0
@@ -1,223 +1,642 @@
1
- import os
2
1
  import pytest
3
- import pathlib
4
- from typing import Optional, Union
2
+ from unittest.mock import AsyncMock, patch, MagicMock
3
+ from uuid import UUID
5
4
 
6
- import cognee
7
- from cognee.low_level import setup, DataPoint
8
- from cognee.modules.graph.utils import resolve_edges_to_text
9
- from cognee.tasks.storage import add_data_points
10
5
  from cognee.modules.retrieval.graph_completion_retriever import GraphCompletionRetriever
6
+ from cognee.modules.graph.cognee_graph.CogneeGraphElements import Edge
7
+
8
+
9
+ @pytest.fixture
10
+ def mock_edge():
11
+ """Create a mock edge."""
12
+ edge = MagicMock(spec=Edge)
13
+ return edge
11
14
 
12
15
 
13
- class TestGraphCompletionRetriever:
14
- @pytest.mark.asyncio
15
- async def test_graph_completion_context_simple(self):
16
- system_directory_path = os.path.join(
17
- pathlib.Path(__file__).parent, ".cognee_system/test_graph_completion_context_simple"
18
- )
19
- cognee.config.system_root_directory(system_directory_path)
20
- data_directory_path = os.path.join(
21
- pathlib.Path(__file__).parent, ".data_storage/test_graph_completion_context_simple"
22
- )
23
- cognee.config.data_root_directory(data_directory_path)
24
-
25
- await cognee.prune.prune_data()
26
- await cognee.prune.prune_system(metadata=True)
27
- await setup()
28
-
29
- class Company(DataPoint):
30
- name: str
31
- description: str
32
-
33
- class Person(DataPoint):
34
- name: str
35
- description: str
36
- works_for: Company
37
-
38
- company1 = Company(name="Figma", description="Figma is a company")
39
- company2 = Company(name="Canva", description="Canvas is a company")
40
- person1 = Person(
41
- name="Steve Rodger",
42
- description="This is description about Steve Rodger",
43
- works_for=company1,
44
- )
45
- person2 = Person(
46
- name="Ike Loma", description="This is description about Ike Loma", works_for=company1
47
- )
48
- person3 = Person(
49
- name="Jason Statham",
50
- description="This is description about Jason Statham",
51
- works_for=company1,
52
- )
53
- person4 = Person(
54
- name="Mike Broski",
55
- description="This is description about Mike Broski",
56
- works_for=company2,
57
- )
58
- person5 = Person(
59
- name="Christina Mayer",
60
- description="This is description about Christina Mayer",
61
- works_for=company2,
62
- )
63
-
64
- entities = [company1, company2, person1, person2, person3, person4, person5]
65
-
66
- await add_data_points(entities)
16
+ @pytest.mark.asyncio
17
+ async def test_get_triplets_success(mock_edge):
18
+ """Test successful retrieval of triplets."""
19
+ retriever = GraphCompletionRetriever(top_k=5)
67
20
 
68
- retriever = GraphCompletionRetriever()
21
+ with patch(
22
+ "cognee.modules.retrieval.graph_completion_retriever.brute_force_triplet_search",
23
+ return_value=[mock_edge],
24
+ ) as mock_search:
25
+ triplets = await retriever.get_triplets("test query")
69
26
 
70
- context = await resolve_edges_to_text(await retriever.get_context("Who works at Canva?"))
27
+ assert len(triplets) == 1
28
+ assert triplets[0] == mock_edge
29
+ mock_search.assert_awaited_once()
71
30
 
72
- # Ensure the top-level sections are present
73
- assert "Nodes:" in context, "Missing 'Nodes:' section in context"
74
- assert "Connections:" in context, "Missing 'Connections:' section in context"
75
31
 
76
- # --- Nodes headers ---
77
- assert "Node: Steve Rodger" in context, "Missing node header for Steve Rodger"
78
- assert "Node: Figma" in context, "Missing node header for Figma"
79
- assert "Node: Ike Loma" in context, "Missing node header for Ike Loma"
80
- assert "Node: Jason Statham" in context, "Missing node header for Jason Statham"
81
- assert "Node: Mike Broski" in context, "Missing node header for Mike Broski"
82
- assert "Node: Canva" in context, "Missing node header for Canva"
83
- assert "Node: Christina Mayer" in context, "Missing node header for Christina Mayer"
32
+ @pytest.mark.asyncio
33
+ async def test_get_triplets_empty_results():
34
+ """Test that empty list is returned when no triplets are found."""
35
+ retriever = GraphCompletionRetriever()
84
36
 
85
- # --- Node contents ---
86
- assert (
87
- "__node_content_start__\nThis is description about Steve Rodger\n__node_content_end__"
88
- in context
89
- ), "Description block for Steve Rodger altered"
90
- assert "__node_content_start__\nFigma is a company\n__node_content_end__" in context, (
91
- "Description block for Figma altered"
92
- )
93
- assert (
94
- "__node_content_start__\nThis is description about Ike Loma\n__node_content_end__"
95
- in context
96
- ), "Description block for Ike Loma altered"
97
- assert (
98
- "__node_content_start__\nThis is description about Jason Statham\n__node_content_end__"
99
- in context
100
- ), "Description block for Jason Statham altered"
101
- assert (
102
- "__node_content_start__\nThis is description about Mike Broski\n__node_content_end__"
103
- in context
104
- ), "Description block for Mike Broski altered"
105
- assert "__node_content_start__\nCanvas is a company\n__node_content_end__" in context, (
106
- "Description block for Canva altered"
107
- )
108
- assert (
109
- "__node_content_start__\nThis is description about Christina Mayer\n__node_content_end__"
110
- in context
111
- ), "Description block for Christina Mayer altered"
112
-
113
- # --- Connections ---
114
- assert "Steve Rodger --[works_for]--> Figma" in context, (
115
- "Connection Steve Rodger→Figma missing or changed"
116
- )
117
- assert "Ike Loma --[works_for]--> Figma" in context, (
118
- "Connection Ike Loma→Figma missing or changed"
119
- )
120
- assert "Jason Statham --[works_for]--> Figma" in context, (
121
- "Connection Jason Statham→Figma missing or changed"
122
- )
123
- assert "Mike Broski --[works_for]--> Canva" in context, (
124
- "Connection Mike Broski→Canva missing or changed"
125
- )
126
- assert "Christina Mayer --[works_for]--> Canva" in context, (
127
- "Connection Christina Mayer→Canva missing or changed"
128
- )
37
+ with patch(
38
+ "cognee.modules.retrieval.graph_completion_retriever.brute_force_triplet_search",
39
+ return_value=[],
40
+ ):
41
+ triplets = await retriever.get_triplets("test query")
129
42
 
130
- @pytest.mark.asyncio
131
- async def test_graph_completion_context_complex(self):
132
- system_directory_path = os.path.join(
133
- pathlib.Path(__file__).parent, ".cognee_system/test_graph_completion_context_complex"
134
- )
135
- cognee.config.system_root_directory(system_directory_path)
136
- data_directory_path = os.path.join(
137
- pathlib.Path(__file__).parent, ".data_storage/test_graph_completion_context_complex"
138
- )
139
- cognee.config.data_root_directory(data_directory_path)
43
+ assert triplets == []
140
44
 
141
- await cognee.prune.prune_data()
142
- await cognee.prune.prune_system(metadata=True)
143
- await setup()
144
45
 
145
- class Company(DataPoint):
146
- name: str
147
- metadata: dict = {"index_fields": ["name"]}
46
+ @pytest.mark.asyncio
47
+ async def test_get_triplets_top_k_parameter():
48
+ """Test that top_k parameter is passed to brute_force_triplet_search."""
49
+ retriever = GraphCompletionRetriever(top_k=10)
148
50
 
149
- class Car(DataPoint):
150
- brand: str
151
- model: str
152
- year: int
51
+ with patch(
52
+ "cognee.modules.retrieval.graph_completion_retriever.brute_force_triplet_search",
53
+ return_value=[],
54
+ ) as mock_search:
55
+ await retriever.get_triplets("test query")
153
56
 
154
- class Location(DataPoint):
155
- country: str
156
- city: str
57
+ call_kwargs = mock_search.call_args[1]
58
+ assert call_kwargs["top_k"] == 10
157
59
 
158
- class Home(DataPoint):
159
- location: Location
160
- rooms: int
161
- sqm: int
162
60
 
163
- class Person(DataPoint):
164
- name: str
165
- works_for: Company
166
- owns: Optional[list[Union[Car, Home]]] = None
167
-
168
- company1 = Company(name="Figma")
169
- company2 = Company(name="Canva")
170
-
171
- person1 = Person(name="Mike Rodger", works_for=company1)
172
- person1.owns = [Car(brand="Toyota", model="Camry", year=2020)]
173
-
174
- person2 = Person(name="Ike Loma", works_for=company1)
175
- person2.owns = [
176
- Car(brand="Tesla", model="Model S", year=2021),
177
- Home(location=Location(country="USA", city="New York"), sqm=80, rooms=4),
178
- ]
179
-
180
- person3 = Person(name="Jason Statham", works_for=company1)
181
-
182
- person4 = Person(name="Mike Broski", works_for=company2)
183
- person4.owns = [Car(brand="Ford", model="Mustang", year=1978)]
184
-
185
- person5 = Person(name="Christina Mayer", works_for=company2)
186
- person5.owns = [Car(brand="Honda", model="Civic", year=2023)]
187
-
188
- entities = [company1, company2, person1, person2, person3, person4, person5]
189
-
190
- await add_data_points(entities)
191
-
192
- retriever = GraphCompletionRetriever(top_k=20)
193
-
194
- context = await resolve_edges_to_text(await retriever.get_context("Who works at Figma?"))
195
-
196
- print(context)
197
-
198
- assert "Mike Rodger --[works_for]--> Figma" in context, "Failed to get Mike Rodger"
199
- assert "Ike Loma --[works_for]--> Figma" in context, "Failed to get Ike Loma"
200
- assert "Jason Statham --[works_for]--> Figma" in context, "Failed to get Jason Statham"
201
-
202
- @pytest.mark.asyncio
203
- async def test_get_graph_completion_context_on_empty_graph(self):
204
- system_directory_path = os.path.join(
205
- pathlib.Path(__file__).parent,
206
- ".cognee_system/test_get_graph_completion_context_on_empty_graph",
61
+ @pytest.mark.asyncio
62
+ async def test_get_context_success(mock_edge):
63
+ """Test successful retrieval of context."""
64
+ retriever = GraphCompletionRetriever()
65
+
66
+ mock_graph_engine = AsyncMock()
67
+ mock_graph_engine.is_empty = AsyncMock(return_value=False)
68
+
69
+ mock_node1 = MagicMock()
70
+ mock_node2 = MagicMock()
71
+ mock_edge.node1 = mock_node1
72
+ mock_edge.node2 = mock_node2
73
+ mock_edge.attributes = {"text": "mock edge"}
74
+
75
+ with (
76
+ patch(
77
+ "cognee.modules.retrieval.graph_completion_retriever.get_graph_engine",
78
+ return_value=mock_graph_engine,
79
+ ),
80
+ patch(
81
+ "cognee.modules.retrieval.graph_completion_retriever.brute_force_triplet_search",
82
+ return_value=[mock_edge],
83
+ ),
84
+ ):
85
+ context = await retriever.get_context_from_objects("test query", [mock_edge])
86
+
87
+ assert isinstance(context, str)
88
+
89
+
90
+ @pytest.mark.asyncio
91
+ async def test_get_context_empty_results():
92
+ """Test that empty list is returned when no context is found."""
93
+ retriever = GraphCompletionRetriever()
94
+
95
+ mock_graph_engine = AsyncMock()
96
+ mock_graph_engine.is_empty = AsyncMock(return_value=False)
97
+
98
+ with (
99
+ patch(
100
+ "cognee.modules.retrieval.graph_completion_retriever.get_graph_engine",
101
+ return_value=mock_graph_engine,
102
+ ),
103
+ patch(
104
+ "cognee.modules.retrieval.graph_completion_retriever.brute_force_triplet_search",
105
+ return_value=[],
106
+ ),
107
+ ):
108
+ context = await retriever.get_context_from_objects("test query", [])
109
+
110
+ assert context == ""
111
+
112
+
113
+ @pytest.mark.asyncio
114
+ async def test_get_context_empty_graph():
115
+ """Test that empty list is returned when graph is empty."""
116
+ retriever = GraphCompletionRetriever()
117
+
118
+ mock_graph_engine = AsyncMock()
119
+ mock_graph_engine.is_empty = AsyncMock(return_value=True)
120
+
121
+ with patch(
122
+ "cognee.modules.retrieval.graph_completion_retriever.get_graph_engine",
123
+ return_value=mock_graph_engine,
124
+ ):
125
+ context = await retriever.get_context_from_objects("test query", [])
126
+
127
+ assert context == ""
128
+
129
+
130
+ @pytest.mark.asyncio
131
+ async def test_resolve_edges_to_text(mock_edge):
132
+ """Test resolve_edges_to_text method."""
133
+ retriever = GraphCompletionRetriever()
134
+
135
+ with patch(
136
+ "cognee.modules.retrieval.graph_completion_retriever.resolve_edges_to_text",
137
+ return_value="Resolved text",
138
+ ) as mock_resolve:
139
+ result = await retriever.resolve_edges_to_text([mock_edge])
140
+
141
+ assert result == "Resolved text"
142
+ mock_resolve.assert_awaited_once_with([mock_edge])
143
+
144
+
145
+ @pytest.mark.asyncio
146
+ async def test_init_defaults():
147
+ """Test GraphCompletionRetriever initialization with defaults."""
148
+ retriever = GraphCompletionRetriever()
149
+
150
+ assert retriever.top_k == 5
151
+ assert retriever.user_prompt_path == "graph_context_for_question.txt"
152
+ assert retriever.system_prompt_path == "answer_simple_question.txt"
153
+ assert retriever.node_type is None
154
+ assert retriever.node_name is None
155
+
156
+
157
+ @pytest.mark.asyncio
158
+ async def test_init_custom_params():
159
+ """Test GraphCompletionRetriever initialization with custom parameters."""
160
+ retriever = GraphCompletionRetriever(
161
+ top_k=10,
162
+ user_prompt_path="custom_user.txt",
163
+ system_prompt_path="custom_system.txt",
164
+ system_prompt="Custom prompt",
165
+ node_type=str,
166
+ node_name=["node1"],
167
+ save_interaction=True,
168
+ wide_search_top_k=200,
169
+ triplet_distance_penalty=5.0,
170
+ )
171
+
172
+ assert retriever.top_k == 10
173
+ assert retriever.user_prompt_path == "custom_user.txt"
174
+ assert retriever.system_prompt_path == "custom_system.txt"
175
+ assert retriever.system_prompt == "Custom prompt"
176
+ assert retriever.node_type is str
177
+ assert retriever.node_name == ["node1"]
178
+ assert retriever.save_interaction is True
179
+ assert retriever.wide_search_top_k == 200
180
+ assert retriever.triplet_distance_penalty == 5.0
181
+
182
+
183
+ @pytest.mark.asyncio
184
+ async def test_init_none_top_k():
185
+ """Test GraphCompletionRetriever initialization with None top_k."""
186
+ retriever = GraphCompletionRetriever(top_k=None)
187
+
188
+ assert retriever.top_k == 5 # None defaults to 5
189
+
190
+
191
+ @pytest.mark.asyncio
192
+ async def test_get_completion_without_context(mock_edge):
193
+ """Test get_completion retrieves context when not provided."""
194
+ mock_graph_engine = AsyncMock()
195
+ mock_graph_engine.is_empty = AsyncMock(return_value=False)
196
+
197
+ retriever = GraphCompletionRetriever()
198
+
199
+ with (
200
+ patch(
201
+ "cognee.modules.retrieval.graph_completion_retriever.get_graph_engine",
202
+ return_value=mock_graph_engine,
203
+ ),
204
+ patch(
205
+ "cognee.modules.retrieval.graph_completion_retriever.brute_force_triplet_search",
206
+ return_value=[mock_edge],
207
+ ),
208
+ patch(
209
+ "cognee.modules.retrieval.graph_completion_retriever.resolve_edges_to_text",
210
+ return_value="Resolved context",
211
+ ),
212
+ patch(
213
+ "cognee.modules.retrieval.graph_completion_retriever.generate_completion",
214
+ return_value="Generated answer",
215
+ ),
216
+ patch(
217
+ "cognee.modules.retrieval.graph_completion_retriever.CacheConfig"
218
+ ) as mock_cache_config,
219
+ ):
220
+ mock_config = MagicMock()
221
+ mock_config.caching = False
222
+ mock_cache_config.return_value = mock_config
223
+
224
+ completion = await retriever.get_completion_from_context("test query", None, None)
225
+
226
+ assert isinstance(completion, list)
227
+ assert len(completion) == 1
228
+ assert completion[0] == "Generated answer"
229
+
230
+
231
+ @pytest.mark.asyncio
232
+ async def test_get_completion_with_provided_context(mock_edge):
233
+ """Test get_completion uses provided context."""
234
+ retriever = GraphCompletionRetriever()
235
+
236
+ with (
237
+ patch(
238
+ "cognee.modules.retrieval.graph_completion_retriever.resolve_edges_to_text",
239
+ return_value="Resolved context",
240
+ ),
241
+ patch(
242
+ "cognee.modules.retrieval.graph_completion_retriever.generate_completion",
243
+ return_value="Generated answer",
244
+ ),
245
+ patch(
246
+ "cognee.modules.retrieval.graph_completion_retriever.CacheConfig"
247
+ ) as mock_cache_config,
248
+ ):
249
+ mock_config = MagicMock()
250
+ mock_config.caching = False
251
+ mock_cache_config.return_value = mock_config
252
+
253
+ completion = await retriever.get_completion_from_context(
254
+ "test query", None, context="mock edge"
207
255
  )
208
- cognee.config.system_root_directory(system_directory_path)
209
- data_directory_path = os.path.join(
210
- pathlib.Path(__file__).parent,
211
- ".data_storage/test_get_graph_completion_context_on_empty_graph",
256
+
257
+ assert isinstance(completion, list)
258
+ assert len(completion) == 1
259
+ assert completion[0] == "Generated answer"
260
+
261
+
262
+ @pytest.mark.asyncio
263
+ async def test_get_completion_with_session(mock_edge):
264
+ """Test get_completion with session caching enabled."""
265
+ mock_graph_engine = AsyncMock()
266
+ mock_graph_engine.is_empty = AsyncMock(return_value=False)
267
+
268
+ retriever = GraphCompletionRetriever(session_id="test_session")
269
+
270
+ mock_user = MagicMock()
271
+ mock_user.id = "test-user-id"
272
+
273
+ with (
274
+ patch(
275
+ "cognee.modules.retrieval.graph_completion_retriever.get_graph_engine",
276
+ return_value=mock_graph_engine,
277
+ ),
278
+ patch(
279
+ "cognee.modules.retrieval.graph_completion_retriever.brute_force_triplet_search",
280
+ return_value=[mock_edge],
281
+ ),
282
+ patch(
283
+ "cognee.modules.retrieval.graph_completion_retriever.resolve_edges_to_text",
284
+ return_value="Resolved context",
285
+ ),
286
+ patch(
287
+ "cognee.modules.retrieval.graph_completion_retriever.get_conversation_history",
288
+ return_value="Previous conversation",
289
+ ),
290
+ patch(
291
+ "cognee.modules.retrieval.graph_completion_retriever.summarize_text",
292
+ return_value="Context summary",
293
+ ),
294
+ patch(
295
+ "cognee.modules.retrieval.graph_completion_retriever.generate_completion",
296
+ return_value="Generated answer",
297
+ ),
298
+ patch(
299
+ "cognee.modules.retrieval.graph_completion_retriever.save_conversation_history",
300
+ ) as mock_save,
301
+ patch(
302
+ "cognee.modules.retrieval.graph_completion_retriever.CacheConfig"
303
+ ) as mock_cache_config,
304
+ patch(
305
+ "cognee.modules.retrieval.graph_completion_retriever.session_user"
306
+ ) as mock_session_user,
307
+ ):
308
+ mock_config = MagicMock()
309
+ mock_config.caching = True
310
+ mock_cache_config.return_value = mock_config
311
+ mock_session_user.get.return_value = mock_user
312
+
313
+ completion = await retriever.get_completion_from_context("test query", None, None)
314
+
315
+ assert isinstance(completion, list)
316
+ assert len(completion) == 1
317
+ assert completion[0] == "Generated answer"
318
+ mock_save.assert_awaited_once()
319
+
320
+
321
+ @pytest.mark.asyncio
322
+ async def test_get_completion_with_response_model(mock_edge):
323
+ """Test get_completion with custom response model."""
324
+ from pydantic import BaseModel
325
+
326
+ class TestModel(BaseModel):
327
+ answer: str
328
+
329
+ mock_graph_engine = AsyncMock()
330
+ mock_graph_engine.is_empty = AsyncMock(return_value=False)
331
+
332
+ retriever = GraphCompletionRetriever(response_model=TestModel)
333
+
334
+ with (
335
+ patch(
336
+ "cognee.modules.retrieval.graph_completion_retriever.get_graph_engine",
337
+ return_value=mock_graph_engine,
338
+ ),
339
+ patch(
340
+ "cognee.modules.retrieval.graph_completion_retriever.brute_force_triplet_search",
341
+ return_value=[mock_edge],
342
+ ),
343
+ patch(
344
+ "cognee.modules.retrieval.graph_completion_retriever.resolve_edges_to_text",
345
+ return_value="Resolved context",
346
+ ),
347
+ patch(
348
+ "cognee.modules.retrieval.graph_completion_retriever.generate_completion",
349
+ return_value=TestModel(answer="Test answer"),
350
+ ),
351
+ patch(
352
+ "cognee.modules.retrieval.graph_completion_retriever.CacheConfig"
353
+ ) as mock_cache_config,
354
+ ):
355
+ mock_config = MagicMock()
356
+ mock_config.caching = False
357
+ mock_cache_config.return_value = mock_config
358
+
359
+ completion = await retriever.get_completion_from_context("test query", None, None)
360
+
361
+ assert isinstance(completion, list)
362
+ assert len(completion) == 1
363
+ assert isinstance(completion[0], TestModel)
364
+
365
+
366
+ @pytest.mark.asyncio
367
+ async def test_get_completion_empty_context(mock_edge):
368
+ """Test get_completion with empty context."""
369
+ mock_graph_engine = AsyncMock()
370
+ mock_graph_engine.is_empty = AsyncMock(return_value=False)
371
+
372
+ retriever = GraphCompletionRetriever()
373
+
374
+ with (
375
+ patch(
376
+ "cognee.modules.retrieval.graph_completion_retriever.get_graph_engine",
377
+ return_value=mock_graph_engine,
378
+ ),
379
+ patch(
380
+ "cognee.modules.retrieval.graph_completion_retriever.brute_force_triplet_search",
381
+ return_value=[],
382
+ ),
383
+ patch(
384
+ "cognee.modules.retrieval.graph_completion_retriever.resolve_edges_to_text",
385
+ return_value="",
386
+ ),
387
+ patch(
388
+ "cognee.modules.retrieval.graph_completion_retriever.generate_completion",
389
+ return_value="Generated answer",
390
+ ),
391
+ patch(
392
+ "cognee.modules.retrieval.graph_completion_retriever.CacheConfig"
393
+ ) as mock_cache_config,
394
+ ):
395
+ mock_config = MagicMock()
396
+ mock_config.caching = False
397
+ mock_cache_config.return_value = mock_config
398
+
399
+ completion = await retriever.get_completion_from_context("test query", None, None)
400
+
401
+ assert isinstance(completion, list)
402
+ assert len(completion) == 1
403
+
404
+
405
+ @pytest.mark.asyncio
406
+ async def test_save_qa(mock_edge):
407
+ """Test save_qa method."""
408
+ mock_graph_engine = AsyncMock()
409
+ mock_graph_engine.add_edges = AsyncMock()
410
+
411
+ retriever = GraphCompletionRetriever()
412
+
413
+ mock_node1 = MagicMock()
414
+ mock_node2 = MagicMock()
415
+ mock_edge.node1 = mock_node1
416
+ mock_edge.node2 = mock_node2
417
+
418
+ with (
419
+ patch(
420
+ "cognee.modules.retrieval.graph_completion_retriever.get_graph_engine",
421
+ return_value=mock_graph_engine,
422
+ ),
423
+ patch(
424
+ "cognee.modules.retrieval.graph_completion_retriever.extract_uuid_from_node",
425
+ side_effect=["uuid1", "uuid2"],
426
+ ),
427
+ patch(
428
+ "cognee.modules.retrieval.graph_completion_retriever.add_data_points",
429
+ ) as mock_add_data,
430
+ ):
431
+ await retriever.save_qa(
432
+ question="Test question",
433
+ answer="Test answer",
434
+ context="Test context",
435
+ triplets=[mock_edge],
212
436
  )
213
- cognee.config.data_root_directory(data_directory_path)
214
437
 
215
- await cognee.prune.prune_data()
216
- await cognee.prune.prune_system(metadata=True)
438
+ mock_add_data.assert_awaited_once()
439
+ mock_graph_engine.add_edges.assert_awaited_once()
440
+
441
+
442
+ @pytest.mark.asyncio
443
+ async def test_save_qa_no_triplet_ids(mock_edge):
444
+ """Test save_qa when triplets have no extractable IDs."""
445
+ mock_graph_engine = AsyncMock()
446
+ mock_graph_engine.add_edges = AsyncMock()
447
+
448
+ retriever = GraphCompletionRetriever()
449
+
450
+ mock_node1 = MagicMock()
451
+ mock_node2 = MagicMock()
452
+ mock_edge.node1 = mock_node1
453
+ mock_edge.node2 = mock_node2
454
+
455
+ with (
456
+ patch(
457
+ "cognee.modules.retrieval.graph_completion_retriever.get_graph_engine",
458
+ return_value=mock_graph_engine,
459
+ ),
460
+ patch(
461
+ "cognee.modules.retrieval.graph_completion_retriever.extract_uuid_from_node",
462
+ return_value=None,
463
+ ),
464
+ patch(
465
+ "cognee.modules.retrieval.graph_completion_retriever.add_data_points",
466
+ ) as mock_add_data,
467
+ ):
468
+ await retriever.save_qa(
469
+ question="Test question",
470
+ answer="Test answer",
471
+ context="Test context",
472
+ triplets=[mock_edge],
473
+ )
217
474
 
218
- retriever = GraphCompletionRetriever()
475
+ mock_add_data.assert_awaited_once()
476
+ mock_graph_engine.add_edges.assert_not_called()
477
+
478
+
479
+ @pytest.mark.asyncio
480
+ async def test_save_qa_empty_triplets():
481
+ """Test save_qa with empty triplets list."""
482
+ mock_graph_engine = AsyncMock()
483
+ mock_graph_engine.add_edges = AsyncMock()
484
+
485
+ retriever = GraphCompletionRetriever()
486
+
487
+ with (
488
+ patch(
489
+ "cognee.modules.retrieval.graph_completion_retriever.get_graph_engine",
490
+ return_value=mock_graph_engine,
491
+ ),
492
+ patch(
493
+ "cognee.modules.retrieval.graph_completion_retriever.add_data_points",
494
+ ) as mock_add_data,
495
+ ):
496
+ await retriever.save_qa(
497
+ question="Test question",
498
+ answer="Test answer",
499
+ context="Test context",
500
+ triplets=[],
501
+ )
219
502
 
220
- await setup()
503
+ mock_add_data.assert_awaited_once()
504
+ mock_graph_engine.add_edges.assert_not_called()
505
+
506
+
507
+ @pytest.mark.asyncio
508
+ async def test_get_completion_with_save_interaction_no_completion(mock_edge):
509
+ """Test get_completion with save_interaction but no completion."""
510
+ mock_graph_engine = AsyncMock()
511
+ mock_graph_engine.is_empty = AsyncMock(return_value=False)
512
+
513
+ retriever = GraphCompletionRetriever(save_interaction=True)
514
+
515
+ with (
516
+ patch(
517
+ "cognee.modules.retrieval.graph_completion_retriever.get_graph_engine",
518
+ return_value=mock_graph_engine,
519
+ ),
520
+ patch(
521
+ "cognee.modules.retrieval.graph_completion_retriever.brute_force_triplet_search",
522
+ return_value=[mock_edge],
523
+ ),
524
+ patch(
525
+ "cognee.modules.retrieval.graph_completion_retriever.resolve_edges_to_text",
526
+ return_value="Resolved context",
527
+ ),
528
+ patch(
529
+ "cognee.modules.retrieval.graph_completion_retriever.generate_completion",
530
+ return_value=None, # No completion
531
+ ),
532
+ patch(
533
+ "cognee.modules.retrieval.graph_completion_retriever.CacheConfig"
534
+ ) as mock_cache_config,
535
+ ):
536
+ mock_config = MagicMock()
537
+ mock_config.caching = False
538
+ mock_cache_config.return_value = mock_config
539
+
540
+ completion = await retriever.get_completion_from_context("test query", None, None)
541
+
542
+ assert isinstance(completion, list)
543
+ assert len(completion) == 1
544
+ assert completion[0] is None
545
+
546
+
547
+ @pytest.mark.asyncio
548
+ async def test_get_completion_with_save_interaction_no_context(mock_edge):
549
+ """Test get_completion with save_interaction but no context provided."""
550
+ mock_graph_engine = AsyncMock()
551
+ mock_graph_engine.is_empty = AsyncMock(return_value=False)
552
+
553
+ retriever = GraphCompletionRetriever(save_interaction=True)
554
+
555
+ with (
556
+ patch(
557
+ "cognee.modules.retrieval.graph_completion_retriever.get_graph_engine",
558
+ return_value=mock_graph_engine,
559
+ ),
560
+ patch(
561
+ "cognee.modules.retrieval.graph_completion_retriever.brute_force_triplet_search",
562
+ return_value=[mock_edge],
563
+ ),
564
+ patch(
565
+ "cognee.modules.retrieval.graph_completion_retriever.resolve_edges_to_text",
566
+ return_value="Resolved context",
567
+ ),
568
+ patch(
569
+ "cognee.modules.retrieval.graph_completion_retriever.generate_completion",
570
+ return_value="Generated answer",
571
+ ),
572
+ patch(
573
+ "cognee.modules.retrieval.graph_completion_retriever.CacheConfig"
574
+ ) as mock_cache_config,
575
+ ):
576
+ mock_config = MagicMock()
577
+ mock_config.caching = False
578
+ mock_cache_config.return_value = mock_config
579
+
580
+ completion = await retriever.get_completion_from_context("test query", None, context=None)
581
+
582
+ assert isinstance(completion, list)
583
+ assert len(completion) == 1
584
+
585
+
586
+ @pytest.mark.asyncio
587
+ async def test_get_completion_with_save_interaction_all_conditions_met(mock_edge):
588
+ """Test get_completion with save_interaction when all conditions are met (line 216)."""
589
+ mock_graph_engine = AsyncMock()
590
+ mock_graph_engine.is_empty = AsyncMock(return_value=False)
591
+
592
+ retriever = GraphCompletionRetriever(save_interaction=True)
593
+
594
+ mock_node1 = MagicMock()
595
+ mock_node2 = MagicMock()
596
+ mock_edge.node1 = mock_node1
597
+ mock_edge.node2 = mock_node2
598
+
599
+ with (
600
+ patch(
601
+ "cognee.modules.retrieval.graph_completion_retriever.get_graph_engine",
602
+ return_value=mock_graph_engine,
603
+ ),
604
+ patch(
605
+ "cognee.modules.retrieval.graph_completion_retriever.brute_force_triplet_search",
606
+ return_value=[mock_edge],
607
+ ),
608
+ patch(
609
+ "cognee.modules.retrieval.graph_completion_retriever.resolve_edges_to_text",
610
+ return_value="Resolved context",
611
+ ),
612
+ patch(
613
+ "cognee.modules.retrieval.graph_completion_retriever.generate_completion",
614
+ return_value="Generated answer",
615
+ ),
616
+ patch(
617
+ "cognee.modules.retrieval.graph_completion_retriever.extract_uuid_from_node",
618
+ side_effect=[
619
+ UUID("550e8400-e29b-41d4-a716-446655440000"),
620
+ UUID("550e8400-e29b-41d4-a716-446655440001"),
621
+ ],
622
+ ),
623
+ patch(
624
+ "cognee.modules.retrieval.graph_completion_retriever.add_data_points",
625
+ ) as mock_add_data,
626
+ patch(
627
+ "cognee.modules.retrieval.graph_completion_retriever.CacheConfig"
628
+ ) as mock_cache_config,
629
+ ):
630
+ mock_config = MagicMock()
631
+ mock_config.caching = False
632
+ mock_cache_config.return_value = mock_config
633
+
634
+ objects = await retriever.get_retrieved_objects("test query")
635
+ completion = await retriever.get_completion_from_context(
636
+ "test query", objects, context="mock_edge"
637
+ )
221
638
 
222
- context = await retriever.get_context("Who works at Figma?")
223
- assert context == [], "Context should be empty on an empty graph"
639
+ assert isinstance(completion, list)
640
+ assert len(completion) == 1
641
+ assert completion[0] == "Generated answer"
642
+ mock_add_data.assert_awaited_once()