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.
- {memmachine_server-0.3.2/src/memmachine_server.egg-info → memmachine_server-0.3.3}/PKG-INFO +1 -1
- memmachine_server-0.3.3/server_tests/memmachine_server/common/embedder/test_openai_embedder.py +126 -0
- {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
- {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
- {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
- {memmachine_server-0.3.2 → memmachine_server-0.3.3}/server_tests/memmachine_server/semantic_memory/mock_semantic_memory_objects.py +3 -0
- {memmachine_server-0.3.2 → memmachine_server-0.3.3}/server_tests/memmachine_server/semantic_memory/storage/in_memory_semantic_storage.py +28 -0
- {memmachine_server-0.3.2 → memmachine_server-0.3.3}/server_tests/memmachine_server/semantic_memory/storage/test_semantic_storage.py +110 -0
- memmachine_server-0.3.3/server_tests/memmachine_server/semantic_memory/storage/test_text_sanitizer.py +48 -0
- {memmachine_server-0.3.2 → memmachine_server-0.3.3}/server_tests/memmachine_server/semantic_memory/test_semantic_ingestion.py +97 -0
- {memmachine_server-0.3.2 → memmachine_server-0.3.3}/server_tests/memmachine_server/semantic_memory/test_semantic_model.py +93 -0
- {memmachine_server-0.3.2 → memmachine_server-0.3.3}/src/memmachine_server/common/configuration/__init__.py +9 -0
- {memmachine_server-0.3.2 → memmachine_server-0.3.3}/src/memmachine_server/common/configuration/mixin_confs.py +16 -7
- {memmachine_server-0.3.2 → memmachine_server-0.3.3}/src/memmachine_server/common/embedder/openai_embedder.py +1 -0
- {memmachine_server-0.3.2 → memmachine_server-0.3.3}/src/memmachine_server/common/language_model/openai_chat_completions_language_model.py +1 -0
- {memmachine_server-0.3.2 → memmachine_server-0.3.3}/src/memmachine_server/common/language_model/openai_responses_language_model.py +1 -0
- {memmachine_server-0.3.2 → memmachine_server-0.3.3}/src/memmachine_server/common/resource_manager/semantic_manager.py +1 -0
- {memmachine_server-0.3.2 → memmachine_server-0.3.3}/src/memmachine_server/episodic_memory/short_term_memory/short_term_memory.py +44 -20
- {memmachine_server-0.3.2 → memmachine_server-0.3.3}/src/memmachine_server/semantic_memory/semantic_ingestion.py +44 -2
- {memmachine_server-0.3.2 → memmachine_server-0.3.3}/src/memmachine_server/semantic_memory/semantic_llm.py +8 -0
- {memmachine_server-0.3.2 → memmachine_server-0.3.3}/src/memmachine_server/semantic_memory/semantic_memory.py +40 -2
- {memmachine_server-0.3.2 → memmachine_server-0.3.3}/src/memmachine_server/semantic_memory/semantic_model.py +8 -1
- memmachine_server-0.3.3/src/memmachine_server/semantic_memory/storage/alembic_pg/versions/c7a2f8e31b90_add_ingested_composite_index.py +36 -0
- {memmachine_server-0.3.2 → memmachine_server-0.3.3}/src/memmachine_server/semantic_memory/storage/neo4j_semantic_storage.py +24 -0
- {memmachine_server-0.3.2 → memmachine_server-0.3.3}/src/memmachine_server/semantic_memory/storage/sqlalchemy_pgvector_semantic.py +61 -31
- {memmachine_server-0.3.2 → memmachine_server-0.3.3}/src/memmachine_server/semantic_memory/storage/storage_base.py +11 -0
- memmachine_server-0.3.3/src/memmachine_server/semantic_memory/storage/text_sanitizer.py +22 -0
- {memmachine_server-0.3.2 → memmachine_server-0.3.3/src/memmachine_server.egg-info}/PKG-INFO +1 -1
- {memmachine_server-0.3.2 → memmachine_server-0.3.3}/src/memmachine_server.egg-info/SOURCES.txt +3 -0
- memmachine_server-0.3.2/server_tests/memmachine_server/common/embedder/test_openai_embedder.py +0 -48
- {memmachine_server-0.3.2 → memmachine_server-0.3.3}/LICENSE +0 -0
- {memmachine_server-0.3.2 → memmachine_server-0.3.3}/README.md +0 -0
- {memmachine_server-0.3.2 → memmachine_server-0.3.3}/pyproject.toml +0 -0
- {memmachine_server-0.3.2 → memmachine_server-0.3.3}/server_tests/__init__.py +0 -0
- {memmachine_server-0.3.2 → memmachine_server-0.3.3}/server_tests/memmachine_server/__init__.py +0 -0
- {memmachine_server-0.3.2 → memmachine_server-0.3.3}/server_tests/memmachine_server/common/__init__.py +0 -0
- {memmachine_server-0.3.2 → memmachine_server-0.3.3}/server_tests/memmachine_server/common/api/__init__.py +0 -0
- {memmachine_server-0.3.2 → memmachine_server-0.3.3}/server_tests/memmachine_server/common/api/test_version.py +0 -0
- {memmachine_server-0.3.2 → memmachine_server-0.3.3}/server_tests/memmachine_server/common/configuration/__init__.py +0 -0
- {memmachine_server-0.3.2 → memmachine_server-0.3.3}/server_tests/memmachine_server/common/configuration/test_configuration.py +0 -0
- {memmachine_server-0.3.2 → memmachine_server-0.3.3}/server_tests/memmachine_server/common/configuration/test_database_conf.py +0 -0
- {memmachine_server-0.3.2 → memmachine_server-0.3.3}/server_tests/memmachine_server/common/configuration/test_embedder_conf.py +0 -0
- {memmachine_server-0.3.2 → memmachine_server-0.3.3}/server_tests/memmachine_server/common/configuration/test_episodic_config.py +0 -0
- {memmachine_server-0.3.2 → memmachine_server-0.3.3}/server_tests/memmachine_server/common/configuration/test_language_model_conf.py +0 -0
- {memmachine_server-0.3.2 → memmachine_server-0.3.3}/server_tests/memmachine_server/common/configuration/test_log_conf.py +0 -0
- {memmachine_server-0.3.2 → memmachine_server-0.3.3}/server_tests/memmachine_server/common/configuration/test_mixin_confs.py +0 -0
- {memmachine_server-0.3.2 → memmachine_server-0.3.3}/server_tests/memmachine_server/common/configuration/test_prompt_conf.py +0 -0
- {memmachine_server-0.3.2 → memmachine_server-0.3.3}/server_tests/memmachine_server/common/configuration/test_reranker_conf.py +0 -0
- {memmachine_server-0.3.2 → memmachine_server-0.3.3}/server_tests/memmachine_server/common/configuration/test_semantic_conf.py +0 -0
- {memmachine_server-0.3.2 → memmachine_server-0.3.3}/server_tests/memmachine_server/common/configuration/test_server_conf.py +0 -0
- {memmachine_server-0.3.2 → memmachine_server-0.3.3}/server_tests/memmachine_server/common/embedder/__init__.py +0 -0
- {memmachine_server-0.3.2 → memmachine_server-0.3.3}/server_tests/memmachine_server/common/embedder/test_amazon_bedrock_embedder.py +0 -0
- {memmachine_server-0.3.2 → memmachine_server-0.3.3}/server_tests/memmachine_server/common/embedder/test_sentence_transformer_embedder.py +0 -0
- {memmachine_server-0.3.2 → memmachine_server-0.3.3}/server_tests/memmachine_server/common/episode_store/__init__.py +0 -0
- {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
- {memmachine_server-0.3.2 → memmachine_server-0.3.3}/server_tests/memmachine_server/common/episode_store/test_episode_model.py +0 -0
- {memmachine_server-0.3.2 → memmachine_server-0.3.3}/server_tests/memmachine_server/common/episode_store/test_episode_storage.py +0 -0
- {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
- {memmachine_server-0.3.2 → memmachine_server-0.3.3}/server_tests/memmachine_server/common/filter/__init__.py +0 -0
- {memmachine_server-0.3.2 → memmachine_server-0.3.3}/server_tests/memmachine_server/common/filter/test_filter_parser.py +0 -0
- {memmachine_server-0.3.2 → memmachine_server-0.3.3}/server_tests/memmachine_server/common/filter/test_sql_filter_util.py +0 -0
- {memmachine_server-0.3.2 → memmachine_server-0.3.3}/server_tests/memmachine_server/common/language_model/__init__.py +0 -0
- {memmachine_server-0.3.2 → memmachine_server-0.3.3}/server_tests/memmachine_server/common/reranker/__init__.py +0 -0
- {memmachine_server-0.3.2 → memmachine_server-0.3.3}/server_tests/memmachine_server/common/reranker/fake_embedder.py +0 -0
- {memmachine_server-0.3.2 → memmachine_server-0.3.3}/server_tests/memmachine_server/common/reranker/test_amazon_bedrock_reranker.py +0 -0
- {memmachine_server-0.3.2 → memmachine_server-0.3.3}/server_tests/memmachine_server/common/reranker/test_bm25_reranker.py +0 -0
- {memmachine_server-0.3.2 → memmachine_server-0.3.3}/server_tests/memmachine_server/common/reranker/test_cohere_reranker.py +0 -0
- {memmachine_server-0.3.2 → memmachine_server-0.3.3}/server_tests/memmachine_server/common/reranker/test_cross_encoder_reranker.py +0 -0
- {memmachine_server-0.3.2 → memmachine_server-0.3.3}/server_tests/memmachine_server/common/reranker/test_embedder_reranker.py +0 -0
- {memmachine_server-0.3.2 → memmachine_server-0.3.3}/server_tests/memmachine_server/common/reranker/test_identity_reranker.py +0 -0
- {memmachine_server-0.3.2 → memmachine_server-0.3.3}/server_tests/memmachine_server/common/reranker/test_rrf_hybrid_reranker.py +0 -0
- {memmachine_server-0.3.2 → memmachine_server-0.3.3}/server_tests/memmachine_server/common/resource_manager/__init__.py +0 -0
- {memmachine_server-0.3.2 → memmachine_server-0.3.3}/server_tests/memmachine_server/common/resource_manager/test_database_manager.py +0 -0
- {memmachine_server-0.3.2 → memmachine_server-0.3.3}/server_tests/memmachine_server/common/resource_manager/test_embedder_manager.py +0 -0
- {memmachine_server-0.3.2 → memmachine_server-0.3.3}/server_tests/memmachine_server/common/resource_manager/test_language_model_manager.py +0 -0
- {memmachine_server-0.3.2 → memmachine_server-0.3.3}/server_tests/memmachine_server/common/resource_manager/test_reranker_manager.py +0 -0
- {memmachine_server-0.3.2 → memmachine_server-0.3.3}/server_tests/memmachine_server/common/resource_manager/test_resource_manager.py +0 -0
- {memmachine_server-0.3.2 → memmachine_server-0.3.3}/server_tests/memmachine_server/common/session_manager/__init__.py +0 -0
- {memmachine_server-0.3.2 → memmachine_server-0.3.3}/server_tests/memmachine_server/common/session_manager/test_session_manager.py +0 -0
- {memmachine_server-0.3.2 → memmachine_server-0.3.3}/server_tests/memmachine_server/common/session_manager/test_session_manager_migration.py +0 -0
- {memmachine_server-0.3.2 → memmachine_server-0.3.3}/server_tests/memmachine_server/common/test_rw_locks.py +0 -0
- {memmachine_server-0.3.2 → memmachine_server-0.3.3}/server_tests/memmachine_server/common/test_utils.py +0 -0
- {memmachine_server-0.3.2 → memmachine_server-0.3.3}/server_tests/memmachine_server/common/vector_graph_store/__init__.py +0 -0
- {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
- {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
- {memmachine_server-0.3.2 → memmachine_server-0.3.3}/server_tests/memmachine_server/conftest.py +0 -0
- {memmachine_server-0.3.2 → memmachine_server-0.3.3}/server_tests/memmachine_server/episodic_memory/__init__.py +0 -0
- {memmachine_server-0.3.2 → memmachine_server-0.3.3}/server_tests/memmachine_server/episodic_memory/conftest.py +0 -0
- {memmachine_server-0.3.2 → memmachine_server-0.3.3}/server_tests/memmachine_server/episodic_memory/declarative_memory/__init__.py +0 -0
- {memmachine_server-0.3.2 → memmachine_server-0.3.3}/server_tests/memmachine_server/episodic_memory/declarative_memory/test_declarative_memory.py +0 -0
- {memmachine_server-0.3.2 → memmachine_server-0.3.3}/server_tests/memmachine_server/episodic_memory/long_term_memory/__init__.py +0 -0
- {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
- {memmachine_server-0.3.2 → memmachine_server-0.3.3}/server_tests/memmachine_server/episodic_memory/short_term_memory/__init__.py +0 -0
- {memmachine_server-0.3.2 → memmachine_server-0.3.3}/server_tests/memmachine_server/episodic_memory/test_episodic_memory.py +0 -0
- {memmachine_server-0.3.2 → memmachine_server-0.3.3}/server_tests/memmachine_server/episodic_memory/test_episodic_memory_manager.py +0 -0
- {memmachine_server-0.3.2 → memmachine_server-0.3.3}/server_tests/memmachine_server/episodic_memory/test_instance_lru_cache.py +0 -0
- {memmachine_server-0.3.2 → memmachine_server-0.3.3}/server_tests/memmachine_server/installation/__init__.py +0 -0
- {memmachine_server-0.3.2 → memmachine_server-0.3.3}/server_tests/memmachine_server/installation/test_configuration_wizard.py +0 -0
- {memmachine_server-0.3.2 → memmachine_server-0.3.3}/server_tests/memmachine_server/installation/test_memmachine_configure.py +0 -0
- {memmachine_server-0.3.2 → memmachine_server-0.3.3}/server_tests/memmachine_server/installation/test_utilities.py +0 -0
- {memmachine_server-0.3.2 → memmachine_server-0.3.3}/server_tests/memmachine_server/main/__init__.py +0 -0
- {memmachine_server-0.3.2 → memmachine_server-0.3.3}/server_tests/memmachine_server/main/conftest.py +0 -0
- {memmachine_server-0.3.2 → memmachine_server-0.3.3}/server_tests/memmachine_server/main/test_memachine.py +0 -0
- {memmachine_server-0.3.2 → memmachine_server-0.3.3}/server_tests/memmachine_server/main/test_memmachine_delete_session.py +0 -0
- {memmachine_server-0.3.2 → memmachine_server-0.3.3}/server_tests/memmachine_server/main/test_memmachine_integration.py +0 -0
- {memmachine_server-0.3.2 → memmachine_server-0.3.3}/server_tests/memmachine_server/main/test_memmachine_mock.py +0 -0
- {memmachine_server-0.3.2 → memmachine_server-0.3.3}/server_tests/memmachine_server/retrieval_agent/__init__.py +0 -0
- {memmachine_server-0.3.2 → memmachine_server-0.3.3}/server_tests/memmachine_server/retrieval_agent/test_retrieval_agent.py +0 -0
- {memmachine_server-0.3.2 → memmachine_server-0.3.3}/server_tests/memmachine_server/semantic_memory/__init__.py +0 -0
- {memmachine_server-0.3.2 → memmachine_server-0.3.3}/server_tests/memmachine_server/semantic_memory/config_store/__init__.py +0 -0
- {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
- {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
- {memmachine_server-0.3.2 → memmachine_server-0.3.3}/server_tests/memmachine_server/semantic_memory/conftest.py +0 -0
- {memmachine_server-0.3.2 → memmachine_server-0.3.3}/server_tests/memmachine_server/semantic_memory/semantic_test_utils.py +0 -0
- {memmachine_server-0.3.2 → memmachine_server-0.3.3}/server_tests/memmachine_server/semantic_memory/storage/__init__.py +0 -0
- {memmachine_server-0.3.2 → memmachine_server-0.3.3}/server_tests/memmachine_server/semantic_memory/storage/alembic_pg/__init__.py +0 -0
- {memmachine_server-0.3.2 → memmachine_server-0.3.3}/server_tests/memmachine_server/semantic_memory/storage/alembic_pg/helpers.py +0 -0
- {memmachine_server-0.3.2 → memmachine_server-0.3.3}/server_tests/memmachine_server/semantic_memory/storage/alembic_pg/original_schema.sql +0 -0
- {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
- {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
- {memmachine_server-0.3.2 → memmachine_server-0.3.3}/server_tests/memmachine_server/semantic_memory/storage/conftest.py +0 -0
- {memmachine_server-0.3.2 → memmachine_server-0.3.3}/server_tests/memmachine_server/semantic_memory/test_semantic_history_cleanup.py +0 -0
- {memmachine_server-0.3.2 → memmachine_server-0.3.3}/server_tests/memmachine_server/semantic_memory/test_semantic_llm.py +0 -0
- {memmachine_server-0.3.2 → memmachine_server-0.3.3}/server_tests/memmachine_server/semantic_memory/test_semantic_llm_integration.py +0 -0
- {memmachine_server-0.3.2 → memmachine_server-0.3.3}/server_tests/memmachine_server/semantic_memory/test_semantic_memory.py +0 -0
- {memmachine_server-0.3.2 → memmachine_server-0.3.3}/server_tests/memmachine_server/semantic_memory/test_semantic_memory_background.py +0 -0
- {memmachine_server-0.3.2 → memmachine_server-0.3.3}/server_tests/memmachine_server/semantic_memory/test_semantic_memory_integration.py +0 -0
- {memmachine_server-0.3.2 → memmachine_server-0.3.3}/server_tests/memmachine_server/semantic_memory/test_semantic_session_manager.py +0 -0
- {memmachine_server-0.3.2 → memmachine_server-0.3.3}/server_tests/memmachine_server/server/__init__.py +0 -0
- {memmachine_server-0.3.2 → memmachine_server-0.3.3}/server_tests/memmachine_server/server/api_v2/__init__.py +0 -0
- {memmachine_server-0.3.2 → memmachine_server-0.3.3}/server_tests/memmachine_server/server/api_v2/test_config_router.py +0 -0
- {memmachine_server-0.3.2 → memmachine_server-0.3.3}/server_tests/memmachine_server/server/api_v2/test_config_service.py +0 -0
- {memmachine_server-0.3.2 → memmachine_server-0.3.3}/server_tests/memmachine_server/server/api_v2/test_mcp.py +0 -0
- {memmachine_server-0.3.2 → memmachine_server-0.3.3}/server_tests/memmachine_server/server/api_v2/test_router.py +0 -0
- {memmachine_server-0.3.2 → memmachine_server-0.3.3}/server_tests/memmachine_server/server/api_v2/test_service.py +0 -0
- {memmachine_server-0.3.2 → memmachine_server-0.3.3}/server_tests/memmachine_server/server/api_v2/test_spec.py +0 -0
- {memmachine_server-0.3.2 → memmachine_server-0.3.3}/server_tests/memmachine_server/server/prompt/__init__.py +0 -0
- {memmachine_server-0.3.2 → memmachine_server-0.3.3}/server_tests/memmachine_server/server/prompt/test_prompt_utilities.py +0 -0
- {memmachine_server-0.3.2 → memmachine_server-0.3.3}/server_tests/memmachine_server/server/test_middleware.py +0 -0
- {memmachine_server-0.3.2 → memmachine_server-0.3.3}/server_tests/memmachine_server/test_data/longmemeval_snippet.json +0 -0
- {memmachine_server-0.3.2 → memmachine_server-0.3.3}/setup.cfg +0 -0
- {memmachine_server-0.3.2 → memmachine_server-0.3.3}/src/memmachine_server/__init__.py +0 -0
- {memmachine_server-0.3.2 → memmachine_server-0.3.3}/src/memmachine_server/common/__init__.py +0 -0
- {memmachine_server-0.3.2 → memmachine_server-0.3.3}/src/memmachine_server/common/api/__init__.py +0 -0
- {memmachine_server-0.3.2 → memmachine_server-0.3.3}/src/memmachine_server/common/api/version.py +0 -0
- {memmachine_server-0.3.2 → memmachine_server-0.3.3}/src/memmachine_server/common/configuration/database_conf.py +0 -0
- {memmachine_server-0.3.2 → memmachine_server-0.3.3}/src/memmachine_server/common/configuration/default_episode_summary_system_prompt.txt +0 -0
- {memmachine_server-0.3.2 → memmachine_server-0.3.3}/src/memmachine_server/common/configuration/default_episode_summary_user_prompt.txt +0 -0
- {memmachine_server-0.3.2 → memmachine_server-0.3.3}/src/memmachine_server/common/configuration/embedder_conf.py +0 -0
- {memmachine_server-0.3.2 → memmachine_server-0.3.3}/src/memmachine_server/common/configuration/episodic_config.py +0 -0
- {memmachine_server-0.3.2 → memmachine_server-0.3.3}/src/memmachine_server/common/configuration/language_model_conf.py +0 -0
- {memmachine_server-0.3.2 → memmachine_server-0.3.3}/src/memmachine_server/common/configuration/log_conf.py +0 -0
- {memmachine_server-0.3.2 → memmachine_server-0.3.3}/src/memmachine_server/common/configuration/reranker_conf.py +0 -0
- {memmachine_server-0.3.2 → memmachine_server-0.3.3}/src/memmachine_server/common/configuration/retrieval_config.py +0 -0
- {memmachine_server-0.3.2 → memmachine_server-0.3.3}/src/memmachine_server/common/data_types.py +0 -0
- {memmachine_server-0.3.2 → memmachine_server-0.3.3}/src/memmachine_server/common/embedder/__init__.py +0 -0
- {memmachine_server-0.3.2 → memmachine_server-0.3.3}/src/memmachine_server/common/embedder/amazon_bedrock_embedder.py +0 -0
- {memmachine_server-0.3.2 → memmachine_server-0.3.3}/src/memmachine_server/common/embedder/embedder.py +0 -0
- {memmachine_server-0.3.2 → memmachine_server-0.3.3}/src/memmachine_server/common/embedder/sentence_transformer_embedder.py +0 -0
- {memmachine_server-0.3.2 → memmachine_server-0.3.3}/src/memmachine_server/common/episode_store/__init__.py +0 -0
- {memmachine_server-0.3.2 → memmachine_server-0.3.3}/src/memmachine_server/common/episode_store/count_caching_episode_storage.py +0 -0
- {memmachine_server-0.3.2 → memmachine_server-0.3.3}/src/memmachine_server/common/episode_store/episode_model.py +0 -0
- {memmachine_server-0.3.2 → memmachine_server-0.3.3}/src/memmachine_server/common/episode_store/episode_sqlalchemy_store.py +0 -0
- {memmachine_server-0.3.2 → memmachine_server-0.3.3}/src/memmachine_server/common/episode_store/episode_storage.py +0 -0
- {memmachine_server-0.3.2 → memmachine_server-0.3.3}/src/memmachine_server/common/errors.py +0 -0
- {memmachine_server-0.3.2 → memmachine_server-0.3.3}/src/memmachine_server/common/filter/__init__.py +0 -0
- {memmachine_server-0.3.2 → memmachine_server-0.3.3}/src/memmachine_server/common/filter/filter_parser.py +0 -0
- {memmachine_server-0.3.2 → memmachine_server-0.3.3}/src/memmachine_server/common/filter/sql_filter_util.py +0 -0
- {memmachine_server-0.3.2 → memmachine_server-0.3.3}/src/memmachine_server/common/language_model/__init__.py +0 -0
- {memmachine_server-0.3.2 → memmachine_server-0.3.3}/src/memmachine_server/common/language_model/amazon_bedrock_language_model.py +0 -0
- {memmachine_server-0.3.2 → memmachine_server-0.3.3}/src/memmachine_server/common/language_model/language_model.py +0 -0
- {memmachine_server-0.3.2 → memmachine_server-0.3.3}/src/memmachine_server/common/metrics_factory/__init__.py +0 -0
- {memmachine_server-0.3.2 → memmachine_server-0.3.3}/src/memmachine_server/common/metrics_factory/metrics_factory.py +0 -0
- {memmachine_server-0.3.2 → memmachine_server-0.3.3}/src/memmachine_server/common/metrics_factory/operation_tracker.py +0 -0
- {memmachine_server-0.3.2 → memmachine_server-0.3.3}/src/memmachine_server/common/metrics_factory/prometheus_metrics_factory.py +0 -0
- {memmachine_server-0.3.2 → memmachine_server-0.3.3}/src/memmachine_server/common/neo4j_utils.py +0 -0
- {memmachine_server-0.3.2 → memmachine_server-0.3.3}/src/memmachine_server/common/reranker/__init__.py +0 -0
- {memmachine_server-0.3.2 → memmachine_server-0.3.3}/src/memmachine_server/common/reranker/amazon_bedrock_reranker.py +0 -0
- {memmachine_server-0.3.2 → memmachine_server-0.3.3}/src/memmachine_server/common/reranker/bm25_reranker.py +0 -0
- {memmachine_server-0.3.2 → memmachine_server-0.3.3}/src/memmachine_server/common/reranker/cohere_reranker.py +0 -0
- {memmachine_server-0.3.2 → memmachine_server-0.3.3}/src/memmachine_server/common/reranker/cross_encoder_reranker.py +0 -0
- {memmachine_server-0.3.2 → memmachine_server-0.3.3}/src/memmachine_server/common/reranker/embedder_reranker.py +0 -0
- {memmachine_server-0.3.2 → memmachine_server-0.3.3}/src/memmachine_server/common/reranker/identity_reranker.py +0 -0
- {memmachine_server-0.3.2 → memmachine_server-0.3.3}/src/memmachine_server/common/reranker/reranker.py +0 -0
- {memmachine_server-0.3.2 → memmachine_server-0.3.3}/src/memmachine_server/common/reranker/rrf_hybrid_reranker.py +0 -0
- {memmachine_server-0.3.2 → memmachine_server-0.3.3}/src/memmachine_server/common/resource_manager/__init__.py +0 -0
- {memmachine_server-0.3.2 → memmachine_server-0.3.3}/src/memmachine_server/common/resource_manager/base_manager.py +0 -0
- {memmachine_server-0.3.2 → memmachine_server-0.3.3}/src/memmachine_server/common/resource_manager/database_manager.py +0 -0
- {memmachine_server-0.3.2 → memmachine_server-0.3.3}/src/memmachine_server/common/resource_manager/embedder_manager.py +0 -0
- {memmachine_server-0.3.2 → memmachine_server-0.3.3}/src/memmachine_server/common/resource_manager/language_model_manager.py +0 -0
- {memmachine_server-0.3.2 → memmachine_server-0.3.3}/src/memmachine_server/common/resource_manager/reranker_manager.py +0 -0
- {memmachine_server-0.3.2 → memmachine_server-0.3.3}/src/memmachine_server/common/resource_manager/resource_manager.py +0 -0
- {memmachine_server-0.3.2 → memmachine_server-0.3.3}/src/memmachine_server/common/rw_locks.py +0 -0
- {memmachine_server-0.3.2 → memmachine_server-0.3.3}/src/memmachine_server/common/session_manager/__init__.py +0 -0
- {memmachine_server-0.3.2 → memmachine_server-0.3.3}/src/memmachine_server/common/session_manager/session_data_manager.py +0 -0
- {memmachine_server-0.3.2 → memmachine_server-0.3.3}/src/memmachine_server/common/session_manager/session_data_manager_sql_impl.py +0 -0
- {memmachine_server-0.3.2 → memmachine_server-0.3.3}/src/memmachine_server/common/utils.py +0 -0
- {memmachine_server-0.3.2 → memmachine_server-0.3.3}/src/memmachine_server/common/vector_graph_store/__init__.py +0 -0
- {memmachine_server-0.3.2 → memmachine_server-0.3.3}/src/memmachine_server/common/vector_graph_store/data_types.py +0 -0
- {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
- {memmachine_server-0.3.2 → memmachine_server-0.3.3}/src/memmachine_server/common/vector_graph_store/neo4j_vector_graph_store.py +0 -0
- {memmachine_server-0.3.2 → memmachine_server-0.3.3}/src/memmachine_server/common/vector_graph_store/vector_graph_store.py +0 -0
- {memmachine_server-0.3.2 → memmachine_server-0.3.3}/src/memmachine_server/common/vector_store/__init__.py +0 -0
- {memmachine_server-0.3.2 → memmachine_server-0.3.3}/src/memmachine_server/common/vector_store/data_types.py +0 -0
- {memmachine_server-0.3.2 → memmachine_server-0.3.3}/src/memmachine_server/common/vector_store/vector_store.py +0 -0
- {memmachine_server-0.3.2 → memmachine_server-0.3.3}/src/memmachine_server/episodic_memory/__init__.py +0 -0
- {memmachine_server-0.3.2 → memmachine_server-0.3.3}/src/memmachine_server/episodic_memory/declarative_memory/__init__.py +0 -0
- {memmachine_server-0.3.2 → memmachine_server-0.3.3}/src/memmachine_server/episodic_memory/declarative_memory/data_types.py +0 -0
- {memmachine_server-0.3.2 → memmachine_server-0.3.3}/src/memmachine_server/episodic_memory/declarative_memory/declarative_memory.py +0 -0
- {memmachine_server-0.3.2 → memmachine_server-0.3.3}/src/memmachine_server/episodic_memory/episodic_memory.py +0 -0
- {memmachine_server-0.3.2 → memmachine_server-0.3.3}/src/memmachine_server/episodic_memory/episodic_memory_manager.py +0 -0
- {memmachine_server-0.3.2 → memmachine_server-0.3.3}/src/memmachine_server/episodic_memory/instance_lru_cache.py +0 -0
- {memmachine_server-0.3.2 → memmachine_server-0.3.3}/src/memmachine_server/episodic_memory/long_term_memory/__init__.py +0 -0
- {memmachine_server-0.3.2 → memmachine_server-0.3.3}/src/memmachine_server/episodic_memory/long_term_memory/long_term_memory.py +0 -0
- {memmachine_server-0.3.2 → memmachine_server-0.3.3}/src/memmachine_server/episodic_memory/long_term_memory/service_locator.py +0 -0
- {memmachine_server-0.3.2 → memmachine_server-0.3.3}/src/memmachine_server/episodic_memory/service_locator.py +0 -0
- {memmachine_server-0.3.2 → memmachine_server-0.3.3}/src/memmachine_server/episodic_memory/short_term_memory/__init__.py +0 -0
- {memmachine_server-0.3.2 → memmachine_server-0.3.3}/src/memmachine_server/episodic_memory/short_term_memory/service_locator.py +0 -0
- {memmachine_server-0.3.2 → memmachine_server-0.3.3}/src/memmachine_server/installation/__init__.py +0 -0
- {memmachine_server-0.3.2 → memmachine_server-0.3.3}/src/memmachine_server/installation/configuration_wizard.py +0 -0
- {memmachine_server-0.3.2 → memmachine_server-0.3.3}/src/memmachine_server/installation/memmachine_configure.py +0 -0
- {memmachine_server-0.3.2 → memmachine_server-0.3.3}/src/memmachine_server/installation/utilities.py +0 -0
- {memmachine_server-0.3.2 → memmachine_server-0.3.3}/src/memmachine_server/main/__init__.py +0 -0
- {memmachine_server-0.3.2 → memmachine_server-0.3.3}/src/memmachine_server/main/memmachine.py +0 -0
- {memmachine_server-0.3.2 → memmachine_server-0.3.3}/src/memmachine_server/retrieval_agent/__init__.py +0 -0
- {memmachine_server-0.3.2 → memmachine_server-0.3.3}/src/memmachine_server/retrieval_agent/agents/__init__.py +0 -0
- {memmachine_server-0.3.2 → memmachine_server-0.3.3}/src/memmachine_server/retrieval_agent/agents/coq_agent.py +0 -0
- {memmachine_server-0.3.2 → memmachine_server-0.3.3}/src/memmachine_server/retrieval_agent/agents/memmachine_retriever.py +0 -0
- {memmachine_server-0.3.2 → memmachine_server-0.3.3}/src/memmachine_server/retrieval_agent/agents/split_query_agent.py +0 -0
- {memmachine_server-0.3.2 → memmachine_server-0.3.3}/src/memmachine_server/retrieval_agent/agents/tool_select_agent.py +0 -0
- {memmachine_server-0.3.2 → memmachine_server-0.3.3}/src/memmachine_server/retrieval_agent/common/__init__.py +0 -0
- {memmachine_server-0.3.2 → memmachine_server-0.3.3}/src/memmachine_server/retrieval_agent/common/agent_api.py +0 -0
- {memmachine_server-0.3.2 → memmachine_server-0.3.3}/src/memmachine_server/retrieval_agent/service_locator.py +0 -0
- {memmachine_server-0.3.2 → memmachine_server-0.3.3}/src/memmachine_server/semantic_memory/__init__.py +0 -0
- {memmachine_server-0.3.2 → memmachine_server-0.3.3}/src/memmachine_server/semantic_memory/config_store/__init__.py +0 -0
- {memmachine_server-0.3.2 → memmachine_server-0.3.3}/src/memmachine_server/semantic_memory/config_store/caching_semantic_config_storage.py +0 -0
- {memmachine_server-0.3.2 → memmachine_server-0.3.3}/src/memmachine_server/semantic_memory/config_store/config_store.py +0 -0
- {memmachine_server-0.3.2 → memmachine_server-0.3.3}/src/memmachine_server/semantic_memory/config_store/config_store_sqlalchemy.py +0 -0
- {memmachine_server-0.3.2 → memmachine_server-0.3.3}/src/memmachine_server/semantic_memory/semantic_session_manager.py +0 -0
- {memmachine_server-0.3.2 → memmachine_server-0.3.3}/src/memmachine_server/semantic_memory/storage/__init__.py +0 -0
- {memmachine_server-0.3.2 → memmachine_server-0.3.3}/src/memmachine_server/semantic_memory/storage/alembic_pg/__init__.py +0 -0
- {memmachine_server-0.3.2 → memmachine_server-0.3.3}/src/memmachine_server/semantic_memory/storage/alembic_pg/env.py +0 -0
- {memmachine_server-0.3.2 → memmachine_server-0.3.3}/src/memmachine_server/semantic_memory/storage/alembic_pg/script.py.mako +0 -0
- {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
- {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
- {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
- {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
- {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
- {memmachine_server-0.3.2 → memmachine_server-0.3.3}/src/memmachine_server/semantic_memory/storage/alembic_pg/versions/__init__.py +0 -0
- {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
- {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
- {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
- {memmachine_server-0.3.2 → memmachine_server-0.3.3}/src/memmachine_server/semantic_memory/util/__init__.py +0 -0
- {memmachine_server-0.3.2 → memmachine_server-0.3.3}/src/memmachine_server/semantic_memory/util/semantic_prompt_template.py +0 -0
- {memmachine_server-0.3.2 → memmachine_server-0.3.3}/src/memmachine_server/server/__init__.py +0 -0
- {memmachine_server-0.3.2 → memmachine_server-0.3.3}/src/memmachine_server/server/api_v2/__init__.py +0 -0
- {memmachine_server-0.3.2 → memmachine_server-0.3.3}/src/memmachine_server/server/api_v2/config_router.py +0 -0
- {memmachine_server-0.3.2 → memmachine_server-0.3.3}/src/memmachine_server/server/api_v2/config_service.py +0 -0
- {memmachine_server-0.3.2 → memmachine_server-0.3.3}/src/memmachine_server/server/api_v2/exceptions.py +0 -0
- {memmachine_server-0.3.2 → memmachine_server-0.3.3}/src/memmachine_server/server/api_v2/mcp.py +0 -0
- {memmachine_server-0.3.2 → memmachine_server-0.3.3}/src/memmachine_server/server/api_v2/router.py +0 -0
- {memmachine_server-0.3.2 → memmachine_server-0.3.3}/src/memmachine_server/server/api_v2/service.py +0 -0
- {memmachine_server-0.3.2 → memmachine_server-0.3.3}/src/memmachine_server/server/app.py +0 -0
- {memmachine_server-0.3.2 → memmachine_server-0.3.3}/src/memmachine_server/server/diagnostics.py +0 -0
- {memmachine_server-0.3.2 → memmachine_server-0.3.3}/src/memmachine_server/server/mcp_http.py +0 -0
- {memmachine_server-0.3.2 → memmachine_server-0.3.3}/src/memmachine_server/server/mcp_stdio.py +0 -0
- {memmachine_server-0.3.2 → memmachine_server-0.3.3}/src/memmachine_server/server/middleware.py +0 -0
- {memmachine_server-0.3.2 → memmachine_server-0.3.3}/src/memmachine_server/server/prompt/__init__.py +0 -0
- {memmachine_server-0.3.2 → memmachine_server-0.3.3}/src/memmachine_server/server/prompt/coding_style_prompt.py +0 -0
- {memmachine_server-0.3.2 → memmachine_server-0.3.3}/src/memmachine_server/server/prompt/crm_prompt.py +0 -0
- {memmachine_server-0.3.2 → memmachine_server-0.3.3}/src/memmachine_server/server/prompt/default_prompts.py +0 -0
- {memmachine_server-0.3.2 → memmachine_server-0.3.3}/src/memmachine_server/server/prompt/financial_analyst_prompt.py +0 -0
- {memmachine_server-0.3.2 → memmachine_server-0.3.3}/src/memmachine_server/server/prompt/health_assistant_prompt.py +0 -0
- {memmachine_server-0.3.2 → memmachine_server-0.3.3}/src/memmachine_server/server/prompt/profile_prompt.py +0 -0
- {memmachine_server-0.3.2 → memmachine_server-0.3.3}/src/memmachine_server/server/prompt/prompt_utilities.py +0 -0
- {memmachine_server-0.3.2 → memmachine_server-0.3.3}/src/memmachine_server/server/prompt/writing_assistant_prompt.py +0 -0
- {memmachine_server-0.3.2 → memmachine_server-0.3.3}/src/memmachine_server.egg-info/dependency_links.txt +0 -0
- {memmachine_server-0.3.2 → memmachine_server-0.3.3}/src/memmachine_server.egg-info/entry_points.txt +0 -0
- {memmachine_server-0.3.2 → memmachine_server-0.3.3}/src/memmachine_server.egg-info/requires.txt +0 -0
- {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.
|
|
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
|
memmachine_server-0.3.3/server_tests/memmachine_server/common/embedder/test_openai_embedder.py
ADDED
|
@@ -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,
|