agent2agentSourceA2ASchemaself

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