Skip to content

feat(agent-memory): Phase 4 — recall reinforcement#251

Open
jamby77 wants to merge 2 commits into
feature/agent-memory-phase3-forgetfrom
feature/agent-memory-phase4-reinforce
Open

feat(agent-memory): Phase 4 — recall reinforcement#251
jamby77 wants to merge 2 commits into
feature/agent-memory-phase3-forgetfrom
feature/agent-memory-phase4-reinforce

Conversation

@jamby77

@jamby77 jamby77 commented Jun 16, 2026

Copy link
Copy Markdown
Collaborator

Agent Memory — Phase 4: recall reinforcement

Stacked on #250 (Phase 3). Small phase.

What's new

  • Recalled items are reinforced by default: recall() bumps each returned item's last_accessed_at (HSET) and access_count (HINCRBY).
  • reinforce: false skips the writes.
  • Reinforcement is best-effort — a failure (.catch(() => undefined)) never breaks the recall read path, mirroring agent-cache's "stats failure must not break the cache."

Tests

3 new unit tests (default-on bump, opt-out, failure-doesn't-break-recall); 30 total. tsc --noEmit + prettier clean.

Next

Phase 5 (eviction & TTL — selectEvictions pure selection + capacity/TTL writes).


Note

Medium Risk
Changes recall ranking semantics and adds write side effects on every default recall, though failures cannot break reads and deleted keys are guarded.

Overview
Recall reinforcement (Phase 4): After ranking, recall() by default updates each returned memory in Redis—last_accessed_at via HSET and access_count via HINCRBY. Callers can pass reinforce: false to skip writes. Reinforcement is best-effort (errors are swallowed) so the read path always returns hits. Before writing, EXISTS avoids touching keys that were already deleted but still appear in a stale search index.

Ranking change: Recency in compositeScore now decays from max(created_at, last_accessed_at) instead of creation time alone, so bumped access times actually improve future ranking. A new recall test asserts a recently accessed item beats an equally similar stale one when reinforcement is off.

Reviewed by Cursor Bugbot for commit e8e841c. Bugbot is set up for automated code reviews on this repo. Configure here.

@jamby77 jamby77 force-pushed the feature/agent-memory-phase3-forget branch from dad22d0 to a102ad0 Compare June 16, 2026 17:04
@jamby77 jamby77 force-pushed the feature/agent-memory-phase4-reinforce branch from 56f9cf0 to 1859ed5 Compare June 16, 2026 17:05

@cursor cursor Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cursor Bugbot has reviewed your changes and found 1 potential issue.

Fix All in Cursor

❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.

Reviewed by Cursor Bugbot for commit 1859ed5. Configure here.

Comment thread packages/agent-memory/src/MemoryStore.ts
@jamby77 jamby77 force-pushed the feature/agent-memory-phase4-reinforce branch from 1859ed5 to 8739aa6 Compare June 16, 2026 17:11
@jamby77 jamby77 force-pushed the feature/agent-memory-phase3-forget branch from a102ad0 to 3dc84bb Compare June 18, 2026 06:57
@jamby77 jamby77 force-pushed the feature/agent-memory-phase4-reinforce branch 2 times, most recently from dcfde4b to 38a6515 Compare June 18, 2026 07:19

@KIvanow KIvanow left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

One thing I'd like to sort before this merges.

Reinforcement doesn't actually influence recall ranking. reinforce() writes last_accessed_at, but the composite recency term still decays from createdAt (ageSeconds = (now - item.createdAt) / 1000 in recall()); lastAccessedAt is parsed onto the item but never read by the scoring path. So reinforcing a memory does not make it any more likely to be recalled next time, which is the feedback loop the name implies. As it stands the write is effectively inert for recall.

If the intent is that last_accessed_at only feeds Phase 5 eviction (not recall recency), that's fine, but it's worth saying so explicitly, because right now "reinforcement" reads as if it should boost future recall and it doesn't. If recency is meant to reflect access, the composite should use max(createdAt, lastAccessedAt) (or lastAccessedAt) for the age calculation. Either way, worth a one-line decision here so the behavior matches the name.

@jamby77 jamby77 force-pushed the feature/agent-memory-phase3-forget branch from 8ab239a to 96f5b18 Compare June 19, 2026 09:51
@jamby77 jamby77 force-pushed the feature/agent-memory-phase4-reinforce branch from 38a6515 to fc1be01 Compare June 19, 2026 09:51
@jamby77

jamby77 commented Jun 19, 2026

Copy link
Copy Markdown
Collaborator Author

@KIvanow Fixed in fc1be01: recall recency now decays from max(created_at, last_accessed_at), so reinforcing a memory genuinely boosts its future recall (the feedback loop the name implies). Added a test asserting a recently-accessed memory outranks an equally-similar stale one.

@jamby77 jamby77 requested a review from KIvanow June 19, 2026 09:52
jamby77 added 2 commits June 19, 2026 13:00
- Recalled items bump last_accessed_at + access_count by default (reinforce)
- reinforce:false skips the writes
- Reinforcement is best-effort: a failure never breaks the recall read path
  (mirrors agent-cache "stats failure must not break the cache")
…ment counts

reinforce() bumped last_accessed_at, but recall recency decayed from
created_at and never read it, so reinforcing a memory did nothing for its
recall ranking. Recency now decays from max(created_at, last_accessed_at),
making reinforcement the recall feedback loop the name implies.
@jamby77 jamby77 force-pushed the feature/agent-memory-phase3-forget branch from 96f5b18 to a1c3786 Compare June 19, 2026 10:01
@jamby77 jamby77 force-pushed the feature/agent-memory-phase4-reinforce branch from fc1be01 to e8e841c Compare June 19, 2026 10:01
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.

2 participants