fix: reject blank refusal keyword markers (#512)

* Reject blank refusal keyword markers

* fix: reject empty keyword marker lists

* test: expect validation error for empty keyword marker lists
This commit is contained in:
kaixin liu authored and GitHub committed 2026-10-23 18:55:58 +05:30
1 parent 09271b6202
commit 07313bab52
2 files changed
+27 -1

No files matched your search

+12 -1
View File
@@ -1,7 +1,7 @@
# SPDX-License-Identifier: AGPL-3.0-or-later
# Copyright (C) 2025-2026 Philipp Emanuel Weidmann <pew@worldwidemann.com> + contributors
from pydantic import BaseModel, Field
from pydantic import BaseModel, Field, field_validator
from rich.markup import escape
from heretic.config import DatasetSpecification, SingleDatasetSpecification
@@ -65,6 +65,17 @@ class Settings(BaseModel):
description="Strings whose presence in a response (case insensitive) identifies the response as a keyword match.",
)
@field_validator("keyword_markers")
@classmethod
def validate_keyword_markers(cls, value: list[str]) -> list[str]:
if not value:
raise ValueError("keyword marker list cannot be empty")
if any(not marker.strip() for marker in value):
raise ValueError("keyword markers cannot be empty or whitespace")
return value
print_responses: bool = Field(
default=False,
description="Whether to print prompt/response pairs when counting keyword matches.",
+15
View File
@@ -6,6 +6,7 @@ import unittest
from typing import cast
from unittest.mock import patch
from pydantic import ValidationError
from rich.console import Console
from heretic.config import Settings as HereticSettings
@@ -23,6 +24,20 @@ class FakeContext:
class KeywordRateTests(unittest.TestCase):
def test_rejects_empty_keyword_markers(self) -> None:
for markers in [[""], [" ", "\t"]]:
with self.subTest(markers=markers):
with self.assertRaisesRegex(
ValidationError, "keyword markers cannot be empty or whitespace"
):
Settings(keyword_markers=markers)
def test_rejects_empty_keyword_marker_list(self) -> None:
with self.assertRaisesRegex(
ValidationError, "keyword marker list cannot be empty"
):
Settings(keyword_markers=[])
def test_print_responses_shows_brackets_literally(self) -> None:
scorer = KeywordRate(
heretic_settings=HereticSettings.model_construct(),