retrieve

package
v0.4.5 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jul 26, 2026 License: MIT Imports: 23 Imported by: 0

Documentation

Overview

Package retrieve assembles what an agent sees from its memory: the session-start briefing, the user-prompt-submit recall block, and the recall tool's fused search. It reads the store index and (when an embedder is set) the vector store, budgets output by estimated tokens, and sanitizes every interpolated field against prompt injection before it reaches an agent.

Index

Constants

This section is empty.

Variables

View Source
var RecallScopes = []string{"all", "memories", "notes"}

RecallScopes lists every valid RecallInput.Scope value. An empty Scope is a valid Go-API default meaning "all" (scopeKinds treats it that way, and Search shares it), so this set is for boundaries that can distinguish an absent key from an explicitly wrong one -- it is not a precondition of RecallInput.

Functions

func EstimateTokens added in v0.3.7

func EstimateTokens(s string) int

EstimateTokens is the repository-wide cheap token estimate (~4 bytes/token) used to budget model-visible context without a tokenizer dependency.

Types

type BriefingInput

type BriefingInput struct {
	CWD       string // agent working directory; resolved to a project slug
	Source    string // startup|resume|clear|compact
	AgentType string // non-empty => subagent => constraints-only briefing
	// Prompt is the child's spawn prompt, resolved best-effort at SubagentStart
	// (empty on the main-session path and whenever resolution fails). The
	// subagent path matches it against the project's memories and renders the
	// hits as the briefing's RELEVANT section (subagentRelevant); the
	// main-session path never reads it, so main briefings stay byte-identical
	// whether it is set or empty.
	Prompt string
}

BriefingInput carries the SessionStart hook fields the briefing depends on.

type Hit

type Hit struct {
	Kind        string  `json:"kind"` // "memory" | "note"
	ID          string  `json:"id"`
	Name        string  `json:"name"`  // memory name / note slug
	Title       string  `json:"title"` // display title
	Description string  `json:"description"`
	Project     string  `json:"project,omitempty"`
	Age         string  `json:"age"`
	Source      string  `json:"source"` // semantic | fts | fused | link | browse
	Score       float64 `json:"score"`
	// Snippet is the matched text in context, with the matched terms wrapped in
	// store.SnippetStartMark/SnippetEndMark. Only Search sets it, and only for
	// hits an FTS leg found -- Recall always leaves it empty, so omitempty keeps
	// the MCP recall payload byte-identical to what it was before Search existed.
	// It is RAW item text: a renderer must HTML-escape before substituting the
	// sentinels for markup.
	Snippet string `json:"snippet,omitempty"`
	// Similarity is the raw cosine similarity from the semantic leg, for hits
	// that leg found. Like Snippet, only Search sets it -- Recall always leaves
	// it zero, so omitempty keeps the MCP recall payload unchanged. A lexical-only
	// hit has no vector distance to report and also omits it.
	Similarity float64 `json:"similarity,omitempty"`
	// Favorite marks a starred item. omitempty keeps the recall payload
	// byte-identical to the pre-favorites contract for unstarred hits.
	Favorite bool `json:"favorite,omitempty"`
	// Updated is carried internally so the human search page can sort and
	// window hydrated hits. It is deliberately excluded from Recall's JSON
	// contract, whose payload predates console Search and must remain stable.
	Updated time.Time `json:"-"`
}

Hit is one recall result. Kind tells the agent how to read it: a memory by its Name (memory_read), a note by its ID (notes_read).

type MemoryBodyReader

type MemoryBodyReader interface {
	ReadMemory(relPath string) (core.Memory, error)
}

MemoryBodyReader reads a full memory (including its body) from a data-dir- relative file path. *files.Store satisfies it. It is optional on the Service: when unset, the briefing omits the pinned-stage section (index rows carry no body, so stage status cannot be parsed without it).

type RecallInput

type RecallInput struct {
	// Query is the search text. It may be empty only when Kind is set: a kind
	// with no query is the browse mode (list that kind newest-first), the
	// mechanism behind briefing hints like "recall kind=convention".
	Query   string
	Project string
	Scope   string // all | memories | notes (default all)
	// Kind, when non-empty, restricts hits to memories of that frontmatter
	// kind (core.MemoryKinds). It implies memories-only, so Scope "notes" is
	// rejected as contradictory, and link expansion is skipped: a kind filter
	// is a targeted enumeration, and a [[link]] neighbor of another kind would
	// violate it.
	Kind  string
	Limit int
}

RecallInput parameterizes a recall. Project is the session's bound scope; results are limited to that project plus global items.

type SearchInput

type SearchInput struct {
	Query    string
	Scope    string    // all | memories | notes
	Projects []string  // nil = every project
	Limit    int       // default 20
	Semantic bool      // false = FTS-only (the palette's fast path)
	Since    time.Time // zero = all time; otherwise updated at/after this instant
}

SearchInput parameterizes a human-facing search over durable knowledge.

Projects nil means every project -- the difference that makes this a separate entry point from Recall, which is always bound to one session's scope. Semantic false runs the FTS leg only, for a caller that fires a query per keystroke and must not pay a remote embedding round-trip each time.

type Service

type Service struct {
	// contains filtered or unexported fields
}

Service assembles briefings, prompt recall, and fused recall over one store.

func New

func New(db *sql.DB, embedder llm.Embedder, budgets config.Budgets, logger *slog.Logger) *Service

New builds a retrieval Service. embedder may be nil, in which case recall uses FTS only and the semantic paths are skipped. Briefing knobs start at their defaults; SetBriefingConfig overrides them with the loaded file/env values.

func (*Service) Briefing

func (s *Service) Briefing(ctx context.Context, in BriefingInput) (string, []string, error)

Briefing assembles the SessionStart briefing for an agent: constraints (always included), a newest-first memory index, and recent sibling findings, budgeted by estimated tokens and wrapped in <seam-briefing> tags. It returns "" when there is nothing worth injecting (unmapped cwd with no global memories), which the hook forwards as an empty additionalContext. The second return value is the ids of the memories actually rendered (after budget dropping), so the caller can record them as a retrieval.injected event and feed the read-after-inject funnel -- the same telemetry the recall tool emits.

func (*Service) DedupHint

func (s *Service) DedupHint(ctx context.Context, project, name, description string) (*Hit, error)

DedupHint returns the most semantically similar active memory to a proposed (name, description) within the project+global scope, when it clears the similarity threshold. It is advisory only -- memory_write always proceeds -- and semantic-only: with no embedder, or on any embed hiccup, it returns nil so a write is never blocked by retrieval trouble. Ported from v1's dedupHint.

func (*Service) PromptRecall

func (s *Service) PromptRecall(ctx context.Context, cwd, prompt string) (string, []string, error)

PromptRecall matches a user's prompt against the active memory index for the cwd's project and returns a <seam-recall> block (or "" when nothing clears the overlap and score floors). The second return value is the ids of the memories surfaced, so the caller can record them as a retrieval.injected event. It never errors on the hook path except on a store failure.

func (*Service) Recall

func (s *Service) Recall(ctx context.Context, in RecallInput) ([]Hit, error)

Recall fuses semantic (cosine) and FTS results with RRF, hydrates the winners from the index, and packs them into the recall token budget. Scope and validity are both enforced inside the candidate queries, so the fused depth is entirely in-scope and entirely live. With no embedder configured it degrades to FTS only.

func (*Service) Search

func (s *Service) Search(ctx context.Context, in SearchInput) ([]Hit, error)

Search finds memories and notes for a human searching the console. It shares Recall's candidate queries, RRF fusion, and embedder-degradation contract (see candidates) but deliberately drops three Recall behaviors that are wrong for this caller:

  • No token budgeting. Recall packs into an agent's context budget and silently truncates; a search page owes the observer every hit it found, up to the limit they asked for.
  • No post-fusion scope guard. Recall re-checks each hit against its single bound project, which would discard every project-scoped hit of an all-projects search. Scope here is enforced only where it belongs -- in the candidate queries, via Projects.
  • No link expansion. [[name]] resolution is single-project by construction, and a linked neighbor does not textually match the query, so it reads as noise to someone who typed a search term.

Snippet is populated for hits the FTS leg found; a semantic-only hit has none (there is no matched term to quote), and the caller falls back to the item's description.

Search adds one guard Recall does not have: the semantic floor (search.semantic_floor). The cosine leg is pure nearest-neighbor -- there is always a "nearest" item, however far, so without a floor any query fills the page to its limit with noise. A semantic-only hit below the floor is dropped; a hit the lexical leg also matched earned its place regardless of distance. Recall keeps every neighbor on purpose: an agent can judge a weak hit, an observer reads "20 results" as 20 matches. Similarity is set on every hit the semantic leg found, so the caller can show where relevance falls off.

func (*Service) SetBodyReader

func (s *Service) SetBodyReader(r MemoryBodyReader)

SetBodyReader enables the pinned-stage briefing section by giving the Service a way to read stage memory bodies (their Status/Gate header lives in the body).

func (*Service) SetBriefingConfig

func (s *Service) SetBriefingConfig(b config.Briefing)

SetBriefingConfig sets the file/env briefing knobs the Service starts from. The console's runtime override row (store.SettingBriefingConfig) still layers on top of these at briefing-assembly time, so a console save takes effect on the next session start without a restart.

func (*Service) SetSearchConfig added in v0.3.9

func (s *Service) SetSearchConfig(c config.Search)

SetSearchConfig sets the file/env search knobs (Defaults() until called).

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL