Merge V-555 tail: she does not look herself up (#201)
This commit is contained in:
@@ -122,6 +122,12 @@ var querySources = []querySource{
|
||||
{name: "network", answer: (*reactiveHandler).queryNetwork},
|
||||
{name: "calendar", answer: (*reactiveHandler).queryCalendar, dateAware: true},
|
||||
{name: "weather", answer: (*reactiveHandler).queryWeather},
|
||||
// A question about her, above the three sources that search his own data
|
||||
// (Vikunja #555). It has no answer anywhere else: below the boundary
|
||||
// SearXNG answers about somebody else's assistant, and above it his notes
|
||||
// answer by proximity — "кто ты" came back from a note of his, measured on
|
||||
// the box, because the recall index has no idea the subject is her.
|
||||
{name: "self", answer: (*reactiveHandler).querySelf},
|
||||
{name: "embed", answer: (*reactiveHandler).queryEmbed},
|
||||
{name: "memory", answer: (*reactiveHandler).queryMemory},
|
||||
{name: "notes", answer: (*reactiveHandler).queryNotes},
|
||||
@@ -129,11 +135,6 @@ var querySources = []querySource{
|
||||
// below answers from the world's. A question about him that got this far
|
||||
// has no answer in his data, and no outside source can supply one, so this
|
||||
// stops the walk rather than let the encyclopedia and the model guess.
|
||||
// A question about her sits just above the boundary, because it has no
|
||||
// answer below one: refusing it as his says "не нашла у тебя такой записи"
|
||||
// about her own description, and letting it through asks SearXNG about
|
||||
// somebody else's assistant (Vikunja #555).
|
||||
{name: "self", answer: (*reactiveHandler).querySelf},
|
||||
{name: "personal", answer: (*reactiveHandler).queryPersonal},
|
||||
// The world, read live. Owner's ruling of 2026-08-02: a metasearch hit beats
|
||||
// a frozen ZIM, so SearXNG asks before Kiwix does. Nothing of his is at
|
||||
|
||||
+1
-1
@@ -104,7 +104,7 @@ func (h *reactiveHandler) querySelf(ctx context.Context, t *queryTurn) (string,
|
||||
var reply string
|
||||
if h.phraser != nil {
|
||||
var err error
|
||||
reply, err = h.phraser.PhraseQuery(ctx, t.dec.Utterance, []string{selfDescription})
|
||||
reply, err = h.phraser.PhraseSelf(ctx, t.dec.Utterance, selfDescription)
|
||||
if err != nil {
|
||||
log.Printf("voice: phrase self: %v", err)
|
||||
}
|
||||
|
||||
@@ -941,6 +941,36 @@ func (p *LLMPhraser) knowledgePrompt(utterance string) (sys, user string) {
|
||||
fmt.Sprintf("Пользователь спрашивает: \"%s\".", utterance)
|
||||
}
|
||||
|
||||
// PhraseSelf answers a question about her from her own description. Same
|
||||
// discipline as the evidence branch — say only what the text says — and a
|
||||
// different opener, because "вот что я нашла: я — твоя помощница" says she
|
||||
// looked herself up (Vikunja #555). She did not; this is the one subject she
|
||||
// does not have to read about.
|
||||
//
|
||||
// On any error it reads the description out rather than ship a fragment. That
|
||||
// is already a readable answer, which is why this needs no separate fallback.
|
||||
func (p *LLMPhraser) PhraseSelf(ctx context.Context, utterance, description string) (string, error) {
|
||||
sys := persona.Prepend(p.cfg.ContextBlock,
|
||||
"Он спрашивает о тебе. Отвечай ТОЛЬКО по описанию, которое тебе дали: всё, что ты говоришь о себе, должно быть в нём. "+
|
||||
"Не добавляй умений, которых там нет, и не догадывайся. Не начинай с \"вот что я нашла\" — ты говоришь о себе, а не о находке. "+
|
||||
"Отвечай по-русски, коротко и своими словами. О себе — в женском роде, глаголы в прошедшем времени с окончанием -ла. "+
|
||||
"Он мужчина, обращайся к нему на \"ты\". Отвечай ТОЛЬКО одним объектом JSON: {\"response\": \"...\", \"mood\": \"neutral\"}.")
|
||||
prompt := fmt.Sprintf("Он спрашивает: %q\n\nТвоё описание:\n%s\n\nОтветь ему на то, что он спросил.", utterance, description)
|
||||
resp, err := p.chatWithSystem(ctx, sys, prompt, 768)
|
||||
text, _, perr := parseResponseMood(resp)
|
||||
if err != nil || perr != nil {
|
||||
cause := err
|
||||
if cause == nil {
|
||||
cause = perr
|
||||
}
|
||||
return description, fmt.Errorf("phrase self: %w", cause)
|
||||
}
|
||||
if text != "" {
|
||||
return text, nil
|
||||
}
|
||||
return description, nil
|
||||
}
|
||||
|
||||
// evidencePrompt — the sources branch: read these, add nothing. Shared with
|
||||
// PhraseWorld for the same reason as knowledgePrompt.
|
||||
func (p *LLMPhraser) evidencePrompt(utterance string, notes []string) (sys, user string) {
|
||||
|
||||
@@ -49,6 +49,9 @@ type Phraser interface {
|
||||
PhraseNudge(ctx context.Context, c loop.Candidate) (delivery.PhrasedNudge, error)
|
||||
PhraseReminder(ctx context.Context, d loop.ReminderDecision) (delivery.PhrasedReminder, error)
|
||||
PhraseQuery(ctx context.Context, utterance string, notes []string) (string, error)
|
||||
// PhraseSelf answers a question about her from her own description, which
|
||||
// is not a source she read and must not be phrased as one (Vikunja #555).
|
||||
PhraseSelf(ctx context.Context, utterance, description string) (string, error)
|
||||
PhraseChat(ctx context.Context, utterance string, history []dialogue.Turn) (string, error)
|
||||
Close() error
|
||||
}
|
||||
@@ -81,6 +84,13 @@ func (s *Stub) PhraseQuery(_ context.Context, _ string, notes []string) (string,
|
||||
return SourcesFallback(strings.Join(notes, "; ")), nil
|
||||
}
|
||||
|
||||
// PhraseSelf reads the description out as it stands. There is nothing to fall
|
||||
// back to and nothing to shorten: the text is already written in her voice, and
|
||||
// that is the whole reason it is a constant rather than a prompt.
|
||||
func (s *Stub) PhraseSelf(_ context.Context, _, description string) (string, error) {
|
||||
return description, nil
|
||||
}
|
||||
|
||||
// Close implements Phraser.Close (no-op for the stub).
|
||||
func (s *Stub) Close() error { return nil }
|
||||
|
||||
|
||||
Reference in New Issue
Block a user