cognee 0.5.1.dev0__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 (241) 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/routers/get_add_router.py +2 -0
  23. cognee/api/v1/cognify/cognify.py +11 -6
  24. cognee/api/v1/cognify/routers/get_cognify_router.py +8 -0
  25. cognee/api/v1/config/config.py +60 -0
  26. cognee/api/v1/datasets/routers/get_datasets_router.py +45 -3
  27. cognee/api/v1/memify/routers/get_memify_router.py +2 -0
  28. cognee/api/v1/search/routers/get_search_router.py +21 -6
  29. cognee/api/v1/search/search.py +25 -5
  30. cognee/api/v1/sync/routers/get_sync_router.py +3 -3
  31. cognee/cli/commands/add_command.py +1 -1
  32. cognee/cli/commands/cognify_command.py +6 -0
  33. cognee/cli/commands/config_command.py +1 -1
  34. cognee/context_global_variables.py +5 -1
  35. cognee/eval_framework/answer_generation/answer_generation_executor.py +7 -8
  36. cognee/infrastructure/databases/cache/cache_db_interface.py +38 -1
  37. cognee/infrastructure/databases/cache/config.py +6 -0
  38. cognee/infrastructure/databases/cache/fscache/FsCacheAdapter.py +21 -0
  39. cognee/infrastructure/databases/cache/get_cache_engine.py +9 -3
  40. cognee/infrastructure/databases/cache/redis/RedisAdapter.py +60 -1
  41. cognee/infrastructure/databases/dataset_database_handler/supported_dataset_database_handlers.py +7 -0
  42. cognee/infrastructure/databases/graph/get_graph_engine.py +29 -1
  43. cognee/infrastructure/databases/graph/neo4j_driver/Neo4jAuraDevDatasetDatabaseHandler.py +62 -27
  44. cognee/infrastructure/databases/hybrid/neptune_analytics/NeptuneAnalyticsAdapter.py +17 -4
  45. cognee/infrastructure/databases/relational/sqlalchemy/SqlAlchemyAdapter.py +2 -1
  46. cognee/infrastructure/databases/vector/chromadb/ChromaDBAdapter.py +2 -0
  47. cognee/infrastructure/databases/vector/config.py +6 -0
  48. cognee/infrastructure/databases/vector/create_vector_engine.py +69 -22
  49. cognee/infrastructure/databases/vector/embeddings/LiteLLMEmbeddingEngine.py +64 -9
  50. cognee/infrastructure/databases/vector/embeddings/OllamaEmbeddingEngine.py +13 -2
  51. cognee/infrastructure/databases/vector/lancedb/LanceDBAdapter.py +16 -3
  52. cognee/infrastructure/databases/vector/models/ScoredResult.py +3 -3
  53. cognee/infrastructure/databases/vector/pgvector/PGVectorAdapter.py +16 -3
  54. cognee/infrastructure/databases/vector/pgvector/PGVectorDatasetDatabaseHandler.py +86 -0
  55. cognee/infrastructure/databases/vector/pgvector/create_db_and_tables.py +81 -2
  56. cognee/infrastructure/databases/vector/vector_db_interface.py +8 -0
  57. cognee/infrastructure/files/utils/get_data_file_path.py +33 -27
  58. cognee/infrastructure/llm/prompts/extract_query_time.txt +1 -1
  59. cognee/infrastructure/llm/prompts/generate_event_entity_prompt.txt +1 -1
  60. cognee/infrastructure/llm/prompts/generate_event_graph_prompt.txt +1 -1
  61. cognee/infrastructure/llm/prompts/generate_graph_prompt.txt +2 -2
  62. cognee/infrastructure/llm/prompts/generate_graph_prompt_guided.txt +1 -1
  63. cognee/infrastructure/llm/prompts/generate_graph_prompt_oneshot.txt +2 -2
  64. cognee/infrastructure/llm/prompts/generate_graph_prompt_simple.txt +1 -1
  65. cognee/infrastructure/llm/prompts/generate_graph_prompt_strict.txt +1 -1
  66. cognee/infrastructure/llm/prompts/search_type_selector_prompt.txt +6 -6
  67. cognee/infrastructure/llm/prompts/test.txt +1 -1
  68. cognee/infrastructure/llm/prompts/translate_content.txt +19 -0
  69. cognee/infrastructure/llm/structured_output_framework/litellm_instructor/llm/get_llm_client.py +24 -0
  70. cognee/infrastructure/llm/structured_output_framework/litellm_instructor/llm/llama_cpp/adapter.py +191 -0
  71. cognee/modules/chunking/models/DocumentChunk.py +0 -1
  72. cognee/modules/cognify/config.py +2 -0
  73. cognee/modules/data/models/Data.py +1 -0
  74. cognee/modules/engine/models/Entity.py +0 -1
  75. cognee/modules/engine/operations/setup.py +6 -0
  76. cognee/modules/graph/cognee_graph/CogneeGraph.py +150 -37
  77. cognee/modules/graph/cognee_graph/CogneeGraphElements.py +48 -2
  78. cognee/modules/graph/utils/__init__.py +1 -0
  79. cognee/modules/graph/utils/get_entity_nodes_from_triplets.py +12 -0
  80. cognee/modules/notebooks/methods/__init__.py +1 -0
  81. cognee/modules/notebooks/methods/create_notebook.py +0 -34
  82. cognee/modules/notebooks/methods/create_tutorial_notebooks.py +191 -0
  83. cognee/modules/notebooks/methods/get_notebooks.py +12 -8
  84. cognee/modules/notebooks/tutorials/cognee-basics/cell-1.md +3 -0
  85. cognee/modules/notebooks/tutorials/cognee-basics/cell-2.md +10 -0
  86. cognee/modules/notebooks/tutorials/cognee-basics/cell-3.md +7 -0
  87. cognee/modules/notebooks/tutorials/cognee-basics/cell-4.py +28 -0
  88. cognee/modules/notebooks/tutorials/cognee-basics/cell-5.py +3 -0
  89. cognee/modules/notebooks/tutorials/cognee-basics/cell-6.py +9 -0
  90. cognee/modules/notebooks/tutorials/cognee-basics/cell-7.py +17 -0
  91. cognee/modules/notebooks/tutorials/cognee-basics/config.json +4 -0
  92. cognee/modules/notebooks/tutorials/python-development-with-cognee/cell-1.md +3 -0
  93. cognee/modules/notebooks/tutorials/python-development-with-cognee/cell-10.md +3 -0
  94. cognee/modules/notebooks/tutorials/python-development-with-cognee/cell-11.md +3 -0
  95. cognee/modules/notebooks/tutorials/python-development-with-cognee/cell-12.py +3 -0
  96. cognee/modules/notebooks/tutorials/python-development-with-cognee/cell-13.md +7 -0
  97. cognee/modules/notebooks/tutorials/python-development-with-cognee/cell-14.py +6 -0
  98. cognee/modules/notebooks/tutorials/python-development-with-cognee/cell-15.md +3 -0
  99. cognee/modules/notebooks/tutorials/python-development-with-cognee/cell-16.py +7 -0
  100. cognee/modules/notebooks/tutorials/python-development-with-cognee/cell-2.md +9 -0
  101. cognee/modules/notebooks/tutorials/python-development-with-cognee/cell-3.md +7 -0
  102. cognee/modules/notebooks/tutorials/python-development-with-cognee/cell-4.md +9 -0
  103. cognee/modules/notebooks/tutorials/python-development-with-cognee/cell-5.md +5 -0
  104. cognee/modules/notebooks/tutorials/python-development-with-cognee/cell-6.py +13 -0
  105. cognee/modules/notebooks/tutorials/python-development-with-cognee/cell-7.md +3 -0
  106. cognee/modules/notebooks/tutorials/python-development-with-cognee/cell-8.md +3 -0
  107. cognee/modules/notebooks/tutorials/python-development-with-cognee/cell-9.py +31 -0
  108. cognee/modules/notebooks/tutorials/python-development-with-cognee/config.json +4 -0
  109. cognee/modules/notebooks/tutorials/python-development-with-cognee/data/copilot_conversations.json +107 -0
  110. cognee/modules/notebooks/tutorials/python-development-with-cognee/data/guido_contributions.json +976 -0
  111. cognee/modules/notebooks/tutorials/python-development-with-cognee/data/my_developer_rules.md +79 -0
  112. cognee/modules/notebooks/tutorials/python-development-with-cognee/data/pep_style_guide.md +74 -0
  113. cognee/modules/notebooks/tutorials/python-development-with-cognee/data/zen_principles.md +74 -0
  114. cognee/modules/retrieval/EntityCompletionRetriever.py +51 -38
  115. cognee/modules/retrieval/__init__.py +0 -1
  116. cognee/modules/retrieval/base_retriever.py +66 -10
  117. cognee/modules/retrieval/chunks_retriever.py +57 -49
  118. cognee/modules/retrieval/coding_rules_retriever.py +12 -5
  119. cognee/modules/retrieval/completion_retriever.py +29 -28
  120. cognee/modules/retrieval/cypher_search_retriever.py +25 -20
  121. cognee/modules/retrieval/graph_completion_context_extension_retriever.py +42 -46
  122. cognee/modules/retrieval/graph_completion_cot_retriever.py +68 -51
  123. cognee/modules/retrieval/graph_completion_retriever.py +78 -63
  124. cognee/modules/retrieval/graph_summary_completion_retriever.py +2 -0
  125. cognee/modules/retrieval/lexical_retriever.py +34 -12
  126. cognee/modules/retrieval/natural_language_retriever.py +18 -15
  127. cognee/modules/retrieval/summaries_retriever.py +51 -34
  128. cognee/modules/retrieval/temporal_retriever.py +59 -49
  129. cognee/modules/retrieval/triplet_retriever.py +31 -32
  130. cognee/modules/retrieval/utils/access_tracking.py +88 -0
  131. cognee/modules/retrieval/utils/brute_force_triplet_search.py +99 -85
  132. cognee/modules/retrieval/utils/node_edge_vector_search.py +174 -0
  133. cognee/modules/search/methods/__init__.py +1 -0
  134. cognee/modules/search/methods/get_retriever_output.py +53 -0
  135. cognee/modules/search/methods/get_search_type_retriever_instance.py +252 -0
  136. cognee/modules/search/methods/search.py +90 -215
  137. cognee/modules/search/models/SearchResultPayload.py +67 -0
  138. cognee/modules/search/types/SearchResult.py +1 -8
  139. cognee/modules/search/types/SearchType.py +1 -2
  140. cognee/modules/search/types/__init__.py +1 -1
  141. cognee/modules/search/utils/__init__.py +1 -2
  142. cognee/modules/search/utils/transform_insights_to_graph.py +2 -2
  143. cognee/modules/search/utils/{transform_context_to_graph.py → transform_triplets_to_graph.py} +2 -2
  144. cognee/modules/users/authentication/default/default_transport.py +11 -1
  145. cognee/modules/users/authentication/get_api_auth_backend.py +2 -1
  146. cognee/modules/users/authentication/get_client_auth_backend.py +2 -1
  147. cognee/modules/users/methods/create_user.py +0 -9
  148. cognee/modules/users/permissions/methods/has_user_management_permission.py +29 -0
  149. cognee/modules/visualization/cognee_network_visualization.py +1 -1
  150. cognee/run_migrations.py +48 -0
  151. cognee/shared/exceptions/__init__.py +1 -3
  152. cognee/shared/exceptions/exceptions.py +11 -1
  153. cognee/shared/usage_logger.py +332 -0
  154. cognee/shared/utils.py +12 -5
  155. cognee/tasks/chunks/__init__.py +9 -0
  156. cognee/tasks/cleanup/cleanup_unused_data.py +172 -0
  157. cognee/tasks/graph/__init__.py +7 -0
  158. cognee/tasks/memify/__init__.py +8 -0
  159. cognee/tasks/memify/extract_usage_frequency.py +613 -0
  160. cognee/tasks/summarization/models.py +0 -2
  161. cognee/tasks/temporal_graph/__init__.py +0 -1
  162. cognee/tasks/translation/__init__.py +96 -0
  163. cognee/tasks/translation/config.py +110 -0
  164. cognee/tasks/translation/detect_language.py +190 -0
  165. cognee/tasks/translation/exceptions.py +62 -0
  166. cognee/tasks/translation/models.py +72 -0
  167. cognee/tasks/translation/providers/__init__.py +44 -0
  168. cognee/tasks/translation/providers/azure_provider.py +192 -0
  169. cognee/tasks/translation/providers/base.py +85 -0
  170. cognee/tasks/translation/providers/google_provider.py +158 -0
  171. cognee/tasks/translation/providers/llm_provider.py +143 -0
  172. cognee/tasks/translation/translate_content.py +282 -0
  173. cognee/tasks/web_scraper/default_url_crawler.py +6 -2
  174. cognee/tests/cli_tests/cli_unit_tests/test_cli_commands.py +1 -0
  175. cognee/tests/cli_tests/cli_unit_tests/test_cli_edge_cases.py +3 -0
  176. cognee/tests/integration/retrieval/test_brute_force_triplet_search_with_cognify.py +62 -0
  177. cognee/tests/integration/retrieval/test_chunks_retriever.py +115 -16
  178. cognee/tests/integration/retrieval/test_graph_completion_retriever.py +13 -5
  179. cognee/tests/integration/retrieval/test_graph_completion_retriever_context_extension.py +22 -20
  180. cognee/tests/integration/retrieval/test_graph_completion_retriever_cot.py +23 -24
  181. cognee/tests/integration/retrieval/test_rag_completion_retriever.py +70 -5
  182. cognee/tests/integration/retrieval/test_structured_output.py +62 -18
  183. cognee/tests/integration/retrieval/test_summaries_retriever.py +20 -9
  184. cognee/tests/integration/retrieval/test_temporal_retriever.py +38 -8
  185. cognee/tests/integration/retrieval/test_triplet_retriever.py +13 -4
  186. cognee/tests/integration/shared/test_usage_logger_integration.py +255 -0
  187. cognee/tests/tasks/translation/README.md +147 -0
  188. cognee/tests/tasks/translation/__init__.py +1 -0
  189. cognee/tests/tasks/translation/config_test.py +93 -0
  190. cognee/tests/tasks/translation/detect_language_test.py +118 -0
  191. cognee/tests/tasks/translation/providers_test.py +151 -0
  192. cognee/tests/tasks/translation/translate_content_test.py +213 -0
  193. cognee/tests/test_chromadb.py +1 -1
  194. cognee/tests/test_cleanup_unused_data.py +165 -0
  195. cognee/tests/test_delete_by_id.py +6 -6
  196. cognee/tests/test_extract_usage_frequency.py +308 -0
  197. cognee/tests/test_kuzu.py +17 -7
  198. cognee/tests/test_lancedb.py +3 -1
  199. cognee/tests/test_library.py +1 -1
  200. cognee/tests/test_neo4j.py +17 -7
  201. cognee/tests/test_neptune_analytics_vector.py +3 -1
  202. cognee/tests/test_permissions.py +172 -187
  203. cognee/tests/test_pgvector.py +3 -1
  204. cognee/tests/test_relational_db_migration.py +15 -1
  205. cognee/tests/test_remote_kuzu.py +3 -1
  206. cognee/tests/test_s3_file_storage.py +1 -1
  207. cognee/tests/test_search_db.py +97 -110
  208. cognee/tests/test_usage_logger_e2e.py +268 -0
  209. cognee/tests/unit/api/test_get_raw_data_endpoint.py +206 -0
  210. cognee/tests/unit/eval_framework/answer_generation_test.py +4 -3
  211. cognee/tests/unit/infrastructure/databases/cache/test_cache_config.py +2 -0
  212. cognee/tests/unit/modules/graph/cognee_graph_elements_test.py +42 -2
  213. cognee/tests/unit/modules/graph/cognee_graph_test.py +329 -31
  214. cognee/tests/unit/modules/retrieval/chunks_retriever_test.py +31 -59
  215. cognee/tests/unit/modules/retrieval/graph_completion_retriever_context_extension_test.py +70 -33
  216. cognee/tests/unit/modules/retrieval/graph_completion_retriever_cot_test.py +72 -52
  217. cognee/tests/unit/modules/retrieval/graph_completion_retriever_test.py +27 -33
  218. cognee/tests/unit/modules/retrieval/rag_completion_retriever_test.py +28 -15
  219. cognee/tests/unit/modules/retrieval/summaries_retriever_test.py +37 -42
  220. cognee/tests/unit/modules/retrieval/temporal_retriever_test.py +48 -64
  221. cognee/tests/unit/modules/retrieval/test_brute_force_triplet_search.py +263 -24
  222. cognee/tests/unit/modules/retrieval/test_node_edge_vector_search.py +273 -0
  223. cognee/tests/unit/modules/retrieval/triplet_retriever_test.py +30 -16
  224. cognee/tests/unit/modules/search/test_get_search_type_retriever_instance.py +125 -0
  225. cognee/tests/unit/modules/search/test_search.py +176 -0
  226. cognee/tests/unit/modules/search/test_search_prepare_search_result_contract.py +190 -0
  227. cognee/tests/unit/modules/users/test_tutorial_notebook_creation.py +511 -297
  228. cognee/tests/unit/shared/test_usage_logger.py +241 -0
  229. cognee/tests/unit/users/permissions/test_has_user_management_permission.py +46 -0
  230. {cognee-0.5.1.dev0.dist-info → cognee-0.5.2.dist-info}/METADATA +22 -17
  231. {cognee-0.5.1.dev0.dist-info → cognee-0.5.2.dist-info}/RECORD +235 -147
  232. cognee/api/.env.example +0 -5
  233. cognee/modules/retrieval/base_graph_retriever.py +0 -24
  234. cognee/modules/search/methods/get_search_type_tools.py +0 -223
  235. cognee/modules/search/methods/no_access_control_search.py +0 -62
  236. cognee/modules/search/utils/prepare_search_result.py +0 -63
  237. cognee/tests/test_feedback_enrichment.py +0 -174
  238. {cognee-0.5.1.dev0.dist-info → cognee-0.5.2.dist-info}/WHEEL +0 -0
  239. {cognee-0.5.1.dev0.dist-info → cognee-0.5.2.dist-info}/entry_points.txt +0 -0
  240. {cognee-0.5.1.dev0.dist-info → cognee-0.5.2.dist-info}/licenses/LICENSE +0 -0
  241. {cognee-0.5.1.dev0.dist-info → cognee-0.5.2.dist-info}/licenses/NOTICE.md +0 -0
