diff --git a/src/bedrock_agentcore/memory/README.md b/src/bedrock_agentcore/memory/README.md index a698ceb..91927f3 100644 --- a/src/bedrock_agentcore/memory/README.md +++ b/src/bedrock_agentcore/memory/README.md @@ -186,7 +186,7 @@ session.add_turns([ # Search long-term memories (after memory extraction has occurred) memories = session.search_long_term_memories( query="what food does the user like", - namespace_prefix="/food/user-123", + namespace_prefix="/food/user-123/", top_k=5 ) @@ -219,8 +219,8 @@ def my_llm(user_input: str, memories: List[Dict]) -> str: # Configure memory retrieval with multiple namespaces retrieval_config = { - "support/facts/{sessionId}": RetrievalConfig(top_k=5, relevance_score=0.3), - "user/preferences/{actorId}": RetrievalConfig(top_k=3, relevance_score=0.5) + "support/facts/{sessionId}/": RetrievalConfig(top_k=5, relevance_score=0.3), + "user/preferences/{actorId}/": RetrievalConfig(top_k=3, relevance_score=0.5) } # Process complete conversation turn with automatic memory integration @@ -301,7 +301,7 @@ session2 = manager.create_memory_session( ```python # List all memory records in a namespace records = session.list_long_term_memory_records( - namespace_prefix="/user/preferences/user-123", + namespace_prefix="/user/preferences/user-123/", max_results=20 ) @@ -327,7 +327,7 @@ Learn more here!: [Working example](metadata-workflow.ipynb) # Step 1: Retrieve relevant memories memories = session.search_long_term_memories( query="previous discussion", - namespace_prefix="support/facts/session-456", + namespace_prefix="support/facts/session-456/", top_k=5 ) diff --git a/src/bedrock_agentcore/memory/client.py b/src/bedrock_agentcore/memory/client.py index afd8415..b69364f 100644 --- a/src/bedrock_agentcore/memory/client.py +++ b/src/bedrock_agentcore/memory/client.py @@ -104,7 +104,7 @@ def __getattr__(self, name: str): client = MemoryClient() # These calls are forwarded to the appropriate boto3 client - response = client.list_memory_records(memoryId="mem-123", namespace="test") + response = client.list_memory_records(memoryId="mem-123", namespace="test/") metadata = client.get_memory_metadata(memoryId="mem-123") """ if name in self._ALLOWED_GMDP_METHODS and hasattr(self.gmdp_client, name): @@ -296,12 +296,12 @@ def retrieve_memories( # Correct - exact namespace memories = client.retrieve_memories( memory_id="mem-123", - namespace="support/facts/session-456", + namespace="support/facts/session-456/", query="customer preferences" ) # Incorrect - wildcards not supported - # memories = client.retrieve_memories(..., namespace="support/facts/*", ...) + # memories = client.retrieve_memories(..., namespace="support/facts/*/", ...) """ if "*" in namespace: logger.error("Wildcards are not supported in namespaces. Please provide exact namespace.") @@ -730,7 +730,7 @@ def my_llm(user_input: str, memories: List[Dict]) -> str: session_id="session-456", user_input="What did we discuss yesterday?", llm_callback=my_llm, - retrieval_namespace="support/facts/{sessionId}" + retrieval_namespace="support/facts/{sessionId}/" ) """ # Step 1: Retrieve relevant memories @@ -1758,8 +1758,8 @@ def wait_for_memories( existing memories in the namespace, this method may return True immediately even if new extractions haven't completed. 2. Wildcards (*) are NOT supported in namespaces. You must provide the exact - namespace path with all variables resolved (e.g., "support/facts/session-123" - not "support/facts/*"). + namespace path with all variables resolved (e.g., "support/facts/session-123/" + not "support/facts/*/"). For subsequent extractions in populated namespaces, use a fixed wait time: time.sleep(150) # Wait 2.5 minutes for extraction @@ -1931,7 +1931,7 @@ def _add_default_namespaces(self, strategies: List[Dict[str, Any]]) -> List[Dict if "namespaces" not in strategy_config: strategy_type = StrategyType(strategy_type_key) - strategy_config["namespaces"] = DEFAULT_NAMESPACES.get(strategy_type, ["custom/{actorId}/{sessionId}"]) + strategy_config["namespaces"] = DEFAULT_NAMESPACES.get(strategy_type, ["custom/{actorId}/{sessionId}/"]) self._validate_strategy_config(strategy_copy, strategy_type_key) diff --git a/src/bedrock_agentcore/memory/constants.py b/src/bedrock_agentcore/memory/constants.py index 3dbc00a..6ab3a44 100644 --- a/src/bedrock_agentcore/memory/constants.py +++ b/src/bedrock_agentcore/memory/constants.py @@ -73,10 +73,10 @@ class MessageRole(Enum): # Default namespaces for each strategy type DEFAULT_NAMESPACES: Dict[StrategyType, List[str]] = { - StrategyType.SEMANTIC: ["/strategies/{memoryStrategyId}/actors/{actorId}"], - StrategyType.SUMMARY: ["/strategies/{memoryStrategyId}/actors/{actorId}/sessions/{sessionId}"], - StrategyType.USER_PREFERENCE: ["/strategies/{memoryStrategyId}/actors/{actorId}"], - StrategyType.EPISODIC: ["/strategies/{memoryStrategyId}/actors/{actorId}/sessions/{sessionId}"], + StrategyType.SEMANTIC: ["/strategies/{memoryStrategyId}/actors/{actorId}/"], + StrategyType.SUMMARY: ["/strategies/{memoryStrategyId}/actors/{actorId}/sessions/{sessionId}/"], + StrategyType.USER_PREFERENCE: ["/strategies/{memoryStrategyId}/actors/{actorId}/"], + StrategyType.EPISODIC: ["/strategies/{memoryStrategyId}/actors/{actorId}/sessions/{sessionId}/"], } diff --git a/src/bedrock_agentcore/memory/integrations/strands/README.md b/src/bedrock_agentcore/memory/integrations/strands/README.md index 21b6746..5da1018 100644 --- a/src/bedrock_agentcore/memory/integrations/strands/README.md +++ b/src/bedrock_agentcore/memory/integrations/strands/README.md @@ -112,19 +112,19 @@ comprehensive_memory = client.create_memory_and_wait( { "summaryMemoryStrategy": { "name": "SessionSummarizer", - "namespaces": ["/summaries/{actorId}/{sessionId}"] + "namespaces": ["/summaries/{actorId}/{sessionId}/"] } }, { "userPreferenceMemoryStrategy": { "name": "PreferenceLearner", - "namespaces": ["/preferences/{actorId}"] + "namespaces": ["/preferences/{actorId}/"] } }, { "semanticMemoryStrategy": { "name": "FactExtractor", - "namespaces": ["/facts/{actorId}"] + "namespaces": ["/facts/{actorId}/"] } } ] @@ -143,7 +143,7 @@ config = AgentCoreMemoryConfig( session_id=SESSION_ID, actor_id=ACTOR_ID, retrieval_config={ - "/preferences/{actorId}": RetrievalConfig( + "/preferences/{actorId}/": RetrievalConfig( top_k=5, relevance_score=0.7 ) @@ -161,15 +161,15 @@ config = AgentCoreMemoryConfig( session_id=SESSION_ID, actor_id=ACTOR_ID, retrieval_config={ - "/preferences/{actorId}": RetrievalConfig( + "/preferences/{actorId}/": RetrievalConfig( top_k=5, relevance_score=0.7 ), - "/facts/{actorId}": RetrievalConfig( + "/facts/{actorId}/": RetrievalConfig( top_k=10, relevance_score=0.3 ), - "/summaries/{actorId}/{sessionId}": RetrievalConfig( + "/summaries/{actorId}/{sessionId}/": RetrievalConfig( top_k=5, relevance_score=0.5 ) @@ -233,9 +233,9 @@ https://docs.aws.amazon.com/bedrock-agentcore/latest/devguide/memory-strategies. ### Namespace Patterns -- `/preferences/{actorId}`: User-specific preferences -- `/facts/{actorId}`: User-specific facts -- `/summaries/{actorId}/{sessionId}`: Session-specific summaries +- `/preferences/{actorId}/`: User-specific preferences +- `/facts/{actorId}/`: User-specific facts +- `/summaries/{actorId}/{sessionId}/`: Session-specific summaries --- diff --git a/src/bedrock_agentcore/memory/session.py b/src/bedrock_agentcore/memory/session.py index aafdbbd..02dd84e 100644 --- a/src/bedrock_agentcore/memory/session.py +++ b/src/bedrock_agentcore/memory/session.py @@ -72,7 +72,7 @@ def my_llm(user_input: str, memories: List[Dict]) -> str: session_id="session-789", user_input="What did we discuss?", llm_callback=my_llm, - retrieval_namespace="support/facts/{sessionId}" + retrieval_namespace="support/facts/{sessionId}/" ) ``` @@ -298,8 +298,8 @@ def my_llm(user_input: str, memories: List[Dict]) -> str: return response['content'] retrieval_config = { - "support/facts/{sessionId}": RetrievalConfig(top_k=5, relevance_score=0.3), - "user/preferences/{actorId}": RetrievalConfig(top_k=3, relevance_score=0.5) + "support/facts/{sessionId}/": RetrievalConfig(top_k=5, relevance_score=0.3), + "user/preferences/{actorId}/": RetrievalConfig(top_k=3, relevance_score=0.5) } memories, response, event = manager.process_turn_with_llm( diff --git a/tests/bedrock_agentcore/memory/integrations/strands/test_agentcore_memory_session_manager.py b/tests/bedrock_agentcore/memory/integrations/strands/test_agentcore_memory_session_manager.py index a01973c..c05f79d 100644 --- a/tests/bedrock_agentcore/memory/integrations/strands/test_agentcore_memory_session_manager.py +++ b/tests/bedrock_agentcore/memory/integrations/strands/test_agentcore_memory_session_manager.py @@ -25,8 +25,8 @@ def agentcore_config(): def agentcore_config_with_retrieval(): """Create a test AgentCore Memory configuration with retrieval config.""" retrieval_config = { - "user_preferences/{actorId}": RetrievalConfig(top_k=5, relevance_score=0.3), - "session_context/{sessionId}": RetrievalConfig(top_k=3, relevance_score=0.5), + "user_preferences/{actorId}/": RetrievalConfig(top_k=5, relevance_score=0.3), + "session_context/{sessionId}/": RetrievalConfig(top_k=3, relevance_score=0.5), } return AgentCoreMemoryConfig( memory_id="test-memory-123", @@ -471,17 +471,17 @@ def test_validate_namespace_resolution(self, session_manager): # Valid resolution assert session_manager._validate_namespace_resolution( - "user_preferences/{actorId}", "user_preferences/test-actor" + "user_preferences/{actorId}/", "user_preferences/test-actor/" ) # Mock invalid resolution session_manager._validate_namespace_resolution.return_value = False assert not session_manager._validate_namespace_resolution( - "user_preferences/{actorId}", "user_preferences/{actorId}" + "user_preferences/{actorId}/", "user_preferences/{actorId}/" ) # Invalid - empty result - assert not session_manager._validate_namespace_resolution("test_namespace", "") + assert not session_manager._validate_namespace_resolution("test_namespace/", "") def test_load_long_term_memories_with_validation_failure(self, mock_memory_client, test_agent): """Test LTM loading with namespace validation failure.""" @@ -490,7 +490,7 @@ def test_load_long_term_memories_with_validation_failure(self, mock_memory_clien memory_id="test-memory-123", session_id="test-session-456", actor_id="test-actor", - retrieval_config={"user_preferences/{invalidVar}": RetrievalConfig(top_k=5, relevance_score=0.3)}, + retrieval_config={"user_preferences/{invalidVar}/": RetrievalConfig(top_k=5, relevance_score=0.3)}, ) with patch( @@ -563,23 +563,23 @@ def mock_generate_query(namespace, config, agent): # Test preferences namespace config = RetrievalConfig(top_k=5, relevance_score=0.3) - query = session_manager._generate_initialization_query("user_preferences/{actorId}", config, test_agent) + query = session_manager._generate_initialization_query("user_preferences/{actorId}/", config, test_agent) assert query == "user preferences settings" # Test context namespace - query = session_manager._generate_initialization_query("session_context/{sessionId}", config, test_agent) + query = session_manager._generate_initialization_query("session_context/{sessionId}/", config, test_agent) assert query == "conversation context history" # Test semantic namespace - query = session_manager._generate_initialization_query("semantic_knowledge", config, test_agent) + query = session_manager._generate_initialization_query("semantic_knowledge/", config, test_agent) assert query == "facts knowledge information" # Test facts namespace - query = session_manager._generate_initialization_query("facts_database", config, test_agent) + query = session_manager._generate_initialization_query("facts_database/", config, test_agent) assert query == "facts knowledge information" # Test fallback - query = session_manager._generate_initialization_query("unknown_namespace", config, test_agent) + query = session_manager._generate_initialization_query("unknown_namespace/", config, test_agent) assert query == "context preferences facts" def test_generate_initialization_query_custom(self, session_manager, test_agent): @@ -589,7 +589,7 @@ def test_generate_initialization_query_custom(self, session_manager, test_agent) # Mock the method since it doesn't exist yet session_manager._generate_initialization_query = Mock(return_value="custom query for testing") - query = session_manager._generate_initialization_query("user_preferences/{actorId}", config, test_agent) + query = session_manager._generate_initialization_query("user_preferences/{actorId}/", config, test_agent) assert query == "custom query for testing" def test_retrieve_contextual_memories_all_namespaces(self, agentcore_config_with_retrieval, mock_memory_client): @@ -617,11 +617,11 @@ def test_retrieve_contextual_memories_all_namespaces(self, agentcore_config_with manager.retrieve_contextual_memories = Mock( return_value=[ { - "namespace": "user_preferences/test-actor-789", + "namespace": "user_preferences/test-actor-789/", "memories": [{"content": "Relevant memory", "relevanceScore": 0.8}], }, { - "namespace": "session_context/test-session-456", + "namespace": "session_context/test-session-456/", "memories": [{"content": "Less relevant memory", "relevanceScore": 0.2}], }, ] @@ -657,13 +657,13 @@ def test_retrieve_contextual_memories_specific_namespaces( manager.retrieve_contextual_memories = Mock( return_value=[ { - "namespace": "user_preferences/test-actor-789", + "namespace": "user_preferences/test-actor-789/", "memories": [{"content": "User preference memory", "relevanceScore": 0.9}], } ] ) results = manager.retrieve_contextual_memories( - "What are my preferences?", namespaces=["user_preferences/{actorId}"] + "What are my preferences?", namespaces=["user_preferences/{actorId}/"] ) # Should return results for specified namespace only @@ -695,7 +695,7 @@ def test_retrieve_contextual_memories_invalid_namespace(self, agentcore_config_w ): manager = AgentCoreMemorySessionManager(agentcore_config_with_retrieval) manager.retrieve_contextual_memories = Mock(return_value={}) - results = manager.retrieve_contextual_memories("test query", namespaces=["nonexistent_namespace"]) + results = manager.retrieve_contextual_memories("test query", namespaces=["nonexistent_namespace/"]) # Should return empty results assert results == {} @@ -755,27 +755,27 @@ def test_load_long_term_memories_exception_handling( def test_namespace_variable_resolution(self, session_manager): """Test namespace variable resolution with various combinations.""" # Test basic variable resolution - namespace = "user_preferences/{actorId}" + namespace = "user_preferences/{actorId}/" resolved = namespace.format( actorId=session_manager.config.actor_id, sessionId=session_manager.config.session_id, memoryStrategyId="" ) - assert resolved == "user_preferences/test-actor-789" + assert resolved == "user_preferences/test-actor-789/" # Test multiple variables - namespace = "context/{sessionId}/actor/{actorId}" + namespace = "context/{sessionId}/actor/{actorId}/" resolved = namespace.format( actorId=session_manager.config.actor_id, sessionId=session_manager.config.session_id, memoryStrategyId="" ) - assert resolved == "context/test-session-456/actor/test-actor-789" + assert resolved == "context/test-session-456/actor/test-actor-789/" # Test with strategy ID - namespace = "strategy/{memoryStrategyId}/user/{actorId}" + namespace = "strategy/{memoryStrategyId}/user/{actorId}/" resolved = namespace.format( actorId=session_manager.config.actor_id, sessionId=session_manager.config.session_id, memoryStrategyId="test_strategy", ) - assert resolved == "strategy/test_strategy/user/test-actor-789" + assert resolved == "strategy/test_strategy/user/test-actor-789/" def test_generate_initialization_query_patterns(self, session_manager, test_agent): """Test initialization query generation with various namespace patterns.""" @@ -796,17 +796,17 @@ def mock_generate_query(namespace, config, agent): # Test various preference patterns patterns_and_expected = [ - ("user_preferences/{actorId}", "user preferences settings"), - ("preferences/global", "user preferences settings"), - ("my_preferences", "user preferences settings"), - ("session_context/{sessionId}", "conversation context history"), - ("context/history", "conversation context history"), - ("conversation_context", "conversation context history"), - ("semantic_memory", "facts knowledge information"), - ("facts_database", "facts knowledge information"), - ("knowledge_semantic", "facts knowledge information"), - ("random_namespace", "context preferences facts"), - ("unknown", "context preferences facts"), + ("user_preferences/{actorId}/", "user preferences settings"), + ("preferences/global/", "user preferences settings"), + ("my_preferences/", "user preferences settings"), + ("session_context/{sessionId}/", "conversation context history"), + ("context/history/", "conversation context history"), + ("conversation_context/", "conversation context history"), + ("semantic_memory/", "facts knowledge information"), + ("facts_database/", "facts knowledge information"), + ("knowledge_semantic/", "facts knowledge information"), + ("random_namespace/", "context preferences facts"), + ("unknown/", "context preferences facts"), ] for namespace, expected_query in patterns_and_expected: @@ -1063,7 +1063,7 @@ def test_retrieve_customer_context_filters_by_relevance_score(self, mock_memory_ memory_id="test-memory-123", session_id="test-session-456", actor_id="test-actor-789", - retrieval_config={"test_namespace": RetrievalConfig(top_k=10, relevance_score=0.5)}, + retrieval_config={"test_namespace/": RetrievalConfig(top_k=10, relevance_score=0.5)}, ) with patch( diff --git a/tests/bedrock_agentcore/memory/models/test_models.py b/tests/bedrock_agentcore/memory/models/test_models.py index 5315e1f..a1e6b9e 100644 --- a/tests/bedrock_agentcore/memory/models/test_models.py +++ b/tests/bedrock_agentcore/memory/models/test_models.py @@ -131,7 +131,7 @@ def test_memory_record_initialization(self): data = { "memoryRecordId": "record-123", "content": {"text": "This is a memory record"}, - "namespace": "user/preferences", + "namespace": "user/preferences/", "relevanceScore": 0.95, "createdAt": "2023-01-01T00:00:00Z", } @@ -144,7 +144,7 @@ def test_memory_record_initialization(self): def test_memory_record_dict_access(self): """Test MemoryRecord dictionary-like access.""" - data = {"memoryRecordId": "record-456", "namespace": "support/facts"} + data = {"memoryRecordId": "record-456", "namespace": "support/facts/"} memory_record = MemoryRecord(data) assert "memoryRecordId" in memory_record diff --git a/tests/bedrock_agentcore/memory/test_client.py b/tests/bedrock_agentcore/memory/test_client.py index 6c20a08..9e79835 100644 --- a/tests/bedrock_agentcore/memory/test_client.py +++ b/tests/bedrock_agentcore/memory/test_client.py @@ -141,7 +141,7 @@ def test_save_conversation_and_retrieve_memories(): # Test UUID patch for deterministic testing with patch("uuid.uuid4", return_value=uuid.UUID("12345678-1234-5678-1234-567812345678")): # Test retrieve_memories - memories = client.retrieve_memories(memory_id="mem-123", namespace="test/namespace", query="Hello", top_k=3) + memories = client.retrieve_memories(memory_id="mem-123", namespace="test/namespace/", query="Hello", top_k=3) assert len(memories) == 1 assert memories[0]["memoryRecordId"] == "rec-123" @@ -322,7 +322,7 @@ def test_deprecated_methods(): session_id="session-456", user_input="Hello", agent_response="Hi", - retrieval_namespace="test/ns", + retrieval_namespace="test/ns/", ) assert len(w) >= 2 @@ -456,7 +456,7 @@ def mock_llm_callback(user_input: str, memories: list) -> str: session_id="session-456", user_input="What did we discuss before?", llm_callback=mock_llm_callback, - retrieval_namespace="support/facts/session-456", + retrieval_namespace="support/facts/session-456/", retrieval_query="previous discussion", top_k=5, ) @@ -471,7 +471,7 @@ def mock_llm_callback(user_input: str, memories: list) -> str: # Verify retrieval was called with correct parameters retrieve_args, retrieve_kwargs = mock_gmdp.retrieve_memory_records.call_args assert retrieve_kwargs["memoryId"] == "mem-123" - assert retrieve_kwargs["namespace"] == "support/facts/session-456" + assert retrieve_kwargs["namespace"] == "support/facts/session-456/" assert retrieve_kwargs["searchCriteria"]["searchQuery"] == "previous discussion" assert retrieve_kwargs["searchCriteria"]["topK"] == 5 @@ -770,7 +770,7 @@ def test_add_user_preference_strategy(): memory_id="mem-456", name="Test User Preference Strategy", description="User preference test description", - namespaces=["preferences/{actorId}"], + namespaces=["preferences/{actorId}/"], ) assert mock_gmcp.update_memory.called @@ -790,7 +790,7 @@ def test_add_user_preference_strategy(): user_pref_config = strategy["userPreferenceMemoryStrategy"] assert user_pref_config["name"] == "Test User Preference Strategy" assert user_pref_config["description"] == "User preference test description" - assert user_pref_config["namespaces"] == ["preferences/{actorId}"] + assert user_pref_config["namespaces"] == ["preferences/{actorId}/"] # Verify client token and memory ID assert kwargs["memoryId"] == "mem-456" @@ -826,7 +826,7 @@ def test_add_custom_semantic_strategy(): extraction_config=extraction_config, consolidation_config=consolidation_config, description="Custom semantic strategy test description", - namespaces=["custom/{actorId}/{sessionId}"], + namespaces=["custom/{actorId}/{sessionId}/"], ) assert mock_gmcp.update_memory.called @@ -846,7 +846,7 @@ def test_add_custom_semantic_strategy(): custom_config = strategy["customMemoryStrategy"] assert custom_config["name"] == "Test Custom Semantic Strategy" assert custom_config["description"] == "Custom semantic strategy test description" - assert custom_config["namespaces"] == ["custom/{actorId}/{sessionId}"] + assert custom_config["namespaces"] == ["custom/{actorId}/{sessionId}/"] # Verify the semantic override configuration assert "configuration" in custom_config @@ -925,7 +925,7 @@ def test_wait_for_memories(): with patch("time.sleep"): # Test wait_for_memories (should return True when memories found) result = client.wait_for_memories( - memory_id="mem-123", namespace="test/namespace", test_query="test", max_wait=30, poll_interval=5 + memory_id="mem-123", namespace="test/namespace/", test_query="test", max_wait=30, poll_interval=5 ) assert result @@ -945,7 +945,7 @@ def test_wait_for_memories_wildcard_namespace(): # Test with wildcard namespace - should return False immediately result = client.wait_for_memories( - memory_id="mem-123", namespace="test/namespace/*", test_query="test", max_wait=30, poll_interval=5 + memory_id="mem-123", namespace="test/namespace/*/", test_query="test", max_wait=30, poll_interval=5 ) assert not result @@ -1399,7 +1399,7 @@ def test_modify_strategy(): memory_id="mem-123", strategy_id="strat-789", description="Modified description", - namespaces=["custom/namespace"], + namespaces=["custom/namespace/"], ) assert mock_gmcp.update_memory.called @@ -1414,7 +1414,7 @@ def test_modify_strategy(): modified_strategy = kwargs["memoryStrategies"]["modifyMemoryStrategies"][0] assert modified_strategy["memoryStrategyId"] == "strat-789" assert modified_strategy["description"] == "Modified description" - assert modified_strategy["namespaces"] == ["custom/namespace"] + assert modified_strategy["namespaces"] == ["custom/namespace/"] def test_retrieve_memories_resource_not_found_error(): @@ -1432,7 +1432,7 @@ def test_retrieve_memories_resource_not_found_error(): # Test retrieve_memories - should return empty list and log warning result = client.retrieve_memories( - memory_id="nonexistent-mem-123", namespace="test/namespace", query="test query", top_k=5 + memory_id="nonexistent-mem-123", namespace="test/namespace/", query="test query", top_k=5 ) # Should return empty list instead of raising exception @@ -1441,7 +1441,7 @@ def test_retrieve_memories_resource_not_found_error(): # Verify API was called with correct parameters args, kwargs = mock_gmdp.retrieve_memory_records.call_args assert kwargs["memoryId"] == "nonexistent-mem-123" - assert kwargs["namespace"] == "test/namespace" + assert kwargs["namespace"] == "test/namespace/" assert kwargs["searchCriteria"]["searchQuery"] == "test query" assert kwargs["searchCriteria"]["topK"] == 5 @@ -1462,7 +1462,7 @@ def test_retrieve_memories_validation_error(): # Test retrieve_memories - should return empty list and log warning result = client.retrieve_memories( memory_id="mem-123", - namespace="invalid/namespace", + namespace="invalid/namespace/", query="", top_k=-1, # Invalid parameters ) @@ -1488,7 +1488,7 @@ def test_retrieve_memories_service_error(): mock_gmdp.retrieve_memory_records.side_effect = ClientError(error_response, "RetrieveMemoryRecords") # Test retrieve_memories - should return empty list and log warning - result = client.retrieve_memories(memory_id="mem-123", namespace="test/namespace", query="test query", top_k=3) + result = client.retrieve_memories(memory_id="mem-123", namespace="test/namespace/", query="test query", top_k=3) # Should return empty list instead of raising exception assert result == [] @@ -1496,7 +1496,7 @@ def test_retrieve_memories_service_error(): # Verify API was called with correct parameters args, kwargs = mock_gmdp.retrieve_memory_records.call_args assert kwargs["memoryId"] == "mem-123" - assert kwargs["namespace"] == "test/namespace" + assert kwargs["namespace"] == "test/namespace/" assert kwargs["searchCriteria"]["searchQuery"] == "test query" assert kwargs["searchCriteria"]["topK"] == 3 @@ -1515,7 +1515,7 @@ def test_retrieve_memories_unknown_error(): mock_gmdp.retrieve_memory_records.side_effect = ClientError(error_response, "RetrieveMemoryRecords") # Test retrieve_memories - should return empty list and log warning - result = client.retrieve_memories(memory_id="mem-123", namespace="test/namespace", query="test query", top_k=3) + result = client.retrieve_memories(memory_id="mem-123", namespace="test/namespace/", query="test query", top_k=3) # Should return empty list instead of raising exception assert result == [] @@ -1535,7 +1535,7 @@ def test_retrieve_memories_wildcard_namespace(): # Test with wildcard namespace - should return empty list without API call result = client.retrieve_memories( - memory_id="mem-123", namespace="test/namespace/*", query="test query", top_k=3 + memory_id="mem-123", namespace="test/namespace/*/", query="test query", top_k=3 ) # Should return empty list @@ -2225,7 +2225,7 @@ def test_get_memory_record(): "memoryStrategyId": "strat-456", "content": {"text": "Memory record content"}, "createdAt": int(time.time()), - "namespaces": ["test/namespace"], + "namespaces": ["test/namespace/"], } } @@ -2239,7 +2239,7 @@ def test_get_memory_record(): assert response["memoryRecord"]["memoryStrategyId"] == "strat-456" assert response["memoryRecord"]["content"]["text"] == "Memory record content" assert "createdAt" in response["memoryRecord"] - assert response["memoryRecord"]["namespaces"] == ["test/namespace"] + assert response["memoryRecord"]["namespaces"] == ["test/namespace/"] # Verify API call args, kwargs = mock_gmdp.get_memory_record.call_args @@ -2336,7 +2336,7 @@ def test_list_memory_records(): "memoryStrategyId": "strat-456", "content": {"text": "Memory record 1"}, "createdAt": int(time.time()), - "namespaces": ["test/namespace"], + "namespaces": ["test/namespace/"], "score": 0.95, }, { @@ -2344,7 +2344,7 @@ def test_list_memory_records(): "memoryStrategyId": "strat-456", "content": {"text": "Memory record 2"}, "createdAt": int(time.time()), - "namespaces": ["test/namespace"], + "namespaces": ["test/namespace/"], "score": 0.85, }, ], @@ -2352,7 +2352,7 @@ def test_list_memory_records(): } # Test list_memory_records - response = client.list_memory_records(memoryId="mem-123", namespace="test/namespace", maxResults=10) + response = client.list_memory_records(memoryId="mem-123", namespace="test/namespace/", maxResults=10) assert response["memoryRecordSummaries"] assert len(response["memoryRecordSummaries"]) == 2 @@ -2365,7 +2365,7 @@ def test_list_memory_records(): # Verify API call args, kwargs = mock_gmdp.list_memory_records.call_args assert kwargs["memoryId"] == "mem-123" - assert kwargs["namespace"] == "test/namespace" + assert kwargs["namespace"] == "test/namespace/" assert kwargs["maxResults"] == 10 @@ -2386,7 +2386,7 @@ def test_list_memory_records_with_strategy_filter(): "memoryStrategyId": "strat-123", "content": {"text": "Memory record 1"}, "createdAt": int(time.time()), - "namespaces": ["test/namespace"], + "namespaces": ["test/namespace/"], } ], "nextToken": None, @@ -2394,7 +2394,7 @@ def test_list_memory_records_with_strategy_filter(): # Test list_memory_records with strategy filter response = client.list_memory_records( - memoryId="mem-123", namespace="test/namespace", memoryStrategyId="strat-123", maxResults=10 + memoryId="mem-123", namespace="test/namespace/", memoryStrategyId="strat-123", maxResults=10 ) assert response["memoryRecordSummaries"] @@ -2406,7 +2406,7 @@ def test_list_memory_records_with_strategy_filter(): # Verify API call args, kwargs = mock_gmdp.list_memory_records.call_args assert kwargs["memoryId"] == "mem-123" - assert kwargs["namespace"] == "test/namespace" + assert kwargs["namespace"] == "test/namespace/" assert kwargs["memoryStrategyId"] == "strat-123" assert kwargs["maxResults"] == 10 @@ -2427,7 +2427,7 @@ def test_list_memory_records_pagination(): ] # Get first page - response1 = client.list_memory_records(memoryId="mem-123", namespace="test/namespace") + response1 = client.list_memory_records(memoryId="mem-123", namespace="test/namespace/") assert len(response1["memoryRecordSummaries"]) == 1 assert response1["memoryRecordSummaries"][0]["memoryRecordId"] == "rec-1" @@ -2435,7 +2435,7 @@ def test_list_memory_records_pagination(): # Get second page response2 = client.list_memory_records( - memoryId="mem-123", namespace="test/namespace", nextToken=response1["nextToken"] + memoryId="mem-123", namespace="test/namespace/", nextToken=response1["nextToken"] ) assert len(response2["memoryRecordSummaries"]) == 1 @@ -2472,7 +2472,7 @@ def test_list_memory_records_client_error(): # Test error handling try: - client.list_memory_records(memoryId="mem-123", namespace="test/namespace") + client.list_memory_records(memoryId="mem-123", namespace="test/namespace/") raise AssertionError("ClientError was not raised") except ClientError as e: assert error["code"] in str(e) @@ -2886,8 +2886,8 @@ def test_add_episodic_strategy(): memory_id="mem-123", name="Test Episodic Strategy", description="Episodic test description", - namespaces=["episodes/{actorId}/{sessionId}"], - reflection_namespaces=["reflections/{actorId}"], + namespaces=["episodes/{actorId}/{sessionId}/"], + reflection_namespaces=["reflections/{actorId}/"], ) assert mock_gmcp.update_memory.called @@ -2905,8 +2905,8 @@ def test_add_episodic_strategy(): episodic_config = strategy["episodicMemoryStrategy"] assert episodic_config["name"] == "Test Episodic Strategy" assert episodic_config["description"] == "Episodic test description" - assert episodic_config["namespaces"] == ["episodes/{actorId}/{sessionId}"] - assert episodic_config["reflectionConfiguration"] == {"namespaces": ["reflections/{actorId}"]} + assert episodic_config["namespaces"] == ["episodes/{actorId}/{sessionId}/"] + assert episodic_config["reflectionConfiguration"] == {"namespaces": ["reflections/{actorId}/"]} assert kwargs["memoryId"] == "mem-123" @@ -2932,7 +2932,7 @@ def test_add_custom_episodic_strategy(): reflection_config = { "prompt": "Generate reflections from episodes", "modelId": "anthropic.claude-3-sonnet-20240229-v1:0", - "namespaces": ["reflections/{actorId}"], + "namespaces": ["reflections/{actorId}/"], } client.add_custom_episodic_strategy( @@ -2942,7 +2942,7 @@ def test_add_custom_episodic_strategy(): consolidation_config=consolidation_config, reflection_config=reflection_config, description="Custom episodic test", - namespaces=["custom/{actorId}/{sessionId}"], + namespaces=["custom/{actorId}/{sessionId}/"], ) assert mock_gmcp.update_memory.called @@ -2960,7 +2960,7 @@ def test_add_custom_episodic_strategy(): assert episodic_override["extraction"]["appendToPrompt"] == "Extract episodes from conversation" assert episodic_override["consolidation"]["appendToPrompt"] == "Consolidate episodes" assert episodic_override["reflection"]["appendToPrompt"] == "Generate reflections from episodes" - assert episodic_override["reflection"]["namespaces"] == ["reflections/{actorId}"] + assert episodic_override["reflection"]["namespaces"] == ["reflections/{actorId}/"] def test_add_episodic_strategy_and_wait(): @@ -2979,7 +2979,7 @@ def test_add_episodic_strategy_and_wait(): result = client.add_episodic_strategy_and_wait( memory_id="mem-123", name="Test Episodic Strategy", - reflection_namespaces=["reflections/{actorId}"], + reflection_namespaces=["reflections/{actorId}/"], ) assert result["memoryId"] == "mem-123" @@ -3009,7 +3009,7 @@ def test_add_custom_episodic_strategy_and_wait(): reflection_config={ "prompt": "Reflect", "modelId": "model-3", - "namespaces": ["actor/{actorId}"], + "namespaces": ["actor/{actorId}/"], }, ) @@ -3030,7 +3030,7 @@ def test_wrap_configuration_custom_episodic_override(): "reflection": { "appendToPrompt": "Reflect on episodes", "modelId": "reflection-model", - "namespaces": ["actor/{actorId}"], + "namespaces": ["actor/{actorId}/"], }, } diff --git a/tests/bedrock_agentcore/memory/test_controlplane.py b/tests/bedrock_agentcore/memory/test_controlplane.py index fa2e3b0..38b691c 100644 --- a/tests/bedrock_agentcore/memory/test_controlplane.py +++ b/tests/bedrock_agentcore/memory/test_controlplane.py @@ -364,7 +364,7 @@ def test_update_strategy(): memory_id="mem-123", strategy_id="strat-456", description="Updated strategy description", - namespaces=["custom/namespace1", "custom/namespace2"], + namespaces=["custom/namespace1/", "custom/namespace2/"], configuration={"modelId": "test-model"}, ) @@ -381,7 +381,7 @@ def test_update_strategy(): modify_strategy = kwargs["memoryStrategies"]["modifyMemoryStrategies"][0] assert modify_strategy["memoryStrategyId"] == "strat-456" assert modify_strategy["description"] == "Updated strategy description" - assert modify_strategy["namespaces"] == ["custom/namespace1", "custom/namespace2"] + assert modify_strategy["namespaces"] == ["custom/namespace1/", "custom/namespace2/"] assert modify_strategy["configuration"] == {"modelId": "test-model"} diff --git a/tests/bedrock_agentcore/memory/test_session.py b/tests/bedrock_agentcore/memory/test_session.py index 839e91f..bcd6da5 100644 --- a/tests/bedrock_agentcore/memory/test_session.py +++ b/tests/bedrock_agentcore/memory/test_session.py @@ -406,7 +406,7 @@ def mock_llm_callback(user_input: str, memories: List[Dict[str, Any]]) -> str: return f"Response to: {user_input} with {len(memories)} memories" # Test process_turn_with_llm with new RetrievalConfig API - retrieval_config = {"test/namespace": RetrievalConfig(top_k=5)} + retrieval_config = {"test/namespace/": RetrievalConfig(top_k=5)} memories, response, event = manager.process_turn_with_llm( actor_id="user-123", session_id="session-456", @@ -1176,7 +1176,7 @@ def test_search_long_term_memories_success(self): } mock_client_instance.retrieve_memory_records.return_value = mock_response - result = manager.search_long_term_memories(query="test query", namespace_prefix="test/namespace", top_k=5) + result = manager.search_long_term_memories(query="test query", namespace_prefix="test/namespace/", top_k=5) assert len(result) == 2 assert all(isinstance(record, MemoryRecord) for record in result) @@ -1188,7 +1188,7 @@ def test_search_long_term_memories_success(self): assert call_args["memoryId"] == "testMemory-1234567890" assert call_args["searchCriteria"]["searchQuery"] == "test query" assert call_args["searchCriteria"]["topK"] == 5 - assert call_args["namespace"] == "test/namespace" + assert call_args["namespace"] == "test/namespace/" def test_search_long_term_memories_with_strategy(self): """Test search_long_term_memories with strategy_id.""" @@ -1206,7 +1206,7 @@ def test_search_long_term_memories_with_strategy(self): mock_client_instance.retrieve_memory_records.return_value = mock_response result = manager.search_long_term_memories( - query="test query", namespace_prefix="test/namespace", strategy_id="strategy-123" + query="test query", namespace_prefix="test/namespace/", strategy_id="strategy-123" ) assert result == [] @@ -1233,7 +1233,7 @@ def test_search_long_term_memories_client_error(self): ) with pytest.raises(ClientError): - manager.search_long_term_memories(query="invalid query", namespace_prefix="test/namespace") + manager.search_long_term_memories(query="invalid query", namespace_prefix="test/namespace/") def test_list_long_term_memory_records_success(self): """Test list_long_term_memory_records successful execution.""" @@ -1253,7 +1253,7 @@ def test_list_long_term_memory_records_success(self): {"memoryRecords": [{"memoryRecordId": "rec-1"}, {"memoryRecordId": "rec-2"}]} ] - result = manager.list_long_term_memory_records(namespace_prefix="test/namespace") + result = manager.list_long_term_memory_records(namespace_prefix="test/namespace/") assert len(result) == 2 assert all(isinstance(record, MemoryRecord) for record in result) @@ -1275,7 +1275,7 @@ def test_list_long_term_memory_records_with_strategy(self): mock_paginator.paginate.return_value = [{"memoryRecords": []}] result = manager.list_long_term_memory_records( - namespace_prefix="test/namespace", strategy_id="strategy-123" + namespace_prefix="test/namespace/", strategy_id="strategy-123" ) assert result == [] @@ -1303,7 +1303,7 @@ def test_list_long_term_memory_records_client_error(self): ) with pytest.raises(ClientError): - manager.list_long_term_memory_records(namespace_prefix="invalid/namespace") + manager.list_long_term_memory_records(namespace_prefix="invalid/namespace/") def test_list_actors_success(self): """Test list_actors successful execution.""" @@ -1449,7 +1449,7 @@ def test_delete_all_long_term_memories_in_namespace_success(self): } mock_client_instance.batch_delete_memory_records.return_value = mock_response - result = manager.delete_all_long_term_memories_in_namespace("test/namespace") + result = manager.delete_all_long_term_memories_in_namespace("test/namespace/") assert len(result["successfulRecords"]) == 2 assert len(result["failedRecords"]) == 0 @@ -1473,7 +1473,7 @@ def test_delete_all_long_term_memories_in_namespace_empty(self): # Mock empty list_long_term_memory_records with patch.object(manager, "list_long_term_memory_records", return_value=[]): - result = manager.delete_all_long_term_memories_in_namespace("empty/namespace") + result = manager.delete_all_long_term_memories_in_namespace("empty/namespace/") assert result == {"successfulRecords": [], "failedRecords": []} # Should not call batch_delete_memory_records @@ -1500,7 +1500,7 @@ def test_delete_all_long_term_memories_in_namespace_client_error(self): ) with pytest.raises(ClientError): - manager.delete_all_long_term_memories_in_namespace("test/namespace") + manager.delete_all_long_term_memories_in_namespace("test/namespace/") def test_delete_all_long_term_memories_in_namespace_over_100_records(self): """Test deleting more than 100 records in namespace.""" @@ -1525,7 +1525,7 @@ def test_delete_all_long_term_memories_in_namespace_over_100_records(self): }, ] - result = manager.delete_all_long_term_memories_in_namespace("test/namespace") + result = manager.delete_all_long_term_memories_in_namespace("test/namespace/") # Verify two batch calls were made assert mock_client_instance.batch_delete_memory_records.call_count == 2 @@ -1568,7 +1568,7 @@ def test_delete_all_long_term_memories_in_namespace_partial_failure(self): } mock_client_instance.batch_delete_memory_records.return_value = mock_response - result = manager.delete_all_long_term_memories_in_namespace("test/namespace") + result = manager.delete_all_long_term_memories_in_namespace("test/namespace/") assert len(result["successfulRecords"]) == 2 assert len(result["failedRecords"]) == 1 @@ -1848,10 +1848,10 @@ def test_session_search_long_term_memories_delegation(self): # Mock manager method mock_records = [MemoryRecord({"memoryRecordId": "rec-123"})] with patch.object(manager, "search_long_term_memories", return_value=mock_records) as mock_search: - result = session.search_long_term_memories(query="test query", namespace_prefix="test/namespace") + result = session.search_long_term_memories(query="test query", namespace_prefix="test/namespace/") assert result == mock_records - mock_search.assert_called_once_with("test query", "test/namespace", 3, None, 20) + mock_search.assert_called_once_with("test query", "test/namespace/", 3, None, 20) def test_session_list_long_term_memory_records_delegation(self): """Test MemorySession.list_long_term_memory_records delegates to manager.""" @@ -1864,10 +1864,10 @@ def test_session_list_long_term_memory_records_delegation(self): # Mock manager method mock_records = [MemoryRecord({"memoryRecordId": "rec-123"})] with patch.object(manager, "list_long_term_memory_records", return_value=mock_records) as mock_list: - result = session.list_long_term_memory_records(namespace_prefix="test/namespace") + result = session.list_long_term_memory_records(namespace_prefix="test/namespace/") assert result == mock_records - mock_list.assert_called_once_with("test/namespace", None, 10) + mock_list.assert_called_once_with("test/namespace/", None, 10) def test_session_list_actors_delegation(self): """Test MemorySession.list_actors delegates to manager.""" @@ -2019,7 +2019,7 @@ def mock_llm_callback(user_input: str, memories: List[Dict[str, Any]]) -> str: return "Response" # Test with custom retrieval config - retrieval_config = {"test/namespace": RetrievalConfig(top_k=5, retrieval_query="custom query")} + retrieval_config = {"test/namespace/": RetrievalConfig(top_k=5, retrieval_query="custom query")} manager.process_turn_with_llm( actor_id="user-123", session_id="session-456", @@ -2030,7 +2030,7 @@ def mock_llm_callback(user_input: str, memories: List[Dict[str, Any]]) -> str: # Verify custom query was used mock_search.assert_called_once_with( - query="custom query Hello", namespace_prefix="test/namespace", top_k=5 + query="custom query Hello", namespace_prefix="test/namespace/", top_k=5 ) def test_list_events_max_results_respected(self): @@ -2176,7 +2176,7 @@ def test_search_long_term_memories_without_strategy_id(self): mock_response = {"memoryRecordSummaries": []} mock_client_instance.retrieve_memory_records.return_value = mock_response - result = manager.search_long_term_memories(query="test query", namespace_prefix="test/namespace") + result = manager.search_long_term_memories(query="test query", namespace_prefix="test/namespace/") assert result == [] @@ -2200,7 +2200,7 @@ def test_list_long_term_memory_records_without_strategy_id(self): mock_client_instance.get_paginator.return_value = mock_paginator mock_paginator.paginate.return_value = [{"memoryRecords": []}] - result = manager.list_long_term_memory_records(namespace_prefix="test/namespace") + result = manager.list_long_term_memory_records(namespace_prefix="test/namespace/") assert result == [] @@ -2590,7 +2590,7 @@ def mock_llm_callback(user_input: str, memories: List[Dict[str, Any]]) -> str: return f"Response to: {user_input} with {len(memories)} memories" # Test process_turn_with_llm with metadata - retrieval_config = {"test/namespace": RetrievalConfig(top_k=5)} + retrieval_config = {"test/namespace/": RetrievalConfig(top_k=5)} metadata = {"location": {"stringValue": "NYC"}} memories, response, event = manager.process_turn_with_llm( @@ -2704,7 +2704,7 @@ def mock_llm_callback(user_input: str, memories: List[Dict[str, Any]]) -> str: return "Response" # Test with retrieval_config but no retrieval_query (should use user_input) - retrieval_config = {"test/namespace": RetrievalConfig(top_k=3, retrieval_query=None)} + retrieval_config = {"test/namespace/": RetrievalConfig(top_k=3, retrieval_query=None)} manager.process_turn_with_llm( actor_id="user-123", session_id="session-456", @@ -2714,7 +2714,7 @@ def mock_llm_callback(user_input: str, memories: List[Dict[str, Any]]) -> str: ) # Verify user_input was used as query - mock_search.assert_called_once_with(query="Hello", namespace_prefix="test/namespace", top_k=3) + mock_search.assert_called_once_with(query="Hello", namespace_prefix="test/namespace/", top_k=3) def test_add_turns_with_custom_timestamp(self): """Test add_turns with custom timestamp.""" @@ -2836,7 +2836,7 @@ def mock_llm_callback(user_input: str, memories: List[Dict[str, Any]]) -> str: return f"Response with {len(memories)} memories" # Test with relevance_score filtering (should filter out low relevance) - retrieval_config = {"test/namespace": RetrievalConfig(top_k=5, relevance_score=0.4)} + retrieval_config = {"test/namespace/": RetrievalConfig(top_k=5, relevance_score=0.4)} memories, response, event = manager.process_turn_with_llm( actor_id="user-123", session_id="session-456", @@ -3065,7 +3065,7 @@ def mock_llm_callback(user_input: str, memories: List[Dict[str, Any]]) -> str: return "Response" # Test with RetrievalConfig that has a very low relevance_score (effectively no filtering) - retrieval_config = {"test/namespace": RetrievalConfig(top_k=3, relevance_score=0.0)} + retrieval_config = {"test/namespace/": RetrievalConfig(top_k=3, relevance_score=0.0)} memories, response, event = manager.process_turn_with_llm( actor_id="user-123", session_id="session-456", @@ -3198,7 +3198,7 @@ def test_list_long_term_memory_records_memoryRecordSummaries_fallback(self): } ] - result = manager.list_long_term_memory_records(namespace_prefix="test/namespace") + result = manager.list_long_term_memory_records(namespace_prefix="test/namespace/") assert len(result) == 2 assert all(isinstance(record, MemoryRecord) for record in result) @@ -3572,7 +3572,7 @@ def test_search_long_term_memories_info_logging_on_client_error(self): with patch("bedrock_agentcore.memory.session.logger") as mock_logger: with pytest.raises(ClientError): - manager.search_long_term_memories(query="invalid query", namespace_prefix="test/namespace") + manager.search_long_term_memories(query="invalid query", namespace_prefix="test/namespace/") # Verify info logging was called (not error logging) mock_logger.info.assert_called_with(" ❌ Error querying long-term memory: %s", mock.ANY) @@ -3598,7 +3598,7 @@ def test_list_long_term_memory_records_multiple_pages(self): {"memoryRecords": [{"memoryRecordId": "rec-3"}, {"memoryRecordId": "rec-4"}]}, ] - result = manager.list_long_term_memory_records(namespace_prefix="test/namespace") + result = manager.list_long_term_memory_records(namespace_prefix="test/namespace/") assert len(result) == 4 assert all(isinstance(record, MemoryRecord) for record in result) diff --git a/tests_integ/memory/integrations/test_session_manager.py b/tests_integ/memory/integrations/test_session_manager.py index 218fbe4..7924d92 100644 --- a/tests_integ/memory/integrations/test_session_manager.py +++ b/tests_integ/memory/integrations/test_session_manager.py @@ -60,16 +60,16 @@ def test_memory_ltm(self, memory_client): { "summaryMemoryStrategy": { "name": "SessionSummarizer", - "namespaces": ["/summaries/{actorId}/{sessionId}"], + "namespaces": ["/summaries/{actorId}/{sessionId}/"], } }, { "userPreferenceMemoryStrategy": { "name": "PreferenceLearner", - "namespaces": ["/preferences/{actorId}"], + "namespaces": ["/preferences/{actorId}/"], } }, - {"semanticMemoryStrategy": {"name": "FactExtractor", "namespaces": ["/facts/{actorId}"]}}, + {"semanticMemoryStrategy": {"name": "FactExtractor", "namespaces": ["/facts/{actorId}/"]}}, ], ) yield memory @@ -129,7 +129,7 @@ def test_session_manager_with_retrieval_config_adds_context(self, test_memory_lt memory_id=test_memory_ltm["id"], session_id=f"test-session-{int(time.time())}", actor_id=f"test-actor-{int(time.time())}", - retrieval_config={"/preferences/{actorId}": RetrievalConfig(top_k=5, relevance_score=0.7)}, + retrieval_config={"/preferences/{actorId}/": RetrievalConfig(top_k=5, relevance_score=0.7)}, ) session_manager = AgentCoreMemorySessionManager(agentcore_memory_config=config, region_name=REGION) @@ -153,9 +153,9 @@ def test_multiple_namespace_retrieval_config(self, test_memory_ltm): session_id=f"test-session-{int(time.time())}", actor_id=f"test-actor-{int(time.time())}", retrieval_config={ - "/preferences/{actorId}": RetrievalConfig(top_k=5, relevance_score=0.7), - "/facts/{actorId}": RetrievalConfig(top_k=10, relevance_score=0.3), - "/summaries/{actorId}/{sessionId}": RetrievalConfig(top_k=5, relevance_score=0.5), + "/preferences/{actorId}/": RetrievalConfig(top_k=5, relevance_score=0.7), + "/facts/{actorId}/": RetrievalConfig(top_k=10, relevance_score=0.3), + "/summaries/{actorId}/{sessionId}/": RetrievalConfig(top_k=5, relevance_score=0.5), }, ) diff --git a/tests_integ/memory/test_devex.py b/tests_integ/memory/test_devex.py index 9a864a6..720d9b5 100644 --- a/tests_integ/memory/test_devex.py +++ b/tests_integ/memory/test_devex.py @@ -356,7 +356,7 @@ def save_with_retry(memory_id, actor_id, session_id, messages, branch=None, max_ logger.info("Waiting 30 seconds for extraction to trigger...") time.sleep(30) - namespace = "support/facts/%s" % session_id + namespace = "support/facts/%s/" % session_id if client.wait_for_memories(memory_id, namespace, max_wait=180): logger.info("✓ Memories extracted and indexed successfully") @@ -439,7 +439,7 @@ def test_bedrock_integration(client: MemoryClient, memory_id: str): # Retrieve relevant memories logger.info("\n4. Retrieving relevant context...") - namespace = "support/facts/%s" % session_id + namespace = "support/facts/%s/" % session_id memories = client.retrieve_memories(memory_id=memory_id, namespace=namespace, query=user_query, top_k=5) context = "" @@ -701,7 +701,7 @@ def main(): "semanticMemoryStrategy": { "name": "CustomerInfo", "description": "Extract customer information and issues", - "namespaces": ["support/facts/{sessionId}"], + "namespaces": ["support/facts/{sessionId}/"], # NO configuration block } }, @@ -709,7 +709,7 @@ def main(): "userPreferenceMemoryStrategy": { "name": "CustomerPreferences", "description": "Track customer preferences and history", - "namespaces": ["customers/{actorId}/preferences"], + "namespaces": ["customers/{actorId}/preferences/"], # NO configuration block } }, diff --git a/tests_integ/memory/test_memory_client.py b/tests_integ/memory/test_memory_client.py index 6fb69d7..a892dea 100644 --- a/tests_integ/memory/test_memory_client.py +++ b/tests_integ/memory/test_memory_client.py @@ -90,7 +90,7 @@ def test_strategy_polling_fix(client: MemoryClient): logger.info("\n2. Adding summary strategy with polling...") try: memory = client.add_summary_strategy_and_wait( - memory_id=memory_id, name="TestSummary", namespaces=["summaries/{sessionId}"] + memory_id=memory_id, name="TestSummary", namespaces=["summaries/{sessionId}/"] ) logger.info("✓ Added summary strategy, memory is %s", memory["status"]) except Exception as e: @@ -114,7 +114,7 @@ def test_strategy_polling_fix(client: MemoryClient): logger.info("\n4. Adding user preference strategy immediately...") try: memory = client.add_user_preference_strategy_and_wait( - memory_id=memory_id, name="TestPreferences", namespaces=["preferences/{actorId}"] + memory_id=memory_id, name="TestPreferences", namespaces=["preferences/{actorId}/"] ) logger.info("✓ Added user preference strategy without error, memory is %s", memory["status"]) except Exception as e: @@ -302,7 +302,7 @@ def test_namespace_wildcards(client: MemoryClient, memory_id: str): session_id = session_ids[0] # Assuming semantic strategy with pattern "test/{actorId}/{sessionId}" - exact_namespace = f"test/{actor_id}/{session_id}" + exact_namespace = f"test/{actor_id}/{session_id}/" logger.info("Trying exact namespace: %s", exact_namespace) memories = client.retrieve_memories(memory_id=memory_id, namespace=exact_namespace, query="specific keyword") @@ -362,7 +362,7 @@ def main(): { "semanticMemoryStrategy": { "name": "TestStrategy", - "namespaces": ["test/{actorId}/{sessionId}"], # Explicit namespace pattern + "namespaces": ["test/{actorId}/{sessionId}/"], # Explicit namespace pattern } } ],