mdb-engine 0.7.1__tar.gz → 0.7.2__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.
Files changed (106) hide show
  1. {mdb_engine-0.7.1/mdb_engine.egg-info → mdb_engine-0.7.2}/PKG-INFO +1 -1
  2. {mdb_engine-0.7.1 → mdb_engine-0.7.2}/mdb_engine/__init__.py +7 -7
  3. {mdb_engine-0.7.1 → mdb_engine-0.7.2}/mdb_engine/cli/main.py +1 -1
  4. {mdb_engine-0.7.1 → mdb_engine-0.7.2}/mdb_engine/memory/README.md +34 -3
  5. {mdb_engine-0.7.1 → mdb_engine-0.7.2}/mdb_engine/memory/service.py +284 -0
  6. {mdb_engine-0.7.1 → mdb_engine-0.7.2/mdb_engine.egg-info}/PKG-INFO +1 -1
  7. {mdb_engine-0.7.1 → mdb_engine-0.7.2}/pyproject.toml +1 -1
  8. {mdb_engine-0.7.1 → mdb_engine-0.7.2}/setup.py +1 -1
  9. {mdb_engine-0.7.1 → mdb_engine-0.7.2}/LICENSE +0 -0
  10. {mdb_engine-0.7.1 → mdb_engine-0.7.2}/MANIFEST.in +0 -0
  11. {mdb_engine-0.7.1 → mdb_engine-0.7.2}/README.md +0 -0
  12. {mdb_engine-0.7.1 → mdb_engine-0.7.2}/mdb_engine/README.md +0 -0
  13. {mdb_engine-0.7.1 → mdb_engine-0.7.2}/mdb_engine/auth/ARCHITECTURE.md +0 -0
  14. {mdb_engine-0.7.1 → mdb_engine-0.7.2}/mdb_engine/auth/README.md +0 -0
  15. {mdb_engine-0.7.1 → mdb_engine-0.7.2}/mdb_engine/auth/__init__.py +0 -0
  16. {mdb_engine-0.7.1 → mdb_engine-0.7.2}/mdb_engine/auth/audit.py +0 -0
  17. {mdb_engine-0.7.1 → mdb_engine-0.7.2}/mdb_engine/auth/base.py +0 -0
  18. {mdb_engine-0.7.1 → mdb_engine-0.7.2}/mdb_engine/auth/casbin_factory.py +0 -0
  19. {mdb_engine-0.7.1 → mdb_engine-0.7.2}/mdb_engine/auth/casbin_models.py +0 -0
  20. {mdb_engine-0.7.1 → mdb_engine-0.7.2}/mdb_engine/auth/config_defaults.py +0 -0
  21. {mdb_engine-0.7.1 → mdb_engine-0.7.2}/mdb_engine/auth/config_helpers.py +0 -0
  22. {mdb_engine-0.7.1 → mdb_engine-0.7.2}/mdb_engine/auth/cookie_utils.py +0 -0
  23. {mdb_engine-0.7.1 → mdb_engine-0.7.2}/mdb_engine/auth/csrf.py +0 -0
  24. {mdb_engine-0.7.1 → mdb_engine-0.7.2}/mdb_engine/auth/decorators.py +0 -0
  25. {mdb_engine-0.7.1 → mdb_engine-0.7.2}/mdb_engine/auth/dependencies.py +0 -0
  26. {mdb_engine-0.7.1 → mdb_engine-0.7.2}/mdb_engine/auth/helpers.py +0 -0
  27. {mdb_engine-0.7.1 → mdb_engine-0.7.2}/mdb_engine/auth/integration.py +0 -0
  28. {mdb_engine-0.7.1 → mdb_engine-0.7.2}/mdb_engine/auth/jwt.py +0 -0
  29. {mdb_engine-0.7.1 → mdb_engine-0.7.2}/mdb_engine/auth/middleware.py +0 -0
  30. {mdb_engine-0.7.1 → mdb_engine-0.7.2}/mdb_engine/auth/oso_factory.py +0 -0
  31. {mdb_engine-0.7.1 → mdb_engine-0.7.2}/mdb_engine/auth/provider.py +0 -0
  32. {mdb_engine-0.7.1 → mdb_engine-0.7.2}/mdb_engine/auth/rate_limiter.py +0 -0
  33. {mdb_engine-0.7.1 → mdb_engine-0.7.2}/mdb_engine/auth/restrictions.py +0 -0
  34. {mdb_engine-0.7.1 → mdb_engine-0.7.2}/mdb_engine/auth/session_manager.py +0 -0
  35. {mdb_engine-0.7.1 → mdb_engine-0.7.2}/mdb_engine/auth/shared_middleware.py +0 -0
  36. {mdb_engine-0.7.1 → mdb_engine-0.7.2}/mdb_engine/auth/shared_users.py +0 -0
  37. {mdb_engine-0.7.1 → mdb_engine-0.7.2}/mdb_engine/auth/token_lifecycle.py +0 -0
  38. {mdb_engine-0.7.1 → mdb_engine-0.7.2}/mdb_engine/auth/token_store.py +0 -0
  39. {mdb_engine-0.7.1 → mdb_engine-0.7.2}/mdb_engine/auth/users.py +0 -0
  40. {mdb_engine-0.7.1 → mdb_engine-0.7.2}/mdb_engine/auth/utils.py +0 -0
  41. {mdb_engine-0.7.1 → mdb_engine-0.7.2}/mdb_engine/auth/websocket_sessions.py +0 -0
  42. {mdb_engine-0.7.1 → mdb_engine-0.7.2}/mdb_engine/auth/websocket_tickets.py +0 -0
  43. {mdb_engine-0.7.1 → mdb_engine-0.7.2}/mdb_engine/cli/__init__.py +0 -0
  44. {mdb_engine-0.7.1 → mdb_engine-0.7.2}/mdb_engine/cli/commands/__init__.py +0 -0
  45. {mdb_engine-0.7.1 → mdb_engine-0.7.2}/mdb_engine/cli/commands/generate.py +0 -0
  46. {mdb_engine-0.7.1 → mdb_engine-0.7.2}/mdb_engine/cli/commands/migrate.py +0 -0
  47. {mdb_engine-0.7.1 → mdb_engine-0.7.2}/mdb_engine/cli/commands/show.py +0 -0
  48. {mdb_engine-0.7.1 → mdb_engine-0.7.2}/mdb_engine/cli/commands/validate.py +0 -0
  49. {mdb_engine-0.7.1 → mdb_engine-0.7.2}/mdb_engine/cli/utils.py +0 -0
  50. {mdb_engine-0.7.1 → mdb_engine-0.7.2}/mdb_engine/config.py +0 -0
  51. {mdb_engine-0.7.1 → mdb_engine-0.7.2}/mdb_engine/constants.py +0 -0
  52. {mdb_engine-0.7.1 → mdb_engine-0.7.2}/mdb_engine/core/README.md +0 -0
  53. {mdb_engine-0.7.1 → mdb_engine-0.7.2}/mdb_engine/core/__init__.py +0 -0
  54. {mdb_engine-0.7.1 → mdb_engine-0.7.2}/mdb_engine/core/app_registration.py +0 -0
  55. {mdb_engine-0.7.1 → mdb_engine-0.7.2}/mdb_engine/core/app_secrets.py +0 -0
  56. {mdb_engine-0.7.1 → mdb_engine-0.7.2}/mdb_engine/core/connection.py +0 -0
  57. {mdb_engine-0.7.1 → mdb_engine-0.7.2}/mdb_engine/core/encryption.py +0 -0
  58. {mdb_engine-0.7.1 → mdb_engine-0.7.2}/mdb_engine/core/engine.py +0 -0
  59. {mdb_engine-0.7.1 → mdb_engine-0.7.2}/mdb_engine/core/index_management.py +0 -0
  60. {mdb_engine-0.7.1 → mdb_engine-0.7.2}/mdb_engine/core/manifest.py +0 -0
  61. {mdb_engine-0.7.1 → mdb_engine-0.7.2}/mdb_engine/core/ray_integration.py +0 -0
  62. {mdb_engine-0.7.1 → mdb_engine-0.7.2}/mdb_engine/core/seeding.py +0 -0
  63. {mdb_engine-0.7.1 → mdb_engine-0.7.2}/mdb_engine/core/service_initialization.py +0 -0
  64. {mdb_engine-0.7.1 → mdb_engine-0.7.2}/mdb_engine/core/types.py +0 -0
  65. {mdb_engine-0.7.1 → mdb_engine-0.7.2}/mdb_engine/database/README.md +0 -0
  66. {mdb_engine-0.7.1 → mdb_engine-0.7.2}/mdb_engine/database/__init__.py +0 -0
  67. {mdb_engine-0.7.1 → mdb_engine-0.7.2}/mdb_engine/database/abstraction.py +0 -0
  68. {mdb_engine-0.7.1 → mdb_engine-0.7.2}/mdb_engine/database/connection.py +0 -0
  69. {mdb_engine-0.7.1 → mdb_engine-0.7.2}/mdb_engine/database/query_validator.py +0 -0
  70. {mdb_engine-0.7.1 → mdb_engine-0.7.2}/mdb_engine/database/resource_limiter.py +0 -0
  71. {mdb_engine-0.7.1 → mdb_engine-0.7.2}/mdb_engine/database/scoped_wrapper.py +0 -0
  72. {mdb_engine-0.7.1 → mdb_engine-0.7.2}/mdb_engine/dependencies.py +0 -0
  73. {mdb_engine-0.7.1 → mdb_engine-0.7.2}/mdb_engine/di/__init__.py +0 -0
  74. {mdb_engine-0.7.1 → mdb_engine-0.7.2}/mdb_engine/di/container.py +0 -0
  75. {mdb_engine-0.7.1 → mdb_engine-0.7.2}/mdb_engine/di/providers.py +0 -0
  76. {mdb_engine-0.7.1 → mdb_engine-0.7.2}/mdb_engine/di/scopes.py +0 -0
  77. {mdb_engine-0.7.1 → mdb_engine-0.7.2}/mdb_engine/embeddings/README.md +0 -0
  78. {mdb_engine-0.7.1 → mdb_engine-0.7.2}/mdb_engine/embeddings/__init__.py +0 -0
  79. {mdb_engine-0.7.1 → mdb_engine-0.7.2}/mdb_engine/embeddings/dependencies.py +0 -0
  80. {mdb_engine-0.7.1 → mdb_engine-0.7.2}/mdb_engine/embeddings/service.py +0 -0
  81. {mdb_engine-0.7.1 → mdb_engine-0.7.2}/mdb_engine/exceptions.py +0 -0
  82. {mdb_engine-0.7.1 → mdb_engine-0.7.2}/mdb_engine/indexes/README.md +0 -0
  83. {mdb_engine-0.7.1 → mdb_engine-0.7.2}/mdb_engine/indexes/__init__.py +0 -0
  84. {mdb_engine-0.7.1 → mdb_engine-0.7.2}/mdb_engine/indexes/helpers.py +0 -0
  85. {mdb_engine-0.7.1 → mdb_engine-0.7.2}/mdb_engine/indexes/manager.py +0 -0
  86. {mdb_engine-0.7.1 → mdb_engine-0.7.2}/mdb_engine/memory/__init__.py +0 -0
  87. {mdb_engine-0.7.1 → mdb_engine-0.7.2}/mdb_engine/observability/README.md +0 -0
  88. {mdb_engine-0.7.1 → mdb_engine-0.7.2}/mdb_engine/observability/__init__.py +0 -0
  89. {mdb_engine-0.7.1 → mdb_engine-0.7.2}/mdb_engine/observability/health.py +0 -0
  90. {mdb_engine-0.7.1 → mdb_engine-0.7.2}/mdb_engine/observability/logging.py +0 -0
  91. {mdb_engine-0.7.1 → mdb_engine-0.7.2}/mdb_engine/observability/metrics.py +0 -0
  92. {mdb_engine-0.7.1 → mdb_engine-0.7.2}/mdb_engine/repositories/__init__.py +0 -0
  93. {mdb_engine-0.7.1 → mdb_engine-0.7.2}/mdb_engine/repositories/base.py +0 -0
  94. {mdb_engine-0.7.1 → mdb_engine-0.7.2}/mdb_engine/repositories/mongo.py +0 -0
  95. {mdb_engine-0.7.1 → mdb_engine-0.7.2}/mdb_engine/repositories/unit_of_work.py +0 -0
  96. {mdb_engine-0.7.1 → mdb_engine-0.7.2}/mdb_engine/routing/README.md +0 -0
  97. {mdb_engine-0.7.1 → mdb_engine-0.7.2}/mdb_engine/routing/__init__.py +0 -0
  98. {mdb_engine-0.7.1 → mdb_engine-0.7.2}/mdb_engine/routing/websockets.py +0 -0
  99. {mdb_engine-0.7.1 → mdb_engine-0.7.2}/mdb_engine/utils/__init__.py +0 -0
  100. {mdb_engine-0.7.1 → mdb_engine-0.7.2}/mdb_engine/utils/mongo.py +0 -0
  101. {mdb_engine-0.7.1 → mdb_engine-0.7.2}/mdb_engine.egg-info/SOURCES.txt +0 -0
  102. {mdb_engine-0.7.1 → mdb_engine-0.7.2}/mdb_engine.egg-info/dependency_links.txt +0 -0
  103. {mdb_engine-0.7.1 → mdb_engine-0.7.2}/mdb_engine.egg-info/entry_points.txt +0 -0
  104. {mdb_engine-0.7.1 → mdb_engine-0.7.2}/mdb_engine.egg-info/requires.txt +0 -0
  105. {mdb_engine-0.7.1 → mdb_engine-0.7.2}/mdb_engine.egg-info/top_level.txt +0 -0
  106. {mdb_engine-0.7.1 → mdb_engine-0.7.2}/setup.cfg +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: mdb-engine
