Files
Maven/cmd/mavend/self.go
T
claude 5815f0b8f3 a question about herself has an answer (V-555)
"что ты умеешь" reached the personal boundary, which claimed it as his
and said "не знаю — не нашла у тебя такой записи" about her own
description. Letting it past would be no better: SearXNG answers about
somebody else's assistant.

A self query source above the boundary, reading one frozen description.
It is NOT a note — notes are his, and a note about her would come back
for "что я записал", would be fed to the digestion worker as something
he said, and would be recalled by proximity for questions that are not
about her.

The description names only what this box does. Everything that depends
on config — the house, the LAN, the feeds, the list, weather, telegram —
is named as depending on what he allowed, and a test pins that split:
inventing a capability here is the same defect as inventing a fact.

topicSelf is scored like every other topic, with a narrow keyword floor
for the no-embedder case. "что ты умеешь" moved off topicOther, where it
had been sitting so an attention question had something to lose to — a
phrasing on two sides never clears the margin. TestONNXTopics 38/38 ->
43/43 on held-out utterances.
2026-08-05 22:59:56 +04:00

117 lines
5.4 KiB
Go

package main
import (
"context"
"log"
"regexp"
"github.com/kami/maven/internal/phraser"
)
// A question about her — "что ты умеешь", "кто ты" — used to have no answer at
// all (Vikunja #555). It reached the personal boundary, which claimed it as his
// and said "не знаю — не нашла у тебя такой записи", because the boundary knows
// two sides and this is neither: her own description is not his data and it is
// not the world's either. Letting it past the boundary is no better, because
// then SearXNG answers about somebody else's assistant.
//
// The description does NOT live in the note store. Notes are his. A note about
// her sitting in his index would come back for "что я записал", would be fed to
// the digestion worker as something he said, and would be recalled by vector
// proximity for questions that are not about her at all. It is her own text, so
// it lives here, in one place, and it is the only copy.
//
// This source sits ABOVE the boundary, because a question about her never had
// an answer below it.
// selfDescription — what she is and what this box actually does. Frozen text,
// and the one rule for editing it: name only what is really wired. Anything
// that depends on config — the house, the LAN, the feeds, telegram, search — is
// named as depending on what he allowed, never claimed outright. Inventing a
// capability here is the same defect as inventing a fact, and it is worse than
// silence because he would plan around it.
//
// Written in her own voice, feminine, addressing him informally, because it is
// handed to the phraser as the evidence for the answer and the phraser will
// keep the words it is given.
const selfDescription = `Я Мэйвен, твоя помощница. Я живу на твоём сервере, ` +
`и наружу уходит только поисковый запрос — больше ничего.
Что я делаю сама: запоминаю, что ты мне говоришь, и потом отвечаю на вопросы ` +
`об этом; веду заметки; ставлю напоминания; читаю твой календарь и задачи; ` +
`отвечаю на вопросы о мире — сначала поиском, а если сети нет, то по ` +
`офлайновой энциклопедии.
Что зависит от того, что ты мне разрешил: дом, локальная сеть, ленты, ` +
`список покупок, погода, телеграм. Если что-то из этого не настроено, я ` +
`скажу об этом прямо, а не буду выдумывать ответ.
Говорю по-русски и по-английски.`
// selfSeeds — the questions this source claims. Scoring data like every other
// topic set: editing one moves the recogniser and has to be re-measured against
// TestONNXTopics.
//
// All of them are about HER — what she is, what she can do, who made her. The
// neighbouring set is topicAttend, "что требует внимания", which asks about the
// state of his things; the two share almost nothing but the second person.
var selfSeeds = []string{
"что ты умеешь",
"что ты можешь делать",
"кто ты такая",
"расскажи о себе",
"какие у тебя возможности",
// Added after measuring: it won self by 0.0002, under the margin, and the
// floor does not carry it — "способна" names no verb the floor matches.
"на что ты способна",
"чем ты можешь помочь",
"what can you do",
"who are you",
}
// selfFloor — the offline floor, for a handler with no embedder or a turn whose
// vector never got computed. Narrow on purpose, like every other floor here: it
// answers only when the seeds cannot, and a broad guess made blind is worse
// than a narrow one.
//
// Go's \b is ASCII-only and never fires next to a Cyrillic letter, so the
// Russian patterns spell the boundary out.
var selfPatterns = []*regexp.Regexp{
regexp.MustCompile(`(?i)(^|[^\p{L}\p{N}])ты\s+(умеешь|можешь)([^\p{L}\p{N}]|$)`),
regexp.MustCompile(`(?i)(^|[^\p{L}\p{N}])кто\s+ты([^\p{L}\p{N}]|$)`),
regexp.MustCompile(`(?i)(^|[^\p{L}\p{N}])(расскажи|поведай)\s+о\s+себе([^\p{L}\p{N}]|$)`),
regexp.MustCompile(`(?i)\bwhat\s+can\s+you\s+do\b`),
regexp.MustCompile(`(?i)\bwho\s+are\s+you\b`),
}
func selfFloor(utterance string) bool {
for _, re := range selfPatterns {
if re.MatchString(utterance) {
return true
}
}
return false
}
// querySelf answers a question about her from selfDescription. The description
// goes through the phraser as evidence so the answer is shaped to what he
// asked — "что ты умеешь" and "кто ты" want different halves of it — and falls
// back to the text itself, which is already readable, if the model is down.
func (h *reactiveHandler) querySelf(ctx context.Context, t *queryTurn) (string, bool) {
if !h.turnIsAbout(ctx, t, topicSelf, selfFloor) {
return "", false
}
var reply string
if h.phraser != nil {
var err error
reply, err = h.phraser.PhraseQuery(ctx, t.dec.Utterance, []string{selfDescription})
if err != nil {
log.Printf("voice: phrase self: %v", err)
}
}
if reply == "" {
reply = phraser.Q(phraser.QueryFound, map[string]string{"text": selfDescription})
}
return reply, true
}