Documentation
¶
Overview ¶
Package recall is a tiny full-text index over saved sessions. It powers the /recall slash command — search across every conversation you've had with yottacode, ranked by FTS5 relevance.
The index lives at ~/.yottacode/index.sqlite and is rebuilt incrementally whenever a session is saved. At startup the TUI re-indexes every session in a background goroutine so historical sessions become searchable.
Index ¶
- Constants
- func Backfill(idx *Index) error
- type Embedder
- type Hit
- type Index
- func (idx *Index) BackfillVectors(ctx context.Context, e Embedder, model string) error
- func (idx *Index) BackfillVectorsForSession(ctx context.Context, e Embedder, model, sessionID string) error
- func (idx *Index) Close() error
- func (idx *Index) IndexSession(s *session.Session) error
- func (idx *Index) PutVector(sessionID string, msgIndex int, model, content string, vec []float32) error
- func (idx *Index) Search(query string, limit int) ([]Hit, error)
- func (idx *Index) SearchSemantic(queryVec []float32, opts SemanticSearchOpts) ([]ScoredHit, error)
- func (idx *Index) UnvectoredMessages(model string) ([]MsgRef, error)
- type MsgRef
- type ScoredHit
- type SemanticSearchOpts
Constants ¶
const ( ScopeProject = "project" ScopeUser = "user" ScopeAll = "all" )
Scope values for SearchSemantic. "project" restricts recall to sessions in the caller's project (see projectScopeClause); "user"/"all" (and anything else) search the whole store. The store is already per-user under ~/.yottacode, so "user" and "all" are equivalent today — both are accepted so the config vocabulary in the plan stays intact. There is no "off" scope: auto-recall is switched off with `auto = false`.
Variables ¶
This section is empty.
Functions ¶
Types ¶
type Embedder ¶ added in v0.4.0
Embedder is the narrow slice of memory.EmbedClient that vector backfill needs. Kept as an interface here so the recall package doesn't import memory (which would risk an import cycle and pull an HTTP client into a storage package). *memory.EmbedClient satisfies it.
type Hit ¶
type Hit struct {
SessionID string
SessionName string
Model string
Created time.Time
Role adapter.Role
MsgIndex int
Snippet string
}
Hit is one search result: the message that matched plus the surrounding session metadata. Snippet contains FTS5-highlighted match context with `[…]` brackets around the matched terms.
type Index ¶
type Index struct {
// contains filtered or unexported fields
}
Index is the writable handle on the FTS5 database. Safe to share across goroutines; writes through one Index are serialized, and transient SQLite writer contention from other handles/processes is retried.
func MustOpenForTest ¶
MustOpenForTest opens a fresh in-temp-dir index for use from another package's tests. Panics on failure (which would mean the test fixture itself is broken). Lives in the production file so it's exported, but is only intended to be called from *_test.go.
func Open ¶
Open returns the index living at ~/.yottacode/index.sqlite, creating the directory and schema as needed.
func (*Index) BackfillVectors ¶ added in v0.4.0
BackfillVectors embeds every message across all sessions that is missing or stale for the given model. Intended to run in a background goroutine at startup.
func (*Index) BackfillVectorsForSession ¶ added in v0.4.0
func (idx *Index) BackfillVectorsForSession(ctx context.Context, e Embedder, model, sessionID string) error
BackfillVectorsForSession embeds only the given session's missing/stale messages — the cheap incremental path run after each turn, so a conversation becomes recallable in later sessions without waiting for the next startup backfill. Typically embeds just the turn's new user/assistant messages.
func (*Index) Close ¶
Close releases the underlying database handle. It's fine to ignore the error during shutdown.
func (*Index) IndexSession ¶
IndexSession upserts every user/assistant message body for the given session. Replaces any prior FTS rows for that session id, so re-indexing after a turn is correct (and cheap — sessions are at most a few KB).
func (*Index) PutVector ¶ added in v0.4.0
func (idx *Index) PutVector(sessionID string, msgIndex int, model, content string, vec []float32) error
PutVector upserts one message embedding, recording the content hash so a later re-index can detect if the underlying message text changed. Serialized through the write mutex and retried on SQLite writer contention, matching IndexSession.
func (*Index) Search ¶
Search runs an FTS5 MATCH query and returns up to `limit` hits sorted by rank (most relevant first). limit defaults to 10 when ≤ 0.
The first attempt uses the raw query so power users can still write FTS5-native expressions ("auth OR jwt", "\"exact phrase\"", etc.). On a syntax failure we retry with a sanitized version so naive inputs like "nothing-matches-this" — which FTS5 reads as a NOT operator — still produce a clean empty result instead of a SQL error.
func (*Index) SearchSemantic ¶ added in v0.4.0
func (idx *Index) SearchSemantic(queryVec []float32, opts SemanticSearchOpts) ([]ScoredHit, error)
SearchSemantic ranks stored message embeddings by cosine similarity to queryVec and returns the top hits at or above opts.MinScore. Only vectors produced by opts.Model are considered — a vector from another embedding model lives in a different space and its cosine would be noise. Project scope restricts to sessions sharing opts.Cwd; the live session is excluded via opts.ExcludeSession.
type ScoredHit ¶ added in v0.4.0
ScoredHit is a semantic search result: a Hit plus its cosine score against the query vector.
type SemanticSearchOpts ¶ added in v0.4.0
type SemanticSearchOpts struct {
Model string // embed model; only vectors from this model are ranked
Scope string // ScopeProject | ScopeUser | ScopeAll
Cwd string // used when Scope == ScopeProject
ProjectRoots []string // roots that count as "this project" for ScopeProject; sessions at or below any of them match. Empty → exact Cwd only
ExcludeRoots []string // sensitive project roots; sessions at or below any of them never match, whatever the Scope
ExcludeSession string // session id to omit (usually the live session)
Limit int // max hits; defaults to 10 when <= 0
MinScore float64 // cosine floor; hits below this are dropped
}
SemanticSearchOpts parameterizes SearchSemantic.