agentmem

package
v2.25.0 Latest Latest
Warning

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

Go to latest
Published: Jun 17, 2026 License: MIT Imports: 13 Imported by: 0

Documentation

Overview

Package agentmem is a SQL-backed agent memory store.

It mirrors the semantics of agent-go's pkg/store FileMemoryStore — typed memories (fact / skill / pattern / context / preference / observation), Hindsight fields (evidence / confidence / valid_from-to / superseded_by / conflicting / revisions / archived), bank configuration, mental models, and OpenClaw-style context slots — but persists everything in CortexDB's SQLite file rather than a tree of Markdown files.

The package does NOT require an embedder. Search is based on FTS5 (the trigram tokenizer when available, unicode61 as fallback) re-ranked with importance and exponential time decay.

Quick Start

cdb, _ := cortexdb.Open(cortexdb.DefaultConfig("memory.db"))
defer cdb.Close()

store, _ := agentmem.New(cdb)

_ = store.Save(ctx, &agentmem.Memory{
	Scope:      agentmem.Scope{Type: agentmem.ScopeUser, ID: "alice"},
	Type:       agentmem.TypeFact,
	Content:    "Apollo ships on Friday.",
	Importance: 0.8,
	Tags:       []string{"apollo", "deadline"},
})

hits, _ := store.SearchByText(ctx, "apollo deadline", agentmem.SearchOptions{TopK: 5})
for _, h := range hits { _ = h.Memory }

Reflection

Reflect plugs in any Reflector implementation (LLM-backed or deterministic):

type myReflector struct{}
func (myReflector) Consolidate(ctx context.Context, facts, existing []*agentmem.Memory) ([]agentmem.Observation, error) {
	// produce one or more observations citing fact ids as evidence
}

res, _ := store.Reflect(ctx, scope, myReflector{})

Context Slots

Context slots replace agent-go's MEMORY.md/AGENTS.md/SOUL.md/TOOLS.md/HEARTBEAT.md fixed files. They live in agentmem_context_slots and can be assembled into a single string with BuildContextString.

Index

Constants

This section is empty.

Variables

DefaultContextOrder is the order BuildContextString uses by default.

View Source
var ErrNotFound = errors.New("agentmem: memory not found")

ErrNotFound is returned when a memory id has no row.

Functions

func BankID

func BankID(scope Scope) string

BankID returns the canonical bank id for a scope, used as the partition key for memories and context slots.

func IsStale

func IsStale(m *Memory) bool

IsStale reports whether a memory has been superseded.

Types

type BankConfig

type BankConfig struct {
	Mission    string   `json:"mission,omitempty"`
	Directives []string `json:"directives,omitempty"`
	Skepticism int      `json:"skepticism,omitempty"`
	Literalism int      `json:"literalism,omitempty"`
	Empathy    int      `json:"empathy,omitempty"`
}

BankConfig captures the disposition of a memory bank, mirroring agent-go's MemoryBankConfig.

type ContextSlot

type ContextSlot string

ContextSlot names a fixed system-context channel (OpenClaw style).

const (
	SlotSoul      ContextSlot = "SOUL"
	SlotAgents    ContextSlot = "AGENTS"
	SlotTools     ContextSlot = "TOOLS"
	SlotMemory    ContextSlot = "MEMORY"
	SlotHeartbeat ContextSlot = "HEARTBEAT"
)

type EntrypointOptions

type EntrypointOptions struct {
	TopN            int
	IncludeArchived bool
	IncludeStale    bool
	Title           string // optional heading; defaults to "Memory Entrypoint"
}

EntrypointOptions controls BuildEntrypoint.

type Memory

type Memory struct {
	ID         string  `json:"id"`
	Scope      Scope   `json:"scope"`
	Type       Type    `json:"type"`
	Content    string  `json:"content"`
	Importance float64 `json:"importance"`

	Tags     []string `json:"tags,omitempty"`
	Keywords []string `json:"keywords,omitempty"`

	SourceType  SourceType `json:"source_type,omitempty"`
	Confidence  float64    `json:"confidence,omitempty"`
	EvidenceIDs []string   `json:"evidence_ids,omitempty"`

	ValidFrom    time.Time  `json:"valid_from,omitempty"`
	ValidTo      *time.Time `json:"valid_to,omitempty"`
	SupersededBy string     `json:"superseded_by,omitempty"`
	Conflicting  bool       `json:"conflicting,omitempty"`

	Archived      bool       `json:"archived,omitempty"`
	ArchivedAt    *time.Time `json:"archived_at,omitempty"`
	ArchiveReason string     `json:"archive_reason,omitempty"`

	AccessCount  int       `json:"access_count"`
	LastAccessed time.Time `json:"last_accessed,omitempty"`
	CreatedAt    time.Time `json:"created_at"`
	UpdatedAt    time.Time `json:"updated_at"`

	RevisionHistory []Revision `json:"revision_history,omitempty"`
}

Memory is the canonical agentmem record.

type MentalModel

type MentalModel struct {
	ID          string    `json:"id"`
	Name        string    `json:"name,omitempty"`
	Description string    `json:"description,omitempty"`
	Content     string    `json:"content"`
	Tags        []string  `json:"tags,omitempty"`
	UpdatedAt   time.Time `json:"updated_at"`
}

MentalModel is a curated rule or summary kept alongside the bank.

type Observation

type Observation struct {
	Content     string
	Confidence  float64
	EvidenceIDs []string
	Conflicting bool
	UpdateObsID string // when set, the existing observation with this id is marked stale
}

Observation is the result of one consolidation step.

type ReflectResult

type ReflectResult struct {
	Created  int      `json:"created"`
	Updated  int      `json:"updated"`
	Reviewed int      `json:"reviewed"`
	NewIDs   []string `json:"new_ids,omitempty"`
	Note     string   `json:"note,omitempty"`
}

ReflectResult summarises a Reflect run.

type Reflector

type Reflector interface {
	Consolidate(ctx context.Context, facts []*Memory, existing []*Memory) ([]Observation, error)
}

Reflector is the LLM-dependent extension point for consolidating raw facts into observations. It is the agentmem analogue of agent-go's Reflect prompt.

Implementations receive only the candidate facts (already filtered to active, not-yet-evidenced records) and any existing observations in the same scope. They must return one or more Observation rows; agentmem will persist them and optionally mark superseded observations stale.

type Revision

type Revision struct {
	At      time.Time `json:"at"`
	By      string    `json:"by,omitempty"`
	Summary string    `json:"summary,omitempty"`
}

Revision is a single audit entry recording a change to a memory.

type Scope

type Scope struct {
	Type ScopeType `json:"type"`
	ID   string    `json:"id,omitempty"`
}

Scope is a typed memory bank coordinate.

type ScopeType

type ScopeType string

ScopeType identifies a memory isolation scope.

const (
	ScopeGlobal  ScopeType = "global"
	ScopeAgent   ScopeType = "agent"
	ScopeTeam    ScopeType = "team"
	ScopeUser    ScopeType = "user"
	ScopeSession ScopeType = "session"
)

type ScoredMemory

type ScoredMemory struct {
	Memory *Memory `json:"memory"`
	Score  float64 `json:"score"`
}

ScoredMemory is a memory paired with a relevance score.

type SearchOptions

type SearchOptions struct {
	TopK            int
	MinScore        float64
	IncludeArchived bool
	IncludeStale    bool     // include rows whose ValidTo is set or SupersededBy non-empty
	Type            Type     // optional type filter
	BankIDs         []string // pre-resolved bank ids (used by SearchByScope)
}

SearchOptions controls SearchByText/SearchByScope behavior.

type SourceType

type SourceType string

SourceType records how a memory was created.

const (
	SourceUserInput    SourceType = "user_input"
	SourceInferred     SourceType = "inferred"
	SourceConsolidated SourceType = "consolidated"
)

type Store

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

Store provides a SQL-backed agent memory layer mirroring agent-go's FileMemoryStore semantics (typed memories, Hindsight fields, banks, mental models, context slots) without requiring an embedder.

func New

func New(db *cortexdb.DB) (*Store, error)

New creates a Store on top of a cortexdb DB, ensuring schema exists.

func (*Store) AddMentalModel

func (s *Store) AddMentalModel(ctx context.Context, m *MentalModel) error

AddMentalModel inserts or updates a curated rule.

func (*Store) AddRevision

func (s *Store) AddRevision(ctx context.Context, id, by, summary string) error

AddRevision appends a revision entry to a memory's history.

func (*Store) AppendContext

func (s *Store) AppendContext(ctx context.Context, scope Scope, slot ContextSlot, content string) error

AppendContext appends content to a slot, creating it if missing. A newline separator is inserted between the existing content and the new section.

func (*Store) Archive

func (s *Store) Archive(ctx context.Context, id, reason string) error

Archive flags a memory as archived (excluded from default search) and records the reason.

func (*Store) BuildContextString

func (s *Store) BuildContextString(ctx context.Context, scope Scope, order []ContextSlot) (string, error)

BuildContextString concatenates the slots for a scope in the given order (or DefaultContextOrder when nil), emitting `# <SLOT>` headings between non-empty sections. Empty/missing slots are skipped silently.

func (*Store) BuildEntrypoint

func (s *Store) BuildEntrypoint(ctx context.Context, scope Scope, opts EntrypointOptions) (string, error)

BuildEntrypoint renders a Markdown summary of the top-N memories for a scope, ranked by importance (then recency). This replaces agent-go's auto-generated MEMORY.md entrypoint with an in-memory string.

func (*Store) Clear

func (s *Store) Clear(ctx context.Context) error

Clear removes all memories (and side tables) but preserves bank config / mental models / context slots, mirroring agent-go behavior.

func (*Store) ConfigureBank

func (s *Store) ConfigureBank(ctx context.Context, scope Scope, cfg *BankConfig) error

ConfigureBank stores the disposition for a memory bank (per scope).

func (*Store) Delete

func (s *Store) Delete(ctx context.Context, id string) error

Delete removes a memory and its side rows.

func (*Store) DeleteContext

func (s *Store) DeleteContext(ctx context.Context, scope Scope, slot ContextSlot) error

DeleteContext removes a slot.

func (*Store) DeleteMentalModel

func (s *Store) DeleteMentalModel(ctx context.Context, id string) error

DeleteMentalModel removes a rule by id.

func (*Store) Get

func (s *Store) Get(ctx context.Context, id string) (*Memory, error)

Get loads a single memory by id, including side tables.

func (*Store) GetBankConfig

func (s *Store) GetBankConfig(ctx context.Context, scope Scope) (*BankConfig, error)

GetBankConfig returns the bank's stored disposition. Returns ErrNotFound when the bank has not been configured yet.

func (*Store) GetByType

func (s *Store) GetByType(ctx context.Context, t Type, limit int) ([]*Memory, error)

GetByType returns active memories matching a type.

func (*Store) GetContext

func (s *Store) GetContext(ctx context.Context, scope Scope, slot ContextSlot) (string, error)

GetContext reads a single context slot. Returns "" with ErrNotFound when the slot has not been written.

func (*Store) IncrementAccess

func (s *Store) IncrementAccess(ctx context.Context, id string) error

IncrementAccess bumps access_count and last_accessed.

func (*Store) List

func (s *Store) List(ctx context.Context, limit, offset int) ([]*Memory, int, error)

List returns memories with simple pagination, newest first, including the total count.

func (*Store) ListByScope

func (s *Store) ListByScope(ctx context.Context, scope Scope, limit int) ([]*Memory, error)

ListByScope returns active memories within a scope, newest first.

func (*Store) ListMentalModels

func (s *Store) ListMentalModels(ctx context.Context) ([]MentalModel, error)

ListMentalModels returns all curated rules ordered by most recently updated.

func (*Store) MarkStale

func (s *Store) MarkStale(ctx context.Context, id, supersededBy string) error

MarkStale marks a memory as superseded by another. It sets ValidTo to now and appends a revision entry recording the supersession.

func (*Store) Parent

func (s *Store) Parent() *cortexdb.DB

Parent returns the underlying cortexdb.DB so callers can compose other CortexDB layers.

func (*Store) Reflect

func (s *Store) Reflect(ctx context.Context, scope Scope, r Reflector) (*ReflectResult, error)

Reflect collects active facts in scope, asks the Reflector to consolidate them into observations, persists each observation as a new memory, and marks any superseded observations stale.

func (*Store) Save

func (s *Store) Save(ctx context.Context, m *Memory) error

Save upserts a memory. If m.ID is empty it is generated; CreatedAt / UpdatedAt / ValidFrom are populated when zero.

func (*Store) SearchByScope

func (s *Store) SearchByScope(ctx context.Context, query string, scopes []Scope, opts SearchOptions) ([]ScoredMemory, error)

SearchByScope is SearchByText restricted to a list of scopes.

func (*Store) SearchByText

func (s *Store) SearchByText(ctx context.Context, query string, opts SearchOptions) ([]ScoredMemory, error)

SearchByText runs an FTS5 query, then re-ranks with importance + time decay.

func (*Store) SearchByType

func (s *Store) SearchByType(ctx context.Context, t Type, limit int) ([]*Memory, error)

SearchByType returns top-N memories of a given type, ranked by importance + recency (no FTS query). Useful when callers want the latest preferences / observations.

func (*Store) SetContext

func (s *Store) SetContext(ctx context.Context, scope Scope, slot ContextSlot, content string) error

SetContext writes (replaces) the content of a context slot for a given scope.

func (*Store) Unarchive

func (s *Store) Unarchive(ctx context.Context, id string) error

Unarchive clears the archive flags.

func (*Store) UsesFallbackTokenizer

func (s *Store) UsesFallbackTokenizer() bool

UsesFallbackTokenizer reports whether the FTS table fell back from trigram to unicode61. Callers running CJK-heavy workloads on older SQLite builds may want to surface this to users.

type Type

type Type string

Type categorises a memory record.

const (
	TypeFact        Type = "fact"
	TypeSkill       Type = "skill"
	TypePattern     Type = "pattern"
	TypeContext     Type = "context"
	TypePreference  Type = "preference"
	TypeObservation Type = "observation"
)

Jump to

Keyboard shortcuts

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