graphiti-core 0.30.0rc2__py3-none-any.whl → 0.30.0rc4__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.

Potentially problematic release.


This version of graphiti-core might be problematic. Click here for more details.

@@ -92,12 +92,23 @@ def node(context: dict[str, Any]) -> list[Message]:
92
92
 
93
93
  TASK:
94
94
  1. Compare `new_entity` against each item in `existing_entities`.
95
- 2. If it refers to the same realworld object or concept, collect its index.
96
- 3. Let `duplicate_idx` = the *first* collected index, or 1 if none.
97
- 4. Let `duplicates` = the list of *all* collected indices (empty list if none).
98
-
99
- Also return the full name of the NEW ENTITY (whether it is the name of the NEW ENTITY, a node it
100
- is a duplicate of, or a combination of the two).
95
+ 2. If it refers to the same real-world object or concept, collect its index.
96
+ 3. Let `duplicate_idx` = the smallest collected index, or -1 if none.
97
+ 4. Let `duplicates` = the sorted list of all collected indices (empty list if none).
98
+
99
+ Respond with a JSON object containing an "entity_resolutions" array with a single entry:
100
+ {{
101
+ "entity_resolutions": [
102
+ {{
103
+ "id": integer id from NEW ENTITY,
104
+ "name": the best full name for the entity,
105
+ "duplicate_idx": integer index of the best duplicate in EXISTING ENTITIES, or -1 if none,
106
+ "duplicates": sorted list of all duplicate indices you collected (deduplicate the list, use [] when none)
107
+ }}
108
+ ]
109
+ }}
110
+
111
+ Only reference indices that appear in EXISTING ENTITIES, and return [] / -1 when unsure.
101
112
  """,
102
113
  ),
103
114
  ]
@@ -126,26 +137,26 @@ def nodes(context: dict[str, Any]) -> list[Message]:
126
137
  {{
127
138
  id: integer id of the entity,
128
139
  name: "name of the entity",
129
- entity_type: "ontological classification of the entity",
130
- entity_type_description: "Description of what the entity type represents",
131
- duplication_candidates: [
132
- {{
133
- idx: integer index of the candidate entity,
134
- name: "name of the candidate entity",
135
- entity_type: "ontological classification of the candidate entity",
136
- ...<additional attributes>
137
- }}
138
- ]
140
+ entity_type: ["Entity", "<optional additional label>", ...],
141
+ entity_type_description: "Description of what the entity type represents"
139
142
  }}
140
-
143
+
141
144
  <ENTITIES>
142
145
  {to_prompt_json(context['extracted_nodes'], ensure_ascii=context.get('ensure_ascii', True), indent=2)}
143
146
  </ENTITIES>
144
-
147
+
145
148
  <EXISTING ENTITIES>
146
149
  {to_prompt_json(context['existing_nodes'], ensure_ascii=context.get('ensure_ascii', True), indent=2)}
147
150
  </EXISTING ENTITIES>
148
151
 
152
+ Each entry in EXISTING ENTITIES is an object with the following structure:
153
+ {{
154
+ idx: integer index of the candidate entity (use this when referencing a duplicate),
155
+ name: "name of the candidate entity",
156
+ entity_types: ["Entity", "<optional additional label>", ...],
157
+ ...<additional attributes such as summaries or metadata>
158
+ }}
159
+
149
160
  For each of the above ENTITIES, determine if the entity is a duplicate of any of the EXISTING ENTITIES.
150
161
 
151
162
  Entities should only be considered duplicates if they refer to the *same real-world object or concept*.
@@ -155,14 +166,19 @@ def nodes(context: dict[str, Any]) -> list[Message]:
155
166
  - They have similar names or purposes but refer to separate instances or concepts.
156
167
 
157
168
  Task:
158
- Your response will be a list called entity_resolutions which contains one entry for each entity.
159
-
160
- For each entity, return the id of the entity as id, the name of the entity as name, and the duplicate_idx
161
- as an integer.
162
-
163
- - If an entity is a duplicate of one of the EXISTING ENTITIES, return the idx of the candidate it is a
164
- duplicate of.
165
- - If an entity is not a duplicate of one of the EXISTING ENTITIES, return the -1 as the duplication_idx
169
+ Respond with a JSON object that contains an "entity_resolutions" array with one entry for each entity in ENTITIES, ordered by the entity id.
170
+
171
+ For every entity, return an object with the following keys:
172
+ {{
173
+ "id": integer id from ENTITIES,
174
+ "name": the best full name for the entity (preserve the original name unless a duplicate has a more complete name),
175
+ "duplicate_idx": the idx of the EXISTING ENTITY that is the best duplicate match, or -1 if there is no duplicate,
176
+ "duplicates": a sorted list of all idx values from EXISTING ENTITIES that refer to duplicates (deduplicate the list, use [] when none or unsure)
177
+ }}
178
+
179
+ - Only use idx values that appear in EXISTING ENTITIES.
180
+ - Set duplicate_idx to the smallest idx you collected for that entity, or -1 if duplicates is empty.
181
+ - Never fabricate entities or indices.
166
182
  """,