@@ -0,0 +1,67 @@
1
+ from uuid import UUID
2
+ from typing import Optional, Any, List, Union
3
+ from pydantic import BaseModel, ConfigDict, field_serializer
4
+ from pydantic.alias_generators import to_camel
5
+ from cognee.modules.search.types.SearchType import SearchType
6
+
7
+
8
+ class SearchResultPayload(BaseModel):
9
+ """Result payload from retriever classes."""
10
+
11
+ model_config = ConfigDict(
12
+ arbitrary_types_allowed=True,
13
+ alias_generator=to_camel,
14
+ populate_by_name=True,
15
+ )
16
+
17
+ result_object: Any = None
18
+ context: Optional[Union[str, List[str]]] = None
19
+ completion: Optional[Union[str, List[str], List[dict]]] = None
20
+
21
+ # TODO: Add return_type info
22
+ search_type: SearchType
23
+ only_context: bool = False
24
+
25
+ dataset_name: Optional[str] = None
26
+ dataset_id: Optional[UUID] = None
27
+ dataset_tenant_id: Optional[UUID] = None
28
+
29
+ @field_serializer("result_object")
30
+ def serialize_complex_types(self, v: Any):
31
+ """
32
+ Custom serializer to handle complex types in result_object.
33
+ Transforms non-JSON-compatible types to their string representation.
34
+ """
35
+
36
+ # Helper to check if a value is a "simple" JSON-compatible type
37
+ def is_simple(item):
38
+ return isinstance(item, (int, float, dict, str, bool, type(None)))
39
+
40
+ if isinstance(v, list) and all(isinstance(item, dict) for item in v):
41
+ # Handle List of Dictionaries
42
+ return [
43
+ {key: (val if is_simple(val) else str(val)) for key, val in item.items()}
44
+ for item in v
45
+ ]
46
+ elif isinstance(v, list):
47
+ # Handle Lists
48
+ return [item if is_simple(item) else str(item) for item in v]
49
+ elif isinstance(v, dict):
50
+ # Handle Dictionaries
51
+ return {key: (val if is_simple(val) else str(val)) for key, val in v.items()}
52
+ else:
53
+ # Fallback for the object itself
54
+ return v if is_simple(v) else str(v)
55
+
56
+ @property
57
+ def result(self) -> Any:
58
+ """Function used to determine search_result for users request.
59
+ Return context if only_context is True, else return completion if it exists, else return result_object."""
60
+ if self.only_context:
61
+ return self.context
62
+ elif self.completion:
63
+ return self.completion
64
+ elif self.context:
65
+ return self.context
66
+ else:
67
+ return self.result_object
@@ -1,6 +1,6 @@
1
1
  from uuid import UUID
