agenticmem 0.1.3.7__tar.gz → 0.1.3.8__tar.gz

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.

@@ -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,48 @@
1
+ # /user_profiler/agenticmem/agenticmem_client
2
+ Description: Python SDK for remote async access to AgenticMem API
3
+
4
+ ## Main Entry Points
5
+
6
+ - **Client**: `agenticmem/client.py` - `AgenticMemClient`
7
+ - **Utils**: `agenticmem/client_utils.py` - Helper utilities
8
+
9
+ ## Purpose
10
+
11
+ 1. **Remote API access** - Async SDK for applications to call AgenticMem backend
12
+ 2. **Authentication** - Handle login and Bearer token management
13
+ 3. **Type-safe interface** - Auto-parsing responses into Pydantic models
14
+
15
+ ## API Methods
16
+
17
+ **Authentication:**
18
+ - `login(email, password)` - Get auth token
19
+
20
+ **Publishing:**
21
+ - `publish_interaction(request_id, user_id, interactions, source, agent_version)` - Publish interactions (triggers profile/feedback/evaluation)
22
+
23
+ **Profiles:**
24
+ - `search_profiles(request)` - Semantic search
25
+ - `get_profiles(request)` - Get all for user
26
+ - `delete_profile(user_id, profile_id, search_query)` - Delete profiles
27
+ - `get_profile_change_log()` - Get history
28
+
29
+ **Interactions:**
30
+ - `search_interactions(request)` - Semantic search
31
+ - `get_interactions(request)` - Get all for user
32
+ - `delete_interaction(user_id, interaction_id)` - Delete interaction
33
+
34
+ **Feedback:**
35
+ - `get_raw_feedbacks(request)` - Raw feedback from interactions
36
+ - `get_feedbacks(request)` - Aggregated feedback with status
37
+
38
+ **Configuration:**
39
+ - `set_config(config)` - Update org config (extractors, evaluators, storage)
40
+ - `get_config()` - Get current config
41
+
42
+ ## Architecture Pattern
43
+
44
+ - **All async** - Uses `aiohttp` for HTTP requests
45
+ - **Type-safe** - Pydantic models from `agenticmem_commons`
46
+ - **Auto-parsing** - Responses → Pydantic models
47
+ - **Flexible input** - Accepts Pydantic models or dicts
48
+ - **Bearer auth** - Automatic token handling
@@ -2,7 +2,7 @@ __app_name__ = "agenticmem"
2
2
  __version__ = "0.1.1"
3
3
 
4
4
 
5
- from agenticmem.client import AgenticMemClient
5
+ from .client import AgenticMemClient
6
6
  from agenticmem_commons.api_schema.service_schemas import (
7
7
  UserActionType,
8
8
  ProfileTimeToLive,
@@ -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
- headers = headers or {}
67
- if self.api_key:
68
- headers.update(
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=headers, **kwargs
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
- if self.api_key:
98
- self.session.headers.update(
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
- self.session.headers.update(headers)
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
- async def login(self, email: str, password: str) -> Token:
111
- """Async login to the AgenticMem API."""
112
- response = await self._make_async_request(
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
- async def publish_interaction(
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
- ) -> PublishUserInteractionResponse:
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
- async def search_interactions(
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
- if isinstance(request, dict):
176
- request = SearchInteractionRequest(**request)
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
- async def search_profiles(
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
- if isinstance(request, dict):
197
- request = SearchUserProfileRequest(**request)
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
- async def delete_profile(
204
- self, user_id: str, profile_id: str = "", search_query: str = ""
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
- response = await self._make_async_request(
222
- "DELETE", "/api/delete_profile", json=request.model_dump()
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 DeleteUserProfileResponse(**response)
365
+ return DeleteUserInteractionResponse(**response)
225
366
 
226
- async def delete_interaction(
227
- self, user_id: str, interaction_id: str
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
- async def get_profile_change_log(self) -> ProfileChangeLogResponse:
247
- response = await self._make_async_request("GET", "/api/profile_change_log")
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
- async def get_interactions(
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
- if isinstance(request, dict):
263
- request = GetInteractionsRequest(**request)
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
- async def get_profiles(
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
- if isinstance(request, dict):
284
- request = GetUserProfilesRequest(**request)
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
- async def set_config(self, config: Union[Config, dict]) -> dict:
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
- if isinstance(config, dict):
302
- config = Config(**config)
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
- async def get_config(self) -> Config:
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 = await self._make_async_request(
481
+ response = self._make_request(
317
482
  "GET",
318
483
  "/api/get_config",
319
484
  )
320
485
  return Config(**response)
321
486
 
322
- async def get_raw_feedbacks(
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
- elif isinstance(request, dict):
337
- request = GetRawFeedbacksRequest(**request)
338
- response = await self._make_async_request(
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
- async def get_feedbacks(
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
- elif isinstance(request, dict):
360
- request = GetFeedbacksRequest(**request)
361
- response = await self._make_async_request(
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(),
@@ -1,6 +1,6 @@
1
1
  [tool.poetry]
2
2
  name = "agenticmem"
3
- version = "0.1.3.7"
3
+ version = "0.1.3.8"
4
4
  description = "A Python client for the AgenticMem API"
5
5
  authors = ["AgenticMem Team"]
6
6
  readme = "README.md"
@@ -12,7 +12,7 @@ python = "^3.10"
12
12
  requests = "^2.25.0"
13
13
  pydantic = "^2.0.0"
14
14
  python-dateutil = "^2.8.0"
15
- agenticmem-commons = "0.1.3.7"
15
+ agenticmem-commons = "0.1.3.8"
16
16
  mkdocstrings = {version = ">=0.18.0", extras = ["python"]}
17
17
  griffe = "0.48.0"
18
18
  aiohttp = "^3.12.9"
@@ -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,221 +0,0 @@
1
- # AgenticMem Python Client
2
-
3
- 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.
4
-
5
- ## Installation
6
-
7
- ```bash
8
- pip install agenticmem
9
- ```
10
-
11
- ## Quick Start
12
-
13
- ```python
14
- import agenticmem
15
- from agenticmem import (
16
- InteractionRequest,
17
- SearchUserProfileRequest,
18
- SearchInteractionRequest,
19
- UserActionType
20
- )
21
- from datetime import datetime
22
-
23
- # Initialize the client
24
- client = agenticmem.AgenticMemClient(url_endpoint="http://127.0.0.1:8081/")
25
-
26
- # Login with email/password (async)
27
- token = await client.login("user@example.com", "password")
28
- client.api_key = token.api_key
29
-
30
- # Publish a user interaction (async)
31
- response = await client.publish_interaction(
32
- request_id="your_request_id",
33
- user_id="your_user_id",
34
- interaction_requests=[
35
- InteractionRequest(
36
- role="User",
37
- content="Hey, this is John. How can I help you today?",
38
- user_action=UserActionType.NONE,
39
- user_action_description="",
40
- interacted_image_url=""
41
- )
42
- ],
43
- source="conversation"
44
- )
45
- print(f"Published interaction: {response.success} - {response.message}")
46
-
47
- # Search user profiles (async)
48
- profiles = await client.search_profiles(
49
- request=SearchUserProfileRequest(
50
- user_id="your_user_id",
51
- query="john",
52
- threshold=0.7
53
- )
54
- )
55
- for profile in profiles.user_profiles:
56
- print(f"Profile {profile.profile_id}: {profile.profile_content}")
57
-
58
- # Search interactions (async)
59
- interactions = await client.search_interactions(
60
- request=SearchInteractionRequest(
61
- user_id="your_user_id",
62
- query="name is john"
63
- )
64
- )
65
- for interaction in interactions.interactions:
66
- print(f"Interaction {interaction.interaction_id}: {interaction.content}")
67
-
68
- # Get all interactions (async)
69
- all_interactions = await client.get_interactions(
70
- request={"user_id": "your_user_id", "top_k": 10}
71
- )
72
- for interaction in all_interactions.interactions:
73
- print(f"Interaction: {interaction.content}")
74
-
75
- # Get all profiles (async)
76
- all_profiles = await client.get_profiles(
77
- request={"user_id": "your_user_id", "top_k": 10}
78
- )
79
- for profile in all_profiles.user_profiles:
80
- print(f"Profile: {profile.profile_content}")
81
-
82
- # Get profile change log (async)
83
- change_log = await client.get_profile_change_log()
84
- print(f"Profile changes: {len(change_log.profile_change_logs)} logs")
85
- ```
86
-
87
- ## Features
88
-
89
- ### Authentication
90
- - Email/password login (async)
91
- - API key authentication
92
- - Custom endpoint configuration
93
-
94
- ### User Interaction Management
95
- - Publish user interactions (text, images, actions)
96
- - Search interactions with semantic queries
97
- - Get direct list of interactions
98
- - Delete specific interactions
99
- - Support for various interaction types (text, visual, click events)
100
-
101
- ### User Profile Management
102
- - Search user profiles with semantic queries
103
- - Get direct list of user profiles
104
- - Delete specific profiles or profiles matching search queries
105
- - View profile change log history
106
- - Filter by source and custom features
107
-
108
- ### Configuration Management
109
- - Get and set AgenticMem configuration
110
- - Configure profile extractors
111
- - Configure agent feedback systems
112
- - Storage configuration (Supabase, S3, Local)
113
-
114
- ### Agent Feedback System
115
- - Get raw feedbacks from user interactions
116
- - Get aggregated feedbacks
117
- - Automatic feedback generation based on conversations
118
- - Configurable feedback thresholds
119
-
120
- ## API Response Types
121
-
122
- All API methods return strongly-typed responses:
123
-
124
- ### Authentication
125
- - `login()` returns `Token`
126
-
127
- ### Interaction Management
128
- - `publish_interaction()` returns `PublishUserInteractionResponse`
129
- - `search_interactions()` returns `SearchInteractionResponse`
130
- - `get_interactions()` returns `GetInteractionsResponse`
131
- - `delete_interaction()` returns `DeleteUserInteractionResponse`
132
-
133
- ### Profile Management
134
- - `search_profiles()` returns `SearchUserProfileResponse`
135
- - `get_profiles()` returns `GetUserProfilesResponse`
136
- - `delete_profile()` returns `DeleteUserProfileResponse`
137
- - `get_profile_change_log()` returns `ProfileChangeLogResponse`
138
-
139
- ### Configuration Management
140
- - `get_config()` returns `Config`
141
- - `set_config()` returns `dict`
142
-
143
- ### Feedback Management
144
- - `get_raw_feedbacks()` returns `GetRawFeedbacksResponse`
145
- - `get_feedbacks()` returns `GetFeedbacksResponse`
146
-
147
- ## Advanced Usage Examples
148
-
149
- ### Visual Interactions with Images
150
-
151
- ```python
152
- import base64
153
-
154
- # Function to encode the image
155
- def encode_image(image_path):
156
- with open(image_path, "rb") as image_file:
157
- return base64.b64encode(image_file.read()).decode("utf-8")
158
-
159
- # Publish image interaction
160
- base64_image = encode_image("./path/to/image.png")
161
- await client.publish_interaction(
162
- request_id="your_request_id",
163
- user_id="your_user_id",
164
- interaction_requests=[
165
- InteractionRequest(
166
- content="I like this",
167
- image_encoding=base64_image,
168
- )
169
- ]
170
- )
171
- ```
172
-
173
- ### Configuration Management
174
-
175
- ```python
176
- from agenticmem import ProfileExtractorConfig, AgentFeedbackConfig, FeedbackAggregatorConfig
177
-
178
- # Get current configuration
179
- config = await client.get_config()
180
- print(f"Current config: {config}")
181
-
182
- # Update configuration
183
- feedback_config = AgentFeedbackConfig(
184
- feedback_name="sales_feedback",
185
- feedback_definition_prompt="Extract actionable feedback for sales representatives",
186
- feedback_aggregator_config=FeedbackAggregatorConfig()
187
- )
188
-
189
- config.agent_feedback_configs = [feedback_config]
190
- await client.set_config(config)
191
- ```
192
-
193
- ### Feedback Management
194
-
195
- ```python
196
- # Get raw feedbacks
197
- raw_feedbacks = await client.get_raw_feedbacks()
198
- for feedback in raw_feedbacks.raw_feedbacks:
199
- print(f"Feedback: {feedback.feedback_content}")
200
-
201
- # Get aggregated feedbacks
202
- feedbacks = await client.get_feedbacks()
203
- for feedback in feedbacks.feedbacks:
204
- print(f"Aggregated feedback: {feedback}")
205
- ```
206
-
207
- ## Documentation
208
-
209
- For detailed documentation, please visit the `docs/` directory in this repository.
210
-
211
- ## Important Notes
212
-
213
- - All client methods are **async** and require `await`
214
- - Image interactions support base64 encoded images
215
- - The client supports flexible request types (dict or typed objects)
216
- - Configuration changes affect the entire organization
217
- - Feedback generation is automatic based on configured prompts
218
-
219
- ## License
220
-
221
- MIT License