Documentation
¶
Index ¶
- Constants
- func MCPSigningSeed(secrets ...string) []byte
- func NewMCPAuthorizer(issuer, resource string, tokenTTL time.Duration, dev bool, ...) (*mcpAuthorizer, error)
- func NewMCPServer(memory *MemoryStore, logger zerolog.Logger, getToken func() string, ...) http.Handler
- func SetOAuthClientPersistence(onChange func())
- func SetSessionPersistence(hmacKey []byte, onChange func())
- func SetTrustedProxyHops(n int)
- func ValidateSearchKind(kind string) string
- func ValidateWrite(kind, confidence string) string
- func WithOrigin(ctx context.Context, origin string) context.Context
- type AzureOAuthConfig
- type CategoryConfig
- type CellSyncer
- func (s *CellSyncer) Persist(ctx context.Context, it *MemoryItem, namespace string) error
- func (s *CellSyncer) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error)
- func (s *CellSyncer) Remove(ctx context.Context, id, namespace string) error
- func (s *CellSyncer) SeedAll(ctx context.Context, namespace string) error
- func (s *CellSyncer) SetMapRegistrar(r MapRegistrar)
- func (s *CellSyncer) SetRegistryPullSecret(name string)
- func (s *CellSyncer) SetupWithManager(mgr ctrl.Manager) error
- func (s *CellSyncer) StartRetentionSweep(ctx context.Context, namespace string, every time.Duration)
- func (s *CellSyncer) SyncCell(ctx context.Context, cell *mcell.MemoryCell) error
- type ConfigWatcher
- type ConsolidationGroup
- type ConsolidationReport
- type GitHubOAuthConfig
- type GoogleOAuthConfig
- type GraphFetcher
- type MCPServerRef
- type MapRegistrar
- type MemoryChangeEvent
- type MemoryHitEvent
- type MemoryItem
- type MemoryItemSummary
- type MemoryNeighbor
- type MemoryNeighborEdge
- type MemoryNeighborhood
- type MemoryStore
- func (s *MemoryStore) AllItems(subject string) []*MemoryItem
- func (s *MemoryStore) ConsolidateMemory(subject string, apply bool) (ConsolidationReport, []*MemoryItem)
- func (s *MemoryStore) Context(anchor string, maxDepth int) (anchors []*MemoryItem, activated []ScoredItem)
- func (s *MemoryStore) Count() int
- func (s *MemoryStore) Delete(id string) bool
- func (s *MemoryStore) EmbedMetrics() index.EmbedMetrics
- func (s *MemoryStore) Expire(id string) *MemoryItem
- func (s *MemoryStore) ExportAll() []*MemoryItem
- func (s *MemoryStore) FilterItems(subject, kind string) []*MemoryItem
- func (s *MemoryStore) ForgetCell(id string)
- func (s *MemoryStore) Get(id string) *MemoryItem
- func (s *MemoryStore) GetItem(id string) *MemoryItem
- func (s *MemoryStore) Hub() *hub.Hub
- func (s *MemoryStore) KeywordSearch(query, kind, subject string, limit int) []*MemoryItem
- func (s *MemoryStore) KeywordSearchPerKind(query, kind, subject string, limit, perKind int) []*MemoryItem
- func (s *MemoryStore) KnowledgeIndex(subject string) []string
- func (s *MemoryStore) List(kind, scope, subject string, limit int) []*MemoryItem
- func (s *MemoryStore) ListRecent(kind, scope, subject string, limit int) []*MemoryItem
- func (s *MemoryStore) ListSummary(kind, scope, subject string, limit int) (items []MemoryItemSummary, total int)
- func (s *MemoryStore) ListSummaryPerCategory(perCategory int, categories []CategoryConfig) (items []MemoryItemSummary, total int, ...)
- func (s *MemoryStore) ListSummaryPerKind(perKind int) (items []MemoryItemSummary, total int, totalsByKind map[string]int)
- func (s *MemoryStore) MirrorCell(cell *mcell.MemoryCell) bool
- func (s *MemoryStore) Neighborhood(id string, top int) *MemoryNeighborhood
- func (s *MemoryStore) PublishHit(itemIDs []string, kind string, kinds []string)
- func (s *MemoryStore) Refute(ctx context.Context, id, reason string, evidence []string) (changed []*MemoryItem, found bool)
- func (s *MemoryStore) Restore(ctx context.Context, it *MemoryItem)
- func (s *MemoryStore) Search(ctx context.Context, query, kind, subject string, limit int) []*MemoryItem
- func (s *MemoryStore) SetCacheReader(r client.Reader, namespace string)
- func (s *MemoryStore) SetCandidateFanout(n int)
- func (s *MemoryStore) SetEpisodicTTL(ttl time.Duration)
- func (s *MemoryStore) SetLexicalShortCircuit(on bool)
- func (s *MemoryStore) SetLinkExpansion(on bool)
- func (s *MemoryStore) SetLinks(id string, links []mcell.ThoughtLink) bool
- func (s *MemoryStore) SetRecallShaping(on bool)
- func (s *MemoryStore) SetSemanticScoreGap(gap float32)
- func (s *MemoryStore) SetSourceCollapse(relation string)
- func (s *MemoryStore) SetWriteDedup(on bool)
- func (s *MemoryStore) SetWriter(c client.Client)
- func (s *MemoryStore) StartEpisodicReaper(ctx context.Context, syncer *CellSyncer, every time.Duration)
- func (s *MemoryStore) Supersede(ctx context.Context, ...) (changed []*MemoryItem, errMsg string)
- func (s *MemoryStore) Upsert(ctx context.Context, ...) (UpsertResult, string)
- type QuotaUsage
- type ScoredItem
- type SearchMetrics
- type SecretStore
- type Server
- type ServerOption
- type Telemetry
- func (s *Telemetry) AddUserTokens(userHash string, n int64)
- func (s *Telemetry) FlushStats()
- func (s *Telemetry) Metrics() SearchMetrics
- func (s *Telemetry) RestoreStats(st *mcell.RuntimeStats)
- func (s *Telemetry) StartStatsFlusher(ctx context.Context, every time.Duration)
- func (s *Telemetry) ToolMetrics() map[string]any
- func (s *Telemetry) TrackKWTrigramHit()
- func (s *Telemetry) TrackKWVoiceHit()
- func (s *Telemetry) TrackKWVoiceMiss()
- func (s *Telemetry) TrackToolCall(name string, d time.Duration)
- func (s *Telemetry) TrackVoiceCall()
- func (s *Telemetry) TrackVoiceEnd()
- func (s *Telemetry) UserTokensToday(userHash string) int64
- func (s *Telemetry) VoiceMetrics() map[string]any
- type TokenBreakdown
- type UpsertOption
- type UpsertResult
- type VoiceBrowserMessage
- type VoiceManager
- func (m *VoiceManager) ServeHTTP(w http.ResponseWriter, r *http.Request)
- func (m *VoiceManager) SetMemMaps(deps *recallmcp.Deps)
- func (m *VoiceManager) Shutdown()
- func (m *VoiceManager) UserQuota(rawUserID string) (used, limit, remaining int64, ok bool)
- func (m *VoiceManager) VoiceMetrics() map[string]any
- type VoiceServerMessage
- type VoiceSession
- type VoiceSessionConfig
Constants ¶
const ( DefaultMCPListMemoryMaxLimit = 20 DefaultMCPSearchMemoryMaxLimit = 10 DefaultMCPRecentMemoryMaxLimit = 20 )
DefaultMCPListMemoryMaxLimit / DefaultMCPSearchMemoryMaxLimit are the fallback hard result-count ceilings for list_memory/search_memory when the caller (main.go) doesn't override them via --mcp-list-memory-max-limit / --mcp-search-memory-max-limit. Applied regardless of what limit the MCP caller requests — a misbehaving or adversarial client (the limit is fully caller-controlled otherwise) cannot force a full-store dump (ADR-051).
const ( // OriginObserved: written by code from facts. OriginObserved = memstore.OriginObserved // OriginDerived: written by a model. A prior claim, never evidence. A cell // with no origin is derived. OriginDerived = memstore.OriginDerived // OriginHuman: written by an identified person. Outranks derived. OriginHuman = memstore.OriginHuman // OriginVerified: derived, then passed a check. Set only in code. OriginVerified = memstore.OriginVerified )
Origin values stored in MemoryCellSpec.Origin: who a cell came from.
const SystemConfigCRName = "xray-system-configuration"
Variables ¶
This section is empty.
Functions ¶
func MCPSigningSeed ¶
MCPSigningSeed is the exported entry point for mcpSigningSeed, called from main.go with the same OAuth client secrets fed to sessionHMACKey (ADR-050).
func NewMCPAuthorizer ¶
func NewMCPAuthorizer(issuer, resource string, tokenTTL time.Duration, dev bool, writeAllowed []string, seed []byte, logger zerolog.Logger) (*mcpAuthorizer, error)
NewMCPAuthorizer builds the co-located OAuth 2.1 authorization server for MCP. issuer is the public base URL; resource is the MCP endpoint URL (issuer+"/mcp" by convention). dev=true auto-issues tokens for a synthetic user so the flow is testable without a real IdP. seed deterministically derives the Ed25519 signing key so every replica converges on the same key (ADR-050); pass mcpSigningSeed(...) in production. A nil seed generates a random per-process key (single-replica dev). The returned *mcpAuthorizer is passed to both NewMCPServer (for token validation) and Server.SetMCPAuth (for the endpoints).
func NewMCPServer ¶
func NewMCPServer(memory *MemoryStore, logger zerolog.Logger, getToken func() string, auth *mcpAuthorizer, syncer *CellSyncer, namespace string, memMapsDeps *msnap.Deps, listMemoryMaxLimit, searchMemoryMaxLimit, recentMemoryMaxLimit int) http.Handler
NewMCPServer returns an HTTP handler exposing memory tools. syncer and namespace are optional: if syncer is non-nil, upsert/delete also persist changes to AwarenessMemoryCell CRs in the cluster. listMemoryMaxLimit/searchMemoryMaxLimit/recentMemoryMaxLimit are hard result-count ceilings for list_memory/search_memory/recent_memory (ADR-051); pass <= 0 to use the Default* constants.
Authentication accepts two credential types, tried in order:
- an X-Ray-issued OAuth JWT (when auth != nil) — carries per-user scopes;
- the static shared Bearer secret from getToken() — treated as full scope.
At least one must be configured; otherwise the endpoint fails closed (503).
func SetOAuthClientPersistence ¶
func SetOAuthClientPersistence(onChange func())
SetOAuthClientPersistence wires the flush hook so a new/updated registration is persisted to CR status on the next flush tick. Called once at startup, BEFORE mgr.Start, so the first CR replay restores into this store. A nil hook leaves the registry in-memory only (local dev without k8s).
func SetSessionPersistence ¶
func SetSessionPersistence(hmacKey []byte, onChange func())
SetSessionPersistence enables CR-backed session persistence: tokens are hashed with hmacKey (derived from a stable secret so it survives restarts and matches across replicas) and onChange is invoked after each login/logout to flush the set to status. Called once at startup from main.go; a nil hmacKey leaves sessions in-memory only. See ADR-047.
func SetTrustedProxyHops ¶
func SetTrustedProxyHops(n int)
SetTrustedProxyHops configures how many trusted reverse proxies sit in front of the server (e.g. 1 for a single ingress/LB that appends the client IP). Negative values are clamped to 0.
func ValidateSearchKind ¶
ValidateSearchKind rejects a kind filter that names no searchable kind. An empty filter means every kind and is valid.
func ValidateWrite ¶
ValidateWrite checks what an external writer may put in an item: a kind from the vocabulary, and high confidence on a stable_fact. "" means valid.
Types ¶
type AzureOAuthConfig ¶
type AzureOAuthConfig struct {
ClientID string
ClientSecret string
TenantID string
PublicURL string
// UICallbackOrigins allowlists origins a login may hand the session token
// to via ?ui=, for a UI served from a different host than this server.
// Empty (the default) disables the hand-off entirely — see resolveUIOrigin.
UICallbackOrigins []string
}
AzureOAuthConfig holds the Azure AD OAuth app credentials.
type CategoryConfig ¶
type CategoryConfig struct {
ID string `json:"id"`
Label string `json:"label"`
Color string `json:"color"`
Kind string `json:"kind"`
Tag string `json:"tag,omitempty"`
Tier float64 `json:"tier,omitempty"`
Angle float64 `json:"angle,omitempty"`
Icon string `json:"icon,omitempty"`
Scope string `json:"scope,omitempty"`
}
CategoryConfig is the parsed, typed form of mcell.CategoryConfig — a UI display category served pre-auth via /v1/categories. JSON tags match the frontend's RuntimeCategoryConfig shape (ui/lib/category-config.ts). An unset tier or angle is left out: the frontend fills its defaults with ??, which keeps a 0 and would draw every such region at the centre.
type CellSyncer ¶
CellSyncer loads MemoryCell CRs into the MemoryStore and its vector index at startup and follows them as they change.
func NewCellSyncer ¶
func NewCellSyncer(c client.Client, memory *MemoryStore, logger zerolog.Logger) *CellSyncer
func (*CellSyncer) Persist ¶
func (s *CellSyncer) Persist(ctx context.Context, it *MemoryItem, namespace string) error
Persist writes a MemoryItem to the cluster as an MemoryCell CR. Preserves any existing embedding so the reconciler won't re-embed unnecessarily.
func (*CellSyncer) Remove ¶
func (s *CellSyncer) Remove(ctx context.Context, id, namespace string) error
Remove deletes an MemoryCell CR by item ID.
func (*CellSyncer) SeedAll ¶
func (s *CellSyncer) SeedAll(ctx context.Context, namespace string) error
SeedAll lists all MemoryCell CRs in the namespace and loads them into the store and its vector index. Called once at startup before serving requests.
func (*CellSyncer) SetMapRegistrar ¶
func (s *CellSyncer) SetMapRegistrar(r MapRegistrar)
SetMapRegistrar wires the recall registry so graph-carrying cells (Data["graph"]) are loaded as searchable in-memory maps. No-op transport when nil.
func (*CellSyncer) SetRegistryPullSecret ¶
func (s *CellSyncer) SetRegistryPullSecret(name string)
SetRegistryPullSecret names the Secret whose registry credentials are used to pull graphRef artifacts.
func (*CellSyncer) SetupWithManager ¶
func (s *CellSyncer) SetupWithManager(mgr ctrl.Manager) error
SetupWithManager registers the CellSyncer as a controller.
func (*CellSyncer) StartRetentionSweep ¶ added in v2.3.0
func (s *CellSyncer) StartRetentionSweep(ctx context.Context, namespace string, every time.Duration)
StartRetentionSweep is the backstop of deletion at the deadline: every `every` it deletes any cell past its StaleAfter that the deadline may delete, across all non-exempt kinds, in case a reconcile that should have fired at the deadline did not. A no-op when every <= 0. ctx bounds it.
func (*CellSyncer) SyncCell ¶
func (s *CellSyncer) SyncCell(ctx context.Context, cell *mcell.MemoryCell) error
SyncCell reconciles a single MemoryCell into the in-memory store.
type ConfigWatcher ¶
type ConfigWatcher struct {
// contains filtered or unexported fields
}
ConfigWatcher watches the single system_configuration MemoryCell CR by name and keeps a parsed VoiceSessionConfig atomically up to date. It is the only place that reads voice config — no List, no tag parsing.
func NewConfigWatcher ¶
func NewConfigWatcher(memory *MemoryStore) *ConfigWatcher
NewConfigWatcher creates a ConfigWatcher that restores persisted stats into memory when the system_configuration CR is first loaded.
func (*ConfigWatcher) EventHandlerFuncs ¶
func (w *ConfigWatcher) EventHandlerFuncs() toolscache.ResourceEventHandlerFuncs
EventHandlerFuncs returns handler funcs to register on the MemoryCell informer.
func (*ConfigWatcher) Get ¶
func (w *ConfigWatcher) Get() *VoiceSessionConfig
Get returns the current config. Never nil — returns an empty config if not yet loaded.
type ConsolidationGroup ¶
type ConsolidationGroup struct {
Kind string `json:"kind"`
Keep string `json:"keep"`
KeepTitle string `json:"keepTitle"`
Superseded []string `json:"superseded"`
Scores []float64 `json:"scores"`
}
ConsolidationGroup is one near-duplicate cluster found by ConsolidateMemory: Keep is the id a reader should trust going forward, Superseded lists every other member's id (parallel to Scores, each member's score against Keep).
type ConsolidationReport ¶
type ConsolidationReport struct {
Scanned int `json:"scanned"`
Groups []ConsolidationGroup `json:"groups"`
Superseded int `json:"superseded"`
Applied bool `json:"applied"`
}
ConsolidationReport is the outcome of one ConsolidateMemory sweep.
type GitHubOAuthConfig ¶
type GitHubOAuthConfig struct {
ClientID string
ClientSecret string
Org string
Team string // optional — if set, user must be an active team member
PublicURL string // externally reachable base URL, e.g. https://xray.example.com
// UICallbackOrigins allowlists origins a login may hand the session token
// to via ?ui=, for a UI served from a different host than this server.
// Empty (the default) disables the hand-off entirely — see resolveUIOrigin.
UICallbackOrigins []string
}
GitHubOAuthConfig holds the OAuth App credentials and org restriction.
type GoogleOAuthConfig ¶ added in v2.4.0
type GoogleOAuthConfig struct {
ClientID string
ClientSecret string
// Domain is the Google Workspace domain an account must belong to, checked
// against the ID token's hd claim. Empty admits any Google account.
Domain string
PublicURL string
// UICallbackOrigins allowlists origins a login may hand the session token
// to via ?ui= (see resolveUIOrigin). Empty disables the hand-off.
UICallbackOrigins []string
}
GoogleOAuthConfig holds the Google OAuth client credentials.
type GraphFetcher ¶
GraphFetcher pulls a graph artifact. Nil on a CellSyncer means the registry client below; a test injects an in-process one.
type MCPServerRef ¶
type MCPServerRef struct {
Name string
URL string
TokenSecretName string // k8s Secret name
TokenSecretKey string // key within the Secret; defaults to "token"
Token string // resolved from SecretStore at session start; never persisted
Tools []string // allowlist of tool names; empty = all
}
MCPServerRef describes a remote MCP server to connect to at session start. Token is resolved at session start from the SecretStore, not stored in the CR.
type MapRegistrar ¶
type MapRegistrar interface {
AddSnapshotBytes(ctx context.Context, b []byte) error
RemoveSnapshotByLabel(label string)
}
MapRegistrar registers/de-registers a mental-map graph carried in a MemoryCell as an in-memory snapshot. Satisfied by *recall/engine.Registry. Optional on the CellSyncer — nil when the server runs without a recall registry (keyword mode, or --mental-maps-dir unset).
type MemoryChangeEvent ¶
type MemoryChangeEvent = hub.ChangeEvent
MemoryHitEvent and MemoryChangeEvent are the payloads the live stream carries.
type MemoryHitEvent ¶
MemoryHitEvent and MemoryChangeEvent are the payloads the live stream carries.
type MemoryItem ¶
type MemoryItem struct {
ID string `json:"id"`
Kind string `json:"kind"`
Scope string `json:"scope"`
Subject string `json:"subject,omitempty"`
Title string `json:"title"`
Content string `json:"content"`
Confidence string `json:"confidence,omitempty"`
Tags []string `json:"tags,omitempty"`
Status string `json:"status"`
// EventDate is only set for kind=event items. RFC3339.
EventDate string `json:"eventDate,omitempty"`
// Data holds arbitrary named blobs, e.g. Data["image"] for thumbnails.
Data map[string]mcell.DataEntry `json:"data,omitempty"`
// ImageURL is set server-side to /v1/memory/{id}/image when Data["image"] is present.
ImageURL string `json:"imageUrl,omitempty"`
// StaleAfter is the item's expiry deadline (decay by default). nil means no
// deadline: the item never expires on its own.
StaleAfter *time.Time `json:"staleAfter,omitempty"`
CreatedAt time.Time `json:"createdAt"`
UpdatedAt time.Time `json:"updatedAt"`
// Links are the item's ThoughtLinks.
Links []mcell.ThoughtLink `json:"links,omitempty"`
// Origin is the cell's provenance: observed, derived, human or verified. A
// cell stored without one reads as derived.
Origin string `json:"origin,omitempty"`
// EvidenceRefs names the cells or events this item was drawn from. Refute
// follows them.
EvidenceRefs []string `json:"evidenceRefs,omitempty"`
// Supersedes lists the ids of cells this one absorbed.
Supersedes []string `json:"supersedes,omitempty"`
// Via is set only on a search result that was reached through a link: the id
// of the higher-ranked result whose link surfaced it.
Via string `json:"via,omitempty"`
// Collapsed is set only on a search result that stands for near-duplicates
// folded into it.
Collapsed int `json:"collapsed,omitempty"`
}
MemoryItem is the shape of a memory cell on the server's wire: the REST API, the MCP tools and the live stream. The engine's Item is the cell's own spec; this is what a client reads, with the owner of a private item in Subject and the status spelled active, stale or superseded.
type MemoryItemSummary ¶
type MemoryItemSummary struct {
ID string `json:"id"`
Kind string `json:"kind"`
Scope string `json:"scope"`
Subject string `json:"subject,omitempty"`
Title string `json:"title"`
Tags []string `json:"tags,omitempty"`
Status string `json:"status"`
UpdatedAt time.Time `json:"updatedAt"`
HitCount int64 `json:"hitCount"`
}
MemoryItemSummary is the light row the item lists return.
type MemoryNeighbor ¶
type MemoryNeighbor struct {
ID string `json:"id"`
Kind string `json:"kind"`
Title string `json:"title"`
Status string `json:"status"`
Tags []string `json:"tags,omitempty"`
Score float32 `json:"score"`
}
MemoryNeighbor is one nearest cell of a cell, with its similarity.
type MemoryNeighborEdge ¶
type MemoryNeighborEdge struct {
Source string `json:"source"`
Target string `json:"target"`
Score float32 `json:"score"`
}
MemoryNeighborEdge links two neighbours that sit close to each other.
type MemoryNeighborhood ¶
type MemoryNeighborhood struct {
ID string `json:"id"`
Indexed bool `json:"indexed"`
Neighbors []MemoryNeighbor `json:"neighbors"`
Edges []MemoryNeighborEdge `json:"edges"`
}
MemoryNeighborhood is the nearest cells of a cell and the edges between them.
type MemoryStore ¶
type MemoryStore struct {
*Telemetry
// contains filtered or unexported fields
}
MemoryStore is the server's memory: the memstore engine (items, lexical and semantic search, rerank, links, provenance), a cell index when there is an embedder, and a hub that carries changes to connected clients, behind the method set the REST API, the MCP tools and the voice tools use. Items cross this boundary as MemoryItem, the wire shape.
func NewMemoryStore ¶
func NewMemoryStore() *MemoryStore
NewMemoryStore creates a keyword-only MemoryStore (no embedding endpoint).
func NewMemoryStoreWithEmbedder ¶
func NewMemoryStoreWithEmbedder(embedder *index.Embedder, logger zerolog.Logger) *MemoryStore
NewMemoryStoreWithEmbedder creates a MemoryStore with a semantic index.
func (*MemoryStore) AllItems ¶
func (s *MemoryStore) AllItems(subject string) []*MemoryItem
AllItems returns the active shared items of a subject (empty matches all).
func (*MemoryStore) ConsolidateMemory ¶
func (s *MemoryStore) ConsolidateMemory(subject string, apply bool) (ConsolidationReport, []*MemoryItem)
ConsolidateMemory groups the active shared cells of the dedup kinds (optionally of one subject) into near-duplicate clusters and, when apply is true, retires every member but each cluster's keeper (status superseded, the keeper's Supersedes lists them). apply=false returns the same groups and writes nothing. The second result is the changed cells, which a caller backed by the cluster persists.
func (*MemoryStore) Context ¶
func (s *MemoryStore) Context(anchor string, maxDepth int) (anchors []*MemoryItem, activated []ScoredItem)
Context returns the cells an anchor activates: the anchor cells themselves and everything reachable over ThoughtLinks, by spreading activation. Each hop multiplies the score by 0.6 and the link's weight, a cell keeps the best score any path gave it, and at most maxDepth hops are followed (default 3, at most 8). Only shared, active cells take part.
func (*MemoryStore) Delete ¶
func (s *MemoryStore) Delete(id string) bool
Delete removes a memory item by ID. It reports whether the item was held. The vector goes too, whether or not the item was held here: a vector left behind keeps taking top-k slots. A private item's delete reaches only its owner.
func (*MemoryStore) EmbedMetrics ¶
func (s *MemoryStore) EmbedMetrics() index.EmbedMetrics
EmbedMetrics returns the embedder's call and cache counters.
func (*MemoryStore) Expire ¶
func (s *MemoryStore) Expire(id string) *MemoryItem
Expire retires a cell without a verdict on it: it is out of date, not wrong (Refute is for wrong). The cell is kept with status stale and leaves every index. The returned item is already stored in the process; a caller backed by the cluster persists it. nil when id names no cell.
func (*MemoryStore) ExportAll ¶
func (s *MemoryStore) ExportAll() []*MemoryItem
ExportAll returns a copy of every item the store holds, private and retired ones included, for a program that persists the store itself.
func (*MemoryStore) FilterItems ¶
func (s *MemoryStore) FilterItems(subject, kind string) []*MemoryItem
FilterItems returns the active items of a subject and kind (empty matches all), whatever their scope, but never the system configuration.
func (*MemoryStore) ForgetCell ¶ added in v2.3.0
func (s *MemoryStore) ForgetCell(id string)
ForgetCell drops an item whose cell was deleted, here or on another replica, from the store and the vector index.
func (*MemoryStore) Get ¶
func (s *MemoryStore) Get(id string) *MemoryItem
Get returns a single active memory item by ID, or nil if not found.
func (*MemoryStore) GetItem ¶
func (s *MemoryStore) GetItem(id string) *MemoryItem
GetItem returns a memory item by ID in any status, or nil if not found.
func (*MemoryStore) Hub ¶ added in v2.3.0
func (s *MemoryStore) Hub() *hub.Hub
Hub is the hub that carries memory events to connected clients.
func (*MemoryStore) KeywordSearch ¶
func (s *MemoryStore) KeywordSearch(query, kind, subject string, limit int) []*MemoryItem
KeywordSearch scans active items by lexical match on title and content. With a subject it also covers that person's private notes.
func (*MemoryStore) KeywordSearchPerKind ¶
func (s *MemoryStore) KeywordSearchPerKind(query, kind, subject string, limit, perKind int) []*MemoryItem
KeywordSearchPerKind is KeywordSearch with per-kind fairness: at most perKind results per kind, so a dominant kind cannot monopolise the limit and starve smaller categories. Used by the graph search, which spans all kinds over a skewed store.
func (*MemoryStore) KnowledgeIndex ¶
func (s *MemoryStore) KnowledgeIndex(subject string) []string
KnowledgeIndex lists the titles of the shared active items of a subject.
func (*MemoryStore) List ¶
func (s *MemoryStore) List(kind, scope, subject string, limit int) []*MemoryItem
List returns active items filtered by kind, scope and subject up to limit.
func (*MemoryStore) ListRecent ¶
func (s *MemoryStore) ListRecent(kind, scope, subject string, limit int) []*MemoryItem
ListRecent returns active items matching kind/scope/subject sorted newest-first by CreatedAt (UpdatedAt breaks ties), capped to limit. Unlike List, the result is time-ordered: this is the recall path for episodic ("what happened last") memory, where "the latest creation time" is the selection criterion.
func (*MemoryStore) ListSummary ¶
func (s *MemoryStore) ListSummary(kind, scope, subject string, limit int) (items []MemoryItemSummary, total int)
ListSummary is List with light rows and the total that matched.
func (*MemoryStore) ListSummaryPerCategory ¶ added in v2.4.4
func (s *MemoryStore) ListSummaryPerCategory(perCategory int, categories []CategoryConfig) (items []MemoryItemSummary, total int, totalsByKind, totalsByCategory map[string]int)
ListSummaryPerCategory is ListSummaryPerKind with the cap and the totals taken per display category (ADR-035): a category configured with a tag narrows its kind, so a kind split by tag into several categories gets perCategory rows for each of them instead of perCategory rows to share. An item's category key is "kind|tag" for the first tag of its kind's tagged categories it carries (the UI's categoryOf order), else its kind. Without tagged categories this is ListSummaryPerKind.
func (*MemoryStore) ListSummaryPerKind ¶
func (s *MemoryStore) ListSummaryPerKind(perKind int) (items []MemoryItemSummary, total int, totalsByKind map[string]int)
ListSummaryPerKind is ListSummary over the shared items with at most perKind rows of any one kind, and the true total of each kind: the UI shows those as the real category counts, independent of the per-kind render cap.
func (*MemoryStore) MirrorCell ¶ added in v2.3.0
func (s *MemoryStore) MirrorCell(cell *mcell.MemoryCell) bool
MirrorCell reflects a cell into the store: the keyword and vector-independent state, and the change events, follow what the cluster holds. A change this process made itself is a no-op. A private cell written under the older rule, where Subject named the owner, reads as owned by that subject until the cell is migrated. It reports whether the store changed.
func (*MemoryStore) Neighborhood ¶
func (s *MemoryStore) Neighborhood(id string, top int) *MemoryNeighborhood
Neighborhood returns the top nearest shared cells of a cell and the edges between them. Indexed is false when the cell is not in the vector index.
func (*MemoryStore) PublishHit ¶
func (s *MemoryStore) PublishHit(itemIDs []string, kind string, kinds []string)
PublishHit broadcasts a memory search hit event. kinds must be parallel to itemIDs. The event reaches every connected client, so it carries ids and kinds only: the query is what a person asked and is not theirs to share, and callers pass shared items only (see sharedHit).
func (*MemoryStore) Refute ¶
func (s *MemoryStore) Refute(ctx context.Context, id, reason string, evidence []string) (changed []*MemoryItem, found bool)
Refute marks a cell wrong: it records {reason, evidence, at} under Data["refuted"], retires the cell (status stale) and retires every active derived cell that cites it, one hop only: an evidence ref naming the id or a link to it. Observed, human and verified cells are never cascaded. The returned items are the changed cells, the refuted one first, already stored in the process; a caller backed by the cluster persists each. found is false when id names no cell.
func (*MemoryStore) Restore ¶
func (s *MemoryStore) Restore(ctx context.Context, it *MemoryItem)
Restore puts an item back as it was exported: ids, origin, status, links, timestamps and deadline are kept as given. An active shared item is indexed again (keyword and, with an embedder, semantic); a retired or private one is held and left out of the shared indexes, exactly as Upsert would leave it.
func (*MemoryStore) Search ¶
func (s *MemoryStore) Search(ctx context.Context, query, kind, subject string, limit int) []*MemoryItem
Search returns items matching the query. It runs lexical search first; when a semantic index is configured and the top lexical hit is not a confident match it fuses semantic results in by rank fusion, then reranks. With a subject, the subject's shared items are searched and so are the private notes of the person the subject names (lexically: a private note is never embedded). A query that is a cell's id goes first.
func (*MemoryStore) SetCacheReader ¶
func (s *MemoryStore) SetCacheReader(r client.Reader, namespace string)
SetCacheReader wires the cluster reader the stats flusher reads with.
func (*MemoryStore) SetCandidateFanout ¶
func (s *MemoryStore) SetCandidateFanout(n int)
SetCandidateFanout overrides how many times the limit each search channel pulls while source collapse will shrink the pool again. Values below 1 mean 1.
func (*MemoryStore) SetEpisodicTTL ¶
func (s *MemoryStore) SetEpisodicTTL(ttl time.Duration)
SetEpisodicTTL sets the max age before an episodic memory is forgotten. 0 disables expiry. Call once at startup before serving.
func (*MemoryStore) SetLexicalShortCircuit ¶
func (s *MemoryStore) SetLexicalShortCircuit(on bool)
SetLexicalShortCircuit turns the lexical short-circuit on or off. On (the default of an unconfigured store), a confident top lexical hit returns without consulting the semantic channel; off, a search always fuses the two when there is a vector index. The right call for short named-entity queries is on, and for long natural-language questions asked over long cells it is off.
func (*MemoryStore) SetLinkExpansion ¶
func (s *MemoryStore) SetLinkExpansion(on bool)
SetLinkExpansion turns the optional one-hop ThoughtLink expansion of search results on or off (default off).
func (*MemoryStore) SetLinks ¶
func (s *MemoryStore) SetLinks(id string, links []mcell.ThoughtLink) bool
SetLinks replaces the ThoughtLinks of an item. It is the write path for links on items that were never persisted: an ingest pipeline deriving atomic-fact cells from an episode links each fact back to its source with it. It reports false when id names no item.
func (*MemoryStore) SetRecallShaping ¶
func (s *MemoryStore) SetRecallShaping(on bool)
SetRecallShaping turns the near-duplicate collapse and the state-aware rerank on or off (default on). Off, a search returns the fused order unchanged.
func (*MemoryStore) SetSemanticScoreGap ¶
func (s *MemoryStore) SetSemanticScoreGap(gap float32)
SetSemanticScoreGap overrides the semantic relevance cutoff: the absolute cosine gap below the best visible hit past which semantic results are dropped. 0 disables the cutoff.
func (*MemoryStore) SetSourceCollapse ¶
func (s *MemoryStore) SetSourceCollapse(relation string)
SetSourceCollapse turns on source collapse for links of the given relation; "" turns it off. A hit with an outbound link of that relation is replaced by the item it links to (a fact by the episode it was drawn from).
func (*MemoryStore) SetWriteDedup ¶
func (s *MemoryStore) SetWriteDedup(on bool)
SetWriteDedup turns write-side near-duplicate merging on or off (default on): an Upsert that restates an existing stable_fact, operational_pattern, watch_item or hypothesis lands on that cell instead of minting a peer.
func (*MemoryStore) SetWriter ¶
func (s *MemoryStore) SetWriter(c client.Client)
SetWriter wires the cluster client the stats flusher writes with.
func (*MemoryStore) StartEpisodicReaper ¶
func (s *MemoryStore) StartEpisodicReaper(ctx context.Context, syncer *CellSyncer, every time.Duration)
StartEpisodicReaper runs a background sweep that deletes episodic memories older than episodicTTL (the "forget" mechanism). One goroutine, a ticker, exits on ctx cancel. A no-op when TTL<=0 or every<=0. syncer removes the backing cell (nil keeps the sweep in process).
func (*MemoryStore) Supersede ¶
func (s *MemoryStore) Supersede(ctx context.Context, oldID, newID, kind, scope, title, content, subject, confidence string, tags []string, opts ...UpsertOption) (changed []*MemoryItem, errMsg string)
Supersede replaces the cell oldID with a new one: the new cell is written (as Upsert writes it, so origin, id handling and size caps apply) and lists oldID in Supersedes, and the old cell is retired with status superseded. A derived write cannot supersede a human cell. The returned items are the new cell then the old one, both already stored in the process.
func (*MemoryStore) Upsert ¶
func (s *MemoryStore) Upsert(ctx context.Context, id, kind, scope, title, content, subject, confidence, eventDate string, data map[string]mcell.DataEntry, tags []string, opts ...UpsertOption) (UpsertResult, string)
Upsert creates or updates a memory item matched by ID (if provided) or auto-generates one. The write's provenance comes from ctx (withWriteOrigin): an identified person is human, anything else derived. A restated stable_fact, operational_pattern, watch_item or hypothesis lands on the cell it repeats (status "merged"). The owner of a private item is its subject.
type QuotaUsage ¶
type QuotaUsage struct {
Used int64 `json:"used"`
Limit int64 `json:"limit"`
Remaining int64 `json:"remaining"`
Breakdown *TokenBreakdown `json:"breakdown,omitempty"`
}
QuotaUsage is the per-user daily token quota snapshot pushed to the browser. Used/Limit/Remaining are the daily cap (total tokens). Breakdown is the current session's cumulative per-modality split — what the UI shows to explain where the tokens go (audio dominates cost), since the daily store keeps only a fused total.
type ScoredItem ¶
type ScoredItem struct {
Item *MemoryItem
Score float32
}
ScoredItem is a cell reached by Context and how strongly.
type SearchMetrics ¶
type SearchMetrics struct {
TotalSearches int64 `json:"totalSearches"`
KeywordHits int64 `json:"keywordHits"`
KWVoiceHits int64 `json:"kwVoiceHits"`
KWVoiceMisses int64 `json:"kwVoiceMisses"`
KWTrigramHits int64 `json:"kwTrigramHits"`
SemanticCalls int64 `json:"semanticCalls"`
SemanticFallbacks int64 `json:"semanticFallbacks"`
}
SearchMetrics tracks search operation counters since process start.
type SecretStore ¶
type SecretStore struct {
// contains filtered or unexported fields
}
SecretStore holds Secret data watched via the controller-runtime cache. It is safe for concurrent use.
func NewSecretStore ¶
func NewSecretStore() *SecretStore
func (*SecretStore) Delete ¶
func (s *SecretStore) Delete(namespace, name string)
func (*SecretStore) Get ¶
func (s *SecretStore) Get(namespace, name, key string) string
Get returns the value for a key in a Secret. Returns empty string if not found.
func (*SecretStore) SecretEventHandlerFuncs ¶
func (s *SecretStore) SecretEventHandlerFuncs() toolscache.ResourceEventHandlerFuncs
SecretEventHandlerFuncs returns informer handlers that keep the store in sync.
type Server ¶
type Server struct {
// contains filtered or unexported fields
}
Server is the X-Ray HTTP server.
func NewServer ¶
func NewServer(logger zerolog.Logger, memory *MemoryStore, uiFS fs.FS, ghCfg GitHubOAuthConfig, azCfg AzureOAuthConfig, allowedOrigin string, maxBodyBytes int64, config *ConfigWatcher, opts ...ServerOption) *Server
func (*Server) SetMCPAuth ¶
SetMCPAuth mounts the MCP resource endpoint and the co-located OAuth 2.1 authorization server on the main mux. auth provides discovery + token issuance; mcpHandler is the bearer-guarded MCP JSON-RPC handler (built via NewMCPServer with the same authorizer). Either argument may be nil to skip. Must be called before the server starts accepting connections.
func (*Server) SetVoiceManager ¶
func (s *Server) SetVoiceManager(vm *VoiceManager)
SetVoiceManager attaches a VoiceManager and registers the /v1/voice route. Must be called before the server starts accepting connections.
type ServerOption ¶ added in v2.4.0
type ServerOption func(*serverOptions)
ServerOption configures an optional part of the Server.
func WithGoogleOAuth ¶ added in v2.4.0
func WithGoogleOAuth(cfg GoogleOAuthConfig) ServerOption
WithGoogleOAuth turns on Google sign-in.
type Telemetry ¶ added in v2.3.0
type Telemetry struct {
// contains filtered or unexported fields
}
Telemetry is what the server counts and persists about itself, apart from the memory it serves: search and voice counters, each user's daily voice-token spend, tool latencies, and the debounced writer that keeps them, the live sessions and the registered OAuth clients in the system_configuration cell.
func (*Telemetry) AddUserTokens ¶ added in v2.3.0
AddUserTokens accumulates Gemini Live token spend for an authenticated user on the current UTC day. Empty userHash (unauthenticated/dev sessions) is ignored — there is no stable key to meter. Rolls the counter over when the UTC day changes.
func (*Telemetry) FlushStats ¶ added in v2.3.0
func (s *Telemetry) FlushStats()
FlushStats marks stats dirty so the next flush tick persists them. Exported so the session store can request a flush on login/logout (wired via SetSessionPersistence). It no longer writes synchronously — see ADR-047 (debounced stats flush). The change lands on the next StartStatsFlusher tick.
func (*Telemetry) Metrics ¶ added in v2.3.0
func (s *Telemetry) Metrics() SearchMetrics
Metrics returns a snapshot of search operation counters.
func (*Telemetry) RestoreStats ¶ added in v2.3.0
func (s *Telemetry) RestoreStats(st *mcell.RuntimeStats)
RestoreStats loads persisted counters from a RuntimeStats snapshot (e.g. read by ConfigWatcher at startup). voiceActive is intentionally not restored — it is session-local and always starts at 0.
func (*Telemetry) StartStatsFlusher ¶ added in v2.3.0
StartStatsFlusher runs the single CR-status writer: every `every` it writes the current counters + sessions to the system_configuration CR, but only when something changed since the last write (markStatsDirty). This replaces the old per-request synchronous flush, so search/voice/login throughput is no longer gated on an etcd round-trip and N concurrent requests cause at most one write per tick. On ctx cancellation it does a final flush so the last state is durable across a graceful shutdown. Call once at startup after SetWriter. A zero or negative interval disables the loop (in-memory only).
func (*Telemetry) ToolMetrics ¶ added in v2.3.0
ToolMetrics returns per-tool call counts and average latency in milliseconds.
func (*Telemetry) TrackKWTrigramHit ¶ added in v2.3.0
func (s *Telemetry) TrackKWTrigramHit()
TrackKWTrigramHit records that the trigram index contributed at least one candidate to a search result.
func (*Telemetry) TrackKWVoiceHit ¶ added in v2.3.0
func (s *Telemetry) TrackKWVoiceHit()
TrackKWVoiceHit records that the keyword-first path in the voice search_memory tool returned enough results to skip semantic search.
func (*Telemetry) TrackKWVoiceMiss ¶ added in v2.3.0
func (s *Telemetry) TrackKWVoiceMiss()
TrackKWVoiceMiss records that keyword-first returned too few results and fell through to semantic search.
func (*Telemetry) TrackToolCall ¶ added in v2.3.0
TrackToolCall records a tool invocation and its execution duration.
func (*Telemetry) TrackVoiceCall ¶ added in v2.3.0
func (s *Telemetry) TrackVoiceCall()
TrackVoiceCall records a new voice session start and marks stats dirty.
func (*Telemetry) TrackVoiceEnd ¶ added in v2.3.0
func (s *Telemetry) TrackVoiceEnd()
TrackVoiceEnd records a voice session end and marks stats dirty.
func (*Telemetry) UserTokensToday ¶ added in v2.3.0
UserTokensToday returns the user's token spend for the current UTC day, or 0 if the stored counter is from a previous day (not yet rolled over) or the user is unknown.
func (*Telemetry) VoiceMetrics ¶ added in v2.3.0
VoiceMetrics returns a snapshot of voice session counters.
type TokenBreakdown ¶
type TokenBreakdown struct {
InputAudio int64 `json:"inputAudio"`
InputText int64 `json:"inputText"`
OutputAudio int64 `json:"outputAudio"`
OutputText int64 `json:"outputText"`
Cached int64 `json:"cached"`
}
TokenBreakdown is the per-modality token split for the current voice session.
type UpsertOption ¶
type UpsertOption func(*upsertOpts)
UpsertOption sets an optional field of an Upsert.
func WithEvidenceRefs ¶
func WithEvidenceRefs(refs []string) UpsertOption
WithEvidenceRefs records the cells or events the item was drawn from. Refute follows them.
type UpsertResult ¶
type UpsertResult struct {
ID string `json:"id"`
Status string `json:"status"` // "created", "updated" or "merged"
Item *MemoryItem `json:"-"`
}
UpsertResult is the outcome of an Upsert: the id, whether the item was created, updated or merged into the cell it restated, and the stored item.
type VoiceBrowserMessage ¶
type VoiceBrowserMessage struct {
Audio []byte `json:"audio,omitempty"`
AudioStreamEnd bool `json:"audioStreamEnd,omitempty"`
Text string `json:"text,omitempty"`
Ping bool `json:"ping,omitempty"`
Pinned []string `json:"pinned,omitempty"` // live update of pinned item IDs
}
VoiceBrowserMessage is the JSON envelope from the browser.
type VoiceManager ¶
type VoiceManager struct {
// contains filtered or unexported fields
}
VoiceManager manages active voice sessions. Lazily initialises the genai client.
func NewVoiceManager ¶
func NewVoiceManager(memory *MemoryStore, config *ConfigWatcher, secrets *SecretStore, syncer *CellSyncer, namespace, gcpProject, gcpLocation, geminiKey, voiceModel, voiceName string, userDailyAudioTokenLimit int64, maxOutputTokens, headroomLimit int, affectiveDialog, proactiveAudio bool, allowedOrigin string, maxConcurrent int, logger zerolog.Logger) *VoiceManager
NewVoiceManager creates a VoiceManager. syncer may be nil when k8s is unavailable. allowedOrigin scopes the WebSocket Origin check (empty = allow any, dev only). maxConcurrent caps simultaneous sessions (0 = unlimited).
func (*VoiceManager) ServeHTTP ¶
func (m *VoiceManager) ServeHTTP(w http.ResponseWriter, r *http.Request)
ServeHTTP upgrades the request to a WebSocket and runs a voice session.
func (*VoiceManager) SetMemMaps ¶
func (m *VoiceManager) SetMemMaps(deps *recallmcp.Deps)
SetMemMaps wires the embedded code-graph snapshot into voice sessions so the model gets search_graph et al. as NATIVE in-process tools (direct function calls — no MCP). No-op effect when deps is nil. Call before serving.
func (*VoiceManager) Shutdown ¶
func (m *VoiceManager) Shutdown()
Shutdown closes all active sessions.
func (*VoiceManager) UserQuota ¶
func (m *VoiceManager) UserQuota(rawUserID string) (used, limit, remaining int64, ok bool)
UserQuota reports the per-user daily token quota for the given raw SSO ID. limit is the effective cap (0 = unlimited); used is today's spend; remaining is limit-used floored at 0. ok is false when there is no cap to report — either no limit is configured or the user is unauthenticated (empty rawUserID).
func (*VoiceManager) VoiceMetrics ¶
func (m *VoiceManager) VoiceMetrics() map[string]any
VoiceMetrics returns lifetime voice session counters.
type VoiceServerMessage ¶
type VoiceServerMessage struct {
Audio []byte `json:"audio,omitempty"`
Transcript string `json:"transcript,omitempty"`
InputTranscript string `json:"inputTranscript,omitempty"`
ToolCall string `json:"toolCall,omitempty"`
ToolResult string `json:"toolResult,omitempty"`
Interrupt bool `json:"interrupt,omitempty"`
Error string `json:"error,omitempty"`
Done bool `json:"done,omitempty"`
Quota *QuotaUsage `json:"quota,omitempty"` // pushed per turn while a daily limit is in effect
}
VoiceServerMessage is the JSON envelope sent to the browser.
type VoiceSession ¶
type VoiceSession struct {
// contains filtered or unexported fields
}
VoiceSession is one active browser ↔ Gemini Live session.
func (*VoiceSession) Close ¶
func (s *VoiceSession) Close()
Close cancels the session and waits for cleanup.
type VoiceSessionConfig ¶
type VoiceSessionConfig struct {
SystemPrompt string
Greeting string
VoiceName string
VoiceModel string
EnabledTools []string
MCPServers []MCPServerRef
WriteAllowedUsers []string // usernames permitted to invoke write tools via voice
// MaxUserDailyAudioTokens caps per-user Gemini Live AUDIO token spend (audio-in
// + audio-out) per UTC day. 0 means "not set in CR" — the caller falls back to
// the --user-daily-audio-token-limit flag. See ADR-042.
MaxUserDailyAudioTokens int64
// MaxItemContentChars caps each search-result item's content (headroom
// LossyCompress budget). 0 means "not set in CR" — the caller falls back to the
// --headroom-content-limit flag. See ADR-038.
MaxItemContentChars int
// AffectiveDialog / ProactiveAudio are native-audio quality toggles. nil means
// "not set in CR" — the caller falls back to the corresponding flag.
AffectiveDialog *bool
ProactiveAudio *bool
// Categories is the UI display category taxonomy (ADR-035 item 4). Empty
// means the UI falls back to its in-repo default taxonomy.
Categories []CategoryConfig
}
VoiceSessionConfig is the parsed, typed voice session configuration loaded from the system_configuration MemoryCell CR.