package router import ( "context" "testing" ) // narrativeRouter wires the grammars in the order the daemon wires them // (voicewire.go), with the narrative rule last — so a test that passes here is // a test of the deployed precedence, not of the rule in isolation. func narrativeRouter(t *testing.T) *Router { t.Helper() r := newTestRouter(t, 0.0) r.grammars = append(r.grammars, SystemTimeDateGrammars()...) r.grammars = append(r.grammars, AgendaQueryGrammars()...) r.grammars = append(r.grammars, TaskListGrammar()) r.grammars = append(r.grammars, TaskCaptureGrammar()) r.grammars = append(r.grammars, NarrativeQueryGrammars()...) return r } // "расскажи про X" and "что дальше?" carried no question mark and no // interrogative, so nothing at stage 0 claimed them and the model called both // facts (Vikunja #498, point 1 of #470). The fact write is contained now, but // the round trip and the wrong fixture score are not. func TestNarrativeAndRestOfDayRouteToQueryAtStageZero(t *testing.T) { r := narrativeRouter(t) for _, u := range []string{ "расскажи про битву при Ватерлоо", "расскажи мне про Юникод", "объясни как работает tcp", "опиши Самару", "перечисли планеты", "tell me about the fall of Rome", "что дальше?", "и что там дальше", "что дальше", "what's next?", } { d, err := r.Route(context.Background(), u, refNow()) if err != nil { t.Fatalf("route(%q): %v", u, err) } if d.Intent != IntentQuery { t.Errorf("route(%q) = %s, want query", u, d.Intent) } if d.Stage != 0 { t.Errorf("route(%q) decided at stage %d, want 0 — the point is to skip the model", u, d.Stage) } } } // The narrative rule must not take a turn that belongs to something else. A // capture marker wins because it is what he said, and asking her for a joke is // chat: the query chain has no source that answers it. func TestNarrativeGrammarLeavesOtherTurnsAlone(t *testing.T) { r := narrativeRouter(t) for _, u := range []string{ "расскажи анекдот", "расскажи о себе", "расскажи шутку", "расскажи", } { d, err := r.Route(context.Background(), u, refNow()) if err != nil { t.Fatalf("route(%q): %v", u, err) } if d.Stage == 0 && d.Intent == IntentQuery { t.Errorf("route(%q) was claimed as a world question at stage 0", u) } } } // The topic reaches the query chain without the verb that introduced it: the // search leg wants "битву при Ватерлоо", not "расскажи про битву при Ватерлоо". func TestNarrativeGrammarKeepsTheTopic(t *testing.T) { r := narrativeRouter(t) d, err := r.Route(context.Background(), "расскажи про битву при Ватерлоо", refNow()) if err != nil { t.Fatal(err) } if got, want := d.Slots.Text, "битву при Ватерлоо"; got != want { t.Errorf("text = %q, want %q", got, want) } }