fe489dff6d
attentionq.go, repair.go and internal/router/complaint.go carry the last
hand-written Russian patterns of the V-522 sweep, and they live on task/467.
internal/lexicon, internal/morph and cmd/mavend/topics.go live here. One of
the two had to move.
Four conflicts, and one of them is a real collision rather than a mechanical
one. Both branches wrote the narrative stage 0 rule. This side had
NarrativeQueryGrammars, plural, with the rest-of-day rule beside it and the
verb alternation built from the lexicon; task/467 had NarrativeQueryGrammar,
singular, which extracts the topic into Slots.Text, refuses a bare "расскажи",
and excludes the shapes that are chat ("расскажи о себе", "историю на ночь").
Resolved by keeping this side's container and this side's lexicon-built
pattern, and taking every behaviour only the other side had: the topic slot,
the empty-topic refusal, chatNarrativeTopics, and its wiring position after
TaskCaptureGrammar so "запиши" still beats "расскажи".
The rest: queryFeeds keeps task/467's conditional claim (V-474 supersedes the
unconditional one), rank.go keeps Spoken and drops pluralTasksRU because
say.CountWord is the one copy of Russian count agreement, and vendor/ was
re-vendored — the merged modules.txt claimed replaces for nexus and praxis
that neither go.mod has.
Routing fixture 58/82, unchanged from both sides.
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()[1])
|
|
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)
|
|
}
|
|
}
|