recallrai 0.0.1__py3-none-any.whl → 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.

Potentially problematic release.


This version of recallrai might be problematic. Click here for more details.

recallrai/__init__.py CHANGED
@@ -0,0 +1,19 @@
1
+ # Path: recallrai/__init__.py
2
+ # Description: Package initialization file with SDK version and main class exports
3
+
4
+ """
5
+ RecallrAI Python SDK
6
+
7
+ This package provides a Python interface to interact with the RecallrAI API.
8
+ """
9
+
10
+ from .client import RecallrAI
11
+ from .user import User
12
+ from .session import Session
13
+
14
+ __version__ = "0.1.0"
15
+ __all__ = [
16
+ "RecallrAI",
17
+ "User",
18
+ "Session",
19
+ ]
recallrai/client.py ADDED
@@ -0,0 +1,220 @@
1
+ # Path: recallrai/client.py
2
+ # Description: Main client class for the RecallrAI SDK
3
+
4
+ """
5
+ Main client class for the RecallrAI SDK.
6
+
7
+ This module provides the RecallrAI class, which is the primary interface for the SDK.
8
+ """
9
+
10
+ import uuid
11
+ from typing import Any, Dict, Optional
12
+ from pydantic import HttpUrl
13
+ from .utils import HTTPClient, RecallrAIError
14
+ from .models import User as UserModel, UserList, SessionStatus, SessionList
15
+ from .user import User
16
+ from .session import Session
17
+ from logging import getLogger
18
+
19
+ logger = getLogger(__name__)
20
+
21
+ class RecallrAI:
22
+ """
23
+ Main client for interacting with the RecallrAI API.
24
+
25
+ This class provides methods for creating and managing users, sessions, and memories.
26
+ """
27
+
28
+ def __init__(
29
+ self,
30
+ api_key: str,
31
+ project_id: uuid.UUID,
32
+ base_url: HttpUrl = "https://api.recallrai.com",
33
+ timeout: int = 30,
34
+ ):
35
+ """
36
+ Initialize the RecallrAI client.
37
+
38
+ Args:
39
+ api_key: Your RecallrAI API key
40
+ project_id: Your project ID
41
+ base_url: The base URL for the RecallrAI API
42
+ timeout: Request timeout in seconds
43
+ """
44
+ if not api_key.startswith("rai_"):
45
+ raise ValueError("API key must start with 'rai_'")
46
+
47
+ self.api_key = api_key
48
+ self.project_id = str(project_id)
49
+ self.base_url = str(base_url)
50
+
51
+ self.http = HTTPClient(
52
+ api_key=self.api_key,
53
+ project_id=self.project_id,
54
+ base_url=self.base_url,
55
+ timeout=timeout,
56
+ )
57
+
58
+ # User management
59
+ def create_user(self, user_id: str, metadata: Optional[Dict[str, Any]] = None) -> User:
60
+ """
61
+ Create a new user.
62
+
63
+ Args:
64
+ user_id: Unique identifier for the user
65
+ metadata: Optional metadata to associate with the user
66
+
67
+ Returns:
68
+ The created user object
69
+
70
+ Raises:
71
+ ValidationError: If the user_id is invalid
72
+ BadRequestError: If a user with the same ID already exists
73
+ """
74
+ response = self.http.post("/api/v1/users", data={"user_id": user_id, "metadata": metadata or {}})
75
+ user_data = UserModel.from_api_response(response)
76
+ return User(self.http, user_data)
77
+
78
+ def get_user(self, user_id: str) -> User:
79
+ """
80
+ Get a user by ID.
81
+
82
+ Args:
83
+ user_id: Unique identifier of the user
84
+
85
+ Returns:
86
+ A User object representing the user
87
+
88
+ Raises:
89
+ NotFoundError: If the user is not found
90
+ """
91
+ response = self.http.get(f"/api/v1/users/{user_id}")
92
+ user_data = UserModel.from_api_response(response)
93
+ return User(self.http, user_data)
94
+
95
+ def list_users(self, offset: int = 0, limit: int = 10) -> UserList:
96
+ """
97
+ List users with pagination.
98
+
99
+ Args:
100
+ offset: Number of records to skip
101
+ limit: Maximum number of records to return
102
+
103
+ Returns:
104
+ List of users with pagination info
105
+ """
106
+ response = self.http.get("/api/v1/users", params={"offset": offset, "limit": limit})
107
+ return UserList.from_api_response(response)
108
+
109
+ def update_user(
110
+ self,
111
+ user_id: str,
112
+ new_metadata: Optional[Dict[str, Any]] = None,
113
+ new_user_id: Optional[str] = None
114
+ ) -> User:
115
+ """
116
+ Update a user's metadata or ID.
117
+
118
+ Args:
119
+ user_id: Current ID of the user
120
+ new_metadata: New metadata to associate with the user
121
+ new_user_id: New ID for the user
122
+
123
+ Returns:
124
+ The updated user
125
+
126
+ Raises:
127
+ NotFoundError: If the user is not found
128
+ ValidationError: If the new_user_id is invalid
129
+ BadRequestError: If a user with the new_user_id already exists
130
+ """
131
+ data = {}
132
+ if new_metadata is not None:
133
+ data["new_metadata"] = new_metadata
134
+ if new_user_id is not None:
135
+ data["new_user_id"] = new_user_id
136
+
137
+ response = self.http.put(f"/api/v1/users/{user_id}", data=data)
138
+ user_data = UserModel.from_api_response(response)
139
+ return User(self.http, user_data)
140
+
141
+ def delete_user(self, user_id: str) -> None:
142
+ """
143
+ Delete a user.
144
+
145
+ Args:
146
+ user_id: ID of the user to delete
147
+
148
+ Raises:
149
+ NotFoundError: If the user is not found
150
+ """
151
+ self.http.delete(f"/api/v1/users/{user_id}")
152
+
153
+ # Session management
154
+ def create_session(self, user_id: str, auto_process_after_minutes: int = -1) -> Session:
155
+ """
156
+ Create a new session for a user.
157
+
158
+ Args:
159
+ user_id: ID of the user to create the session for
160
+ auto_process_after_minutes: Minutes to wait before auto-processing (-1 to disable)
161
+
162
+ Returns:
163
+ A Session object to interact with the created session
164
+
165
+ Raises:
166
+ NotFoundError: If the user is not found
167
+ ValidationError: If auto_process_after_minutes is invalid
168
+ """
169
+ response = self.http.post(
170
+ f"/api/v1/users/{user_id}/sessions",
171
+ data={"auto_process_after_minutes": auto_process_after_minutes},
172
+ )
173
+
174
+ session_id = response["session_id"]
175
+ return Session(self.http, user_id, session_id)
176
+
177
+ def get_session(self, user_id: str, session_id: str) -> Session:
178
+ """
179
+ Get an existing session.
180
+
181
+ Args:
182
+ user_id: ID of the user who owns the session
183
+ session_id: ID of the session to retrieve
184
+
185
+ Returns:
186
+ A Session object to interact with the session
187
+
188
+ Raises:
189
+ NotFoundError: If the user or session is not found
190
+ """
191
+ # Ensure the session exists by checking its status
192
+ session = Session(self.http, user_id, session_id)
193
+ status = session.get_status()
194
+ if status == SessionStatus.PROCESSING:
195
+ raise RecallrAIError("Session is already processing. You can't add messages to it. Create a new session instead.")
196
+ elif status == SessionStatus.PROCESSED:
197
+ raise RecallrAIError("Session has already been processed. You can't add messages to it. Create a new session instead.")
198
+
199
+ return session
200
+
201
+ def list_sessions(self, user_id: str, offset: int = 0, limit: int = 10) -> SessionList:
202
+ """
203
+ List sessions for a user with pagination.
204
+
205
+ Args:
206
+ user_id: ID of the user
207
+ offset: Number of records to skip
208
+ limit: Maximum number of records to return
209
+
210
+ Returns:
211
+ List of sessions with pagination info
212
+
213
+ Raises:
214
+ NotFoundError: If the user is not found
215
+ """
216
+ response = self.http.get(
217
+ f"/api/v1/users/{user_id}/sessions",
218
+ params={"offset": offset, "limit": limit},
219
+ )
220
+ return SessionList.from_api_response(response)
@@ -0,0 +1,16 @@
1
+ # Path: recallrai/models/__init__.py
2
+ # Description: Package initialization for data models
3
+
4
+ from .session import Context, Message, MessageRole, Session, SessionList, SessionStatus
5
+ from .user import User, UserList
6
+
7
+ __all__ = [
8
+ "User",
9
+ "UserList",
10
+ "Session",
11
+ "SessionList",
12
+ "SessionStatus",
13
+ "Message",
14
+ "MessageRole",
15
+ "Context",
16
+ ]
@@ -0,0 +1,138 @@
1
+ # Path: recallrai/models/session.py
2
+ # Description: Session data models for the RecallrAI SDK
3
+
4
+ """
5
+ Session-related data models for the RecallrAI SDK.
6
+ """
7
+
8
+ import enum, uuid
9
+ from datetime import datetime
10
+ from typing import Any, Dict, List, Optional
11
+
12
+ from pydantic import BaseModel, Field
13
+
14
+
15
+ class MessageRole(str, enum.Enum):
16
+ """
17
+ Message role in a conversation.
18
+ """
19
+ USER = "user"
20
+ ASSISTANT = "assistant"
21
+
22
+
23
+ class Message(BaseModel):
24
+ """
25
+ Represents a message in a conversation session.
26
+ """
27
+ role: MessageRole = Field(..., description="Role of the message sender (user or assistant)")
28
+ content: str = Field(..., description="Content of the message")
29
+ timestamp: datetime = Field(..., description="When the message was sent")
30
+
31
+ class Config:
32
+ """Pydantic configuration."""
33
+ frozen = True
34
+ json_encoders = {
35
+ datetime: lambda dt: dt.isoformat()
36
+ }
37
+
38
+
39
+ class SessionStatus(str, enum.Enum):
40
+ """
41
+ Status of a session.
42
+ """
43
+ PENDING = "pending"
44
+ PROCESSING = "processing"
45
+ PROCESSED = "processed"
46
+
47
+
48
+ class Session(BaseModel):
49
+ """
50
+ Represents a conversation session.
51
+ """
52
+ session_id: uuid.UUID = Field(..., description="Unique identifier for the session")
53
+ status: SessionStatus = Field(..., description="Current status of the session")
54
+ created_at: datetime = Field(..., description="When the session was created")
55
+
56
+ class Config:
57
+ """Pydantic configuration."""
58
+ frozen = True
59
+ json_encoders = {
60
+ datetime: lambda dt: dt.isoformat(),
61
+ uuid.UUID: lambda id: str(id)
62
+ }
63
+
64
+ @classmethod
65
+ def from_api_response(cls, data: Dict[str, Any]) -> "Session":
66
+ """
67
+ Create a Session instance from an API response.
68
+
69
+ Args:
70
+ data: API response data
71
+
72
+ Returns:
73
+ A Session instance
74
+ """
75
+ return cls(
76
+ session_id=data["session_id"],
77
+ status=data.get("status", SessionStatus.PENDING),
78
+ created_at=data.get("created_at", datetime.now()),
79
+ messages=None
80
+ )
81
+
82
+
83
+ class SessionList(BaseModel):
84
+ """
85
+ Represents a paginated list of sessions.
86
+ """
87
+ sessions: List[Session] = Field(..., description="List of sessions")
88
+ total: int = Field(..., description="Total number of sessions")
89
+ has_more: bool = Field(..., description="Whether there are more sessions to fetch")
90
+
91
+ class Config:
92
+ """Pydantic configuration."""
93
+ frozen = True
94
+
95
+ @classmethod
96
+ def from_api_response(cls, data: Dict[str, Any]) -> "SessionList":
97
+ """
98
+ Create a SessionList instance from an API response.
99
+
100
+ Args:
101
+ data: API response data
102
+
103
+ Returns:
104
+ A SessionList instance
105
+ """
106
+ return cls(
107
+ sessions=[Session.from_api_response(session) for session in data["sessions"]],
108
+ total=data["total"],
109
+ has_more=data["has_more"],
110
+ )
111
+
112
+
113
+ class Context(BaseModel):
114
+ """
115
+ Represents the context for a session.
116
+ """
117
+ memory_used: bool = Field(..., description="Whether memory was used to generate the context")
118
+ context: str = Field(..., description="The context for the session")
119
+
120
+ class Config:
121
+ """Pydantic configuration."""
122
+ frozen = True
123
+
124
+ @classmethod
125
+ def from_api_response(cls, data: Dict[str, Any]) -> "Context":
126
+ """
127
+ Create a Context instance from an API response.
128
+
129
+ Args:
130
+ data: API response data
131
+
132
+ Returns:
133
+ A Context instance
134
+ """
135
+ return cls(
136
+ memory_used=data["memory_used"],
137
+ context=data["context"],
138
+ )
@@ -0,0 +1,75 @@
1
+ # Path: recallrai/models/user.py
2
+ # Description: User data models for the RecallrAI SDK
3
+
4
+ """
5
+ User-related data models for the RecallrAI SDK.
6
+ """
7
+
8
+ from datetime import datetime
9
+ from typing import Any, Dict
10
+
11
+ from pydantic import BaseModel, Field
12
+
13
+
14
+ class User(BaseModel):
15
+ """Represents a user in the RecallrAI system."""
16
+
17
+ user_id: str = Field(..., description="Unique identifier for the user")
18
+ metadata: Dict[str, Any] = Field(default_factory=dict, description="Custom metadata for the user")
19
+ created_at: datetime = Field(..., description="When the user was created")
20
+ last_active_at: datetime = Field(..., description="When the user was last active")
21
+
22
+ class Config:
23
+ """Pydantic configuration."""
24
+ frozen = True
25
+ json_encoders = {
26
+ datetime: lambda dt: dt.isoformat()
27
+ }
28
+
29
+ @classmethod
30
+ def from_api_response(cls, data: Dict[str, Any]) -> "User":
31
+ """
32
+ Create a User instance from an API response.
33
+
34
+ Args:
35
+ data: API response data
36
+
37
+ Returns:
38
+ A User instance
39
+ """
40
+ if "user" in data:
41
+ user_data = data["user"]
42
+ else:
43
+ user_data = data
44
+
45
+ return cls(
46
+ user_id=user_data["user_id"],
47
+ metadata=user_data.get("metadata", {}),
48
+ created_at=user_data["created_at"],
49
+ last_active_at=user_data["last_active_at"],
50
+ )
51
+
52
+
53
+ class UserList(BaseModel):
54
+ """Represents a paginated list of users."""
55
+
56
+ users: list[User] = Field(..., description="List of users")
57
+ total: int = Field(..., description="Total number of users")
58
+ has_more: bool = Field(..., description="Whether there are more users to fetch")
59
+
60
+ @classmethod
61
+ def from_api_response(cls, data: Dict[str, Any]) -> "UserList":
62
+ """
63
+ Create a UserList instance from an API response.
64
+
65
+ Args:
66
+ data: API response data
67
+
68
+ Returns:
69
+ A UserList instance
70
+ """
71
+ return cls(
72
+ users=[User.from_api_response({"user": user}) for user in data["users"]],
73
+ total=data["total"],
74
+ has_more=data["has_more"],
75
+ )
recallrai/session.py ADDED
@@ -0,0 +1,169 @@
1
+ # Path: recallrai/session.py
2
+ # Description: Session management class for the RecallrAI SDK
3
+
4
+ """
5
+ Session management functionality for the RecallrAI SDK.
6
+ """
7
+
8
+ from typing import List
9
+ from .utils import HTTPClient, RecallrAIError
10
+ from .models import (
11
+ Context,
12
+ Message,
13
+ SessionStatus,
14
+ MessageRole
15
+ )
16
+ from logging import getLogger
17
+
18
+ logger = getLogger(__name__)
19
+
20
+ class Session:
21
+ """
22
+ Manages a conversation session with RecallrAI.
23
+
24
+ This class handles adding messages, retrieving context, and processing the session
25
+ to update the user's memory.
26
+ """
27
+
28
+ def __init__(
29
+ self,
30
+ http_client: HTTPClient,
31
+ user_id: str,
32
+ session_id: str,
33
+ ):
34
+ """
35
+ Initialize a session.
36
+
37
+ Args:
38
+ http_client: HTTP client for API communication
39
+ user_id: ID of the user who owns this session
40
+ session_id: Unique identifier for the session
41
+ """
42
+ self._http = http_client
43
+ self.user_id = user_id
44
+ self.session_id = session_id
45
+
46
+ def add_user_message(self, message: str) -> None:
47
+ """
48
+ Add a user message to the session.
49
+
50
+ Args:
51
+ message: Content of the user message
52
+
53
+ Raises:
54
+ BadRequestError: If the session is already processed
55
+ NotFoundError: If the session or user is not found
56
+ """
57
+ # Check the status of session
58
+ status = self.get_status()
59
+ if status == SessionStatus.PROCESSED:
60
+ raise RecallrAIError("Cannot add message to a session that has already been processed")
61
+ elif status == SessionStatus.PROCESSING:
62
+ raise RecallrAIError("Cannot add message to a session that is currently being processed")
63
+
64
+ # Add the user message
65
+ self._http.post(
66
+ f"/api/v1/users/{self.user_id}/sessions/{self.session_id}/add-message",
67
+ data={"message": message, "role": MessageRole.USER},
68
+ )
69
+
70
+ def add_assistant_message(self, message: str) -> None:
71
+ """
72
+ Add an assistant message to the session.
73
+
74
+ Args:
75
+ message: Content of the assistant message
76
+
77
+ Raises:
78
+ BadRequestError: If the session is already processed
79
+ NotFoundError: If the session or user is not found
80
+ """
81
+ # Check the status of session
82
+ status = self.get_status()
83
+ if status == SessionStatus.PROCESSED:
84
+ raise RecallrAIError("Cannot add message to a session that has already been processed")
85
+ elif status == SessionStatus.PROCESSING:
86
+ raise RecallrAIError("Cannot add message to a session that is currently being processed")
87
+
88
+ # Add the assistant message
89
+ self._http.post(
90
+ f"/api/v1/users/{self.user_id}/sessions/{self.session_id}/add-message",
91
+ data={"message": message, "role": MessageRole.ASSISTANT},
92
+ )
93
+
94
+ def get_context(self) -> Context:
95
+ """
96
+ Get the current context for this session.
97
+
98
+ The context contains information from the user's memory that is relevant
99
+ to the current conversation.
100
+
101
+ Returns:
102
+ Context information with the memory text and whether memory was used
103
+
104
+ Raises:
105
+ NotFoundError: If the session or user is not found
106
+ """
107
+ status = self.get_status()
108
+ if status == SessionStatus.PROCESSED:
109
+ logger.warning("Cannot add message to a session that has already been processed")
110
+ elif status == SessionStatus.PROCESSING:
111
+ logger.warning("Cannot add message to a session that is currently being processed")
112
+ response = self._http.get(
113
+ f"/api/v1/users/{self.user_id}/sessions/{self.session_id}/context"
114
+ )
115
+ return Context.from_api_response(response)
116
+
117
+ def process(self) -> None:
118
+ """
119
+ Process the session to update the user's memory.
120
+
121
+ This method triggers the processing of the conversation to extract and update
122
+ the user's memory.
123
+
124
+ Raises:
125
+ BadRequestError: If the session is already processed or being processed
126
+ NotFoundError: If the session or user is not found
127
+ SessionProcessingError: If there is an error during processing
128
+ """
129
+ # Check the status of session
130
+ status = self.get_status()
131
+ if status == SessionStatus.PROCESSED:
132
+ raise RecallrAIError("Cannot process a session that has already been processed")
133
+ elif status == SessionStatus.PROCESSING:
134
+ raise RecallrAIError("Cannot process a session that is currently being processed")
135
+
136
+ # Process the session
137
+ self._http.post(
138
+ f"/api/v1/users/{self.user_id}/sessions/{self.session_id}/process"
139
+ )
140
+
141
+ def get_status(self) -> SessionStatus:
142
+ """
143
+ Get the current status of the session.
144
+
145
+ Returns:
146
+ SessionStatus: The current status of the session
147
+
148
+ Raises:
149
+ NotFoundError: If the session or user is not found
150
+ """
151
+ response = self._http.get(
152
+ f"/api/v1/users/{self.user_id}/sessions/{self.session_id}/status"
153
+ )
154
+ return SessionStatus(response["status"])
155
+
156
+ def get_messages(self) -> List[Message]:
157
+ """
158
+ Get all messages in the session.
159
+
160
+ Returns:
161
+ List of messages in the session
162
+
163
+ Raises:
164
+ NotFoundError: If the session or user is not found
165
+ """
166
+ response = self._http.get(
167
+ f"/api/v1/users/{self.user_id}/sessions/{self.session_id}/messages"
168
+ )
169
+ return [Message(**msg) for msg in response["messages"]]
recallrai/user.py ADDED
@@ -0,0 +1,130 @@
1
+ """
2
+ User management functionality for the RecallrAI SDK.
3
+ """
4
+
5
+ from typing import Any, Dict, Optional
6
+ from .utils import HTTPClient
7
+ from .models import User as UserModel, SessionList
8
+ from .session import Session
9
+
10
+ class User:
11
+ """
12
+ Represents a user in the RecallrAI system with methods for user management.
13
+
14
+ This class wraps a user object and provides methods for updating user data,
15
+ and for creating and managing sessions.
16
+ """
17
+
18
+ def __init__(
19
+ self,
20
+ http_client: HTTPClient,
21
+ user_data: UserModel,
22
+ ):
23
+ """
24
+ Initialize a user.
25
+
26
+ Args:
27
+ http_client: HTTP client for API communication
28
+ user_data: User data model with user information
29
+ """
30
+ self._http = http_client
31
+ self._user_data = user_data
32
+ self.user_id = user_data.user_id
33
+ self.metadata = user_data.metadata
34
+ self.created_at = user_data.created_at
35
+ self.last_active_at = user_data.last_active_at
36
+
37
+ def update(self, new_metadata: Optional[Dict[str, Any]] = None, new_user_id: Optional[str] = None) -> 'User':
38
+ """
39
+ Update this user's metadata or ID.
40
+
41
+ Args:
42
+ new_metadata: New metadata to associate with the user
43
+ new_user_id: New ID for the user
44
+
45
+ Returns:
46
+ The updated user object
47
+
48
+ Raises:
49
+ NotFoundError: If the user is not found
50
+ ValidationError: If the new_user_id is invalid
51
+ BadRequestError: If a user with the new_user_id already exists
52
+ """
53
+ data = {}
54
+ if new_metadata is not None:
55
+ data["new_metadata"] = new_metadata
56
+ if new_user_id is not None:
57
+ data["new_user_id"] = new_user_id
58
+
59
+ response = self._http.put(f"/api/v1/users/{self.user_id}", data=data)
60
+ updated_data = UserModel.from_api_response(response)
61
+
62
+ # Update internal state
63
+ self._user_data = updated_data
64
+ self.user_id = updated_data.user_id
65
+ self.metadata = updated_data.metadata
66
+ self.last_active_at = updated_data.last_active_at
67
+
68
+ return self
69
+
70
+ def delete(self) -> None:
71
+ """
72
+ Delete this user.
73
+
74
+ Raises:
75
+ NotFoundError: If the user is not found
76
+ """
77
+ self._http.delete(f"/api/v1/users/{self.user_id}")
78
+
79
+ def create_session(self, auto_process_after_minutes: int = -1) -> Session:
80
+ """
81
+ Create a new session for this user.
82
+
83
+ Args:
84
+ auto_process_after_minutes: Minutes to wait before auto-processing (-1 to disable)
85
+
86
+ Returns:
87
+ A Session object to interact with the created session
88
+
89
+ Raises:
90
+ ValidationError: If auto_process_after_minutes is invalid
91
+ """
92
+ response = self._http.post(
93
+ f"/api/v1/users/{self.user_id}/sessions",
94
+ data={"auto_process_after_minutes": auto_process_after_minutes},
95
+ )
96
+
97
+ session_id = response["session_id"]
98
+ return Session(self._http, self.user_id, session_id)
99
+
100
+ def get_session(self, session_id: str) -> Session:
101
+ """
102
+ Get an existing session for this user.
103
+
104
+ Args:
105
+ session_id: ID of the session to retrieve
106
+
107
+ Returns:
108
+ A Session object to interact with the session
109
+
110
+ Raises:
111
+ NotFoundError: If the session is not found
112
+ """
113
+ return Session(self._http, self.user_id, session_id)
114
+
115
+ def list_sessions(self, offset: int = 0, limit: int = 10) -> SessionList:
116
+ """
117
+ List sessions for this user with pagination.
118
+
119
+ Args:
120
+ offset: Number of records to skip
121
+ limit: Maximum number of records to return
122
+
123
+ Returns:
124
+ List of sessions with pagination info
125
+ """
126
+ response = self._http.get(
127
+ f"/api/v1/users/{self.user_id}/sessions",
128
+ params={"offset": offset, "limit": limit},
129
+ )
130
+ return SessionList.from_api_response(response)
@@ -0,0 +1,10 @@
1
+ # Path: recallrai/utils/__init__.py
2
+ # Description: Package initialization for utilities
3
+
4
+ from .http import HTTPClient
5
+ from .exceptions import RecallrAIError
6
+
7
+ __all__ = [
8
+ "HTTPClient",
9
+ "RecallrAIError",
10
+ ]
@@ -0,0 +1,61 @@
1
+ # Path: recallrai/exceptions.py
2
+ # Description: Custom exceptions for the RecallrAI SDK
3
+
4
+ """
5
+ Custom exceptions for the RecallrAI SDK.
6
+ """
7
+
8
+ from typing import Any, Dict, Optional
9
+
10
+
11
+ class RecallrAIError(Exception):
12
+ """Base exception for all RecallrAI SDK errors."""
13
+
14
+ def __init__(self, message: str, code: Optional[str] = None, details: Optional[Dict[str, Any]] = None):
15
+ """
16
+ Initialize a RecallrAI error.
17
+
18
+ Args:
19
+ message: A human-readable error message
20
+ code: An optional error code
21
+ details: Optional additional details about the error
22
+ """
23
+ self.message = message
24
+ self.code = code
25
+ self.details = details or {}
26
+ super().__init__(self.message)
27
+
28
+
29
+ class AuthenticationError(RecallrAIError):
30
+ """Raised when there is an authentication issue with the API key or project ID."""
31
+ pass
32
+
33
+
34
+ class NotFoundError(RecallrAIError):
35
+ """Raised when a requested resource is not found."""
36
+ pass
37
+
38
+
39
+ class ValidationError(RecallrAIError):
40
+ """Raised when the API rejects a request due to validation errors."""
41
+ pass
42
+
43
+
44
+ class RateLimitError(RecallrAIError):
45
+ """Raised when the API rate limit has been exceeded."""
46
+ pass
47
+
48
+
49
+ class ServerError(RecallrAIError):
50
+ """Raised when the API encounters an unexpected server error."""
51
+ pass
52
+
53
+
54
+ class BadRequestError(RecallrAIError):
55
+ """Raised when the API rejects a request due to invalid parameters."""
56
+ pass
57
+
58
+
59
+ class SessionProcessingError(RecallrAIError):
60
+ """Raised when there is an error processing a session."""
61
+ pass
@@ -0,0 +1,167 @@
1
+ # Path: recallrai/utils/http.py
2
+ # Description: HTTP client utilities for the RecallrAI SDK
3
+
4
+ """
5
+ HTTP client utilities for making requests to the RecallrAI API.
6
+ """
7
+
8
+ import json
9
+ from typing import Any, Dict, Optional, Tuple, Union
10
+
11
+ import httpx
12
+
13
+ from .exceptions import (
14
+ AuthenticationError,
15
+ BadRequestError,
16
+ NotFoundError,
17
+ RateLimitError,
18
+ RecallrAIError,
19
+ ServerError,
20
+ ValidationError,
21
+ )
22
+
23
+ ACCEPTED_STATUS_CODES = [
24
+ 200, # OK
25
+ 201, # Created
26
+ 204, # No Content
27
+ ]
28
+
29
+ class HTTPClient:
30
+ """HTTP client for making requests to the RecallrAI API."""
31
+
32
+ def __init__(
33
+ self,
34
+ api_key: str,
35
+ project_id: str,
36
+ base_url: str,
37
+ timeout: int = 30,
38
+ ):
39
+ """
40
+ Initialize the HTTP client.
41
+
42
+ Args:
43
+ api_key: Your RecallrAI API key
44
+ project_id: Your project ID
45
+ base_url: The base URL for the RecallrAI API
46
+ timeout: Request timeout in seconds
47
+ """
48
+ self.api_key = api_key
49
+ self.project_id = project_id
50
+ self.base_url = base_url.rstrip("/")
51
+ self.timeout = timeout
52
+ self.client = httpx.Client(
53
+ timeout=self.timeout,
54
+ headers={
55
+ "X-Api-Key": self.api_key,
56
+ "X-Project-Id": self.project_id,
57
+ "Content-Type": "application/json",
58
+ "Accept": "application/json",
59
+ "User-Agent": "RecallrAI-Python-SDK",
60
+ # TODO: "SDK-Version": "0.1.0",
61
+ },
62
+ )
63
+
64
+ def _handle_response(self, response: httpx.Response) -> Dict[str, Any]:
65
+ """
66
+ Handle the HTTP response and raise appropriate exceptions for errors.
67
+
68
+ Args:
69
+ response: The HTTP response from the API
70
+
71
+ Returns:
72
+ The parsed JSON response body
73
+
74
+ Raises:
75
+ AuthenticationError: When the API key or project ID is invalid
76
+ NotFoundError: When the requested resource is not found
77
+ ValidationError: When the API rejects the request due to validation errors
78
+ RateLimitError: When the API rate limit has been exceeded
79
+ ServerError: When the API encounters an unexpected server error
80
+ RecallrAIError: For other types of errors
81
+ """
82
+ if response.status_code == 204:
83
+ return {}
84
+
85
+ try:
86
+ data = response.json() if response.content else {}
87
+ except json.JSONDecodeError:
88
+ data = {}
89
+
90
+ error_detail = data.get("detail", "Unknown error")
91
+
92
+ if response.status_code in ACCEPTED_STATUS_CODES:
93
+ return data
94
+ elif response.status_code == 400:
95
+ raise BadRequestError(message=f"Bad request: {error_detail}", details=data)
96
+ elif response.status_code == 401:
97
+ raise AuthenticationError(message="Invalid API key or project ID", details=data)
98
+ elif response.status_code == 404:
99
+ raise NotFoundError(message=f"Resource not found: {error_detail}", details=data)
100
+ elif response.status_code == 422:
101
+ raise ValidationError(message=f"Validation error: {error_detail}", details=data)
102
+ elif response.status_code == 429:
103
+ raise RateLimitError(message="API rate limit exceeded", details=data)
104
+ elif response.status_code >= 500:
105
+ raise ServerError(message=f"Server error: {error_detail}", details=data)
106
+ else:
107
+ raise RecallrAIError(
108
+ message=f"Unexpected error: {response.status_code} - {error_detail}",
109
+ details=data,
110
+ )
111
+
112
+ def request(
113
+ self,
114
+ method: str,
115
+ path: str,
116
+ params: Optional[Dict[str, Any]] = None,
117
+ data: Optional[Dict[str, Any]] = None,
118
+ ) -> Dict[str, Any]:
119
+ """
120
+ Make a request to the RecallrAI API.
121
+
122
+ Args:
123
+ method: HTTP method (GET, POST, PUT, DELETE)
124
+ path: API endpoint path
125
+ params: Query parameters
126
+ data: Request body data
127
+
128
+ Returns:
129
+ The parsed JSON response
130
+ """
131
+ url = f"{self.base_url}{path}"
132
+
133
+ # Filter out None values in params and data
134
+ if params:
135
+ params = {k: v for k, v in params.items() if v is not None}
136
+
137
+ if data:
138
+ data = {k: v for k, v in data.items() if v is not None}
139
+
140
+ try:
141
+ response = self.client.request(
142
+ method=method,
143
+ url=url,
144
+ params=params,
145
+ json=data,
146
+ )
147
+ return self._handle_response(response)
148
+ except httpx.HTTPError as e:
149
+ raise RecallrAIError(f"HTTP error: {str(e)}")
150
+ except Exception as e:
151
+ raise RecallrAIError(f"Unexpected error: {str(e)}")
152
+
153
+ def get(self, path: str, params: Optional[Dict[str, Any]] = None) -> Dict[str, Any]:
154
+ """Make a GET request."""
155
+ return self.request("GET", path, params=params)
156
+
157
+ def post(self, path: str, data: Optional[Dict[str, Any]] = None) -> Dict[str, Any]:
158
+ """Make a POST request."""
159
+ return self.request("POST", path, data=data)
160
+
161
+ def put(self, path: str, data: Optional[Dict[str, Any]] = None) -> Dict[str, Any]:
162
+ """Make a PUT request."""
163
+ return self.request("PUT", path, data=data)
164
+
165
+ def delete(self, path: str) -> Dict[str, Any]:
166
+ """Make a DELETE request."""
167
+ return self.request("DELETE", path)
@@ -0,0 +1,268 @@
1
+ Metadata-Version: 2.3
2
+ Name: recallrai
3
+ Version: 0.1.0
4
+ Summary: Official Python SDK for RecallrAI - Revolutionary contextual memory system that enables AI assistants to form meaningful connections between conversations, just like human memory.
5
+ License: MIT
6
+ Keywords: ai,memory,context,llm,mem0,getzep,zep
7
+ Author: Devasheesh Mishra
8
+ Author-email: devasheeshmishra4@gmail.com
9
+ Requires-Python: >=3.8,<4.0
10
+ Classifier: Intended Audience :: Developers
11
+ Classifier: License :: OSI Approved :: MIT License
12
+ Classifier: Operating System :: OS Independent
13
+ Classifier: Programming Language :: Python :: 3
14
+ Classifier: Programming Language :: Python :: 3.8
15
+ Classifier: Programming Language :: Python :: 3.9
16
+ Classifier: Programming Language :: Python :: 3.10
17
+ Classifier: Programming Language :: Python :: 3.11
18
+ Classifier: Programming Language :: Python :: 3.12
19
+ Classifier: Programming Language :: Python :: 3.13
20
+ Requires-Dist: httpx (>=0.25.0,<0.26.0)
21
+ Requires-Dist: pydantic (>=2.4.0,<3.0.0)
22
+ Project-URL: Homepage, https://recallrai.com
23
+ Project-URL: Repository, https://github.com/recallrai/sdk-python
24
+ Description-Content-Type: text/markdown
25
+
26
+ # RecallrAI Python SDK
27
+
28
+ Official Python SDK for RecallrAI – a revolutionary contextual memory system that enables AI assistants to form meaningful connections between conversations, just like human memory.
29
+
30
+ ## Installation
31
+
32
+ Install the SDK via Poetry or pip:
33
+
34
+ ```bash
35
+ poetry add recallrai
36
+ # or
37
+ pip install recallrai
38
+ ```
39
+
40
+ ## Initialization
41
+
42
+ Create a client instance with your API key and project ID:
43
+
44
+ ```python
45
+ from recallrai import RecallrAI
46
+
47
+ api_key = "rai_yourapikey"
48
+ project_id = "project-uuid"
49
+ client = RecallrAI(api_key=api_key, project_id=project_id)
50
+ ```
51
+
52
+ ## User Management
53
+
54
+ ### Create a User
55
+
56
+ ```python
57
+ from recallrai.user import User
58
+
59
+ user_id = "user123"
60
+ metadata = {"key": "value"}
61
+ user = client.create_user(user_id=user_id, metadata=metadata)
62
+ print("Created user:", user.user_id)
63
+ ```
64
+
65
+ ### Get a User
66
+
67
+ ```python
68
+ user = client.get_user("user123")
69
+ print("User metadata:", user.metadata)
70
+ ```
71
+
72
+ ### List Users
73
+
74
+ ```python
75
+ user_list = client.list_users(offset=0, limit=10)
76
+ for user in user_list.users:
77
+ print(user.user_id, user.metadata)
78
+ ```
79
+
80
+ ### Update a User
81
+
82
+ ```python
83
+ # Update the user's metadata and/or change the user ID
84
+ updated_user = client.update_user(user_id="user123", new_metadata={"role": "user"}, new_user_id="user1234")
85
+ print("Updated user id:", updated_user.user_id)
86
+ ```
87
+
88
+ ### Delete a User
89
+
90
+ ```python
91
+ client.delete_user("user1234")
92
+ print("User deleted.")
93
+ ```
94
+
95
+ ## Session Management
96
+
97
+ ### Create a Session
98
+
99
+ ```python
100
+ from recallrai.session import Session
101
+
102
+ # Create a session for a user; auto_process_after_minutes set to -1 disables auto-processing.
103
+ session = client.create_session(user_id="user123", auto_process_after_minutes=5)
104
+ print("Created session id:", session.session_id)
105
+ ```
106
+
107
+ ### Get an Existing Session
108
+
109
+ ```python
110
+ # Retrieve an existing session by its ID
111
+ session = client.get_session(user_id="user123", session_id="session-uuid")
112
+ print("Session status:", session.get_status())
113
+ ```
114
+
115
+ ### List Sessions
116
+
117
+ ```python
118
+ session_list = client.list_sessions(user_id="user123", offset=0, limit=10)
119
+ for session in session_list.sessions:
120
+ print(session.session_id, session.status)
121
+ ```
122
+
123
+ ### Session – Adding Messages
124
+
125
+ #### Add a User Message
126
+
127
+ ```python
128
+ session.add_user_message("Hello! How are you?")
129
+ ```
130
+
131
+ ### Session – Retrieving Context
132
+
133
+ ```python
134
+ context = session.get_context()
135
+ print("Memory used:", context.memory_used)
136
+ print("Context:", context.context)
137
+ ```
138
+
139
+ #### Add an Assistant Message
140
+
141
+ ```python
142
+ session.add_assistant_message("I'm an assistant. How can I help you?")
143
+ ```
144
+
145
+ ### Session – Process Session
146
+
147
+ ```python
148
+ session.process()
149
+ ```
150
+
151
+ ### Session – Get Status and Messages
152
+
153
+ ```python
154
+ status = session.get_status()
155
+ print("Session status:", status)
156
+
157
+ messages = session.get_messages()
158
+ for message in messages:
159
+ print(f"{message.role}: {message.content} at {message.timestamp}")
160
+ ```
161
+
162
+ ## Example Usage with LLMs
163
+
164
+ ```python
165
+ import openai
166
+ from recallrai import RecallrAI
167
+
168
+ # Initialize RecallrAI and OpenAI clients
169
+ recallrai_client = RecallrAI(api_key="rai_yourapikey", project_id="project-uuid")
170
+ openai_client = openai.OpenAI(api_key="your-openai-api-key")
171
+
172
+ def chat_with_memory(user_id, session_id=None):
173
+ # Get or create user
174
+ try:
175
+ user = recallrai_client.get_user(user_id)
176
+ except:
177
+ user = recallrai_client.create_user(user_id)
178
+
179
+ # Create a new session or get an existing one
180
+ if session_id:
181
+ session = recallrai_client.get_session(user_id=user_id, session_id=session_id)
182
+ else:
183
+ session = recallrai_client.create_session(user_id=user_id, auto_process_after_minutes=30)
184
+ print(f"Created new session: {session.session_id}")
185
+
186
+ print("Chat session started. Type 'exit' to end the conversation.")
187
+
188
+ while True:
189
+ # Get user input
190
+ user_message = input("You: ")
191
+ if user_message.lower() == 'exit':
192
+ break
193
+
194
+ # Add the user message to RecallrAI
195
+ session.add_user_message(user_message)
196
+
197
+ # Get context from RecallrAI after adding the user message
198
+ context = session.get_context()
199
+
200
+ # Create a system prompt that includes the context
201
+ system_prompt = f"""You are a helpful assistant with memory of previous conversations.
202
+
203
+ MEMORIES ABOUT THE USER:
204
+ {context.context}
205
+
206
+ You can use the above memories to provide better responses to the user.
207
+ Don't mention that you have access to memories unless you are explicitly asked."""
208
+
209
+ # Get previous messages
210
+ previous_messages = session.get_messages()
211
+ previous_messages = [{"role": message.role, "content": message.content} for message in previous_messages]
212
+
213
+ # Call the LLM with the system prompt and user message
214
+ response = openai_client.chat.completions.create(
215
+ model="gpt-4o-mini",
216
+ messages=[
217
+ {"role": "system", "content": system_prompt},
218
+ **previous_messages,
219
+ ],
220
+ temperature=0.7
221
+ )
222
+
223
+ assistant_message = response.choices[0].message.content
224
+
225
+ # Print the assistant's response
226
+ print(f"Assistant: {assistant_message}")
227
+
228
+ # Add the assistant's response to RecallrAI
229
+ session.add_assistant_message(assistant_message)
230
+
231
+ # Process the session at the end of the conversation
232
+ print("Processing session to update memory...")
233
+ session.process()
234
+ print(f"Session ended. Session ID: {session.session_id}")
235
+ return session.session_id
236
+
237
+ # Example usage
238
+ if __name__ == "__main__":
239
+ user_id = "user123"
240
+ # To continue a previous session, uncomment below and provide the session ID
241
+ # previous_session_id = "previously-saved-session-uuid"
242
+ # session_id = chat_with_memory(user_id, previous_session_id)
243
+
244
+ # Start a new session
245
+ session_id = chat_with_memory(user_id)
246
+ print(f"To continue this conversation later, use session ID: {session_id}")
247
+ ```
248
+
249
+ ## Exception Handling
250
+
251
+ > Exception handling will be improved in future.
252
+ Each operation may raise custom exceptions defined in the SDK:
253
+
254
+ ```python
255
+ from recallrai.utils.exceptions import NotFoundError, ValidationError
256
+
257
+ try:
258
+ user = client.get_user("nonexistent_id")
259
+ except NotFoundError as e:
260
+ print("User not found:", e.message)
261
+ except ValidationError as e:
262
+ print("Invalid input:", e.message)
263
+ ```
264
+
265
+ ## Conclusion
266
+
267
+ This README outlines the basic usage of the RecallrAI SDK functions for user and session management. For additional documentation and advanced usage, please see the [official documentation](https://recallrai.com) or the source code repository on [GitHub](https://github.com/recallrai/sdk-python).
268
+
@@ -0,0 +1,13 @@
1
+ recallrai/__init__.py,sha256=lw4pmQKtKkfTZ50xY3Z3J9IRxaG1XMrvEsN-jSazeHY,385
2
+ recallrai/client.py,sha256=lzD4DYL8kedr6P-9zJbf93CCt9PxmmHcSE2HzKBIU0w,6976
3
+ recallrai/models/__init__.py,sha256=2wwbyVAY4IgBn1a7YcbA4i1_pXJpYPYuQo80N8PVTlI,361
4
+ recallrai/models/session.py,sha256=Okn2tMmnl0UPL9q-Bl4cBaUcgs_U_nnvmKj3CHWavGY,3701
5
+ recallrai/models/user.py,sha256=yu7HzceZ-U2Hp6lbRjA31SQsyfD3dmuBoQ9dVGvfZ14,2190
6
+ recallrai/session.py,sha256=r045TL3a4_g0JjbCJ7VyRdhMX4JsUpVTDmMeeVwpGtY,5690
7
+ recallrai/user.py,sha256=VwQhKSJrwEEV7LgGDHOIRbIfwRi7OE5V-F146CGD8kY,4035
8
+ recallrai/utils/__init__.py,sha256=p_RBdfNvgBWQ62psiokCPCmZI5H7AQm8EJiRLxfHUjA,212
9
+ recallrai/utils/exceptions.py,sha256=b-8ONmtUgcjJxUg68pXwnana-5zt4C0cR2rTliFBGBE,1581
10
+ recallrai/utils/http.py,sha256=dGd4uUWtRDRBLZctNDNfdDr5njekMjCPBYSWcvKRpJM,5513
11
+ recallrai-0.1.0.dist-info/METADATA,sha256=WU87emxQgZ4t5p8k9ipp8MwbbwDLWDmzrWyYzY_-TJg,7801
12
+ recallrai-0.1.0.dist-info/WHEEL,sha256=XbeZDeTWKc1w7CSIyre5aMDU_-PohRwTQceYnisIYYY,88
13
+ recallrai-0.1.0.dist-info/RECORD,,
@@ -1,4 +1,4 @@
1
1
  Wheel-Version: 1.0
2
- Generator: poetry-core 2.0.0
2
+ Generator: poetry-core 2.1.1
3
3
  Root-Is-Purelib: true
4
4
  Tag: py3-none-any
recallrai/__main__.py DELETED
File without changes
@@ -1,17 +0,0 @@
1
- Metadata-Version: 2.3
2
- Name: recallrai
3
- Version: 0.0.1
4
- Summary: Comming soon
5
- License: MIT
6
- Author: Devasheesh Mishra
7
- Author-email: devasheeshmishra4@gmail.com
8
- Requires-Python: >=3.10,<4.0
9
- Classifier: License :: OSI Approved :: MIT License
10
- Classifier: Programming Language :: Python :: 3
11
- Classifier: Programming Language :: Python :: 3.10
12
- Classifier: Programming Language :: Python :: 3.11
13
- Classifier: Programming Language :: Python :: 3.12
14
- Classifier: Programming Language :: Python :: 3.13
15
- Description-Content-Type: text/markdown
16
-
17
- Comming soon...
@@ -1,5 +0,0 @@
1
- recallrai/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
2
- recallrai/__main__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
3
- recallrai-0.0.1.dist-info/METADATA,sha256=SBCR1N69hXrhhNh6qZ2T9qO8ZyXBd8chEXPUNCiCZio,545
4
- recallrai-0.0.1.dist-info/WHEEL,sha256=RaoafKOydTQ7I_I3JTrPCg6kUmTgtm4BornzOqyEfJ8,88
5
- recallrai-0.0.1.dist-info/RECORD,,