Files
Assistant/modules/interaction/domain/gen2_context_test.go
T

105 lines
5.7 KiB
Go

package domain_test
import (
"git.cin.su/m/Assistant/contracts/interaction"
"git.cin.su/m/Assistant/modules/interaction/domain"
"strings"
"testing"
)
func TestGen2ContextUsesRetrievalProjectionAndKeepsV1Fallback(t *testing.T) {
got := domain.BuildGen2Context([]interaction.HumanUtterance{{ID: "u", Content: "Я сейчас в Москве", ReceivedAtUnixMillis: 1}})
if got.Source != "retrieval:interaction-utterances" || got.UsedPersonalMemoryFallback {
t.Fatalf("got %#v", got)
}
empty := domain.BuildGen2Context(nil)
if !empty.UsedPersonalMemoryFallback {
t.Fatalf("fallback missing: %#v", empty)
}
}
func TestGen2ContextDoesNotProjectAnotherPrincipal(t *testing.T) {
got := domain.BuildScopedGen2Context([]interaction.HumanUtterance{
{ID: "mine", PrincipalID: "principal-1", Content: "Я сейчас в Москве", ReceivedAtUnixMillis: 2},
{ID: "other", PrincipalID: "principal-2", Content: "Я сейчас в Казани", ReceivedAtUnixMillis: 3},
}, "principal-1")
if got.Text == "" || strings.Contains(got.Text, "Казани") || !strings.Contains(got.Text, "Москве") {
t.Fatalf("scoped context=%#v", got)
}
}
func TestGen2ContextProjectsExplicitRememberedAssertion(t *testing.T) {
got := domain.BuildScopedGen2Context([]interaction.HumanUtterance{
{ID: "assertion", PrincipalID: "principal-1", Content: "Для этого разговора запомни: мой тестовый цвет — синий.", ReceivedAtUnixMillis: 1},
}, "principal-1")
if got.Source != "retrieval:interaction-assertions" || got.UsedPersonalMemoryFallback || !strings.Contains(got.Text, "тестовый цвет = синий") {
t.Fatalf("remembered assertion was not projected: %#v", got)
}
}
func TestGen2ContextSelectsArbitraryRelevantCurrentAssertion(t *testing.T) {
history := []interaction.HumanUtterance{
{ID: "assertion", PrincipalID: "principal-1", Content: "контрольный код = ORBIT-731", ReceivedAtUnixMillis: 1},
{ID: "turn-1", PrincipalID: "principal-1", Content: "Спасибо", ReceivedAtUnixMillis: 2},
{ID: "turn-2", PrincipalID: "principal-1", Content: "Продолжим", ReceivedAtUnixMillis: 3},
}
got := domain.BuildScopedGen2ContextForQuery(history, nil, "principal-1", "", "Какой контрольный код я назвал?")
if got.Source != "retrieval:interaction-assertions" || !strings.Contains(got.Text, "ORBIT-731") || len(got.Fragments) != 1 {
t.Fatalf("arbitrary assertion was not selected: %#v", got)
}
}
func TestGen2ContextKeepsHistoricalAssertionOutOfCurrentProjection(t *testing.T) {
history := []interaction.HumanUtterance{
{ID: "old", PrincipalID: "principal-1", Content: "контрольный код = OLD-111", ReceivedAtUnixMillis: 1},
{ID: "new", PrincipalID: "principal-1", Content: "контрольный код = NEW-222", ReceivedAtUnixMillis: 2},
}
got := domain.BuildScopedGen2ContextForQuery(history, nil, "principal-1", "", "Какой контрольный код?")
if strings.Contains(got.Text, "OLD-111") || !strings.Contains(got.Text, "NEW-222") || len(got.Historical) != 1 || !strings.Contains(got.Historical[0].Text, "OLD-111") {
t.Fatalf("current/historical assertion separation failed: %#v", got)
}
}
func TestGen2ContextCorrectionSupersedesBeforeTimestampTieBreaker(t *testing.T) {
history := []interaction.HumanUtterance{
{ID: "observed-later", PrincipalID: "principal-1", Content: "контрольный код = LATER", ReceivedAtUnixMillis: 9},
{ID: "original", PrincipalID: "principal-1", Content: "контрольный код = ORIGINAL", ReceivedAtUnixMillis: 1},
{ID: "correction", PrincipalID: "principal-1", Content: "контрольный код = CORRECTED", ReceivedAtUnixMillis: 2, CorrectsUtteranceID: "observed-later"},
}
got := domain.BuildScopedGen2ContextForQuery(history, nil, "principal-1", "", "Какой контрольный код?")
if !strings.Contains(got.Text, "CORRECTED") || strings.Contains(got.Text, "LATER") {
t.Fatalf("explicit correction did not supersede: %#v", got)
}
}
func TestGen2ContextHardFiltersProjectReferencesBeforeRanking(t *testing.T) {
history := []interaction.HumanUtterance{
{ID: "a", PrincipalID: "principal-1", Content: "контрольный код = ALPHA", ReceivedAtUnixMillis: 1},
{ID: "b", PrincipalID: "principal-1", Content: "контрольный код = BETA", ReceivedAtUnixMillis: 2},
}
references := []interaction.ProjectReference{
{ID: "ref-a", UtteranceID: "a", ProjectID: "company-a"},
{ID: "ref-b", UtteranceID: "b", ProjectID: "company-b"},
}
for projectID, expected := range map[string]struct{ want, absent string }{
"company-a": {want: "ALPHA", absent: "BETA"},
"company-b": {want: "BETA", absent: "ALPHA"},
} {
got := domain.BuildScopedGen2ContextForQuery(history, references, "principal-1", projectID, "Какой контрольный код?")
if !strings.Contains(got.Text, expected.want) || strings.Contains(got.Text, expected.absent) || len(got.Fragments) != 1 || got.Fragments[0].ScopeRef != projectID {
t.Fatalf("scope %s leaked context: %#v", projectID, got)
}
}
}
func TestGen2ContextExcludesIrrelevantAssertionsFromBoundedProjection(t *testing.T) {
history := []interaction.HumanUtterance{
{ID: "code", PrincipalID: "principal-1", Content: "контрольный код = ORBIT-731", ReceivedAtUnixMillis: 1},
{ID: "city", PrincipalID: "principal-1", Content: "город встречи = Казань", ReceivedAtUnixMillis: 2},
}
got := domain.BuildScopedGen2ContextForQuery(history, nil, "principal-1", "", "Какой контрольный код?")
if strings.Contains(got.Text, "Казань") || len(got.Fragments) != 1 {
t.Fatalf("irrelevant assertion entered bounded projection: %#v", got)
}
}