graphiti-core 0.13.1__py3-none-any.whl → 0.14.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 +72 -3
- graphiti_core/helpers.py +35 -0
- graphiti_core/nodes.py +2 -0
- graphiti_core/prompts/dedupe_edges.py +2 -0
- graphiti_core/search/search_utils.py +1 -1
- graphiti_core/telemetry/__init__.py +9 -0
- graphiti_core/telemetry/telemetry.py +117 -0
- graphiti_core/utils/bulk_utils.py +5 -2
- graphiti_core/utils/maintenance/node_operations.py +6 -0
- {graphiti_core-0.13.1.dist-info → graphiti_core-0.14.0.dist-info}/METADATA +125 -33
- {graphiti_core-0.13.1.dist-info → graphiti_core-0.14.0.dist-info}/RECORD +18 -16
- {graphiti_core-0.13.1.dist-info → graphiti_core-0.14.0.dist-info}/WHEEL +1 -1
- {graphiti_core-0.13.1.dist-info → graphiti_core-0.14.0.dist-info/licenses}/LICENSE +0 -0
graphiti_core/graphiti.py
CHANGED
|
@@ -29,7 +29,12 @@ from graphiti_core.driver.neo4j_driver import Neo4jDriver
|
|
|
29
29
|
from graphiti_core.edges import EntityEdge, EpisodicEdge
|
|
30
30
|
from graphiti_core.embedder import EmbedderClient, OpenAIEmbedder
|
|
31
31
|
from graphiti_core.graphiti_types import GraphitiClients
|
|
32
|
-
from graphiti_core.helpers import
|
|
32
|
+
from graphiti_core.helpers import (
|
|
33
|
+
DEFAULT_DATABASE,
|
|
34
|
+
semaphore_gather,
|
|
35
|
+
validate_excluded_entity_types,
|
|
36
|
+
validate_group_id,
|
|
37
|
+
)
|
|
33
38
|
from graphiti_core.llm_client import LLMClient, OpenAIClient
|
|
34
39
|
from graphiti_core.nodes import CommunityNode, EntityNode, EpisodeType, EpisodicNode
|
|
35
40
|
from graphiti_core.search.search import SearchConfig, search
|
|
@@ -46,6 +51,7 @@ from graphiti_core.search.search_utils import (
|
|
|
46
51
|
get_mentioned_nodes,
|
|
47
52
|
get_relevant_edges,
|
|
48
53
|
)
|
|
54
|
+
from graphiti_core.telemetry import capture_event
|
|
49
55
|
from graphiti_core.utils.bulk_utils import (
|
|
50
56
|
RawEpisode,
|
|
51
57
|
add_nodes_and_edges_bulk,
|
|
@@ -181,6 +187,61 @@ class Graphiti:
|
|
|
181
187
|
cross_encoder=self.cross_encoder,
|
|
182
188
|
)
|
|
183
189
|
|
|
190
|
+
# Capture telemetry event
|
|
191
|
+
self._capture_initialization_telemetry()
|
|
192
|
+
|
|
193
|
+
def _capture_initialization_telemetry(self):
|
|
194
|
+
"""Capture telemetry event for Graphiti initialization."""
|
|
195
|
+
try:
|
|
196
|
+
# Detect provider types from class names
|
|
197
|
+
llm_provider = self._get_provider_type(self.llm_client)
|
|
198
|
+
embedder_provider = self._get_provider_type(self.embedder)
|
|
199
|
+
reranker_provider = self._get_provider_type(self.cross_encoder)
|
|
200
|
+
database_provider = self._get_provider_type(self.driver)
|
|
201
|
+
|
|
202
|
+
properties = {
|
|
203
|
+
'llm_provider': llm_provider,
|
|
204
|
+
'embedder_provider': embedder_provider,
|
|
205
|
+
'reranker_provider': reranker_provider,
|
|
206
|
+
'database_provider': database_provider,
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
capture_event('graphiti_initialized', properties)
|
|
210
|
+
except Exception:
|
|
211
|
+
# Silently handle telemetry errors
|
|
212
|
+
pass
|
|
213
|
+
|
|
214
|
+
def _get_provider_type(self, client) -> str:
|
|
215
|
+
"""Get provider type from client class name."""
|
|
216
|
+
if client is None:
|
|
217
|
+
return 'none'
|
|
218
|
+
|
|
219
|
+
class_name = client.__class__.__name__.lower()
|
|
220
|
+
|
|
221
|
+
# LLM providers
|
|
222
|
+
if 'openai' in class_name:
|
|
223
|
+
return 'openai'
|
|
224
|
+
elif 'azure' in class_name:
|
|
225
|
+
return 'azure'
|
|
226
|
+
elif 'anthropic' in class_name:
|
|
227
|
+
return 'anthropic'
|
|
228
|
+
elif 'crossencoder' in class_name:
|
|
229
|
+
return 'crossencoder'
|
|
230
|
+
elif 'gemini' in class_name:
|
|
231
|
+
return 'gemini'
|
|
232
|
+
elif 'groq' in class_name:
|
|
233
|
+
return 'groq'
|
|
234
|
+
# Database providers
|
|
235
|
+
elif 'neo4j' in class_name:
|
|
236
|
+
return 'neo4j'
|
|
237
|
+
elif 'falkor' in class_name:
|
|
238
|
+
return 'falkordb'
|
|
239
|
+
# Embedder providers
|
|
240
|
+
elif 'voyage' in class_name:
|
|
241
|
+
return 'voyage'
|
|
242
|
+
else:
|
|
243
|
+
return 'unknown'
|
|
244
|
+
|
|
184
245
|
async def close(self):
|
|
185
246
|
"""
|
|
186
247
|
Close the connection to the Neo4j database.
|
|
@@ -293,6 +354,7 @@ class Graphiti:
|
|
|
293
354
|
uuid: str | None = None,
|
|
294
355
|
update_communities: bool = False,
|
|
295
356
|
entity_types: dict[str, BaseModel] | None = None,
|
|
357
|
+
excluded_entity_types: list[str] | None = None,
|
|
296
358
|
previous_episode_uuids: list[str] | None = None,
|
|
297
359
|
edge_types: dict[str, BaseModel] | None = None,
|
|
298
360
|
edge_type_map: dict[tuple[str, str], list[str]] | None = None,
|
|
@@ -321,6 +383,12 @@ class Graphiti:
|
|
|
321
383
|
Optional uuid of the episode.
|
|
322
384
|
update_communities : bool
|
|
323
385
|
Optional. Whether to update communities with new node information
|
|
386
|
+
entity_types : dict[str, BaseModel] | None
|
|
387
|
+
Optional. Dictionary mapping entity type names to their Pydantic model definitions.
|
|
388
|
+
excluded_entity_types : list[str] | None
|
|
389
|
+
Optional. List of entity type names to exclude from the graph. Entities classified
|
|
390
|
+
into these types will not be added to the graph. Can include 'Entity' to exclude
|
|
391
|
+
the default entity type.
|
|
324
392
|
previous_episode_uuids : list[str] | None
|
|
325
393
|
Optional. list of episode uuids to use as the previous episodes. If this is not provided,
|
|
326
394
|
the most recent episodes by created_at date will be used.
|
|
@@ -351,6 +419,7 @@ class Graphiti:
|
|
|
351
419
|
now = utc_now()
|
|
352
420
|
|
|
353
421
|
validate_entity_types(entity_types)
|
|
422
|
+
validate_excluded_entity_types(excluded_entity_types, entity_types)
|
|
354
423
|
validate_group_id(group_id)
|
|
355
424
|
|
|
356
425
|
previous_episodes = (
|
|
@@ -389,7 +458,7 @@ class Graphiti:
|
|
|
389
458
|
# Extract entities as nodes
|
|
390
459
|
|
|
391
460
|
extracted_nodes = await extract_nodes(
|
|
392
|
-
self.clients, episode, previous_episodes, entity_types
|
|
461
|
+
self.clients, episode, previous_episodes, entity_types, excluded_entity_types
|
|
393
462
|
)
|
|
394
463
|
|
|
395
464
|
# Extract edges and resolve nodes
|
|
@@ -534,7 +603,7 @@ class Graphiti:
|
|
|
534
603
|
extracted_nodes,
|
|
535
604
|
extracted_edges,
|
|
536
605
|
episodic_edges,
|
|
537
|
-
) = await extract_nodes_and_edges_bulk(self.clients, episode_pairs)
|
|
606
|
+
) = await extract_nodes_and_edges_bulk(self.clients, episode_pairs, None, None)
|
|
538
607
|
|
|
539
608
|
# Generate embeddings
|
|
540
609
|
await semaphore_gather(
|
graphiti_core/helpers.py
CHANGED
|
@@ -24,6 +24,7 @@ import numpy as np
|
|
|
24
24
|
from dotenv import load_dotenv
|
|
25
25
|
from neo4j import time as neo4j_time
|
|
26
26
|
from numpy._typing import NDArray
|
|
27
|
+
from pydantic import BaseModel
|
|
27
28
|
from typing_extensions import LiteralString
|
|
28
29
|
|
|
29
30
|
from graphiti_core.errors import GroupIdValidationError
|
|
@@ -132,3 +133,37 @@ def validate_group_id(group_id: str) -> bool:
|
|
|
132
133
|
raise GroupIdValidationError(group_id)
|
|
133
134
|
|
|
134
135
|
return True
|
|
136
|
+
|
|
137
|
+
|
|
138
|
+
def validate_excluded_entity_types(
|
|
139
|
+
excluded_entity_types: list[str] | None, entity_types: dict[str, BaseModel] | None = None
|
|
140
|
+
) -> bool:
|
|
141
|
+
"""
|
|
142
|
+
Validate that excluded entity types are valid type names.
|
|
143
|
+
|
|
144
|
+
Args:
|
|
145
|
+
excluded_entity_types: List of entity type names to exclude
|
|
146
|
+
entity_types: Dictionary of available custom entity types
|
|
147
|
+
|
|
148
|
+
Returns:
|
|
149
|
+
True if valid
|
|
150
|
+
|
|
151
|
+
Raises:
|
|
152
|
+
ValueError: If any excluded type names are invalid
|
|
153
|
+
"""
|
|
154
|
+
if not excluded_entity_types:
|
|
155
|
+
return True
|
|
156
|
+
|
|
157
|
+
# Build set of available type names
|
|
158
|
+
available_types = {'Entity'} # Default type is always available
|
|
159
|
+
if entity_types:
|
|
160
|
+
available_types.update(entity_types.keys())
|
|
161
|
+
|
|
162
|
+
# Check for invalid type names
|
|
163
|
+
invalid_types = set(excluded_entity_types) - available_types
|
|
164
|
+
if invalid_types:
|
|
165
|
+
raise ValueError(
|
|
166
|
+
f'Invalid excluded entity types: {sorted(invalid_types)}. Available types: {sorted(available_types)}'
|
|
167
|
+
)
|
|
168
|
+
|
|
169
|
+
return True
|
graphiti_core/nodes.py
CHANGED
|
@@ -586,6 +586,8 @@ def get_community_node_from_record(record: Any) -> CommunityNode:
|
|
|
586
586
|
|
|
587
587
|
|
|
588
588
|
async def create_entity_node_embeddings(embedder: EmbedderClient, nodes: list[EntityNode]):
|
|
589
|
+
if not nodes: # Handle empty list case
|
|
590
|
+
return
|
|
589
591
|
name_embeddings = await embedder.create_batch([node.name for node in nodes])
|
|
590
592
|
for node, name_embedding in zip(nodes, name_embeddings, strict=True):
|
|
591
593
|
node.name_embedding = name_embedding
|
|
@@ -141,6 +141,7 @@ def resolve_edge(context: dict[str, Any]) -> list[Message]:
|
|
|
141
141
|
|
|
142
142
|
Task:
|
|
143
143
|
If the NEW FACT represents the same factual information as any fact in EXISTING FACTS, return the idx of the duplicate fact.
|
|
144
|
+
Facts with similar information that contain key differences should not be marked as duplicates.
|
|
144
145
|
If the NEW FACT is not a duplicate of any of the EXISTING FACTS, return -1.
|
|
145
146
|
|
|
146
147
|
Given the predefined FACT TYPES, determine if the NEW FACT should be classified as one of these types.
|
|
@@ -152,6 +153,7 @@ def resolve_edge(context: dict[str, Any]) -> list[Message]:
|
|
|
152
153
|
|
|
153
154
|
Guidelines:
|
|
154
155
|
1. The facts do not need to be completely identical to be duplicates, they just need to express the same information.
|
|
156
|
+
2. Some facts may be very similar but will have key differences, particularly around numeric values in the facts.
|
|
155
157
|
""",
|
|
156
158
|
),
|
|
157
159
|
]
|
|
@@ -67,7 +67,7 @@ def fulltext_query(query: str, group_ids: list[str] | None = None):
|
|
|
67
67
|
)
|
|
68
68
|
group_ids_filter = ''
|
|
69
69
|
for f in group_ids_filter_list:
|
|
70
|
-
group_ids_filter += f if not group_ids_filter else f'OR {f}'
|
|
70
|
+
group_ids_filter += f if not group_ids_filter else f' OR {f}'
|
|
71
71
|
|
|
72
72
|
group_ids_filter += ' AND ' if group_ids_filter else ''
|
|
73
73
|
|
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Telemetry client for Graphiti.
|
|
3
|
+
|
|
4
|
+
Collects anonymous usage statistics to help improve the product.
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
import contextlib
|
|
8
|
+
import os
|
|
9
|
+
import platform
|
|
10
|
+
import sys
|
|
11
|
+
import uuid
|
|
12
|
+
from pathlib import Path
|
|
13
|
+
from typing import Any
|
|
14
|
+
|
|
15
|
+
# PostHog configuration
|
|
16
|
+
# Note: This is a public API key intended for client-side use and safe to commit
|
|
17
|
+
# PostHog public keys are designed to be exposed in client applications
|
|
18
|
+
POSTHOG_API_KEY = 'phc_UG6EcfDbuXz92neb3rMlQFDY0csxgMqRcIPWESqnSmo'
|
|
19
|
+
POSTHOG_HOST = 'https://us.i.posthog.com'
|
|
20
|
+
|
|
21
|
+
# Environment variable to control telemetry
|
|
22
|
+
TELEMETRY_ENV_VAR = 'GRAPHITI_TELEMETRY_ENABLED'
|
|
23
|
+
|
|
24
|
+
# Cache directory for anonymous ID
|
|
25
|
+
CACHE_DIR = Path.home() / '.cache' / 'graphiti'
|
|
26
|
+
ANON_ID_FILE = CACHE_DIR / 'telemetry_anon_id'
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
def is_telemetry_enabled() -> bool:
|
|
30
|
+
"""Check if telemetry is enabled."""
|
|
31
|
+
# Disable during pytest runs
|
|
32
|
+
if 'pytest' in sys.modules:
|
|
33
|
+
return False
|
|
34
|
+
|
|
35
|
+
# Check environment variable (default: enabled)
|
|
36
|
+
env_value = os.environ.get(TELEMETRY_ENV_VAR, 'true').lower()
|
|
37
|
+
return env_value in ('true', '1', 'yes', 'on')
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
def get_anonymous_id() -> str:
|
|
41
|
+
"""Get or create anonymous user ID."""
|
|
42
|
+
try:
|
|
43
|
+
# Create cache directory if it doesn't exist
|
|
44
|
+
CACHE_DIR.mkdir(parents=True, exist_ok=True)
|
|
45
|
+
|
|
46
|
+
# Try to read existing ID
|
|
47
|
+
if ANON_ID_FILE.exists():
|
|
48
|
+
try:
|
|
49
|
+
return ANON_ID_FILE.read_text().strip()
|
|
50
|
+
except Exception:
|
|
51
|
+
pass
|
|
52
|
+
|
|
53
|
+
# Generate new ID
|
|
54
|
+
anon_id = str(uuid.uuid4())
|
|
55
|
+
|
|
56
|
+
# Save to file
|
|
57
|
+
with contextlib.suppress(Exception):
|
|
58
|
+
ANON_ID_FILE.write_text(anon_id)
|
|
59
|
+
|
|
60
|
+
return anon_id
|
|
61
|
+
except Exception:
|
|
62
|
+
return 'UNKNOWN'
|
|
63
|
+
|
|
64
|
+
|
|
65
|
+
def get_graphiti_version() -> str:
|
|
66
|
+
"""Get Graphiti version."""
|
|
67
|
+
try:
|
|
68
|
+
# Try to get version from package metadata
|
|
69
|
+
import importlib.metadata
|
|
70
|
+
|
|
71
|
+
return importlib.metadata.version('graphiti-core')
|
|
72
|
+
except Exception:
|
|
73
|
+
return 'unknown'
|
|
74
|
+
|
|
75
|
+
|
|
76
|
+
def initialize_posthog():
|
|
77
|
+
"""Initialize PostHog client."""
|
|
78
|
+
try:
|
|
79
|
+
import posthog
|
|
80
|
+
|
|
81
|
+
posthog.api_key = POSTHOG_API_KEY
|
|
82
|
+
posthog.host = POSTHOG_HOST
|
|
83
|
+
return posthog
|
|
84
|
+
except ImportError:
|
|
85
|
+
# PostHog not installed, silently disable telemetry
|
|
86
|
+
return None
|
|
87
|
+
except Exception:
|
|
88
|
+
# Any other error, silently disable telemetry
|
|
89
|
+
return None
|
|
90
|
+
|
|
91
|
+
|
|
92
|
+
def capture_event(event_name: str, properties: dict[str, Any] | None = None) -> None:
|
|
93
|
+
"""Capture a telemetry event."""
|
|
94
|
+
if not is_telemetry_enabled():
|
|
95
|
+
return
|
|
96
|
+
|
|
97
|
+
try:
|
|
98
|
+
posthog_client = initialize_posthog()
|
|
99
|
+
if posthog_client is None:
|
|
100
|
+
return
|
|
101
|
+
|
|
102
|
+
# Get anonymous ID
|
|
103
|
+
user_id = get_anonymous_id()
|
|
104
|
+
|
|
105
|
+
# Prepare event properties
|
|
106
|
+
event_properties = {
|
|
107
|
+
'$process_person_profile': False,
|
|
108
|
+
'graphiti_version': get_graphiti_version(),
|
|
109
|
+
'architecture': platform.machine(),
|
|
110
|
+
**(properties or {}),
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
# Capture the event
|
|
114
|
+
posthog_client.capture(distinct_id=user_id, event=event_name, properties=event_properties)
|
|
115
|
+
except Exception:
|
|
116
|
+
# Silently handle all telemetry errors to avoid disrupting the main application
|
|
117
|
+
pass
|
|
@@ -177,11 +177,14 @@ async def add_nodes_and_edges_bulk_tx(
|
|
|
177
177
|
|
|
178
178
|
|
|
179
179
|
async def extract_nodes_and_edges_bulk(
|
|
180
|
-
clients: GraphitiClients,
|
|
180
|
+
clients: GraphitiClients,
|
|
181
|
+
episode_tuples: list[tuple[EpisodicNode, list[EpisodicNode]]],
|
|
182
|
+
entity_types: dict[str, BaseModel] | None = None,
|
|
183
|
+
excluded_entity_types: list[str] | None = None,
|
|
181
184
|
) -> tuple[list[EntityNode], list[EntityEdge], list[EpisodicEdge]]:
|
|
182
185
|
extracted_nodes_bulk = await semaphore_gather(
|
|
183
186
|
*[
|
|
184
|
-
extract_nodes(clients, episode, previous_episodes)
|
|
187
|
+
extract_nodes(clients, episode, previous_episodes, entity_types, excluded_entity_types)
|
|
185
188
|
for episode, previous_episodes in episode_tuples
|
|
186
189
|
]
|
|
187
190
|
)
|
|
@@ -71,6 +71,7 @@ async def extract_nodes(
|
|
|
71
71
|
episode: EpisodicNode,
|
|
72
72
|
previous_episodes: list[EpisodicNode],
|
|
73
73
|
entity_types: dict[str, BaseModel] | None = None,
|
|
74
|
+
excluded_entity_types: list[str] | None = None,
|
|
74
75
|
) -> list[EntityNode]:
|
|
75
76
|
start = time()
|
|
76
77
|
llm_client = clients.llm_client
|
|
@@ -154,6 +155,11 @@ async def extract_nodes(
|
|
|
154
155
|
'entity_type_name'
|
|
155
156
|
)
|
|
156
157
|
|
|
158
|
+
# Check if this entity type should be excluded
|
|
159
|
+
if excluded_entity_types and entity_type_name in excluded_entity_types:
|
|
160
|
+
logger.debug(f'Excluding entity "{extracted_entity.name}" of type "{entity_type_name}"')
|
|
161
|
+
continue
|
|
162
|
+
|
|
157
163
|
labels: list[str] = list({'Entity', str(entity_type_name)})
|
|
158
164
|
|
|
159
165
|
new_node = EntityNode(
|
|
@@ -1,34 +1,48 @@
|
|
|
1
|
-
Metadata-Version: 2.
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
2
|
Name: graphiti-core
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.14.0
|
|
4
4
|
Summary: A temporal graph building library
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
Author-email: paul@getzep.com
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
5
|
+
Project-URL: Homepage, https://help.getzep.com/graphiti/graphiti/overview
|
|
6
|
+
Project-URL: Repository, https://github.com/getzep/graphiti
|
|
7
|
+
Author-email: Paul Paliychuk <paul@getzep.com>, Preston Rasmussen <preston@getzep.com>, Daniel Chalef <daniel@getzep.com>
|
|
8
|
+
License-Expression: Apache-2.0
|
|
9
|
+
License-File: LICENSE
|
|
10
|
+
Requires-Python: <4,>=3.10
|
|
11
|
+
Requires-Dist: diskcache>=5.6.3
|
|
12
|
+
Requires-Dist: neo4j>=5.26.0
|
|
13
|
+
Requires-Dist: numpy>=1.0.0
|
|
14
|
+
Requires-Dist: openai>=1.91.0
|
|
15
|
+
Requires-Dist: posthog>=3.0.0
|
|
16
|
+
Requires-Dist: pydantic>=2.11.5
|
|
17
|
+
Requires-Dist: python-dotenv>=1.0.1
|
|
18
|
+
Requires-Dist: tenacity>=9.0.0
|
|
15
19
|
Provides-Extra: anthropic
|
|
20
|
+
Requires-Dist: anthropic>=0.49.0; extra == 'anthropic'
|
|
21
|
+
Provides-Extra: dev
|
|
22
|
+
Requires-Dist: anthropic>=0.49.0; extra == 'dev'
|
|
23
|
+
Requires-Dist: diskcache-stubs>=5.6.3.6.20240818; extra == 'dev'
|
|
24
|
+
Requires-Dist: google-genai>=1.8.0; extra == 'dev'
|
|
25
|
+
Requires-Dist: groq>=0.2.0; extra == 'dev'
|
|
26
|
+
Requires-Dist: ipykernel>=6.29.5; extra == 'dev'
|
|
27
|
+
Requires-Dist: jupyterlab>=4.2.4; extra == 'dev'
|
|
28
|
+
Requires-Dist: langchain-anthropic>=0.2.4; extra == 'dev'
|
|
29
|
+
Requires-Dist: langchain-openai>=0.2.6; extra == 'dev'
|
|
30
|
+
Requires-Dist: langgraph>=0.2.15; extra == 'dev'
|
|
31
|
+
Requires-Dist: langsmith>=0.1.108; extra == 'dev'
|
|
32
|
+
Requires-Dist: mypy>=1.11.1; extra == 'dev'
|
|
33
|
+
Requires-Dist: pytest-asyncio>=0.24.0; extra == 'dev'
|
|
34
|
+
Requires-Dist: pytest-xdist>=3.6.1; extra == 'dev'
|
|
35
|
+
Requires-Dist: pytest>=8.3.3; extra == 'dev'
|
|
36
|
+
Requires-Dist: ruff>=0.7.1; extra == 'dev'
|
|
37
|
+
Requires-Dist: sentence-transformers>=3.2.1; extra == 'dev'
|
|
38
|
+
Requires-Dist: transformers>=4.45.2; extra == 'dev'
|
|
39
|
+
Requires-Dist: voyageai>=0.2.3; extra == 'dev'
|
|
16
40
|
Provides-Extra: falkord-db
|
|
41
|
+
Requires-Dist: falkordb<2.0.0,>=1.1.2; extra == 'falkord-db'
|
|
17
42
|
Provides-Extra: google-genai
|
|
43
|
+
Requires-Dist: google-genai>=1.8.0; extra == 'google-genai'
|
|
18
44
|
Provides-Extra: groq
|
|
19
|
-
Requires-Dist:
|
|
20
|
-
Requires-Dist: diskcache (>=5.6.3)
|
|
21
|
-
Requires-Dist: falkordb (>=1.1.2,<2.0.0) ; extra == "falkord-db"
|
|
22
|
-
Requires-Dist: google-genai (>=1.8.0) ; extra == "google-genai"
|
|
23
|
-
Requires-Dist: groq (>=0.2.0) ; extra == "groq"
|
|
24
|
-
Requires-Dist: neo4j (>=5.26.0)
|
|
25
|
-
Requires-Dist: numpy (>=1.0.0)
|
|
26
|
-
Requires-Dist: openai (>=1.91.0)
|
|
27
|
-
Requires-Dist: pydantic (>=2.11.5)
|
|
28
|
-
Requires-Dist: python-dotenv (>=1.0.1)
|
|
29
|
-
Requires-Dist: tenacity (>=9.0.0)
|
|
30
|
-
Project-URL: Homepage, https://help.getzep.com/graphiti/graphiti/overview
|
|
31
|
-
Project-URL: Repository, https://github.com/getzep/graphiti
|
|
45
|
+
Requires-Dist: groq>=0.2.0; extra == 'groq'
|
|
32
46
|
Description-Content-Type: text/markdown
|
|
33
47
|
|
|
34
48
|
<p align="center">
|
|
@@ -161,7 +175,7 @@ pip install graphiti-core
|
|
|
161
175
|
or
|
|
162
176
|
|
|
163
177
|
```bash
|
|
164
|
-
|
|
178
|
+
uv add graphiti-core
|
|
165
179
|
```
|
|
166
180
|
|
|
167
181
|
You can also install optional LLM providers as extras:
|
|
@@ -294,11 +308,11 @@ Graphiti supports Google's Gemini models for both LLM inference and embeddings.
|
|
|
294
308
|
Install Graphiti:
|
|
295
309
|
|
|
296
310
|
```bash
|
|
297
|
-
|
|
311
|
+
uv add "graphiti-core[google-genai]"
|
|
298
312
|
|
|
299
313
|
# or
|
|
300
314
|
|
|
301
|
-
|
|
315
|
+
pip install "graphiti-core[google-genai]"
|
|
302
316
|
```
|
|
303
317
|
|
|
304
318
|
```python
|
|
@@ -335,10 +349,9 @@ graphiti = Graphiti(
|
|
|
335
349
|
|
|
336
350
|
Graphiti supports Ollama for running local LLMs and embedding models via Ollama's OpenAI-compatible API. This is ideal for privacy-focused applications or when you want to avoid API costs.
|
|
337
351
|
|
|
338
|
-
|
|
339
352
|
Install the models:
|
|
340
|
-
ollama pull deepseek-r1:7b
|
|
341
|
-
ollama pull nomic-embed-text
|
|
353
|
+
ollama pull deepseek-r1:7b # LLM
|
|
354
|
+
ollama pull nomic-embed-text # embeddings
|
|
342
355
|
|
|
343
356
|
```python
|
|
344
357
|
from graphiti_core import Graphiti
|
|
@@ -379,13 +392,93 @@ graphiti = Graphiti(
|
|
|
379
392
|
|
|
380
393
|
Ensure Ollama is running (`ollama serve`) and that you have pulled the models you want to use.
|
|
381
394
|
|
|
382
|
-
|
|
383
395
|
## Documentation
|
|
384
396
|
|
|
385
397
|
- [Guides and API documentation](https://help.getzep.com/graphiti).
|
|
386
398
|
- [Quick Start](https://help.getzep.com/graphiti/graphiti/quick-start)
|
|
387
399
|
- [Building an agent with LangChain's LangGraph and Graphiti](https://help.getzep.com/graphiti/graphiti/lang-graph-agent)
|
|
388
400
|
|
|
401
|
+
## Telemetry
|
|
402
|
+
|
|
403
|
+
Graphiti collects anonymous usage statistics to help us understand how the framework is being used and improve it for everyone. We believe transparency is important, so here's exactly what we collect and why.
|
|
404
|
+
|
|
405
|
+
### What We Collect
|
|
406
|
+
|
|
407
|
+
When you initialize a Graphiti instance, we collect:
|
|
408
|
+
|
|
409
|
+
- **Anonymous identifier**: A randomly generated UUID stored locally in `~/.cache/graphiti/telemetry_anon_id`
|
|
410
|
+
- **System information**: Operating system, Python version, and system architecture
|
|
411
|
+
- **Graphiti version**: The version you're using
|
|
412
|
+
- **Configuration choices**:
|
|
413
|
+
- LLM provider type (OpenAI, Azure, Anthropic, etc.)
|
|
414
|
+
- Database backend (Neo4j, FalkorDB)
|
|
415
|
+
- Embedder provider (OpenAI, Azure, Voyage, etc.)
|
|
416
|
+
|
|
417
|
+
### What We Don't Collect
|
|
418
|
+
|
|
419
|
+
We are committed to protecting your privacy. We **never** collect:
|
|
420
|
+
|
|
421
|
+
- Personal information or identifiers
|
|
422
|
+
- API keys or credentials
|
|
423
|
+
- Your actual data, queries, or graph content
|
|
424
|
+
- IP addresses or hostnames
|
|
425
|
+
- File paths or system-specific information
|
|
426
|
+
- Any content from your episodes, nodes, or edges
|
|
427
|
+
|
|
428
|
+
### Why We Collect This Data
|
|
429
|
+
|
|
430
|
+
This information helps us:
|
|
431
|
+
|
|
432
|
+
- Understand which configurations are most popular to prioritize support and testing
|
|
433
|
+
- Identify which LLM and database providers to focus development efforts on
|
|
434
|
+
- Track adoption patterns to guide our roadmap
|
|
435
|
+
- Ensure compatibility across different Python versions and operating systems
|
|
436
|
+
|
|
437
|
+
By sharing this anonymous information, you help us make Graphiti better for everyone in the community.
|
|
438
|
+
|
|
439
|
+
### View the Telemetry Code
|
|
440
|
+
|
|
441
|
+
The Telemetry code [may be found here](graphiti_core/telemetry/telemetry.py).
|
|
442
|
+
|
|
443
|
+
### How to Disable Telemetry
|
|
444
|
+
|
|
445
|
+
Telemetry is **opt-out** and can be disabled at any time. To disable telemetry collection:
|
|
446
|
+
|
|
447
|
+
**Option 1: Environment Variable**
|
|
448
|
+
|
|
449
|
+
```bash
|
|
450
|
+
export GRAPHITI_TELEMETRY_ENABLED=false
|
|
451
|
+
```
|
|
452
|
+
|
|
453
|
+
**Option 2: Set in your shell profile**
|
|
454
|
+
|
|
455
|
+
```bash
|
|
456
|
+
# For bash users (~/.bashrc or ~/.bash_profile)
|
|
457
|
+
echo 'export GRAPHITI_TELEMETRY_ENABLED=false' >> ~/.bashrc
|
|
458
|
+
|
|
459
|
+
# For zsh users (~/.zshrc)
|
|
460
|
+
echo 'export GRAPHITI_TELEMETRY_ENABLED=false' >> ~/.zshrc
|
|
461
|
+
```
|
|
462
|
+
|
|
463
|
+
**Option 3: Set for a specific Python session**
|
|
464
|
+
|
|
465
|
+
```python
|
|
466
|
+
import os
|
|
467
|
+
os.environ['GRAPHITI_TELEMETRY_ENABLED'] = 'false'
|
|
468
|
+
|
|
469
|
+
# Then initialize Graphiti as usual
|
|
470
|
+
from graphiti_core import Graphiti
|
|
471
|
+
graphiti = Graphiti(...)
|
|
472
|
+
```
|
|
473
|
+
|
|
474
|
+
Telemetry is automatically disabled during test runs (when `pytest` is detected).
|
|
475
|
+
|
|
476
|
+
### Technical Details
|
|
477
|
+
|
|
478
|
+
- Telemetry uses PostHog for anonymous analytics collection
|
|
479
|
+
- All telemetry operations are designed to fail silently - they will never interrupt your application or affect Graphiti functionality
|
|
480
|
+
- The anonymous ID is stored locally and is not tied to any personal information
|
|
481
|
+
|
|
389
482
|
## Status and Roadmap
|
|
390
483
|
|
|
391
484
|
Graphiti is under active development. We aim to maintain API stability while working on:
|
|
@@ -406,4 +499,3 @@ to [CONTRIBUTING](CONTRIBUTING.md).
|
|
|
406
499
|
## Support
|
|
407
500
|
|
|
408
501
|
Join the [Zep Discord server](https://discord.com/invite/W8Kw6bsgXQ) and make your way to the **#Graphiti** channel!
|
|
409
|
-
|
|
@@ -1,4 +1,12 @@
|
|
|
1
1
|
graphiti_core/__init__.py,sha256=e5SWFkRiaUwfprYIeIgVIh7JDedNiloZvd3roU-0aDY,55
|
|
2
|
+
graphiti_core/edges.py,sha256=h67vyXYhZYqlwaOmaqjHiGns6nEjuBVSIAFBMveNVo8,16257
|
|
3
|
+
graphiti_core/errors.py,sha256=cH_v9TPgEPeQE6GFOHIg5TvejpUCBddGarMY2Whxbwc,2707
|
|
4
|
+
graphiti_core/graph_queries.py,sha256=KfWDp8xDnPa9bcHskw8NeMpeeHBtZWBCosVdu1Iwv34,7076
|
|
5
|
+
graphiti_core/graphiti.py,sha256=FzSTwU5zK6aFOETXLzdEvGn8yuf5cEjrBfnwabYY-xw,32990
|
|
6
|
+
graphiti_core/graphiti_types.py,sha256=rL-9bvnLobunJfXU4hkD6mAj14pofKp_wq8QsFDZwDU,1035
|
|
7
|
+
graphiti_core/helpers.py,sha256=xHSlDlu5cCLOw40EeJSzshUqdsbqsNqv9AGGIiI-7qI,4907
|
|
8
|
+
graphiti_core/nodes.py,sha256=WG7czM-neIeUDjLc5JCS1k0xRDANMY1lT9rDBc7Ms8U,18724
|
|
9
|
+
graphiti_core/py.typed,sha256=vlmmzQOt7bmeQl9L3XJP4W6Ry0iiELepnOrinKz5KQg,79
|
|
2
10
|
graphiti_core/cross_encoder/__init__.py,sha256=hry59vz21x-AtGZ0MJ7ugw0HTwJkXiddpp_Yqnwsen0,723
|
|
3
11
|
graphiti_core/cross_encoder/bge_reranker_client.py,sha256=sY7RKsCp90vTjYxv6vmIHT4p3oCsFCRYWH-H0Ia0vN0,1449
|
|
4
12
|
graphiti_core/cross_encoder/client.py,sha256=KLsbfWKOEaAV3adFe3XZlAeb-gje9_sVKCVZTaJP3ac,1441
|
|
@@ -7,18 +15,12 @@ graphiti_core/driver/__init__.py,sha256=DumfxIEY3z_nkz5YGaYH1GM50HgeAdEowNK189jc
|
|
|
7
15
|
graphiti_core/driver/driver.py,sha256=-FHAA2gM8FA0re-q6udmjQ6pNFdFGRQrMRuAiqX_1A4,1829
|
|
8
16
|
graphiti_core/driver/falkordb_driver.py,sha256=Iz3wnfoJIO7EslqZvG6mduyZ5C-DWxFDPM5Q4QJRCuo,4686
|
|
9
17
|
graphiti_core/driver/neo4j_driver.py,sha256=D8CV5GbhKoHIQ78BA9ozlwdvXPLUbBmFSfT2lww8PJk,1910
|
|
10
|
-
graphiti_core/edges.py,sha256=h67vyXYhZYqlwaOmaqjHiGns6nEjuBVSIAFBMveNVo8,16257
|
|
11
18
|
graphiti_core/embedder/__init__.py,sha256=EL564ZuE-DZjcuKNUK_exMn_XHXm2LdO9fzdXePVKL4,179
|
|
12
19
|
graphiti_core/embedder/azure_openai.py,sha256=OyomPwC1fIsddI-3n6g00kQFdQznZorBhHwkQKCLUok,2384
|
|
13
20
|
graphiti_core/embedder/client.py,sha256=qEpSHceL_Gc4QQPJWIOnuNLemNuR_TYA4r28t2Vldbg,1115
|
|
14
21
|
graphiti_core/embedder/gemini.py,sha256=7En-W46YxqC5qL3vYB5Ed-Xm0hqLxi7-LgZ95c4M7ME,3263
|
|
15
22
|
graphiti_core/embedder/openai.py,sha256=bIThUoLMeGlHG2-3VikzK6JZfOHKn4PKvUMx5sHxJy8,2192
|
|
16
23
|
graphiti_core/embedder/voyage.py,sha256=gQhdcz2IYPSyOcDn3w8aHToVS3KQhyZrUBm4vqr3WcE,2224
|
|
17
|
-
graphiti_core/errors.py,sha256=cH_v9TPgEPeQE6GFOHIg5TvejpUCBddGarMY2Whxbwc,2707
|
|
18
|
-
graphiti_core/graph_queries.py,sha256=KfWDp8xDnPa9bcHskw8NeMpeeHBtZWBCosVdu1Iwv34,7076
|
|
19
|
-
graphiti_core/graphiti.py,sha256=6TcOq65HEtJ5gQ29YHJ6HVhBkjsoWtv_mVhlcZok2MY,30399
|
|
20
|
-
graphiti_core/graphiti_types.py,sha256=rL-9bvnLobunJfXU4hkD6mAj14pofKp_wq8QsFDZwDU,1035
|
|
21
|
-
graphiti_core/helpers.py,sha256=0qmGnKxxYk27JGQbx6PlM7E6nRghUrEKBym0d3WSJY4,3875
|
|
22
24
|
graphiti_core/llm_client/__init__.py,sha256=QgBWUiCeBp6YiA_xqyrDvJ9jIyy1hngH8g7FWahN3nw,776
|
|
23
25
|
graphiti_core/llm_client/anthropic_client.py,sha256=392rtkH_I7yOJUlQvjoOnS8Lz14WBP8egQ3OfRH0nFs,12481
|
|
24
26
|
graphiti_core/llm_client/azure_openai_client.py,sha256=ekERggAekbb7enes1RJqdRChf_mjaZTFXsnMbxO7azQ,2497
|
|
@@ -36,9 +38,8 @@ graphiti_core/models/edges/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJ
|
|
|
36
38
|
graphiti_core/models/edges/edge_db_queries.py,sha256=4vSWdmE5MKoDrlHJmmr2xNhVSQ-buE1O7mCX_H0Wtfk,2294
|
|
37
39
|
graphiti_core/models/nodes/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
38
40
|
graphiti_core/models/nodes/node_db_queries.py,sha256=AQgRGVO-GgFWfLq1G6k8s86WItwpXruy3Mj4DBli-vM,2145
|
|
39
|
-
graphiti_core/nodes.py,sha256=kdJY-Ugyk6J2x70w4EF_EoFNgy7D3TMOMVSUfEth6rE,18665
|
|
40
41
|
graphiti_core/prompts/__init__.py,sha256=EA-x9xUki9l8wnu2l8ek_oNf75-do5tq5hVq7Zbv8Kw,101
|
|
41
|
-
graphiti_core/prompts/dedupe_edges.py,sha256
|
|
42
|
+
graphiti_core/prompts/dedupe_edges.py,sha256=-Fq8YlCPHOEnjJceSOy68dya3VIbmvMtcS8V9u9Tv6g,5699
|
|
42
43
|
graphiti_core/prompts/dedupe_nodes.py,sha256=WdSnqu6O4TkEE_z1u2CEnNH0sWgBNDl4dUx20gSp464,7852
|
|
43
44
|
graphiti_core/prompts/eval.py,sha256=gnBQTmwsCl3Qvwpcm7aieVszzo6y1sMCUT8jQiKTvvE,5317
|
|
44
45
|
graphiti_core/prompts/extract_edge_dates.py,sha256=3Drs3CmvP0gJN5BidWSxrNvLet3HPoTybU3BUIAoc0Y,4218
|
|
@@ -49,26 +50,27 @@ graphiti_core/prompts/lib.py,sha256=DCyHePM4_q-CptTpEXGO_dBv9k7xDtclEaB1dGu7EcI,
|
|
|
49
50
|
graphiti_core/prompts/models.py,sha256=NgxdbPHJpBEcpbXovKyScgpBc73Q-GIW-CBDlBtDjto,894
|
|
50
51
|
graphiti_core/prompts/prompt_helpers.py,sha256=-9TABwIcIQUVHcNANx6wIZd-FT2DgYKyGTfx4IGYq2I,64
|
|
51
52
|
graphiti_core/prompts/summarize_nodes.py,sha256=tbg-AgWlzgFBeImKkZ28h2SpmqfPPqvN2Ol1Q71VF9Y,4146
|
|
52
|
-
graphiti_core/py.typed,sha256=vlmmzQOt7bmeQl9L3XJP4W6Ry0iiELepnOrinKz5KQg,79
|
|
53
53
|
graphiti_core/search/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
54
54
|
graphiti_core/search/search.py,sha256=bJCFaNApu5396pXTa-xciu8ORDdRFJqfE3j2ieRVd7Y,15162
|
|
55
55
|
graphiti_core/search/search_config.py,sha256=VvKg6AB_RPhoe56DBBXHRBXHThAVJ_OLFCyq_yKof-A,3765
|
|
56
56
|
graphiti_core/search/search_config_recipes.py,sha256=4GquRphHhJlpXQhAZOySYnCzBWYoTwxlJj44eTOavZQ,7443
|
|
57
57
|
graphiti_core/search/search_filters.py,sha256=jG30nMWX03xoT9ohgyHNu_Xes8GwjIF2eTv6QaiWMqw,6466
|
|
58
58
|
graphiti_core/search/search_helpers.py,sha256=G5Ceaq5Pfgx0Weelqgeylp_pUHwiBnINaUYsDbURJbE,2636
|
|
59
|
-
graphiti_core/search/search_utils.py,sha256=
|
|
59
|
+
graphiti_core/search/search_utils.py,sha256=74d3RDbx9MWkDei1U5g0K5l1EenzB1NPNYdSP9l8aEg,34958
|
|
60
|
+
graphiti_core/telemetry/__init__.py,sha256=5kALLDlU9bb2v19CdN7qVANsJWyfnL9E60J6FFgzm3o,226
|
|
61
|
+
graphiti_core/telemetry/telemetry.py,sha256=47LrzOVBCcZxsYPsnSxWFiztHoxYKKxPwyRX0hnbDGc,3230
|
|
60
62
|
graphiti_core/utils/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
61
|
-
graphiti_core/utils/bulk_utils.py,sha256=
|
|
63
|
+
graphiti_core/utils/bulk_utils.py,sha256=YnyXzmOFgqbLdIAIu9Y6aJjUZHhXj8nBnlegkXBTKi8,16344
|
|
62
64
|
graphiti_core/utils/datetime_utils.py,sha256=Ti-2tnrDFRzBsbfblzsHybsM3jaDLP4-VT2t0VhpIzU,1357
|
|
63
65
|
graphiti_core/utils/maintenance/__init__.py,sha256=vW4H1KyapTl-OOz578uZABYcpND4wPx3Vt6aAPaXh78,301
|
|
64
66
|
graphiti_core/utils/maintenance/community_operations.py,sha256=2rhRqtL9gDbjXKO4-S0nGpaWvS4ck5rFiazZiogIJao,10088
|
|
65
67
|
graphiti_core/utils/maintenance/edge_operations.py,sha256=Fwu2TLmQF_9EVcA-uUlt1ZiGC6RILIfKDr9W7R4gAno,21633
|
|
66
68
|
graphiti_core/utils/maintenance/graph_data_operations.py,sha256=OHuiAyP1Z7dfR90dWVQ87TJQO83P0sQihJyr4WIhOhk,5362
|
|
67
|
-
graphiti_core/utils/maintenance/node_operations.py,sha256
|
|
69
|
+
graphiti_core/utils/maintenance/node_operations.py,sha256=0WdH_VrkVXLV9YX3xPErXOFygOo2N9g3es9yIB2Yl8Q,15876
|
|
68
70
|
graphiti_core/utils/maintenance/temporal_operations.py,sha256=mJkw9xLB4W2BsLfC5POr0r-PHWL9SIfNj_l_xu0B5ug,3410
|
|
69
71
|
graphiti_core/utils/maintenance/utils.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
70
72
|
graphiti_core/utils/ontology_utils/entity_types_utils.py,sha256=QJX5cG0GSSNF_Mm_yrldr69wjVAbN_MxLhOSznz85Hk,1279
|
|
71
|
-
graphiti_core-0.
|
|
72
|
-
graphiti_core-0.
|
|
73
|
-
graphiti_core-0.
|
|
74
|
-
graphiti_core-0.
|
|
73
|
+
graphiti_core-0.14.0.dist-info/METADATA,sha256=ePJs8ax8EBgFysrMfz-D_uJ9RKo6O5T5DjvETb7ijqU,20591
|
|
74
|
+
graphiti_core-0.14.0.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
|
|
75
|
+
graphiti_core-0.14.0.dist-info/licenses/LICENSE,sha256=KCUwCyDXuVEgmDWkozHyniRyWjnWUWjkuDHfU6o3JlA,11325
|
|
76
|
+
graphiti_core-0.14.0.dist-info/RECORD,,
|
|
File without changes
|