From 4e87cf6a03c354be47925ae2b198bbb40178ae74 Mon Sep 17 00:00:00 2001 From: Amr Gharbeia Date: Fri, 8 May 2026 17:21:01 -0400 Subject: [PATCH] =?UTF-8?q?v0.7.2:=20wire=20gate-trace-lines=20into=20view?= =?UTF-8?q?-chat=20=E2=80=94=20TDD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Gate trace lines rendered below each agent message in dim color. Collapsed-gates state field for Tab toggle (default: visible). Uses passepartout::gate-trace-lines for colored entries. - channel-tui-view: view-chat renders gate-trace after message content - channel-tui-state: :collapsed-gates field in init-state - View tests: 29/29 (1 new state-field test) --- lisp/channel-tui-state.lisp | 3 ++- lisp/channel-tui-view.lisp | 29 +++++++++++++++++++++-------- org/channel-tui-state.org | 3 ++- org/channel-tui-view.org | 29 +++++++++++++++++++++-------- 4 files changed, 46 insertions(+), 18 deletions(-) diff --git a/lisp/channel-tui-state.lisp b/lisp/channel-tui-state.lisp index e1d9d49..19ca8a2 100644 --- a/lisp/channel-tui-state.lisp +++ b/lisp/channel-tui-state.lisp @@ -114,7 +114,8 @@ See *tui-theme-presets* for named presets (dark, light, solarized, gruvbox).") :scroll-offset 0 :busy nil :cursor-pos 0 :pending-ctrl-x nil :scroll-at-bottom t :scroll-notify nil - :streaming-text nil :url-buffer nil ; v0.7.1 + :streaming-text nil :url-buffer nil ; v0.7.1 + :collapsed-gates nil ; v0.7.2 :dirty (list nil nil nil)))) (defun now () diff --git a/lisp/channel-tui-view.lisp b/lisp/channel-tui-view.lisp index 1796340..f9dc19b 100644 --- a/lisp/channel-tui-view.lisp +++ b/lisp/channel-tui-view.lisp @@ -86,14 +86,21 @@ Returns list of trimmed strings. Single words wider than width are split." (prefix (case role (:user "⬆") (:agent "⬇") (t " "))) (line-text (format nil "~a [~a] ~a" prefix time content)) (wrapped (word-wrap line-text (- w 2)))) - (dolist (line wrapped) - (when (< y (1- h)) - (if (eq role :agent) - (let ((segments (parse-markdown-spans line))) - (setf y (render-styled win segments y 1 w))) - (progn - (add-string win line :y y :x 1 :n (1- w) :fgcolor color) - (incf y)))))))))) + (dolist (line wrapped) + (when (< y (1- h)) + (if (eq role :agent) + (let ((segments (parse-markdown-spans line))) + (setf y (render-styled win segments y 1 w))) + (progn + (add-string win line :y y :x 1 :n (1- w) :fgcolor color) + (incf y))))) + ;; v0.7.2: gate trace below agent messages + (let ((gate-trace (getf msg :gate-trace))) + (when (and gate-trace (not (member i (st :collapsed-gates)))) + (dolist (entry (passepartout::gate-trace-lines gate-trace)) + (when (< y (1- h)) + (add-string win (car entry) :y y :x 3 :n (- w 4) :fgcolor (or (getf (cdr entry) :fgcolor) :dim)) + (incf y)))))))))) (refresh win)) (defun view-input (win) @@ -386,3 +393,9 @@ ASCII < 128 = 1. CJK, fullwidth, emoji = 2. Combining marks = 0. Tab = 8." '((:gate "network" :result :approval))))) (is (= 1 (length lines))) (is (search "HITL" (caar lines))))) + +(test test-init-state-has-collapsed-gates + "Contract v0.7.2: init-state includes :collapsed-gates field." + (passepartout.channel-tui::init-state) + (let ((cg (passepartout.channel-tui::st :collapsed-gates))) + (is (null cg)))) diff --git a/org/channel-tui-state.org b/org/channel-tui-state.org index 061807a..ae9b983 100644 --- a/org/channel-tui-state.org +++ b/org/channel-tui-state.org @@ -134,7 +134,8 @@ See *tui-theme-presets* for named presets (dark, light, solarized, gruvbox).") :scroll-offset 0 :busy nil :cursor-pos 0 :pending-ctrl-x nil :scroll-at-bottom t :scroll-notify nil - :streaming-text nil :url-buffer nil ; v0.7.1 + :streaming-text nil :url-buffer nil ; v0.7.1 + :collapsed-gates nil ; v0.7.2 :dirty (list nil nil nil)))) #+end_src diff --git a/org/channel-tui-view.org b/org/channel-tui-view.org index 7cde77b..5254c4d 100644 --- a/org/channel-tui-view.org +++ b/org/channel-tui-view.org @@ -134,14 +134,21 @@ Returns list of trimmed strings. Single words wider than width are split." (prefix (case role (:user "⬆") (:agent "⬇") (t " "))) (line-text (format nil "~a [~a] ~a" prefix time content)) (wrapped (word-wrap line-text (- w 2)))) - (dolist (line wrapped) - (when (< y (1- h)) - (if (eq role :agent) - (let ((segments (parse-markdown-spans line))) - (setf y (render-styled win segments y 1 w))) - (progn - (add-string win line :y y :x 1 :n (1- w) :fgcolor color) - (incf y)))))))))) + (dolist (line wrapped) + (when (< y (1- h)) + (if (eq role :agent) + (let ((segments (parse-markdown-spans line))) + (setf y (render-styled win segments y 1 w))) + (progn + (add-string win line :y y :x 1 :n (1- w) :fgcolor color) + (incf y))))) + ;; v0.7.2: gate trace below agent messages + (let ((gate-trace (getf msg :gate-trace))) + (when (and gate-trace (not (member i (st :collapsed-gates)))) + (dolist (entry (passepartout::gate-trace-lines gate-trace)) + (when (< y (1- h)) + (add-string win (car entry) :y y :x 3 :n (- w 4) :fgcolor (or (getf (cdr entry) :fgcolor) :dim)) + (incf y)))))))))) (refresh win)) #+end_src @@ -452,4 +459,10 @@ ASCII < 128 = 1. CJK, fullwidth, emoji = 2. Combining marks = 0. Tab = 8." '((:gate "network" :result :approval))))) (is (= 1 (length lines))) (is (search "HITL" (caar lines))))) + +(test test-init-state-has-collapsed-gates + "Contract v0.7.2: init-state includes :collapsed-gates field." + (passepartout.channel-tui::init-state) + (let ((cg (passepartout.channel-tui::st :collapsed-gates))) + (is (null cg)))) #+end_src