Skip to content

Categorize Memories in the Gate's Existing Request - #16183

Closed
aligulzar729 wants to merge 3 commits into
LibreChat-AI:devfrom
aligulzar729:feat/classification-memory
Closed

aligulzar729 wants to merge 3 commits into
LibreChat-AI:devfrom
aligulzar729:feat/classification-memory

Conversation

@aligulzar729

@aligulzar729 aligulzar729 commented Sep 22, 2026 •

Copy link
Copy Markdown

Summary

Depends on #16181.

I run a self-hosted instance and use this with local models, where a small classifier is cheap enough to put in front of a larger one.

Measured on my own instance: across 120 conversations, 713 user turns produced 2 stored memories, holding 101 tokens between them. With memory enabled, the memory model runs once per completed turn, so that is 713 model calls to produce two durable facts. Most turns have nothing to remember, and the model call is spent finding that out.

The memory gate already makes one classification request per turn to decide whether to run the memory model. A classifier answers every question in a single call, so asking more costs no extra round trip.

This adds two optional questions to that same request:

  • categorize asks which of memory.validKeys the durable part belongs under
  • detectUpdates asks whether it changes something already stored rather than adding something new

The answers reach the memory model as a suggestion it may ignore, following the same pattern the skill catalog uses:

<memory_hint>
The durable part of this turn most likely belongs under `work_context`. It looks
like a change to what is already stored there, not a new fact.
Ignore this if it does not fit what the user actually said.
</memory_hint>

Memories land in the right key without depending on the writer model to guess, an update to an existing fact is recognised as an update instead of accumulating a near-duplicate, and the decision is inspectable: the probabilities are in the log rather than implicit in a model's choice.

How it works

memory gate (one request)
  durable?     -> false: skip the memory model entirely
  category?    -> below categoryThreshold: no suggestion
  updates?     -> phrasing of the hint
  hint appended to the memory model's instructions for this turn only

Categorization is skipped when memory.validKeys is not configured, since there would be nothing to choose between. No database change: this steers what the memory model writes, it does not add fields to a memory.

Type of change

  • Feature

Testing

How the numbers were produced: a read-only script reading GET /api/convos (120 conversations) and GET /api/messages/{conversationId}, counting messages with isCreatedByUser, and GET /api/memories for the stored total. It measures how often the memory model would run against how much it produced; it is one deployment, and an instance whose users state more durable facts would see a different ratio.

gate.spec.ts, 22 cases. The new ones cover: only the durability question by default, all three in one request when enabled, categorization skipped without validKeys, a low-confidence key dropped rather than suggested, the update phrasing, and no hint at all when the turn is not durable.

cd packages/api && npx jest src/classification src/tools src/memory passes 274. npx tsc --noEmit clean for all three workspaces.

Both options were also exercised against a live classifier, with validKeys: [user_preferences, work_context, personal_information]:

Turn Logged
"I work in Tokyo and I always want code examples in TypeScript, never JavaScript." durable 0.89: processing, suggesting `user_preferences`
"Actually, change that: I moved to Osaka, so update my location." durable 0.89: processing, suggesting `personal_information` as an update
"what time is it in UTC right now?" durable 0.04 below 0.25: skipping

The second turn is the case both options exist for: the key moves from preferences to personal information because the durable part changed subject, and it is marked as a change to what is stored rather than a new fact.

Risk / compatibility

Both options default to false, so the gate behaves exactly as it does in #16181 unless enabled. The hint is advisory: the memory model keeps its own judgment and its existing validKeys validation still rejects an invalid key.

Checklist

@aligulzar729
aligulzar729 force-pushed the feat/classification-memory branch from 09913bf to 1568eb6 Compare September 22, 2026 04:35
@aligulzar729 aligulzar729 changed the title 🧠 feat: Categorize Memories in the Gate's Existing Request Categorize Memories in the Gate's Existing Request Sep 22, 2026
@aligulzar729
aligulzar729 force-pushed the feat/classification-memory branch from 1568eb6 to ec01c3e Compare September 22, 2026 05:43
@aligulzar729

Copy link
Copy Markdown
Author

Folded into #16181. These are cross-fork pull requests, so GitHub could only show each branch's full diff against dev and the two looked identical. One pull request carrying the gate and its categorize/detectUpdates options is honest about what changed.

@aligulzar729
aligulzar729 deleted the feat/classification-memory branch September 22, 2026 12:27
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant