graphiti-core 0.1.0__py3-none-any.whl → 0.2.0__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.
- graphiti_core/graphiti.py +105 -85
- graphiti_core/llm_client/openai_client.py +0 -1
- graphiti_core/prompts/dedupe_edges.py +46 -8
- graphiti_core/prompts/dedupe_nodes.py +61 -13
- graphiti_core/prompts/extract_edges.py +2 -1
- graphiti_core/prompts/extract_nodes.py +2 -0
- graphiti_core/search/search.py +8 -8
- graphiti_core/search/search_utils.py +44 -26
- graphiti_core/utils/bulk_utils.py +138 -20
- graphiti_core/utils/maintenance/edge_operations.py +76 -9
- graphiti_core/utils/maintenance/node_operations.py +98 -40
- graphiti_core/utils/maintenance/temporal_operations.py +3 -4
- graphiti_core/utils/utils.py +22 -1
- {graphiti_core-0.1.0.dist-info → graphiti_core-0.2.0.dist-info}/METADATA +38 -38
- {graphiti_core-0.1.0.dist-info → graphiti_core-0.2.0.dist-info}/RECORD +17 -17
- {graphiti_core-0.1.0.dist-info → graphiti_core-0.2.0.dist-info}/LICENSE +0 -0
- {graphiti_core-0.1.0.dist-info → graphiti_core-0.2.0.dist-info}/WHEEL +0 -0
|
@@ -14,6 +14,7 @@ See the License for the specific language governing permissions and
|
|
|
14
14
|
limitations under the License.
|
|
15
15
|
"""
|
|
16
16
|
|
|
17
|
+
import asyncio
|
|
17
18
|
import logging
|
|
18
19
|
from datetime import datetime
|
|
19
20
|
from time import time
|
|
@@ -27,7 +28,7 @@ logger = logging.getLogger(__name__)
|
|
|
27
28
|
|
|
28
29
|
|
|
29
30
|
async def extract_message_nodes(
|
|
30
|
-
|
|
31
|
+
llm_client: LLMClient, episode: EpisodicNode, previous_episodes: list[EpisodicNode]
|
|
31
32
|
) -> list[dict[str, Any]]:
|
|
32
33
|
# Prepare context for LLM
|
|
33
34
|
context = {
|
|
@@ -48,8 +49,8 @@ async def extract_message_nodes(
|
|
|
48
49
|
|
|
49
50
|
|
|
50
51
|
async def extract_json_nodes(
|
|
51
|
-
|
|
52
|
-
|
|
52
|
+
llm_client: LLMClient,
|
|
53
|
+
episode: EpisodicNode,
|
|
53
54
|
) -> list[dict[str, Any]]:
|
|
54
55
|
# Prepare context for LLM
|
|
55
56
|
context = {
|
|
@@ -66,9 +67,9 @@ async def extract_json_nodes(
|
|
|
66
67
|
|
|
67
68
|
|
|
68
69
|
async def extract_nodes(
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
70
|
+
llm_client: LLMClient,
|
|
71
|
+
episode: EpisodicNode,
|
|
72
|
+
previous_episodes: list[EpisodicNode],
|
|
72
73
|
) -> list[EntityNode]:
|
|
73
74
|
start = time()
|
|
74
75
|
extracted_node_data: list[dict[str, Any]] = []
|
|
@@ -95,29 +96,24 @@ async def extract_nodes(
|
|
|
95
96
|
|
|
96
97
|
|
|
97
98
|
async def dedupe_extracted_nodes(
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
) -> tuple[list[EntityNode], dict[str, str]
|
|
99
|
+
llm_client: LLMClient,
|
|
100
|
+
extracted_nodes: list[EntityNode],
|
|
101
|
+
existing_nodes: list[EntityNode],
|
|
102
|
+
) -> tuple[list[EntityNode], dict[str, str]]:
|
|
102
103
|
start = time()
|
|
103
104
|
|
|
104
105
|
# build existing node map
|
|
105
106
|
node_map: dict[str, EntityNode] = {}
|
|
106
107
|
for node in existing_nodes:
|
|
107
|
-
node_map[node.
|
|
108
|
-
|
|
109
|
-
# Temp hack
|
|
110
|
-
new_nodes_map: dict[str, EntityNode] = {}
|
|
111
|
-
for node in extracted_nodes:
|
|
112
|
-
new_nodes_map[node.name] = node
|
|
108
|
+
node_map[node.uuid] = node
|
|
113
109
|
|
|
114
110
|
# Prepare context for LLM
|
|
115
111
|
existing_nodes_context = [
|
|
116
|
-
{'name': node.name, 'summary': node.summary} for node in existing_nodes
|
|
112
|
+
{'uuid': node.uuid, 'name': node.name, 'summary': node.summary} for node in existing_nodes
|
|
117
113
|
]
|
|
118
114
|
|
|
119
115
|
extracted_nodes_context = [
|
|
120
|
-
{'name': node.name, 'summary': node.summary} for node in extracted_nodes
|
|
116
|
+
{'uuid': node.uuid, 'name': node.name, 'summary': node.summary} for node in extracted_nodes
|
|
121
117
|
]
|
|
122
118
|
|
|
123
119
|
context = {
|
|
@@ -134,42 +130,104 @@ async def dedupe_extracted_nodes(
|
|
|
134
130
|
|
|
135
131
|
uuid_map: dict[str, str] = {}
|
|
136
132
|
for duplicate in duplicate_data:
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
uuid_map[uuid] = uuid_value
|
|
133
|
+
uuid_value = duplicate['duplicate_of']
|
|
134
|
+
uuid_map[duplicate['uuid']] = uuid_value
|
|
140
135
|
|
|
141
136
|
nodes: list[EntityNode] = []
|
|
142
|
-
brand_new_nodes: list[EntityNode] = []
|
|
143
137
|
for node in extracted_nodes:
|
|
144
138
|
if node.uuid in uuid_map:
|
|
145
139
|
existing_uuid = uuid_map[node.uuid]
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
140
|
+
existing_node = node_map[existing_uuid]
|
|
141
|
+
nodes.append(existing_node)
|
|
142
|
+
else:
|
|
143
|
+
nodes.append(node)
|
|
144
|
+
|
|
145
|
+
return nodes, uuid_map
|
|
146
|
+
|
|
147
|
+
|
|
148
|
+
async def resolve_extracted_nodes(
|
|
149
|
+
llm_client: LLMClient,
|
|
150
|
+
extracted_nodes: list[EntityNode],
|
|
151
|
+
existing_nodes_lists: list[list[EntityNode]],
|
|
152
|
+
) -> tuple[list[EntityNode], dict[str, str]]:
|
|
153
|
+
uuid_map: dict[str, str] = {}
|
|
154
|
+
resolved_nodes: list[EntityNode] = []
|
|
155
|
+
results: list[tuple[EntityNode, dict[str, str]]] = list(
|
|
156
|
+
await asyncio.gather(
|
|
157
|
+
*[
|
|
158
|
+
resolve_extracted_node(llm_client, extracted_node, existing_nodes)
|
|
159
|
+
for extracted_node, existing_nodes in zip(extracted_nodes, existing_nodes_lists)
|
|
160
|
+
]
|
|
161
|
+
)
|
|
162
|
+
)
|
|
163
|
+
|
|
164
|
+
for result in results:
|
|
165
|
+
uuid_map.update(result[1])
|
|
166
|
+
resolved_nodes.append(result[0])
|
|
167
|
+
|
|
168
|
+
return resolved_nodes, uuid_map
|
|
169
|
+
|
|
170
|
+
|
|
171
|
+
async def resolve_extracted_node(
|
|
172
|
+
llm_client: LLMClient, extracted_node: EntityNode, existing_nodes: list[EntityNode]
|
|
173
|
+
) -> tuple[EntityNode, dict[str, str]]:
|
|
174
|
+
start = time()
|
|
175
|
+
|
|
176
|
+
# Prepare context for LLM
|
|
177
|
+
existing_nodes_context = [
|
|
178
|
+
{'uuid': node.uuid, 'name': node.name, 'summary': node.summary} for node in existing_nodes
|
|
179
|
+
]
|
|
180
|
+
|
|
181
|
+
extracted_node_context = {
|
|
182
|
+
'uuid': extracted_node.uuid,
|
|
183
|
+
'name': extracted_node.name,
|
|
184
|
+
'summary': extracted_node.summary,
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
context = {
|
|
188
|
+
'existing_nodes': existing_nodes_context,
|
|
189
|
+
'extracted_nodes': extracted_node_context,
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
llm_response = await llm_client.generate_response(prompt_library.dedupe_nodes.v3(context))
|
|
193
|
+
|
|
194
|
+
is_duplicate: bool = llm_response.get('is_duplicate', False)
|
|
195
|
+
uuid: str | None = llm_response.get('uuid', None)
|
|
196
|
+
summary = llm_response.get('summary', '')
|
|
197
|
+
|
|
198
|
+
node = extracted_node
|
|
199
|
+
uuid_map: dict[str, str] = {}
|
|
200
|
+
if is_duplicate:
|
|
201
|
+
for existing_node in existing_nodes:
|
|
202
|
+
if existing_node.uuid != uuid:
|
|
203
|
+
continue
|
|
204
|
+
node = existing_node
|
|
205
|
+
node.summary = summary
|
|
206
|
+
uuid_map[extracted_node.uuid] = existing_node.uuid
|
|
152
207
|
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
208
|
+
end = time()
|
|
209
|
+
logger.info(
|
|
210
|
+
f'Resolved node: {extracted_node.name} is {node.name}, in {(end - start) * 1000} ms'
|
|
211
|
+
)
|
|
156
212
|
|
|
157
|
-
return
|
|
213
|
+
return node, uuid_map
|
|
158
214
|
|
|
159
215
|
|
|
160
216
|
async def dedupe_node_list(
|
|
161
|
-
|
|
162
|
-
|
|
217
|
+
llm_client: LLMClient,
|
|
218
|
+
nodes: list[EntityNode],
|
|
163
219
|
) -> tuple[list[EntityNode], dict[str, str]]:
|
|
164
220
|
start = time()
|
|
165
221
|
|
|
166
222
|
# build node map
|
|
167
223
|
node_map = {}
|
|
168
224
|
for node in nodes:
|
|
169
|
-
node_map[node.
|
|
225
|
+
node_map[node.uuid] = node
|
|
170
226
|
|
|
171
227
|
# Prepare context for LLM
|
|
172
|
-
nodes_context = [
|
|
228
|
+
nodes_context = [
|
|
229
|
+
{'uuid': node.uuid, 'name': node.name, 'summary': node.summary} for node in nodes
|
|
230
|
+
]
|
|
173
231
|
|
|
174
232
|
context = {
|
|
175
233
|
'nodes': nodes_context,
|
|
@@ -188,12 +246,12 @@ async def dedupe_node_list(
|
|
|
188
246
|
unique_nodes = []
|
|
189
247
|
uuid_map: dict[str, str] = {}
|
|
190
248
|
for node_data in nodes_data:
|
|
191
|
-
node = node_map[node_data['
|
|
249
|
+
node = node_map[node_data['uuids'][0]]
|
|
250
|
+
node.summary = node_data['summary']
|
|
192
251
|
unique_nodes.append(node)
|
|
193
252
|
|
|
194
|
-
for
|
|
195
|
-
|
|
196
|
-
uuid_value = node_map[node_data['names'][0]].uuid
|
|
253
|
+
for uuid in node_data['uuids'][1:]:
|
|
254
|
+
uuid_value = node_map[node_data['uuids'][0]].uuid
|
|
197
255
|
uuid_map[uuid] = uuid_value
|
|
198
256
|
|
|
199
257
|
return unique_nodes, uuid_map
|
|
@@ -147,16 +147,15 @@ def process_edge_invalidation_llm_response(
|
|
|
147
147
|
async def extract_edge_dates(
|
|
148
148
|
llm_client: LLMClient,
|
|
149
149
|
edge: EntityEdge,
|
|
150
|
-
reference_time: datetime,
|
|
151
150
|
current_episode: EpisodicNode,
|
|
152
151
|
previous_episodes: List[EpisodicNode],
|
|
153
|
-
) -> tuple[datetime | None, datetime | None
|
|
152
|
+
) -> tuple[datetime | None, datetime | None]:
|
|
154
153
|
context = {
|
|
155
154
|
'edge_name': edge.name,
|
|
156
155
|
'edge_fact': edge.fact,
|
|
157
156
|
'current_episode': current_episode.content,
|
|
158
157
|
'previous_episodes': [ep.content for ep in previous_episodes],
|
|
159
|
-
'reference_timestamp':
|
|
158
|
+
'reference_timestamp': current_episode.valid_at.isoformat(),
|
|
160
159
|
}
|
|
161
160
|
llm_response = await llm_client.generate_response(prompt_library.extract_edge_dates.v1(context))
|
|
162
161
|
|
|
@@ -181,4 +180,4 @@ async def extract_edge_dates(
|
|
|
181
180
|
|
|
182
181
|
logger.info(f'Edge date extraction explanation: {explanation}')
|
|
183
182
|
|
|
184
|
-
return valid_at_datetime, invalid_at_datetime
|
|
183
|
+
return valid_at_datetime, invalid_at_datetime
|
graphiti_core/utils/utils.py
CHANGED
|
@@ -15,8 +15,9 @@ limitations under the License.
|
|
|
15
15
|
"""
|
|
16
16
|
|
|
17
17
|
import logging
|
|
18
|
+
from collections import defaultdict
|
|
18
19
|
|
|
19
|
-
from graphiti_core.edges import EpisodicEdge
|
|
20
|
+
from graphiti_core.edges import EntityEdge, EpisodicEdge
|
|
20
21
|
from graphiti_core.nodes import EntityNode, EpisodicNode
|
|
21
22
|
|
|
22
23
|
logger = logging.getLogger(__name__)
|
|
@@ -37,3 +38,23 @@ def build_episodic_edges(
|
|
|
37
38
|
)
|
|
38
39
|
|
|
39
40
|
return edges
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
def chunk_edges_by_nodes(edges: list[EntityEdge]) -> list[list[EntityEdge]]:
|
|
44
|
+
# We only want to dedupe edges that are between the same pair of nodes
|
|
45
|
+
# We build a map of the edges based on their source and target nodes.
|
|
46
|
+
edge_chunk_map: dict[str, list[EntityEdge]] = defaultdict(list)
|
|
47
|
+
for edge in edges:
|
|
48
|
+
# We drop loop edges
|
|
49
|
+
if edge.source_node_uuid == edge.target_node_uuid:
|
|
50
|
+
continue
|
|
51
|
+
|
|
52
|
+
# Keep the order of the two nodes consistent, we want to be direction agnostic during edge resolution
|
|
53
|
+
pointers = [edge.source_node_uuid, edge.target_node_uuid]
|
|
54
|
+
pointers.sort()
|
|
55
|
+
|
|
56
|
+
edge_chunk_map[pointers[0] + pointers[1]].append(edge)
|
|
57
|
+
|
|
58
|
+
edge_chunks = [chunk for chunk in edge_chunk_map.values()]
|
|
59
|
+
|
|
60
|
+
return edge_chunks
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: graphiti-core
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.2.0
|
|
4
4
|
Summary: A temporal graph building library
|
|
5
5
|
License: Apache-2.0
|
|
6
6
|
Author: Paul Paliychuk
|
|
@@ -17,64 +17,67 @@ Requires-Dist: neo4j (>=5.23.0,<6.0.0)
|
|
|
17
17
|
Requires-Dist: openai (>=1.38.0,<2.0.0)
|
|
18
18
|
Requires-Dist: pydantic (>=2.8.2,<3.0.0)
|
|
19
19
|
Requires-Dist: sentence-transformers (>=3.0.1,<4.0.0)
|
|
20
|
-
Requires-Dist: tenacity (
|
|
20
|
+
Requires-Dist: tenacity (<9.0.0)
|
|
21
21
|
Description-Content-Type: text/markdown
|
|
22
22
|
|
|
23
23
|
<div align="center">
|
|
24
24
|
|
|
25
|
-
#
|
|
25
|
+
# Graphiti
|
|
26
26
|
|
|
27
27
|
## Temporal Knowledge Graphs for Agentic Applications
|
|
28
28
|
|
|
29
29
|
<br />
|
|
30
30
|
|
|
31
31
|
[](https://discord.com/invite/W8Kw6bsgXQ)
|
|
32
|
-
[](https://codespaces.new/getzep/
|
|
32
|
+
[](https://github.com/getzep/Graphiti/actions/workflows/lint.yml)
|
|
33
|
+
[](https://github.com/getzep/Graphiti/actions/workflows/unit_tests.yml)
|
|
34
|
+
[](https://github.com/getzep/Graphiti/actions/workflows/typecheck.yml)
|
|
35
|
+
[](https://codespaces.new/getzep/Graphiti)
|
|
36
36
|
|
|
37
37
|
<br />
|
|
38
38
|
|
|
39
39
|
</div>
|
|
40
40
|
|
|
41
|
-
|
|
41
|
+
Graphiti builds dynamic, temporally aware Knowledge Graphs that represent complex, evolving relationships between entities over time. Graphiti ingests both unstructured and structured data, and the resulting graph may be queried using a fusion of time, full-text, semantic, and graph algorithm approaches.
|
|
42
42
|
|
|
43
43
|
<br />
|
|
44
44
|
|
|
45
|
-
|
|
46
45
|
<p align="center">
|
|
47
|
-
<img src="/images/graphiti-intro
|
|
46
|
+
<img src="/images/graphiti-graph-intro.gif" alt="Graphiti temporal walkthrough" width="700px">
|
|
48
47
|
</p>
|
|
49
48
|
|
|
50
49
|
<br />
|
|
51
|
-
|
|
52
|
-
|
|
50
|
+
|
|
51
|
+
Graphiti helps you create and query Knowledge Graphs that evolve over time. A knowledge graph is a network of interconnected facts, such as _“Kendra loves Adidas shoes.”_ Each fact is a “triplet” represented by two entities, or nodes (_”Kendra”_, _“Adidas shoes”_), and their relationship, or edge (_”loves”_). Knowledge Graphs have been explored extensively for information retrieval. What makes Graphiti unique is its ability to autonomously build a knowledge graph while handling changing relationships and maintaining historical context.
|
|
52
|
+
|
|
53
|
+
With Graphiti, you can build LLM applications such as:
|
|
53
54
|
|
|
54
55
|
- Assistants that learn from user interactions, fusing personal knowledge with dynamic data from business systems like CRMs and billing platforms.
|
|
55
56
|
- Agents that autonomously execute complex tasks, reasoning with state changes from multiple dynamic sources.
|
|
56
57
|
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
## Why graphiti?
|
|
58
|
+
Graphiti supports a wide range of applications in sales, customer service, health, finance, and more, enabling long-term recall and state-based reasoning for both assistants and agents.
|
|
60
59
|
|
|
61
|
-
|
|
60
|
+
## Why Graphiti?
|
|
62
61
|
|
|
63
|
-
|
|
64
|
-
- **Rich Edge Semantics**: Generates human-readable, semantic, and full-text searchable representations for edges during graph construction, enabling search and enhancing interpretability.
|
|
65
|
-
- **Temporal Awareness**: Extracts and updates time-based edge metadata from input data, enabling reasoning over changing relationships.
|
|
66
|
-
- **Hybrid Search**: Offers semantic, BM25, and graph-based search with the ability to fuse results.
|
|
67
|
-
- **Fast**: Search results in < 100ms, with latency primarily determined by the 3rd-party embedding API call.
|
|
68
|
-
- **Schema Consistency**: Maintains a coherent graph structure by reusing existing schema, preventing unnecessary proliferation of node and edge types.
|
|
62
|
+
We were intrigued by Microsoft’s GraphRAG, which expanded on RAG text chunking by using a graph to better model a document corpus and making this representation available via semantic and graph search techniques. However, GraphRAG did not address our core problem: It's primarily designed for static documents and doesn't inherently handle temporal aspects of data.
|
|
69
63
|
|
|
64
|
+
Graphiti is designed from the ground up to handle constantly changing information, hybrid semantic and graph search, and scale:
|
|
70
65
|
|
|
71
|
-
|
|
66
|
+
- **Temporal Awareness:** Tracks changes in facts and relationships over time, enabling point-in-time queries. Graph edges include temporal metadata to record relationship lifecycles.
|
|
67
|
+
- **Episodic Processing:** Ingests data as discrete episodes, maintaining data provenance and allowing incremental entity and relationship extraction.
|
|
68
|
+
- **Hybrid Search:** Combines semantic and BM25 full-text search, with the ability to rerank results by distance from a central node e.g. “Kendra”.
|
|
69
|
+
- **Scalable:** Designed for processing large datasets, with parallelization of LLM calls for bulk processing while preserving the chronology of events.
|
|
70
|
+
- **Supports Varied Sources:** Can ingest both unstructured text and structured JSON data.
|
|
72
71
|
|
|
73
|
-
|
|
72
|
+
<p align="center">
|
|
73
|
+
<img src="/images/graphiti-intro-slides-stock-2.gif" alt="Graphiti structured + unstructured demo" width="700px">
|
|
74
|
+
</p>
|
|
74
75
|
|
|
75
|
-
|
|
76
|
+
## Graphiti and Zep Memory
|
|
76
77
|
|
|
78
|
+
Graphiti powers the core of [Zep's memory layer](https://www.getzep.com) for LLM-powered Assistants and Agents.
|
|
77
79
|
|
|
80
|
+
We're excited to open-source Graphiti, believing its potential reaches far beyond memory applications.
|
|
78
81
|
|
|
79
82
|
## Installation
|
|
80
83
|
|
|
@@ -101,12 +104,10 @@ or
|
|
|
101
104
|
poetry add graphiti-core
|
|
102
105
|
```
|
|
103
106
|
|
|
104
|
-
|
|
105
|
-
|
|
106
107
|
## Quick Start
|
|
107
108
|
|
|
108
109
|
> [!IMPORTANT]
|
|
109
|
-
>
|
|
110
|
+
> Graphiti uses OpenAI for LLM inference and embedding. Ensure that an `OPENAI_API_KEY` is set in your environment. Support for Anthropic and Groq LLM inferences is available, too.
|
|
110
111
|
|
|
111
112
|
```python
|
|
112
113
|
from graphiti_core import Graphiti
|
|
@@ -116,6 +117,9 @@ from datetime import datetime
|
|
|
116
117
|
# Initialize Graphiti
|
|
117
118
|
graphiti = Graphiti("bolt://localhost:7687", "neo4j", "password")
|
|
118
119
|
|
|
120
|
+
# Initialize the graph database with Graphiti's indices. This only needs to be done once.
|
|
121
|
+
graphiti.build_indices_and_constraints()
|
|
122
|
+
|
|
119
123
|
# Add episodes
|
|
120
124
|
episodes = [
|
|
121
125
|
"Kamala Harris is the Attorney General of California. She was previously "
|
|
@@ -161,24 +165,21 @@ results = await graphiti.search('Who was the California Attorney General?')
|
|
|
161
165
|
# Rerank search results based on graph distance
|
|
162
166
|
# Provide a node UUID to prioritize results closer to that node in the graph.
|
|
163
167
|
# Results are weighted by their proximity, with distant edges receiving lower scores.
|
|
164
|
-
await
|
|
168
|
+
await graphiti.search('Who was the California Attorney General?', center_node_uuid)
|
|
165
169
|
|
|
166
170
|
# Close the connection
|
|
167
171
|
graphiti.close()
|
|
168
172
|
```
|
|
169
173
|
|
|
170
|
-
|
|
171
|
-
|
|
172
174
|
## Documentation
|
|
173
175
|
|
|
174
|
-
Visit the Zep knowledge base for
|
|
175
|
-
|
|
176
|
+
Visit the Zep knowledge base for Graphiti [Guides and API documentation](https://help.getzep.com/Graphiti/Graphiti).
|
|
176
177
|
|
|
177
178
|
## Status and Roadmap
|
|
178
179
|
|
|
179
|
-
|
|
180
|
+
Graphiti is under active development. We aim to maintain API stability while working on:
|
|
180
181
|
|
|
181
|
-
- [
|
|
182
|
+
- [x] Implementing node and edge CRUD operations
|
|
182
183
|
- [ ] Improving performance and scalability
|
|
183
184
|
- [ ] Achieving good performance with different LLM and embedding models
|
|
184
185
|
- [ ] Creating a dedicated embedder interface
|
|
@@ -188,12 +189,11 @@ graphiti is under active development. We aim to maintain API stability while wor
|
|
|
188
189
|
- [ ] Enhancing retrieval capabilities with more robust and configurable options
|
|
189
190
|
- [ ] Expanding test coverage to ensure reliability and catch edge cases
|
|
190
191
|
|
|
191
|
-
|
|
192
192
|
## Contributing
|
|
193
193
|
|
|
194
|
-
We encourage and appreciate all forms of contributions, whether it's code, documentation, addressing GitHub Issues, or answering questions in the
|
|
194
|
+
We encourage and appreciate all forms of contributions, whether it's code, documentation, addressing GitHub Issues, or answering questions in the Graphiti Discord channel. For detailed guidelines on code contributions, please refer to [CONTRIBUTING](CONTRIBUTING.md).
|
|
195
195
|
|
|
196
196
|
## Support
|
|
197
197
|
|
|
198
|
-
Join the [Zep Discord server](https://discord.com/invite/W8Kw6bsgXQ) and make your way to the **#
|
|
198
|
+
Join the [Zep Discord server](https://discord.com/invite/W8Kw6bsgXQ) and make your way to the **#Graphiti** channel!
|
|
199
199
|
|
|
@@ -1,37 +1,37 @@
|
|
|
1
1
|
graphiti_core/__init__.py,sha256=e5SWFkRiaUwfprYIeIgVIh7JDedNiloZvd3roU-0aDY,55
|
|
2
2
|
graphiti_core/edges.py,sha256=Sxsqw7WZAC6YJKftMaF9t69o7HV_GM6m6ULjtLhZg0M,7484
|
|
3
|
-
graphiti_core/graphiti.py,sha256=
|
|
3
|
+
graphiti_core/graphiti.py,sha256=BuKFvBA6tqcYKlwGexKQZ0sLNavEvDRzAMo_umlFVcM,23450
|
|
4
4
|
graphiti_core/helpers.py,sha256=EAeC3RrcecjiTGN2vxergN5RHTy2_jhFXA5PQVT3toU,200
|
|
5
5
|
graphiti_core/llm_client/__init__.py,sha256=f4OSk82jJ70wZ2HOuQu6-RQWkkf7HIB0FCT6xOuxZkQ,154
|
|
6
6
|
graphiti_core/llm_client/anthropic_client.py,sha256=C8lOLm7in_eNfOP7s8gjMM0Y99-TzKWlGaPuVGceX68,2180
|
|
7
7
|
graphiti_core/llm_client/client.py,sha256=ysBf3zDOVbgBgwHbHB478TCVnOBjIwTELNsBovUh35g,3135
|
|
8
8
|
graphiti_core/llm_client/config.py,sha256=d1oZ9tt7QBQlbph7v-0HjItb6otK9_-IwF8kkRYL2rc,2359
|
|
9
9
|
graphiti_core/llm_client/groq_client.py,sha256=qscr5-190wBTUCBL31EAjQTLytK9AF75-y9GsVRvGJU,2206
|
|
10
|
-
graphiti_core/llm_client/openai_client.py,sha256=
|
|
10
|
+
graphiti_core/llm_client/openai_client.py,sha256=Bkrp_mKzAxK6kgPzv1UtVUgr1ZvvJhE2H39hgAwWrsI,2211
|
|
11
11
|
graphiti_core/llm_client/utils.py,sha256=H8-Kwa5SyvIYDNIas8O4bHJ6jsOL49li44VoDEMyauY,555
|
|
12
12
|
graphiti_core/nodes.py,sha256=lUSGkWs7EN88qQ1kwwun-t1SWNmTL4z8fOg1dOCqwl0,7879
|
|
13
13
|
graphiti_core/prompts/__init__.py,sha256=EA-x9xUki9l8wnu2l8ek_oNf75-do5tq5hVq7Zbv8Kw,101
|
|
14
|
-
graphiti_core/prompts/dedupe_edges.py,sha256=
|
|
15
|
-
graphiti_core/prompts/dedupe_nodes.py,sha256=
|
|
14
|
+
graphiti_core/prompts/dedupe_edges.py,sha256=FuZQVZlXTYjskaRUYblToLw4cFjyDp4ECrSf-Y8Z4sU,6530
|
|
15
|
+
graphiti_core/prompts/dedupe_nodes.py,sha256=BZ9S-PB9SSGjc5Oo8ivdgA6rZx3OGOFhKtwrBlQ0bm0,7269
|
|
16
16
|
graphiti_core/prompts/extract_edge_dates.py,sha256=G-Gnsyt8pYx9lFJEwlIsTdADF3ESDe26WSsrAGmvlYk,3086
|
|
17
|
-
graphiti_core/prompts/extract_edges.py,sha256=
|
|
18
|
-
graphiti_core/prompts/extract_nodes.py,sha256=
|
|
17
|
+
graphiti_core/prompts/extract_edges.py,sha256=AQ8xYbAv_RKXAT6WMwXs1_GvUdLtM_lhLNbt3SkOAmk,5348
|
|
18
|
+
graphiti_core/prompts/extract_nodes.py,sha256=isYly1Yq9tpD-Dlj2JNvKMdsJUqjWMSO16ZFinFxWic,5304
|
|
19
19
|
graphiti_core/prompts/invalidate_edges.py,sha256=-BJ5j73fDAhRJa1abs35rKYyo-_OSZYTlQNphfo5Kuk,2993
|
|
20
20
|
graphiti_core/prompts/lib.py,sha256=RR8f8DQfioUK5bJonMzn02pKLxJlaENv1VocpvRJ488,3532
|
|
21
21
|
graphiti_core/prompts/models.py,sha256=cvx_Bv5RMFUD_5IUawYrbpOKLPHogai7_bm7YXrSz84,867
|
|
22
22
|
graphiti_core/search/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
23
|
-
graphiti_core/search/search.py,sha256=
|
|
24
|
-
graphiti_core/search/search_utils.py,sha256=
|
|
23
|
+
graphiti_core/search/search.py,sha256=kL3bTnDUwi2-yCWA9RX9JZrbEnk3FVB1RfcEw5naWtY,4414
|
|
24
|
+
graphiti_core/search/search_utils.py,sha256=F1zA_kN3CSwkgKRUohEN0E5H7TWuC6bo879NwprKGpY,15170
|
|
25
25
|
graphiti_core/utils/__init__.py,sha256=cJAcMnBZdHBQmWrZdU1PQ1YmaL75bhVUkyVpIPuOyns,260
|
|
26
|
-
graphiti_core/utils/bulk_utils.py,sha256=
|
|
26
|
+
graphiti_core/utils/bulk_utils.py,sha256=rArgax8-OpC7MEay0BUzHXZIZKyl3luUiUm3gtrB6kc,11671
|
|
27
27
|
graphiti_core/utils/maintenance/__init__.py,sha256=4b9sfxqyFZMLwxxS2lnQ6_wBr3xrJRIqfAWOidK8EK0,388
|
|
28
|
-
graphiti_core/utils/maintenance/edge_operations.py,sha256=
|
|
28
|
+
graphiti_core/utils/maintenance/edge_operations.py,sha256=Z9t9Rwnpjcc2obcOG6kAxeqrfQCNak54hT8do2RrITs,7201
|
|
29
29
|
graphiti_core/utils/maintenance/graph_data_operations.py,sha256=ggzCWezFyLC29VZBiYHvanOpSRLaPtcmbgHgcl-qHy8,5321
|
|
30
|
-
graphiti_core/utils/maintenance/node_operations.py,sha256=
|
|
31
|
-
graphiti_core/utils/maintenance/temporal_operations.py,sha256=
|
|
30
|
+
graphiti_core/utils/maintenance/node_operations.py,sha256=K2O_8Ey2ugBW9DkEUjy4p53qeJ5mbPAEGX7XzN9HF54,8016
|
|
31
|
+
graphiti_core/utils/maintenance/temporal_operations.py,sha256=XIo3xSYQ_4LFiRDBJ-V03l2-rYeIcq6Id0O1o53yWWY,6865
|
|
32
32
|
graphiti_core/utils/maintenance/utils.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
33
|
-
graphiti_core/utils/utils.py,sha256=
|
|
34
|
-
graphiti_core-0.
|
|
35
|
-
graphiti_core-0.
|
|
36
|
-
graphiti_core-0.
|
|
37
|
-
graphiti_core-0.
|
|
33
|
+
graphiti_core/utils/utils.py,sha256=LguHvEDi9JruXKWXXHaz2f4vpezdfgY-rpxjPq0dao8,1959
|
|
34
|
+
graphiti_core-0.2.0.dist-info/LICENSE,sha256=KCUwCyDXuVEgmDWkozHyniRyWjnWUWjkuDHfU6o3JlA,11325
|
|
35
|
+
graphiti_core-0.2.0.dist-info/METADATA,sha256=ce4A0ZTcN36eNCvy0G8BbTy1l5Epr3WqEbIrgaNtOuQ,9040
|
|
36
|
+
graphiti_core-0.2.0.dist-info/WHEEL,sha256=sP946D7jFCHeNz5Iq4fL4Lu-PrWrFsgfLXbbkciIZwg,88
|
|
37
|
+
graphiti_core-0.2.0.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|