Class: Rubino::Tools::RetrieveOutputTool

Inherits:
Base
  • Object
show all
Defined in:
lib/rubino/tools/retrieve_output_tool.rb

Overview

Recovers the full, uncompressed output of an earlier tool call by its id.

When tool-output compression hides lower-signal lines, the executor spills the verbatim original to <home>/tool-results/<sanitized id>.txt and the compressed view ends with a pointer carrying that id. This tool reads that file back — the ONLY recovery path (there is deliberately no cat-able filesystem path in the model-facing pointer, so a small model can’t ‘sed`/`grep`/`cat` the spill and re-inflate the very output compression just shrank). Registered only while compression is enabled.

Read-only and low risk: it reads exclusively from the agent’s own tool-results dir, sanitizing the id the SAME way ToolExecutor#spill_full_output sanitizes the call_id, so a ‘../` in the id can’t traverse out.

Instance Attribute Summary

Attributes inherited from Base

#cancel_token, #read_tracker, #stream_chunk, #stream_kind

Instance Method Summary collapse

Methods inherited from Base

#cancellation_requested?, #display_name, #emit_chunk, #mcp?, #risky?, #to_tool_definition, workspace_root, workspace_roots

Instance Method Details

#call(arguments) ⇒ Object



52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
# File 'lib/rubino/tools/retrieve_output_tool.rb', line 52

def call(arguments)
  raw = arguments["id"] || arguments[:id]
  return "Error: id is required" if raw.nil? || raw.to_s.strip.empty?

  # Sanitize identically to ToolExecutor#spill_full_output so the id maps
  # to the same file, and a traversal attempt collapses to underscores.
  id = raw.to_s.gsub(/[^a-zA-Z0-9_.-]/, "_")
  return "Error: id is required" if id.empty?

  path = File.join(Rubino.home_path, "tool-results", "#{id}.txt")
  return "No stored output for id=#{id} (it may have expired)." unless File.file?(path)

  File.read(path)
rescue StandardError => e
  "Error: could not retrieve output for id=#{arguments["id"] || arguments[:id]}: #{e.message}"
end

#config_keyObject

Gate on the SAME key the compression feature uses, so it disappears from the registry whenever compression is off (the default).



25
26
27
# File 'lib/rubino/tools/retrieve_output_tool.rb', line 25

def config_key
  "tool_output_compression"
end

#descriptionObject



29
30
31
32
33
# File 'lib/rubino/tools/retrieve_output_tool.rb', line 29

def description
  "Retrieve the full, uncompressed output of an earlier tool call by its id — " \
    "use ONLY when a specific hidden line is needed; the compressed view already " \
    "keeps the important content (errors/failures, summary, changes)."
end

#input_schemaObject



35
36
37
38
39
40
41
42
43
44
45
46
# File 'lib/rubino/tools/retrieve_output_tool.rb', line 35

def input_schema
  {
    type: "object",
    properties: {
      id: {
        type: "string",
        description: "The id printed in a compression pointer (retrieve_output id=…)."
      }
    },
    required: %w[id]
  }
end

#nameObject



19
20
21
# File 'lib/rubino/tools/retrieve_output_tool.rb', line 19

def name
  "retrieve_output"
end

#risk_levelObject



48
49
50
# File 'lib/rubino/tools/retrieve_output_tool.rb', line 48

def risk_level
  :low
end