Avoid truncated output filename collisions
ober
2d4413a5a8703aedc9cde66c2c25ac9f2de0b934
--- a/src/jcode/core/agent.ss +++ b/src/jcode/core/agent.ss @@ -284,6 +284,23 @@ Be concise. Prefer edit over write for modifying existing files. *local-max-tool-bytes* *max-tool-bytes*))) +(def (write-truncated-output text) + "Write TEXT to a unique file under truncated-dir and return its path. + Tool calls can finish in parallel, so second-level timestamps are not + unique enough." + (let ((dir (truncated-dir)) + (stamp (time-second (current-time)))) + (let loop ((attempt 0)) + (let ((file (path-join dir + (format "tool-~a-~a.txt" stamp (random 1000000000))))) + (guard (e [#t + (if (< attempt 100) + (loop (+ attempt 1)) + (error 'write-truncated-output + "failed to write truncated tool output"))]) + (with-output-to-file file (lambda () (display text))) + file))))) + (def (truncate-tool-output text) "Cap tool output at *max-tool-lines* / *max-tool-bytes*. If truncated, save the full output to ~/.jcode/truncated/ and return a preview + hint." @@ -301,12 +318,10 @@ Be concise. Prefer edit over write for modifying existing files. (>= bytes byte-limit)) ;; Save full output, return preview + hint (let* ((preview (string-join (reverse acc) "\n")) - (file (path-join (truncated-dir) - (format "tool-~a.txt" (time-second (current-time))))) + (file (write-truncated-output text)) (removed (if (> total-bytes byte-limit) (format "~a bytes" (- total-bytes (string-length preview))) (format "~a lines" (- total-lines count))))) - (with-output-to-file file (lambda () (display text))) (string-append preview (format "\n\n...~a truncated...\n\nFull output saved to: ~a\nUse grep to search or read with specific line ranges." removed file)))