class RubyLLM::CodeExecution
CodeExecution is the run_code tool Chat#with_code_execution gives the model. Each call runs Ruby, Python, JavaScript, or a shell script in a Sandbox, in a fresh run directory with read-only copies of the conversation’s files, and returns the exit code, the output, and every file the code wrote there as an attachment on the tool result. In a chat with a file store (see Chat#with_file_store), runs work with the chat’s files instead. With FileStore::Directory, code runs in the store’s folder and changes the files in place. With any other store, each run has read-only copies of the conversation’s files as usual, copies in the files the model names in files, and what the code writes is saved back to the store.
Calls run in the chat’s default sandbox. With escalate_to:, the model may name a wider sandbox for one call and say why; that call waits for Chat#approve, and the next call is back in the default.
chat = RubyLLM.chat.with_code_execution(escalate_to: [WorkspaceSandbox]) chat.tools[:run_code].escalations # => ["workspace"]
Constants
- LANGUAGES
-
The languages code execution can run.
- MAX_FILES
-
Files a run returns at most.
- MAX_MODEL_TEXT
-
Bytes of a text file the model reads back. Larger files, and files that are not images, PDFs, or text, reach the model as a description.
- MAX_OUTPUT
-
Characters of standard output and of standard error kept per run.
- OPTIONS
-
The options
Chat#with_code_executionaccepts. - RUN_DIR
-
The environment variable holding a run’s directory, for code that starts in a sandbox’s own directory.
Public Instance Methods
Source
# File lib/ruby_llm/code_execution.rb, line 339 def description [ "Runs #{language_list} code in a sandbox and returns its exit code, output, and the files it writes.", *files_note, mounts_note, packages_note, directory_note(sandbox), describe_sandbox(sandbox, directory: false), escalations_note ].compact.join(' ') end
Returns the description the model sees, naming only the languages the sandbox can run and the sandboxes it may ask for.
Source
# File lib/ruby_llm/code_execution.rb, line 282 def escalations escalation_sandboxes.keys end
Returns the names of the sandboxes the model may ask for, leaving out those that cannot run on this machine.
chat.tools[:run_code].escalations # => ["workspace", "online"]
# File lib/ruby_llm/code_execution.rb, line 371 def execute(language:, code:, sandbox: nil, reason: nil, files: nil, tool_call: nil) # rubocop:disable Lint/UnusedMethodArgument language = language.to_s.downcase.to_sym unless languages.include?(language) return { error: "Unsupported language #{language}. Use one of: #{languages.join(', ')}" } end runner, error = runner_for(sandbox, code, tool_call) return { error: } if error store = @file_store.call root = store&.local_root Workspace.open(attachments: root.nil?) do |workspace| options = { runner:, name: sandbox, tool_call:, store: } next run_in_place(Language[language], code, workspace, root:, **options) if root run(Language[language], code, workspace, names: files, **options) end rescue Workspace::Unavailable => e { error: e.message } end
Runs code written in language and returns its report, followed by the files it wrote as Attachments. files names the chat’s files to copy into the run directory, for a store without a folder. With sandbox, runs in that sandbox only when the chat recorded an approval for tool_call.
Source
# File lib/ruby_llm/code_execution.rb, line 320 def languages value = sandbox_value key = sandbox_key(value) (@languages ||= {}.compare_by_identity)[key] ||= begin options = { env: @packages.base_env(Dir.tmpdir), readable: @packages.runtimes, denied: @packages.denied } runner = @packages.with_libraries(resolved(value)) checks = @requested_languages.to_h do |name| [name, self.class.check(key, runner, Language[name], **options)] end available = checks.select { |_, check| check == true }.keys raise ConfigurationError, "The sandbox cannot run #{failed_checks(checks)}" if available.empty? available end end
Returns the languages the model may use: those requested that the sandbox can run. Raises ConfigurationError when it can run none.
Source
# File lib/ruby_llm/code_execution.rb, line 300 def mounts mounts = @mounts.is_a?(Proc) ? @mounts.call : @mounts raise ArgumentError, 'mounts: takes a Hash or a Proc that returns one' unless mounts.is_a?(Hash) mounts.to_h do |name, directory| directory = File.expand_path(directory) raise ArgumentError, "#{directory} is not a directory" unless File.directory?(directory) [self.class.mount_name(name), File.realpath(directory)] end end
Returns the directories mounted read-only in each run directory, keyed by their path there. Raises ArgumentError for a path outside the run directory or a directory that does not exist.
Source
# File lib/ruby_llm/code_execution.rb, line 354 def parameters_schema properties = { 'language' => { 'type' => 'string', 'enum' => languages.map(&:to_s), 'description' => 'The language the code is written in' }, 'code' => { 'type' => 'string', 'description' => 'The complete program to run' } } properties['files'] = FILES_PROPERTY if copies_files? properties.merge!(escalation_properties) if escalations.any? { 'type' => 'object', 'properties' => properties, 'required' => properties.keys, 'additionalProperties' => false, 'strict' => true } end
Returns the JSON Schema of the arguments: language and code, files when runs copy in the chat’s files, and sandbox and reason when the model may ask for another sandbox.
# File lib/ruby_llm/code_execution.rb, line 314 def requires_approval?(tool_call = nil) !escalation_for(tool_call).nil? end
Returns whether tool_call asks for a sandbox wider than the default: such a call waits for Chat#approve, every time.
Source
# File lib/ruby_llm/code_execution.rb, line 274 def sandbox resolved(sandbox_value) end
Returns the default Sandbox calls run in. Raises ConfigurationError when there is none.
Source
# File lib/ruby_llm/code_execution.rb, line 292 def summary(name) sandbox = escalation_sandboxes[name.to_s] describe_sandbox(sandbox) if sandbox end
Returns what the sandbox named name allows, in one sentence, for the person approving a call that asks for it, or nil for an unknown name.
chat.tools[:run_code].summary("workspace") # => "Starts in /srv/app. Can change /srv/app. No network access. Stops after 300 seconds."