Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -84,8 +84,11 @@ def format
return nil unless tc

name = tc[:name]
args = tc[:arguments]
"TOOL: #{name} #{args.inspect}" if name
return nil unless name

args = tc[:arguments] || {}
tool_use = ToolUse.new(name:, arguments: args)
tool_use.format
end
end
end
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,10 @@ module Messages
# Example:
# {"type":"tool_execution_end"}
class ToolExecutionEndMessage < Message
#: () -> String
def format
"⚙ tool execution complete"
end
end
end
end
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,10 @@ module Messages
# Example:
# {"type":"tool_execution_start"}
class ToolExecutionStartMessage < Message
#: () -> String
def format
"⚙ executing tool..."
end
end
end
end
Expand Down
11 changes: 11 additions & 0 deletions lib/roast/cogs/agent/providers/pi/messages/turn_end_message.rb
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,17 @@ def content
def stop_reason
@message&.dig(:stopReason)
end

# Format for progress display
#
#: () -> String?
def format
u = usage
return nil unless u

cost_str = u.dig(:cost, :total) ? sprintf("$%.6f", u.dig(:cost, :total)) : "n/a"
"--- turn end (#{model || "unknown"}: #{u[:input] || 0} in, #{u[:output] || 0} out, #{cost_str}) ---"
end
end
end
end
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,10 @@ module Messages
# Example:
# {"type":"turn_start"}
class TurnStartMessage < Message
#: () -> String
def format
"--- turn start ---"
end
end
end
end
Expand Down
7 changes: 4 additions & 3 deletions lib/roast/cogs/agent/providers/pi/pi_invocation.rb
Original file line number Diff line number Diff line change
Expand Up @@ -130,10 +130,11 @@ def handle_message(message)
@result.success = true
when Messages::TurnEndMessage
accumulate_turn_stats(message)
when Messages::MessageUpdateMessage
# Show progress for text deltas
end

if @show_progress
formatted = message.format
puts formatted if formatted.present? && @show_progress
puts formatted if formatted.present?
end

unless message.unparsed.blank?
Expand Down
57 changes: 57 additions & 0 deletions lib/roast/cogs/agent/providers/pi/tool_result.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
# typed: true
# frozen_string_literal: true

module Roast
module Cogs
class Agent < Cog
module Providers
class Pi < Provider
# Formats a Pi tool execution result for progress display
#
# Tool results represent the output of a tool execution, which may be
# successful content or an error.
class ToolResult
#: String
attr_reader :tool_name

#: String?
attr_reader :content

#: bool
attr_reader :is_error

#: (tool_name: String, content: String?, is_error: bool) -> void
def initialize(tool_name:, content:, is_error:)
@tool_name = tool_name
@content = content
@is_error = is_error
end

#: () -> String
def format
status = is_error ? "ERROR" : "OK"
preview = content_preview
"RESULT [#{tool_name}] #{status}#{preview ? ": #{preview}" : ""}"
end

private

MAX_PREVIEW_LENGTH = 200 #: Integer

#: () -> String?
def content_preview
return nil if content.nil? || content.empty?

truncated = content.strip.gsub(/\s+/, " ")
if truncated.length > MAX_PREVIEW_LENGTH
"#{truncated[0...MAX_PREVIEW_LENGTH]}..."
else
truncated
end
end
end
end
end
end
end
end
90 changes: 90 additions & 0 deletions lib/roast/cogs/agent/providers/pi/tool_use.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
# typed: true
# frozen_string_literal: true

module Roast
module Cogs
class Agent < Cog
module Providers
class Pi < Provider
# Formats a Pi tool call for progress display
#
# Pi tool calls come from `toolcall_end` events in `message_update` messages.
# Each tool has a name and arguments hash. Known tools get specialized formatting;
# unknown tools get a generic display.
class ToolUse
#: String
attr_reader :name

#: Hash[Symbol, untyped]
attr_reader :arguments

#: (name: String, arguments: Hash[Symbol, untyped]) -> void
def initialize(name:, arguments:)
@name = name
@arguments = arguments
end

