phraser: say "даже не знаю, что сказать" when there is nothing to say (V-397)
Review of #108: "поговорили." reads as a summary of a conversation that did not happen. One exported constant now, so the Stub, the LLMPhraser fallback and the daemon all say the same thing. internal/voice/replier.go keeps its own copy — that is the separate replier seam, not this one. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
@@ -40,6 +40,7 @@ import (
|
|||||||
"context"
|
"context"
|
||||||
"log"
|
"log"
|
||||||
|
|
||||||
|
"github.com/kami/maven/internal/phraser"
|
||||||
"github.com/kami/maven/internal/router"
|
"github.com/kami/maven/internal/router"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -65,7 +66,7 @@ func (h *reactiveHandler) actionChat(ctx context.Context, dec router.Decision) s
|
|||||||
log.Printf("voice: chat: %v", err)
|
log.Printf("voice: chat: %v", err)
|
||||||
}
|
}
|
||||||
if reply == "" {
|
if reply == "" {
|
||||||
return "поговорили."
|
return phraser.ChatFallback
|
||||||
}
|
}
|
||||||
return reply
|
return reply
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
// A dead server must be distinguishable from bad phrasing. Both PhraseChat and
|
// A dead server must be distinguishable from bad phrasing. Both PhraseChat and
|
||||||
// PhraseQuery keep the turn alive with canned text — "поговорили.", "не знаю.",
|
// PhraseQuery keep the turn alive with canned text — ChatFallback, "не знаю.",
|
||||||
// "вот что я нашла: …" — and every one of those is also a legitimate reply, so
|
// "вот что я нашла: …" — and every one of those is also a legitimate reply, so
|
||||||
// the text alone cannot say which happened. The error is the only signal, and
|
// the text alone cannot say which happened. The error is the only signal, and
|
||||||
// before Vikunja #397 it was dropped: the talk scorer reported a full run with
|
// before Vikunja #397 it was dropped: the talk scorer reported a full run with
|
||||||
@@ -28,7 +28,7 @@ func TestPhrasingReportsTheFailureWithTheFallback(t *testing.T) {
|
|||||||
}{
|
}{
|
||||||
{"chat", func() (string, error) {
|
{"chat", func() (string, error) {
|
||||||
return p.PhraseChat(context.Background(), "как дела", nil)
|
return p.PhraseChat(context.Background(), "как дела", nil)
|
||||||
}, "поговорили."},
|
}, ChatFallback},
|
||||||
{"knowledge", func() (string, error) {
|
{"knowledge", func() (string, error) {
|
||||||
return p.PhraseQuery(context.Background(), "кто написал войну и мир", nil)
|
return p.PhraseQuery(context.Background(), "кто написал войну и мир", nil)
|
||||||
}, "не знаю."},
|
}, "не знаю."},
|
||||||
|
|||||||
@@ -483,7 +483,7 @@ func (p *LLMPhraser) PhraseQuery(ctx context.Context, utterance string, notes []
|
|||||||
|
|
||||||
// PhraseChat uses the LLM to respond conversationally, building a multi-turn
|
// PhraseChat uses the LLM to respond conversationally, building a multi-turn
|
||||||
// message array from dialogue history + the current user utterance. On any LLM
|
// message array from dialogue history + the current user utterance. On any LLM
|
||||||
// error it returns both "поговорили." and the error, on the same rule as
|
// error it returns both ChatFallback and the error, on the same rule as
|
||||||
// PhraseQuery: the fallback keeps the turn alive, the error stays visible.
|
// PhraseQuery: the fallback keeps the turn alive, the error stays visible.
|
||||||
func (p *LLMPhraser) PhraseChat(ctx context.Context, utterance string, history []dialogue.Turn) (string, error) {
|
func (p *LLMPhraser) PhraseChat(ctx context.Context, utterance string, history []dialogue.Turn) (string, error) {
|
||||||
sys := chatSystemPrompt(p.cfg.ContextBlock)
|
sys := chatSystemPrompt(p.cfg.ContextBlock)
|
||||||
@@ -501,11 +501,11 @@ func (p *LLMPhraser) PhraseChat(ctx context.Context, utterance string, history [
|
|||||||
|
|
||||||
resp, err := p.chatWithMessages(ctx, msgs, 768)
|
resp, err := p.chatWithMessages(ctx, msgs, 768)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "поговорили.", fmt.Errorf("phrase chat: %w", err)
|
return ChatFallback, fmt.Errorf("phrase chat: %w", err)
|
||||||
}
|
}
|
||||||
text, _, perr := parseResponseMood(resp)
|
text, _, perr := parseResponseMood(resp)
|
||||||
if perr != nil {
|
if perr != nil {
|
||||||
return "поговорили.", fmt.Errorf("phrase chat: %w", perr)
|
return ChatFallback, fmt.Errorf("phrase chat: %w", perr)
|
||||||
}
|
}
|
||||||
if text != "" {
|
if text != "" {
|
||||||
return text, nil
|
return text, nil
|
||||||
|
|||||||
@@ -66,11 +66,17 @@ type Stub struct{}
|
|||||||
// NewStub builds the floor phraser. no config — the Stub is stateless.
|
// NewStub builds the floor phraser. no config — the Stub is stateless.
|
||||||
func NewStub() *Stub { return &Stub{} }
|
func NewStub() *Stub { return &Stub{} }
|
||||||
|
|
||||||
|
// ChatFallback — what she says on the chat path when the model gave her
|
||||||
|
// nothing to say. It replaced "поговорили.", which reads as a summary of a
|
||||||
|
// conversation that did not happen. Said out loud this one is an admission,
|
||||||
|
// which is what it is.
|
||||||
|
const ChatFallback = "даже не знаю, что сказать."
|
||||||
|
|
||||||
// PhraseChat returns a stub reply — the LLMPhraser replaces this with a
|
// PhraseChat returns a stub reply — the LLMPhraser replaces this with a
|
||||||
// prompted response from the model. The history parameter is accepted but
|
// prompted response from the model. The history parameter is accepted but
|
||||||
// ignored at the stub level (the production impl uses it for multi-turn).
|
// ignored at the stub level (the production impl uses it for multi-turn).
|
||||||
func (s *Stub) PhraseChat(_ context.Context, _ string, _ []dialogue.Turn) (string, error) {
|
func (s *Stub) PhraseChat(_ context.Context, _ string, _ []dialogue.Turn) (string, error) {
|
||||||
return "поговорили.", nil
|
return ChatFallback, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// PhraseQuery returns a deterministic summary of the best matching notes.
|
// PhraseQuery returns a deterministic summary of the best matching notes.
|
||||||
|
|||||||
Reference in New Issue
Block a user