Class: A2A::Protocol::JsonSchema::Definition

Inherits:
Object
  • Object
show all
Defined in:
lib/a2a/protocol/json_schema/definition.rb

Overview

Base class for schema-validated A2A protocol objects.

Each A2A definition type (Agent Card, Agent Capabilities, Task, etc.) gets a dynamically-generated subclass of Definition with:

- A JSONSchemer sub-schema attached (.schema)
- Reader methods for each property (snake_case)
- Validation via .valid? / .valid!

caps = A2A::Protocol::JsonSchema["Agent Capabilities"].new(
streaming: true,
push_notifications: false
)
caps.valid?             #=> true
caps.streaming          #=> true
caps.push_notifications #=> false
caps.to_h               #=> { "streaming" => true, "pushNotifications" => false }

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(hash = {}) ⇒ Definition

Returns a new instance of Definition.



28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
# File 'lib/a2a/protocol/json_schema/definition.rb', line 28

def initialize(hash = {})
  props    = self.class.schema_properties
  snake    = self.class.snake_to_camel_map
  refs     = self.class.property_refs
  @data    = {}

  hash.each do |key, value|
    k = key.to_s

    # Resolve snake_case input to camelCase storage key
    camel = snake[k] || k

    if props.include?(camel)
      @data[camel] = if value.is_a?(Definition)
        value.to_h
      elsif (ref_info = refs[camel])
        wrap_ref(value, ref_info)
      else
        value
      end
    end
  end
end

Class Method Details

.camel_to_snake_mapObject

Reverse of snake_to_camel_map. Built first-entry-wins: the factory inserts the snake_case key before the camelCase identity key, so camelCase storage keys map back to their snake_case reader names.



78
79
80
81
82
# File 'lib/a2a/protocol/json_schema/definition.rb', line 78

def self.camel_to_snake_map
  @camel_to_snake_map ||= snake_to_camel_map.each_with_object({}) do |(key, camel), map|
    map[camel] ||= key
  end
end

.definition_nameObject



58
59
60
# File 'lib/a2a/protocol/json_schema/definition.rb', line 58

def self.definition_name
  raise "A2A::Protocol::JsonSchema::Definition should NOT be instantiated directly"
end

.property_refsObject



70
71
72
# File 'lib/a2a/protocol/json_schema/definition.rb', line 70

def self.property_refs
  raise "A2A::Protocol::JsonSchema::Definition should NOT be instantiated directly"
end

.schemaObject

--- class methods overridden by the factory -----------------------



54
55
56
# File 'lib/a2a/protocol/json_schema/definition.rb', line 54

def self.schema
  raise "A2A::Protocol::JsonSchema::Definition should NOT be instantiated directly"
end

.schema_propertiesObject



62
63
64
# File 'lib/a2a/protocol/json_schema/definition.rb', line 62

def self.schema_properties
  raise "A2A::Protocol::JsonSchema::Definition should NOT be instantiated directly"
end

.snake_to_camel_mapObject



66
67
68
# File 'lib/a2a/protocol/json_schema/definition.rb', line 66

def self.snake_to_camel_map
  raise "A2A::Protocol::JsonSchema::Definition should NOT be instantiated directly"
end

Instance Method Details

#==(other) ⇒ Object



109
110
111
# File 'lib/a2a/protocol/json_schema/definition.rb', line 109

def ==(other)
  other.is_a?(Definition) && to_h == other.to_h
end

#deconstruct_keys(keys) ⇒ Object

Supports Ruby hash pattern matching:

case env["a2a.request"].message
in { task_id: String => id, parts: }
...
end

Keys are the snake_case property names, same as the reader methods (camelCase symbols also work). Absent properties are omitted from the result so patterns that require them fail to match. Nested Definition values are returned as-is, so patterns can destructure recursively.



127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
# File 'lib/a2a/protocol/json_schema/definition.rb', line 127

def deconstruct_keys(keys)
  snake = self.class.snake_to_camel_map

  if keys
    keys.each_with_object({}) do |key, result|
      camel = snake[key.to_s] || key.to_s
      result[key] = @data[camel] if @data.key?(camel)
    end
  else
    camel_to_snake = self.class.camel_to_snake_map
    @data.each_with_object({}) do |(camel, value), result|
      result[(camel_to_snake[camel] || camel).to_sym] = value
    end
  end
end

#inspectObject



143
144
145
# File 'lib/a2a/protocol/json_schema/definition.rb', line 143

def inspect
  "#<#{self.class.definition_name} #{to_h.inspect}>"
end

#to_hObject

Returns the data as a plain Hash with camelCase string keys, matching the JSON wire format. Nested Definition instances are auto-coerced via deep_compact.



105
106
107
# File 'lib/a2a/protocol/json_schema/definition.rb', line 105

def to_h
  deep_compact(@data)
end

#valid!Object

Raises:



90
91
92
93
94
95
96
97
98
# File 'lib/a2a/protocol/json_schema/definition.rb', line 90

def valid!
  errors = self.class.schema.validate(to_h).to_a
  return true if errors.empty?

  raise ValidationError.new(errors,
    definition_name: self.class.definition_name,
    data: to_h
  )
end

#valid?Boolean

--- validation ----------------------------------------------------

Returns:

  • (Boolean)


86
87
88
# File 'lib/a2a/protocol/json_schema/definition.rb', line 86

def valid?
  self.class.schema.valid?(to_h)
end