Class: Phronomy::Tool::Base
- Inherits:
-
RubyLLM::Tool
- Object
- RubyLLM::Tool
- Phronomy::Tool::Base
- Defined in:
- lib/phronomy/tool/base.rb
Overview
Base class extending RubyLLM::Tool with Phronomy-specific DSL.
Additional DSL over RubyLLM::Tool:
- tool_name : explicit function name exposed to the LLM (overrides auto-conversion)
- scope : access-scope metadata (:read_only, :write, etc.)
- on_error : error-handling policy (:raise or :return_empty)
- on_schema_error : behavior when LLM passes schema-violating arguments :return_error (default), :raise, or :coerce
- requires_approval : require human approval before execution
- param :name, enum: [...] : restrict allowed values in the JSON Schema
Class Attribute Summary collapse
-
._sleep_proc ⇒ #call
Injectable sleep callable for testing.
Class Method Summary collapse
-
.on_error(behavior = nil) ⇒ Object
Configures error-handling behavior.
-
.on_schema_error(behavior = nil) ⇒ Object
Configures how this tool responds when the LLM passes arguments that violate the declared parameter types or enum constraints.
-
.param(name, enum: nil, **options) ⇒ Object
Extends RubyLLM::Tool.param with an optional +enum:+ keyword.
-
.param_enums ⇒ Hash{Symbol => Array}
Returns the enum constraints registered via .param.
-
.requires_approval(value = nil) ⇒ Object
Configures whether human approval is required before executing this tool.
-
.retry_on(*exception_classes, times: 1, wait: 0, base: 1.0) ⇒ Object
Registers a retry policy for one or more exception classes.
-
.retry_policies ⇒ Array<Hash>
Returns all retry policies registered on this tool class.
-
.scope(value = nil) ⇒ Object
Sets the access scope for this tool (metadata; enforcement is the responsibility of the Graph/Guardrail layer).
-
.tool_name(value = nil) ⇒ Object
Sets an explicit function name to expose to the LLM, bypassing RubyLLM's automatic CamelCase-to-snake_case conversion.
Instance Method Summary collapse
-
#call(args) ⇒ Object
Overrides RubyLLM::Tool#call to apply schema validation, the retry policy, the on_error policy, and wrap errors as ToolError.
-
#execute(**_args) ⇒ String
abstract
Override this method to implement the tool's logic.
-
#name ⇒ Object
Returns the function name exposed to the LLM.
-
#params_schema ⇒ Object
Returns the JSON Schema for this tool's parameters.
-
#requires_approval? ⇒ Boolean
Instance method for requires_approval? (convenience accessor).
Class Attribute Details
._sleep_proc ⇒ #call
Injectable sleep callable for testing. Defaults to Kernel#sleep.
130 131 132 |
# File 'lib/phronomy/tool/base.rb', line 130 def _sleep_proc @_sleep_proc || method(:sleep) end |
Class Method Details
.on_error(behavior = nil) ⇒ Object
Configures error-handling behavior.
71 72 73 74 75 |
# File 'lib/phronomy/tool/base.rb', line 71 def on_error(behavior = nil) return @on_error || :raise if behavior.nil? @on_error = behavior end |
.on_schema_error(behavior = nil) ⇒ Object
Configures how this tool responds when the LLM passes arguments that violate the declared parameter types or enum constraints.
86 87 88 89 90 |
# File 'lib/phronomy/tool/base.rb', line 86 def on_schema_error(behavior = nil) return @on_schema_error || :return_error if behavior.nil? @on_schema_error = behavior end |
.param(name, enum: nil, **options) ⇒ Object
Extends RubyLLM::Tool.param with an optional +enum:+ keyword. The enum values are stored separately and injected into the JSON Schema produced by #params_schema.
49 50 51 52 |
# File 'lib/phronomy/tool/base.rb', line 49 def param(name, enum: nil, **) super(name, **) param_enums[name] = enum if enum end |
.param_enums ⇒ Hash{Symbol => Array}
Returns the enum constraints registered via .param.
56 57 58 |
# File 'lib/phronomy/tool/base.rb', line 56 def param_enums @param_enums ||= {} end |
.requires_approval(value = nil) ⇒ Object
Configures whether human approval is required before executing this tool.
94 95 96 97 98 |
# File 'lib/phronomy/tool/base.rb', line 94 def requires_approval(value = nil) return @requires_approval || false if value.nil? @requires_approval = value end |
.retry_on(*exception_classes, times: 1, wait: 0, base: 1.0) ⇒ Object
Registers a retry policy for one or more exception classes.
When the tool raises one of the listed exception classes, it will be retried up to +times+ times with the specified wait strategy. Multiple policies can be registered and are evaluated in order.
GuardrailError is never retried regardless of this configuration.
116 117 118 119 |
# File 'lib/phronomy/tool/base.rb', line 116 def retry_on(*exception_classes, times: 1, wait: 0, base: 1.0) @retry_policies ||= [] @retry_policies << {exceptions: exception_classes, times: times, wait: wait, base: base} end |
.retry_policies ⇒ Array<Hash>
Returns all retry policies registered on this tool class.
123 124 125 |
# File 'lib/phronomy/tool/base.rb', line 123 def retry_policies @retry_policies || [] end |
.scope(value = nil) ⇒ Object
Sets the access scope for this tool (metadata; enforcement is the responsibility of the Graph/Guardrail layer).
63 64 65 66 67 |
# File 'lib/phronomy/tool/base.rb', line 63 def scope(value = nil) return @scope if value.nil? @scope = value end |
.tool_name(value = nil) ⇒ Object
Sets an explicit function name to expose to the LLM, bypassing RubyLLM's automatic CamelCase-to-snake_case conversion. When omitted, RubyLLM's default conversion applies (e.g. WeatherTool → "weather").
36 37 38 39 40 |
# File 'lib/phronomy/tool/base.rb', line 36 def tool_name(value = nil) return @tool_name if value.nil? @tool_name = value.to_s end |
Instance Method Details
#call(args) ⇒ Object
Overrides RubyLLM::Tool#call to apply schema validation, the retry policy, the on_error policy, and wrap errors as ToolError.
Execution order:
- Schema validation (type + enum checks).
- Call super(validated_args) inside a retry loop.
- On persistent failure, apply on_error policy.
173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 |
# File 'lib/phronomy/tool/base.rb', line 173 def call(args) validated_args, schema_error = validate_and_coerce(args) if schema_error case self.class.on_schema_error when :raise raise Phronomy::ToolError, "#{self.class.name} schema error: #{schema_error}" else # :return_error (default) and coerce fallback return "Schema validation failed: #{schema_error}" end end with_tool_retry { super(validated_args) } rescue Phronomy::ToolError raise rescue => e case self.class.on_error when :return_empty [] else raise Phronomy::ToolError, "#{self.class.name} execution failed: #{e.}" end end |
#execute(**_args) ⇒ String
Subclasses must implement this method.
Override this method to implement the tool's logic.
The method receives the declared param fields as keyword arguments. The return value is passed back to the LLM as the tool result.
217 218 219 |
# File 'lib/phronomy/tool/base.rb', line 217 def execute(**_args) raise NotImplementedError, "#{self.class}#execute is not implemented" end |
#name ⇒ Object
Returns the function name exposed to the LLM. Uses the class-level tool_name if set; otherwise falls back to RubyLLM's automatic conversion (CamelCase → snake_case, strips trailing "_tool").
142 143 144 |
# File 'lib/phronomy/tool/base.rb', line 142 def name self.class.tool_name || super end |
#params_schema ⇒ Object
Returns the JSON Schema for this tool's parameters. Injects "enum" entries for any param declared with enum: [...].
148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 |
# File 'lib/phronomy/tool/base.rb', line 148 def params_schema schema = super return schema if schema.nil? || self.class.param_enums.empty? enums = self.class.param_enums properties = schema.dig("properties") || schema.dig(:properties) return schema unless properties enums.each do |param_name, values| key = properties.key?(param_name.to_s) ? param_name.to_s : param_name.to_sym next unless properties[key] properties[key]["enum"] = values.map(&:to_s) end schema end |
#requires_approval? ⇒ Boolean
Instance method for requires_approval? (convenience accessor).
197 198 199 |
# File 'lib/phronomy/tool/base.rb', line 197 def requires_approval? self.class.requires_approval end |