diff --git a/lib/roast/cog/output.rb b/lib/roast/cog/output.rb index e4815fcc..e4e7b257 100644 --- a/lib/roast/cog/output.rb +++ b/lib/roast/cog/output.rb @@ -241,8 +241,9 @@ def extract_number_candidates(input) lines.reverse.each do |line| # Look for numbers with various separators, formats, and currency symbols (very permissive) # Matches: 123, 1,234, 1_234, 1 234, 1.23, -1.23, 1.23e10, 1.23e-10 + # Reversed so that the last number on the line is tried first (matching the bottom-up line order) matches = line.scan(/-?[\d\s$¢£€¥.,_]+(?:[eE][+-]?\d+)?/) #: as Array[String] - candidates.concat(matches.map(&:strip)) + candidates.concat(matches.map(&:strip).reverse) end candidates.compact.uniq diff --git a/test/roast/cog/output_test.rb b/test/roast/cog/output_test.rb index e0dc0b73..e3efb4de 100644 --- a/test/roast/cog/output_test.rb +++ b/test/roast/cog/output_test.rb @@ -209,6 +209,78 @@ def raw_text assert_equal 42.50, number_output.float! end + test "output with number support extracts last number from a line with multiple numbers" do + number_output = Class.new(Output) do + include Output::WithNumber + + def raw_text + "12 - 5 = 7" + end + end.new + + assert_equal 7, number_output.integer! + end + + test "output with number support extracts last number from arithmetic expression" do + number_output = Class.new(Output) do + include Output::WithNumber + + def raw_text + "2 + 2 = 4" + end + end.new + + assert_equal 4, number_output.integer! + end + + test "output with number support extracts last number from multi-line response" do + number_output = Class.new(Output) do + include Output::WithNumber + + def raw_text + "First I calculated 2 + 2 = 4\nThen I multiplied 4 * 3 = 12\nFinally 12 - 5 = 7" + end + end.new + + assert_equal 7, number_output.integer! + end + + test "output with number support extracts last number from sentence with embedded numbers" do + number_output = Class.new(Output) do + include Output::WithNumber + + def raw_text + "The answer to 100 divided by 4 is 25" + end + end.new + + assert_equal 25, number_output.integer! + end + + test "output with number support extracts last float from a line with multiple numbers" do + number_output = Class.new(Output) do + include Output::WithNumber + + def raw_text + "3.14 * 2 = 6.28" + end + end.new + + assert_in_delta 6.28, number_output.float! + end + + test "output with number support prefers last line last number over earlier lines" do + number_output = Class.new(Output) do + include Output::WithNumber + + def raw_text + "Step 1: 100\nStep 2: 50\nResult: 42" + end + end.new + + assert_equal 42, number_output.integer! + end + # Test Output subclasses with text formatting capabilities test "output with text support returns stripped text" do text_output = Class.new(Output) do