diff --git a/CHANGELOG.md b/CHANGELOG.md index b93db1744..307be6f84 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,8 @@ ## Unreleased +- Truncate oversized failed tool output, preserving full logs on disk instead of overflowing the model context. + ## 0.147.3 - Fix remote server silently falling back to HTTP when the TLS private key is in SEC1 EC format; validate keys before caching and log HTTP fallback. #521 diff --git a/src/eca/features/tools/util.clj b/src/eca/features/tools/util.clj index 6b21eea93..bee007288 100644 --- a/src/eca/features/tools/util.clj +++ b/src/eca/features/tools/util.clj @@ -242,13 +242,14 @@ [result config tool-call-id] (let [max-lines (get-in config [:toolCall :outputTruncation :lines]) max-size-kb (get-in config [:toolCall :outputTruncation :sizeKb])] - (if (or (nil? max-lines) (nil? max-size-kb) (:error result)) + (if (or (nil? max-lines) (nil? max-size-kb)) result (let [full-text (contents->text (:contents result))] (if (exceeds-truncation-limits? full-text max-lines max-size-kb) (let [saved-path (cache/save-tool-call-output! tool-call-id full-text) truncated (truncate-text full-text max-lines max-size-kb) - notice (str "\n\n[OUTPUT TRUNCATED] The tool call succeeded but the output was truncated. " + outcome (if (:error result) "failed" "succeeded") + notice (str "\n\n[OUTPUT TRUNCATED] The tool call " outcome " and the output was truncated. " "Full output saved to: " saved-path "\n" "Use `eca__grep` or `eca__read_file` with offset/limit to view specific sections. Do not full read the file.")] (assoc result :contents [{:type :text diff --git a/test/eca/features/tools/util_test.clj b/test/eca/features/tools/util_test.clj index a37f8b167..a51884490 100644 --- a/test/eca/features/tools/util_test.clj +++ b/test/eca/features/tools/util_test.clj @@ -66,12 +66,18 @@ (is (string/includes? output-text "[OUTPUT TRUNCATED]")) (is (false? (:error truncated)))))) -(deftest maybe-truncate-output-skips-error-results-test - (testing "does not truncate error results" +(deftest maybe-truncate-output-truncates-error-results-test + (testing "truncates error results and preserves the failure status" (let [long-text (string/join "\n" (repeat 5000 "error line")) result {:error true :contents [{:type :text :text long-text}]} - config (config-with-truncation 100 1)] - (is (= result (tools.util/maybe-truncate-output result config "call-err")))))) + config (config-with-truncation 100 1) + truncated (tools.util/maybe-truncate-output result config "call-err") + output-text (-> truncated :contents first :text)] + (is (true? (:error truncated))) + (is (string/includes? output-text "[OUTPUT TRUNCATED]")) + (is (string/includes? output-text "The tool call failed")) + (is (string/includes? output-text "Full output saved to:")) + (is (not (string/includes? output-text (string/join "\n" (repeat 5000 "error line")))))))) (deftest maybe-truncate-output-nil-config-test (testing "returns result unchanged when truncation config is nil"