Skip to main content

Documentation Index

Fetch the complete documentation index at: https://srk-e37e8aa3.mintlify.app/llms.txt

Use this file to discover all available pages before exploring further.

Pattern store and adaptive memory

Two cache layers sit between the body and the LLM. The pattern store handles exact and very-similar situations. Adaptive memory handles “this looks like one we have seen before” situations.

PatternStore

A feature-keyed cache. You give it a function that turns an entity into a small object of strings, numbers, and booleans.
const { PatternStore } = require("scp-protocol")

const store = new PatternStore({
  featureExtractor: (entity) => ({
    kind: entity.kind,
    distance_bucket: entity.distance < 5 ? "near" : "far",
  }),
})

Exact match

lookup first hashes the feature vector and looks for that exact hash.
store.learn({ kind: "drone", distance: 3 }, "engage")
store.lookup({ kind: "drone", distance: 4 })
// { decision: "engage", confidence: 0.05, source: "exact" }
The hash is order-independent. Same features, same hash.

Similarity match

If the exact hash misses, lookup walks every other pattern and scores numeric distance plus string equality.
store.lookup({ kind: "drone", distance: 50 })
// returns the closest pattern only if similarity > 0.8 AND its confidence > threshold
The default similarity threshold is 0.8. Patterns below the confidence threshold are skipped.

Confidence

Confidence is a simple count: how many times the same decision has been seen for this exact feature vector. It saturates at 20.
for (let i = 0; i < 10; i++) store.learn({ kind: "ally" }, "wave")
store.lookup({ kind: "ally" })
// confidence: 0.5  (10 of 20)
Confidence below confidenceThreshold (default 0.6) is treated as “not yet trusted” and forces a brain call.

Exploration rate

Even confident hits get re-checked every now and then so the cache does not drift.
new PatternStore({ explorationRate: 0.1 })   // 10% of hits return null
explorationRate: 0 makes the cache deterministic. Useful in tests.

Success rate monitoring

After every cached decision, report what happened.
const hit = store.lookup(entity)
if (hit) {
  await execute(hit.decision)
  store.report(entity, observed_success)   // true or false
}
The store tracks consecutive failures per pattern. After failureThreshold (default 3) the entry is purged and the store emits pattern_invalidated.
store.on("pattern_invalidated", (info) => {
  console.log("dropped pattern", info.features)
})
store.stats() returns hit rate, average success rate, low-confidence count, and totals.

AdaptiveMemory

Adaptive memory is a similarity-scored decision store that generalizes from past LLM decisions when the pattern store cannot.
const { AdaptiveMemory } = require("scp-protocol")

const mem = new AdaptiveMemory({
  threshold: 0.8,           // minimum similarity to count as a hit
  k: 5,                     // top-k neighbors used for confidence blending
  maxHistory: 500,
  weights: { kind: 5, distance: 1 },   // optional per-feature weights
})

mem.store({ kind: "enemy", distance: 4 }, "halt")
mem.lookup({ kind: "enemy", distance: 4.2 })
// { decision: "halt", confidence: 0.78 }

Scoring

Distance is weighted euclidean over normalized feature space. The final confidence is similarity * stored confidence * fraction of top-k that agree on the decision. Disagreement among neighbors dilutes confidence.

Outcome reporting

Same shape as PatternStore:
mem.report(features, success)
Success bumps the entry’s confidence. Failure decays it. After failureThreshold consecutive failures the entry is purged.

Persistence

const mem = new AdaptiveMemory({ storage: "sqlite", storageKey: "scp_adaptive.db" })
mem.save()    // writes the in-memory entries to SQLite
mem.load()    // hydrates from disk on startup
better-sqlite3 is an optional peer dep. If it is not installed, persistence calls return 0 and the store stays in memory.

Wiring both layers into a body

SCPBody.decideLocally consults the pattern store first, then the adaptive memory.
const body = new MyBody({
  patternStore:   new PatternStore({ featureExtractor: f }),
  adaptiveMemory: new AdaptiveMemory({ threshold: 0.8 }),
})

const local = body.decideLocally(entity)
if (local) {
  execute(local.decision)
} else {
  const fromBrain = await brain.call(entity)
  body.learnFromBrain(entity, fromBrain)   // writes to both layers
  execute(fromBrain)
}
learnFromBrain is the only call that needs to know about both stores. The decision flow takes care of the rest.