memorisdk 2.1.1__tar.gz → 2.3.0__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 memorisdk might be problematic. Click here for more details.

Files changed (76) hide show
  1. {memorisdk-2.1.1/memorisdk.egg-info → memorisdk-2.3.0}/PKG-INFO +2 -1
  2. {memorisdk-2.1.1 → memorisdk-2.3.0}/README.md +1 -0
  3. {memorisdk-2.1.1 → memorisdk-2.3.0}/memori/__init__.py +1 -1
  4. {memorisdk-2.1.1 → memorisdk-2.3.0}/memori/agents/conscious_agent.py +5 -4
  5. {memorisdk-2.1.1 → memorisdk-2.3.0}/memori/agents/memory_agent.py +9 -7
  6. {memorisdk-2.1.1 → memorisdk-2.3.0}/memori/agents/retrieval_agent.py +45 -17
  7. {memorisdk-2.1.1 → memorisdk-2.3.0}/memori/core/conversation.py +8 -7
  8. {memorisdk-2.1.1 → memorisdk-2.3.0}/memori/core/memory.py +103 -40
  9. {memorisdk-2.1.1 → memorisdk-2.3.0}/memori/database/auto_creator.py +72 -5
  10. {memorisdk-2.1.1 → memorisdk-2.3.0}/memori/database/search_service.py +265 -121
  11. {memorisdk-2.1.1 → memorisdk-2.3.0}/memori/database/sqlalchemy_manager.py +61 -13
  12. {memorisdk-2.1.1 → memorisdk-2.3.0/memorisdk.egg-info}/PKG-INFO +2 -1
  13. {memorisdk-2.1.1 → memorisdk-2.3.0}/pyproject.toml +1 -1
  14. {memorisdk-2.1.1 → memorisdk-2.3.0}/LICENSE +0 -0
  15. {memorisdk-2.1.1 → memorisdk-2.3.0}/memori/agents/__init__.py +0 -0
  16. {memorisdk-2.1.1 → memorisdk-2.3.0}/memori/config/__init__.py +0 -0
  17. {memorisdk-2.1.1 → memorisdk-2.3.0}/memori/config/manager.py +0 -0
  18. {memorisdk-2.1.1 → memorisdk-2.3.0}/memori/config/memory_manager.py +0 -0
  19. {memorisdk-2.1.1 → memorisdk-2.3.0}/memori/config/settings.py +0 -0
  20. {memorisdk-2.1.1 → memorisdk-2.3.0}/memori/core/__init__.py +0 -0
  21. {memorisdk-2.1.1 → memorisdk-2.3.0}/memori/core/database.py +0 -0
  22. {memorisdk-2.1.1 → memorisdk-2.3.0}/memori/core/providers.py +0 -0
  23. {memorisdk-2.1.1 → memorisdk-2.3.0}/memori/database/__init__.py +0 -0
  24. {memorisdk-2.1.1 → memorisdk-2.3.0}/memori/database/adapters/__init__.py +0 -0
  25. {memorisdk-2.1.1 → memorisdk-2.3.0}/memori/database/adapters/mongodb_adapter.py +0 -0
  26. {memorisdk-2.1.1 → memorisdk-2.3.0}/memori/database/adapters/mysql_adapter.py +0 -0
  27. {memorisdk-2.1.1 → memorisdk-2.3.0}/memori/database/adapters/postgresql_adapter.py +0 -0
  28. {memorisdk-2.1.1 → memorisdk-2.3.0}/memori/database/adapters/sqlite_adapter.py +0 -0
  29. {memorisdk-2.1.1 → memorisdk-2.3.0}/memori/database/connection_utils.py +0 -0
  30. {memorisdk-2.1.1 → memorisdk-2.3.0}/memori/database/connectors/__init__.py +0 -0
  31. {memorisdk-2.1.1 → memorisdk-2.3.0}/memori/database/connectors/base_connector.py +0 -0
  32. {memorisdk-2.1.1 → memorisdk-2.3.0}/memori/database/connectors/mongodb_connector.py +0 -0
  33. {memorisdk-2.1.1 → memorisdk-2.3.0}/memori/database/connectors/mysql_connector.py +0 -0
  34. {memorisdk-2.1.1 → memorisdk-2.3.0}/memori/database/connectors/postgres_connector.py +0 -0
  35. {memorisdk-2.1.1 → memorisdk-2.3.0}/memori/database/connectors/sqlite_connector.py +0 -0
  36. {memorisdk-2.1.1 → memorisdk-2.3.0}/memori/database/models.py +0 -0
  37. {memorisdk-2.1.1 → memorisdk-2.3.0}/memori/database/mongodb_manager.py +0 -0
  38. {memorisdk-2.1.1 → memorisdk-2.3.0}/memori/database/queries/__init__.py +0 -0
  39. {memorisdk-2.1.1 → memorisdk-2.3.0}/memori/database/queries/base_queries.py +0 -0
  40. {memorisdk-2.1.1 → memorisdk-2.3.0}/memori/database/queries/chat_queries.py +0 -0
  41. {memorisdk-2.1.1 → memorisdk-2.3.0}/memori/database/queries/entity_queries.py +0 -0
  42. {memorisdk-2.1.1 → memorisdk-2.3.0}/memori/database/queries/memory_queries.py +0 -0
  43. {memorisdk-2.1.1 → memorisdk-2.3.0}/memori/database/query_translator.py +0 -0
  44. {memorisdk-2.1.1 → memorisdk-2.3.0}/memori/database/schema_generators/__init__.py +0 -0
  45. {memorisdk-2.1.1 → memorisdk-2.3.0}/memori/database/schema_generators/mongodb_schema_generator.py +0 -0
  46. {memorisdk-2.1.1 → memorisdk-2.3.0}/memori/database/schema_generators/mysql_schema_generator.py +0 -0
  47. {memorisdk-2.1.1 → memorisdk-2.3.0}/memori/database/search/__init__.py +0 -0
  48. {memorisdk-2.1.1 → memorisdk-2.3.0}/memori/database/search/mongodb_search_adapter.py +0 -0
  49. {memorisdk-2.1.1 → memorisdk-2.3.0}/memori/database/search/mysql_search_adapter.py +0 -0
  50. {memorisdk-2.1.1 → memorisdk-2.3.0}/memori/database/search/sqlite_search_adapter.py +0 -0
  51. {memorisdk-2.1.1 → memorisdk-2.3.0}/memori/database/templates/__init__.py +0 -0
  52. {memorisdk-2.1.1 → memorisdk-2.3.0}/memori/database/templates/basic_template.py +0 -0
  53. {memorisdk-2.1.1 → memorisdk-2.3.0}/memori/database/templates/schemas/__init__.py +0 -0
  54. {memorisdk-2.1.1 → memorisdk-2.3.0}/memori/integrations/__init__.py +0 -0
  55. {memorisdk-2.1.1 → memorisdk-2.3.0}/memori/integrations/anthropic_integration.py +0 -0
  56. {memorisdk-2.1.1 → memorisdk-2.3.0}/memori/integrations/litellm_integration.py +0 -0
  57. {memorisdk-2.1.1 → memorisdk-2.3.0}/memori/integrations/openai_integration.py +0 -0
  58. {memorisdk-2.1.1 → memorisdk-2.3.0}/memori/tools/__init__.py +0 -0
  59. {memorisdk-2.1.1 → memorisdk-2.3.0}/memori/tools/memory_tool.py +0 -0
  60. {memorisdk-2.1.1 → memorisdk-2.3.0}/memori/utils/__init__.py +0 -0
  61. {memorisdk-2.1.1 → memorisdk-2.3.0}/memori/utils/exceptions.py +0 -0
  62. {memorisdk-2.1.1 → memorisdk-2.3.0}/memori/utils/helpers.py +0 -0
  63. {memorisdk-2.1.1 → memorisdk-2.3.0}/memori/utils/input_validator.py +0 -0
  64. {memorisdk-2.1.1 → memorisdk-2.3.0}/memori/utils/logging.py +0 -0
  65. {memorisdk-2.1.1 → memorisdk-2.3.0}/memori/utils/pydantic_models.py +0 -0
  66. {memorisdk-2.1.1 → memorisdk-2.3.0}/memori/utils/query_builder.py +0 -0
  67. {memorisdk-2.1.1 → memorisdk-2.3.0}/memori/utils/schemas.py +0 -0
  68. {memorisdk-2.1.1 → memorisdk-2.3.0}/memori/utils/security_audit.py +0 -0
  69. {memorisdk-2.1.1 → memorisdk-2.3.0}/memori/utils/security_integration.py +0 -0
  70. {memorisdk-2.1.1 → memorisdk-2.3.0}/memori/utils/transaction_manager.py +0 -0
  71. {memorisdk-2.1.1 → memorisdk-2.3.0}/memori/utils/validators.py +0 -0
  72. {memorisdk-2.1.1 → memorisdk-2.3.0}/memorisdk.egg-info/SOURCES.txt +0 -0
  73. {memorisdk-2.1.1 → memorisdk-2.3.0}/memorisdk.egg-info/dependency_links.txt +0 -0
  74. {memorisdk-2.1.1 → memorisdk-2.3.0}/memorisdk.egg-info/requires.txt +0 -0
  75. {memorisdk-2.1.1 → memorisdk-2.3.0}/memorisdk.egg-info/top_level.txt +0 -0
  76. {memorisdk-2.1.1 → memorisdk-2.3.0}/setup.cfg +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: memorisdk
