Class: AgUi::Protocol::JsonSchema::Definition

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

Overview

Base class for schema-validated AG-UI protocol objects. Ported from a2a's Protocol::JsonSchema::Definition.

Each AG-UI definition (RunAgentInput, TextMessageContentEvent, …) 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!

NOTE: #to_h deep-compacts nil values (matching pydantic's exclude_none on the wire). Inbound payloads that carry explicit nulls (e.g. RunAgentInput.state) should be validated as raw hashes via JsonSchema.schemer, not round-tripped through here.

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(hash = {}) ⇒ Definition

Returns a new instance of Definition.



23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
# File 'lib/ag_ui/protocol/json_schema/definition.rb', line 23

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.



73
74
75
76
77
# File 'lib/ag_ui/protocol/json_schema/definition.rb', line 73

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



53
54
55
# File 'lib/ag_ui/protocol/json_schema/definition.rb', line 53

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

.property_refsObject



65
66
67
# File 'lib/ag_ui/protocol/json_schema/definition.rb', line 65

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

.schemaObject

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



49
50
51
# File 'lib/ag_ui/protocol/json_schema/definition.rb', line 49

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

.schema_propertiesObject



57
58
59
# File 'lib/ag_ui/protocol/json_schema/definition.rb', line 57

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

.snake_to_camel_mapObject



61
62
63
# File 'lib/ag_ui/protocol/json_schema/definition.rb', line 61

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

Instance Method Details

#==(other) ⇒ Object



108
109
110
# File 'lib/ag_ui/protocol/json_schema/definition.rb', line 108

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

#deconstruct_keys(keys) ⇒ Object

Supports Ruby hash pattern matching with snake_case (or camelCase) keys. Absent properties are omitted so patterns requiring them fail to match; nested Definitions destructure recursively.



117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
# File 'lib/ag_ui/protocol/json_schema/definition.rb', line 117

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
      if @data.key?(camel)
        result[key] = @data[camel]
      end
    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



135
136
137
# File 'lib/ag_ui/protocol/json_schema/definition.rb', line 135

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.



104
105
106
# File 'lib/ag_ui/protocol/json_schema/definition.rb', line 104

def to_h
  deep_compact(@data)
end

#valid!Object



85
86
87
88
89
90
91
92
93
94
95
96
97
# File 'lib/ag_ui/protocol/json_schema/definition.rb', line 85

def valid!
  errors = self.class.schema.validate(to_h).to_a

  if errors.empty?
    true
  else
    raise ValidationError.new(
      errors,
      definition_name: self.class.definition_name,
      data: to_h,
    )
  end
end

#valid?Boolean

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

Returns:

  • (Boolean)


81
82
83
# File 'lib/ag_ui/protocol/json_schema/definition.rb', line 81

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