(in-package :opencortex) (defvar *interrupt-flag* nil "Thread-safe signal to halt the metabolic pipeline and daemon.") (defvar *interrupt-lock* (bt:make-lock "harness-interrupt-lock") "Protects the interrupt flag from concurrent access.") (defvar *heartbeat-thread* nil "Reference to the background thread driving autonomous reflection.") (defun process-signal (signal) "The entry point to the Metabolic Pipeline: Perceive -> Reason -> Act." (let ((current-signal signal)) (loop while current-signal do (let ((depth (getf current-signal :depth 0)) (meta (getf current-signal :meta))) ;; Safety: Prevent infinite cognitive recursion. (when (> depth 10) (harness-log "METABOLISM ERROR: Max depth reached.") (return nil)) ;; Check for graceful shutdown. (when (bt:with-lock-held (*interrupt-lock*) *interrupt-flag*) (harness-log "METABOLISM: Interrupted.") (bt:with-lock-held (*interrupt-lock*) (setf *interrupt-flag* nil)) (return nil)) (handler-case (progn ;; Stage 1: Ingest and Normalize (setf current-signal (perceive-gate current-signal)) ;; Stage 2: Cogitate and Verify (setf current-signal (reason-gate current-signal)) ;; Stage 3: Actuate and Generate Feedback (let ((feedback (act-gate current-signal))) (if feedback (progn ;; Inheritance: Metadata must persist across recursive cycles. (unless (getf feedback :meta) (setf (getf feedback :meta) meta)) (setf current-signal feedback)) (setf current-signal nil)))) (error (c) (let ((sensor (ignore-errors (getf (getf current-signal :payload) :sensor)))) (harness-log "METABOLISM CRASH [~a]: ~a" (or sensor :unknown) c) ;; Resilience: Only rollback on critical system errors. (unless (member sensor '(:loop-error :tool-error :syntax-error)) (harness-log "CRITICAL ERROR: Initiating Micro-Rollback.") (rollback-memory 0)) ;; If recursion is shallow, attempt to notify the user of the error. (if (or (> depth 2) (member sensor '(:loop-error :tool-error))) (setf current-signal nil) (setf current-signal (list :type :EVENT :depth (1+ depth) :meta meta :payload (list :sensor :loop-error :message (format nil "~a" c) :depth depth))))))))))) (defun start-heartbeat () "Starts the background heartbeat thread. Interval is loaded from HEARTBEAT_INTERVAL (default: 60s)." (let ((interval (or (ignore-errors (parse-integer (uiop:getenv "HEARTBEAT_INTERVAL"))) 60))) (setf *heartbeat-thread* (bt:make-thread (lambda () (loop (sleep interval) ;; Note: inject-stimulus is synchronous for heartbeats to prevent task accumulation. (inject-stimulus (list :type :EVENT :payload (list :sensor :heartbeat :unix-time (get-universal-time)))))) :name "opencortex-heartbeat")))) (defun main () "Primary entry point for the OpenCortex daemon." ;; 1. Environment Hydration (let* ((home (uiop:getenv "HOME")) (env-file (uiop:merge-pathnames* ".local/share/opencortex/.env" (uiop:ensure-directory-pathname home)))) (when (uiop:file-exists-p env-file) (cl-dotenv:load-env env-file))) ;; 2. System Bootstrap (initialize-actuators) (initialize-all-skills) ;; 3. Wake up the heart. (start-heartbeat) ;; 4. OS Signal Handling (SBCL specific) #+sbcl (sb-sys:enable-interrupt sb-unix:sigint (lambda (sig code scp) (declare (ignore sig code scp)) (harness-log "SHUTDOWN: SIGINT received. Exiting...") (uiop:quit 0))) ;; 5. Primary Idle Loop (let ((sleep-interval (or (ignore-errors (parse-integer (uiop:getenv "DAEMON_SLEEP_INTERVAL"))) 3600))) (loop (when (bt:with-lock-held (*interrupt-lock*) *interrupt-flag*) (return)) (sleep sleep-interval))))