43f2c37538
"какие планы на сегодня" worked and "какие планы на завтра" answered "пока не умею": the agenda rule needs "у меня" or a calendar noun, and that phrasing carries neither. "когда планёрка?" had the same shape. Two rules. One takes a plan noun aimed at a named day, one takes a closed list of event nouns after "когда"/"во сколько". Both route intent only, so the query chain still decides which source answers. classifier+onnx over the fixture: 55/79, 69.6% full, with the two new cases passing and no case moving the other way.
122 lines
4.0 KiB
Go
122 lines
4.0 KiB
Go
package router
|
||
|
||
import (
|
||
"context"
|
||
"testing"
|
||
)
|
||
|
||
// agendaRouter wires both grammar sets in the order the daemon wires them
|
||
// (voicewire.go): the clock rules first, the agenda rules after, so a test
|
||
// that passes here is a test of the deployed precedence.
|
||
func agendaRouter(t *testing.T) *Router {
|
||
t.Helper()
|
||
r := newTestRouter(t, 0.0)
|
||
r.grammars = append(r.grammars, SystemTimeDateGrammars()...)
|
||
r.grammars = append(r.grammars, AgendaQueryGrammars()...)
|
||
return r
|
||
}
|
||
|
||
// An agenda question is answered from the calendar, which lives in the query
|
||
// chain. Routed to system it reaches replySystem, which has no agenda arm and
|
||
// says "пока не умею" — seen on the deployed daemon, 01-08-2026.
|
||
func TestAgendaQuestionsRouteToQuery(t *testing.T) {
|
||
r := agendaRouter(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.Intent != IntentQuery {
|
||
t.Errorf("route(%q) = %s, want query", u, d.Intent)
|
||
}
|
||
}
|
||
}
|
||
|
||
// The clock rules keep their utterances. They are registered first and the
|
||
// agenda patterns do not match them, so both statements have to hold.
|
||
func TestAgendaGrammarsLeaveTheClockAlone(t *testing.T) {
|
||
r := agendaRouter(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.Intent != IntentSystem {
|
||
t.Errorf("route(%q) = %s, want system", u, d.Intent)
|
||
}
|
||
}
|
||
}
|
||
|
||
// The agenda pattern is anchored and needs the possessive, so an ordinary
|
||
// statement that happens to contain "у меня" is not swallowed.
|
||
func TestAgendaGrammarSparesStatements(t *testing.T) {
|
||
r := agendaRouter(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 by the agenda grammar", u)
|
||
}
|
||
}
|
||
}
|
||
|
||
// The tomorrow form and the bare event noun. Both were measured answering
|
||
// "пока не умею" on the deployed daemon, 02-08-2026, while the same question
|
||
// about today worked — the first rule set needed "у меня" or a calendar noun
|
||
// and these phrasings carry neither (Vikunja #471).
|
||
func TestAgendaCoversOtherDaysAndNamedEvents(t *testing.T) {
|
||
r := agendaRouter(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.Intent != IntentQuery {
|
||
t.Errorf("route(%q) = %s, want query", u, d.Intent)
|
||
}
|
||
}
|
||
}
|
||
|
||
// The two new rules are narrow on purpose. A world question that opens with
|
||
// "когда" is not an agenda question, and telling her about a plan is not
|
||
// asking about one.
|
||
func TestAgendaGrammarsLeaveTheWorldAlone(t *testing.T) {
|
||
r := agendaRouter(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 {
|
||
t.Errorf("route(%q) was claimed at stage 0 as %s", u, d.Intent)
|
||
}
|
||
}
|
||
}
|