Centralize tool result error handling in format with error_line helper#948
Centralize tool result error handling in format with error_line helper#948LasmarKhalifa wants to merge 1 commit into
Conversation
d674c9e to
9a40624
Compare
9a40624 to
d0ec520
Compare
There was a problem hiding this comment.
Nice foundation PR! The error-handling centralization is clean — pulling the error path into an early-return at the top of format means every downstream formatter only needs to think about the success case. Makes the rest of your stack cleaner.
Two small things to address:
- The
error_linedoc comment could use a couple of examples (see inline comment). - A test for
error_linewhencontentis nil would round out the edge-case coverage.
And lets switch to the xml parser we had talked about
| # Renders "<TOOL> ERROR <message>" with any <tool_use_error> wrapper stripped. | ||
| # | ||
| #: () -> String | ||
| def error_line |
There was a problem hiding this comment.
The doc comment here is good — it explains what the method does. Since this is a foundation helper that every tool in the stack will rely on for error formatting, it would be helpful to expand it a bit:
# Renders "<TOOL> ERROR <message>" with any <tool_use_error> wrapper stripped.
#
# Reads the instance's +content+ and +tool_name+ to produce a single-line
# error summary. Error messages are intentionally NOT truncated so the full
# diagnostic is preserved for debugging.
#
# Examples:
# BASH ERROR File has not been read yet.
# UNKNOWN ERROR command not found
#
#: () -> String
def error_lineThe reason is that someone reading a downstream formatter for the first time will look at error_line to understand the contract — having examples makes that a 5-second task instead of a 30-second one.
| assert_match(/error details/, output) | ||
| end | ||
|
|
||
| test "error_line strips the tool_use_error wrapper and upcases the tool name" do |
There was a problem hiding this comment.
Nice coverage here. One edge case to add: what happens when content is nil? The implementation handles it via content.to_s, but an explicit test documents that expectation:
test "error_line handles nil content gracefully" do
tool_use_message = Claude::Messages::ToolUseMessage.new(
type: :tool_use,
hash: { name: "read", input: {} },
)
tool_result = Claude::ToolResult.new(
tool_use: tool_use_message,
content: nil,
is_error: true,
)
output = tool_result.send(:error_line)
assert_equal "READ ERROR", output
endSomething to think about: when content is nil, this produces "READ ERROR " (with a trailing space) because the string interpolation gives "READ ERROR #{""}". If you'd prefer "READ ERROR" with no trailing space, a .strip or .squeeze(" ") at the end would do it — but it's a very minor cosmetic point.
| # | ||
| #: () -> String | ||
| def error_line | ||
| message = content.to_s.gsub(%r{</?tool_use_error>}, "").strip |
There was a problem hiding this comment.
as we had previously discussed, let's parse this with an xml parser

No description provided.