v0.7.2: self-help (/why) + CONFIG injection — TDD

- CONFIG section in system prompt: providers, context window, gate count,
  rules learned, docs path
- /why TUI command: shows most recent gate trace from message history
- assemble-config-section reads live state at each think() call
- Core: 75/76  TUI Main: 77/78 (1 pre-existing RCE test flake)
This commit is contained in:
2026-05-08 17:06:16 -04:00
parent ca44136a55
commit e3a6573542
5 changed files with 126 additions and 7 deletions

View File

@@ -152,9 +152,28 @@ Event handlers + daemon I/O + main loop.
(list :action :hitl-respond :token token :decision :denied)))
(add-msg :system (format nil "Denied: ~a" token))))
;; /help command
;; /why command — show last gate trace
((string-equal text "/why")
(let ((msgs (st :messages))
(found nil))
(loop for i from (1- (length msgs)) downto 0
for m = (aref msgs i)
for gt = (getf m :gate-trace)
when (and gt (listp gt) (> (length gt) 0))
do (setf found t)
(dolist (entry gt)
(let* ((gate (getf entry :gate))
(result (getf entry :result))
(reason (getf entry :reason))
(msg (format nil "~a ~a~@[ — ~a~]"
(case result (:passed "[PASS]") (:blocked "[BLOCKED]") (:approval "[HITL]"))
(or gate "unknown")
reason)))
(add-msg :system msg)))
(loop-finish))
(unless found
(add-msg :system "No recent gate trace. Run a tool to see gate decisions."))))
((string-equal text "/help")
(add-msg :system
"/eval <expr> Evaluate Lisp expression")
(add-msg :system
"/focus <proj> Set project context")
(add-msg :system
@@ -873,4 +892,29 @@ Event handlers + daemon I/O + main loop.
(let ((m (aref (st :messages) 0)))
(fiveam:is (eq :system (getf m :role)))
(fiveam:is (search "Redo" (getf m :content)))))
;; ── v0.7.2 Self-help ──
(fiveam:test test-why-command
"Contract v0.7.2: /why shows gate trace from last message."
(init-state)
(add-msg :agent "did something" :gate-trace '((:gate "shell" :result :blocked :reason "rm -rf")))
(dolist (ch (coerce "/why" 'list))
(on-key (char-code ch)))
(on-key 13)
(let* ((msgs (st :messages))
(m (aref msgs (1- (length msgs)))))
(fiveam:is (eq :system (getf m :role)))
(fiveam:is (search "[BLOCKED]" (getf m :content)))
(fiveam:is (search "shell" (getf m :content)))))
(fiveam:test test-why-no-trace
"Contract v0.7.2: /why with no gate trace shows fallback message."
(init-state)
(dolist (ch (coerce "/why" 'list))
(on-key (char-code ch)))
(on-key 13)
(let* ((msgs (st :messages))
(m (aref msgs (1- (length msgs)))))
(fiveam:is (search "No recent" (getf m :content)))))
#+end_src