the chat path answers with no llama-server (V-45)

Step 4 of the QA list, pinned as a test rather than checked by hand: the deploy
has llama-server up and stopping it to look is not available here.

Both halves of a turn call the model. The cascade falls to the classifier and
the replier falls to the stub, and each was covered separately by a stubbed
error value. This wires a real client at a closed port so a dial error walks
the whole path, and asserts three utterances still come back with words.

Also pins that daemonAPI.Chat errors only when the voice path was never wired,
which is what keeps mavweb's /api/chat off its error branch when the model is
down. mavweb never returns 500 there in any case: it redirects to /chat.
This commit is contained in:
2026-08-05 13:32:35 +04:00
parent 9d80a39a30
commit dd63180e44
+50
View File
@@ -0,0 +1,50 @@
package main
import (
"context"
"testing"
"time"
"github.com/kami/maven/internal/llm"
"github.com/kami/maven/internal/router"
)
// The chat path must answer when llama-server is down (Vikunja #45 step 4).
// Both halves of a turn call the model — the router and the replier — and each
// has its own floor: the cascade falls to the classifier, the replier falls to
// the stub. This wires a client at a closed port so both floors are exercised
// by a dial error rather than by a stubbed error value.
func TestChatAnswersWithNoLlamaServer(t *testing.T) {
h, _, _ := newClarifyHandler(t)
dead := llm.New("http://127.0.0.1:1", 500*time.Millisecond)
emb := router.NewHashEmbedder(1024)
h.recall.embedder = emb
h.router = buildRouter(emb, h.matcher, 0.55, pickLLMRouter(true, dead))
h.replier = newLLMReplier(dead, nil)
ctx := withDialogueID(context.Background(), dialogueIDFor(sourceText, "web"))
for _, utt := range []string{
"привет",
"запиши что кофе закончился",
"что у меня сегодня",
} {
reply := h.handleText(ctx, "web", utt)
if reply == "" {
t.Errorf("%q answered with nothing; a dead model must degrade to the stub", utt)
}
}
}
// daemonAPI.Chat reports an error only when the voice path was never wired.
// A turn that reaches handleText always carries text, which is what keeps
// mavweb's /api/chat off its error branch when the model is down.
func TestChatAPIErrsOnlyWhenUnwired(t *testing.T) {
d := &daemonAPI{}
if _, err := d.Chat(context.Background(), "web", "привет"); err == nil {
t.Fatal("an unwired daemon must say so")
}
d.chatFn = func(context.Context, string, string) string { return "" }
if _, err := d.Chat(context.Background(), "web", "привет"); err != nil {
t.Fatalf("a wired daemon must not error: %v", err)
}
}