fix(perceive): complete reconstruction of perceive.org to resolve catastrophic syntax failures

This commit is contained in:
2026-04-28 19:14:49 -04:00
parent fa44b2a58e
commit 9f71f7c391

View File

@@ -1,4 +1,3 @@
#+PROPERTY: header-args:lisp :tangle perceive.lisp
#+TITLE: Stage 1: Perceive (perceive.lisp) #+TITLE: Stage 1: Perceive (perceive.lisp)
#+AUTHOR: Agent #+AUTHOR: Agent
#+FILETAGS: :harness:perceive: #+FILETAGS: :harness:perceive:
@@ -18,57 +17,25 @@ The Perceive stage is the "sensory cortex" of OpenCortex. Its job is to take raw
** Sensor Configuration ** Sensor Configuration
#+begin_src lisp #+begin_src lisp
(defvar *async-sensors* '(:chat-message :delegation :user-command) (defvar *async-sensors* '(:chat-message :delegation :user-command)
"Sensors that are processed in dedicated threads. "Sensors that are processed in dedicated threads.")
These sensors can block (waiting for API responses, user input, etc.)
so they run in separate threads to avoid blocking the main pipeline.
Other sensors (:heartbeat, :interrupt, :buffer-update) are processed
synchronously to maintain temporal ordering.")
(defvar *foveal-focus-id* nil (defvar *foveal-focus-id* nil
"The Org ID of the node the user is currently interacting with. "The Org ID of the node the user is currently interacting with.")
This enables the reasoning engine to provide contextually relevant
responses. When editing a specific note, the agent knows which
note you're referring to without needing explicit ID references.
Updated on :point-update events from Emacs.")
This enables the reasoning engine to provide contextually relevant
responses. When editing a specific note, the agent knows which
note you're referring to without needing explicit ID references.
Updated on :point-update events from Emacs.
#+end_src #+end_src
** Stimulus Injection (inject-stimulus) ** Stimulus Injection (inject-stimulus)
#+begin_src lisp #+begin_src lisp
(defun inject-stimulus (raw-message &key stream (depth 0)) (defun inject-stimulus (raw-message &key stream (depth 0))
"Inject a raw message into the signal processing pipeline. "Inject a raw message into the signal processing pipeline."
RAW-MESSAGE is a property list that will be normalized into a Signal.
STREAM is an optional output stream for responses (used by TUI/CLI).
DEPTH tracks recursion depth for feedback loops.
This function determines whether to process synchronously or
asynchronously based on the sensor type, then calls process-signal
to run through the Perceive -> Reason -> Act pipeline.
Error handling: Uses restarts to prevent individual signals from
crashing the entire system. Failed signals are logged and dropped."
(let* ((payload (getf raw-message :payload)) (let* ((payload (getf raw-message :payload))
(sensor (getf payload :sensor)) (sensor (getf payload :sensor))
(meta (getf raw-message :meta)) (meta (getf raw-message :meta))
(async-p (or (getf payload :async-p) (async-p (or (getf payload :async-p)
(member sensor *async-sensors*)))) (member sensor *async-sensors*))))
;; Ensure metadata exists
(unless meta (unless meta
(setf meta (list :SOURCE :SYSTEM :SESSION-ID "internal"))) (setf meta (list :SOURCE :SYSTEM :SESSION-ID "internal")))
;; Attach reply stream if provided
(when stream (when stream
(setf (getf meta :reply-stream) stream)) (setf (getf meta :reply-stream) stream))
@@ -76,77 +43,51 @@ The Perceive stage is the "sensory cortex" of OpenCortex. Its job is to take raw
(setf (getf raw-message :depth) depth) (setf (getf raw-message :depth) depth)
(if async-p (if async-p
;; Async: process in dedicated thread
(bt:make-thread (bt:make-thread
(lambda () (lambda ()
(restart-case (process-signal raw-message) (restart-case (process-signal raw-message)
(skip-event () nil))) (skip-event () nil)))
:name "opencortex-async-task :name "opencortex-async-task")
;; Sync: process in main thread with recovery
(restart-case (restart-case
(handler-bind ((error (lambda (c) (handler-bind ((error (lambda (c)
(harness-log "SYSTEM ERROR: ~a" c) (harness-log "SYSTEM ERROR: ~a" c)
(invoke-restart 'skip-event)))) (invoke-restart 'skip-event))))
(process-signal raw-message)) (process-signal raw-message))
(skip-event () (skip-event ()
(harness-log "SYSTEM RECOVERY: Stimulus dropped.))))) (harness-log "SYSTEM RECOVERY: Stimulus dropped."))))))
#+end_src #+end_src
** Perceive Gate (perceive-gate) ** Perceive Gate (perceive-gate)
#+begin_src lisp #+begin_src lisp
(defun perceive-gate (signal) (defun perceive-gate (signal)
"Stage 1 of the metabolic pipeline: Normalize sensory input. "Stage 1 of the metabolic pipeline: Normalize sensory input."
This function:
1. Logs the incoming signal for debugging
2. Handles special sensor types (:buffer-update, :point-update, etc.)
3. Updates the Memory graph with incoming data
4. Tracks foveal focus (user's current node)
5. Sets :status to :perceived
Modifies the signal in place and returns it for the next stage."
(let* ((payload (getf signal :payload)) (let* ((payload (getf signal :payload))
(type (getf signal :type)) (type (getf signal :type))
(meta (getf signal :meta)) (meta (getf signal :meta))
(sensor (getf payload :sensor))) (sensor (getf payload :sensor)))
;; Log the incoming signal for debugging
(harness-log "GATE [Perceive]: ~a (~a) [Source: ~s]" (harness-log "GATE [Perceive]: ~a (~a) [Source: ~s]"
type (or sensor "no-sensor (getf meta :source)) type (or sensor "no-sensor") (getf meta :source))
;; Handle EVENT type sensors
(cond ((eq type :EVENT) (cond ((eq type :EVENT)
(case sensor (case sensor
;; Org buffer was modified - update memory
(:buffer-update (:buffer-update
(let ((ast (getf payload :ast))) (let ((ast (getf payload :ast)))
(when ast (when ast
(snapshot-memory) (snapshot-memory)
(ingest-ast ast)))) (ingest-ast ast))))
;; Point moved to different org node - update focus
(:point-update (:point-update
(let ((element (getf payload :element))) (let ((element (getf payload :element)))
(when element (when element
(snapshot-memory) (snapshot-memory)
;; Track foveal focus for contextual reasoning (setf *foveal-focus-id* (getf element :id))
(setf *foveal-focus-id*
(ignore-errors (getf element :id)))
(ingest-ast element)))) (ingest-ast element))))
;; System interrupt - trigger shutdown
(:interrupt (:interrupt
(setf *interrupt-flag* t)))) (setf *interrupt-flag* t))))
;; Log responses from actuators
((eq type :RESPONSE) ((eq type :RESPONSE)
(harness-log "GATE [Perceive]: Act Result -> ~a" (harness-log "GATE [Perceive]: Act Result -> ~a" (getf payload :status))))
(getf payload :status))))
;; Update signal status
(setf (getf signal :status) :perceived) (setf (getf signal :status) :perceived)
(setf (getf signal :foveal-focus) *foveal-focus-id*) (setf (getf signal :foveal-focus) *foveal-focus-id*)
signal)) signal))
@@ -154,26 +95,27 @@ The Perceive stage is the "sensory cortex" of OpenCortex. Its job is to take raw
* Test Suite * Test Suite
#+begin_src lisp :tangle perceive.lisp #+begin_src lisp :tangle tests/pipeline-perceive-tests.lisp
(eval-when (:compile-toplevel :load-toplevel :execute)
(ql:quickload :fiveam :silent t))
(defpackage :opencortex-pipeline-perceive-tests (defpackage :opencortex-pipeline-perceive-tests
(:use :cl :fiveam :opencortex) (:use :cl :fiveam :opencortex)
(:export #:pipeline-perceive-suite)) (:export #:pipeline-perceive-suite))
(in-package :opencortex-pipeline-perceive-tests) (in-package :opencortex-pipeline-perceive-tests)
(def-suite pipeline-perceive-suite :description "Test suite for Perceive pipeline (def-suite pipeline-perceive-suite :description "Test suite for Perceive pipeline")
(in-suite pipeline-perceive-suite) (in-suite pipeline-perceive-suite)
(test test-perceive-gate (test test-perceive-gate
"Perceive gate should update the object store and normalize signal."
(clrhash opencortex::*memory*) (clrhash opencortex::*memory*)
(let* ((signal (list :type :EVENT :payload (list :sensor :buffer-update :ast (list :type :HEADLINE :properties (list :ID "test-node" :TITLE "Test :contents nil)))) (let* ((signal (list :type :EVENT :payload (list :sensor :buffer-update :ast (list :type :HEADLINE :properties (list :ID "test-node" :TITLE "Test") :contents nil))))
(result (perceive-gate signal))) (result (perceive-gate signal)))
(is (eq :perceived (getf result :status))) (is (eq :perceived (getf result :status)))
(is (not (null (gethash "test-node" opencortex::*memory*)))))) (is (not (null (gethash "test-node" opencortex::*memory*))))))
(test test-depth-limiting (test test-depth-limiting
"Verify that the pipeline terminates runaway feedback loops."
(let ((runaway-signal (list :type :EVENT :depth 11 :payload (list :sensor :heartbeat)))) (let ((runaway-signal (list :type :EVENT :depth 11 :payload (list :sensor :heartbeat))))
(is (null (process-signal runaway-signal))))) (is (null (process-signal runaway-signal)))))
#+end_src #+end_src