cognee 0.3.5__py3-none-any.whl → 0.3.7__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 (161) hide show
  1. cognee/__init__.py +1 -0
  2. cognee/api/health.py +2 -12
  3. cognee/api/v1/add/add.py +46 -6
  4. cognee/api/v1/add/routers/get_add_router.py +5 -1
  5. cognee/api/v1/cognify/cognify.py +29 -9
  6. cognee/api/v1/datasets/datasets.py +11 -0
  7. cognee/api/v1/responses/default_tools.py +0 -1
  8. cognee/api/v1/responses/dispatch_function.py +1 -1
  9. cognee/api/v1/responses/routers/default_tools.py +0 -1
  10. cognee/api/v1/search/search.py +11 -9
  11. cognee/api/v1/settings/routers/get_settings_router.py +7 -1
  12. cognee/api/v1/ui/ui.py +47 -16
  13. cognee/api/v1/update/routers/get_update_router.py +1 -1
  14. cognee/api/v1/update/update.py +3 -3
  15. cognee/cli/_cognee.py +61 -10
  16. cognee/cli/commands/add_command.py +3 -3
  17. cognee/cli/commands/cognify_command.py +3 -3
  18. cognee/cli/commands/config_command.py +9 -7
  19. cognee/cli/commands/delete_command.py +3 -3
  20. cognee/cli/commands/search_command.py +3 -7
  21. cognee/cli/config.py +0 -1
  22. cognee/context_global_variables.py +5 -0
  23. cognee/exceptions/exceptions.py +1 -1
  24. cognee/infrastructure/databases/cache/__init__.py +2 -0
  25. cognee/infrastructure/databases/cache/cache_db_interface.py +79 -0
  26. cognee/infrastructure/databases/cache/config.py +44 -0
  27. cognee/infrastructure/databases/cache/get_cache_engine.py +67 -0
  28. cognee/infrastructure/databases/cache/redis/RedisAdapter.py +243 -0
  29. cognee/infrastructure/databases/exceptions/__init__.py +1 -0
  30. cognee/infrastructure/databases/exceptions/exceptions.py +18 -2
  31. cognee/infrastructure/databases/graph/get_graph_engine.py +1 -1
  32. cognee/infrastructure/databases/graph/graph_db_interface.py +5 -0
  33. cognee/infrastructure/databases/graph/kuzu/adapter.py +67 -44
  34. cognee/infrastructure/databases/graph/neo4j_driver/adapter.py +13 -3
  35. cognee/infrastructure/databases/graph/neo4j_driver/deadlock_retry.py +1 -1
  36. cognee/infrastructure/databases/graph/neptune_driver/neptune_utils.py +1 -1
  37. cognee/infrastructure/databases/relational/sqlalchemy/SqlAlchemyAdapter.py +1 -1
  38. cognee/infrastructure/databases/vector/embeddings/FastembedEmbeddingEngine.py +21 -3
  39. cognee/infrastructure/databases/vector/embeddings/LiteLLMEmbeddingEngine.py +17 -10
  40. cognee/infrastructure/databases/vector/embeddings/OllamaEmbeddingEngine.py +17 -4
  41. cognee/infrastructure/databases/vector/embeddings/config.py +2 -3
  42. cognee/infrastructure/databases/vector/exceptions/exceptions.py +1 -1
  43. cognee/infrastructure/databases/vector/lancedb/LanceDBAdapter.py +0 -1
  44. cognee/infrastructure/files/exceptions.py +1 -1
  45. cognee/infrastructure/files/storage/LocalFileStorage.py +9 -9
  46. cognee/infrastructure/files/storage/S3FileStorage.py +11 -11
  47. cognee/infrastructure/files/utils/guess_file_type.py +6 -0
  48. cognee/infrastructure/llm/prompts/search_type_selector_prompt.txt +0 -5
  49. cognee/infrastructure/llm/structured_output_framework/litellm_instructor/llm/anthropic/adapter.py +19 -9
  50. cognee/infrastructure/llm/structured_output_framework/litellm_instructor/llm/gemini/adapter.py +17 -5
  51. cognee/infrastructure/llm/structured_output_framework/litellm_instructor/llm/generic_llm_api/adapter.py +17 -5
  52. cognee/infrastructure/llm/structured_output_framework/litellm_instructor/llm/get_llm_client.py +32 -0
  53. cognee/infrastructure/llm/structured_output_framework/litellm_instructor/llm/mistral/__init__.py +0 -0
  54. cognee/infrastructure/llm/structured_output_framework/litellm_instructor/llm/mistral/adapter.py +109 -0
  55. cognee/infrastructure/llm/structured_output_framework/litellm_instructor/llm/ollama/adapter.py +33 -8
  56. cognee/infrastructure/llm/structured_output_framework/litellm_instructor/llm/openai/adapter.py +40 -18
  57. cognee/infrastructure/loaders/LoaderEngine.py +27 -7
  58. cognee/infrastructure/loaders/external/__init__.py +7 -0
  59. cognee/infrastructure/loaders/external/advanced_pdf_loader.py +2 -8
  60. cognee/infrastructure/loaders/external/beautiful_soup_loader.py +310 -0
  61. cognee/infrastructure/loaders/supported_loaders.py +7 -0
  62. cognee/modules/data/exceptions/exceptions.py +1 -1
  63. cognee/modules/data/methods/__init__.py +3 -0
  64. cognee/modules/data/methods/get_dataset_data.py +4 -1
  65. cognee/modules/data/methods/has_dataset_data.py +21 -0
  66. cognee/modules/engine/models/TableRow.py +0 -1
  67. cognee/modules/ingestion/save_data_to_file.py +9 -2
  68. cognee/modules/pipelines/exceptions/exceptions.py +1 -1
  69. cognee/modules/pipelines/operations/pipeline.py +12 -1
  70. cognee/modules/pipelines/operations/run_tasks.py +25 -197
  71. cognee/modules/pipelines/operations/run_tasks_data_item.py +260 -0
  72. cognee/modules/pipelines/operations/run_tasks_distributed.py +121 -38
  73. cognee/modules/retrieval/EntityCompletionRetriever.py +48 -8
  74. cognee/modules/retrieval/base_graph_retriever.py +3 -1
  75. cognee/modules/retrieval/base_retriever.py +3 -1
  76. cognee/modules/retrieval/chunks_retriever.py +5 -1
  77. cognee/modules/retrieval/code_retriever.py +20 -2
  78. cognee/modules/retrieval/completion_retriever.py +50 -9
  79. cognee/modules/retrieval/cypher_search_retriever.py +11 -1
  80. cognee/modules/retrieval/graph_completion_context_extension_retriever.py +47 -8
  81. cognee/modules/retrieval/graph_completion_cot_retriever.py +32 -1
  82. cognee/modules/retrieval/graph_completion_retriever.py +54 -10
  83. cognee/modules/retrieval/lexical_retriever.py +20 -2
  84. cognee/modules/retrieval/natural_language_retriever.py +10 -1
  85. cognee/modules/retrieval/summaries_retriever.py +5 -1
  86. cognee/modules/retrieval/temporal_retriever.py +62 -10
  87. cognee/modules/retrieval/user_qa_feedback.py +3 -2
  88. cognee/modules/retrieval/utils/completion.py +5 -0
  89. cognee/modules/retrieval/utils/description_to_codepart_search.py +1 -1
  90. cognee/modules/retrieval/utils/session_cache.py +156 -0
  91. cognee/modules/search/methods/get_search_type_tools.py +0 -5
  92. cognee/modules/search/methods/no_access_control_search.py +12 -1
  93. cognee/modules/search/methods/search.py +34 -2
  94. cognee/modules/search/types/SearchType.py +0 -1
  95. cognee/modules/settings/get_settings.py +23 -0
  96. cognee/modules/users/methods/get_authenticated_user.py +3 -1
  97. cognee/modules/users/methods/get_default_user.py +1 -6
  98. cognee/modules/users/roles/methods/create_role.py +2 -2
  99. cognee/modules/users/tenants/methods/create_tenant.py +2 -2
  100. cognee/shared/exceptions/exceptions.py +1 -1
  101. cognee/tasks/codingagents/coding_rule_associations.py +1 -2
  102. cognee/tasks/documents/exceptions/exceptions.py +1 -1
  103. cognee/tasks/graph/extract_graph_from_data.py +2 -0
  104. cognee/tasks/ingestion/data_item_to_text_file.py +3 -3
  105. cognee/tasks/ingestion/ingest_data.py +11 -5
  106. cognee/tasks/ingestion/save_data_item_to_storage.py +12 -1
  107. cognee/tasks/storage/add_data_points.py +3 -10
  108. cognee/tasks/storage/index_data_points.py +19 -14
  109. cognee/tasks/storage/index_graph_edges.py +25 -11
  110. cognee/tasks/web_scraper/__init__.py +34 -0
  111. cognee/tasks/web_scraper/config.py +26 -0
  112. cognee/tasks/web_scraper/default_url_crawler.py +446 -0
  113. cognee/tasks/web_scraper/models.py +46 -0
  114. cognee/tasks/web_scraper/types.py +4 -0
  115. cognee/tasks/web_scraper/utils.py +142 -0
  116. cognee/tasks/web_scraper/web_scraper_task.py +396 -0
  117. cognee/tests/cli_tests/cli_unit_tests/test_cli_utils.py +0 -1
  118. cognee/tests/integration/web_url_crawler/test_default_url_crawler.py +13 -0
  119. cognee/tests/integration/web_url_crawler/test_tavily_crawler.py +19 -0
  120. cognee/tests/integration/web_url_crawler/test_url_adding_e2e.py +344 -0
  121. cognee/tests/subprocesses/reader.py +25 -0
  122. cognee/tests/subprocesses/simple_cognify_1.py +31 -0
  123. cognee/tests/subprocesses/simple_cognify_2.py +31 -0
  124. cognee/tests/subprocesses/writer.py +32 -0
  125. cognee/tests/tasks/descriptive_metrics/metrics_test_utils.py +0 -2
  126. cognee/tests/tasks/descriptive_metrics/neo4j_metrics_test.py +8 -3
  127. cognee/tests/tasks/entity_extraction/entity_extraction_test.py +89 -0
  128. cognee/tests/tasks/web_scraping/web_scraping_test.py +172 -0
  129. cognee/tests/test_add_docling_document.py +56 -0
  130. cognee/tests/test_chromadb.py +7 -11
  131. cognee/tests/test_concurrent_subprocess_access.py +76 -0
  132. cognee/tests/test_conversation_history.py +240 -0
  133. cognee/tests/test_kuzu.py +27 -15
  134. cognee/tests/test_lancedb.py +7 -11
  135. cognee/tests/test_library.py +32 -2
  136. cognee/tests/test_neo4j.py +24 -16
  137. cognee/tests/test_neptune_analytics_vector.py +7 -11
  138. cognee/tests/test_permissions.py +9 -13
  139. cognee/tests/test_pgvector.py +4 -4
  140. cognee/tests/test_remote_kuzu.py +8 -11
  141. cognee/tests/test_s3_file_storage.py +1 -1
  142. cognee/tests/test_search_db.py +6 -8
  143. cognee/tests/unit/infrastructure/databases/cache/test_cache_config.py +89 -0
  144. cognee/tests/unit/modules/retrieval/conversation_history_test.py +154 -0
  145. {cognee-0.3.5.dist-info → cognee-0.3.7.dist-info}/METADATA +22 -7
  146. {cognee-0.3.5.dist-info → cognee-0.3.7.dist-info}/RECORD +155 -128
  147. {cognee-0.3.5.dist-info → cognee-0.3.7.dist-info}/entry_points.txt +1 -0
  148. distributed/Dockerfile +0 -3
  149. distributed/entrypoint.py +21 -9
  150. distributed/signal.py +5 -0
  151. distributed/workers/data_point_saving_worker.py +64 -34
  152. distributed/workers/graph_saving_worker.py +71 -47
  153. cognee/infrastructure/databases/graph/memgraph/memgraph_adapter.py +0 -1116
  154. cognee/modules/retrieval/insights_retriever.py +0 -133
  155. cognee/tests/test_memgraph.py +0 -109
  156. cognee/tests/unit/modules/retrieval/insights_retriever_test.py +0 -251
  157. distributed/poetry.lock +0 -12238
  158. distributed/pyproject.toml +0 -185
  159. {cognee-0.3.5.dist-info → cognee-0.3.7.dist-info}/WHEEL +0 -0
  160. {cognee-0.3.5.dist-info → cognee-0.3.7.dist-info}/licenses/LICENSE +0 -0
  161. {cognee-0.3.5.dist-info → cognee-0.3.7.dist-info}/licenses/NOTICE.md +0 -0
