graphiti-core 0.21.0rc9__py3-none-any.whl → 0.21.0rc11__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/edges.py CHANGED
@@ -644,8 +644,11 @@ def get_community_edge_from_record(record: Any):
644
644
 
645
645
 
646
646
  async def create_entity_edge_embeddings(embedder: EmbedderClient, edges: list[EntityEdge]):
647
- if len(edges) == 0:
647
+ # filter out falsey values from edges
648
+ filtered_edges = [edge for edge in edges if edge.fact]
649
+
650
+ if len(filtered_edges) == 0:
648
651
  return
649
- fact_embeddings = await embedder.create_batch([edge.fact for edge in edges])
650
- for edge, fact_embedding in zip(edges, fact_embeddings, strict=True):
652
+ fact_embeddings = await embedder.create_batch([edge.fact for edge in filtered_edges])
653
+ for edge, fact_embedding in zip(filtered_edges, fact_embeddings, strict=True):
651
654
  edge.fact_embedding = fact_embedding
graphiti_core/nodes.py CHANGED
@@ -868,9 +868,12 @@ def get_community_node_from_record(record: Any) -> CommunityNode:
868
868
 
869
869
 
870
870
  async def create_entity_node_embeddings(embedder: EmbedderClient, nodes: list[EntityNode]):
871
- if not nodes: # Handle empty list case
871
+ # filter out falsey values from nodes
872
+ filtered_nodes = [node for node in nodes if node.name]
873
+
874
+ if not filtered_nodes:
872
875
  return
873
876
 
874
- name_embeddings = await embedder.create_batch([node.name for node in nodes])
875
- for node, name_embedding in zip(nodes, name_embeddings, strict=True):
877
+ name_embeddings = await embedder.create_batch([node.name for node in filtered_nodes])
878
+ for node, name_embedding in zip(filtered_nodes, name_embeddings, strict=True):
876
879
  node.name_embedding = name_embedding
@@ -166,7 +166,8 @@ def nodes(context: dict[str, Any]) -> list[Message]:
166
166
  - They have similar names or purposes but refer to separate instances or concepts.
167
167
 
168
168
  Task:
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.
169
+ ENTITIES contains {len(context['extracted_nodes'])} entities with IDs 0 through {len(context['extracted_nodes']) - 1}.
170
+ Your response MUST include EXACTLY {len(context['extracted_nodes'])} resolutions with IDs 0 through {len(context['extracted_nodes']) - 1}. Do not skip or add IDs.
170
171
 
171
172
  For every entity, return an object with the following keys:
172
173
  {{
@@ -151,7 +151,7 @@ For each entity extracted, also determine its entity type based on the provided
151
151
  Indicate the classified entity type by providing its entity_type_id.
152
152
 
153
153
  Guidelines:
154
- 1. Always try to extract an entities that the JSON represents. This will often be something like a "name" or "user field
154
+ 1. Extract all entities that the JSON represents. This will often be something like a "name" or "user" field
155
155
  2. Extract all entities mentioned in all other properties throughout the JSON structure
156
156
  3. Do NOT extract any properties that contain dates
157
157
  """
@@ -15,6 +15,7 @@ limitations under the License.
15
15
  """
16
16
 
17
17
  import logging
18
+ from collections.abc import Awaitable, Callable
18
19
  from time import time
19
20
  from typing import Any
20
21
 
@@ -55,6 +56,8 @@ from graphiti_core.utils.maintenance.edge_operations import (
55
56
 
56
57
  logger = logging.getLogger(__name__)
57
58
 
59
+ NodeSummaryFilter = Callable[[EntityNode], Awaitable[bool]]
60
+
58
61
 
59
62
  async def extract_nodes_reflexion(
60
63
  llm_client: LLMClient,
@@ -266,6 +269,27 @@ async def _resolve_with_llm(
266
269
  for i, node in enumerate(llm_extracted_nodes)
267
270
  ]
268
271
 
272
+ sent_ids = [ctx['id'] for ctx in extracted_nodes_context]
273
+ logger.debug(
274
+ 'Sending %d entities to LLM for deduplication with IDs 0-%d (actual IDs sent: %s)',
275
+ len(llm_extracted_nodes),
276
+ len(llm_extracted_nodes) - 1,
277
+ sent_ids if len(sent_ids) < 20 else f'{sent_ids[:10]}...{sent_ids[-10:]}',
278
+ )
279
+ if llm_extracted_nodes:
280
+ sample_size = min(3, len(extracted_nodes_context))
281
+ logger.debug(
282
+ 'First %d entities: %s',
283
+ sample_size,
284
+ [(ctx['id'], ctx['name']) for ctx in extracted_nodes_context[:sample_size]],
285
+ )
286
+ if len(extracted_nodes_context) > 3:
287
+ logger.debug(
288
+ 'Last %d entities: %s',
289
+ sample_size,
290
+ [(ctx['id'], ctx['name']) for ctx in extracted_nodes_context[-sample_size:]],
291
+ )
292
+
269
293
  existing_nodes_context = [
270
294
  {
271
295
  **{
@@ -298,15 +322,38 @@ async def _resolve_with_llm(
298
322
  valid_relative_range = range(len(state.unresolved_indices))
299
323
  processed_relative_ids: set[int] = set()
300
324
 
325
+ received_ids = {r.id for r in node_resolutions}
326
+ expected_ids = set(valid_relative_range)
327
+ missing_ids = expected_ids - received_ids
328
+ extra_ids = received_ids - expected_ids
329
+
330
+ logger.debug(
331
+ 'Received %d resolutions for %d entities',
332
+ len(node_resolutions),
333
+ len(state.unresolved_indices),
334
+ )
335
+
336
+ if missing_ids:
337
+ logger.warning('LLM did not return resolutions for IDs: %s', sorted(missing_ids))
338
+
339
+ if extra_ids:
340
+ logger.warning(
341
+ 'LLM returned invalid IDs outside valid range 0-%d: %s (all returned IDs: %s)',
342
+ len(state.unresolved_indices) - 1,
343
+ sorted(extra_ids),
344
+ sorted(received_ids),
345
+ )
346
+
301
347
  for resolution in node_resolutions:
302
348
  relative_id: int = resolution.id
303
349
  duplicate_idx: int = resolution.duplicate_idx
304
350
 
305
351
  if relative_id not in valid_relative_range:
306
352
  logger.warning(
307
- 'Skipping invalid LLM dedupe id %s (unresolved indices: %s)',
353
+ 'Skipping invalid LLM dedupe id %d (valid range: 0-%d, received %d resolutions)',
308
354
  relative_id,
309
- state.unresolved_indices,
355
+ len(state.unresolved_indices) - 1,
356
+ len(node_resolutions),
310
357
  )
311
358
  continue
312
359
 
@@ -402,6 +449,7 @@ async def extract_attributes_from_nodes(
402
449
  episode: EpisodicNode | None = None,
403
450
  previous_episodes: list[EpisodicNode] | None = None,
404
451
  entity_types: dict[str, type[BaseModel]] | None = None,
452
+ should_summarize_node: NodeSummaryFilter | None = None,
405
453
  ) -> list[EntityNode]:
406
454
  llm_client = clients.llm_client
407
455
  embedder = clients.embedder
@@ -418,6 +466,7 @@ async def extract_attributes_from_nodes(
418
466
  else None
419
467
  ),
420
468
  clients.ensure_ascii,
469
+ should_summarize_node,
421
470
  )
422
471
  for node in nodes
423
472
  ]
@@ -435,6 +484,7 @@ async def extract_attributes_from_node(
435
484
  previous_episodes: list[EpisodicNode] | None = None,
436
485
  entity_type: type[BaseModel] | None = None,
437
486
  ensure_ascii: bool = False,
487
+ should_summarize_node: NodeSummaryFilter | None = None,
438
488
  ) -> EntityNode:
439
489
  node_context: dict[str, Any] = {
440
490
  'name': node.name,
@@ -477,16 +527,22 @@ async def extract_attributes_from_node(
477
527
  else {}
478
528
  )
479
529
 
480
- summary_response = await llm_client.generate_response(
481
- prompt_library.extract_nodes.extract_summary(summary_context),
482
- response_model=EntitySummary,
483
- model_size=ModelSize.small,
484
- )
530
+ # Determine if summary should be generated
531
+ generate_summary = True
532
+ if should_summarize_node is not None:
533
+ generate_summary = await should_summarize_node(node)
534
+
535
+ # Conditionally generate summary
536
+ if generate_summary:
537
+ summary_response = await llm_client.generate_response(
538
+ prompt_library.extract_nodes.extract_summary(summary_context),
539
+ response_model=EntitySummary,
540
+ model_size=ModelSize.small,
541
+ )
542
+ node.summary = summary_response.get('summary', '')
485
543
 
486
544
  if has_entity_attributes and entity_type is not None:
487
545
  entity_type(**llm_response)
488
-
489
- node.summary = summary_response.get('summary', '')
490
546
  node_attributes = {key: value for key, value in llm_response.items()}
491
547
 
492
548
  node.attributes.update(node_attributes)
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: graphiti-core
3
- Version: 0.21.0rc9
3
+ Version: 0.21.0rc11
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
@@ -1,11 +1,11 @@
1
1
  graphiti_core/__init__.py,sha256=e5SWFkRiaUwfprYIeIgVIh7JDedNiloZvd3roU-0aDY,55
2
- graphiti_core/edges.py,sha256=PhJm_s28cHLEaIqcw66wP16hOq4P4bVQbC_sESHQkXU,20919
2
+ graphiti_core/edges.py,sha256=2jA3x-9AGTldB52B5rWUhDtXXsj4PWM-MO1msIPsbdI,21048
3
3
  graphiti_core/errors.py,sha256=cH_v9TPgEPeQE6GFOHIg5TvejpUCBddGarMY2Whxbwc,2707
4
4
  graphiti_core/graph_queries.py,sha256=ZWMqAo5pwb8PO5ddg4zZ0ArhHWuWV42g3R9ULIxsHOs,8058
5
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
- graphiti_core/nodes.py,sha256=wYLQcVEXvQMxTpTc9LWSoPTzzaoUOm0rl07c9wS1XSY,30323
8
+ graphiti_core/nodes.py,sha256=ox7uDYpaayc5J_mrbMaP-d-jACFx9R7Fb14tvh9aRI8,30426
9
9
  graphiti_core/py.typed,sha256=vlmmzQOt7bmeQl9L3XJP4W6Ry0iiELepnOrinKz5KQg,79
10
10
  graphiti_core/cross_encoder/__init__.py,sha256=hry59vz21x-AtGZ0MJ7ugw0HTwJkXiddpp_Yqnwsen0,723
11
11
  graphiti_core/cross_encoder/bge_reranker_client.py,sha256=y3TfFxZh0Yvj6HUShmfUm6MC7OPXwWUlv1Qe5HF3S3I,1797
@@ -44,11 +44,11 @@ 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=H4sIzpi1gBwPedTMhdY175jnLj5JtnEeb_WNITitPLU,9171
47
+ graphiti_core/prompts/dedupe_nodes.py,sha256=42txTc4QrXQDqM2XE8_USAB9vfsWUgvwS1no_EJNcbA,9320
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=S115_KnenGJLjmVMzdarXBRj2wJ6y553UfYJgUTTDZI,6920
51
- graphiti_core/prompts/extract_nodes.py,sha256=GYX97qlSSrR_3QLc48EGCti8tdC1_OKpEdAR0Y2wfVY,11629
51
+ graphiti_core/prompts/extract_nodes.py,sha256=Ksf3PRBZ8LoZ5bOStZVRlHvVrdh3rT3xsepL81Ewy3M,11617
52
52
  graphiti_core/prompts/invalidate_edges.py,sha256=yfpcs_pyctnoM77ULPZXEtKW0oHr1MeLsJzC5yrE-o4,3547
53
53
  graphiti_core/prompts/lib.py,sha256=DCyHePM4_q-CptTpEXGO_dBv9k7xDtclEaB1dGu7EcI,4092
54
54
  graphiti_core/prompts/models.py,sha256=NgxdbPHJpBEcpbXovKyScgpBc73Q-GIW-CBDlBtDjto,894
@@ -71,11 +71,11 @@ graphiti_core/utils/maintenance/community_operations.py,sha256=XMiokEemn96GlvjkO
71
71
  graphiti_core/utils/maintenance/dedup_helpers.py,sha256=B7k6KkB6Sii8PZCWNNTvsNiy4BNTNWpoLeGgrPLq6BE,9220
72
72
  graphiti_core/utils/maintenance/edge_operations.py,sha256=p16cLA2eJeIYS9W0o1i8wYtvUpjt9mGWzRXVemAr7Bk,25305
73
73
  graphiti_core/utils/maintenance/graph_data_operations.py,sha256=42icj3S_ELAJ-NK3jVS_rg_243dmnaZOyUitJj_uJ-M,6085
74
- graphiti_core/utils/maintenance/node_operations.py,sha256=TKpXPtnTVxxan8I1xQyVkGn3zyRdb_Q00cgUpLcloig,16860
74
+ graphiti_core/utils/maintenance/node_operations.py,sha256=gzIE32D3vCY0RorKwCz6wI9xS95BaiJoO1WyKzuDDKk,19014
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.21.0rc9.dist-info/METADATA,sha256=K8BMq3mCQ5o9NUY3M1ZImcnwLykmMAjYcvJMvp5MN6k,27084
79
- graphiti_core-0.21.0rc9.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
80
- graphiti_core-0.21.0rc9.dist-info/licenses/LICENSE,sha256=KCUwCyDXuVEgmDWkozHyniRyWjnWUWjkuDHfU6o3JlA,11325
81
- graphiti_core-0.21.0rc9.dist-info/RECORD,,
78
+ graphiti_core-0.21.0rc11.dist-info/METADATA,sha256=LQry-ruHgk3SEGYON167542JVQ-udutxUGRpA7FbRYc,27085
79
+ graphiti_core-0.21.0rc11.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
80
+ graphiti_core-0.21.0rc11.dist-info/licenses/LICENSE,sha256=KCUwCyDXuVEgmDWkozHyniRyWjnWUWjkuDHfU6o3JlA,11325
81
+ graphiti_core-0.21.0rc11.dist-info/RECORD,,