Skip to content

Commit 1de940d

Browse files
authored
Add trailing slash to namespace strings (#238)
1 parent 53a1baa commit 1de940d

13 files changed

Lines changed: 153 additions & 153 deletions

File tree

src/bedrock_agentcore/memory/README.md

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -186,7 +186,7 @@ session.add_turns([
186186
# Search long-term memories (after memory extraction has occurred)
187187
memories = session.search_long_term_memories(
188188
query="what food does the user like",
189-
namespace_prefix="/food/user-123",
189+
namespace_prefix="/food/user-123/",
190190
top_k=5
191191
)
192192

@@ -219,8 +219,8 @@ def my_llm(user_input: str, memories: List[Dict]) -> str:
219219

220220
# Configure memory retrieval with multiple namespaces
221221
retrieval_config = {
222-
"support/facts/{sessionId}": RetrievalConfig(top_k=5, relevance_score=0.3),
223-
"user/preferences/{actorId}": RetrievalConfig(top_k=3, relevance_score=0.5)
222+
"support/facts/{sessionId}/": RetrievalConfig(top_k=5, relevance_score=0.3),
223+
"user/preferences/{actorId}/": RetrievalConfig(top_k=3, relevance_score=0.5)
224224
}
225225

226226
# Process complete conversation turn with automatic memory integration
@@ -301,7 +301,7 @@ session2 = manager.create_memory_session(
301301
```python
302302
# List all memory records in a namespace
303303
records = session.list_long_term_memory_records(
304-
namespace_prefix="/user/preferences/user-123",
304+
namespace_prefix="/user/preferences/user-123/",
305305
max_results=20
306306
)
307307

@@ -327,7 +327,7 @@ Learn more here!: [Working example](metadata-workflow.ipynb)
327327
# Step 1: Retrieve relevant memories
328328
memories = session.search_long_term_memories(
329329
query="previous discussion",
330-
namespace_prefix="support/facts/session-456",
330+
namespace_prefix="support/facts/session-456/",
331331
top_k=5
332332
)
333333

src/bedrock_agentcore/memory/client.py

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -105,7 +105,7 @@ def __getattr__(self, name: str):
105105
client = MemoryClient()
106106
107107
# These calls are forwarded to the appropriate boto3 client
108-
response = client.list_memory_records(memoryId="mem-123", namespace="test")
108+
response = client.list_memory_records(memoryId="mem-123", namespace="test/")
109109
metadata = client.get_memory_metadata(memoryId="mem-123")
110110
"""
111111
if name in self._ALLOWED_GMDP_METHODS and hasattr(self.gmdp_client, name):
@@ -297,12 +297,12 @@ def retrieve_memories(
297297
# Correct - exact namespace
298298
memories = client.retrieve_memories(
299299
memory_id="mem-123",
300-
namespace="support/facts/session-456",
300+
namespace="support/facts/session-456/",
301301
query="customer preferences"
302302
)
303303
304304
# Incorrect - wildcards not supported
305-
# memories = client.retrieve_memories(..., namespace="support/facts/*", ...)
305+
# memories = client.retrieve_memories(..., namespace="support/facts/*/", ...)
306306
"""
307307
if "*" in namespace:
308308
logger.error("Wildcards are not supported in namespaces. Please provide exact namespace.")
@@ -745,7 +745,7 @@ def my_llm(user_input: str, memories: List[Dict]) -> str:
745745
session_id="session-456",
746746
user_input="What did we discuss yesterday?",
747747
llm_callback=my_llm,
748-
retrieval_namespace="support/facts/{sessionId}"
748+
retrieval_namespace="support/facts/{sessionId}/"
749749
)
750750
"""
751751
# Step 1: Retrieve relevant memories
@@ -1791,8 +1791,8 @@ def wait_for_memories(
17911791
existing memories in the namespace, this method may return True immediately
17921792
even if new extractions haven't completed.
17931793
2. Wildcards (*) are NOT supported in namespaces. You must provide the exact
1794-
namespace path with all variables resolved (e.g., "support/facts/session-123"
1795-
not "support/facts/*").
1794+
namespace path with all variables resolved (e.g., "support/facts/session-123/"
1795+
not "support/facts/*/").
17961796
17971797
For subsequent extractions in populated namespaces, use a fixed wait time:
17981798
time.sleep(150) # Wait 2.5 minutes for extraction
@@ -1964,7 +1964,7 @@ def _add_default_namespaces(self, strategies: List[Dict[str, Any]]) -> List[Dict
19641964

19651965
if "namespaces" not in strategy_config:
19661966
strategy_type = StrategyType(strategy_type_key)
1967-
strategy_config["namespaces"] = DEFAULT_NAMESPACES.get(strategy_type, ["custom/{actorId}/{sessionId}"])
1967+
strategy_config["namespaces"] = DEFAULT_NAMESPACES.get(strategy_type, ["custom/{actorId}/{sessionId}/"])
19681968

19691969
self._validate_strategy_config(strategy_copy, strategy_type_key)
19701970

src/bedrock_agentcore/memory/constants.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -73,10 +73,10 @@ class MessageRole(Enum):
7373

7474
# Default namespaces for each strategy type
7575
DEFAULT_NAMESPACES: Dict[StrategyType, List[str]] = {
76-
StrategyType.SEMANTIC: ["/strategies/{memoryStrategyId}/actors/{actorId}"],
77-
StrategyType.SUMMARY: ["/strategies/{memoryStrategyId}/actors/{actorId}/sessions/{sessionId}"],
78-
StrategyType.USER_PREFERENCE: ["/strategies/{memoryStrategyId}/actors/{actorId}"],
79-
StrategyType.EPISODIC: ["/strategies/{memoryStrategyId}/actors/{actorId}/sessions/{sessionId}"],
76+
StrategyType.SEMANTIC: ["/strategies/{memoryStrategyId}/actors/{actorId}/"],
77+
StrategyType.SUMMARY: ["/strategies/{memoryStrategyId}/actors/{actorId}/sessions/{sessionId}/"],
78+
StrategyType.USER_PREFERENCE: ["/strategies/{memoryStrategyId}/actors/{actorId}/"],
79+
StrategyType.EPISODIC: ["/strategies/{memoryStrategyId}/actors/{actorId}/sessions/{sessionId}/"],
8080
}
8181

8282

src/bedrock_agentcore/memory/integrations/strands/README.md

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -112,19 +112,19 @@ comprehensive_memory = client.create_memory_and_wait(
112112
{
113113
"summaryMemoryStrategy": {
114114
"name": "SessionSummarizer",
115-
"namespaces": ["/summaries/{actorId}/{sessionId}"]
115+
"namespaces": ["/summaries/{actorId}/{sessionId}/"]
116116
}
117117
},
118118
{
119119
"userPreferenceMemoryStrategy": {
120120
"name": "PreferenceLearner",
121-
"namespaces": ["/preferences/{actorId}"]
121+
"namespaces": ["/preferences/{actorId}/"]
122122
}
123123
},
124124
{
125125
"semanticMemoryStrategy": {
126126
"name": "FactExtractor",
127-
"namespaces": ["/facts/{actorId}"]
127+
"namespaces": ["/facts/{actorId}/"]
128128
}
129129
}
130130
]
@@ -143,7 +143,7 @@ config = AgentCoreMemoryConfig(
143143
session_id=SESSION_ID,
144144
actor_id=ACTOR_ID,
145145
retrieval_config={
146-
"/preferences/{actorId}": RetrievalConfig(
146+
"/preferences/{actorId}/": RetrievalConfig(
147147
top_k=5,
148148
relevance_score=0.7
149149
)
@@ -161,15 +161,15 @@ config = AgentCoreMemoryConfig(
161161
session_id=SESSION_ID,
162162
actor_id=ACTOR_ID,
163163
retrieval_config={
164-
"/preferences/{actorId}": RetrievalConfig(
164+
"/preferences/{actorId}/": RetrievalConfig(
165165
top_k=5,
166166
relevance_score=0.7
167167
),
168-
"/facts/{actorId}": RetrievalConfig(
168+
"/facts/{actorId}/": RetrievalConfig(
169169
top_k=10,
170170
relevance_score=0.3
171171
),
172-
"/summaries/{actorId}/{sessionId}": RetrievalConfig(
172+
"/summaries/{actorId}/{sessionId}/": RetrievalConfig(
173173
top_k=5,
174174
relevance_score=0.5
175175
)
@@ -233,9 +233,9 @@ https://docs.aws.amazon.com/bedrock-agentcore/latest/devguide/memory-strategies.
233233

234234
### Namespace Patterns
235235

236-
- `/preferences/{actorId}`: User-specific preferences
237-
- `/facts/{actorId}`: User-specific facts
238-
- `/summaries/{actorId}/{sessionId}`: Session-specific summaries
236+
- `/preferences/{actorId}/`: User-specific preferences
237+
- `/facts/{actorId}/`: User-specific facts
238+
- `/summaries/{actorId}/{sessionId}/`: Session-specific summaries
239239

240240

241241
---

src/bedrock_agentcore/memory/session.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -72,7 +72,7 @@ def my_llm(user_input: str, memories: List[Dict]) -> str:
7272
session_id="session-789",
7373
user_input="What did we discuss?",
7474
llm_callback=my_llm,
75-
retrieval_namespace="support/facts/{sessionId}"
75+
retrieval_namespace="support/facts/{sessionId}/"
7676
)
7777
```
7878
@@ -298,8 +298,8 @@ def my_llm(user_input: str, memories: List[Dict]) -> str:
298298
return response['content']
299299
300300
retrieval_config = {
301-
"support/facts/{sessionId}": RetrievalConfig(top_k=5, relevance_score=0.3),
302-
"user/preferences/{actorId}": RetrievalConfig(top_k=3, relevance_score=0.5)
301+
"support/facts/{sessionId}/": RetrievalConfig(top_k=5, relevance_score=0.3),
302+
"user/preferences/{actorId}/": RetrievalConfig(top_k=3, relevance_score=0.5)
303303
}
304304
305305
memories, response, event = manager.process_turn_with_llm(

tests/bedrock_agentcore/memory/integrations/strands/test_agentcore_memory_session_manager.py

Lines changed: 35 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -25,8 +25,8 @@ def agentcore_config():
2525
def agentcore_config_with_retrieval():
2626
"""Create a test AgentCore Memory configuration with retrieval config."""
2727
retrieval_config = {
28-
"user_preferences/{actorId}": RetrievalConfig(top_k=5, relevance_score=0.3),
29-
"session_context/{sessionId}": RetrievalConfig(top_k=3, relevance_score=0.5),
28+
"user_preferences/{actorId}/": RetrievalConfig(top_k=5, relevance_score=0.3),
29+
"session_context/{sessionId}/": RetrievalConfig(top_k=3, relevance_score=0.5),
3030
}
3131
return AgentCoreMemoryConfig(
3232
memory_id="test-memory-123",
@@ -471,17 +471,17 @@ def test_validate_namespace_resolution(self, session_manager):
471471

472472
# Valid resolution
473473
assert session_manager._validate_namespace_resolution(
474-
"user_preferences/{actorId}", "user_preferences/test-actor"
474+
"user_preferences/{actorId}/", "user_preferences/test-actor/"
475475
)
476476

477477
# Mock invalid resolution
478478
session_manager._validate_namespace_resolution.return_value = False
479479
assert not session_manager._validate_namespace_resolution(
480-
"user_preferences/{actorId}", "user_preferences/{actorId}"
480+
"user_preferences/{actorId}/", "user_preferences/{actorId}/"
481481
)
482482

483483
# Invalid - empty result
484-
assert not session_manager._validate_namespace_resolution("test_namespace", "")
484+
assert not session_manager._validate_namespace_resolution("test_namespace/", "")
485485

486486
def test_load_long_term_memories_with_validation_failure(self, mock_memory_client, test_agent):
487487
"""Test LTM loading with namespace validation failure."""
@@ -490,7 +490,7 @@ def test_load_long_term_memories_with_validation_failure(self, mock_memory_clien
490490
memory_id="test-memory-123",
491491
session_id="test-session-456",
492492
actor_id="test-actor",
493-
retrieval_config={"user_preferences/{invalidVar}": RetrievalConfig(top_k=5, relevance_score=0.3)},
493+
retrieval_config={"user_preferences/{invalidVar}/": RetrievalConfig(top_k=5, relevance_score=0.3)},
494494
)
495495

496496
with patch(
@@ -563,23 +563,23 @@ def mock_generate_query(namespace, config, agent):
563563

564564
# Test preferences namespace
565565
config = RetrievalConfig(top_k=5, relevance_score=0.3)
566-
query = session_manager._generate_initialization_query("user_preferences/{actorId}", config, test_agent)
566+
query = session_manager._generate_initialization_query("user_preferences/{actorId}/", config, test_agent)
567567
assert query == "user preferences settings"
568568

569569
# Test context namespace
570-
query = session_manager._generate_initialization_query("session_context/{sessionId}", config, test_agent)
570+
query = session_manager._generate_initialization_query("session_context/{sessionId}/", config, test_agent)
571571
assert query == "conversation context history"
572572

573573
# Test semantic namespace
574-
query = session_manager._generate_initialization_query("semantic_knowledge", config, test_agent)
574+
query = session_manager._generate_initialization_query("semantic_knowledge/", config, test_agent)
575575
assert query == "facts knowledge information"
576576

577577
# Test facts namespace
578-
query = session_manager._generate_initialization_query("facts_database", config, test_agent)
578+
query = session_manager._generate_initialization_query("facts_database/", config, test_agent)
579579
assert query == "facts knowledge information"
580580

581581
# Test fallback
582-
query = session_manager._generate_initialization_query("unknown_namespace", config, test_agent)
582+
query = session_manager._generate_initialization_query("unknown_namespace/", config, test_agent)
583583
assert query == "context preferences facts"
584584

585585
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)
589589
# Mock the method since it doesn't exist yet
590590
session_manager._generate_initialization_query = Mock(return_value="custom query for testing")
591591

592-
query = session_manager._generate_initialization_query("user_preferences/{actorId}", config, test_agent)
592+
query = session_manager._generate_initialization_query("user_preferences/{actorId}/", config, test_agent)
593593
assert query == "custom query for testing"
594594

595595
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
617617
manager.retrieve_contextual_memories = Mock(
618618
return_value=[
619619
{
620-
"namespace": "user_preferences/test-actor-789",
620+
"namespace": "user_preferences/test-actor-789/",
621621
"memories": [{"content": "Relevant memory", "relevanceScore": 0.8}],
622622
},
623623
{
624-
"namespace": "session_context/test-session-456",
624+
"namespace": "session_context/test-session-456/",
625625
"memories": [{"content": "Less relevant memory", "relevanceScore": 0.2}],
626626
},
627627
]
@@ -657,13 +657,13 @@ def test_retrieve_contextual_memories_specific_namespaces(
657657
manager.retrieve_contextual_memories = Mock(
658658
return_value=[
659659
{
660-
"namespace": "user_preferences/test-actor-789",
660+
"namespace": "user_preferences/test-actor-789/",
661661
"memories": [{"content": "User preference memory", "relevanceScore": 0.9}],
662662
}
663663
]
664664
)
665665
results = manager.retrieve_contextual_memories(
666-
"What are my preferences?", namespaces=["user_preferences/{actorId}"]
666+
"What are my preferences?", namespaces=["user_preferences/{actorId}/"]
667667
)
668668

669669
# Should return results for specified namespace only
@@ -695,7 +695,7 @@ def test_retrieve_contextual_memories_invalid_namespace(self, agentcore_config_w
695695
):
696696
manager = AgentCoreMemorySessionManager(agentcore_config_with_retrieval)
697697
manager.retrieve_contextual_memories = Mock(return_value={})
698-
results = manager.retrieve_contextual_memories("test query", namespaces=["nonexistent_namespace"])
698+
results = manager.retrieve_contextual_memories("test query", namespaces=["nonexistent_namespace/"])
699699

700700
# Should return empty results
701701
assert results == {}
@@ -755,27 +755,27 @@ def test_load_long_term_memories_exception_handling(
755755
def test_namespace_variable_resolution(self, session_manager):
756756
"""Test namespace variable resolution with various combinations."""
757757
# Test basic variable resolution
758-
namespace = "user_preferences/{actorId}"
758+
namespace = "user_preferences/{actorId}/"
759759
resolved = namespace.format(
760760
actorId=session_manager.config.actor_id, sessionId=session_manager.config.session_id, memoryStrategyId=""
761761
)
762-
assert resolved == "user_preferences/test-actor-789"
762+
assert resolved == "user_preferences/test-actor-789/"
763763

764764
# Test multiple variables
765-
namespace = "context/{sessionId}/actor/{actorId}"
765+
namespace = "context/{sessionId}/actor/{actorId}/"
766766
resolved = namespace.format(
767767
actorId=session_manager.config.actor_id, sessionId=session_manager.config.session_id, memoryStrategyId=""
768768
)
769-
assert resolved == "context/test-session-456/actor/test-actor-789"
769+
assert resolved == "context/test-session-456/actor/test-actor-789/"
770770

771771
# Test with strategy ID
772-
namespace = "strategy/{memoryStrategyId}/user/{actorId}"
772+
namespace = "strategy/{memoryStrategyId}/user/{actorId}/"
773773
resolved = namespace.format(
774774
actorId=session_manager.config.actor_id,
775775
sessionId=session_manager.config.session_id,
776776
memoryStrategyId="test_strategy",
777777
)
778-
assert resolved == "strategy/test_strategy/user/test-actor-789"
778+
assert resolved == "strategy/test_strategy/user/test-actor-789/"
779779

780780
def test_generate_initialization_query_patterns(self, session_manager, test_agent):
781781
"""Test initialization query generation with various namespace patterns."""
@@ -796,17 +796,17 @@ def mock_generate_query(namespace, config, agent):
796796

797797
# Test various preference patterns
798798
patterns_and_expected = [
799-
("user_preferences/{actorId}", "user preferences settings"),
800-
("preferences/global", "user preferences settings"),
801-
("my_preferences", "user preferences settings"),
802-
("session_context/{sessionId}", "conversation context history"),
803-
("context/history", "conversation context history"),
804-
("conversation_context", "conversation context history"),
805-
("semantic_memory", "facts knowledge information"),
806-
("facts_database", "facts knowledge information"),
807-
("knowledge_semantic", "facts knowledge information"),
808-
("random_namespace", "context preferences facts"),
809-
("unknown", "context preferences facts"),
799+
("user_preferences/{actorId}/", "user preferences settings"),
800+
("preferences/global/", "user preferences settings"),
801+
("my_preferences/", "user preferences settings"),
802+
("session_context/{sessionId}/", "conversation context history"),
803+
("context/history/", "conversation context history"),
804+
("conversation_context/", "conversation context history"),
805+
("semantic_memory/", "facts knowledge information"),
806+
("facts_database/", "facts knowledge information"),
807+
("knowledge_semantic/", "facts knowledge information"),
808+
("random_namespace/", "context preferences facts"),
809+
("unknown/", "context preferences facts"),
810810
]
811811

812812
for namespace, expected_query in patterns_and_expected:
@@ -1063,7 +1063,7 @@ def test_retrieve_customer_context_filters_by_relevance_score(self, mock_memory_
10631063
memory_id="test-memory-123",
10641064
session_id="test-session-456",
10651065
actor_id="test-actor-789",
1066-
retrieval_config={"test_namespace": RetrievalConfig(top_k=10, relevance_score=0.5)},
1066+
retrieval_config={"test_namespace/": RetrievalConfig(top_k=10, relevance_score=0.5)},
10671067
)
10681068

10691069
with patch(

tests/bedrock_agentcore/memory/models/test_models.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -131,7 +131,7 @@ def test_memory_record_initialization(self):
131131
data = {
132132
"memoryRecordId": "record-123",
133133
"content": {"text": "This is a memory record"},
134-
"namespace": "user/preferences",
134+
"namespace": "user/preferences/",
135135
"relevanceScore": 0.95,
136136
"createdAt": "2023-01-01T00:00:00Z",
137137
}
@@ -144,7 +144,7 @@ def test_memory_record_initialization(self):
144144

145145
def test_memory_record_dict_access(self):
146146
"""Test MemoryRecord dictionary-like access."""
147-
data = {"memoryRecordId": "record-456", "namespace": "support/facts"}
147+
data = {"memoryRecordId": "record-456", "namespace": "support/facts/"}
148148
memory_record = MemoryRecord(data)
149149

150150
assert "memoryRecordId" in memory_record

0 commit comments

Comments
 (0)