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 }