Documentation
¶
Overview ¶
Package memory defines memini's core domain types.
Index ¶
- Constants
- Variables
- func Fingerprint(content string) string
- func GrowConfidence(c float64) float64
- func NormalizeContent(s string) string
- func SeedImportance(t Tier) float64
- type Chunk
- type Level
- type Memory
- func (m *Memory) DurableScore(now time.Time) float64
- func (m *Memory) EffectiveConfidence(now time.Time) float64
- func (m *Memory) EffectiveImportance() float64
- func (m *Memory) EmbedStuck() bool
- func (m *Memory) Expired(now time.Time) bool
- func (m *Memory) PendingEmbed() bool
- func (m *Memory) Quality(now time.Time) float64
- func (m *Memory) Recency(now time.Time) float64
- func (m *Memory) RetentionScore(now time.Time) float64
- func (m *Memory) Salience() float64
- type Term
- type Tier
Constants ¶
const ( PendingEmbedKey = "pending_embed" PendingEmbedValue = "true" )
PendingEmbedKey/PendingEmbedValue are the metadata flag a degraded write carries when it was stored vectorless because the embedder was unreachable; the backfill loop re-embeds flagged rows and deletes the key on success.
const ( // ConfidenceSeedFresh is the starting confidence of a durable fact written // or promoted from observed activity (some basis, not yet corroborated). ConfidenceSeedFresh = 0.4 // ConfidenceSeedImported is the starting confidence of an uncorroborated // bulk import: lower, so imports must earn trust before outranking facts the // agent actually established. ConfidenceSeedImported = 0.25 // ConfidenceDemoteFloor is the corroboration below which an old, never- // recalled durable memory is treated as uncorroborated debris (demotion // eligibility, and the diagnostic's low-confidence count). ConfidenceDemoteFloor = 0.35 )
Confidence lifecycle constants.
const EmbedStateStuck = "failed"
EmbedStateStuck is the EmbedState of a memory whose repair exhausted its attempt ceiling: it will not be retried until the sweeper re-arms it, so it is the one repair state an operator has to be told about. Mirrors store.RepairFailed.
Variables ¶
var AssessedSalienceWeight = 0.0
AssessedSalienceWeight is the share of the importance term Salience takes from the LLM's assessment rather than the stored importance, read at ranking time. Above 0 the term becomes (1-w)*Importance + w*AssessedImportance for a row that carries an assessment; a row without one is unchanged at any w, and at 0 it is an exact no-op (stored importance only). The memini server sets it from MEMINI_ASSESSED_SALIENCE_WEIGHT (default 0) in cmd/memini; this package-level default stays 0 so direct library callers and unit tests keep the unmodulated baseline unless they opt in.
var StabilityK = 0.0
StabilityK is the spaced-repetition strength (Ebbinghaus stability), read at ranking time by Quality. Above 0 it stretches a short-term memory's effective half-life with reinforcement — S = retentionHalfLife*(1 + StabilityK*ln(1+ AccessCount)) — so a frequently-recalled memory forgets more slowly (the curve flattens, not just shifts up); at 0 it is an exact no-op (fixed half-life). The memini server sets it from MEMINI_STABILITY_K (default 1) in cmd/memini; this package-level default stays 0 so direct library callers and unit tests keep the unmodulated baseline unless they opt in. See bench/reinforcement_test.go.
Functions ¶
func Fingerprint ¶ added in v0.2.9
Fingerprint is a content key for exact-restatement dedup: the SHA-256 of the normalized content, so writes differing only in case or whitespace collide.
func GrowConfidence ¶ added in v0.0.11
GrowConfidence raises a confidence toward 1 logistically on corroboration: each re-observation closes 10% of the remaining gap, so confidence asymptotes to 1 and never overshoots.
func NormalizeContent ¶
NormalizeContent collapses whitespace and case so trivially-duplicated memories compare equal. Used by recall dedup and the fsck duplicate audit.
func SeedImportance ¶ added in v0.7.18
SeedImportance is the tier-based importance floor for a fresh write that carried none: durable curated tiers outrank episodic turns, which outrank raw working-intake notes.
Types ¶
type Chunk ¶ added in v0.7.3
Chunk is one embedded segment of a memory's content. Idx is its position in the content, from 0, so a row is stable across re-splits.
Text is the segment the Embedding was built from. It is stored rather than recomputed because it is what the reranker must judge: rerank cuts a candidate down to its own budget (300 bytes for the LLM backend, 2048 runes for the cross-encoder), so handing it the whole memory means judging a prefix that need not contain the passage that retrieved it, and dropping the memory chunked recall just found. Recomputing it from content would be possible while the split config is unchanged, and wrong the moment it is not.
type Level ¶ added in v0.5.10
type Level string
Level classifies a memory by how it was derived: user-stated versus LLM-inferred. Empty string is legacy/unknown (every pre-level row) and passes filters unconstrained.
const ( // LevelExplicit is a user-stated or directly-extracted fact, stamped by // the heuristic extract-on-write path and by direct RememberInput callers. LevelExplicit Level = "explicit" // LevelDeduced is an LLM-inferred fact (distilled from episodic material). // Traceable to its sources via metadata.source_ids. LevelDeduced Level = "deduced" )
type Memory ¶
type Memory struct {
ID string `json:"id"`
Namespace string `json:"namespace"`
Tier Tier `json:"tier"`
Level Level `json:"level,omitempty"`
Content string `json:"content"`
Summary string `json:"summary,omitempty"`
// Metadata is arbitrary structured data, persisted as JSON.
Metadata map[string]any `json:"metadata,omitempty"`
// Tags are free-form labels used for keyword retrieval and filtering.
Tags []string `json:"tags,omitempty"`
// Importance biases decay and ranking; higher survives longer. Range [0,1].
Importance float64 `json:"importance"`
CreatedAt time.Time `json:"created_at"`
UpdatedAt time.Time `json:"updated_at"`
LastAccessedAt time.Time `json:"last_accessed_at"`
AccessCount int `json:"access_count"`
ExpiresAt *time.Time `json:"expires_at,omitempty"`
// SupersededBy points at the memory that replaced this one during
// contradiction resolution; non-nil means this record is tombstoned.
SupersededBy *string `json:"superseded_by,omitempty"`
// ValidFrom / ValidTo bound the wall-clock interval a fact was true. Both nil
// means "always" (the common case). ValidTo is stamped when a fact is
// superseded, so a time-filtered recall (Filter.AsOf) can answer "what was
// true in March" by surfacing facts valid then even if later replaced.
ValidFrom *time.Time `json:"valid_from,omitempty"`
ValidTo *time.Time `json:"valid_to,omitempty"`
// Confidence is how corroborated a durable (semantic/procedural) fact is,
// in [0,1]. It starts low for a fresh or imported fact, grows logistically
// each time the fact is re-observed, and decays without reinforcement, so a
// corroborated fact outranks one-off noise. nil means "not tracked" (every
// short-term memory, and durable memories written before the field existed),
// treated as fully trusted so existing data is never retroactively penalized.
Confidence *float64 `json:"confidence,omitempty"`
// AssessedImportance is how intrinsically important the LLM judged this
// content to be, in [0.1,0.9]. nil means never assessed (every memory
// written before the field existed, and every write the assessor did not
// reach). Invariant: it is cleared whenever a caller supplies an explicit
// Importance, so a non-nil value always refines a tier-seeded guess and
// never overrides what a user asked for.
AssessedImportance *float64 `json:"assessed_importance,omitempty"`
// LinkedMemoryIDs references related memories (same entity/topic but distinct
// facts). Populated by the LLM consolidator when a new memory is related but
// neither a duplicate nor a contradiction. At recall, IncludeLinked expands
// results 1-hop via these links. Links are advisory — stale links (target
// superseded) are resolved at recall time.
LinkedMemoryIDs []string `json:"linked_memory_ids,omitempty"`
// Embedding is the dense vector for similarity search. It is required when
// writing to the store and is omitted from API responses.
Embedding []float32 `json:"-"`
// EmbedState is the deferred-repair state a write commits alongside the
// memory: "" for a healthy write, "pending" when it stored without a vector
// because the embedder was unreachable. The values are store.RepairState's;
// it is a plain string here only because internal/memory cannot import
// internal/store.
//
// Writing it on the Memory rather than through a separate call is the whole
// point: the state and the memory it describes commit in one transaction,
// so there is no window in which a degraded write exists without the record
// that it needs repairing. On read paths it reflects the stored column, so
// a caller can tell a memory that will be repaired shortly from one whose
// repair has given up (see EmbedStuck).
EmbedState string `json:"embed_state,omitempty"`
// Chunks are per-segment vectors covering content that runs past the
// per-item embed budget, so recall can match text the Embedding above does
// not reach. Optional: a store need not implement store.ChunkStore, and
// short content has none by design (see internal/chunk).
//
// On Upsert, nil means the store decides: existing chunk rows are kept
// when the content is unchanged (same fingerprint) and cleared when it
// changed. That default fails safe in both directions — stale chunks make
// recall return a memory whose text no longer contains the passage that
// matched it, while missing ones are re-created by the backfill loop, so
// a caller that rewrites content without recomputing loses nothing
// durable, and a caller that merely stamps metadata cannot wipe an index
// it never touched. A non-nil slice replaces the rows exactly as given;
// an empty non-nil slice is an explicit clear, for callers whose chunks
// went stale without a content change (reembed: the model changed under
// them).
Chunks []Chunk `json:"-"`
}
Memory is a single stored memory, scoped to a namespace.
func (*Memory) DurableScore ¶ added in v0.0.13
DurableScore ranks a memory as durable knowledge (e.g. a session briefing): salience × corroboration × reinforcement, without Quality's recency decay, so a core fact unrecalled for weeks is not buried under fresher trivia.
func (*Memory) EffectiveConfidence ¶ added in v0.0.11
EffectiveConfidence is a durable memory's corroboration at now: the stored confidence lazily decayed for the weeks elapsed since it was last corroborated (UpdatedAt) or recalled (LastAccessedAt). Decay is applied at read time so the maintenance sweep needs no extra write. Returns 1 (neutral) for short-term memories and for any memory that never had confidence recorded — so existing data written before the field is treated as fully trusted, not penalized.
func (*Memory) EffectiveImportance ¶ added in v0.7.18
EffectiveImportance is the importance signal ranking should read: the assessed value when present, else the stored (user-supplied or tier-seeded) importance. Write paths maintain the invariant that assessed is absent on any row whose importance was explicitly set, so this never shadows a user's choice.
func (*Memory) EmbedStuck ¶ added in v0.7.16
EmbedStuck reports whether this memory's repair has given up. It is the distinction the UI and doctor need: a pending repair fixes itself within seconds, a stuck one never will without intervention, and rendering them identically is what lets silent degradation hide.
func (*Memory) PendingEmbed ¶ added in v0.7.3
PendingEmbed reports whether this memory is still awaiting its embedding (stored vectorless by a degraded write; keyword-retrieval only until the repair completes).
The metadata flag is checked alongside the column so a database written by a release that predates the repair columns still reports honestly until the sweeper adopts it.
func (*Memory) Quality ¶ added in v0.0.11
Quality scores a memory for both recall ranking and lifecycle decisions (higher = more worth keeping and surfacing). It multiplies the base salience by corroboration (confidence), reinforcement (access frequency), and — for short-term tiers — recency (exponential decay since last access). Durable tiers skip the recency factor: they already age through confidence decay, and a 7-day half-life would zero out tier salience for any fact not recalled recently, burying core knowledge under fresh session trivia.
func (*Memory) Recency ¶
Recency returns an exponentially-decaying [0,1] factor for how recently the memory was accessed, halving every retentionHalfLife. Used by recall ranking.
func (*Memory) RetentionScore ¶
RetentionScore is the legacy short-term-eviction score, retained as an alias of Quality so existing callers keep working; new code should call Quality.
func (*Memory) Salience ¶ added in v0.0.11
Salience is the base, time-independent quality of a memory in [0,1]: the tier's weight modulated by importance. It does not depend on access or age. When AssessedSalienceWeight is above 0, the importance term is blended with the LLM's assessment for rows that carry one; at the default 0 it is stored importance alone.
type Term ¶
type Term string
Term is the coarse memory horizon: short-term memories are transient and TTL'd; long-term memories are durable and curated.
type Tier ¶
type Tier string
Tier classifies a memory by how consolidated it is: working → episodic → semantic, with procedural held separately for how-to knowledge.
const ( // TierWorking holds raw, short-lived observations (typically session-scoped). TierWorking Tier = "working" // TierEpisodic holds summaries of what happened in a session. TierEpisodic Tier = "episodic" // TierSemantic holds durable extracted facts ("what I know"). TierSemantic Tier = "semantic" // TierProcedural holds workflows and how-to knowledge. TierProcedural Tier = "procedural" )
func (Tier) DefaultTTL ¶
DefaultTTL is the TTL for a tier; zero means never expires.