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