Files
passepartout/harness/act.org
Amr Gharbeia 94a8a0ab0b
Some checks failed
Deploy-Agent-V15-Stdin / JOB-V15-STDIN (push) Failing after 3s
RELEASE: Finalize Semantic Restructuring v0.1.0
- Folders: literate->harness, src->library, system->environment, scripts->interfaces.
- Synchronized all :tangle paths and system definitions.
- Hardened .gitignore for binary and log artifacts.
- Consolidated all documentation into docs/.
2026-04-21 12:41:50 -04:00

9.7 KiB

Stage 3: Act (act.lisp)

Stage 3: Act (act.lisp)

Architectural Intent: Actuation

The Act stage performs the final physical side-effects of the metabolic pipeline. It takes an approved Action (the result of the Reasoning stage) and routes it to the correct physical Actuator.

Actuators are the "hands" of the OpenCortex. They can be local (printing to a terminal), virtual (executing a shell command), or remote (sending a Matrix message). Crucially, the core microharness does not know how to talk to these services; it only knows how to dispatch to the registered actuator functions.

Pipeline Initialization

(in-package :opencortex)

Actuator Configuration

Default Actuator

(defvar *default-actuator* :cli
  "The fallback actuator used if a signal has no source or target metadata.")

Silent Actuators

To prevent infinite feedback loops, certain actuators are flagged as "silent." Results from these actuators are logged but do not trigger a fresh metabolic cycle.

(defvar *silent-actuators* '(:cli :system-message :emacs)
  "List of actuators whose feedback should not re-enter the Reasoning stage.")

Initialization Logic (initialize-actuators)

This function hydrates the actuator configuration from the environment and registers the core built-in actuators.

