router: stage 0 claims the other days and the named event (V-471)
"какие планы на сегодня" 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.
This commit is contained in:
@@ -75,3 +75,47 @@ func TestAgendaGrammarSparesStatements(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 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)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -23,6 +23,8 @@
|
|||||||
{ "id": "ru-query-012", "utterance": "какие заметки я оставил про полив", "lang": "ru", "intent": "query", "tags": ["recall"] },
|
{ "id": "ru-query-012", "utterance": "какие заметки я оставил про полив", "lang": "ru", "intent": "query", "tags": ["recall"] },
|
||||||
{ "id": "ru-query-013", "utterance": "во сколько у меня встреча", "lang": "ru", "intent": "query", "tags": ["calendar"] },
|
{ "id": "ru-query-013", "utterance": "во сколько у меня встреча", "lang": "ru", "intent": "query", "tags": ["calendar"] },
|
||||||
{ "id": "ru-query-019", "utterance": "что у меня стоит в календаре на послезавтра", "lang": "ru", "intent": "query", "tags": ["calendar", "hard"], "note": "agenda, not the clock: the daemon answers this from CalendarEvents inside the query branch, so the clock/date system rule must not swallow it" },
|
{ "id": "ru-query-019", "utterance": "что у меня стоит в календаре на послезавтра", "lang": "ru", "intent": "query", "tags": ["calendar", "hard"], "note": "agenda, not the clock: the daemon answers this from CalendarEvents inside the query branch, so the clock/date system rule must not swallow it" },
|
||||||
|
{ "id": "ru-query-022", "utterance": "какие планы на завтра?", "lang": "ru", "intent": "query", "tags": ["calendar"], "note": "the same agenda question as ru-query-019 aimed at another day; it answered \u043f\u043e\u043a\u0430 \u043d\u0435 \u0443\u043c\u0435\u044e on the deployed daemon while the today form worked (Vikunja #471)" },
|
||||||
|
{ "id": "ru-query-023", "utterance": "\u043a\u043e\u0433\u0434\u0430 \u043f\u043b\u0430\u043d\u0451\u0440\u043a\u0430?", "lang": "ru", "intent": "query", "tags": ["calendar", "hard"], "note": "a named event with no calendar word — the noun is the only signal that this is a question about his day" },
|
||||||
{ "id": "ru-query-014", "utterance": "я успеваю до дедлайна", "lang": "ru", "intent": "query", "tags": ["hard", "no-question-word"] },
|
{ "id": "ru-query-014", "utterance": "я успеваю до дедлайна", "lang": "ru", "intent": "query", "tags": ["hard", "no-question-word"] },
|
||||||
{ "id": "ru-query-015", "utterance": "сколько я прошёл шагов", "lang": "ru", "intent": "query", "tags": ["aggregate"] },
|
{ "id": "ru-query-015", "utterance": "сколько я прошёл шагов", "lang": "ru", "intent": "query", "tags": ["aggregate"] },
|
||||||
{ "id": "ru-query-016", "utterance": "покажи давление за неделю", "lang": "ru", "intent": "query", "tags": ["hard", "imperative"], "note": "imperative form but a read — must not route to act" },
|
{ "id": "ru-query-016", "utterance": "покажи давление за неделю", "lang": "ru", "intent": "query", "tags": ["hard", "imperative"], "note": "imperative form but a read — must not route to act" },
|
||||||
|
|||||||
@@ -182,9 +182,38 @@ func AgendaQueryGrammars() []Grammar {
|
|||||||
Pattern: regexp.MustCompile(`(?i)^\s*(что|чего|какие|сколько|во\s+сколько|когда)\s+у\s+меня(\s|[?!.]|$)`),
|
Pattern: regexp.MustCompile(`(?i)^\s*(что|чего|какие|сколько|во\s+сколько|когда)\s+у\s+меня(\s|[?!.]|$)`),
|
||||||
Build: agendaQueryBuild,
|
Build: agendaQueryBuild,
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
// A plan noun aimed at a named day, with no possessive to anchor
|
||||||
|
// on: "какие планы на завтра", "что по делам в среду". The rule
|
||||||
|
// above wants "у меня" and this phrasing never has it, so
|
||||||
|
// "какие планы на завтра" answered "пока не умею" while "какие
|
||||||
|
// планы на сегодня" worked (Vikunja #471). The day word is what
|
||||||
|
// makes it an agenda question rather than a topic.
|
||||||
|
Name: "plan-day-query",
|
||||||
|
// Only "план" and "дел". A verb stem like "встреч" would take
|
||||||
|
// "встречаемся в среду", which is him telling her something, not
|
||||||
|
// asking.
|
||||||
|
Pattern: regexp.MustCompile(`(?i)(^|\s)(план|дел)[а-я]*\s+(на|в|во|по)\s+` + dayWordPattern + `(\s|[?!.]|$)`),
|
||||||
|
Build: agendaQueryBuild,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
// A named event with no calendar word at all: "когда планёрка?",
|
||||||
|
// "во сколько созвон". He is asking when something on his calendar
|
||||||
|
// happens, and the noun is the only signal. Closed list, so "когда
|
||||||
|
// битва при Ватерлоо" is still a world question.
|
||||||
|
Name: "event-time-query",
|
||||||
|
Pattern: regexp.MustCompile(`(?i)^\s*(когда|во\s+сколько|в\s+котором\s+часу)\s+(будет\s+|у\s+нас\s+)?(планёрк|планерк|встреч|созвон|митинг|совещани|звонок|созвон|приём|прием|интервью|собеседовани|тренировк|урок|занятие|пара)[а-я]*(\s|[?!.]|$)`),
|
||||||
|
Build: agendaQueryBuild,
|
||||||
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// dayWordPattern — the day words an agenda question can name. Weekdays appear
|
||||||
|
// in the accusative and prepositional forms the questions actually use ("в
|
||||||
|
// среду", "на среде"), which is why the stems carry an inflection tail rather
|
||||||
|
// than a fixed ending.
|
||||||
|
const dayWordPattern = `(сегодня|завтра|послезавтра|выходн[а-я]+|недел[а-я]+|понедельник[а-я]*|вторник[а-я]*|сред[ауые][а-я]*|четверг[а-я]*|пятниц[ауые][а-я]*|суббот[ауые][а-я]*|воскресень[ея][а-я]*)`
|
||||||
|
|
||||||
// agendaQueryBuild — shared Build for the agenda grammars. Confidence 1.0 on
|
// agendaQueryBuild — shared Build for the agenda grammars. Confidence 1.0 on
|
||||||
// the intent only: the utterance travels intact and the query chain's own
|
// the intent only: the utterance travels intact and the query chain's own
|
||||||
// matchers decide the rest.
|
// matchers decide the rest.
|
||||||
|
|||||||
Reference in New Issue
Block a user