diff --git a/packages/junior-memory/src/events.ts b/packages/junior-memory/src/events.ts index 2fc437d874..5fc44ca7c2 100644 --- a/packages/junior-memory/src/events.ts +++ b/packages/junior-memory/src/events.ts @@ -3,6 +3,14 @@ import { z } from "zod"; import { MEMORY_KINDS, MEMORY_SCOPES } from "./types"; import type { MemoryRecord } from "./store"; +function currentScope( + scope: "personal" | "conversation" | "private" | "public", +): "private" | "public" { + if (scope === "personal") return "private"; + if (scope === "conversation") return "public"; + return scope; +} + const capturedMemoryFields = { content: z.string().min(1), id: z.string().min(1), @@ -20,7 +28,17 @@ const legacyCapturedMemorySchema = z const capturedMemorySchema = z .object({ ...capturedMemoryFields, - scope: z.enum(MEMORY_SCOPES), + scope: z.preprocess((val) => { + if ( + val === "personal" || + val === "conversation" || + val === "private" || + val === "public" + ) { + return currentScope(val); + } + return val; + }, z.enum(MEMORY_SCOPES)), }) .strict(); @@ -39,14 +57,6 @@ const recalledMemoriesSchema = z }) .strict(); -function currentScope( - scope: "personal" | "conversation" | "private" | "public", -) { - if (scope === "personal") return "private"; - if (scope === "conversation") return "public"; - return scope; -} - function renderCapturedMemories(event: { memories: Array< | z.output diff --git a/packages/junior-memory/tests/events.test.ts b/packages/junior-memory/tests/events.test.ts index eb91722c67..c72000d777 100644 --- a/packages/junior-memory/tests/events.test.ts +++ b/packages/junior-memory/tests/events.test.ts @@ -22,20 +22,37 @@ describe("memory conversation events", () => { memoriesCapturedEventV1.renderEvent(legacy)?.details?.[0]?.metadata, ).toEqual(["preference", "private"]); - expect(() => - memoriesCapturedEvent.parse({ - costUsd: 0.0042, - memories: [ - { - content: "Release notes live in Notion.", - id: "memory-v2", - kind: "knowledge", - observedAtMs: 2, - scope: "conversation", - }, - ], - }), - ).toThrow(/scope/); + const v2Legacy = memoriesCapturedEvent.parse({ + costUsd: 0.0042, + memories: [ + { + content: "Release notes live in Notion.", + id: "memory-v2", + kind: "knowledge", + observedAtMs: 2, + scope: "conversation", + }, + { + content: "Prefer short replies.", + id: "memory-v2-personal", + kind: "preference", + observedAtMs: 3, + scope: "personal", + }, + ], + }); + expect(v2Legacy.memories.map((memory) => memory.scope)).toEqual([ + "public", + "private", + ]); + expect( + memoriesCapturedEvent.renderEvent(v2Legacy)?.details?.map( + (detail) => detail.metadata, + ), + ).toEqual([ + ["knowledge", "public"], + ["preference", "private"], + ]); }); it("omits empty extraction results from transcript presentation", () => {