Add diagnostic trace coverage for intent selection lineage
CI / test (push) Failing after 14s

This commit is contained in:
m
2026-08-18 16:54:46 +03:00
parent b025bec777
commit b6237334c6
2 changed files with 72 additions and 1 deletions
@@ -78,8 +78,12 @@ func TestLiveInterpretationTrace(t *testing.T) {
for _, message := range []string{
"расскажи как это работает",
"Расскажи, как это работает?",
"Расскажи как это работает",
"можешь объяснить почему база растёт",
"почему postgres использует столько памяти",
"ПОЧЕМУ postgres использует так много памяти",
"домовой не видит ии",
"домовой не вижит ии",
"разберись почему сервис упал",
"посмотри что произошло",
"исправь ошибку если найдёшь",
@@ -277,4 +281,4 @@ func cognitiveCandidateFromGateway(utteranceID interaction.HumanUtteranceID, can
CapabilityHints: capabilityHints,
RecordedAtUnixMillis: now.UnixMilli(),
}, nil
}
}
@@ -8,6 +8,7 @@ import (
"git.cin.su/m/Assistant/contracts/identity"
"git.cin.su/m/Assistant/contracts/interaction"
"git.cin.su/m/Assistant/contracts/situation"
"git.cin.su/m/Assistant/platform/ids"
)
func TestInterpretUtteranceRecordsExplicitProjectFocus(t *testing.T) {
@@ -136,6 +137,7 @@ func TestInterpretUtteranceNaturalRussianHelpflowUsesContextAwareCognitionInput(
{message: "нет не UPO а UPO2 и обнови конфиг", wantSpeech: "", wantCognition: true, allowNoMatch: true},
{message: "postgres сейчас работает", wantSpeech: "", wantCognition: true, allowNoMatch: true},
{message: "сейчас домовой не видит ии", wantSpeech: "", wantCognition: true, allowNoMatch: true},
{message: "домовой не видит ии", wantSpeech: "", wantCognition: true, allowNoMatch: true},
{message: "основная база называется UPO", wantSpeech: interaction.SpeechActAssertion, wantCognition: false},
{message: "привет", wantSpeech: interaction.SpeechActConversational, wantCognition: false},
{message: "спасибо", wantSpeech: interaction.SpeechActConversational, wantCognition: false},
@@ -151,6 +153,7 @@ func TestInterpretUtteranceNaturalRussianHelpflowUsesContextAwareCognitionInput(
{message: "домовой не отвечает мне", wantSpeech: "", wantCognition: true, allowNoMatch: true},
{message: "домовой не слушает меня", wantSpeech: "", wantCognition: true, allowNoMatch: true},
{message: "домовой не отвечает на команды", wantSpeech: "", wantCognition: true, allowNoMatch: true},
{message: "ПОЧЕМУ postgres использует так много памяти", wantSpeech: "", wantCognition: true, allowNoMatch: true},
}
for _, tc := range cases {
result := interpretForTest(t, tc.message, nil, "")
@@ -169,6 +172,70 @@ func TestInterpretUtteranceNaturalRussianHelpflowUsesContextAwareCognitionInput(
}
}
func TestInterpretUtteranceDiagnosticTraceLineage(t *testing.T) {
message := "ты кто"
conversation := interaction.Conversation{ID: "conversation-1", ActorID: "actor-1", PrincipalID: "principal-1", Channel: interaction.ChannelWebChat, State: interaction.ConversationOpen}
utterance, _, _, err := NewHumanUtterance(conversation, interaction.ChatMessageRequest{Message: message}, time.Unix(100, 0))
if err != nil {
t.Fatal(err)
}
result, err := InterpretUtterance(utterance, projectRegistryForTest(), nil, time.Unix(100, 0))
if err != nil {
t.Fatal(err)
}
candidateID, err := ids.New()
if err != nil {
t.Fatal(err)
}
cognitiveCandidate := interaction.SemanticCandidate{
ID: interaction.SemanticCandidateID(candidateID),
UtteranceID: utterance.ID,
Source: interaction.CandidateSourceCognitive,
SelectionState: interaction.CandidateObserved,
PrimarySpeechAct: interaction.SpeechActQuestion,
SecondarySpeechAct: interaction.SpeechActUnknown,
ConfidenceMillis: 780,
Applicability: interaction.SemanticNeedsBroaderInterpret,
RequestedOutcome: "",
Clarification: interaction.ClarificationNotRequired,
NeedsCognition: true,
SelectionReason: "trace-oriented cognitive clarification of identity-style intent",
CapabilityHints: []string{"COGNITIVE_REASONING"},
RecordedAtUnixMillis: time.Unix(100, 0).UnixMilli(),
}
selected := ApplyCognitiveCandidate(result, message, cognitiveCandidate, nil)
var deterministic, selectedCandidate *interaction.SemanticCandidate
for index := range selected.Candidates {
c := &selected.Candidates[index]
if c.Source == interaction.CandidateSourceDeterministic {
deterministic = c
}
if c.SelectionState == interaction.CandidateSelected {
selectedCandidate = c
}
}
if deterministic == nil {
t.Fatal("expected deterministic candidate in trace")
}
if selectedCandidate == nil {
t.Fatal("expected selected candidate in trace")
}
if selected.Interpretation.Source != string(interaction.CandidateSourceCognitive) {
t.Fatalf("selection source should switch to cognitive, got %s", selected.Interpretation.Source)
}
if selected.Interpretation.NeedsCognition != selectedCandidate.NeedsCognition {
t.Fatalf("expected selected interpretation cognition=%t got %t", selectedCandidate.NeedsCognition, selected.Interpretation.NeedsCognition)
}
if selected.Interpretation.Clarification != selectedCandidate.Clarification {
t.Fatalf("expected selected candidate clarification to match interpretation clarification")
}
if selectedCandidate.SelectionReason == "" {
t.Fatal("expected clarification/selection reason in selected trace")
}
t.Logf("TRACE deterministic_source=%s cognitive_source=%s selected_source=%s needs_cognition=%t clarification_reason=%s",
deterministic.Source, selectedCandidate.Source, selected.Interpretation.Source, selected.Interpretation.NeedsCognition, selected.Interpretation.SelectionReason)
}
func TestInterpretUtteranceModalExplanationRequestStillRequestsCognition(t *testing.T) {
for _, message := range []string{"можешь расказать об утре", "расскажи об утре", "про утро расскажешь"} {
result := interpretForTest(t, message, nil, "")