graphiti-core 0.12.0rc1__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.
Files changed (68) hide show
  1. graphiti_core/cross_encoder/bge_reranker_client.py +12 -2
  2. graphiti_core/cross_encoder/gemini_reranker_client.py +161 -0
  3. graphiti_core/cross_encoder/openai_reranker_client.py +7 -5
  4. graphiti_core/decorators.py +110 -0
  5. graphiti_core/driver/__init__.py +19 -0
  6. graphiti_core/driver/driver.py +124 -0
  7. graphiti_core/driver/falkordb_driver.py +362 -0
  8. graphiti_core/driver/graph_operations/graph_operations.py +191 -0
  9. graphiti_core/driver/kuzu_driver.py +182 -0
  10. graphiti_core/driver/neo4j_driver.py +117 -0
  11. graphiti_core/driver/neptune_driver.py +305 -0
  12. graphiti_core/driver/search_interface/search_interface.py +89 -0
  13. graphiti_core/edges.py +287 -172
  14. graphiti_core/embedder/azure_openai.py +71 -0
  15. graphiti_core/embedder/client.py +2 -1
  16. graphiti_core/embedder/gemini.py +116 -22
  17. graphiti_core/embedder/voyage.py +13 -2
  18. graphiti_core/errors.py +8 -0
  19. graphiti_core/graph_queries.py +162 -0
  20. graphiti_core/graphiti.py +705 -193
  21. graphiti_core/graphiti_types.py +4 -2
  22. graphiti_core/helpers.py +87 -10
  23. graphiti_core/llm_client/__init__.py +16 -0
  24. graphiti_core/llm_client/anthropic_client.py +159 -56
  25. graphiti_core/llm_client/azure_openai_client.py +115 -0
  26. graphiti_core/llm_client/client.py +98 -21
  27. graphiti_core/llm_client/config.py +1 -1
  28. graphiti_core/llm_client/gemini_client.py +290 -41
  29. graphiti_core/llm_client/groq_client.py +14 -3
  30. graphiti_core/llm_client/openai_base_client.py +261 -0
  31. graphiti_core/llm_client/openai_client.py +56 -132
  32. graphiti_core/llm_client/openai_generic_client.py +91 -56
  33. graphiti_core/models/edges/edge_db_queries.py +259 -35
  34. graphiti_core/models/nodes/node_db_queries.py +311 -32
  35. graphiti_core/nodes.py +420 -205
  36. graphiti_core/prompts/dedupe_edges.py +46 -32
  37. graphiti_core/prompts/dedupe_nodes.py +67 -42
  38. graphiti_core/prompts/eval.py +4 -4
  39. graphiti_core/prompts/extract_edges.py +27 -16
  40. graphiti_core/prompts/extract_nodes.py +74 -31
  41. graphiti_core/prompts/prompt_helpers.py +39 -0
  42. graphiti_core/prompts/snippets.py +29 -0
  43. graphiti_core/prompts/summarize_nodes.py +23 -25
  44. graphiti_core/search/search.py +158 -82
  45. graphiti_core/search/search_config.py +39 -4
  46. graphiti_core/search/search_filters.py +126 -35
  47. graphiti_core/search/search_helpers.py +5 -6
  48. graphiti_core/search/search_utils.py +1405 -485
  49. graphiti_core/telemetry/__init__.py +9 -0
  50. graphiti_core/telemetry/telemetry.py +117 -0
  51. graphiti_core/tracer.py +193 -0
  52. graphiti_core/utils/bulk_utils.py +364 -285
  53. graphiti_core/utils/datetime_utils.py +13 -0
  54. graphiti_core/utils/maintenance/community_operations.py +67 -49
  55. graphiti_core/utils/maintenance/dedup_helpers.py +262 -0
  56. graphiti_core/utils/maintenance/edge_operations.py +339 -197
  57. graphiti_core/utils/maintenance/graph_data_operations.py +50 -114
  58. graphiti_core/utils/maintenance/node_operations.py +319 -238
  59. graphiti_core/utils/maintenance/temporal_operations.py +11 -3
  60. graphiti_core/utils/ontology_utils/entity_types_utils.py +1 -1
  61. graphiti_core/utils/text_utils.py +53 -0
  62. graphiti_core-0.24.3.dist-info/METADATA +726 -0
  63. graphiti_core-0.24.3.dist-info/RECORD +86 -0
  64. {graphiti_core-0.12.0rc1.dist-info → graphiti_core-0.24.3.dist-info}/WHEEL +1 -1
  65. graphiti_core-0.12.0rc1.dist-info/METADATA +0 -350
  66. graphiti_core-0.12.0rc1.dist-info/RECORD +0 -66
  67. /graphiti_core/{utils/maintenance/utils.py → migrations/__init__.py} +0 -0
  68. {graphiti_core-0.12.0rc1.dist-info → graphiti_core-0.24.3.dist-info/licenses}/LICENSE +0 -0
