Improve episodic memory ranking with reinforcement and decay#2
Conversation
mcheemaa
left a comment
There was a problem hiding this comment.
This is a really strong first contribution. Thank you for spending time understanding the codebase before jumping into code - the issue discussion in #1, the phased approach, and the attention to the Cardinal Rule all show a deep read of the project.
A few things I appreciated:
- The extraction to
ranking.tsis the right refactor. The episodic store was accumulating scoring logic that belongs in a pure-function module. Clean separation. - Catching the
updateAccessCountsbug (private method not incrementingaccess_count) is a sharp find. Reinforcement would never have worked from the recall path without this fix. - The math is solid. Exponential decay with configurable half-lives, log-saturating reinforcement, sensible bypass rules for high-importance episodes.
- The context filter is exactly the right scope - a single
filter()call that keeps stale low-signal episodes from burning prompt tokens.
Two optional suggestions (neither blocks merge):
-
In
calculateEpisodeContextScore, theweightedAveragecall passes a dummy zero for the third argument since the function takes 3 inputs but you only need 2. A brief comment or a 2-arg helper would help readability. -
The
hoursSinceIIFE has a redundantNumber.isNaNguard -Date.parsealready returnsNaNfor invalid strings and theNumber.isFinitecheck handles it.
Verified locally (789 tests pass, typecheck and lint clean) and deployed to a test VM. Memory recall is working correctly with the new ranking in place.
Approving as-is. Welcome to Phantom.
|
I’ll look into your suggestions and add another PR for it at some point unless someone else gets it first. Sent from my iPhoneOn Mar 31, 2026, at 12:52 AM, Muhammad Ahmed Cheema ***@***.***> wrote:
Merged #2 into main.
—Reply to this email directly, view it on GitHub, or unsubscribe.You are receiving this because you authored the thread.Message ID: ***@***.***>
|
What Changed
This PR improves episodic memory retrieval without adding a second memory pipeline.
access_counton recall so reinforcement reflects actual usageWhy
This is a first focused step toward the memory strategy discussed in #1.
Phantom already has good capture and search primitives, but episodic retrieval was mostly recency-biased and prompt injection could still include old one-off memories with little durable value. This change keeps TypeScript in the plumbing lane: ranking, decay, retrieval, and prompt shaping. It does not move semantic reasoning out of the Agent SDK or judges.
How I Tested
Commands run:
Notes:
src/mcp/__tests__/dynamic-handlers.test.ts, unrelated to this PR.Checklist
bun test)bun run lint)bun run typecheck).envfiles included