Skip to content

Memory Pipeline

Handles all memory writes that occur within or around a chat turn: detecting whether the user explicitly wants something remembered long-term, capturing the conversation in the short-term cache after each turn, and executing LLM-initiated memory tool calls that persist or update facts in the database.

The pipeline has two distinct sub-paths that a single turn may or may not activate, governed by an intent-detection gate that runs before the tool-loop:

  • STM path — always runs (passive capture), and optionally runs a LLM-authored summary upgrade via the update_short_term_memory tool.
  • LTM path — only runs when the LLM calls create_long_term_memory or update_long_term_memory during the tool-loop.

The two paths are not mutually exclusive per turn, but the intent gate (hasExplicitLongTermMemoryIntent) suppresses the STM upgrade tool when the user’s message explicitly asks for persistent memory, steering the LLM toward the LTM tools instead.

  1. README.md — this file (pipeline overview, intent gate, sub-path split)
  2. stm/README.mdstm/01-passive-capture.mdstm/02-summary-upgrade.md
  3. ltm/README.mdltm/01-ltm-create.mdltm/02-ltm-update-delete.md

Symbol: hasExplicitLongTermMemoryIntentsrc/utils/memory/explicitLongTermMemoryIntent.ts:31

Where it runs: Inside buildChatTurnContext (src/utils/chat/contextPipeline.ts:70), before the tool-loop begins.

What it does: Scans the incoming user message for explicit persistence phrases. English phrases: "remember", "don't forget", "note", "commit to memory", "for future conversations", "for future reference". Japanese phrases: "覚えておいて", "忘れないで", and several conjugation variants. Matching is case-insensitive and NFKC-normalized.

When a match is found, streamingContext.explicitLongTermMemoryIntent = true is set on the StreamingContext that flows into the provider and tool-loop pipelines. Two downstream effects:

  1. UpdateShortTermMemoryTool.isAvailableForContext() returns false — the STM upgrade tool is not offered to the LLM that turn.
  2. The STM system-prompt nudge built in buildShortTermMemoryContext (src/utils/text/context/memories.ts:245) is omitted — the LLM receives no STM-update invitation when the user is asking for persistent memory.
incoming user message
[Intent detection gate]
hasExplicitLongTermMemoryIntent()
├─ true ─────────────────────────────────────────────────┐
│ explicitLongTermMemoryIntent flag set │
│ STM tool suppressed this turn │
│ │
│ tool-loop ─────────────────────────────────────────► │
│ │ │
│ └─ LLM calls create / update LTM ─────────────► [LTM path]
│ │
├─ false (or no match) ──────────────────────────────┐ │
│ │ │
│ tool-loop ───────────────────────────────────► │ │
│ │ │ │
│ └─ LLM calls update_short_term_memory ──► [STM upgrade]
│ │ │
└───────────────────────────────────────────────────┘ │
post-turn ─────────────────────────────────────────────────► │
│ │
▼ │
[Passive STM capture] │
storeShortTermMemory() ─────────────────────────────────────────┘
Sub-folderStagesWhat it covers
stm/2 stagesIn-process cache writes: passive turn capture + LLM-authored summary upgrade
ltm/2 stagesDatabase writes: LTM creation and LTM update/delete via LLM tool calls
TypeStorageTTLWritten byRead by
STM crude conversationIn-process Map<key, ShortTermMemoryEntry>12 h (default)Passive capture (post-turn)Context-build STM stage
STM summarySame cache, summary field24 h (default)update_short_term_memory toolContext-build STM stage (summary takes priority over crude)
LTM server memoryserver_memories DB tablePermanentcreate_long_term_memory toolContext-build server-memory stage
LTM personal memorypersonal_memories DB tablePermanentcreate_long_term_memory toolContext-build personal-memory stage

Both LTM tools (create_long_term_memory, update_long_term_memory) require self_teaching_enabled = true in TomoriState.config. The STM tools have no feature flag — they are always available (except the NovelAI provider exclusion for update_short_term_memory).

  • PrivacyLevel.FULL triggerer — passive STM capture is skipped entirely.
  • PrivacyLevel.PARTIAL or FULL target user — personal LTM create and update are blocked; the tool returns an error the LLM can relay to the user.
  • persona_lineage_id = 0 — LTM create is blocked (reserved for global memories; signals an un-run schema migration).

After every successful LTM DB write:

  • Server memory: invalidateTomoriStateCache(serverId) — the next context-build for that server will re-load from DB.
  • Personal memory: invalidateUserCache(userId) — the next context-build for that user will re-load from DB.

Invalidation happens in the same code path as the DB write (immediately after the dbResult check), never before.