3737 Role ,
3838 StrategyType ,
3939)
40- from .models .filters import EventMetadataFilter , MetadataValue
40+ from .models .filters import EventMetadataFilter , IndexedKey , MemoryMetadataFilter , MetadataValue
4141
4242logger = logging .getLogger (__name__ )
4343
@@ -160,8 +160,25 @@ def create_memory(
160160 event_expiry_days : int = 90 ,
161161 memory_execution_role_arn : Optional [str ] = None ,
162162 stream_delivery_resources : Optional [Dict [str , Any ]] = None ,
163+ indexed_keys : Optional [List [IndexedKey ]] = None ,
163164 ) -> Dict [str , Any ]:
164- """Create a memory with simplified configuration."""
165+ """Create a memory with simplified configuration.
166+
167+ Args:
168+ name: Name for the memory resource
169+ strategies: Optional list of strategy configurations
170+ description: Optional description
171+ event_expiry_days: How long to retain events (default: 90 days)
172+ memory_execution_role_arn: IAM role ARN for memory execution
173+ stream_delivery_resources: Optional delivery configuration for streaming memory records
174+ indexed_keys: Optional list of metadata keys to index for filtering.
175+ Each entry should have 'key' (str) and 'type' ('STRING', 'STRINGLIST', or 'NUMBER').
176+ Once declared, indexed keys cannot be removed.
177+ Example: [{"key": "priority", "type": "NUMBER"}, {"key": "agent_type", "type": "STRING"}]
178+
179+ Returns:
180+ Created memory object
181+ """
165182 if strategies is None :
166183 strategies = []
167184
@@ -184,6 +201,9 @@ def create_memory(
184201 if stream_delivery_resources is not None :
185202 params ["streamDeliveryResources" ] = stream_delivery_resources
186203
204+ if indexed_keys is not None :
205+ params ["indexedKeys" ] = indexed_keys
206+
187207 response = self .gmcp_client .create_memory (** params )
188208
189209 memory = response ["memory" ]
@@ -205,9 +225,21 @@ def create_or_get_memory(
205225 event_expiry_days : int = 90 ,
206226 memory_execution_role_arn : Optional [str ] = None ,
207227 stream_delivery_resources : Optional [Dict [str , Any ]] = None ,
228+ indexed_keys : Optional [List [IndexedKey ]] = None ,
208229 ) -> Dict [str , Any ]:
209230 """Create a memory resource or fetch the existing memory details if it already exists.
210231
232+ Args:
233+ name: Name for the memory resource
234+ strategies: Optional list of strategy configurations
235+ description: Optional description
236+ event_expiry_days: How long to retain events (default: 90 days)
237+ memory_execution_role_arn: IAM role ARN for memory execution
238+ stream_delivery_resources: Optional delivery configuration for streaming memory records
239+ indexed_keys: Optional list of metadata keys to index for filtering.
240+ Once declared, indexed keys cannot be removed; new keys can be added
241+ via `update_memory(addIndexedKeys=...)`.
242+
211243 Returns:
212244 Memory object, either newly created or existing
213245 """
@@ -219,6 +251,7 @@ def create_or_get_memory(
219251 event_expiry_days = event_expiry_days ,
220252 memory_execution_role_arn = memory_execution_role_arn ,
221253 stream_delivery_resources = stream_delivery_resources ,
254+ indexed_keys = indexed_keys ,
222255 )
223256 return memory
224257 except ClientError as e :
@@ -241,6 +274,7 @@ def create_memory_and_wait(
241274 event_expiry_days : int = 90 ,
242275 memory_execution_role_arn : Optional [str ] = None ,
243276 stream_delivery_resources : Optional [Dict [str , Any ]] = None ,
277+ indexed_keys : Optional [List [IndexedKey ]] = None ,
244278 max_wait : int = 300 ,
245279 poll_interval : int = 10 ,
246280 ) -> Dict [str , Any ]:
@@ -256,6 +290,10 @@ def create_memory_and_wait(
256290 event_expiry_days: How long to retain events (default: 90 days)
257291 memory_execution_role_arn: IAM role ARN for memory execution
258292 stream_delivery_resources: Optional delivery configuration for streaming memory records
293+ indexed_keys: Optional list of metadata keys to index for filtering.
294+ Each entry should have 'key' (str) and 'type' ('STRING', 'STRINGLIST', or 'NUMBER').
295+ Once declared, indexed keys cannot be removed; new keys can be added
296+ via `update_memory(addIndexedKeys=...)`.
259297 max_wait: Maximum seconds to wait (default: 300)
260298 poll_interval: Seconds between status checks (default: 10)
261299
@@ -274,6 +312,7 @@ def create_memory_and_wait(
274312 event_expiry_days = event_expiry_days ,
275313 memory_execution_role_arn = memory_execution_role_arn ,
276314 stream_delivery_resources = stream_delivery_resources ,
315+ indexed_keys = indexed_keys ,
277316 )
278317
279318 memory_id = memory .get ("memoryId" , memory .get ("id" )) # Handle both field names
@@ -318,6 +357,7 @@ def retrieve_memories(
318357 actor_id : Optional [str ] = None ,
319358 top_k : int = 3 ,
320359 namespace_path : Optional [str ] = None ,
360+ metadata_filters : Optional [List [MemoryMetadataFilter ]] = None ,
321361 ) -> List [Dict [str , Any ]]:
322362 """Retrieve relevant memories using exact match or hierarchical path prefix.
323363
@@ -330,15 +370,29 @@ def retrieve_memories(
330370 actor_id: Optional actor ID (deprecated, use namespace)
331371 top_k: Number of results to return
332372 namespace_path: Hierarchical path prefix (e.g., "/org/team/")
373+ metadata_filters: Optional list of metadata filter expressions to scope results.
374+ Use MemoryMetadataFilter.build_expression() to construct filters.
375+ The service accepts 1-5 filters. An empty list is treated as no filter.
376+ Example: [MemoryMetadataFilter.build_expression(
377+ MemoryRecordLeftExpression.build("priority"),
378+ MemoryRecordOperatorType.EQUALS_TO,
379+ MemoryRecordRightExpression.build_string("high"),
380+ )]
333381
334382 Returns:
335383 List of memory records. Returns an empty list if the namespace
336384 arguments are invalid (both provided, neither provided, or contain
337385 wildcards) or if the service call fails.
386+
387+ Raises:
388+ ValueError: If `metadata_filters` exceeds the service maximum of 5.
338389 """
339390 if query is None :
340391 raise TypeError ("retrieve_memories() missing required argument: 'query'" )
341392
393+ if metadata_filters is not None and len (metadata_filters ) > 5 :
394+ raise ValueError (f"metadata_filters supports a maximum of 5 expressions; received { len (metadata_filters )} ." )
395+
342396 try :
343397 ns_params = build_namespace_params (namespace , namespace_path )
344398 except ValueError as e :
@@ -348,8 +402,13 @@ def retrieve_memories(
348402 ns_value = namespace or namespace_path
349403
350404 try :
405+ search_criteria = {"searchQuery" : query , "topK" : top_k }
406+ if metadata_filters :
407+ search_criteria ["metadataFilters" ] = metadata_filters
408+ logger .debug ("Applying %d metadata filter(s)" , len (metadata_filters ))
409+
351410 response = self .gmdp_client .retrieve_memory_records (
352- memoryId = memory_id , searchCriteria = { "searchQuery" : query , "topK" : top_k } , ** ns_params
411+ memoryId = memory_id , searchCriteria = search_criteria , ** ns_params
353412 )
354413 memories = response .get ("memoryRecordSummaries" , [])
355414 logger .info ("Retrieved %d memories from namespace: %s" , len (memories ), ns_value )
0 commit comments