3
- Version: 0.7.1
3
+ Version: 0.7.2
4
4
  Summary: MongoDB Engine
5
5
  Home-page: https://github.com/ranfysvalle02/mdb-engine
6
6
  Author: Fabian Valle
@@ -82,13 +82,13 @@ from .repositories import Entity, MongoRepository, Repository, UnitOfWork
82
82
  from .utils import clean_mongo_doc, clean_mongo_docs
83
83
 
84
84
  __version__ = (
85
- "0.7.1" # Memory service initialization fix for multi-app setups
86
- # - FIXED: Memory service initialization in create_multi_app context
87
- # - FIXED: get_memory_service() now returns service when memory_config.enabled: true
88
- # - ENHANCED: Explicit memory service initialization in create_multi_app lifespan
89
- # - ENHANCED: Better error handling and logging for memory service initialization
90
- # - ADDED: Comprehensive integration tests for memory service in multi-app context
91
- # - ADDED: Unit tests for memory service initialization edge cases
85
+ "0.7.2" # Memory service update functionality
86
+ # - ADDED: Memory service update() method for in-place memory updates
87
+ # - ADDED: Support for updating memory content and metadata while preserving IDs
88
+ # - ADDED: Automatic embedding recomputation via Mem0's update method
89
+ # - ADDED: Comprehensive unit tests for memory update functionality (17 tests)
90
+ # - ENHANCED: Memory service now uses Mem0's native update method exclusively
91
+ # - REMOVED: Direct MongoDB update fallback (simplified implementation)
92
92
  )
