(sdk: ISdk, kv: StateKV)
| 16 | } |
| 17 | |
| 18 | export function registerLessonsFunctions(sdk: ISdk, kv: StateKV): void { |
| 19 | sdk.registerFunction("mem::lesson-save", |
| 20 | async (data: { |
| 21 | content: string; |
| 22 | context?: string; |
| 23 | confidence?: number; |
| 24 | project?: string; |
| 25 | tags?: string[]; |
| 26 | source?: "crystal" | "manual" | "consolidation"; |
| 27 | sourceIds?: string[]; |
| 28 | }) => { |
| 29 | if (!data.content?.trim()) { |
| 30 | return { success: false, error: "content is required" }; |
| 31 | } |
| 32 | |
| 33 | const fp = fingerprintId("lsn", data.content.trim().toLowerCase()); |
| 34 | const existing = await kv.get<Lesson>(KV.lessons, fp); |
| 35 | |
| 36 | if (existing && !existing.deleted) { |
| 37 | reinforceLesson(existing); |
| 38 | if (data.context && !existing.context) { |
| 39 | existing.context = data.context; |
| 40 | } |
| 41 | await kv.set(KV.lessons, existing.id, existing); |
| 42 | |
| 43 | try { |
| 44 | await recordAudit(kv, "lesson_strengthen", "mem::lesson-save", [ |
| 45 | existing.id, |
| 46 | ]); |
| 47 | } catch {} |
| 48 | |
| 49 | return { |
| 50 | success: true, |
| 51 | action: "strengthened", |
| 52 | lesson: existing, |
| 53 | }; |
| 54 | } |
| 55 | |
| 56 | const confidence = |
| 57 | typeof data.confidence === "number" && |
| 58 | data.confidence >= 0 && |
| 59 | data.confidence <= 1 |
| 60 | ? data.confidence |
| 61 | : 0.5; |
| 62 | |
| 63 | const now = new Date().toISOString(); |
| 64 | const lesson: Lesson = { |
| 65 | id: fp, |
| 66 | content: data.content.trim(), |
| 67 | context: data.context?.trim() || "", |
| 68 | confidence, |
| 69 | reinforcements: 0, |
| 70 | source: data.source || "manual", |
| 71 | sourceIds: data.sourceIds || [], |
| 72 | project: data.project, |
| 73 | tags: data.tags || [], |
| 74 | createdAt: now, |
| 75 | updatedAt: now, |
no test coverage detected