agenticmem 0.1.3.7__py3-none-any.whl → 0.1.3.8__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 agenticmem might be problematic. Click here for more details.
- agenticmem/__init__.py +1 -1
- agenticmem/client.py +239 -74
- agenticmem-0.1.3.8.dist-info/METADATA +72 -0
- agenticmem-0.1.3.8.dist-info/RECORD +6 -0
- agenticmem-0.1.3.7.dist-info/METADATA +0 -245
- agenticmem-0.1.3.7.dist-info/RECORD +0 -6
- {agenticmem-0.1.3.7.dist-info → agenticmem-0.1.3.8.dist-info}/WHEEL +0 -0
agenticmem/__init__.py
CHANGED
agenticmem/client.py
CHANGED
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
import os
|
|
2
2
|
import aiohttp
|
|
3
|
+
import asyncio
|
|
3
4
|
from urllib.parse import urljoin
|
|
4
5
|
import requests
|
|
6
|
+
from concurrent.futures import ThreadPoolExecutor
|
|
5
7
|
from typing import Optional, Union
|
|
6
8
|
from agenticmem_commons.api_schema.retriever_schema import (
|
|
7
9
|
SearchInteractionRequest,
|
|
@@ -47,6 +49,9 @@ from agenticmem_commons.config_schema import Config
|
|
|
47
49
|
class AgenticMemClient:
|
|
48
50
|
"""Client for interacting with the AgenticMem API."""
|
|
49
51
|
|
|
52
|
+
# Shared thread pool for all instances to maximize efficiency
|
|
53
|
+
_thread_pool = ThreadPoolExecutor(max_workers=4, thread_name_prefix="agenticmem")
|
|
54
|
+
|
|
50
55
|
def __init__(self, api_key: str = "", url_endpoint: str = ""):
|
|
51
56
|
"""Initialize the AgenticMem client.
|
|
52
57
|
|
|
@@ -57,24 +62,83 @@ class AgenticMemClient:
|
|
|
57
62
|
self.base_url = url_endpoint if url_endpoint else BACKEND_URL
|
|
58
63
|
self.session = requests.Session()
|
|
59
64
|
|
|
65
|
+
def _get_auth_headers(self) -> dict:
|
|
66
|
+
"""Get authentication headers for API requests.
|
|
67
|
+
|
|
68
|
+
Returns:
|
|
69
|
+
dict: Headers with authorization and content-type
|
|
70
|
+
"""
|
|
71
|
+
if self.api_key:
|
|
72
|
+
return {
|
|
73
|
+
"Authorization": f"Bearer {self.api_key}",
|
|
74
|
+
"Content-Type": "application/json",
|
|
75
|
+
}
|
|
76
|
+
return {}
|
|
77
|
+
|
|
78
|
+
def _convert_to_model(self, data: Union[dict, object], model_class):
|
|
79
|
+
"""Convert dict to model instance if needed.
|
|
80
|
+
|
|
81
|
+
Args:
|
|
82
|
+
data: Either a dict or already an instance of model_class
|
|
83
|
+
model_class: The target class to convert to
|
|
84
|
+
|
|
85
|
+
Returns:
|
|
86
|
+
An instance of model_class
|
|
87
|
+
"""
|
|
88
|
+
if isinstance(data, dict):
|
|
89
|
+
return model_class(**data)
|
|
90
|
+
return data
|
|
91
|
+
|
|
92
|
+
def _fire_and_forget(self, sync_func, async_func, *args, **kwargs):
|
|
93
|
+
"""Execute a request in fire-and-forget mode.
|
|
94
|
+
|
|
95
|
+
This method optimizes execution based on context:
|
|
96
|
+
- In async contexts (e.g., FastAPI): Uses existing event loop (most efficient)
|
|
97
|
+
- In sync contexts: Uses shared thread pool (avoids thread creation overhead)
|
|
98
|
+
|
|
99
|
+
Args:
|
|
100
|
+
sync_func: Synchronous function to call
|
|
101
|
+
async_func: Asynchronous function to call
|
|
102
|
+
*args: Positional arguments to pass to the function
|
|
103
|
+
**kwargs: Keyword arguments to pass to the function
|
|
104
|
+
"""
|
|
105
|
+
try:
|
|
106
|
+
loop = asyncio.get_running_loop()
|
|
107
|
+
|
|
108
|
+
# We're in an async context - use the event loop
|
|
109
|
+
async def fire_and_forget():
|
|
110
|
+
try:
|
|
111
|
+
await async_func(*args, **kwargs)
|
|
112
|
+
except Exception:
|
|
113
|
+
# Silently ignore errors in fire-and-forget mode
|
|
114
|
+
pass
|
|
115
|
+
|
|
116
|
+
loop.create_task(fire_and_forget())
|
|
117
|
+
except RuntimeError:
|
|
118
|
+
# No running loop - we're in sync context, use thread pool
|
|
119
|
+
def send_request():
|
|
120
|
+
try:
|
|
121
|
+
sync_func(*args, **kwargs)
|
|
122
|
+
except Exception:
|
|
123
|
+
# Silently ignore errors in fire-and-forget mode
|
|
124
|
+
pass
|
|
125
|
+
|
|
126
|
+
self._thread_pool.submit(send_request)
|
|
127
|
+
|
|
60
128
|
async def _make_async_request(
|
|
61
129
|
self, method: str, endpoint: str, headers: Optional[dict] = None, **kwargs
|
|
62
130
|
):
|
|
63
131
|
"""Make an async HTTP request to the API."""
|
|
64
132
|
url = urljoin(self.base_url, endpoint)
|
|
65
133
|
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
"Authorization": f"Bearer {self.api_key}",
|
|
71
|
-
"Content-Type": "application/json",
|
|
72
|
-
}
|
|
73
|
-
)
|
|
134
|
+
# Merge auth headers with any provided headers
|
|
135
|
+
request_headers = self._get_auth_headers()
|
|
136
|
+
if headers:
|
|
137
|
+
request_headers.update(headers)
|
|
74
138
|
|
|
75
139
|
async with aiohttp.ClientSession() as async_session:
|
|
76
140
|
response = await async_session.request(
|
|
77
|
-
method, url, headers=
|
|
141
|
+
method, url, headers=request_headers, **kwargs
|
|
78
142
|
)
|
|
79
143
|
response.raise_for_status()
|
|
80
144
|
return await response.json()
|
|
@@ -94,22 +158,20 @@ class AgenticMemClient:
|
|
|
94
158
|
dict: API response
|
|
95
159
|
"""
|
|
96
160
|
url = urljoin(self.base_url, endpoint)
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
"Authorization": f"Bearer {self.api_key}",
|
|
101
|
-
"Content-Type": "application/json",
|
|
102
|
-
}
|
|
103
|
-
)
|
|
161
|
+
|
|
162
|
+
# Merge auth headers with any provided headers
|
|
163
|
+
request_headers = self._get_auth_headers()
|
|
104
164
|
if headers:
|
|
105
|
-
|
|
165
|
+
request_headers.update(headers)
|
|
166
|
+
|
|
167
|
+
self.session.headers.update(request_headers)
|
|
106
168
|
response = self.session.request(method, url, **kwargs)
|
|
107
169
|
response.raise_for_status()
|
|
108
170
|
return response.json()
|
|
109
171
|
|
|
110
|
-
|
|
111
|
-
"""
|
|
112
|
-
response =
|
|
172
|
+
def login(self, email: str, password: str) -> Token:
|
|
173
|
+
"""Login to the AgenticMem API."""
|
|
174
|
+
response = self._make_request(
|
|
113
175
|
"POST",
|
|
114
176
|
"/token",
|
|
115
177
|
data={"username": email, "password": password},
|
|
@@ -120,23 +182,52 @@ class AgenticMemClient:
|
|
|
120
182
|
)
|
|
121
183
|
return Token(**response)
|
|
122
184
|
|
|
123
|
-
|
|
185
|
+
def _publish_interaction_sync(
|
|
186
|
+
self, request: PublishUserInteractionRequest
|
|
187
|
+
) -> PublishUserInteractionResponse:
|
|
188
|
+
"""Internal sync method to publish interaction."""
|
|
189
|
+
response = self._make_request(
|
|
190
|
+
"POST",
|
|
191
|
+
"/api/publish_interaction",
|
|
192
|
+
json=request.model_dump(),
|
|
193
|
+
)
|
|
194
|
+
return PublishUserInteractionResponse(**response)
|
|
195
|
+
|
|
196
|
+
async def _publish_interaction_async(
|
|
197
|
+
self, request: PublishUserInteractionRequest
|
|
198
|
+
) -> PublishUserInteractionResponse:
|
|
199
|
+
"""Internal async method to publish interaction."""
|
|
200
|
+
response = await self._make_async_request(
|
|
201
|
+
"POST",
|
|
202
|
+
"/api/publish_interaction",
|
|
203
|
+
json=request.model_dump(),
|
|
204
|
+
)
|
|
205
|
+
return PublishUserInteractionResponse(**response)
|
|
206
|
+
|
|
207
|
+
def publish_interaction(
|
|
124
208
|
self,
|
|
125
209
|
request_id: str,
|
|
126
210
|
user_id: str,
|
|
127
211
|
interaction_requests: list[Union[InteractionRequest, dict]],
|
|
128
212
|
source: str = "",
|
|
129
213
|
agent_version: str = "",
|
|
130
|
-
|
|
214
|
+
wait_for_response: bool = False,
|
|
215
|
+
) -> Optional[PublishUserInteractionResponse]:
|
|
131
216
|
"""Publish user interactions.
|
|
132
217
|
|
|
218
|
+
This method is optimized for resource efficiency:
|
|
219
|
+
- In async contexts (e.g., FastAPI): Uses existing event loop (most efficient)
|
|
220
|
+
- In sync contexts: Uses shared thread pool (avoids thread creation overhead)
|
|
221
|
+
|
|
133
222
|
Args:
|
|
134
223
|
request_id (str): The request ID
|
|
135
224
|
user_id (str): The user ID
|
|
136
225
|
interaction_requests (List[InteractionRequest]): List of interaction requests
|
|
137
226
|
source (str, optional): The source of the interaction
|
|
227
|
+
agent_version (str, optional): The agent version
|
|
228
|
+
wait_for_response (bool, optional): If True, wait for response. If False, send request without waiting. Defaults to False.
|
|
138
229
|
Returns:
|
|
139
|
-
PublishUserInteractionResponse: Response containing success status and message
|
|
230
|
+
Optional[PublishUserInteractionResponse]: Response containing success status and message if wait_for_response=True, None otherwise
|
|
140
231
|
"""
|
|
141
232
|
interaction_requests = [
|
|
142
233
|
(
|
|
@@ -153,14 +244,18 @@ class AgenticMemClient:
|
|
|
153
244
|
source=source,
|
|
154
245
|
agent_version=agent_version,
|
|
155
246
|
)
|
|
156
|
-
response = await self._make_async_request(
|
|
157
|
-
"POST",
|
|
158
|
-
"/api/publish_interaction",
|
|
159
|
-
json=request.model_dump(),
|
|
160
|
-
)
|
|
161
|
-
return PublishUserInteractionResponse(**response)
|
|
162
247
|
|
|
163
|
-
|
|
248
|
+
if wait_for_response:
|
|
249
|
+
# Synchronous blocking call
|
|
250
|
+
return self._publish_interaction_sync(request)
|
|
251
|
+
else:
|
|
252
|
+
# Non-blocking fire-and-forget
|
|
253
|
+
self._fire_and_forget(
|
|
254
|
+
self._publish_interaction_sync, self._publish_interaction_async, request
|
|
255
|
+
)
|
|
256
|
+
return None
|
|
257
|
+
|
|
258
|
+
def search_interactions(
|
|
164
259
|
self,
|
|
165
260
|
request: Union[SearchInteractionRequest, dict],
|
|
166
261
|
) -> SearchInteractionResponse:
|
|
@@ -172,16 +267,15 @@ class AgenticMemClient:
|
|
|
172
267
|
Returns:
|
|
173
268
|
SearchInteractionResponse: Response containing matching interactions
|
|
174
269
|
"""
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
response = await self._make_async_request(
|
|
270
|
+
request = self._convert_to_model(request, SearchInteractionRequest)
|
|
271
|
+
response = self._make_request(
|
|
178
272
|
"POST",
|
|
179
273
|
"/api/search_interactions",
|
|
180
274
|
json=request.model_dump(),
|
|
181
275
|
)
|
|
182
276
|
return SearchInteractionResponse(**response)
|
|
183
277
|
|
|
184
|
-
|
|
278
|
+
def search_profiles(
|
|
185
279
|
self,
|
|
186
280
|
request: Union[SearchUserProfileRequest, dict],
|
|
187
281
|
) -> SearchUserProfileResponse:
|
|
@@ -193,61 +287,135 @@ class AgenticMemClient:
|
|
|
193
287
|
Returns:
|
|
194
288
|
SearchUserProfileResponse: Response containing matching profiles
|
|
195
289
|
"""
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
response = await self._make_async_request(
|
|
290
|
+
request = self._convert_to_model(request, SearchUserProfileRequest)
|
|
291
|
+
response = self._make_request(
|
|
199
292
|
"POST", "/api/search_profiles", json=request.model_dump()
|
|
200
293
|
)
|
|
201
294
|
return SearchUserProfileResponse(**response)
|
|
202
295
|
|
|
203
|
-
|
|
204
|
-
self,
|
|
296
|
+
def _delete_profile_sync(
|
|
297
|
+
self, request: DeleteUserProfileRequest
|
|
298
|
+
) -> DeleteUserProfileResponse:
|
|
299
|
+
"""Internal sync method to delete profile."""
|
|
300
|
+
response = self._make_request(
|
|
301
|
+
"DELETE",
|
|
302
|
+
"/api/delete_profile",
|
|
303
|
+
json=request.model_dump(),
|
|
304
|
+
)
|
|
305
|
+
return DeleteUserProfileResponse(**response)
|
|
306
|
+
|
|
307
|
+
async def _delete_profile_async(
|
|
308
|
+
self, request: DeleteUserProfileRequest
|
|
205
309
|
) -> DeleteUserProfileResponse:
|
|
310
|
+
"""Internal async method to delete profile."""
|
|
311
|
+
response = await self._make_async_request(
|
|
312
|
+
"DELETE",
|
|
313
|
+
"/api/delete_profile",
|
|
314
|
+
json=request.model_dump(),
|
|
315
|
+
)
|
|
316
|
+
return DeleteUserProfileResponse(**response)
|
|
317
|
+
|
|
318
|
+
def delete_profile(
|
|
319
|
+
self,
|
|
320
|
+
user_id: str,
|
|
321
|
+
profile_id: str = "",
|
|
322
|
+
search_query: str = "",
|
|
323
|
+
wait_for_response: bool = False,
|
|
324
|
+
) -> Optional[DeleteUserProfileResponse]:
|
|
206
325
|
"""Delete user profiles.
|
|
207
326
|
|
|
327
|
+
This method is optimized for resource efficiency:
|
|
328
|
+
- In async contexts (e.g., FastAPI): Uses existing event loop (most efficient)
|
|
329
|
+
- In sync contexts: Uses shared thread pool (avoids thread creation overhead)
|
|
330
|
+
|
|
208
331
|
Args:
|
|
209
332
|
user_id (str): The user ID
|
|
210
333
|
profile_id (str, optional): Specific profile ID to delete
|
|
211
334
|
search_query (str, optional): Query to match profiles for deletion
|
|
335
|
+
wait_for_response (bool, optional): If True, wait for response. If False, send request without waiting. Defaults to False.
|
|
212
336
|
|
|
213
337
|
Returns:
|
|
214
|
-
DeleteUserProfileResponse: Response containing success status and message
|
|
338
|
+
Optional[DeleteUserProfileResponse]: Response containing success status and message if wait_for_response=True, None otherwise
|
|
215
339
|
"""
|
|
216
340
|
request = DeleteUserProfileRequest(
|
|
217
341
|
user_id=user_id,
|
|
218
342
|
profile_id=profile_id,
|
|
219
343
|
search_query=search_query,
|
|
220
344
|
)
|
|
221
|
-
|
|
222
|
-
|
|
345
|
+
|
|
346
|
+
if wait_for_response:
|
|
347
|
+
# Synchronous blocking call
|
|
348
|
+
return self._delete_profile_sync(request)
|
|
349
|
+
else:
|
|
350
|
+
# Non-blocking fire-and-forget
|
|
351
|
+
self._fire_and_forget(
|
|
352
|
+
self._delete_profile_sync, self._delete_profile_async, request
|
|
353
|
+
)
|
|
354
|
+
return None
|
|
355
|
+
|
|
356
|
+
def _delete_interaction_sync(
|
|
357
|
+
self, request: DeleteUserInteractionRequest
|
|
358
|
+
) -> DeleteUserInteractionResponse:
|
|
359
|
+
"""Internal sync method to delete interaction."""
|
|
360
|
+
response = self._make_request(
|
|
361
|
+
"DELETE",
|
|
362
|
+
"/api/delete_interaction",
|
|
363
|
+
json=request.model_dump(),
|
|
223
364
|
)
|
|
224
|
-
return
|
|
365
|
+
return DeleteUserInteractionResponse(**response)
|
|
225
366
|
|
|
226
|
-
async def
|
|
227
|
-
self,
|
|
367
|
+
async def _delete_interaction_async(
|
|
368
|
+
self, request: DeleteUserInteractionRequest
|
|
228
369
|
) -> DeleteUserInteractionResponse:
|
|
370
|
+
"""Internal async method to delete interaction."""
|
|
371
|
+
response = await self._make_async_request(
|
|
372
|
+
"DELETE",
|
|
373
|
+
"/api/delete_interaction",
|
|
374
|
+
json=request.model_dump(),
|
|
375
|
+
)
|
|
376
|
+
return DeleteUserInteractionResponse(**response)
|
|
377
|
+
|
|
378
|
+
def delete_interaction(
|
|
379
|
+
self, user_id: str, interaction_id: str, wait_for_response: bool = False
|
|
380
|
+
) -> Optional[DeleteUserInteractionResponse]:
|
|
229
381
|
"""Delete a user interaction.
|
|
230
382
|
|
|
383
|
+
This method is optimized for resource efficiency:
|
|
384
|
+
- In async contexts (e.g., FastAPI): Uses existing event loop (most efficient)
|
|
385
|
+
- In sync contexts: Uses shared thread pool (avoids thread creation overhead)
|
|
386
|
+
|
|
231
387
|
Args:
|
|
232
388
|
user_id (str): The user ID
|
|
233
389
|
interaction_id (str): The interaction ID to delete
|
|
390
|
+
wait_for_response (bool, optional): If True, wait for response. If False, send request without waiting. Defaults to False.
|
|
234
391
|
|
|
235
392
|
Returns:
|
|
236
|
-
DeleteUserInteractionResponse: Response containing success status and message
|
|
393
|
+
Optional[DeleteUserInteractionResponse]: Response containing success status and message if wait_for_response=True, None otherwise
|
|
237
394
|
"""
|
|
238
395
|
request = DeleteUserInteractionRequest(
|
|
239
396
|
user_id=user_id, interaction_id=interaction_id
|
|
240
397
|
)
|
|
241
|
-
response = await self._make_async_request(
|
|
242
|
-
"DELETE", "/api/delete_interaction", json=request.model_dump()
|
|
243
|
-
)
|
|
244
|
-
return DeleteUserInteractionResponse(**response)
|
|
245
398
|
|
|
246
|
-
|
|
247
|
-
|
|
399
|
+
if wait_for_response:
|
|
400
|
+
# Synchronous blocking call
|
|
401
|
+
return self._delete_interaction_sync(request)
|
|
402
|
+
else:
|
|
403
|
+
# Non-blocking fire-and-forget
|
|
404
|
+
self._fire_and_forget(
|
|
405
|
+
self._delete_interaction_sync, self._delete_interaction_async, request
|
|
406
|
+
)
|
|
407
|
+
return None
|
|
408
|
+
|
|
409
|
+
def get_profile_change_log(self) -> ProfileChangeLogResponse:
|
|
410
|
+
"""Get profile change log.
|
|
411
|
+
|
|
412
|
+
Returns:
|
|
413
|
+
ProfileChangeLogResponse: Response containing profile change log
|
|
414
|
+
"""
|
|
415
|
+
response = self._make_request("GET", "/api/profile_change_log")
|
|
248
416
|
return ProfileChangeLogResponse(**response)
|
|
249
417
|
|
|
250
|
-
|
|
418
|
+
def get_interactions(
|
|
251
419
|
self,
|
|
252
420
|
request: Union[GetInteractionsRequest, dict],
|
|
253
421
|
) -> GetInteractionsResponse:
|
|
@@ -259,16 +427,15 @@ class AgenticMemClient:
|
|
|
259
427
|
Returns:
|
|
260
428
|
GetInteractionsResponse: Response containing list of interactions
|
|
261
429
|
"""
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
response = await self._make_async_request(
|
|
430
|
+
request = self._convert_to_model(request, GetInteractionsRequest)
|
|
431
|
+
response = self._make_request(
|
|
265
432
|
"POST",
|
|
266
433
|
"/api/get_interactions",
|
|
267
434
|
json=request.model_dump(),
|
|
268
435
|
)
|
|
269
436
|
return GetInteractionsResponse(**response)
|
|
270
437
|
|
|
271
|
-
|
|
438
|
+
def get_profiles(
|
|
272
439
|
self,
|
|
273
440
|
request: Union[GetUserProfilesRequest, dict],
|
|
274
441
|
) -> GetUserProfilesResponse:
|
|
@@ -280,16 +447,15 @@ class AgenticMemClient:
|
|
|
280
447
|
Returns:
|
|
281
448
|
GetUserProfilesResponse: Response containing list of profiles
|
|
282
449
|
"""
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
response = await self._make_async_request(
|
|
450
|
+
request = self._convert_to_model(request, GetUserProfilesRequest)
|
|
451
|
+
response = self._make_request(
|
|
286
452
|
"POST",
|
|
287
453
|
"/api/get_profiles",
|
|
288
454
|
json=request.model_dump(),
|
|
289
455
|
)
|
|
290
456
|
return GetUserProfilesResponse(**response)
|
|
291
457
|
|
|
292
|
-
|
|
458
|
+
def set_config(self, config: Union[Config, dict]) -> dict:
|
|
293
459
|
"""Set configuration for the organization.
|
|
294
460
|
|
|
295
461
|
Args:
|
|
@@ -298,28 +464,27 @@ class AgenticMemClient:
|
|
|
298
464
|
Returns:
|
|
299
465
|
dict: Response containing success status and message
|
|
300
466
|
"""
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
response = await self._make_async_request(
|
|
467
|
+
config = self._convert_to_model(config, Config)
|
|
468
|
+
response = self._make_request(
|
|
304
469
|
"POST",
|
|
305
470
|
"/api/set_config",
|
|
306
471
|
json=config.model_dump(),
|
|
307
472
|
)
|
|
308
473
|
return response
|
|
309
474
|
|
|
310
|
-
|
|
475
|
+
def get_config(self) -> Config:
|
|
311
476
|
"""Get configuration for the organization.
|
|
312
477
|
|
|
313
478
|
Returns:
|
|
314
479
|
Config: The current configuration
|
|
315
480
|
"""
|
|
316
|
-
response =
|
|
481
|
+
response = self._make_request(
|
|
317
482
|
"GET",
|
|
318
483
|
"/api/get_config",
|
|
319
484
|
)
|
|
320
485
|
return Config(**response)
|
|
321
486
|
|
|
322
|
-
|
|
487
|
+
def get_raw_feedbacks(
|
|
323
488
|
self,
|
|
324
489
|
request: Optional[Union[GetRawFeedbacksRequest, dict]] = None,
|
|
325
490
|
) -> GetRawFeedbacksResponse:
|
|
@@ -333,16 +498,16 @@ class AgenticMemClient:
|
|
|
333
498
|
"""
|
|
334
499
|
if request is None:
|
|
335
500
|
request = GetRawFeedbacksRequest()
|
|
336
|
-
|
|
337
|
-
request =
|
|
338
|
-
response =
|
|
501
|
+
else:
|
|
502
|
+
request = self._convert_to_model(request, GetRawFeedbacksRequest)
|
|
503
|
+
response = self._make_request(
|
|
339
504
|
"POST",
|
|
340
505
|
"/api/get_raw_feedbacks",
|
|
341
506
|
json=request.model_dump(),
|
|
342
507
|
)
|
|
343
508
|
return GetRawFeedbacksResponse(**response)
|
|
344
509
|
|
|
345
|
-
|
|
510
|
+
def get_feedbacks(
|
|
346
511
|
self,
|
|
347
512
|
request: Optional[Union[GetFeedbacksRequest, dict]] = None,
|
|
348
513
|
) -> GetFeedbacksResponse:
|
|
@@ -356,9 +521,9 @@ class AgenticMemClient:
|
|
|
356
521
|
"""
|
|
357
522
|
if request is None:
|
|
358
523
|
request = GetFeedbacksRequest()
|
|
359
|
-
|
|
360
|
-
request =
|
|
361
|
-
response =
|
|
524
|
+
else:
|
|
525
|
+
request = self._convert_to_model(request, GetFeedbacksRequest)
|
|
526
|
+
response = self._make_request(
|
|
362
527
|
"POST",
|
|
363
528
|
"/api/get_feedbacks",
|
|
364
529
|
json=request.model_dump(),
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
Metadata-Version: 2.3
|
|
2
|
+
Name: agenticmem
|
|
3
|
+
Version: 0.1.3.8
|
|
4
|
+
Summary: A Python client for the AgenticMem API
|
|
5
|
+
License: MIT
|
|
6
|
+
Author: AgenticMem Team
|
|
7
|
+
Requires-Python: >=3.10,<4.0
|
|
8
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
9
|
+
Classifier: Programming Language :: Python :: 3
|
|
10
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
11
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
12
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
13
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
14
|
+
Requires-Dist: agenticmem-commons (==0.1.3.8)
|
|
15
|
+
Requires-Dist: aiohttp (>=3.12.9,<4.0.0)
|
|
16
|
+
Requires-Dist: griffe (==0.48.0)
|
|
17
|
+
Requires-Dist: mkdocs-with-pdf (>=0.9.3,<0.10.0)
|
|
18
|
+
Requires-Dist: mkdocstrings[python] (>=0.18.0)
|
|
19
|
+
Requires-Dist: pydantic (>=2.0.0,<3.0.0)
|
|
20
|
+
Requires-Dist: python-dateutil (>=2.8.0,<3.0.0)
|
|
21
|
+
Requires-Dist: requests (>=2.25.0,<3.0.0)
|
|
22
|
+
Description-Content-Type: text/markdown
|
|
23
|
+
|
|
24
|
+
# /user_profiler/agenticmem/agenticmem_client
|
|
25
|
+
Description: Python SDK for remote async access to AgenticMem API
|
|
26
|
+
|
|
27
|
+
## Main Entry Points
|
|
28
|
+
|
|
29
|
+
- **Client**: `agenticmem/client.py` - `AgenticMemClient`
|
|
30
|
+
- **Utils**: `agenticmem/client_utils.py` - Helper utilities
|
|
31
|
+
|
|
32
|
+
## Purpose
|
|
33
|
+
|
|
34
|
+
1. **Remote API access** - Async SDK for applications to call AgenticMem backend
|
|
35
|
+
2. **Authentication** - Handle login and Bearer token management
|
|
36
|
+
3. **Type-safe interface** - Auto-parsing responses into Pydantic models
|
|
37
|
+
|
|
38
|
+
## API Methods
|
|
39
|
+
|
|
40
|
+
**Authentication:**
|
|
41
|
+
- `login(email, password)` - Get auth token
|
|
42
|
+
|
|
43
|
+
**Publishing:**
|
|
44
|
+
- `publish_interaction(request_id, user_id, interactions, source, agent_version)` - Publish interactions (triggers profile/feedback/evaluation)
|
|
45
|
+
|
|
46
|
+
**Profiles:**
|
|
47
|
+
- `search_profiles(request)` - Semantic search
|
|
48
|
+
- `get_profiles(request)` - Get all for user
|
|
49
|
+
- `delete_profile(user_id, profile_id, search_query)` - Delete profiles
|
|
50
|
+
- `get_profile_change_log()` - Get history
|
|
51
|
+
|
|
52
|
+
**Interactions:**
|
|
53
|
+
- `search_interactions(request)` - Semantic search
|
|
54
|
+
- `get_interactions(request)` - Get all for user
|
|
55
|
+
- `delete_interaction(user_id, interaction_id)` - Delete interaction
|
|
56
|
+
|
|
57
|
+
**Feedback:**
|
|
58
|
+
- `get_raw_feedbacks(request)` - Raw feedback from interactions
|
|
59
|
+
- `get_feedbacks(request)` - Aggregated feedback with status
|
|
60
|
+
|
|
61
|
+
**Configuration:**
|
|
62
|
+
- `set_config(config)` - Update org config (extractors, evaluators, storage)
|
|
63
|
+
- `get_config()` - Get current config
|
|
64
|
+
|
|
65
|
+
## Architecture Pattern
|
|
66
|
+
|
|
67
|
+
- **All async** - Uses `aiohttp` for HTTP requests
|
|
68
|
+
- **Type-safe** - Pydantic models from `agenticmem_commons`
|
|
69
|
+
- **Auto-parsing** - Responses → Pydantic models
|
|
70
|
+
- **Flexible input** - Accepts Pydantic models or dicts
|
|
71
|
+
- **Bearer auth** - Automatic token handling
|
|
72
|
+
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
agenticmem/__init__.py,sha256=nSrWdD87z0hbmqVzZxt4xiSccgKyAQOkXosvZlte1ps,1794
|
|
2
|
+
agenticmem/client.py,sha256=v7B16F8X-r7vF1tFi_BVJw1KjB7vK3118VhRREBqvY8,18542
|
|
3
|
+
agenticmem/client_utils.py,sha256=kWTWlyO7s768v38ef41nRDq87Qmb60NX2vmZTVlCB6g,297
|
|
4
|
+
agenticmem-0.1.3.8.dist-info/METADATA,sha256=j1tny6rIA2zyt5nGVmpT6Znep0k8L2JE67eXwGWUCEU,2564
|
|
5
|
+
agenticmem-0.1.3.8.dist-info/WHEEL,sha256=fGIA9gx4Qxk2KDKeNJCbOEwSrmLtjWCwzBz351GyrPQ,88
|
|
6
|
+
agenticmem-0.1.3.8.dist-info/RECORD,,
|
|
@@ -1,245 +0,0 @@
|
|
|
1
|
-
Metadata-Version: 2.3
|
|
2
|
-
Name: agenticmem
|
|
3
|
-
Version: 0.1.3.7
|
|
4
|
-
Summary: A Python client for the AgenticMem API
|
|
5
|
-
License: MIT
|
|
6
|
-
Author: AgenticMem Team
|
|
7
|
-
Requires-Python: >=3.10,<4.0
|
|
8
|
-
Classifier: License :: OSI Approved :: MIT License
|
|
9
|
-
Classifier: Programming Language :: Python :: 3
|
|
10
|
-
Classifier: Programming Language :: Python :: 3.10
|
|
11
|
-
Classifier: Programming Language :: Python :: 3.11
|
|
12
|
-
Classifier: Programming Language :: Python :: 3.12
|
|
13
|
-
Classifier: Programming Language :: Python :: 3.13
|
|
14
|
-
Requires-Dist: agenticmem-commons (==0.1.3.7)
|
|
15
|
-
Requires-Dist: aiohttp (>=3.12.9,<4.0.0)
|
|
16
|
-
Requires-Dist: griffe (==0.48.0)
|
|
17
|
-
Requires-Dist: mkdocs-with-pdf (>=0.9.3,<0.10.0)
|
|
18
|
-
Requires-Dist: mkdocstrings[python] (>=0.18.0)
|
|
19
|
-
Requires-Dist: pydantic (>=2.0.0,<3.0.0)
|
|
20
|
-
Requires-Dist: python-dateutil (>=2.8.0,<3.0.0)
|
|
21
|
-
Requires-Dist: requests (>=2.25.0,<3.0.0)
|
|
22
|
-
Description-Content-Type: text/markdown
|
|
23
|
-
|
|
24
|
-
# AgenticMem Python Client
|
|
25
|
-
|
|
26
|
-
A Python client library for interacting with the AgenticMem API. This client provides easy-to-use interfaces for managing user interactions, profiles, configuration, and agent feedback.
|
|
27
|
-
|
|
28
|
-
## Installation
|
|
29
|
-
|
|
30
|
-
```bash
|
|
31
|
-
pip install agenticmem
|
|
32
|
-
```
|
|
33
|
-
|
|
34
|
-
## Quick Start
|
|
35
|
-
|
|
36
|
-
```python
|
|
37
|
-
import agenticmem
|
|
38
|
-
from agenticmem import (
|
|
39
|
-
InteractionRequest,
|
|
40
|
-
SearchUserProfileRequest,
|
|
41
|
-
SearchInteractionRequest,
|
|
42
|
-
UserActionType
|
|
43
|
-
)
|
|
44
|
-
from datetime import datetime
|
|
45
|
-
|
|
46
|
-
# Initialize the client
|
|
47
|
-
client = agenticmem.AgenticMemClient(url_endpoint="http://127.0.0.1:8081/")
|
|
48
|
-
|
|
49
|
-
# Login with email/password (async)
|
|
50
|
-
token = await client.login("user@example.com", "password")
|
|
51
|
-
client.api_key = token.api_key
|
|
52
|
-
|
|
53
|
-
# Publish a user interaction (async)
|
|
54
|
-
response = await client.publish_interaction(
|
|
55
|
-
request_id="your_request_id",
|
|
56
|
-
user_id="your_user_id",
|
|
57
|
-
interaction_requests=[
|
|
58
|
-
InteractionRequest(
|
|
59
|
-
role="User",
|
|
60
|
-
content="Hey, this is John. How can I help you today?",
|
|
61
|
-
user_action=UserActionType.NONE,
|
|
62
|
-
user_action_description="",
|
|
63
|
-
interacted_image_url=""
|
|
64
|
-
)
|
|
65
|
-
],
|
|
66
|
-
source="conversation"
|
|
67
|
-
)
|
|
68
|
-
print(f"Published interaction: {response.success} - {response.message}")
|
|
69
|
-
|
|
70
|
-
# Search user profiles (async)
|
|
71
|
-
profiles = await client.search_profiles(
|
|
72
|
-
request=SearchUserProfileRequest(
|
|
73
|
-
user_id="your_user_id",
|
|
74
|
-
query="john",
|
|
75
|
-
threshold=0.7
|
|
76
|
-
)
|
|
77
|
-
)
|
|
78
|
-
for profile in profiles.user_profiles:
|
|
79
|
-
print(f"Profile {profile.profile_id}: {profile.profile_content}")
|
|
80
|
-
|
|
81
|
-
# Search interactions (async)
|
|
82
|
-
interactions = await client.search_interactions(
|
|
83
|
-
request=SearchInteractionRequest(
|
|
84
|
-
user_id="your_user_id",
|
|
85
|
-
query="name is john"
|
|
86
|
-
)
|
|
87
|
-
)
|
|
88
|
-
for interaction in interactions.interactions:
|
|
89
|
-
print(f"Interaction {interaction.interaction_id}: {interaction.content}")
|
|
90
|
-
|
|
91
|
-
# Get all interactions (async)
|
|
92
|
-
all_interactions = await client.get_interactions(
|
|
93
|
-
request={"user_id": "your_user_id", "top_k": 10}
|
|
94
|
-
)
|
|
95
|
-
for interaction in all_interactions.interactions:
|
|
96
|
-
print(f"Interaction: {interaction.content}")
|
|
97
|
-
|
|
98
|
-
# Get all profiles (async)
|
|
99
|
-
all_profiles = await client.get_profiles(
|
|
100
|
-
request={"user_id": "your_user_id", "top_k": 10}
|
|
101
|
-
)
|
|
102
|
-
for profile in all_profiles.user_profiles:
|
|
103
|
-
print(f"Profile: {profile.profile_content}")
|
|
104
|
-
|
|
105
|
-
# Get profile change log (async)
|
|
106
|
-
change_log = await client.get_profile_change_log()
|
|
107
|
-
print(f"Profile changes: {len(change_log.profile_change_logs)} logs")
|
|
108
|
-
```
|
|
109
|
-
|
|
110
|
-
## Features
|
|
111
|
-
|
|
112
|
-
### Authentication
|
|
113
|
-
- Email/password login (async)
|
|
114
|
-
- API key authentication
|
|
115
|
-
- Custom endpoint configuration
|
|
116
|
-
|
|
117
|
-
### User Interaction Management
|
|
118
|
-
- Publish user interactions (text, images, actions)
|
|
119
|
-
- Search interactions with semantic queries
|
|
120
|
-
- Get direct list of interactions
|
|
121
|
-
- Delete specific interactions
|
|
122
|
-
- Support for various interaction types (text, visual, click events)
|
|
123
|
-
|
|
124
|
-
### User Profile Management
|
|
125
|
-
- Search user profiles with semantic queries
|
|
126
|
-
- Get direct list of user profiles
|
|
127
|
-
- Delete specific profiles or profiles matching search queries
|
|
128
|
-
- View profile change log history
|
|
129
|
-
- Filter by source and custom features
|
|
130
|
-
|
|
131
|
-
### Configuration Management
|
|
132
|
-
- Get and set AgenticMem configuration
|
|
133
|
-
- Configure profile extractors
|
|
134
|
-
- Configure agent feedback systems
|
|
135
|
-
- Storage configuration (Supabase, S3, Local)
|
|
136
|
-
|
|
137
|
-
### Agent Feedback System
|
|
138
|
-
- Get raw feedbacks from user interactions
|
|
139
|
-
- Get aggregated feedbacks
|
|
140
|
-
- Automatic feedback generation based on conversations
|
|
141
|
-
- Configurable feedback thresholds
|
|
142
|
-
|
|
143
|
-
## API Response Types
|
|
144
|
-
|
|
145
|
-
All API methods return strongly-typed responses:
|
|
146
|
-
|
|
147
|
-
### Authentication
|
|
148
|
-
- `login()` returns `Token`
|
|
149
|
-
|
|
150
|
-
### Interaction Management
|
|
151
|
-
- `publish_interaction()` returns `PublishUserInteractionResponse`
|
|
152
|
-
- `search_interactions()` returns `SearchInteractionResponse`
|
|
153
|
-
- `get_interactions()` returns `GetInteractionsResponse`
|
|
154
|
-
- `delete_interaction()` returns `DeleteUserInteractionResponse`
|
|
155
|
-
|
|
156
|
-
### Profile Management
|
|
157
|
-
- `search_profiles()` returns `SearchUserProfileResponse`
|
|
158
|
-
- `get_profiles()` returns `GetUserProfilesResponse`
|
|
159
|
-
- `delete_profile()` returns `DeleteUserProfileResponse`
|
|
160
|
-
- `get_profile_change_log()` returns `ProfileChangeLogResponse`
|
|
161
|
-
|
|
162
|
-
### Configuration Management
|
|
163
|
-
- `get_config()` returns `Config`
|
|
164
|
-
- `set_config()` returns `dict`
|
|
165
|
-
|
|
166
|
-
### Feedback Management
|
|
167
|
-
- `get_raw_feedbacks()` returns `GetRawFeedbacksResponse`
|
|
168
|
-
- `get_feedbacks()` returns `GetFeedbacksResponse`
|
|
169
|
-
|
|
170
|
-
## Advanced Usage Examples
|
|
171
|
-
|
|
172
|
-
### Visual Interactions with Images
|
|
173
|
-
|
|
174
|
-
```python
|
|
175
|
-
import base64
|
|
176
|
-
|
|
177
|
-
# Function to encode the image
|
|
178
|
-
def encode_image(image_path):
|
|
179
|
-
with open(image_path, "rb") as image_file:
|
|
180
|
-
return base64.b64encode(image_file.read()).decode("utf-8")
|
|
181
|
-
|
|
182
|
-
# Publish image interaction
|
|
183
|
-
base64_image = encode_image("./path/to/image.png")
|
|
184
|
-
await client.publish_interaction(
|
|
185
|
-
request_id="your_request_id",
|
|
186
|
-
user_id="your_user_id",
|
|
187
|
-
interaction_requests=[
|
|
188
|
-
InteractionRequest(
|
|
189
|
-
content="I like this",
|
|
190
|
-
image_encoding=base64_image,
|
|
191
|
-
)
|
|
192
|
-
]
|
|
193
|
-
)
|
|
194
|
-
```
|
|
195
|
-
|
|
196
|
-
### Configuration Management
|
|
197
|
-
|
|
198
|
-
```python
|
|
199
|
-
from agenticmem import ProfileExtractorConfig, AgentFeedbackConfig, FeedbackAggregatorConfig
|
|
200
|
-
|
|
201
|
-
# Get current configuration
|
|
202
|
-
config = await client.get_config()
|
|
203
|
-
print(f"Current config: {config}")
|
|
204
|
-
|
|
205
|
-
# Update configuration
|
|
206
|
-
feedback_config = AgentFeedbackConfig(
|
|
207
|
-
feedback_name="sales_feedback",
|
|
208
|
-
feedback_definition_prompt="Extract actionable feedback for sales representatives",
|
|
209
|
-
feedback_aggregator_config=FeedbackAggregatorConfig()
|
|
210
|
-
)
|
|
211
|
-
|
|
212
|
-
config.agent_feedback_configs = [feedback_config]
|
|
213
|
-
await client.set_config(config)
|
|
214
|
-
```
|
|
215
|
-
|
|
216
|
-
### Feedback Management
|
|
217
|
-
|
|
218
|
-
```python
|
|
219
|
-
# Get raw feedbacks
|
|
220
|
-
raw_feedbacks = await client.get_raw_feedbacks()
|
|
221
|
-
for feedback in raw_feedbacks.raw_feedbacks:
|
|
222
|
-
print(f"Feedback: {feedback.feedback_content}")
|
|
223
|
-
|
|
224
|
-
# Get aggregated feedbacks
|
|
225
|
-
feedbacks = await client.get_feedbacks()
|
|
226
|
-
for feedback in feedbacks.feedbacks:
|
|
227
|
-
print(f"Aggregated feedback: {feedback}")
|
|
228
|
-
```
|
|
229
|
-
|
|
230
|
-
## Documentation
|
|
231
|
-
|
|
232
|
-
For detailed documentation, please visit the `docs/` directory in this repository.
|
|
233
|
-
|
|
234
|
-
## Important Notes
|
|
235
|
-
|
|
236
|
-
- All client methods are **async** and require `await`
|
|
237
|
-
- Image interactions support base64 encoded images
|
|
238
|
-
- The client supports flexible request types (dict or typed objects)
|
|
239
|
-
- Configuration changes affect the entire organization
|
|
240
|
-
- Feedback generation is automatic based on configured prompts
|
|
241
|
-
|
|
242
|
-
## License
|
|
243
|
-
|
|
244
|
-
MIT License
|
|
245
|
-
|
|
@@ -1,6 +0,0 @@
|
|
|
1
|
-
agenticmem/__init__.py,sha256=2AOIWHjfEbGNBa8QAlfqWoMbKzK4T_ixXv9-EyRfbnE,1804
|
|
2
|
-
agenticmem/client.py,sha256=Rpmz_4UTXcO3ckOsLQZBBSkXrX0YO5YKjepUNnkheOE,12137
|
|
3
|
-
agenticmem/client_utils.py,sha256=kWTWlyO7s768v38ef41nRDq87Qmb60NX2vmZTVlCB6g,297
|
|
4
|
-
agenticmem-0.1.3.7.dist-info/METADATA,sha256=epRBEcQ-7msg7y-SfPQMIDTASJrDZJbn4aAqg8nRng0,7165
|
|
5
|
-
agenticmem-0.1.3.7.dist-info/WHEEL,sha256=fGIA9gx4Qxk2KDKeNJCbOEwSrmLtjWCwzBz351GyrPQ,88
|
|
6
|
-
agenticmem-0.1.3.7.dist-info/RECORD,,
|
|
File without changes
|