@@ -1,20 +1,26 @@
1
+ import asyncio
1
2
  from typing import Any, Optional, Type, List
2
3
  from uuid import NAMESPACE_OID, uuid5
3
4
 
4
5
  from cognee.infrastructure.engine import DataPoint
5
6
  from cognee.modules.graph.cognee_graph.CogneeGraphElements import Edge
6
- from cognee.modules.users.methods import get_default_user
7
7
  from cognee.tasks.storage import add_data_points
8
8
  from cognee.modules.graph.utils import resolve_edges_to_text
9
9
  from cognee.modules.graph.utils.convert_node_to_data_point import get_all_subclasses
10
10
  from cognee.modules.retrieval.base_graph_retriever import BaseGraphRetriever
11
11
  from cognee.modules.retrieval.utils.brute_force_triplet_search import brute_force_triplet_search
12
- from cognee.modules.retrieval.utils.completion import generate_completion
12
+ from cognee.modules.retrieval.utils.completion import generate_completion, summarize_text
13
+ from cognee.modules.retrieval.utils.session_cache import (
14
+ save_conversation_history,
15
+ get_conversation_history,
16
+ )
13
17
  from cognee.shared.logging_utils import get_logger
14
18
  from cognee.modules.retrieval.utils.extract_uuid_from_node import extract_uuid_from_node
15
19
  from cognee.modules.retrieval.utils.models import CogneeUserInteraction
16
20
  from cognee.modules.engine.models.node_set import NodeSet
17
21
  from cognee.infrastructure.databases.graph import get_graph_engine
22
+ from cognee.context_global_variables import session_user
23
+ from cognee.infrastructure.databases.cache.config import CacheConfig
18
24
 
19
25
  logger = get_logger("GraphCompletionRetriever")
20
26
 
@@ -118,6 +124,13 @@ class GraphCompletionRetriever(BaseGraphRetriever):
118
124
  - str: A string representing the resolved context from the retrieved triplets, or an
119
125
  empty string if no triplets are found.
120
126
  """
127
+ graph_engine = await get_graph_engine()
128
+ is_empty = await graph_engine.is_empty()
129
+
130
+ if is_empty:
131
+ logger.warning("Search attempt on an empty knowledge graph")
132
+ return []
133
+
121
134
  triplets = await self.get_triplets(query)
122
135
 
123
136
  if len(triplets) == 0:
@@ -132,6 +145,7 @@ class GraphCompletionRetriever(BaseGraphRetriever):
132
145
  self,
133
146
  query: str,
134
147
  context: Optional[List[Edge]] = None,
148
+ session_id: Optional[str] = None,
135
149
  ) -> List[str]:
136
150
  """
137
151
  Generates a completion using graph connections context based on a query.
@@ -142,6 +156,8 @@ class GraphCompletionRetriever(BaseGraphRetriever):
142
156
  - query (str): The query string for which a completion is generated.
143
157
  - context (Optional[Any]): Optional context to use for generating the completion; if
144
158
  not provided, context is retrieved based on the query. (default None)
159
+ - session_id (Optional[str]): Optional session identifier for caching. If None,
160
+ defaults to 'default_session'. (default None)
145
161
 
146
162
  Returns:
147
163
  --------
@@ -155,19 +171,47 @@ class GraphCompletionRetriever(BaseGraphRetriever):
155
171
 
156
172
  context_text = await resolve_edges_to_text(triplets)
157
173
 
158
- completion = await generate_completion(
159
- query=query,
160
- context=context_text,
161
- user_prompt_path=self.user_prompt_path,
162
- system_prompt_path=self.system_prompt_path,
163
- system_prompt=self.system_prompt,
164
- )
174
+ cache_config = CacheConfig()
175
+ user = session_user.get()
176
+ user_id = getattr(user, "id", None)
177
+ session_save = user_id and cache_config.caching
178
+
179
+ if session_save:
180
+ conversation_history = await get_conversation_history(session_id=session_id)
181
+
182
+ context_summary, completion = await asyncio.gather(
183
+ summarize_text(context_text),
184
+ generate_completion(
185
+ query=query,
186
+ context=context_text,
187
+ user_prompt_path=self.user_prompt_path,
188
+ system_prompt_path=self.system_prompt_path,
189
+ system_prompt=self.system_prompt,
190
+ conversation_history=conversation_history,
191
+ ),
192
+ )
193
+ else:
194
+ completion = await generate_completion(
195
+ query=query,
196
+ context=context_text,
197
+ user_prompt_path=self.user_prompt_path,
198
+ system_prompt_path=self.system_prompt_path,
199
+ system_prompt=self.system_prompt,
200
+ )
165
201
 
166
202
  if self.save_interaction and context and triplets and completion:
167
203
  await self.save_qa(
168
204
  question=query, answer=completion, context=context_text, triplets=triplets
169
205
  )
170
206
 
207
+ if session_save:
208
+ await save_conversation_history(
209
+ query=query,
210
+ context_summary=context_summary,
211
+ answer=completion,
212
+ session_id=session_id,
213
+ )
214
+
171
215
  return [completion]
172
216
 
173
217
  async def save_qa(self, question: str, answer: str, context: str, triplets: List) -> None:
@@ -194,7 +238,7 @@ class GraphCompletionRetriever(BaseGraphRetriever):
194
238
  belongs_to_set=interactions_node_set,
195
239
  )
196
240
 
197
- await add_data_points(data_points=[cognee_user_interaction], update_edge_collection=False)
241
+ await add_data_points(data_points=[cognee_user_interaction])
198
242
 
199
243
  relationships = []
200
244
  relationship_name = "used_graph_element_to_answer"
@@ -116,8 +116,26 @@ class LexicalRetriever(BaseRetriever):
116
116
  else:
117
117
  return [self.payloads[chunk_id] for chunk_id, _ in top_results]
118
118
 
119
- async def get_completion(self, query: str, context: Optional[Any] = None) -> Any:
120
- """Returns context for the given query (retrieves if not provided)."""
119
+ async def get_completion(
120
+ self, query: str, context: Optional[Any] = None, session_id: Optional[str] = None
121
+ ) -> Any:
122
+ """
123
+ Returns context for the given query (retrieves if not provided).
124
+
125
+ Parameters:
126
+ -----------
127
+
128
+ - query (str): The query string to retrieve context for.
129
+ - context (Optional[Any]): Optional pre-fetched context; if None, it retrieves
130
+ the context for the query. (default None)
131
+ - session_id (Optional[str]): Optional session identifier for caching. If None,
132
+ defaults to 'default_session'. (default None)
133
+
134
+ Returns:
135
+ --------
136
+
137
+ - Any: The context, either provided or retrieved.
138
+ """
121
139
  if context is None:
122
140
  context = await self.get_context(query)
123
141
  return context
@@ -122,10 +122,17 @@ class NaturalLanguageRetriever(BaseRetriever):
122
122
  query.
123
123
  """
124
124
  graph_engine = await get_graph_engine()
125
+ is_empty = await graph_engine.is_empty()
126
+
127
+ if is_empty:
128
+ logger.warning("Search attempt on an empty knowledge graph")
129
+ return []
125
130
 
126
131
  return await self._execute_cypher_query(query, graph_engine)
127
132
 
128
- async def get_completion(self, query: str, context: Optional[Any] = None) -> Any:
133
+ async def get_completion(
134
+ self, query: str, context: Optional[Any] = None, session_id: Optional[str] = None
135
+ ) -> Any:
129
136
  """
130
137
  Returns a completion based on the query and context.
131
138
 
@@ -139,6 +146,8 @@ class NaturalLanguageRetriever(BaseRetriever):
139
146
  - query (str): The natural language query to get a completion from.
140
147
  - context (Optional[Any]): The context in which to base the completion; if not
141
148
  provided, it will be retrieved using the query. (default None)
149
+ - session_id (Optional[str]): Optional session identifier for caching. If None,
150
+ defaults to 'default_session'. (default None)
142
151
 
143
152
  Returns:
144
153
  --------
@@ -62,7 +62,9 @@ class SummariesRetriever(BaseRetriever):
62
62
  logger.info(f"Returning {len(summary_payloads)} summary payloads")
63
63
  return summary_payloads
64
64
 
