Description
RubyLLM::Content does not implement #empty?, but several Anthropic provider code paths call msg.content.empty? on message content. When a message has ActiveStorage attachments, extract_content (in active_record/message_methods.rb) wraps the content in a Content object instead of returning a plain String. This causes a NoMethodError when the message is later formatted for the Anthropic API.
Steps to reproduce
- Create a message with ActiveStorage attachments (e.g., via
has_many_attached :attachments on the message model)
- Have the agent respond with tool calls in the same conversation
- On the next turn,
extract_content returns a RubyLLM::Content for the user message with attachments
- The Anthropic provider calls
msg.content.empty? during format_tool_call_with_thinking or format_tool_result
- NoMethodError: undefined method 'empty?' for an instance of RubyLLM::Content
Affected code paths
lib/ruby_llm/providers/anthropic/chat.rb:179 — msg.content.nil? || msg.content.empty?
lib/ruby_llm/providers/anthropic/tools.rb:19 — msg.content.nil? || msg.content.empty?
Expected behavior
RubyLLM::Content should respond to #empty? (returning true when text is nil and attachments are empty), consistent with how String and Array respond to it.
Workaround
RubyLLM::Content.class_eval do
def empty?
text.nil? && attachments.empty?
end
end
Environment
- ruby_llm 1.14.0
- Rails 8.1 with ActiveStorage
- Anthropic provider (Claude models)
Description
RubyLLM::Contentdoes not implement#empty?, but several Anthropic provider code paths callmsg.content.empty?on message content. When a message has ActiveStorage attachments,extract_content(inactive_record/message_methods.rb) wraps the content in aContentobject instead of returning a plain String. This causes aNoMethodErrorwhen the message is later formatted for the Anthropic API.Steps to reproduce
has_many_attached :attachmentson the message model)extract_contentreturns aRubyLLM::Contentfor the user message with attachmentsmsg.content.empty?duringformat_tool_call_with_thinkingorformat_tool_resultAffected code paths
lib/ruby_llm/providers/anthropic/chat.rb:179—msg.content.nil? || msg.content.empty?lib/ruby_llm/providers/anthropic/tools.rb:19—msg.content.nil? || msg.content.empty?Expected behavior
RubyLLM::Contentshould respond to#empty?(returning true when text is nil and attachments are empty), consistent with how String and Array respond to it.Workaround
Environment