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

graphiti_core/graphiti.py CHANGED
@@ -1070,6 +1070,7 @@ class Graphiti:
1070
1070
  group_id=edge.group_id,
1071
1071
  ),
1072
1072
  None,
1073
+ None,
1073
1074
  self.ensure_ascii,
1074
1075
  )
1075
1076
 
@@ -477,6 +477,7 @@ async def dedupe_edges_bulk(
477
477
  candidates,
478
478
  episode,
479
479
  edge_types,
480
+ set(edge_types),
480
481
  clients.ensure_ascii,
481
482
  )
482
483
  for episode, edge, candidates in dedupe_tuples
@@ -283,8 +283,12 @@ async def resolve_extracted_edges(
283
283
  # Build entity hash table
284
284
  uuid_entity_map: dict[str, EntityNode] = {entity.uuid: entity for entity in entities}
285
285
 
286
- # Determine which edge types are relevant for each edge
286
+ # Determine which edge types are relevant for each edge.
287
+ # `edge_types_lst` stores the subset of custom edge definitions whose
288
+ # node signature matches each extracted edge. Anything outside this subset
289
+ # should only stay on the edge if it is a non-custom (LLM generated) label.
287
290
  edge_types_lst: list[dict[str, type[BaseModel]]] = []
291
+ custom_type_names = set(edge_types or {})
288
292
  for extracted_edge in extracted_edges:
289
293
  source_node = uuid_entity_map.get(extracted_edge.source_node_uuid)
290
294
  target_node = uuid_entity_map.get(extracted_edge.target_node_uuid)
@@ -314,11 +318,16 @@ async def resolve_extracted_edges(
314
318
 
315
319
  for extracted_edge, extracted_edge_types in zip(extracted_edges, edge_types_lst, strict=True):
316
320
  allowed_type_names = set(extracted_edge_types)
321
+ is_custom_name = extracted_edge.name in custom_type_names
317
322
  if not allowed_type_names:
318
- if extracted_edge.name != DEFAULT_EDGE_NAME:
323
+ # No custom types are valid for this node pairing. Keep LLM generated
324
+ # labels, but flip disallowed custom names back to the default.
325
+ if is_custom_name and extracted_edge.name != DEFAULT_EDGE_NAME:
319
326
  extracted_edge.name = DEFAULT_EDGE_NAME
320
327
  continue
321
- if extracted_edge.name not in allowed_type_names:
328
+ if is_custom_name and extracted_edge.name not in allowed_type_names:
329
+ # Custom name exists but it is not permitted for this source/target
330
+ # signature, so fall back to the default edge label.
322
331
  extracted_edge.name = DEFAULT_EDGE_NAME
323
332
 
324
333
  # resolve edges with related edges in the graph and find invalidation candidates
@@ -332,6 +341,7 @@ async def resolve_extracted_edges(
332
341
  existing_edges,
333
342
  episode,
334
343
  extracted_edge_types,
344
+ custom_type_names,
335
345
  clients.ensure_ascii,
336
346
  )
337
347
  for extracted_edge, related_edges, existing_edges, extracted_edge_types in zip(
@@ -404,8 +414,37 @@ async def resolve_extracted_edge(
404
414
  existing_edges: list[EntityEdge],
405
415
  episode: EpisodicNode,
406
416
  edge_type_candidates: dict[str, type[BaseModel]] | None = None,
417
+ custom_edge_type_names: set[str] | None = None,
407
418
  ensure_ascii: bool = True,
408
419
  ) -> tuple[EntityEdge, list[EntityEdge], list[EntityEdge]]:
420
+ """Resolve an extracted edge against existing graph context.
421
+
422
+ Parameters
423
+ ----------
424
+ llm_client : LLMClient
425
+ Client used to invoke the LLM for deduplication and attribute extraction.
426
+ extracted_edge : EntityEdge
427
+ Newly extracted edge whose canonical representation is being resolved.
428
+ related_edges : list[EntityEdge]
429
+ Candidate edges with identical endpoints used for duplicate detection.
430
+ existing_edges : list[EntityEdge]
431
+ Broader set of edges evaluated for contradiction / invalidation.
432
+ episode : EpisodicNode
433
+ Episode providing content context when extracting edge attributes.
434
+ edge_type_candidates : dict[str, type[BaseModel]] | None
435
+ Custom edge types permitted for the current source/target signature.
436
+ custom_edge_type_names : set[str] | None
437
+ Full catalog of registered custom edge names. Used to distinguish
438
+ between disallowed custom types (which fall back to the default label)
439
+ and ad-hoc labels emitted by the LLM.
440
+ ensure_ascii : bool
441
+ Whether prompt payloads should coerce ASCII output.
442
+
443
+ Returns
444
+ -------
445
+ tuple[EntityEdge, list[EntityEdge], list[EntityEdge]]
446
+ The resolved edge, any duplicates, and edges to invalidate.
447
+ """
409
448
  if len(related_edges) == 0 and len(existing_edges) == 0:
410
449
  return extracted_edge, [], []
411
450
 
@@ -480,7 +519,15 @@ async def resolve_extracted_edge(
480
519
 
481
520
  fact_type: str = response_object.fact_type
482
521
  candidate_type_names = set(edge_type_candidates or {})
483
- if candidate_type_names and fact_type in candidate_type_names:
522
+ custom_type_names = custom_edge_type_names or set()
523
+
524
+ is_default_type = fact_type.upper() == 'DEFAULT'
525
+ is_custom_type = fact_type in custom_type_names
526
+ is_allowed_custom_type = fact_type in candidate_type_names
527
+
528
+ if is_allowed_custom_type:
529
+ # The LLM selected a custom type that is allowed for the node pair.
530
+ # Adopt the custom type and, if needed, extract its structured attributes.
484
531
  resolved_edge.name = fact_type
485
532
 
486
533
  edge_attributes_context = {
@@ -499,9 +546,16 @@ async def resolve_extracted_edge(
499
546
  )
500
547
 
501
548
  resolved_edge.attributes = edge_attributes_response
502
- elif fact_type.upper() != 'DEFAULT':
549
+ elif not is_default_type and is_custom_type:
550
+ # The LLM picked a custom type that is not allowed for this signature.
551
+ # Reset to the default label and drop any structured attributes.
503
552
  resolved_edge.name = DEFAULT_EDGE_NAME
504
553
  resolved_edge.attributes = {}
554
+ elif not is_default_type:
555
+ # Non-custom labels are allowed to pass through so long as the LLM does
556
+ # not return the sentinel DEFAULT value.
557
+ resolved_edge.name = fact_type
558
+ resolved_edge.attributes = {}
505
559
 
506
560
  end = time()
507
561
  logger.debug(
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: graphiti-core
3
- Version: 0.30.0rc4
3
+ Version: 0.30.0rc5
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
@@ -20,6 +20,7 @@ Provides-Extra: anthropic
20
20
  Requires-Dist: anthropic>=0.49.0; extra == 'anthropic'
21
21
  Provides-Extra: dev
22
22
  Requires-Dist: anthropic>=0.49.0; extra == 'dev'
23
+ Requires-Dist: boto3>=1.39.16; extra == 'dev'
23
24
  Requires-Dist: diskcache-stubs>=5.6.3.6.20240818; extra == 'dev'
24
25
  Requires-Dist: falkordb<2.0.0,>=1.1.2; extra == 'dev'
25
26
  Requires-Dist: google-genai>=1.8.0; extra == 'dev'
@@ -28,9 +29,11 @@ Requires-Dist: ipykernel>=6.29.5; extra == 'dev'
28
29
  Requires-Dist: jupyterlab>=4.2.4; extra == 'dev'
29
30
  Requires-Dist: kuzu>=0.11.2; extra == 'dev'
30
31
  Requires-Dist: langchain-anthropic>=0.2.4; extra == 'dev'
32
+ Requires-Dist: langchain-aws>=0.2.29; extra == 'dev'
31
33
  Requires-Dist: langchain-openai>=0.2.6; extra == 'dev'
32
34
  Requires-Dist: langgraph>=0.2.15; extra == 'dev'
33
35
  Requires-Dist: langsmith>=0.1.108; extra == 'dev'
36
+ Requires-Dist: opensearch-py>=3.0.0; extra == 'dev'
34
37
  Requires-Dist: pyright>=1.1.404; extra == 'dev'
35
38
  Requires-Dist: pytest-asyncio>=0.24.0; extra == 'dev'
36
39
  Requires-Dist: pytest-xdist>=3.6.1; extra == 'dev'
@@ -2,7 +2,7 @@ graphiti_core/__init__.py,sha256=e5SWFkRiaUwfprYIeIgVIh7JDedNiloZvd3roU-0aDY,55
2
2
  graphiti_core/edges.py,sha256=PhJm_s28cHLEaIqcw66wP16hOq4P4bVQbC_sESHQkXU,20919
3
3
  graphiti_core/errors.py,sha256=cH_v9TPgEPeQE6GFOHIg5TvejpUCBddGarMY2Whxbwc,2707
4
4
  graphiti_core/graph_queries.py,sha256=ZWMqAo5pwb8PO5ddg4zZ0ArhHWuWV42g3R9ULIxsHOs,8058
5
- graphiti_core/graphiti.py,sha256=fC7CCGeZDNAGK2Bj2tW30QzHMAjqWvpYZiY1A0yUvHM,41917
5
+ graphiti_core/graphiti.py,sha256=5Y3SdcC_Ebhp-oqbbIxb0KGshWU24EQx4YYKvK8Id8g,41935
6
6
  graphiti_core/graphiti_types.py,sha256=C_p2XwScQlCzo7ets097TrSLs9ATxPZQ4WCsxDS7QHc,1066
7
7
  graphiti_core/helpers.py,sha256=q8kbL9gz8igdlh-oMUS-ylUyeMlXZb-ccf-HQkrES_0,5184
8
8
  graphiti_core/nodes.py,sha256=wYLQcVEXvQMxTpTc9LWSoPTzzaoUOm0rl07c9wS1XSY,30323
@@ -64,18 +64,18 @@ graphiti_core/search/search_utils.py,sha256=ak1aBeKNuxS7szydNHwva2ABWSRlQ0S_v8ZO
64
64
  graphiti_core/telemetry/__init__.py,sha256=5kALLDlU9bb2v19CdN7qVANsJWyfnL9E60J6FFgzm3o,226
65
65
  graphiti_core/telemetry/telemetry.py,sha256=47LrzOVBCcZxsYPsnSxWFiztHoxYKKxPwyRX0hnbDGc,3230
66
66
  graphiti_core/utils/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
67
- graphiti_core/utils/bulk_utils.py,sha256=yeURrhy6whJQDYiFfwna7bPDy0HF04WNfRZRSpPv4E8,20255
67
+ graphiti_core/utils/bulk_utils.py,sha256=0rpBaPg1CBQu7djcSS9XWfv9T1unRRVW8_ge_Tf7lF0,20288
68
68
  graphiti_core/utils/datetime_utils.py,sha256=J-zYSq7-H-2n9hYOXNIun12kM10vNX9mMATGR_egTmY,1806
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=LHud849E-w6_arUszhbCEdqVxWFk_Hm-jv60YIY51zo,22015
72
+ graphiti_core/utils/maintenance/edge_operations.py,sha256=9bRCI_3loKJX3EAMLpNULWLnhSDCHsCghiqbXPdicPM,24808
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.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,,
78
+ graphiti_core-0.30.0rc5.dist-info/METADATA,sha256=mHYpDhzM0wWbKChp3NqY8WbiLRfFroA718M6SOtKUy8,27084
79
+ graphiti_core-0.30.0rc5.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
80
+ graphiti_core-0.30.0rc5.dist-info/licenses/LICENSE,sha256=KCUwCyDXuVEgmDWkozHyniRyWjnWUWjkuDHfU6o3JlA,11325
81
+ graphiti_core-0.30.0rc5.dist-info/RECORD,,