Episodic memory

Episodic memory

Episodic memory is the embedding-backed memory layer for source-backed entries from previous threads. It helps an agent recognize similar situations without mixing episodic evidence into the user profile or session memory.

Product name Episodic memory in the Agents Memory panel.
SDK/config name Memory.episodicMemory(...) and memory.episodicMemory.
Storage agents_memory_entries, scoped by agentId + resourceId.
Requires An OpenAI credential in n8n. The n8n integration currently uses openai/text-embedding-3-small.

For implementation details and verbatim prompts, see the episodic memory implementation notes.

Runtime flow

Episodic memory has a read path before the model call and a write path after successful turns.

1

Configure

Enable memory.episodicMemory with an OpenAI credential.

2

Retrieve

Embed the current user message and search entries in the same agentId + resourceId scope.

3

Inject

Surface top entries in the model prompt as <memory>.

4

Answer

The model can use injected entries or call recall_memory for a deliberate lookup.

5

Extract

After the turn, extract, validate, dedupe, embed, and store new source-backed entries.

Entry shape

Stored entries are compact notes about concrete situations. They should preserve the useful mechanism, not just an isolated statement.

What belongs here
  • Symptoms, environment details, and troubleshooting context.
  • Causal mappings and directionality, such as which record held state and which record was checked.
  • Mismatched identifiers or values, such as producer value versus matcher expectation.
  • Assistant diagnostic findings, confirmed resolutions, outcomes, and open case state.
What stays out
  • Stable user preferences and profile-shaped context.
  • Agent behavior rules or rewritten agent instructions.
  • Current-thread objectives that only belong in session memory.
  • Generic advice, recalled-memory restatements, or unsupported speculation.
{
  "entries": [
    {
      "content": "A workspace stayed inactive after renewal because record A held the active subscription while record B was used for entitlement checks. Merging the records and refreshing derived entitlements resolved the lockout.",
      "source": "verified_assistant_finding",
      "evidence": "The active subscription is on record A, but entitlement checks are reading record B."
    }
  ]
}

Extractor decisions

The extractor reads the role-labeled transcript JSON after the agent has answered. It writes entries only when the transcript contains durable episodic context that could help a future turn recognize a similar situation, continue an investigation, avoid repeated work, or apply a previous mechanism or fix. Known <user-profile> and <memory> context can be passed in for dedupe and exclusions, but those blocks are not sources for new entries.

When it stores an entry
  • The transcript contains a concrete situation with a useful mechanism, current diagnostic state, attempted step, ruled-out path, outcome, or open question.
  • The entry preserves causal direction, such as which record held state, which service checked it, or which emitted value did not match a rule.
  • Unresolved cases are allowed when the observation is stable enough to resume later. Uncertainty stays explicit instead of being upgraded into fact.
  • Useful details that only make sense together stay in one entry rather than being split into disconnected facts.
When it skips
  • Stable user preferences, user-profile details, and agent behavior rules are not episodic entries.
  • Generic advice, assistant summaries, recalled-memory restatements, and unsupported recommendations are ignored.
  • Earlier diagnostic branches are skipped when the same transcript later corrects or supersedes them.
  • Current-thread details that have no likely value outside the thread are left to session memory.
Source labels
  • user_assertion: the user directly stated the mechanism, fix, outcome, attempted step, or open state.
  • user_accepted_assistant_proposal: the assistant proposed a mechanism or fix and the user explicitly accepted, applied, or verified it.
  • verified_assistant_finding: the assistant stated a concrete diagnostic conclusion, ruled-out path, attempted-step result, or open case state.
Evidence validation
  • Every default-extracted entry must include exact evidence from the transcript.
  • User-sourced entries require exact user-message evidence.
  • verified_assistant_finding can use exact assistant evidence, or exact user evidence that confirms or grounds the finding.
  • After validation, entries are normalized, capped by maxEntryLength, limited by maxEntriesPerTurn, deduped by exact hash, checked for similarity duplicates, embedded, and stored.

Retrieval and injection

The runtime retrieves broadly enough for the current turn, then injects entries most-recent-first so stale case context is less likely to dominate fresh context.

Default retrieval
  • autoInject defaults to true.
  • autoInjectTopK defaults to 12.
  • The current user message is the retrieval query.
  • recall_memory(query) remains available for more specific lookups.
Ranking and dedupe
  • Ranking uses lexical and vector signals plus recency weighting.
  • Exact normalized hashes prevent duplicate inserts.
  • Similarity dedupe defaults to dedupeSimilarityThreshold = 0.86.
  • Embedding vectors are never exposed to the frontend.
<memory>
<description>Source-backed case entries retrieved from previous threads for this turn.</description>
<value>
- A priority item routed incorrectly because the source emitted tier=enterprise_plus while the matcher expected tier=enterprise-plus. Updating the matcher to accept both variants resolved the case. (2 days ago)
</value>
</memory>

Config and storage

n8n JSON config
{
  "memory": {
    "enabled": true,
    "storage": "n8n",
    "episodicMemory": {
      "enabled": true,
      "credential": "openai-credential-id"
    }
  }
}
SDK config
const memory = new Memory()
  .storage(myMemoryBackend)
  .episodicMemory({
    embedder,
    embeddingModel: "openai/text-embedding-3-small",
  });
  • agents_memory_entries stores content, content hash, provenance fields, embedding model name, embedding values, metadata, and timestamps.
  • n8n JSON config stores only the episodic memory credential. The integration maps that credential to openai/text-embedding-3-small.
  • SDK consumers pass a Vercel AI SDK embedder. embeddingModel is the stored label for that embedder, not a frontend setting.
  • n8n resolves embedding credentials through n8n credentials. Episodic memory does not read embedding credentials from environment variables.
  • semanticRecall is a separate older recall path and is not part of Episodic memory.

Boundaries

Episodic memory only powers source-backed entries injected through <memory> and queried through recall_memory. <user-profile> is separate and stores what this agent remembers about the user. <session-memory> is separate and stores current-thread state.

  • Read and write scope is fixed to agentId + resourceId.
  • Episodic memory stores source-backed entries that may be useful in later threads.
  • User-profile memory stores what this agent remembers about the user.
  • Session memory stores the current thread objective, decisions, state, and follow-ups.