diff --git a/apps/mcp/src/ui/mcp-app.ts b/apps/mcp/src/ui/mcp-app.ts index ba20d89a..6939edcc 100644 --- a/apps/mcp/src/ui/mcp-app.ts +++ b/apps/mcp/src/ui/mcp-app.ts @@ -173,9 +173,16 @@ function transformData(data: ToolResultData): { } { const nodes: GraphNode[] = [] const links: GraphLink[] = [] - const nodeIds = new Set() const SPREAD = 50 + // Pre-populate all node IDs so edge targets are always resolvable + // regardless of iteration order. + const nodeIds = new Set() + for (const doc of data.documents) { + nodeIds.add(doc.id) + for (const mem of doc.memories) nodeIds.add(mem.id) + } + for (const doc of data.documents) { const pos = initialPosition(doc.id, SPREAD) nodes.push({ @@ -189,7 +196,6 @@ function transformData(data: ToolResultData): { x: pos.x, y: pos.y, } as DocumentNode) - nodeIds.add(doc.id) const memCount = doc.memories.length for (let i = 0; i < memCount; i++) { @@ -211,15 +217,16 @@ function transformData(data: ToolResultData): { x: pos.x + Math.cos(angle) * CLUSTER_SPREAD, y: pos.y + Math.sin(angle) * CLUSTER_SPREAD, } as MemoryNode) - nodeIds.add(mem.id) // Derives link (doc -> memory) links.push({ source: doc.id, target: mem.id, edgeType: "derives" }) // Memory-to-memory relation edges from backend data. // Uses memoryRelations as primary source, falls back to parentMemoryId. + // Keep in sync with packages/memory-graph/src/hooks/use-graph-data.ts let relations: Record = {} if ( + // Defensive: data comes from structuredContent cast, may be unexpected type mem.memoryRelations && typeof mem.memoryRelations === "object" && Object.keys(mem.memoryRelations).length > 0 diff --git a/apps/web/components/memory-graph/hooks/use-graph-api.ts b/apps/web/components/memory-graph/hooks/use-graph-api.ts index 3984088d..5710f6ca 100644 --- a/apps/web/components/memory-graph/hooks/use-graph-api.ts +++ b/apps/web/components/memory-graph/hooks/use-graph-api.ts @@ -6,6 +6,7 @@ import { $fetch } from "@lib/api" import type { GraphApiDocument, GraphApiMemory, + MemoryRelation, } from "@supermemory/memory-graph" const PAGE_SIZE = 100 @@ -30,10 +31,10 @@ interface ApiMemoryEntry { rootMemoryId?: string | null createdAt: string updatedAt: string - relation?: "updates" | "extends" | "derives" | null + relation?: MemoryRelation | null updatesMemoryId?: string | null nextVersionId?: string | null - memoryRelations?: Record | null + memoryRelations?: Record | null spaceContainerTag?: string | null } diff --git a/packages/memory-graph/src/hooks/use-graph-data.ts b/packages/memory-graph/src/hooks/use-graph-data.ts index d539e86c..037b989f 100644 --- a/packages/memory-graph/src/hooks/use-graph-data.ts +++ b/packages/memory-graph/src/hooks/use-graph-data.ts @@ -200,6 +200,7 @@ export function useGraphData( for (const mem of doc.memories) { let relations: Record = {} + // Defensive: API may return unexpected types at runtime if ( mem.memoryRelations && typeof mem.memoryRelations === "object" && diff --git a/packages/memory-graph/src/mock-data.ts b/packages/memory-graph/src/mock-data.ts index e32adb13..9cd25a1c 100644 --- a/packages/memory-graph/src/mock-data.ts +++ b/packages/memory-graph/src/mock-data.ts @@ -361,7 +361,7 @@ export function generateMockGraphData(options: MockGraphOptions = {}): { if (targetMem) { const relType = random() < 0.5 ? "extends" : "derives" memoryRelations = { - [targetMem.id]: relType as "extends" | "derives", + [targetMem.id]: relType, } } } diff --git a/packages/memory-graph/src/types.ts b/packages/memory-graph/src/types.ts index 447c17ee..6fa5b9ff 100644 --- a/packages/memory-graph/src/types.ts +++ b/packages/memory-graph/src/types.ts @@ -39,7 +39,7 @@ export interface GraphApiDocument { export interface GraphApiEdge { source: string target: string - edgeType: "derives" | "updates" | "extends" + edgeType: MemoryRelation } // Typed node data @@ -98,7 +98,7 @@ export interface GraphEdge { opacity: number thickness: number } - edgeType: "derives" | "updates" | "extends" + edgeType: MemoryRelation } export interface GraphThemeColors { @@ -221,5 +221,4 @@ export type { DocumentWithMemories, MemoryEntry, DocumentsResponse, - MemoryRelation, } from "./api-types"