From dd200958cd88d329fc84b615244e6752267a1ebf Mon Sep 17 00:00:00 2001 From: Krrish Dholakia Date: Thu, 23 Apr 2026 22:19:49 -0700 Subject: [PATCH] fix(ui/memory): send explicit null when user clears metadata MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Addresses the remaining P1 from the last greptile review: When the edit modal's metadata textarea was cleared and saved, `metadataParsed` stayed `undefined`, `JSON.stringify` dropped the key entirely, and the backend's `model_fields_set` guard therefore left the stored metadata untouched — UI showed success but nothing changed. Now: empty textarea on edit → send explicit `null` so the backend sees `metadata` in `model_fields_set` and clears the column. Empty textarea on create still maps to `undefined` (field omitted) to avoid Prisma's `Json? = None` quirk on insert. Co-Authored-By: Claude Opus 4.7 (1M context) --- .../src/components/MemoryView/MemoryView.tsx | 22 ++++++++++++++----- 1 file changed, 17 insertions(+), 5 deletions(-) diff --git a/ui/litellm-dashboard/src/components/MemoryView/MemoryView.tsx b/ui/litellm-dashboard/src/components/MemoryView/MemoryView.tsx index b6adcd178be..6ae3ecbfa59 100644 --- a/ui/litellm-dashboard/src/components/MemoryView/MemoryView.tsx +++ b/ui/litellm-dashboard/src/components/MemoryView/MemoryView.tsx @@ -127,27 +127,39 @@ export const MemoryView: React.FC = ({ accessToken }) => { isCreate: boolean, ): Promise => { if (!accessToken) return false; - let metadataParsed: unknown | undefined; - if (metadataText.trim()) { + + // On edit, an empty textarea is a user's intent to CLEAR existing + // metadata — we must send explicit `null` (not `undefined`), or + // JSON.stringify drops the field and the backend's model_fields_set + // won't see it, leaving the stored value untouched. + // + // On create, an empty textarea just means "no metadata" — we omit the + // field so the DB default (NULL) applies and we avoid Prisma's + // `Json? = None` quirk on create. + let metadataPayload: unknown; + if (!metadataText.trim()) { + metadataPayload = isCreate ? undefined : null; + } else { try { - metadataParsed = JSON.parse(metadataText); + metadataPayload = JSON.parse(metadataText); } catch { message.error("Metadata must be valid JSON (or leave empty)."); return false; } } + try { if (isCreate) { await createMemory(accessToken, { key, value, - metadata: metadataParsed, + metadata: metadataPayload, }); message.success(`Created ${key}`); } else { await updateMemory(accessToken, key, { value, - metadata: metadataParsed, + metadata: metadataPayload, }); message.success(`Updated ${key}`); }