TUI: capture Chez parameters across spawn in tool execution
ober
e46e348eab50b6f8bc0eaaaff8bd0459279d2d16
--- a/src/jcode/core/agent.ss +++ b/src/jcode/core/agent.ss @@ -285,11 +285,24 @@ Prefer using the edit tool over write for modifying existing files." (log-info logger "executing-tools" `((count . ,(length tool-calls)))) (if (<= (length tool-calls) 1) (map execute-single-tool tool-calls) - ;; Parallel: spawn a green thread per tool call, join all - (let ((threads (map (lambda (tc) - (spawn (lambda () (execute-single-tool tc)))) - tool-calls))) - (map thread-join! threads)))) + ;; Parallel: spawn a green thread per tool call, join all. + ;; Capture parameters before spawn — Chez parameters are thread-local + ;; and don't inherit. Without this, current-error-port defaults to + ;; real stderr (TTY in raw mode under TUI); log-debug writes back up + ;; the TTY buffer and deadlock the log mutex. Same class of bug as + ;; commit 0a3a04d (TUI worker thread). + (let ((err-port (current-error-port)) + (log-lvl (current-log-level)) + (tool-cb (current-tool-cb))) + (let ((threads (map (lambda (tc) + (spawn (lambda () + (parameterize + ((current-error-port err-port) + (current-log-level log-lvl) + (current-tool-cb tool-cb)) + (execute-single-tool tc))))) + tool-calls))) + (map thread-join! threads))))) (def (execute-single-tool tc) (let* ((name (tool-call-name tc)) --- a/src/jcode/tool/batch.ss +++ b/src/jcode/tool/batch.ss @@ -25,7 +25,13 @@ ((not (list? calls)) "Error: 'calls' must be an array of tool call objects") (else - (let ((results + ;; Capture parameters before spawn — Chez parameters are thread-local + ;; and don't inherit. Without this, current-error-port defaults to real + ;; stderr (TTY in raw mode under TUI), and any log call writes back up + ;; the TTY buffer, deadlocking the log mutex. See agent.ss execute-tool-calls. + (let* ((err-port (current-error-port)) + (log-lvl (current-log-level)) + (results (let ((threads (map (lambda (call) (let ((tool-name (and (hash-table? call) (hash-get call "tool"))) @@ -33,8 +39,16 @@ (or (hash-get call "args") (make-hash-table))))) (if tool-name - (spawn (lambda () (cons tool-name (tool-execute tool-name tool-args)))) - (spawn (lambda () (cons "?" "Error: missing 'tool' field")))))) + (spawn (lambda () + (parameterize + ((current-error-port err-port) + (current-log-level log-lvl)) + (cons tool-name (tool-execute tool-name tool-args))))) + (spawn (lambda () + (parameterize + ((current-error-port err-port) + (current-log-level log-lvl)) + (cons "?" "Error: missing 'tool' field"))))))) calls))) (map thread-join! threads)))) (string-join