Module: ToolTailor

Defined in:
lib/tool_tailor.rb,
lib/tool_tailor/version.rb

Defined Under Namespace

Classes: Error

Constant Summary collapse

VERSION =
"0.2.1"

Class Method Summary collapse

Class Method Details

.convert(object) ⇒ String

Converts a function or class to a JSON schema representation.

Examples:

def example_method(param1:, param2:)
  # method implementation
end

ToolTailor.convert(method(:example_method))
class ExampleClass
  def initialize(param1:, param2:)
    # initialization
  end
end

ToolTailor.convert(ExampleClass)

Parameters:

Returns:

  • (String)

    The JSON schema representation of the function or class.

Raises:

  • (ArgumentError)

    If the provided object is not a Method, UnboundMethod, or Class.



30
31
32
33
34
35
36
37
38
39
# File 'lib/tool_tailor.rb', line 30

def self.convert(object)
  case object
  when Method, UnboundMethod
    convert_method(object)
  when Class
    convert_class(object)
  else
    raise ArgumentError, "Unsupported object type: #{object.class}"
  end
end

.convert_class(klass) ⇒ Object



111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
# File 'lib/tool_tailor.rb', line 111

def self.convert_class(klass)
  initialize_method = klass.instance_method(:initialize)
  schema = JSON.parse(convert_method(initialize_method))
  schema["function"]["name"] = klass.name

  # Re-parse YARD documentation for the class
  file_path, _ = initialize_method.source_location
  YARD.parse(file_path)
  class_object = YARD::Registry.at(klass.name)

  if class_object
    schema["function"]["description"] = class_object.docstring.to_s
  end

  schema.to_json
end

.convert_method(method) ⇒ String

Converts a method to a JSON schema representation.

Parameters:

Returns:

  • (String)

    The JSON schema representation of the method.



45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
# File 'lib/tool_tailor.rb', line 45

def self.convert_method(method)
  # Ensure only named arguments are allowed
  unless method.parameters.all? { |type, _| type == :keyreq || type == :key }
    raise ArgumentError, "Only named arguments are supported"
  end

  file_path, line_number = method.source_location
  YARD.parse(file_path)

  method_path = "#{method.owner}##{method.name}"
  yard_object = YARD::Registry.at(method_path)

  # Extract parameters from the method definition
  parameters = method.parameters.map do |_, name|
    {
      name: name.to_s,
      type: "string",
      description: "",
      enum: nil
    }
  end

  method_description = ""

  if yard_object
    method_description = yard_object.docstring

    yard_object.tags("param").each do |tag|
      param_name = tag.name.chomp(':')
      param = parameters.find { |p| p[:name] == param_name }
      if param
        param[:type] = type_mapping(tag.types.first)
        param[:description] = tag.text
      end
    end

    yard_object.tags("values").each do |tag|
      param_name = tag.name.chomp(':')
      param = parameters.find { |p| p[:name] == param_name }
      param[:enum] = tag.text if param
    end
  end

  {
    type: "function",
    function: {
      name: method.name.to_s,
      description: method_description,
      parameters: {
        type: "object",
        properties: parameters.map do |param|
          [
            param[:name],
            {
              type: param[:type],
              description: param[:description],
              enum: param[:enum]
            }.compact
          ]
        end.to_h,
        required: method.parameters.select { |type, _| type == :keyreq }.map { |_, name| name.to_s }
      }
    }
  }.to_json
end

.type_mapping(type) ⇒ String

Maps Ruby types to JSON schema types.

Parameters:

  • type (String)

    The Ruby type to map.

Returns:

  • (String)

    The corresponding JSON schema type.

Raises:

  • (ArgumentError)

    If the provided type is not supported.



133
134
135
136
137
138
139
140
141
142
143
144
145
# File 'lib/tool_tailor.rb', line 133

def self.type_mapping(type)
  case type
  when "String"    then "string"
  when "Integer"   then "integer"
  when "Float"     then "number"
  when "TrueClass", "FalseClass" then "boolean"
  when "Array"     then "array"
  when "Hash"      then "object"
  when "NilClass"  then "null"
  else
    raise ArgumentError, "Unsupported type: #{type} #{type.class}"
  end
end