recallrai 0.2.0__py3-none-any.whl → 0.3.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/models/user.py CHANGED
@@ -3,17 +3,20 @@ User-related data models for the RecallrAI SDK.
3
3
  """
4
4
 
5
5
  from datetime import datetime
6
- from typing import Any, Dict
6
+ from typing import TYPE_CHECKING, Any, Dict, List, Optional
7
7
  from pydantic import BaseModel, Field
8
+ from ..utils import HTTPClient
9
+ if TYPE_CHECKING:
10
+ from ..user import User
8
11
 
9
12
 
10
13
  class UserModel(BaseModel):
11
14
  """Represents a user in the RecallrAI system."""
12
15
 
13
- user_id: str = Field(..., description="Unique identifier for the user")
14
- metadata: Dict[str, Any] = Field(default_factory=dict, description="Custom metadata for the user")
15
- created_at: datetime = Field(..., description="When the user was created")
16
- last_active_at: datetime = Field(..., description="When the user was last active")
16
+ user_id: str = Field(..., description="Unique identifier for the user.")
17
+ metadata: Dict[str, Any] = Field(..., description="Custom metadata for the user.")
18
+ created_at: datetime = Field(..., description="When the user was created.")
19
+ last_active_at: datetime = Field(..., description="When the user was last active.")
17
20
 
18
21
  class Config:
19
22
  """Pydantic configuration."""
@@ -28,16 +31,16 @@ class UserModel(BaseModel):
28
31
  Create a UserModel instance from an API response.
29
32
 
30
33
  Args:
31
- data: API response data
34
+ data: API response data.
32
35
 
33
36
  Returns:
34
- A UserModel instance
37
+ A UserModel instance.
35
38
  """
36
39
  if "user" in data:
37
40
  user_data = data["user"]
38
41
  else:
39
42
  user_data = data
