mirror of
https://github.com/supermemoryai/supermemory.git
synced 2026-08-04 05:40:30 +00:00
177 lines
4.6 KiB
TypeScript
177 lines
4.6 KiB
TypeScript
import { describe, expect, it } from "bun:test"
|
|
import { extractHighlightDocumentIdsFromMessages } from "./chat-highlight-documents"
|
|
import {
|
|
buildCitationIndex,
|
|
extractDocumentIdsFromMemoryOutput,
|
|
extractMemoryToolOutputs,
|
|
getDocumentSourceUrl,
|
|
mapDocumentsByKnownIds,
|
|
} from "./chat-memory-tools"
|
|
|
|
const assistantMessage = {
|
|
id: "m1",
|
|
role: "assistant",
|
|
parts: [
|
|
{
|
|
type: "tool-recallContext",
|
|
state: "output-available",
|
|
output: {
|
|
sourceIds: ["S1"],
|
|
documentIds: ["topDoc"],
|
|
results: [
|
|
{
|
|
citationId: "S1",
|
|
content: "memo",
|
|
document: {
|
|
id: "docA",
|
|
customId: "customA",
|
|
title: "Doc A",
|
|
type: "google_doc",
|
|
summary: "sum",
|
|
},
|
|
},
|
|
],
|
|
},
|
|
},
|
|
{
|
|
type: "tool-discoverSpaces",
|
|
state: "input-streaming",
|
|
output: { sourceIds: ["ignored"], documentIds: ["ignoredDoc"] },
|
|
},
|
|
{
|
|
type: "text",
|
|
text: 'Answer <response source="S1">from memory</response>',
|
|
},
|
|
],
|
|
} as const
|
|
|
|
describe("chat memory tool citation mapping", () => {
|
|
it("extracts only ready memory tool outputs", () => {
|
|
const outputs = extractMemoryToolOutputs({
|
|
parts: [
|
|
...assistantMessage.parts,
|
|
{
|
|
type: "tool-searchMemories",
|
|
state: "done",
|
|
output: { sourceIds: ["done"], documentIds: ["doneDoc"] },
|
|
},
|
|
{
|
|
type: "tool-searchMemories",
|
|
output: { sourceIds: ["stateless"], documentIds: ["statelessDoc"] },
|
|
},
|
|
],
|
|
})
|
|
|
|
expect(outputs).toHaveLength(3)
|
|
expect(outputs.map((output) => output.output.sourceIds?.[0])).toEqual([
|
|
"S1",
|
|
"done",
|
|
"stateless",
|
|
])
|
|
})
|
|
|
|
it("maps citation ids to document and custom ids", () => {
|
|
const [output] = extractMemoryToolOutputs(assistantMessage)
|
|
const index = buildCitationIndex(output ? [output] : [])
|
|
|
|
expect(index.get("S1")?.documentId).toBe("docA")
|
|
expect(index.get("S1")?.customId).toBe("customA")
|
|
expect(index.has("ignored")).toBe(false)
|
|
})
|
|
|
|
it("extracts graph highlight document ids from memory outputs", () => {
|
|
const [output] = extractMemoryToolOutputs(assistantMessage)
|
|
|
|
expect(output && extractDocumentIdsFromMemoryOutput(output.output)).toEqual(
|
|
["topDoc", "docA", "customA"],
|
|
)
|
|
expect(
|
|
extractHighlightDocumentIdsFromMessages([assistantMessage as never]),
|
|
).toEqual(["topDoc", "docA", "customA"])
|
|
})
|
|
|
|
it("keeps graph highlights for legacy memory tool states and ids", () => {
|
|
const legacyMessage = {
|
|
id: "legacy",
|
|
role: "assistant",
|
|
parts: [
|
|
{
|
|
type: "tool-searchMemories",
|
|
state: "done",
|
|
output: { results: [{ id: "legacyDoc" }] },
|
|
},
|
|
{
|
|
type: "tool-recallContext",
|
|
output: { documentIds: ["statelessDoc"] },
|
|
},
|
|
],
|
|
} as const
|
|
|
|
expect(extractMemoryToolOutputs(legacyMessage)).toHaveLength(2)
|
|
expect(
|
|
extractHighlightDocumentIdsFromMessages([legacyMessage as never]),
|
|
).toEqual(["legacyDoc", "statelessDoc"])
|
|
})
|
|
|
|
it("normalizes nested discoverSpaces memory results", () => {
|
|
const outputs = extractMemoryToolOutputs({
|
|
parts: [
|
|
{
|
|
type: "tool-discoverSpaces",
|
|
state: "output-available",
|
|
output: {
|
|
spaces: [
|
|
{
|
|
sourceIds: ["S2"],
|
|
documentIds: ["spaceDoc"],
|
|
results: [{ citationId: "S2", documentIds: ["nestedDoc"] }],
|
|
},
|
|
],
|
|
},
|
|
},
|
|
],
|
|
})
|
|
|
|
const index = buildCitationIndex(outputs)
|
|
expect(index.get("S2")?.documentId).toBe("nestedDoc")
|
|
expect(
|
|
extractDocumentIdsFromMemoryOutput(outputs[0]?.output ?? {}),
|
|
).toEqual(["spaceDoc", "nestedDoc"])
|
|
})
|
|
|
|
it("builds editable Google source URLs from custom ids and API URLs", () => {
|
|
expect(
|
|
getDocumentSourceUrl({
|
|
type: "google_doc",
|
|
customId: "docCustom",
|
|
url: "https://docs.googleapis.com/v1/documents/apiDoc",
|
|
} as never),
|
|
).toBe("https://docs.google.com/document/d/docCustom/edit")
|
|
expect(
|
|
getDocumentSourceUrl({
|
|
type: "google_doc",
|
|
url: "https://docs.googleapis.com/v1/documents/apiDoc",
|
|
} as never),
|
|
).toBe("https://docs.google.com/document/d/apiDoc/edit")
|
|
expect(
|
|
getDocumentSourceUrl({
|
|
type: "google_sheet",
|
|
url: "https://sheets.googleapis.com/v4/spreadsheets/sheetId/values/A1",
|
|
} as never),
|
|
).toBe("https://docs.google.com/spreadsheets/d/sheetId/edit")
|
|
expect(
|
|
getDocumentSourceUrl({
|
|
type: "google_slide",
|
|
url: "https://slides.googleapis.com/v1/presentations/slideId/pages",
|
|
} as never),
|
|
).toBe("https://docs.google.com/presentation/d/slideId/edit")
|
|
})
|
|
|
|
it("maps documents by all known ids", () => {
|
|
const mapped = mapDocumentsByKnownIds([
|
|
{ id: "docA", customId: "customA", type: "text", url: null } as never,
|
|
])
|
|
expect(mapped.get("docA")?.id).toBe("docA")
|
|
expect(mapped.get("customA")?.id).toBe("docA")
|
|
})
|
|
})
|