feat: HITL — continuation-based human-in-the-loop
Some checks failed
Deploy (Gitea) / deploy (push) Failing after 3s
Some checks failed
Deploy (Gitea) / deploy (push) Failing after 3s
- dispatcher-check: add :level :approval-required to network/high-impact returns - cognitive-verify: distinguish approval-required from hard rejection; pass approval requests through to act gate instead of returning early - loop-gate-reason: don't retry approval requests; pass them as approved-action with :status :requires-approval - loop-gate-act: detect approval-required, create Flight Plan, dispatch HITL message to user's client, don't execute original action - loop-gate-perceive: handle re-injected approved signals from dispatcher-approvals-process; set :approved-action on signal - dispatcher-approvals-process: fix function name (stimulus-inject) and wrap action in proper signal envelope with :sensor :approval-required - Fix: list-objects-with-attribute → memory-objects-by-attribute - Fix: org-id-new → org-id-generate - Fix: inject-stimulus → stimulus-inject (correct function name) Flow: 1. LLM proposes high-risk action → dispatcher returns approval-required 2. cognitive-verify collects approval request → passes to reason as :requires-approval 3. loop-gate-act creates Flight Plan → dispatches HITL message to client → exits 4. Human approves in Emacs → heartbeat re-injects with :approved t 5. Re-injected signal flows through pipeline → dispatcher passes through 6. Action executed normally
This commit is contained in:
@@ -196,16 +196,36 @@ After dispatch, the gate captures any feedback produced by the actuation (tool o
|
||||
;; REPL-VERIFIED: 2026-05-03T13:00:00
|
||||
#+begin_src lisp
|
||||
(defun loop-gate-act (signal)
|
||||
"Final stage of the metabolic pipeline: Actuation."
|
||||
"Final stage of the metabolic pipeline: Actuation.
|
||||
For approval-required actions, creates a Flight Plan instead of executing."
|
||||
(let* ((approved (getf signal :approved-action))
|
||||
(signal-status (getf signal :status))
|
||||
(type (getf signal :type))
|
||||
(meta (getf signal :meta))
|
||||
(source (getf meta :source))
|
||||
(feedback nil))
|
||||
;; HITL: if the approved action requires human approval,
|
||||
;; create a Flight Plan and notify the user via their client.
|
||||
(when (and approved
|
||||
(eq (getf approved :level) :approval-required))
|
||||
(let* ((payload (getf approved :payload))
|
||||
(blocked-action (getf payload :action)))
|
||||
(log-message "ACT: Action requires approval — creating Flight Plan")
|
||||
(dispatcher-flight-plan-create blocked-action)
|
||||
(setf (getf signal :status) :suspended)
|
||||
;; Dispatch HITL notification to the user's client via the source actuator
|
||||
(action-dispatch (list :target source
|
||||
:payload (list :text
|
||||
"HITL: Action requires your approval. Check Flight Plan and set TODO to APPROVED."))
|
||||
signal)
|
||||
(setf approved nil) ;; Don't execute the original action
|
||||
(setf feedback nil))) ;; Don't loop back — wait for human
|
||||
(when approved
|
||||
(let* ((original-type (getf approved :type))
|
||||
(verified (cognitive-verify approved signal)))
|
||||
(if (and (listp verified) (member (getf verified :type) '(:LOG :EVENT)) (not (member original-type '(:LOG :EVENT))))
|
||||
(if (and (listp verified) (member (getf verified :type) '(:LOG :EVENT))
|
||||
(not (eq (getf verified :level) :approval-required))
|
||||
(not (member original-type '(:LOG :EVENT))))
|
||||
(progn
|
||||
(log-message "ACT BLOCKED: Action failed last-mile deterministic check.")
|
||||
(setf (getf signal :approved-action) nil)
|
||||
@@ -248,9 +268,9 @@ Verifies that the act gate correctly processes an approved action and sets the s
|
||||
(in-suite pipeline-act-suite)
|
||||
|
||||
(test test-loop-gate-act-basic
|
||||
(clrhash passepartout::*skills-registry*)
|
||||
(clrhash passepartout::*skill-registry*)
|
||||
(let* ((signal (list :type :EVENT :status nil :depth 0 :approved-action '(:target :cli :payload (:text "Hello"))))
|
||||
(result (loop-gate-act signal)))
|
||||
(result (loop-gate-act signal)))
|
||||
(is (eq :acted (getf signal :status)))
|
||||
(is (null result))))
|
||||
#+end_src
|
||||
Reference in New Issue
Block a user