mirror of
https://github.com/supermemoryai/supermemory.git
synced 2026-08-28 05:25:33 +00:00
fix: show all memory relations
This commit is contained in:
parent
2f4bcca445
commit
c2a5cce02c
3 changed files with 86 additions and 59 deletions
|
|
@ -31,7 +31,9 @@ export default function Home() {
|
|||
|
||||
// State for slideshow
|
||||
const [isSlideshowActive, setIsSlideshowActive] = useState(false)
|
||||
const [currentSlideshowNode, setCurrentSlideshowNode] = useState<string | null>(null)
|
||||
const [currentSlideshowNode, setCurrentSlideshowNode] = useState<
|
||||
string | null
|
||||
>(null)
|
||||
|
||||
const PAGE_SIZE = 500
|
||||
|
||||
|
|
@ -279,7 +281,7 @@ export default function Home() {
|
|||
hasMore={hasMore}
|
||||
loadMoreDocuments={loadMoreDocuments}
|
||||
totalLoaded={documents.length}
|
||||
variant="consumer"
|
||||
variant="console"
|
||||
// Controlled space selection
|
||||
selectedSpace={selectedSpace}
|
||||
onSpaceChange={handleSpaceChange}
|
||||
|
|
|
|||
17
bun.lock
17
bun.lock
|
|
@ -227,7 +227,6 @@
|
|||
"@emotion/is-prop-valid": "^1.4.0",
|
||||
"@radix-ui/react-collapsible": "^1.1.12",
|
||||
"@radix-ui/react-slot": "^1.2.4",
|
||||
"@supermemory/memory-graph": "^0.1.7",
|
||||
"@vanilla-extract/css": "^1.17.4",
|
||||
"@vanilla-extract/recipes": "^0.5.7",
|
||||
"@vanilla-extract/sprinkles": "^1.6.5",
|
||||
|
|
@ -1457,7 +1456,7 @@
|
|||
|
||||
"@smithy/util-utf8": ["@smithy/util-utf8@4.2.0", "", { "dependencies": { "@smithy/util-buffer-from": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-zBPfuzoI8xyBtR2P6WQj63Rz8i3AmfAaJLuNG8dWsfvPe8lO4aCPYLn879mEgHndZH1zQ2oXmG8O1GGzzaoZiw=="],
|
||||
|
||||
"@smithy/util-waiter": ["@smithy/util-waiter@2.2.0", "", { "dependencies": { "@smithy/abort-controller": "^2.2.0", "@smithy/types": "^2.12.0", "tslib": "^2.6.2" } }, "sha512-IHk53BVw6MPMi2Gsn+hCng8rFA3ZmR3Rk7GllxDUW9qFJl/hiSvskn7XldkECapQVkIg/1dHpMAxI9xSTaLLSA=="],
|
||||
"@smithy/util-waiter": ["@smithy/util-waiter@4.2.5", "", { "dependencies": { "@smithy/abort-controller": "^4.2.5", "@smithy/types": "^4.9.0", "tslib": "^2.6.2" } }, "sha512-Dbun99A3InifQdIrsXZ+QLcC0PGBPAdrl4cj1mTgJvyc9N2zf7QSxg8TBkzsCmGJdE3TLbO9ycwpY0EkWahQ/g=="],
|
||||
|
||||
"@smithy/uuid": ["@smithy/uuid@1.1.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-4aUIteuyxtBUhVdiQqcDhKFitwfd9hqoSDYY2KRXiWtgoWJ9Bmise+KfEPDiVHWeJepvF8xJO9/9+WDIciMFFw=="],
|
||||
|
||||
|
|
@ -4411,14 +4410,10 @@
|
|||
|
||||
"@aws-sdk/client-cloudfront/@smithy/util-utf8": ["@smithy/util-utf8@2.3.0", "", { "dependencies": { "@smithy/util-buffer-from": "^2.2.0", "tslib": "^2.6.2" } }, "sha512-R8Rdn8Hy72KKcebgLiv8jQcQkXoLMOGGv5uI1/k0l+snqkOzQ1R0ChUBCxWMlBsFMekWjq0wRudIweFs7sKT5A=="],
|
||||
|
||||
"@aws-sdk/client-cloudfront/@smithy/util-waiter": ["@smithy/util-waiter@2.2.0", "", { "dependencies": { "@smithy/abort-controller": "^2.2.0", "@smithy/types": "^2.12.0", "tslib": "^2.6.2" } }, "sha512-IHk53BVw6MPMi2Gsn+hCng8rFA3ZmR3Rk7GllxDUW9qFJl/hiSvskn7XldkECapQVkIg/1dHpMAxI9xSTaLLSA=="],
|
||||
|
||||
"@aws-sdk/client-cloudfront/fast-xml-parser": ["fast-xml-parser@4.2.5", "", { "dependencies": { "strnum": "^1.0.5" }, "bin": { "fxparser": "src/cli/cli.js" } }, "sha512-B9/wizE4WngqQftFPmdaMYlXoJlJOYxGQOanC77fq9k8+Z0v5dDSVh+3glErdIROP//s/jgb7ZuxKfB8nVyo0g=="],
|
||||
|
||||
"@aws-sdk/client-dynamodb/@smithy/util-waiter": ["@smithy/util-waiter@4.2.5", "", { "dependencies": { "@smithy/abort-controller": "^4.2.5", "@smithy/types": "^4.9.0", "tslib": "^2.6.2" } }, "sha512-Dbun99A3InifQdIrsXZ+QLcC0PGBPAdrl4cj1mTgJvyc9N2zf7QSxg8TBkzsCmGJdE3TLbO9ycwpY0EkWahQ/g=="],
|
||||
|
||||
"@aws-sdk/client-lambda/@smithy/util-waiter": ["@smithy/util-waiter@4.2.5", "", { "dependencies": { "@smithy/abort-controller": "^4.2.5", "@smithy/types": "^4.9.0", "tslib": "^2.6.2" } }, "sha512-Dbun99A3InifQdIrsXZ+QLcC0PGBPAdrl4cj1mTgJvyc9N2zf7QSxg8TBkzsCmGJdE3TLbO9ycwpY0EkWahQ/g=="],
|
||||
|
||||
"@aws-sdk/client-s3/@smithy/util-waiter": ["@smithy/util-waiter@4.2.5", "", { "dependencies": { "@smithy/abort-controller": "^4.2.5", "@smithy/types": "^4.9.0", "tslib": "^2.6.2" } }, "sha512-Dbun99A3InifQdIrsXZ+QLcC0PGBPAdrl4cj1mTgJvyc9N2zf7QSxg8TBkzsCmGJdE3TLbO9ycwpY0EkWahQ/g=="],
|
||||
|
||||
"@aws-sdk/client-sts/@aws-crypto/sha256-browser": ["@aws-crypto/sha256-browser@3.0.0", "", { "dependencies": { "@aws-crypto/ie11-detection": "^3.0.0", "@aws-crypto/sha256-js": "^3.0.0", "@aws-crypto/supports-web-crypto": "^3.0.0", "@aws-crypto/util": "^3.0.0", "@aws-sdk/types": "^3.222.0", "@aws-sdk/util-locate-window": "^3.0.0", "@aws-sdk/util-utf8-browser": "^3.0.0", "tslib": "^1.11.1" } }, "sha512-8VLmW2B+gjFbU5uMeqtQM6Nj0/F1bro80xQXCW6CQBWgosFWXTx77aeOF5CAIAmbOK64SdMBJdNr6J41yP5mvQ=="],
|
||||
|
||||
"@aws-sdk/client-sts/@aws-crypto/sha256-js": ["@aws-crypto/sha256-js@3.0.0", "", { "dependencies": { "@aws-crypto/util": "^3.0.0", "@aws-sdk/types": "^3.222.0", "tslib": "^1.11.1" } }, "sha512-PnNN7os0+yd1XvXAy23CFOmTbMaDxgxXtTKHybrJ39Y8kGzBATgBFibWJKH6BhytLI/Zyszs87xCOBNyBig6vQ=="],
|
||||
|
|
@ -4715,10 +4710,6 @@
|
|||
|
||||
"@shikijs/core/hast-util-to-html": ["hast-util-to-html@9.0.5", "", { "dependencies": { "@types/hast": "^3.0.0", "@types/unist": "^3.0.0", "ccount": "^2.0.0", "comma-separated-tokens": "^2.0.0", "hast-util-whitespace": "^3.0.0", "html-void-elements": "^3.0.0", "mdast-util-to-hast": "^13.0.0", "property-information": "^7.0.0", "space-separated-tokens": "^2.0.0", "stringify-entities": "^4.0.0", "zwitch": "^2.0.4" } }, "sha512-OguPdidb+fbHQSU4Q4ZiLKnzWo8Wwsf5bZfbvu7//a9oTYoqD/fWpe96NuHkoS9h0ccGOTe0C4NGXdtS0iObOw=="],
|
||||
|
||||
"@smithy/util-waiter/@smithy/abort-controller": ["@smithy/abort-controller@2.2.0", "", { "dependencies": { "@smithy/types": "^2.12.0", "tslib": "^2.6.2" } }, "sha512-wRlta7GuLWpTqtFfGo+nZyOO1vEvewdNR1R4rTxpC8XU6vG/NDyrFBhwLZsqg1NUoR1noVaXJPC/7ZK47QCySw=="],
|
||||
|
||||
"@smithy/util-waiter/@smithy/types": ["@smithy/types@2.12.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-QwYgloJ0sVNBeBuBs65cIkTbfzV/Q6ZNPCJ99EICFEdJYG50nGIY/uYXp+TbsdJReIuPr0a0kXmCvren3MbRRw=="],
|
||||
|
||||
"@stoplight/better-ajv-errors/leven": ["leven@3.1.0", "", {}, "sha512-qsda+H8jTaUaN/x5vzW2rzc+8Rw4TAQ/4KjB46IwK5VH+IlVeeeje/EoZRpiXvIqjFgK84QffqPztGI3VBLG1A=="],
|
||||
|
||||
"@stoplight/json/safe-stable-stringify": ["safe-stable-stringify@1.1.1", "", {}, "sha512-ERq4hUjKDbJfE4+XtZLFPCDi8Vb1JqaxAPTxWFLBx8XcAlf9Bda/ZJdVezs/NAfsMQScyIlUMx+Yeu7P7rx5jw=="],
|
||||
|
|
@ -5249,6 +5240,8 @@
|
|||
|
||||
"@aws-sdk/client-cloudfront/@smithy/util-utf8/@smithy/util-buffer-from": ["@smithy/util-buffer-from@2.2.0", "", { "dependencies": { "@smithy/is-array-buffer": "^2.2.0", "tslib": "^2.6.2" } }, "sha512-IJdWBbTcMQ6DA0gdNhh/BwrLkDR+ADW5Kr1aZmd4k3DIF6ezMV4R2NIAmT08wQJ3yUK82thHWmC/TnK/wpMMIA=="],
|
||||
|
||||
"@aws-sdk/client-cloudfront/@smithy/util-waiter/@smithy/abort-controller": ["@smithy/abort-controller@2.2.0", "", { "dependencies": { "@smithy/types": "^2.12.0", "tslib": "^2.6.2" } }, "sha512-wRlta7GuLWpTqtFfGo+nZyOO1vEvewdNR1R4rTxpC8XU6vG/NDyrFBhwLZsqg1NUoR1noVaXJPC/7ZK47QCySw=="],
|
||||
|
||||
"@aws-sdk/client-cloudfront/fast-xml-parser/strnum": ["strnum@1.1.2", "", {}, "sha512-vrN+B7DBIoTTZjnPNewwhx6cBA/H+IS7rfW68n7XxC1y7uoiGQBxaKzqucGUgavX15dJgiGztLJ8vxuEzwqBdA=="],
|
||||
|
||||
"@aws-sdk/client-sts/@aws-crypto/sha256-browser/@aws-crypto/supports-web-crypto": ["@aws-crypto/supports-web-crypto@3.0.0", "", { "dependencies": { "tslib": "^1.11.1" } }, "sha512-06hBdMwUAb2WFTuGG73LSC0wfPu93xWwo5vL2et9eymgmu3Id5vFAHBbajVWiGhPO37qcsdCap/FqXvJGJWPIg=="],
|
||||
|
|
|
|||
|
|
@ -19,7 +19,16 @@ import type {
|
|||
export function useGraphData(
|
||||
data: DocumentsResponse | null,
|
||||
selectedSpace: string,
|
||||
nodePositions: Map<string, { x: number; y: number; parentDocId?: string; offsetX?: number; offsetY?: number }>,
|
||||
nodePositions: Map<
|
||||
string,
|
||||
{
|
||||
x: number
|
||||
y: number
|
||||
parentDocId?: string
|
||||
offsetX?: number
|
||||
offsetY?: number
|
||||
}
|
||||
>,
|
||||
draggingNodeId: string | null,
|
||||
memoryLimit?: number,
|
||||
maxNodes?: number,
|
||||
|
|
@ -60,35 +69,34 @@ export function useGraphData(
|
|||
})
|
||||
|
||||
// Filter by space and prepare documents
|
||||
let processedDocs = sortedDocs
|
||||
.map((doc) => {
|
||||
let memories =
|
||||
selectedSpace === "all"
|
||||
? doc.memoryEntries
|
||||
: doc.memoryEntries.filter(
|
||||
(memory) =>
|
||||
(memory.spaceContainerTag ?? memory.spaceId ?? "default") ===
|
||||
selectedSpace,
|
||||
)
|
||||
let processedDocs = sortedDocs.map((doc) => {
|
||||
let memories =
|
||||
selectedSpace === "all"
|
||||
? doc.memoryEntries
|
||||
: doc.memoryEntries.filter(
|
||||
(memory) =>
|
||||
(memory.spaceContainerTag ?? memory.spaceId ?? "default") ===
|
||||
selectedSpace,
|
||||
)
|
||||
|
||||
// Sort memories by relevance score (if available) or recency
|
||||
memories = memories.sort((a, b) => {
|
||||
// Prioritize sourceRelevanceScore if available
|
||||
if (a.sourceRelevanceScore != null && b.sourceRelevanceScore != null) {
|
||||
return b.sourceRelevanceScore - a.sourceRelevanceScore // Higher score first
|
||||
}
|
||||
// Fall back to most recent
|
||||
const dateA = new Date(a.updatedAt || a.createdAt).getTime()
|
||||
const dateB = new Date(b.updatedAt || b.createdAt).getTime()
|
||||
return dateB - dateA // Most recent first
|
||||
})
|
||||
|
||||
return {
|
||||
...doc,
|
||||
memoryEntries: memories,
|
||||
// Sort memories by relevance score (if available) or recency
|
||||
memories = memories.sort((a, b) => {
|
||||
// Prioritize sourceRelevanceScore if available
|
||||
if (a.sourceRelevanceScore != null && b.sourceRelevanceScore != null) {
|
||||
return b.sourceRelevanceScore - a.sourceRelevanceScore // Higher score first
|
||||
}
|
||||
// Fall back to most recent
|
||||
const dateA = new Date(a.updatedAt || a.createdAt).getTime()
|
||||
const dateB = new Date(b.updatedAt || b.createdAt).getTime()
|
||||
return dateB - dateA // Most recent first
|
||||
})
|
||||
|
||||
return {
|
||||
...doc,
|
||||
memoryEntries: memories,
|
||||
}
|
||||
})
|
||||
|
||||
// Apply maxNodes limit using Option B (dynamic cap per document)
|
||||
if (maxNodes && maxNodes > 0) {
|
||||
const totalDocs = processedDocs.length
|
||||
|
|
@ -112,37 +120,57 @@ export function useGraphData(
|
|||
// If we still have budget left, distribute remaining nodes to first docs
|
||||
let remainingBudget = maxNodes - totalNodes
|
||||
if (remainingBudget > 0) {
|
||||
for (let i = 0; i < processedDocs.length && remainingBudget > 0; i++) {
|
||||
for (
|
||||
let i = 0;
|
||||
i < processedDocs.length && remainingBudget > 0;
|
||||
i++
|
||||
) {
|
||||
const doc = processedDocs[i]
|
||||
if (!doc) continue
|
||||
const originalDoc = sortedDocs.find(d => d.id === doc.id)
|
||||
const originalDoc = sortedDocs.find((d) => d.id === doc.id)
|
||||
if (!originalDoc) continue
|
||||
|
||||
const currentMemCount = doc.memoryEntries.length
|
||||
const originalMemCount = originalDoc.memoryEntries.filter(
|
||||
m => selectedSpace === "all" ||
|
||||
(m.spaceContainerTag ?? m.spaceId ?? "default") === selectedSpace
|
||||
(m) =>
|
||||
selectedSpace === "all" ||
|
||||
(m.spaceContainerTag ?? m.spaceId ?? "default") ===
|
||||
selectedSpace,
|
||||
).length
|
||||
|
||||
// Can we add more memories to this doc?
|
||||
const canAdd = originalMemCount - currentMemCount
|
||||
if (canAdd > 0) {
|
||||
const toAdd = Math.min(canAdd, remainingBudget)
|
||||
const additionalMems = doc.memoryEntries.slice(0, currentMemCount + toAdd)
|
||||
const additionalMems = doc.memoryEntries.slice(
|
||||
0,
|
||||
currentMemCount + toAdd,
|
||||
)
|
||||
processedDocs[i] = {
|
||||
...doc,
|
||||
memoryEntries: originalDoc.memoryEntries
|
||||
.filter(m => selectedSpace === "all" ||
|
||||
(m.spaceContainerTag ?? m.spaceId ?? "default") === selectedSpace)
|
||||
.filter(
|
||||
(m) =>
|
||||
selectedSpace === "all" ||
|
||||
(m.spaceContainerTag ?? m.spaceId ?? "default") ===
|
||||
selectedSpace,
|
||||
)
|
||||
.sort((a, b) => {
|
||||
if (a.sourceRelevanceScore != null && b.sourceRelevanceScore != null) {
|
||||
if (
|
||||
a.sourceRelevanceScore != null &&
|
||||
b.sourceRelevanceScore != null
|
||||
) {
|
||||
return b.sourceRelevanceScore - a.sourceRelevanceScore
|
||||
}
|
||||
const dateA = new Date(a.updatedAt || a.createdAt).getTime()
|
||||
const dateB = new Date(b.updatedAt || b.createdAt).getTime()
|
||||
const dateA = new Date(
|
||||
a.updatedAt || a.createdAt,
|
||||
).getTime()
|
||||
const dateB = new Date(
|
||||
b.updatedAt || b.createdAt,
|
||||
).getTime()
|
||||
return dateB - dateA
|
||||
})
|
||||
.slice(0, currentMemCount + toAdd)
|
||||
.slice(0, currentMemCount + toAdd),
|
||||
}
|
||||
remainingBudget -= toAdd
|
||||
}
|
||||
|
|
@ -238,8 +266,7 @@ export function useGraphData(
|
|||
})
|
||||
|
||||
// Enhanced Layout with Space Separation
|
||||
const { centerX, centerY, clusterRadius } =
|
||||
LAYOUT_CONSTANTS
|
||||
const { centerX, centerY, clusterRadius } = LAYOUT_CONSTANTS
|
||||
|
||||
/* 1. Build DOCUMENT nodes with space-aware clustering */
|
||||
const documentNodes: GraphNode[] = []
|
||||
|
|
@ -255,8 +282,10 @@ export function useGraphData(
|
|||
|
||||
// Loose grid spacing - physics will organize it better
|
||||
const spacing = 200
|
||||
const defaultX = centerX + (col - gridSize / 2) * spacing + (Math.random() - 0.5) * 50
|
||||
const defaultY = centerY + (row - gridSize / 2) * spacing + (Math.random() - 0.5) * 50
|
||||
const defaultX =
|
||||
centerX + (col - gridSize / 2) * spacing + (Math.random() - 0.5) * 50
|
||||
const defaultY =
|
||||
centerY + (row - gridSize / 2) * spacing + (Math.random() - 0.5) * 50
|
||||
|
||||
const customPos = nodePositions.get(doc.id)
|
||||
|
||||
|
|
@ -318,9 +347,11 @@ export function useGraphData(
|
|||
|
||||
if (customMemPos) {
|
||||
// If memory was manually positioned and has stored offset relative to parent
|
||||
if (customMemPos.parentDocId === docNode.id &&
|
||||
if (
|
||||
customMemPos.parentDocId === docNode.id &&
|
||||
customMemPos.offsetX !== undefined &&
|
||||
customMemPos.offsetY !== undefined) {
|
||||
customMemPos.offsetY !== undefined
|
||||
) {
|
||||
// Apply the stored offset to the current document position
|
||||
finalMemX = docNode.x + customMemPos.offsetX
|
||||
finalMemY = docNode.y + customMemPos.offsetY
|
||||
|
|
@ -386,7 +417,8 @@ export function useGraphData(
|
|||
data.documents.forEach((doc) => {
|
||||
doc.memoryEntries.forEach((mem: MemoryEntry) => {
|
||||
// Support both new object structure and legacy array/single parent fields
|
||||
let parentRelations: Record<string, MemoryRelation> = {}
|
||||
let parentRelations: Record<string, MemoryRelation> =
|
||||
mem.memoryRelations ?? ({} as Record<string, MemoryRelation>)
|
||||
|
||||
if (
|
||||
mem.memoryRelations &&
|
||||
|
|
@ -436,4 +468,4 @@ export function useGraphData(
|
|||
|
||||
return { nodes: allNodes, edges: allEdges }
|
||||
}, [data, filteredDocuments, nodePositions, draggingNodeId, similarityEdges])
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue