recallrai 0.2.0__py3-none-any.whl → 0.3.1__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 +2 -2
- recallrai/client.py +66 -51
- recallrai/exceptions/__init__.py +21 -9
- recallrai/exceptions/auth.py +2 -5
- recallrai/exceptions/base.py +4 -13
- recallrai/exceptions/merge_conflicts.py +69 -0
- recallrai/exceptions/network.py +6 -23
- recallrai/exceptions/server.py +17 -40
- recallrai/exceptions/sessions.py +6 -28
- recallrai/exceptions/users.py +16 -31
- recallrai/exceptions/validation.py +2 -9
- recallrai/merge_conflict.py +189 -0
- recallrai/models/__init__.py +38 -5
- recallrai/models/merge_conflict.py +151 -0
- recallrai/models/session.py +64 -28
- recallrai/models/user.py +135 -16
- recallrai/session.py +195 -145
- recallrai/user.py +353 -78
- recallrai/utils/__init__.py +1 -0
- recallrai/utils/http_client.py +38 -23
- recallrai-0.3.1.dist-info/METADATA +902 -0
- recallrai-0.3.1.dist-info/RECORD +23 -0
- {recallrai-0.2.0.dist-info → recallrai-0.3.1.dist-info}/WHEEL +1 -1
- recallrai-0.2.0.dist-info/METADATA +0 -439
- recallrai-0.2.0.dist-info/RECORD +0 -20
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(
|
|
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:
|
|
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=[
|
|
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
|
|
5
|
+
from typing import Optional, Dict, Any
|
|
6
6
|
from .utils import HTTPClient
|
|
7
7
|
from .models import (
|
|
8
8
|
Context,
|
|
9
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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.
|
|
47
|
-
self.
|
|
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
|
|
55
|
+
def add_message(self, role: MessageRole, content: str) -> None:
|
|
50
56
|
"""
|
|
51
|
-
|
|
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
|
-
|
|
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.
|
|
107
|
-
data={"message":
|
|
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.
|
|
114
|
-
raise UserNotFoundError(
|
|
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(
|
|
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=
|
|
88
|
+
message=detail,
|
|
89
|
+
http_status=response.status_code
|
|
120
90
|
)
|
|
121
91
|
elif response.status_code != 200:
|
|
122
92
|
raise RecallrAIError(
|
|
123
|
-
message=
|
|
93
|
+
message=response.json().get('detail', 'Unknown error'),
|
|
124
94
|
http_status=response.status_code
|
|
125
95
|
)
|
|
126
96
|
|
|
127
|
-
def get_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
|
-
|
|
132
|
-
|
|
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.
|
|
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.
|
|
154
|
-
raise UserNotFoundError(
|
|
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(
|
|
158
|
+
raise SessionNotFoundError(message=detail, http_status=response.status_code)
|
|
157
159
|
elif response.status_code != 200:
|
|
158
160
|
raise RecallrAIError(
|
|
159
|
-
message=
|
|
161
|
+
message=response.json().get('detail', 'Unknown error'),
|
|
160
162
|
http_status=response.status_code
|
|
161
163
|
)
|
|
162
|
-
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
|
|
170
|
+
def update(self, new_metadata: Optional[Dict[str, Any]] = None) -> None:
|
|
170
171
|
"""
|
|
171
|
-
|
|
172
|
+
Update the session's metadata.
|
|
172
173
|
|
|
173
|
-
|
|
174
|
-
|
|
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
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
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.
|
|
187
|
-
f"/api/v1/users/{self.
|
|
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.
|
|
194
|
-
raise UserNotFoundError(
|
|
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(
|
|
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=
|
|
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
|
|
207
|
+
def refresh(self) -> None:
|
|
208
208
|
"""
|
|
209
|
-
|
|
209
|
+
Refresh the session data from the API.
|
|
210
210
|
|
|
211
|
-
|
|
212
|
-
|
|
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.
|
|
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.
|
|
231
|
-
raise UserNotFoundError(
|
|
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(
|
|
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=
|
|
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(
|
|
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
|
-
|
|
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.
|
|
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.
|
|
266
|
-
raise UserNotFoundError(
|
|
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(
|
|
316
|
+
raise SessionNotFoundError(message=detail, http_status=response.status_code)
|
|
269
317
|
elif response.status_code != 200:
|
|
270
318
|
raise RecallrAIError(
|
|
271
|
-
message=
|
|
319
|
+
message=response.json().get('detail', 'Unknown error'),
|
|
272
320
|
http_status=response.status_code
|
|
273
321
|
)
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
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}>"
|