Class: Rubino::Context::EnvironmentInspector

Inherits:
Object
  • Object
show all
Defined in:
lib/rubino/context/environment_inspector.rb

Overview

Builds the “[Environment]” block injected into every system prompt.

Probes the host once per process for the static bits (OS, ruby/python versions, external utilities on PATH) and asks for the dynamic bits (date, cwd, git branch) on every build. The static cache survives the length of the process — long enough for an HTTP server’s lifetime, short enough that a ‘gem install` between deploys repopulates it.

The goal is a concrete, honest description of the actual runtime the model is talking to. If markitdown isn’t installed in the VM image, we don’t list it — the agent will then ask the user instead of confidently invoking a binary that doesn’t exist.

Constant Summary collapse

DEFAULT_UTILITIES =

External CLI tools we probe by default. The list mixes hard dependencies (git, ruby) and useful-but-optional binaries the agent may want to shell out to (markitdown, pandoc, …). Anything not found on PATH is silently dropped — see #available_utilities.

%w[
  git gh rg jq curl wget
  ruby python3 node npm bundle
  docker psql sqlite3 redis-cli
  ffmpeg pandoc markitdown pdftotext tesseract
].freeze

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(extra_utilities: [], cwd: nil, clock: -> { Time.now }) ⇒ EnvironmentInspector

Returns a new instance of EnvironmentInspector.



44
45
46
47
48
# File 'lib/rubino/context/environment_inspector.rb', line 44

def initialize(extra_utilities: [], cwd: nil, clock: -> { Time.now })
  @extra_utilities = Array(extra_utilities).map(&:to_s)
  @cwd = cwd
  @clock = clock
end

Class Method Details

.cacheObject

Process-wide cache of the static fields. Reset via #reset_cache! from specs.



35
36
37
# File 'lib/rubino/context/environment_inspector.rb', line 35

def cache
  @cache ||= {}
end

.reset_cache!Object



39
40
41
# File 'lib/rubino/context/environment_inspector.rb', line 39

def reset_cache!
  @cache = {}
end

Instance Method Details

#available_utilitiesObject

Public for spec inspection. The list is sorted to keep the prompt stable turn-to-turn (otherwise reordering would invalidate the provider-side prompt cache).



88
89
90
91
# File 'lib/rubino/context/environment_inspector.rb', line 88

def available_utilities
  probes = (DEFAULT_UTILITIES + @extra_utilities).uniq
  self.class.cache[:utilities] ||= probes.select { |bin| on_path?(bin) }.sort
end

#document_formatsObject

The CORE document formats readable in-process via read_attachment (driven by which optional extraction gems loaded). Advertised so the model knows it can read a docx/pdf even when no ‘markitdown` binary exists on PATH – closing the gap this file’s own comment describes.



77
78
79
80
81
82
83
# File 'lib/rubino/context/environment_inspector.rb', line 77

def document_formats
  self.class.cache[:document_formats] ||= begin
    Rubino::Documents::Registry.available_formats
  rescue StandardError
    []
  end
end

#renderObject

Returns the assembled [Environment] block, or nil if the caller disabled it at the config layer (PromptAssembler decides — this class always renders when asked).



53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
# File 'lib/rubino/context/environment_inspector.rb', line 53

def render
  lines = []
  lines << "[Environment]"
  lines << "- Today's date: #{today}"
  lines << "- Platform: #{platform}"
  lines << "- Shell: #{shell}"
  lines << "- Working dir: #{working_dir}"
  git = git_description
  lines << "- Git: #{git}" if git
  lines << "- Runtimes: #{runtimes}"
  utilities = available_utilities
  lines << "- Available CLI tools on PATH: #{utilities.join(", ")}" if utilities.any?
  docs = document_formats
  if docs.any?
    lines << "- Document reading: the `read_attachment` tool converts these formats " \
             "to Markdown in-process (no external binary needed): #{docs.join(", ")}"
  end
  lines.join("\n")
end