Documentation
¶
Index ¶
- Variables
- func BuildTranscript(messages []types.Message, maxChars int) string
- type Consolidatable
- type ConsolidationReport
- type Consolidator
- type ConsolidatorConfig
- type Entity
- type EntityInput
- type Extractor
- type ExtractorConfig
- type Graph
- type LLMCaller
- type ObservationInput
- type ObservationResult
- type Relation
- type RelationInput
- type SQLiteStore
- func (s *SQLiteStore) AddObservations(ctx context.Context, userID string, inputs []ObservationInput) ([]ObservationResult, error)
- func (s *SQLiteStore) ListEntities(ctx context.Context, userID string) ([]Entity, error)
- func (s *SQLiteStore) OpenNodes(ctx context.Context, userID string, names []string) (*Graph, error)
- func (s *SQLiteStore) ReplaceEntities(ctx context.Context, userID string, snapshot []Entity, entities []EntityInput, ...) error
- func (s *SQLiteStore) RetrieveForContext(ctx context.Context, userID, query string, maxTokens int) (string, error)
- func (s *SQLiteStore) SearchNodes(ctx context.Context, userID, query string) (*Graph, error)
- func (s *SQLiteStore) UpsertEntities(ctx context.Context, userID string, inputs []EntityInput) ([]Entity, error)
- type Store
Constants ¶
This section is empty.
Variables ¶
var ErrChangedDuringConsolidation = errors.New("memory changed while it was being consolidated")
ErrChangedDuringConsolidation is returned when memory was written while a consolidation was being computed. The consolidation is dropped, not retried: the next one starts from the new state.
var ErrRefusedConsolidation = errors.New("consolidation result refused")
ErrRefusedConsolidation is returned when the model's result was refused as unsafe to apply.
Functions ¶
Types ¶
type Consolidatable ¶ added in v1.10.1
type Consolidatable interface {
Store
// ListEntities returns every entity of the user, ordered by name.
ListEntities(ctx context.Context, userID string) ([]Entity, error)
// ReplaceEntities rewrites the entities of snapshot (what ListEntities returned) as entities, atomically: a
// snapshot entity not in entities is removed, one in entities is created or rewritten. It returns
// ErrChangedDuringConsolidation, changing nothing, if any snapshot entity was modified or removed since the
// snapshot; entities created since are left alone. renames maps the name of an entity merged into another to the
// name it now has, so that relations follow it; a relation left without both endpoints, or pointing to itself, is
// removed.
ReplaceEntities(ctx context.Context, userID string, snapshot []Entity, entities []EntityInput, renames map[string]string) error
}
Consolidatable is a Store that can be rewritten as a whole, which consolidation needs: the plain Store only adds. SQLiteStore implements it; a host with its own Store opts in by implementing it too.
type ConsolidationReport ¶ added in v1.10.1
type ConsolidationReport struct {
EntitiesBefore, EntitiesAfter int
ObservationsBefore, ObservationsAfter int
}
ConsolidationReport says what a consolidation changed.
type Consolidator ¶ added in v1.10.1
type Consolidator struct {
// contains filtered or unexported fields
}
Consolidator is the second phase of memory: extraction only ever adds, so memory fills with near-duplicates and facts that were later contradicted. The consolidator rereads a user's whole memory and rewrites it smaller: merging duplicates, keeping the newest of two statements that conflict, and dropping what no longer holds.
func NewConsolidator ¶ added in v1.10.1
func NewConsolidator(store Consolidatable, caller LLMCaller, cfg ConsolidatorConfig) *Consolidator
NewConsolidator creates a Consolidator.
func (*Consolidator) Consolidate ¶ added in v1.10.1
func (c *Consolidator) Consolidate(ctx context.Context, userID string) (*ConsolidationReport, error)
Consolidate rewrites the user's memory now, if it holds at least MinObservations. It returns a nil report when it is too small.
func (*Consolidator) MaybeConsolidate ¶ added in v1.10.1
func (c *Consolidator) MaybeConsolidate(ctx context.Context, userID string) (*ConsolidationReport, error)
MaybeConsolidate consolidates the user's memory if it is big enough and was not consolidated recently, and does nothing otherwise (a nil report). An attempt that fails still counts as recent, so a failing model is not called again at every session.
type ConsolidatorConfig ¶ added in v1.10.1
type ConsolidatorConfig struct {
// MinObservations is the number of observations a user must hold before consolidation is worth a model call.
// Default: 60.
MinObservations int
// MinInterval is the shortest time between two consolidations of the same user, kept per process. Default: 24h.
MinInterval time.Duration
// MaxInputChars caps the memory sent to the model. Entities past it are left as they are. Default: 60000.
MaxInputChars int
// MinKeepRatio is the share of the observations a result must keep to be applied: a result that drops more is
// taken for a model error and refused. Default: 0.3.
MinKeepRatio float64
// Model is the model that consolidates. Zero uses the caller's default.
Model types.ModelIdentifier
// Timeout is the deadline of the model call. Default: 120s.
Timeout time.Duration
}
ConsolidatorConfig controls when and how memory is consolidated.
type Entity ¶
type Entity struct {
ID string `json:"id"`
UserID string `json:"user_id"`
Name string `json:"name"`
EntityType string `json:"entity_type"`
Observations []string `json:"observations"`
CreatedAt time.Time `json:"created_at"`
UpdatedAt time.Time `json:"updated_at"`
}
Entity is a named thing with a type and a list of observations. Modelled after the MCP memory server reference (servers/src/memory).
type EntityInput ¶
type EntityInput struct {
Name string `json:"name"`
EntityType string `json:"entity_type"`
Observations []string `json:"observations"`
}
EntityInput is used for upsert operations.
func ParseLLMResponse ¶
func ParseLLMResponse(raw string) ([]EntityInput, error)
ParseLLMResponse extracts EntityInputs from a JSON string that may be wrapped in markdown fences or surrounded by explanatory prose.
func ScreenEntities ¶ added in v1.10.1
func ScreenEntities(in []EntityInput) []EntityInput
ScreenEntities applies the limits to what a model proposed to remember: it drops an observation that holds a credential, shortens an overlong one, and keeps at most maxEntitiesPerExtraction entities with maxObservationsPerEntity observations each. An entity left with nothing to say is dropped.
type Extractor ¶
type Extractor struct {
// contains filtered or unexported fields
}
Extractor runs LLM-powered extraction of entities and observations from session transcripts and persists them in the long-term memory graph.
Extraction is designed to be asynchronous and best-effort: any error is logged at DEBUG level and not surfaced to the user.
func NewExtractor ¶
func NewExtractor(store Store, caller LLMCaller, cfg ExtractorConfig) *Extractor
NewExtractor creates an Extractor. Zero-value config fields are replaced with defaults.
func (*Extractor) Extract ¶
Extract analyses the conversation and upserts any extracted entities into the knowledge graph for userID.
It is safe to call from a goroutine: all errors are logged and the function always returns nil to the caller (extraction failures are non-fatal).
func (*Extractor) SetConsolidator ¶ added in v1.10.1
func (e *Extractor) SetConsolidator(c *Consolidator)
SetConsolidator makes the extractor consolidate the user's memory after each extraction, when the consolidator finds it due. Nil (the default) never consolidates.
type ExtractorConfig ¶
type ExtractorConfig struct {
// MinTurns is the minimum number of user turns required before extraction
// runs. Short sessions rarely contain facts worth persisting.
// Default: 3.
MinTurns int
// MaxTranscriptChars caps the conversation snippet fed to the LLM.
// Keeps extraction cheap; recent turns are preferred when truncating.
// Default: 8000.
MaxTranscriptChars int
// Model is the LLM model used for extraction. Haiku-class recommended.
// When Model.Model is empty the request is sent without an explicit model
// field, relying on the caller's default.
Model types.ModelIdentifier
// ExtractionTimeout is the per-call deadline passed to CreateMessage.
// Default: 45 s.
ExtractionTimeout time.Duration
}
ExtractorConfig controls extraction behaviour.
func DefaultExtractorConfig ¶
func DefaultExtractorConfig() ExtractorConfig
DefaultExtractorConfig returns sensible defaults.
type LLMCaller ¶
type LLMCaller interface {
CreateMessage(ctx context.Context, req types.APIRequest) (*types.APIResponse, error)
}
LLMCaller is the minimal interface for calling the provider API. *providers.Client satisfies this — defined here as an interface so the extractor can be tested without a live network call.
type ObservationInput ¶
type ObservationInput struct {
EntityName string `json:"entity_name"`
Contents []string `json:"contents"`
}
ObservationInput appends observations to an existing entity.
type ObservationResult ¶
type ObservationResult struct {
EntityName string `json:"entity_name"`
AddedObservations []string `json:"added_observations"`
}
ObservationResult reports what was actually added after deduplication.
type Relation ¶
type Relation struct {
ID string `json:"id"`
UserID string `json:"user_id"`
From string `json:"from"` // entity name
To string `json:"to"` // entity name
RelationType string `json:"relation_type"`
CreatedAt time.Time `json:"created_at"`
}
Relation is a directed edge between two entities (active-voice convention).
type RelationInput ¶
type RelationInput struct {
From string `json:"from"`
To string `json:"to"`
RelationType string `json:"relation_type"`
}
RelationInput is used for create operations.
type SQLiteStore ¶
type SQLiteStore struct {
// contains filtered or unexported fields
}
SQLiteStore implements Store using a SQLite database. Schema is initialized via migration 20260615_012_longterm_memory.
func NewSQLiteStore ¶
func NewSQLiteStore(db *sql.DB) *SQLiteStore
NewSQLiteStore wraps an open *sql.DB as a longterm memory Store. The caller is responsible for closing the underlying DB.
func (*SQLiteStore) AddObservations ¶
func (s *SQLiteStore) AddObservations(ctx context.Context, userID string, inputs []ObservationInput) ([]ObservationResult, error)
AddObservations appends new observations to existing entities. Duplicate observation strings (per entity) are silently skipped.
func (*SQLiteStore) ListEntities ¶ added in v1.10.1
ListEntities returns every entity of the user, ordered by name.
func (*SQLiteStore) OpenNodes ¶
OpenNodes retrieves specific entities by exact name and their relations.
func (*SQLiteStore) ReplaceEntities ¶ added in v1.10.1
func (s *SQLiteStore) ReplaceEntities(ctx context.Context, userID string, snapshot []Entity, entities []EntityInput, renames map[string]string) error
ReplaceEntities implements Consolidatable.
func (*SQLiteStore) RetrieveForContext ¶
func (s *SQLiteStore) RetrieveForContext(ctx context.Context, userID, query string, maxTokens int) (string, error)
RetrieveForContext searches memory and formats results as a Markdown block.
func (*SQLiteStore) SearchNodes ¶
SearchNodes performs case-insensitive substring search across entity names, types, and observation content.
func (*SQLiteStore) UpsertEntities ¶
func (s *SQLiteStore) UpsertEntities(ctx context.Context, userID string, inputs []EntityInput) ([]Entity, error)
UpsertEntities creates entities that do not yet exist (deduplicates by name per user). Returns only the entities that were actually inserted.
type Store ¶
type Store interface {
// UpsertEntities creates entities that do not exist yet (deduplicates by name).
// Returns only the entities that were actually inserted.
UpsertEntities(ctx context.Context, userID string, inputs []EntityInput) ([]Entity, error)
// AddObservations appends new observations to existing entities.
// Duplicate observation strings are silently skipped.
AddObservations(ctx context.Context, userID string, inputs []ObservationInput) ([]ObservationResult, error)
// SearchNodes performs case-insensitive substring search across entity names,
// entity types, and observation content. Returns matching entities plus all
// relations where at least one endpoint is in the result set.
SearchNodes(ctx context.Context, userID, query string) (*Graph, error)
// OpenNodes returns specific entities by exact name and the relations that
// touch them (at least one endpoint in the requested set).
OpenNodes(ctx context.Context, userID string, names []string) (*Graph, error)
// RetrieveForContext retrieves memory relevant to the current query and
// formats it as a Markdown block capped to approximately maxTokens.
// Returns an empty string when there is nothing relevant.
RetrieveForContext(ctx context.Context, userID, query string, maxTokens int) (string, error)
}
Store is the persistence interface for the long-term memory knowledge graph. Concrete persistence implementations are injected by the embedding runtime. All operations are scoped to a single user via userID.