1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
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
|
# frozen_string_literal: true
require "json_schemer"
module Dispatch
module Tools
class Definition
attr_reader :name, :description, :parameters
def initialize(name:, description:, parameters:, &block)
@name = name
@description = description
@parameters = parameters
@block = block
@schemer = JSONSchemer.schema(deep_stringify_keys(parameters))
end
def call(params, context: {})
symbolized = symbolize_keys(params)
valid, errors = validate_params(params)
return Result.failure(error: "Parameter validation failed: #{errors.join("; ")}") unless valid
begin
@block.call(symbolized, context)
rescue Exception => e # rubocop:disable Lint/RescueException
Result.failure(error: "#{e.class}: #{e.message}")
end
end
def to_h
{ name:, description:, parameters: }
end
def to_tool_definition
to_h
end
def validate_params(params)
stringified = deep_stringify_keys(params)
errors = @schemer.validate(stringified).map { |err| err["error"] || err.fetch("type", "unknown error") }
if errors.empty?
[ true, [] ]
else
[ false, errors ]
end
end
private
def symbolize_keys(hash)
hash.each_with_object({}) do |(key, value), result|
result[key.to_sym] = value
end
end
def deep_stringify_keys(obj)
case obj
when Hash
obj.each_with_object({}) do |(key, value), result|
result[key.to_s] = deep_stringify_keys(value)
end
when Array
obj.map { |item| deep_stringify_keys(item) }
else
obj
end
end
end
end
end
|