From af63b1e44aae239e61eaa2889537ff7017a74196 Mon Sep 17 00:00:00 2001 From: Lasmar Khalifa Date: Thu, 2 Jul 2026 11:43:13 -0400 Subject: [PATCH] add read tool formatters --- .../pi/messages/tool_call_message.rb | 18 ++++++++++ .../pi/messages/tool_result_message.rb | 17 ++++++++++ .../pi/messages/tool_call_message_test.rb | 15 +++++++++ .../pi/messages/tool_result_message_test.rb | 33 +++++++++++++++++++ 4 files changed, 83 insertions(+) diff --git a/lib/roast/cogs/agent/providers/pi/messages/tool_call_message.rb b/lib/roast/cogs/agent/providers/pi/messages/tool_call_message.rb index d66c00fb..2f6088b1 100644 --- a/lib/roast/cogs/agent/providers/pi/messages/tool_call_message.rb +++ b/lib/roast/cogs/agent/providers/pi/messages/tool_call_message.rb @@ -61,6 +61,24 @@ def format_bash command.empty? ? "BASH" : "BASH #{command}" end + # Formats a read tool call. + # + # Input fields: + # :path (String) – file to read [required] + # + # Output: "READ ", with :path truncated to TRUNCATE_LIMIT chars. + # A missing path renders the bare "READ". + # + # Examples: + # READ lib/roast.rb + # READ + # + #: () -> String + def format_read + path = truncate(arguments[:path]) + path.empty? ? "READ" : "READ #{path}" + end + # Formats a tool call for which Roast has no dedicated formatter. # # Output: " : , ..." – the upcased tool name, then each diff --git a/lib/roast/cogs/agent/providers/pi/messages/tool_result_message.rb b/lib/roast/cogs/agent/providers/pi/messages/tool_result_message.rb index 05377281..adac0e26 100644 --- a/lib/roast/cogs/agent/providers/pi/messages/tool_result_message.rb +++ b/lib/roast/cogs/agent/providers/pi/messages/tool_result_message.rb @@ -74,6 +74,23 @@ def format_bash ok_line("#{count} #{"line".pluralize(count)}", preview) end + # Formats a read tool result. + # + # Content: the file's text. + # + # Output: "READ OK " – is the line count (pluralized). + # + # Examples: + # READ OK 42 lines + # READ OK 1 line + # READ OK 0 lines + # + #: () -> String + def format_read + count = content.to_s.lines.length + ok_line("#{count} #{"line".pluralize(count)}") + end + # Formats a result for which Roast has no dedicated formatter. # # Content: the tool's output text. diff --git a/test/roast/cogs/agent/providers/pi/messages/tool_call_message_test.rb b/test/roast/cogs/agent/providers/pi/messages/tool_call_message_test.rb index 673f1c84..66de1343 100644 --- a/test/roast/cogs/agent/providers/pi/messages/tool_call_message_test.rb +++ b/test/roast/cogs/agent/providers/pi/messages/tool_call_message_test.rb @@ -26,6 +26,21 @@ class ToolCallMessageTest < ActiveSupport::TestCase assert_equal "BASH #{"x" * (ToolCallMessage::TRUNCATE_LIMIT - 3)}...", msg.format end + test "format renders READ with the path" do + msg = ToolCallMessage.new(id: "1", name: "read", arguments: { path: "lib/roast.rb" }) + assert_equal "READ lib/roast.rb", msg.format + end + + test "format renders a bare READ when the path is missing" do + msg = ToolCallMessage.new(id: "1", name: "read", arguments: {}) + assert_equal "READ", msg.format + end + + test "format truncates a long read path" do + msg = ToolCallMessage.new(id: "1", name: "read", arguments: { path: "x" * 100 }) + assert_equal "READ #{"x" * (ToolCallMessage::TRUNCATE_LIMIT - 3)}...", msg.format + end + test "format renders an unhandled tool as NAME key: value, ..." do msg = ToolCallMessage.new( id: "1", diff --git a/test/roast/cogs/agent/providers/pi/messages/tool_result_message_test.rb b/test/roast/cogs/agent/providers/pi/messages/tool_result_message_test.rb index 9635fc1e..24c92d0b 100644 --- a/test/roast/cogs/agent/providers/pi/messages/tool_result_message_test.rb +++ b/test/roast/cogs/agent/providers/pi/messages/tool_result_message_test.rb @@ -43,6 +43,39 @@ def setup assert_equal "BASH OK 0 lines", msg.format(@context) end + test "format summarizes read output with a line count" do + msg = ToolResultMessage.new( + tool_call_id: "1", + tool_name: "read", + content: "line one\nline two\nline three", + is_error: false, + ) + + assert_equal "READ OK 3 lines", msg.format(@context) + end + + test "format pluralizes a single line of read output" do + msg = ToolResultMessage.new( + tool_call_id: "1", + tool_name: "read", + content: "just one line", + is_error: false, + ) + + assert_equal "READ OK 1 line", msg.format(@context) + end + + test "format reports zero lines when the file is empty" do + msg = ToolResultMessage.new( + tool_call_id: "1", + tool_name: "read", + content: nil, + is_error: false, + ) + + assert_equal "READ OK 0 lines", msg.format(@context) + end + test "format renders NAME ERROR with the message for an error result" do msg = ToolResultMessage.new( tool_call_id: "1",