memmachine-server 0.3.2__tar.gz → 0.3.3__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 (280) hide show
  1. {memmachine_server-0.3.2/src/memmachine_server.egg-info → memmachine_server-0.3.3}/PKG-INFO +1 -1
  2. memmachine_server-0.3.3/server_tests/memmachine_server/common/embedder/test_openai_embedder.py +126 -0
  3. {memmachine_server-0.3.2 → memmachine_server-0.3.3}/server_tests/memmachine_server/common/language_model/test_openai_chat_completions_language_model.py +29 -0
  4. {memmachine_server-0.3.2 → memmachine_server-0.3.3}/server_tests/memmachine_server/common/language_model/test_openai_responses_language_model.py +29 -0
  5. {memmachine_server-0.3.2 → memmachine_server-0.3.3}/server_tests/memmachine_server/episodic_memory/short_term_memory/test_short_term_memory.py +72 -0
  6. {memmachine_server-0.3.2 → memmachine_server-0.3.3}/server_tests/memmachine_server/semantic_memory/mock_semantic_memory_objects.py +3 -0
  7. {memmachine_server-0.3.2 → memmachine_server-0.3.3}/server_tests/memmachine_server/semantic_memory/storage/in_memory_semantic_storage.py +28 -0
  8. {memmachine_server-0.3.2 → memmachine_server-0.3.3}/server_tests/memmachine_server/semantic_memory/storage/test_semantic_storage.py +110 -0
  9. memmachine_server-0.3.3/server_tests/memmachine_server/semantic_memory/storage/test_text_sanitizer.py +48 -0
  10. {memmachine_server-0.3.2 → memmachine_server-0.3.3}/server_tests/memmachine_server/semantic_memory/test_semantic_ingestion.py +97 -0
  11. {memmachine_server-0.3.2 → memmachine_server-0.3.3}/server_tests/memmachine_server/semantic_memory/test_semantic_model.py +93 -0
  12. {memmachine_server-0.3.2 → memmachine_server-0.3.3}/src/memmachine_server/common/configuration/__init__.py +9 -0
  13. {memmachine_server-0.3.2 → memmachine_server-0.3.3}/src/memmachine_server/common/configuration/mixin_confs.py +16 -7
  14. {memmachine_server-0.3.2 → memmachine_server-0.3.3}/src/memmachine_server/common/embedder/openai_embedder.py +1 -0
  15. {memmachine_server-0.3.2 → memmachine_server-0.3.3}/src/memmachine_server/common/language_model/openai_chat_completions_language_model.py +1 -0
  16. {memmachine_server-0.3.2 → memmachine_server-0.3.3}/src/memmachine_server/common/language_model/openai_responses_language_model.py +1 -0
  17. {memmachine_server-0.3.2 → memmachine_server-0.3.3}/src/memmachine_server/common/resource_manager/semantic_manager.py +1 -0
  18. {memmachine_server-0.3.2 → memmachine_server-0.3.3}/src/memmachine_server/episodic_memory/short_term_memory/short_term_memory.py +44 -20
  19. {memmachine_server-0.3.2 → memmachine_server-0.3.3}/src/memmachine_server/semantic_memory/semantic_ingestion.py +44 -2
  20. {memmachine_server-0.3.2 → memmachine_server-0.3.3}/src/memmachine_server/semantic_memory/semantic_llm.py +8 -0
  21. {memmachine_server-0.3.2 → memmachine_server-0.3.3}/src/memmachine_server/semantic_memory/semantic_memory.py +40 -2
  22. {memmachine_server-0.3.2 → memmachine_server-0.3.3}/src/memmachine_server/semantic_memory/semantic_model.py +8 -1
  23. memmachine_server-0.3.3/src/memmachine_server/semantic_memory/storage/alembic_pg/versions/c7a2f8e31b90_add_ingested_composite_index.py +36 -0
  24. {memmachine_server-0.3.2 → memmachine_server-0.3.3}/src/memmachine_server/semantic_memory/storage/neo4j_semantic_storage.py +24 -0
  25. {memmachine_server-0.3.2 → memmachine_server-0.3.3}/src/memmachine_server/semantic_memory/storage/sqlalchemy_pgvector_semantic.py +61 -31
  26. {memmachine_server-0.3.2 → memmachine_server-0.3.3}/src/memmachine_server/semantic_memory/storage/storage_base.py +11 -0
  27. memmachine_server-0.3.3/src/memmachine_server/semantic_memory/storage/text_sanitizer.py +22 -0
  28. {memmachine_server-0.3.2 → memmachine_server-0.3.3/src/memmachine_server.egg-info}/PKG-INFO +1 -1
  29. {memmachine_server-0.3.2 → memmachine_server-0.3.3}/src/memmachine_server.egg-info/SOURCES.txt +3 -0
  30. memmachine_server-0.3.2/server_tests/memmachine_server/common/embedder/test_openai_embedder.py +0 -48
  31. {memmachine_server-0.3.2 → memmachine_server-0.3.3}/LICENSE +0 -0
  32. {memmachine_server-0.3.2 → memmachine_server-0.3.3}/README.md +0 -0
  33. {memmachine_server-0.3.2 → memmachine_server-0.3.3}/pyproject.toml +0 -0
  34. {memmachine_server-0.3.2 → memmachine_server-0.3.3}/server_tests/__init__.py +0 -0
  35. {memmachine_server-0.3.2 → memmachine_server-0.3.3}/server_tests/memmachine_server/__init__.py +0 -0
  36. {memmachine_server-0.3.2 → memmachine_server-0.3.3}/server_tests/memmachine_server/common/__init__.py +0 -0
  37. {memmachine_server-0.3.2 → memmachine_server-0.3.3}/server_tests/memmachine_server/common/api/__init__.py +0 -0
  38. {memmachine_server-0.3.2 → memmachine_server-0.3.3}/server_tests/memmachine_server/common/api/test_version.py +0 -0
  39. {memmachine_server-0.3.2 → memmachine_server-0.3.3}/server_tests/memmachine_server/common/configuration/__init__.py +0 -0
  40. {memmachine_server-0.3.2 → memmachine_server-0.3.3}/server_tests/memmachine_server/common/configuration/test_configuration.py +0 -0
  41. {memmachine_server-0.3.2 → memmachine_server-0.3.3}/server_tests/memmachine_server/common/configuration/test_database_conf.py +0 -0
  42. {memmachine_server-0.3.2 → memmachine_server-0.3.3}/server_tests/memmachine_server/common/configuration/test_embedder_conf.py +0 -0
  43. {memmachine_server-0.3.2 → memmachine_server-0.3.3}/server_tests/memmachine_server/common/configuration/test_episodic_config.py +0 -0
  44. {memmachine_server-0.3.2 → memmachine_server-0.3.3}/server_tests/memmachine_server/common/configuration/test_language_model_conf.py +0 -0
  45. {memmachine_server-0.3.2 → memmachine_server-0.3.3}/server_tests/memmachine_server/common/configuration/test_log_conf.py +0 -0
  46. {memmachine_server-0.3.2 → memmachine_server-0.3.3}/server_tests/memmachine_server/common/configuration/test_mixin_confs.py +0 -0
  47. {memmachine_server-0.3.2 → memmachine_server-0.3.3}/server_tests/memmachine_server/common/configuration/test_prompt_conf.py +0 -0
  48. {memmachine_server-0.3.2 → memmachine_server-0.3.3}/server_tests/memmachine_server/common/configuration/test_reranker_conf.py +0 -0
  49. {memmachine_server-0.3.2 → memmachine_server-0.3.3}/server_tests/memmachine_server/common/configuration/test_semantic_conf.py +0 -0
  50. {memmachine_server-0.3.2 → memmachine_server-0.3.3}/server_tests/memmachine_server/common/configuration/test_server_conf.py +0 -0
  51. {memmachine_server-0.3.2 → memmachine_server-0.3.3}/server_tests/memmachine_server/common/embedder/__init__.py +0 -0
  52. {memmachine_server-0.3.2 → memmachine_server-0.3.3}/server_tests/memmachine_server/common/embedder/test_amazon_bedrock_embedder.py +0 -0
  53. {memmachine_server-0.3.2 → memmachine_server-0.3.3}/server_tests/memmachine_server/common/embedder/test_sentence_transformer_embedder.py +0 -0
  54. {memmachine_server-0.3.2 → memmachine_server-0.3.3}/server_tests/memmachine_server/common/episode_store/__init__.py +0 -0
  55. {memmachine_server-0.3.2 → memmachine_server-0.3.3}/server_tests/memmachine_server/common/episode_store/test_count_caching_episode_storage.py +0 -0
  56. {memmachine_server-0.3.2 → memmachine_server-0.3.3}/server_tests/memmachine_server/common/episode_store/test_episode_model.py +0 -0
  57. {memmachine_server-0.3.2 → memmachine_server-0.3.3}/server_tests/memmachine_server/common/episode_store/test_episode_storage.py +0 -0
  58. {memmachine_server-0.3.2 → memmachine_server-0.3.3}/server_tests/memmachine_server/common/episode_store/test_sqlalchemy_episode_store_startup.py +0 -0
  59. {memmachine_server-0.3.2 → memmachine_server-0.3.3}/server_tests/memmachine_server/common/filter/__init__.py +0 -0
  60. {memmachine_server-0.3.2 → memmachine_server-0.3.3}/server_tests/memmachine_server/common/filter/test_filter_parser.py +0 -0
  61. {memmachine_server-0.3.2 → memmachine_server-0.3.3}/server_tests/memmachine_server/common/filter/test_sql_filter_util.py +0 -0
  62. {memmachine_server-0.3.2 → memmachine_server-0.3.3}/server_tests/memmachine_server/common/language_model/__init__.py +0 -0
  63. {memmachine_server-0.3.2 → memmachine_server-0.3.3}/server_tests/memmachine_server/common/reranker/__init__.py +0 -0
  64. {memmachine_server-0.3.2 → memmachine_server-0.3.3}/server_tests/memmachine_server/common/reranker/fake_embedder.py +0 -0
  65. {memmachine_server-0.3.2 → memmachine_server-0.3.3}/server_tests/memmachine_server/common/reranker/test_amazon_bedrock_reranker.py +0 -0
  66. {memmachine_server-0.3.2 → memmachine_server-0.3.3}/server_tests/memmachine_server/common/reranker/test_bm25_reranker.py +0 -0
  67. {memmachine_server-0.3.2 → memmachine_server-0.3.3}/server_tests/memmachine_server/common/reranker/test_cohere_reranker.py +0 -0
  68. {memmachine_server-0.3.2 → memmachine_server-0.3.3}/server_tests/memmachine_server/common/reranker/test_cross_encoder_reranker.py +0 -0
  69. {memmachine_server-0.3.2 → memmachine_server-0.3.3}/server_tests/memmachine_server/common/reranker/test_embedder_reranker.py +0 -0
  70. {memmachine_server-0.3.2 → memmachine_server-0.3.3}/server_tests/memmachine_server/common/reranker/test_identity_reranker.py +0 -0
  71. {memmachine_server-0.3.2 → memmachine_server-0.3.3}/server_tests/memmachine_server/common/reranker/test_rrf_hybrid_reranker.py +0 -0
  72. {memmachine_server-0.3.2 → memmachine_server-0.3.3}/server_tests/memmachine_server/common/resource_manager/__init__.py +0 -0
  73. {memmachine_server-0.3.2 → memmachine_server-0.3.3}/server_tests/memmachine_server/common/resource_manager/test_database_manager.py +0 -0
  74. {memmachine_server-0.3.2 → memmachine_server-0.3.3}/server_tests/memmachine_server/common/resource_manager/test_embedder_manager.py +0 -0
  75. {memmachine_server-0.3.2 → memmachine_server-0.3.3}/server_tests/memmachine_server/common/resource_manager/test_language_model_manager.py +0 -0
  76. {memmachine_server-0.3.2 → memmachine_server-0.3.3}/server_tests/memmachine_server/common/resource_manager/test_reranker_manager.py +0 -0
  77. {memmachine_server-0.3.2 → memmachine_server-0.3.3}/server_tests/memmachine_server/common/resource_manager/test_resource_manager.py +0 -0
  78. {memmachine_server-0.3.2 → memmachine_server-0.3.3}/server_tests/memmachine_server/common/session_manager/__init__.py +0 -0
  79. {memmachine_server-0.3.2 → memmachine_server-0.3.3}/server_tests/memmachine_server/common/session_manager/test_session_manager.py +0 -0
  80. {memmachine_server-0.3.2 → memmachine_server-0.3.3}/server_tests/memmachine_server/common/session_manager/test_session_manager_migration.py +0 -0
  81. {memmachine_server-0.3.2 → memmachine_server-0.3.3}/server_tests/memmachine_server/common/test_rw_locks.py +0 -0
  82. {memmachine_server-0.3.2 → memmachine_server-0.3.3}/server_tests/memmachine_server/common/test_utils.py +0 -0
  83. {memmachine_server-0.3.2 → memmachine_server-0.3.3}/server_tests/memmachine_server/common/vector_graph_store/__init__.py +0 -0
  84. {memmachine_server-0.3.2 → memmachine_server-0.3.3}/server_tests/memmachine_server/common/vector_graph_store/test_nebula_graph_vector_graph_store.py +0 -0
  85. {memmachine_server-0.3.2 → memmachine_server-0.3.3}/server_tests/memmachine_server/common/vector_graph_store/test_neo4j_vector_graph_store.py +0 -0
  86. {memmachine_server-0.3.2 → memmachine_server-0.3.3}/server_tests/memmachine_server/conftest.py +0 -0
  87. {memmachine_server-0.3.2 → memmachine_server-0.3.3}/server_tests/memmachine_server/episodic_memory/__init__.py +0 -0
  88. {memmachine_server-0.3.2 → memmachine_server-0.3.3}/server_tests/memmachine_server/episodic_memory/conftest.py +0 -0
  89. {memmachine_server-0.3.2 → memmachine_server-0.3.3}/server_tests/memmachine_server/episodic_memory/declarative_memory/__init__.py +0 -0
  90. {memmachine_server-0.3.2 → memmachine_server-0.3.3}/server_tests/memmachine_server/episodic_memory/declarative_memory/test_declarative_memory.py +0 -0
  91. {memmachine_server-0.3.2 → memmachine_server-0.3.3}/server_tests/memmachine_server/episodic_memory/long_term_memory/__init__.py +0 -0
  92. {memmachine_server-0.3.2 → memmachine_server-0.3.3}/server_tests/memmachine_server/episodic_memory/long_term_memory/test_long_term_memory.py +0 -0
  93. {memmachine_server-0.3.2 → memmachine_server-0.3.3}/server_tests/memmachine_server/episodic_memory/short_term_memory/__init__.py +0 -0
  94. {memmachine_server-0.3.2 → memmachine_server-0.3.3}/server_tests/memmachine_server/episodic_memory/test_episodic_memory.py +0 -0
  95. {memmachine_server-0.3.2 → memmachine_server-0.3.3}/server_tests/memmachine_server/episodic_memory/test_episodic_memory_manager.py +0 -0
  96. {memmachine_server-0.3.2 → memmachine_server-0.3.3}/server_tests/memmachine_server/episodic_memory/test_instance_lru_cache.py +0 -0
  97. {memmachine_server-0.3.2 → memmachine_server-0.3.3}/server_tests/memmachine_server/installation/__init__.py +0 -0
  98. {memmachine_server-0.3.2 → memmachine_server-0.3.3}/server_tests/memmachine_server/installation/test_configuration_wizard.py +0 -0
  99. {memmachine_server-0.3.2 → memmachine_server-0.3.3}/server_tests/memmachine_server/installation/test_memmachine_configure.py +0 -0
  100. {memmachine_server-0.3.2 → memmachine_server-0.3.3}/server_tests/memmachine_server/installation/test_utilities.py +0 -0
  101. {memmachine_server-0.3.2 → memmachine_server-0.3.3}/server_tests/memmachine_server/main/__init__.py +0 -0
  102. {memmachine_server-0.3.2 → memmachine_server-0.3.3}/server_tests/memmachine_server/main/conftest.py +0 -0
  103. {memmachine_server-0.3.2 → memmachine_server-0.3.3}/server_tests/memmachine_server/main/test_memachine.py +0 -0
  104. {memmachine_server-0.3.2 → memmachine_server-0.3.3}/server_tests/memmachine_server/main/test_memmachine_delete_session.py +0 -0
  105. {memmachine_server-0.3.2 → memmachine_server-0.3.3}/server_tests/memmachine_server/main/test_memmachine_integration.py +0 -0
  106. {memmachine_server-0.3.2 → memmachine_server-0.3.3}/server_tests/memmachine_server/main/test_memmachine_mock.py +0 -0
  107. {memmachine_server-0.3.2 → memmachine_server-0.3.3}/server_tests/memmachine_server/retrieval_agent/__init__.py +0 -0
  108. {memmachine_server-0.3.2 → memmachine_server-0.3.3}/server_tests/memmachine_server/retrieval_agent/test_retrieval_agent.py +0 -0
  109. {memmachine_server-0.3.2 → memmachine_server-0.3.3}/server_tests/memmachine_server/semantic_memory/__init__.py +0 -0
  110. {memmachine_server-0.3.2 → memmachine_server-0.3.3}/server_tests/memmachine_server/semantic_memory/config_store/__init__.py +0 -0
  111. {memmachine_server-0.3.2 → memmachine_server-0.3.3}/server_tests/memmachine_server/semantic_memory/config_store/test_caching_semantic_config_storage.py +0 -0
  112. {memmachine_server-0.3.2 → memmachine_server-0.3.3}/server_tests/memmachine_server/semantic_memory/config_store/test_semantic_config_storage.py +0 -0
  113. {memmachine_server-0.3.2 → memmachine_server-0.3.3}/server_tests/memmachine_server/semantic_memory/conftest.py +0 -0
  114. {memmachine_server-0.3.2 → memmachine_server-0.3.3}/server_tests/memmachine_server/semantic_memory/semantic_test_utils.py +0 -0
  115. {memmachine_server-0.3.2 → memmachine_server-0.3.3}/server_tests/memmachine_server/semantic_memory/storage/__init__.py +0 -0
  116. {memmachine_server-0.3.2 → memmachine_server-0.3.3}/server_tests/memmachine_server/semantic_memory/storage/alembic_pg/__init__.py +0 -0
  117. {memmachine_server-0.3.2 → memmachine_server-0.3.3}/server_tests/memmachine_server/semantic_memory/storage/alembic_pg/helpers.py +0 -0
  118. {memmachine_server-0.3.2 → memmachine_server-0.3.3}/server_tests/memmachine_server/semantic_memory/storage/alembic_pg/original_schema.sql +0 -0
  119. {memmachine_server-0.3.2 → memmachine_server-0.3.3}/server_tests/memmachine_server/semantic_memory/storage/alembic_pg/test_set_id_migration.py +0 -0
  120. {memmachine_server-0.3.2 → memmachine_server-0.3.3}/server_tests/memmachine_server/semantic_memory/storage/alembic_pg/test_sqlalchemy_vs_alembic.py +0 -0
  121. {memmachine_server-0.3.2 → memmachine_server-0.3.3}/server_tests/memmachine_server/semantic_memory/storage/conftest.py +0 -0
  122. {memmachine_server-0.3.2 → memmachine_server-0.3.3}/server_tests/memmachine_server/semantic_memory/test_semantic_history_cleanup.py +0 -0
  123. {memmachine_server-0.3.2 → memmachine_server-0.3.3}/server_tests/memmachine_server/semantic_memory/test_semantic_llm.py +0 -0
  124. {memmachine_server-0.3.2 → memmachine_server-0.3.3}/server_tests/memmachine_server/semantic_memory/test_semantic_llm_integration.py +0 -0
  125. {memmachine_server-0.3.2 → memmachine_server-0.3.3}/server_tests/memmachine_server/semantic_memory/test_semantic_memory.py +0 -0
  126. {memmachine_server-0.3.2 → memmachine_server-0.3.3}/server_tests/memmachine_server/semantic_memory/test_semantic_memory_background.py +0 -0
  127. {memmachine_server-0.3.2 → memmachine_server-0.3.3}/server_tests/memmachine_server/semantic_memory/test_semantic_memory_integration.py +0 -0
  128. {memmachine_server-0.3.2 → memmachine_server-0.3.3}/server_tests/memmachine_server/semantic_memory/test_semantic_session_manager.py +0 -0
  129. {memmachine_server-0.3.2 → memmachine_server-0.3.3}/server_tests/memmachine_server/server/__init__.py +0 -0
  130. {memmachine_server-0.3.2 → memmachine_server-0.3.3}/server_tests/memmachine_server/server/api_v2/__init__.py +0 -0
  131. {memmachine_server-0.3.2 → memmachine_server-0.3.3}/server_tests/memmachine_server/server/api_v2/test_config_router.py +0 -0
  132. {memmachine_server-0.3.2 → memmachine_server-0.3.3}/server_tests/memmachine_server/server/api_v2/test_config_service.py +0 -0
  133. {memmachine_server-0.3.2 → memmachine_server-0.3.3}/server_tests/memmachine_server/server/api_v2/test_mcp.py +0 -0
  134. {memmachine_server-0.3.2 → memmachine_server-0.3.3}/server_tests/memmachine_server/server/api_v2/test_router.py +0 -0
  135. {memmachine_server-0.3.2 → memmachine_server-0.3.3}/server_tests/memmachine_server/server/api_v2/test_service.py +0 -0
  136. {memmachine_server-0.3.2 → memmachine_server-0.3.3}/server_tests/memmachine_server/server/api_v2/test_spec.py +0 -0
  137. {memmachine_server-0.3.2 → memmachine_server-0.3.3}/server_tests/memmachine_server/server/prompt/__init__.py +0 -0
  138. {memmachine_server-0.3.2 → memmachine_server-0.3.3}/server_tests/memmachine_server/server/prompt/test_prompt_utilities.py +0 -0
  139. {memmachine_server-0.3.2 → memmachine_server-0.3.3}/server_tests/memmachine_server/server/test_middleware.py +0 -0
  140. {memmachine_server-0.3.2 → memmachine_server-0.3.3}/server_tests/memmachine_server/test_data/longmemeval_snippet.json +0 -0
  141. {memmachine_server-0.3.2 → memmachine_server-0.3.3}/setup.cfg +0 -0
  142. {memmachine_server-0.3.2 → memmachine_server-0.3.3}/src/memmachine_server/__init__.py +0 -0
  143. {memmachine_server-0.3.2 → memmachine_server-0.3.3}/src/memmachine_server/common/__init__.py +0 -0
  144. {memmachine_server-0.3.2 → memmachine_server-0.3.3}/src/memmachine_server/common/api/__init__.py +0 -0
  145. {memmachine_server-0.3.2 → memmachine_server-0.3.3}/src/memmachine_server/common/api/version.py +0 -0
  146. {memmachine_server-0.3.2 → memmachine_server-0.3.3}/src/memmachine_server/common/configuration/database_conf.py +0 -0
  147. {memmachine_server-0.3.2 → memmachine_server-0.3.3}/src/memmachine_server/common/configuration/default_episode_summary_system_prompt.txt +0 -0
  148. {memmachine_server-0.3.2 → memmachine_server-0.3.3}/src/memmachine_server/common/configuration/default_episode_summary_user_prompt.txt +0 -0
  149. {memmachine_server-0.3.2 → memmachine_server-0.3.3}/src/memmachine_server/common/configuration/embedder_conf.py +0 -0
  150. {memmachine_server-0.3.2 → memmachine_server-0.3.3}/src/memmachine_server/common/configuration/episodic_config.py +0 -0
  151. {memmachine_server-0.3.2 → memmachine_server-0.3.3}/src/memmachine_server/common/configuration/language_model_conf.py +0 -0
  152. {memmachine_server-0.3.2 → memmachine_server-0.3.3}/src/memmachine_server/common/configuration/log_conf.py +0 -0
  153. {memmachine_server-0.3.2 → memmachine_server-0.3.3}/src/memmachine_server/common/configuration/reranker_conf.py +0 -0
  154. {memmachine_server-0.3.2 → memmachine_server-0.3.3}/src/memmachine_server/common/configuration/retrieval_config.py +0 -0
  155. {memmachine_server-0.3.2 → memmachine_server-0.3.3}/src/memmachine_server/common/data_types.py +0 -0
  156. {memmachine_server-0.3.2 → memmachine_server-0.3.3}/src/memmachine_server/common/embedder/__init__.py +0 -0
  157. {memmachine_server-0.3.2 → memmachine_server-0.3.3}/src/memmachine_server/common/embedder/amazon_bedrock_embedder.py +0 -0
  158. {memmachine_server-0.3.2 → memmachine_server-0.3.3}/src/memmachine_server/common/embedder/embedder.py +0 -0
  159. {memmachine_server-0.3.2 → memmachine_server-0.3.3}/src/memmachine_server/common/embedder/sentence_transformer_embedder.py +0 -0
  160. {memmachine_server-0.3.2 → memmachine_server-0.3.3}/src/memmachine_server/common/episode_store/__init__.py +0 -0
  161. {memmachine_server-0.3.2 → memmachine_server-0.3.3}/src/memmachine_server/common/episode_store/count_caching_episode_storage.py +0 -0
  162. {memmachine_server-0.3.2 → memmachine_server-0.3.3}/src/memmachine_server/common/episode_store/episode_model.py +0 -0
  163. {memmachine_server-0.3.2 → memmachine_server-0.3.3}/src/memmachine_server/common/episode_store/episode_sqlalchemy_store.py +0 -0
  164. {memmachine_server-0.3.2 → memmachine_server-0.3.3}/src/memmachine_server/common/episode_store/episode_storage.py +0 -0
  165. {memmachine_server-0.3.2 → memmachine_server-0.3.3}/src/memmachine_server/common/errors.py +0 -0
  166. {memmachine_server-0.3.2 → memmachine_server-0.3.3}/src/memmachine_server/common/filter/__init__.py +0 -0
  167. {memmachine_server-0.3.2 → memmachine_server-0.3.3}/src/memmachine_server/common/filter/filter_parser.py +0 -0
  168. {memmachine_server-0.3.2 → memmachine_server-0.3.3}/src/memmachine_server/common/filter/sql_filter_util.py +0 -0
  169. {memmachine_server-0.3.2 → memmachine_server-0.3.3}/src/memmachine_server/common/language_model/__init__.py +0 -0
  170. {memmachine_server-0.3.2 → memmachine_server-0.3.3}/src/memmachine_server/common/language_model/amazon_bedrock_language_model.py +0 -0
  171. {memmachine_server-0.3.2 → memmachine_server-0.3.3}/src/memmachine_server/common/language_model/language_model.py +0 -0
  172. {memmachine_server-0.3.2 → memmachine_server-0.3.3}/src/memmachine_server/common/metrics_factory/__init__.py +0 -0
  173. {memmachine_server-0.3.2 → memmachine_server-0.3.3}/src/memmachine_server/common/metrics_factory/metrics_factory.py +0 -0
  174. {memmachine_server-0.3.2 → memmachine_server-0.3.3}/src/memmachine_server/common/metrics_factory/operation_tracker.py +0 -0
  175. {memmachine_server-0.3.2 → memmachine_server-0.3.3}/src/memmachine_server/common/metrics_factory/prometheus_metrics_factory.py +0 -0
  176. {memmachine_server-0.3.2 → memmachine_server-0.3.3}/src/memmachine_server/common/neo4j_utils.py +0 -0
  177. {memmachine_server-0.3.2 → memmachine_server-0.3.3}/src/memmachine_server/common/reranker/__init__.py +0 -0
  178. {memmachine_server-0.3.2 → memmachine_server-0.3.3}/src/memmachine_server/common/reranker/amazon_bedrock_reranker.py +0 -0
  179. {memmachine_server-0.3.2 → memmachine_server-0.3.3}/src/memmachine_server/common/reranker/bm25_reranker.py +0 -0
  180. {memmachine_server-0.3.2 → memmachine_server-0.3.3}/src/memmachine_server/common/reranker/cohere_reranker.py +0 -0
  181. {memmachine_server-0.3.2 → memmachine_server-0.3.3}/src/memmachine_server/common/reranker/cross_encoder_reranker.py +0 -0
  182. {memmachine_server-0.3.2 → memmachine_server-0.3.3}/src/memmachine_server/common/reranker/embedder_reranker.py +0 -0
  183. {memmachine_server-0.3.2 → memmachine_server-0.3.3}/src/memmachine_server/common/reranker/identity_reranker.py +0 -0
  184. {memmachine_server-0.3.2 → memmachine_server-0.3.3}/src/memmachine_server/common/reranker/reranker.py +0 -0
  185. {memmachine_server-0.3.2 → memmachine_server-0.3.3}/src/memmachine_server/common/reranker/rrf_hybrid_reranker.py +0 -0
  186. {memmachine_server-0.3.2 → memmachine_server-0.3.3}/src/memmachine_server/common/resource_manager/__init__.py +0 -0
  187. {memmachine_server-0.3.2 → memmachine_server-0.3.3}/src/memmachine_server/common/resource_manager/base_manager.py +0 -0
  188. {memmachine_server-0.3.2 → memmachine_server-0.3.3}/src/memmachine_server/common/resource_manager/database_manager.py +0 -0
  189. {memmachine_server-0.3.2 → memmachine_server-0.3.3}/src/memmachine_server/common/resource_manager/embedder_manager.py +0 -0
  190. {memmachine_server-0.3.2 → memmachine_server-0.3.3}/src/memmachine_server/common/resource_manager/language_model_manager.py +0 -0
  191. {memmachine_server-0.3.2 → memmachine_server-0.3.3}/src/memmachine_server/common/resource_manager/reranker_manager.py +0 -0
  192. {memmachine_server-0.3.2 → memmachine_server-0.3.3}/src/memmachine_server/common/resource_manager/resource_manager.py +0 -0
  193. {memmachine_server-0.3.2 → memmachine_server-0.3.3}/src/memmachine_server/common/rw_locks.py +0 -0
  194. {memmachine_server-0.3.2 → memmachine_server-0.3.3}/src/memmachine_server/common/session_manager/__init__.py +0 -0
  195. {memmachine_server-0.3.2 → memmachine_server-0.3.3}/src/memmachine_server/common/session_manager/session_data_manager.py +0 -0
  196. {memmachine_server-0.3.2 → memmachine_server-0.3.3}/src/memmachine_server/common/session_manager/session_data_manager_sql_impl.py +0 -0
  197. {memmachine_server-0.3.2 → memmachine_server-0.3.3}/src/memmachine_server/common/utils.py +0 -0
  198. {memmachine_server-0.3.2 → memmachine_server-0.3.3}/src/memmachine_server/common/vector_graph_store/__init__.py +0 -0
  199. {memmachine_server-0.3.2 → memmachine_server-0.3.3}/src/memmachine_server/common/vector_graph_store/data_types.py +0 -0
  200. {memmachine_server-0.3.2 → memmachine_server-0.3.3}/src/memmachine_server/common/vector_graph_store/nebula_graph_vector_graph_store.py +0 -0
  201. {memmachine_server-0.3.2 → memmachine_server-0.3.3}/src/memmachine_server/common/vector_graph_store/neo4j_vector_graph_store.py +0 -0
  202. {memmachine_server-0.3.2 → memmachine_server-0.3.3}/src/memmachine_server/common/vector_graph_store/vector_graph_store.py +0 -0
  203. {memmachine_server-0.3.2 → memmachine_server-0.3.3}/src/memmachine_server/common/vector_store/__init__.py +0 -0
  204. {memmachine_server-0.3.2 → memmachine_server-0.3.3}/src/memmachine_server/common/vector_store/data_types.py +0 -0
  205. {memmachine_server-0.3.2 → memmachine_server-0.3.3}/src/memmachine_server/common/vector_store/vector_store.py +0 -0
  206. {memmachine_server-0.3.2 → memmachine_server-0.3.3}/src/memmachine_server/episodic_memory/__init__.py +0 -0
  207. {memmachine_server-0.3.2 → memmachine_server-0.3.3}/src/memmachine_server/episodic_memory/declarative_memory/__init__.py +0 -0
  208. {memmachine_server-0.3.2 → memmachine_server-0.3.3}/src/memmachine_server/episodic_memory/declarative_memory/data_types.py +0 -0
  209. {memmachine_server-0.3.2 → memmachine_server-0.3.3}/src/memmachine_server/episodic_memory/declarative_memory/declarative_memory.py +0 -0
  210. {memmachine_server-0.3.2 → memmachine_server-0.3.3}/src/memmachine_server/episodic_memory/episodic_memory.py +0 -0
  211. {memmachine_server-0.3.2 → memmachine_server-0.3.3}/src/memmachine_server/episodic_memory/episodic_memory_manager.py +0 -0
  212. {memmachine_server-0.3.2 → memmachine_server-0.3.3}/src/memmachine_server/episodic_memory/instance_lru_cache.py +0 -0
  213. {memmachine_server-0.3.2 → memmachine_server-0.3.3}/src/memmachine_server/episodic_memory/long_term_memory/__init__.py +0 -0
  214. {memmachine_server-0.3.2 → memmachine_server-0.3.3}/src/memmachine_server/episodic_memory/long_term_memory/long_term_memory.py +0 -0
  215. {memmachine_server-0.3.2 → memmachine_server-0.3.3}/src/memmachine_server/episodic_memory/long_term_memory/service_locator.py +0 -0
  216. {memmachine_server-0.3.2 → memmachine_server-0.3.3}/src/memmachine_server/episodic_memory/service_locator.py +0 -0
  217. {memmachine_server-0.3.2 → memmachine_server-0.3.3}/src/memmachine_server/episodic_memory/short_term_memory/__init__.py +0 -0
  218. {memmachine_server-0.3.2 → memmachine_server-0.3.3}/src/memmachine_server/episodic_memory/short_term_memory/service_locator.py +0 -0
  219. {memmachine_server-0.3.2 → memmachine_server-0.3.3}/src/memmachine_server/installation/__init__.py +0 -0
  220. {memmachine_server-0.3.2 → memmachine_server-0.3.3}/src/memmachine_server/installation/configuration_wizard.py +0 -0
  221. {memmachine_server-0.3.2 → memmachine_server-0.3.3}/src/memmachine_server/installation/memmachine_configure.py +0 -0
  222. {memmachine_server-0.3.2 → memmachine_server-0.3.3}/src/memmachine_server/installation/utilities.py +0 -0
  223. {memmachine_server-0.3.2 → memmachine_server-0.3.3}/src/memmachine_server/main/__init__.py +0 -0
  224. {memmachine_server-0.3.2 → memmachine_server-0.3.3}/src/memmachine_server/main/memmachine.py +0 -0
  225. {memmachine_server-0.3.2 → memmachine_server-0.3.3}/src/memmachine_server/retrieval_agent/__init__.py +0 -0
  226. {memmachine_server-0.3.2 → memmachine_server-0.3.3}/src/memmachine_server/retrieval_agent/agents/__init__.py +0 -0
  227. {memmachine_server-0.3.2 → memmachine_server-0.3.3}/src/memmachine_server/retrieval_agent/agents/coq_agent.py +0 -0
  228. {memmachine_server-0.3.2 → memmachine_server-0.3.3}/src/memmachine_server/retrieval_agent/agents/memmachine_retriever.py +0 -0
  229. {memmachine_server-0.3.2 → memmachine_server-0.3.3}/src/memmachine_server/retrieval_agent/agents/split_query_agent.py +0 -0
  230. {memmachine_server-0.3.2 → memmachine_server-0.3.3}/src/memmachine_server/retrieval_agent/agents/tool_select_agent.py +0 -0
  231. {memmachine_server-0.3.2 → memmachine_server-0.3.3}/src/memmachine_server/retrieval_agent/common/__init__.py +0 -0
  232. {memmachine_server-0.3.2 → memmachine_server-0.3.3}/src/memmachine_server/retrieval_agent/common/agent_api.py +0 -0
  233. {memmachine_server-0.3.2 → memmachine_server-0.3.3}/src/memmachine_server/retrieval_agent/service_locator.py +0 -0
  234. {memmachine_server-0.3.2 → memmachine_server-0.3.3}/src/memmachine_server/semantic_memory/__init__.py +0 -0
  235. {memmachine_server-0.3.2 → memmachine_server-0.3.3}/src/memmachine_server/semantic_memory/config_store/__init__.py +0 -0
  236. {memmachine_server-0.3.2 → memmachine_server-0.3.3}/src/memmachine_server/semantic_memory/config_store/caching_semantic_config_storage.py +0 -0
  237. {memmachine_server-0.3.2 → memmachine_server-0.3.3}/src/memmachine_server/semantic_memory/config_store/config_store.py +0 -0
  238. {memmachine_server-0.3.2 → memmachine_server-0.3.3}/src/memmachine_server/semantic_memory/config_store/config_store_sqlalchemy.py +0 -0
  239. {memmachine_server-0.3.2 → memmachine_server-0.3.3}/src/memmachine_server/semantic_memory/semantic_session_manager.py +0 -0
  240. {memmachine_server-0.3.2 → memmachine_server-0.3.3}/src/memmachine_server/semantic_memory/storage/__init__.py +0 -0
  241. {memmachine_server-0.3.2 → memmachine_server-0.3.3}/src/memmachine_server/semantic_memory/storage/alembic_pg/__init__.py +0 -0
  242. {memmachine_server-0.3.2 → memmachine_server-0.3.3}/src/memmachine_server/semantic_memory/storage/alembic_pg/env.py +0 -0
  243. {memmachine_server-0.3.2 → memmachine_server-0.3.3}/src/memmachine_server/semantic_memory/storage/alembic_pg/script.py.mako +0 -0
  244. {memmachine_server-0.3.2 → memmachine_server-0.3.3}/src/memmachine_server/semantic_memory/storage/alembic_pg/versions/001_initial_migration.py +0 -0
  245. {memmachine_server-0.3.2 → memmachine_server-0.3.3}/src/memmachine_server/semantic_memory/storage/alembic_pg/versions/3d6aaebdc526_sync_sqlalchemy_schema.py +0 -0
  246. {memmachine_server-0.3.2 → memmachine_server-0.3.3}/src/memmachine_server/semantic_memory/storage/alembic_pg/versions/62dff1150a46_add_created_at_to_history_add.py +0 -0
  247. {memmachine_server-0.3.2 → memmachine_server-0.3.3}/src/memmachine_server/semantic_memory/storage/alembic_pg/versions/79f00a9f2409_change_history_id_to_string.py +0 -0
  248. {memmachine_server-0.3.2 → memmachine_server-0.3.3}/src/memmachine_server/semantic_memory/storage/alembic_pg/versions/843f6d216d10_rename_semantic_type_to_semantic_.py +0 -0
  249. {memmachine_server-0.3.2 → memmachine_server-0.3.3}/src/memmachine_server/semantic_memory/storage/alembic_pg/versions/__init__.py +0 -0
  250. {memmachine_server-0.3.2 → memmachine_server-0.3.3}/src/memmachine_server/semantic_memory/storage/alembic_pg/versions/adb5618bd4ee_remove_history_table.py +0 -0
  251. {memmachine_server-0.3.2 → memmachine_server-0.3.3}/src/memmachine_server/semantic_memory/storage/alembic_pg/versions/b65f7f4a9d2c_migrate_legacy_set_ids.py +0 -0
  252. {memmachine_server-0.3.2 → memmachine_server-0.3.3}/src/memmachine_server/semantic_memory/storage/alembic_pg/versions/d1a9df11343b_add_indexes.py +0 -0
  253. {memmachine_server-0.3.2 → memmachine_server-0.3.3}/src/memmachine_server/semantic_memory/util/__init__.py +0 -0
  254. {memmachine_server-0.3.2 → memmachine_server-0.3.3}/src/memmachine_server/semantic_memory/util/semantic_prompt_template.py +0 -0
  255. {memmachine_server-0.3.2 → memmachine_server-0.3.3}/src/memmachine_server/server/__init__.py +0 -0
  256. {memmachine_server-0.3.2 → memmachine_server-0.3.3}/src/memmachine_server/server/api_v2/__init__.py +0 -0
  257. {memmachine_server-0.3.2 → memmachine_server-0.3.3}/src/memmachine_server/server/api_v2/config_router.py +0 -0
  258. {memmachine_server-0.3.2 → memmachine_server-0.3.3}/src/memmachine_server/server/api_v2/config_service.py +0 -0
  259. {memmachine_server-0.3.2 → memmachine_server-0.3.3}/src/memmachine_server/server/api_v2/exceptions.py +0 -0
  260. {memmachine_server-0.3.2 → memmachine_server-0.3.3}/src/memmachine_server/server/api_v2/mcp.py +0 -0
  261. {memmachine_server-0.3.2 → memmachine_server-0.3.3}/src/memmachine_server/server/api_v2/router.py +0 -0
  262. {memmachine_server-0.3.2 → memmachine_server-0.3.3}/src/memmachine_server/server/api_v2/service.py +0 -0
  263. {memmachine_server-0.3.2 → memmachine_server-0.3.3}/src/memmachine_server/server/app.py +0 -0
  264. {memmachine_server-0.3.2 → memmachine_server-0.3.3}/src/memmachine_server/server/diagnostics.py +0 -0
  265. {memmachine_server-0.3.2 → memmachine_server-0.3.3}/src/memmachine_server/server/mcp_http.py +0 -0
  266. {memmachine_server-0.3.2 → memmachine_server-0.3.3}/src/memmachine_server/server/mcp_stdio.py +0 -0
  267. {memmachine_server-0.3.2 → memmachine_server-0.3.3}/src/memmachine_server/server/middleware.py +0 -0
  268. {memmachine_server-0.3.2 → memmachine_server-0.3.3}/src/memmachine_server/server/prompt/__init__.py +0 -0
  269. {memmachine_server-0.3.2 → memmachine_server-0.3.3}/src/memmachine_server/server/prompt/coding_style_prompt.py +0 -0
  270. {memmachine_server-0.3.2 → memmachine_server-0.3.3}/src/memmachine_server/server/prompt/crm_prompt.py +0 -0
  271. {memmachine_server-0.3.2 → memmachine_server-0.3.3}/src/memmachine_server/server/prompt/default_prompts.py +0 -0
  272. {memmachine_server-0.3.2 → memmachine_server-0.3.3}/src/memmachine_server/server/prompt/financial_analyst_prompt.py +0 -0
  273. {memmachine_server-0.3.2 → memmachine_server-0.3.3}/src/memmachine_server/server/prompt/health_assistant_prompt.py +0 -0
  274. {memmachine_server-0.3.2 → memmachine_server-0.3.3}/src/memmachine_server/server/prompt/profile_prompt.py +0 -0
  275. {memmachine_server-0.3.2 → memmachine_server-0.3.3}/src/memmachine_server/server/prompt/prompt_utilities.py +0 -0
  276. {memmachine_server-0.3.2 → memmachine_server-0.3.3}/src/memmachine_server/server/prompt/writing_assistant_prompt.py +0 -0
  277. {memmachine_server-0.3.2 → memmachine_server-0.3.3}/src/memmachine_server.egg-info/dependency_links.txt +0 -0
  278. {memmachine_server-0.3.2 → memmachine_server-0.3.3}/src/memmachine_server.egg-info/entry_points.txt +0 -0
  279. {memmachine_server-0.3.2 → memmachine_server-0.3.3}/src/memmachine_server.egg-info/requires.txt +0 -0
  280. {memmachine_server-0.3.2 → memmachine_server-0.3.3}/src/memmachine_server.egg-info/top_level.txt +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: memmachine-server
3
- Version: 0.3.2
3
+ Version: 0.3.3
4
4
  Summary: MemMachine Server - The complete MemMachine memory system server with episodic and profile memory
5
5
  Author-email: MemMachine <noreply@memmachine.ai>
6
6
  License-Expression: Apache-2.0
@@ -0,0 +1,126 @@
1
+ from unittest.mock import AsyncMock, MagicMock, patch
2
+
3
+ import openai
4
+ import pytest
5
+
6
+ from memmachine_server.common.data_types import ExternalServiceAPIError
7
+ from memmachine_server.common.embedder.openai_embedder import (
8
+ OpenAIEmbedder,
9
+ OpenAIEmbedderParams,
10
+ )
11
+
12
+
13
+ @pytest.fixture(
14
+ params=[
15
+ ["Are tomatoes fruits?", "Tomatoes are red."],
16
+ ["Are tomatoes fruits?", "Tomatoes are red.", ""],
17
+ ["."],
18
+ [" "],
19
+ [""],
20
+ [],
21
+ ],
22
+ )
23
+ def inputs(request):
24
+ return request.param
25
+
26
+
27
+ @pytest.mark.integration
28
+ @pytest.mark.asyncio
29
+ async def test_ingest_embed(openai_embedder, inputs):
30
+ embeddings = await openai_embedder.ingest_embed(inputs)
31
+ assert isinstance(embeddings, list)
32
+ assert len(embeddings) == len(inputs)
33
+ assert all(len(embedding) == openai_embedder.dimensions for embedding in embeddings)
34
+
35
+
36
+ @pytest.mark.integration
37
+ @pytest.mark.asyncio
38
+ async def test_search_embed(openai_embedder, inputs):
39
+ embeddings = await openai_embedder.search_embed(inputs)
40
+ assert isinstance(embeddings, list)
41
+ assert len(embeddings) == len(inputs)
42
+ assert all(len(embedding) == openai_embedder.dimensions for embedding in embeddings)
43
+
44
+
45
+ @pytest.mark.integration
46
+ @pytest.mark.asyncio
47
+ async def test_large_input(openai_embedder):
48
+ input_text = "👩‍💻" * 10000
49
+
50
+ assert len(await openai_embedder.ingest_embed([input_text])) == 1
51
+ assert len(await openai_embedder.search_embed([input_text])) == 1
52
+
53
+
54
+ @pytest.mark.integration
55
+ @pytest.mark.asyncio
56
+ async def test_many_inputs(openai_embedder):
57
+ input_texts = ["Hello, world!"] * 10000
58
+ assert len(await openai_embedder.ingest_embed(input_texts)) == 10000
59
+ assert len(await openai_embedder.search_embed(input_texts)) == 10000
60
+
61
+
62
+ @pytest.mark.asyncio
63
+ @patch("asyncio.sleep", new_callable=AsyncMock)
64
+ async def test_embed_retry_on_internal_server_error(mock_sleep):
65
+ """Test retry logic on InternalServerError."""
66
+ mock_client = AsyncMock(spec=openai.AsyncOpenAI)
67
+
68
+ mock_embedding = MagicMock()
69
+ mock_embedding.embedding = [0.1] * 256
70
+
71
+ mock_response = MagicMock()
72
+ mock_response.data = [mock_embedding]
73
+ mock_response.usage.prompt_tokens = 10
74
+ mock_response.usage.total_tokens = 10
75
+
76
+ mock_client.embeddings.create = AsyncMock(
77
+ side_effect=[
78
+ openai.InternalServerError(
79
+ "internal server error", response=MagicMock(), body=None
80
+ ),
81
+ mock_response,
82
+ ]
83
+ )
84
+
85
+ embedder = OpenAIEmbedder(
86
+ OpenAIEmbedderParams(
87
+ client=mock_client,
88
+ model="test-model",
89
+ dimensions=256,
90
+ )
91
+ )
92
+
93
+ result = await embedder.ingest_embed(["test input"], max_attempts=2)
94
+
95
+ assert len(result) == 1
96
+ assert len(result[0]) == 256
97
+ assert mock_client.embeddings.create.call_count == 2
98
+ mock_sleep.assert_awaited_once_with(1)
99
+
100
+
101
+ @pytest.mark.asyncio
102
+ @patch("asyncio.sleep", new_callable=AsyncMock)
103
+ async def test_embed_fail_after_max_retries_on_internal_server_error(mock_sleep):
104
+ """Test that ExternalServiceAPIError is raised after max_attempts on InternalServerError."""
105
+ mock_client = AsyncMock(spec=openai.AsyncOpenAI)
106
+ mock_client.embeddings.create = AsyncMock(
107
+ side_effect=openai.InternalServerError(
108
+ "internal server error", response=MagicMock(), body=None
109
+ ),
110
+ )
111
+
112
+ embedder = OpenAIEmbedder(
113
+ OpenAIEmbedderParams(
114
+ client=mock_client,
115
+ model="test-model",
116
+ dimensions=256,
117
+ )
118
+ )
119
+
120
+ with pytest.raises(ExternalServiceAPIError, match=r"max attempts"):
121
+ await embedder.ingest_embed(["test input"], max_attempts=3)
122
+
123
+ assert mock_client.embeddings.create.call_count == 3
124
+ assert mock_sleep.call_count == 2
125
+ mock_sleep.assert_any_await(1)
126
+ mock_sleep.assert_any_await(2)
@@ -397,6 +397,35 @@ async def test_generate_response_fail_after_max_retries(
397
397
  mock_sleep.assert_any_await(2)
398
398
 
399
399
 
400
+ @pytest.mark.asyncio
401
+ @patch("asyncio.sleep", new_callable=AsyncMock)
402
+ async def test_generate_response_retry_on_internal_server_error(
403
+ mock_sleep,
404
+ mock_async_openai,
405
+ minimal_config,
406
+ ):
407
+ """Test retry logic on InternalServerError."""
408
+ mock_response = MagicMock()
409
+ mock_response.choices[0].message.content = "Success after retry"
410
+ mock_response.choices[0].message.tool_calls = None
411
+ mock_response.usage = None
412
+
413
+ mock_client = mock_async_openai.return_value
414
+ mock_client.chat.completions.create.side_effect = [
415
+ openai.InternalServerError(
416
+ "internal server error", response=MagicMock(), body=None
417
+ ),
418
+ mock_response,
419
+ ]
420
+
421
+ lm = OpenAIChatCompletionsLanguageModel(minimal_config)
422
+ content, _ = await lm.generate_response(max_attempts=2)
423
+
424
+ assert content == "Success after retry"
425
+ assert mock_client.chat.completions.create.call_count == 2
426
+ mock_sleep.assert_awaited_once_with(1)
427
+
428
+
400
429
  @pytest.mark.asyncio
401
430
  @pytest.mark.parametrize(
402
431
  "exception",
@@ -353,6 +353,35 @@ async def test_generate_response_fail_after_max_retries(
353
353
  mock_sleep.assert_any_await(2)
354
354
 
355
355
 
356
+ @pytest.mark.asyncio
357
+ @patch("asyncio.sleep", new_callable=AsyncMock)
358
+ async def test_generate_response_retry_on_internal_server_error(
359
+ mock_sleep,
360
+ mock_async_openai,
361
+ minimal_config,
362
+ ):
363
+ """Test retry logic on InternalServerError."""
364
+ mock_response = MagicMock()
365
+ mock_response.output_text = "Success after retry"
366
+ mock_response.output = None
367
+ mock_response.usage = None
368
+
369
+ mock_client = mock_async_openai.return_value
370
+ mock_client.responses.create.side_effect = [
371
+ openai.InternalServerError(
372
+ "internal server error", response=MagicMock(), body=None
373
+ ),
374
+ mock_response,
375
+ ]
376
+
377
+ lm = OpenAIResponsesLanguageModel(minimal_config)
378
+ content, _ = await lm.generate_response(max_attempts=2)
379
+
380
+ assert content == "Success after retry"
381
+ assert mock_client.responses.create.call_count == 2
382
+ mock_sleep.assert_awaited_once_with(1)
383
+
384
+
356
385
  @pytest.mark.asyncio
357
386
  @pytest.mark.asyncio
358
387
  @pytest.mark.parametrize(
@@ -347,6 +347,78 @@ class TestSessionMemoryPublicAPI:
347
347
  # context window limit causes recursive splitting into 4 LLM calls
348
348
  assert mock_model.call_count == 4
349
349
 
350
+ @pytest.mark.asyncio
351
+ async def test_summary_exceed_context_window_single_episode(
352
+ self, mock_data_manager
353
+ ):
354
+ class ChunkingLanguageModel(LanguageModel):
355
+ def __init__(self) -> None:
356
+ self.call_count = 0
357
+
358
+ async def generate_response(
359
+ self,
360
+ system_prompt: str | None = None,
361
+ user_prompt: str | None = None,
362
+ tools: list[dict[str, Any]] | None = None,
363
+ tool_choice: str | dict[str, str] | None = None,
364
+ max_attempts: int = 1,
365
+ ) -> tuple[str, Any]:
366
+ prompt = user_prompt or ""
367
+ if len(prompt) > 10000:
368
+ raise ValueError("User prompt exceeds context window")
369
+ self.call_count += 1
370
+ match = re.search(r"summary:(\d+)(?: \d+)?$", prompt)
371
+ prev_summary = int(match.group(1)) if match else 0
372
+ messages = re.findall(r'"([^"]*)"', prompt)
373
+ return (
374
+ f"summary:{prev_summary + sum(len(message) for message in messages)}",
375
+ "",
376
+ )
377
+
378
+ async def generate_response_with_token_usage(
379
+ self,
380
+ system_prompt: str | None = None,
381
+ user_prompt: str | None = None,
382
+ tools: list[dict[str, Any]] | None = None,
383
+ tool_choice: str | dict[str, str] | None = None,
384
+ max_attempts: int = 1,
385
+ ) -> tuple[str, Any, int, int]:
386
+ response, tool_output = await self.generate_response(
387
+ system_prompt=system_prompt,
388
+ user_prompt=user_prompt,
389
+ tools=tools,
390
+ tool_choice=tool_choice,
391
+ max_attempts=max_attempts,
392
+ )
393
+ return response, tool_output, 0, 0
394
+
395
+ async def generate_parsed_response(
396
+ self,
397
+ output_format: type[T],
398
+ system_prompt: str | None = None,
399
+ user_prompt: str | None = None,
400
+ max_attempts: int = 1,
401
+ ) -> T:
402
+ return cast(T, "summary")
403
+
404
+ model = ChunkingLanguageModel()
405
+ params = ShortTermMemoryConsolidator.Params(
406
+ summary_user_prompt="User prompt: {episodes} {summary} {max_length}",
407
+ summary_system_prompt="System Prompt",
408
+ max_summary_length_words=100,
409
+ session_key="test_session",
410
+ model=model,
411
+ data_manager=mock_data_manager,
412
+ )
413
+ consolidator = ShortTermMemoryConsolidator(params)
414
+
415
+ oversized_content = "a" * 12000
416
+ episode = create_test_episode(content=oversized_content)
417
+ summary = await consolidator._create_summary("", [episode])
418
+
419
+ assert summary == "summary:12000"
420
+ assert model.call_count > 1
421
+
350
422
  @pytest.mark.asyncio
351
423
  async def test_summary_catch_up(self, mock_model, mock_data_manager):
352
424
  params = ShortTermMemoryConsolidator.Params(
@@ -182,6 +182,9 @@ class MockSemanticStorage(SemanticStorage):
182
182
  ) -> list[SetIdT]:
183
183
  raise NotImplementedError
184
184
 
185
+ async def purge_ingested_rows(self, set_ids: list[SetIdT]) -> int:
186
+ raise NotImplementedError
187
+
185
188
  async def get_set_ids_starts_with(self, prefix: str) -> list[SetIdT]:
186
189
  raise NotImplementedError
187
190
 
@@ -339,6 +339,34 @@ class InMemorySemanticStorage(SemanticStorage):
339
339
 
340
340
  return set_ids
341
341
 
342
+ async def purge_ingested_rows(self, set_ids: list[SetIdT]) -> int:
343
+ if not set_ids:
344
+ return 0
345
+ deleted = 0
346
+ async with self._lock:
347
+ for set_id in set_ids:
348
+ history_map = self._set_history_map.get(set_id)
349
+ if history_map is None:
350
+ continue
351
+ # Skip sets that still have pending (uningested) messages
352
+ # to preserve the duplicate guard for in-flight work.
353
+ has_pending = any(not v for v in history_map.values())
354
+ if has_pending:
355
+ continue
356
+ ingested_ids = list(history_map.keys())
357
+ for h_id in ingested_ids:
358
+ del history_map[h_id]
359
+ self._history_created_at.pop((set_id, h_id), None)
360
+ h_sets = self._history_to_sets.get(h_id)
361
+ if h_sets is not None:
362
+ h_sets.pop(set_id, None)
363
+ if not h_sets:
364
+ self._history_to_sets.pop(h_id, None)
365
+ deleted += 1
366
+ if not history_map:
367
+ self._set_history_map.pop(set_id, None)
368
+ return deleted
369
+
342
370
  async def get_set_ids_starts_with(self, prefix: str) -> list[SetIdT]:
343
371
  async with self._lock:
344
372
  set_ids = {
@@ -1097,6 +1097,98 @@ async def test_get_set_ids_with_older_than_and_min_uningested(
1097
1097
  assert set_ids == ["busy_user"]
1098
1098
 
1099
1099
 
1100
+ @pytest.mark.asyncio
1101
+ async def test_purge_ingested_rows_fully_ingested(
1102
+ semantic_storage: SemanticStorage,
1103
+ episode_storage,
1104
+ ):
1105
+ """Purge deletes all rows for a set_id when every message is ingested."""
1106
+ history_ids = [
1107
+ await _add_episode(episode_storage, content=f"purge-msg-{idx}")
1108
+ for idx in range(3)
1109
+ ]
1110
+
1111
+ for h_id in history_ids:
1112
+ await semantic_storage.add_history_to_set(set_id="purge_user", history_id=h_id)
1113
+
1114
+ # Mark all 3 as ingested
1115
+ await semantic_storage.mark_messages_ingested(
1116
+ set_id="purge_user",
1117
+ history_ids=history_ids,
1118
+ )
1119
+
1120
+ deleted = await semantic_storage.purge_ingested_rows(["purge_user"])
1121
+ assert deleted == 3
1122
+
1123
+ total = await semantic_storage.get_history_messages_count(
1124
+ set_ids=["purge_user"],
1125
+ )
1126
+ assert total == 0
1127
+
1128
+
1129
+ @pytest.mark.asyncio
1130
+ async def test_purge_ingested_rows_skips_partially_ingested(
1131
+ semantic_storage: SemanticStorage,
1132
+ episode_storage,
1133
+ ):
1134
+ """Purge preserves rows when a set still has uningested messages,
1135
+ keeping the (set_id, history_id) duplicate guard intact."""
1136
+ history_ids = [
1137
+ await _add_episode(episode_storage, content=f"partial-msg-{idx}")
1138
+ for idx in range(3)
1139
+ ]
1140
+
1141
+ for h_id in history_ids:
1142
+ await semantic_storage.add_history_to_set(
1143
+ set_id="partial_user", history_id=h_id
1144
+ )
1145
+
1146
+ # Mark 2 of 3 as ingested — 1 still pending
1147
+ await semantic_storage.mark_messages_ingested(
1148
+ set_id="partial_user",
1149
+ history_ids=history_ids[:2],
1150
+ )
1151
+
1152
+ # Purge should skip this set entirely
1153
+ deleted = await semantic_storage.purge_ingested_rows(["partial_user"])
1154
+ assert deleted == 0
1155
+
1156
+ # All 3 rows should remain
1157
+ total = await semantic_storage.get_history_messages_count(
1158
+ set_ids=["partial_user"],
1159
+ )
1160
+ assert total == 3
1161
+
1162
+
1163
+ @pytest.mark.asyncio
1164
+ async def test_purge_ingested_rows_empty_list(
1165
+ semantic_storage: SemanticStorage,
1166
+ episode_storage,
1167
+ ):
1168
+ history_ids = [
1169
+ await _add_episode(episode_storage, content=f"keep-msg-{idx}")
1170
+ for idx in range(2)
1171
+ ]
1172
+
1173
+ for h_id in history_ids:
1174
+ await semantic_storage.add_history_to_set(set_id="keep_user", history_id=h_id)
1175
+
1176
+ await semantic_storage.mark_messages_ingested(
1177
+ set_id="keep_user",
1178
+ history_ids=history_ids[:1],
1179
+ )
1180
+
1181
+ # Purge with empty list should be a no-op
1182
+ deleted = await semantic_storage.purge_ingested_rows([])
1183
+ assert deleted == 0
1184
+
1185
+ # Data should be unchanged
1186
+ total = await semantic_storage.get_history_messages_count(
1187
+ set_ids=["keep_user"],
1188
+ )
1189
+ assert total == 2
1190
+
1191
+
1100
1192
  @pytest.mark.asyncio
1101
1193
  async def test_filter_features_by_created_at_date(
1102
1194
  semantic_storage: SemanticStorage,
@@ -1257,6 +1349,24 @@ async def test_filter_features_by_created_at_range(
1257
1349
  assert results[0].value == "note2"
1258
1350
 
1259
1351
 
1352
+ @pytest.mark.asyncio
1353
+ async def test_add_feature_with_null_bytes_does_not_crash(
1354
+ semantic_storage: SemanticStorage,
1355
+ ):
1356
+ """Regression test for issue #1147: null bytes in feature values must not crash."""
1357
+ feature_id = await semantic_storage.add_feature(
1358
+ set_id="user1",
1359
+ category_name="profile",
1360
+ feature="cultural\x00focus",
1361
+ value="D\x00a de Los Muertos",
1362
+ tag="Ins\x00ights",
1363
+ embedding=np.array([1.0] * 1536, dtype=float),
1364
+ )
1365
+
1366
+ stored = await semantic_storage.get_feature(feature_id)
1367
+ assert stored is not None
1368
+
1369
+
1260
1370
  @pytest.mark.asyncio
1261
1371
  async def test_filter_equality(semantic_storage: SemanticStorage):
1262
1372
  feature_ids: list[FeatureIdT] = [
@@ -0,0 +1,48 @@
1
+ """Tests for the PostgreSQL text sanitizer utility."""
2
+
3
+ import logging
4
+
5
+ from memmachine_server.semantic_memory.storage.text_sanitizer import sanitize_pg_text
6
+
7
+
8
+ class TestSanitizePgText:
9
+ """Tests for sanitize_pg_text."""
10
+
11
+ def test_clean_string_passes_through(self):
12
+ assert sanitize_pg_text("hello world") == "hello world"
13
+
14
+ def test_empty_string_passes_through(self):
15
+ assert sanitize_pg_text("") == ""
16
+
17
+ def test_unicode_string_passes_through(self):
18
+ value = "Día de Los Muertos"
19
+ assert sanitize_pg_text(value) == value
20
+
21
+ def test_strips_single_null_byte(self):
22
+ assert sanitize_pg_text("D\x00a de Los Muertos") == "Da de Los Muertos"
23
+
24
+ def test_strips_multiple_null_bytes(self):
25
+ assert sanitize_pg_text("a\x00b\x00c") == "abc"
26
+
27
+ def test_strips_leading_null_byte(self):
28
+ assert sanitize_pg_text("\x00hello") == "hello"
29
+
30
+ def test_strips_trailing_null_byte(self):
31
+ assert sanitize_pg_text("hello\x00") == "hello"
32
+
33
+ def test_string_of_only_null_bytes(self):
34
+ assert sanitize_pg_text("\x00\x00\x00") == ""
35
+
36
+ def test_logs_warning_when_stripping(self, caplog):
37
+ with caplog.at_level(logging.WARNING):
38
+ sanitize_pg_text("D\x00a de Los Muertos", context="feature.value")
39
+
40
+ assert len(caplog.records) == 1
41
+ assert "null byte" in caplog.records[0].message.lower()
42
+ assert "feature.value" in caplog.records[0].message
43
+
44
+ def test_no_log_for_clean_string(self, caplog):
45
+ with caplog.at_level(logging.WARNING):
46
+ sanitize_pg_text("clean string")
47
+
48
+ assert len(caplog.records) == 0
@@ -7,6 +7,7 @@ import numpy as np
7
7
  import pytest
8
8
  import pytest_asyncio
9
9
 
10
+ from memmachine_server.common.data_types import ExternalServiceAPIError
10
11
  from memmachine_server.common.episode_store import (
11
12
  EpisodeEntry,
12
13
  EpisodeIdT,
@@ -212,6 +213,49 @@ async def test_process_single_set_applies_commands(
212
213
  assert embedder_double.ingest_calls == [["blue"]]
213
214
 
214
215
 
216
+ @pytest.mark.asyncio
217
+ async def test_process_single_set_marks_context_length_errors_as_ingested(
218
+ ingestion_service: IngestionService,
219
+ semantic_storage: SemanticStorage,
220
+ episode_storage: EpisodeStorage,
221
+ monkeypatch,
222
+ ):
223
+ class ContextLengthExceededError(Exception):
224
+ code = "context_length_exceeded"
225
+
226
+ message_id = await add_history(
227
+ episode_storage,
228
+ content="very long message that exceeds model context",
229
+ )
230
+ await semantic_storage.add_history_to_set(
231
+ set_id="user-context-overflow",
232
+ history_id=message_id,
233
+ )
234
+
235
+ async def mock_context_length_error(*args, **kwargs):
236
+ err = ContextLengthExceededError("input exceeds context window")
237
+ raise ExternalServiceAPIError("LLM request failed") from err
238
+
239
+ monkeypatch.setattr(
240
+ "memmachine_server.semantic_memory.semantic_ingestion.llm_feature_update",
241
+ mock_context_length_error,
242
+ )
243
+
244
+ await ingestion_service._process_single_set("user-context-overflow")
245
+
246
+ assert (
247
+ await semantic_storage.get_history_messages(
248
+ set_ids=["user-context-overflow"],
249
+ is_ingested=False,
250
+ )
251
+ == []
252
+ )
253
+ assert await semantic_storage.get_history_messages(
254
+ set_ids=["user-context-overflow"],
255
+ is_ingested=True,
256
+ ) == [message_id]
257
+
258
+
215
259
  @pytest.mark.asyncio
216
260
  async def test_consolidation_groups_by_tag(
217
261
  ingestion_service: IngestionService,
@@ -543,6 +587,59 @@ async def test_process_single_set_raises_in_debug_mode_for_invalid_ids(
543
587
  await ingestion_service._process_single_set("user-888")
544
588
 
545
589
 
590
+ @pytest.mark.asyncio
591
+ async def test_process_single_set_limits_features_sent_to_llm(
592
+ semantic_storage: SemanticStorage,
593
+ episode_storage: EpisodeStorage,
594
+ resource_retriever: MockResourceRetriever,
595
+ semantic_category: SemanticCategory,
596
+ monkeypatch,
597
+ ):
598
+ """The feature lookup for each message must pass a page_size cap so that a
599
+ very large profile does not cause the LLM response to overflow its token budget."""
600
+ message_id = await add_history(episode_storage, content="I love sushi")
601
+ await semantic_storage.add_history_to_set(set_id="user-222", history_id=message_id)
602
+
603
+ # Seed more features than the expected cap
604
+ for i in range(60):
605
+ await semantic_storage.add_feature(
606
+ set_id="user-222",
607
+ category_name=semantic_category.name,
608
+ feature=f"feature_{i}",
609
+ value=f"value_{i}",
610
+ tag="misc",
611
+ embedding=np.array([float(i), float(-i)]),
612
+ )
613
+
614
+ llm_mock = AsyncMock(return_value=[])
615
+ monkeypatch.setattr(
616
+ "memmachine_server.semantic_memory.semantic_ingestion.llm_feature_update",
617
+ llm_mock,
618
+ )
619
+
620
+ ingestion_service = IngestionService(
621
+ IngestionService.Params(
622
+ semantic_storage=semantic_storage,
623
+ history_store=episode_storage,
624
+ resource_retriever=resource_retriever.get_resources,
625
+ consolidated_threshold=100,
626
+ debug_fail_loudly=False,
627
+ )
628
+ )
629
+
630
+ await ingestion_service._process_single_set("user-222")
631
+
632
+ # get_feature_set must have been called with a non-None page_size
633
+ # to prevent sending all 60 features to the LLM at once.
634
+ llm_mock.assert_awaited_once()
635
+ assert llm_mock.await_args is not None
636
+ passed_features: list[SemanticFeature] = llm_mock.await_args.kwargs["features"]
637
+ assert len(passed_features) < 60, (
638
+ "Expected feature set to be capped before calling the LLM, "
639
+ f"but {len(passed_features)} features were passed"
640
+ )
641
+
642
+
546
643
  @pytest.mark.asyncio
547
644
  async def test_consolidation_deletes_features_not_in_keep_list(
548
645
  ingestion_service: IngestionService,