Documentation
¶
Index ¶
- Constants
- Variables
- func BotScopeFilters(botID string) map[string]any
- func BuildProfileMetadata(userID, channelIdentityID, displayName string) map[string]any
- func EncodeSourceRef(sessionID, messageID string) string
- func MemoryContextQueryHash(query string) string
- func MemoryLayers() []string
- func MergeMetadata(base map[string]any, extra map[string]any) map[string]any
- func MergeSourceRefs(existing, extra []string) []string
- func NormalizeMemoryLayer(raw string) string
- func NormalizeSourceRefs(refs []string) []string
- func ParseScopedSourceRef(ref string) (sessionID, messageID string, ok bool)
- func ParseSourceRef(ref string) (sessionID, messageID string)
- func RetainSourceRefs(refs []string, limit int) []string
- func StringFromConfig(config map[string]any, key string) string
- func TruncateSnippet(s string, n int) string
- func ValidateMemoryScope(botID string, memoryIDs ...string) error
- type AddRequest
- type AfterChatRequest
- type BeforeChatRequest
- type BeforeChatResult
- type CandidateMemory
- type CompactRequest
- type CompactResponse
- type CompactResult
- type DecideRequest
- type DecideResponse
- type DecisionAction
- type DeleteAllRequest
- type DeleteResponse
- type ExtractRequest
- type ExtractResponse
- type Factory
- type GetAllRequest
- type HealthStatus
- type IngestResult
- type LLM
- type MarkdownIngestProvider
- type MemoryCompactCapability
- type MemoryConfig
- type MemoryConfigUpdateRequest
- type MemoryContextCache
- func (c *MemoryContextCache) Get(key MemoryContextCacheKey) (MemoryContextCacheValue, bool)
- func (c *MemoryContextCache) GetFreshOrStale(key MemoryContextCacheKey) (MemoryContextCacheValue, MemoryContextCacheState, bool)
- func (c *MemoryContextCache) GetStale(key MemoryContextCacheKey) (MemoryContextCacheValue, bool)
- func (c *MemoryContextCache) Set(key MemoryContextCacheKey, value MemoryContextCacheValue)
- type MemoryContextCacheConfig
- type MemoryContextCacheKey
- type MemoryContextCacheState
- type MemoryContextCacheValue
- type MemoryItem
- type MemoryStatusResponse
- type MemoryVersionProvider
- type Message
- type Provider
- type ProviderConfigLoader
- type ProviderGetResponse
- type ProviderType
- type RebuildResult
- type Registry
- func (r *Registry) Close() error
- func (r *Registry) Get(ctx context.Context, id string) (Provider, error)
- func (r *Registry) Instantiate(ctx context.Context, id, providerType string, config map[string]any) (Provider, error)
- func (r *Registry) Register(id string, provider Provider)
- func (r *Registry) RegisterContext(ctx context.Context, id string, provider Provider) error
- func (r *Registry) RegisterFactory(providerType string, factory Factory)
- func (r *Registry) Remove(ctx context.Context, id string) error
- func (r *Registry) SetConfigLoader(loader ProviderConfigLoader)
- func (r *Registry) SetTeamDefaultFactory(factory TeamDefaultFactory)
- type SearchRequest
- type SearchResponse
- type SemanticCompactProvider
- type Service
- func (s *Service) EnsureBuiltin(ctx context.Context) (ProviderGetResponse, error)
- func (s *Service) EnsureBuiltinID(ctx context.Context) (string, error)
- func (s *Service) Get(ctx context.Context, id string) (ProviderGetResponse, error)
- func (s *Service) GetConfig(ctx context.Context) (MemoryConfig, error)
- func (s *Service) SetRegistry(registry *Registry)
- func (s *Service) UpdateConfig(ctx context.Context, req MemoryConfigUpdateRequest) (MemoryConfig, error)
- type SourceSyncProvider
- type TeamDefaultFactory
- type TeamIDResolver
- type UpdateRequest
- type UsageResponse
Constants ¶
const ( ToolSearchMemory = "search_memory" ToolCreateMemory = "create_memory" ToolUpdateMemory = "update_memory" ToolDeleteMemory = "delete_memory" )
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 )
const DefaultBuiltinProviderID = "__builtin_default__"
DefaultBuiltinProviderID is the virtual provider selected when a bot has no persisted memory_provider_id. Registries materialize it per team.
SharedMemoryNamespace is the namespace bot-shared memory lives in. Every writer — formation, the management API, and the agent-facing write tools — must scope to it, or the write lands somewhere recall never looks.
Variables ¶
var ErrMemoryScope = errors.New("memory does not belong to this bot")
ErrMemoryScope deliberately does not reveal whether a foreign ID exists.
Functions ¶
func BotScopeFilters ¶ added in v0.21.0
BotScopeFilters is the canonical scope for one bot's shared memory.
func BuildProfileMetadata ¶
func EncodeSourceRef ¶
EncodeSourceRef builds a "<sessionID>/<messageID>" source ref. The session part is optional so bare message IDs stay valid refs.
func MemoryContextQueryHash ¶
MemoryContextQueryHash returns a stable compact hash for cache keys.
func MemoryLayers ¶ added in v0.21.0
func MemoryLayers() []string
MemoryLayers is the layer vocabulary a memory write may declare. It is derived from the node vocabulary rather than restated, so a tool schema and the store it writes into cannot drift apart.
func MergeSourceRefs ¶
MergeSourceRefs appends new associations to existing provenance and applies the same canonical validation and bound used at storage boundaries.
func NormalizeMemoryLayer ¶ added in v0.21.0
NormalizeMemoryLayer accepts only the declared vocabulary. An unknown layer is dropped rather than rejected, so the node falls back to its own default instead of failing a write over a cosmetic field.
func NormalizeSourceRefs ¶
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 ¶
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 ¶
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 ¶
RetainSourceRefs validates before applying the limit, so malformed tail entries cannot crowd out older valid provenance.
func StringFromConfig ¶
StringFromConfig extracts a trimmed string value from a config map.
func TruncateSnippet ¶
TruncateSnippet truncates a string to n runes, appending "..." if truncated.
func ValidateMemoryScope ¶ added in v0.21.0
ValidateMemoryScope checks canonical builtin IDs against an independently authorized bot. An ID identifies an object; it never grants access to its bot. Callers must validate a whole batch before performing any mutations.
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
// SkipFormation turns off automatic memory formation for this turn.
// External agent runtimes own the model that ran the turn: the platform
// neither borrows another model to extract facts nor dumps the raw
// transcript into the same store those facts live in. Those runtimes
// write their own memories through the create_memory tool instead.
SkipFormation bool
}
AfterChatRequest is passed to OnAfterChat after receiving the gateway response.
type BeforeChatRequest ¶
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, etc.
FallbackReason string // non-empty when the provider degraded to another retrieval path
ResultCount int // number of memory items represented in ContextText; zero when item metadata is unavailable
ResultRefs []string
}
BeforeChatResult contains memory context to inject into the conversation.
type CandidateMemory ¶
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 DecideResponse ¶
type DecideResponse struct {
Actions []DecisionAction `json:"actions"`
}
type DecisionAction ¶
type DeleteAllRequest ¶
type DeleteResponse ¶
type DeleteResponse struct {
Message string `json:"message"`
}
type ExtractRequest ¶
type ExtractResponse ¶
type Factory ¶
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 HealthStatus ¶
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 MemoryConfig ¶ added in v0.21.0
type MemoryConfig struct {
// EmbeddingModelID optionally maintains the pgvector semantic seed index
// for graph recall. Empty means graph-only recall.
EmbeddingModelID string `json:"embedding_model_id"`
}
MemoryConfig is the team-level Built-in Memory configuration.
type MemoryConfigUpdateRequest ¶ added in v0.21.0
type MemoryConfigUpdateRequest struct {
EmbeddingModelID *string `json:"embedding_model_id,omitempty"`
}
MemoryConfigUpdateRequest updates the team-level Built-in Memory configuration: nil keeps the current value, "" clears it.
type MemoryContextCache ¶
type MemoryContextCache struct {
// contains filtered or unexported fields
}
MemoryContextCache stores rendered memory context for fast first-token paths.
func NewMemoryContextCache ¶
func NewMemoryContextCache(cfg MemoryContextCacheConfig) *MemoryContextCache
func (*MemoryContextCache) Get ¶
func (c *MemoryContextCache) Get(key MemoryContextCacheKey) (MemoryContextCacheValue, bool)
Get returns a fresh cache value.
func (*MemoryContextCache) GetFreshOrStale ¶ added in v0.20.0
func (c *MemoryContextCache) GetFreshOrStale(key MemoryContextCacheKey) (MemoryContextCacheValue, MemoryContextCacheState, bool)
GetFreshOrStale returns an available value and atomically classifies its age.
func (*MemoryContextCache) GetStale ¶
func (c *MemoryContextCache) GetStale(key MemoryContextCacheKey) (MemoryContextCacheValue, bool)
GetStale returns a value inside its stale grace window.
func (*MemoryContextCache) Set ¶
func (c *MemoryContextCache) Set(key MemoryContextCacheKey, value MemoryContextCacheValue)
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 MemoryContextCacheState ¶ added in v0.20.0
type MemoryContextCacheState string
MemoryContextCacheState classifies an available cache entry by age.
const ( MemoryContextCacheFresh MemoryContextCacheState = "fresh" MemoryContextCacheStale MemoryContextCacheState = "stale" )
type MemoryContextCacheValue ¶
type MemoryContextCacheValue struct {
ContextText string
RetrievalMode string
FallbackReason string
ResultCount int
ResultRefs []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 ¶
MemoryVersionProvider is implemented by providers that can expose a cheap cache-busting version for the bot's memory source of truth.
type Provider ¶
type Provider interface {
// Type returns the provider type identifier ("builtin").
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/Delete/DeleteBatch require the authorized bot, independently of caller-supplied IDs.
Update(ctx context.Context, req UpdateRequest) (MemoryItem, error)
Delete(ctx context.Context, botID string, memoryID string) (DeleteResponse, error)
DeleteBatch(ctx context.Context, botID string, 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 interface the Built-in Memory runtime implements for chat hooks, memory tools, and management operations.
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 ProviderGetResponse ¶
type ProviderType ¶
type ProviderType string
Memory provider storage types. Built-in Memory is the only provider type; memory_providers rows store the team's Built-in Memory configuration, and a bot's memory_provider_id is non-null exactly when its memory is enabled.
const ProviderBuiltin ProviderType = "builtin"
type RebuildResult ¶
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 ¶
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 ¶
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) RegisterContext ¶
RegisterContext adds a pre-built provider under the team resolved from ctx.
func (*Registry) RegisterFactory ¶
RegisterFactory registers a factory for a given provider type (e.g. "builtin").
func (*Registry) Remove ¶
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 (*Service) EnsureBuiltin ¶ added in v0.21.0
func (s *Service) EnsureBuiltin(ctx context.Context) (ProviderGetResponse, error)
EnsureBuiltin returns the team's Built-in Memory row, creating it on first use.
func (*Service) EnsureBuiltinID ¶ added in v0.21.0
EnsureBuiltinID returns the ID a memory-enabled bot should reference.
func (*Service) GetConfig ¶ added in v0.21.0
func (s *Service) GetConfig(ctx context.Context) (MemoryConfig, error)
GetConfig returns the team's Built-in Memory configuration. A team that has never saved one reads as the zero configuration.
func (*Service) SetRegistry ¶
SetRegistry configures the runtime registry so that configuration updates can evict and re-instantiate provider instances automatically.
func (*Service) UpdateConfig ¶ added in v0.21.0
func (s *Service) UpdateConfig(ctx context.Context, req MemoryConfigUpdateRequest) (MemoryConfig, error)
UpdateConfig saves the team's Built-in Memory configuration, creating the builtin row on first use. Stored keys the request does not cover are kept.
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 ¶
TeamDefaultFactory creates the builtin fallback independently for each team. It is used for bots without an explicit memory provider.
type TeamIDResolver ¶
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 {
// BotID is the trusted caller scope, never inferred from MemoryID.
BotID string `json:"bot_id"`
MemoryID string `json:"memory_id"`
Memory string `json:"memory"`
EmbeddingEnabled *bool `json:"embedding_enabled,omitempty"`
SourceMessageIDs []string `json:"source_message_ids,omitempty"`
}