fix: preserve selected semantic candidate provenance
This commit is contained in:
@@ -29,6 +29,7 @@ func InterpretUtterance(utterance interaction.HumanUtterance, projects []situati
|
||||
millis := now.UnixMilli()
|
||||
deterministicCandidate := BuildDeterministicCandidate(utterance.Content, utterance.CorrectsUtteranceID, millis)
|
||||
deterministicCandidate.UtteranceID = utterance.ID
|
||||
deterministicCandidate.SelectionState = interaction.CandidateSelected
|
||||
selectedCandidate := deterministicCandidate
|
||||
result := SemanticResult{
|
||||
Interpretation: interaction.UtteranceInterpretation{
|
||||
@@ -103,14 +104,18 @@ func ApplyCognitiveCandidate(result SemanticResult, message string, candidate in
|
||||
|
||||
matched := false
|
||||
for index := range result.Candidates {
|
||||
if result.Candidates[index].SelectionState == interaction.CandidateSelected {
|
||||
result.Candidates[index].SelectionState = interaction.CandidateObserved
|
||||
}
|
||||
if result.Candidates[index].ID == candidate.ID {
|
||||
result.Candidates[index] = candidate
|
||||
matched = true
|
||||
}
|
||||
}
|
||||
if selected {
|
||||
for index := range result.Candidates {
|
||||
if result.Candidates[index].ID != candidate.ID && result.Candidates[index].SelectionState == interaction.CandidateSelected {
|
||||
result.Candidates[index].SelectionState = interaction.CandidateObserved
|
||||
}
|
||||
}
|
||||
}
|
||||
if !matched {
|
||||
result.Candidates = append(result.Candidates, candidate)
|
||||
}
|
||||
|
||||
@@ -119,10 +119,10 @@ func TestInterpretUtteranceAmbiguousDestructiveRequiresClarification(t *testing.
|
||||
|
||||
func TestInterpretUtteranceNaturalRussianHelpflowUsesContextAwareCognitionInput(t *testing.T) {
|
||||
cases := []struct {
|
||||
message string
|
||||
wantSpeech interaction.SpeechAct
|
||||
wantCognition bool
|
||||
allowNoMatch bool
|
||||
message string
|
||||
wantSpeech interaction.SpeechAct
|
||||
wantCognition bool
|
||||
allowNoMatch bool
|
||||
}{
|
||||
{message: "расскажи как это работает", wantSpeech: interaction.SpeechActQuestion, wantCognition: true},
|
||||
{message: "Расскажи, как это работает?", wantSpeech: interaction.SpeechActQuestion, wantCognition: true},
|
||||
@@ -325,6 +325,49 @@ func TestInterpretUtteranceModalExplanationRequestStillRequestsCognition(t *test
|
||||
}
|
||||
}
|
||||
|
||||
func TestInterpretUtteranceSelectsDeterministicCandidateByDefault(t *testing.T) {
|
||||
result := interpretForTest(t, "основная база называется UPO", nil, "")
|
||||
if len(result.Candidates) != 1 {
|
||||
t.Fatalf("expected one deterministic candidate, got %d", len(result.Candidates))
|
||||
}
|
||||
if result.Candidates[0].SelectionState != interaction.CandidateSelected {
|
||||
t.Fatalf("deterministic candidate must be selected by default, got %s", result.Candidates[0].SelectionState)
|
||||
}
|
||||
}
|
||||
|
||||
func TestRejectedCognitiveCandidatePreservesSelectedDeterministicCandidate(t *testing.T) {
|
||||
result := interpretForTest(t, "основная база называется UPO", nil, "")
|
||||
candidateID, err := ids.New()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
rejected := interaction.SemanticCandidate{
|
||||
ID: interaction.SemanticCandidateID(candidateID),
|
||||
UtteranceID: result.Interpretation.UtteranceID,
|
||||
Source: interaction.CandidateSourceCognitive,
|
||||
PrimarySpeechAct: interaction.SpeechActQuestion,
|
||||
SecondarySpeechAct: interaction.SpeechActUnknown,
|
||||
ConfidenceMillis: 700,
|
||||
Applicability: interaction.SemanticApplicable,
|
||||
Clarification: interaction.ClarificationNotRequired,
|
||||
NeedsCognition: false,
|
||||
SelectionReason: "must not replace a safe assertion with an unrelated candidate",
|
||||
}
|
||||
result = ApplyCognitiveCandidate(result, "основная база называется UPO", rejected, nil)
|
||||
selected := 0
|
||||
for _, candidate := range result.Candidates {
|
||||
if candidate.SelectionState == interaction.CandidateSelected {
|
||||
selected++
|
||||
if candidate.Source != interaction.CandidateSourceDeterministic {
|
||||
t.Fatalf("rejected cognitive candidate replaced deterministic selection: %#v", candidate)
|
||||
}
|
||||
}
|
||||
}
|
||||
if selected != 1 {
|
||||
t.Fatalf("expected exactly one selected candidate after rejection, got %d", selected)
|
||||
}
|
||||
}
|
||||
|
||||
func interpretForTest(t *testing.T, message string, previous *situation.ActiveProjectFocus, corrects interaction.HumanUtteranceID) SemanticResult {
|
||||
t.Helper()
|
||||
conversation := interaction.Conversation{ID: "conversation-1", ActorID: "actor-1", PrincipalID: "principal-1", Channel: interaction.ChannelWebChat, State: interaction.ConversationOpen}
|
||||
|
||||
Reference in New Issue
Block a user