fix(mcp): preserve pagination after filtering memories

This commit is contained in:
shamAnimates 2026-08-16 18:53:08 +05:30
parent e651045ac5
commit 60cbe9b4b6
3 changed files with 125 additions and 3 deletions

View file

@ -29,5 +29,9 @@ jobs:
- name: Run TypeScript type checking
run: bunx turbo run check-types --filter='@supermemory/ai-sdk' --filter='@supermemory/memory-graph'
- name: Run MCP unit tests
working-directory: apps/mcp
run: bun run test:unit
- name: Run Biome CI (format & lint on changed files)
run: bunx biome ci --changed --since=origin/main --no-errors-on-unmatched

View file

@ -0,0 +1,107 @@
import { describe, expect, it } from "vitest"
import type { MemoryEntriesResponse, MemoryEntry } from "./client"
import { formatMemoryEntriesList } from "./format"
function memoryEntry(overrides: Partial<MemoryEntry> = {}): MemoryEntry {
return {
id: "memory-1",
memory: "Current fact",
version: 1,
isLatest: true,
isForgotten: false,
createdAt: "2026-08-15T10:00:00.000Z",
updatedAt: "2026-08-15T10:00:00.000Z",
...overrides,
}
}
function memoryResponse(
overrides: Partial<MemoryEntriesResponse> = {},
): MemoryEntriesResponse {
return {
memoryEntries: [],
pagination: {
currentPage: 1,
limit: 10,
totalItems: 0,
totalPages: 1,
},
...overrides,
}
}
describe("formatMemoryEntriesList", () => {
it("reports a truly empty store", () => {
expect(formatMemoryEntriesList(memoryResponse())).toBe(
"No active memories stored yet.",
)
})
it("continues past a filtered-empty page when a later page has active data", () => {
const firstPage = formatMemoryEntriesList(
memoryResponse({
memoryEntries: [
memoryEntry({ id: "forgotten", isForgotten: true }),
memoryEntry({ id: "superseded", isLatest: false }),
],
pagination: {
currentPage: 1,
limit: 2,
totalItems: 3,
totalPages: 2,
},
}),
)
const secondPage = formatMemoryEntriesList(
memoryResponse({
memoryEntries: [memoryEntry({ id: "still-active" })],
pagination: {
currentPage: 2,
limit: 2,
totalItems: 3,
totalPages: 2,
},
}),
)
expect(firstPage).toBe(
"No active memories on page 1 (2 pages total).\n\nMore available - call listMemories with page: 2.",
)
expect(secondPage).toContain("[still-active] Current fact")
})
it("does not offer another page from a filtered-empty last page", () => {
const result = formatMemoryEntriesList(
memoryResponse({
memoryEntries: [memoryEntry({ isForgotten: true })],
pagination: {
currentPage: 2,
limit: 10,
totalItems: 11,
totalPages: 2,
},
}),
)
expect(result).toBe("No active memories on page 2 (2 pages total).")
expect(result).not.toContain("More available")
})
it("keeps active-memory output unchanged", () => {
const result = formatMemoryEntriesList(
memoryResponse({
memoryEntries: [memoryEntry()],
pagination: {
currentPage: 1,
limit: 10,
totalItems: 1,
totalPages: 1,
},
}),
)
expect(result).toBe(
"1 active memory (page 1 of 1, 1 memory entry total), newest first.\n\n- [memory-1] Current fact\n version 1 | updated 2026-08-15",
)
})
})

View file

@ -81,9 +81,20 @@ export function formatMemoryEntriesList(
)
if (activeEntries.length === 0) {
return pagination.currentPage > 1
? `No active memories on page ${pagination.currentPage} (${pagination.totalPages} page${pagination.totalPages === 1 ? "" : "s"} total).`
: "No active memories stored yet."
if (pagination.currentPage === 1 && pagination.totalItems === 0) {
return "No active memories stored yet."
}
const parts = [
`No active memories on page ${pagination.currentPage} (${pagination.totalPages} page${pagination.totalPages === 1 ? "" : "s"} total).`,
]
if (pagination.currentPage < pagination.totalPages) {
parts.push(
"",
`More available - call listMemories with page: ${pagination.currentPage + 1}.`,
)
}
return parts.join("\n")
}
const blocks = activeEntries.map((entry) => {