cognee 0.5.1__py3-none-any.whl → 0.5.1.dev0__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.
- cognee/api/v1/add/add.py +2 -1
- cognee/api/v1/datasets/routers/get_datasets_router.py +1 -0
- cognee/api/v1/memify/routers/get_memify_router.py +1 -0
- cognee/api/v1/search/search.py +0 -4
- cognee/infrastructure/databases/relational/config.py +16 -1
- cognee/infrastructure/databases/relational/create_relational_engine.py +13 -3
- cognee/infrastructure/databases/relational/sqlalchemy/SqlAlchemyAdapter.py +24 -2
- cognee/infrastructure/databases/vector/create_vector_engine.py +9 -2
- cognee/infrastructure/llm/LLMGateway.py +0 -13
- cognee/infrastructure/llm/structured_output_framework/litellm_instructor/llm/anthropic/adapter.py +17 -12
- cognee/infrastructure/llm/structured_output_framework/litellm_instructor/llm/gemini/adapter.py +31 -25
- cognee/infrastructure/llm/structured_output_framework/litellm_instructor/llm/generic_llm_api/adapter.py +132 -7
- cognee/infrastructure/llm/structured_output_framework/litellm_instructor/llm/get_llm_client.py +5 -5
- cognee/infrastructure/llm/structured_output_framework/litellm_instructor/llm/llm_interface.py +2 -6
- cognee/infrastructure/llm/structured_output_framework/litellm_instructor/llm/mistral/adapter.py +58 -13
- cognee/infrastructure/llm/structured_output_framework/litellm_instructor/llm/ollama/adapter.py +0 -1
- cognee/infrastructure/llm/structured_output_framework/litellm_instructor/llm/openai/adapter.py +25 -131
- cognee/infrastructure/llm/structured_output_framework/litellm_instructor/llm/types.py +10 -0
- cognee/modules/data/models/Data.py +2 -1
- cognee/modules/retrieval/triplet_retriever.py +1 -1
- cognee/modules/retrieval/utils/brute_force_triplet_search.py +0 -18
- cognee/modules/search/methods/search.py +18 -25
- cognee/tasks/ingestion/data_item.py +8 -0
- cognee/tasks/ingestion/ingest_data.py +12 -1
- cognee/tasks/ingestion/save_data_item_to_storage.py +5 -0
- cognee/tests/integration/retrieval/test_chunks_retriever.py +252 -0
- cognee/tests/integration/retrieval/test_graph_completion_retriever.py +268 -0
- cognee/tests/integration/retrieval/test_graph_completion_retriever_context_extension.py +226 -0
- cognee/tests/integration/retrieval/test_graph_completion_retriever_cot.py +218 -0
- cognee/tests/integration/retrieval/test_rag_completion_retriever.py +254 -0
- cognee/tests/{unit/modules/retrieval/structured_output_test.py → integration/retrieval/test_structured_output.py} +87 -77
- cognee/tests/integration/retrieval/test_summaries_retriever.py +184 -0
- cognee/tests/integration/retrieval/test_temporal_retriever.py +306 -0
- cognee/tests/integration/retrieval/test_triplet_retriever.py +35 -0
- cognee/tests/test_custom_data_label.py +68 -0
- cognee/tests/test_search_db.py +334 -181
- cognee/tests/unit/eval_framework/benchmark_adapters_test.py +25 -0
- cognee/tests/unit/eval_framework/corpus_builder_test.py +33 -4
- cognee/tests/unit/infrastructure/databases/relational/test_RelationalConfig.py +69 -0
- cognee/tests/unit/modules/retrieval/chunks_retriever_test.py +181 -199
- cognee/tests/unit/modules/retrieval/conversation_history_test.py +338 -0
- cognee/tests/unit/modules/retrieval/graph_completion_retriever_context_extension_test.py +454 -162
- cognee/tests/unit/modules/retrieval/graph_completion_retriever_cot_test.py +674 -156
- cognee/tests/unit/modules/retrieval/graph_completion_retriever_test.py +625 -200
- cognee/tests/unit/modules/retrieval/rag_completion_retriever_test.py +319 -203
- cognee/tests/unit/modules/retrieval/summaries_retriever_test.py +189 -155
- cognee/tests/unit/modules/retrieval/temporal_retriever_test.py +539 -58
- cognee/tests/unit/modules/retrieval/test_brute_force_triplet_search.py +218 -9
- cognee/tests/unit/modules/retrieval/test_completion.py +343 -0
- cognee/tests/unit/modules/retrieval/test_graph_summary_completion_retriever.py +157 -0
- cognee/tests/unit/modules/retrieval/test_user_qa_feedback.py +312 -0
- cognee/tests/unit/modules/retrieval/triplet_retriever_test.py +246 -0
- {cognee-0.5.1.dist-info → cognee-0.5.1.dev0.dist-info}/METADATA +1 -1
- {cognee-0.5.1.dist-info → cognee-0.5.1.dev0.dist-info}/RECORD +58 -45
- cognee/tests/unit/modules/search/test_search.py +0 -100
- {cognee-0.5.1.dist-info → cognee-0.5.1.dev0.dist-info}/WHEEL +0 -0
- {cognee-0.5.1.dist-info → cognee-0.5.1.dev0.dist-info}/entry_points.txt +0 -0
- {cognee-0.5.1.dist-info → cognee-0.5.1.dev0.dist-info}/licenses/LICENSE +0 -0
- {cognee-0.5.1.dist-info → cognee-0.5.1.dev0.dist-info}/licenses/NOTICE.md +0 -0
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import asyncio
|
|
2
|
-
|
|
2
|
+
import os
|
|
3
3
|
import pytest
|
|
4
|
-
import cognee
|
|
5
4
|
import pathlib
|
|
6
|
-
import
|
|
5
|
+
import pytest_asyncio
|
|
6
|
+
import cognee
|
|
7
7
|
|
|
8
8
|
from pydantic import BaseModel
|
|
9
9
|
from cognee.low_level import setup, DataPoint
|
|
@@ -125,80 +125,90 @@ async def _test_get_structured_entity_completion():
|
|
|
125
125
|
_assert_structured_answer(structured_answer)
|
|
126
126
|
|
|
127
127
|
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
128
|
+
@pytest_asyncio.fixture
|
|
129
|
+
async def setup_test_environment():
|
|
130
|
+
"""Set up a clean test environment with graph and document data."""
|
|
131
|
+
base_dir = pathlib.Path(__file__).parent.parent.parent.parent
|
|
132
|
+
system_directory_path = str(base_dir / ".cognee_system/test_get_structured_completion")
|
|
133
|
+
data_directory_path = str(base_dir / ".data_storage/test_get_structured_completion")
|
|
134
|
+
|
|
135
|
+
cognee.config.system_root_directory(system_directory_path)
|
|
136
|
+
cognee.config.data_root_directory(data_directory_path)
|
|
137
|
+
|
|
138
|
+
await cognee.prune.prune_data()
|
|
139
|
+
await cognee.prune.prune_system(metadata=True)
|
|
140
|
+
await setup()
|
|
141
|
+
|
|
142
|
+
class Company(DataPoint):
|
|
143
|
+
name: str
|
|
144
|
+
|
|
145
|
+
class Person(DataPoint):
|
|
146
|
+
name: str
|
|
147
|
+
works_for: Company
|
|
148
|
+
works_since: int
|
|
149
|
+
|
|
150
|
+
company1 = Company(name="Figma")
|
|
151
|
+
person1 = Person(name="Steve Rodger", works_for=company1, works_since=2015)
|
|
152
|
+
|
|
153
|
+
entities = [company1, person1]
|
|
154
|
+
await add_data_points(entities)
|
|
155
|
+
|
|
156
|
+
document = TextDocument(
|
|
157
|
+
name="Steve Rodger's career",
|
|
158
|
+
raw_data_location="somewhere",
|
|
159
|
+
external_metadata="",
|
|
160
|
+
mime_type="text/plain",
|
|
161
|
+
)
|
|
162
|
+
|
|
163
|
+
chunk1 = DocumentChunk(
|
|
164
|
+
text="Steve Rodger",
|
|
165
|
+
chunk_size=2,
|
|
166
|
+
chunk_index=0,
|
|
167
|
+
cut_type="sentence_end",
|
|
168
|
+
is_part_of=document,
|
|
169
|
+
contains=[],
|
|
170
|
+
)
|
|
171
|
+
chunk2 = DocumentChunk(
|
|
172
|
+
text="Mike Broski",
|
|
173
|
+
chunk_size=2,
|
|
174
|
+
chunk_index=1,
|
|
175
|
+
cut_type="sentence_end",
|
|
176
|
+
is_part_of=document,
|
|
177
|
+
contains=[],
|
|
178
|
+
)
|
|
179
|
+
chunk3 = DocumentChunk(
|
|
180
|
+
text="Christina Mayer",
|
|
181
|
+
chunk_size=2,
|
|
182
|
+
chunk_index=2,
|
|
183
|
+
cut_type="sentence_end",
|
|
184
|
+
is_part_of=document,
|
|
185
|
+
contains=[],
|
|
186
|
+
)
|
|
187
|
+
|
|
188
|
+
entities = [chunk1, chunk2, chunk3]
|
|
189
|
+
await add_data_points(entities)
|
|
190
|
+
|
|
191
|
+
entity_type = EntityType(name="Person", description="A human individual")
|
|
192
|
+
entity = Entity(name="Albert Einstein", is_a=entity_type, description="A famous physicist")
|
|
193
|
+
|
|
194
|
+
entities = [entity]
|
|
195
|
+
await add_data_points(entities)
|
|
196
|
+
|
|
197
|
+
yield
|
|
139
198
|
|
|
199
|
+
try:
|
|
140
200
|
await cognee.prune.prune_data()
|
|
141
201
|
await cognee.prune.prune_system(metadata=True)
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
entities = [company1, person1]
|
|
156
|
-
await add_data_points(entities)
|
|
157
|
-
|
|
158
|
-
document = TextDocument(
|
|
159
|
-
name="Steve Rodger's career",
|
|
160
|
-
raw_data_location="somewhere",
|
|
161
|
-
external_metadata="",
|
|
162
|
-
mime_type="text/plain",
|
|
163
|
-
)
|
|
164
|
-
|
|
165
|
-
chunk1 = DocumentChunk(
|
|
166
|
-
text="Steve Rodger",
|
|
167
|
-
chunk_size=2,
|
|
168
|
-
chunk_index=0,
|
|
169
|
-
cut_type="sentence_end",
|
|
170
|
-
is_part_of=document,
|
|
171
|
-
contains=[],
|
|
172
|
-
)
|
|
173
|
-
chunk2 = DocumentChunk(
|
|
174
|
-
text="Mike Broski",
|
|
175
|
-
chunk_size=2,
|
|
176
|
-
chunk_index=1,
|
|
177
|
-
cut_type="sentence_end",
|
|
178
|
-
is_part_of=document,
|
|
179
|
-
contains=[],
|
|
180
|
-
)
|
|
181
|
-
chunk3 = DocumentChunk(
|
|
182
|
-
text="Christina Mayer",
|
|
183
|
-
chunk_size=2,
|
|
184
|
-
chunk_index=2,
|
|
185
|
-
cut_type="sentence_end",
|
|
186
|
-
is_part_of=document,
|
|
187
|
-
contains=[],
|
|
188
|
-
)
|
|
189
|
-
|
|
190
|
-
entities = [chunk1, chunk2, chunk3]
|
|
191
|
-
await add_data_points(entities)
|
|
192
|
-
|
|
193
|
-
entity_type = EntityType(name="Person", description="A human individual")
|
|
194
|
-
entity = Entity(name="Albert Einstein", is_a=entity_type, description="A famous physicist")
|
|
195
|
-
|
|
196
|
-
entities = [entity]
|
|
197
|
-
await add_data_points(entities)
|
|
198
|
-
|
|
199
|
-
await _test_get_structured_graph_completion_cot()
|
|
200
|
-
await _test_get_structured_graph_completion()
|
|
201
|
-
await _test_get_structured_graph_completion_temporal()
|
|
202
|
-
await _test_get_structured_graph_completion_rag()
|
|
203
|
-
await _test_get_structured_graph_completion_context_extension()
|
|
204
|
-
await _test_get_structured_entity_completion()
|
|
202
|
+
except Exception:
|
|
203
|
+
pass
|
|
204
|
+
|
|
205
|
+
|
|
206
|
+
@pytest.mark.asyncio
|
|
207
|
+
async def test_get_structured_completion(setup_test_environment):
|
|
208
|
+
"""Integration test: verify structured output completion for all retrievers."""
|
|
209
|
+
await _test_get_structured_graph_completion_cot()
|
|
210
|
+
await _test_get_structured_graph_completion()
|
|
211
|
+
await _test_get_structured_graph_completion_temporal()
|
|
212
|
+
await _test_get_structured_graph_completion_rag()
|
|
213
|
+
await _test_get_structured_graph_completion_context_extension()
|
|
214
|
+
await _test_get_structured_entity_completion()
|
|
@@ -0,0 +1,184 @@
|
|
|
1
|
+
import os
|
|
2
|
+
import pytest
|
|
3
|
+
import pathlib
|
|
4
|
+
import pytest_asyncio
|
|
5
|
+
import cognee
|
|
6
|
+
|
|
7
|
+
from cognee.low_level import setup
|
|
8
|
+
from cognee.tasks.storage import add_data_points
|
|
9
|
+
from cognee.infrastructure.databases.vector import get_vector_engine
|
|
10
|
+
from cognee.modules.chunking.models import DocumentChunk
|
|
11
|
+
from cognee.tasks.summarization.models import TextSummary
|
|
12
|
+
from cognee.modules.data.processing.document_types import TextDocument
|
|
13
|
+
from cognee.modules.retrieval.exceptions.exceptions import NoDataError
|
|
14
|
+
from cognee.modules.retrieval.summaries_retriever import SummariesRetriever
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
@pytest_asyncio.fixture
|
|
18
|
+
async def setup_test_environment_with_summaries():
|
|
19
|
+
"""Set up a clean test environment with summaries."""
|
|
20
|
+
base_dir = pathlib.Path(__file__).parent.parent.parent.parent
|
|
21
|
+
system_directory_path = str(base_dir / ".cognee_system/test_summaries_retriever_context")
|
|
22
|
+
data_directory_path = str(base_dir / ".data_storage/test_summaries_retriever_context")
|
|
23
|
+
|
|
24
|
+
cognee.config.system_root_directory(system_directory_path)
|
|
25
|
+
cognee.config.data_root_directory(data_directory_path)
|
|
26
|
+
|
|
27
|
+
await cognee.prune.prune_data()
|
|
28
|
+
await cognee.prune.prune_system(metadata=True)
|
|
29
|
+
await setup()
|
|
30
|
+
|
|
31
|
+
document1 = TextDocument(
|
|
32
|
+
name="Employee List",
|
|
33
|
+
raw_data_location="somewhere",
|
|
34
|
+
external_metadata="",
|
|
35
|
+
mime_type="text/plain",
|
|
36
|
+
)
|
|
37
|
+
|
|
38
|
+
document2 = TextDocument(
|
|
39
|
+
name="Car List",
|
|
40
|
+
raw_data_location="somewhere",
|
|
41
|
+
external_metadata="",
|
|
42
|
+
mime_type="text/plain",
|
|
43
|
+
)
|
|
44
|
+
|
|
45
|
+
chunk1 = DocumentChunk(
|
|
46
|
+
text="Steve Rodger",
|
|
47
|
+
chunk_size=2,
|
|
48
|
+
chunk_index=0,
|
|
49
|
+
cut_type="sentence_end",
|
|
50
|
+
is_part_of=document1,
|
|
51
|
+
contains=[],
|
|
52
|
+
)
|
|
53
|
+
chunk1_summary = TextSummary(
|
|
54
|
+
text="S.R.",
|
|
55
|
+
made_from=chunk1,
|
|
56
|
+
)
|
|
57
|
+
chunk2 = DocumentChunk(
|
|
58
|
+
text="Mike Broski",
|
|
59
|
+
chunk_size=2,
|
|
60
|
+
chunk_index=1,
|
|
61
|
+
cut_type="sentence_end",
|
|
62
|
+
is_part_of=document1,
|
|
63
|
+
contains=[],
|
|
64
|
+
)
|
|
65
|
+
chunk2_summary = TextSummary(
|
|
66
|
+
text="M.B.",
|
|
67
|
+
made_from=chunk2,
|
|
68
|
+
)
|
|
69
|
+
chunk3 = DocumentChunk(
|
|
70
|
+
text="Christina Mayer",
|
|
71
|
+
chunk_size=2,
|
|
72
|
+
chunk_index=2,
|
|
73
|
+
cut_type="sentence_end",
|
|
74
|
+
is_part_of=document1,
|
|
75
|
+
contains=[],
|
|
76
|
+
)
|
|
77
|
+
chunk3_summary = TextSummary(
|
|
78
|
+
text="C.M.",
|
|
79
|
+
made_from=chunk3,
|
|
80
|
+
)
|
|
81
|
+
chunk4 = DocumentChunk(
|
|
82
|
+
text="Range Rover",
|
|
83
|
+
chunk_size=2,
|
|
84
|
+
chunk_index=0,
|
|
85
|
+
cut_type="sentence_end",
|
|
86
|
+
is_part_of=document2,
|
|
87
|
+
contains=[],
|
|
88
|
+
)
|
|
89
|
+
chunk4_summary = TextSummary(
|
|
90
|
+
text="R.R.",
|
|
91
|
+
made_from=chunk4,
|
|
92
|
+
)
|
|
93
|
+
chunk5 = DocumentChunk(
|
|
94
|
+
text="Hyundai",
|
|
95
|
+
chunk_size=2,
|
|
96
|
+
chunk_index=1,
|
|
97
|
+
cut_type="sentence_end",
|
|
98
|
+
is_part_of=document2,
|
|
99
|
+
contains=[],
|
|
100
|
+
)
|
|
101
|
+
chunk5_summary = TextSummary(
|
|
102
|
+
text="H.Y.",
|
|
103
|
+
made_from=chunk5,
|
|
104
|
+
)
|
|
105
|
+
chunk6 = DocumentChunk(
|
|
106
|
+
text="Chrysler",
|
|
107
|
+
chunk_size=2,
|
|
108
|
+
chunk_index=2,
|
|
109
|
+
cut_type="sentence_end",
|
|
110
|
+
is_part_of=document2,
|
|
111
|
+
contains=[],
|
|
112
|
+
)
|
|
113
|
+
chunk6_summary = TextSummary(
|
|
114
|
+
text="C.H.",
|
|
115
|
+
made_from=chunk6,
|
|
116
|
+
)
|
|
117
|
+
|
|
118
|
+
entities = [
|
|
119
|
+
chunk1_summary,
|
|
120
|
+
chunk2_summary,
|
|
121
|
+
chunk3_summary,
|
|
122
|
+
chunk4_summary,
|
|
123
|
+
chunk5_summary,
|
|
124
|
+
chunk6_summary,
|
|
125
|
+
]
|
|
126
|
+
|
|
127
|
+
await add_data_points(entities)
|
|
128
|
+
|
|
129
|
+
yield
|
|
130
|
+
|
|
131
|
+
try:
|
|
132
|
+
await cognee.prune.prune_data()
|
|
133
|
+
await cognee.prune.prune_system(metadata=True)
|
|
134
|
+
except Exception:
|
|
135
|
+
pass
|
|
136
|
+
|
|
137
|
+
|
|
138
|
+
@pytest_asyncio.fixture
|
|
139
|
+
async def setup_test_environment_empty():
|
|
140
|
+
"""Set up a clean test environment without summaries."""
|
|
141
|
+
base_dir = pathlib.Path(__file__).parent.parent.parent.parent
|
|
142
|
+
system_directory_path = str(base_dir / ".cognee_system/test_summaries_retriever_context_empty")
|
|
143
|
+
data_directory_path = str(base_dir / ".data_storage/test_summaries_retriever_context_empty")
|
|
144
|
+
|
|
145
|
+
cognee.config.system_root_directory(system_directory_path)
|
|
146
|
+
cognee.config.data_root_directory(data_directory_path)
|
|
147
|
+
|
|
148
|
+
await cognee.prune.prune_data()
|
|
149
|
+
await cognee.prune.prune_system(metadata=True)
|
|
150
|
+
|
|
151
|
+
yield
|
|
152
|
+
|
|
153
|
+
try:
|
|
154
|
+
await cognee.prune.prune_data()
|
|
155
|
+
await cognee.prune.prune_system(metadata=True)
|
|
156
|
+
except Exception:
|
|
157
|
+
pass
|
|
158
|
+
|
|
159
|
+
|
|
160
|
+
@pytest.mark.asyncio
|
|
161
|
+
async def test_summaries_retriever_context(setup_test_environment_with_summaries):
|
|
162
|
+
"""Integration test: verify SummariesRetriever can retrieve summary context."""
|
|
163
|
+
retriever = SummariesRetriever(top_k=20)
|
|
164
|
+
|
|
165
|
+
context = await retriever.get_context("Christina")
|
|
166
|
+
|
|
167
|
+
assert isinstance(context, list), "Context should be a list"
|
|
168
|
+
assert len(context) > 0, "Context should not be empty"
|
|
169
|
+
assert context[0]["text"] == "C.M.", "Failed to get Christina Mayer"
|
|
170
|
+
|
|
171
|
+
|
|
172
|
+
@pytest.mark.asyncio
|
|
173
|
+
async def test_summaries_retriever_context_on_empty_graph(setup_test_environment_empty):
|
|
174
|
+
"""Integration test: verify SummariesRetriever handles empty graph correctly."""
|
|
175
|
+
retriever = SummariesRetriever()
|
|
176
|
+
|
|
177
|
+
with pytest.raises(NoDataError):
|
|
178
|
+
await retriever.get_context("Christina Mayer")
|
|
179
|
+
|
|
180
|
+
vector_engine = get_vector_engine()
|
|
181
|
+
await vector_engine.create_collection("TextSummary_text", payload_schema=TextSummary)
|
|
182
|
+
|
|
183
|
+
context = await retriever.get_context("Christina Mayer")
|
|
184
|
+
assert context == [], "Returned context should be empty on an empty graph"
|
|
@@ -0,0 +1,306 @@
|
|
|
1
|
+
import os
|
|
2
|
+
import pytest
|
|
3
|
+
import pathlib
|
|
4
|
+
import pytest_asyncio
|
|
5
|
+
import cognee
|
|
6
|
+
|
|
7
|
+
from cognee.low_level import setup, DataPoint
|
|
8
|
+
from cognee.tasks.storage import add_data_points
|
|
9
|
+
from cognee.modules.retrieval.temporal_retriever import TemporalRetriever
|
|
10
|
+
from cognee.modules.engine.models.Event import Event
|
|
11
|
+
from cognee.modules.engine.models.Timestamp import Timestamp
|
|
12
|
+
from cognee.modules.engine.models.Interval import Interval
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
@pytest_asyncio.fixture
|
|
16
|
+
async def setup_test_environment_with_events():
|
|
17
|
+
"""Set up a clean test environment with temporal events."""
|
|
18
|
+
base_dir = pathlib.Path(__file__).parent.parent.parent.parent
|
|
19
|
+
system_directory_path = str(base_dir / ".cognee_system/test_temporal_retriever_with_events")
|
|
20
|
+
data_directory_path = str(base_dir / ".data_storage/test_temporal_retriever_with_events")
|
|
21
|
+
|
|
22
|
+
cognee.config.system_root_directory(system_directory_path)
|
|
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
|
+
# Create timestamps for events
|
|
30
|
+
timestamp1 = Timestamp(
|
|
31
|
+
time_at=1609459200, # 2021-01-01 00:00:00
|
|
32
|
+
year=2021,
|
|
33
|
+
month=1,
|
|
34
|
+
day=1,
|
|
35
|
+
hour=0,
|
|
36
|
+
minute=0,
|
|
37
|
+
second=0,
|
|
38
|
+
timestamp_str="2021-01-01T00:00:00",
|
|
39
|
+
)
|
|
40
|
+
|
|
41
|
+
timestamp2 = Timestamp(
|
|
42
|
+
time_at=1612137600, # 2021-02-01 00:00:00
|
|
43
|
+
year=2021,
|
|
44
|
+
month=2,
|
|
45
|
+
day=1,
|
|
46
|
+
hour=0,
|
|
47
|
+
minute=0,
|
|
48
|
+
second=0,
|
|
49
|
+
timestamp_str="2021-02-01T00:00:00",
|
|
50
|
+
)
|
|
51
|
+
|
|
52
|
+
timestamp3 = Timestamp(
|
|
53
|
+
time_at=1614556800, # 2021-03-01 00:00:00
|
|
54
|
+
year=2021,
|
|
55
|
+
month=3,
|
|
56
|
+
day=1,
|
|
57
|
+
hour=0,
|
|
58
|
+
minute=0,
|
|
59
|
+
second=0,
|
|
60
|
+
timestamp_str="2021-03-01T00:00:00",
|
|
61
|
+
)
|
|
62
|
+
|
|
63
|
+
timestamp4 = Timestamp(
|
|
64
|
+
time_at=1625097600, # 2021-07-01 00:00:00
|
|
65
|
+
year=2021,
|
|
66
|
+
month=7,
|
|
67
|
+
day=1,
|
|
68
|
+
hour=0,
|
|
69
|
+
minute=0,
|
|
70
|
+
second=0,
|
|
71
|
+
timestamp_str="2021-07-01T00:00:00",
|
|
72
|
+
)
|
|
73
|
+
|
|
74
|
+
timestamp5 = Timestamp(
|
|
75
|
+
time_at=1633046400, # 2021-10-01 00:00:00
|
|
76
|
+
year=2021,
|
|
77
|
+
month=10,
|
|
78
|
+
day=1,
|
|
79
|
+
hour=0,
|
|
80
|
+
minute=0,
|
|
81
|
+
second=0,
|
|
82
|
+
timestamp_str="2021-10-01T00:00:00",
|
|
83
|
+
)
|
|
84
|
+
|
|
85
|
+
# Create interval for event spanning multiple timestamps
|
|
86
|
+
interval1 = Interval(time_from=timestamp2, time_to=timestamp3)
|
|
87
|
+
|
|
88
|
+
# Create events with timestamps
|
|
89
|
+
event1 = Event(
|
|
90
|
+
name="Project Alpha Launch",
|
|
91
|
+
description="Launched Project Alpha at the beginning of 2021",
|
|
92
|
+
at=timestamp1,
|
|
93
|
+
location="San Francisco",
|
|
94
|
+
)
|
|
95
|
+
|
|
96
|
+
event2 = Event(
|
|
97
|
+
name="Team Meeting",
|
|
98
|
+
description="Monthly team meeting discussing Q1 goals",
|
|
99
|
+
during=interval1,
|
|
100
|
+
location="New York",
|
|
101
|
+
)
|
|
102
|
+
|
|
103
|
+
event3 = Event(
|
|
104
|
+
name="Product Release",
|
|
105
|
+
description="Released new product features in July",
|
|
106
|
+
at=timestamp4,
|
|
107
|
+
location="Remote",
|
|
108
|
+
)
|
|
109
|
+
|
|
110
|
+
event4 = Event(
|
|
111
|
+
name="Company Retreat",
|
|
112
|
+
description="Annual company retreat in October",
|
|
113
|
+
at=timestamp5,
|
|
114
|
+
location="Lake Tahoe",
|
|
115
|
+
)
|
|
116
|
+
|
|
117
|
+
entities = [event1, event2, event3, event4]
|
|
118
|
+
|
|
119
|
+
await add_data_points(entities)
|
|
120
|
+
|
|
121
|
+
yield
|
|
122
|
+
|
|
123
|
+
try:
|
|
124
|
+
await cognee.prune.prune_data()
|
|
125
|
+
await cognee.prune.prune_system(metadata=True)
|
|
126
|
+
except Exception:
|
|
127
|
+
pass
|
|
128
|
+
|
|
129
|
+
|
|
130
|
+
@pytest_asyncio.fixture
|
|
131
|
+
async def setup_test_environment_with_graph_data():
|
|
132
|
+
"""Set up a clean test environment with graph data (for fallback to triplets)."""
|
|
133
|
+
base_dir = pathlib.Path(__file__).parent.parent.parent.parent
|
|
134
|
+
system_directory_path = str(base_dir / ".cognee_system/test_temporal_retriever_with_graph")
|
|
135
|
+
data_directory_path = str(base_dir / ".data_storage/test_temporal_retriever_with_graph")
|
|
136
|
+
|
|
137
|
+
cognee.config.system_root_directory(system_directory_path)
|
|
138
|
+
cognee.config.data_root_directory(data_directory_path)
|
|
139
|
+
|
|
140
|
+
await cognee.prune.prune_data()
|
|
141
|
+
await cognee.prune.prune_system(metadata=True)
|
|
142
|
+
await setup()
|
|
143
|
+
|
|
144
|
+
class Company(DataPoint):
|
|
145
|
+
name: str
|
|
146
|
+
description: str
|
|
147
|
+
|
|
148
|
+
class Person(DataPoint):
|
|
149
|
+
name: str
|
|
150
|
+
description: str
|
|
151
|
+
works_for: Company
|
|
152
|
+
|
|
153
|
+
company1 = Company(name="Figma", description="Figma is a company")
|
|
154
|
+
person1 = Person(
|
|
155
|
+
name="Steve Rodger",
|
|
156
|
+
description="This is description about Steve Rodger",
|
|
157
|
+
works_for=company1,
|
|
158
|
+
)
|
|
159
|
+
|
|
160
|
+
entities = [company1, person1]
|
|
161
|
+
|
|
162
|
+
await add_data_points(entities)
|
|
163
|
+
|
|
164
|
+
yield
|
|
165
|
+
|
|
166
|
+
try:
|
|
167
|
+
await cognee.prune.prune_data()
|
|
168
|
+
await cognee.prune.prune_system(metadata=True)
|
|
169
|
+
except Exception:
|
|
170
|
+
pass
|
|
171
|
+
|
|
172
|
+
|
|
173
|
+
@pytest_asyncio.fixture
|
|
174
|
+
async def setup_test_environment_empty():
|
|
175
|
+
"""Set up a clean test environment without data."""
|
|
176
|
+
base_dir = pathlib.Path(__file__).parent.parent.parent.parent
|
|
177
|
+
system_directory_path = str(base_dir / ".cognee_system/test_temporal_retriever_empty")
|
|
178
|
+
data_directory_path = str(base_dir / ".data_storage/test_temporal_retriever_empty")
|
|
179
|
+
|
|
180
|
+
cognee.config.system_root_directory(system_directory_path)
|
|
181
|
+
cognee.config.data_root_directory(data_directory_path)
|
|
182
|
+
|
|
183
|
+
await cognee.prune.prune_data()
|
|
184
|
+
await cognee.prune.prune_system(metadata=True)
|
|
185
|
+
await setup()
|
|
186
|
+
|
|
187
|
+
yield
|
|
188
|
+
|
|
189
|
+
try:
|
|
190
|
+
await cognee.prune.prune_data()
|
|
191
|
+
await cognee.prune.prune_system(metadata=True)
|
|
192
|
+
except Exception:
|
|
193
|
+
pass
|
|
194
|
+
|
|
195
|
+
|
|
196
|
+
@pytest.mark.asyncio
|
|
197
|
+
async def test_temporal_retriever_context_with_time_range(setup_test_environment_with_events):
|
|
198
|
+
"""Integration test: verify TemporalRetriever can retrieve events within time range."""
|
|
199
|
+
retriever = TemporalRetriever(top_k=5)
|
|
200
|
+
|
|
201
|
+
context = await retriever.get_context("What happened in January 2021?")
|
|
202
|
+
|
|
203
|
+
assert isinstance(context, str), "Context should be a string"
|
|
204
|
+
assert len(context) > 0, "Context should not be empty"
|
|
205
|
+
assert "Project Alpha" in context or "Launch" in context, (
|
|
206
|
+
"Should retrieve Project Alpha Launch event from January 2021"
|
|
207
|
+
)
|
|
208
|
+
|
|
209
|
+
|
|
210
|
+
@pytest.mark.asyncio
|
|
211
|
+
async def test_temporal_retriever_context_with_single_time(setup_test_environment_with_events):
|
|
212
|
+
"""Integration test: verify TemporalRetriever can retrieve events at specific time."""
|
|
213
|
+
retriever = TemporalRetriever(top_k=5)
|
|
214
|
+
|
|
215
|
+
context = await retriever.get_context("What happened in July 2021?")
|
|
216
|
+
|
|
217
|
+
assert isinstance(context, str), "Context should be a string"
|
|
218
|
+
assert len(context) > 0, "Context should not be empty"
|
|
219
|
+
assert "Product Release" in context or "July" in context, (
|
|
220
|
+
"Should retrieve Product Release event from July 2021"
|
|
221
|
+
)
|
|
222
|
+
|
|
223
|
+
|
|
224
|
+
@pytest.mark.asyncio
|
|
225
|
+
async def test_temporal_retriever_context_fallback_to_triplets(
|
|
226
|
+
setup_test_environment_with_graph_data,
|
|
227
|
+
):
|
|
228
|
+
"""Integration test: verify TemporalRetriever falls back to triplets when no time extracted."""
|
|
229
|
+
retriever = TemporalRetriever(top_k=5)
|
|
230
|
+
|
|
231
|
+
context = await retriever.get_context("Who works at Figma?")
|
|
232
|
+
|
|
233
|
+
assert isinstance(context, str), "Context should be a string"
|
|
234
|
+
assert len(context) > 0, "Context should not be empty"
|
|
235
|
+
assert "Steve" in context or "Figma" in context, (
|
|
236
|
+
"Should retrieve graph data via triplet search fallback"
|
|
237
|
+
)
|
|
238
|
+
|
|
239
|
+
|
|
240
|
+
@pytest.mark.asyncio
|
|
241
|
+
async def test_temporal_retriever_context_empty_graph(setup_test_environment_empty):
|
|
242
|
+
"""Integration test: verify TemporalRetriever handles empty graph correctly."""
|
|
243
|
+
retriever = TemporalRetriever()
|
|
244
|
+
|
|
245
|
+
context = await retriever.get_context("What happened?")
|
|
246
|
+
|
|
247
|
+
assert isinstance(context, str), "Context should be a string"
|
|
248
|
+
assert len(context) >= 0, "Context should be a string (possibly empty)"
|
|
249
|
+
|
|
250
|
+
|
|
251
|
+
@pytest.mark.asyncio
|
|
252
|
+
async def test_temporal_retriever_get_completion(setup_test_environment_with_events):
|
|
253
|
+
"""Integration test: verify TemporalRetriever can generate completions."""
|
|
254
|
+
retriever = TemporalRetriever()
|
|
255
|
+
|
|
256
|
+
completion = await retriever.get_completion("What happened in January 2021?")
|
|
257
|
+
|
|
258
|
+
assert isinstance(completion, list), "Completion should be a list"
|
|
259
|
+
assert len(completion) > 0, "Completion should not be empty"
|
|
260
|
+
assert all(isinstance(item, str) and item.strip() for item in completion), (
|
|
261
|
+
"Completion items should be non-empty strings"
|
|
262
|
+
)
|
|
263
|
+
|
|
264
|
+
|
|
265
|
+
@pytest.mark.asyncio
|
|
266
|
+
async def test_temporal_retriever_get_completion_fallback(setup_test_environment_with_graph_data):
|
|
267
|
+
"""Integration test: verify TemporalRetriever get_completion works with triplet fallback."""
|
|
268
|
+
retriever = TemporalRetriever()
|
|
269
|
+
|
|
270
|
+
completion = await retriever.get_completion("Who works at Figma?")
|
|
271
|
+
|
|
272
|
+
assert isinstance(completion, list), "Completion should be a list"
|
|
273
|
+
assert len(completion) > 0, "Completion should not be empty"
|
|
274
|
+
assert all(isinstance(item, str) and item.strip() for item in completion), (
|
|
275
|
+
"Completion items should be non-empty strings"
|
|
276
|
+
)
|
|
277
|
+
|
|
278
|
+
|
|
279
|
+
@pytest.mark.asyncio
|
|
280
|
+
async def test_temporal_retriever_top_k_limit(setup_test_environment_with_events):
|
|
281
|
+
"""Integration test: verify TemporalRetriever respects top_k parameter."""
|
|
282
|
+
retriever = TemporalRetriever(top_k=2)
|
|
283
|
+
|
|
284
|
+
context = await retriever.get_context("What happened in 2021?")
|
|
285
|
+
|
|
286
|
+
assert isinstance(context, str), "Context should be a string"
|
|
287
|
+
separator_count = context.count("#####################")
|
|
288
|
+
assert separator_count <= 1, "Should respect top_k limit of 2 events"
|
|
289
|
+
|
|
290
|
+
|
|
291
|
+
@pytest.mark.asyncio
|
|
292
|
+
async def test_temporal_retriever_multiple_events(setup_test_environment_with_events):
|
|
293
|
+
"""Integration test: verify TemporalRetriever can retrieve multiple events."""
|
|
294
|
+
retriever = TemporalRetriever(top_k=10)
|
|
295
|
+
|
|
296
|
+
context = await retriever.get_context("What events occurred in 2021?")
|
|
297
|
+
|
|
298
|
+
assert isinstance(context, str), "Context should be a string"
|
|
299
|
+
assert len(context) > 0, "Context should not be empty"
|
|
300
|
+
|
|
301
|
+
assert (
|
|
302
|
+
"Project Alpha" in context
|
|
303
|
+
or "Team Meeting" in context
|
|
304
|
+
or "Product Release" in context
|
|
305
|
+
or "Company Retreat" in context
|
|
306
|
+
), "Should retrieve at least one event from 2021"
|