graphiti-core 0.17.5__py3-none-any.whl → 0.17.7__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.

@@ -46,6 +46,9 @@ class GraphDriverSession(ABC):
46
46
 
47
47
  class GraphDriver(ABC):
48
48
  provider: str
49
+ fulltext_syntax: str = (
50
+ '' # Neo4j (default) syntax does not require a prefix for fulltext queries
51
+ )
49
52
 
50
53
  @abstractmethod
51
54
  def execute_query(self, cypher_query_: str, **kwargs: Any) -> Coroutine:
@@ -97,6 +97,8 @@ class FalkorDriver(GraphDriver):
97
97
  self.client = FalkorDB(host=host, port=port, username=username, password=password)
98
98
  self._database = database
99
99
 
100
+ self.fulltext_syntax = '@' # FalkorDB uses a redisearch-like syntax for fulltext queries see https://redis.io/docs/latest/develop/ai/search-and-query/query/full-text/
101
+
100
102
  def _get_graph(self, graph_name: str | None) -> FalkorGraph:
101
103
  # FalkorDB requires a non-None database name for multi-tenant graphs; the default is "default_db"
102
104
  if graph_name is None:
graphiti_core/graphiti.py CHANGED
@@ -30,6 +30,7 @@ from graphiti_core.edges import EntityEdge, EpisodicEdge
30
30
  from graphiti_core.embedder import EmbedderClient, OpenAIEmbedder
31
31
  from graphiti_core.graphiti_types import GraphitiClients
32
32
  from graphiti_core.helpers import (
33
+ get_default_group_id,
33
34
  semaphore_gather,
34
35
  validate_excluded_entity_types,
35
36
  validate_group_id,
@@ -352,7 +353,7 @@ class Graphiti:
352
353
  source_description: str,
353
354
  reference_time: datetime,
354
355
  source: EpisodeType = EpisodeType.message,
355
- group_id: str = '',
356
+ group_id: str | None = None,
356
357
  uuid: str | None = None,
357
358
  update_communities: bool = False,
358
359
  entity_types: dict[str, BaseModel] | None = None,
@@ -420,7 +421,10 @@ class Graphiti:
420
421
  start = time()
421
422
  now = utc_now()
422
423
 
424
+ # if group_id is None, use the default group id by the provider
425
+ group_id = group_id or get_default_group_id(self.driver.provider)
423
426
  validate_entity_types(entity_types)
427
+
424
428
  validate_excluded_entity_types(excluded_entity_types, entity_types)
425
429
  validate_group_id(group_id)
426
430
 
@@ -537,7 +541,7 @@ class Graphiti:
537
541
  async def add_episode_bulk(
538
542
  self,
539
543
  bulk_episodes: list[RawEpisode],
540
- group_id: str = '',
544
+ group_id: str | None = None,
541
545
  entity_types: dict[str, BaseModel] | None = None,
542
546
  excluded_entity_types: list[str] | None = None,
543
547
  edge_types: dict[str, BaseModel] | None = None,
@@ -583,6 +587,8 @@ class Graphiti:
583
587
  start = time()
584
588
  now = utc_now()
585
589
 
590
+ # if group_id is None, use the default group id by the provider
591
+ group_id = group_id or get_default_group_id(self.driver.provider)
586
592
  validate_group_id(group_id)
587
593
 
588
594
  # Create default edge type map
graphiti_core/helpers.py CHANGED
@@ -52,6 +52,17 @@ def parse_db_date(neo_date: neo4j_time.DateTime | str | None) -> datetime | None
52
52
  )
53
53
 
54
54
 
55
+ def get_default_group_id(db_type: str) -> str:
56
+ """
57
+ This function differentiates the default group id based on the database type.
58
+ For most databases, the default group id is an empty string, while there are database types that require a specific default group id.
59
+ """
60
+ if db_type == 'falkordb':
61
+ return '_'
62
+ else:
63
+ return ''
64
+
65
+
55
66
  def lucene_sanitize(query: str) -> str:
56
67
  # Escape special characters from a query before passing into Lucene
57
68
  # + - && || ! ( ) { } [ ] ^ " ~ * ? : \ /
@@ -57,12 +57,14 @@ RELEVANT_SCHEMA_LIMIT = 10
57
57
  DEFAULT_MIN_SCORE = 0.6
58
58
  DEFAULT_MMR_LAMBDA = 0.5
59
59
  MAX_SEARCH_DEPTH = 3
60
- MAX_QUERY_LENGTH = 32
60
+ MAX_QUERY_LENGTH = 128
61
61
 
62
62
 
63
- def fulltext_query(query: str, group_ids: list[str] | None = None):
63
+ def fulltext_query(query: str, group_ids: list[str] | None = None, fulltext_syntax: str = ''):
64
64
  group_ids_filter_list = (
65
- [f'group_id:"{lucene_sanitize(g)}"' for g in group_ids] if group_ids is not None else []
65
+ [fulltext_syntax + f"group_id:'{lucene_sanitize(g)}'" for g in group_ids]
66
+ if group_ids is not None
67
+ else []
66
68
  )
67
69
  group_ids_filter = ''
68
70
  for f in group_ids_filter_list:
@@ -157,7 +159,7 @@ async def edge_fulltext_search(
157
159
  limit=RELEVANT_SCHEMA_LIMIT,
158
160
  ) -> list[EntityEdge]:
159
161
  # fulltext search over facts
160
- fuzzy_query = fulltext_query(query, group_ids)
162
+ fuzzy_query = fulltext_query(query, group_ids, driver.fulltext_syntax)
161
163
  if fuzzy_query == '':
162
164
  return []
163
165
 
@@ -293,12 +295,12 @@ async def edge_bfs_search(
293
295
 
294
296
  query = (
295
297
  """
296
- UNWIND $bfs_origin_node_uuids AS origin_uuid
297
- MATCH path = (origin:Entity|Episodic {uuid: origin_uuid})-[:RELATES_TO|MENTIONS]->{1,3}(n:Entity)
298
- UNWIND relationships(path) AS rel
299
- MATCH (n:Entity)-[r:RELATES_TO]-(m:Entity)
300
- WHERE r.uuid = rel.uuid
301
- """
298
+ UNWIND $bfs_origin_node_uuids AS origin_uuid
299
+ MATCH path = (origin:Entity|Episodic {uuid: origin_uuid})-[:RELATES_TO|MENTIONS]->{1,3}(n:Entity)
300
+ UNWIND relationships(path) AS rel
301
+ MATCH (n:Entity)-[r:RELATES_TO]-(m:Entity)
302
+ WHERE r.uuid = rel.uuid
303
+ """
302
304
  + filter_query
303
305
  + """
304
306
  RETURN DISTINCT
@@ -340,7 +342,7 @@ async def node_fulltext_search(
340
342
  limit=RELEVANT_SCHEMA_LIMIT,
341
343
  ) -> list[EntityNode]:
342
344
  # BM25 search to get top nodes
343
- fuzzy_query = fulltext_query(query, group_ids)
345
+ fuzzy_query = fulltext_query(query, group_ids, driver.fulltext_syntax)
344
346
  if fuzzy_query == '':
345
347
  return []
346
348
  filter_query, filter_params = node_search_filter_query_constructor(search_filter)
@@ -441,10 +443,10 @@ async def node_bfs_search(
441
443
 
442
444
  query = (
443
445
  """
444
- UNWIND $bfs_origin_node_uuids AS origin_uuid
445
- MATCH (origin:Entity|Episodic {uuid: origin_uuid})-[:RELATES_TO|MENTIONS]->{1,3}(n:Entity)
446
- WHERE n.group_id = origin.group_id
447
- """
446
+ UNWIND $bfs_origin_node_uuids AS origin_uuid
447
+ MATCH (origin:Entity|Episodic {uuid: origin_uuid})-[:RELATES_TO|MENTIONS]->{1,3}(n:Entity)
448
+ WHERE n.group_id = origin.group_id
449
+ """
448
450
  + filter_query
449
451
  + ENTITY_NODE_RETURN
450
452
  + """
@@ -472,7 +474,7 @@ async def episode_fulltext_search(
472
474
  limit=RELEVANT_SCHEMA_LIMIT,
473
475
  ) -> list[EpisodicNode]:
474
476
  # BM25 search to get top episodes
475
- fuzzy_query = fulltext_query(query, group_ids)
477
+ fuzzy_query = fulltext_query(query, group_ids, driver.fulltext_syntax)
476
478
  if fuzzy_query == '':
477
479
  return []
478
480
 
@@ -516,7 +518,7 @@ async def community_fulltext_search(
516
518
  limit=RELEVANT_SCHEMA_LIMIT,
517
519
  ) -> list[CommunityNode]:
518
520
  # BM25 search to get top communities
519
- fuzzy_query = fulltext_query(query, group_ids)
521
+ fuzzy_query = fulltext_query(query, group_ids, driver.fulltext_syntax)
520
522
  if fuzzy_query == '':
521
523
  return []
522
524
 
@@ -740,7 +742,7 @@ async def get_relevant_nodes(
740
742
  'uuid': node.uuid,
741
743
  'name': node.name,
742
744
  'name_embedding': node.name_embedding,
743
- 'fulltext_query': fulltext_query(node.name, [node.group_id]),
745
+ 'fulltext_query': fulltext_query(node.name, [node.group_id], driver.fulltext_syntax),
744
746
  }
745
747
  for node in nodes
746
748
  ]
@@ -274,8 +274,14 @@ async def resolve_extracted_edges(
274
274
  # Determine which edge types are relevant for each edge
275
275
  edge_types_lst: list[dict[str, BaseModel]] = []
276
276
  for extracted_edge in extracted_edges:
277
- source_node_labels = uuid_entity_map[extracted_edge.source_node_uuid].labels + ['Entity']
278
- target_node_labels = uuid_entity_map[extracted_edge.target_node_uuid].labels + ['Entity']
277
+ source_node = uuid_entity_map.get(extracted_edge.source_node_uuid)
278
+ target_node = uuid_entity_map.get(extracted_edge.target_node_uuid)
279
+ source_node_labels = (
280
+ source_node.labels + ['Entity'] if source_node is not None else ['Entity']
281
+ )
282
+ target_node_labels = (
283
+ target_node.labels + ['Entity'] if target_node is not None else ['Entity']
284
+ )
279
285
  label_tuples = [
280
286
  (source_label, target_label)
281
287
  for source_label in source_node_labels
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: graphiti-core
3
- Version: 0.17.5
3
+ Version: 0.17.7
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
@@ -2,9 +2,9 @@ graphiti_core/__init__.py,sha256=e5SWFkRiaUwfprYIeIgVIh7JDedNiloZvd3roU-0aDY,55
2
2
  graphiti_core/edges.py,sha256=-SSP6rhk8Dl8LwUZ08GHymJTT5pNDtzb3BV-6z1fBYY,16030
3
3
  graphiti_core/errors.py,sha256=cH_v9TPgEPeQE6GFOHIg5TvejpUCBddGarMY2Whxbwc,2707
4
4
  graphiti_core/graph_queries.py,sha256=KfWDp8xDnPa9bcHskw8NeMpeeHBtZWBCosVdu1Iwv34,7076
5
- graphiti_core/graphiti.py,sha256=rlz1Q2zF6vcFqfLoFP7jbxZvHNKgy8eVcTHDqoIykjs,39244
5
+ graphiti_core/graphiti.py,sha256=imPrIjBgJ2Ca6MBHynn2G-xc6d0xdLY2T6ac4NDdLsE,39597
6
6
  graphiti_core/graphiti_types.py,sha256=rL-9bvnLobunJfXU4hkD6mAj14pofKp_wq8QsFDZwDU,1035
7
- graphiti_core/helpers.py,sha256=b4998WOrqgzesNyMlw7UKIdo3x3uo_BwheztqMblwzE,4885
7
+ graphiti_core/helpers.py,sha256=YoMAEhe_aMPz_Cd_t1dnIffNwDpenINJu4URePglt2s,5247
8
8
  graphiti_core/nodes.py,sha256=AcqHvhNWyapQwBSuziMvPJ-HnOr4Pv1-OiYsEodJcAA,18613
9
9
  graphiti_core/py.typed,sha256=vlmmzQOt7bmeQl9L3XJP4W6Ry0iiELepnOrinKz5KQg,79
10
10
  graphiti_core/cross_encoder/__init__.py,sha256=hry59vz21x-AtGZ0MJ7ugw0HTwJkXiddpp_Yqnwsen0,723
@@ -13,8 +13,8 @@ graphiti_core/cross_encoder/client.py,sha256=KLsbfWKOEaAV3adFe3XZlAeb-gje9_sVKCV
13
13
  graphiti_core/cross_encoder/gemini_reranker_client.py,sha256=hmITG5YIib52nrKvINwRi4xTfAO1U4jCCaEVIwImHw0,6208
14
14
  graphiti_core/cross_encoder/openai_reranker_client.py,sha256=hoaGyu9nCNMJyP8si0Bha5Q9CFszfiHQmLgE9IsX7sY,4653
15
15
  graphiti_core/driver/__init__.py,sha256=kCWimqQU19airu5gKwCmZtZuXkDfaQfKSUhMDoL-rTA,626
16
- graphiti_core/driver/driver.py,sha256=UGnsRFqRXndMe_QC72NOG6oJlP4p3NyvCM9ufn6zTLE,1786
17
- graphiti_core/driver/falkordb_driver.py,sha256=vTbbYsv-ruRd9TxifJUbfkt8UGcEuFLAHtBCpI9_vSc,6396
16
+ graphiti_core/driver/driver.py,sha256=VndkriaEdTnafhVs1ks11klXQERqylV0X76Yc4WsAfU,1905
17
+ graphiti_core/driver/falkordb_driver.py,sha256=lol0ahK_3pBhoBNQhchouWEM2YuJpNSpsycbWQfMwx8,6573
18
18
  graphiti_core/driver/neo4j_driver.py,sha256=0MCAWAPay0LdcqrFSkY91GooUtrn1yX1CTKuE4Lj_Po,2255
19
19
  graphiti_core/embedder/__init__.py,sha256=EL564ZuE-DZjcuKNUK_exMn_XHXm2LdO9fzdXePVKL4,179
20
20
  graphiti_core/embedder/azure_openai.py,sha256=OyomPwC1fIsddI-3n6g00kQFdQznZorBhHwkQKCLUok,2384
@@ -57,7 +57,7 @@ graphiti_core/search/search_config.py,sha256=VvKg6AB_RPhoe56DBBXHRBXHThAVJ_OLFCy
57
57
  graphiti_core/search/search_config_recipes.py,sha256=4GquRphHhJlpXQhAZOySYnCzBWYoTwxlJj44eTOavZQ,7443
58
58
  graphiti_core/search/search_filters.py,sha256=cxiFkqB-r7QzVMh8nmujECLhzgsbeCpBHUQqDXnCQ3A,6383
59
59
  graphiti_core/search/search_helpers.py,sha256=G5Ceaq5Pfgx0Weelqgeylp_pUHwiBnINaUYsDbURJbE,2636
60
- graphiti_core/search/search_utils.py,sha256=616pGqC95PgW7DljgP5TDybzDKyO6IqrSPEEWQ87Pw0,34026
60
+ graphiti_core/search/search_utils.py,sha256=86_2EncBcXhomdP9dZaIWC5InYU_m5QubMLrErLX6dQ,34248
61
61
  graphiti_core/telemetry/__init__.py,sha256=5kALLDlU9bb2v19CdN7qVANsJWyfnL9E60J6FFgzm3o,226
62
62
  graphiti_core/telemetry/telemetry.py,sha256=47LrzOVBCcZxsYPsnSxWFiztHoxYKKxPwyRX0hnbDGc,3230
63
63
  graphiti_core/utils/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
@@ -65,13 +65,13 @@ graphiti_core/utils/bulk_utils.py,sha256=jMpGEyiAd1uCllGzxEpsV8pwLOq0DbWK4Ph_Qhd
65
65
  graphiti_core/utils/datetime_utils.py,sha256=Ti-2tnrDFRzBsbfblzsHybsM3jaDLP4-VT2t0VhpIzU,1357
66
66
  graphiti_core/utils/maintenance/__init__.py,sha256=vW4H1KyapTl-OOz578uZABYcpND4wPx3Vt6aAPaXh78,301
67
67
  graphiti_core/utils/maintenance/community_operations.py,sha256=ROKo9_5Jj3RqfTrD9wJjlDRSF6iUyXUY4czkc9RGVdw,9905
68
- graphiti_core/utils/maintenance/edge_operations.py,sha256=WVljCbILNMNkxdGuSXQncRglpByRzYhfVkvKpIawJ94,19261
68
+ graphiti_core/utils/maintenance/edge_operations.py,sha256=gVSNC-GWZ0Ud-ONfhUDlHlIb2z1mI6SYtZPptPXSTeQ,19471
69
69
  graphiti_core/utils/maintenance/graph_data_operations.py,sha256=4czJPiHZpaqhKYYcXonErYQV2tV86ai2H-cg6dK8u60,5192
70
70
  graphiti_core/utils/maintenance/node_operations.py,sha256=ZnopNRTNdBjBotQ2uQiI7EYtVhs__b8C9QfRvNiMG6Q,14580
71
71
  graphiti_core/utils/maintenance/temporal_operations.py,sha256=mJkw9xLB4W2BsLfC5POr0r-PHWL9SIfNj_l_xu0B5ug,3410
72
72
  graphiti_core/utils/maintenance/utils.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
73
73
  graphiti_core/utils/ontology_utils/entity_types_utils.py,sha256=QJX5cG0GSSNF_Mm_yrldr69wjVAbN_MxLhOSznz85Hk,1279
74
- graphiti_core-0.17.5.dist-info/METADATA,sha256=WGz5dFLlBQ5foRMl7gnecaQzjvJlngqhcFEkLexJAmo,23812
75
- graphiti_core-0.17.5.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
76
- graphiti_core-0.17.5.dist-info/licenses/LICENSE,sha256=KCUwCyDXuVEgmDWkozHyniRyWjnWUWjkuDHfU6o3JlA,11325
77
- graphiti_core-0.17.5.dist-info/RECORD,,
74
+ graphiti_core-0.17.7.dist-info/METADATA,sha256=t2VOfx3ak61jHiNFOM2J_zFoRJqf-DjdgUiIarim9ag,23812
75
+ graphiti_core-0.17.7.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
76
+ graphiti_core-0.17.7.dist-info/licenses/LICENSE,sha256=KCUwCyDXuVEgmDWkozHyniRyWjnWUWjkuDHfU6o3JlA,11325
77
+ graphiti_core-0.17.7.dist-info/RECORD,,