Files
Maven/cmd/mavend/kiwixwire.go
T
kami 79893d646b kiwix: read the article, not the snippet, and state the persona as morphology
Two things that were each half-done.

The prompts handed the model copyable examples. chatSystemPrompt lost its
openers this morning and the "Я подумала, что" tic went with them, but "не
забыл ли я" appeared in its place: the removed example had been suppressing
the masculine self-reference by accident. Two predicatives are not enough
signal, so the rule is now stated as morphology (-ла) rather than as a pair of
words — a suffix rule generalises where an example only gets copied.
querySystemPrompt had the same defect and gets the same treatment; its "вот что
я нашла: " opener is deliberate and stays.

internal/kiwix had no caller. actions_query.go said "once internal/kiwix is
wired into this chain" and that never happened. It is wired now, between the
notes pass and the web source: everything of his answers first, and only what
is left over is looked up. Off unless a `kiwix` block names a server and a book.

Reading the search snippet does not work. Kiwix builds it from wherever the
keyword matched, which on Wikipedia is the navigation box at the foot of the
page — the first version of this answered "что такое фотосинтез?" by reciting
"Ecological economics Ecological footprint Ecological forecasting …". Client
grows an Article method; the head of the article is the lead paragraph, which
is the definition the snippet was meant to be. Verified on the box: the same
question now answers correctly off the ZIM.

Only the rewritten query leaves the process. A test asserts it: a turn carrying
a stored note must not put that note in the search string.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01TrVSBKe3RFDF4fGYKWYQnX
2026-08-01 19:46:39 +04:00

55 lines
1.8 KiB
Go

package main
import (
"log"
"github.com/kami/maven/internal/config"
"github.com/kami/maven/internal/kiwix"
"github.com/kami/maven/internal/llm"
)
// kiwixWiring — the offline encyclopedia, assembled. nil ⇒ off, which is the
// default: the query chain simply has no ZIM source.
//
// The rewriter is separately optional. Searching without one is legal and
// mostly useless against English ZIMs, but it is the honest degraded mode when
// there is no llama-server to rewrite with, and it is what `rewrite: false`
// asks for.
type kiwixWiring struct {
client *kiwix.Client
rewriter *kiwix.Rewriter // nil ⇒ the question is searched verbatim
book string
max int
runes int
}
// wireKiwix builds the ZIM reader from the `kiwix` block, or returns nil when
// there is none. config.Normalise has already dropped a block with no URL and
// filled the two size defaults, so this does no validation of its own.
//
// The llm client is the phraser's swap-aware one (llmClientFor), so a model
// swap re-points the rewriter with everything else. A nil client means there is
// no resident model at all; that degrades the rewriter, not the source.
func wireKiwix(cfg *config.Config, c *llm.Client) *kiwixWiring {
if cfg.Kiwix == nil {
return nil
}
kc := cfg.Kiwix
w := &kiwixWiring{
client: kiwix.New(kc.URL),
book: kc.Book,
max: kc.MaxResults,
runes: kc.SnippetRunes,
}
switch {
case !kc.RewriteEnabled():
log.Printf("voice: kiwix at %s (book %q, query rewriting off by config)", kc.URL, kc.Book)
case c == nil:
log.Printf("voice: kiwix at %s (book %q, no llama-server: searching questions verbatim)", kc.URL, kc.Book)
default:
w.rewriter = kiwix.NewRewriter(c)
log.Printf("voice: kiwix at %s (book %q)", kc.URL, kc.Book)
}
return w
}