Class: Mistri::Schema
- Inherits:
-
Object
- Object
- Mistri::Schema
- Defined in:
- lib/mistri/schema.rb
Overview
A small builder for tool argument schemas, so a tool declares its inputs in Ruby instead of hand-writing JSON Schema. It emits the object schema every provider accepts:
Schema.build do
string :city, "City name", required: true
string :units, "Temperature units", enum: %w[celsius fahrenheit]
integer :days, "Forecast length"
end
A raw JSON Schema hash is always accepted directly for anything the builder does not cover, so the DSL is a convenience, never a ceiling.
Constant Summary collapse
- TYPES =
{ "object" => ->(v) { v.is_a?(Hash) }, "array" => ->(v) { v.is_a?(Array) }, "string" => ->(v) { v.is_a?(String) }, "integer" => ->(v) { v.is_a?(Integer) }, "number" => ->(v) { v.is_a?(Numeric) }, "boolean" => ->(v) { [true, false].include?(v) }, "null" => lambda(&:nil?) }.freeze
Class Method Summary collapse
-
.build ⇒ Object
instance_exec, not instance_eval: it binds self to the builder without passing an argument, so a zero-arity lambda works as naturally as a proc.
-
.strict(schema, all_required: false) ⇒ Object
Prepares a schema for constrained decoding: every object gains additionalProperties: false (Anthropic and OpenAI both demand it), and all_required marks every property required (OpenAI strict mode's rule).
-
.violations(value, schema, path = "$") ⇒ Object
Violations of a value against the schema subset the harness emits and providers constrain: types (including type arrays), object properties with required and additionalProperties: false, array items, enum.
Instance Method Summary collapse
- #array(name, description = nil, items: { type: "string" }, required: false, **extra) ⇒ Object
-
#initialize ⇒ Schema
constructor
A new instance of Schema.
- #object(name, description = nil, required: false) ⇒ Object
- #to_h ⇒ Object
Constructor Details
#initialize ⇒ Schema
Returns a new instance of Schema.
25 26 27 28 |
# File 'lib/mistri/schema.rb', line 25 def initialize @properties = {} @required = [] end |
Class Method Details
.build ⇒ Object
instance_exec, not instance_eval: it binds self to the builder without passing an argument, so a zero-arity lambda works as naturally as a proc.
19 20 21 22 23 |
# File 'lib/mistri/schema.rb', line 19 def self.build(&) builder = new builder.instance_exec(&) builder.to_h end |
.strict(schema, all_required: false) ⇒ Object
Prepares a schema for constrained decoding: every object gains additionalProperties: false (Anthropic and OpenAI both demand it), and all_required marks every property required (OpenAI strict mode's rule). String keys throughout, ready for the wire.
89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 |
# File 'lib/mistri/schema.rb', line 89 def strict(schema, all_required: false) spec = schema.transform_keys(&:to_s) out = spec.dup if spec["type"] == "object" || spec.key?("properties") props = (spec["properties"] || {}).to_h do |key, member| [key.to_s, strict(member, all_required: all_required)] end out["properties"] = props out["additionalProperties"] = false out["required"] = all_required ? props.keys : Array(spec["required"]).map(&:to_s) end if spec["items"].is_a?(Hash) out["items"] = strict(spec["items"], all_required: all_required) end out end |
.violations(value, schema, path = "$") ⇒ Object
Violations of a value against the schema subset the harness emits and providers constrain: types (including type arrays), object properties with required and additionalProperties: false, array items, enum. Empty means valid; entries are human-readable, written to be fed back to a model for one-shot correction.
69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 |
# File 'lib/mistri/schema.rb', line 69 def violations(value, schema, path = "$") spec = schema.transform_keys(&:to_s) mismatch = type_violation(value, spec, path) return [mismatch] if mismatch errors = [] if (enum = spec["enum"]) && !enum.include?(value) errors << "#{path} must be one of: #{enum.join(", ")}" end case value when Hash then errors.concat(object_violations(value, spec, path)) when Array then errors.concat(array_violations(value, spec, path)) end errors end |
Instance Method Details
#array(name, description = nil, items: { type: "string" }, required: false, **extra) ⇒ Object
41 42 43 44 45 46 47 |
# File 'lib/mistri/schema.rb', line 41 def array(name, description = nil, items: { type: "string" }, required: false, **extra) prop = { type: "array", items: items } prop[:description] = description if description @properties[name.to_s] = prop.merge(extra) @required << name.to_s if required nil end |
#object(name, description = nil, required: false) ⇒ Object
49 50 51 52 53 54 55 |
# File 'lib/mistri/schema.rb', line 49 def object(name, description = nil, required: false, &) prop = self.class.build(&) prop[:description] = description if description @properties[name.to_s] = prop @required << name.to_s if required nil end |
#to_h ⇒ Object
57 58 59 60 61 |
# File 'lib/mistri/schema.rb', line 57 def to_h schema = { type: "object", properties: @properties } schema[:required] = @required unless @required.empty? schema end |