@@ -15,96 +15,42 @@ limitations under the License.
15
15
  """
16
16
 
17
17
  import logging
18
- from datetime import datetime, timezone
18
+ from datetime import datetime
19
19
 
20
- from neo4j import AsyncDriver
21
20
  from typing_extensions import LiteralString
22
21
 
23
- from graphiti_core.helpers import DEFAULT_DATABASE, semaphore_gather
24
- from graphiti_core.nodes import EpisodeType, EpisodicNode
22
+ from graphiti_core.driver.driver import GraphDriver, GraphProvider
23
+ from graphiti_core.models.nodes.node_db_queries import (
24
+ EPISODIC_NODE_RETURN,
25
+ EPISODIC_NODE_RETURN_NEPTUNE,
26
+ )
27
+ from graphiti_core.nodes import EpisodeType, EpisodicNode, get_episodic_node_from_record
25
28
 
26
29
  EPISODE_WINDOW_LEN = 3
27
30
 
28
31
  logger = logging.getLogger(__name__)
29
32
 
30
33
 
31
- async def build_indices_and_constraints(driver: AsyncDriver, delete_existing: bool = False):
32
- if delete_existing:
33
- records, _, _ = await driver.execute_query(
34
- """
35
- SHOW INDEXES YIELD name
36
- """,
37
- database_=DEFAULT_DATABASE,
38
- )
39
- index_names = [record['name'] for record in records]
40
- await semaphore_gather(
41
- *[
42
- driver.execute_query(
43
- """DROP INDEX $name""",
44
- name=name,
45
- database_=DEFAULT_DATABASE,
46
- )
47
- for name in index_names
48
- ]
49
- )
50
-
51
- range_indices: list[LiteralString] = [
52
- 'CREATE INDEX entity_uuid IF NOT EXISTS FOR (n:Entity) ON (n.uuid)',
53
- 'CREATE INDEX episode_uuid IF NOT EXISTS FOR (n:Episodic) ON (n.uuid)',
54
- 'CREATE INDEX community_uuid IF NOT EXISTS FOR (n:Community) ON (n.uuid)',
55
- 'CREATE INDEX relation_uuid IF NOT EXISTS FOR ()-[e:RELATES_TO]-() ON (e.uuid)',
56
- 'CREATE INDEX mention_uuid IF NOT EXISTS FOR ()-[e:MENTIONS]-() ON (e.uuid)',
57
- 'CREATE INDEX has_member_uuid IF NOT EXISTS FOR ()-[e:HAS_MEMBER]-() ON (e.uuid)',
58
- 'CREATE INDEX entity_group_id IF NOT EXISTS FOR (n:Entity) ON (n.group_id)',
59
- 'CREATE INDEX episode_group_id IF NOT EXISTS FOR (n:Episodic) ON (n.group_id)',
60
- 'CREATE INDEX relation_group_id IF NOT EXISTS FOR ()-[e:RELATES_TO]-() ON (e.group_id)',
61
- 'CREATE INDEX mention_group_id IF NOT EXISTS FOR ()-[e:MENTIONS]-() ON (e.group_id)',
62
- 'CREATE INDEX name_entity_index IF NOT EXISTS FOR (n:Entity) ON (n.name)',
63
- 'CREATE INDEX created_at_entity_index IF NOT EXISTS FOR (n:Entity) ON (n.created_at)',
64
- 'CREATE INDEX created_at_episodic_index IF NOT EXISTS FOR (n:Episodic) ON (n.created_at)',
65
- 'CREATE INDEX valid_at_episodic_index IF NOT EXISTS FOR (n:Episodic) ON (n.valid_at)',
66
- 'CREATE INDEX name_edge_index IF NOT EXISTS FOR ()-[e:RELATES_TO]-() ON (e.name)',
67
- 'CREATE INDEX created_at_edge_index IF NOT EXISTS FOR ()-[e:RELATES_TO]-() ON (e.created_at)',
68
- 'CREATE INDEX expired_at_edge_index IF NOT EXISTS FOR ()-[e:RELATES_TO]-() ON (e.expired_at)',
69
- 'CREATE INDEX valid_at_edge_index IF NOT EXISTS FOR ()-[e:RELATES_TO]-() ON (e.valid_at)',
70
- 'CREATE INDEX invalid_at_edge_index IF NOT EXISTS FOR ()-[e:RELATES_TO]-() ON (e.invalid_at)',
71
- ]
72
-
73
- fulltext_indices: list[LiteralString] = [
74
- """CREATE FULLTEXT INDEX episode_content IF NOT EXISTS
75
- FOR (e:Episodic) ON EACH [e.content, e.source, e.source_description, e.group_id]""",
76
- """CREATE FULLTEXT INDEX node_name_and_summary IF NOT EXISTS
77
- FOR (n:Entity) ON EACH [n.name, n.summary, n.group_id]""",
78
- """CREATE FULLTEXT INDEX community_name IF NOT EXISTS
79
- FOR (n:Community) ON EACH [n.name, n.group_id]""",
80
- """CREATE FULLTEXT INDEX edge_name_and_fact IF NOT EXISTS
81
- FOR ()-[e:RELATES_TO]-() ON EACH [e.name, e.fact, e.group_id]""",
82
- ]
83
-
84
- index_queries: list[LiteralString] = range_indices + fulltext_indices
85
-
86
- await semaphore_gather(
87
- *[
88
- driver.execute_query(
89
- query,
90
- database_=DEFAULT_DATABASE,
91
- )
92
- for query in index_queries
93
- ]
94
- )
95
-
96
-
97
- async def clear_data(driver: AsyncDriver, group_ids: list[str] | None = None):
98
- async with driver.session(database=DEFAULT_DATABASE) as session:
34
+ async def clear_data(driver: GraphDriver, group_ids: list[str] | None = None):
35
+ async with driver.session() as session:
99
36
 
100
37
  async def delete_all(tx):
101
38
  await tx.run('MATCH (n) DETACH DELETE n')
102
39
 
103
40
  async def delete_group_ids(tx):
104
- await tx.run(
105
- 'MATCH (n:Entity|Episodic|Community) WHERE n.group_id IN $group_ids DETACH DELETE n',
106
- group_ids=group_ids,
107
- )
41
+ labels = ['Entity', 'Episodic', 'Community']
42
+ if driver.provider == GraphProvider.KUZU:
43
+ labels.append('RelatesToNode_')
44
+
45
+ for label in labels:
46
+ await tx.run(
47
+ f"""
48
+ MATCH (n:{label})
49
+ WHERE n.group_id IN $group_ids
50
+ DETACH DELETE n
51
+ """,
52
+ group_ids=group_ids,
53
+ )
108
54
 
109
55
  if group_ids is None:
110
56
  await session.execute_write(delete_all)
@@ -113,7 +59,7 @@ async def clear_data(driver: AsyncDriver, group_ids: list[str] | None = None):
113
59
 
114
60
 
115
61
  async def retrieve_episodes(
116
- driver: AsyncDriver,
62
+ driver: GraphDriver,
117
63
  reference_time: datetime,
118
64
  last_n: int = EPISODE_WINDOW_LEN,
119
65
  group_ids: list[str] | None = None,
@@ -123,7 +69,7 @@ async def retrieve_episodes(
123
69
  Retrieve the last n episodic nodes from the graph.
124
70
 
125
71
  Args:
126
- driver (AsyncDriver): The Neo4j driver instance.
72
+ driver (Driver): The Neo4j driver instance.
127
73
  reference_time (datetime): The reference time to filter episodes. Only episodes with a valid_at timestamp
128
74
  less than or equal to this reference_time will be retrieved. This allows for
129
75
  querying the graph's state at a specific point in time.
@@ -133,52 +79,42 @@ async def retrieve_episodes(
133
79
  Returns:
134
80
  list[EpisodicNode]: A list of EpisodicNode objects representing the retrieved episodes.
135
81
  """
