graphiti-core 0.17.4__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.
- 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 +61 -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 +582 -255
- graphiti_core/graphiti_types.py +2 -0
- graphiti_core/helpers.py +21 -14
- 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 +94 -50
- graphiti_core/llm_client/openai_client.py +28 -8
- 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 +23 -14
- graphiti_core/prompts/extract_nodes.py +73 -32
- 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 +109 -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/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 +286 -126
- graphiti_core/utils/maintenance/graph_data_operations.py +44 -74
- graphiti_core/utils/maintenance/node_operations.py +320 -158
- 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.24.3.dist-info}/METADATA +221 -87
- graphiti_core-0.24.3.dist-info/RECORD +86 -0
- {graphiti_core-0.17.4.dist-info → graphiti_core-0.24.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.24.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,27 @@ 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(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
|
+
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
|
+
|
|
40
54
|
class SearchFilters(BaseModel):
|
|
41
55
|
node_labels: list[str] | None = Field(
|
|
42
56
|
default=None, description='List of node labels to filter on'
|
|
@@ -48,47 +62,93 @@ class SearchFilters(BaseModel):
|
|
|
48
62
|
invalid_at: list[list[DateFilter]] | None = Field(default=None)
|
|
49
63
|
created_at: list[list[DateFilter]] | None = Field(default=None)
|
|
50
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)
|
|
51
77
|
|
|
52
78
|
|
|
53
79
|
def node_search_filter_query_constructor(
|
|
54
80
|
filters: SearchFilters,
|
|
55
|
-
|
|
56
|
-
|
|
81
|
+
provider: GraphProvider,
|
|
82
|
+
) -> tuple[list[str], dict[str, Any]]:
|
|
83
|
+
filter_queries: list[str] = []
|
|
57
84
|
filter_params: dict[str, Any] = {}
|
|
58
85
|
|
|
59
86
|
if filters.node_labels is not None:
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
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)
|
|
94
|
+
|
|
95
|
+
return filter_queries, filter_params
|
|
96
|
+
|
|
63
97
|
|
|
64
|
-
|
|
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
|
|
65
109
|
|
|
66
110
|
|
|
67
111
|
def edge_search_filter_query_constructor(
|
|
68
112
|
filters: SearchFilters,
|
|
69
|
-
|
|
70
|
-
|
|
113
|
+
provider: GraphProvider,
|
|
114
|
+
) -> tuple[list[str], dict[str, Any]]:
|
|
115
|
+
filter_queries: list[str] = []
|
|
71
116
|
filter_params: dict[str, Any] = {}
|
|
72
117
|
|
|
73
118
|
if filters.edge_types is not None:
|
|
74
119
|
edge_types = filters.edge_types
|
|
75
|
-
|
|
76
|
-
filter_query += edge_types_filter
|
|
120
|
+
filter_queries.append('e.name in $edge_types')
|
|
77
121
|
filter_params['edge_types'] = edge_types
|
|
78
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
|
+
|
|
79
127
|
if filters.node_labels is not None:
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
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)
|
|
83
137
|
|
|
84
138
|
if filters.valid_at is not None:
|
|
85
|
-
valid_at_filter = '
|
|
139
|
+
valid_at_filter = '('
|
|
86
140
|
for i, or_list in enumerate(filters.valid_at):
|
|
87
141
|
for j, date_filter in enumerate(or_list):
|
|
88
|
-
|
|
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
|
|
89
147
|
|
|
90
148
|
and_filters = [
|
|
91
|
-
|
|
149
|
+
date_filter_query_constructor(
|
|
150
|
+
'e.valid_at', f'$valid_at_{j}', date_filter.comparison_operator
|
|
151
|
+
)
|
|
92
152
|
for j, date_filter in enumerate(or_list)
|
|
93
153
|
]
|
|
94
154
|
and_filter_query = ''
|
|
@@ -104,16 +164,22 @@ def edge_search_filter_query_constructor(
|
|
|
104
164
|
else:
|
|
105
165
|
valid_at_filter += ' OR '
|
|
106
166
|
|
|
107
|
-
|
|
167
|
+
filter_queries.append(valid_at_filter)
|
|
108
168
|
|
|
109
169
|
if filters.invalid_at is not None:
|
|
110
|
-
invalid_at_filter = '
|
|
170
|
+
invalid_at_filter = '('
|
|
111
171
|
for i, or_list in enumerate(filters.invalid_at):
|
|
112
172
|
for j, date_filter in enumerate(or_list):
|
|
113
|
-
|
|
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
|
|
114
178
|
|
|
115
179
|
and_filters = [
|
|
116
|
-
|
|
180
|
+
date_filter_query_constructor(
|
|
181
|
+
'e.invalid_at', f'$invalid_at_{j}', date_filter.comparison_operator
|
|
182
|
+
)
|
|
117
183
|
for j, date_filter in enumerate(or_list)
|
|
118
184
|
]
|
|
119
185
|
and_filter_query = ''
|
|
@@ -129,16 +195,22 @@ def edge_search_filter_query_constructor(
|
|
|
129
195
|
else:
|
|
130
196
|
invalid_at_filter += ' OR '
|
|
131
197
|
|
|
132
|
-
|
|
198
|
+
filter_queries.append(invalid_at_filter)
|
|
133
199
|
|
|
134
200
|
if filters.created_at is not None:
|
|
135
|
-
created_at_filter = '
|
|
201
|
+
created_at_filter = '('
|
|
136
202
|
for i, or_list in enumerate(filters.created_at):
|
|
137
203
|
for j, date_filter in enumerate(or_list):
|
|
138
|
-
|
|
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
|
|
139
209
|
|
|
140
210
|
and_filters = [
|
|
141
|
-
|
|
211
|
+
date_filter_query_constructor(
|
|
212
|
+
'e.created_at', f'$created_at_{j}', date_filter.comparison_operator
|
|
213
|
+
)
|
|
142
214
|
for j, date_filter in enumerate(or_list)
|
|
143
215
|
]
|
|
144
216
|
and_filter_query = ''
|
|
@@ -154,16 +226,22 @@ def edge_search_filter_query_constructor(
|
|
|
154
226
|
else:
|
|
155
227
|
created_at_filter += ' OR '
|
|
156
228
|
|
|
157
|
-
|
|
229
|
+
filter_queries.append(created_at_filter)
|
|
158
230
|
|
|
159
231
|
if filters.expired_at is not None:
|
|
160
|
-
expired_at_filter = '
|
|
232
|
+
expired_at_filter = '('
|
|
161
233
|
for i, or_list in enumerate(filters.expired_at):
|
|
162
234
|
for j, date_filter in enumerate(or_list):
|
|
163
|
-
|
|
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
|
|
164
240
|
|
|
165
241
|
and_filters = [
|
|
166
|
-
|
|
242
|
+
date_filter_query_constructor(
|
|
243
|
+
'e.expired_at', f'$expired_at_{j}', date_filter.comparison_operator
|
|
244
|
+
)
|
|
167
245
|
for j, date_filter in enumerate(or_list)
|
|
168
246
|
]
|
|
169
247
|
and_filter_query = ''
|
|
@@ -179,6 +257,6 @@ def edge_search_filter_query_constructor(
|
|
|
179
257
|
else:
|
|
180
258
|
expired_at_filter += ' OR '
|
|
181
259
|
|
|
182
|
-
|
|
260
|
+
filter_queries.append(expired_at_filter)
|
|
183
261
|
|
|
184
|
-
return
|
|
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
|
-
|
|
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
|
|