memory

package
v0.12.0 Latest Latest
Warning

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

Go to latest
Published: Apr 16, 2026 License: MIT Imports: 9 Imported by: 0

Documentation

Overview

Package memory defines the pluggable memory provider contract.

Every memory plugin implements Provider as its core interface. Optional capabilities are discovered via type assertion at runtime, following the same pattern as github.com/vaayne/anna/pkg/hooks.

Index

Constants

View Source
const (
	SummarizePolicyNormal     = "normal"
	SummarizePolicyAggressive = "aggressive"
)

SummarizePolicy constants control how aggressively content is compressed.

Variables

This section is empty.

Functions

func AgentIDFromContext

func AgentIDFromContext(ctx context.Context) string

AgentIDFromContext extracts the agent ID from context.

func BuildPrompt

func BuildPrompt(text string, opts SummarizeOptions) string

BuildPrompt constructs the appropriate summarization prompt.

func BuildTool

func BuildTool(provider Provider, opts ...ToolOption) tools.Tool

BuildTool inspects provider capabilities and returns a memory tool whose available actions match exactly what the provider supports. If the provider supports no optional capabilities, the tool still exists but only offers a "status" action.

func EstimateTokens

func EstimateTokens(text string) int

EstimateTokens returns a rough token count (~4 chars per token).

func MessageRole

func MessageRole(msg ai.Message) string

MessageRole returns the role string for an ai.Message.

func MessageText

func MessageText(msg ai.Message) string

MessageText extracts the plain text content from an ai.Message. Returns the text for user/assistant messages, or the tool result for tool messages.

func MessageTimestamp

func MessageTimestamp(msg ai.Message) time.Time

MessageTimestamp returns the timestamp of an ai.Message.

func SessionIDFromContext

func SessionIDFromContext(ctx context.Context) string

SessionIDFromContext extracts the session ID from context.

func UserIDFromContext

func UserIDFromContext(ctx context.Context) int64

UserIDFromContext extracts the user ID from context.

func WithAgentID

func WithAgentID(ctx context.Context, agentID string) context.Context

WithAgentID attaches an agent ID to the context.

func WithSessionID

func WithSessionID(ctx context.Context, sessionID string) context.Context

WithSessionID attaches a session ID to the context.

func WithUserID

func WithUserID(ctx context.Context, userID int64) context.Context

WithUserID attaches a user ID to the context.

Types

type CompactionMode

type CompactionMode int

CompactionMode controls compaction behavior.

const (
	// CompactionIncremental runs one leaf pass + one condensed pass.
	CompactionIncremental CompactionMode = iota
	// CompactionFull repeats until no more compaction is possible.
	CompactionFull
)

func (CompactionMode) String

func (m CompactionMode) String() string

String returns the human-readable name of the compaction mode.

type CompactionResult

type CompactionResult struct {
	LeafSummariesCreated      int
	CondensedSummariesCreated int
	MessagesCompacted         int
	TokensBefore              int
	TokensAfter               int
	Duration                  time.Duration
}

CompactionResult reports what a compaction cycle accomplished.

type Compactor

type Compactor interface {
	// NeedsCompaction returns true if the session's context has grown large enough
	// to warrant compaction. threshold is a fraction of the session's token budget
	// (e.g. 0.75 means "compact when context is 75% full").
	NeedsCompaction(ctx context.Context, session Session, threshold float64) bool

	// Compact runs the compaction algorithm on the session.
	// Incremental mode runs a single summarisation pass (fast, called automatically).
	// Full mode runs repeated passes until no further reduction is possible
	// (slow, called on demand e.g. via /compact slash command).
	Compact(ctx context.Context, session Session, mode CompactionMode) (*CompactionResult, error)
}

Compactor is implemented by providers that support background compaction. The Pool calls NeedsCompaction before each chat turn and Compact when needed.

type DescribeResult

type DescribeResult struct {
	SummaryID       string
	Kind            string     // "leaf" or "condensed"
	Depth           int        // 0 = leaf, 1+ = condensed
	Content         string     // the summary text
	EarliestAt      *time.Time // timestamp of oldest source message
	LatestAt        *time.Time // timestamp of newest source message
	DescendantCount int        // total original messages this summary covers
	ParentIDs       []string   // summaries that contain this one (condensed parents)
	ChildIDs        []string   // summaries or messages this one was built from
}

DescribeResult represents summary metadata and lineage.

type ExpandChild

type ExpandChild struct {
	SummaryID string
	Kind      string
	Depth     int
	Content   string
}

ExpandChild is a child summary in an expand result.

type ExpandMessage

type ExpandMessage struct {
	MessageID int64
	Role      string
	Content   string
	CreatedAt time.Time
}

ExpandMessage is a source message in an expand result.

type ExpandResult

type ExpandResult struct {
	SummaryID string
	// For leaf summaries: the original source messages.
	Messages []ExpandMessage
	// For condensed summaries: the child summaries.
	Children []ExpandChild
}

ExpandResult represents drill-down results from exploring a summary.

type Explorer

type Explorer interface {
	// Describe returns metadata and lineage for a summary ID.
	Describe(ctx context.Context, summaryID string) (*DescribeResult, error)

	// Expand drills into a summary:
	//   - For leaf summaries: returns the original source messages
	//   - For condensed summaries: returns the child summaries
	// tokenCap limits how many tokens of content are returned.
	Expand(ctx context.Context, summaryID string, tokenCap int) (*ExpandResult, error)
}

Explorer is implemented by providers that store summaries in a navigable hierarchy. It lets the agent inspect and drill into compressed history.

Note: these methods take summaryID only, not Session. Summary IDs are globally unique (e.g. "sum_a1b2c3d4") and already scoped to a conversation internally.

type LLMSummarizer

type LLMSummarizer struct {
	// Generate calls the LLM with the given prompt and returns the response text.
	Generate func(ctx context.Context, prompt string) (string, error)
}

LLMSummarizer generates summaries using an LLM via a callback function.

func (*LLMSummarizer) Summarize

func (s *LLMSummarizer) Summarize(ctx context.Context, text string, opts SummarizeOptions) (string, error)

Summarize generates a summary with escalation: normal -> aggressive -> deterministic fallback.

type ListOptions

type ListOptions struct {
	AgentID         string // filter by agent (empty = all)
	UserID          int64  // filter by user (0 = all)
	IncludeArchived bool
	Limit           int // 0 = no limit
}

ListOptions controls session listing filters.

type ProfileStore

type ProfileStore interface {
	// GetProfile returns the current user profile for the (userID, agentID) pair.
	// Returns ("", nil) if no profile exists yet (not an error).
	GetProfile(ctx context.Context, userID int64, agentID string) (string, error)

	// SetProfile overwrites the user profile for the (userID, agentID) pair.
	// Callers are responsible for merging new content with existing content
	// before calling SetProfile — this method always replaces, never appends.
	SetProfile(ctx context.Context, userID int64, agentID string, content string) error

	// GetAgentSoul returns the agent soul for the (userID, agentID) pair.
	// The soul defines the agent's identity, personality, and behavior as
	// customised by this specific user. Returns ("", nil) if not set.
	GetAgentSoul(ctx context.Context, userID int64, agentID string) (string, error)

	// SetAgentSoul overwrites the agent soul for the (userID, agentID) pair.
	// Callers are responsible for merging; this method always replaces.
	SetAgentSoul(ctx context.Context, userID int64, agentID string, content string) error
}

ProfileStore is implemented by providers that support per-user-per-agent persistent memory: agent soul (identity/personality customization) and user profile (facts/context about the user).

Both are scoped to (userID, agentID) — each user can customise the agent's soul independently, and the agent maintains separate profile notes per user. Content is free-form text managed entirely by the agent. The system injects both into the system prompt at session start.

type Provider

type Provider interface {
	// Name returns the plugin identifier (e.g. "lcm", "simple").
	// Used in logs and admin UI.
	Name() string

	// Bootstrap ensures the session is initialized and ready for use.
	// Called once at the start of every Pool.Chat call before any Append or Assemble.
	// Implementations use this to create conversation records, initialize caches,
	// or establish remote connections for the session.
	Bootstrap(ctx context.Context, session Session) error

	// Append persists one or more messages to the session's event log.
	// Messages must be appended in the order they arrive.
	// Callers pass all messages from a single turn together so implementations
	// can store them in a single atomic transaction if they choose.
	//
	// Concurrency: implementations MUST be safe for concurrent Append calls
	// on different sessions. Concurrent Append calls on the SAME session
	// MUST be serialised by the implementation (see Concurrency Contract).
	Append(ctx context.Context, session Session, msgs ...ai.Message) error

	// Assemble builds the context window to send to the LLM.
	// budget: maximum number of tokens the returned messages may consume.
	// freshTail: minimum number of recent messages to always include verbatim,
	//   regardless of budget pressure. Implementations MUST honour this.
	// Returns messages in chronological order (oldest first).
	// Older content that does not fit in the budget is either summarised
	// (if the plugin supports Compactor) or omitted.
	Assemble(ctx context.Context, session Session, budget, freshTail int) ([]ai.Message, error)

	// Stats returns basic statistics about a session's memory state.
	// Used by the memory tool's "status" action and by admin endpoints.
	// Returns zero-value stats (not an error) if the session does not exist.
	Stats(ctx context.Context, session Session) (SessionStats, error)

	// Close releases any resources held by the provider (DB connections, caches, etc.).
	// Called when the Pool shuts down. Must be safe to call multiple times.
	Close() error
}

Provider is the memory plugin contract. Every memory plugin must implement this interface. Optional capabilities are discovered via type assertion — see Capability Interfaces.

func Unwrap

func Unwrap(p Provider) Provider

Unwrap returns the innermost Provider by recursively unwrapping traced layers. If p does not implement the unwrapper interface, p itself is returned.

func WithTracing

func WithTracing(provider Provider, hooksFn func() *hooks.HookSet) Provider

WithTracing wraps a Provider to emit PostMemoryCall hooks after each operation. hooksFn is called on each operation to get the current HookSet; it may return nil. The returned Provider implements all optional capability interfaces (Compactor, Searcher, Explorer, ProfileStore, SessionManager, Reviewer). Methods for capabilities not supported by the inner provider return sensible zero values or errors. Use Unwrap to check the inner provider's actual capabilities.

The Detail field is always populated with content previews. The trace hook decides whether to emit it based on log level (see [LevelTrace]).

type Reviewer

type Reviewer interface {
	// BuildReviewContext returns a text representation of the conversation
	// suitable for passing to a reviewer agent's prompt.
	//
	// since: if non-zero, only include content created after this time.
	//   The provider should include prior context (e.g. summaries from before
	//   this timestamp) to give the reviewer enough background.
	//   If zero, include all content.
	//
	// Returns ("", nil) if there is no content to review.
	BuildReviewContext(ctx context.Context, session Session, since time.Time) (string, error)
}

Reviewer is implemented by providers that can format conversation content for review by a background agent (the reflect system).

This is deliberately a single method. Watermark tracking (which sessions have been reviewed, when) is not the memory plugin's concern — it belongs to the consumer (`plugins/reflect`). The memory plugin's only job is: "given a session and an optional time boundary, produce reviewable text."

type SearchQuery

type SearchQuery struct {
	Text  string      // search term (keyword or natural language depending on plugin)
	Scope SearchScope // which layer of storage to search
	Limit int         // max results (default 20)
}

SearchQuery describes a search request.

type SearchResult

type SearchResult struct {
	SourceType string    // "message" or "summary"
	SourceID   string    // message ID or summary ID
	Content    string    // snippet of the matching content (truncated at ~500 chars)
	Score      float64   // relevance score: 0 for keyword match, 0.0-1.0 for semantic
	Timestamp  time.Time // when the source was created
}

SearchResult represents a single search hit.

type SearchScope

type SearchScope int

SearchScope controls which storage layer to search.

const (
	SearchScopeBoth      SearchScope = iota // default: search everything
	SearchScopeMessages                     // raw messages only
	SearchScopeSummaries                    // summaries only
)

type Searcher

type Searcher interface {
	Search(ctx context.Context, session Session, query SearchQuery) ([]SearchResult, error)
}

Searcher is implemented by providers that support history search.

type Session

type Session struct {
	ID      string // unique session key (e.g. "default:cli:42:main")
	AgentID string // agent this session belongs to (e.g. "default")
	UserID  int64  // internal user ID (0 for anonymous/legacy)
	Channel string // originating channel (e.g. "cli", "telegram")
}

Session identifies the context of a single conversation. It is created by Pool.Chat and passed to all Provider methods.

type SessionInfo

type SessionInfo struct {
	ID         string
	AgentID    string
	UserID     int64
	Channel    string
	Title      string // auto-generated from first message
	CreatedAt  time.Time
	LastActive time.Time
	Archived   bool
}

SessionInfo holds metadata about a session.

type SessionManager

type SessionManager interface {
	// SaveInfo persists or updates session metadata.
	SaveInfo(ctx context.Context, info SessionInfo) error

	// LoadInfo retrieves metadata for a single session.
	LoadInfo(ctx context.Context, sessionID string) (SessionInfo, error)

	// ListInfo lists sessions matching the options.
	ListInfo(ctx context.Context, opts ListOptions) ([]SessionInfo, error)

	// LoadHistory returns the complete raw message history for a session
	// in chronological order. Used by the admin panel viewer and export.
	LoadHistory(ctx context.Context, sessionID string) ([]ai.Message, error)
}

SessionManager is implemented by providers that support session lifecycle management.

type SessionStats

type SessionStats struct {
	MessageCount int       // total messages stored for this session
	TokenCount   int       // estimated total tokens across all stored messages
	SummaryCount int       // number of summaries (0 for providers without Compactor)
	OldestAt     time.Time // timestamp of the earliest message (zero if empty)
	NewestAt     time.Time // timestamp of the most recent message (zero if empty)
}

SessionStats contains basic statistics about a session's memory state. Every provider can produce this since it only requires knowledge of what was stored via Append.

type StaticSummarizer

type StaticSummarizer struct {
	Response string
	Err      error
}

StaticSummarizer always returns a fixed response (for testing).

func (*StaticSummarizer) Summarize

Summarize returns the static response.

type SummarizeOptions

type SummarizeOptions struct {
	IsCondensed  bool
	Depth        int
	Aggressive   bool
	Previous     string // previous summary for continuity
	TargetTokens int
}

SummarizeOptions controls summarization behavior.

type Summarizer

type Summarizer interface {
	Summarize(ctx context.Context, text string, opts SummarizeOptions) (string, error)
}

Summarizer generates summaries from content.

type ToolOption

type ToolOption func(*toolConfig)

ToolOption configures the generated memory tool.

func WithActionsOnly

func WithActionsOnly(actions ...string) ToolOption

WithActionsOnly restricts the tool to the named actions only. Actions not in the list are omitted even if the provider supports them.

func WithReadOnlyProfile

func WithReadOnlyProfile() ToolOption

WithReadOnlyProfile disables the profile_update action. Used when building the tool for the self-improve reviewer agent, which should read but not arbitrarily overwrite profile notes.

func WithReadOnlySoul

func WithReadOnlySoul() ToolOption

WithReadOnlySoul disables the soul_update action.

Directories

Path Synopsis
Package memorytest provides test doubles and conformance testing for memory.Provider implementations.
Package memorytest provides test doubles and conformance testing for memory.Provider implementations.

Jump to

Keyboard shortcuts

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