d9ef9ecef2
The textual merge in fe489df left a second rest-of-day-query grammar inside
NarrativeQueryGrammars. buildRouter wires the agenda grammars first, so the
copy never claimed a turn, and narrative_test.go only ever indexed the
narrative rule beside it.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
86 lines
3.0 KiB
Go
86 lines
3.0 KiB
Go
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)
|
|
}
|
|
}
|