#+TITLE: Stage 1: Perceive (perceive.lisp) #+AUTHOR: Amr #+FILETAGS: :harness:perceive: #+STARTUP: content * Stage 1: Perceive (perceive.lisp) ** Architectural Intent: Sensory Ingestion The Perceive stage is the "sensory cortex" of the Org-Agent. It takes raw stimuli from the outside world (keyboard events, chat messages, heartbeats, or system interrupts) and normalizes them into internal **Signals**. ** Async Sensor Routing To prevent blocking the main pipeline, certain sensors (like user commands or chat messages) are processed asynchronously in their own threads. #+begin_src lisp :tangle ../src/perceive.lisp (in-package :org-agent) (defvar *async-sensors* '(:chat-message :delegation :user-command) "List of sensors that should be processed asynchronously to avoid blocking gateways.") #+end_src ** Foveal Focus State The system tracks the user's current point of interaction to provide context to the reasoning engine. #+begin_src lisp :tangle ../src/perceive.lisp (defvar *foveal-focus-id* nil "The Org ID of the node the user is currently interacting with.") #+end_src ** Stimulus Injection The entry point for raw messages. It determines if the signal should be processed synchronously or asynchronously. #+begin_src lisp :tangle ../src/perceive.lisp (defun inject-stimulus (raw-message &key stream (depth 0)) "Enqueues a raw message into the reactive signal pipeline." (let* ((payload (getf raw-message :payload)) (sensor (getf payload :sensor)) (async-p (or (getf payload :async-p) (member sensor *async-sensors*)))) (when stream (setf (getf raw-message :reply-stream) stream)) (if async-p (bt:make-thread (lambda () (restart-case (handler-bind ((error (lambda (c) (harness-log "ASYNC ERROR: ~a" c) (invoke-restart 'skip-event)))) (process-signal raw-message)) (skip-event () nil))) :name "org-agent-async-task") (restart-case (handler-bind ((error (lambda (c) (harness-log "SYSTEM ERROR: ~a" c) (invoke-restart 'skip-event)))) (process-signal raw-message)) (skip-event () (harness-log "SYSTEM RECOVERY: Stimulus dropped.~%")))))) #+end_src ** The Perceive Gate The initial stage of the metabolic loop. It logs the signal, performs selective memory snapshots, and updates the Memory graph based on incoming AST updates. #+begin_src lisp :tangle ../src/perceive.lisp (defun perceive-gate (signal) "Initial processing: Normalizes raw stimuli and updates memory." (let* ((payload (getf signal :payload)) (type (getf signal :type)) (sensor (getf payload :sensor))) (harness-log "GATE [Perceive]: ~a (~a)" type (or sensor "no-sensor")) (cond ((eq type :EVENT) (case sensor (:buffer-update (let ((ast (getf payload :ast))) (when ast (snapshot-memory) (ingest-ast ast)))) (:point-update (let ((element (getf payload :element))) (when element (snapshot-memory) (setf *foveal-focus-id* (ignore-errors (getf element :id))) (ingest-ast element)))) (:interrupt (bt:with-lock-held (*interrupt-lock*) (setf *interrupt-flag* t))))) ((eq type :RESPONSE) (harness-log "GATE [Perceive]: Act Result -> ~a" (getf payload :status)))) (setf (getf signal :status) :perceived) (setf (getf signal :foveal-focus) *foveal-focus-id*) signal)) #+end_src