(defun initialize-actuators ()
  "Loads actuator routing defaults from environment variables and registers core harness actuators."
  (let ((def (uiop:getenv "DEFAULT_ACTUATOR"))
        (silent (uiop:getenv "SILENT_ACTUATORS")))
    (when def
      (setf *default-actuator* (intern (string-upcase def) "KEYWORD")))
    (when silent
      (setf *silent-actuators*
            (mapcar (lambda (s) (intern (string-upcase (string-trim '(#\Space) s)) "KEYWORD"))
                    (str:split "," silent)))))
  
  ;; Register core harness actuators
  (register-actuator :system #'execute-system-action)
  (register-actuator :tool #'execute-tool-action)
  (register-actuator :tui (lambda (action context)
                            (let* ((meta (getf context :meta))
                                   (stream (getf meta :reply-stream)))
                              (when (and stream (open-stream-p stream))
                                (format stream "~a" (frame-message action))
                                (finish-output stream))))))

Primary Routing

Dispatching Logic (dispatch-action)

The primary router. It identifies the target actuator based on the Signal's `:META` source or the Action's `:TARGET`.

(defun dispatch-action (action context)
  "Routes an approved action to its registered physical actuator."
  (let ((payload (proto-get action :payload)))
    ;; Optimization: Heartbeats are system events, not actions.
    (when (eq (proto-get payload :sensor) :heartbeat)
      (return-from dispatch-action nil)))

  (when (and action (listp action))
    (let* ((meta (proto-get context :meta))
           (source (proto-get meta :source))
           (raw-target (or (ignore-errors (getf action :TARGET))
                           (ignore-errors (getf action :target))
                           source
                           *default-actuator*))
           (target (intern (string-upcase (string raw-target)) :keyword))
           (actuator-fn (gethash target *actuator-registry*)))
      ;; Propagation: Ensure outbound action inherits metadata
      (when (and meta (null (getf action :meta)))
        (setf (getf action :meta) meta))
      (if actuator-fn 
          (funcall actuator-fn action context) 
          (harness-log "ACT ERROR: No actuator for ~s (from ~s)" target raw-target)))))

Built-in Actuators

System Actuator (execute-system-action)

Handles meta-operations like hot-loading skills or evaluating raw Lisp within the image.

(defun execute-system-action (action context)
  "Processes internal harness commands. (ACTUATOR)"
  (declare (ignore context))
  (let* ((payload (ignore-errors (getf action :payload))) 
         (cmd (ignore-errors (getf payload :action))))
    (case cmd
      (:eval (let ((code (getf payload :code)))
               (eval (read-from-string code))))
      (:create-skill (let* ((filename (getf payload :filename)) (content (getf payload :content))
                            (skills-dir (merge-pathnames "skills/" (asdf:system-source-directory :opencortex))) 
                            (full-path (merge-pathnames filename skills-dir)))
                       (with-open-file (out full-path :direction :output :if-exists :supersede) (write-string content out))
                       (load-skill-from-org full-path)))
      (:message (harness-log "ACT [System]: ~a" (getf payload :text)))
      (t (harness-log "ACT ERROR [System]: Unknown command ~s" cmd)))))

Tool Result Formatting (format-tool-result)

A UI helper that distills technical LLM responses into human-readable text.

(defun format-tool-result (tool-name result)
  "Intelligently formats a tool result for user display."
  (if (listp result)
      (let ((status (getf result :status))
            (content (getf result :content))
            (msg (getf result :message)))
        (cond ((and (eq status :success) content) (format nil "~a" content))
              ((and (eq status :error) msg) (format nil "ERROR [~a]: ~a" tool-name msg))
              (t (format nil "TOOL [~a] RESULT: ~s" tool-name result))))
      (format nil "TOOL [~a] RESULT: ~a" tool-name result)))

Tool Actuator (execute-tool-action)

The engine for physical interaction. It executes a cognitive tool and generates feedback signals for the user.

(defun execute-tool-action (action context)
  "Executes a registered cognitive tool and generates feedback signals. (ACTUATOR)"
  (let* ((payload (getf action :payload))
         (tool-name (getf payload :tool))
         (tool-args (getf payload :args))
         (depth (getf context :depth 0))
         (meta (getf context :meta))
         (source (getf meta :source))
         (tool (gethash (string-downcase (string tool-name)) *cognitive-tools*)))
    (if tool
        (handler-case
            (let* ((clean-args (if (and (listp tool-args) (listp (car tool-args))) (car tool-args) tool-args))
                   (result (funcall (cognitive-tool-body tool) clean-args)))
              (let ((feedback (list :TYPE :EVENT :DEPTH (1+ depth) :META meta
                                    :PAYLOAD (list :SENSOR :tool-output :RESULT result :TOOL tool-name))))
                ;; UI Propagation: Send distilled text result back to the source client
                (when source
                   (dispatch-action (list :TYPE :REQUEST :TARGET source 
                                          :PAYLOAD (list :ACTION :MESSAGE :TEXT (format-tool-result tool-name result))) 
                                    context))
                feedback))
          (error (c)
            (list :TYPE :EVENT :DEPTH (1+ depth) :META meta
                  :PAYLOAD (list :SENSOR :tool-error :tool tool-name :message (format nil "~a" c)))))
        (list :TYPE :EVENT :DEPTH (1+ depth) :META meta
              :PAYLOAD (list :SENSOR :tool-error :message "Tool not found")))))

The Final Pipeline Stage

Act Gate (act-gate)

The exit point of the metabolic pipeline. It applies a last-mile safety check via the Deterministic Engine and dispatches the signal to the physical world.

(defun act-gate (signal)
  "Final Stage: Actuation and feedback generation."
  (let* ((approved (getf signal :approved-action))
         (type (getf signal :type))
         (meta (getf signal :meta))
         (source (getf meta :source))
         (feedback nil)
         ;; context must keep internal objects for actuators to function
         (context signal))
    
    ;; 1. Last-Mile Safety Check (The Bouncer & Deterministic Gates)
    (when approved
      (let* ((original-type (getf approved :type))
             (verified (deterministic-verify approved signal)))
        (if (and (listp verified) 
                 (member (getf verified :type) '(:LOG :EVENT :log :event))
                 (not (member original-type '(:LOG :EVENT :log :event))))
            (progn
              (harness-log "ACT BLOCKED: Action failed last-mile deterministic check.")
              (setf (getf signal :approved-action) nil)
              (setf approved nil)
              (setf feedback verified))
            (progn
              (setf (getf signal :approved-action) verified)
              (setf approved verified)))))

    ;; 2. Actuation Logic
    (case type
      (:REQUEST (dispatch-action signal context))
      (:LOG (dispatch-action signal context))
      (:EVENT 
       (if approved
           (let* ((target (getf approved :target))
                  (result (dispatch-action approved context)))
             (cond ((and (listp result) (member (getf result :type) '(:EVENT :LOG)))
                    (setf feedback result))
                   ((and result (not (member target *silent-actuators*)))
                    (setf feedback (list :type :EVENT :depth (1+ (getf signal :depth 0)) :meta meta
                                         :payload (list :sensor :tool-output :result result :tool approved))))))
           ;; Fallback: route generic stimuli back to their origin
           (when source
             (dispatch-action signal context)))))
    
    (setf (getf signal :status) :acted)
    feedback))