adapters

package
v0.19.0 Latest Latest
Warning

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

Go to latest
Published: Aug 30, 2026 License: AGPL-3.0 Imports: 16 Imported by: 0

Documentation

Index

Constants

View Source
const (

	// MaxSourceRefsPerMemory bounds durable provenance growth for one memory.
	// The PostgreSQL upsert enforces the same limit atomically.
	MaxSourceRefsPerMemory = 64

	// MaxSourceRefsPerToolResult bounds source locators exposed for one memory
	// hit after validation and authorization.
	MaxSourceRefsPerToolResult = 8
)
View Source
const DefaultBuiltinProviderID = "__builtin_default__"

DefaultBuiltinProviderID is the virtual provider selected when a bot has no persisted memory_provider_id. Registries materialize it per team.

View Source
const ToolSearchMemory = "search_memory"

Variables

This section is empty.

Functions

func BuildProfileMetadata

func BuildProfileMetadata(userID, channelIdentityID, displayName string) map[string]any

func EncodeSourceRef

func EncodeSourceRef(sessionID, messageID string) string

EncodeSourceRef builds a "<sessionID>/<messageID>" source ref. The session part is optional so bare message IDs stay valid refs.

func MemoryContextQueryHash

func MemoryContextQueryHash(query string) string

MemoryContextQueryHash returns a stable compact hash for cache keys.

func MergeMetadata

func MergeMetadata(base map[string]any, extra map[string]any) map[string]any

func MergeSourceRefs

func MergeSourceRefs(existing, extra []string) []string

MergeSourceRefs appends new associations to existing provenance and applies the same canonical validation and bound used at storage boundaries.

func NormalizeSourceRefs

func NormalizeSourceRefs(refs []string) []string

NormalizeSourceRefs validates, de-duplicates, and retains the newest associations up to the durable per-memory limit. Input order is association order; retained output keeps that order.

func ParseScopedSourceRef

func ParseScopedSourceRef(ref string) (sessionID, messageID string, ok bool)

ParseScopedSourceRef accepts only the durable ref shape emitted by the chat persistence path. Bare legacy message IDs cannot be authorized across sessions and malformed multi-segment refs are rejected.

func ParseSourceRef

func ParseSourceRef(ref string) (sessionID, messageID string)

ParseSourceRef splits a source ref into its session and message parts. A ref without a separator is treated as a bare message ID.

func RetainSourceRefs

func RetainSourceRefs(refs []string, limit int) []string

RetainSourceRefs validates before applying the limit, so malformed tail entries cannot crowd out older valid provenance.

func StringFromConfig

func StringFromConfig(config map[string]any, key string) string

StringFromConfig extracts a trimmed string value from a config map.

func TruncateSnippet

func TruncateSnippet(s string, n int) string

TruncateSnippet truncates a string to n runes, appending "..." if truncated.

Types

type AddRequest

type AddRequest struct {
	Message          string         `json:"message,omitempty"`
	Messages         []Message      `json:"messages,omitempty"`
	BotID            string         `json:"bot_id,omitempty"`
	AgentID          string         `json:"agent_id,omitempty"`
	RunID            string         `json:"run_id,omitempty"`
	Metadata         map[string]any `json:"metadata,omitempty"`
	Filters          map[string]any `json:"filters,omitempty"`
	Infer            *bool          `json:"infer,omitempty"`
	EmbeddingEnabled *bool          `json:"embedding_enabled,omitempty"`
	SourceMessageIDs []string       `json:"source_message_ids,omitempty"`
}

type AfterChatRequest

type AfterChatRequest struct {
	BotID             string
	Messages          []Message
	UserID            string
	ChannelIdentityID string
	DisplayName       string
	TimezoneLocation  *time.Location
}

AfterChatRequest is passed to OnAfterChat after receiving the gateway response.

type BeforeChatRequest

type BeforeChatRequest struct {
	Query  string
	BotID  string
	ChatID string
}

BeforeChatRequest is passed to OnBeforeChat before sending to the agent gateway.

type BeforeChatResult

type BeforeChatResult struct {
	ContextText    string // formatted text to inject as a user message
	RetrievalMode  string // graph, file_fallback, mem0, etc.
	FallbackReason string // non-empty when the provider degraded to another retrieval path
}

BeforeChatResult contains memory context to inject into the conversation.

type CandidateMemory

type CandidateMemory struct {
	ID        string         `json:"id"`
	Memory    string         `json:"memory"`
	CreatedAt string         `json:"created_at,omitempty"`
	Metadata  map[string]any `json:"metadata,omitempty"`
}

type CompactRequest

