Class: Rubino::Tools::Registry

Inherits:
Object
  • Object
show all
Defined in:
lib/rubino/tools/registry.rb

Overview

Singleton registry for all available tools. Tools register themselves and can be looked up by name.

Class Method Summary collapse

Class Method Details

.allObject

Returns all registered tools



50
51
52
# File 'lib/rubino/tools/registry.rb', line 50

def all
  @tools.values
end

.display_label(name) ⇒ Object

The DISPLAY label for a registered tool name — the single resolution point both the live tool card and the approval card route through, so an MCP tool shows its <bare> (mcp:<server>) source while a built-in renders unchanged. Detection is driven off the registered object being an MCP wrapper (#mcp?), NEVER off the name's shape, so a built-in whose name legitimately contains an underscore (read_attachment, shell_output) is never mistaken for a <server>_<tool> MCP name. Falls back to the bare name when the tool isn't registered (defensive — the model-facing name is always a safe label).



35
36
37
38
39
40
# File 'lib/rubino/tools/registry.rb', line 35

def display_label(name)
  tool = find(name)
  return name.to_s unless tool.respond_to?(:mcp?) && tool.mcp?

  tool.display_name
end

.enabled_toolsObject

Returns only enabled tools based on configuration AND the active mode (Modes.current). Plan mode pares the registry down to its read-only whitelist so the model literally has no edit/shell definition in the request — it can't even propose a mutating tool call. Yolo and default leave everything through; their difference is on the approval path, not the registry.



60
61
62
63
64
65
66
67
68
69
70
# File 'lib/rubino/tools/registry.rb', line 60

def enabled_tools
  config = Rubino.configuration
  disabled = config.agent_disabled_toolsets

  @tools.values.reject do |tool|
    disabled.include?(tool.name) ||
      !tool_enabled_in_config?(tool, config) ||
      !Rubino::Modes.allows_tool?(tool.name) ||
      !aux_dependency_satisfied?(tool, config)
  end
end

.find(name) ⇒ Object

Finds a tool by name



22
23
24
# File 'lib/rubino/tools/registry.rb', line 22

def find(name)
  @tools[name.to_s]
end

.instanceObject

Returns the singleton instance



12
13
14
# File 'lib/rubino/tools/registry.rb', line 12

def instance
  self
end

.register(tool) ⇒ Object

Registers a tool instance



17
18
19
# File 'lib/rubino/tools/registry.rb', line 17

def register(tool)
  @tools[tool.name] = tool
end

.register_defaults!Object

Registers all default tools



86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
# File 'lib/rubino/tools/registry.rb', line 86

def register_defaults!
  register(Rubino::Tools::ReadTool.new)
  register(Rubino::Tools::WriteTool.new)
  register(Rubino::Tools::EditTool.new)
  register(Rubino::Tools::MultiEditTool.new)
  register(Rubino::Tools::GrepTool.new)
  register(Rubino::Tools::GlobTool.new)
  register(Rubino::Tools::ShellTool.new)
  register(Rubino::Tools::ShellOutputTool.new)
  register(Rubino::Tools::ShellTailTool.new)
  register(Rubino::Tools::ShellInputTool.new)
  register(Rubino::Tools::ShellKillTool.new)
  register(Rubino::Tools::RubyTool.new)
  register(Rubino::Tools::PatchTool.new)
  register(Rubino::Tools::WebFetchTool.new)
  register(Rubino::Tools::WebSearchTool.new)
  register(Rubino::Tools::QuestionTool.new)
  register(Rubino::Tools::TodoTool.new)
  register(Rubino::Tools::MemoryTool.new)
  register(Rubino::Tools::SessionSearchTool.new)
  register(Rubino::Tools::AttachFileTool.new)
  # Gated, on-demand attachment reader (#6): converts a document to
  # Markdown IN-PROCESS (Rubino::Documents) and frames it as untrusted
  # data, so attachment bytes enter context only when the model asks.
  register(Rubino::Tools::ReadAttachmentTool.new)
  register(Rubino::Tools::VisionTool.new)
  # Skills tool: loads a skill body (Level 2) and bundled files
  # (Level 3) on demand. Gated like any tool via `tools.skill`.
  register(Rubino::Skills::SkillTool.new)
  # Delegation tool: lets the model spawn an isolated subagent run.
  # Gated like any other tool (tools.task in config). Subagents now KEEP
  # it (scoped nesting, S1) — a subagent can spawn its own subagents,
  # bounded by the depth / fan-out / global caps in BackgroundTasks#reserve.
  register(Rubino::Tools::TaskTool.new)
  # Companion poll/stop tools for background subagents (the default
  # path of `task`). Mirror the shell_output/shell_kill trio. Gated by
  # the same tools.task key — disabling delegation disables these too.
  register(Rubino::Tools::TaskResultTool.new)
  register(Rubino::Tools::TaskStopTool.new)
  # steer / probe (S2/S3): the MODEL-callable parent->child channels,
  # registered for ALL agents and AUTHORIZED by ownership at call time
  # (a node with no children just gets a "not your child" error). NOT on
  # any strip list — scoping happens inside the tool, not in the registry.
  register(Rubino::Tools::SteerTool.new)
  register(Rubino::Tools::ProbeTool.new)
  # retrieve_output: the ONLY recovery path for compressed tool output.
  # Registered solely when tool_output_compression is enabled (the
  # default is OFF), so the shipped registry count is unchanged. When on,
  # the compression pointer carries an `id=…` and this tool reads the
  # spilled original back — deliberately NO cat-able path is printed, so
  # a small model can't shell-re-inflate the output compression shrank.
  register(Rubino::Tools::RetrieveOutputTool.new) if tool_output_compression_enabled_default?
end

.reset!Object

Clears all registered tools (useful for testing)



78
79
80
81
82
83
# File 'lib/rubino/tools/registry.rb', line 78

def reset!
  @tools = {}
  # Drop the memoized web-capability probe (#411) so a fresh test run
  # re-evaluates it rather than inheriting a prior process's verdict.
  @web_backend_available = nil
end

.tool_definitionsObject

Returns tool definitions for LLM registration



73
74
75
# File 'lib/rubino/tools/registry.rb', line 73

def tool_definitions
  enabled_tools.map(&:to_tool_definition)
end

.tool_output_compression_enabled_default?Boolean

True when compression is enabled in the resolved config, used to gate the retrieve_output tool's registration. Best-effort: any config error falls back to OFF (matching the shipped default), so a broken config never silently adds a tool that wouldn't otherwise be present.

Returns:

  • (Boolean)


144
145
146
147
148
# File 'lib/rubino/tools/registry.rb', line 144

def tool_output_compression_enabled_default?
  Rubino.configuration.tool_output_compression_enabled?
rescue StandardError
  false
end

.unregister(name) ⇒ Object

Removes a tool by name (#182): stopping an MCP server must also drop its MCPToolWrapper instances, or the model keeps seeing tools whose client is gone and every call fails.



45
46
47
# File 'lib/rubino/tools/registry.rb', line 45

def unregister(name)
  @tools.delete(name.to_s)
end