diff --git a/lib/roast/cogs/agent/providers/claude/tool_use.rb b/lib/roast/cogs/agent/providers/claude/tool_use.rb index c5f476b9..eb701c4f 100644 --- a/lib/roast/cogs/agent/providers/claude/tool_use.rb +++ b/lib/roast/cogs/agent/providers/claude/tool_use.rb @@ -266,6 +266,33 @@ def format_task details.empty? ? "TASK #{description}" : "TASK #{description} (#{details})" end + # Formats an Agent tool-use line. + # + # Input fields: + # :description (String) – short label for the work [required] + # :run_in_background (bool) – run the agent asynchronously [optional] + # :subagent_type (String) – which agent type to spawn [optional] + # + # Output: "AGENT ", with " (
)" appended when any + # optional field is set: "background" (when :run_in_background is set), + # then :subagent_type — joined with " · " in that order and shown as raw + # values (no key= labels). :description is truncated to TRUNCATE_LIMIT + # chars; :subagent_type is not. + # + # Examples: + # AGENT Find all callers (background · Explore) + # AGENT Summarize the diff + # + #: () -> String + def format_agent + description = truncate(input[:description]) + details = [ + ("background" if input[:run_in_background]), + input[:subagent_type], + ].compact.join(" · ") + details.empty? ? "AGENT #{description}" : "AGENT #{description} (#{details})" + end + #: () -> String def format_unknown "UNKNOWN [#{name}] #{input.inspect}" diff --git a/test/roast/cogs/agent/providers/claude/tool_use_test.rb b/test/roast/cogs/agent/providers/claude/tool_use_test.rb index f2d86724..158feede 100644 --- a/test/roast/cogs/agent/providers/claude/tool_use_test.rb +++ b/test/roast/cogs/agent/providers/claude/tool_use_test.rb @@ -338,6 +338,36 @@ class ToolUseTest < ActiveSupport::TestCase assert_equal "TASK #{truncated} (#{long} · #{long})", output end + # format_agent + + test "format_agent renders the description alone with no optional fields" do + tool_use = ToolUse.new(name: :agent, input: { description: "Find all callers" }) + + output = tool_use.format + + assert_equal "AGENT Find all callers", output + end + + test "format_agent renders the description with all optional fields" do + input = { description: "Audit", run_in_background: true, subagent_type: "Explore" } + tool_use = ToolUse.new(name: :agent, input: input) + + output = tool_use.format + + assert_equal "AGENT Audit (background · Explore)", output + end + + test "format_agent truncates the description but not the subagent type" do + long = "a" * (ToolUse::TRUNCATE_LIMIT + 10) + truncated = "#{"a" * (ToolUse::TRUNCATE_LIMIT - 3)}..." + input = { description: long, subagent_type: long } + tool_use = ToolUse.new(name: :agent, input: input) + + output = tool_use.format + + assert_equal "AGENT #{truncated} (#{long})", output + end + test "format calls format_unknown for unknown tool" do tool_use = ToolUse.new(name: :unknown_tool, input: { arg: "value" })