A model's safety-filter refusal is an error that says so, not an empty reply #165
@@ -18,7 +18,7 @@ from nisse_core.loop.expert import (
|
||||
ExpertDesk,
|
||||
parse_answer,
|
||||
)
|
||||
from nisse_core.models.llm import LLMError, ModelRefused, RoleMap
|
||||
from nisse_core.models.llm import LLMError, RoleMap, _refused
|
||||
from nisse_core.oplog import OpLog
|
||||
from nisse_core.state.store import Transcript
|
||||
from nisse_dev.state import StateStore
|
||||
@@ -147,7 +147,7 @@ class DecliningClient(ScriptedClient):
|
||||
|
||||
def complete(self, events: Any, tools: Any, model: str, system: Any = None) -> Any:
|
||||
self.calls.append({"model": model, "system": system})
|
||||
raise ModelRefused(f"{model} declined to answer: its provider's safety filter")
|
||||
raise _refused(model) # the clients' own wording
|
||||
|
||||
|
||||
def test_a_declined_question_is_not_asked_again_and_says_why(
|
||||
@@ -162,7 +162,11 @@ def test_a_declined_question_is_not_asked_again_and_says_why(
|
||||
e.event for e in log(store).read() if isinstance(e.event, DelegationCompleted)
|
||||
]
|
||||
assert completed.exit_status == "failed"
|
||||
assert "safety filter" in completed.handback
|
||||
assert completed.handback == (
|
||||
|
|
||||
"claude-haiku-4-5 declined to answer: its provider's safety filter stopped the "
|
||||
"reply. That says nothing about the subject itself. Ask it "
|
||||
"differently, or work from the repository"
|
||||
)
|
||||
|
||||
|
||||
def test_retry_succeeds_after_a_bad_first_reply(store: StateStore) -> None:
|
||||
|
||||
Reference in new issue
Block a user
This handback check matches
DecliningClient's own hand-rolled message (line 150), not the production wording from_refused()inllm.py— which is only ever asserted at the route level intest_llm.py(partialmatch=). So the desk test proves the wrapping (". Ask it differently, or work from the repository") and the one-call behaviour, but it would still pass if the real message lost "safety filter". Raising_refused(model)here instead (it's importable fromnisse_core.models.llm) would make this test exercise the actual message end-to-end, which is what the PR description's "hands back the new message" promises.Agreed, done in
369b6ed.DecliningClientnow raises_refused(model)fromllm.py, and the test compares the whole handback, so it fails if the clients' wording changes (checked: dropping "safety" from_refusedfails it).Verified at head and confirmed addressed:
DecliningClientraises_refused(model)(test_expert.py:150) and the test asserts the full handback string (165-169), so a wording change in either_refused()or the desk's wrapping now fails the test — exactly what was asked. Importing the private_refusedin a test is consistent with the repo's existing pattern (_HELPER,_parse_projects), so no further nit. Point closed.