65
- async def get_completion(self, query: str, context: Optional[Any] = None, **kwargs) -> Any:
65
+ async def get_completion(
66
+ self, query: str, context: Optional[Any] = None, session_id: Optional[str] = None, **kwargs
67
+ ) -> Any:
66
68
  """
67
69
  Generates a completion using summaries context.
68
70
 
@@ -75,6 +77,8 @@ class SummariesRetriever(BaseRetriever):
75
77
  - query (str): The search query for generating the completion.
76
78
  - context (Optional[Any]): Optional context for the completion; if not provided,
77
79
  will be retrieved based on the query. (default None)
80
+ - session_id (Optional[str]): Optional session identifier for caching. If None,
81
+ defaults to 'default_session'. (default None)
78
82
 
79
83
  Returns:
80
84
  --------
@@ -1,16 +1,22 @@
1
1
  import os
2
+ import asyncio
2
3
  from typing import Any, Optional, List, Type
3
4
 
4
5
 
5
6
  from operator import itemgetter
6
7
  from cognee.infrastructure.databases.vector import get_vector_engine
7
- from cognee.modules.retrieval.utils.completion import generate_completion
8
+ from cognee.modules.retrieval.utils.completion import generate_completion, summarize_text
9
+ from cognee.modules.retrieval.utils.session_cache import (
10
+ save_conversation_history,
11
+ get_conversation_history,
12
+ )
8
13
  from cognee.infrastructure.databases.graph import get_graph_engine
9
14
  from cognee.infrastructure.llm.prompts import render_prompt
10
15
  from cognee.infrastructure.llm import LLMGateway
11
16
  from cognee.modules.retrieval.graph_completion_retriever import GraphCompletionRetriever
12
17
  from cognee.shared.logging_utils import get_logger
13
-
18
+ from cognee.context_global_variables import session_user
19
+ from cognee.infrastructure.databases.cache.config import CacheConfig
14
20
 
15
21
  from cognee.tasks.temporal_graph.models import QueryInterval
16
22
 
@@ -137,17 +143,63 @@ class TemporalRetriever(GraphCompletionRetriever):
137
143
 
138
144
  return self.descriptions_to_string(top_k_events)
139
145
 
140
- async def get_completion(self, query: str, context: Optional[str] = None) -> List[str]:
141
- """Generates a response using the query and optional context."""
146
+ async def get_completion(
147
+ self, query: str, context: Optional[str] = None, session_id: Optional[str] = None
148
+ ) -> List[str]:
149
+ """
150
+ Generates a response using the query and optional context.
151
+
152
+ Parameters:
153
+ -----------
154
+
155
+ - query (str): The query string for which a completion is generated.
156
+ - context (Optional[str]): Optional context to use; if None, it will be
157
+ retrieved based on the query. (default None)
158
+ - session_id (Optional[str]): Optional session identifier for caching. If None,
159
+ defaults to 'default_session'. (default None)
160
+
161
+ Returns:
162
+ --------
163
+
164
+ - List[str]: A list containing the generated completion.
165
+ """
142
166
  if not context:
143
167
  context = await self.get_context(query=query)
144
168
 
145
169
  if context:
146
- completion = await generate_completion(
147
- query=query,
148
- context=context,
149
- user_prompt_path=self.user_prompt_path,
150
- system_prompt_path=self.system_prompt_path,
151
- )
170
+ # Check if we need to generate context summary for caching
171
+ cache_config = CacheConfig()
172
+ user = session_user.get()
173
+ user_id = getattr(user, "id", None)
174
+ session_save = user_id and cache_config.caching
175
+
176
+ if session_save:
177
+ conversation_history = await get_conversation_history(session_id=session_id)
178
+
179
+ context_summary, completion = await asyncio.gather(
180
+ summarize_text(context),
181
+ generate_completion(
182
+ query=query,
183
+ context=context,
184
+ user_prompt_path=self.user_prompt_path,
185
+ system_prompt_path=self.system_prompt_path,
186
+ conversation_history=conversation_history,
187
+ ),
188
+ )
189
+ else:
190
+ completion = await generate_completion(
191
+ query=query,
192
+ context=context,
193
+ user_prompt_path=self.user_prompt_path,
194
+ system_prompt_path=self.system_prompt_path,
195
+ )
196
+
197
+ if session_save:
198
+ await save_conversation_history(
199
+ query=query,
200
+ context_summary=context_summary,
201
+ answer=completion,
202
+ session_id=session_id,
203
+ )
152
204
 
153
205
  return [completion]
@@ -8,7 +8,7 @@ from cognee.shared.logging_utils import get_logger
8
8
  from cognee.modules.retrieval.base_feedback import BaseFeedback
9
9
  from cognee.modules.retrieval.utils.models import CogneeUserFeedback
10
10
  from cognee.modules.retrieval.utils.models import UserFeedbackEvaluation
11
- from cognee.tasks.storage import add_data_points
11
+ from cognee.tasks.storage import add_data_points, index_graph_edges
12
12
 
13
13
  logger = get_logger("CompletionRetriever")
14
14
 
@@ -47,7 +47,7 @@ class UserQAFeedback(BaseFeedback):
47
47
  belongs_to_set=feedbacks_node_set,
48
48
  )
49
49
 
50
- await add_data_points(data_points=[cognee_user_feedback], update_edge_collection=False)
50
+ await add_data_points(data_points=[cognee_user_feedback])
51
51
 
52
52
  relationships = []
53
53
  relationship_name = "gives_feedback_to"
@@ -76,6 +76,7 @@ class UserQAFeedback(BaseFeedback):
76
76
  if len(relationships) > 0:
77
77
  graph_engine = await get_graph_engine()
78
78
  await graph_engine.add_edges(relationships)
79
+ await index_graph_edges(relationships)
79
80
  await graph_engine.apply_feedback_weight(
80
81
  node_ids=to_node_ids, weight=feedback_sentiment.score
81
82
  )
@@ -9,12 +9,17 @@ async def generate_completion(
9
9
  user_prompt_path: str,
10
10
  system_prompt_path: str,
11
11
  system_prompt: Optional[str] = None,
12
+ conversation_history: Optional[str] = None,
12
13
  ) -> str:
13
14
  """Generates a completion using LLM with given context and prompts."""
14
15
  args = {"question": query, "context": context}
15
16
  user_prompt = render_prompt(user_prompt_path, args)
16
17
  system_prompt = system_prompt if system_prompt else read_query_prompt(system_prompt_path)
17
18
 
19
+ if conversation_history:
20
+ #:TODO: I would separate the history and put it into the system prompt but we have to test what works best with longer convos
21
+ system_prompt = conversation_history + "\nTASK:" + system_prompt
22
+
18
23
  return await LLMGateway.acreate_structured_output(
19
24
  text_input=user_prompt,
20
25
  system_prompt=system_prompt,
@@ -62,7 +62,7 @@ async def code_description_to_code_part(
62
62
 
63
63
  try:
64
64
  if include_docs:
65
- search_results = await search(query_text=query, query_type="INSIGHTS")
65
+ search_results = await search(query_text=query, query_type="GRAPH_COMPLETION")
66
66
 
67
67
  concatenated_descriptions = " ".join(
68
68
  obj["description"]
@@ -0,0 +1,156 @@
1
+ from typing import Optional, List, Dict, Any
2
+ from cognee.context_global_variables import session_user
3
+ from cognee.infrastructure.databases.cache.config import CacheConfig
4
+ from cognee.infrastructure.databases.exceptions import CacheConnectionError
5
+ from cognee.shared.logging_utils import get_logger
6
+
7
+ logger = get_logger("session_cache")
8
+
9
+
10
+ async def save_conversation_history(
11
+ query: str,
12
+ context_summary: str,
13
+ answer: str,
14
+ session_id: Optional[str] = None,
15
+ ) -> bool:
16
+ """
17
+ Saves Q&A interaction to the session cache if user is authenticated and caching is enabled.
18
+
19
+ Handles cache unavailability gracefully by logging warnings instead of failing.
20
+
21
+ Parameters:
22
+ -----------
23
+
24
+ - query (str): The user's query/question.
25
+ - context_summary (str): Summarized context used for generating the answer.
26
+ - answer (str): The generated answer/completion.
27
+ - session_id (Optional[str]): Session identifier. Defaults to 'default_session' if None.
28
+
29
+ Returns:
30
+ --------
31
+
32
+ - bool: True if successfully saved to cache, False otherwise.
33
+ """
34
+ try:
35
+ cache_config = CacheConfig()
36
+ user = session_user.get()
37
+ user_id = getattr(user, "id", None)
38
+
39
+ if not (user_id and cache_config.caching):
40
+ logger.debug("Session caching disabled or user not authenticated")
41
+ return False
42
+
43
+ if session_id is None:
44
+ session_id = "default_session"
45
+
46
+ from cognee.infrastructure.databases.cache.get_cache_engine import get_cache_engine
47
+
48
+ cache_engine = get_cache_engine()
49
+
50
+ if cache_engine is None:
51
+ logger.warning("Cache engine not available, skipping session save")
52
+ return False
53
+
54
+ await cache_engine.add_qa(
55
+ str(user_id),
56
+ session_id=session_id,
57
+ question=query,
58
+ context=context_summary,
59
+ answer=answer,
60
+ )
61
+
62
+ logger.info(
63
+ f"Successfully saved Q&A to session cache: user_id={user_id}, session_id={session_id}"
64
+ )
65
+ return True
66
+
67
+ except CacheConnectionError as e:
68
+ logger.warning(f"Cache unavailable, continuing without session save: {e.message}")
69
+ return False
70
+
71
+ except Exception as e:
72
+ logger.error(
73
+ f"Unexpected error saving to session cache: {type(e).__name__}: {str(e)}. Continuing without caching."
74
+ )
75
+ return False
76
+
77
+
78
+ async def get_conversation_history(
79
+ session_id: Optional[str] = None,
80
+ ) -> str:
81
+ """
82
+ Retrieves conversation history from cache and formats it as text.
83
+
84
+ Returns formatted conversation history with time, question, context, and answer
85
+ for the last N Q&A pairs (N is determined by cache engine default).
86
+
87
+ Parameters:
88
+ -----------
89
+
90
+ - session_id (Optional[str]): Session identifier. Defaults to 'default_session' if None.
91
+
92
+ Returns:
93
+ --------
94
+
95
+ - str: Formatted conversation history string, or empty string if no history or error.
96
+
97
+ Format:
98
+ -------
99
+
100
+ Previous conversation:
101
+
102
+ [2024-01-15 10:30:45]
103
+ QUESTION: What is X?
104
+ CONTEXT: X is a concept...
105
+ ANSWER: X is...
106
+
107
+ [2024-01-15 10:31:20]
108
+ QUESTION: How does Y work?
109
+ CONTEXT: Y is related to...
110
+ ANSWER: Y works by...
111
+ """
112
+ try:
113
+ cache_config = CacheConfig()
114
+ user = session_user.get()
115
+ user_id = getattr(user, "id", None)
116
+
117
+ if not (user_id and cache_config.caching):
118
+ logger.debug("Session caching disabled or user not authenticated")
119
+ return ""
120
+
121
+ if session_id is None:
122
+ session_id = "default_session"
123
+
124
+ from cognee.infrastructure.databases.cache.get_cache_engine import get_cache_engine
125
+
126
+ cache_engine = get_cache_engine()
127
+
128
+ if cache_engine is None:
129
+ logger.warning("Cache engine not available, skipping conversation history retrieval")
130
+ return ""
131
+
132
+ history_entries = await cache_engine.get_latest_qa(str(user_id), session_id)
133
+
134
+ if not history_entries:
135
+ logger.debug("No conversation history found")
136
+ return ""
137
+
138
+ history_text = "Previous conversation:\n\n"
139
+ for entry in history_entries:
140
+ history_text += f"[{entry.get('time', 'Unknown time')}]\n"
141
+ history_text += f"QUESTION: {entry.get('question', '')}\n"
142
+ history_text += f"CONTEXT: {entry.get('context', '')}\n"
143
+ history_text += f"ANSWER: {entry.get('answer', '')}\n\n"
144
+
145
+ logger.debug(f"Retrieved {len(history_entries)} conversation history entries")
146
+ return history_text
147
+
148
+ except CacheConnectionError as e:
149
+ logger.warning(f"Cache unavailable, continuing without conversation history: {e.message}")
150
+ return ""
151
+
152
+ except Exception as e:
153
+ logger.warning(
154
+ f"Unexpected error retrieving conversation history: {type(e).__name__}: {str(e)}"
155
+ )
156
+ return ""
@@ -9,7 +9,6 @@ from cognee.modules.search.exceptions import UnsupportedSearchTypeError
9
9
  # Retrievers
10
10
  from cognee.modules.retrieval.user_qa_feedback import UserQAFeedback
11
11
  from cognee.modules.retrieval.chunks_retriever import ChunksRetriever
12
- from cognee.modules.retrieval.insights_retriever import InsightsRetriever
13
12
  from cognee.modules.retrieval.summaries_retriever import SummariesRetriever
14
13
  from cognee.modules.retrieval.completion_retriever import CompletionRetriever
15
14
  from cognee.modules.retrieval.graph_completion_retriever import GraphCompletionRetriever
@@ -44,10 +43,6 @@ async def get_search_type_tools(
44
43
  SummariesRetriever(top_k=top_k).get_completion,
45
44
  SummariesRetriever(top_k=top_k).get_context,
46
45
  ],
47
- SearchType.INSIGHTS: [
48
- InsightsRetriever(top_k=top_k).get_completion,
49
- InsightsRetriever(top_k=top_k).get_context,
50
- ],
51
46
  SearchType.CHUNKS: [
52
47
  ChunksRetriever(top_k=top_k).get_completion,
53
48
  ChunksRetriever(top_k=top_k).get_context,
@@ -1,12 +1,16 @@
1
1
  from typing import Any, List, Optional, Tuple, Type, Union
2
2
 
3
+ from cognee.infrastructure.databases.graph import get_graph_engine
3
4
  from cognee.modules.data.models.Dataset import Dataset
4
5
  from cognee.modules.engine.models.node_set import NodeSet
5
6
  from cognee.modules.graph.cognee_graph.CogneeGraphElements import Edge
6
7
  from cognee.modules.search.types import SearchType
8
+ from cognee.shared.logging_utils import get_logger
7
9
 
8
10
  from .get_search_type_tools import get_search_type_tools
9
11
 
12
+ logger = get_logger()
13
+
10
14
 
11
15
  async def no_access_control_search(
12
16
  query_type: SearchType,
@@ -19,6 +23,7 @@ async def no_access_control_search(
19
23
  save_interaction: bool = False,
20
24
  last_k: Optional[int] = None,
21
25
  only_context: bool = False,
26
+ session_id: Optional[str] = None,
22
27
  ) -> Tuple[Any, Union[str, List[Edge]], List[Dataset]]:
23
28
  search_tools = await get_search_type_tools(
24
29
  query_type=query_type,
@@ -31,6 +36,12 @@ async def no_access_control_search(
31
36
  save_interaction=save_interaction,
32
37
  last_k=last_k,
33
38
  )
39
+ graph_engine = await get_graph_engine()
40
+ is_empty = await graph_engine.is_empty()
41
+
42
+ if is_empty:
43
+ # TODO: we can log here, but not all search types use graph. Still keeping this here for reviewer input
44
+ logger.warning("Search attempt on an empty knowledge graph")
34
45
  if len(search_tools) == 2:
35
46
  [get_completion, get_context] = search_tools
36
47
 
@@ -38,7 +49,7 @@ async def no_access_control_search(
38
49
  return None, await get_context(query_text), []
39
50
 
40
51
  context = await get_context(query_text)
41
- result = await get_completion(query_text, context)
52
+ result = await get_completion(query_text, context, session_id=session_id)
42
53
  else:
43
54
  unknown_tool = search_tools[0]
44
55
  result = await unknown_tool(query_text)