ed491e23fc
The review comment asked for basic DI. The answer is the idiom voice.go already had for capabilities — a cohesive *Wiring struct — applied to a group that is not a capability toggle, plus the decision written down so it is a rule and not a habit. recallWiring holds the embedder, the vector store, the personal boundary and the two numbers that gate an answer. They sat in three places on reactiveHandler, with the gate numbers a hundred lines from the store they gate. Its zero value means no recall, so it is a value, not a pointer like the optional-capability groups. dataStore stays out of it. patterns.go, ecosystem_acts.go and confirm.go use it, so it is not part of this cluster. docs/handler-wiring.md records the choice, rejects a container or a wire-style generator outright, defers narrow per-handler interfaces to the package split that would justify them, and states the constraint the task named: a wiring change does not ride a feature PR. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
60 lines
2.4 KiB
Go
60 lines
2.4 KiB
Go
package main
|
|
|
|
import (
|
|
"github.com/kami/maven/internal/memory"
|
|
"github.com/kami/maven/internal/router"
|
|
)
|
|
|
|
// bestRecall is the read side of the long-term memory store: the top hit when
|
|
// it clears the confidence gate. The index holds BOTH notes and facts, and
|
|
// either can win — the caller looks at the returned hit's meta["type"] to see
|
|
// which. Facts aren't in the notes table, so this is the only path that can
|
|
// answer "when did I last …?" from a captured fact.
|
|
//
|
|
// The whole hit is returned, not just its text, because "which memory answered"
|
|
// decides how the answer is said: a note gets phrased in Maven's voice, a fact
|
|
// is read back as stored.
|
|
//
|
|
// ok=false when the hit fails the confidence gate (see memory.Confident: an
|
|
// absolute floor plus a margin over the runner-up) or carries no text.
|
|
func bestRecall(results []memory.Result, minScore, minMargin float64) (memory.Result, bool) {
|
|
if !memory.Confident(results, minScore, minMargin) {
|
|
return memory.Result{}, false
|
|
}
|
|
if results[0].Meta["text"] == "" {
|
|
return memory.Result{}, false
|
|
}
|
|
return results[0], true
|
|
}
|
|
|
|
// recallWiring — the recall subsystem's dependencies, held as one group on
|
|
// reactiveHandler (Vikunja #433). It is the worked example for the wiring
|
|
// decision in docs/handler-wiring.md: cohesive groups of fields, not thirty
|
|
// loose ones, so a handler names what it needs and the package can be split
|
|
// later without exporting the whole struct.
|
|
//
|
|
// The zero value is usable and means "no recall": no embedder, no vector
|
|
// store, and a gate that is never consulted because nothing is ever searched.
|
|
type recallWiring struct {
|
|
// embedder — reused for note write/query (same model as the classifier).
|
|
embedder router.Embedder
|
|
|
|
// memStore — the vector index over notes and facts.
|
|
memStore memory.Store
|
|
|
|
// boundary — the embedded seed sets behind the personal boundary
|
|
// (personalboundary.go). Zero value is usable and loads on first query;
|
|
// with no embedder it never loads and the boundary uses personalMarkers.
|
|
boundary personalBoundary
|
|
|
|
// minScore — the note-recall confidence gate. Top cosine below this ⇒
|
|
// "I don't know" instead of a guess. Tuned for the ONNX embedder; a knob,
|
|
// not load-bearing math (same posture as the presence thresholds). Set by
|
|
// wireVoice from VoiceConfig; default 0.55.
|
|
minScore float64
|
|
|
|
// minMargin — the second half of that gate: how far the top hit must beat
|
|
// the runner-up. 0 ⇒ margin off.
|
|
minMargin float64
|
|
}
|