agent-client-protocol 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/LICENSE +190 -0
- data/README.md +126 -0
- data/lib/agent_client_protocol/codec.rb +111 -0
- data/lib/agent_client_protocol/constants.rb +78 -0
- data/lib/agent_client_protocol/decoder.rb +134 -0
- data/lib/agent_client_protocol/error.rb +104 -0
- data/lib/agent_client_protocol/methods.rb +19 -0
- data/lib/agent_client_protocol/protocol_version.rb +56 -0
- data/lib/agent_client_protocol/rpc.rb +160 -0
- data/lib/agent_client_protocol/schema_registry.rb +112 -0
- data/lib/agent_client_protocol/type_registry.rb +99 -0
- data/lib/agent_client_protocol/types/base.rb +314 -0
- data/lib/agent_client_protocol/types.rb +8 -0
- data/lib/agent_client_protocol/validator.rb +300 -0
- data/lib/agent_client_protocol/version.rb +5 -0
- data/lib/agent_client_protocol.rb +41 -0
- data/schema/meta.json +24 -0
- data/schema/meta.unstable.json +31 -0
- data/schema/schema.json +3430 -0
- data/schema/schema.unstable.json +4125 -0
- metadata +64 -0
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module AgentClientProtocol
|
|
4
|
+
module ErrorCode
|
|
5
|
+
PARSE_ERROR = -32_700
|
|
6
|
+
INVALID_REQUEST = -32_600
|
|
7
|
+
METHOD_NOT_FOUND = -32_601
|
|
8
|
+
INVALID_PARAMS = -32_602
|
|
9
|
+
INTERNAL_ERROR = -32_603
|
|
10
|
+
REQUEST_CANCELLED = -32_800
|
|
11
|
+
AUTH_REQUIRED = -32_000
|
|
12
|
+
RESOURCE_NOT_FOUND = -32_002
|
|
13
|
+
|
|
14
|
+
DEFAULT_MESSAGES = {
|
|
15
|
+
PARSE_ERROR => "Parse error",
|
|
16
|
+
INVALID_REQUEST => "Invalid request",
|
|
17
|
+
METHOD_NOT_FOUND => "Method not found",
|
|
18
|
+
INVALID_PARAMS => "Invalid params",
|
|
19
|
+
INTERNAL_ERROR => "Internal error",
|
|
20
|
+
REQUEST_CANCELLED => "Request cancelled",
|
|
21
|
+
AUTH_REQUIRED => "Authentication required",
|
|
22
|
+
RESOURCE_NOT_FOUND => "Resource not found"
|
|
23
|
+
}.freeze
|
|
24
|
+
|
|
25
|
+
module_function
|
|
26
|
+
|
|
27
|
+
def default_message(code)
|
|
28
|
+
DEFAULT_MESSAGES.fetch(code, "Unknown error")
|
|
29
|
+
end
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
class Error < StandardError
|
|
33
|
+
attr_reader :code, :data
|
|
34
|
+
|
|
35
|
+
def initialize(code:, message: nil, data: nil)
|
|
36
|
+
@code = Integer(code)
|
|
37
|
+
@data = data
|
|
38
|
+
super(message || ErrorCode.default_message(@code))
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
def to_h
|
|
42
|
+
error = {
|
|
43
|
+
"code" => code,
|
|
44
|
+
"message" => message
|
|
45
|
+
}
|
|
46
|
+
error["data"] = data unless data.nil?
|
|
47
|
+
error
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
class << self
|
|
51
|
+
def from_h(hash)
|
|
52
|
+
normalized = stringify_keys(hash)
|
|
53
|
+
new(
|
|
54
|
+
code: normalized.fetch("code"),
|
|
55
|
+
message: normalized["message"],
|
|
56
|
+
data: normalized["data"]
|
|
57
|
+
)
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
def parse_error(data = nil)
|
|
61
|
+
new(code: ErrorCode::PARSE_ERROR, data: data)
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
def invalid_request(data = nil)
|
|
65
|
+
new(code: ErrorCode::INVALID_REQUEST, data: data)
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
def method_not_found(data = nil)
|
|
69
|
+
new(code: ErrorCode::METHOD_NOT_FOUND, data: data)
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
def invalid_params(data = nil)
|
|
73
|
+
new(code: ErrorCode::INVALID_PARAMS, data: data)
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
def internal_error(data = nil)
|
|
77
|
+
new(code: ErrorCode::INTERNAL_ERROR, data: data)
|
|
78
|
+
end
|
|
79
|
+
|
|
80
|
+
def request_cancelled(data = nil)
|
|
81
|
+
new(code: ErrorCode::REQUEST_CANCELLED, data: data)
|
|
82
|
+
end
|
|
83
|
+
|
|
84
|
+
def auth_required(data = nil)
|
|
85
|
+
new(code: ErrorCode::AUTH_REQUIRED, data: data)
|
|
86
|
+
end
|
|
87
|
+
|
|
88
|
+
def resource_not_found(uri = nil)
|
|
89
|
+
payload = uri.nil? ? nil : { "uri" => uri }
|
|
90
|
+
new(code: ErrorCode::RESOURCE_NOT_FOUND, data: payload)
|
|
91
|
+
end
|
|
92
|
+
|
|
93
|
+
private
|
|
94
|
+
|
|
95
|
+
def stringify_keys(value)
|
|
96
|
+
return value unless value.is_a?(Hash)
|
|
97
|
+
|
|
98
|
+
value.each_with_object({}) do |(k, v), acc|
|
|
99
|
+
acc[k.to_s] = v
|
|
100
|
+
end
|
|
101
|
+
end
|
|
102
|
+
end
|
|
103
|
+
end
|
|
104
|
+
end
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module AgentClientProtocol
|
|
4
|
+
module Methods
|
|
5
|
+
module_function
|
|
6
|
+
|
|
7
|
+
def agent(unstable: false)
|
|
8
|
+
SchemaRegistry.agent_methods(unstable: unstable)
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
def client(unstable: false)
|
|
12
|
+
SchemaRegistry.client_methods(unstable: unstable)
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
def protocol(unstable: false)
|
|
16
|
+
SchemaRegistry.protocol_methods(unstable: unstable)
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
end
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module AgentClientProtocol
|
|
4
|
+
class ProtocolVersion
|
|
5
|
+
include Comparable
|
|
6
|
+
|
|
7
|
+
V0 = 0
|
|
8
|
+
V1 = 1
|
|
9
|
+
LATEST = V1
|
|
10
|
+
MAX_VALUE = 65_535
|
|
11
|
+
|
|
12
|
+
attr_reader :value
|
|
13
|
+
|
|
14
|
+
def initialize(value)
|
|
15
|
+
unless value.is_a?(Integer) && value >= 0 && value <= MAX_VALUE
|
|
16
|
+
raise ArgumentError, "protocol version must be an Integer between 0 and #{MAX_VALUE}"
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
@value = value
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
def self.parse(raw)
|
|
23
|
+
case raw
|
|
24
|
+
when Integer
|
|
25
|
+
new(raw)
|
|
26
|
+
when String
|
|
27
|
+
# ACP legacy behavior: old string versions map to protocol version 0.
|
|
28
|
+
new(V0)
|
|
29
|
+
else
|
|
30
|
+
raise ArgumentError, "protocol version must be an Integer or String"
|
|
31
|
+
end
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
def <=>(other)
|
|
35
|
+
other_value = other.is_a?(ProtocolVersion) ? other.value : other
|
|
36
|
+
value <=> other_value
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
def ==(other)
|
|
40
|
+
other_value = other.is_a?(ProtocolVersion) ? other.value : other
|
|
41
|
+
value == other_value
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
def to_i
|
|
45
|
+
value
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
def to_h
|
|
49
|
+
value
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
def to_s
|
|
53
|
+
value.to_s
|
|
54
|
+
end
|
|
55
|
+
end
|
|
56
|
+
end
|
|
@@ -0,0 +1,160 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "json"
|
|
4
|
+
|
|
5
|
+
module AgentClientProtocol
|
|
6
|
+
module RPC
|
|
7
|
+
JSONRPC_VERSION = "2.0"
|
|
8
|
+
|
|
9
|
+
module_function
|
|
10
|
+
|
|
11
|
+
def parse(message)
|
|
12
|
+
normalized = normalize_input(message)
|
|
13
|
+
|
|
14
|
+
if normalized.key?("jsonrpc") && normalized["jsonrpc"] != JSONRPC_VERSION
|
|
15
|
+
raise Error.invalid_request("unsupported jsonrpc version: #{normalized['jsonrpc']}")
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
if normalized.key?("method")
|
|
19
|
+
return Request.new(
|
|
20
|
+
id: normalized["id"],
|
|
21
|
+
method: normalized["method"],
|
|
22
|
+
params: normalized["params"]
|
|
23
|
+
) if normalized.key?("id")
|
|
24
|
+
|
|
25
|
+
return Notification.new(method: normalized["method"], params: normalized["params"])
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
if normalized.key?("result") || normalized.key?("error")
|
|
29
|
+
response_kwargs = { id: normalized["id"] }
|
|
30
|
+
response_kwargs[:result] = normalized["result"] if normalized.key?("result")
|
|
31
|
+
response_kwargs[:error] = normalized["error"] if normalized.key?("error")
|
|
32
|
+
return Response.new(**response_kwargs)
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
raise Error.invalid_request("message is neither request, response, nor notification")
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
def parse_json(json)
|
|
39
|
+
parse(JSON.parse(json))
|
|
40
|
+
rescue JSON::ParserError => e
|
|
41
|
+
raise Error.parse_error(e.message)
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
def normalize_input(message)
|
|
45
|
+
case message
|
|
46
|
+
when String
|
|
47
|
+
JSON.parse(message)
|
|
48
|
+
when Hash
|
|
49
|
+
deep_stringify_keys(message)
|
|
50
|
+
else
|
|
51
|
+
raise ArgumentError, "message must be a Hash or JSON String"
|
|
52
|
+
end
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
def deep_stringify_keys(value)
|
|
56
|
+
case value
|
|
57
|
+
when Hash
|
|
58
|
+
value.each_with_object({}) do |(k, v), result|
|
|
59
|
+
result[k.to_s] = deep_stringify_keys(v)
|
|
60
|
+
end
|
|
61
|
+
when Array
|
|
62
|
+
value.map { |item| deep_stringify_keys(item) }
|
|
63
|
+
else
|
|
64
|
+
value
|
|
65
|
+
end
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
class Request
|
|
69
|
+
attr_reader :id, :method, :params
|
|
70
|
+
|
|
71
|
+
def initialize(id:, method:, params: nil)
|
|
72
|
+
@id = RequestId.coerce(id)
|
|
73
|
+
@method = String(method)
|
|
74
|
+
@params = params
|
|
75
|
+
end
|
|
76
|
+
|
|
77
|
+
def to_h(include_jsonrpc: true)
|
|
78
|
+
payload = {
|
|
79
|
+
"id" => id,
|
|
80
|
+
"method" => method
|
|
81
|
+
}
|
|
82
|
+
payload["params"] = params unless params.nil?
|
|
83
|
+
include_jsonrpc ? { "jsonrpc" => JSONRPC_VERSION }.merge(payload) : payload
|
|
84
|
+
end
|
|
85
|
+
end
|
|
86
|
+
|
|
87
|
+
class Notification
|
|
88
|
+
attr_reader :method, :params
|
|
89
|
+
|
|
90
|
+
def initialize(method:, params: nil)
|
|
91
|
+
@method = String(method)
|
|
92
|
+
@params = params
|
|
93
|
+
end
|
|
94
|
+
|
|
95
|
+
def to_h(include_jsonrpc: true)
|
|
96
|
+
payload = { "method" => method }
|
|
97
|
+
payload["params"] = params unless params.nil?
|
|
98
|
+
include_jsonrpc ? { "jsonrpc" => JSONRPC_VERSION }.merge(payload) : payload
|
|
99
|
+
end
|
|
100
|
+
end
|
|
101
|
+
|
|
102
|
+
class Response
|
|
103
|
+
attr_reader :id, :result, :error
|
|
104
|
+
|
|
105
|
+
def initialize(id:, result: :__undefined__, error: :__undefined__)
|
|
106
|
+
@id = RequestId.coerce(id)
|
|
107
|
+
has_result = result != :__undefined__
|
|
108
|
+
has_error = error != :__undefined__
|
|
109
|
+
|
|
110
|
+
if has_result == has_error
|
|
111
|
+
raise ArgumentError, "response must have exactly one of result or error"
|
|
112
|
+
end
|
|
113
|
+
|
|
114
|
+
@result = has_result ? result : nil
|
|
115
|
+
@error = normalize_error(error) if has_error
|
|
116
|
+
end
|
|
117
|
+
|
|
118
|
+
def success?
|
|
119
|
+
error.nil?
|
|
120
|
+
end
|
|
121
|
+
|
|
122
|
+
def failure?
|
|
123
|
+
!success?
|
|
124
|
+
end
|
|
125
|
+
|
|
126
|
+
def to_h(include_jsonrpc: true)
|
|
127
|
+
payload = { "id" => id }
|
|
128
|
+
if success?
|
|
129
|
+
payload["result"] = result
|
|
130
|
+
else
|
|
131
|
+
payload["error"] = error.is_a?(Error) ? error.to_h : error
|
|
132
|
+
end
|
|
133
|
+
|
|
134
|
+
include_jsonrpc ? { "jsonrpc" => JSONRPC_VERSION }.merge(payload) : payload
|
|
135
|
+
end
|
|
136
|
+
|
|
137
|
+
private
|
|
138
|
+
|
|
139
|
+
def normalize_error(error)
|
|
140
|
+
return error if error.is_a?(Error)
|
|
141
|
+
return Error.from_h(error) if error.is_a?(Hash)
|
|
142
|
+
|
|
143
|
+
raise ArgumentError, "error must be an AgentClientProtocol::Error or a Hash"
|
|
144
|
+
end
|
|
145
|
+
end
|
|
146
|
+
|
|
147
|
+
module RequestId
|
|
148
|
+
module_function
|
|
149
|
+
|
|
150
|
+
def coerce(value)
|
|
151
|
+
case value
|
|
152
|
+
when nil, String, Integer
|
|
153
|
+
value
|
|
154
|
+
else
|
|
155
|
+
raise ArgumentError, "request id must be nil, String, or Integer"
|
|
156
|
+
end
|
|
157
|
+
end
|
|
158
|
+
end
|
|
159
|
+
end
|
|
160
|
+
end
|
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "json"
|
|
4
|
+
|
|
5
|
+
module AgentClientProtocol
|
|
6
|
+
class SchemaRegistry
|
|
7
|
+
ROOT = File.expand_path("../..", __dir__)
|
|
8
|
+
STABLE_SCHEMA_PATH = File.join(ROOT, "schema", "schema.json")
|
|
9
|
+
UNSTABLE_SCHEMA_PATH = File.join(ROOT, "schema", "schema.unstable.json")
|
|
10
|
+
STABLE_META_PATH = File.join(ROOT, "schema", "meta.json")
|
|
11
|
+
UNSTABLE_META_PATH = File.join(ROOT, "schema", "meta.unstable.json")
|
|
12
|
+
|
|
13
|
+
class << self
|
|
14
|
+
def stable_schema
|
|
15
|
+
@stable_schema ||= load_json(STABLE_SCHEMA_PATH)
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
def unstable_schema
|
|
19
|
+
@unstable_schema ||= load_json(UNSTABLE_SCHEMA_PATH)
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
def stable_meta
|
|
23
|
+
@stable_meta ||= symbolize_keys(load_json(STABLE_META_PATH))
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
def unstable_meta
|
|
27
|
+
@unstable_meta ||= symbolize_keys(load_json(UNSTABLE_META_PATH))
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
def defs(unstable: false)
|
|
31
|
+
schema = unstable ? unstable_schema : stable_schema
|
|
32
|
+
schema.fetch("$defs")
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
def method_catalog(unstable: false)
|
|
36
|
+
key = unstable ? :unstable : :stable
|
|
37
|
+
@method_catalog ||= {}
|
|
38
|
+
@method_catalog[key] ||= build_method_catalog(defs(unstable: unstable))
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
def agent_methods(unstable: false)
|
|
42
|
+
meta = unstable ? unstable_meta : stable_meta
|
|
43
|
+
(meta[:agentMethods] || {}).dup
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
def client_methods(unstable: false)
|
|
47
|
+
meta = unstable ? unstable_meta : stable_meta
|
|
48
|
+
(meta[:clientMethods] || {}).dup
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
def protocol_methods(unstable: false)
|
|
52
|
+
meta = unstable ? unstable_meta : stable_meta
|
|
53
|
+
(meta[:protocolMethods] || {}).dup
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
def schema_for(definition_name, unstable: false)
|
|
57
|
+
defs(unstable: unstable).fetch(definition_name)
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
private
|
|
61
|
+
|
|
62
|
+
def load_json(path)
|
|
63
|
+
JSON.parse(File.read(path))
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
def build_method_catalog(definitions)
|
|
67
|
+
catalog = Hash.new { |h, side| h[side] = {} }
|
|
68
|
+
|
|
69
|
+
definitions.each do |definition_name, schema|
|
|
70
|
+
side = schema["x-side"]
|
|
71
|
+
method = schema["x-method"]
|
|
72
|
+
next if side.nil? || method.nil?
|
|
73
|
+
|
|
74
|
+
kind = infer_kind(definition_name)
|
|
75
|
+
next if kind.nil?
|
|
76
|
+
|
|
77
|
+
side_key = side.to_sym
|
|
78
|
+
method_entry = catalog[side_key][method] ||= {}
|
|
79
|
+
method_entry[kind] = definition_name
|
|
80
|
+
end
|
|
81
|
+
|
|
82
|
+
catalog.each_value do |methods|
|
|
83
|
+
methods.each_value(&:freeze)
|
|
84
|
+
methods.freeze
|
|
85
|
+
end
|
|
86
|
+
|
|
87
|
+
catalog.freeze
|
|
88
|
+
end
|
|
89
|
+
|
|
90
|
+
def infer_kind(definition_name)
|
|
91
|
+
return :request if definition_name.end_with?("Request")
|
|
92
|
+
return :response if definition_name.end_with?("Response")
|
|
93
|
+
return :notification if definition_name.end_with?("Notification")
|
|
94
|
+
|
|
95
|
+
nil
|
|
96
|
+
end
|
|
97
|
+
|
|
98
|
+
def symbolize_keys(value)
|
|
99
|
+
case value
|
|
100
|
+
when Hash
|
|
101
|
+
value.each_with_object({}) do |(k, v), result|
|
|
102
|
+
result[k.to_sym] = symbolize_keys(v)
|
|
103
|
+
end
|
|
104
|
+
when Array
|
|
105
|
+
value.map { |item| symbolize_keys(item) }
|
|
106
|
+
else
|
|
107
|
+
value
|
|
108
|
+
end
|
|
109
|
+
end
|
|
110
|
+
end
|
|
111
|
+
end
|
|
112
|
+
end
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module AgentClientProtocol
|
|
4
|
+
module Types
|
|
5
|
+
module Unstable
|
|
6
|
+
end
|
|
7
|
+
end
|
|
8
|
+
|
|
9
|
+
class TypeRegistry
|
|
10
|
+
@mutex = Mutex.new
|
|
11
|
+
@loaded = {}
|
|
12
|
+
|
|
13
|
+
class << self
|
|
14
|
+
def fetch(definition_name, unstable: false)
|
|
15
|
+
ensure_loaded!(unstable: unstable)
|
|
16
|
+
namespace = unstable ? Types::Unstable : Types
|
|
17
|
+
return nil unless namespace.const_defined?(definition_name, false)
|
|
18
|
+
|
|
19
|
+
namespace.const_get(definition_name, false)
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
def all(unstable: false)
|
|
23
|
+
ensure_loaded!(unstable: unstable)
|
|
24
|
+
namespace = unstable ? Types::Unstable : Types
|
|
25
|
+
|
|
26
|
+
namespace.constants(false).sort.each_with_object({}) do |const_name, acc|
|
|
27
|
+
klass = namespace.const_get(const_name, false)
|
|
28
|
+
next unless klass.is_a?(Class)
|
|
29
|
+
next unless klass.respond_to?(:definition_name)
|
|
30
|
+
next if klass.definition_name.nil?
|
|
31
|
+
|
|
32
|
+
acc[const_name.to_s] = klass
|
|
33
|
+
end
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
def build(definition_name, payload, unstable: false)
|
|
37
|
+
klass = fetch(definition_name, unstable: unstable)
|
|
38
|
+
return payload if klass.nil?
|
|
39
|
+
|
|
40
|
+
klass.coerce(payload)
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
private
|
|
44
|
+
|
|
45
|
+
def ensure_loaded!(unstable: false)
|
|
46
|
+
key = unstable ? :unstable : :stable
|
|
47
|
+
return if @loaded[key]
|
|
48
|
+
|
|
49
|
+
@mutex.synchronize do
|
|
50
|
+
return if @loaded[key]
|
|
51
|
+
|
|
52
|
+
namespace = unstable ? Types::Unstable : Types
|
|
53
|
+
definitions = SchemaRegistry.defs(unstable: unstable)
|
|
54
|
+
build_types!(namespace, definitions, unstable: unstable)
|
|
55
|
+
|
|
56
|
+
@loaded[key] = true
|
|
57
|
+
end
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
def build_types!(namespace, definitions, unstable:)
|
|
61
|
+
definitions.each do |definition_name, schema|
|
|
62
|
+
next if namespace.const_defined?(definition_name, false)
|
|
63
|
+
|
|
64
|
+
parent = object_schema?(schema) ? Types::Base : Types::Scalar
|
|
65
|
+
klass = Class.new(parent)
|
|
66
|
+
if parent == Types::Scalar
|
|
67
|
+
klass.configure(
|
|
68
|
+
definition_name: definition_name,
|
|
69
|
+
schema: schema,
|
|
70
|
+
unstable: unstable,
|
|
71
|
+
coercer: scalar_coercer_for(definition_name)
|
|
72
|
+
)
|
|
73
|
+
else
|
|
74
|
+
klass.configure(
|
|
75
|
+
definition_name: definition_name,
|
|
76
|
+
schema: schema,
|
|
77
|
+
unstable: unstable
|
|
78
|
+
)
|
|
79
|
+
end
|
|
80
|
+
|
|
81
|
+
namespace.const_set(definition_name, klass)
|
|
82
|
+
end
|
|
83
|
+
end
|
|
84
|
+
|
|
85
|
+
def object_schema?(schema)
|
|
86
|
+
schema["type"] == "object" || schema.key?("properties")
|
|
87
|
+
end
|
|
88
|
+
|
|
89
|
+
def scalar_coercer_for(definition_name)
|
|
90
|
+
case definition_name
|
|
91
|
+
when "ProtocolVersion"
|
|
92
|
+
lambda { |value| ::AgentClientProtocol::ProtocolVersion.parse(value).to_i }
|
|
93
|
+
else
|
|
94
|
+
nil
|
|
95
|
+
end
|
|
96
|
+
end
|
|
97
|
+
end
|
|
98
|
+
end
|
|
99
|
+
end
|