graphiti-core 0.30.0rc3__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
@@ -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
 
@@ -281,8 +283,12 @@ async def resolve_extracted_edges(
281
283
  # Build entity hash table
282
284
  uuid_entity_map: dict[str, EntityNode] = {entity.uuid: entity for entity in entities}
283
285
 
284
- # 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.
285
290
  edge_types_lst: list[dict[str, type[BaseModel]]] = []
291
+ custom_type_names = set(edge_types or {})
286
292
  for extracted_edge in extracted_edges:
287
293
  source_node = uuid_entity_map.get(extracted_edge.source_node_uuid)
288
294
  target_node = uuid_entity_map.get(extracted_edge.target_node_uuid)
@@ -310,6 +316,20 @@ async def resolve_extracted_edges(
310
316
 
311
317
  edge_types_lst.append(extracted_edge_types)
312
318
 
319
+ for extracted_edge, extracted_edge_types in zip(extracted_edges, edge_types_lst, strict=True):
320
+ allowed_type_names = set(extracted_edge_types)
321
+ is_custom_name = extracted_edge.name in custom_type_names
322
+ if not allowed_type_names:
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:
326
+ extracted_edge.name = DEFAULT_EDGE_NAME
327
+ continue
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.
331
+ extracted_edge.name = DEFAULT_EDGE_NAME
332
+
313
333
  # resolve edges with related edges in the graph and find invalidation candidates
314
334
  results: list[tuple[EntityEdge, list[EntityEdge], list[EntityEdge]]] = list(
315
335
  await semaphore_gather(
@@ -321,6 +341,7 @@ async def resolve_extracted_edges(
321
341
  existing_edges,
322
342
  episode,
323
343
  extracted_edge_types,
344
+ custom_type_names,
324
345
  clients.ensure_ascii,
325
346
  )
326
347
  for extracted_edge, related_edges, existing_edges, extracted_edge_types in zip(
@@ -392,9 +413,38 @@ async def resolve_extracted_edge(
392
413
  related_edges: list[EntityEdge],
393
414
  existing_edges: list[EntityEdge],
394
415
  episode: EpisodicNode,
395
- edge_types: dict[str, type[BaseModel]] | None = None,
416
+ edge_type_candidates: dict[str, type[BaseModel]] | None = None,
417
+ custom_edge_type_names: set[str] | None = None,
396
418
  ensure_ascii: bool = True,
397
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
+ """
398
448
  if len(related_edges) == 0 and len(existing_edges) == 0:
399
449
  return extracted_edge, [], []
400
450
 
@@ -429,9 +479,9 @@ async def resolve_extracted_edge(
429
479
  'fact_type_name': type_name,
430
480
  'fact_type_description': type_model.__doc__,
431
481
  }
432
- for i, (type_name, type_model) in enumerate(edge_types.items())
482
+ for i, (type_name, type_model) in enumerate(edge_type_candidates.items())
433
483
  ]
434
- if edge_types is not None
484
+ if edge_type_candidates is not None
435
485
  else []
436
486
  )
437
487
 
@@ -468,7 +518,16 @@ async def resolve_extracted_edge(
468
518
  ]
469
519
 
470
520
  fact_type: str = response_object.fact_type
471
- if fact_type.upper() != 'DEFAULT' and edge_types is not None:
521
+ candidate_type_names = set(edge_type_candidates or {})
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.
472
531
  resolved_edge.name = fact_type
473
532
 
474
533
  edge_attributes_context = {
@@ -478,7 +537,7 @@ async def resolve_extracted_edge(
478
537
  'ensure_ascii': ensure_ascii,
479
538
  }
480
539
 
481
- edge_model = edge_types.get(fact_type)
540
+ edge_model = edge_type_candidates.get(fact_type) if edge_type_candidates else None
482
541
  if edge_model is not None and len(edge_model.model_fields) != 0:
483
542
  edge_attributes_response = await llm_client.generate_response(
484
543
  prompt_library.extract_edges.extract_attributes(edge_attributes_context),
@@ -487,6 +546,16 @@ async def resolve_extracted_edge(
487
546
  )
488
547
 
489
548
  resolved_edge.attributes = edge_attributes_response
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.
552
+ resolved_edge.name = DEFAULT_EDGE_NAME
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 = {}
490
559
 
491
560
  end = time()
492
561
  logger.debug(
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: graphiti-core
3
- Version: 0.30.0rc3
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=fvWKJWzz4_d2Y8bOfZFjJpLnGmsFwnrutFW25LX-S08,21287
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.0rc3.dist-info/METADATA,sha256=y9D976_UrZVxaSYxn8yEVDHl9bTHk1d9fcWoffuDO7Y,26933
79
- graphiti_core-0.30.0rc3.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
80
- graphiti_core-0.30.0rc3.dist-info/licenses/LICENSE,sha256=KCUwCyDXuVEgmDWkozHyniRyWjnWUWjkuDHfU6o3JlA,11325
81
- graphiti_core-0.30.0rc3.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,,