graphiti-core 0.21.0rc3__py3-none-any.whl → 0.21.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.

@@ -311,3 +311,12 @@ class GraphDriver(ABC):
311
311
  return success if failed == 0 else success
312
312
 
313
313
  return 0
314
+
315
+ def build_fulltext_query(
316
+ self, query: str, group_ids: list[str] | None = None, max_query_length: int = 128
317
+ ) -> str:
318
+ """
319
+ Specific fulltext query builder for database providers.
320
+ Only implemented by providers that need custom fulltext query building.
321
+ """
322
+ raise NotImplementedError(f'build_fulltext_query not implemented for {self.provider}')
@@ -36,6 +36,42 @@ from graphiti_core.utils.datetime_utils import convert_datetimes_to_strings
36
36
 
37
37
  logger = logging.getLogger(__name__)
38
38
 
39
+ STOPWORDS = [
40
+ 'a',
41
+ 'is',
42
+ 'the',
43
+ 'an',
44
+ 'and',
45
+ 'are',
46
+ 'as',
47
+ 'at',
48
+ 'be',
49
+ 'but',
50
+ 'by',
51
+ 'for',
52
+ 'if',
53
+ 'in',
54
+ 'into',
55
+ 'it',
56
+ 'no',
57
+ 'not',
58
+ 'of',
59
+ 'on',
60
+ 'or',
61
+ 'such',
62
+ 'that',
63
+ 'their',
64
+ 'then',
65
+ 'there',
66
+ 'these',
67
+ 'they',
68
+ 'this',
69
+ 'to',
70
+ 'was',
71
+ 'will',
72
+ 'with',
73
+ ]
74
+
39
75
 
40
76
  class FalkorDriverSession(GraphDriverSession):
41
77
  provider = GraphProvider.FALKORDB
@@ -167,3 +203,78 @@ class FalkorDriver(GraphDriver):
167
203
  cloned = FalkorDriver(falkor_db=self.client, database=database)
168
204
 
169
205
  return cloned
206
+
207
+ def sanitize(self, query: str) -> str:
208
+ """
209
+ Replace FalkorDB special characters with whitespace.
210
+ Based on FalkorDB tokenization rules: ,.<>{}[]"':;!@#$%^&*()-+=~
211
+ """
212
+ # FalkorDB separator characters that break text into tokens
213
+ separator_map = str.maketrans(
214
+ {
215
+ ',': ' ',
216
+ '.': ' ',
217
+ '<': ' ',
218
+ '>': ' ',
219
+ '{': ' ',
220
+ '}': ' ',
221
+ '[': ' ',
222
+ ']': ' ',
223
+ '"': ' ',
224
+ "'": ' ',
225
+ ':': ' ',
226
+ ';': ' ',
227
+ '!': ' ',
228
+ '@': ' ',
229
+ '#': ' ',
230
+ '$': ' ',
231
+ '%': ' ',
232
+ '^': ' ',
233
+ '&': ' ',
234
+ '*': ' ',
235
+ '(': ' ',
236
+ ')': ' ',
237
+ '-': ' ',
238
+ '+': ' ',
239
+ '=': ' ',
240
+ '~': ' ',
241
+ '?': ' ',
242
+ }
243
+ )
244
+ sanitized = query.translate(separator_map)
245
+ # Clean up multiple spaces
246
+ sanitized = ' '.join(sanitized.split())
247
+ return sanitized
248
+
249
+ def build_fulltext_query(
250
+ self, query: str, group_ids: list[str] | None = None, max_query_length: int = 128
251
+ ) -> str:
252
+ """
253
+ Build a fulltext query string for FalkorDB using RedisSearch syntax.
254
+ FalkorDB uses RedisSearch-like syntax where:
255
+ - Field queries use @ prefix: @field:value
256
+ - Multiple values for same field: (@field:value1|value2)
257
+ - Text search doesn't need @ prefix for content fields
258
+ - AND is implicit with space: (@group_id:value) (text)
259
+ - OR uses pipe within parentheses: (@group_id:value1|value2)
260
+ """
261
+ if group_ids is None or len(group_ids) == 0:
262
+ group_filter = ''
263
+ else:
264
+ group_values = '|'.join(group_ids)
265
+ group_filter = f'(@group_id:{group_values})'
266
+
267
+ sanitized_query = self.sanitize(query)
268
+
269
+ # Remove stopwords from the sanitized query
270
+ query_words = sanitized_query.split()
271
+ filtered_words = [word for word in query_words if word.lower() not in STOPWORDS]
272
+ sanitized_query = ' | '.join(filtered_words)
273
+
274
+ # If the query is too long return no query
275
+ if len(sanitized_query.split(' ')) + len(group_ids or '') >= max_query_length:
276
+ return ''
277
+
278
+ full_query = group_filter + ' (' + sanitized_query + ')'
279
+
280
+ return full_query
@@ -71,12 +71,41 @@ def get_range_indices(provider: GraphProvider) -> list[LiteralString]:
71
71
 
72
72
  def get_fulltext_indices(provider: GraphProvider) -> list[LiteralString]:
73
73
  if provider == GraphProvider.FALKORDB:
74
- return [
75
- """CREATE FULLTEXT INDEX FOR (e:Episodic) ON (e.content, e.source, e.source_description, e.group_id)""",
76
- """CREATE FULLTEXT INDEX FOR (n:Entity) ON (n.name, n.summary, n.group_id)""",
77
- """CREATE FULLTEXT INDEX FOR (n:Community) ON (n.name, n.group_id)""",
78
- """CREATE FULLTEXT INDEX FOR ()-[e:RELATES_TO]-() ON (e.name, e.fact, e.group_id)""",
79
- ]
74
+ from typing import cast
75
+
76
+ from graphiti_core.driver.falkordb_driver import STOPWORDS
77
+
78
+ # Convert to string representation for embedding in queries
79
+ stopwords_str = str(STOPWORDS)
80
+
81
+ # Use type: ignore to satisfy LiteralString requirement while maintaining single source of truth
82
+ return cast(
83
+ list[LiteralString],
84
+ [
85
+ f"""CALL db.idx.fulltext.createNodeIndex(
86
+ {{
87
+ label: 'Episodic',
88
+ stopwords: {stopwords_str}
89
+ }},
90
+ 'content', 'source', 'source_description', 'group_id'
91
+ )""",
92
+ f"""CALL db.idx.fulltext.createNodeIndex(
93
+ {{
94
+ label: 'Entity',
95
+ stopwords: {stopwords_str}
96
+ }},
97
+ 'name', 'summary', 'group_id'
98
+ )""",
99
+ f"""CALL db.idx.fulltext.createNodeIndex(
100
+ {{
101
+ label: 'Community',
102
+ stopwords: {stopwords_str}
103
+ }},
104
+ 'name', 'group_id'
105
+ )""",
106
+ """CREATE FULLTEXT INDEX FOR ()-[e:RELATES_TO]-() ON (e.name, e.fact, e.group_id)""",
107
+ ],
108
+ )
80
109
 
81
110
  if provider == GraphProvider.KUZU:
82
111
  return [
graphiti_core/graphiti.py CHANGED
@@ -456,12 +456,12 @@ class Graphiti:
456
456
  start = time()
457
457
  now = utc_now()
458
458
 
459
- # if group_id is None, use the default group id by the provider
460
- group_id = group_id or get_default_group_id(self.driver.provider)
461
459
  validate_entity_types(entity_types)
462
460
 
463
461
  validate_excluded_entity_types(excluded_entity_types, entity_types)
464
462
  validate_group_id(group_id)
463
+ # if group_id is None, use the default group id by the provider
464
+ group_id = group_id or get_default_group_id(self.driver.provider)
465
465
 
466
466
  previous_episodes = (
467
467
  await self.retrieve_episodes(
graphiti_core/helpers.py CHANGED
@@ -54,7 +54,7 @@ def get_default_group_id(provider: GraphProvider) -> str:
54
54
  For most databases, the default group id is an empty string, while there are database types that require a specific default group id.
55
55
  """
56
56
  if provider == GraphProvider.FALKORDB:
57
- return '_'
57
+ return '\\_'
58
58
  else:
59
59
  return ''
60
60
 
@@ -116,7 +116,7 @@ async def semaphore_gather(
116
116
  return await asyncio.gather(*(_wrap_coroutine(coroutine) for coroutine in coroutines))
117
117
 
118
118
 
119
- def validate_group_id(group_id: str) -> bool:
119
+ def validate_group_id(group_id: str | None) -> bool:
120
120
  """
121
121
  Validate that a group_id contains only ASCII alphanumeric characters, dashes, and underscores.
122
122
 
@@ -92,6 +92,8 @@ def fulltext_query(query: str, group_ids: list[str] | None, driver: GraphDriver)
92
92
  if len(query.split(' ')) > MAX_QUERY_LENGTH:
93
93
  return ''
94
94
  return query
95
+ elif driver.provider == GraphProvider.FALKORDB:
96
+ return driver.build_fulltext_query(query, group_ids, MAX_QUERY_LENGTH)
95
97
  group_ids_filter_list = (
96
98
  [driver.fulltext_syntax + f'group_id:"{g}"' for g in group_ids]
97
99
  if group_ids is not None
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: graphiti-core
3
- Version: 0.21.0rc3
3
+ Version: 0.21.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
@@ -1,10 +1,10 @@
1
1
  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
- graphiti_core/graph_queries.py,sha256=9DWMiFTB-OmodMDaOws0lwzgiD7EUDNO7mAFJ1nxusE,6624
5
- graphiti_core/graphiti.py,sha256=UPa85sdCdO4xnl68EsFYnbkqTgta2LA-XwP7hzcAsyg,42072
4
+ graphiti_core/graph_queries.py,sha256=ZWMqAo5pwb8PO5ddg4zZ0ArhHWuWV42g3R9ULIxsHOs,8058
5
+ graphiti_core/graphiti.py,sha256=Uxppvzjc-jFO6JCRE3PUlU5B5zUo-jBrC02uETb0-x0,42072
6
6
  graphiti_core/graphiti_types.py,sha256=C_p2XwScQlCzo7ets097TrSLs9ATxPZQ4WCsxDS7QHc,1066
7
- graphiti_core/helpers.py,sha256=6q_wpiOW3_j28EfZ7FgWW7Hl5pONj_5zvVXZGW9FxTU,5175
7
+ graphiti_core/helpers.py,sha256=q8kbL9gz8igdlh-oMUS-ylUyeMlXZb-ccf-HQkrES_0,5184
8
8
  graphiti_core/nodes.py,sha256=wYLQcVEXvQMxTpTc9LWSoPTzzaoUOm0rl07c9wS1XSY,30323
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=WHMl6Q6gEslR2EzjwpFSZt2Kh6bnu8alkLvzmi0MDtg,4674
15
15
  graphiti_core/driver/__init__.py,sha256=kCWimqQU19airu5gKwCmZtZuXkDfaQfKSUhMDoL-rTA,626
16
- graphiti_core/driver/driver.py,sha256=5YbpyUq7L1pf8s5R2FYv6B3KabTCmRvhSAHiVyRvt5o,10433
17
- graphiti_core/driver/falkordb_driver.py,sha256=JsNBRQHBVENA8eqAngD-8dw1aTH1ZKUtE1on8sd7owY,6431
16
+ graphiti_core/driver/driver.py,sha256=EO9Aj5O2vpH7iyvQQcE5uJGQ8eA-_i6f8NwfAlW8r74,10831
17
+ graphiti_core/driver/falkordb_driver.py,sha256=Q-dImfK4O2bkikqFzo0Wg2g7iFFRSuzy_c6u82tX6-M,9361
18
18
  graphiti_core/driver/kuzu_driver.py,sha256=RcWu8E0CCdofrFe34NmCeqfuhaZr_7ZN5jqDkI3VQMI,5453
19
19
  graphiti_core/driver/neo4j_driver.py,sha256=E93PdOZaH7wzEbIfoiDSYht49jr6zSzvMMyo1INGEOw,4096
20
20
  graphiti_core/driver/neptune_driver.py,sha256=akNLHhFHPEeQu-xO3PM51RomklntT6k5eA2CQ4AFbCc,10311
@@ -60,7 +60,7 @@ graphiti_core/search/search_config.py,sha256=v_rUHsu1yo5OuPfEm21lSuXexQs-o8qYwSS
60
60
  graphiti_core/search/search_config_recipes.py,sha256=4GquRphHhJlpXQhAZOySYnCzBWYoTwxlJj44eTOavZQ,7443
61
61
  graphiti_core/search/search_filters.py,sha256=DOAmYkc6A0z20EZId5fJZj1RvLz4WeQcoPANk9k-Sh8,10304
62
62
  graphiti_core/search/search_helpers.py,sha256=wj3ARlCNnZixNNntgCdAqzGoE4de4lW3r4rSG-3WyGw,2877
63
- graphiti_core/search/search_utils.py,sha256=HqNYbyQklAq5GoOUo_W8Xut1GMGVYlNv0kE0rh03KHo,76827
63
+ graphiti_core/search/search_utils.py,sha256=ak1aBeKNuxS7szydNHwva2ABWSRlQ0S_v8ZOx7k0wc4,76958
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
@@ -74,7 +74,7 @@ graphiti_core/utils/maintenance/node_operations.py,sha256=r9ilkA01eq1z-nF8P_s1EX
74
74
  graphiti_core/utils/maintenance/temporal_operations.py,sha256=IIaVtShpVkOYe6haxz3a1x3v54-MzaEXG8VsxFUNeoY,3582
75
75
  graphiti_core/utils/maintenance/utils.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
76
76
  graphiti_core/utils/ontology_utils/entity_types_utils.py,sha256=4eVgxLWY6Q8k9cRJ5pW59IYF--U4nXZsZIGOVb_yHfQ,1285
77
- graphiti_core-0.21.0rc3.dist-info/METADATA,sha256=7a30OAvffGwDCJRWGF5Mr_AP3p-JXc1f1pQXVJcQ4RY,26933
78
- graphiti_core-0.21.0rc3.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
79
- graphiti_core-0.21.0rc3.dist-info/licenses/LICENSE,sha256=KCUwCyDXuVEgmDWkozHyniRyWjnWUWjkuDHfU6o3JlA,11325
80
- graphiti_core-0.21.0rc3.dist-info/RECORD,,
77
+ graphiti_core-0.21.0rc4.dist-info/METADATA,sha256=W_bFyM6HCQ8N7-tFNyjGHuRafGDYj89EtQ4tngZPUKc,26933
78
+ graphiti_core-0.21.0rc4.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
79
+ graphiti_core-0.21.0rc4.dist-info/licenses/LICENSE,sha256=KCUwCyDXuVEgmDWkozHyniRyWjnWUWjkuDHfU6o3JlA,11325
80
+ graphiti_core-0.21.0rc4.dist-info/RECORD,,