class << self
Definitions
def [](name)
Look up a definition by title.
A2A::Schema["Agent Capabilities"] #=> Class < Definition
Implementation
def [](name)
@definition_classes[name] ||= begin
definitions = raw_schema.fetch("definitions", {})
unless definitions.key?(name)
raise "No A2A definition found for #{name.inspect}!" \
"\nAvailable: #{list_definitions.join(", ")}"
end
encoded = URI::DEFAULT_PARSER.escape(name)
ref_schema = schemer.ref("#/definitions/#{encoded}")
build_definition_class(ref_schema, name, definitions[name])
end
end
def list_definitions
All available definition titles, sorted.
A2A::Schema.list_definitions #=> ["API Key Security Scheme", "Agent Capabilities", ...]
Implementation
def list_definitions
raw_schema.fetch("definitions", {}).keys.sort
end
def schemer
The JSONSchemer instance for the full A2A schema bundle. Cached after first access.
Implementation
def schemer
@schemer ||= JSONSchemer.schema(raw_schema)
end
def raw_schema
The parsed + ref-rewritten JSON schema hash.
Implementation
def raw_schema
@raw_schema ||= load_and_rewrite_schema
end
def reset!
Reset all cached state (useful for tests).
Implementation
def reset!
@definition_classes.clear
@schemer = nil
@raw_schema = nil
@ref_map = nil
end
def load_and_rewrite_schema
Load data/a2a.json, build the $ref rewrite map, and walk the entire tree replacing external refs with internal ones.
Implementation
def load_and_rewrite_schema
schema = JSON.parse(File.read(DATA_PATH))
map = build_ref_map(schema)
rewrite_refs!(schema, map)
schema
end
def build_ref_map(schema)
Build a map from external $ref strings to internal #/definitions/Title pointers.
Implementation
def build_ref_map(schema)
return @ref_map if @ref_map
definitions = schema.fetch("definitions", {})
pascal_to_title = {}
definitions.each_key do |title|
pascal = title.gsub(/\s+/, "")
pascal_to_title[pascal] = title
end
refs = collect_refs(schema)
map = {}
refs.each do |ref_str|
type_name = ref_str
.sub(/\.jsonschema\.json\z/, "")
.split(".")
.last
if (title = pascal_to_title[type_name])
encoded = URI::DEFAULT_PARSER.escape(title)
map[ref_str] = "#/definitions/#{encoded}"
end
end
@ref_map = map
end
def collect_refs(obj, refs = Set.new)
Recursively collect all $ref string values from a JSON tree.
Implementation
def collect_refs(obj, refs = Set.new)
case obj
when Hash
obj.each do |k, v|
if k == "$ref" && v.is_a?(String) && !v.start_with?("#")
refs << v
else
collect_refs(v, refs)
end
end
when Array
obj.each { |v| collect_refs(v, refs) }
end
refs
end
def rewrite_refs!(obj, map)
Walk the schema tree and replace all external $ref values with their internal #/definitions/... equivalents.
Implementation
def rewrite_refs!(obj, map)
case obj
when Hash
obj.each do |k, v|
if k == "$ref" && v.is_a?(String) && map.key?(v)
obj[k] = map[v]
else
rewrite_refs!(v, map)
end
end
when Array
obj.each { |v| rewrite_refs!(v, map) }
end
end
def build_definition_class(schema_instance, definition_name, raw_definition)
Build a Definition subclass for a specific A2A type.
Implementation
def build_definition_class(schema_instance, definition_name, raw_definition)
properties = raw_definition.fetch("properties", {})
camel_keys = properties.keys
snake_to_camel = build_snake_to_camel(camel_keys)
reader_pairs = camel_keys.map { |ck| [camel_to_snake(ck).to_sym, ck] }
Class.new(Definition) do
@schema = schema_instance
@definition_name = definition_name
@schema_properties = camel_keys
@snake_to_camel = snake_to_camel
class << self
def schema = @schema
def definition_name = @definition_name
def schema_properties = @schema_properties
def snake_to_camel_map = @snake_to_camel
end
reader_pairs.each do |snake_sym, camel_key|
define_method(snake_sym) { @data[camel_key] }
end
end
end