b2521988e1
The daemon tests that compared against one literal ask the entry instead: IsAck names the line she could have said without pinning the wording. The eval scores every ack variant on the persona checks the nudges already pass.
69 lines
2.3 KiB
Go
69 lines
2.3 KiB
Go
package main
|
|
|
|
import (
|
|
"context"
|
|
"testing"
|
|
|
|
"github.com/kami/maven/internal/llm"
|
|
"github.com/kami/maven/internal/phraser"
|
|
"github.com/kami/maven/internal/router"
|
|
"github.com/kami/maven/internal/voice"
|
|
)
|
|
|
|
// The phrasing itself is tested in internal/phraser. What is left here is the
|
|
// only thing the daemon adds: the stub floor, on the three ways a reply can
|
|
// fail to arrive.
|
|
type stubCompleter struct {
|
|
out string
|
|
err error
|
|
}
|
|
|
|
func (s stubCompleter) Complete(_ context.Context, _ llm.Req) (string, error) { return s.out, s.err }
|
|
|
|
func TestLLMReplierPassesTheModelReplyThrough(t *testing.T) {
|
|
r := newLLMReplier(stubCompleter{out: `{"response":"записала, кофе закончился","mood":"neutral"}`}, nil)
|
|
got := r.Reply(router.Decision{Intent: router.IntentNote, Slots: router.Slots{Text: "кофе закончился"}})
|
|
if got != "записала, кофе закончился" {
|
|
t.Errorf("got %q, want %q", got, "записала, кофе закончился")
|
|
}
|
|
}
|
|
|
|
func TestLLMReplierFallsBackToStubOnError(t *testing.T) {
|
|
r := newLLMReplier(stubCompleter{err: errReplierTest}, nil)
|
|
assertAck(t, r, router.Decision{Intent: router.IntentNote}, phraser.AckNote, "llm error")
|
|
}
|
|
|
|
func TestLLMReplierFallsBackToStubOnEmpty(t *testing.T) {
|
|
r := newLLMReplier(stubCompleter{out: ""}, nil)
|
|
assertAck(t, r, router.Decision{Intent: router.IntentNote}, phraser.AckNote, "empty llm")
|
|
}
|
|
|
|
func TestLLMReplierClarifyUsesStub(t *testing.T) {
|
|
r := newLLMReplier(stubCompleter{out: "я всё поняла"}, nil)
|
|
assertStub(t, r, router.Decision{Clarify: true}, "clarify")
|
|
}
|
|
|
|
// assertAck — the stub picks between variants now, so two calls to it are not
|
|
// expected to match. What must hold is that the reply is a line that entry can
|
|
// produce, which is the same claim without pinning one wording.
|
|
func assertAck(t *testing.T, r *llmReplier, d router.Decision, key, what string) {
|
|
t.Helper()
|
|
if got := r.Reply(d); !phraser.IsAck(key, nil, got) {
|
|
t.Errorf("on %s: got %q, want a %q line", what, got, key)
|
|
}
|
|
}
|
|
|
|
func assertStub(t *testing.T, r *llmReplier, d router.Decision, what string) {
|
|
t.Helper()
|
|
got, want := r.Reply(d), voice.NewStubReplier().Reply(d)
|
|
if got != want {
|
|
t.Errorf("on %s: got %q, want stub %q", what, got, want)
|
|
}
|
|
}
|
|
|
|
var errReplierTest = errTest("llm down")
|
|
|
|
type errTest string
|
|
|
|
func (e errTest) Error() string { return string(e) }
|