recallrai 0.5.4__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.
@@ -0,0 +1,911 @@
1
+ Metadata-Version: 2.4
2
+ Name: recallrai
3
+ Version: 0.5.4
4
+ Summary: Official Python SDK for RecallrAI - Revolutionary contextual memory system that enables AI assistants to form meaningful connections between conversations, just like human memory.
5
+ License: MIT
6
+ Keywords: ai,memory,context,llm,mem0,getzep,zep
7
+ Author: Devasheesh Mishra
8
+ Author-email: devasheesh@recallrai.com
9
+ Requires-Python: >=3.9,<3.15
10
+ Classifier: Intended Audience :: Developers
11
+ Classifier: License :: OSI Approved :: MIT License
12
+ Classifier: Operating System :: OS Independent
13
+ Classifier: Programming Language :: Python :: 3
14
+ Classifier: Programming Language :: Python :: 3.9
15
+ Classifier: Programming Language :: Python :: 3.10
16
+ Classifier: Programming Language :: Python :: 3.11
17
+ Classifier: Programming Language :: Python :: 3.12
18
+ Classifier: Programming Language :: Python :: 3.13
19
+ Classifier: Programming Language :: Python :: 3.14
20
+ Requires-Dist: httpx (>=0.28.1,<0.29.0)
21
+ Requires-Dist: pydantic (>=2.11.1,<3.0.0)
22
+ Project-URL: Homepage, https://recallrai.com
23
+ Project-URL: Repository, https://github.com/recallrai/sdk-python
24
+ Description-Content-Type: text/markdown
25
+
26
+ # RecallrAI Python SDK
27
+
28
+ Official Python SDK for RecallrAI – a revolutionary contextual memory system that enables AI assistants to form meaningful connections between conversations, just like human memory.
29
+
30
+ **Note:** All datetime objects returned by the SDK are in UTC timezone.
31
+
32
+ ## Installation
33
+
34
+ Install the SDK via Poetry or pip:
35
+
36
+ ```bash
37
+ poetry add recallrai
38
+ # or
39
+ pip install recallrai
40
+ ```
41
+
42
+ ## Async Support
43
+
44
+ The SDK provides full async/await support for all operations! Use `AsyncRecallrAI`, `AsyncUser`, and `AsyncSession` for async applications. All usage patterns are identical to the sync versions, just with `await` keywords.
45
+
46
+ ## Initialization
47
+
48
+ Create a client instance with your API key and project ID:
49
+
50
+ ```python
51
+ from recallrai import RecallrAI
52
+
53
+ client = RecallrAI(
54
+ api_key="rai_yourapikey",
55
+ project_id="project-uuid",
56
+ base_url="https://api.recallrai.com", # custom endpoint if applicable
57
+ timeout=60, # seconds
58
+ )
59
+ ```
60
+
61
+ ## User Management
62
+
63
+ ### Create a User
64
+
65
+ ```python
66
+ from recallrai.exceptions import UserAlreadyExistsError
67
+ try:
68
+ user = client.create_user(user_id="user123", metadata={"name": "John Doe"})
69
+ print(f"Created user: {user.user_id}")
70
+ print(f"User metadata: {user.metadata}")
71
+ print(f"Created at: {user.created_at}")
72
+ except UserAlreadyExistsError as e:
73
+ print(f"Error: {e}")
74
+ ```
75
+
76
+ ### Get a User
77
+
78
+ ```python
79
+ from recallrai.exceptions import UserNotFoundError
80
+ try:
81
+ user = client.get_user("user123")
82
+ print(f"User metadata: {user.metadata}")
83
+ print(f"Last active: {user.last_active_at}")
84
+ except UserNotFoundError as e:
85
+ print(f"Error: {e}")
86
+ ```
87
+
88
+ ### List Users
89
+
90
+ ```python
91
+ user_list = client.list_users(offset=0, limit=10, metadata_filter={"role": "admin"})
92
+ print(f"Total users: {user_list.total}")
93
+ print(f"Has more users: {user_list.has_more}")
94
+ print("---")
95
+
96
+ for u in user_list.users:
97
+ print(f"User ID: {u.user_id}")
98
+ print(f"Metadata: {u.metadata}")
99
+ print(f"Created at: {u.created_at}")
100
+ print(f"Last active: {u.last_active_at}")
101
+ print("---")
102
+ ```
103
+
104
+ ### Update a User
105
+
106
+ ```python
107
+ from recallrai.exceptions import UserNotFoundError, UserAlreadyExistsError
108
+ try:
109
+ user = client.get_user("user123")
110
+ # update() mutates the instance; no value is returned
111
+ user.update(
112
+ new_metadata={"name": "John Doe", "role": "admin"},
113
+ new_user_id="john_doe"
114
+ )
115
+ print(f"Updated user ID: {user.user_id}")
116
+ print(f"Updated metadata: {user.metadata}")
117
+ print(f"Last active: {user.last_active_at}")
118
+ except UserNotFoundError as e:
119
+ print(f"Error: {e}")
120
+ except UserAlreadyExistsError as e:
121
+ print(f"Error: {e}")
122
+ ```
123
+
124
+ ### Refresh User Instance
125
+
126
+ ```python
127
+ from recallrai.exceptions import UserNotFoundError
128
+ try:
129
+ user = client.get_user("john_doe")
130
+ user.refresh()
131
+ print(f"Refreshed user metadata: {user.metadata}")
132
+ print(f"Last active: {user.last_active_at}")
133
+ except UserNotFoundError as e:
134
+ print(f"Error: {e}")
135
+ ```
136
+
137
+ ### Delete a User
138
+
139
+ ```python
140
+ from recallrai.exceptions import UserNotFoundError
141
+ try:
142
+ user = client.get_user("john_doe")
143
+ user.delete()
144
+ print("User deleted successfully")
145
+ except UserNotFoundError as e:
146
+ print(f"Error: {e}")
147
+ ```
148
+
149
+ ## Session Management
150
+
151
+ ### Create a Session
152
+
153
+ ```python
154
+ from recallrai.exceptions import UserNotFoundError
155
+ from recallrai.session import Session
156
+
157
+ try:
158
+ # First, get the user
159
+ user = client.get_user("user123")
160
+
161
+ # Create a session for the user.
162
+ session: Session = user.create_session(
163
+ auto_process_after_seconds=600,
164
+ metadata={"type": "chat"}
165
+ )
166
+ print("Created session id:", session.session_id)
167
+ except UserNotFoundError as e:
168
+ print(f"Error: {e}")
169
+ ```
170
+
171
+ ### Get an Existing Session
172
+
173
+ ```python
174
+ from recallrai.exceptions import UserNotFoundError, SessionNotFoundError
175
+
176
+ try:
177
+ # First, get the user
178
+ user = client.get_user("user123")
179
+
180
+ # Retrieve an existing session by its ID
181
+ session = user.get_session(session_id="session-uuid")
182
+ print("Session status:", session.status)
183
+ print("Session metadata:", session.metadata)
184
+ except UserNotFoundError as e:
185
+ print(f"Error: {e}")
186
+ except SessionNotFoundError as e:
187
+ print(f"Error: {e}")
188
+ ```
189
+
190
+ ### Update a Session
191
+
192
+ ```python
193
+ from recallrai.exceptions import UserNotFoundError, SessionNotFoundError
194
+ try:
195
+ # First, get the user
196
+ user = client.get_user("user123")
197
+
198
+ # Retrieve an existing session by its ID
199
+ session = user.get_session(session_id="session-uuid")
200
+
201
+ # Update session metadata
202
+ session.update(new_metadata={"type": "support_chat"})
203
+ print("Updated session metadata:", session.metadata)
204
+ except UserNotFoundError as e:
205
+ print(f"Error: {e}")
206
+ except SessionNotFoundError as e:
207
+ print(f"Error: {e}")
208
+ ```
209
+
210
+ ### Refresh a Session
211
+
212
+ ```python
213
+ from recallrai.exceptions import UserNotFoundError, SessionNotFoundError
214
+ try:
215
+ # First, get the user
216
+ user = client.get_user("user123")
217
+
218
+ # Retrieve an existing session by its ID
219
+ session = user.get_session(session_id="session-uuid")
220
+
221
+ # Refresh session data from the server
222
+ session.refresh()
223
+ print("Session status:", session.status)
224
+ print("Refreshed session metadata:", session.metadata)
225
+ except UserNotFoundError as e:
226
+ print(f"Error: {e}")
227
+ except SessionNotFoundError as e:
228
+ print(f"Error: {e}")
229
+ ```
230
+
231
+ ### List Sessions
232
+
233
+ ```python
234
+ from recallrai.models import SessionStatus
235
+ from recallrai.exceptions import UserNotFoundError
236
+
237
+ try:
238
+ # First, get the user
239
+ user = client.get_user("user123")
240
+
241
+ # List sessions for this user with optional filters
242
+ session_list = user.list_sessions(
243
+ offset=0,
244
+ limit=10,
245
+ metadata_filter={"type": "chat"}, # optional: filter by session metadata
246
+ status_filter=[SessionStatus.PENDING, SessionStatus.PROCESSING] # optional: filter by session status
247
+ )
248
+ print(f"Total sessions: {session_list.total}")
249
+ print(f"Has more sessions: {session_list.has_more}")
250
+ for s in session_list.sessions:
251
+ print(s.session_id, s.status, s.metadata)
252
+ except UserNotFoundError as e:
253
+ print(f"Error: {e}")
254
+ ```
255
+
256
+ ### Session – Adding Messages
257
+
258
+ ```python
259
+ from recallrai.exceptions import UserNotFoundError, SessionNotFoundError, InvalidSessionStateError
260
+ from recallrai.models import MessageRole
261
+
262
+ try:
263
+ # Add a user message
264
+ session.add_message(role=MessageRole.USER, content="Hello! How are you?")
265
+
266
+ # Add an assistant message
267
+ session.add_message(role=MessageRole.ASSISTANT, content="I'm an assistant. How can I help you?")
268
+
269
+ # Available message roles:
270
+ # - MessageRole.USER: Messages from the user/human
271
+ # - MessageRole.ASSISTANT: Messages from the AI assistant
272
+ except UserNotFoundError as e:
273
+ print(f"Error: {e}")
274
+ except SessionNotFoundError as e:
275
+ print(f"Error: {e}")
276
+ except InvalidSessionStateError as e:
277
+ print(f"Error: {e}")
278
+ ```
279
+
280
+ ### Session – Retrieving Context
281
+
282
+ ```python
283
+ from recallrai.exceptions import UserNotFoundError, SessionNotFoundError
284
+ from recallrai.models import RecallStrategy
285
+
286
+ try:
287
+ # Get context with default parameters
288
+ context = session.get_context()
289
+ print("Context:", context.context)
290
+
291
+ # Get context with specific recall strategy
292
+ context = session.get_context(recall_strategy=RecallStrategy.LOW_LATENCY)
293
+ print("Context:", context.context)
294
+
295
+ # Get context with custom memory retrieval parameters
296
+ context = session.get_context(
297
+ recall_strategy=RecallStrategy.BALANCED,
298
+ min_top_k=10,
299
+ max_top_k=100,
300
+ memories_threshold=0.6,
301
+ summaries_threshold=0.5,
302
+ last_n_messages=20,
303
+ last_n_summaries=5,
304
+ timezone="America/Los_Angeles" # Optional: timezone for timestamp formatting, None for UTC
305
+ )
306
+ print("Context:", context.context)
307
+
308
+ # Available recall strategies:
309
+ # - RecallStrategy.LOW_LATENCY: Fast retrieval with basic relevance
310
+ # - RecallStrategy.BALANCED: Good balance of speed and quality (default)
311
+ # - RecallStrategy.DEEP: More thorough but slower memory search
312
+
313
+ # Parameters:
314
+ # - min_top_k: Minimum number of memories to return (default: 15, range: 5-50)
315
+ # - max_top_k: Maximum number of memories to return (default: 50, range: 10-100)
316
+ # - memories_threshold: Similarity threshold for memories (default: 0.6, range: 0.2-0.8)
317
+ # - summaries_threshold: Similarity threshold for summaries (default: 0.5, range: 0.2-0.8)
318
+ # - last_n_messages: Number of last messages to include in context (optional, range: 1-100)
319
+ # - last_n_summaries: Number of last summaries to include in context (optional, range: 1-20)
320
+ # - timezone: Timezone for formatting timestamps (optional, e.g., 'America/New_York', None for UTC)
321
+ # - include_system_prompt: Whether to include the default system prompt of Recallr AI (default: True)
322
+ except UserNotFoundError as e:
323
+ print(f"Error: {e}")
324
+ except SessionNotFoundError as e:
325
+ print(f"Error: {e}")
326
+ ```
327
+
328
+ ### Session – Process Session
329
+
330
+ ```python
331
+ from recallrai.exceptions import UserNotFoundError, SessionNotFoundError, InvalidSessionStateError
332
+
333
+ try:
334
+ session.process()
335
+ except UserNotFoundError as e:
336
+ print(f"Error: {e}")
337
+ except SessionNotFoundError as e:
338
+ print(f"Error: {e}")
339
+ except InvalidSessionStateError as e:
340
+ print(f"Error: {e}")
341
+ ```
342
+
343
+ ### Session – List Messages
344
+
345
+ ```python
346
+ from recallrai.exceptions import UserNotFoundError, SessionNotFoundError
347
+
348
+ try:
349
+ # Paginated retrieval
350
+ messages = session.get_messages(offset=0, limit=50)
351
+ for msg in messages.messages:
352
+ print(f"{msg.role.value.upper()} (at {msg.timestamp}): {msg.content}")
353
+ print(f"Has more?: {messages.has_more}")
354
+ print(f"Total messages: {messages.total}")
355
+ except UserNotFoundError as e:
356
+ print(f"Error: {e}")
357
+ except SessionNotFoundError as e:
358
+ print(f"Error: {e}")
359
+ ```
360
+
361
+ ## User Memories
362
+
363
+ ### List User Memories (with optional category filters)
364
+
365
+ ```python
366
+ from recallrai.exceptions import UserNotFoundError, InvalidCategoriesError
367
+
368
+ try:
369
+ user = client.get_user("user123")
370
+
371
+ # List memories with all available options
372
+ memories = user.list_memories(
373
+ categories=["food_preferences", "allergies"], # optional: filter by categories
374
+ session_id_filter=["session-uuid-1", "session-uuid-2"], # optional: filter by specific sessions
375
+ session_metadata_filter={"environment": "production"}, # optional: filter by session metadata
376
+ offset=0,
377
+ limit=20, # max 200
378
+ include_previous_versions=True, # default: True - include version history
379
+ include_connected_memories=True, # default: True - include related memories
380
+ )
381
+
382
+ for mem in memories.items:
383
+ print(f"Memory ID: {mem.memory_id}")
384
+ print(f"Categories: {mem.categories}")
385
+ print(f"Content: {mem.content}")
386
+ print(f"Created at: {mem.created_at}")
387
+ print(f"Session ID: {mem.session_id}")
388
+
389
+ # Version information
390
+ print(f"Version: {mem.version_number} of {mem.total_versions}")
391
+ print(f"Has previous versions: {mem.has_previous_versions}")
392
+
393
+ # Previous versions (if included)
394
+ if mem.previous_versions:
395
+ print(f"Previous versions: {len(mem.previous_versions)}")
396
+ for version in mem.previous_versions:
397
+ print(f" - Version {version.version_number}: {version.content}")
398
+ print(f" Created: {version.created_at}, Expired: {version.expired_at}")
399
+ print(f" Expiration reason: {version.expiration_reason}")
400
+
401
+ # Connected memories (if included)
402
+ if mem.connected_memories:
403
+ print(f"Connected memories: {len(mem.connected_memories)}")
404
+ for connected in mem.connected_memories:
405
+ print(f" - {connected.memory_id}: {connected.content}")
406
+
407
+ # Merge conflict status
408
+ print(f"Merge conflict in progress: {mem.merge_conflict_in_progress}")
409
+ print("---")
410
+
411
+ print(f"Has more?: {memories.has_more}")
412
+ print(f"Total memories: {memories.total}")
413
+
414
+ except UserNotFoundError as e:
415
+ print(f"Error: {e}")
416
+ except InvalidCategoriesError as e:
417
+ print(f"Invalid categories: {e.invalid_categories}")
418
+ print(f"Error: {e}")
419
+ ```
420
+
421
+ #### Memory Item Fields
422
+
423
+ Each memory item returned contains the following information:
424
+
425
+ - **memory_id**: Unique identifier for the current/latest version of the memory
426
+ - **categories**: List of category strings the memory belongs to
427
+ - **content**: The current version's content text
428
+ - **created_at**: Timestamp when the latest version was created
429
+ - **session_id**: ID of the session that created this version
430
+ - **version_number**: Which version this is (e.g., 3 means this is the 3rd version)
431
+ - **total_versions**: Total number of versions that exist for this memory
432
+ - **has_previous_versions**: Boolean indicating if `total_versions > 1`
433
+ - **previous_versions** (optional): List of `MemoryVersionInfo` objects containing:
434
+ - `version_number`: Sequential version number (1 = oldest)
435
+ - `content`: Content of that version
436
+ - `created_at`: When this version was created
437
+ - `expired_at`: When this version expired
438
+ - `expiration_reason`: Why it expired (e.g., new version created)
439
+ - **connected_memories** (optional): List of `MemoryRelationship` objects containing:
440
+ - `memory_id`: ID of the connected memory
441
+ - `content`: Brief content for context
442
+ - **merge_conflict_in_progress**: Boolean indicating if this memory has an active merge conflict
443
+
444
+ ## User Messages
445
+
446
+ ### Get Last N Messages
447
+
448
+ Retrieve the most recent messages for a user across all their sessions. This is particularly useful for chatbot applications where you need conversation context, such as WhatsApp support bots where you want to pass the last few messages to understand the ongoing conversation.
449
+
450
+ ```python
451
+ from recallrai.exceptions import UserNotFoundError
452
+
453
+ try:
454
+ user = client.get_user("user123")
455
+
456
+ # Fetch last N messages (e.g., last 5)
457
+ messages = user.get_last_n_messages(n=5)
458
+
459
+ for msg in messages.messages:
460
+ print(f"Session ID: {msg.session_id}")
461
+ print(f"{msg.role.upper()} (at {msg.timestamp}): {msg.content}")
462
+ print("---")
463
+
464
+ except UserNotFoundError as e:
465
+ print(f"Error: {e}")
466
+ ```
467
+
468
+ ## Merge Conflict Management
469
+
470
+ When RecallrAI processes sessions, it may detect conflicts between new memories and existing ones. The SDK provides comprehensive tools to handle these merge conflicts, allowing you to guide the resolution process through clarifying questions.
471
+
472
+ ### List Merge Conflicts
473
+
474
+ ```python
475
+ from recallrai.exceptions import UserNotFoundError
476
+ from recallrai.models import MergeConflictStatus
477
+
478
+ try:
479
+ user = client.get_user("user123")
480
+
481
+ # List all merge conflicts (with optional status filter)
482
+ conflicts = user.list_merge_conflicts(
483
+ offset=0,
484
+ limit=10,
485
+ status=MergeConflictStatus.PENDING, # optional: filter by status
486
+ sort_by="created_at", # created_at, resolved_at
487
+ sort_order="desc", # asc, desc
488
+ )
489
+
490
+ print(f"Total conflicts: {conflicts.total}")
491
+ print(f"Has more: {conflicts.has_more}")
492
+
493
+ for conf in conflicts.conflicts:
494
+ print(f"Conflict ID: {conf.conflict_id}")
495
+ print(f"Status: {conf.status}")
496
+ print(f"New memory: {conf.new_memory_content}")
497
+ print(f"Conflicting memories: {len(conf.conflicting_memories)}")
498
+ print(f"Questions: {len(conf.clarifying_questions)}")
499
+ print(f"Created at: {conf.created_at}")
500
+ print("---")
501
+
502
+ except UserNotFoundError as e:
503
+ print(f"Error: {e}")
504
+ ```
505
+
506
+ ### Get a Specific Merge Conflict
507
+
508
+ ```python
509
+ from recallrai.exceptions import UserNotFoundError, MergeConflictNotFoundError
510
+
511
+ try:
512
+ user = client.get_user("user123")
513
+ conflict = user.get_merge_conflict("conflict-uuid")
514
+
515
+ print(f"Conflict ID: {conflict.conflict_id}")
516
+ print(f"Status: {conflict.status.value}")
517
+ print(f"New memory content: {conflict.new_memory_content}")
518
+
519
+ # Examine conflicting memories
520
+ print("\nConflicting memories:")
521
+ for mem in conflict.conflicting_memories:
522
+ print(f" Content: {mem.content}")
523
+ print(f" Reason: {mem.reason}")
524
+ print()
525
+
526
+ # View clarifying questions
527
+ print("Clarifying questions:")
528
+ for ques in conflict.clarifying_questions:
529
+ print(f" Question: {ques.question}")
530
+ print(f" Options: {ques.options}")
531
+ print()
532
+
533
+ except UserNotFoundError as e:
534
+ print(f"Error: {e}")
535
+ except MergeConflictNotFoundError as e:
536
+ print(f"Error: {e}")
537
+ ```
538
+
539
+ ### Resolve a Merge Conflict
540
+
541
+ ```python
542
+ from recallrai.exceptions import (
543
+ UserNotFoundError,
544
+ MergeConflictNotFoundError,
545
+ MergeConflictAlreadyResolvedError,
546
+ MergeConflictInvalidQuestionsError,
547
+ MergeConflictMissingAnswersError,
548
+ MergeConflictInvalidAnswerError,
549
+ ValidationError
550
+ )
551
+ from recallrai.models import MergeConflictAnswer
552
+
553
+ try:
554
+ user = client.get_user("user123")
555
+ conflict = user.get_merge_conflict("conflict-uuid")
556
+
557
+ # Prepare answers to the clarifying questions
558
+ answers = []
559
+ for ques in conflict.clarifying_questions:
560
+ print(f" Question: {ques.question}")
561
+ print(f" Options: {ques.options}")
562
+ print()
563
+
564
+ answer = MergeConflictAnswer(
565
+ question=ques.question,
566
+ answer=ques.options[0], # Select first option
567
+ message="User prefers this option based on recent conversation"
568
+ )
569
+ answers.append(answer)
570
+
571
+ # Resolve the conflict
572
+ conflict.resolve(answers)
573
+ print(f"Conflict resolved! Status: {conflict.status}")
574
+ print(f"Resolved at: {conflict.resolved_at}")
575
+
576
+ if conflict.resolution_data:
577
+ print(f"Resolution data: {conflict.resolution_data}")
578
+
579
+ except UserNotFoundError as e:
580
+ print(f"Error: {e}")
581
+ except MergeConflictNotFoundError as e:
582
+ print(f"Error: {e}")
583
+ except MergeConflictAlreadyResolvedError as e:
584
+ print(f"Error: {e}")
585
+ except MergeConflictInvalidQuestionsError as e:
586
+ print(f"Error: {e}")
587
+ if e.invalid_questions:
588
+ print(f"Invalid questions: {e.invalid_questions}")
589
+ except MergeConflictMissingAnswersError as e:
590
+ print(f"Error: {e}")
591
+ if e.missing_questions:
592
+ print(f"Missing answers for: {e.missing_questions}")
593
+ except MergeConflictInvalidAnswerError as e:
594
+ print(f"Error: {e}")
595
+ if e.question and e.valid_options:
596
+ print(f"Question: {e.question}")
597
+ print(f"Valid options: {e.valid_options}")
598
+ except ValidationError as e:
599
+ print(f"Error: {e}")
600
+ ```
601
+
602
+ ### Refresh Merge Conflict Data
603
+
604
+ ```python
605
+ from recallrai.exceptions import UserNotFoundError, MergeConflictNotFoundError
606
+
607
+ try:
608
+ user = client.get_user("user123")
609
+ conflict = user.get_merge_conflict("conflict-uuid")
610
+
611
+ # Refresh to get latest status from server
612
+ conflict.refresh()
613
+ print(f"Current status: {conflict.status}")
614
+ print(f"Last updated: {conflict.resolved_at}")
615
+
616
+ except UserNotFoundError as e:
617
+ print(f"Error: {e}")
618
+ except MergeConflictNotFoundError as e:
619
+ print(f"Error: {e}")
620
+ ```
621
+
622
+ ### Working with Merge Conflict Statuses
623
+
624
+ The merge conflict system uses several status values to track the lifecycle of conflicts:
625
+
626
+ - **PENDING**: Conflict detected and waiting for resolution
627
+ - **IN_QUEUE**: Conflict is queued for automated processing
628
+ - **RESOLVING**: Conflict is being processed
629
+ - **RESOLVED**: Conflict has been successfully resolved
630
+ - **FAILED**: Conflict resolution failed
631
+
632
+ ## Example Usage with LLMs
633
+
634
+ ```python
635
+ import openai
636
+ from recallrai import RecallrAI
637
+ from recallrai.exceptions import UserNotFoundError
638
+ from recallrai.models import MessageRole
639
+
640
+ # Initialize RecallrAI and OpenAI clients
641
+ rai_client = RecallrAI(
642
+ api_key="rai_yourapikey",
643
+ project_id="your-project-uuid"
644
+ )
645
+ oai_client = openai.OpenAI(api_key="your-openai-api-key")
646
+
647
+ def chat_with_memory(user_id, session_id=None):
648
+ # Get or create user
649
+ try:
650
+ user = rai_client.get_user(user_id)
651
+ except UserNotFoundError:
652
+ user = rai_client.create_user(user_id)
653
+
654
+ # Create a new session or get an existing one
655
+ if session_id:
656
+ session = user.get_session(session_id=session_id)
657
+ else:
658
+ session = user.create_session(auto_process_after_seconds=1800)
659
+ print(f"Created new session: {session.session_id}")
660
+
661
+ print("Chat session started. Type 'exit' to end the conversation.")
662
+
663
+ while True:
664
+ # Get user input
665
+ user_message = input("You: ")
666
+ if user_message.lower() == 'exit':
667
+ break
668
+
669
+ # Add the user message to RecallrAI
670
+ session.add_message(role=MessageRole.USER, content=user_message)
671
+
672
+ # Get context from RecallrAI after adding the user message
673
+ # You can specify a recall strategy for different performance/quality trade-offs
674
+ # Additional parameters like min_top_k, max_top_k, memories_threshold, summaries_threshold, last_n_messages, last_n_summaries are available
675
+ context = session.get_context() # Uses default BALANCED strategy
676
+
677
+ # Create a system prompt that includes the context
678
+ system_prompt = "You are a helpful assistant" + context.context
679
+
680
+ # Get previous messages
681
+ messages = session.get_messages(offset=0, limit=50)
682
+ previous_messages = [{"role": message.role, "content": message.content} for message in messages.messages]
683
+
684
+ # Call the LLM with the system prompt and conversation history
685
+ response = oai_client.chat.completions.create(
686
+ model="gpt-4o-mini",
687
+ messages=[
688
+ {"role": "system", "content": system_prompt},
689
+ **previous_messages,
690
+ ],
691
+ temperature=0.7
692
+ )
693
+
694
+ assistant_message = response.choices[0].message.content
695
+
696
+ # Print the assistant's response
697
+ print(f"Assistant: {assistant_message}")
698
+
699
+ # Add the assistant's response to RecallrAI
700
+ session.add_message(role=MessageRole.ASSISTANT, content=assistant_message)
701
+
702
+ # Process the session at the end of the conversation
703
+ print("Processing session to update memory...")
704
+ session.process()
705
+ print(f"Session ended. Session ID: {session.session_id}")
706
+ return session.session_id
707
+
708
+ # Example usage
709
+ if __name__ == "__main__":
710
+ user_id = "user123"
711
+ # To continue a previous session, uncomment below and provide the session ID
712
+ # previous_session_id = "previously-saved-session-uuid"
713
+ # session_id = chat_with_memory(user_id, previous_session_id)
714
+
715
+ # Start a new session
716
+ session_id = chat_with_memory(user_id)
717
+ print(f"To continue this conversation later, use session ID: {session_id}")
718
+ ```
719
+
720
+ ## Exception Handling
721
+
722
+ The RecallrAI SDK implements a comprehensive exception hierarchy to help you handle different error scenarios gracefully:
723
+
724
+ ### Base Exception
725
+
726
+ - **RecallrAIError**: The base exception for all SDK-specific errors. All other exceptions inherit from this.
727
+
728
+ ### Authentication Errors
729
+
730
+ - **AuthenticationError**: Raised when there's an issue with your API key or project ID authentication.
731
+
732
+ ### Network-Related Errors
733
+
734
+ - **TimeoutError**: Occurs when a request takes too long to complete.
735
+ - **ConnectionError**: Happens when the SDK cannot establish a connection to the RecallrAI API.
736
+
737
+ ### Server Errors
738
+
739
+ - **InternalServerError**: Raised when the RecallrAI API returns a 5xx error code.
740
+ - **RateLimitError**: Raised when the API rate limit has been exceeded (HTTP 429). When available, the `retry_after` value is provided in the exception details.
741
+
742
+ ### User-Related Errors
743
+
744
+ - **UserNotFoundError**: Raised when attempting to access a user that doesn't exist.
745
+ - **UserAlreadyExistsError**: Occurs when creating a user with an ID that already exists.
746
+ - **InvalidCategoriesError**: Raised when filtering user memories by categories that do not exist in the project. The exception contains the list of invalid categories in `e.invalid_categories`.
747
+
748
+ ### Session-Related Errors
749
+
750
+ - **SessionNotFoundError**: Raised when attempting to access a non-existent session.
751
+ - **InvalidSessionStateError**: Occurs when performing an operation that's not valid for the current session state (e.g., adding a message to a processed session).
752
+
753
+ ### Merge Conflict-Related Errors
754
+
755
+ - **MergeConflictError**: Base class for merge conflict-related exceptions.
756
+ - **MergeConflictNotFoundError**: Raised when attempting to access a merge conflict that doesn't exist.
757
+ - **MergeConflictAlreadyResolvedError**: Occurs when trying to resolve a merge conflict that has already been processed.
758
+ - **MergeConflictInvalidQuestionsError**: Raised when the provided questions don't match the original clarifying questions.
759
+ - **MergeConflictMissingAnswersError**: Occurs when not all required clarifying questions have been answered.
760
+ - **MergeConflictInvalidAnswerError**: Raised when an answer is not one of the valid options for a question.
761
+
762
+ ### Input Validation Errors
763
+
764
+ - **ValidationError**: Raised when provided data doesn't meet the required format or constraints.
765
+
766
+ ### Importing Exceptions
767
+
768
+ You can import exceptions directly from the `recallrai.exceptions` module:
769
+
770
+ ```python
771
+ # Import specific exceptions
772
+ from recallrai.exceptions import (
773
+ UserNotFoundError,
774
+ SessionNotFoundError,
775
+ InvalidCategoriesError,
776
+ MergeConflictNotFoundError,
777
+ MergeConflictAlreadyResolvedError,
778
+ MergeConflictInvalidQuestionsError,
779
+ MergeConflictMissingAnswersError,
780
+ MergeConflictInvalidAnswerError,
781
+ )
782
+
783
+ # Import all exceptions
784
+ from recallrai.exceptions import (
785
+ RecallrAIError,
786
+ AuthenticationError,
787
+ TimeoutError,
788
+ ConnectionError,
789
+ InternalServerError,
790
+ RateLimitError,
791
+ SessionNotFoundError,
792
+ InvalidSessionStateError,
793
+ UserNotFoundError,
794
+ UserAlreadyExistsError,
795
+ InvalidCategoriesError,
796
+ ValidationError,
797
+ MergeConflictError,
798
+ MergeConflictNotFoundError,
799
+ MergeConflictAlreadyResolvedError,
800
+ MergeConflictInvalidQuestionsError,
801
+ MergeConflictMissingAnswersError,
802
+ MergeConflictInvalidAnswerError,
803
+ )
804
+ ```
805
+
806
+ ### Exception Hierarchy Diagram
807
+
808
+ ```mermaid
809
+ flowchart LR
810
+ %% Title
811
+ title[Errors and Exceptions Hierarchy]
812
+ style title fill:none,stroke:none
813
+
814
+ %% Base exception class
815
+ Exception[Exception]
816
+ RecallrAIError[RecallrAIError]
817
+
818
+ %% First level exceptions
819
+ AuthenticationError[AuthenticationError]
820
+ NetworkError[NetworkError]
821
+ ServerError[ServerError]
822
+ UserError[UserError]
823
+ SessionError[SessionError]
824
+ MergeConflictError[MergeConflictError]
825
+ ValidationError[ValidationError]
826
+
827
+ %% Second level exceptions - NetworkError children
828
+ TimeoutError[TimeoutError]
829
+ ConnectionError[ConnectionError]
830
+
831
+ %% Second level exceptions - ServerError children
832
+ InternalServerError[Internal ServerError]
833
+ RateLimitError[RateLimitError]
834
+
835
+ %% Second level exceptions - UserError children
836
+ UserNotFoundError[User NotFound Error]
837
+ UserAlreadyExistsError[User AlreadyExists Error]
838
+
839
+ %% Second level exceptions - SessionError children
840
+ InvalidSessionStateError[Invalid SessionState Error]
841
+ SessionNotFoundError[Session NotFound Error]
842
+
843
+ %% Second level exceptions - MergeConflictError children
844
+ MergeConflictNotFoundError[MergeConflict NotFound Error]
845
+ MergeConflictAlreadyResolvedError[MergeConflict AlreadyResolved Error]
846
+ MergeConflictInvalidQuestionsError[MergeConflict InvalidQuestions Error]
847
+ MergeConflictMissingAnswersError[MergeConflict MissingAnswers Error]
848
+ MergeConflictInvalidAnswerError[MergeConflict InvalidAnswer Error]
849
+
850
+ %% Connect parent to base
851
+ Exception --> RecallrAIError
852
+
853
+ %% Connect base to first level
854
+ RecallrAIError --> AuthenticationError
855
+ RecallrAIError --> NetworkError
856
+ RecallrAIError --> ServerError
857
+ RecallrAIError --> UserError
858
+ RecallrAIError --> SessionError
859
+ RecallrAIError --> MergeConflictError
860
+ RecallrAIError --> ValidationError
861
+
862
+ %% Connect first level to second level
863
+ NetworkError --> TimeoutError
864
+ NetworkError --> ConnectionError
865
+ ServerError --> InternalServerError
866
+ ServerError --> RateLimitError
867
+ UserError --> UserNotFoundError
868
+ UserError --> UserAlreadyExistsError
869
+ SessionError --> InvalidSessionStateError
870
+ SessionError --> SessionNotFoundError
871
+ MergeConflictError --> MergeConflictNotFoundError
872
+ MergeConflictError --> MergeConflictAlreadyResolvedError
873
+ MergeConflictError --> MergeConflictInvalidQuestionsError
874
+ MergeConflictError --> MergeConflictMissingAnswersError
875
+ MergeConflictError --> MergeConflictInvalidAnswerError
876
+ ```
877
+
878
+ ### Best Practices for Error Handling
879
+
880
+ When implementing error handling with the RecallrAI SDK, consider these best practices:
881
+
882
+ 1. **Handle specific exceptions first**: Catch more specific exceptions before general ones.
883
+
884
+ ```python
885
+ try:
886
+ # SDK operation
887
+ except UserNotFoundError:
888
+ # Specific handling
889
+ except RecallrAIError:
890
+ # General fallback
891
+ ```
892
+
893
+ 2. **Implement retry logic for transient errors**: Network and timeout errors might be temporary.
894
+
895
+ 3. **Log detailed error information**: Exceptions contain useful information for debugging.
896
+
897
+ 4. **Handle common user flows**: For example, check if a user exists before operations, or create them if they don't:
898
+
899
+ ```python
900
+ try:
901
+ user = client.get_user(user_id)
902
+ except UserNotFoundError:
903
+ user = client.create_user(user_id)
904
+ ```
905
+
906
+ For more detailed information on specific exceptions, refer to the API documentation.
907
+
908
+ ## Conclusion
909
+
910
+ This README outlines the basic usage of the RecallrAI SDK functions for user and session management. For additional documentation and advanced usage, please see the [official documentation](https://docs.recallrai.com) or the source code repository on [GitHub](https://github.com/recallrai/sdk-python).
911
+