feat: implement Latent Reflection (Proactive Gardening) skill

This commit is contained in:
2026-04-09 16:15:40 -04:00
parent a6eac8e84f
commit ffc2088f6d

View File

@@ -0,0 +1,103 @@
:PROPERTIES:
:ID: latent-reflection-skill
:CREATED: [2026-04-09 Thu]
:END:
#+TITLE: SKILL: Latent Reflection (Proactive Gardening)
#+STARTUP: content
#+FILETAGS: :memory:gardening:reflection:psf:
#+DEPENDS_ON: id:e8b500e2-3f26-4c8e-8558-528061e178ca
* Overview
The *Latent Reflection* skill utilizes the idle cycles of the heartbeat to proactively garden the Memex. By randomly sampling the knowledge graph, it surfaces forgotten connections and synthesizes new insights without direct user prompting. This mimics the human default mode network, fostering creativity and serendipity.
* Implementation
** Package
#+begin_src lisp :tangle ../src/latent-reflection.lisp
(in-package :org-agent)
#+end_src
** State
We maintain an interval to prevent the agent from spamming the LLM on every 60-second heartbeat.
#+begin_src lisp :tangle ../src/latent-reflection.lisp
(defvar *last-reflection-time* 0)
(defvar *reflection-interval* 14400) ;; 4 hours by default
#+end_src
** Random Sampling (sample-random-memories)
Selects N random objects from the entire `*object-store*`.
#+begin_src lisp :tangle ../src/latent-reflection.lisp
(defun sample-random-memories (count)
"Returns COUNT random objects from the object-store."
(let ((keys nil)
(selected nil))
(maphash (lambda (k v) (declare (ignore v)) (push k keys)) *object-store*)
(let ((len (length keys)))
(when (> len 0)
(dotimes (i count)
(let* ((random-key (nth (random len) keys))
(obj (gethash random-key *object-store*)))
(when obj
(push obj selected))))))
selected))
#+end_src
** Tool Registry
Allows the user to manually trigger a reflection cycle if desired.
#+begin_src lisp :tangle ../src/latent-reflection.lisp
(def-cognitive-tool :trigger-latent-reflection "Manually triggers a proactive gardening cycle."
:parameters nil
:body (lambda (args)
(declare (ignore args))
(setf *last-reflection-time* 0)
"Latent reflection triggered. Wait for the next heartbeat."))
#+end_src
** Skill Definition
Hooks into the `:heartbeat` sensor.
#+begin_src lisp :tangle ../src/latent-reflection.lisp
(defskill :skill-latent-reflection
:priority 30
:trigger (lambda (ctx)
(let* ((payload (getf ctx :payload))
(sensor (getf payload :sensor))
(now (get-universal-time)))
(if (and (eq sensor :heartbeat)
(> (- now *last-reflection-time*) *reflection-interval*))
(progn
(kernel-log "GARDENER - Initiating Latent Reflection...")
(setf *last-reflection-time* now)
t)
nil)))
:neuro (lambda (ctx)
(declare (ignore ctx))
(let* ((memories (sample-random-memories 3))
(context-string "LATENT REFLECTION CANDIDATES:\n"))
(dolist (m memories)
(let ((title (or (getf (org-object-attributes m) :TITLE) "Untitled"))
(content (or (org-object-content m) "")))
(setf context-string
(concatenate 'string context-string
(format nil "- ID: ~a | TITLE: ~a | CONTENT: ~a~%"
(org-object-id m) title content)))))
(format nil "You are the Proactive Gardener of the Memex.
I have selected 3 random notes from the knowledge graph.
Please read them and synthesize a 'Latent Reflection'.
Find hidden connections, suggest new tags, or propose a new insight that bridges them.
~a
MANDATE: Output EXACTLY ONE Common Lisp property list starting with (:type :REQUEST).
Use the :emacs target and :insert-at-end action to write your reflection into the \"*org-agent-chat*\" buffer."
context-string)))
:symbolic (lambda (action ctx)
(declare (ignore ctx))
;; Approve any safe request
action))
#+end_src