fix: strip keyword rows in keyword moderation (#42048)

This commit is contained in:
Harsh Kashyap authored and GitHub committed 2026-09-11 01:02:22 +00:00
1 parent f0d69e7b39
commit a1bb317892
3 files changed
+32 -10

No files matched your search

+12 -4
View File
@@ -42,8 +42,7 @@ class KeywordsModeration(Moderation):
if query:
inputs["query__"] = query
# Filter out empty values
keywords_list = [keyword for keyword in self.config["keywords"].split("\n") if keyword]
keywords_list = self._keyword_rows(self.config["keywords"])
flagged = self._is_violated(inputs, keywords_list)
@@ -59,8 +58,7 @@ class KeywordsModeration(Moderation):
raise ValueError("The config is not set.")
if self.config["outputs_config"]["enabled"]:
# Filter out empty values
keywords_list = [keyword for keyword in self.config["keywords"].split("\n") if keyword]
keywords_list = self._keyword_rows(self.config["keywords"])
flagged = self._is_violated({"text": text}, keywords_list)
preset_response = self.config["outputs_config"]["preset_response"]
@@ -69,6 +67,16 @@ class KeywordsModeration(Moderation):
flagged=flagged, action=ModerationAction.DIRECT_OUTPUT, preset_response=preset_response
)
@staticmethod
def _keyword_rows(keywords: str) -> list[str]:
"""Split the keywords config into stripped, non-empty rows.
Rows keep surrounding whitespace from pasted configs (for example CRLF
line endings) unless stripped: a keyword ending in "\r" never matches
real text, and a whitespace-only row matches nearly every message.
"""
return [row for row in (row.strip() for row in keywords.split("\n")) if row]
def _is_violated(self, inputs: dict[str, Any], keywords_list: list[str]) -> bool:
return any(self._check_keywords_in_value(keywords_list, value) for value in inputs.values())
@@ -127,6 +127,24 @@ class TestKeywordsModeration:
with pytest.raises(ValueError, match="inputs_config.preset_response must be less than 100 characters"):
KeywordsModeration.validate_config("test-tenant", config)
def test_moderation_for_inputs_crlf_keywords_match(self, keywords_config: dict[str, Any]):
"""Keywords pasted with Windows line endings still match."""
keywords_config["keywords"] = "spam\r\nfree money"
moderation = KeywordsModeration(app_id="app", tenant_id="tenant", config=keywords_config)
result = moderation.moderation_for_inputs({}, query="this is spam")
assert result.flagged is True
def test_moderation_whitespace_only_keyword_row_is_ignored(self, keywords_config: dict[str, Any]):
"""A whitespace-only keyword row must not flag every message."""
keywords_config["keywords"] = "spam\n \n "
moderation = KeywordsModeration(app_id="app", tenant_id="tenant", config=keywords_config)
result = moderation.moderation_for_inputs({}, query="a perfectly normal message")
assert result.flagged is False
def test_moderation_for_inputs_no_violation(self, keywords_moderation: KeywordsModeration):
"""Test input moderation when no keywords are matched."""
inputs = {"user_input": "This is a clean message"}
@@ -621,13 +621,9 @@ class TestEdgeCases:
"""Test keyword that is only spaces."""
moderation = self._create_moderation(" ")
# Text without three consecutive spaces should not match
result1 = moderation.moderation_for_inputs({"text": "This has spaces"})
assert result1.flagged is False
result = moderation.moderation_for_inputs({"text": "This has spaces"})
# Text with three consecutive spaces should match
result2 = moderation.moderation_for_inputs({"text": "This has spaces"})
assert result2.flagged is True
assert result.flagged is False
def test_config_not_set_error_for_inputs(self):
"""Test error when config is not set for input moderation."""