8833a9c76b
The prompt, the call and the output parsing now live in internal/phraser. What is left here is the one thing the daemon adds: a clarify, a model error and an unusable generation all answer from voice.StubReplier, so a turn never breaks on the model. The duplicated stripThink and parseResponseMood copies are gone; capture.go uses phraser.StripThink.
35 lines
1017 B
Go
35 lines
1017 B
Go
package main
|
|
|
|
import (
|
|
"context"
|
|
|
|
"github.com/kami/maven/internal/phraser"
|
|
"github.com/kami/maven/internal/router"
|
|
"github.com/kami/maven/internal/voice"
|
|
)
|
|
|
|
// llmReplier is the daemon-side wiring around phraser.Replier: it owns the
|
|
// deterministic floor, and nothing else. The phrasing itself, the prompt and the
|
|
// output parsing live in internal/phraser so the eval can score them (#396).
|
|
type llmReplier struct {
|
|
p *phraser.Replier
|
|
stub *voice.StubReplier
|
|
}
|
|
|
|
func newLLMReplier(c phraser.Completer, block func() string) *llmReplier {
|
|
return &llmReplier{p: phraser.NewReplier(c, block), stub: voice.NewStubReplier()}
|
|
}
|
|
|
|
// Reply never fails: a clarify, a model error and an unusable generation all
|
|
// answer from the stub, which is what keeps a turn from breaking on the model.
|
|
func (r *llmReplier) Reply(d router.Decision) string {
|
|
if d.Clarify {
|
|
return r.stub.Reply(d)
|
|
}
|
|
out, err := r.p.PhraseReply(context.Background(), d)
|
|
if err != nil || out == "" {
|
|
return r.stub.Reply(d)
|
|
}
|
|
return out
|
|
}
|