fix: resolve Prisma 'vector' deserialization error and missing PDF canvas dependency
Some checks failed
CI / Lint, Test & Build (push) Failing after 5m29s
CI / Deploy production (on server) (push) Has been cancelled

This commit is contained in:
Antigravity
2026-05-19 21:34:50 +00:00
parent 37d9bea7bb
commit b935466480
3 changed files with 41 additions and 20 deletions

View File

@@ -111,7 +111,7 @@ export class MemoryEchoService {
userId,
isArchived: false,
trashedAt: null,
noteEmbedding: { isNot: null } // Only notes with embeddings
// noteEmbedding: { isNot: null } // Removed because Unsupported type cannot be used in 'where' easily
},
select: {
id: true,
@@ -127,11 +127,20 @@ export class MemoryEchoService {
return [] // Need at least 2 notes to find connections
}
if (notes.length < 2) return []
// Fetch embeddings separately using raw SQL to avoid deserialization error
const noteIds = notes.map(n => n.id)
const embeddings: Array<{ noteId: string, embedding: any }> = await prisma.$queryRawUnsafe(
`SELECT "noteId", "embedding"::text FROM "NoteEmbedding" WHERE "noteId" IN (${noteIds.map(id => `'${id}'`).join(',')})`
)
const embeddingMap = new Map(embeddings.map(e => [e.noteId, e.embedding]))
const notesWithEmbeddings = notes
.map(note => ({
...note,
embedding: note.noteEmbedding?.embedding
? embeddingService.fromVectorString(note.noteEmbedding.embedding as unknown as string)
embedding: embeddingMap.has(note.id)
? embeddingService.fromVectorString(embeddingMap.get(note.id))
: null
}))
.filter(note => note.embedding && Array.isArray(note.embedding))
@@ -446,7 +455,6 @@ Explain in one brief sentence (max 15 words) why these notes are connected. Focu
id: true,
title: true,
content: true,
noteEmbedding: true,
createdAt: true,
userId: true
}
@@ -456,7 +464,14 @@ Explain in one brief sentence (max 15 words) why these notes are connected. Focu
return [] // Note not found or doesn't belong to user
}
if (!targetNote.noteEmbedding) {
// Fetch embedding separately
const embeddingResult: Array<{ embedding: any }> = await prisma.$queryRawUnsafe(
`SELECT "embedding"::text FROM "NoteEmbedding" WHERE "noteId" = $1`,
noteId
)
const targetEmbeddingStr = embeddingResult[0]?.embedding
if (!targetEmbeddingStr) {
return [] // Note has no embedding
}
@@ -490,13 +505,11 @@ Explain in one brief sentence (max 15 words) why these notes are connected. Focu
id: { not: noteId },
isArchived: false,
trashedAt: null,
noteEmbedding: { isNot: null }
},
select: {
id: true,
title: true,
content: true,
noteEmbedding: true,
createdAt: true
},
orderBy: { createdAt: 'desc' }
@@ -506,11 +519,18 @@ Explain in one brief sentence (max 15 words) why these notes are connected. Focu
return []
}
const targetEmbedding = targetNote.noteEmbedding?.embedding
? embeddingService.fromVectorString(targetNote.noteEmbedding.embedding as unknown as string)
const targetEmbedding = targetEmbeddingStr
? embeddingService.fromVectorString(targetEmbeddingStr)
: null
if (!targetEmbedding) return []
// Fetch all other embeddings
const otherNoteIds = otherNotes.map(n => n.id)
const otherEmbeddings: Array<{ noteId: string, embedding: any }> = await prisma.$queryRawUnsafe(
`SELECT "noteId", "embedding"::text FROM "NoteEmbedding" WHERE "noteId" IN (${otherNoteIds.map(id => `'${id}'`).join(',')})`
)
const otherEmbeddingMap = new Map(otherEmbeddings.map(e => [e.noteId, e.embedding]))
// Check if user has demo mode enabled
const settings = await prisma.userAISettings.findUnique({
where: { userId }
@@ -540,11 +560,10 @@ Explain in one brief sentence (max 15 words) why these notes are connected. Focu
// Compare target note with all other notes
for (const otherNote of otherNotes) {
if (!otherNote.noteEmbedding) continue
const otherEmbeddingStr = otherEmbeddingMap.get(otherNote.id)
if (!otherEmbeddingStr) continue
const otherEmbedding = otherNote.noteEmbedding?.embedding
? embeddingService.fromVectorString(otherNote.noteEmbedding.embedding as unknown as string)
: null
const otherEmbedding = embeddingService.fromVectorString(otherEmbeddingStr)
if (!otherEmbedding) continue
// Check if this connection was dismissed

View File

@@ -120,7 +120,8 @@
"tailwind-merge": "^3.4.0",
"tinyld": "^1.3.4",
"vazirmatn": "^33.0.3",
"zod": "^4.3.5"
"zod": "^4.3.5",
"@napi-rs/canvas": "^0.1.65"
},
"devDependencies": {
"@playwright/test": "^1.57.0",

View File

@@ -1,11 +1,12 @@
generator client {
provider = "prisma-client-js"
binaryTargets = ["debian-openssl-3.0.x", "native"]
provider = "prisma-client-js"
previewFeatures = ["debian-openssl-3.0.x", "native", "postgresqlExtensions"]
}
datasource db {
provider = "postgresql"
url = env("DATABASE_URL")
provider = "postgresql"
url = env("DATABASE_URL")
extensions = [pgvector]
}
model User {
@@ -315,8 +316,8 @@ model UserAISettings {
model NoteEmbedding {
id String @id @default(cuid())
noteId String @unique
embedding String
noteId String @unique
embedding Unsupported("vector(1536)")?
createdAt DateTime @default(now())
note Note @relation(fields: [noteId], references: [id], onDelete: Cascade)