Class: RubyLLM::CodeMode
- Inherits:
-
Tool
- Object
- Tool
- RubyLLM::CodeMode
- Defined in:
- lib/ruby_llm/code_mode.rb
Defined Under Namespace
Classes: Mount
Constant Summary collapse
- VERSION =
"0.1.1"- DEFAULT_TIMEOUT_MS =
30_000- DEFAULT_FUEL_MS =
10_000- FIXED_DESCRIPTION =
"Executes Ruby code inside a secure sandbox and returns what it produced.\n\n## How to use\n\nPass a complete, self-contained Ruby script as the `code` argument. It runs\nas a fresh Ruby 4.0 process with:\n- no network, no threads, no subprocesses, and no access to the host\n filesystem outside the mounted folders listed below;\n- a private writable scratch directory at `/work`, wiped between executions;\n- no state carried over between executions, except the contents of\n read-write folders.\n\nCapture progress with `puts` (returned as `stdout`) and end with a value or\na JSON-serializable data structure (returned as `value`; non-serializable\nobjects come back as their inspect string). If the code raises, the error\nclass, message and backtrace are returned so you can fix and retry.\n".freeze
Class Method Summary collapse
- .build_description ⇒ Object
- .configuration ⇒ Object
- .description(text = nil) ⇒ Object
- .inherited(subclass) ⇒ Object
- .mount(source:, dest:, description: nil) ⇒ Object
- .mount_rw(source:, dest:, description: nil) ⇒ Object
- .mounts ⇒ Object
- .tool_name ⇒ Object
- .warmup ⇒ Object
Instance Method Summary collapse
Class Method Details
.build_description ⇒ Object
66 67 68 69 70 71 72 73 |
# File 'lib/ruby_llm/code_mode.rb', line 66 def build_description read_only, read_write = mounts.partition { |m| m.mode == :read_only } [ FIXED_DESCRIPTION.rstrip, folder_section("## Read-only folders (readable, never writable)", read_only), folder_section("## Read-write folders (readable and writable)", read_write) ].compact.join("\n\n") end |
.configuration ⇒ Object
58 59 60 61 62 63 64 |
# File 'lib/ruby_llm/code_mode.rb', line 58 def configuration @configuration ||= SecurityBox::Configuration.build( timeout_ms: DEFAULT_TIMEOUT_MS, fuel_ms: DEFAULT_FUEL_MS, mounts: mounts.map(&:payload) ) end |
.description(text = nil) ⇒ Object
75 76 77 78 79 80 81 |
# File 'lib/ruby_llm/code_mode.rb', line 75 def description(text = nil) raise ArgumentError, "RubyLLM::CodeMode builds the tool description from the declared mounts; " \ "the description is fixed and cannot be set by hand" if text build_description end |
.inherited(subclass) ⇒ Object
87 88 89 90 91 |
# File 'lib/ruby_llm/code_mode.rb', line 87 def inherited(subclass) super subclass.instance_variable_set(:@mounts, mounts.dup) subclass.instance_variable_set(:@configuration, nil) end |
.mount(source:, dest:, description: nil) ⇒ Object
46 47 48 |
# File 'lib/ruby_llm/code_mode.rb', line 46 def mount(source:, dest:, description: nil) add_mount(source, dest, :read_only, description) end |
.mount_rw(source:, dest:, description: nil) ⇒ Object
50 51 52 |
# File 'lib/ruby_llm/code_mode.rb', line 50 def mount_rw(source:, dest:, description: nil) add_mount(source, dest, :read_write, description) end |
.mounts ⇒ Object
54 55 56 |
# File 'lib/ruby_llm/code_mode.rb', line 54 def mounts @mounts ||= [] end |
.tool_name ⇒ Object
39 40 41 42 43 44 |
# File 'lib/ruby_llm/code_mode.rb', line 39 def tool_name leaf = name.to_s.split('::').last return '' unless leaf RubyLLM::Support::Utils.underscore(leaf).delete_suffix('_tool') end |
.warmup ⇒ Object
83 84 85 |
# File 'lib/ruby_llm/code_mode.rb', line 83 def warmup SecurityBox.warmup(timeout_ms: DEFAULT_TIMEOUT_MS, fuel_ms: DEFAULT_FUEL_MS) end |
Instance Method Details
#execute(code:) ⇒ Object
123 124 125 126 127 |
# File 'lib/ruby_llm/code_mode.rb', line 123 def execute(code:) format_result(sandbox.eval(code)) rescue SecurityBox::Error => e { status: "sandbox_error", error: { class: e.class.name, message: e. } } end |