167
183
  ),
168
184
  ]
@@ -43,6 +43,8 @@ from graphiti_core.search.search_filters import SearchFilters
43
43
  from graphiti_core.utils.datetime_utils import ensure_utc, utc_now
44
44
  from graphiti_core.utils.maintenance.dedup_helpers import _normalize_string_exact
45
45
 
46
+ DEFAULT_EDGE_NAME = 'RELATES_TO'
47
+
46
48
  logger = logging.getLogger(__name__)
47
49
 
48
50
 
@@ -310,6 +312,15 @@ async def resolve_extracted_edges(
310
312
 
311
313
  edge_types_lst.append(extracted_edge_types)
312
314
 
315
+ for extracted_edge, extracted_edge_types in zip(extracted_edges, edge_types_lst, strict=True):
316
+ allowed_type_names = set(extracted_edge_types)
317
+ if not allowed_type_names:
318
+ if extracted_edge.name != DEFAULT_EDGE_NAME:
319
+ extracted_edge.name = DEFAULT_EDGE_NAME
320
+ continue
321
+ if extracted_edge.name not in allowed_type_names:
322
+ extracted_edge.name = DEFAULT_EDGE_NAME
323
+
313
324
  # resolve edges with related edges in the graph and find invalidation candidates
314
325
  results: list[tuple[EntityEdge, list[EntityEdge], list[EntityEdge]]] = list(
315
326
  await semaphore_gather(
@@ -392,7 +403,7 @@ async def resolve_extracted_edge(
392
403
  related_edges: list[EntityEdge],
393
404
  existing_edges: list[EntityEdge],
394
405
  episode: EpisodicNode,
395
- edge_types: dict[str, type[BaseModel]] | None = None,
406
+ edge_type_candidates: dict[str, type[BaseModel]] | None = None,
396
407
  ensure_ascii: bool = True,
397
408
  ) -> tuple[EntityEdge, list[EntityEdge], list[EntityEdge]]:
398
409
  if len(related_edges) == 0 and len(existing_edges) == 0:
@@ -429,9 +440,9 @@ async def resolve_extracted_edge(
429
440
  'fact_type_name': type_name,
430
441
  'fact_type_description': type_model.__doc__,
431
442
  }
432
- for i, (type_name, type_model) in enumerate(edge_types.items())
443
+ for i, (type_name, type_model) in enumerate(edge_type_candidates.items())
433
444
  ]
434
- if edge_types is not None
445
+ if edge_type_candidates is not None
435
446
  else []
436
447
  )
437
448
 
@@ -468,7 +479,8 @@ async def resolve_extracted_edge(
468
479
  ]
469
480
 
470
481
  fact_type: str = response_object.fact_type
471
- if fact_type.upper() != 'DEFAULT' and edge_types is not None:
482
+ candidate_type_names = set(edge_type_candidates or {})
483
+ if candidate_type_names and fact_type in candidate_type_names:
472
484
  resolved_edge.name = fact_type
473
485
 
474
486
  edge_attributes_context = {
@@ -478,7 +490,7 @@ async def resolve_extracted_edge(
478
490
  'ensure_ascii': ensure_ascii,
479
491
  }
480
492
 
481
- edge_model = edge_types.get(fact_type)
493
+ edge_model = edge_type_candidates.get(fact_type) if edge_type_candidates else None
482
494
  if edge_model is not None and len(edge_model.model_fields) != 0:
483
495
  edge_attributes_response = await llm_client.generate_response(
484
496
  prompt_library.extract_edges.extract_attributes(edge_attributes_context),
@@ -487,6 +499,9 @@ async def resolve_extracted_edge(
487
499
  )
488
500
 
489
501
  resolved_edge.attributes = edge_attributes_response
502
+ elif fact_type.upper() != 'DEFAULT':
503
+ resolved_edge.name = DEFAULT_EDGE_NAME
504
+ resolved_edge.attributes = {}
490
505
 
491
506
  end = time()
492
507
  logger.debug(
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: graphiti-core
3
- Version: 0.30.0rc2
3
+ Version: 0.30.0rc4
4
4
  Summary: A temporal graph building library
5
5
  Project-URL: Homepage, https://help.getzep.com/graphiti/graphiti/overview
6
6
  Project-URL: Repository, https://github.com/getzep/graphiti
@@ -44,7 +44,7 @@ graphiti_core/models/nodes/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJ
44
44
  graphiti_core/models/nodes/node_db_queries.py,sha256=TCHZKG5bQNarV9C5k4hOFFqc-LwTVQ8Pnd6okVVNKbo,12826
45
45
  graphiti_core/prompts/__init__.py,sha256=EA-x9xUki9l8wnu2l8ek_oNf75-do5tq5hVq7Zbv8Kw,101
46
46
  graphiti_core/prompts/dedupe_edges.py,sha256=WRXQi7JQZdIfKDICWyU7Wbs5WyD_KBblLBSeKdbLyuk,5914
47
- graphiti_core/prompts/dedupe_nodes.py,sha256=eYDk0axHEKLjZS2tKlT4Zy1fW9EJkn6EnrJLSN0fvAY,8235
47
+ graphiti_core/prompts/dedupe_nodes.py,sha256=H4sIzpi1gBwPedTMhdY175jnLj5JtnEeb_WNITitPLU,9171
48
48
  graphiti_core/prompts/eval.py,sha256=ijwxbE87G678imdhfPvRujepQMq_JZ3XHX4vOAcVnVI,5507
49
49
  graphiti_core/prompts/extract_edge_dates.py,sha256=3Drs3CmvP0gJN5BidWSxrNvLet3HPoTybU3BUIAoc0Y,4218
50
50
  graphiti_core/prompts/extract_edges.py,sha256=mnncxb6lyr3ufKajRAh09czmJawiEM54sSPNy9ukiio,6888
@@ -69,13 +69,13 @@ graphiti_core/utils/datetime_utils.py,sha256=J-zYSq7-H-2n9hYOXNIun12kM10vNX9mMAT
69
69
  graphiti_core/utils/maintenance/__init__.py,sha256=vW4H1KyapTl-OOz578uZABYcpND4wPx3Vt6aAPaXh78,301
70
70
  graphiti_core/utils/maintenance/community_operations.py,sha256=XMiokEemn96GlvjkOvbo9hIX04Fea3eVj408NHG5P4o,11042
71
71
  graphiti_core/utils/maintenance/dedup_helpers.py,sha256=B7k6KkB6Sii8PZCWNNTvsNiy4BNTNWpoLeGgrPLq6BE,9220
72
- graphiti_core/utils/maintenance/edge_operations.py,sha256=fvWKJWzz4_d2Y8bOfZFjJpLnGmsFwnrutFW25LX-S08,21287
72
+ graphiti_core/utils/maintenance/edge_operations.py,sha256=LHud849E-w6_arUszhbCEdqVxWFk_Hm-jv60YIY51zo,22015
73
73
  graphiti_core/utils/maintenance/graph_data_operations.py,sha256=42icj3S_ELAJ-NK3jVS_rg_243dmnaZOyUitJj_uJ-M,6085
74
74
  graphiti_core/utils/maintenance/node_operations.py,sha256=TKpXPtnTVxxan8I1xQyVkGn3zyRdb_Q00cgUpLcloig,16860
75
75
  graphiti_core/utils/maintenance/temporal_operations.py,sha256=IIaVtShpVkOYe6haxz3a1x3v54-MzaEXG8VsxFUNeoY,3582
76
76
  graphiti_core/utils/maintenance/utils.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
77
77
  graphiti_core/utils/ontology_utils/entity_types_utils.py,sha256=4eVgxLWY6Q8k9cRJ5pW59IYF--U4nXZsZIGOVb_yHfQ,1285
78
- graphiti_core-0.30.0rc2.dist-info/METADATA,sha256=eGlZ91MklPKsP1m7Me1RivW4qPnc9wff6uIGZ5XRVqI,26933
79
- graphiti_core-0.30.0rc2.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
80
- graphiti_core-0.30.0rc2.dist-info/licenses/LICENSE,sha256=KCUwCyDXuVEgmDWkozHyniRyWjnWUWjkuDHfU6o3JlA,11325
81
- graphiti_core-0.30.0rc2.dist-info/RECORD,,
78
+ graphiti_core-0.30.0rc4.dist-info/METADATA,sha256=W12RaBo2Hhk7ttsTVOIJbMZyj11BqH1B_4UTVJENqUw,26933
79
+ graphiti_core-0.30.0rc4.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
80
+ graphiti_core-0.30.0rc4.dist-info/licenses/LICENSE,sha256=KCUwCyDXuVEgmDWkozHyniRyWjnWUWjkuDHfU6o3JlA,11325
81
+ graphiti_core-0.30.0rc4.dist-info/RECORD,,