From f827807e934ed7e7c0f1a50603e1175de7d67c60 Mon Sep 17 00:00:00 2001 From: Valter Silva Date: Sat, 27 Jun 2026 15:51:44 +0800 Subject: [PATCH] fix(memory): type EventMetadataFilter.operator as str `EventMetadataFilter.build_expression` stores `operator.value` (the operator's string, e.g. "EQUALS_TO") in the returned dict, but the TypedDict annotated `operator` as the `OperatorType` enum. Every constructed filter therefore mis-typed the field, contradicting the runtime value that is serialized to the AgentCore service. Annotate `operator` as `str`, matching the sibling `MemoryMetadataFilter` which already documents and types this the same way. Add the first unit tests for `EventMetadataFilter` (the type previously had none), covering the field annotation and `build_expression` for both a value operator and an existence operator. Fixes #240 --- .../memory/models/filters.py | 4 +- .../memory/models/test_filters.py | 45 +++++++++++++++++++ 2 files changed, 48 insertions(+), 1 deletion(-) diff --git a/src/bedrock_agentcore/memory/models/filters.py b/src/bedrock_agentcore/memory/models/filters.py index 88bd48c3..5e677fca 100644 --- a/src/bedrock_agentcore/memory/models/filters.py +++ b/src/bedrock_agentcore/memory/models/filters.py @@ -86,7 +86,9 @@ class EventMetadataFilter(TypedDict): """ left: LeftExpression - operator: OperatorType + # Stored as the operator's string value (e.g. "EQUALS_TO"), not the enum itself, + # since this dict is serialized directly to the AgentCore service. + operator: str right: Optional[RightExpression] def build_expression( diff --git a/tests/bedrock_agentcore/memory/models/test_filters.py b/tests/bedrock_agentcore/memory/models/test_filters.py index 4e6ceeed..5398955c 100644 --- a/tests/bedrock_agentcore/memory/models/test_filters.py +++ b/tests/bedrock_agentcore/memory/models/test_filters.py @@ -1,19 +1,64 @@ """Unit tests for memory record metadata filter models.""" from datetime import datetime +from typing import get_type_hints import pytest from bedrock_agentcore.memory.models import ( + EventMetadataFilter, IndexedKey, + LeftExpression, MemoryMetadataFilter, MemoryRecordLeftExpression, MemoryRecordOperatorType, MemoryRecordRightExpression, MetadataValueType, + OperatorType, + RightExpression, ) +class TestEventMetadataFilter: + """Test cases for EventMetadataFilter.""" + + def test_operator_is_annotated_as_str(self): + """The stored `operator` is the enum's string value, so the field is typed `str`. + + Regression for #240: `build_expression` stores `operator.value` (a string), + but the field was annotated `OperatorType` (the enum), which mis-typed every + constructed filter. This mirrors the already-correct `MemoryMetadataFilter`. + """ + assert get_type_hints(EventMetadataFilter)["operator"] is str + + def test_build_expression_equals_string(self): + """build_expression stores the operator's string value, not the enum.""" + result = EventMetadataFilter.build_expression( + LeftExpression.build("location"), + OperatorType.EQUALS_TO, + RightExpression.build("NYC"), + ) + + assert result == { + "left": {"metadataKey": "location"}, + "operator": "EQUALS_TO", + "right": {"metadataValue": {"stringValue": "NYC"}}, + } + + def test_build_expression_exists_no_right_operand(self): + """An EXISTS filter omits the right operand.""" + result = EventMetadataFilter.build_expression( + LeftExpression.build("location"), + OperatorType.EXISTS, + ) + + assert result == { + "left": {"metadataKey": "location"}, + "operator": "EXISTS", + } + assert "right" not in result + + class TestMemoryRecordLeftExpression: """Test cases for MemoryRecordLeftExpression."""