-
Notifications
You must be signed in to change notification settings - Fork 0
Adaptive Memory
@0xx0lostcause0xx0/polypack/activation is the adaptive-memory layer:
durable, decayed relevance per node, spreading activation over edges,
semantic "pulses," a budgeted/diversity-aware working-memory set, and
feedback-driven learned scoring — built on top of the property
graph.
import { PolyGraph, ActivationEngine } from '@0xx0lostcause0xx0/polypack'
const graph = new PolyGraph()
const engine = new ActivationEngine(graph)
graph.reinforceNode('article', 1.0, 'user_read') // durable + synced
graph.reinforceNode('article', 0.3, 'user_read', 'project-x') // also reinforces a context
graph.suppressNode('outdated-note', 1.0, 'stale') // durable inhibition
engine.bumpAttention('article', 0.2) // local only
engine.effective('article') // durable + attention − inhibition
engine.effective('article', 'project-x') // context-scoped lens instead of global
const spread = engine.spread(['article'], { depth: 2, decay: 0.5 }) // neighbours warm up
const scores = await engine.pulse('vector search') // semantic region scoring
await engine.absorb('vector search') // pulse + reinforce above threshold
engine.workingMemory(5)
engine.workingMemory({ limit: 8, tokenBudget: 2000, diversityLambda: 0.5 })-
Durable —
NodeActivation(score,importance,reinforcementCount,lastMeaningfulActivation, plus optionalinhibition/lastInhibitedAt/context) rides as an optional field on every node, so it persists through the snapshot/WAL and adapters, and replicates through sync. -
Transient — runtime-only attention held by
ActivationEngine, never serialized or synced.
Decay is a pure function of elapsed time anchored at
lastMeaningfulActivation (0.5 ** (elapsed / halfLife)), so two replicas
with the same stored state compute identical current scores. inhibition
decays independently against lastInhibitedAt (12h default half-life,
shorter than score so suppression fades unless reinforced) and is
subtracted from score only at the final read/ranking layer (effective)
— never inside pulse's composite or spread — so a suppressed node stays
re-evaluable, not permanently invisible. Each context entry decays
independently against its own anchor (same curve as score by default) and
is an additional lens on top of the global score, not a replacement.
Synchronization is additive for deltas (coalesced and gated by
activationSyncThreshold, default 0.05) and max for total-state node
payloads — activation is accumulated knowledge, not last-write-wins data
(mergeActivation).
-
reinforceNode(id, amount, reason?, context?)/reinforceNodeSafe(...)— decay-correct to now, addamounttoscore, fold a fraction intoimportance, incrementreinforcementCount, re-anchorlastMeaningfulActivation. Emitsactivation_updated. -
suppressNode(id, amount, reason?)/suppressNodeSafe(...)— durable suppression delta oninhibition. A negativeamountreleases suppression. Emitsinhibition_updated. -
getActivation(id, halfLifeMs?),getActivationState(id),getContextActivation(id, context)— reads (context reads never fall back to the global score; a node with no history incontextreads cold there). -
topActivated(limit, minScore?)— loaded nodes ranked by current activation descending (the working-memory primitive without an engine). -
decay(now?)— materializes decayed values for all loaded nodes and re-anchors them; reads already decay lazily, so this only matters before eviction-driven lifecycle events.
-
supersede(id, supersededId, amount = 1, reason = 'superseded')— recordsid.supersedes = supersededId, adds aSUPERSEDED_BYedge (reference, no cascade), and suppresses the superseded node so retrieval prefers the newer one without deleting the old one. Mechanism, not policy — it doesn't detect contradictions, only acts on ones the caller identifies. -
consolidate(node, sourceIds, options?)— writesnodeviaaddNode(insert-or-replace, so passing an existing id extends a prior consolidation), mergessourceIdsintoderivedFrom(deduplicated, not overwritten — re-consolidating as evidence accumulates is normal), addsCONSOLIDATED_FROMedges, and suppresses each source (options.suppressAmountdefault 1,options.reasondefault'consolidated').
new ActivationEngine(graph, config?) composes the scoring layer.
config: scoreHalfLifeMs (24h), importanceHalfLifeMs (30d),
importanceGain (0.05), spreadDecay (0.5), spreadDepth (2),
recencyHalfLifeMs (7d), weights (all 1), minReinforceDelta (0.05),
pulseThreshold (0), absorbThreshold (0.3), absorbGain (0.05),
classHalfLives (per-MemoryClass overrides).
-
reinforce/reinforceAll/suppress— call through to thePolyGraphdurable primitives above.inhibitionOf(id)reads current inhibition. -
bumpAttention(id, amount)/attentionOf(id)— the transient tier. Accumulates locally and is promoted to durable reinforcement once it clearsminReinforceDelta, so tiny events (scrolls, focus) stay local while meaningful ones persist and sync. -
effective(id, context?)— durable decayed score (or the context-scoped score) plus attention, minus decayed inhibition. Decay uses the node's resolved memory-class half-life when it has one (resolveHalfLives), else the flat config default. -
resolveHalfLives(node)—node.memoryClassif set, else the owning type's registered default, else the flat config half-lives. Built-in class defaults: episodic 12h score / 7d importance, semantic 7d / 90d, procedural 7d / 60d, entity 30d / non-decaying. -
spread(seeds, { depth?, decay?, edgeTypes? })— spreading activation: each hop attenuates bydecay; multiple paths to a node sum. Returns{ nodeId: contribution }. -
pulse(text | vector, { topK?, semanticThreshold?, pulseThreshold?, context?, ... })— scores the activated region around a query: semantic seeds via vector similarity (zero-similarity nodes never seed) plus outward spreading, folded with recency and usage. Read-only. -
absorb(input, options?)— runspulseand durably reinforces every node whose composite clearsabsorbThreshold, byabsorbGain * score.options.contextalso reinforces that context on every absorbed node. -
workingMemory(limit?, minScore?)orworkingMemory(options)— loaded nodes ranked byeffectivedescending. The options form ({ limit?, minScore?, context?, contextFallback?, tokenBudget?, costOf?, diversityLambda?, similarityOf? }) is a budgeted, diversity-aware selection — a memory-flavoured maximal-marginal-relevance pass suited to LLM context assembly: greedily picks the highestrelevance − diversityLambda × similarity-to-selectedcandidate undertokenBudget.similarityOfdefaults to cosine similarity ofnode.vector. -
workingMemoryPersisted(options?)— the same adaptive ranking over all persisted nodes, not just loaded ones (transient attention unavailable for cold nodes).contextFallback: trueuses global activation when a node has no history in the requested context. -
estimateNodeTokens(node)— conservative JSON-size token estimate; usable ascostOffor a token budget. -
scoreBreakdownOf(node, semantic, graphContribution)— raw and weighted semantic/graph/recency/usage components plus total. -
recordFeedback(id, wasUseful, learningRate = 0.05)— nudges the compositeweights(used bypulse) toward whichever signal was strongest foridlast time it was scored, clamped non-negative. Simple exponential-moving-average-style nudge, not a full online learner. In-memory only — not persisted or synced;getWeights()/setWeights()let an application persist and restore a snapshot across sessions. -
dispose()— unsubscribe from graph changes and drop transient attention.
useWorkingMemory(graph, limit?, deps?, delay?, nodeTypes?, engine?) — a
live view of the current working memory, re-queried after any graph change
including activation_updated. Without engine it ranks by
graph.topActivated; pass an ActivationEngine to rank by
engine.workingMemory instead. See the full API
reference
for the other hooks.
polypack-mcp exposes this layer as MCP tools
(memory_store, memory_recall, memory_feedback, memory_suppress,
memory_supersede, memory_consolidate, ...) for LLM agents.
Four-Agents-Polypack uses it as the sole shared
state for a multi-agent collaboration experiment.
Back to Home.
polypack
By feature
- Property graph
- Query builder
- Vector search & embeddings
- Persistence
- Database core
- Schema migrations
- Adaptive memory
- Real-time sync
- React integration
Related projects
In the repo