Class: Rubino::Tools::Registry
- Inherits:
-
Object
- Object
- Rubino::Tools::Registry
- 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
-
.all ⇒ Object
Returns all registered tools.
-
.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. -
.enabled_tools ⇒ Object
Returns only enabled tools based on configuration AND the active mode (Modes.current).
-
.find(name) ⇒ Object
Finds a tool by name.
-
.instance ⇒ Object
Returns the singleton instance.
-
.register(tool) ⇒ Object
Registers a tool instance.
-
.register_defaults! ⇒ Object
Registers all default tools.
-
.reset! ⇒ Object
Clears all registered tools (useful for testing).
-
.tool_definitions ⇒ Object
Returns tool definitions for LLM registration.
-
.tool_output_compression_enabled_default? ⇒ Boolean
True when compression is enabled in the resolved config, used to gate the retrieve_output tool's registration.
-
.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.
Class Method Details
.all ⇒ Object
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_tools ⇒ Object
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 |
.instance ⇒ Object
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_definitions ⇒ Object
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.
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 |