From 586847bd0234d81c48c7bde53cc627cd0db0c5b3 Mon Sep 17 00:00:00 2001 From: Amr Gharbeia Date: Wed, 22 Apr 2026 15:26:39 -0400 Subject: [PATCH] fix: Implement COSINE-SIMILARITY and fix memory persistence serialization - Replace stub COSINE-SIMILARITY with real dot-product implementation - Fix memory persistence to convert hash tables to alists before serialization --- harness/memory.org | 30 +++++++++++++++++++++--------- harness/skills.org | 20 +++++++++++++++++++- library/memory.lisp | 30 +++++++++++++++++++++--------- library/skills.lisp | 20 +++++++++++++++++++- 4 files changed, 80 insertions(+), 20 deletions(-) diff --git a/harness/memory.org b/harness/memory.org index c1cf9ec..470811c 100644 --- a/harness/memory.org +++ b/harness/memory.org @@ -164,29 +164,41 @@ Essential for surviving crashes. Saves the in-memory hash tables to disk and loa (uiop:merge-pathnames* "memory.snap" (user-homedir-pathname))))))) (defun save-memory-to-disk () - "Serializes *memory* and *history-store* to disk for crash recovery." + "Serializes *memory* and *history-store* to disk for crash recovery. +Converts hash tables to alists for proper serialization." (let ((path (ensure-memory-snapshot-path))) (with-open-file (stream path :direction :output :if-exists :supersede :if-does-not-exist :create) (format stream ";; OpenCortex Memory Snapshot~%") (format stream ";; Created: ~a~%~%" (format nil "~a" (get-universal-time))) - (prin1 (list :memory *memory* :history-store *history-store*) stream)) + (let ((memory-alist nil) + (history-alist nil)) + (maphash (lambda (k v) (push (cons k v) memory-alist)) *memory*) + (maphash (lambda (k v) (push (cons k v) history-alist)) *history-store*) + (prin1 (list :memory memory-alist :history-store history-alist) stream))) (harness-log "MEMORY - Saved to ~a" path) path)) (defun load-memory-from-disk () - "Loads *memory* and *history-store* from disk if the snapshot exists." + "Loads *memory* and *history-store* from disk if the snapshot exists. +Reconstitutes alists into hash tables." (let ((path (ensure-memory-snapshot-path))) (when (uiop:file-exists-p path) (handler-case (with-open-file (stream path :direction :input) (let ((data (read stream nil))) (when data - (setf *memory* (getf data :memory)) - (setf *history-store* (getf data :history-store)) - (harness-log "MEMORY - Loaded from ~a (~a objects)" path (hash-table-size *memory*))))) - (error (c) - (harness-log "MEMORY WARNING - Failed to load snapshot: ~a" c)))) - t)) + (let ((memory-alist (getf data :memory)) + (history-alist (getf data :history-store))) + (setf *memory* (make-hash-table :test 'equal :size (length memory-alist))) + (dolist (kv memory-alist) + (setf (gethash (car kv) *memory*) (cdr kv))) + (setf *history-store* (make-hash-table :test 'equal :size (length history-alist))) + (dolist (kv history-alist) + (setf (gethash (car kv) *history-store*) (cdr kv))) + (harness-log "MEMORY - Loaded from ~a (~a objects)" path (hash-table-size *memory*)))))) + (error (c) + (harness-log "MEMORY WARNING - Failed to load snapshot: ~a" c)))) + t)) #+end_src ** Lookup Utilities diff --git a/harness/skills.org b/harness/skills.org index 9a5dd28..8f7af42 100644 --- a/harness/skills.org +++ b/harness/skills.org @@ -13,7 +13,25 @@ A static, hardcoded architecture is inherently fragile. The ~opencortex~ Skill E #+begin_src lisp :tangle ../library/skills.lisp (in-package :opencortex) -(defun COSINE-SIMILARITY (v1 v2) 1.0) ; Stub +(defun COSINE-SIMILARITY (v1 v2) + "Computes the cosine similarity between two vectors. +Both arguments should be sequences of numbers. Returns a value between -1.0 and 1.0." + (let ((len1 (length v1)) (len2 (length v2))) + (if (or (zerop len1) (zerop len2)) + 0.0 + (let ((dot-product 0.0d0) + (norm1 0.0d0) + (norm2 0.0d0)) + (let ((len (min len1 len2))) + (dotimes (i len) + (let ((x (coerce (elt v1 i) 'double-float))) + (let ((y (coerce (elt v2 i) 'double-float))) + (incf dot-product (* x y)) + (incf norm1 (* x x)) + (incf norm2 (* y y)))))) + (if (or (zerop norm1) (zerop norm2)) + 0.0 + (/ dot-product (sqrt (* norm1 norm2)))))))) (defun VAULT-MASK-STRING (s) "[MASKED]") ; Stub (defvar *VAULT-MEMORY* (make-hash-table :test 'equal)) diff --git a/library/memory.lisp b/library/memory.lisp index d48b10d..1724c00 100644 --- a/library/memory.lisp +++ b/library/memory.lisp @@ -91,29 +91,41 @@ (uiop:merge-pathnames* "memory.snap" (user-homedir-pathname))))))) (defun save-memory-to-disk () - "Serializes *memory* and *history-store* to disk for crash recovery." + "Serializes *memory* and *history-store* to disk for crash recovery. +Converts hash tables to alists for proper serialization." (let ((path (ensure-memory-snapshot-path))) (with-open-file (stream path :direction :output :if-exists :supersede :if-does-not-exist :create) (format stream ";; OpenCortex Memory Snapshot~%") (format stream ";; Created: ~a~%~%" (format nil "~a" (get-universal-time))) - (prin1 (list :memory *memory* :history-store *history-store*) stream)) + (let ((memory-alist nil) + (history-alist nil)) + (maphash (lambda (k v) (push (cons k v) memory-alist)) *memory*) + (maphash (lambda (k v) (push (cons k v) history-alist)) *history-store*) + (prin1 (list :memory memory-alist :history-store history-alist) stream))) (harness-log "MEMORY - Saved to ~a" path) path)) (defun load-memory-from-disk () - "Loads *memory* and *history-store* from disk if the snapshot exists." + "Loads *memory* and *history-store* from disk if the snapshot exists. +Reconstitutes alists into hash tables." (let ((path (ensure-memory-snapshot-path))) (when (uiop:file-exists-p path) (handler-case (with-open-file (stream path :direction :input) (let ((data (read stream nil))) (when data - (setf *memory* (getf data :memory)) - (setf *history-store* (getf data :history-store)) - (harness-log "MEMORY - Loaded from ~a (~a objects)" path (hash-table-size *memory*))))) - (error (c) - (harness-log "MEMORY WARNING - Failed to load snapshot: ~a" c)))) - t)) + (let ((memory-alist (getf data :memory)) + (history-alist (getf data :history-store))) + (setf *memory* (make-hash-table :test 'equal :size (length memory-alist))) + (dolist (kv memory-alist) + (setf (gethash (car kv) *memory*) (cdr kv))) + (setf *history-store* (make-hash-table :test 'equal :size (length history-alist))) + (dolist (kv history-alist) + (setf (gethash (car kv) *history-store*) (cdr kv))) + (harness-log "MEMORY - Loaded from ~a (~a objects)" path (hash-table-size *memory*)))))) + (error (c) + (harness-log "MEMORY WARNING - Failed to load snapshot: ~a" c)))) + t)) (defun org-id-new () "Generates a new UUID string for Org-mode identification." diff --git a/library/skills.lisp b/library/skills.lisp index eafadc0..3738d58 100644 --- a/library/skills.lisp +++ b/library/skills.lisp @@ -1,6 +1,24 @@ (in-package :opencortex) -(defun COSINE-SIMILARITY (v1 v2) 1.0) ; Stub +(defun COSINE-SIMILARITY (v1 v2) + "Computes the cosine similarity between two vectors. +Both arguments should be sequences of numbers. Returns a value between -1.0 and 1.0." + (let ((len1 (length v1)) (len2 (length v2))) + (if (or (zerop len1) (zerop len2)) + 0.0 + (let ((dot-product 0.0d0) + (norm1 0.0d0) + (norm2 0.0d0)) + (let ((len (min len1 len2))) + (dotimes (i len) + (let ((x (coerce (elt v1 i) 'double-float))) + (let ((y (coerce (elt v2 i) 'double-float))) + (incf dot-product (* x y)) + (incf norm1 (* x x)) + (incf norm2 (* y y)))))) + (if (or (zerop norm1) (zerop norm2)) + 0.0 + (/ dot-product (sqrt (* norm1 norm2)))))))) (defun VAULT-MASK-STRING (s) "[MASKED]") ; Stub (defvar *VAULT-MEMORY* (make-hash-table :test 'equal))