#: () -> String
def format
format_method_name = "format_#{name}".to_sym
return send(format_method_name) if respond_to?(format_method_name, true)

format_unknown
end

private

#: () -> String
def format_bash
command = arguments[:command] || arguments[:cmd]
"BASH: #{command}"
end

#: () -> String
def format_read
path = arguments[:path]
"READ: #{path}"
end

#: () -> String
def format_write
path = arguments[:path]
"WRITE: #{path}"
end

#: () -> String
def format_edit
path = arguments[:path]
"EDIT: #{path}"
end

#: () -> String
def format_grep
pattern = arguments[:pattern] || arguments[:query]
path = arguments[:path]
"GREP: #{pattern}#{path ? " in #{path}" : ""}"
end

#: () -> String
def format_find
path = arguments[:path] || arguments[:dir]
pattern = arguments[:pattern] || arguments[:name]
"FIND: #{pattern}#{path ? " in #{path}" : ""}"
end

#: () -> String
def format_ls
path = arguments[:path]
"LS: #{path}"
end

#: () -> String
def format_unknown
"TOOL [#{name}] #{arguments.inspect}"
end
end
end
end
end
end
end
Original file line number Diff line number Diff line change
Expand Up @@ -115,8 +115,19 @@ class MessageUpdateMessageTest < ActiveSupport::TestCase
message = MessageUpdateMessage.new(type: "message_update", hash:)

result = message.format
assert_includes result, "TOOL: bash"
assert_includes result, "command"
assert_equal "BASH: ls", result
end

test "format returns ToolUse formatted output for read tool" do
hash = {
assistantMessageEvent: {
type: "toolcall_end",
toolCall: { name: "read", arguments: { path: "/tmp/test.txt" } },
},
}
message = MessageUpdateMessage.new(type: "message_update", hash:)

assert_equal "READ: /tmp/test.txt", message.format
end

test "format returns nil for text_start events" do
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,12 @@ class ToolExecutionEndMessageTest < ActiveSupport::TestCase

assert_equal "tool_execution_end", message.type
end

test "format returns completion marker" do
message = ToolExecutionEndMessage.new(type: "tool_execution_end", hash: {})

assert_equal "⚙ tool execution complete", message.format
end
end
end
end
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,12 @@ class ToolExecutionStartMessageTest < ActiveSupport::TestCase

assert_equal "tool_execution_start", message.type
end

test "format returns execution marker" do
message = ToolExecutionStartMessage.new(type: "tool_execution_start", hash: {})

assert_equal "⚙ executing tool...", message.format
end
end
end
end
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,50 @@ class TurnEndMessageTest < ActiveSupport::TestCase

assert_nil message.stop_reason
end

# format tests

test "format returns summary with model and usage" do
hash = {
message: {
model: "claude-opus-4-6",
usage: { input: 100, output: 50, cost: { total: 0.025 } },
},
}
message = TurnEndMessage.new(type: "turn_end", hash:)

result = message.format

assert_includes result, "turn end"
assert_includes result, "claude-opus-4-6"
assert_includes result, "100 in"
assert_includes result, "50 out"
assert_includes result, "$0.025000"
end

test "format returns nil when no usage" do
hash = { message: { model: "test" } }
message = TurnEndMessage.new(type: "turn_end", hash:)

assert_nil message.format
end

test "format returns nil when message is nil" do
message = TurnEndMessage.new(type: "turn_end", hash: {})

assert_nil message.format
end

test "format shows unknown model when model is nil" do
hash = {
message: {
usage: { input: 10, output: 5, cost: { total: 0.001 } },
},
}
message = TurnEndMessage.new(type: "turn_end", hash:)

assert_includes message.format, "unknown"
end
end
end
end
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,12 @@ class TurnStartMessageTest < ActiveSupport::TestCase

assert_equal "turn_start", message.type
end

test "format returns turn start marker" do
message = TurnStartMessage.new(type: "turn_start", hash: {})

assert_equal "--- turn start ---", message.format
end
end
end
end
Expand Down
Loading
Loading