136
- group_id_filter: LiteralString = (
137
- '\nAND e.group_id IN $group_ids' if group_ids and len(group_ids) > 0 else ''
138
- )
139
- source_filter: LiteralString = '\nAND e.source = $source' if source is not None else ''
82
+
83
+ query_params: dict = {}
84
+ query_filter = ''
85
+ if group_ids and len(group_ids) > 0:
86
+ query_filter += '\nAND e.group_id IN $group_ids'
87
+ query_params['group_ids'] = group_ids
88
+
89
+ if source is not None:
90
+ query_filter += '\nAND e.source = $source'
91
+ query_params['source'] = source.name
140
92
 
141
93
  query: LiteralString = (
142
94
  """
143
- MATCH (e:Episodic) WHERE e.valid_at <= $reference_time
144
- """
145
- + group_id_filter
146
- + source_filter
95
+ MATCH (e:Episodic)
96
+ WHERE e.valid_at <= $reference_time
97
+ """
98
+ + query_filter
99
+ + """
100
+ RETURN
101
+ """
102
+ + (
103
+ EPISODIC_NODE_RETURN_NEPTUNE
104
+ if driver.provider == GraphProvider.NEPTUNE
105
+ else EPISODIC_NODE_RETURN
106
+ )
147
107
  + """
148
- RETURN e.content AS content,
149
- e.created_at AS created_at,
150
- e.valid_at AS valid_at,
151
- e.uuid AS uuid,
152
- e.group_id AS group_id,
153
- e.name AS name,
154
- e.source_description AS source_description,
155
- e.source AS source
156
108
  ORDER BY e.valid_at DESC
157
109
  LIMIT $num_episodes
158
110
  """
159
111
  )
160
-
161
- result = await driver.execute_query(
112
+ result, _, _ = await driver.execute_query(
162
113
  query,
163
114
  reference_time=reference_time,
164
- source=source.name if source is not None else None,
165
115
  num_episodes=last_n,
166
- group_ids=group_ids,
167
- database_=DEFAULT_DATABASE,
116
+ **query_params,
168
117
  )
169
- episodes = [
170
- EpisodicNode(
171
- content=record['content'],
172
- created_at=datetime.fromtimestamp(
173
- record['created_at'].to_native().timestamp(), timezone.utc
174
- ),
175
- valid_at=(record['valid_at'].to_native()),
176
- uuid=record['uuid'],
177
- group_id=record['group_id'],
178
- source=EpisodeType.from_str(record['source']),
179
- name=record['name'],
180
- source_description=record['source_description'],
181
- )
182
- for record in result.records
183
- ]
118
+
119
+ episodes = [get_episodic_node_from_record(record) for record in result]
184
120
  return list(reversed(episodes)) # Return in chronological order