93
93
 
94
94
  __all__ = [
@@ -15,7 +15,7 @@ from .commands.validate import validate
15
15
 
16
16
 
17
17
  @click.group()
18
- @click.version_option(version="0.7.1", prog_name="mdb")
18
+ @click.version_option(version="0.7.2", prog_name="mdb")
19
19
  def cli() -> None:
20
20
  """
21
21
  MDB_ENGINE CLI - Manifest management tool.
@@ -181,18 +181,49 @@ memories = await memory_service.get_all(
181
181
 
182
182
  ### Update Memory
183
183
 
184
- Update existing memories:
184
+ Update existing memories in-place while preserving the original memory ID and creation timestamp:
185
185
 
186
186
  ```python
187
- # Update memory
188
- updated = await memory_service.update(
187
+ # Update memory content and metadata
188
+ updated = memory_service.update(
189
+ memory_id="memory_123",
190
+ user_id="user123",
191
+ memory="Updated memory content",
192
+ metadata={"updated": True, "category": "technical"}
193
+ )
194
+
195
+ # Update using messages format
196
+ updated = memory_service.update(
189
197
  memory_id="memory_123",
190
198
  user_id="user123",
191
199
  messages=[{"role": "user", "content": "Updated content"}],
192
200
  metadata={"updated": True}
193
201
  )
202
+
203
+ # Update only metadata (content unchanged)
204
+ updated = memory_service.update(
205
+ memory_id="memory_123",
206
+ user_id="user123",
207
+ metadata={"category": "updated"}
208
+ )
209
+
210
+ # Backward compatibility: using 'data' parameter
211
+ updated = memory_service.update(
212
+ memory_id="memory_123",
213
+ user_id="user123",
214
+ data="Updated content",
215
+ metadata={"updated": True}
216
+ )
194
217
  ```
195
218
 
219
+ **Key Features:**
220
+ - **Preserves Memory ID**: The original memory ID is maintained
221
+ - **Preserves Creation Timestamp**: `created_at` is not modified
222
+ - **Updates Timestamp**: `updated_at` is automatically set to current time
223
+ - **Recomputes Embeddings**: If content changes, the embedding vector is automatically recomputed
224
+ - **Metadata Merging**: New metadata is merged with existing metadata (doesn't replace)
225
+ - **Partial Updates**: Can update content only, metadata only, or both
226
+
196
227
  ### Delete Memory
197
228
 
198
229
  Remove memories:
@@ -44,6 +44,20 @@ class Mem0MemoryServiceError(Exception):
44
44
 
45
45
 
46
46
  class Mem0MemoryService:
47
+ """
48
+ Production-ready Mem0 Memory Service with MongoDB integration.
49
+
50
+ Features:
51
+ - In-place memory updates preserving IDs and timestamps
52
+ - Automatic embedding recomputation on content changes
53
+ - Knowledge graph support (if enabled in Mem0 config)
54
+ - Comprehensive error handling and logging
55
+ - Backward compatibility with existing code
56
+
57
+ All operations go through Mem0's API to ensure proper state management,
58
+ graph updates, and relationship handling.
59
+ """
60
+
47
61
  def __init__(
48
62
  self,
49
63
  mongo_uri: str,
@@ -54,6 +68,9 @@ class Mem0MemoryService:
54
68
  if not _check_mem0_available():
55
69
  raise Mem0MemoryServiceError("Mem0 not installed. pip install mem0ai")
56
70
 
71
+ if not mongo_uri or not db_name or not app_slug:
72
+ raise Mem0MemoryServiceError("mongo_uri, db_name, and app_slug are required parameters")
73
+
57
74
  self.mongo_uri = mongo_uri
58
75
  self.db_name = db_name
59
76
  self.app_slug = app_slug
@@ -461,6 +478,273 @@ class Mem0MemoryService:
461
478
  ):
462
479
  return False
463
480
 
481
+ def update(
482
+ self,
483
+ memory_id: str,
484
+ user_id: str | None = None,
485
+ memory: str | None = None,
486
+ data: str | dict[str, Any] | None = None,
487
+ messages: str | list[dict[str, str]] | None = None,
488
+ metadata: dict[str, Any] | None = None,
489
+ **kwargs,
490
+ ) -> dict[str, Any] | None:
491
+ """
492
+ Update an existing memory in-place with production-grade error handling.
493
+
494
+ Updates the memory content and/or metadata while preserving:
495
+ - Original memory ID (never changes)
496
+ - Creation timestamp (created_at) - preserved
497
+ - Other existing fields - preserved unless explicitly updated
498
+
499
+ If content is updated, the embedding vector is automatically recomputed.
500
+
501
+ Args:
502
+ memory_id: The ID of the memory to update (required)
503
+ user_id: The user ID who owns the memory (for scoping and security)
504
+ memory: New memory content as a string (optional)
505
+ data: Alternative parameter name for memory content (backward compatibility).
506
+ Can be a string or dict with 'memory'/'text'/'content' key.
507
+ messages: Alternative way to provide content as messages (optional).
508
+ Can be a string or list of dicts with 'content' key.
509
+ metadata: Metadata updates to merge with existing metadata (optional).
510
+ Merged, not replaced - existing keys are preserved unless overridden.
511
+ **kwargs: Additional arguments passed to Mem0 operations
512
+
513
+ Returns:
514
+ Updated memory object with same ID, or None if memory not found
515
+
516
+ Raises:
517
+ Mem0MemoryServiceError: If update operation fails
518
+ ValueError: If memory_id is invalid or empty
519
+
520
+ Example:
521
+ ```python
522
+ # Update content and metadata
523
+ updated = memory_service.update(
524
+ memory_id="04f78986-dfad-46fe-8381-034bbee9a2fc",
525
+ user_id="user123",
526
+ memory="I love Python programming",
527
+ metadata={"category": "technical", "updated": True}
528
+ )
529
+
530
+ # Update only metadata (content unchanged)
531
+ updated = memory_service.update(
532
+ memory_id="04f78986-dfad-46fe-8381-034bbee9a2fc",
533
+ user_id="user123",
534
+ metadata={"category": "updated"}
535
+ )
536
+ ```
537
+ """
538
+ # Input validation
539
+ if not memory_id or not isinstance(memory_id, str) or not memory_id.strip():
540
+ raise ValueError("memory_id is required and must be a non-empty string")
541
+
542
+ try:
543
+ # Normalize data parameter (backward compatibility)
544
+ normalized_memory = self._normalize_content_input(memory, data, messages)
545
+ normalized_metadata = self._normalize_metadata_input(metadata, data)
546
+
547
+ # Verify memory exists before attempting update
548
+ existing_memory = self.get(memory_id=memory_id, user_id=user_id, **kwargs)
549
+ if not existing_memory:
550
+ logger.warning(
551
+ f"Memory {memory_id} not found for update",
552
+ extra={"memory_id": memory_id, "user_id": user_id},
553
+ )
554
+ return None
555
+
556
+ # Use Mem0's built-in update method
557
+ # Mem0's Memory class update method handles:
558
+ # - In-place updates preserving memory ID
559
+ # - Automatic embedding recomputation
560
+ # - Metadata merging
561
+ # - User scoping
562
+ # - Knowledge graph updates (if enabled)
563
+ # - Relationship management
564
+ if not hasattr(self.memory, "update") or not callable(self.memory.update):
565
+ raise Mem0MemoryServiceError(
566
+ "Mem0 update method not available. "
567
+ "Please ensure you're using a compatible version of mem0ai "
568
+ "that supports updates. Install with: pip install --upgrade mem0ai"
569
+ )
570
+
571
+ result = self._update_via_mem0(
572
+ memory_id=memory_id,
573
+ user_id=user_id,
574
+ memory=normalized_memory,
575
+ metadata=normalized_metadata,
576
+ **kwargs,
577
+ )
578
+
579
+ if result is None:
580
+ logger.warning(
581
+ f"Mem0 update returned None for memory {memory_id}",
582
+ extra={"memory_id": memory_id, "user_id": user_id},
583
+ )
584
+ return None
585
+
586
+ logger.info(
587
+ f"Successfully updated memory {memory_id} using Mem0 update method",
588
+ extra={
589
+ "memory_id": memory_id,
590
+ "content_updated": bool(normalized_memory),
591
+ "metadata_updated": bool(normalized_metadata),
592
+ },
593
+ )
594
+ return result
595
+
596
+ except ValueError:
597
+ # Re-raise validation errors as-is
598
+ raise
599
+ except (AttributeError, TypeError, ValueError, KeyError) as e:
600
+ logger.exception(
601
+ f"Error updating memory {memory_id}",
602
+ extra={"memory_id": memory_id, "user_id": user_id},
603
+ )
604
+ raise Mem0MemoryServiceError(f"Update failed: {e}") from e
605
+
606
+ def _normalize_content_input(
607
+ self,
608
+ memory: str | None,
609
+ data: str | dict[str, Any] | None,
610
+ messages: str | list[dict[str, str]] | None,
611
+ ) -> str | None:
612
+ """
613
+ Normalize content input from various parameter formats.
614
+
615
+ Priority: memory > data > messages
616
+ """
617
+ # Already have memory content
618
+ if memory:
619
+ if not isinstance(memory, str):
620
+ raise TypeError("memory parameter must be a string")
621
+ return memory.strip() if memory.strip() else None
622
+
623
+ # Check data parameter
624
+ if data:
625
+ if isinstance(data, str):
626
+ return data.strip() if data.strip() else None
627
+ elif isinstance(data, dict):
628
+ content = data.get("memory") or data.get("text") or data.get("content")
629
+ if content and isinstance(content, str):
630
+ return content.strip() if content.strip() else None
631
+
632
+ # Check messages parameter
633
+ if messages:
634
+ if isinstance(messages, str):
635
+ return messages.strip() if messages.strip() else None
636
+ elif isinstance(messages, list):
637
+ content_parts = []
638
+ for msg in messages:
639
+ if isinstance(msg, dict) and "content" in msg:
640
+ content = msg["content"]
641
+ if isinstance(content, str) and content.strip():
642
+ content_parts.append(content.strip())
643
+ if content_parts:
644
+ return " ".join(content_parts)
645
+
646
+ return None
647
+
648
+ def _normalize_metadata_input(
649
+ self, metadata: dict[str, Any] | None, data: dict[str, Any] | None
650
+ ) -> dict[str, Any] | None:
651
+ """Normalize metadata input, extracting from data dict if needed."""
652
+ if metadata is not None and not isinstance(metadata, dict):
653
+ raise TypeError("metadata must be a dict or None")
654
+
655
+ # If metadata provided directly, use it
656
+ if metadata is not None:
657
+ return metadata
658
+
659
+ # Check if metadata is in data dict
660
+ if isinstance(data, dict) and "metadata" in data:
661
+ data_metadata = data.get("metadata")
662
+ if isinstance(data_metadata, dict):
663
+ return data_metadata
664
+
665
+ return None
666
+
667
+ def _update_via_mem0(
668
+ self,
669
+ memory_id: str,
670
+ user_id: str | None,
671
+ memory: str | None,
672
+ metadata: dict[str, Any] | None,
673
+ **kwargs,
674
+ ) -> dict[str, Any] | None:
675
+ """
676
+ Update memory using Mem0's built-in update method.
677
+
678
+ This is the primary update path. Mem0's update method handles:
679
+ - In-place updates preserving memory ID and created_at timestamp
680
+ - Automatic embedding recomputation when content changes
681
+ - Metadata merging
682
+ - User scoping for security
683
+
684
+ Args:
685
+ memory_id: Memory ID to update
686
+ user_id: User ID for scoping
687
+ memory: New memory content (normalized)
688
+ metadata: Metadata to merge (normalized)
689
+ **kwargs: Additional arguments passed to Mem0
690
+
691
+ Returns:
692
+ Updated memory dict or None if not found
693
+
694
+ Raises:
695
+ Various exceptions from Mem0 if update fails
696
+ """
697
+ # Build update parameters matching Mem0's API
698
+ # Mem0's update method signature:
699
+ # update(memory_id, text=None, metadata=None, user_id=None, **kwargs)
700
+ update_kwargs: dict[str, Any] = {"memory_id": memory_id}
701
+
702
+ # Add user_id for scoping (Mem0 supports this)
703
+ if user_id:
704
+ update_kwargs["user_id"] = str(user_id)
705
+
706
+ # Add text/content if provided
707
+ # Mem0 uses "text" parameter for content
708
+ if memory:
709
+ update_kwargs["text"] = memory
710
+
711
+ # Add metadata if provided
712
+ # Mem0 merges metadata automatically
713
+ if metadata is not None:
714
+ update_kwargs["metadata"] = metadata
715
+
716
+ # Pass through any additional kwargs
717
+ update_kwargs.update(kwargs)
718
+
719
+ logger.debug(
720
+ f"Calling mem0.update() for memory_id={memory_id}",
721
+ extra={
722
+ "memory_id": memory_id,
723
+ "has_content": bool(memory),
724
+ "has_metadata": bool(metadata),
725
+ "user_id": user_id,
726
+ },
727
+ )
728
+
729
+ # Call Mem0's update method directly
730
+ # This handles all the complexity: embedding recomputation, ID preservation, etc.
731
+ result = self.memory.update(**update_kwargs)
732
+
733
+ # Normalize result format
734
+ # Mem0 may return dict, list, or other formats
735
+ if isinstance(result, dict):
736
+ return result
737
+ elif isinstance(result, list) and len(result) > 0:
738
+ # If list, return first item
739
+ return result[0] if isinstance(result[0], dict) else None
740
+ else:
741
+ # If result is None or unexpected format, return None to trigger fallback
742
+ logger.debug(
743
+ f"Mem0 update returned unexpected format: {type(result)}",
744
+ extra={"memory_id": memory_id},
745
+ )
746
+ return None
747
+
464
748
  def _normalize_result(self, result: Any) -> list[dict[str, Any]]:
465
749
  """Normalize Mem0's return type (dict vs list)."""
466
750
  if result is None:
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: mdb-engine
3
- Version: 0.7.1
3
+ Version: 0.7.2
4
4
  Summary: MongoDB Engine
5
5
  Home-page: https://github.com/ranfysvalle02/mdb-engine
6
6
  Author: Fabian Valle
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "mdb-engine"
7
- version = "0.7.1"
7
+ version = "0.7.2"
8
8
  description = "MongoDB Engine"
9
9
  readme = "README.md"
10
10
  requires-python = ">=3.10"
@@ -14,7 +14,7 @@ if readme_file.exists():
14
14
 
15
15
  setup(
16
16
  name="mdb-engine",
17
- version="0.7.1",
17
+ version="0.7.2",
18
18
  description="MongoDB Engine",
19
19
  long_description=long_description,
20
20
  long_description_content_type="text/markdown",
File without changes
File without changes
File without changes
File without changes