Files
passepartout/literate/reason.org
Amr Gharbeia c70f182888
Some checks failed
Deploy-Agent-V15-Stdin / JOB-V15-STDIN (push) Failing after 3s
FEAT: Stabilize Unified Envelope Architecture & TUI UX
- Fixed background boot crash via --non-interactive flag.
- Implemented robust protocol sanitization (stripped raw streams).
- Refined TUI formatting to display human-readable tool results.
- Fixed opencortex.sh variable shadowing and connection logic.
- Resolved :target field schema validation errors.
2026-04-20 18:19:54 -04:00

7.1 KiB

Stage 2: Reason (reason.lisp)

Stage 2: Reason (reason.lisp)

Architectural Intent: Unified Cognition

The Reason stage is the cognitive engine of the OpenCortex. It bridges the gap between raw sensory data (Perceive) and physical side-effects (Act).

Cognition Engine (reason.lisp)

Package Context

(in-package :opencortex)

Neural Backend Registry

(defvar *probabilistic-backends* (make-hash-table :test 'equal))
(defvar *provider-cascade* nil)
(defvar *model-selector-fn* nil)
(defvar *consensus-enabled-p* nil)

(defun register-probabilistic-backend (name fn)
  "Registers a neural provider (e.g., :gemini, :anthropic) with its calling function."
  (setf (gethash name *probabilistic-backends*) fn))

Probabilistic Reasoning (probabilistic-call)

(defun probabilistic-call (prompt &key (system-prompt "You are the Probabilistic engine.") (cascade nil) (context nil))
  "Dispatches a neural request through the provider cascade. Returns a Lisp plist or a failure log."
  (let ((backends (or cascade *provider-cascade*)))
    (or (dolist (backend backends)
          (let ((backend-fn (gethash backend *probabilistic-backends*)))
            (when backend-fn
              (harness-log "PROBABILISTIC: Attempting backend ~a..." backend)
              (let* ((model (when *model-selector-fn* (funcall *model-selector-fn* backend context)))
                     (result (if model 
                                 (funcall backend-fn prompt system-prompt :model model)
                                 (funcall backend-fn prompt system-prompt))))
                (cond ((and (listp result) (eq (getf result :status) :success))
                       (return (getf result :content)))
                      ((stringp result) (return result))
                      (t (harness-log "PROBABILISTIC: Backend ~a failed: ~a" backend (getf result :message))))))))
        (list :type :LOG :payload (list :text "Neural Cascade Failure: All providers exhausted.")))))

Cognitive Proposal (Think)

(defun think (context)
  "Generates a Lisp action proposal based on current context."
  (let* ((active-skill (find-triggered-skill context))
         (tool-belt (generate-tool-belt-prompt))
         (global-context (context-assemble-global-awareness))
         (system-logs (context-get-system-logs))
         (assistant-name (or (uiop:getenv "MEMEX_ASSISTANT") "Agent")))
    (let* ((prompt-generator (when active-skill (skill-probabilistic-prompt active-skill)))
           (raw-prompt (if prompt-generator 
                           (funcall prompt-generator context)
                           (let ((p (proto-get (proto-get context :payload) :text)))
                             (if (and p (stringp p)) p "Maintain metabolic stasis."))))
           (system-prompt (format nil "IDENTITY: ~a. MANDATE: Respond with ONE Lisp plist. ~a ~a RECENT_LOGS: ~a
IMPORTANT: To reply to the user, you MUST use:
(:TYPE :REQUEST :PAYLOAD (:ACTION :MESSAGE :TEXT \"<Response Text>\"))

To call a tool, you MUST use:
(:TYPE :REQUEST :TARGET :TOOL :ACTION :CALL :TOOL \"<name>\" :ARGS (:arg1 \"val\"))

PROVIDER RULE: Always use :provider :openrouter if calling LLM tools unless specified otherwise." 
                                  assistant-name global-context tool-belt system-logs)))
      (let* ((thought (probabilistic-call raw-prompt :system-prompt system-prompt :context context))
             (cleaned (if (stringp thought) (string-trim '(#\Space #\Newline #\Tab) thought) thought))
             (meta (proto-get context :meta))
             (source (proto-get meta :source)))
        (if (and cleaned (stringp cleaned))
            (let ((*read-eval* nil))
              (if (and (> (length cleaned) 0) (char= (char cleaned 0) #\())
                  (handler-case 
                      (let ((parsed (read-from-string cleaned)))
                        (let ((type (proto-get parsed :TYPE))
                              (target (or (proto-get parsed :TARGET) (proto-get parsed :target))))
                          (cond ((member type '(:REQUEST :EVENT :STATUS :RESPONSE))
                                 (unless (proto-get parsed :target) (setf (getf parsed :target) (or source :CLI)))
                                 parsed)
                                ;; Handle raw plists that look like tool calls
                                ((or (eq target :TOOL) (eq target :tool) (getf parsed :TOOL) (getf parsed :tool))
                                 (list :TYPE :REQUEST :TARGET :TOOL :PAYLOAD parsed))
                                (t (list :TYPE :REQUEST :TARGET (or source :CLI) :PAYLOAD (list :ACTION :MESSAGE :TEXT cleaned))))))
                    (error (c) (list :TYPE :REQUEST :TARGET (or source :CLI) :PAYLOAD (list :ACTION :MESSAGE :TEXT cleaned))))
                  (list :TYPE :REQUEST :TARGET (or source :CLI) :PAYLOAD (list :ACTION :MESSAGE :TEXT cleaned))))
            thought)))))

Deterministic Verification

(defun deterministic-verify (proposed-action context)
  "Iterates through all skill deterministic-gates sorted by priority."
  (let ((current-action proposed-action)
        (skills nil))
    (maphash (lambda (name skill) (declare (ignore name)) (when (skill-deterministic-fn skill) (push skill skills))) *skills-registry*)
    (setf skills (sort skills #'> :key #'skill-priority))
    (dolist (skill skills)
      (let ((trigger (skill-trigger-fn skill))
            (gate (skill-deterministic-fn skill)))
        (when (or (null trigger) (ignore-errors (funcall trigger context)))
          (let ((next-action (funcall gate current-action context)))
            (let ((original-type (proto-get current-action :type)))
              (when (and (listp next-action) 
                         (member (proto-get next-action :type) '(:LOG :EVENT :log :event))
                         (or (not (member original-type '(:LOG :EVENT :log :event)))
                             (not (eq next-action current-action))))
                (harness-log "DETERMINISTIC: Intercepted by skill '~a'" (skill-name skill))
                (return-from deterministic-verify next-action)))
            (setf current-action next-action)))))
    current-action))

Reasoning Gate (The Pipeline Stage)

(defun reason-gate (signal)
  "Unified Stage: Combines Probabilistic proposals and Deterministic verification."
  (let* ((type (proto-get signal :type))
         (payload (proto-get signal :payload))
         (sensor (proto-get payload :sensor)))
    (unless (and (eq type :EVENT) (member sensor '(:user-input :chat-message)))
      (return-from reason-gate signal))
    (let ((candidate (think signal)))
      (if candidate
          (setf (getf signal :approved-action) (deterministic-verify candidate signal))
          (setf (getf signal :approved-action) nil))
      (setf (getf signal :status) :reasoned)
      signal)))