40
-
43
+
41
44
  return cls(
42
45
  user_id=user_data["user_id"],
43
46
  metadata=user_data.get("metadata", {}),
@@ -48,24 +51,140 @@ class UserModel(BaseModel):
48
51
 
49
52
  class UserList(BaseModel):
50
53
  """Represents a paginated list of users."""
51
-
52
- users: list[UserModel] = Field(..., description="List of users")
53
- total: int = Field(..., description="Total number of users")
54
- has_more: bool = Field(..., description="Whether there are more users to fetch")
54
+
55
+ users: List["User"] = Field(..., description="List of users.")
56
+ total: int = Field(..., description="Total number of users.")
57
+ has_more: bool = Field(..., description="Whether there are more users to fetch.")
58
+
59
+ class Config:
60
+ arbitrary_types_allowed = True
55
61
 
56
62
  @classmethod
57
- def from_api_response(cls, data: Dict[str, Any]) -> "UserList":
63
+ def from_api_response(cls, data: Dict[str, Any], http_client: HTTPClient) -> "UserList":
58
64
  """
59
65
  Create a UserList instance from an API response.
60
66
 
61
67
  Args:
62
- data: API response data
68
+ data: API response data.
63
69
 
64
70
  Returns:
65
- A UserList instance
71
+ A UserList instance.
66
72
  """
73
+ from ..user import User
67
74
  return cls(
68
- users=[UserModel.from_api_response({"user": user}) for user in data["users"]],
75
+ users=[
76
+ User(http_client, UserModel.from_api_response(user)) for user in data["users"]
77
+ ],
69
78
  total=data["total"],
70
79
  has_more=data["has_more"],
71
80
  )
81
+
82
+
83
+ class MemoryVersionInfo(BaseModel):
84
+ """Information about a specific version of a memory."""
85
+
86
+ version_number: int = Field(..., description="Version number (1 = oldest, N = current)")
87
+ content: str = Field(..., description="Content of this version")
88
+ created_at: datetime = Field(..., description="When this version was created")
89
+ expired_at: datetime = Field(..., description="When this version expired")
90
+ expiration_reason: str = Field(..., description="Why this version expired (NewMemoryVersionCreationReason enum)")
91
+
92
+ class Config:
93
+ frozen = True
94
+ json_encoders = {
95
+ datetime: lambda dt: dt.isoformat()
96
+ }
97
+
98
+
99
+ class MemoryRelationship(BaseModel):
100
+ """Connected memory information."""
101
+
102
+ memory_id: str = Field(..., description="ID of the connected memory")
103
+ content: str = Field(..., description="Brief content for context")
104
+
105
+ class Config:
106
+ frozen = True
107
+
108
+
109
+ class UserMemoryItem(BaseModel):
110
+ """Complete memory information with all metadata."""
111
+
112
+ memory_id: str = Field(..., description="ID of the current/latest version")
113
+ categories: List[str] = Field(..., description="Memory categories")
114
+ content: str = Field(..., description="Current version content")
115
+ created_at: datetime = Field(..., description="When the latest version was created")
116
+
117
+ # Version information
118
+ version_number: int = Field(..., description="Which version this is (e.g., 3 means 3rd version)")
119
+ total_versions: int = Field(..., description="How many versions exist total")
120
+ has_previous_versions: bool = Field(..., description="If total_versions > 1")
121
+
122
+ # Version history (only if requested)
123
+ previous_versions: Optional[List[MemoryVersionInfo]] = Field(None, description="Memories connected via prev_version_id")
124
+
125
+ # Relationships (only if requested)
126
+ connected_memories: Optional[List[MemoryRelationship]] = Field(None, description="Memories connected via ProjectUserMemoryConnections")
127
+
128
+ # Merge conflict info
129
+ merge_conflict_in_progress: bool = Field(..., description="Whether a merge conflict is in progress")
130
+
131
+ # Session info
132
+ session_id: str = Field(..., description="Which session created this version")
133
+
134
+ class Config:
135
+ frozen = True
136
+ json_encoders = {
137
+ datetime: lambda dt: dt.isoformat()
138
+ }
139
+
140
+
141
+ class UserMemoriesList(BaseModel):
142
+ """Represents a paginated list of user memories."""
143
+
144
+ items: List[UserMemoryItem]
145
+ total: int
146
+ has_more: bool
147
+
148
+ @classmethod
149
+ def from_api_response(cls, data: Dict[str, Any]) -> "UserMemoriesList":
150
+ return cls(
151
+ items=[UserMemoryItem(**item) for item in data["items"]],
152
+ total=data["total"],
153
+ has_more=data["has_more"],
154
+ )
155
+
156
+
157
+ class UserMessage(BaseModel):
158
+ """Represents a single message from a user's conversation history."""
159
+
160
+ role: str = Field(..., description="Role of the message sender (user or assistant).")
161
+ content: str = Field(..., description="Content of the message.")
162
+ timestamp: datetime = Field(..., description="When the message was sent.")
163
+ session_id: str = Field(..., description="ID of the session this message belongs to.")
164
+
165
+ class Config:
166
+ frozen = True
167
+ json_encoders = {
168
+ datetime: lambda dt: dt.isoformat()
169
+ }
170
+
171
+
172
+ class UserMessagesList(BaseModel):
173
+ """Represents a list of user messages."""
174
+
175
+ messages: List[UserMessage] = Field(..., description="List of user messages.")
176
+
177
+ @classmethod
178
+ def from_api_response(cls, data: Dict[str, Any]) -> "UserMessagesList":
179
+ """
180
+ Create a UserMessagesList instance from an API response.
181
+
182
+ Args:
183
+ data: API response data.
184
+
185
+ Returns:
186
+ A UserMessagesList instance.
187
+ """
188
+ return cls(
189
+ messages=[UserMessage(**message) for message in data["messages"]]
190
+ )
recallrai/session.py CHANGED
@@ -2,13 +2,15 @@
2
2
  Session management functionality for the RecallrAI SDK.
3
3
  """
4
4
 
5
- from typing import List
5
+ from typing import Optional, Dict, Any
6
6
  from .utils import HTTPClient
7
7
  from .models import (
8
8
  Context,
9
- Message,
9
+ SessionMessagesList,
10
+ SessionModel,
10
11
  SessionStatus,
11
- MessageRole
12
+ MessageRole,
13
+ RecallStrategy,
12
14
  )
13
15
  from .exceptions import (
14
16
  UserNotFoundError,
@@ -32,245 +34,293 @@ class Session:
32
34
  self,
33
35
  http_client: HTTPClient,
34
36
  user_id: str,
35
- session_id: str,
37
+ session_data: SessionModel,
36
38
  ):
37
39
  """
38
40
  Initialize a session.
39
41
 
40
42
  Args:
41
- http_client: HTTP client for API communication
42
- user_id: ID of the user who owns this session
43
- session_id: Unique identifier for the session
43
+ http_client: HTTP client for API communication.
44
+ user_id: ID of the user who owns this session.
45
+ session_data: Initial session data from the API.
44
46
  """
45
47
  self._http = http_client
46
- self.user_id = user_id
47
- self.session_id = session_id
48
+ self._user_id = user_id
49
+ self._session_data = session_data
50
+ self.session_id = self._session_data.session_id
51
+ self.status = self._session_data.status
52
+ self.created_at = self._session_data.created_at
53
+ self.metadata = self._session_data.metadata
48
54
 
49
- def add_user_message(self, message: str) -> None:
55
+ def add_message(self, role: MessageRole, content: str) -> None:
50
56
  """
51
- Add a user message to the session.
52
-
53
- Args:
54
- message: Content of the user message
55
-
56
- Raises:
57
- UserNotFoundError: If the user is not found
58
- SessionNotFoundError: If the session is not found
59
- InvalidSessionStateError: If the session is already processed or processing
60
- AuthenticationError: If the API key or project ID is invalid
61
- InternalServerError: If the server encounters an error
62
- NetworkError: If there are network issues
63
- TimeoutError: If the request times out
64
- RecallrAIError: For other API-related errors
65
- """
66
- self._add_message(message, MessageRole.USER)
67
-
68
- def add_assistant_message(self, message: str) -> None:
69
- """
70
- Add an assistant message to the session.
57
+ Internal helper to add a message to the session.
71
58
 
72
59
  Args:
73
- message: Content of the assistant message
60
+ role: Role of the message sender.
61
+ content: Content of the message.
74
62
 
75
63
  Raises:
76
- UserNotFoundError: If the user is not found
77
- SessionNotFoundError: If the session is not found
78
- InvalidSessionStateError: If the session is already processed or processing
79
- AuthenticationError: If the API key or project ID is invalid
80
- InternalServerError: If the server encounters an error
81
- NetworkError: If there are network issues
82
- TimeoutError: If the request times out
83
- RecallrAIError: For other API-related errors
84
- """
85
- self._add_message(message, MessageRole.ASSISTANT)
86
-
87
- def _add_message(self, message: str, role: MessageRole) -> None:
88
- """
89
- Internal helper to add a message to the session.
90
-
91
- Args:
92
- message: Content of the message
93
- role: Role of the message sender
94
-
95
- Raises:
96
- UserNotFoundError: If the user is not found
97
- SessionNotFoundError: If the session is not found
98
- InvalidSessionStateError: If the session is already processed or processing
99
- AuthenticationError: If the API key or project ID is invalid
100
- InternalServerError: If the server encounters an error
101
- NetworkError: If there are network issues
102
- TimeoutError: If the request times out
103
- RecallrAIError: For other API-related errors
64
+ UserNotFoundError: If the user is not found.
65
+ SessionNotFoundError: If the session is not found.
66
+ InvalidSessionStateError: If the session is already processed or processing.
67
+ AuthenticationError: If the API key or project ID is invalid.
68
+ InternalServerError: If the server encounters an error.
69
+ NetworkError: If there are network issues.
70
+ TimeoutError: If the request times out.
71
+ RecallrAIError: For other API-related errors.
104
72
  """
105
73
  response = self._http.post(
106
- f"/api/v1/users/{self.user_id}/sessions/{self.session_id}/add-message",
107
- data={"message": message, "role": role.value},
74
+ f"/api/v1/users/{self._user_id}/sessions/{self.session_id}/add-message",
75
+ data={"message": content, "role": role.value},
108
76
  )
109
-
77
+
110
78
  if response.status_code == 404:
111
79
  # Check if it's a user not found or session not found error
112
80
  detail = response.json().get('detail', '')
113
- if f"User {self.user_id} not found" in detail:
114
- raise UserNotFoundError(user_id=self.user_id)
81
+ if f"User {self._user_id} not found" in detail:
82
+ raise UserNotFoundError(message=detail, http_status=response.status_code)
115
83
  else:
116
- raise SessionNotFoundError(session_id=self.session_id)
84
+ raise SessionNotFoundError(message=detail, http_status=response.status_code)
117
85
  elif response.status_code == 400:
86
+ detail = response.json().get('detail', f"Cannot add message to session with status {self.status}")
118
87
  raise InvalidSessionStateError(
119
- message=f"Cannot add message to session with status {self.get_status()}",
88
+ message=detail,
89
+ http_status=response.status_code
120
90
  )
121
91
  elif response.status_code != 200:
122
92
  raise RecallrAIError(
123
- message=f"Failed to add message: {response.json().get('detail', 'Unknown error')}",
93
+ message=response.json().get('detail', 'Unknown error'),
124
94
  http_status=response.status_code
125
95
  )
126
96
 
127
- def get_context(self) -> Context:
97
+ def get_context(
98
+ self,
99
+ recall_strategy: RecallStrategy = RecallStrategy.BALANCED,
100
+ min_top_k: int = 15,
101
+ max_top_k: int = 50,
102
+ memories_threshold: float = 0.6,
103
+ summaries_threshold: float = 0.5,
104
+ last_n_messages: Optional[int] = None,
105
+ last_n_summaries: Optional[int] = None,
106
+ timezone: Optional[str] = None
107
+ ) -> Context:
128
108
  """
129
109
  Get the current context for this session.
130
110
 
131
- The context contains information from the user's memory that is relevant
132
- to the current conversation.
111
+ Args:
112
+ recall_strategy: The type of recall strategy to use.
113
+ min_top_k: Minimum number of memories to return.
114
+ max_top_k: Maximum number of memories to return.
115
+ memories_threshold: Similarity threshold for memories.
116
+ summaries_threshold: Similarity threshold for summaries.
117
+ last_n_messages: Number of last messages to include in context.
118
+ last_n_summaries: Number of last summaries to include in context.
119
+ timezone: Timezone for formatting timestamps (e.g., 'America/New_York'). None for UTC.
133
120
 
134
121
  Returns:
135
- Context information with the memory text and whether memory was used
122
+ Context information with the memory text and whether memory was used.
136
123
 
137
124
  Raises:
138
- UserNotFoundError: If the user is not found
139
- SessionNotFoundError: If the session is not found
140
- AuthenticationError: If the API key or project ID is invalid
141
- InternalServerError: If the server encounters an error
142
- NetworkError: If there are network issues
143
- TimeoutError: If the request times out
144
- RecallrAIError: For other API-related errors
125
+ UserNotFoundError: If the user is not found.
126
+ SessionNotFoundError: If the session is not found.
127
+ AuthenticationError: If the API key or project ID is invalid.
128
+ InternalServerError: If the server encounters an error.
129
+ NetworkError: If there are network issues.
130
+ TimeoutError: If the request times out.
131
+ RecallrAIError: For other API-related errors.
145
132
  """
133
+ params = {
134
+ "recall_strategy": recall_strategy.value,
135
+ "min_top_k": min_top_k,
136
+ "max_top_k": max_top_k,
137
+ "memories_threshold": memories_threshold,
138
+ "summaries_threshold": summaries_threshold,
139
+ }
140
+ if last_n_messages is not None:
141
+ params["last_n_messages"] = last_n_messages
142
+ if last_n_summaries is not None:
143
+ params["last_n_summaries"] = last_n_summaries
144
+ if timezone is not None:
145
+ params["timezone"] = timezone
146
+
146
147
  response = self._http.get(
147
- f"/api/v1/users/{self.user_id}/sessions/{self.session_id}/context"
148
+ f"/api/v1/users/{self._user_id}/sessions/{self.session_id}/context",
149
+ params=params,
148
150
  )
149
-
151
+
150
152
  if response.status_code == 404:
151
153
  # Check if it's a user not found or session not found error
152
154
  detail = response.json().get('detail', '')
153
- if f"User {self.user_id} not found" in detail:
154
- raise UserNotFoundError(user_id=self.user_id)
155
+ if f"User {self._user_id} not found" in detail:
156
+ raise UserNotFoundError(message=detail, http_status=response.status_code)
155
157
  else:
156
- raise SessionNotFoundError(session_id=self.session_id)
158
+ raise SessionNotFoundError(message=detail, http_status=response.status_code)
157
159
  elif response.status_code != 200:
158
160
  raise RecallrAIError(
159
- message=f"Failed to get context: {response.json().get('detail', 'Unknown error')}",
161
+ message=response.json().get('detail', 'Unknown error'),
160
162
  http_status=response.status_code
161
163
  )
162
- status = self.get_status()
163
- if status == SessionStatus.PROCESSED:
164
+ if self.status == SessionStatus.PROCESSED:
164
165
  logger.warning("You are trying to get context for a processed session. Why do you need it?")
165
- elif status == SessionStatus.PROCESSING:
166
+ elif self.status == SessionStatus.PROCESSING:
166
167
  logger.warning("You are trying to get context for a processing session. Why do you need it?")
167
168
  return Context.from_api_response(response.json())
168
169
 
169
- def process(self) -> None:
170
+ def update(self, new_metadata: Optional[Dict[str, Any]] = None) -> None:
170
171
  """
171
- Process the session to update the user's memory.
172
+ Update the session's metadata.
172
173
 
173
- This method triggers the processing of the conversation to extract and update
174
- the user's memory.
174
+ Args:
175
+ new_metadata: New metadata to associate with the session.
175
176
 
176
177
  Raises:
177
- UserNotFoundError: If the user is not found
178
- SessionNotFoundError: If the session is not found
179
- InvalidSessionStateError: If the session is already processed or being processed
180
- AuthenticationError: If the API key or project ID is invalid
181
- InternalServerError: If the server encounters an error
182
- NetworkError: If there are network issues
183
- TimeoutError: If the request times out
184
- RecallrAIError: For other API-related errors
178
+ UserNotFoundError: If the user is not found.
179
+ SessionNotFoundError: If the session is not found.
180
+ AuthenticationError: If the API key or project ID is invalid.
181
+ InternalServerError: If the server encounters an error.
182
+ NetworkError: If there are network issues.
183
+ TimeoutError: If the request times out.
184
+ RecallrAIError: For other API-related errors.
185
185
  """
186
- response = self._http.post(
187
- f"/api/v1/users/{self.user_id}/sessions/{self.session_id}/process"
186
+ response = self._http.put(
187
+ f"/api/v1/users/{self._user_id}/sessions/{self.session_id}",
188
+ data={"new_metadata": new_metadata},
188
189
  )
189
-
190
+
190
191
  if response.status_code == 404:
191
192
  # Check if it's a user not found or session not found error
192
193
  detail = response.json().get('detail', '')
193
- if f"User {self.user_id} not found" in detail:
194
- raise UserNotFoundError(user_id=self.user_id)
194
+ if f"User {self._user_id} not found" in detail:
195
+ raise UserNotFoundError(message=detail, http_status=response.status_code)
195
196
  else:
196
- raise SessionNotFoundError(session_id=self.session_id)
197
- elif response.status_code == 400:
198
- raise InvalidSessionStateError(
199
- message=f"{response.json().get('detail', f'Cannot process session with status {self.get_status()}')}",
200
- )
197
+ raise SessionNotFoundError(message=detail, http_status=response.status_code)
201
198
  elif response.status_code != 200:
202
199
  raise RecallrAIError(
203
- message=f"Failed to process session: {response.json().get('detail', 'Unknown error')}",
200
+ message=response.json().get('detail', 'Unknown error'),
204
201
  http_status=response.status_code
205
202
  )
203
+
204
+ updated_data = SessionModel.from_api_response(response.json())
205
+ self.metadata = updated_data.metadata
206
206
 
207
- def get_status(self) -> SessionStatus:
207
+ def refresh(self) -> None:
208
208
  """
209
- Get the current status of the session.
209
+ Refresh the session data from the API.
210
210
 
211
- Returns:
212
- SessionStatus: The current status of the session
211
+ This method updates the local session data to reflect any changes
212
+ that may have occurred on the server.
213
213
 
214
214
  Raises:
215
- UserNotFoundError: If the user is not found
216
- SessionNotFoundError: If the session is not found
217
- AuthenticationError: If the API key or project ID is invalid
218
- InternalServerError: If the server encounters an error
219
- NetworkError: If there are network issues
220
- TimeoutError: If the request times out
221
- RecallrAIError: For other API-related errors
215
+ UserNotFoundError: If the user is not found.
216
+ SessionNotFoundError: If the session is not found.
217
+ AuthenticationError: If the API key or project ID is invalid.
218
+ InternalServerError: If the server encounters an error.
219
+ NetworkError: If there are network issues.
220
+ TimeoutError: If the request times out.
221
+ RecallrAIError: For other API-related errors.
222
222
  """
223
223
  response = self._http.get(
224
- f"/api/v1/users/{self.user_id}/sessions/{self.session_id}/status"
224
+ f"/api/v1/users/{self._user_id}/sessions/{self.session_id}"
225
+ )
226
+
227
+ if response.status_code == 404:
228
+ # Check if it's a user not found or session not found error
229
+ detail = response.json().get('detail', '')
230
+ if f"User {self._user_id} not found" in detail:
231
+ raise UserNotFoundError(message=detail, http_status=response.status_code)
232
+ else:
233
+ raise SessionNotFoundError(message=detail, http_status=response.status_code)
234
+ elif response.status_code != 200:
235
+ raise RecallrAIError(
236
+ message=response.json().get('detail', 'Unknown error'),
237
+ http_status=response.status_code
238
+ )
239
+
240
+ self._session_data = SessionModel.from_api_response(response.json())
241
+ self.status = self._session_data.status
242
+ self.created_at = self._session_data.created_at
243
+ self.metadata = self._session_data.metadata
244
+
245
+ def process(self) -> None:
246
+ """
247
+ Process the session to update the user's memory.
248
+
249
+ This method triggers the processing of the conversation to extract and update
250
+ the user's memory.
251
+
252
+ Raises:
253
+ UserNotFoundError: If the user is not found.
254
+ SessionNotFoundError: If the session is not found.
255
+ InvalidSessionStateError: If the session is already processed or being processed.
256
+ AuthenticationError: If the API key or project ID is invalid.
257
+ InternalServerError: If the server encounters an error.
258
+ NetworkError: If there are network issues.
259
+ TimeoutError: If the request times out.
260
+ RecallrAIError: For other API-related errors.
261
+ """
262
+ response = self._http.post(
263
+ f"/api/v1/users/{self._user_id}/sessions/{self.session_id}/process"
225
264
  )
226
265
 
227
266
  if response.status_code == 404:
228
267
  # Check if it's a user not found or session not found error
229
268
  detail = response.json().get('detail', '')
230
- if f"User {self.user_id} not found" in detail:
231
- raise UserNotFoundError(user_id=self.user_id)
269
+ if f"User {self._user_id} not found" in detail:
270
+ raise UserNotFoundError(message=detail, http_status=response.status_code)
232
271
  else:
233
- raise SessionNotFoundError(session_id=self.session_id)
272
+ raise SessionNotFoundError(message=detail, http_status=response.status_code)
273
+ elif response.status_code == 400:
274
+ detail = response.json().get('detail', f'Cannot process session with status {self.status}')
275
+ raise InvalidSessionStateError(
276
+ message=detail,
277
+ http_status=response.status_code
278
+ )
234
279
  elif response.status_code != 200:
235
280
  raise RecallrAIError(
236
- message=f"Failed to get session status: {response.json().get('detail', 'Unknown error')}",
281
+ message=response.json().get('detail', 'Unknown error'),
237
282
  http_status=response.status_code
238
283
  )
239
-
240
- return SessionStatus(response.json()["status"])
241
284
 
242
- def get_messages(self) -> List[Message]:
285
+ def get_messages(
286
+ self,
287
+ offset: int = 0,
288
+ limit: int = 50,
289
+ ) -> SessionMessagesList:
243
290
  """
244
291
  Get all messages in the session.
245
292
 
246
293
  Returns:
247
- List of messages in the session
294
+ Paginated list of messages in the session.
248
295
 
249
296
  Raises:
250
- UserNotFoundError: If the user is not found
251
- SessionNotFoundError: If the session is not found
252
- AuthenticationError: If the API key or project ID is invalid
253
- InternalServerError: If the server encounters an error
254
- NetworkError: If there are network issues
255
- TimeoutError: If the request times out
256
- RecallrAIError: For other API-related errors
297
+ UserNotFoundError: If the user is not found.
298
+ SessionNotFoundError: If the session is not found.
299
+ AuthenticationError: If the API key or project ID is invalid.
300
+ InternalServerError: If the server encounters an error.
301
+ NetworkError: If there are network issues.
302
+ TimeoutError: If the request times out.
303
+ RecallrAIError: For other API-related errors.
257
304
  """
258
305
  response = self._http.get(
259
- f"/api/v1/users/{self.user_id}/sessions/{self.session_id}/messages"
306
+ f"/api/v1/users/{self._user_id}/sessions/{self.session_id}/messages",
307
+ params={"offset": offset, "limit": limit},
260
308
  )
261
309
 
262
310
  if response.status_code == 404:
263
311
  # Check if it's a user not found or session not found error
264
312
  detail = response.json().get('detail', '')
265
- if f"User {self.user_id} not found" in detail:
266
- raise UserNotFoundError(user_id=self.user_id)
313
+ if f"User {self._user_id} not found" in detail:
314
+ raise UserNotFoundError(message=detail, http_status=response.status_code)
267
315
  else:
268
- raise SessionNotFoundError(session_id=self.session_id)
316
+ raise SessionNotFoundError(message=detail, http_status=response.status_code)
269
317
  elif response.status_code != 200:
270
318
  raise RecallrAIError(
271
- message=f"Failed to get messages: {response.json().get('detail', 'Unknown error')}",
319
+ message=response.json().get('detail', 'Unknown error'),
272
320
  http_status=response.status_code
273
321
  )
274
-
275
- data = response.json()
276
- return [Message(**msg) for msg in data["messages"]]
322
+
323
+ return SessionMessagesList.from_api_response(response.json())
324
+
325
+ def __repr__(self) -> str:
326
+ return f"<Session id={self.session_id} user_id={self._user_id} status={self.status}>"