Skip to content

fix(api): sort /memories newest-first before pagination#995

Open
costajohnt wants to merge 1 commit into
rohitg00:mainfrom
costajohnt:fix/990-memories-latest-sort-order
Open

fix(api): sort /memories newest-first before pagination#995
costajohnt wants to merge 1 commit into
rohitg00:mainfrom
costajohnt:fix/990-memories-latest-sort-order

Conversation

@costajohnt

@costajohnt costajohnt commented Jun 30, 2026

Copy link
Copy Markdown

What

Fixes #990. GET /agentmemory/memories?latest=true&limit=N returned the N oldest "latest" memories, so the viewer showed stale data once the corpus exceeded the limit.

Root cause

The api::memories handler (src/triggers/api.ts) builds its list from kv.list(KV.memories) — insertion order, oldest first — filters by isLatest/agentId, then slices offset..offset+limit. There's no sort, so the slice takes the head (oldest).

Fix

Sort the filtered list newest-first (createdAt desc, fallback updatedAt) before the slice, using the same key/localeCompare pattern as the merged viewer-side fix for the Memories tab (#674/#701) — making the server endpoint consistent with what the viewer already does client-side.

Test

test/memories-latest-sort-order.test.ts asserts the handler sorts on the agreed keys and that the sort runs before the slice (slicing an unsorted list is the bug), matching the source-assertion style of the existing api::memories pagination tests. Full vitest suite passes.

Summary by CodeRabbit

  • Bug Fixes

    • Improved memory list results so pagination now returns the most recent items first, with a fallback sort when timestamps match.
    • Fixed an issue where older entries could appear in paged results once the list grew beyond the requested limit.
  • Tests

    • Added regression coverage to verify the updated memory ordering and pagination behavior.

GET /agentmemory/memories returned rows in kv.list insertion order (oldest
first) and sliced the head, so ?latest=true&limit=N served the N OLDEST
memories and the viewer showed stale data once the corpus exceeded the limit.

Sort the filtered list newest-first (createdAt desc, fallback updatedAt) before
the offset/limit slice, mirroring the viewer-side sort already applied for the
Memories tab (rohitg00#674/rohitg00#701).
@vercel

vercel Bot commented Jun 30, 2026

Copy link
Copy Markdown

@costajohnt is attempting to deploy a commit to the rohitg00's projects Team on Vercel.

A member of the Team first needs to authorize it.

@coderabbitai

coderabbitai Bot commented Jun 30, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

📝 Walkthrough

Walkthrough

The api::memories handler in src/triggers/api.ts now sorts filtered memories by createdAt/updatedAt descending before applying the offset/limit slice. A new test file verifies that filtered.sort(...) appears before filtered.slice(offset...) in the handler source and checks the sort expression.

Memories sort fix and regression test

Layer / File(s) Summary
Sort before paginate in api::memories
src/triggers/api.ts
Inserts filtered.sort() by createdAt/updatedAt descending (with empty-string fallback) immediately before the filtered.slice(offset...) pagination call.
Regression test for sort-before-slice
test/memories-latest-sort-order.test.ts
New test isolates the handler source between marker strings and asserts sort precedes slice, using createdAt descending, updatedAt fallback, and localeCompare.

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~10 minutes

Possibly related issues

Possibly related PRs

  • rohitg00/agentmemory#701: Changes the same memories ordering logic to sort by createdAt descending with updatedAt fallback before pagination, with corresponding tests.

Poem

🐇 Hop, hop! No more stale old carrots in your page,
The freshest memories now lead the parade.
I sorted by date before I took a slice,
Newest-first, newest-first — oh, isn't that nice?
A test checks the order to keep us precise! 🥕

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly summarizes the main change: sorting /memories newest-first before pagination.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@test/memories-latest-sort-order.test.ts`:
- Around line 35-38: The test in memories-latest-sort-order.test.ts only checks
for localeCompare usage, so it can still pass if the comparator direction is
reversed. Update the assertion around the sort comparator in the relevant test
to explicitly verify newest-first ordering by checking for
bKey.localeCompare(aKey) in the comparator logic, or by asserting the comparator
result on sample timestamps through the handler used in the test. This should be
anchored to the existing handler and sort-order expectations so the regression
lock targets the comparator direction itself.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 77175019-a174-4848-b912-098580a189ec

📥 Commits

Reviewing files that changed from the base of the PR and between 93ae9bc and 283a96b.

📒 Files selected for processing (2)
  • src/triggers/api.ts
  • test/memories-latest-sort-order.test.ts

Comment on lines +35 to +38
it("sorts on createdAt desc with updatedAt fallback (matches the #701 viewer fix)", () => {
expect(handler).toMatch(/a\.createdAt \|\| a\.updatedAt/);
expect(handler).toMatch(/b\.createdAt \|\| b\.updatedAt/);
expect(handler).toMatch(/localeCompare/);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Assert the comparator direction explicitly.

This still passes if the implementation flips to aKey.localeCompare(bKey), which would reintroduce oldest-first ordering. Check for bKey.localeCompare(aKey) (or evaluate the comparator on sample timestamps) so the regression actually locks newest-first behavior.

Suggested tightening
   it("sorts on createdAt desc with updatedAt fallback (matches the `#701` viewer fix)", () => {
     expect(handler).toMatch(/a\.createdAt \|\| a\.updatedAt/);
     expect(handler).toMatch(/b\.createdAt \|\| b\.updatedAt/);
-    expect(handler).toMatch(/localeCompare/);
+    expect(handler).toMatch(/bKey\.localeCompare\(aKey\)/);
   });
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
it("sorts on createdAt desc with updatedAt fallback (matches the #701 viewer fix)", () => {
expect(handler).toMatch(/a\.createdAt \|\| a\.updatedAt/);
expect(handler).toMatch(/b\.createdAt \|\| b\.updatedAt/);
expect(handler).toMatch(/localeCompare/);
it("sorts on createdAt desc with updatedAt fallback (matches the `#701` viewer fix)", () => {
expect(handler).toMatch(/a\.createdAt \|\| a\.updatedAt/);
expect(handler).toMatch(/b\.createdAt \|\| b\.updatedAt/);
expect(handler).toMatch(/bKey\.localeCompare\(aKey\)/);
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@test/memories-latest-sort-order.test.ts` around lines 35 - 38, The test in
memories-latest-sort-order.test.ts only checks for localeCompare usage, so it
can still pass if the comparator direction is reversed. Update the assertion
around the sort comparator in the relevant test to explicitly verify
newest-first ordering by checking for bKey.localeCompare(aKey) in the comparator
logic, or by asserting the comparator result on sample timestamps through the
handler used in the test. This should be anchored to the existing handler and
sort-order expectations so the regression lock targets the comparator direction
itself.

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.

GET /agentmemory/memories?latest=true returns oldest memories first — viewer shows stale data when corpus > limit

1 participant