fix(goal): reject trailing model evaluation documents

This commit is contained in:
mateaix 2026-09-14 01:12:26 +08:00
parent b58fd93430
commit 5e1248432d
2 changed files with 22 additions and 0 deletions

View File

@ -96,6 +96,7 @@ public class GoalEvaluationService implements Evaluator {
// choose the last value of an ambiguous model-produced JSON key.
ObjectMapper evaluatorJson = objectMapper.copy()
.disable(com.fasterxml.jackson.databind.DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES)
.enable(com.fasterxml.jackson.databind.DeserializationFeature.FAIL_ON_TRAILING_TOKENS)
.enable(com.fasterxml.jackson.core.JsonParser.Feature.STRICT_DUPLICATE_DETECTION);
this.draftConverter = new BeanOutputConverter<>(GoalCriteriaDraft.class, evaluatorJson);
this.verdictConverter = new BeanOutputConverter<>(GoalChecklistVerdict.class, evaluatorJson);

View File

@ -299,6 +299,27 @@ class GoalEvaluationServiceTest {
}
}
@Test
void aSecondStructuredResultCannotBeIgnoredAfterACompletionVerdict() {
stubChatResponse("{\"criterionVerdicts\":[{\"id\":\"C1\",\"passed\":true,\"evidence\":\"ready\"},"
+ "{\"id\":\"C2\",\"passed\":true,\"evidence\":\"ready\"}]} "
+ "{\"criterionVerdicts\":[{\"id\":\"C1\",\"passed\":false,\"evidence\":\"not ready\"}]}");
var result = svc.evaluate(goalWithCriteria(), List.of(), "finished");
assertEquals(GoalEvaluationResult.DECISION_FALLBACK, result.decision());
assertFalse(result.completed());
assertEquals(1, result.llmCallsConsumed());
assertTrue(result.criterionVerdicts().isEmpty());
}
@Test
void bootstrapCannotIgnoreTrailingContradictoryContent() {
stubChatResponse("{\"criteria\":[{\"text\":\"deliver report\"}]} {\"criteria\":[]}");
var result = svc.evaluate(goal(), List.of(), "finished");
assertEquals(GoalEvaluationResult.DECISION_FALLBACK, result.decision());
assertEquals(1, result.llmCallsConsumed());
assertNull(result.bootstrapCriteria());
}
// ==================== Parser tolerance ====================
@Test