recallrai 0.1.1__py3-none-any.whl → 0.3.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of recallrai might be problematic. Click here for more details.

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