graphiti-core 0.7.0__tar.gz → 0.7.2__tar.gz

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.

Files changed (61) hide show
  1. {graphiti_core-0.7.0 → graphiti_core-0.7.2}/PKG-INFO +18 -14
  2. {graphiti_core-0.7.0 → graphiti_core-0.7.2}/README.md +17 -13
  3. {graphiti_core-0.7.0 → graphiti_core-0.7.2}/graphiti_core/graphiti.py +6 -3
  4. {graphiti_core-0.7.0 → graphiti_core-0.7.2}/graphiti_core/search/search.py +10 -4
  5. {graphiti_core-0.7.0 → graphiti_core-0.7.2}/graphiti_core/search/search_filters.py +23 -4
  6. {graphiti_core-0.7.0 → graphiti_core-0.7.2}/graphiti_core/search/search_utils.py +56 -21
  7. {graphiti_core-0.7.0 → graphiti_core-0.7.2}/graphiti_core/utils/bulk_utils.py +2 -1
  8. {graphiti_core-0.7.0 → graphiti_core-0.7.2}/pyproject.toml +1 -1
  9. {graphiti_core-0.7.0 → graphiti_core-0.7.2}/LICENSE +0 -0
  10. {graphiti_core-0.7.0 → graphiti_core-0.7.2}/graphiti_core/__init__.py +0 -0
  11. {graphiti_core-0.7.0 → graphiti_core-0.7.2}/graphiti_core/cross_encoder/__init__.py +0 -0
  12. {graphiti_core-0.7.0 → graphiti_core-0.7.2}/graphiti_core/cross_encoder/bge_reranker_client.py +0 -0
  13. {graphiti_core-0.7.0 → graphiti_core-0.7.2}/graphiti_core/cross_encoder/client.py +0 -0
  14. {graphiti_core-0.7.0 → graphiti_core-0.7.2}/graphiti_core/cross_encoder/openai_reranker_client.py +0 -0
  15. {graphiti_core-0.7.0 → graphiti_core-0.7.2}/graphiti_core/edges.py +0 -0
  16. {graphiti_core-0.7.0 → graphiti_core-0.7.2}/graphiti_core/embedder/__init__.py +0 -0
  17. {graphiti_core-0.7.0 → graphiti_core-0.7.2}/graphiti_core/embedder/client.py +0 -0
  18. {graphiti_core-0.7.0 → graphiti_core-0.7.2}/graphiti_core/embedder/openai.py +0 -0
  19. {graphiti_core-0.7.0 → graphiti_core-0.7.2}/graphiti_core/embedder/voyage.py +0 -0
  20. {graphiti_core-0.7.0 → graphiti_core-0.7.2}/graphiti_core/errors.py +0 -0
  21. {graphiti_core-0.7.0 → graphiti_core-0.7.2}/graphiti_core/helpers.py +0 -0
  22. {graphiti_core-0.7.0 → graphiti_core-0.7.2}/graphiti_core/llm_client/__init__.py +0 -0
  23. {graphiti_core-0.7.0 → graphiti_core-0.7.2}/graphiti_core/llm_client/anthropic_client.py +0 -0
  24. {graphiti_core-0.7.0 → graphiti_core-0.7.2}/graphiti_core/llm_client/client.py +0 -0
  25. {graphiti_core-0.7.0 → graphiti_core-0.7.2}/graphiti_core/llm_client/config.py +0 -0
  26. {graphiti_core-0.7.0 → graphiti_core-0.7.2}/graphiti_core/llm_client/errors.py +0 -0
  27. {graphiti_core-0.7.0 → graphiti_core-0.7.2}/graphiti_core/llm_client/groq_client.py +0 -0
  28. {graphiti_core-0.7.0 → graphiti_core-0.7.2}/graphiti_core/llm_client/openai_client.py +0 -0
  29. {graphiti_core-0.7.0 → graphiti_core-0.7.2}/graphiti_core/llm_client/openai_generic_client.py +0 -0
  30. {graphiti_core-0.7.0 → graphiti_core-0.7.2}/graphiti_core/llm_client/utils.py +0 -0
  31. {graphiti_core-0.7.0 → graphiti_core-0.7.2}/graphiti_core/models/__init__.py +0 -0
  32. {graphiti_core-0.7.0 → graphiti_core-0.7.2}/graphiti_core/models/edges/__init__.py +0 -0
  33. {graphiti_core-0.7.0 → graphiti_core-0.7.2}/graphiti_core/models/edges/edge_db_queries.py +0 -0
  34. {graphiti_core-0.7.0 → graphiti_core-0.7.2}/graphiti_core/models/nodes/__init__.py +0 -0
  35. {graphiti_core-0.7.0 → graphiti_core-0.7.2}/graphiti_core/models/nodes/node_db_queries.py +0 -0
  36. {graphiti_core-0.7.0 → graphiti_core-0.7.2}/graphiti_core/nodes.py +0 -0
  37. {graphiti_core-0.7.0 → graphiti_core-0.7.2}/graphiti_core/prompts/__init__.py +0 -0
  38. {graphiti_core-0.7.0 → graphiti_core-0.7.2}/graphiti_core/prompts/dedupe_edges.py +0 -0
  39. {graphiti_core-0.7.0 → graphiti_core-0.7.2}/graphiti_core/prompts/dedupe_nodes.py +0 -0
  40. {graphiti_core-0.7.0 → graphiti_core-0.7.2}/graphiti_core/prompts/eval.py +0 -0
  41. {graphiti_core-0.7.0 → graphiti_core-0.7.2}/graphiti_core/prompts/extract_edge_dates.py +0 -0
  42. {graphiti_core-0.7.0 → graphiti_core-0.7.2}/graphiti_core/prompts/extract_edges.py +0 -0
  43. {graphiti_core-0.7.0 → graphiti_core-0.7.2}/graphiti_core/prompts/extract_nodes.py +0 -0
  44. {graphiti_core-0.7.0 → graphiti_core-0.7.2}/graphiti_core/prompts/invalidate_edges.py +0 -0
  45. {graphiti_core-0.7.0 → graphiti_core-0.7.2}/graphiti_core/prompts/lib.py +0 -0
  46. {graphiti_core-0.7.0 → graphiti_core-0.7.2}/graphiti_core/prompts/models.py +0 -0
  47. {graphiti_core-0.7.0 → graphiti_core-0.7.2}/graphiti_core/prompts/prompt_helpers.py +0 -0
  48. {graphiti_core-0.7.0 → graphiti_core-0.7.2}/graphiti_core/prompts/summarize_nodes.py +0 -0
  49. {graphiti_core-0.7.0 → graphiti_core-0.7.2}/graphiti_core/py.typed +0 -0
  50. {graphiti_core-0.7.0 → graphiti_core-0.7.2}/graphiti_core/search/__init__.py +0 -0
  51. {graphiti_core-0.7.0 → graphiti_core-0.7.2}/graphiti_core/search/search_config.py +0 -0
  52. {graphiti_core-0.7.0 → graphiti_core-0.7.2}/graphiti_core/search/search_config_recipes.py +0 -0
  53. {graphiti_core-0.7.0 → graphiti_core-0.7.2}/graphiti_core/utils/__init__.py +0 -0
  54. {graphiti_core-0.7.0 → graphiti_core-0.7.2}/graphiti_core/utils/datetime_utils.py +0 -0
  55. {graphiti_core-0.7.0 → graphiti_core-0.7.2}/graphiti_core/utils/maintenance/__init__.py +0 -0
  56. {graphiti_core-0.7.0 → graphiti_core-0.7.2}/graphiti_core/utils/maintenance/community_operations.py +0 -0
  57. {graphiti_core-0.7.0 → graphiti_core-0.7.2}/graphiti_core/utils/maintenance/edge_operations.py +0 -0
  58. {graphiti_core-0.7.0 → graphiti_core-0.7.2}/graphiti_core/utils/maintenance/graph_data_operations.py +0 -0
  59. {graphiti_core-0.7.0 → graphiti_core-0.7.2}/graphiti_core/utils/maintenance/node_operations.py +0 -0
  60. {graphiti_core-0.7.0 → graphiti_core-0.7.2}/graphiti_core/utils/maintenance/temporal_operations.py +0 -0
  61. {graphiti_core-0.7.0 → graphiti_core-0.7.2}/graphiti_core/utils/maintenance/utils.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: graphiti-core
3
- Version: 0.7.0
3
+ Version: 0.7.2
4
4
  Summary: A temporal graph building library
5
5
  License: Apache-2.0
6
6
  Author: Paul Paliychuk
@@ -20,12 +20,16 @@ Requires-Dist: python-dotenv (>=1.0.1,<2.0.0)
20
20
  Requires-Dist: tenacity (==9.0.0)
21
21
  Description-Content-Type: text/markdown
22
22
 
23
- <div align="center">
24
-
25
- # Graphiti
26
-
27
- ## Temporal Knowledge Graphs for Agentic Applications
23
+ <p align="center">
24
+ <a href="https://www.getzep.com/">
25
+ <img src="https://github.com/user-attachments/assets/119c5682-9654-4257-8922-56b7cb8ffd73" width="150" alt="Zep Logo">
26
+ </a>
27
+ </p>
28
28
 
29
+ <h1 align="center">
30
+ Graphiti
31
+ </h1>
32
+ <h2 align="center"> Temporal Knowledge Graphs for Agentic Applications</h2>
29
33
  <br />
30
34
 
31
35
  [![Discord](https://dcbadge.vercel.app/api/server/W8Kw6bsgXQ?style=flat)](https://discord.com/invite/W8Kw6bsgXQ)
@@ -34,10 +38,9 @@ Description-Content-Type: text/markdown
34
38
  [![MyPy Check](https://github.com/getzep/Graphiti/actions/workflows/typecheck.yml/badge.svg)](https://github.com/getzep/Graphiti/actions/workflows/typecheck.yml)
35
39
  [![Open in GitHub Codespaces](https://github.com/codespaces/badge.svg)](https://codespaces.new/getzep/Graphiti)
36
40
 
41
+ :star: *Help us reach more developers and grow the Graphiti community. Star this repo!*
37
42
  <br />
38
43
 
39
- </div>
40
-
41
44
  Graphiti builds dynamic, temporally aware Knowledge Graphs that represent complex, evolving relationships between
42
45
  entities over time. Graphiti ingests both unstructured and structured data, and the resulting graph may be queried using
43
46
  a fusion of time, full-text, semantic, and graph algorithm approaches.
@@ -69,7 +72,8 @@ recall and state-based reasoning for both assistants and agents.
69
72
 
70
73
  Graphiti powers the core of [Zep's memory layer](https://www.getzep.com) for LLM-powered Assistants and Agents.
71
74
 
72
- Using Graphiti, we've demonstrated Zep is the [State of the Art in Agent Memory](https://blog.getzep.com/state-of-the-art-agent-memory/).
75
+ Using Graphiti, we've demonstrated Zep is
76
+ the [State of the Art in Agent Memory](https://blog.getzep.com/state-of-the-art-agent-memory/).
73
77
 
74
78
  Read our paper: [Zep: A Temporal Knowledge Graph Architecture for Agent Memory](https://arxiv.org/abs/2501.13956).
75
79
 
@@ -108,7 +112,7 @@ scale:
108
112
  Requirements:
109
113
 
110
114
  - Python 3.10 or higher
111
- - Neo4j 5.21 or higher
115
+ - Neo4j 5.26 or higher
112
116
  - OpenAI API key (for LLM inference and embedding)
113
117
 
114
118
  Optional:
@@ -133,7 +137,8 @@ poetry add graphiti-core
133
137
 
134
138
  > [!IMPORTANT]
135
139
  > Graphiti uses OpenAI for LLM inference and embedding. Ensure that an `OPENAI_API_KEY` is set in your environment.
136
- > Support for Anthropic and Groq LLM inferences is available, too. Other LLM providers may be supported via OpenAI compatible APIs.
140
+ > Support for Anthropic and Groq LLM inferences is available, too. Other LLM providers may be supported via OpenAI
141
+ > compatible APIs.
137
142
 
138
143
  ```python
139
144
  from graphiti_core import Graphiti
@@ -198,7 +203,6 @@ graphiti.close()
198
203
  ```
199
204
 
200
205
  ## Graph Service
201
-
202
206
  The `server` directory contains an API service for interacting with the Graphiti API. It is built using FastAPI.
203
207
 
204
208
  Please see the [server README](./server/README.md) for more information.
@@ -225,8 +229,8 @@ as such this feature is off by default.
225
229
  Graphiti is under active development. We aim to maintain API stability while working on:
226
230
 
227
231
  - [ ] Supporting custom graph schemas:
228
- - Allow developers to provide their own defined node and edge classes when ingesting episodes
229
- - Enable more flexible knowledge representation tailored to specific use cases
232
+ - Allow developers to provide their own defined node and edge classes when ingesting episodes
233
+ - Enable more flexible knowledge representation tailored to specific use cases
230
234
  - [x] Enhancing retrieval capabilities with more robust and configurable options
231
235
  - [ ] Expanding test coverage to ensure reliability and catch edge cases
232
236
 
@@ -1,9 +1,13 @@
1
- <div align="center">
2
-
3
- # Graphiti
4
-
5
- ## Temporal Knowledge Graphs for Agentic Applications
1
+ <p align="center">
2
+ <a href="https://www.getzep.com/">
3
+ <img src="https://github.com/user-attachments/assets/119c5682-9654-4257-8922-56b7cb8ffd73" width="150" alt="Zep Logo">
4
+ </a>
5
+ </p>
6
6
 
7
+ <h1 align="center">
8
+ Graphiti
9
+ </h1>
10
+ <h2 align="center"> Temporal Knowledge Graphs for Agentic Applications</h2>
7
11
  <br />
8
12
 
9
13
  [![Discord](https://dcbadge.vercel.app/api/server/W8Kw6bsgXQ?style=flat)](https://discord.com/invite/W8Kw6bsgXQ)
@@ -12,10 +16,9 @@
12
16
  [![MyPy Check](https://github.com/getzep/Graphiti/actions/workflows/typecheck.yml/badge.svg)](https://github.com/getzep/Graphiti/actions/workflows/typecheck.yml)
13
17
  [![Open in GitHub Codespaces](https://github.com/codespaces/badge.svg)](https://codespaces.new/getzep/Graphiti)
14
18
 
19
+ :star: *Help us reach more developers and grow the Graphiti community. Star this repo!*
15
20
  <br />
16
21
 
17
- </div>
18
-
19
22
  Graphiti builds dynamic, temporally aware Knowledge Graphs that represent complex, evolving relationships between
20
23
  entities over time. Graphiti ingests both unstructured and structured data, and the resulting graph may be queried using
21
24
  a fusion of time, full-text, semantic, and graph algorithm approaches.
@@ -47,7 +50,8 @@ recall and state-based reasoning for both assistants and agents.
47
50
 
48
51
  Graphiti powers the core of [Zep's memory layer](https://www.getzep.com) for LLM-powered Assistants and Agents.
49
52
 
50
- Using Graphiti, we've demonstrated Zep is the [State of the Art in Agent Memory](https://blog.getzep.com/state-of-the-art-agent-memory/).
53
+ Using Graphiti, we've demonstrated Zep is
54
+ the [State of the Art in Agent Memory](https://blog.getzep.com/state-of-the-art-agent-memory/).
51
55
 
52
56
  Read our paper: [Zep: A Temporal Knowledge Graph Architecture for Agent Memory](https://arxiv.org/abs/2501.13956).
53
57
 
@@ -86,7 +90,7 @@ scale:
86
90
  Requirements:
87
91
 
88
92
  - Python 3.10 or higher
89
- - Neo4j 5.21 or higher
93
+ - Neo4j 5.26 or higher
90
94
  - OpenAI API key (for LLM inference and embedding)
91
95
 
92
96
  Optional:
@@ -111,7 +115,8 @@ poetry add graphiti-core
111
115
 
112
116
  > [!IMPORTANT]
113
117
  > Graphiti uses OpenAI for LLM inference and embedding. Ensure that an `OPENAI_API_KEY` is set in your environment.
114
- > Support for Anthropic and Groq LLM inferences is available, too. Other LLM providers may be supported via OpenAI compatible APIs.
118
+ > Support for Anthropic and Groq LLM inferences is available, too. Other LLM providers may be supported via OpenAI
119
+ > compatible APIs.
115
120
 
116
121
  ```python
117
122
  from graphiti_core import Graphiti
@@ -176,7 +181,6 @@ graphiti.close()
176
181
  ```
177
182
 
178
183
  ## Graph Service
179
-
180
184
  The `server` directory contains an API service for interacting with the Graphiti API. It is built using FastAPI.
181
185
 
182
186
  Please see the [server README](./server/README.md) for more information.
@@ -203,8 +207,8 @@ as such this feature is off by default.
203
207
  Graphiti is under active development. We aim to maintain API stability while working on:
204
208
 
205
209
  - [ ] Supporting custom graph schemas:
206
- - Allow developers to provide their own defined node and edge classes when ingesting episodes
207
- - Enable more flexible knowledge representation tailored to specific use cases
210
+ - Allow developers to provide their own defined node and edge classes when ingesting episodes
211
+ - Enable more flexible knowledge representation tailored to specific use cases
208
212
  - [x] Enhancing retrieval capabilities with more robust and configurable options
209
213
  - [ ] Expanding test coverage to ensure reliability and catch edge cases
210
214
 
@@ -351,7 +351,10 @@ class Graphiti:
351
351
  # Find relevant nodes already in the graph
352
352
  existing_nodes_lists: list[list[EntityNode]] = list(
353
353
  await semaphore_gather(
354
- *[get_relevant_nodes(self.driver, [node]) for node in extracted_nodes]
354
+ *[
355
+ get_relevant_nodes(self.driver, SearchFilters(), [node])
356
+ for node in extracted_nodes
357
+ ]
355
358
  )
356
359
  )
357
360
 
@@ -732,8 +735,8 @@ class Graphiti:
732
735
  self.llm_client,
733
736
  [source_node, target_node],
734
737
  [
735
- await get_relevant_nodes(self.driver, [source_node]),
736
- await get_relevant_nodes(self.driver, [target_node]),
738
+ await get_relevant_nodes(self.driver, SearchFilters(), [source_node]),
739
+ await get_relevant_nodes(self.driver, SearchFilters(), [target_node]),
737
740
  ],
738
741
  )
739
742
 
@@ -100,6 +100,7 @@ async def search(
100
100
  query_vector,
101
101
  group_ids,
102
102
  config.node_config,
103
+ search_filter,
103
104
  center_node_uuid,
104
105
  bfs_origin_node_uuids,
105
106
  config.limit,
@@ -233,6 +234,7 @@ async def node_search(
233
234
  query_vector: list[float],
234
235
  group_ids: list[str] | None,
235
236
  config: NodeSearchConfig | None,
237
+ search_filter: SearchFilters,
236
238
  center_node_uuid: str | None = None,
237
239
  bfs_origin_node_uuids: list[str] | None = None,
238
240
  limit=DEFAULT_SEARCH_LIMIT,
@@ -243,11 +245,13 @@ async def node_search(
243
245
  search_results: list[list[EntityNode]] = list(
244
246
  await semaphore_gather(
245
247
  *[
246
- node_fulltext_search(driver, query, group_ids, 2 * limit),
248
+ node_fulltext_search(driver, query, search_filter, group_ids, 2 * limit),
247
249
  node_similarity_search(
248
- driver, query_vector, group_ids, 2 * limit, config.sim_min_score
250
+ driver, query_vector, search_filter, group_ids, 2 * limit, config.sim_min_score
251
+ ),
252
+ node_bfs_search(
253
+ driver, bfs_origin_node_uuids, search_filter, config.bfs_max_depth, 2 * limit
249
254
  ),
250
- node_bfs_search(driver, bfs_origin_node_uuids, config.bfs_max_depth, 2 * limit),
251
255
  ]
252
256
  )
253
257
  )
@@ -255,7 +259,9 @@ async def node_search(
255
259
  if NodeSearchMethod.bfs in config.search_methods and bfs_origin_node_uuids is None:
256
260
  origin_node_uuids = [node.uuid for result in search_results for node in result]
257
261
  search_results.append(
258
- await node_bfs_search(driver, origin_node_uuids, config.bfs_max_depth, 2 * limit)
262
+ await node_bfs_search(
263
+ driver, origin_node_uuids, search_filter, config.bfs_max_depth, 2 * limit
264
+ )
259
265
  )
260
266
 
261
267
  search_result_uuids = [[node.uuid for node in result] for result in search_results]
@@ -39,18 +39,37 @@ class DateFilter(BaseModel):
39
39
 
40
40
 
41
41
  class SearchFilters(BaseModel):
42
+ node_labels: list[str] | None = Field(
43
+ default=None, description='List of node labels to filter on'
44
+ )
42
45
  valid_at: list[list[DateFilter]] | None = Field(default=None)
43
46
  invalid_at: list[list[DateFilter]] | None = Field(default=None)
44
47
  created_at: list[list[DateFilter]] | None = Field(default=None)
45
48
  expired_at: list[list[DateFilter]] | None = Field(default=None)
46
49
 
47
50
 
48
- def search_filter_query_constructor(filters: SearchFilters) -> tuple[LiteralString, dict[str, Any]]:
51
+ def node_search_filter_query_constructor(
52
+ filters: SearchFilters,
53
+ ) -> tuple[LiteralString, dict[str, Any]]:
54
+ filter_query: LiteralString = ''
55
+ filter_params: dict[str, Any] = {}
56
+
57
+ 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
61
+
62
+ return filter_query, filter_params
63
+
64
+
65
+ def edge_search_filter_query_constructor(
66
+ filters: SearchFilters,
67
+ ) -> tuple[LiteralString, dict[str, Any]]:
49
68
  filter_query: LiteralString = ''
50
69
  filter_params: dict[str, Any] = {}
51
70
 
52
71
  if filters.valid_at is not None:
53
- valid_at_filter = 'AND ('
72
+ valid_at_filter = ' AND ('
54
73
  for i, or_list in enumerate(filters.valid_at):
55
74
  for j, date_filter in enumerate(or_list):
56
75
  filter_params['valid_at_' + str(j)] = date_filter.date
@@ -75,7 +94,7 @@ def search_filter_query_constructor(filters: SearchFilters) -> tuple[LiteralStri
75
94
  filter_query += valid_at_filter
76
95
 
77
96
  if filters.invalid_at is not None:
78
- invalid_at_filter = 'AND ('
97
+ invalid_at_filter = ' AND ('
79
98
  for i, or_list in enumerate(filters.invalid_at):
80
99
  for j, date_filter in enumerate(or_list):
81
100
  filter_params['invalid_at_' + str(j)] = date_filter.date
@@ -100,7 +119,7 @@ def search_filter_query_constructor(filters: SearchFilters) -> tuple[LiteralStri
100
119
  filter_query += invalid_at_filter
101
120
 
102
121
  if filters.created_at is not None:
103
- created_at_filter = 'AND ('
122
+ created_at_filter = ' AND ('
104
123
  for i, or_list in enumerate(filters.created_at):
105
124
  for j, date_filter in enumerate(or_list):
106
125
  filter_params['created_at_' + str(j)] = date_filter.date
@@ -38,7 +38,11 @@ from graphiti_core.nodes import (
38
38
  get_community_node_from_record,
39
39
  get_entity_node_from_record,
40
40
  )
41
- from graphiti_core.search.search_filters import SearchFilters, search_filter_query_constructor
41
+ from graphiti_core.search.search_filters import (
42
+ SearchFilters,
43
+ edge_search_filter_query_constructor,
44
+ node_search_filter_query_constructor,
45
+ )
42
46
 
43
47
  logger = logging.getLogger(__name__)
44
48
 
@@ -148,13 +152,13 @@ async def edge_fulltext_search(
148
152
  if fuzzy_query == '':
149
153
  return []
150
154
 
151
- filter_query, filter_params = search_filter_query_constructor(search_filter)
155
+ filter_query, filter_params = edge_search_filter_query_constructor(search_filter)
152
156
 
153
157
  cypher_query = Query(
154
158
  """
155
159
  CALL db.index.fulltext.queryRelationships("edge_name_and_fact", $query, {limit: $limit})
156
160
  YIELD relationship AS rel, score
157
- MATCH (:ENTITY)-[r:RELATES_TO]->(:ENTITY)
161
+ MATCH (:Entity)-[r:RELATES_TO]->(:Entity)
158
162
  WHERE r.group_id IN $group_ids"""
159
163
  + filter_query
160
164
  + """\nWITH r, score, startNode(r) AS n, endNode(r) AS m
@@ -207,7 +211,7 @@ async def edge_similarity_search(
207
211
 
208
212
  query_params: dict[str, Any] = {}
209
213
 
210
- filter_query, filter_params = search_filter_query_constructor(search_filter)
214
+ filter_query, filter_params = edge_search_filter_query_constructor(search_filter)
211
215
  query_params.update(filter_params)
212
216
 
213
217
  group_filter_query: LiteralString = ''
@@ -225,8 +229,8 @@ async def edge_similarity_search(
225
229
 
226
230
  query: LiteralString = (
227
231
  """
228
- MATCH (n:Entity)-[r:RELATES_TO]->(m:Entity)
229
- """
232
+ MATCH (n:Entity)-[r:RELATES_TO]->(m:Entity)
233
+ """
230
234
  + group_filter_query
231
235
  + filter_query
232
236
  + """\nWITH DISTINCT r, vector.similarity.cosine(r.fact_embedding, $search_vector) AS score
@@ -278,7 +282,7 @@ async def edge_bfs_search(
278
282
  if bfs_origin_node_uuids is None:
279
283
  return []
280
284
 
281
- filter_query, filter_params = search_filter_query_constructor(search_filter)
285
+ filter_query, filter_params = edge_search_filter_query_constructor(search_filter)
282
286
 
283
287
  query = Query(
284
288
  """
@@ -325,6 +329,7 @@ async def edge_bfs_search(
325
329
  async def node_fulltext_search(
326
330
  driver: AsyncDriver,
327
331
  query: str,
332
+ search_filter: SearchFilters,
328
333
  group_ids: list[str] | None = None,
329
334
  limit=RELEVANT_SCHEMA_LIMIT,
330
335
  ) -> list[EntityNode]:
@@ -333,10 +338,17 @@ async def node_fulltext_search(
333
338
  if fuzzy_query == '':
334
339
  return []
335
340
 
341
+ filter_query, filter_params = node_search_filter_query_constructor(search_filter)
342
+
336
343
  records, _, _ = await driver.execute_query(
337
344
  """
338
345
  CALL db.index.fulltext.queryNodes("node_name_and_summary", $query, {limit: $limit})
339
- YIELD node AS n, score
346
+ YIELD node AS node, score
347
+ MATCH (n:Entity)
348
+ WHERE n.uuid = node.uuid
349
+ """
350
+ + filter_query
351
+ + """
340
352
  RETURN
341
353
  n.uuid AS uuid,
342
354
  n.group_id AS group_id,
@@ -349,6 +361,7 @@ async def node_fulltext_search(
349
361
  ORDER BY score DESC
350
362
  LIMIT $limit
351
363
  """,
364
+ filter_params,
352
365
  query=fuzzy_query,
353
366
  group_ids=group_ids,
354
367
  limit=limit,
@@ -363,6 +376,7 @@ async def node_fulltext_search(
363
376
  async def node_similarity_search(
364
377
  driver: AsyncDriver,
365
378
  search_vector: list[float],
379
+ search_filter: SearchFilters,
366
380
  group_ids: list[str] | None = None,
367
381
  limit=RELEVANT_SCHEMA_LIMIT,
368
382
  min_score: float = DEFAULT_MIN_SCORE,
@@ -379,12 +393,16 @@ async def node_similarity_search(
379
393
  group_filter_query += 'WHERE n.group_id IN $group_ids'
380
394
  query_params['group_ids'] = group_ids
381
395
 
396
+ filter_query, filter_params = node_search_filter_query_constructor(search_filter)
397
+ query_params.update(filter_params)
398
+
382
399
  records, _, _ = await driver.execute_query(
383
400
  runtime_query
384
401
  + """
385
402
  MATCH (n:Entity)
386
403
  """
387
404
  + group_filter_query
405
+ + filter_query
388
406
  + """
389
407
  WITH n, vector.similarity.cosine(n.name_embedding, $search_vector) AS score
390
408
  WHERE score > $min_score
@@ -416,6 +434,7 @@ async def node_similarity_search(
416
434
  async def node_bfs_search(
417
435
  driver: AsyncDriver,
418
436
  bfs_origin_node_uuids: list[str] | None,
437
+ search_filter: SearchFilters,
419
438
  bfs_max_depth: int,
420
439
  limit: int,
421
440
  ) -> list[EntityNode]:
@@ -423,21 +442,28 @@ async def node_bfs_search(
423
442
  if bfs_origin_node_uuids is None:
424
443
  return []
425
444
 
445
+ filter_query, filter_params = node_search_filter_query_constructor(search_filter)
446
+
426
447
  records, _, _ = await driver.execute_query(
427
448
  """
428
449
  UNWIND $bfs_origin_node_uuids AS origin_uuid
429
450
  MATCH (origin:Entity|Episodic {uuid: origin_uuid})-[:RELATES_TO|MENTIONS]->{1,3}(n:Entity)
430
- RETURN DISTINCT
431
- n.uuid As uuid,
432
- n.group_id AS group_id,
433
- n.name AS name,
434
- n.name_embedding AS name_embedding,
435
- n.created_at AS created_at,
436
- n.summary AS summary,
437
- labels(n) AS labels,
438
- properties(n) AS attributes
439
- LIMIT $limit
440
- """,
451
+ WHERE n.group_id = origin.group_id
452
+ """
453
+ + filter_query
454
+ + """
455
+ RETURN DISTINCT
456
+ n.uuid As uuid,
457
+ n.group_id AS group_id,
458
+ n.name AS name,
459
+ n.name_embedding AS name_embedding,
460
+ n.created_at AS created_at,
461
+ n.summary AS summary,
462
+ labels(n) AS labels,
463
+ properties(n) AS attributes
464
+ LIMIT $limit
465
+ """,
466
+ filter_params,
441
467
  bfs_origin_node_uuids=bfs_origin_node_uuids,
442
468
  depth=bfs_max_depth,
443
469
  limit=limit,
@@ -539,6 +565,7 @@ async def hybrid_node_search(
539
565
  queries: list[str],
540
566
  embeddings: list[list[float]],
541
567
  driver: AsyncDriver,
568
+ search_filter: SearchFilters,
542
569
  group_ids: list[str] | None = None,
543
570
  limit: int = RELEVANT_SCHEMA_LIMIT,
544
571
  ) -> list[EntityNode]:
@@ -583,8 +610,14 @@ async def hybrid_node_search(
583
610
  start = time()
584
611
  results: list[list[EntityNode]] = list(
585
612
  await semaphore_gather(
586
- *[node_fulltext_search(driver, q, group_ids, 2 * limit) for q in queries],
587
- *[node_similarity_search(driver, e, group_ids, 2 * limit) for e in embeddings],
613
+ *[
614
+ node_fulltext_search(driver, q, search_filter, group_ids, 2 * limit)
615
+ for q in queries
616
+ ],
617
+ *[
618
+ node_similarity_search(driver, e, search_filter, group_ids, 2 * limit)
619
+ for e in embeddings
620
+ ],
588
621
  )
589
622
  )
590
623
 
@@ -604,6 +637,7 @@ async def hybrid_node_search(
604
637
 
605
638
  async def get_relevant_nodes(
606
639
  driver: AsyncDriver,
640
+ search_filter: SearchFilters,
607
641
  nodes: list[EntityNode],
608
642
  ) -> list[EntityNode]:
609
643
  """
@@ -635,6 +669,7 @@ async def get_relevant_nodes(
635
669
  [node.name for node in nodes],
636
670
  [node.name_embedding for node in nodes if node.name_embedding is not None],
637
671
  driver,
672
+ search_filter,
638
673
  [node.group_id for node in nodes],
639
674
  )
640
675
 
@@ -37,6 +37,7 @@ from graphiti_core.models.nodes.node_db_queries import (
37
37
  EPISODIC_NODE_SAVE_BULK,
38
38
  )
39
39
  from graphiti_core.nodes import EntityNode, EpisodeType, EpisodicNode
40
+ from graphiti_core.search.search_filters import SearchFilters
40
41
  from graphiti_core.search.search_utils import get_relevant_edges, get_relevant_nodes
41
42
  from graphiti_core.utils.datetime_utils import utc_now
42
43
  from graphiti_core.utils.maintenance.edge_operations import (
@@ -188,7 +189,7 @@ async def dedupe_nodes_bulk(
188
189
 
189
190
  existing_nodes_chunks: list[list[EntityNode]] = list(
190
191
  await semaphore_gather(
191
- *[get_relevant_nodes(driver, node_chunk) for node_chunk in node_chunks]
192
+ *[get_relevant_nodes(driver, SearchFilters(), node_chunk) for node_chunk in node_chunks]
192
193
  )
193
194
  )
194
195
 
@@ -1,6 +1,6 @@
1
1
  [tool.poetry]
2
2
  name = "graphiti-core"
3
- version = "0.7.0"
3
+ version = "0.7.2"
4
4
  description = "A temporal graph building library"
5
5
  authors = [
6
6
  "Paul Paliychuk <paul@getzep.com>",
File without changes