2
2
  from pydantic import BaseModel
3
- from typing import Any, Dict, List, Optional
3
+ from typing import Any, Optional
4
4
 
5
5
 
6
6
  class SearchResultDataset(BaseModel):
@@ -8,13 +8,6 @@ class SearchResultDataset(BaseModel):
8
8
  name: str
9
9
 
10
10
 
11
- class CombinedSearchResult(BaseModel):
12
- result: Optional[Any]
13
- context: Dict[str, Any]
14
- graphs: Optional[Dict[str, Any]] = {}
15
- datasets: Optional[List[SearchResultDataset]] = None
16
-
17
-
18
11
  class SearchResult(BaseModel):
19
12
  search_result: Any
20
13
  dataset_id: Optional[UUID]
@@ -1,7 +1,7 @@
1
1
  from enum import Enum
2
2
 
3
3
 
4
- class SearchType(Enum):
4
+ class SearchType(str, Enum):
5
5
  SUMMARIES = "SUMMARIES"
6
6
  CHUNKS = "CHUNKS"
7
7
  RAG_COMPLETION = "RAG_COMPLETION"
@@ -13,7 +13,6 @@ class SearchType(Enum):
13
13
  GRAPH_COMPLETION_COT = "GRAPH_COMPLETION_COT"
14
14
  GRAPH_COMPLETION_CONTEXT_EXTENSION = "GRAPH_COMPLETION_CONTEXT_EXTENSION"
15
15
  FEELING_LUCKY = "FEELING_LUCKY"
16
- FEEDBACK = "FEEDBACK"
17
16
  TEMPORAL = "TEMPORAL"
18
17
  CODING_RULES = "CODING_RULES"
19
18
  CHUNKS_LEXICAL = "CHUNKS_LEXICAL"
@@ -1,2 +1,2 @@
1
1
  from .SearchType import SearchType
2
- from .SearchResult import SearchResult, SearchResultDataset, CombinedSearchResult
2
+ from .SearchResult import SearchResult, SearchResultDataset
@@ -1,2 +1 @@
1
- from .prepare_search_result import prepare_search_result
2
- from .transform_context_to_graph import transform_context_to_graph
1
+ from .transform_triplets_to_graph import transform_triplets_to_graph
@@ -1,11 +1,11 @@
1
1
  from typing import Dict, List, Tuple
2
2
 
3
3
 
4
- def transform_insights_to_graph(context: List[Tuple[Dict, Dict, Dict]]):
4
+ def transform_insights_to_graph(input_triplets: List[Tuple[Dict, Dict, Dict]]):
5
5
  nodes = {}
6
6
  edges = {}
7
7
 
8
- for triplet in context:
8
+ for triplet in input_triplets:
9
9
  nodes[triplet[0]["id"]] = {
10
10
  "id": triplet[0]["id"],
11
11
  "label": triplet[0]["name"] if "name" in triplet[0] else triplet[0]["id"],
@@ -3,11 +3,11 @@ from typing import List
3
3
  from cognee.modules.graph.cognee_graph.CogneeGraphElements import Edge
4
4
 
5
5
 
6
- def transform_context_to_graph(context: List[Edge]):
6
+ def transform_triplets_to_graph(input_triplets: List[Edge]):
7
7
  nodes = {}
8
8
  edges = {}
9
9
 
10
- for triplet in context:
10
+ for triplet in input_triplets:
11
11
  nodes[triplet.node1.id] = {
12
12
  "id": triplet.node1.id,
13
13
  "label": triplet.node1.attributes["name"]
@@ -1,12 +1,22 @@
1
1
  import os
2
2
  from fastapi_users.authentication import CookieTransport
3
3
 
4
+ # Get cookie domain from environment variable
5
+ # If not set or empty, use None to allow cookie to work on any domain
6
+ cookie_domain = os.getenv("AUTH_TOKEN_COOKIE_DOMAIN")
7
+ if cookie_domain == "":
8
+ cookie_domain = None
9
+
10
+ # Note: Cookie expiration is automatically set by FastAPI Users based on JWT Strategy's lifetime_seconds
11
+ # The JWT Strategy lifetime_seconds is configured in get_client_auth_backend.py
12
+ # and reads from JWT_LIFETIME_SECONDS environment variable
13
+
4
14
  default_transport = CookieTransport(
5
15
  cookie_name=os.getenv("AUTH_TOKEN_COOKIE_NAME", "auth_token"),
6
16
  cookie_secure=False,
7
17
  cookie_httponly=True,
8
18
  cookie_samesite="Lax",
9
- cookie_domain="localhost",
19
+ cookie_domain=cookie_domain, # None allows cookie to work on any domain
10
20
  )
11
21
 
12
22
  default_transport.name = "cookie"
@@ -16,8 +16,9 @@ def get_api_auth_backend():
16
16
 
17
17
  def get_jwt_strategy() -> JWTStrategy[models.UP, models.ID]:
18
18
  secret = os.getenv("FASTAPI_USERS_JWT_SECRET", "super_secret")
19
+ lifetime_seconds = int(os.getenv("JWT_LIFETIME_SECONDS", "3600"))
19
20
 
20
- return APIJWTStrategy(secret, lifetime_seconds=36000)
21
+ return APIJWTStrategy(secret, lifetime_seconds=lifetime_seconds)
21
22
 
22
23
  auth_backend = AuthenticationBackend(
23
24
  name=transport.name,
@@ -18,8 +18,9 @@ def get_client_auth_backend():
18
18
  from .default.default_jwt_strategy import DefaultJWTStrategy
19
19
 
20
20
  secret = os.getenv("FASTAPI_USERS_JWT_SECRET", "super_secret")
21
+ lifetime_seconds = int(os.getenv("JWT_LIFETIME_SECONDS", "3600"))
21
22
 
22
- return DefaultJWTStrategy(secret, lifetime_seconds=3600)
23
+ return DefaultJWTStrategy(secret, lifetime_seconds=lifetime_seconds)
23
24
 
24
25
  auth_backend = AuthenticationBackend(
25
26
  name=transport.name,
@@ -1,18 +1,9 @@
1
- from uuid import UUID, uuid4
2
1
  from fastapi_users.exceptions import UserAlreadyExists
3
- from sqlalchemy.ext.asyncio import AsyncSession
4
2
 
5
3
  from cognee.infrastructure.databases.relational import get_relational_engine
6
- from cognee.modules.notebooks.models.Notebook import Notebook
7
- from cognee.modules.notebooks.methods.create_notebook import _create_tutorial_notebook
8
- from cognee.modules.users.exceptions import TenantNotFoundError
9
4
  from cognee.modules.users.get_user_manager import get_user_manager_context
10
5
  from cognee.modules.users.get_user_db import get_user_db_context
11
6
  from cognee.modules.users.models.User import UserCreate
12
- from cognee.modules.users.models.Tenant import Tenant
13
-
14
- from sqlalchemy import select
15
- from typing import Optional
16
7
 
17
8
 
18
9
  async def create_user(
@@ -0,0 +1,29 @@
1
+ from uuid import UUID
2
+
3
+ from cognee.modules.users.permissions.methods.get_tenant import get_tenant
4
+ from cognee.modules.users.exceptions import PermissionDeniedError
5
+
6
+
7
+ async def has_user_management_permission(requester_id: UUID, tenant_id: UUID) -> bool:
8
+ """
9
+ Check if requester is allowed to manage users for a tenant.
10
+ Args:
11
+ requester_id: Id of the user making the request
12
+ tenant_id: Id of the tenant
13
+
14
+ Returns:
15
+ True if requester has permission
16
+
17
+ Raises:
18
+ PermissionDeniedError: If requester is not authorized.
19
+ TenantNotFoundError: If the tenant does not exist.
20
+ """
21
+ tenant = await get_tenant(tenant_id)
22
+
23
+ # TODO: extend to support admin roles
24
+ if tenant.owner_id != requester_id:
25
+ raise PermissionDeniedError(
26
+ message="User is not authorized to manage users for this tenant"
27
+ )
28
+
29
+ return True
@@ -92,7 +92,7 @@ async def cognee_network_visualization(graph_data, destination_file_path: str =
92
92
  }
93
93
  links_list.append(link_data)
94
94
 
95
- html_template = """
95
+ html_template = r"""
96
96
  <!DOCTYPE html>
97
97
  <html>
98
98
  <head>
@@ -0,0 +1,48 @@
1
+ import os
2
+ import sys
3
+ import subprocess
4
+ from pathlib import Path
5
+ import importlib.resources as pkg_resources
6
+
7
+ # Assuming your package is named 'cognee' and the migrations are under 'cognee/alembic'
8
+ # This is a placeholder for the path logic.
9
+ MIGRATIONS_PACKAGE = "cognee"
10
+ MIGRATIONS_DIR_NAME = "alembic"
11
+
12
+
13
+ async def run_migrations():
14
+ """
15
+ Finds the Alembic configuration within the installed package and
16
+ programmatically executes 'alembic upgrade head'.
17
+ """
18
+ # 1. Locate the base path of the installed package.
19
+ # This reliably finds the root directory of the installed 'cognee' package.
20
+ # We look for the parent of the 'migrations' directory.
21
+ package_root = str(pkg_resources.files(MIGRATIONS_PACKAGE))
22
+
23
+ # 2. Define the paths for config and scripts
24
+ alembic_ini_path = os.path.join(package_root, "alembic.ini")
25
+ script_location_path = os.path.join(package_root, MIGRATIONS_DIR_NAME)
26
+
27
+ if not os.path.exists(alembic_ini_path):
28
+ raise FileNotFoundError(
29
+ f"Error: alembic.ini not found at expected locations for package '{MIGRATIONS_PACKAGE}'."
30
+ )
31
+ if not os.path.exists(script_location_path):
32
+ raise FileNotFoundError(
33
+ f"Error: Migrations directory not found at expected locations for package '{MIGRATIONS_PACKAGE}'."
34
+ )
35
+
36
+ migration_result = subprocess.run(
37
+ ["python", "-m", "alembic", "upgrade", "head"],
38
+ capture_output=True,
39
+ text=True,
40
+ cwd=Path(package_root),
41
+ )
42
+
43
+ if migration_result.returncode != 0:
44
+ migration_output = migration_result.stderr + migration_result.stdout
45
+ print(f"Migration failed with unexpected error: {migration_output}")
46
+ sys.exit(1)
47
+
48
+ print("Migration completed successfully.")
@@ -4,6 +4,4 @@ Custom exceptions for the Cognee API.
4
4
  This module defines a set of exceptions for handling various shared utility errors
5
5
  """
6
6
 
7
- from .exceptions import (
8
- IngestionError,
9
- )
7
+ from .exceptions import IngestionError, UsageLoggerError
@@ -1,4 +1,4 @@
1
- from cognee.exceptions import CogneeValidationError
1
+ from cognee.exceptions import CogneeConfigurationError, CogneeValidationError
2
2
  from fastapi import status
3
3
 
4
4
 
@@ -10,3 +10,13 @@ class IngestionError(CogneeValidationError):
10
10
  status_code=status.HTTP_422_UNPROCESSABLE_CONTENT,
11
11
  ):
12
12
  super().__init__(message, name, status_code)
13
+
14
+
15
+ class UsageLoggerError(CogneeConfigurationError):
16
+ def __init__(
17
+ self,
18
+ message: str = "Usage logging configuration is invalid.",
19
+ name: str = "UsageLoggerError",
20
+ status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
21
+ ):
22
+ super().__init__(message, name, status_code)
@@ -0,0 +1,332 @@
1
+ import asyncio
2
+ import inspect
3
+ import os
4
+ from datetime import datetime, timezone
5
+ from functools import singledispatch, wraps
6
+ from typing import Any, Callable, Optional
7
+ from uuid import UUID
8
+
9
+ from cognee.infrastructure.databases.cache.config import get_cache_config
10
+ from cognee.infrastructure.databases.cache.get_cache_engine import get_cache_engine
11
+ from cognee.shared.exceptions import UsageLoggerError
12
+ from cognee.shared.logging_utils import get_logger
13
+ from cognee import __version__ as cognee_version
14
+
15
+ logger = get_logger("usage_logger")
16
+
17
+
18
+ @singledispatch
19
+ def _sanitize_value(value: Any) -> Any:
20
+ """Default handler for JSON serialization - converts to string."""
21
+ try:
22
+ str_repr = str(value)
23
+ if str_repr.startswith("<") and str_repr.endswith(">"):
24
+ return f"<cannot be serialized: {type(value).__name__}>"
25
+ return str_repr
26
+ except Exception:
27
+ return f"<cannot be serialized: {type(value).__name__}>"
28
+
29
+
30
+ @_sanitize_value.register(type(None))
31
+ def _(value: None) -> None:
32
+ """Handle None values - returns None as-is."""
33
+ return None
34
+
35
+
36
+ @_sanitize_value.register(str)
37
+ @_sanitize_value.register(int)
38
+ @_sanitize_value.register(float)
39
+ @_sanitize_value.register(bool)
40
+ def _(value: str | int | float | bool) -> str | int | float | bool:
41
+ """Handle primitive types - returns value as-is since they're JSON-serializable."""
42
+ return value
43
+
44
+
45
+ @_sanitize_value.register(UUID)
46
+ def _(value: UUID) -> str:
47
+ """Convert UUID to string representation."""
48
+ return str(value)
49
+
50
+
51
+ @_sanitize_value.register(datetime)
52
+ def _(value: datetime) -> str:
53
+ """Convert datetime to ISO format string."""
54
+ return value.isoformat()
55
+
56
+
57
+ @_sanitize_value.register(list)
58
+ @_sanitize_value.register(tuple)
59
+ def _(value: list | tuple) -> list:
60
+ """Recursively sanitize list or tuple elements."""
61
+ return [_sanitize_value(v) for v in value]
62
+
63
+
64
+ @_sanitize_value.register(dict)
65
+ def _(value: dict) -> dict:
66
+ """Recursively sanitize dictionary keys and values."""
67
+ sanitized = {}
68
+ for k, v in value.items():
69
+ key_str = k if isinstance(k, str) else _sanitize_dict_key(k)
70
+ sanitized[key_str] = _sanitize_value(v)
71
+ return sanitized
72
+
73
+
74
+ def _sanitize_dict_key(key: Any) -> str:
75
+ """Convert a non-string dict key to a string."""
76
+ sanitized_key = _sanitize_value(key)
77
+ if isinstance(sanitized_key, str):
78
+ if sanitized_key.startswith("<cannot be serialized"):
79
+ return f"<key:{type(key).__name__}>"
80
+ return sanitized_key
81
+ return str(sanitized_key)
82
+
83
+
84
+ def _get_param_names(func: Callable) -> list[str]:
85
+ """Get parameter names from function signature."""
86
+ try:
87
+ return list(inspect.signature(func).parameters.keys())
88
+ except Exception:
89
+ return []
90
+
91
+
92
+ def _get_param_defaults(func: Callable) -> dict[str, Any]:
93
+ """Get parameter defaults from function signature."""
94
+ try:
95
+ sig = inspect.signature(func)
96
+ defaults = {}
97
+ for param_name, param in sig.parameters.items():
98
+ if param.default != inspect.Parameter.empty:
99
+ defaults[param_name] = param.default
100
+ return defaults
101
+ except Exception:
102
+ return {}
103
+
104
+
105
+ def _extract_user_id(args: tuple, kwargs: dict, param_names: list[str]) -> Optional[str]:
106
+ """Extract user_id from function arguments if available."""
107
+ try:
108
+ if "user" in kwargs and kwargs["user"] is not None:
109
+ user = kwargs["user"]
110
+ if hasattr(user, "id"):
111
+ return str(user.id)
112
+
113
+ for i, param_name in enumerate(param_names):
114
+ if i < len(args) and param_name == "user":
115
+ user = args[i]
116
+ if user is not None and hasattr(user, "id"):
117
+ return str(user.id)
118
+ return None
119
+ except Exception:
120
+ return None
121
+
122
+
123
+ def _extract_parameters(args: tuple, kwargs: dict, param_names: list[str], func: Callable) -> dict:
124
+ """Extract function parameters - captures all parameters including defaults, sanitizes for JSON."""
125
+ params = {}
126
+
127
+ for key, value in kwargs.items():
128
+ if key != "user":
129
+ params[key] = _sanitize_value(value)
130
+
131
+ if param_names:
132
+ for i, param_name in enumerate(param_names):
133
+ if i < len(args) and param_name != "user" and param_name not in kwargs:
134
+ params[param_name] = _sanitize_value(args[i])
135
+ else:
136
+ for i, arg_value in enumerate(args):
137
+ params[f"arg_{i}"] = _sanitize_value(arg_value)
138
+
139
+ if param_names:
140
+ defaults = _get_param_defaults(func)
141
+ for param_name in param_names:
142
+ if param_name != "user" and param_name not in params and param_name in defaults:
143
+ params[param_name] = _sanitize_value(defaults[param_name])
144
+
145
+ return params
146
+
147
+
148
+ async def _log_usage_async(
149
+ function_name: str,
150
+ log_type: str,
151
+ user_id: Optional[str],
152
+ parameters: dict,
153
+ result: Any,
154
+ success: bool,
155
+ error: Optional[str],
156
+ duration_ms: float,
157
+ start_time: datetime,
158
+ end_time: datetime,
159
+ ):
160
+ """Asynchronously log function usage to Redis.
161
+
162
+ Args:
163
+ function_name: Name of the function being logged.
164
+ log_type: Type of log entry (e.g., "api_endpoint", "mcp_tool", "function").
165
+ user_id: User identifier, or None to use "unknown".
166
+ parameters: Dictionary of function parameters (sanitized).
167
+ result: Function return value (will be sanitized).
168
+ success: Whether the function executed successfully.
169
+ error: Error message if function failed, None otherwise.
170
+ duration_ms: Execution duration in milliseconds.
171
+ start_time: Function start timestamp.
172
+ end_time: Function end timestamp.
173
+
174
+ Note:
175
+ This function silently handles errors to avoid disrupting the original
176
+ function execution. Logs are written to Redis with TTL from config.
177
+ """
178
+ try:
179
+ logger.debug(f"Starting to log usage for {function_name} at {start_time.isoformat()}")
180
+ config = get_cache_config()
181
+ if not config.usage_logging:
182
+ logger.debug("Usage logging disabled, skipping log")
183
+ return
184
+
185
+ logger.debug(f"Getting cache engine for {function_name}")
186
+ cache_engine = get_cache_engine()
187
+ if cache_engine is None:
188
+ logger.warning(
189
+ f"Cache engine not available for usage logging (function: {function_name})"
190
+ )
191
+ return
192
+
193
+ logger.debug(f"Cache engine obtained for {function_name}")
194
+
195
+ if user_id is None:
196
+ user_id = "unknown"
197
+ logger.debug(f"No user_id provided, using 'unknown' for {function_name}")
198
+
199
+ log_entry = {
200
+ "timestamp": start_time.isoformat(),
201
+ "type": log_type,
202
+ "function_name": function_name,
203
+ "user_id": user_id,
204
+ "parameters": parameters,
205
+ "result": _sanitize_value(result),
206
+ "success": success,
207
+ "error": error,
208
+ "duration_ms": round(duration_ms, 2),
209
+ "start_time": start_time.isoformat(),
210
+ "end_time": end_time.isoformat(),
211
+ "metadata": {
212
+ "cognee_version": cognee_version,
213
+ "environment": os.getenv("ENV", "prod"),
214
+ },
215
+ }
216
+
217
+ logger.debug(f"Calling log_usage for {function_name}, user_id={user_id}")
218
+ await cache_engine.log_usage(
219
+ user_id=user_id,
220
+ log_entry=log_entry,
221
+ ttl=config.usage_logging_ttl,
222
+ )
223
+ logger.info(f"Successfully logged usage for {function_name} (user_id={user_id})")
224
+ except Exception as e:
225
+ logger.error(f"Failed to log usage for {function_name}: {str(e)}", exc_info=True)
226
+
227
+
228
+ def log_usage(function_name: Optional[str] = None, log_type: str = "function"):
229
+ """
230
+ Decorator to log function usage to Redis.
231
+
232
+ This decorator is completely transparent - it doesn't change function behavior.
233
+ It logs function name, parameters, result, timing, and user (if available).
234
+
235
+ Args:
236
+ function_name: Optional name for the function (defaults to func.__name__)
237
+ log_type: Type of log entry (e.g., "api_endpoint", "mcp_tool")
238
+
239
+ Usage:
240
+ @log_usage(function_name="MCP my_mcp_tool", log_type="mcp_tool")
241
+ async def my_mcp_tool(...):
242
+ # mcp code
243
+
244
+ @log_usage(function_name="POST API /v1/add", log_type="api_endpoint")
245
+ async def add(...):
246
+ # endpoint code
247
+ """
248
+
249
+ def decorator(func: Callable) -> Callable:
250
+ """Inner decorator that wraps the function with usage logging.
251
+
252
+ Args:
253
+ func: The async function to wrap with usage logging.
254
+
255
+ Returns:
256
+ Callable: The wrapped function with usage logging enabled.
257
+
258
+ Raises:
259
+ UsageLoggerError: If the function is not async.
260
+ """
261
+ if not inspect.iscoroutinefunction(func):
262
+ raise UsageLoggerError(
263
+ f"@log_usage requires an async function. Got {func.__name__} which is not async."
264
+ )
265
+
266
+ @wraps(func)
267
+ async def async_wrapper(*args, **kwargs):
268
+ """Wrapper function that executes the original function and logs usage.
269
+
270
+ This wrapper:
271
+ - Extracts user ID and parameters from function arguments
272
+ - Executes the original function
273
+ - Captures result, success status, and any errors
274
+ - Logs usage information asynchronously without blocking
275
+
276
+ Args:
277
+ *args: Positional arguments passed to the original function.
278
+ **kwargs: Keyword arguments passed to the original function.
279
+
280
+ Returns:
281
+ Any: The return value of the original function.
282
+
283
+ Raises:
284
+ Any exception raised by the original function (re-raised after logging).
285
+ """
286
+ config = get_cache_config()
287
+ if not config.usage_logging:
288
+ return await func(*args, **kwargs)
289
+
290
+ start_time = datetime.now(timezone.utc)
291
+
292
+ param_names = _get_param_names(func)
293
+ user_id = _extract_user_id(args, kwargs, param_names)
294
+ parameters = _extract_parameters(args, kwargs, param_names, func)
295
+
296
+ result = None
297
+ success = True
298
+ error = None
299
+
300
+ try:
301
+ result = await func(*args, **kwargs)
302
+ return result
303
+ except Exception as e:
304
+ success = False
305
+ error = str(e)
306
+ raise
307
+ finally:
308
+ end_time = datetime.now(timezone.utc)
309
+ duration_ms = (end_time - start_time).total_seconds() * 1000
310
+
311
+ try:
312
+ await _log_usage_async(
313
+ function_name=function_name or func.__name__,
314
+ log_type=log_type,
315
+ user_id=user_id,
316
+ parameters=parameters,
317
+ result=result,
318
+ success=success,
319
+ error=error,
320
+ duration_ms=duration_ms,
321
+ start_time=start_time,
322
+ end_time=end_time,
323
+ )
324
+ except Exception as e:
325
+ logger.error(
326
+ f"Failed to log usage for {function_name or func.__name__}: {str(e)}",
327
+ exc_info=True,
328
+ )
329
+
330
+ return async_wrapper
331
+
332
+ return decorator