From 68b0959393bcec58c4d5f1c445455b2aead8bc17 Mon Sep 17 00:00:00 2001 From: Taylor Jones Date: Tue, 27 Jan 2026 14:25:53 -0600 Subject: [PATCH 1/4] python(feat): Adds support for configuring live rules --- .../telemetry_config.py | 2 +- .../_tests/resources/test_rules.py | 146 ++++++++++++++++++ python/lib/sift_client/sift_types/rule.py | 3 + python/lib/sift_py/rule/_service_test.py | 73 +++++++++ python/lib/sift_py/rule/config.py | 10 +- python/lib/sift_py/rule/service.py | 5 +- 6 files changed, 231 insertions(+), 8 deletions(-) diff --git a/python/examples/ingestion_with_python_config/telemetry_config.py b/python/examples/ingestion_with_python_config/telemetry_config.py index 62c16b816..fa985609c 100644 --- a/python/examples/ingestion_with_python_config/telemetry_config.py +++ b/python/examples/ingestion_with_python_config/telemetry_config.py @@ -81,7 +81,7 @@ def nostromos_lv_426() -> TelemetryConfig: FlowConfig(name="logs", channels=[log_channel]), ], rules=[ - # Add `is_live=True` if you want these rules to run on live data. + # Add `is_live_evaluation_enabled=True` if you want these rules to run on live data. RuleConfig( name="overheating", description="Checks for vehicle overheating", diff --git a/python/lib/sift_client/_tests/resources/test_rules.py b/python/lib/sift_client/_tests/resources/test_rules.py index d870e3a2a..340f20e39 100644 --- a/python/lib/sift_client/_tests/resources/test_rules.py +++ b/python/lib/sift_client/_tests/resources/test_rules.py @@ -321,6 +321,88 @@ async def test_create_rule_with_dict(self, rules_api_async): finally: await rules_api_async.archive(created_rule) + @pytest.mark.asyncio + async def test_create_rule_with_live_evaluation_enabled_true(self, rules_api_async): + """Test creating a rule with is_live_evaluation_enabled=True.""" + from datetime import datetime, timezone + + rule_name = f"test_rule_live_true_{datetime.now(timezone.utc).isoformat()}" + description = "Test rule with live evaluation enabled" + + channels = await rules_api_async.client.async_.channels.list_(limit=2) + assert len(channels) >= 2 + + assets = await rules_api_async.client.async_.assets.list_(limit=1) + assert len(assets) >= 1 + + rule_create = RuleCreate( + name=rule_name, + description=description, + expression="$1 > $2", + channel_references=[ + ChannelReference(channel_reference="$1", channel_identifier=channels[0].name), + ChannelReference(channel_reference="$2", channel_identifier=channels[1].name), + ], + action=RuleAction.annotation( + annotation_type=RuleAnnotationType.DATA_REVIEW, + tags=[], + ), + asset_ids=[assets[0]._id_or_error], + is_live_evaluation_enabled=True, + ) + + created_rule = await rules_api_async.create(rule_create) + + try: + assert created_rule is not None + assert created_rule.is_live_evaluation_enabled + # Verify by fetching the rule again + fetched_rule = await rules_api_async.get(rule_id=created_rule.id_) + assert fetched_rule.is_live_evaluation_enabled + finally: + await rules_api_async.archive(created_rule) + + @pytest.mark.asyncio + async def test_create_rule_with_live_evaluation_enabled_false(self, rules_api_async): + """Test creating a rule with is_live_evaluation_enabled=False.""" + from datetime import datetime, timezone + + rule_name = f"test_rule_live_false_{datetime.now(timezone.utc).isoformat()}" + description = "Test rule with live evaluation disabled" + + channels = await rules_api_async.client.async_.channels.list_(limit=2) + assert len(channels) >= 2 + + assets = await rules_api_async.client.async_.assets.list_(limit=1) + assert len(assets) >= 1 + + rule_create = RuleCreate( + name=rule_name, + description=description, + expression="$1 > $2", + channel_references=[ + ChannelReference(channel_reference="$1", channel_identifier=channels[0].name), + ChannelReference(channel_reference="$2", channel_identifier=channels[1].name), + ], + action=RuleAction.annotation( + annotation_type=RuleAnnotationType.DATA_REVIEW, + tags=[], + ), + asset_ids=[assets[0]._id_or_error], + is_live_evaluation_enabled=False, + ) + + created_rule = await rules_api_async.create(rule_create) + + try: + assert created_rule is not None + assert not created_rule.is_live_evaluation_enabled + # Verify by fetching the rule again + fetched_rule = await rules_api_async.get(rule_id=created_rule.id_) + assert not fetched_rule.is_live_evaluation_enabled + finally: + await rules_api_async.archive(created_rule) + class TestUpdate: """Tests for the async update method.""" @@ -368,6 +450,70 @@ async def test_update_with_dict(self, rules_api_async, new_rule): finally: await rules_api_async.archive(new_rule.id_) + @pytest.mark.asyncio + async def test_update_rule_live_evaluation_enabled(self, rules_api_async, new_rule): + """Test updating a rule's is_live_evaluation_enabled field.""" + from datetime import datetime, timezone + + try: + # First, create a rule with is_live_evaluation_enabled=False + rule_name = f"test_rule_update_live_{datetime.now(timezone.utc).isoformat()}" + channels = await rules_api_async.client.async_.channels.list_(limit=2) + assets = await rules_api_async.client.async_.assets.list_(limit=1) + + rule_create = RuleCreate( + name=rule_name, + description="Test rule for updating live evaluation", + expression="$1 > $2", + channel_references=[ + ChannelReference( + channel_reference="$1", channel_identifier=channels[0].name + ), + ChannelReference( + channel_reference="$2", channel_identifier=channels[1].name + ), + ], + action=RuleAction.annotation( + annotation_type=RuleAnnotationType.DATA_REVIEW, + tags=[], + ), + asset_ids=[assets[0]._id_or_error], + is_live_evaluation_enabled=False, + ) + + created_rule = await rules_api_async.create(rule_create) + + # Verify initial state + assert created_rule.is_live_evaluation_enabled is False + + # Update to enable live evaluation + update = RuleUpdate(is_live_evaluation_enabled=True) + updated_rule = await rules_api_async.update(created_rule, update) + + assert updated_rule.id_ == created_rule.id_ + assert updated_rule.is_live_evaluation_enabled is True + # Verify by fetching the rule again + fetched_rule = await rules_api_async.get(rule_id=updated_rule.id_) + assert fetched_rule.is_live_evaluation_enabled is True + + # Update back to disable live evaluation + update = RuleUpdate(is_live_evaluation_enabled=False) + updated_rule = await rules_api_async.update(created_rule, update) + + assert updated_rule.is_live_evaluation_enabled is False + # Verify by fetching the rule again + fetched_rule = await rules_api_async.get(rule_id=updated_rule.id_) + assert fetched_rule.is_live_evaluation_enabled is False + + await rules_api_async.archive(created_rule) + except Exception: + # Clean up if something goes wrong + try: + await rules_api_async.archive(created_rule) + except Exception: + pass + raise + @pytest.mark.asyncio async def test_update_with_id_string(self, rules_api_async, new_rule): """Test updating a rule by passing ID as string.""" diff --git a/python/lib/sift_client/sift_types/rule.py b/python/lib/sift_client/sift_types/rule.py index 5713f0b7a..0ea59a66c 100644 --- a/python/lib/sift_client/sift_types/rule.py +++ b/python/lib/sift_client/sift_types/rule.py @@ -64,6 +64,7 @@ class Rule(BaseType[RuleProto, "Rule"]): client_key: str | None rule_version: RuleVersion | None archived_date: datetime | None + is_live_evaluation_enabled: bool | None = None @property def assets(self) -> list[Asset]: @@ -153,6 +154,7 @@ def _from_proto(cls, proto: RuleProto, sift_client: SiftClient | None = None) -> ), is_archived=proto.is_archived, is_external=proto.is_external, + is_live_evaluation_enabled=proto.is_live_evaluation_enabled, _client=sift_client, ) @@ -166,6 +168,7 @@ class RuleCreateUpdateBase(ModelCreateUpdateBase): asset_tag_ids: list[str] | None = None contextual_channels: list[str] | None = None is_external: bool = False + is_live_evaluation_enabled: bool | None = None class RuleCreate(RuleCreateUpdateBase, ModelCreate[CreateRuleRequest]): diff --git a/python/lib/sift_py/rule/_service_test.py b/python/lib/sift_py/rule/_service_test.py index f33ee58ae..e97130037 100644 --- a/python/lib/sift_py/rule/_service_test.py +++ b/python/lib/sift_py/rule/_service_test.py @@ -292,3 +292,76 @@ def test_rule_service_load_rules_from_yaml_with_contextual_channels(rule_service assert len(rule_config.contextual_channels) == 2 assert rule_config.contextual_channels[0] == "humidity" assert rule_config.contextual_channels[1] == "pressure" + + +def test_rule_service_create_rule_with_is_live_evaluation_enabled(rule_service): + """Test creating a rule with is_live_evaluation_enabled""" + rule = RuleConfig( + name="rule", + rule_client_key="rule-client-key", + channel_references=[ + { + "channel_reference": "$1", + "channel_config": ChannelConfig( + name="temperature", + data_type=ChannelDataType.DOUBLE, + ), + } + ], + is_live_evaluation_enabled=True, + expression="$1 > 10", + action=RuleActionCreateDataReviewAnnotation(), + ) + + with mock.patch.object(RuleService, "_create_rule") as mock_create_rule: + rule_service.create_or_update_rule(rule) + mock_create_rule.assert_called_once_with(rule) + created_rule = mock_create_rule.call_args[0][0] + assert created_rule.is_live_evaluation_enabled + + +def test_rule_service_load_rules_from_yaml_with_is_live_evaluation_enabled(rule_service): + """Test loading rules from YAML with is_live_evaluation_enabled""" + rule_yaml = { + "name": "rule", + "rule_client_key": "rule-client-key", + "channel_references": [{"$1": "temperature"}], + "contextual_channels": ["humidity", "pressure"], + "description": "description", + "expression": "$1 > 0", + "type": "review", + "asset_names": ["asset"], + "is_live_evaluation_enabled": True, + } + + with mock.patch.object(RuleService, "create_or_update_rule"): + with mock.patch( + "sift_py.rule.service.load_rule_modules", + return_value=[rule_yaml], + ): + rule_configs = rule_service.load_rules_from_yaml(["path/to/rules.yml"]) + assert len(rule_configs) == 1 + + rule_config = rule_configs[0] + assert rule_config.is_live_evaluation_enabled + + +def test_rule_service_update_rule_with_is_live_evaluation_enabled(rule_service): + """Test updating a rule with is_live_evaluation_enabled""" + rule = RuleConfig( + name="rule", + rule_client_key="rule-client-key", + is_live_evaluation_enabled=True, + channel_references=[], + ) + + with mock.patch.object(RuleService, "_update_rule") as mock_update_rule: + with mock.patch.object( + RuleService, "_get_rule_from_client_key", return_value=Rule(name=rule.name) + ) as mock_get_rule_from_client_key: + rule_service.create_or_update_rule(rule) + mock_get_rule_from_client_key.assert_called_once_with(rule.rule_client_key) + mock_update_rule.assert_called_once() + + updated_rule = mock_update_rule.call_args[0][0] + assert updated_rule.is_live_evaluation_enabled diff --git a/python/lib/sift_py/rule/config.py b/python/lib/sift_py/rule/config.py index 5729c4d0a..d2cad7d60 100644 --- a/python/lib/sift_py/rule/config.py +++ b/python/lib/sift_py/rule/config.py @@ -27,7 +27,7 @@ class RuleConfig(AsJson): - `tag_names`: A list of asset tags that this rule should be applied to. ONLY VALID if defining rules outside of a telemetry config. - `contextual_channels`: A list of channel names that provide context but aren't directly used in the expression. - `is_external`: If this is an external rule. - - `is_live`: If set to True then this rule will be evaluated on live data, otherwise live rule evaluation will be disabled. + - `is_live_evaluation_enabled`: If set to True then this rule will be evaluated on live data, otherwise live rule evaluation will be disabled. This rule can still be used, however, in report generation. """ @@ -41,7 +41,7 @@ class RuleConfig(AsJson): tag_names: List[str] contextual_channels: List[str] is_external: bool - is_live: bool + is_live_evaluation_enabled: bool _rule_id: Optional[str] # Allow passing of rule_id when existing config retrieved from API def __init__( @@ -59,7 +59,7 @@ def __init__( sub_expressions: Dict[str, Any] = {}, contextual_channels: Optional[List[str]] = None, is_external: bool = False, - is_live: bool = False, + is_live_evaluation_enabled: bool = False, ): self.channel_references = _channel_references_from_dicts(channel_references) self.contextual_channels = contextual_channels or [] @@ -72,7 +72,7 @@ def __init__( self.description = description self.expression = self.__class__.interpolate_sub_expressions(expression, sub_expressions) self.is_external = is_external - self.is_live = is_live + self.is_live_evaluation_enabled = is_live_evaluation_enabled self._rule_id = None def as_json(self) -> Any: @@ -90,7 +90,7 @@ def as_json(self) -> Any: "description": self.description, "expression": self.expression, "is_external": self.is_external, - "is_live": self.is_live, + "is_live_evaluation_enabled": self.is_live_evaluation_enabled, } hash_map["expression_channel_references"] = self.channel_references diff --git a/python/lib/sift_py/rule/service.py b/python/lib/sift_py/rule/service.py index 56d4f137e..76dd965b2 100644 --- a/python/lib/sift_py/rule/service.py +++ b/python/lib/sift_py/rule/service.py @@ -252,7 +252,7 @@ def _parse_rules_from_yaml( tag_names=rule_yaml.get("tag_names", []), sub_expressions=subexpr, is_external=rule_yaml.get("is_external", False), - is_live=rule_yaml.get("is_live", False), + is_live_evaluation_enabled=rule_yaml.get("is_live_evaluation_enabled", False), ) ) @@ -549,7 +549,7 @@ def _update_req_from_rule_config( ), contextual_channels=ContextualChannels(channels=contextual_channel_names), is_external=config.is_external, - is_live_evaluation_enabled=config.is_live, + is_live_evaluation_enabled=config.is_live_evaluation_enabled, ) def get_rule(self, rule: str) -> Optional[RuleConfig]: @@ -617,6 +617,7 @@ def get_rule(self, rule: str) -> Optional[RuleConfig]: tag_names=asset_tag_names, action=action, expression=expression, + is_live_evaluation_enabled=rule_pb.is_live_evaluation_enabled, ) # rule_id currently required for an existing rule From 2ecd47c0a1235d14bc3921ed8e69082e7468bca8 Mon Sep 17 00:00:00 2001 From: Taylor Jones Date: Tue, 27 Jan 2026 16:10:09 -0600 Subject: [PATCH 2/4] Fix yaml rule --- python/lib/sift_py/yaml/rule.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/python/lib/sift_py/yaml/rule.py b/python/lib/sift_py/yaml/rule.py index e2220eb9b..0a3f1e34e 100644 --- a/python/lib/sift_py/yaml/rule.py +++ b/python/lib/sift_py/yaml/rule.py @@ -271,7 +271,7 @@ class RuleYamlSpec(TypedDict): `asset_names`: A list of asset names that this rule should be applied to. ONLY VALID if defining rules outside of a telemetry config. `tag_names`: A list of tag names that this rule should be applied to. ONLY VALID if defining rules outside of a telemetry config. `is_external`: If this is an external rule. - `is_live`: If set to True then this rule will be evaluated on live data, otherwise live rule evaluation will be disabled. + `is_live_evaluation_enabled`: If set to True then this rule will be evaluated on live data, otherwise live rule evaluation will be disabled. This rule can still be used, however, in report generation. Channel references: @@ -330,7 +330,7 @@ class RuleYamlSpec(TypedDict): asset_names: NotRequired[List[str]] tag_names: NotRequired[List[str]] is_external: NotRequired[bool] - is_live: NotRequired[bool] + is_live_evaluation_enabled: NotRequired[bool] class NamedExpressionYamlSpec(TypedDict): From e7525ccaf9dd9c34cf1d0b6d4d36d449d7339a0f Mon Sep 17 00:00:00 2001 From: Taylor Jones Date: Tue, 27 Jan 2026 16:18:53 -0600 Subject: [PATCH 3/4] Simplify/fix test --- .../_tests/resources/test_rules.py | 65 +++---------------- 1 file changed, 8 insertions(+), 57 deletions(-) diff --git a/python/lib/sift_client/_tests/resources/test_rules.py b/python/lib/sift_client/_tests/resources/test_rules.py index 340f20e39..0573e7688 100644 --- a/python/lib/sift_client/_tests/resources/test_rules.py +++ b/python/lib/sift_client/_tests/resources/test_rules.py @@ -453,66 +453,17 @@ async def test_update_with_dict(self, rules_api_async, new_rule): @pytest.mark.asyncio async def test_update_rule_live_evaluation_enabled(self, rules_api_async, new_rule): """Test updating a rule's is_live_evaluation_enabled field.""" - from datetime import datetime, timezone - try: - # First, create a rule with is_live_evaluation_enabled=False - rule_name = f"test_rule_update_live_{datetime.now(timezone.utc).isoformat()}" - channels = await rules_api_async.client.async_.channels.list_(limit=2) - assets = await rules_api_async.client.async_.assets.list_(limit=1) - - rule_create = RuleCreate( - name=rule_name, - description="Test rule for updating live evaluation", - expression="$1 > $2", - channel_references=[ - ChannelReference( - channel_reference="$1", channel_identifier=channels[0].name - ), - ChannelReference( - channel_reference="$2", channel_identifier=channels[1].name - ), - ], - action=RuleAction.annotation( - annotation_type=RuleAnnotationType.DATA_REVIEW, - tags=[], - ), - asset_ids=[assets[0]._id_or_error], - is_live_evaluation_enabled=False, - ) - - created_rule = await rules_api_async.create(rule_create) - - # Verify initial state - assert created_rule.is_live_evaluation_enabled is False - - # Update to enable live evaluation - update = RuleUpdate(is_live_evaluation_enabled=True) - updated_rule = await rules_api_async.update(created_rule, update) - - assert updated_rule.id_ == created_rule.id_ - assert updated_rule.is_live_evaluation_enabled is True - # Verify by fetching the rule again - fetched_rule = await rules_api_async.get(rule_id=updated_rule.id_) - assert fetched_rule.is_live_evaluation_enabled is True - - # Update back to disable live evaluation - update = RuleUpdate(is_live_evaluation_enabled=False) - updated_rule = await rules_api_async.update(created_rule, update) + update_dict = {"is_live_evaluation_enabled": True} + updated_rule = await rules_api_async.update(new_rule, update_dict) + assert updated_rule.is_live_evaluation_enabled - assert updated_rule.is_live_evaluation_enabled is False - # Verify by fetching the rule again - fetched_rule = await rules_api_async.get(rule_id=updated_rule.id_) - assert fetched_rule.is_live_evaluation_enabled is False + update_dict = {"is_live_evaluation_enabled": False} + updated_rule = await rules_api_async.update(new_rule, update_dict) + assert not updated_rule.is_live_evaluation_enabled - await rules_api_async.archive(created_rule) - except Exception: - # Clean up if something goes wrong - try: - await rules_api_async.archive(created_rule) - except Exception: - pass - raise + finally: + await rules_api_async.archive(new_rule.id_) @pytest.mark.asyncio async def test_update_with_id_string(self, rules_api_async, new_rule): From e0fa372e57ce4195826c4c6f681335912d0d3c37 Mon Sep 17 00:00:00 2001 From: Taylor Jones Date: Tue, 27 Jan 2026 17:03:17 -0600 Subject: [PATCH 4/4] Only update sift_py --- .../_tests/resources/test_rules.py | 97 ------------------- python/lib/sift_client/sift_types/rule.py | 3 - 2 files changed, 100 deletions(-) diff --git a/python/lib/sift_client/_tests/resources/test_rules.py b/python/lib/sift_client/_tests/resources/test_rules.py index 0573e7688..d870e3a2a 100644 --- a/python/lib/sift_client/_tests/resources/test_rules.py +++ b/python/lib/sift_client/_tests/resources/test_rules.py @@ -321,88 +321,6 @@ async def test_create_rule_with_dict(self, rules_api_async): finally: await rules_api_async.archive(created_rule) - @pytest.mark.asyncio - async def test_create_rule_with_live_evaluation_enabled_true(self, rules_api_async): - """Test creating a rule with is_live_evaluation_enabled=True.""" - from datetime import datetime, timezone - - rule_name = f"test_rule_live_true_{datetime.now(timezone.utc).isoformat()}" - description = "Test rule with live evaluation enabled" - - channels = await rules_api_async.client.async_.channels.list_(limit=2) - assert len(channels) >= 2 - - assets = await rules_api_async.client.async_.assets.list_(limit=1) - assert len(assets) >= 1 - - rule_create = RuleCreate( - name=rule_name, - description=description, - expression="$1 > $2", - channel_references=[ - ChannelReference(channel_reference="$1", channel_identifier=channels[0].name), - ChannelReference(channel_reference="$2", channel_identifier=channels[1].name), - ], - action=RuleAction.annotation( - annotation_type=RuleAnnotationType.DATA_REVIEW, - tags=[], - ), - asset_ids=[assets[0]._id_or_error], - is_live_evaluation_enabled=True, - ) - - created_rule = await rules_api_async.create(rule_create) - - try: - assert created_rule is not None - assert created_rule.is_live_evaluation_enabled - # Verify by fetching the rule again - fetched_rule = await rules_api_async.get(rule_id=created_rule.id_) - assert fetched_rule.is_live_evaluation_enabled - finally: - await rules_api_async.archive(created_rule) - - @pytest.mark.asyncio - async def test_create_rule_with_live_evaluation_enabled_false(self, rules_api_async): - """Test creating a rule with is_live_evaluation_enabled=False.""" - from datetime import datetime, timezone - - rule_name = f"test_rule_live_false_{datetime.now(timezone.utc).isoformat()}" - description = "Test rule with live evaluation disabled" - - channels = await rules_api_async.client.async_.channels.list_(limit=2) - assert len(channels) >= 2 - - assets = await rules_api_async.client.async_.assets.list_(limit=1) - assert len(assets) >= 1 - - rule_create = RuleCreate( - name=rule_name, - description=description, - expression="$1 > $2", - channel_references=[ - ChannelReference(channel_reference="$1", channel_identifier=channels[0].name), - ChannelReference(channel_reference="$2", channel_identifier=channels[1].name), - ], - action=RuleAction.annotation( - annotation_type=RuleAnnotationType.DATA_REVIEW, - tags=[], - ), - asset_ids=[assets[0]._id_or_error], - is_live_evaluation_enabled=False, - ) - - created_rule = await rules_api_async.create(rule_create) - - try: - assert created_rule is not None - assert not created_rule.is_live_evaluation_enabled - # Verify by fetching the rule again - fetched_rule = await rules_api_async.get(rule_id=created_rule.id_) - assert not fetched_rule.is_live_evaluation_enabled - finally: - await rules_api_async.archive(created_rule) - class TestUpdate: """Tests for the async update method.""" @@ -450,21 +368,6 @@ async def test_update_with_dict(self, rules_api_async, new_rule): finally: await rules_api_async.archive(new_rule.id_) - @pytest.mark.asyncio - async def test_update_rule_live_evaluation_enabled(self, rules_api_async, new_rule): - """Test updating a rule's is_live_evaluation_enabled field.""" - try: - update_dict = {"is_live_evaluation_enabled": True} - updated_rule = await rules_api_async.update(new_rule, update_dict) - assert updated_rule.is_live_evaluation_enabled - - update_dict = {"is_live_evaluation_enabled": False} - updated_rule = await rules_api_async.update(new_rule, update_dict) - assert not updated_rule.is_live_evaluation_enabled - - finally: - await rules_api_async.archive(new_rule.id_) - @pytest.mark.asyncio async def test_update_with_id_string(self, rules_api_async, new_rule): """Test updating a rule by passing ID as string.""" diff --git a/python/lib/sift_client/sift_types/rule.py b/python/lib/sift_client/sift_types/rule.py index 0ea59a66c..5713f0b7a 100644 --- a/python/lib/sift_client/sift_types/rule.py +++ b/python/lib/sift_client/sift_types/rule.py @@ -64,7 +64,6 @@ class Rule(BaseType[RuleProto, "Rule"]): client_key: str | None rule_version: RuleVersion | None archived_date: datetime | None - is_live_evaluation_enabled: bool | None = None @property def assets(self) -> list[Asset]: @@ -154,7 +153,6 @@ def _from_proto(cls, proto: RuleProto, sift_client: SiftClient | None = None) -> ), is_archived=proto.is_archived, is_external=proto.is_external, - is_live_evaluation_enabled=proto.is_live_evaluation_enabled, _client=sift_client, ) @@ -168,7 +166,6 @@ class RuleCreateUpdateBase(ModelCreateUpdateBase): asset_tag_ids: list[str] | None = None contextual_channels: list[str] | None = None is_external: bool = False - is_live_evaluation_enabled: bool | None = None class RuleCreate(RuleCreateUpdateBase, ModelCreate[CreateRuleRequest]):