cognee 1.2.2.dev1__py3-none-any.whl → 1.2.2.dev2__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.
@@ -19,7 +19,7 @@ so no property is lost.
19
19
  """
20
20
 
21
21
  import json
22
- from typing import Any, Dict, List, Optional, Type, Union
22
+ from typing import Any, Dict, Iterable, List, Optional, Tuple, Type, Union
23
23
 
24
24
  from pydantic import BaseModel, ConfigDict, Field, SerializeAsAny, create_model, field_validator
25
25
 
@@ -59,13 +59,41 @@ class _DynamicDataPoint(DataPoint):
59
59
  model_config = ConfigDict(arbitrary_types_allowed=True, extra="allow")
60
60
 
61
61
 
62
- _dynamic_models: Dict[str, Type[DataPoint]] = {}
62
+ _dynamic_models: Dict[Tuple[str, Tuple[str, ...], Tuple[str, ...]], Type[DataPoint]] = {}
63
63
 
64
64
 
65
- def _dynamic_model(type_name: str) -> Type[DataPoint]:
66
- if type_name not in _dynamic_models:
67
- _dynamic_models[type_name] = create_model(type_name, __base__=_DynamicDataPoint)
68
- return _dynamic_models[type_name]
65
+ def _dynamic_model(
66
+ type_name: str,
67
+ property_names: Optional[Iterable[str]] = None,
68
+ index_fields: Optional[List[str]] = None,
69
+ ) -> Type[DataPoint]:
70
+ """A DataPoint subclass named ``type_name`` that DECLARES the record's
71
+ properties as fields and bakes ``index_fields`` into the CLASS-level
72
+ metadata default.
73
+
74
+ Instance-level state is not enough on either count: downstream model
75
+ machinery only sees declared fields. ``get_graph_from_model`` iterates
76
+ declared fields when collecting node properties (``extra="allow"`` values
77
+ are silently dropped — imported DocumentChunk text never reached storage),
78
+ and rebuilds nodes through ``copy_model``, which re-applies class field
79
+ defaults (a plain DataPoint metadata default of ``index_fields: []``
80
+ dropped the embeddable-field markers, so nothing was vector-indexed).
81
+ """
82
+ extra_fields = tuple(
83
+ sorted(
84
+ name
85
+ for name in (property_names or ())
86
+ if name != "metadata" and name not in DataPoint.model_fields
87
+ )
88
+ )
89
+ key = (type_name, extra_fields, tuple(index_fields or ()))
90
+ if key not in _dynamic_models:
91
+ field_definitions: Dict[str, Any] = {name: (Any, None) for name in extra_fields}
92
+ field_definitions["metadata"] = (dict, {"index_fields": list(index_fields or [])})
93
+ _dynamic_models[key] = create_model(
94
+ type_name, __base__=_DynamicDataPoint, **field_definitions
95
+ )
96
+ return _dynamic_models[key]
69
97
 
70
98
 
71
99
  def _clean_properties(properties: Dict[str, Any]) -> Dict[str, Any]:
@@ -101,14 +129,20 @@ def rehydrate_node(
101
129
  except Exception: # noqa: BLE001 — fall back to a dynamic model
102
130
  pass
103
131
 
132
+ # Carry the record's properties and embeddable fields onto the dynamic
133
+ # CLASS so they survive downstream field iteration and copy_model
134
+ # rebuilds (see _dynamic_model).
135
+ metadata = props.get("metadata")
136
+ index_fields = metadata.get("index_fields") if isinstance(metadata, dict) else None
137
+
104
138
  try:
105
139
  # Created lazily: only when the registered class is absent or fails.
106
- return _dynamic_model(type_name)(**props)
140
+ return _dynamic_model(type_name, props, index_fields)(**props)
107
141
  except Exception: # noqa: BLE001 — final fallback below
108
142
  pass
109
143
 
110
144
  base_safe = {key: value for key, value in props.items() if key in _BASE_FIELDS}
111
- return _dynamic_model(type_name)(**base_safe)
145
+ return _dynamic_model(type_name, base_safe, index_fields)(**base_safe)
112
146
 
113
147
 
114
148
  class GraphEdge(BaseModel):
@@ -155,6 +155,18 @@ async def main():
155
155
  assert len(restored_results) != 0, "Search on the restored instance returned nothing."
156
156
  logger.info("Restored search results: %s", restored_results)
157
157
 
158
+ # Chunk-level retrieval needs the imported DocumentChunk text to be
159
+ # vector-indexed (regression: rehydrated raw nodes lost their
160
+ # index_fields, so restored archives had no DocumentChunk_text
161
+ # collection and chunk/hybrid retrieval failed with NoDataError).
162
+ chunk_results = await cognee.search(
163
+ query_type=SearchType.CHUNKS, query_text="rooftop observatory", datasets=[dataset_name]
164
+ )
165
+ assert len(chunk_results) != 0, (
166
+ "Chunk search on the restored instance returned nothing — imported "
167
+ "DocumentChunk text was not vector-indexed."
168
+ )
169
+
158
170
  print("COGX roundtrip e2e passed: export -> fresh store -> import -> search.")
159
171
 
160
172
 
@@ -1,5 +1,6 @@
1
1
  """Unit tests for the Pydantic-native export (GraphSnapshot). Pure: no DB, no LLM."""
2
2
 
3
+ import asyncio
3
4
  from uuid import uuid4
4
5
 
5
6
  from cognee.infrastructure.engine import DataPoint
@@ -68,6 +69,58 @@ class TestRehydrateNode:
68
69
  assert isinstance(node, Entity)
69
70
  assert node.metadata["index_fields"] == ["name"]
70
71
 
72
+ def test_dynamic_model_bakes_index_fields_into_class_default(self):
73
+ node = rehydrate_node(
74
+ {
75
+ "id": str(uuid4()),
76
+ "type": "AlienChunk",
77
+ "text": "Zorg lives on Mars.",
78
+ "metadata": {"index_fields": ["text"]},
79
+ }
80
+ )
81
+ # The CLASS default must carry index_fields, not just the instance:
82
+ # get_graph_from_model rebuilds nodes via copy_model from class field
83
+ # defaults, so instance-only metadata never reaches the vector index.
84
+ assert type(node).model_fields["metadata"].default["index_fields"] == ["text"]
85
+
86
+ def test_index_fields_and_text_survive_graph_extraction(self):
87
+ """Regression: imported DocumentChunk raw nodes fail real-class
88
+ validation (flat properties lack the required relation fields) and
89
+ fall back to a dynamic model. Downstream model machinery only sees
90
+ DECLARED fields, so the dynamic class must declare the record's
91
+ properties AND carry index_fields as its class metadata default —
92
+ otherwise get_graph_from_model drops the chunk's text (extra="allow"
93
+ values are not iterated) and/or its embeddable-field markers
94
+ (copy_model re-applies class defaults), the restored archive has no
95
+ DocumentChunk_text collection, and hybrid retrieval fails with
96
+ NoDataError."""
97
+ from cognee.modules.graph.utils import get_graph_from_model
98
+
99
+ node = rehydrate_node(
100
+ {
101
+ "id": str(uuid4()),
102
+ "type": "DocumentChunk",
103
+ "text": "Alice lives in Berlin.",
104
+ "chunk_index": 0,
105
+ "metadata": {"index_fields": ["text"]},
106
+ }
107
+ )
108
+ assert node.metadata["index_fields"] == ["text"]
109
+ assert node.text == "Alice lives in Berlin."
110
+
111
+ nodes, _ = asyncio.run(
112
+ get_graph_from_model(node, added_nodes={}, added_edges={}, visited_properties={})
113
+ )
114
+ (extracted,) = nodes
115
+ assert extracted.metadata["index_fields"] == ["text"], (
116
+ "index_fields lost during graph extraction — imported chunk text "
117
+ "will not be vector-indexed"
118
+ )
119
+ assert getattr(extracted, "text", None) == "Alice lives in Berlin.", (
120
+ "chunk text lost during graph extraction — undeclared extra fields "
121
+ "are dropped, so the imported chunk stores and indexes as empty"
122
+ )
123
+
71
124
 
72
125
  class TestGraphSnapshot:
73
126
  def _snapshot(self, link_relations=False):
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: cognee
3
- Version: 1.2.2.dev1
3
+ Version: 1.2.2.dev2
4
4
  Summary: Cognee - is a library for enriching LLM context with a semantic layer for better understanding and reasoning.
5
5
  Project-URL: Homepage, https://www.cognee.ai
6
6
  Project-URL: Repository, https://github.com/topoteretes/cognee
@@ -787,7 +787,7 @@ cognee/modules/migration/export.py,sha256=v-GPc1oT41cmXpuU_vqOCX0Us_9sWQZFoVwMTN
787
787
  cognee/modules/migration/formats.py,sha256=-o2hqVwSHXz2O7d_bsxdACZjTd-h8goKoLQ_UqFBcSw,5785
788
788
  cognee/modules/migration/import_source.py,sha256=ch7hSReqAKdt2jzbuY-FyL-hXgDJhrzQWyzE1vgNFx4,11475
789
789
  cognee/modules/migration/loader.py,sha256=1fWim7Zblt-DggcIJ56EjZj0IFP3Up0AxmKztCHNoSU,23935
790
- cognee/modules/migration/snapshot.py,sha256=wYOSuX_N9R3AF5NaHUyX4YbgXil2y7bhJWS3A0srAU4,9084
790
+ cognee/modules/migration/snapshot.py,sha256=z81JRsbLr7Z4jawueOn48OfRkL9fHGe8lRVHFJfm7R8,10773
791
791
  cognee/modules/migration/sources/__init__.py,sha256=HofNJVBO45VaaEWHnC_I7lV5XFtsMLqbm_bpiD3-0Ck,348
792
792
  cognee/modules/migration/sources/base.py,sha256=WXhgaRX9M7GCvLmyzvWkREgGCvTliJwk_DGK7LjicVE,2135
793
793
  cognee/modules/migration/sources/cogx_archive.py,sha256=x4wz5E-Gim7_vLkB9JFJ9NiZB_JIFKt5ISA1VZNToGs,1569
@@ -1261,7 +1261,7 @@ cognee/tests/test_advanced_pdf_loader.py,sha256=0Jdg4ZZ67_3dg5Z0bCYzubHSLYDQtNgH
1261
1261
  cognee/tests/test_agent_memory_e2e.py,sha256=I1d52atkk0r0dycBG_FTu7_gOyQL-tYt067dW-GTQF0,6681
1262
1262
  cognee/tests/test_chunk_associations.py,sha256=OnsX3a9pLV_Yaj7Xyb297mOciihEz3TFK5uwhbjh_80,8182
1263
1263
  cognee/tests/test_cognee_server_start.py,sha256=nld8SkG4WHUPiHVz6872ImWmcERcUnNN_-6Gf8fUj0E,7572
1264
- cognee/tests/test_cogx_roundtrip.py,sha256=QgISGfRT97TGs1zH4Z-A0-27QuMw5UjEk2xWDPQB_AY,6883
1264
+ cognee/tests/test_cogx_roundtrip.py,sha256=K0kiGxZ1COFsytTS5zfhymMwClWCUTOQK7VTsWOZxgk,7522
1265
1265
  cognee/tests/test_concurrent_cognify_e2e.py,sha256=tdmp0QA6uatFd5YL0bBahk8GWq-GG8LKrhiDfrP4jWQ,5682
1266
1266
  cognee/tests/test_concurrent_subprocess_access.py,sha256=xh72FclRY1LnwUbpmIQTzvK7Yayoov6oewWmHivPTxE,3041
1267
1267
  cognee/tests/test_conversation_history.py,sha256=80be_RWiT4acwZ6agSQY2ch69hmJ8MN-RSeL2qIx0pM,18186
@@ -1547,7 +1547,7 @@ cognee/tests/unit/migration/test_migration.py,sha256=5tqGzk01dsfhGxDDRzyumQ2fotb
1547
1547
  cognee/tests/unit/migration/test_provenance_ctx.py,sha256=GHiAA8NLs2JWaeztyFJuaeeuo9NScgzUNtQGX5wguuA,3057
1548
1548
  cognee/tests/unit/migration/test_push.py,sha256=GYRZXhAKHsyWSNLYa23PDCM9qX5BoXlRY9EWRe-8TwY,16905
1549
1549
  cognee/tests/unit/migration/test_remember_router_cogx.py,sha256=Q72DFoaW9gjdGZI07EXSgU_pQlhnr0-5LlDx1TY_h-A,12156
1550
- cognee/tests/unit/migration/test_snapshot.py,sha256=tdzSUAHq187ZaN8gMBlF2WBe9ABv6kBw6VYu6Os4sHU,4898
1550
+ cognee/tests/unit/migration/test_snapshot.py,sha256=dfXsSqT6X9DIRFS9Qac5emimLyjOR08j5YvJyc9KPOk,7383
1551
1551
  cognee/tests/unit/modules/agent_memory/test_agent_memory.py,sha256=AGgsjsS1BTvdJbgX6M4peNgkbMBbRSHGH2BRD2sLuXc,40791
1552
1552
  cognee/tests/unit/modules/agents/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
1553
1553
  cognee/tests/unit/modules/agents/conftest.py,sha256=5QcS2mitl-wl1ytZVm1_T7SAofrPhgBbs4P3I95nLJE,1027
@@ -1713,9 +1713,9 @@ distributed/workers/data_point_saving_worker.py,sha256=kmaQy2A2J7W3k9Gd5lyoiT0XY
1713
1713
  distributed/workers/graph_saving_worker.py,sha256=KVds58rBh-m3TnOyouE4cqSDnzIHNRqw-Td06abOGS0,4961
1714
1714
  kuzu/__init__.py,sha256=NqYsYyycqMZOUte0_3r_eO5VJGe_BCNdOdLPpJTvgdk,224
1715
1715
  kuzu/database.py,sha256=JfHFK1YAFKrnSId0p_5sqFwhX2IWfKo0MFNEPPNeQ9k,154
1716
- cognee-1.2.2.dev1.dist-info/METADATA,sha256=Rl32xhDD3k-Se-Ur0hybsHY5vSZim72PFlVlBZ5yed0,26799
1717
- cognee-1.2.2.dev1.dist-info/WHEEL,sha256=mffPy8wBnZQn2VnJUU5jE99KsxaSfiyMHV9Yt0aLVxs,87
1718
- cognee-1.2.2.dev1.dist-info/entry_points.txt,sha256=GCCTsNg8gzOJkolq7dR7OK1VlIAO202dGDnMI8nm8oQ,55
1719
- cognee-1.2.2.dev1.dist-info/licenses/LICENSE,sha256=pHHjSQj1DD8SDppW88MMs04TPk7eAanL1c5xj8NY7NQ,11344
1720
- cognee-1.2.2.dev1.dist-info/licenses/NOTICE.md,sha256=6L3saP3kSpcingOxDh-SGjMS8GY79Rlh2dBNLaO0o5c,339
1721
- cognee-1.2.2.dev1.dist-info/RECORD,,
1716
+ cognee-1.2.2.dev2.dist-info/METADATA,sha256=iNvFhyIiE25-hlxU5l-vrhJn-uosLnwDT8JnFnxGGss,26799
1717
+ cognee-1.2.2.dev2.dist-info/WHEEL,sha256=mffPy8wBnZQn2VnJUU5jE99KsxaSfiyMHV9Yt0aLVxs,87
1718
+ cognee-1.2.2.dev2.dist-info/entry_points.txt,sha256=GCCTsNg8gzOJkolq7dR7OK1VlIAO202dGDnMI8nm8oQ,55
1719
+ cognee-1.2.2.dev2.dist-info/licenses/LICENSE,sha256=pHHjSQj1DD8SDppW88MMs04TPk7eAanL1c5xj8NY7NQ,11344
1720
+ cognee-1.2.2.dev2.dist-info/licenses/NOTICE.md,sha256=6L3saP3kSpcingOxDh-SGjMS8GY79Rlh2dBNLaO0o5c,339
1721
+ cognee-1.2.2.dev2.dist-info/RECORD,,