mavend: world questions ask the workstation, and name the gap when it is asleep (V-490)
queryGeneral has nothing fetched to fall back on, so it is the sharp case: with a workstation configured and asleep he is told that, rather than told something false in a confident voice. The 1.7B answering a world question is where "Война и мир" got Левитан as its author. The sources that already hold a passage — a live search, a ZIM article, a page he named — go through the world model too, but read the passage back when it is not there instead of naming a gap. A real quote beats "не могу сейчас", and nothing is invented on either path. The Stub and every test double keep the Phraser interface they have. PhraseWorld is reached by assertion, and a phraser without it is the no-workstation case.
This commit is contained in:
+25
-24
@@ -13,6 +13,7 @@ import (
|
||||
"github.com/kami/maven/internal/ipc"
|
||||
"github.com/kami/maven/internal/memory"
|
||||
"github.com/kami/maven/internal/morning"
|
||||
"github.com/kami/maven/internal/phraser"
|
||||
"github.com/kami/maven/internal/router"
|
||||
"github.com/kami/maven/internal/rss"
|
||||
"github.com/kami/maven/internal/store"
|
||||
@@ -523,10 +524,7 @@ func (h *reactiveHandler) queryWeb(ctx context.Context, t *queryTurn) (string, b
|
||||
// the question he actually asked. She answers the question, she does not
|
||||
// recite the page.
|
||||
snippet := page.Title + "\n" + crawl.TrimRunes(page.Text, webPageContextRunes)
|
||||
reply, perr := h.phraser.PhraseQuery(ctx, t.dec.Utterance, []string{snippet})
|
||||
if perr != nil {
|
||||
log.Printf("voice: web: phrase: %v", perr)
|
||||
}
|
||||
reply := h.phraseSource(ctx, "web", t.dec.Utterance, []string{snippet})
|
||||
if reply == "" {
|
||||
// No phraser (or it failed): read back the top of the page rather than
|
||||
// pretend the fetch did not happen.
|
||||
@@ -592,14 +590,7 @@ func (h *reactiveHandler) querySearch(ctx context.Context, t *queryTurn) (string
|
||||
// question he asked, not something to recite. The trim is one budget over the
|
||||
// joined block, so a long first snippet cannot crowd out the rest.
|
||||
evidence := crawl.TrimRunes(strings.Join(resp.Snippets(), "\n"), h.search.runes)
|
||||
var reply string
|
||||
if h.phraser != nil {
|
||||
var perr error
|
||||
reply, perr = h.phraser.PhraseQuery(ctx, t.dec.Utterance, []string{evidence})
|
||||
if perr != nil {
|
||||
log.Printf("voice: search: phrase: %v", perr)
|
||||
}
|
||||
}
|
||||
reply := h.phraseSource(ctx, "search", t.dec.Utterance, []string{evidence})
|
||||
if reply == "" {
|
||||
// No phraser, or it failed. Read back the best evidence rather than
|
||||
// pretend the search did not happen.
|
||||
@@ -680,14 +671,7 @@ func (h *reactiveHandler) queryKiwix(ctx context.Context, t *queryTurn) (string,
|
||||
// Handed over the same way a note or a page is: context for the question he
|
||||
// asked, not something to recite.
|
||||
snippet := top.Title + "\n" + crawl.TrimRunes(page.Text, h.kiwix.runes)
|
||||
var reply string
|
||||
if h.phraser != nil {
|
||||
var perr error
|
||||
reply, perr = h.phraser.PhraseQuery(ctx, t.dec.Utterance, []string{snippet})
|
||||
if perr != nil {
|
||||
log.Printf("voice: kiwix: phrase: %v", perr)
|
||||
}
|
||||
}
|
||||
reply := h.phraseSource(ctx, "kiwix", t.dec.Utterance, []string{snippet})
|
||||
if reply == "" {
|
||||
// No phraser, or it failed. Read back the best hit rather than pretend
|
||||
// the search did not happen.
|
||||
@@ -755,11 +739,28 @@ func isPersonalQuery(utterance string) bool {
|
||||
return false
|
||||
}
|
||||
|
||||
// queryGeneral — general knowledge from the phraser, the last source before
|
||||
// giving up. It always claims: either the model answers or Maven says she
|
||||
// doesn't know.
|
||||
// queryGeneral — general knowledge, the last source before giving up. It always
|
||||
// claims: either a model answers, or Maven names the gap, or she says she does
|
||||
// not know.
|
||||
//
|
||||
// This is the sharpest case for the naming half. Nothing has been fetched, so
|
||||
// there is no passage to fall back on and no floor under the answer except the
|
||||
// model's weights — and a 1.7B's weights are where the invented answers come
|
||||
// from. With a workstation configured and asleep he is told that, rather than
|
||||
// told something false in a confident voice. With no workstation configured at
|
||||
// all the resident model answers exactly as it does today: naming a gap requires
|
||||
// a gap, and on that box the 1.7B is the whole product.
|
||||
func (h *reactiveHandler) queryGeneral(ctx context.Context, t *queryTurn) (string, bool) {
|
||||
reply, err := h.phraser.PhraseQuery(ctx, t.dec.Utterance, nil)
|
||||
if h.phraser == nil {
|
||||
// No model of any size. That is not the workstation being asleep, so it
|
||||
// is not that gap: it is simply not knowing.
|
||||
return "не знаю.", true
|
||||
}
|
||||
reply, err := h.phraseWorld(ctx, t.dec.Utterance, nil)
|
||||
if errors.Is(err, phraser.ErrNoWorldModel) {
|
||||
log.Printf("voice: %q needs the world model and it is not available", t.dec.Utterance)
|
||||
return worldGap, true
|
||||
}
|
||||
if err != nil || reply == "" {
|
||||
return "не знаю.", true
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user