fix: MCP forward-reference bug + type cleanup from review

- Fix MCP transformData to pre-populate nodeIds before edge computation,
  preventing silently dropped edges for forward-referenced memories
- Use MemoryRelation type for edgeType fields in GraphApiEdge and GraphEdge
- Use MemoryRelation type in use-graph-api.ts instead of inline literals
- Remove redundant MemoryRelation re-export from types.ts (already in index.tsx)
- Remove unnecessary type assertion cast in mock-data.ts
- Add defensive comments for runtime typeof checks
This commit is contained in:
Vorflux AI 2026-03-28 23:23:23 +00:00
parent 795981218b
commit a2765e377a
5 changed files with 17 additions and 9 deletions

View file

@ -173,9 +173,16 @@ function transformData(data: ToolResultData): {
} {
const nodes: GraphNode[] = []
const links: GraphLink[] = []
const nodeIds = new Set<string>()
const SPREAD = 50
// Pre-populate all node IDs so edge targets are always resolvable
// regardless of iteration order.
const nodeIds = new Set<string>()
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<string, string> = {}
if (
// Defensive: data comes from structuredContent cast, may be unexpected type
mem.memoryRelations &&
typeof mem.memoryRelations === "object" &&
Object.keys(mem.memoryRelations).length > 0

View file

@ -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<string, "updates" | "extends" | "derives"> | null
memoryRelations?: Record<string, MemoryRelation> | null
spaceContainerTag?: string | null
}

View file

@ -200,6 +200,7 @@ export function useGraphData(
for (const mem of doc.memories) {
let relations: Record<string, string> = {}
// Defensive: API may return unexpected types at runtime
if (
mem.memoryRelations &&
typeof mem.memoryRelations === "object" &&

View file

@ -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,
}
}
}

View file

@ -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"