recallrai 0.1.1__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
@@ -1,23 +1,22 @@
1
- # Path: recallrai/models/user.py
2
- # Description: User data models for the RecallrAI SDK
3
-
4
1
  """
5
2
  User-related data models for the RecallrAI SDK.
6
3
  """
7
4
 
8
5
  from datetime import datetime
9
- from typing import Any, Dict
10
-
6
+ from typing import TYPE_CHECKING, Any, Dict, List, Optional
11
7
  from pydantic import BaseModel, Field
8
+ from ..utils import HTTPClient
9
+ if TYPE_CHECKING:
10
+ from ..user import User
12
11
 
13
12
 
14
- class User(BaseModel):
13
+ class UserModel(BaseModel):
15
14
  """Represents a user in the RecallrAI system."""
16
15
 
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")
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.")
21
20
 
22
21
  class Config:
23
22
  """Pydantic configuration."""
@@ -27,21 +26,21 @@ class User(BaseModel):
27
26
  }
28
27
 
29
28
  @classmethod
30
- def from_api_response(cls, data: Dict[str, Any]) -> "User":
29
+ def from_api_response(cls, data: Dict[str, Any]) -> "UserModel":
31
30
  """
32
- Create a User instance from an API response.
31
+ Create a UserModel instance from an API response.
33
32
 
34
33
  Args:
35
- data: API response data
34
+ data: API response data.
36
35
 
37
36
  Returns:
38
- A User instance
37
+ A UserModel instance.
39
38
  """
40
39
  if "user" in data:
41
40
  user_data = data["user"]
42
41
  else:
43
42
  user_data = data
