Module: RubyLLM::Toolbox::ProcessRunner
- Defined in:
- lib/ruby_llm/toolbox/process_runner.rb
Overview
Shared subprocess runner used by BashTool and the Docker sandbox. Always array-form (no shell), streams both pipes so a chatty child can’t deadlock on a full pipe buffer, and hard-kills the process if it blows the wall-clock budget.
Returns [stdout, stderr, status] where status is a Process::Status or the symbol :timeout.
Class Method Summary collapse
- .capture(argv, env: {}, stdin: nil, timeout: 30, unsetenv_others: true, chdir: nil, rlimits: {}) ⇒ Object
- .kill(pid) ⇒ Object
- .pump(stdout, stderr, wait_thr, timeout) ⇒ Object
- .write_stdin(io, stdin) ⇒ Object
Class Method Details
.capture(argv, env: {}, stdin: nil, timeout: 30, unsetenv_others: true, chdir: nil, rlimits: {}) ⇒ Object
18 19 20 21 22 23 24 25 26 |
# File 'lib/ruby_llm/toolbox/process_runner.rb', line 18 def capture(argv, env: {}, stdin: nil, timeout: 30, unsetenv_others: true, chdir: nil, rlimits: {}) opts = { unsetenv_others: unsetenv_others } opts[:chdir] = chdir if chdir opts.merge!(rlimits) if rlimits && !rlimits.empty? Open3.popen3(env, *argv, **opts) do |i, o, e, thr| write_stdin(i, stdin) pump(o, e, thr, timeout) end end |
.kill(pid) ⇒ Object
65 66 67 68 69 |
# File 'lib/ruby_llm/toolbox/process_runner.rb', line 65 def kill(pid) Process.kill("KILL", pid) rescue StandardError nil end |
.pump(stdout, stderr, wait_thr, timeout) ⇒ Object
41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 |
# File 'lib/ruby_llm/toolbox/process_runner.rb', line 41 def pump(stdout, stderr, wait_thr, timeout) out = +"" err = +"" readers = [stdout, stderr] Timeout.timeout(timeout) do until readers.empty? ready, = IO.select(readers) ready.each do |io| chunk = io.read_nonblock(4096) (io.equal?(stdout) ? out : err) << chunk rescue IO::WaitReadable next rescue EOFError readers.delete(io) end end [out, err, wait_thr.value] end rescue Timeout::Error kill(wait_thr.pid) [out, err, :timeout] end |
.write_stdin(io, stdin) ⇒ Object
28 29 30 31 32 33 34 35 36 37 38 39 |
# File 'lib/ruby_llm/toolbox/process_runner.rb', line 28 def write_stdin(io, stdin) io.write(stdin) if stdin && !stdin.empty? rescue StandardError # Child may have exited/closed the pipe before we finished writing. nil ensure begin io.close rescue StandardError nil end end |