Some checks failed
Deploy-Agent-V15-Stdin / JOB-V15-STDIN (push) Failing after 3s
- 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/.
213 lines
9.7 KiB
Org Mode
213 lines
9.7 KiB
Org Mode
#+TITLE: Stage 3: Act (act.lisp)
|
|
#+AUTHOR: Amr
|
|
#+FILETAGS: :harness:act:
|
|
#+STARTUP: content
|
|
|
|
* 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
|
|
#+begin_src lisp :tangle ../library/act.lisp
|
|
(in-package :opencortex)
|
|
#+end_src
|
|
|
|
* Actuator Configuration
|
|
|
|
** Default Actuator
|
|
#+begin_src lisp :tangle ../library/act.lisp
|
|
(defvar *default-actuator* :cli
|
|
"The fallback actuator used if a signal has no source or target metadata.")
|
|
#+end_src
|
|
|
|
** 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.
|
|
|
|
#+begin_src lisp :tangle ../library/act.lisp
|
|
(defvar *silent-actuators* '(:cli :system-message :emacs)
|
|
"List of actuators whose feedback should not re-enter the Reasoning stage.")
|
|
#+end_src
|
|
|
|
** Initialization Logic (initialize-actuators)
|
|
This function hydrates the actuator configuration from the environment and registers the core built-in actuators.
|
|
|
|
#+begin_src lisp :tangle ../library/act.lisp
|
|
(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))))))
|
|
#+end_src
|
|
|
|
* 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`.
|
|
|
|
#+begin_src lisp :tangle ../library/act.lisp
|
|
(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)))))
|
|
#+end_src
|
|
|
|
* Built-in Actuators
|
|
|
|
** System Actuator (execute-system-action)
|
|
Handles meta-operations like hot-loading skills or evaluating raw Lisp within the image.
|
|
|
|
#+begin_src lisp :tangle ../library/act.lisp
|
|
(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)))))
|
|
#+end_src
|
|
|
|
** Tool Result Formatting (format-tool-result)
|
|
A UI helper that distills technical LLM responses into human-readable text.
|
|
|
|
#+begin_src lisp :tangle ../library/act.lisp
|
|
(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)))
|
|
#+end_src
|
|
|
|
** Tool Actuator (execute-tool-action)
|
|
The engine for physical interaction. It executes a cognitive tool and generates feedback signals for the user.
|
|
|
|
#+begin_src lisp :tangle ../library/act.lisp
|
|
(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")))))
|
|
#+end_src
|
|
|
|
* 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.
|
|
|
|
#+begin_src lisp :tangle ../library/act.lisp
|
|
(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))
|
|
#+end_src
|