Class: RubyPi::Tools::Definition
- Inherits:
-
Object
- Object
- RubyPi::Tools::Definition
- Defined in:
- lib/ruby_pi/tools/definition.rb
Constant Summary collapse
- NAME_FORMAT =
Tool names must satisfy the strictest provider constraint (Anthropic’s ^[a-zA-Z0-9_-]1,64$). Without this guard, a name like “send.email” registers fine and then 400s on every API request with an opaque server-side validation error that doesn’t point back to the tool.
/\A[a-zA-Z0-9_-]{1,64}\z/
Instance Attribute Summary collapse
-
#category ⇒ Symbol?
readonly
An optional category for grouping related tools.
-
#description ⇒ String
readonly
A human-readable description of what this tool does.
-
#name ⇒ Symbol
readonly
The unique name identifying this tool.
-
#parameters ⇒ Hash
readonly
A JSON Schema hash describing the tool’s parameters.
Instance Method Summary collapse
-
#call(args = {}) ⇒ Object
Invokes the tool with the given arguments.
-
#initialize(name:, description:, category: nil, parameters: {}) {|Hash| ... } ⇒ Definition
constructor
Creates a new tool definition.
-
#inspect ⇒ String
Provides a human-readable string representation of the definition.
-
#to_anthropic_format ⇒ Hash
Converts this tool definition to Anthropic’s tool format.
-
#to_gemini_format ⇒ Hash
Converts this tool definition to Google Gemini function declaration format.
-
#to_openai_format ⇒ Hash
Converts this tool definition to OpenAI’s function calling format.
Constructor Details
#initialize(name:, description:, category: nil, parameters: {}) {|Hash| ... } ⇒ Definition
Creates a new tool definition.
58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 |
# File 'lib/ruby_pi/tools/definition.rb', line 58 def initialize(name:, description:, category: nil, parameters: {}, &block) raise ArgumentError, "Tool name is required" if name.nil? || name.to_s.strip.empty? unless name.to_s.match?(NAME_FORMAT) raise ArgumentError, "Tool name #{name.to_s.inspect} is invalid — provider APIs require " \ "names matching #{NAME_FORMAT.inspect} (letters, digits, underscore, " \ "hyphen; 1-64 characters)" end raise ArgumentError, "Tool description is required" if description.nil? || description.strip.empty? raise ArgumentError, "Tool implementation block is required" unless block_given? @name = name.to_sym @description = description @category = category&.to_sym @parameters = parameters @implementation = block # On Ruby 3.x a positional Hash is never auto-splatted to keywords, so # a block written `{ |content:, platform:| ... }` — the natural style # given named schema parameters — would fail every call with # "missing keyword". Detect keyword parameters once here and splat in # #call accordingly. @expects_keywords = block.parameters.any? { |type, _| %i[key keyreq keyrest].include?(type) } end |
Instance Attribute Details
#category ⇒ Symbol? (readonly)
Returns An optional category for grouping related tools.
35 36 37 |
# File 'lib/ruby_pi/tools/definition.rb', line 35 def category @category end |
#description ⇒ String (readonly)
Returns A human-readable description of what this tool does.
32 33 34 |
# File 'lib/ruby_pi/tools/definition.rb', line 32 def description @description end |
#name ⇒ Symbol (readonly)
Returns The unique name identifying this tool.
29 30 31 |
# File 'lib/ruby_pi/tools/definition.rb', line 29 def name @name end |
#parameters ⇒ Hash (readonly)
Returns A JSON Schema hash describing the tool’s parameters.
38 39 40 |
# File 'lib/ruby_pi/tools/definition.rb', line 38 def parameters @parameters end |
Instance Method Details
#call(args = {}) ⇒ Object
Invokes the tool with the given arguments.
Blocks may be written either style:
{ |args| args[:content] } # single positional Hash
{ |content:, platform: "x"| ... } # keyword parameters
When the block declares keyword parameters, the arguments hash is splatted to keywords. Note that a keyword-style block without **rest raises ArgumentError on unexpected keys — strict by design, since the keys come from the LLM.
95 96 97 98 99 100 101 |
# File 'lib/ruby_pi/tools/definition.rb', line 95 def call(args = {}) if @expects_keywords @implementation.call(**args) else @implementation.call(args) end end |
#inspect ⇒ String
Provides a human-readable string representation of the definition.
154 155 156 |
# File 'lib/ruby_pi/tools/definition.rb', line 154 def inspect "#<RubyPi::Tools::Definition name=#{@name.inspect} category=#{@category.inspect}>" end |
#to_anthropic_format ⇒ Hash
Converts this tool definition to Anthropic’s tool format.
Anthropic expects:
{ name: "...", description: "...", input_schema: { ... } }
124 125 126 127 128 129 130 131 |
# File 'lib/ruby_pi/tools/definition.rb', line 124 def to_anthropic_format tool = { name: @name.to_s, description: @description } tool[:input_schema] = @parameters unless @parameters.empty? tool end |
#to_gemini_format ⇒ Hash
Converts this tool definition to Google Gemini function declaration format.
Gemini expects:
{ name: "...", description: "...", parameters: { ... } }
109 110 111 112 113 114 115 116 |
# File 'lib/ruby_pi/tools/definition.rb', line 109 def to_gemini_format declaration = { name: @name.to_s, description: @description } declaration[:parameters] = @parameters unless @parameters.empty? declaration end |
#to_openai_format ⇒ Hash
Converts this tool definition to OpenAI’s function calling format.
OpenAI expects:
{ type: "function", function: { name: "...", description: "...", parameters: { ... } } }
139 140 141 142 143 144 145 146 147 148 149 |
# File 'lib/ruby_pi/tools/definition.rb', line 139 def to_openai_format function = { name: @name.to_s, description: @description } function[:parameters] = @parameters unless @parameters.empty? { type: "function", function: function } end |