type CompactRequest struct {
	BotID       string            `json:"bot_id,omitempty"`
	Memories    []CandidateMemory `json:"memories"`
	TargetCount int               `json:"target_count"`
	DecayDays   int               `json:"decay_days,omitempty"`
}

type CompactResponse

type CompactResponse struct {
	Facts []string `json:"facts"`
}

type CompactResult

type CompactResult struct {
	BeforeCount int          `json:"before_count"`
	AfterCount  int          `json:"after_count"`
	Ratio       float64      `json:"ratio"`
	Results     []MemoryItem `json:"results"`
}

type DecideRequest

type DecideRequest struct {
	BotID      string            `json:"bot_id,omitempty"`
	Facts      []string          `json:"facts"`
	Candidates []CandidateMemory `json:"candidates"`
	Filters    map[string]any    `json:"filters,omitempty"`
	Metadata   map[string]any    `json:"metadata,omitempty"`
}

type DecideResponse

type DecideResponse struct {
	Actions []DecisionAction `json:"actions"`
}

type DecisionAction

type DecisionAction struct {
	Event             string `json:"event"`
	ID                string `json:"id,omitempty"`
	Text              string `json:"text"`
	OldMemory         string `json:"old_memory,omitempty"`
	SourceFactIndices []int  `json:"source_fact_indices,omitempty"`
}

type DeleteAllRequest

type DeleteAllRequest struct {
	BotID   string         `json:"bot_id,omitempty"`
	AgentID string         `json:"agent_id,omitempty"`
	RunID   string         `json:"run_id,omitempty"`
	Filters map[string]any `json:"filters,omitempty"`
}

type DeleteResponse

type DeleteResponse struct {
	Message string `json:"message"`
}

type ExtractRequest

type ExtractRequest struct {
	BotID            string         `json:"bot_id,omitempty"`
	Messages         []Message      `json:"messages"`
	Filters          map[string]any `json:"filters,omitempty"`
	Metadata         map[string]any `json:"metadata,omitempty"`
	TimezoneLocation *time.Location `json:"-"`
}

type ExtractResponse

type ExtractResponse struct {
	Facts                []string   `json:"facts"`
	FactSourceMessageIDs [][]string `json:"-"`
}

type Factory

type Factory func(ctx context.Context, teamID, id string, config map[string]any) (Provider, error)

Factory creates a Provider from a provider type string and JSON config. The registry uses factories to lazily instantiate providers from DB rows.

type GetAllRequest

type GetAllRequest struct {
	BotID   string         `json:"bot_id,omitempty"`
	AgentID string         `json:"agent_id,omitempty"`
	RunID   string         `json:"run_id,omitempty"`
	Limit   int            `json:"limit,omitempty"`
	Filters map[string]any `json:"filters,omitempty"`
	NoStats bool           `json:"no_stats,omitempty"`
}

type HealthStatus

type HealthStatus struct {
	OK    bool   `json:"ok"`
	Error string `json:"error,omitempty"`
}

type IngestResult

type IngestResult struct {
	// Ingested is the number of memory nodes written to the store (inserts +
	// updates; re-ingesting an unchanged file counts as an update).
	Ingested int `json:"ingested"`
	// Skipped is the number of source items that parsed to empty content or
	// failed to persist.
	Skipped int `json:"skipped"`
}

IngestResult reports the outcome of a file→DB memory ingest pass.

type LLM

type LLM interface {
	Extract(ctx context.Context, req ExtractRequest) (ExtractResponse, error)
	Decide(ctx context.Context, req DecideRequest) (DecideResponse, error)
	Compact(ctx context.Context, req CompactRequest) (CompactResponse, error)
}

LLM is the interface for LLM operations needed by memory service.

type MarkdownIngestProvider

type MarkdownIngestProvider interface {
	IngestFromMarkdown(ctx context.Context, botID string) (IngestResult, error)
}

MarkdownIngestProvider is implemented by providers whose canonical source of truth is the DB but which also accept agent-authored Markdown files as input. IngestFromMarkdown reads /data/memory/*.md and upserts them as DB nodes, closing the gap left by the DB→file derived-view sync (which only writes files FROM nodes). Providers that treat files as the source of truth (e.g. the legacy file runtime) do not implement this.

type MemoryCompactCapability

type MemoryCompactCapability struct {
	Semantic     bool   `json:"semantic"`
	Archive      bool   `json:"archive,omitempty"`
	RebuildIndex bool   `json:"rebuild_index,omitempty"`
	Reason       string `json:"reason,omitempty"`
}

type MemoryContextCache

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

MemoryContextCache stores rendered memory context for fast first-token paths.

func (*MemoryContextCache) Get

Get returns a fresh cache value.

func (*MemoryContextCache) GetStale

GetStale returns a value inside its stale grace window.

func (*MemoryContextCache) Set

Set stores a rendered memory context.

type MemoryContextCacheConfig

type MemoryContextCacheConfig struct {
	TTL        time.Duration
	StaleTTL   time.Duration
	MaxEntries int
	Now        func() time.Time
}

MemoryContextCacheConfig configures the short-lived chat memory context cache. StaleTTL is the additional grace window after TTL expires.

type MemoryContextCacheKey

type MemoryContextCacheKey struct {
	BotID         string
	ChatID        string
	ProviderID    string
	QueryHash     string
	MemoryVersion string
}

MemoryContextCacheKey identifies one rendered memory context payload.

type MemoryContextCacheValue

type MemoryContextCacheValue struct {
	ContextText    string
	RetrievalMode  string
	FallbackReason string
	CreatedAt      time.Time
	ExpiresAt      time.Time
	StaleUntil     time.Time
	LastAccessedAt time.Time
}

MemoryContextCacheValue is a cached rendered memory context.

type MemoryItem

type MemoryItem struct {
	ID        string         `json:"id"`
	Memory    string         `json:"memory"`
	Hash      string         `json:"hash,omitempty"`
	CreatedAt string         `json:"created_at,omitempty"`
	UpdatedAt string         `json:"updated_at,omitempty"`
	Score     float64        `json:"score,omitempty"`
	Metadata  map[string]any `json:"metadata,omitempty"`
	BotID     string         `json:"bot_id,omitempty"`
	AgentID   string         `json:"agent_id,omitempty"`
	RunID     string         `json:"run_id,omitempty"`
	// SourceMessageIDs is internal provenance. Public HTTP responses must not
	// expose raw session/message locators; tool projections authorize and render
	// them explicitly at the request boundary.
	SourceMessageIDs []string `json:"-"`
}

func DeduplicateItems

func DeduplicateItems(items []MemoryItem) []MemoryItem

DeduplicateItems removes duplicate MemoryItems by ID.

type MemoryStatusResponse

type MemoryStatusResponse struct {
	ProviderType      string                  `json:"provider_type,omitempty"`
	MemoryMode        string                  `json:"memory_mode,omitempty"`
	Compact           MemoryCompactCapability `json:"compact"`
	CanManualSync     bool                    `json:"can_manual_sync"`
	SourceDir         string                  `json:"source_dir,omitempty"`
	OverviewPath      string                  `json:"overview_path,omitempty"`
	MarkdownFileCount int                     `json:"markdown_file_count"`
	SourceCount       int                     `json:"source_count"`
	EdgeCount         int                     `json:"edge_count"`
	IndexedCount      int                     `json:"indexed_count"`
	VectorIndex       string                  `json:"vector_index,omitempty"`
	Encoder           *HealthStatus           `json:"encoder,omitempty"`
	Pgvector          *HealthStatus           `json:"pgvector,omitempty"`
	// Degraded reports that the semantic seed index is behind the wiki store
	// (failed upserts are queued for retry); graph recall still works.
	Degraded        bool `json:"degraded"`
	RetryQueueDepth int  `json:"retry_queue_depth"`
}

type MemoryVersionProvider

type MemoryVersionProvider interface {
	MemoryVersion(ctx context.Context, botID string) string
}

MemoryVersionProvider is implemented by providers that can expose a cheap cache-busting version for the bot's memory source of truth.

type Message

type Message struct {
	Role            string `json:"role"`
	Content         string `json:"content"`
	SourceMessageID string `json:"-"`
}

type Provider

type Provider interface {
	// Type returns the provider type identifier (e.g. "builtin", "mem0").
	Type() string

	OnBeforeChat(ctx context.Context, req BeforeChatRequest) (*BeforeChatResult, error)
	OnAfterChat(ctx context.Context, req AfterChatRequest) error

	ListTools(ctx context.Context, session mcp.ToolSessionContext) ([]mcp.ToolDescriptor, error)
	CallTool(ctx context.Context, session mcp.ToolSessionContext, toolName string, arguments map[string]any) (map[string]any, error)

	Add(ctx context.Context, req AddRequest) (SearchResponse, error)
	Search(ctx context.Context, req SearchRequest) (SearchResponse, error)
	GetAll(ctx context.Context, req GetAllRequest) (SearchResponse, error)
	Update(ctx context.Context, req UpdateRequest) (MemoryItem, error)
	Delete(ctx context.Context, memoryID string) (DeleteResponse, error)
	DeleteBatch(ctx context.Context, memoryIDs []string) (DeleteResponse, error)
	DeleteAll(ctx context.Context, req DeleteAllRequest) (DeleteResponse, error)

	Compact(ctx context.Context, filters map[string]any, ratio float64, decayDays int) (CompactResult, error)
	Usage(ctx context.Context, filters map[string]any) (UsageResponse, error)
}

Provider is the unified interface for memory systems. Each provider type (builtin, mem0, openviking, etc.) implements this independently with its own storage, retrieval, and tool logic.

type ProviderCollectionStatus

type ProviderCollectionStatus struct {
	Name   string       `json:"name"`
	Exists bool         `json:"exists"`
	Points int          `json:"points"`
	Health HealthStatus `json:"health"`
}

type ProviderConfigLoader

type ProviderConfigLoader func(ctx context.Context, id string) (providerType string, config map[string]any, err error)

ProviderConfigLoader loads one provider configuration under the team already bound to ctx. It lets a registry lazily instantiate providers on first use instead of requiring an all-team startup scan.

type ProviderConfigSchema

type ProviderConfigSchema struct {
	Fields map[string]ProviderFieldSchema `json:"fields"`
}

type ProviderCreateRequest

type ProviderCreateRequest struct {
	Name     string         `json:"name"`
	Provider ProviderType   `json:"provider"`
	Config   map[string]any `json:"config,omitempty"`
}

type ProviderFieldSchema

type ProviderFieldSchema struct {
	Type        string `json:"type"`
	Title       string `json:"title,omitempty"`
	Description string `json:"description,omitempty"`
	Required    bool   `json:"required,omitempty"`
	Secret      bool   `json:"secret,omitempty"`
	Example     any    `json:"example,omitempty"`
}

type ProviderGetResponse

type ProviderGetResponse struct {
	ID        string         `json:"id"`
	Name      string         `json:"name"`
	Provider  string         `json:"provider"`
	Config    map[string]any `json:"config,omitempty"`
	IsDefault bool           `json:"is_default"`
	CreatedAt time.Time      `json:"created_at"`
	UpdatedAt time.Time      `json:"updated_at"`
}

type ProviderMeta

type ProviderMeta struct {
	Provider     string               `json:"provider"`
	DisplayName  string               `json:"display_name"`
	ConfigSchema ProviderConfigSchema `json:"config_schema"`
}

type ProviderStatusResponse

type ProviderStatusResponse struct {
	ProviderType     string                     `json:"provider_type"`
	MemoryMode       string                     `json:"memory_mode,omitempty"`
	EmbeddingModelID string                     `json:"embedding_model_id,omitempty"`
	Collections      []ProviderCollectionStatus `json:"collections,omitempty"`
}

type ProviderType

type ProviderType string

Memory provider admin types.

const (
	ProviderBuiltin    ProviderType = "builtin"
	ProviderMem0       ProviderType = "mem0"
	ProviderOpenViking ProviderType = "openviking"
)

type ProviderUpdateRequest

type ProviderUpdateRequest struct {
	Name   *string        `json:"name,omitempty"`
	Config map[string]any `json:"config,omitempty"`
}

type RebuildResult

type RebuildResult struct {
	FsCount       int `json:"fs_count"`
	StorageCount  int `json:"storage_count"`
	MissingCount  int `json:"missing_count"`
	RestoredCount int `json:"restored_count"`
}

type Registry

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

Registry manages provider instances keyed by their DB id. It caches instantiated providers and uses registered factories to create them on demand from stored configuration.

func NewRegistry

func NewRegistry(log *slog.Logger, resolvers ...TeamIDResolver) *Registry

func (*Registry) Close

func (r *Registry) Close() error

Close releases every instantiated provider. It is safe to call more than once and is used during process shutdown as well as team registry teardown.

func (*Registry) Get

func (r *Registry) Get(ctx context.Context, id string) (Provider, error)

Get returns the team-owned provider for the given DB record ID. Cache misses are loaded and instantiated under the same team scope.

func (*Registry) Instantiate

func (r *Registry) Instantiate(ctx context.Context, id, providerType string, config map[string]any) (Provider, error)

Instantiate creates a provider from a DB row and caches it. If the instance already exists, it is returned directly.

func (*Registry) Register

func (r *Registry) Register(id string, provider Provider)

Register adds a pre-built provider instance by ID.

func (*Registry) RegisterContext

func (r *Registry) RegisterContext(ctx context.Context, id string, provider Provider) error

RegisterContext adds a pre-built provider under the team resolved from ctx.

func (*Registry) RegisterFactory

func (r *Registry) RegisterFactory(providerType string, factory Factory)

RegisterFactory registers a factory for a given provider type (e.g. "builtin").

func (*Registry) Remove

func (r *Registry) Remove(ctx context.Context, id string) error

Remove evicts a cached provider instance (e.g. after config update or delete).

func (*Registry) SetConfigLoader

func (r *Registry) SetConfigLoader(loader ProviderConfigLoader)

SetConfigLoader configures lazy provider lookup for cache misses.

func (*Registry) SetTeamDefaultFactory

func (r *Registry) SetTeamDefaultFactory(factory TeamDefaultFactory)

SetTeamDefaultFactory configures lazy, team-owned builtin fallbacks.

type SearchRequest

type SearchRequest struct {
	Query            string         `json:"query"`
	BotID            string         `json:"bot_id,omitempty"`
	AgentID          string         `json:"agent_id,omitempty"`
	RunID            string         `json:"run_id,omitempty"`
	Limit            int            `json:"limit,omitempty"`
	Filters          map[string]any `json:"filters,omitempty"`
	Sources          []string       `json:"sources,omitempty"`
	EmbeddingEnabled *bool          `json:"embedding_enabled,omitempty"`
	NoStats          bool           `json:"no_stats,omitempty"`
}

type SearchResponse

type SearchResponse struct {
	Results        []MemoryItem `json:"results"`
	Relations      []any        `json:"relations,omitempty"`
	RetrievalMode  string       `json:"retrieval_mode,omitempty"`
	FallbackReason string       `json:"fallback_reason,omitempty"`
}

type SemanticCompactProvider

type SemanticCompactProvider interface {
	SemanticCompactCapability() MemoryCompactCapability
}

SemanticCompactProvider is implemented by providers that can apply Memoh's semantic memory compact contract under the selected bot scope.

type Service

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

func NewService

func NewService(log *slog.Logger, queries dbstore.Queries, cfg config.Config) *Service

func (*Service) Create

func (*Service) Delete

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

func (*Service) EnsureDefault

func (s *Service) EnsureDefault(ctx context.Context) (ProviderGetResponse, error)

EnsureDefault creates a default builtin provider if none exists.

func (*Service) Get

func (*Service) InstantiateAll

func (s *Service) InstantiateAll(ctx context.Context) (int, error)

func (*Service) List

func (s *Service) List(ctx context.Context) ([]ProviderGetResponse, error)

func (*Service) ListMeta

func (*Service) ListMeta(_ context.Context) []ProviderMeta

func (*Service) SetRegistry

func (s *Service) SetRegistry(registry *Registry)

SetRegistry configures the runtime registry so that CRUD operations can instantiate/evict provider instances automatically.

func (*Service) Status

func (s *Service) Status(ctx context.Context, id string) (ProviderStatusResponse, error)

func (*Service) Update

type SourceSyncProvider

type SourceSyncProvider interface {
	Status(ctx context.Context, botID string) (MemoryStatusResponse, error)
	Rebuild(ctx context.Context, botID string) (RebuildResult, error)
}

SourceSyncProvider is implemented by providers that can report runtime status and rebuild derived storage from a canonical source of truth.

type TeamDefaultFactory

type TeamDefaultFactory func(ctx context.Context, teamID string) (Provider, error)

TeamDefaultFactory creates the builtin fallback independently for each team. It is used for bots without an explicit memory provider.

type TeamIDResolver

type TeamIDResolver func(context.Context) (string, error)

TeamIDResolver resolves the team that owns a memory operation. Hosted deployments can inject a strict request-context resolver; upstream defaults to its published singleton team.

func FixedTeamIDResolver

func FixedTeamIDResolver(teamID string) TeamIDResolver

FixedTeamIDResolver returns a resolver permanently scoped to teamID. Provider factories use this for team-owned runtimes whose background work may outlive the request context that instantiated them.

type UpdateRequest

type UpdateRequest struct {
	MemoryID         string   `json:"memory_id"`
	Memory           string   `json:"memory"`
	EmbeddingEnabled *bool    `json:"embedding_enabled,omitempty"`
	SourceMessageIDs []string `json:"source_message_ids,omitempty"`
}

type UsageResponse

type UsageResponse struct {
	Count                 int   `json:"count"`
	TotalTextBytes        int64 `json:"total_text_bytes"`
	AvgTextBytes          int64 `json:"avg_text_bytes"`
	EstimatedStorageBytes int64 `json:"estimated_storage_bytes"`
}

Directories

Path Synopsis

Jump to

Keyboard shortcuts

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