Module: Tools::ResponseTruncator

Defined in:
lib/tools/response_truncator.rb

Overview

Truncates oversized tool results to protect the agent’s context window.

When a tool returns more characters than the configured threshold, saves the full output to a temp file and returns a truncated version: first 10 lines + notice + last 10 lines. The agent can use the read_file tool with offset/limit to inspect the full output.

Two thresholds exist:

  • **Tool threshold** (~3000 chars) — for raw tool output (bash, web, etc.)

  • **Sub-agent threshold** (~24000 chars) — for curated sub-agent results

Examples:

Truncating a tool result

ResponseTruncator.truncate(huge_string, threshold: 3000)
# => "line 1\nline 2\n...\n---\n⚠️ Response truncated..."

Constant Summary collapse

HEAD_LINES =
10
TAIL_LINES =
10
ATTRIBUTION_FORMAT =

Attribution prefix for messages routed from sub-agent to parent. Shared by Events::Subscribers::SubagentMessageRouter and MarkGoalCompleted to keep formatting consistent.

"[sub-agent %s]: %s"
NOTICE =
<<~NOTICE.strip
  ---
  ⚠️ Response truncated (%<total>d lines total%<reason>s). Full output saved to: %<path>s
  Use `read_file` tool with offset/limit to inspect specific sections.
  ---
NOTICE

Class Method Summary collapse

Class Method Details

.save_full_output(content) ⇒ String

Saves full content to a temp file that persists until system cleanup.

Parameters:

  • content (String)

    the full tool result

Returns:

  • (String)

    absolute path to the saved file



63
64
65
66
67
68
# File 'lib/tools/response_truncator.rb', line 63

def self.save_full_output(content)
  file = Tempfile.create(["tool_result_", ".txt"])
  file.write(content)
  file.close
  file.path
end

.truncate(content, threshold:, reason: nil) ⇒ Object

Truncates content that exceeds the character threshold.

Parameters:

  • content (Object)

    the tool result to (maybe) truncate; non-strings pass through unchanged

  • threshold (Integer)

    character limit before truncation kicks in

  • reason (String, nil) (defaults to: nil)

    why truncation occurred (e.g. “bash output displays first/last 10 lines”)

Returns:

  • (Object)

    original value if non-String/under threshold/few lines, truncated String otherwise



42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
# File 'lib/tools/response_truncator.rb', line 42

def self.truncate(content, threshold:, reason: nil)
  return content unless content.is_a?(String)
  return content if content.length <= threshold

  lines = content.lines
  total = lines.size
  return content if total <= HEAD_LINES + TAIL_LINES

  path = save_full_output(content)
  head = lines.first(HEAD_LINES).join
  tail = lines.last(TAIL_LINES).join
  reason_text = reason ? "#{reason}" : ""
  notice = format(NOTICE, total: total, path: path, reason: reason_text)

  "#{head}\n#{notice}\n\n#{tail}"
end