44
-
43
+
45
44
  return cls(
46
45
  user_id=user_data["user_id"],
47
46
  metadata=user_data.get("metadata", {}),
@@ -52,24 +51,140 @@ class User(BaseModel):
52
51
 
53
52
  class UserList(BaseModel):
54
53
  """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")
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
59
61
 
60
62
  @classmethod
61
- def from_api_response(cls, data: Dict[str, Any]) -> "UserList":
63
+ def from_api_response(cls, data: Dict[str, Any], http_client: HTTPClient) -> "UserList":
62
64
  """
63
65
  Create a UserList instance from an API response.
64
66
 
65
67
  Args:
66
- data: API response data
68
+ data: API response data.
67
69
 
68
70
  Returns:
69
- A UserList instance
71
+ A UserList instance.
70
72
  """
73
+ from ..user import User
71
74
  return cls(
72
- users=[User.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
+ ],
73
78
  total=data["total"],
74
79
  has_more=data["has_more"],
75
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
@@ -1,17 +1,16 @@
1
- # Path: recallrai/session.py
2
- # Description: Session management class for the RecallrAI SDK
3
-
4
1
  """
5
2
  Session management functionality for the RecallrAI SDK.
6
3
  """
7
4
 
8
- from typing import List
5
+ from typing import Optional, Dict, Any
9
6
  from .utils import HTTPClient
10
7
  from .models import (
11
8
  Context,
12
- Message,
9
+ SessionMessagesList,
10
+ SessionModel,
13
11
  SessionStatus,
14
- MessageRole
12
+ MessageRole,
13
+ RecallStrategy,
15
14
  )
16
15
  from .exceptions import (
17
16
  UserNotFoundError,
@@ -35,245 +34,293 @@ class Session:
35
34
  self,
36
35
  http_client: HTTPClient,
37
36
  user_id: str,
38
- session_id: str,
37
+ session_data: SessionModel,
39
38
  ):
40
39
  """
41
40
  Initialize a session.
42
41
 
43
42
  Args:
44
- http_client: HTTP client for API communication
45
- user_id: ID of the user who owns this session
46
- 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.
47
46
  """
48
47
  self._http = http_client
49
- self.user_id = user_id
50
- 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
51
54
 
52
- def add_user_message(self, message: str) -> None:
55
+ def add_message(self, role: MessageRole, content: str) -> None:
53
56
  """
54
- Add a user message to the session.
55
-
56
- Args:
57
- message: Content of the user message
58
-
59
- Raises:
60
- UserNotFoundError: If the user is not found
61
- SessionNotFoundError: If the session is not found
62
- InvalidSessionStateError: If the session is already processed or processing
63
- AuthenticationError: If the API key or project ID is invalid
64
- InternalServerError: If the server encounters an error
65
- NetworkError: If there are network issues
66
- TimeoutError: If the request times out
67
- RecallrAIError: For other API-related errors
68
- """
69
- self._add_message(message, MessageRole.USER)
70
-
71
- def add_assistant_message(self, message: str) -> None:
72
- """
73
- Add an assistant message to the session.
57
+ Internal helper to add a message to the session.
74
58
 
75
59
  Args:
76
- message: Content of the assistant message
60
+ role: Role of the message sender.
61
+ content: Content of the message.
77
62
 
78
63
  Raises:
79
- UserNotFoundError: If the user is not found
80
- SessionNotFoundError: If the session is not found
81
- InvalidSessionStateError: If the session is already processed or processing
82
- AuthenticationError: If the API key or project ID is invalid
83
- InternalServerError: If the server encounters an error
84
- NetworkError: If there are network issues
85
- TimeoutError: If the request times out
86
- RecallrAIError: For other API-related errors
87
- """
88
- self._add_message(message, MessageRole.ASSISTANT)
89
-
90
- def _add_message(self, message: str, role: MessageRole) -> None:
91
- """
92
- Internal helper to add a message to the session.
93
-
94
- Args:
95
- message: Content of the message
96
- role: Role of the message sender
97
-
98
- Raises:
99
- UserNotFoundError: If the user is not found
100
- SessionNotFoundError: If the session is not found
101
- InvalidSessionStateError: If the session is already processed or processing
102
- AuthenticationError: If the API key or project ID is invalid
103
- InternalServerError: If the server encounters an error
104
- NetworkError: If there are network issues
105
- TimeoutError: If the request times out
106
- 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.
107
72
  """
108
73
  response = self._http.post(
109
- f"/api/v1/users/{self.user_id}/sessions/{self.session_id}/add-message",
110
- 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},
111
76
  )
112
-
77
+
113
78
  if response.status_code == 404:
114
79
  # Check if it's a user not found or session not found error
115
80
  detail = response.json().get('detail', '')
116
- if f"User {self.user_id} not found" in detail:
117
- 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)
118
83
  else:
119
- raise SessionNotFoundError(session_id=self.session_id)
84
+ raise SessionNotFoundError(message=detail, http_status=response.status_code)
120
85
  elif response.status_code == 400:
86
+ detail = response.json().get('detail', f"Cannot add message to session with status {self.status}")
121
87
  raise InvalidSessionStateError(
122
- message=f"Cannot add message to session with status {self.get_status()}",
88
+ message=detail,
89
+ http_status=response.status_code
123
90
  )
124
91
  elif response.status_code != 200:
125
92
  raise RecallrAIError(
126
- message=f"Failed to add message: {response.json().get('detail', 'Unknown error')}",
93
+ message=response.json().get('detail', 'Unknown error'),
127
94
  http_status=response.status_code
128
95
  )
129
96
 
130
- 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:
131
108
  """
132
109
  Get the current context for this session.
133
110
 
134
- The context contains information from the user's memory that is relevant
135
- 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.
136
120
 
137
121
  Returns:
138
- Context information with the memory text and whether memory was used
122
+ Context information with the memory text and whether memory was used.
139
123
 
140
124
  Raises:
141
- UserNotFoundError: If the user is not found
142
- SessionNotFoundError: If the session is not found
143
- AuthenticationError: If the API key or project ID is invalid
144
- InternalServerError: If the server encounters an error
145
- NetworkError: If there are network issues
146
- TimeoutError: If the request times out
147
- 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.
148
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
+
149
147
  response = self._http.get(
150
- 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,
151
150
  )
152
-
151
+
153
152
  if response.status_code == 404:
154
153
  # Check if it's a user not found or session not found error
155
154
  detail = response.json().get('detail', '')
156
- if f"User {self.user_id} not found" in detail:
157
- 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)
158
157
  else:
159
- raise SessionNotFoundError(session_id=self.session_id)
158
+ raise SessionNotFoundError(message=detail, http_status=response.status_code)
160
159
  elif response.status_code != 200:
161
160
  raise RecallrAIError(
162
- message=f"Failed to get context: {response.json().get('detail', 'Unknown error')}",
161
+ message=response.json().get('detail', 'Unknown error'),
163
162
  http_status=response.status_code
164
163
  )
165
- status = self.get_status()
166
- if status == SessionStatus.PROCESSED:
167
- logger.warning("Cannot add message to a session that has already been processed")
168
- elif status == SessionStatus.PROCESSING:
169
- logger.warning("Cannot add message to a session that is currently being processed")
164
+ if self.status == SessionStatus.PROCESSED:
165
+ logger.warning("You are trying to get context for a processed session. Why do you need it?")
166
+ elif self.status == SessionStatus.PROCESSING:
167
+ logger.warning("You are trying to get context for a processing session. Why do you need it?")
170
168
  return Context.from_api_response(response.json())
171
169
 
172
- def process(self) -> None:
170
+ def update(self, new_metadata: Optional[Dict[str, Any]] = None) -> None:
173
171
  """
174
- Process the session to update the user's memory.
172
+ Update the session's metadata.
175
173
 
176
- This method triggers the processing of the conversation to extract and update
177
- the user's memory.
174
+ Args:
175
+ new_metadata: New metadata to associate with the session.
178
176
 
179
177
  Raises:
180
- UserNotFoundError: If the user is not found
181
- SessionNotFoundError: If the session is not found
182
- InvalidSessionStateError: If the session is already processed or being processed
183
- AuthenticationError: If the API key or project ID is invalid
184
- InternalServerError: If the server encounters an error
185
- NetworkError: If there are network issues
186
- TimeoutError: If the request times out
187
- 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.
188
185
  """
189
- response = self._http.post(
190
- 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},
191
189
  )
192
-
190
+
193
191
  if response.status_code == 404:
194
192
  # Check if it's a user not found or session not found error
195
193
  detail = response.json().get('detail', '')
196
- if f"User {self.user_id} not found" in detail:
197
- 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)
198
196
  else:
199
- raise SessionNotFoundError(session_id=self.session_id)
200
- elif response.status_code == 400:
201
- raise InvalidSessionStateError(
202
- message=f"{response.json().get('detail', f'Cannot process session with status {self.get_status()}')}",
203
- )
197
+ raise SessionNotFoundError(message=detail, http_status=response.status_code)
204
198
  elif response.status_code != 200:
205
199
  raise RecallrAIError(
206
- message=f"Failed to process session: {response.json().get('detail', 'Unknown error')}",
200
+ message=response.json().get('detail', 'Unknown error'),
207
201
  http_status=response.status_code
208
202
  )
203
+
204
+ updated_data = SessionModel.from_api_response(response.json())
205
+ self.metadata = updated_data.metadata
209
206
 
210
- def get_status(self) -> SessionStatus:
207
+ def refresh(self) -> None:
211
208
  """
212
- Get the current status of the session.
209
+ Refresh the session data from the API.
213
210
 
214
- Returns:
215
- 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.
216
213
 
217
214
  Raises:
218
- UserNotFoundError: If the user is not found
219
- SessionNotFoundError: If the session is not found
220
- AuthenticationError: If the API key or project ID is invalid
221
- InternalServerError: If the server encounters an error
222
- NetworkError: If there are network issues
223
- TimeoutError: If the request times out
224
- 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.
225
222
  """
226
223
  response = self._http.get(
227
- 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"
228
264
  )
229
265
 
230
266
  if response.status_code == 404:
231
267
  # Check if it's a user not found or session not found error
232
268
  detail = response.json().get('detail', '')
233
- if f"User {self.user_id} not found" in detail:
234
- 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)
235
271
  else:
236
- 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
+ )
237
279
  elif response.status_code != 200:
238
280
  raise RecallrAIError(
239
- message=f"Failed to get session status: {response.json().get('detail', 'Unknown error')}",
281
+ message=response.json().get('detail', 'Unknown error'),
240
282
  http_status=response.status_code
241
283
  )
242
-
243
- return SessionStatus(response.json()["status"])
244
284
 
245
- def get_messages(self) -> List[Message]:
285
+ def get_messages(
286
+ self,
287
+ offset: int = 0,
288
+ limit: int = 50,
289
+ ) -> SessionMessagesList:
246
290
  """
247
291
  Get all messages in the session.
248
292
 
249
293
  Returns:
250
- List of messages in the session
294
+ Paginated list of messages in the session.
251
295
 
252
296
  Raises:
253
- UserNotFoundError: If the user is not found
254
- SessionNotFoundError: If the session is not found
255
- AuthenticationError: If the API key or project ID is invalid
256
- InternalServerError: If the server encounters an error
257
- NetworkError: If there are network issues
258
- TimeoutError: If the request times out
259
- 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.
260
304
  """
261
305
  response = self._http.get(
262
- 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},
263
308
  )
264
309
 
265
310
  if response.status_code == 404:
266
311
  # Check if it's a user not found or session not found error
267
312
  detail = response.json().get('detail', '')
268
- if f"User {self.user_id} not found" in detail:
269
- 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)
270
315
  else:
271
- raise SessionNotFoundError(session_id=self.session_id)
316
+ raise SessionNotFoundError(message=detail, http_status=response.status_code)
272
317
  elif response.status_code != 200:
273
318
  raise RecallrAIError(
274
- message=f"Failed to get messages: {response.json().get('detail', 'Unknown error')}",
319
+ message=response.json().get('detail', 'Unknown error'),
275
320
  http_status=response.status_code
276
321
  )
277
-
278
- data = response.json()
279
- 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}>"