120 lines
6.4 KiB
Org Mode
120 lines
6.4 KiB
Org Mode
#+TITLE: Stage 2: Reason (reason.lisp)
|
|
#+AUTHOR: Amr
|
|
#+FILETAGS: :harness:reason:
|
|
#+STARTUP: content
|
|
|
|
* Stage 2: Reason (reason.lisp)
|
|
** Architectural Intent: Unified Cognition
|
|
The Reason stage is the cognitive engine of the OpenCortex. It unifies two distinct reasoning modes:
|
|
1. **Probabilistic Reasoning:** Consulting neural models (LLMs) to generate action proposals based on current context.
|
|
2. **Deterministic Reasoning:** Running those proposals through a series of deterministic safety gates (Policy, Invariants, and Skill-specific validation) to ensure alignment and security.
|
|
|
|
** Package and Registry
|
|
We initialize the probabilistic backends and the provider cascade which determines the order in which models are consulted.
|
|
|
|
#+begin_src lisp :tangle ../src/reason.lisp
|
|
(in-package :opencortex)
|
|
|
|
(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))
|
|
#+end_src
|
|
|
|
** Neural Dispatch (Probabilistic)
|
|
The `probabilistic-call` function manages the cascade of neural providers. If the primary provider fails, it automatically falls back to the next one in the list.
|
|
|
|
#+begin_src lisp :tangle ../src/reason.lisp
|
|
(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))))
|
|
;; If the result is valid and doesn't contain a failure log, return it.
|
|
(unless (or (null result)
|
|
(and (stringp result) (search ":LOG" result)))
|
|
(return result))))))
|
|
;; Final fallback if all backends in the cascade fail.
|
|
(list :type :LOG :payload (list :text "Neural Cascade Failure: All providers exhausted.")))))
|
|
#+end_src
|
|
|
|
** Cognitive Proposal (Think)
|
|
The `think` function represents the "intuitive" side of the agent. It identifies the active skill, assembles the global context, and asks the probabilistic engine for a structured action proposal.
|
|
|
|
#+begin_src lisp :tangle ../src/reason.lisp
|
|
(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")))
|
|
(if active-skill
|
|
(let* ((prompt-generator (skill-probabilistic-prompt active-skill))
|
|
(raw-prompt (when prompt-generator (funcall prompt-generator context)))
|
|
(system-prompt (format nil "IDENTITY: Actuator for ~a. MANDATE: ONE Lisp plist. ~a ~a RECENT_LOGS: ~a"
|
|
assistant-name global-context tool-belt system-logs)))
|
|
(if (and raw-prompt (> (length raw-prompt) 1))
|
|
(let* ((thought (probabilistic-call raw-prompt :system-prompt system-prompt :context context))
|
|
;; Ensure we are working with a string for read-from-string
|
|
(cleaned (if (stringp thought) (string-trim '(#\Space #\Newline #\Tab) thought) thought)))
|
|
(if (stringp cleaned)
|
|
(handler-case (read-from-string cleaned)
|
|
(error (c) (list :type :EVENT :payload (list :sensor :syntax-error :code cleaned :error (format nil "~a" c)))))
|
|
cleaned))
|
|
(list :type :LOG :payload (list :text (format nil "Skill '~a' triggered (Deterministic only)" (skill-name active-skill))))))
|
|
nil)))
|
|
#+end_src
|
|
|
|
** Deterministic Verification
|
|
Once a proposal is generated, it MUST pass through the deterministic gates. Every skill can register a gate that inspects and potentially modifies or blocks the proposed action.
|
|
|
|
#+begin_src lisp :tangle ../src/reason.lisp
|
|
(defun deterministic-verify (proposed-action context)
|
|
"Iterates through all skill deterministic-gates sorted by priority."
|
|
(let ((current-action proposed-action)
|
|
(skills nil))
|
|
;; 1. Collect and sort active gates
|
|
(maphash (lambda (name skill) (declare (ignore name)) (when (skill-deterministic-fn skill) (push skill skills))) *skills-registry*)
|
|
(setf skills (sort skills #'> :key #'skill-priority))
|
|
|
|
;; 2. Execute gates sequentially if their trigger allows
|
|
(dolist (skill skills)
|
|
(let ((trigger (skill-trigger-fn skill))
|
|
(gate (skill-deterministic-fn skill)))
|
|
(when (or (null trigger) (ignore-errors (funcall trigger context)))
|
|
(setf current-action (funcall gate current-action context))
|
|
;; If any gate returns a LOG or EVENT, it has intercepted the action.
|
|
(when (and (listp current-action) (member (getf current-action :type) '(:LOG :EVENT :log :event)))
|
|
(harness-log "DETERMINISTIC: Intercepted by skill '~a'" (skill-name skill))
|
|
(return-from deterministic-verify current-action)))))
|
|
current-action))
|
|
#+end_src
|
|
|
|
** The Reason Gate
|
|
The entry point for the Reason stage. It orchestrates the transition from probabilistic "thought" to deterministic "verification."
|
|
|
|
#+begin_src lisp :tangle ../src/reason.lisp
|
|
(defun reason-gate (signal)
|
|
"Unified Stage: Combines Probabilistic proposals and Deterministic verification."
|
|
;; Only process events that haven't been reasoned yet.
|
|
(unless (eq (getf signal :type) :EVENT) (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))
|
|
#+end_src
|