feat: implement Foveal-Peripheral vision model and Org renderer

This commit is contained in:
2026-04-09 14:31:00 -04:00
parent 71401e606a
commit 13d660c3e9
6 changed files with 147 additions and 39 deletions

View File

@@ -80,7 +80,7 @@ Reads the raw literate source of a specific skill. This is crucial for "System 2
#+end_src #+end_src
** Kernel Logs (context-get-system-logs) ** Kernel Logs (context-get-system-logs)
Retrieves the most recent system logs, providing temporal context to the LLM. Retrieves the most recent lines from the kernel's internal log.
#+begin_src lisp :tangle ../src/context.lisp #+begin_src lisp :tangle ../src/context.lisp
(defun context-get-system-logs (&optional (limit 20)) (defun context-get-system-logs (&optional (limit 20))
@@ -98,19 +98,33 @@ Provides execution stats for a specific skill.
(bt:with-lock-held (*telemetry-lock*) (gethash (string-downcase skill-name) *skill-telemetry*))) (bt:with-lock-held (*telemetry-lock*) (gethash (string-downcase skill-name) *skill-telemetry*)))
#+end_src #+end_src
** Sparse Trees (context-filter-sparse-tree) ** AST to Org Rendering (context-render-to-org)
Prunes the Org AST to show only specific nodes and their ancestors, creating a "skeleton" view that fits within LLM context limits. Transforms the internal Object Store structures back into a human-readable (and LLM-readable) Org-mode string. It supports depth-based indentation and content suppression for peripheral nodes.
#+begin_src lisp :tangle ../src/context.lisp #+begin_src lisp :tangle ../src/context.lisp
(defun context-filter-sparse-tree (ast predicate) (defun context-render-to-org (obj &key (depth 1) (foveal-id nil))
"Prunes an AST to show only nodes matching a predicate and their ancestors." "Recursively renders an org-object and its children to an Org string."
(if (listp ast) (let* ((is-foveal (equal (org-object-id obj) foveal-id))
(let* ((contents (getf ast :contents)) (title (or (getf (org-object-attributes obj) :TITLE) "Untitled"))
(filtered-contents (remove-if #'null (mapcar (lambda (c) (context-filter-sparse-tree c predicate)) contents)))) (id (org-object-id obj))
(if (or (funcall predicate ast) (not (null filtered-contents))) (content (org-object-content obj))
(let ((new-ast (copy-list ast))) (setf (getf new-ast :contents) filtered-contents) new-ast) (children (org-object-children obj))
nil)) (stars (make-string depth :initial-element #\*))
nil)) (output (format nil "~a ~a~%:PROPERTIES:~%:ID: ~a~%:END:~%" stars title id)))
;; Only include content if this is the foveal focus
(when (and is-foveal content)
(setf output (concatenate 'string output content (string #\Newline))))
;; Recursively render children
(dolist (child-id children)
(let ((child-obj (lookup-object child-id)))
(when child-obj
(setf output (concatenate 'string output
(context-render-to-org child-obj
:depth (1+ depth)
:foveal-id foveal-id))))))
output))
#+end_src #+end_src
** Path Resolution (context-resolve-path) ** Path Resolution (context-resolve-path)
@@ -130,20 +144,20 @@ Expands environment variables (like `$HOME`) within path strings.
#+end_src #+end_src
** Global Awareness (context-assemble-global-awareness) ** Global Awareness (context-assemble-global-awareness)
The primary "peripheral vision" generator. It produces the skeletal overview of the Memex that is prepended to LLM prompts. The primary context generator. It identifies active projects and the current foveal focus, then assembles a pruned Org-mode view of the Memex.
#+begin_src lisp :tangle ../src/context.lisp #+begin_src lisp :tangle ../src/context.lisp
(defun context-assemble-global-awareness () (defun context-assemble-global-awareness (&optional signal)
"Produces a high-level skeletal outline of the current Object Store for the LLM." "Produces a high-level skeletal outline of the current Object Store for the LLM."
(let ((projects (context-get-active-projects)) (let* ((payload (when signal (getf signal :payload)))
(output "GLOBAL MEMEX AWARENESS (Peripheral Vision): (foveal-id (when payload (getf payload :target-id)))
(projects (context-get-active-projects))
(output "GLOBAL MEMEX AWARENESS (Peripheral Vision):
")) "))
(if projects (if projects
(dolist (project projects) (dolist (project projects)
(setf output (concatenate 'string output (setf output (concatenate 'string output
(format nil "- PROJECT: ~a (ID: ~a)~%" (context-render-to-org project :foveal-id foveal-id))))
(getf (org-object-attributes project) :TITLE)
(org-object-id project)))))
(setf output (concatenate 'string output "No active projects found.~%"))) (setf output (concatenate 'string output "No active projects found.~%")))
output)) output))
#+end_src #+end_src
@@ -205,3 +219,41 @@ Identifies the top-k most semantically related objects in the entire store by co
(maphash (lambda (id obj) (let ((vec (org-object-vector obj))) (when vec (push (cons (cosine-similarity query-vector vec) obj) similarities)))) *object-store*) (maphash (lambda (id obj) (let ((vec (org-object-vector obj))) (when vec (push (cons (cosine-similarity query-vector vec) obj) similarities)))) *object-store*)
(let ((sorted (sort similarities #'> :key #'car))) (subseq sorted 0 (min top-k (length sorted)))))) (let ((sorted (sort similarities #'> :key #'car))) (subseq sorted 0 (min top-k (length sorted))))))
#+end_src #+end_src
* Phase E: Chaos (Verification)
Verification of the peripheral vision extraction and rendering logic.
#+begin_src lisp :tangle ../tests/peripheral-vision-tests.lisp
(defpackage :org-agent-peripheral-vision-tests
(:use :cl :fiveam :org-agent))
(in-package :org-agent-peripheral-vision-tests)
(def-suite vision-suite
:description "Verification of Foveal-Peripheral context model.")
(in-suite vision-suite)
(test test-foveal-rendering
"Verify that the foveal target is rendered with content, while siblings are skeletal."
(clrhash org-agent::*object-store*)
(let* ((ast '(:type :HEADLINE :properties (:ID "proj-root" :TITLE "Project" :TAGS "project")
:contents ((:type :HEADLINE :properties (:ID "node-foveal" :TITLE "Foveal Node")
:raw-content "FOVEAL CONTENT" :contents nil)
(:type :HEADLINE :properties (:ID "node-peripheral" :TITLE "Peripheral Node")
:raw-content "PERIPHERAL CONTENT" :contents nil)))))
(ingest-ast ast)
(let ((output (context-assemble-global-awareness (list :payload (list :target-id "node-foveal")))))
;; Foveal node should have its content
(is (search "FOVEAL CONTENT" output))
;; Peripheral node should be skeletal (only title/ID)
(is (search "* Peripheral Node" output))
(is (not (search "PERIPHERAL CONTENT" output))))))
(test test-awareness-budget
"Verify that context-assemble-global-awareness handles multiple projects."
(clrhash org-agent::*object-store*)
(ingest-ast '(:type :HEADLINE :properties (:ID "p1" :TITLE "Project 1" :TAGS "project") :contents nil))
(ingest-ast '(:type :HEADLINE :properties (:ID "p2" :TITLE "Project 2" :TAGS "project") :contents nil))
(let ((output (context-assemble-global-awareness)))
(is (search "Project 1" output))
(is (search "Project 2" output))))
#+end_src

View File

@@ -33,6 +33,7 @@
:components ((:module "tests" :components ((:module "tests"
:components ((:file "oacp-tests") :components ((:file "oacp-tests")
(:file "pipeline-tests") (:file "pipeline-tests")
(:file "peripheral-vision-tests")
(:file "boot-sequence-tests") (:file "boot-sequence-tests")
(:file "object-store-tests") (:file "object-store-tests")
(:file "immune-system-tests") (:file "immune-system-tests")
@@ -40,6 +41,7 @@
:perform (test-op (o s) :perform (test-op (o s)
(uiop:symbol-call :fiveam :run! (uiop:find-symbol* :oacp-suite :org-agent-tests)) (uiop:symbol-call :fiveam :run! (uiop:find-symbol* :oacp-suite :org-agent-tests))
(uiop:symbol-call :fiveam :run! (uiop:find-symbol* :pipeline-suite :org-agent-pipeline-tests)) (uiop:symbol-call :fiveam :run! (uiop:find-symbol* :pipeline-suite :org-agent-pipeline-tests))
(uiop:symbol-call :fiveam :run! (uiop:find-symbol* :vision-suite :org-agent-peripheral-vision-tests))
(uiop:symbol-call :fiveam :run! (uiop:find-symbol* :boot-suite :org-agent-boot-tests)) (uiop:symbol-call :fiveam :run! (uiop:find-symbol* :boot-suite :org-agent-boot-tests))
(uiop:symbol-call :fiveam :run! (uiop:find-symbol* :object-store-suite :org-agent-object-store-tests)) (uiop:symbol-call :fiveam :run! (uiop:find-symbol* :object-store-suite :org-agent-object-store-tests))
(uiop:symbol-call :fiveam :run! (uiop:find-symbol* :immune-suite :org-agent-immune-system-tests)) (uiop:symbol-call :fiveam :run! (uiop:find-symbol* :immune-suite :org-agent-immune-system-tests))

View File

@@ -26,6 +26,7 @@
:components ((:module "tests" :components ((:module "tests"
:components ((:file "oacp-tests") :components ((:file "oacp-tests")
(:file "pipeline-tests") (:file "pipeline-tests")
(:file "peripheral-vision-tests")
(:file "boot-sequence-tests") (:file "boot-sequence-tests")
(:file "object-store-tests") (:file "object-store-tests")
(:file "immune-system-tests") (:file "immune-system-tests")
@@ -33,6 +34,7 @@
:perform (test-op (o s) :perform (test-op (o s)
(uiop:symbol-call :fiveam :run! (uiop:find-symbol* :oacp-suite :org-agent-tests)) (uiop:symbol-call :fiveam :run! (uiop:find-symbol* :oacp-suite :org-agent-tests))
(uiop:symbol-call :fiveam :run! (uiop:find-symbol* :pipeline-suite :org-agent-pipeline-tests)) (uiop:symbol-call :fiveam :run! (uiop:find-symbol* :pipeline-suite :org-agent-pipeline-tests))
(uiop:symbol-call :fiveam :run! (uiop:find-symbol* :vision-suite :org-agent-peripheral-vision-tests))
(uiop:symbol-call :fiveam :run! (uiop:find-symbol* :boot-suite :org-agent-boot-tests)) (uiop:symbol-call :fiveam :run! (uiop:find-symbol* :boot-suite :org-agent-boot-tests))
(uiop:symbol-call :fiveam :run! (uiop:find-symbol* :object-store-suite :org-agent-object-store-tests)) (uiop:symbol-call :fiveam :run! (uiop:find-symbol* :object-store-suite :org-agent-object-store-tests))
(uiop:symbol-call :fiveam :run! (uiop:find-symbol* :immune-suite :org-agent-immune-system-tests)) (uiop:symbol-call :fiveam :run! (uiop:find-symbol* :immune-suite :org-agent-immune-system-tests))

View File

@@ -18,9 +18,11 @@
(remove-if (lambda (obj) (equal (getf (org-object-attributes obj) :TODO-STATE) "DONE")) (remove-if (lambda (obj) (equal (getf (org-object-attributes obj) :TODO-STATE) "DONE"))
(context-query-store :tag "project" :type :HEADLINE))) (context-query-store :tag "project" :type :HEADLINE)))
(defun context-get-recent-completed-tasks () (context-query-store :todo-state "DONE" :type :HEADLINE)) (defun context-get-recent-completed-tasks ()
"Retrieves recently finished tasks from the store." "Retrieves recently finished tasks from the store."
(defun context-list-all-skills () (context-query-store :todo-state "DONE" :type :HEADLINE))
(defun context-list-all-skills ()
"Provides a sorted overview of currently loaded system capabilities." "Provides a sorted overview of currently loaded system capabilities."
(let ((results nil)) (let ((results nil))
(maphash (lambda (name skill) (maphash (lambda (name skill)
@@ -45,15 +47,29 @@
"Returns performance and execution data for a specific skill." "Returns performance and execution data for a specific skill."
(bt:with-lock-held (*telemetry-lock*) (gethash (string-downcase skill-name) *skill-telemetry*))) (bt:with-lock-held (*telemetry-lock*) (gethash (string-downcase skill-name) *skill-telemetry*)))
(defun context-filter-sparse-tree (ast predicate) (defun context-render-to-org (obj &key (depth 1) (foveal-id nil))
"Prunes an AST to show only nodes matching a predicate and their ancestors." "Recursively renders an org-object and its children to an Org string."
(if (listp ast) (let* ((is-foveal (equal (org-object-id obj) foveal-id))
(let* ((contents (getf ast :contents)) (title (or (getf (org-object-attributes obj) :TITLE) "Untitled"))
(filtered-contents (remove-if #'null (mapcar (lambda (c) (context-filter-sparse-tree c predicate)) contents)))) (id (org-object-id obj))
(if (or (funcall predicate ast) (not (null filtered-contents))) (content (org-object-content obj))
(let ((new-ast (copy-list ast))) (setf (getf new-ast :contents) filtered-contents) new-ast) (children (org-object-children obj))
nil)) (stars (make-string depth :initial-element #\*))
nil)) (output (format nil "~a ~a~%:PROPERTIES:~%:ID: ~a~%:END:~%" stars title id)))
;; Only include content if this is the foveal focus
(when (and is-foveal content)
(setf output (concatenate 'string output content (string #\Newline))))
;; Recursively render children
(dolist (child-id children)
(let ((child-obj (lookup-object child-id)))
(when child-obj
(setf output (concatenate 'string output
(context-render-to-org child-obj
:depth (1+ depth)
:foveal-id foveal-id))))))
output))
(defun context-resolve-path (path-string) (defun context-resolve-path (path-string)
"Expands environment variables within path strings (e.g. $HOME/...)." "Expands environment variables within path strings (e.g. $HOME/...)."
@@ -66,16 +82,16 @@
path-string)) path-string))
path-string)) path-string))
(defun context-assemble-global-awareness () (defun context-assemble-global-awareness (&optional signal)
"Produces a high-level skeletal outline of the current Object Store for the LLM." "Produces a high-level skeletal outline of the current Object Store for the LLM."
(let ((projects (context-get-active-projects)) (let* ((payload (when signal (getf signal :payload)))
(output "GLOBAL MEMEX AWARENESS (Peripheral Vision): (foveal-id (when payload (getf payload :target-id)))
(projects (context-get-active-projects))
(output "GLOBAL MEMEX AWARENESS (Peripheral Vision):
")) "))
(if projects (if projects
(dolist (project projects) (dolist (project projects)
(setf output (concatenate 'string output (setf output (concatenate 'string output
(format nil "- PROJECT: ~a (ID: ~a)~%" (context-render-to-org project :foveal-id foveal-id))))
(getf (org-object-attributes project) :TITLE)
(org-object-id project)))))
(setf output (concatenate 'string output "No active projects found.~%"))) (setf output (concatenate 'string output "No active projects found.~%")))
output)) output))

View File

@@ -12,11 +12,15 @@
(cdr (assoc :values (cdr (assoc :embedding json))))) (cdr (assoc :values (cdr (assoc :embedding json)))))
(error (c) (kernel-log "EMBEDDING FAILURE: ~a" c) nil))))) (error (c) (kernel-log "EMBEDDING FAILURE: ~a" c) nil)))))
(defun dot-product (v1 v2) (reduce #'+ (mapcar #'* v1 v2))) (defun dot-product (v1 v2)
"Calculates the dot product of two numerical vectors." "Calculates the dot product of two numerical vectors."
(defun magnitude (v) (sqrt (reduce #'+ (mapcar (lambda (x) (* x x)) v)))) (reduce #'+ (mapcar #'* v1 v2)))
(defun magnitude (v)
"Calculates the Euclidean magnitude of a numerical vector." "Calculates the Euclidean magnitude of a numerical vector."
(defun cosine-similarity (v1 v2) (sqrt (reduce #'+ (mapcar (lambda (x) (* x x)) v))))
(defun cosine-similarity (v1 v2)
"Calculates the semantic distance between two vectors." "Calculates the semantic distance between two vectors."
(let ((m1 (magnitude v1)) (m2 (magnitude v2))) (if (or (zerop m1) (zerop m2)) 0 (/ (dot-product v1 v2) (* m1 m2))))) (let ((m1 (magnitude v1)) (m2 (magnitude v2))) (if (or (zerop m1) (zerop m2)) 0 (/ (dot-product v1 v2) (* m1 m2)))))

View File

@@ -0,0 +1,32 @@
(defpackage :org-agent-peripheral-vision-tests
(:use :cl :fiveam :org-agent))
(in-package :org-agent-peripheral-vision-tests)
(def-suite vision-suite
:description "Verification of Foveal-Peripheral context model.")
(in-suite vision-suite)
(test test-foveal-rendering
"Verify that the foveal target is rendered with content, while siblings are skeletal."
(clrhash org-agent::*object-store*)
(let* ((ast '(:type :HEADLINE :properties (:ID "proj-root" :TITLE "Project" :TAGS "project")
:contents ((:type :HEADLINE :properties (:ID "node-foveal" :TITLE "Foveal Node")
:raw-content "FOVEAL CONTENT" :contents nil)
(:type :HEADLINE :properties (:ID "node-peripheral" :TITLE "Peripheral Node")
:raw-content "PERIPHERAL CONTENT" :contents nil)))))
(ingest-ast ast)
(let ((output (context-assemble-global-awareness (list :payload (list :target-id "node-foveal")))))
;; Foveal node should have its content
(is (search "FOVEAL CONTENT" output))
;; Peripheral node should be skeletal (only title/ID)
(is (search "* Peripheral Node" output))
(is (not (search "PERIPHERAL CONTENT" output))))))
(test test-awareness-budget
"Verify that context-assemble-global-awareness handles multiple projects."
(clrhash org-agent::*object-store*)
(ingest-ast '(:type :HEADLINE :properties (:ID "p1" :TITLE "Project 1" :TAGS "project") :contents nil))
(ingest-ast '(:type :HEADLINE :properties (:ID "p2" :TITLE "Project 2" :TAGS "project") :contents nil))
(let ((output (context-assemble-global-awareness)))
(is (search "Project 1" output))
(is (search "Project 2" output))))