zep-crewai 0.1.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.
zep_crewai/__init__.py ADDED
@@ -0,0 +1,45 @@
1
+ """
2
+ Zep CrewAI Integration.
3
+
4
+ This package provides memory integration between Zep and CrewAI agents,
5
+ enabling persistent conversation memory and context retrieval.
6
+
7
+ Installation:
8
+ pip install zep-crewai
9
+
10
+ Usage:
11
+ from zep_crewai import ZepStorage
12
+ from zep_cloud.client import AsyncZep
13
+ from crewai.memory.external.external_memory import ExternalMemory
14
+ from crewai import Crew
15
+
16
+ # Initialize Zep client and storage
17
+ zep_client = AsyncZep(api_key="your-api-key")
18
+ zep_storage = ZepStorage(client=zep_client, user_id="user123", thread_id="thread123")
19
+ external_memory = ExternalMemory(storage=zep_storage)
20
+
21
+ # Create crew with Zep memory
22
+ crew = Crew(
23
+ agents=[...],
24
+ tasks=[...],
25
+ external_memory=external_memory
26
+ )
27
+ """
28
+
29
+ __version__ = "0.1.0"
30
+ __author__ = "Zep AI"
31
+ __description__ = "Zep integration for CrewAI"
32
+
33
+ from .exceptions import ZepDependencyError
34
+
35
+ try:
36
+ # Check for required CrewAI dependencies - just test import
37
+ import crewai.memory.storage.interface # noqa: F401
38
+
39
+ # Import our integration
40
+ from .memory import ZepStorage
41
+
42
+ __all__ = ["ZepStorage", "ZepDependencyError"]
43
+
44
+ except ImportError as e:
45
+ raise ZepDependencyError(framework="CrewAI", install_command="pip install zep-crewai") from e
@@ -0,0 +1,12 @@
1
+ """
2
+ Exception classes for CrewAI integration.
3
+ """
4
+
5
+
6
+ class ZepDependencyError(ImportError):
7
+ """Raised when required CrewAI dependencies are not installed."""
8
+
9
+ def __init__(self, framework: str, install_command: str):
10
+ self.framework = framework
11
+ self.install_command = install_command
12
+ super().__init__(f"{framework} dependencies not found. Install with: {install_command}")
zep_crewai/memory.py ADDED
@@ -0,0 +1,177 @@
1
+ """
2
+ Zep Memory integration for CrewAI.
3
+
4
+ This module provides memory storage that integrates Zep with CrewAI's memory system.
5
+ """
6
+
7
+ import logging
8
+ from concurrent.futures import ThreadPoolExecutor
9
+ from typing import Any
10
+
11
+ from crewai.memory.storage.interface import Storage
12
+ from zep_cloud.client import Zep
13
+ from zep_cloud.types import GraphSearchResults, Message
14
+
15
+
16
+ class ZepStorage(Storage):
17
+ """
18
+ A storage implementation that integrates with Zep for persistent storage
19
+ and retrieval of CrewAI agent memories.
20
+ """
21
+
22
+ def __init__(self, client: Zep, user_id: str, thread_id: str, **kwargs: Any) -> None:
23
+ """
24
+ Initialize ZepStorage with a Zep client instance.
25
+
26
+ Args:
27
+ client: An initialized Zep instance (sync client)
28
+ user_id: User ID identifying a created Zep user (required)
29
+ thread_id: Thread ID identifying current conversation thread (required)
30
+ **kwargs: Additional configuration options
31
+ """
32
+ if not isinstance(client, Zep):
33
+ raise TypeError("client must be an instance of Zep")
34
+
35
+ if not user_id:
36
+ raise ValueError("user_id is required")
37
+
38
+ if not thread_id:
39
+ raise ValueError("thread_id is required")
40
+
41
+ self._client = client
42
+ self._user_id = user_id
43
+ self._thread_id = thread_id
44
+ self._config = kwargs
45
+
46
+ self._logger = logging.getLogger(__name__)
47
+
48
+ def save(self, value: Any, metadata: dict[str, Any] | None = None) -> None:
49
+ """
50
+ Save a memory entry to Zep using metadata-based routing.
51
+
52
+ Routes storage based on metadata.type:
53
+ - "message": Store as thread message with role from metadata
54
+ - "json" or "text": Store as graph data
55
+
56
+ Args:
57
+ value: The memory content to store
58
+ metadata: Metadata including type, role, name, etc.
59
+ """
60
+ metadata = metadata or {}
61
+
62
+ content_str = str(value)
63
+ content_type = metadata.get("type", "text")
64
+ if content_type not in ["message", "json", "text"]:
65
+ content_type = "text"
66
+
67
+ try:
68
+ if content_type == "message":
69
+ message_metadata = metadata.copy()
70
+ role = message_metadata.get("role", "norole")
71
+ name = message_metadata.get("name")
72
+
73
+ message = Message(
74
+ role=role,
75
+ name=name,
76
+ content=content_str,
77
+ )
78
+
79
+ self._client.thread.add_messages(thread_id=self._thread_id, messages=[message])
80
+
81
+ self._logger.debug(
82
+ f"Saved message from {metadata.get('name', 'unknown')}: {content_str[:100]}..."
83
+ )
84
+
85
+ else:
86
+ self._client.graph.add(
87
+ user_id=self._user_id,
88
+ data=content_str,
89
+ type=content_type,
90
+ )
91
+
92
+ self._logger.debug(f"Saved {content_type} data: {content_str[:100]}...")
93
+
94
+ except Exception as e:
95
+ self._logger.error(f"Error saving to Zep: {e}")
96
+ raise
97
+
98
+ def search(
99
+ self, query: str, limit: int = 5, score_threshold: float = 0.5
100
+ ) -> dict[str, Any] | list[Any]:
101
+ """
102
+ Search Zep user graph.
103
+
104
+ This always retrieves thread-specific context and performs targeted graph search on the user graph
105
+ using the provided query, combining both sources.
106
+
107
+ Args:
108
+ query: Search query string (truncated to 400 chars max for graph search)
109
+ limit: Maximum number of results to return from graph search
110
+
111
+ Returns:
112
+ List of matching memory entries from both thread context and graph search
113
+ """
114
+ results: list[dict[str, Any]] = []
115
+
116
+ # Truncate query to max 400 characters to avoid API errors
117
+ truncated_query = query[:400] if len(query) > 400 else query
118
+
119
+ # Define search functions for concurrent execution
120
+ def get_thread_context() -> Any:
121
+ try:
122
+ return self._client.thread.get_user_context(thread_id=self._thread_id)
123
+ except Exception as e:
124
+ self._logger.debug(f"Thread context not available: {e}")
125
+ return None
126
+
127
+ def search_graph_edges() -> list[str]:
128
+ try:
129
+ if not query:
130
+ return []
131
+ results: GraphSearchResults = self._client.graph.search(
132
+ user_id=self._user_id, query=truncated_query, limit=limit, scope="edges"
133
+ )
134
+ edges: list[str] = []
135
+ if results.edges:
136
+ for edge in results.edges:
137
+ edge_str = f"{edge.fact} (valid_at: {edge.valid_at}, invalid_at: {edge.invalid_at or 'current'})"
138
+ edges.append(edge_str)
139
+ return edges
140
+ except Exception as e:
141
+ self._logger.debug(f"Graph search not available: {e}")
142
+ return []
143
+
144
+ thread_context = None
145
+ edges_search_results: list[str] = []
146
+
147
+ try:
148
+ with ThreadPoolExecutor(max_workers=2) as executor:
149
+ future_thread = executor.submit(get_thread_context)
150
+ future_edges = executor.submit(search_graph_edges)
151
+
152
+ thread_context = future_thread.result()
153
+ edges_search_results = future_edges.result() or []
154
+
155
+ except Exception as e:
156
+ self._logger.debug(f"Failed to search user memories: {e}")
157
+
158
+ if thread_context and hasattr(thread_context, "context") and thread_context.context:
159
+ results.append({"memory": thread_context.context})
160
+
161
+ for result in edges_search_results:
162
+ results.append({"memory": result})
163
+
164
+ return results
165
+
166
+ def reset(self) -> None:
167
+ pass
168
+
169
+ @property
170
+ def user_id(self) -> str:
171
+ """Get the user ID."""
172
+ return self._user_id
173
+
174
+ @property
175
+ def thread_id(self) -> str:
176
+ """Get the thread ID."""
177
+ return self._thread_id
@@ -0,0 +1,186 @@
1
+ Metadata-Version: 2.4
2
+ Name: zep-crewai
3
+ Version: 0.1.0
4
+ Summary: CrewAI integration for Zep
5
+ Project-URL: Homepage, https://github.com/getzep/zep
6
+ Project-URL: Documentation, https://help.getzep.com
7
+ Project-URL: Repository, https://github.com/getzep/zep
8
+ Project-URL: Bug Tracker, https://github.com/getzep/zep/issues
9
+ Requires-Python: >=3.10
10
+ Requires-Dist: aiohttp>=3.8.0
11
+ Requires-Dist: crewai>=0.80.0
12
+ Requires-Dist: python-dotenv>=1.0.0
13
+ Requires-Dist: python-slugify>=8.0.4
14
+ Requires-Dist: rich>=14.0.0
15
+ Requires-Dist: zep-cloud>=3.0.0rc1
16
+ Provides-Extra: dev
17
+ Requires-Dist: mypy>=1.0.0; extra == 'dev'
18
+ Requires-Dist: pytest-asyncio; extra == 'dev'
19
+ Requires-Dist: pytest-cov; extra == 'dev'
20
+ Requires-Dist: pytest>=7.0.0; extra == 'dev'
21
+ Requires-Dist: ruff>=0.1.0; extra == 'dev'
22
+ Description-Content-Type: text/markdown
23
+
24
+ # Zep CrewAI Integration Tutorial
25
+
26
+ Learn how to add persistent memory to your CrewAI agents using Zep's powerful memory platform.
27
+
28
+ ## Installation
29
+
30
+ Install the Zep CrewAI integration package:
31
+
32
+ ```bash
33
+ pip install zep-crewai
34
+ ```
35
+
36
+ ## Setup
37
+
38
+ ### 1. Get Your API Key
39
+
40
+ Sign up at [Zep Cloud](https://app.getzep.com) and get your API key.
41
+
42
+ ### 2. Set Environment Variable
43
+
44
+ ```bash
45
+ export ZEP_API_KEY="your-zep-api-key"
46
+ ```
47
+
48
+ ## Basic Usage
49
+
50
+ ### 1. Initialize Zep Client
51
+
52
+ ```python
53
+ import os
54
+ from zep_cloud.client import Zep
55
+
56
+ # Initialize Zep client
57
+ zep_client = Zep(api_key=os.getenv("ZEP_API_KEY"))
58
+ ```
59
+
60
+ ### 2. Create User and Thread
61
+
62
+ **Important**: You must create a user and thread in Zep before using ZepStorage.
63
+
64
+ ```python
65
+ # Create a user
66
+ user_id = "john_doe_123"
67
+ zep_client.user.add(
68
+ user_id=user_id,
69
+ first_name="John",
70
+ last_name="Doe",
71
+ email="john.doe@example.com"
72
+ )
73
+
74
+ # Create a thread
75
+ thread_id = "project_alpha_456"
76
+ zep_client.thread.create(
77
+ user_id=user_id,
78
+ thread_id=thread_id
79
+ )
80
+ ```
81
+
82
+ ### 3. Initialize ZepStorage
83
+
84
+ ```python
85
+ from zep_crewai import ZepStorage
86
+ from crewai.memory.external.external_memory import ExternalMemory
87
+
88
+ # Create storage for your project
89
+ zep_storage = ZepStorage(
90
+ client=zep_client,
91
+ user_id=user_id,
92
+ thread_id=thread_id
93
+ )
94
+
95
+ # Wrap in CrewAI's external memory
96
+ external_memory = ExternalMemory(storage=zep_storage)
97
+ ```
98
+
99
+ ### 4. Create Crew with Persistent Memory
100
+
101
+ ```python
102
+ from crewai import Agent, Crew, Task, Process
103
+
104
+ # Create your agents
105
+ research_agent = Agent(
106
+ role='Research Analyst',
107
+ goal='Analyze market trends and provide insights',
108
+ backstory='You are an expert at finding and analyzing market data...',
109
+ )
110
+
111
+ # Create crew with Zep memory
112
+ crew = Crew(
113
+ agents=[research_agent],
114
+ tasks=[...],
115
+ external_memory=external_memory, # This enables the crew to search Zep
116
+ process=Process.sequential,
117
+ )
118
+
119
+ # Run your crew - memories will be automatically saved and retrieved
120
+ result = crew.kickoff()
121
+ ```
122
+
123
+ ## How Memory Works
124
+
125
+ Zep stores different types of content using metadata-based routing.
126
+
127
+ ### Messages (Conversation Context)
128
+ Stored in Zep threads for conversation history:
129
+
130
+ ```python
131
+ external_memory.save(
132
+ "I need help planning a business trip to New York",
133
+ metadata={"type": "message", "role": "user", "name": "John Doe"}
134
+ )
135
+
136
+ external_memory.save(
137
+ "I'd be happy to help you plan your trip!",
138
+ metadata={"type": "message", "role": "assistant", "name": "Travel Agent"}
139
+ )
140
+ ```
141
+
142
+ ### Structured Data
143
+ Added as episodes to the user knowledge graph in Zep:
144
+
145
+ ```python
146
+ # JSON data
147
+ external_memory.save(
148
+ '{"destination": "New York", "duration": "3 days", "budget": 2000}',
149
+ metadata={"type": "json"}
150
+ )
151
+
152
+ # Text facts and insights
153
+ external_memory.save(
154
+ "User prefers mid-range hotels with business amenities",
155
+ metadata={"type": "text"}
156
+ )
157
+ ```
158
+
159
+ ### Automatic Memory Retrieval
160
+
161
+ CrewAI automatically searches your memories when agents need context:
162
+
163
+ ```python
164
+ # When agents run, they automatically get relevant context from Zep
165
+ results = crew.kickoff()
166
+
167
+ # You can also search manually
168
+ memory_results = zep_storage.search("hotel preferences", limit=5)
169
+ for result in memory_results:
170
+ print(result['memory'])
171
+ ```
172
+
173
+ ## Complete Example
174
+
175
+ For a full working example, check out [`examples/simple_example.py`](examples/simple_example.py) in this repository. This example demonstrates:
176
+
177
+ - Setting up Zep user and thread
178
+ - Saving different types of memory (messages, JSON data, text)
179
+ - Creating CrewAI agents with access to Zep memory
180
+ - Automatic context retrieval during agent execution
181
+
182
+ ## Requirements
183
+
184
+ - Python 3.10+
185
+ - `zep-cloud>=3.0.0rc1`
186
+ - `crewai>=0.80.0`
@@ -0,0 +1,6 @@
1
+ zep_crewai/__init__.py,sha256=H8xpqfQd79JPRbd7h9wHjgSbsKrQGiTDV_CePgeo_cQ,1280
2
+ zep_crewai/exceptions.py,sha256=buRZJt5TDankN7PvLq_u0wDlQ0Sp6LKXroS1qTj6koY,403
3
+ zep_crewai/memory.py,sha256=lhoOsmJK6Yfe9OULt7OQ98Rk963pCY9_HGbHTnA22u8,6082
4
+ zep_crewai-0.1.0.dist-info/METADATA,sha256=panKSkdvw1uRiGebFgNZ8lfL_xQaPd_L5mSH6bDku-8,4470
5
+ zep_crewai-0.1.0.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
6
+ zep_crewai-0.1.0.dist-info/RECORD,,
@@ -0,0 +1,4 @@
1
+ Wheel-Version: 1.0
2
+ Generator: hatchling 1.27.0
3
+ Root-Is-Purelib: true
4
+ Tag: py3-none-any