router: answer the task-list ask at stage 0 too, and mirror it in the fixture (V-467)
The capture half landed with the grammar in 87d1761. This is the exposure
the task asked to check for: IsTaskListQuery is a deterministic lookup that
only runs once the turn is already a query, so a phrasing the model calls
system never reaches it. The eval fixture was also missing both grammars,
which is only worth having while it is the daemon's grammar set.
This commit is contained in:
@@ -385,6 +385,9 @@ func buildRouter(emb router.Embedder, acts router.ActMatcher, threshold float64,
|
||||
// Same reason as the agenda rules, for the feeds: "что нового в лентах?"
|
||||
// routed system and answered "пока не умею" (Vikunja #474).
|
||||
grammars = append(grammars, router.FeedQueryGrammar())
|
||||
// The list side of the same exposure: a phrasing with no possessive in it
|
||||
// ("список дел") routed system and never reached queryTasks (Vikunja #467).
|
||||
grammars = append(grammars, router.TaskListGrammar())
|
||||
grammars = append(grammars, router.ReminderGrammar())
|
||||
// Last, and it matches any utterance shape — its Build is the filter. An
|
||||
// explicit capture marker beats the model, which called it an act and
|
||||
|
||||
@@ -237,7 +237,11 @@ func newBaselineRouter(t *testing.T, emb router.Embedder, llmR *router.LLMRouter
|
||||
// anything while its grammar set is the daemon's grammar set.
|
||||
grammars = append(grammars, router.AgendaQueryGrammars()...)
|
||||
grammars = append(grammars, router.FeedQueryGrammar())
|
||||
// The list side of the same exposure: a phrasing with no possessive in it
|
||||
// ("список дел") routed system and never reached queryTasks (Vikunja #467).
|
||||
grammars = append(grammars, router.TaskListGrammar())
|
||||
grammars = append(grammars, router.ReminderGrammar())
|
||||
grammars = append(grammars, router.TaskCaptureGrammar())
|
||||
return router.New(router.Config{
|
||||
Grammars: grammars,
|
||||
Classifier: cls,
|
||||
|
||||
@@ -248,3 +248,32 @@ func TaskCaptureGrammar() Grammar {
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
// TaskListGrammar — stage 0 for "какие у меня задачи", "список дел", "что мне
|
||||
// нужно сделать" (Vikunja #467).
|
||||
//
|
||||
// The same exposure the capture marker had, pointed the other way. IsTaskListQuery
|
||||
// is a deterministic lookup that lives inside a query source, so it is only
|
||||
// consulted once the turn is already IntentQuery. A phrasing the model calls
|
||||
// system or note never reaches it, and "пока не умею" is what he hears — the
|
||||
// failure the agenda and feed rules were written for.
|
||||
//
|
||||
// Placed after the agenda rules, which already send "какие у меня задачи" to
|
||||
// query. What this adds is the phrasings with no possessive in them.
|
||||
func TaskListGrammar() Grammar {
|
||||
return Grammar{
|
||||
Name: "task-list-query",
|
||||
Pattern: regexp.MustCompile(`(?s)^\s*(.+)$`),
|
||||
Build: func(m []string) (Decision, bool) {
|
||||
if !IsTaskListQuery(m[1]) {
|
||||
return Decision{}, false
|
||||
}
|
||||
return Decision{
|
||||
Stage: 0,
|
||||
Intent: IntentQuery,
|
||||
Confidence: 1.0,
|
||||
Slots: Slots{Text: strings.TrimSpace(m[1])},
|
||||
}, true
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
@@ -119,3 +119,27 @@ func TestTaskCaptureGrammarClaimsTheMarker(t *testing.T) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// TestTaskListGrammarClaimsTheAsk — a list question answered before the model,
|
||||
// including the phrasings with no possessive that used to route elsewhere.
|
||||
func TestTaskListGrammarClaimsTheAsk(t *testing.T) {
|
||||
g := TaskListGrammar()
|
||||
claimed := []string{"какие у меня задачи", "список дел", "что мне нужно сделать"}
|
||||
for _, u := range claimed {
|
||||
m := g.Pattern.FindStringSubmatch(u)
|
||||
if m == nil {
|
||||
t.Fatalf("%q did not match the grammar pattern", u)
|
||||
}
|
||||
d, ok := g.Build(m)
|
||||
if !ok || d.Intent != IntentQuery {
|
||||
t.Errorf("%q built %+v ok=%v; want a query", u, d, ok)
|
||||
}
|
||||
}
|
||||
passed := []string{"как дела", "напомни купить хлеб", "что docker делает"}
|
||||
for _, u := range passed {
|
||||
m := g.Pattern.FindStringSubmatch(u)
|
||||
if _, ok := g.Build(m); ok {
|
||||
t.Errorf("%q was claimed as a task list", u)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user