3
- Version: 2.1.1
3
+ Version: 2.3.0
4
4
  Summary: The Open-Source Memory Layer for AI Agents & Multi-Agent Systems
5
5
  Author-email: GibsonAI Team <noc@gibsonai.com>
6
6
  License: Apache-2.0
@@ -482,6 +482,7 @@ Memori works seamlessly with popular AI frameworks:
482
482
  | [Agno](./examples/integrations/agno_example.py) | Memory-enhanced agent framework integration with persistent conversations | Simple chat agent with memory search |
483
483
  | [AWS Strands](./examples/integrations/aws_strands_example.py) | Professional development coach with Strands SDK and persistent memory | Career coaching agent with goal tracking |
484
484
  | [Azure AI Foundry](./examples/integrations/azure_ai_foundry_example.py) | Azure AI Foundry agents with persistent memory across conversations | Enterprise AI agents with Azure integration |
485
+ | [AutoGen](./examples/integrations/autogen_example.py) | Multi-agent group chat memory recording | Agent chats with memory integration |
485
486
  | [CamelAI](./examples/integrations/camelai_example.py) | Multi-agent communication framework with automatic memory recording and retrieval | Memory-enhanced chat agents with conversation continuity |
486
487
  | [CrewAI](./examples/integrations/crewai_example.py) | Multi-agent system with shared memory across agent interactions | Collaborative agents with memory |
