feat: HITL — continuation-based human-in-the-loop
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:
2026-05-03 13:00:19 -04:00
parent 231c3bb445
commit 5e7b1cee33
11 changed files with 209 additions and 108 deletions

View File

@@ -388,7 +388,8 @@ privacy tags, privacy text, shell safety, network exfil, high-impact approval."
(and (eq target :tool) (equal (proto-get payload :tool) "shell")))
(dispatcher-check-network-exfil cmd))
(log-message "SECURITY WARNING: External network call detected. Queuing for approval.")
(list :type :EVENT :payload (list :sensor :approval-required :action action)))
(list :type :EVENT :level :approval-required
:payload (list :sensor :approval-required :action action)))
;; Vector 8: High-impact action approval
((or (member target '(:shell))
@@ -405,7 +406,7 @@ privacy tags, privacy text, shell safety, network exfil, high-impact approval."
#+begin_src lisp
(defun dispatcher-approvals-process ()
"Scans for APPROVED flight plans and re-injects them."
(let ((approved-nodes (list-objects-with-attribute :TODO "APPROVED"))
(let ((approved-nodes (memory-objects-by-attribute :TODO "APPROVED"))
(found-any nil))
(dolist (node approved-nodes)
(let* ((attrs (memory-object-attributes node))
@@ -416,7 +417,11 @@ privacy tags, privacy text, shell safety, network exfil, high-impact approval."
(let ((action (ignore-errors (read-from-string action-str))))
(when action
(setf (getf action :approved) t)
(inject-stimulus action)
(stimulus-inject (list :type :EVENT
:payload (list :sensor :approval-required
:action action
:approved t)
:meta (list :source :system)))
(setf (getf (memory-object-attributes node) :TODO) "DONE")
(setq found-any t))))))
found-any))
@@ -427,7 +432,7 @@ privacy tags, privacy text, shell safety, network exfil, high-impact approval."
#+begin_src lisp
(defun dispatcher-flight-plan-create (blocked-action)
"Creates a Flight Plan node for manual approval."
(let ((id (org-id-new)))
(let ((id (org-id-generate)))
(log-message "BOUNCER: Creating flight plan node '~a'..." id)
(list :type :REQUEST :target :emacs
:payload (list :action :insert-node :id id