class RubyLLM::CodeExecution
CodeExecution is the run_code tool Chat#with_code_execution gives the model. Each call runs Ruby, Python, or a shell script in the configured Sandbox, in a fresh working directory with read-only copies of the conversation’s files, and returns the exit code, the output, and every file the code wrote as an attachment on the tool result.
chat = RubyLLM.chat.with_code_execution chat.tools[:run_code] # => #<RubyLLM::CodeExecution ...>
Constants
- DEFAULT_TIMEOUT
-
Seconds a run may take unless
timeout:says otherwise. - LANGUAGES
-
The languages code execution can run.
- MAX_FILES
-
Files a run returns at most.
- MAX_FILE_SIZE
-
Bytes a returned file may have 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.
Attributes
The extra paths runs may read.
The seconds a run may take.
Public Class Methods
# File lib/ruby_llm/code_execution.rb, line 166 def initialize(sandbox:, attachments: -> { [] }, mounts: -> { {} }, chat: nil, config: nil, package_cache_dir: nil, languages: %i[ruby shell], timeout: DEFAULT_TIMEOUT, network: false, readable: [], grants: -> { {} }, requests: -> { false }, **packages) super() @sandbox = sandbox self.sandbox @attachments = attachments @mounts = mounts @chat = chat @config = config @requested_languages = languages @timeout = timeout @network = network @readable = Array(readable).map { |path| File.expand_path(path) } @grants = grants @requests = requests @packages = Packages.new(sandbox: -> { self.sandbox }, cache_dir: package_cache_dir, **packages) end
Creates the tool for sandbox with the options Chat#with_code_execution takes. sandbox and config may be Procs, called whenever the tool needs them. attachments returns the conversation’s files when called, and mounts a Hash of paths inside the working directory to directories mounted there read-only. chat and config describe where the instrumentation events go. grants returns the hosts and paths the chat’s permissions granted, and requests whether the model can ask for more with request_permission. Raises ConfigurationError without a sandbox.
Public Instance Methods
Source
# File lib/ruby_llm/code_execution.rb, line 213 def description [ "Runs #{language_list} code in a sandbox and returns its exit code, output, and the files it writes.", 'Each call starts in a new empty working directory, and nothing carries over between calls.', "Files attached to the conversation, and files earlier calls returned, are in ./#{Workspace::ATTACHMENTS} " \ '(read-only). Write files to the working directory to return them to the user.', packages_note, network_note, requests_note, "A call stops after #{timeout} seconds." ].compact.join(' ') end
Returns the description the model sees, naming only the languages the sandbox can run.
Source
# File lib/ruby_llm/code_execution.rb, line 243 def execute(language:, code:) language = language.to_s.downcase.to_sym unless languages.include?(language) return { error: "Unsupported language #{language}. Use one of: #{languages.join(', ')}" } end Workspace.open { |workspace| run(Language[language], code, workspace) } end
Runs code written in language and returns its report, followed by the files it wrote as Attachments.
Source
# File lib/ruby_llm/code_execution.rb, line 200 def languages (@languages ||= {}.compare_by_identity)[sandbox] ||= begin options = { env: @packages.base_env(Dir.tmpdir), readable: RubyInstallation.current.readable, denied: @packages.denied } available = @requested_languages.select { |name| self.class.available?(sandbox, Language[name], **options) } raise ConfigurationError, "The sandbox cannot run #{@requested_languages.join(', ')}" 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 146 def network granted = grants[:network] return @network if @network == true || granted.empty? configured = @network.is_a?(Hash) ? Array(@network[:allow]) : [] { allow: (configured + granted).uniq } end
The network access runs get: false, true, or { allow: [...] }, with the hosts the chat’s permissions granted added to the list.
Source
# File lib/ruby_llm/code_execution.rb, line 227 def parameters_schema { 'type' => 'object', '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' } }, 'required' => %w[language code], 'additionalProperties' => false, 'strict' => true } end
Returns the JSON Schema of the language and code arguments.
Source
# File lib/ruby_llm/code_execution.rb, line 187 def read_only? grants[:writable].empty? end
Returns whether runs change nothing outside the sandbox: true until the chat’s permissions grant a writable path.
Source
# File lib/ruby_llm/code_execution.rb, line 193 def sandbox current = @sandbox.is_a?(Proc) ? @sandbox.call : @sandbox current || raise(ConfigurationError, 'Code execution needs a sandbox. Set config.sandbox = :mxc.') end
Returns the Sandbox the code runs in. Raises ConfigurationError when there is none.