487
488
  | [Digital Ocean AI](./examples/integrations/digital_ocean_example.py) | Memory-enhanced customer support using Digital Ocean's AI platform | Customer support assistant with conversation history |
@@ -385,6 +385,7 @@ Memori works seamlessly with popular AI frameworks:
385
385
  | [Agno](./examples/integrations/agno_example.py) | Memory-enhanced agent framework integration with persistent conversations | Simple chat agent with memory search |
386
386
  | [AWS Strands](./examples/integrations/aws_strands_example.py) | Professional development coach with Strands SDK and persistent memory | Career coaching agent with goal tracking |
387
387
  | [Azure AI Foundry](./examples/integrations/azure_ai_foundry_example.py) | Azure AI Foundry agents with persistent memory across conversations | Enterprise AI agents with Azure integration |
388
+ | [AutoGen](./examples/integrations/autogen_example.py) | Multi-agent group chat memory recording | Agent chats with memory integration |
388
389
  | [CamelAI](./examples/integrations/camelai_example.py) | Multi-agent communication framework with automatic memory recording and retrieval | Memory-enhanced chat agents with conversation continuity |
389
390
  | [CrewAI](./examples/integrations/crewai_example.py) | Multi-agent system with shared memory across agent interactions | Collaborative agents with memory |
390
391
  | [Digital Ocean AI](./examples/integrations/digital_ocean_example.py) | Memory-enhanced customer support using Digital Ocean's AI platform | Customer support assistant with conversation history |
@@ -5,7 +5,7 @@ Professional-grade memory layer with comprehensive error handling, configuration
5
5
  management, and modular architecture for production AI systems.
6
6
  """
7
7
 
8
- __version__ = "2.1.1"
8
+ __version__ = "2.3.0"
9
9
  __author__ = "Harshal More"
10
10
  __email__ = "harshalmore2468@gmail.com"
11
11
 
@@ -116,7 +116,7 @@ class ConsciouscAgent:
116
116
  return False
117
117
 
118
118
  async def initialize_existing_conscious_memories(
119
- self, db_manager, namespace: str = "default"
119
+ self, db_manager, namespace: str = "default", limit: int = 10
120
120
  ) -> bool:
121
121
  """
122
122
  Initialize by copying ALL existing conscious-info memories to short-term memory
@@ -143,16 +143,17 @@ class ConsciouscAgent:
143
143
  from sqlalchemy import text
144
144
 
145
145
  with db_manager._get_connection() as connection:
146
- # Get ALL conscious-info labeled memories from long-term memory
146
+ # Get top conscious-info labeled memories from long-term memory (limited for performance)
147
147
  cursor = connection.execute(
148
148
  text(
149
149
  """SELECT memory_id, processed_data, summary, searchable_content,
150
150
  importance_score, created_at
151
151
  FROM long_term_memory
152
152
  WHERE namespace = :namespace AND classification = 'conscious-info'
153
- ORDER BY importance_score DESC, created_at DESC"""
153
+ ORDER BY importance_score DESC, created_at DESC
154
+ LIMIT :limit"""
154
155
  ),
155
- {"namespace": namespace},
156
+ {"namespace": namespace, "limit": limit},
156
157
  )
157
158
  existing_conscious_memories = cursor.fetchall()
158
159
 
@@ -237,17 +237,19 @@ CONVERSATION CONTEXT:
237
237
  )
238
238
 
239
239
  logger.debug(
240
- f"Processed conversation {chat_id}: "
241
- f"classification={processed_memory.classification}, "
242
- f"importance={processed_memory.importance}, "
243
- f"conscious_context={processed_memory.is_user_context}, "
244
- f"promotion_eligible={processed_memory.promotion_eligible}"
240
+ f"[AGENT] Processed conversation {chat_id[:8]}... - "
241
+ f"classification: {processed_memory.classification.value} | "
242
+ f"importance: {processed_memory.importance.value} | "
243
+ f"conscious_context: {processed_memory.is_user_context} | "
244
+ f"promotion_eligible: {processed_memory.promotion_eligible}"
245
245
  )
246
246
 
247
247
  return processed_memory
248
248
 
249
249
  except Exception as e:
250
- logger.error(f"Memory agent processing failed for {chat_id}: {e}")
250
+ logger.error(
251
+ f"[AGENT] Memory processing failed for {chat_id[:8]}... - {type(e).__name__}: {e}"
252
+ )
251
253
  return self._create_empty_long_term_memory(
252
254
  chat_id, f"Processing failed: {str(e)}"
253
255
  )
@@ -307,7 +309,7 @@ CONVERSATION CONTEXT:
307
309
 
308
310
  if avg_similarity >= similarity_threshold:
309
311
  logger.info(
310
- f"Duplicate detected: {avg_similarity:.2f} similarity with {existing.conversation_id}"
312
+ f"[AGENT] Duplicate detected - {avg_similarity:.2f} similarity with {existing.conversation_id[:8]}..."
311
313
  )
312
314
  return existing.conversation_id
313
315
 
@@ -218,15 +218,25 @@ Be strategic and comprehensive in your search planning."""
218
218
  all_results = []
219
219
  seen_memory_ids = set()
220
220
 
221
- # For MongoDB and SQL, use the unified search_memories method as primary strategy
222
- # This ensures we use the database's native search capabilities
223
- logger.debug(f"Executing unified database search using {db_type} manager")
224
- primary_results = db_manager.search_memories(
225
- query=search_plan.query_text or query, namespace=namespace, limit=limit
226
- )
227
- logger.debug(
228
- f"Primary database search returned {len(primary_results)} results"
229
- )
221
+ # For MongoDB and SQL, use SearchService directly to avoid recursion
222
+ # This ensures we use the database's native search capabilities without triggering context injection
223
+ logger.debug(f"Executing direct SearchService search using {db_type}")
224
+ try:
225
+ from ..database.search_service import SearchService
226
+
227
+ with db_manager.SessionLocal() as session:
228
+ search_service = SearchService(session, db_type)
229
+ primary_results = search_service.search_memories(
230
+ query=search_plan.query_text or query,
231
+ namespace=namespace,
232
+ limit=limit,
233
+ )
234
+ logger.debug(
235
+ f"Direct SearchService returned {len(primary_results)} results"
236
+ )
237
+ except Exception as e:
238
+ logger.error(f"SearchService direct access failed: {e}")
239
+ primary_results = []
230
240
 
231
241
  # Process primary results and add search metadata
232
242
  for result in primary_results:
@@ -383,9 +393,17 @@ Be strategic and comprehensive in your search planning."""
383
393
 
384
394
  search_terms = " ".join(keywords)
385
395
  try:
386
- results = db_manager.search_memories(
387
- query=search_terms, namespace=namespace, limit=limit
388
- )
396
+ # Use SearchService directly to avoid recursion
397
+ from ..database.search_service import SearchService
398
+
399
+ db_type = self._detect_database_type(db_manager)
400
+
401
+ with db_manager.SessionLocal() as session:
402
+ search_service = SearchService(session, db_type)
403
+ results = search_service.search_memories(
404
+ query=search_terms, namespace=namespace, limit=limit
405
+ )
406
+
389
407
  # Ensure results is a list of dictionaries
390
408
  if not isinstance(results, list):
391
409
  logger.warning(f"Search returned non-list result: {type(results)}")
@@ -417,14 +435,24 @@ Be strategic and comprehensive in your search planning."""
417
435
  if not categories:
418
436
  return []
419
437
 
420
- # This would need to be implemented in the database manager
421
- # For now, get all memories and filter by category
438
+ # Use SearchService directly to avoid recursion
439
+ # Get all memories and filter by category
422
440
  logger.debug(
423
441
  f"Searching memories by categories: {categories} in namespace: {namespace}"
424
442
  )
425
- all_results = db_manager.search_memories(
426
- query="", namespace=namespace, limit=limit * 3
427
- )
443
+ try:
444
+ from ..database.search_service import SearchService
445
+
446
+ db_type = self._detect_database_type(db_manager)
447
+
448
+ with db_manager.SessionLocal() as session:
449
+ search_service = SearchService(session, db_type)
450
+ all_results = search_service.search_memories(
451
+ query="", namespace=namespace, limit=limit * 3
452
+ )
453
+ except Exception as e:
454
+ logger.error(f"Category search failed: {e}")
455
+ all_results = []
428
456
 
429
457
  logger.debug(
430
458
  f"Retrieved {len(all_results)} total results for category filtering"
@@ -207,7 +207,7 @@ class ConversationManager:
207
207
  elif mode == "auto":
208
208
  # Auto mode: Search long-term memory database for relevant context
209
209
  logger.debug(
210
- f"Auto-ingest: Processing user input for long-term memory search: '{user_input[:50]}...'"
210
+ f"[CONTEXT] Auto-ingest processing - Query: '{user_input[:50]}...' | Session: {session_id[:8]}..."
211
211
  )
212
212
  context = (
213
213
  memori_instance._get_auto_ingest_context(user_input)
@@ -217,11 +217,11 @@ class ConversationManager:
217
217
  if context:
218
218
  context_prompt = self._build_auto_context_prompt(context)
219
219
  logger.debug(
220
- f"Auto-ingest: Successfully injected long-term memory context with {len(context)} items for session {session_id}"
220
+ f"[CONTEXT] Long-term memory injected - {len(context)} items | Session: {session_id[:8]}..."
221
221
  )
222
222
  else:
223
223
  logger.debug(
224
- f"Auto-ingest: No relevant memories found in long-term database for query '{user_input[:50]}...' in session {session_id}"
224
+ f"[CONTEXT] No relevant memories found for '{user_input[:30]}...' | Session: {session_id[:8]}..."
225
225
  )
226
226
 
227
227
  # Get conversation history
@@ -246,7 +246,7 @@ class ConversationManager:
246
246
  system_content += f"{role_label}: {msg['content']}\n"
247
247
  system_content += "--- End History ---\n"
248
248
  logger.debug(
249
- f"Added {len(previous_messages)} history messages for session {session_id}"
249
+ f"[CONTEXT] Added {len(previous_messages)} history messages | Session: {session_id[:8]}..."
250
250
  )
251
251
 
252
252
  # Find existing system message or create new one
@@ -267,16 +267,17 @@ class ConversationManager:
267
267
  0, {"role": "system", "content": system_content}
268
268
  )
269
269
 
270
+ context_status = "yes" if context_prompt else "no"
271
+ history_status = "yes" if len(history_messages) > 1 else "no"
270
272
  logger.debug(
271
- f"Enhanced messages for session {session_id}: context={'yes' if context_prompt else 'no'}, "
272
- f"history={'yes' if len(history_messages) > 1 else 'no'}"
273
+ f"[CONTEXT] Enhanced messages for session {session_id[:8]}... - context: {context_status} | history: {history_status}"
273
274
  )
274
275
 
275
276
  return enhanced_messages
276
277
 
277
278
  except Exception as e:
278
279
  logger.error(
279
- f"Failed to inject context with history for session {session_id}: {e}"
280
+ f"[CONTEXT] Failed to inject context for session {session_id[:8]}... - {type(e).__name__}: {e}"
280
281
  )
281
282
  return messages
282
283
 
@@ -3,6 +3,7 @@ Main Memori class - Pydantic-based memory interface v1.0
3
3
  """
4
4
 
5
5
  import asyncio
6
+ import threading
6
7
  import time
7
8
  import uuid
8
9
  from datetime import datetime
@@ -65,6 +66,7 @@ class Memori:
65
66
  schema_init: bool = True, # Initialize database schema and create tables
66
67
  database_prefix: str | None = None, # Database name prefix
67
68
  database_suffix: str | None = None, # Database name suffix
69
+ conscious_memory_limit: int = 10, # Limit for conscious memory processing
68
70
  ):
69
71
  """
70
72
  Initialize Memori memory system v1.0.
@@ -109,6 +111,14 @@ class Memori:
109
111
  self.schema_init = schema_init
110
112
  self.database_prefix = database_prefix
111
113
  self.database_suffix = database_suffix
114
+ # Validate conscious_memory_limit parameter
115
+ if not isinstance(conscious_memory_limit, int) or conscious_memory_limit < 1:
116
+ raise ValueError("conscious_memory_limit must be a positive integer")
117
+
118
+ self.conscious_memory_limit = conscious_memory_limit
119
+
120
+ # Thread safety for conscious memory initialization
121
+ self._conscious_init_lock = threading.RLock()
112
122
 
113
123
  # Configure provider based on explicit settings ONLY - no auto-detection
114
124
  if provider_config:
@@ -452,7 +462,7 @@ class Memori:
452
462
  )
453
463
  init_success = (
454
464
  await self.conscious_agent.initialize_existing_conscious_memories(
455
- self.db_manager, self.namespace
465
+ self.db_manager, self.namespace, self.conscious_memory_limit
456
466
  )
457
467
  )
458
468
  if init_success:
@@ -478,52 +488,104 @@ class Memori:
478
488
 
479
489
  def _run_synchronous_conscious_initialization(self):
480
490
  """Run conscious agent initialization synchronously (when no event loop is available)"""
481
- try:
482
- if not self.conscious_agent:
483
- return
491
+ with self._conscious_init_lock:
492
+ try:
493
+ if not self.conscious_agent:
494
+ return
484
495
 
485
- # If both auto_ingest and conscious_ingest are enabled,
486
- # initialize by copying ALL existing conscious-info memories first
487
- if self.auto_ingest and self.conscious_ingest:
488
- logger.info(
489
- "Conscious-ingest: Both auto_ingest and conscious_ingest enabled - initializing existing conscious memories"
490
- )
496
+ # Check if we've already initialized in this session to avoid repeated work
497
+ # Use namespace-specific key to prevent conflicts between instances
498
+ init_key = f"_conscious_initialized_{self.namespace or 'default'}"
499
+ if hasattr(self, init_key) and getattr(self, init_key):
500
+ logger.debug(
501
+ f"[CONSCIOUS] Already initialized for namespace '{self.namespace or 'default'}', skipping"
502
+ )
503
+ return
491
504
 
492
- # Run synchronous initialization of existing memories
493
- self._initialize_existing_conscious_memories_sync()
505
+ # If both auto_ingest and conscious_ingest are enabled,
506
+ # initialize by copying the most important existing conscious-info memories first
507
+ if self.auto_ingest and self.conscious_ingest:
508
+ logger.info(
509
+ "[CONSCIOUS] Both auto_ingest and conscious_ingest enabled - initializing existing conscious memories"
510
+ )
494
511
 
495
- logger.debug(
496
- "Conscious-ingest: Synchronous conscious context extraction completed"
497
- )
512
+ # Run optimized synchronous initialization of existing memories
513
+ import time
498
514
 
499
- except Exception as e:
500
- logger.error(f"Synchronous conscious agent initialization failed: {e}")
515
+ start_time = time.time()
516
+
517
+ initialized = self._initialize_existing_conscious_memories_sync()
518
+
519
+ elapsed = time.time() - start_time
520
+ if initialized:
521
+ logger.debug(
522
+ f"[CONSCIOUS] Initialization completed in {elapsed:.2f}s"
523
+ )
524
+ else:
525
+ logger.debug(
526
+ f"[CONSCIOUS] Initialization skipped (no work needed) in {elapsed:.2f}s"
527
+ )
528
+
529
+ # Mark as initialized to avoid repeated work for this specific namespace
530
+ init_key = f"_conscious_initialized_{self.namespace or 'default'}"
531
+ setattr(self, init_key, True)
532
+
533
+ logger.debug(
534
+ "[CONSCIOUS] Synchronous conscious context extraction completed"
535
+ )
536
+
537
+ except Exception as e:
538
+ logger.error(f"Synchronous conscious agent initialization failed: {e}")
501
539
 
502
540
  def _initialize_existing_conscious_memories_sync(self):
503
- """Synchronously initialize existing conscious-info memories"""
541
+ """Synchronously initialize existing conscious-info memories with optimization"""
504
542
  try:
505
543
  from sqlalchemy import text
506
544
 
507
545
  with self.db_manager._get_connection() as connection:
508
- # Get ALL conscious-info labeled memories from long-term memory
546
+ # First, check if we already have conscious memories in short-term storage
547
+ existing_short_term = connection.execute(
548
+ text(
549
+ """SELECT COUNT(*) FROM short_term_memory
550
+ WHERE namespace = :namespace
551
+ AND (category_primary = 'conscious_context' OR memory_id LIKE 'conscious_%')"""
552
+ ),
553
+ {"namespace": self.namespace or "default"},
554
+ ).scalar()
555
+
556
+ if existing_short_term > 0:
557
+ logger.debug(
558
+ f"[CONSCIOUS] {existing_short_term} conscious memories already in short-term storage, skipping initialization"
559
+ )
560
+ return False
561
+
562
+ # Get only the most important conscious-info memories (limit to 10 for performance)
509
563
  cursor = connection.execute(
510
564
  text(
511
565
  """SELECT memory_id, processed_data, summary, searchable_content,
512
566
  importance_score, created_at
513
567
  FROM long_term_memory
514
568
  WHERE namespace = :namespace AND classification = 'conscious-info'
515
- ORDER BY importance_score DESC, created_at DESC"""
569
+ ORDER BY importance_score DESC, created_at DESC
570
+ LIMIT :limit"""
516
571
  ),
517
- {"namespace": self.namespace or "default"},
572
+ {
573
+ "namespace": self.namespace or "default",
574
+ "limit": self.conscious_memory_limit,
575
+ },
518
576
  )
519
577
  existing_conscious_memories = cursor.fetchall()
520
578
 
521
579
  if not existing_conscious_memories:
522
580
  logger.debug(
523
- "Conscious-ingest: No existing conscious-info memories found for initialization"
581
+ "[CONSCIOUS] No conscious-info memories found for initialization"
524
582
  )
525
583
  return False
526
584
 
585
+ # Batch process memories for efficiency
586
+ logger.debug(
587
+ f"[CONSCIOUS] Processing {len(existing_conscious_memories)} conscious memories..."
588
+ )
527
589
  copied_count = 0
528
590
  for memory_row in existing_conscious_memories:
529
591
  success = self._copy_memory_to_short_term_sync(memory_row)
@@ -532,12 +594,12 @@ class Memori:
532
594
 
533
595
  if copied_count > 0:
534
596
  logger.info(
535
- f"Conscious-ingest: Initialized {copied_count} existing conscious-info memories to short-term memory"
597
+ f"[CONSCIOUS] Initialized {copied_count} conscious memories to short-term storage"
536
598
  )
537
599
  return True
538
600
  else:
539
601
  logger.debug(
540
- "Conscious-ingest: No new conscious memories to initialize (all were duplicates)"
602
+ "[CONSCIOUS] No new conscious memories to initialize (all were duplicates)"
541
603
  )
542
604
  return False
543
605
 
@@ -564,26 +626,25 @@ class Memori:
564
626
  from sqlalchemy import text
565
627
 
566
628
  with self.db_manager._get_connection() as connection:
567
- # Check if similar content already exists in short-term memory
629
+ # Database-agnostic duplicate check with safer pattern matching
568
630
  existing_check = connection.execute(
569
631
  text(
570
632
  """SELECT COUNT(*) FROM short_term_memory
571
633
  WHERE namespace = :namespace
572
- AND category_primary = 'conscious_context'
573
- AND (searchable_content = :searchable_content
574
- OR summary = :summary)"""
634
+ AND (memory_id = :exact_id
635
+ OR memory_id LIKE :conscious_pattern)"""
575
636
  ),
576
637
  {
577
638
  "namespace": self.namespace or "default",
578
- "searchable_content": searchable_content,
579
- "summary": summary,
639
+ "exact_id": memory_id,
640
+ "conscious_pattern": f"conscious_{memory_id}_%",
580
641
  },
581
642
  )
582
643
 
583
644
  existing_count = existing_check.scalar()
584
645
  if existing_count > 0:
585
646
  logger.debug(
586
- f"Conscious-ingest: Skipping duplicate memory {memory_id} - similar content already exists in short-term memory"
647
+ f"[CONSCIOUS] Skipping duplicate memory {memory_id[:8]}... - already exists in short-term memory"
587
648
  )
588
649
  return False
589
650
 
@@ -1892,7 +1953,7 @@ class Memori:
1892
1953
 
1893
1954
  # Debug logging for conversation recording
1894
1955
  logger.info(
1895
- f"Recording conversation - Input: '{user_input[:100]}...' Model: {model}"
1956
+ f"[MEMORY] Recording conversation - Input: '{user_input[:60]}...' | Model: {model} | Session: {self.session_id[:8]}..."
1896
1957
  )
1897
1958
 
1898
1959
  # Parse response
@@ -1915,29 +1976,31 @@ class Memori:
1915
1976
  namespace=self.namespace,
1916
1977
  metadata=metadata or {},
1917
1978
  )
1918
- logger.debug(
1919
- f"Successfully stored chat history for conversation: {chat_id}"
1920
- )
1979
+ logger.debug(f"[MEMORY] Chat history stored - ID: {chat_id[:8]}...")
1921
1980
 
1922
1981
  # Always process into long-term memory when memory agent is available
1923
1982
  if self.memory_agent:
1924
1983
  self._schedule_memory_processing(
1925
1984
  chat_id, user_input, response_text, response_model
1926
1985
  )
1927
- logger.debug(f"Scheduled memory processing for conversation: {chat_id}")
1986
+ logger.debug(f"[MEMORY] Processing scheduled - ID: {chat_id[:8]}...")
1928
1987
  else:
1929
1988
  logger.warning(
1930
- f"Memory agent not available, skipping memory processing for: {chat_id}"
1989
+ f"[MEMORY] Agent unavailable, skipping processing - ID: {chat_id[:8]}..."
1931
1990
  )
1932
1991
 
1933
- logger.info(f"Recorded conversation successfully: {chat_id}")
1992
+ logger.info(
1993
+ f"[MEMORY] Conversation recorded successfully - ID: {chat_id[:8]}..."
1994
+ )
1934
1995
  return chat_id
1935
1996
 
1936
1997
  except Exception as e:
1937
- logger.error(f"Failed to record conversation {chat_id}: {e}")
1998
+ logger.error(
1999
+ f"[MEMORY] Failed to record conversation {chat_id[:8]}... - {type(e).__name__}: {e}"
2000
+ )
1938
2001
  import traceback
1939
2002
 
1940
- logger.error(f"Recording error details: {traceback.format_exc()}")
2003
+ logger.debug(f"[MEMORY] Recording error details: {traceback.format_exc()}")
1941
2004
  raise
1942
2005
 
1943
2006
  def _schedule_memory_processing(
@@ -28,6 +28,21 @@ class DatabaseAutoCreator:
28
28
  self.schema_init = schema_init
29
29
  self.utils = DatabaseConnectionUtils()
30
30
 
31
+ def _is_gibsonai_temp_connection(self, components: dict[str, str] | None) -> bool:
32
+ """Detect GibsonAI temporary database credentials to avoid noisy warnings."""
33
+ if not components:
34
+ return False
35
+
36
+ host = (components.get("host") or "").lower()
37
+ if "gibsonai.com" not in host:
38
+ return False
39
+
40
+ user = components.get("user") or components.get("username") or ""
41
+ database = components.get("database") or ""
42
+
43
+ # GibsonAI temporary credentials follow predictable us_/db_ prefixes
44
+ return user.startswith("us_") or database.startswith("db_")
45
+
31
46
  def ensure_database_exists(self, connection_string: str) -> str:
32
47
  """
33
48
  Ensure target database exists, creating it if necessary.
@@ -45,6 +60,7 @@ class DatabaseAutoCreator:
45
60
  logger.debug("Auto-creation disabled, using original connection string")
46
61
  return connection_string
47
62
 
63
+ components = None
48
64
  try:
49
65
  # Parse connection string
50
66
  components = self.utils.parse_connection_string(connection_string)
@@ -56,6 +72,13 @@ class DatabaseAutoCreator:
56
72
  )
57
73
  return connection_string
58
74
 
75
+ # Skip noisy warnings for managed GibsonAI temporary databases
76
+ if self._is_gibsonai_temp_connection(components):
77
+ logger.debug(
78
+ "[DB_SETUP] GibsonAI managed database detected - skipping auto-creation checks"
79
+ )
80
+ return connection_string
81
+
59
82
  # Validate database name
60
83
  if not self.utils.validate_database_name(components["database"]):
61
84
  raise ValueError(f"Invalid database name: {components['database']}")
@@ -70,10 +93,39 @@ class DatabaseAutoCreator:
70
93
  logger.info(f"Successfully created database '{components['database']}'")
71
94
  return connection_string
72
95
 
96
+ except PermissionError as e:
97
+ if components and self._is_gibsonai_temp_connection(components):
98
+ logger.debug(
99
+ "[DB_SETUP] GibsonAI managed database does not allow auto-creation (permission denied)"
100
+ )
101
+ return connection_string
102
+
103
+ logger.error(f"[DB_SETUP] Permission denied - {e}")
104
+ if components:
105
+ logger.warning(
106
+ f"[DB_SETUP] Database '{components['database']}' may need manual creation with proper permissions"
107
+ )
108
+ else:
109
+ logger.warning(
110
+ "[DB_SETUP] Database may need manual creation with proper permissions"
111
+ )
112
+ return connection_string
113
+ except RuntimeError as e:
114
+ logger.error(f"[DB_SETUP] Database creation error - {e}")
115
+ logger.info(
116
+ "[DB_SETUP] Proceeding with original connection string, database may need manual setup"
117
+ )
118
+ return connection_string
73
119
  except Exception as e:
74
- logger.error(f"Database auto-creation failed: {e}")
75
- # Don't raise exception - let the original connection attempt proceed
76
- # This allows graceful degradation if user has manual setup
120
+ logger.error(
121
+ f"[DB_SETUP] Unexpected database auto-creation failure - {type(e).__name__}: {e}"
122
+ )
123
+ if components:
124
+ logger.debug(
125
+ f"[DB_SETUP] Connection string: {components['engine']}://{components['host']}:{components['port']}/{components['database']}"
126
+ )
127
+ else:
128
+ logger.debug(f"[DB_SETUP] Connection string: {connection_string}")
77
129
  return connection_string
78
130
 
79
131
  def _database_exists(self, components: dict[str, str]) -> bool:
@@ -90,7 +142,12 @@ class DatabaseAutoCreator:
90
142
  return False
91
143
 
92
144
  except Exception as e:
93
- logger.error(f"Failed to check database existence: {e}")
145
+ if self._is_gibsonai_temp_connection(components):
146
+ logger.debug(
147
+ "[DB_CONNECTION] Skipping GibsonAI database existence check due to restricted permissions"
148
+ )
149
+ else:
150
+ logger.error(f"Failed to check database existence: {e}")
94
151
  return False
95
152
 
96
153
  def _postgresql_database_exists(self, components: dict[str, str]) -> bool:
@@ -176,7 +233,17 @@ class DatabaseAutoCreator:
176
233
  logger.error(error_msg)
177
234
  return False
178
235
  except Exception as e:
179
- logger.error(f"MySQL database existence check failed: {e}")
236
+ if self._is_gibsonai_temp_connection(components):
237
+ logger.debug(
238
+ f"[DB_CONNECTION] GibsonAI existence check bypassed for '{components['database']}' ({e})"
239
+ )
240
+ else:
241
+ logger.error(
242
+ f"[DB_CONNECTION] MySQL database existence check failed for '{components['database']}': {e}"
243
+ )
244
+ logger.debug(
245
+ f"[DB_CONNECTION] Connection details - host: {components.get('host')}, port: {components.get('port')}, user: {components.get('user') or components.get('username')}"
246
+ )
180
247
  return False
181
248
 
182
249
  def _create_database(self, components: dict[str, str]) -> None: