graphiti-core 0.12.0rc1__py3-none-any.whl → 0.24.3__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.
Files changed (68) hide show
  1. graphiti_core/cross_encoder/bge_reranker_client.py +12 -2
  2. graphiti_core/cross_encoder/gemini_reranker_client.py +161 -0
  3. graphiti_core/cross_encoder/openai_reranker_client.py +7 -5
  4. graphiti_core/decorators.py +110 -0
  5. graphiti_core/driver/__init__.py +19 -0
  6. graphiti_core/driver/driver.py +124 -0
  7. graphiti_core/driver/falkordb_driver.py +362 -0
  8. graphiti_core/driver/graph_operations/graph_operations.py +191 -0
  9. graphiti_core/driver/kuzu_driver.py +182 -0
  10. graphiti_core/driver/neo4j_driver.py +117 -0
  11. graphiti_core/driver/neptune_driver.py +305 -0
  12. graphiti_core/driver/search_interface/search_interface.py +89 -0
  13. graphiti_core/edges.py +287 -172
  14. graphiti_core/embedder/azure_openai.py +71 -0
  15. graphiti_core/embedder/client.py +2 -1
  16. graphiti_core/embedder/gemini.py +116 -22
  17. graphiti_core/embedder/voyage.py +13 -2
  18. graphiti_core/errors.py +8 -0
  19. graphiti_core/graph_queries.py +162 -0
  20. graphiti_core/graphiti.py +705 -193
  21. graphiti_core/graphiti_types.py +4 -2
  22. graphiti_core/helpers.py +87 -10
  23. graphiti_core/llm_client/__init__.py +16 -0
  24. graphiti_core/llm_client/anthropic_client.py +159 -56
  25. graphiti_core/llm_client/azure_openai_client.py +115 -0
  26. graphiti_core/llm_client/client.py +98 -21
  27. graphiti_core/llm_client/config.py +1 -1
  28. graphiti_core/llm_client/gemini_client.py +290 -41
  29. graphiti_core/llm_client/groq_client.py +14 -3
  30. graphiti_core/llm_client/openai_base_client.py +261 -0
  31. graphiti_core/llm_client/openai_client.py +56 -132
  32. graphiti_core/llm_client/openai_generic_client.py +91 -56
  33. graphiti_core/models/edges/edge_db_queries.py +259 -35
  34. graphiti_core/models/nodes/node_db_queries.py +311 -32
  35. graphiti_core/nodes.py +420 -205
  36. graphiti_core/prompts/dedupe_edges.py +46 -32
  37. graphiti_core/prompts/dedupe_nodes.py +67 -42
  38. graphiti_core/prompts/eval.py +4 -4
  39. graphiti_core/prompts/extract_edges.py +27 -16
  40. graphiti_core/prompts/extract_nodes.py +74 -31
  41. graphiti_core/prompts/prompt_helpers.py +39 -0
  42. graphiti_core/prompts/snippets.py +29 -0
  43. graphiti_core/prompts/summarize_nodes.py +23 -25
  44. graphiti_core/search/search.py +158 -82
  45. graphiti_core/search/search_config.py +39 -4
  46. graphiti_core/search/search_filters.py +126 -35
  47. graphiti_core/search/search_helpers.py +5 -6
  48. graphiti_core/search/search_utils.py +1405 -485
  49. graphiti_core/telemetry/__init__.py +9 -0
  50. graphiti_core/telemetry/telemetry.py +117 -0
  51. graphiti_core/tracer.py +193 -0
  52. graphiti_core/utils/bulk_utils.py +364 -285
  53. graphiti_core/utils/datetime_utils.py +13 -0
  54. graphiti_core/utils/maintenance/community_operations.py +67 -49
  55. graphiti_core/utils/maintenance/dedup_helpers.py +262 -0
  56. graphiti_core/utils/maintenance/edge_operations.py +339 -197
  57. graphiti_core/utils/maintenance/graph_data_operations.py +50 -114
  58. graphiti_core/utils/maintenance/node_operations.py +319 -238
  59. graphiti_core/utils/maintenance/temporal_operations.py +11 -3
  60. graphiti_core/utils/ontology_utils/entity_types_utils.py +1 -1
  61. graphiti_core/utils/text_utils.py +53 -0
  62. graphiti_core-0.24.3.dist-info/METADATA +726 -0
  63. graphiti_core-0.24.3.dist-info/RECORD +86 -0
  64. {graphiti_core-0.12.0rc1.dist-info → graphiti_core-0.24.3.dist-info}/WHEEL +1 -1
  65. graphiti_core-0.12.0rc1.dist-info/METADATA +0 -350
  66. graphiti_core-0.12.0rc1.dist-info/RECORD +0 -66
  67. /graphiti_core/{utils/maintenance/utils.py → migrations/__init__.py} +0 -0
  68. {graphiti_core-0.12.0rc1.dist-info → graphiti_core-0.24.3.dist-info/licenses}/LICENSE +0 -0
@@ -19,7 +19,8 @@ from enum import Enum
19
19
  from typing import Any
20
20
 
21
21
  from pydantic import BaseModel, Field
22
- from typing_extensions import LiteralString
22
+
23
+ from graphiti_core.driver.driver import GraphProvider
23
24
 
24
25
 
25
26
  class ComparisonOperator(Enum):
@@ -29,143 +30,233 @@ class ComparisonOperator(Enum):
29
30
  less_than = '<'
30
31
  greater_than_equal = '>='
31
32
  less_than_equal = '<='
33
+ is_null = 'IS NULL'
34
+ is_not_null = 'IS NOT NULL'
32
35
 
33
36
 
34
37
  class DateFilter(BaseModel):
35
- date: datetime = Field(description='A datetime to filter on')
38
+ date: datetime | None = Field(description='A datetime to filter on')
36
39
  comparison_operator: ComparisonOperator = Field(
37
40
  description='Comparison operator for date filter'
38
41
  )
39
42
 
40
43
 
44
+ class PropertyFilter(BaseModel):
45
+ property_name: str = Field(description='Property name')
46
+ property_value: str | int | float | None = Field(
47
+ description='Value you want to match on for the property'
48
+ )
49
+ comparison_operator: ComparisonOperator = Field(
50
+ description='Comparison operator for the property'
51
+ )
52
+
53
+
41
54
  class SearchFilters(BaseModel):
42
55
  node_labels: list[str] | None = Field(
43
56
  default=None, description='List of node labels to filter on'
44
57
  )
58
+ edge_types: list[str] | None = Field(
59
+ default=None, description='List of edge types to filter on'
60
+ )
45
61
  valid_at: list[list[DateFilter]] | None = Field(default=None)
46
62
  invalid_at: list[list[DateFilter]] | None = Field(default=None)
47
63
  created_at: list[list[DateFilter]] | None = Field(default=None)
48
64
  expired_at: list[list[DateFilter]] | None = Field(default=None)
65
+ edge_uuids: list[str] | None = Field(default=None)
66
+ property_filters: list[PropertyFilter] | None = Field(default=None)
67
+
68
+
69
+ def cypher_to_opensearch_operator(op: ComparisonOperator) -> str:
70
+ mapping = {
71
+ ComparisonOperator.greater_than: 'gt',
72
+ ComparisonOperator.less_than: 'lt',
73
+ ComparisonOperator.greater_than_equal: 'gte',
74
+ ComparisonOperator.less_than_equal: 'lte',
75
+ }
76
+ return mapping.get(op, op.value)
49
77
 
50
78
 
51
79
  def node_search_filter_query_constructor(
52
80
  filters: SearchFilters,
53
- ) -> tuple[LiteralString, dict[str, Any]]:
54
- filter_query: LiteralString = ''
81
+ provider: GraphProvider,
82
+ ) -> tuple[list[str], dict[str, Any]]:
83
+ filter_queries: list[str] = []
55
84
  filter_params: dict[str, Any] = {}
56
85
 
57
86
  if filters.node_labels is not None:
58
- node_labels = '|'.join(filters.node_labels)
59
- node_label_filter = ' AND n:' + node_labels
60
- filter_query += node_label_filter
87
+ if provider == GraphProvider.KUZU:
88
+ node_label_filter = 'list_has_all(n.labels, $labels)'
89
+ filter_params['labels'] = filters.node_labels
90
+ else:
91
+ node_labels = '|'.join(filters.node_labels)
92
+ node_label_filter = 'n:' + node_labels
93
+ filter_queries.append(node_label_filter)
61
94
 
62
- return filter_query, filter_params
95
+ return filter_queries, filter_params
96
+
97
+
98
+ def date_filter_query_constructor(
99
+ value_name: str, param_name: str, operator: ComparisonOperator
100
+ ) -> str:
101
+ query = '(' + value_name + ' '
102
+
103
+ if operator == ComparisonOperator.is_null or operator == ComparisonOperator.is_not_null:
104
+ query += operator.value + ')'
105
+ else:
106
+ query += operator.value + ' ' + param_name + ')'
107
+
108
+ return query
63
109
 
64
110
 
65
111
  def edge_search_filter_query_constructor(
66
112
  filters: SearchFilters,
67
- ) -> tuple[LiteralString, dict[str, Any]]:
68
- filter_query: LiteralString = ''
113
+ provider: GraphProvider,
114
+ ) -> tuple[list[str], dict[str, Any]]:
115
+ filter_queries: list[str] = []
69
116
  filter_params: dict[str, Any] = {}
70
117
 
118
+ if filters.edge_types is not None:
119
+ edge_types = filters.edge_types
120
+ filter_queries.append('e.name in $edge_types')
121
+ filter_params['edge_types'] = edge_types
122
+
123
+ if filters.edge_uuids is not None:
124
+ filter_queries.append('e.uuid in $edge_uuids')
125
+ filter_params['edge_uuids'] = filters.edge_uuids
126
+
127
+ if filters.node_labels is not None:
128
+ if provider == GraphProvider.KUZU:
129
+ node_label_filter = (
130
+ 'list_has_all(n.labels, $labels) AND list_has_all(m.labels, $labels)'
131
+ )
132
+ filter_params['labels'] = filters.node_labels
133
+ else:
134
+ node_labels = '|'.join(filters.node_labels)
135
+ node_label_filter = 'n:' + node_labels + ' AND m:' + node_labels
136
+ filter_queries.append(node_label_filter)
137
+
71
138
  if filters.valid_at is not None:
72
- valid_at_filter = ' AND ('
139
+ valid_at_filter = '('
73
140
  for i, or_list in enumerate(filters.valid_at):
74
141
  for j, date_filter in enumerate(or_list):
75
- filter_params['valid_at_' + str(j)] = date_filter.date
142
+ if date_filter.comparison_operator not in [
143
+ ComparisonOperator.is_null,
144
+ ComparisonOperator.is_not_null,
145
+ ]:
146
+ filter_params['valid_at_' + str(j)] = date_filter.date
76
147
 
77
148
  and_filters = [
78
- '(r.valid_at ' + date_filter.comparison_operator.value + f' $valid_at_{j})'
149
+ date_filter_query_constructor(
150
+ 'e.valid_at', f'$valid_at_{j}', date_filter.comparison_operator
151
+ )
79
152
  for j, date_filter in enumerate(or_list)
80
153
  ]
81
154
  and_filter_query = ''
82
155
  for j, and_filter in enumerate(and_filters):
83
156
  and_filter_query += and_filter
84
- if j != len(and_filter_query) - 1:
157
+ if j != len(and_filters) - 1:
85
158
  and_filter_query += ' AND '
86
159
 
87
160
  valid_at_filter += and_filter_query
88
161
 
89
- if i == len(or_list) - 1:
162
+ if i == len(filters.valid_at) - 1:
90
163
  valid_at_filter += ')'
91
164
  else:
92
165
  valid_at_filter += ' OR '
93
166
 
94
- filter_query += valid_at_filter
167
+ filter_queries.append(valid_at_filter)
95
168
 
96
169
  if filters.invalid_at is not None:
97
- invalid_at_filter = ' AND ('
170
+ invalid_at_filter = '('
98
171
  for i, or_list in enumerate(filters.invalid_at):
99
172
  for j, date_filter in enumerate(or_list):
100
- filter_params['invalid_at_' + str(j)] = date_filter.date
173
+ if date_filter.comparison_operator not in [
174
+ ComparisonOperator.is_null,
175
+ ComparisonOperator.is_not_null,
176
+ ]:
177
+ filter_params['invalid_at_' + str(j)] = date_filter.date
101
178
 
102
179
  and_filters = [
103
- '(r.invalid_at ' + date_filter.comparison_operator.value + f' $invalid_at_{j})'
180
+ date_filter_query_constructor(
181
+ 'e.invalid_at', f'$invalid_at_{j}', date_filter.comparison_operator
182
+ )
104
183
  for j, date_filter in enumerate(or_list)
105
184
  ]
106
185
  and_filter_query = ''
107
186
  for j, and_filter in enumerate(and_filters):
108
187
  and_filter_query += and_filter
109
- if j != len(and_filter_query) - 1:
188
+ if j != len(and_filters) - 1:
110
189
  and_filter_query += ' AND '
111
190
 
112
191
  invalid_at_filter += and_filter_query
113
192
 
114
- if i == len(or_list) - 1:
193
+ if i == len(filters.invalid_at) - 1:
115
194
  invalid_at_filter += ')'
116
195
  else:
117
196
  invalid_at_filter += ' OR '
118
197
 
119
- filter_query += invalid_at_filter
198
+ filter_queries.append(invalid_at_filter)
120
199
 
121
200
  if filters.created_at is not None:
122
- created_at_filter = ' AND ('
201
+ created_at_filter = '('
123
202
  for i, or_list in enumerate(filters.created_at):
124
203
  for j, date_filter in enumerate(or_list):
125
- filter_params['created_at_' + str(j)] = date_filter.date
204
+ if date_filter.comparison_operator not in [
205
+ ComparisonOperator.is_null,
206
+ ComparisonOperator.is_not_null,
207
+ ]:
208
+ filter_params['created_at_' + str(j)] = date_filter.date
126
209
 
127
210
  and_filters = [
128
- '(r.created_at ' + date_filter.comparison_operator.value + f' $created_at_{j})'
211
+ date_filter_query_constructor(
212
+ 'e.created_at', f'$created_at_{j}', date_filter.comparison_operator
213
+ )
129
214
  for j, date_filter in enumerate(or_list)
130
215
  ]
131
216
  and_filter_query = ''
132
217
  for j, and_filter in enumerate(and_filters):
133
218
  and_filter_query += and_filter
134
- if j != len(and_filter_query) - 1:
219
+ if j != len(and_filters) - 1:
135
220
  and_filter_query += ' AND '
136
221
 
137
222
  created_at_filter += and_filter_query
138
223
 
139
- if i == len(or_list) - 1:
224
+ if i == len(filters.created_at) - 1:
140
225
  created_at_filter += ')'
141
226
  else:
142
227
  created_at_filter += ' OR '
143
228
 
144
- filter_query += created_at_filter
229
+ filter_queries.append(created_at_filter)
145
230
 
146
231
  if filters.expired_at is not None:
147
- expired_at_filter = 'AND ('
232
+ expired_at_filter = '('
148
233
  for i, or_list in enumerate(filters.expired_at):
149
234
  for j, date_filter in enumerate(or_list):
150
- filter_params['expired_at_' + str(j)] = date_filter.date
235
+ if date_filter.comparison_operator not in [
236
+ ComparisonOperator.is_null,
237
+ ComparisonOperator.is_not_null,
238
+ ]:
239
+ filter_params['expired_at_' + str(j)] = date_filter.date
151
240
 
152
241
  and_filters = [
153
- '(r.expired_at ' + date_filter.comparison_operator.value + f' $expired_at_{j})'
242
+ date_filter_query_constructor(
243
+ 'e.expired_at', f'$expired_at_{j}', date_filter.comparison_operator
244
+ )
154
245
  for j, date_filter in enumerate(or_list)
155
246
  ]
156
247
  and_filter_query = ''
157
248
  for j, and_filter in enumerate(and_filters):
158
249
  and_filter_query += and_filter
159
- if j != len(and_filter_query) - 1:
250
+ if j != len(and_filters) - 1:
160
251
  and_filter_query += ' AND '
161
252
 
162
253
  expired_at_filter += and_filter_query
163
254
 
164
- if i == len(or_list) - 1:
255
+ if i == len(filters.expired_at) - 1:
165
256
  expired_at_filter += ')'
166
257
  else:
167
258
  expired_at_filter += ' OR '
168
259
 
169
- filter_query += expired_at_filter
260
+ filter_queries.append(expired_at_filter)
170
261
 
171
- return filter_query, filter_params
262
+ return filter_queries, filter_params
@@ -14,9 +14,8 @@ See the License for the specific language governing permissions and
14
14
  limitations under the License.
15
15
  """
16
16
 
17
- import json
18
-
19
17
  from graphiti_core.edges import EntityEdge
18
+ from graphiti_core.prompts.prompt_helpers import to_prompt_json
20
19
  from graphiti_core.search.search_config import SearchResults
21
20
 
22
21
 
@@ -57,16 +56,16 @@ def search_results_to_context_string(search_results: SearchResults) -> str:
57
56
  These are the most relevant facts and their valid and invalid dates. Facts are considered valid
58
57
  between their valid_at and invalid_at dates. Facts with an invalid_at date of "Present" are considered valid.
59
58
  <FACTS>
60
- {json.dumps(fact_json, indent=12)}
59
+ {to_prompt_json(fact_json)}
61
60
  </FACTS>
62
61
  <ENTITIES>
63
- {json.dumps(entity_json, indent=12)}
62
+ {to_prompt_json(entity_json)}
64
63
  </ENTITIES>
65
64
  <EPISODES>
66
- {json.dumps(episode_json, indent=12)}
65
+ {to_prompt_json(episode_json)}
67
66
  </EPISODES>
68
67
  <COMMUNITIES>
69
- {json.dumps(community_json, indent=12)}
68
+ {to_prompt_json(community_json)}
70
69
  </COMMUNITIES>
71
70
  """
72
71