diff --git a/lib/ruby_llm/attachment.rb b/lib/ruby_llm/attachment.rb index f6d4d0454..8041b11e4 100644 --- a/lib/ruby_llm/attachment.rb +++ b/lib/ruby_llm/attachment.rb @@ -62,9 +62,8 @@ def encoded def save(path) return unless io_like? - File.open(path, 'w') do |f| - f.puts(@source.read) - end + @source.rewind if @source.respond_to?(:rewind) + File.binwrite(path, @source.read) end def for_llm diff --git a/spec/ruby_llm/attachment_spec.rb b/spec/ruby_llm/attachment_spec.rb index 2bcd8cd92..265221615 100644 --- a/spec/ruby_llm/attachment_spec.rb +++ b/spec/ruby_llm/attachment_spec.rb @@ -3,6 +3,8 @@ require 'spec_helper' require 'open3' require 'rbconfig' +require 'stringio' +require 'tempfile' RSpec.describe RubyLLM::Attachment do it 'supports path attachments from the public API' do @@ -22,4 +24,17 @@ expect(status.success?).to be(true), stderr expect(stdout.strip).to eq('ruby.txt,text/plain') end + + it 'saves io attachments without altering binary content' do + binary_content = "\x00\xFFbinary\npayload".b + io = StringIO.new(binary_content) + io.read(2) + attachment = described_class.new(io, filename: 'payload.bin') + + Tempfile.create('attachment') do |file| + attachment.save(file.path) + + expect(File.binread(file.path)).to eq(binary_content) + end + end end