Skip to content

Commit 2578caa

Browse files
authored
Enable Langchain::Tool::RubyCodeInterpreter on Ruby 3.3+ (#977)
safe_ruby has supported Ruby 3.3+ since version 1.0.5: ukutaht/safe_ruby#4 (comment) ## Before (using safe_ruby 1.0.4) A `NameError` occurred when running under Ruby 3.3: ```console $ ruby -v ruby 3.3.8 (2025-04-09 revision b200bad6cd) [x86_64-darwin24] $ bundle exec ruby -rlangchain -e "Langchain::Tool::RubyCodeInterpreter.new.execute(input: '[1, 2, 3].map{ |n| n + 1 }')" D, [2025-05-01T00:15:18.396619 #61580] DEBUG -- [Langchain.rb]: Langchain::Tool::RubyCodeInterpreter - Executing "[1, 2, 3].map{ |n| n + 1 }" /Users/koic/.rbenv/versions/3.3.8/lib/ruby/gems/3.3.0/gems/safe_ruby-1.0.4/lib/safe_ruby/runner.rb:45: in `rescue in eval': /var/folders/6j/5l8q3y250b97529_tcssrwlm0000gn/T/saferuby20250430-90315-4c2rkb:17: in `undef_method': undefined method `new' for class `String' (NameError) (RuntimeError) klass.send(:undef_method, method) ^^^^^ Did you mean? next from /var/folders/6j/5l8q3y250b97529_tcssrwlm0000gn/T/saferuby20250430-90315-4c2rkb:17:in `block in keep_methods' from /var/folders/6j/5l8q3y250b97529_tcssrwlm0000gn/T/saferuby20250430-90315-4c2rkb:16:in `each' from /var/folders/6j/5l8q3y250b97529_tcssrwlm0000gn/T/saferuby20250430-90315-4c2rkb:16:in `keep_methods' from /var/folders/6j/5l8q3y250b97529_tcssrwlm0000gn/T/saferuby20250430-90315-4c2rkb:37:in `<main>' from /Users/koic/.rbenv/versions/3.3.8/lib/ruby/gems/3.3.0/gems/safe_ruby-1.0.4/lib/safe_ruby/runner.rb:41:in `eval' from /Users/koic/.rbenv/versions/3.3.8/lib/ruby/gems/3.3.0/gems/safe_ruby-1.0.4/lib/safe_ruby/runner.rb:20:in `eval' from /Users/koic/src/github.com/patterns-ai-core/langchainrb/lib/langchain/tool/ruby_code_interpreter.rb:38:in `safe_eval' from /Users/koic/src/github.com/patterns-ai-core/langchainrb/lib/langchain/tool/ruby_code_interpreter.rb:34:in `execute' from -e:1:in `<main>' <internal:marshal>:34:in `load': incompatible marshal file format (can't be read) (TypeError) format version 4.8 required; 47.118 given from /Users/koic/.rbenv/versions/3.3.8/lib/ruby/gems/3.3.0/gems/safe_ruby-1.0.4/lib/safe_ruby/runner.rb:42:in `eval' from /Users/koic/.rbenv/versions/3.3.8/lib/ruby/gems/3.3.0/gems/safe_ruby-1.0.4/lib/safe_ruby/runner.rb:20:in `eval' from /Users/koic/src/github.com/patterns-ai-core/langchainrb/lib/langchain/tool/ruby_code_interpreter.rb:38:in `safe_eval' from /Users/koic/src/github.com/patterns-ai-core/langchainrb/lib/langchain/tool/ruby_code_interpreter.rb:34:in `execute' from -e:1:in `<main>' ``` ## After (using safe_ruby 1.0.5) No error occurs: ```console $ ruby -v ruby 3.3.8 (2025-04-09 revision b200bad6cd) [x86_64-darwin24] $ bundle exec ruby -rlangchain -e "Langchain::Tool::RubyCodeInterpreter.new.execute(input: '[1, 2, 3].map{ |n| n + 1 }')" D, [2025-05-01T00:16:09.404532 #63102] DEBUG -- [Langchain.rb]: Langchain::Tool::RubyCodeInterpreter - Executing "[1, 2, 3].map{ |n| n + 1 }" ``` Ruby 3.4 works as well.
1 parent d06acdb commit 2578caa

File tree

5 files changed

+24
-31
lines changed

5 files changed

+24
-31
lines changed

Gemfile.lock

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,8 @@ GEM
6565
bigdecimal (3.1.8)
6666
builder (3.3.0)
6767
byebug (12.0.0)
68-
childprocess (5.0.0)
68+
childprocess (5.1.0)
69+
logger (~> 1.5)
6970
chroma-db (0.6.0)
7071
dry-monads (~> 1.6)
7172
ruby-next (>= 0.15.0)
@@ -386,8 +387,8 @@ GEM
386387
ruby-progressbar (1.13.0)
387388
ruby-rc4 (0.1.5)
388389
rubyzip (2.3.2)
389-
safe_ruby (1.0.4)
390-
childprocess (>= 0.3.9)
390+
safe_ruby (1.0.5)
391+
childprocess (~> 5)
391392
securerandom (0.4.1)
392393
sequel (5.87.0)
393394
bigdecimal
@@ -486,7 +487,7 @@ DEPENDENCIES
486487
rubocop
487488
ruby-anthropic (~> 0.4)
488489
ruby-openai (~> 7.1.0)
489-
safe_ruby (~> 1.0.4)
490+
safe_ruby (~> 1.0.5)
490491
sequel (~> 5.87.0)
491492
standard (>= 1.35.1)
492493
vcr

langchain.gemspec

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -69,7 +69,7 @@ Gem::Specification.new do |spec|
6969
spec.add_development_dependency "roo", "~> 2.10.0"
7070
spec.add_development_dependency "roo-xls", "~> 1.2.0"
7171
spec.add_development_dependency "ruby-openai", "~> 7.1.0"
72-
spec.add_development_dependency "safe_ruby", "~> 1.0.4"
72+
spec.add_development_dependency "safe_ruby", "~> 1.0.5"
7373
spec.add_development_dependency "sequel", "~> 5.87.0"
7474
spec.add_development_dependency "weaviate-ruby", "~> 0.9.2"
7575
spec.add_development_dependency "wikipedia-client", "~> 1.17.0"

lib/langchain.rb

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -29,10 +29,6 @@
2929

3030
loader.collapse("#{__dir__}/langchain/llm/response")
3131

32-
# RubyCodeInterpreter does not work with Ruby 3.3;
33-
# https://github.com/ukutaht/safe_ruby/issues/4
34-
loader.ignore("#{__dir__}/langchain/tool/ruby_code_interpreter") if RUBY_VERSION >= "3.3.0"
35-
3632
loader.setup
3733

3834
# Langchain.rb a is library for building LLM-backed Ruby applications. It is an abstraction layer that sits on top of the emerging AI-related tools that makes it easy for developers to consume and string those services together.

lib/langchain/tool/ruby_code_interpreter.rb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ module Langchain::Tool
55
# A tool that execute Ruby code in a sandboxed environment.
66
#
77
# Gem requirements:
8-
# gem "safe_ruby", "~> 1.0.4"
8+
# gem "safe_ruby", "~> 1.0.5"
99
#
1010
# Usage:
1111
# interpreter = Langchain::Tool::RubyCodeInterpreter.new
Lines changed: 17 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1,29 +1,25 @@
11
# frozen_string_literal: true
22

3-
# RubyCodeInterpreter does not work with Ruby 3.3;
4-
# https://github.com/ukutaht/safe_ruby/issues/4
5-
if RUBY_VERSION <= "3.2"
6-
RSpec.describe Langchain::Tool::RubyCodeInterpreter do
7-
describe "#execute" do
8-
it "executes the expression" do
9-
response = subject.execute(input: '"hello world".reverse!')
10-
expect(response).to be_a(Langchain::ToolResponse)
11-
expect(response.content).to eq("dlrow olleh")
12-
end
3+
RSpec.describe Langchain::Tool::RubyCodeInterpreter do
4+
describe "#execute" do
5+
it "executes the expression" do
6+
response = subject.execute(input: '"hello world".reverse!')
7+
expect(response).to be_a(Langchain::ToolResponse)
8+
expect(response.content).to eq("dlrow olleh")
9+
end
1310

14-
it "executes a more complicated expression" do
15-
code = <<~CODE
16-
def reverse(string)
17-
string.reverse!
18-
end
11+
it "executes a more complicated expression" do
12+
code = <<~CODE
13+
def reverse(string)
14+
string.reverse!
15+
end
1916
20-
reverse('hello world')
21-
CODE
17+
reverse('hello world')
18+
CODE
2219

23-
response = subject.execute(input: code)
24-
expect(response).to be_a(Langchain::ToolResponse)
25-
expect(response.content).to eq("dlrow olleh")
26-
end
20+
response = subject.execute(input: code)
21+
expect(response).to be_a(Langchain::ToolResponse)
22+
expect(response.content).to eq("dlrow olleh")
2723
end
2824
end
2925
end

0 commit comments

Comments
 (0)