From cf38ef470688a195650b1b71e01bd73b9ac80cf8 Mon Sep 17 00:00:00 2001 From: Carmine Paolino Date: Sat, 6 Jun 2026 12:57:40 +0200 Subject: [PATCH] Decide Draft 2020-12 output contract --- README.md | 20 +++- lib/ruby_llm/schema/json_output.rb | 59 +++++++++--- .../entry_points/class_inheritance_spec.rb | 24 ++--- .../schema/entry_points/factory_spec.rb | 20 ++-- .../schema/entry_points/helpers_spec.rb | 18 ++-- spec/ruby_llm/schema/json_output_spec.rb | 94 +++++++++++++++++++ .../schema/properties/conditionals_spec.rb | 6 +- .../schema/properties/core_keywords_spec.rb | 2 +- .../properties/definitions_reference_spec.rb | 14 +-- .../schema/properties/nested_schemas_spec.rb | 4 +- .../comprehensive_scenarios_spec.rb | 6 +- .../robustness/instance_methods_spec.rb | 17 ++-- .../schema/robustness/runtime_values_spec.rb | 8 +- .../schema/robustness/validation_spec.rb | 2 +- spec/ruby_llm/schema/strict_spec.rb | 8 +- 15 files changed, 224 insertions(+), 78 deletions(-) create mode 100644 spec/ruby_llm/schema/json_output_spec.rb diff --git a/README.md b/README.md index 01cd40e..204e68b 100644 --- a/README.md +++ b/README.md @@ -565,6 +565,24 @@ Conditions propagate through nested schemas via `of:`. schema = PersonSchema.new schema.to_json_schema # => { +# "$schema" => "https://json-schema.org/draft/2020-12/schema", +# "title" => "PersonSchema", +# "type" => "object", +# "properties" => { ... }, +# "required" => [...], +# "additionalProperties" => false +# } + +puts schema.to_json # Pretty JSON string +``` + +`to_json_schema` and `to_json` return pure Draft 2020-12 JSON Schema documents with JSON-compatible string keys. Provider-only envelope fields such as `name`, `schema`, and `strict` are not included. + +For migration, the old RubyLLM/provider envelope remains available: + +```ruby +schema.to_ruby_llm_schema +# => { # name: "PersonSchema", # description: nil, # schema: { @@ -575,8 +593,6 @@ schema.to_json_schema # strict: true # } # } - -puts schema.to_json # Pretty JSON string ``` ## License diff --git a/lib/ruby_llm/schema/json_output.rb b/lib/ruby_llm/schema/json_output.rb index b5b3bba..9ab7a6b 100644 --- a/lib/ruby_llm/schema/json_output.rb +++ b/lib/ruby_llm/schema/json_output.rb @@ -3,28 +3,27 @@ module RubyLLM class Schema module JsonOutput + DRAFT_2020_12_SCHEMA = "https://json-schema.org/draft/2020-12/schema" + def to_json_schema validate! # Validate schema before generating JSON - schema_hash = { - type: "object", - properties: self.class.properties, - required: self.class.required_properties, - additionalProperties: self.class.additional_properties - } + stringify_keys(resolve_runtime_values({ + "$schema" => DRAFT_2020_12_SCHEMA, + title: self.class.schema_metadata[:title] || @name, + description: @description || self.class.description + }.compact.merge(build_schema_hash))) + end - schema_hash[:strict] = self.class.strict unless self.class.strict.nil? + alias to_json_schema_document to_json_schema - # Only include $defs if there are definitions - schema_hash["$defs"] = self.class.definitions unless self.class.definitions.empty? - - self.class.send(:merge_conditions, schema_hash, self.class) - self.class.send(:merge_core_keywords, schema_hash, self.class) + def to_ruby_llm_schema + validate! # Validate schema before generating JSON { name: @name, description: resolve_runtime_values(@description || self.class.description), - schema: resolve_runtime_values(schema_hash) + schema: resolve_runtime_values(build_schema_hash(include_strict: true)) } end @@ -35,6 +34,25 @@ def to_json(*_args) private + def build_schema_hash(include_strict: false) + schema_hash = { + type: "object", + properties: self.class.properties, + required: self.class.required_properties, + additionalProperties: self.class.additional_properties + } + + schema_hash[:strict] = self.class.strict if include_strict && !self.class.strict.nil? + + # Only include $defs if there are definitions + schema_hash["$defs"] = self.class.definitions unless self.class.definitions.empty? + + self.class.send(:merge_conditions, schema_hash, self.class) + self.class.send(:merge_core_keywords, schema_hash, self.class) + + schema_hash + end + def resolve_runtime_values(value) case value when Proc @@ -51,6 +69,21 @@ def resolve_runtime_values(value) def evaluate_runtime_value(value) value.arity.zero? ? instance_exec(&value) : value.call(self) end + + def stringify_keys(value) + case value + when Hash + value.each_with_object({}) do |(key, nested_value), stringified| + stringified[key.to_s] = stringify_keys(nested_value) + end + when Array + value.map { |nested_value| stringify_keys(nested_value) } + when Symbol + value.to_s + else + value + end + end end end end diff --git a/spec/ruby_llm/schema/entry_points/class_inheritance_spec.rb b/spec/ruby_llm/schema/entry_points/class_inheritance_spec.rb index 2648fdd..89bc100 100644 --- a/spec/ruby_llm/schema/entry_points/class_inheritance_spec.rb +++ b/spec/ruby_llm/schema/entry_points/class_inheritance_spec.rb @@ -10,10 +10,10 @@ it "derives schema names from constants, instances, and defaults" do stub_const("NamedSchema", build_schema_class) - expect(NamedSchema.new.to_json_schema[:name]).to eq("NamedSchema") + expect(NamedSchema.new.to_ruby_llm_schema[:name]).to eq("NamedSchema") - expect(base_schema.new.to_json_schema[:name]).to eq("Schema") - expect(base_schema.new("CustomName").to_json_schema[:name]).to eq("CustomName") + expect(base_schema.new.to_ruby_llm_schema[:name]).to eq("Schema") + expect(base_schema.new("CustomName").to_ruby_llm_schema[:name]).to eq("CustomName") end it "honours description precedence" do @@ -22,18 +22,18 @@ string :title end - anonymous_output = base_schema.new.to_json_schema + anonymous_output = base_schema.new.to_ruby_llm_schema expect(anonymous_output[:description]).to be_nil - class_level_output = schema_with_description.new.to_json_schema + class_level_output = schema_with_description.new.to_ruby_llm_schema expect(class_level_output[:description]).to eq("Class-level description") - instance_override = schema_with_description.new("Test", description: "Instance description").to_json_schema + instance_override = schema_with_description.new("Test", description: "Instance description").to_ruby_llm_schema expect(instance_override[:description]).to eq("Instance description") end it "controls additional properties and strictness" do - default_output = base_schema.new.to_json_schema + default_output = base_schema.new.to_ruby_llm_schema expect(default_output[:schema][:additionalProperties]).to eq(false) expect(default_output[:schema][:strict]).to eq(true) @@ -43,7 +43,7 @@ string :title end - configured_output = configured_schema.new.to_json_schema + configured_output = configured_schema.new.to_ruby_llm_schema expect(configured_output[:schema][:additionalProperties]).to eq(true) expect(configured_output[:schema][:strict]).to eq(false) end @@ -56,7 +56,7 @@ integer :count, required: false end - output = configured_schema.new("ConfiguredSchema").to_json_schema + output = configured_schema.new("ConfiguredSchema").to_ruby_llm_schema expect(output).to include( name: "ConfiguredSchema", @@ -84,7 +84,7 @@ end expect(RedefinedSchema.required_properties).to eq([:name]) - expect(RedefinedSchema.new.to_json_schema[:schema][:required]).to eq([:name]) + expect(RedefinedSchema.new.to_ruby_llm_schema[:schema][:required]).to eq([:name]) end it "returns nil from property declarations" do @@ -102,7 +102,7 @@ schema_class.string :name, required: false expect(schema_class.required_properties).to eq([]) - expect(schema_class.new.to_json_schema[:schema][:required]).to eq([]) + expect(schema_class.new.to_ruby_llm_schema[:schema][:required]).to eq([]) end end @@ -131,7 +131,7 @@ end it "supports full-feature schemas" do - json_output = schema_class.new("TestSchema").to_json_schema + json_output = schema_class.new("TestSchema").to_ruby_llm_schema expect(json_output[:name]).to eq("TestSchema") expect(json_output[:schema][:additionalProperties]).to eq(true) diff --git a/spec/ruby_llm/schema/entry_points/factory_spec.rb b/spec/ruby_llm/schema/entry_points/factory_spec.rb index 3045c1a..4eebfd7 100644 --- a/spec/ruby_llm/schema/entry_points/factory_spec.rb +++ b/spec/ruby_llm/schema/entry_points/factory_spec.rb @@ -10,10 +10,10 @@ it "derives schema names from constants, instances, and defaults" do stub_const("NamedFactorySchema", build_factory_schema { string :title }) - expect(NamedFactorySchema.new.to_json_schema[:name]).to eq("NamedFactorySchema") + expect(NamedFactorySchema.new.to_ruby_llm_schema[:name]).to eq("NamedFactorySchema") - expect(base_schema.new.to_json_schema[:name]).to eq("Schema") - expect(base_schema.new("CustomName").to_json_schema[:name]).to eq("CustomName") + expect(base_schema.new.to_ruby_llm_schema[:name]).to eq("Schema") + expect(base_schema.new("CustomName").to_ruby_llm_schema[:name]).to eq("CustomName") end it "honours description precedence" do @@ -22,18 +22,18 @@ string :title end - anonymous_output = base_schema.new.to_json_schema + anonymous_output = base_schema.new.to_ruby_llm_schema expect(anonymous_output[:description]).to be_nil - class_level_output = schema_with_description.new.to_json_schema + class_level_output = schema_with_description.new.to_ruby_llm_schema expect(class_level_output[:description]).to eq("Factory description") - instance_override = schema_with_description.new("NamedSchema", description: "Instance description").to_json_schema + instance_override = schema_with_description.new("NamedSchema", description: "Instance description").to_ruby_llm_schema expect(instance_override[:description]).to eq("Instance description") end it "controls additional properties and strictness" do - default_output = base_schema.new.to_json_schema + default_output = base_schema.new.to_ruby_llm_schema expect(default_output[:schema][:additionalProperties]).to eq(false) expect(default_output[:schema][:strict]).to eq(true) @@ -43,7 +43,7 @@ string :title end - configured_output = configured_schema.new.to_json_schema + configured_output = configured_schema.new.to_ruby_llm_schema expect(configured_output[:schema][:additionalProperties]).to eq(true) expect(configured_output[:schema][:strict]).to eq(false) end @@ -56,7 +56,7 @@ integer :count, required: false end - output = configured_schema.new("FactoryConfiguredSchema").to_json_schema + output = configured_schema.new("FactoryConfiguredSchema").to_ruby_llm_schema expect(output).to include( name: "FactoryConfiguredSchema", @@ -100,7 +100,7 @@ end it "supports full-feature schemas" do - json_output = schema_class.new("FactorySchema").to_json_schema + json_output = schema_class.new("FactorySchema").to_ruby_llm_schema expect(json_output[:name]).to eq("FactorySchema") expect(json_output[:schema][:additionalProperties]).to eq(true) diff --git a/spec/ruby_llm/schema/entry_points/helpers_spec.rb b/spec/ruby_llm/schema/entry_points/helpers_spec.rb index c52de32..5e7c177 100644 --- a/spec/ruby_llm/schema/entry_points/helpers_spec.rb +++ b/spec/ruby_llm/schema/entry_points/helpers_spec.rb @@ -8,20 +8,20 @@ describe "schema attributes" do it "derives schema names from parameters and defaults" do named_schema = build_helper_schema("ProvidedName") { string :title } - expect(named_schema.to_json_schema[:name]).to eq("ProvidedName") + expect(named_schema.to_ruby_llm_schema[:name]).to eq("ProvidedName") default_schema = build_helper_schema { string :title } - expect(default_schema.to_json_schema[:name]).to eq("Schema") + expect(default_schema.to_ruby_llm_schema[:name]).to eq("Schema") end it "honours description precedence" do - default_output = build_helper_schema("TestSchema") { string :title }.to_json_schema + default_output = build_helper_schema("TestSchema") { string :title }.to_ruby_llm_schema expect(default_output[:description]).to be_nil block_description = build_helper_schema("TestSchema") do description "Block description" string :title - end.to_json_schema + end.to_ruby_llm_schema expect(block_description[:description]).to eq("Block description") parameter_override = build_helper_schema( @@ -30,12 +30,12 @@ ) do description "Block description" string :title - end.to_json_schema + end.to_ruby_llm_schema expect(parameter_override[:description]).to eq("Parameter description") end it "controls additional properties and strictness" do - default_output = build_helper_schema { string :title }.to_json_schema + default_output = build_helper_schema { string :title }.to_ruby_llm_schema expect(default_output[:schema][:additionalProperties]).to eq(false) expect(default_output[:schema][:strict]).to eq(true) @@ -43,7 +43,7 @@ additional_properties true strict false string :title - end.to_json_schema + end.to_ruby_llm_schema expect(configured_output[:schema][:additionalProperties]).to eq(true) expect(configured_output[:schema][:strict]).to eq(false) @@ -57,7 +57,7 @@ additional_properties false string :title integer :count, required: false - end.to_json_schema + end.to_ruby_llm_schema expect(json_output).to include( name: "HelperConfiguredSchema", @@ -99,7 +99,7 @@ string null end - end.to_json_schema + end.to_ruby_llm_schema expect(json_output[:name]).to eq("HelperSchema") expect(json_output[:description]).to eq("Comprehensive helper schema") diff --git a/spec/ruby_llm/schema/json_output_spec.rb b/spec/ruby_llm/schema/json_output_spec.rb new file mode 100644 index 0000000..a962d24 --- /dev/null +++ b/spec/ruby_llm/schema/json_output_spec.rb @@ -0,0 +1,94 @@ +# frozen_string_literal: true + +require "json" +require "spec_helper" + +RSpec.describe RubyLLM::Schema, "JSON output" do + it "returns a Draft 2020-12 JSON Schema document from to_json_schema" do + schema_class = Class.new(described_class) do + title "Person" + description "A person record" + id "https://example.com/schemas/person" + strict false + + string :name + integer :age, required: false + + define :address do + string :street + end + end + + output = schema_class.new("IgnoredName").to_json_schema + + expect(output).to eq({ + "$schema" => "https://json-schema.org/draft/2020-12/schema", + "title" => "Person", + "description" => "A person record", + "type" => "object", + "properties" => { + "name" => {"type" => "string"}, + "age" => {"type" => "integer"} + }, + "required" => ["name"], + "additionalProperties" => false, + "$defs" => { + "address" => { + "type" => "object", + "properties" => { + "street" => {"type" => "string"} + }, + "required" => ["street"], + "additionalProperties" => false + } + }, + "$id" => "https://example.com/schemas/person" + }) + end + + it "maps the schema instance name to title when no explicit title is set" do + schema_class = Class.new(described_class) do + string :name + end + + output = schema_class.new("PersonSchema").to_json_schema + + expect(output["title"]).to eq("PersonSchema") + end + + it "keeps provider-only strict out of pure JSON Schema output" do + schema_class = Class.new(described_class) do + strict true + string :name + end + + output = schema_class.new.to_json_schema + + expect(output).not_to have_key("strict") + end + + it "keeps the RubyLLM envelope available for migration" do + schema_class = Class.new(described_class) do + strict false + string :name + end + + output = schema_class.new("PersonSchema").to_ruby_llm_schema + + expect(output[:name]).to eq("PersonSchema") + expect(output[:schema][:strict]).to be(false) + expect(output[:schema][:properties][:name]).to eq({type: "string"}) + end + + it "serializes to_json as the pure JSON Schema document" do + schema_class = Class.new(described_class) do + string :name + end + + parsed = JSON.parse(schema_class.new("PersonSchema").to_json) + + expect(parsed["$schema"]).to eq("https://json-schema.org/draft/2020-12/schema") + expect(parsed["title"]).to eq("PersonSchema") + expect(parsed["properties"]["name"]).to eq({"type" => "string"}) + end +end diff --git a/spec/ruby_llm/schema/properties/conditionals_spec.rb b/spec/ruby_llm/schema/properties/conditionals_spec.rb index e654400..43c5cd0 100644 --- a/spec/ruby_llm/schema/properties/conditionals_spec.rb +++ b/spec/ruby_llm/schema/properties/conditionals_spec.rb @@ -6,7 +6,7 @@ let(:schema_class) { Class.new(described_class) } def schema_output - schema_class.new.to_json_schema[:schema] + schema_class.new.to_ruby_llm_schema[:schema] end describe "condition coercion" do @@ -334,7 +334,7 @@ def schema_output array :addresses, of: address_schema, required: false end - items = parent_schema.new.to_json_schema[:schema][:properties][:addresses][:items] + items = parent_schema.new.to_ruby_llm_schema[:schema][:properties][:addresses][:items] expect(items[:if][:properties]["country"]).to eq({const: "US"}) expect(items[:then][:required]).to eq(["state"]) @@ -511,7 +511,7 @@ def schema_output object :payment, of: payment_schema end - payment = order_schema.new.to_json_schema[:schema][:properties][:payment] + payment = order_schema.new.to_ruby_llm_schema[:schema][:properties][:payment] expect(payment[:dependentRequired]).to eq({"credit_card" => ["billing_address"]}) end diff --git a/spec/ruby_llm/schema/properties/core_keywords_spec.rb b/spec/ruby_llm/schema/properties/core_keywords_spec.rb index 09ce027..687d317 100644 --- a/spec/ruby_llm/schema/properties/core_keywords_spec.rb +++ b/spec/ruby_llm/schema/properties/core_keywords_spec.rb @@ -13,7 +13,7 @@ schema_class.dynamic_ref "#node" schema_class.vocabulary "https://json-schema.org/draft/2020-12/vocab/core" => true - schema = schema_class.new.to_json_schema[:schema] + schema = schema_class.new.to_ruby_llm_schema[:schema] expect(schema).to include( "$id" => "https://example.com/schemas/person", diff --git a/spec/ruby_llm/schema/properties/definitions_reference_spec.rb b/spec/ruby_llm/schema/properties/definitions_reference_spec.rb index 791c14b..1645201 100644 --- a/spec/ruby_llm/schema/properties/definitions_reference_spec.rb +++ b/spec/ruby_llm/schema/properties/definitions_reference_spec.rb @@ -20,7 +20,7 @@ expect(ref_hash).to eq({"$ref" => "#/$defs/address"}) instance = schema_class.new - json_output = instance.to_json_schema + json_output = instance.to_ruby_llm_schema expect(json_output[:schema]["$defs"][:address]).to include( type: "object", @@ -41,7 +41,7 @@ schema_class.object :sub_schema, of: :root instance = schema_class.new - json_output = instance.to_json_schema + json_output = instance.to_ruby_llm_schema expect(json_output[:schema][:properties][:sub_schema]).to eq({"$ref" => "#"}) end @@ -60,7 +60,7 @@ end instance = schema_class.new - json_output = instance.to_json_schema + json_output = instance.to_ruby_llm_schema expect(json_output[:schema][:properties][:user][:properties][:address]).to eq({"$ref" => "#/$defs/address"}) expect(json_output[:schema]["$defs"][:address]).to eq({ @@ -86,7 +86,7 @@ end instance = schema_class.new - json_output = instance.to_json_schema + json_output = instance.to_ruby_llm_schema expect(json_output[:schema][:properties][:user][:properties][:address]).to eq({"$ref" => "#/$defs/address"}) expect(json_output[:schema]["$defs"][:address]).to eq({ @@ -124,7 +124,7 @@ schema_class.object :address, of: :address - defs = schema_class.new.to_json_schema[:schema]["$defs"][:address] + defs = schema_class.new.to_ruby_llm_schema[:schema]["$defs"][:address] expect(defs[:if]).to eq({ properties: {"country" => {const: "US"}}, @@ -145,7 +145,7 @@ schema_class.object :payment, of: :payment - defs = schema_class.new.to_json_schema[:schema]["$defs"][:payment] + defs = schema_class.new.to_ruby_llm_schema[:schema]["$defs"][:payment] expect(defs[:dependentRequired]).to eq({"credit_card" => ["billing_address"]}) end @@ -158,7 +158,7 @@ schema_class.object :payment, of: :payment - defs = schema_class.new.to_json_schema[:schema]["$defs"][:payment] + defs = schema_class.new.to_ruby_llm_schema[:schema]["$defs"][:payment] expect(defs[:dependentRequired]).to eq({"credit_card" => ["billing_address"]}) end diff --git a/spec/ruby_llm/schema/properties/nested_schemas_spec.rb b/spec/ruby_llm/schema/properties/nested_schemas_spec.rb index 158f69e..37261db 100644 --- a/spec/ruby_llm/schema/properties/nested_schemas_spec.rb +++ b/spec/ruby_llm/schema/properties/nested_schemas_spec.rb @@ -59,7 +59,7 @@ end instance = schema_class.new - properties = instance.to_json_schema[:schema][:properties] + properties = instance.to_ruby_llm_schema[:schema][:properties] level3 = properties[:level1][:properties][:level2][:properties][:level3] expect(level3[:properties][:deep_value]).to eq({type: "string"}) @@ -130,7 +130,7 @@ stub_const("CompanySchema", company_schema) instance = company_schema.new("CompanySchema") - json_output = instance.to_json_schema + json_output = instance.to_ruby_llm_schema expect(json_output[:schema][:type]).to eq("object") expect(json_output[:schema][:properties][:employees][:items]).to eq(person_schema_hash) expect(json_output[:schema][:properties][:founder]).to eq(person_schema_hash) diff --git a/spec/ruby_llm/schema/robustness/comprehensive_scenarios_spec.rb b/spec/ruby_llm/schema/robustness/comprehensive_scenarios_spec.rb index 5f1068c..19acffc 100644 --- a/spec/ruby_llm/schema/robustness/comprehensive_scenarios_spec.rb +++ b/spec/ruby_llm/schema/robustness/comprehensive_scenarios_spec.rb @@ -6,14 +6,14 @@ include SchemaBuilders it "handles edge cases" do - empty_output = build_schema_class.new("EmptySchema").to_json_schema + empty_output = build_schema_class.new("EmptySchema").to_ruby_llm_schema expect(empty_output[:schema][:properties]).to eq({}) expect(empty_output[:schema][:required]).to eq([]) optional_output = build_schema_class { string :optional1, required: false integer :optional2, required: false - }.new.to_json_schema + }.new.to_ruby_llm_schema expect(optional_output[:schema][:required]).to eq([]) expect(optional_output[:schema][:properties].keys).to contain_exactly(:optional1, :optional2) @@ -54,7 +54,7 @@ end array :authors, of: :author - }.new("ComplexSchema").to_json_schema + }.new("ComplexSchema").to_ruby_llm_schema expect(complex_output[:schema][:properties].keys).to contain_exactly( :id, :metadata, :tags, :items, :status, :authors diff --git a/spec/ruby_llm/schema/robustness/instance_methods_spec.rb b/spec/ruby_llm/schema/robustness/instance_methods_spec.rb index 140f0ad..1f73d64 100644 --- a/spec/ruby_llm/schema/robustness/instance_methods_spec.rb +++ b/spec/ruby_llm/schema/robustness/instance_methods_spec.rb @@ -9,12 +9,12 @@ it "handles naming correctly" do stub_const("TestSchemaClass", build_schema_class) - expect(TestSchemaClass.new.to_json_schema[:name]).to eq("TestSchemaClass") + expect(TestSchemaClass.new.to_ruby_llm_schema[:name]).to eq("TestSchemaClass") - expect(schema_class.new.to_json_schema[:name]).to eq("Schema") - expect(schema_class.new("CustomName").to_json_schema[:name]).to eq("CustomName") + expect(schema_class.new.to_ruby_llm_schema[:name]).to eq("Schema") + expect(schema_class.new("CustomName").to_ruby_llm_schema[:name]).to eq("CustomName") - described_output = schema_class.new("TestName", description: "Custom description").to_json_schema + described_output = schema_class.new("TestName", description: "Custom description").to_ruby_llm_schema expect(described_output[:name]).to eq("TestName") expect(described_output[:description]).to eq("Custom description") end @@ -24,7 +24,7 @@ name "ConfiguredDSLName" end - expect(configured_schema.new.to_json_schema[:name]).to eq("ConfiguredDSLName") + expect(configured_schema.new.to_ruby_llm_schema[:name]).to eq("ConfiguredDSLName") end it "supports method delegation for schema methods" do @@ -42,7 +42,7 @@ integer :age, required: false end - json_output = schema_with_fields.new("TestSchema").to_json_schema + json_output = schema_with_fields.new("TestSchema").to_ruby_llm_schema expect(json_output).to include( name: "TestSchema", @@ -61,6 +61,9 @@ json_string = schema_with_fields.new("TestSchema").to_json expect(json_string).to be_a(String) - expect(JSON.parse(json_string)["name"]).to eq("TestSchema") + + parsed_json = JSON.parse(json_string) + expect(parsed_json["title"]).to eq("TestSchema") + expect(parsed_json["properties"]["name"]).to eq({"type" => "string"}) end end diff --git a/spec/ruby_llm/schema/robustness/runtime_values_spec.rb b/spec/ruby_llm/schema/robustness/runtime_values_spec.rb index 805dc11..5eafbb9 100644 --- a/spec/ruby_llm/schema/robustness/runtime_values_spec.rb +++ b/spec/ruby_llm/schema/robustness/runtime_values_spec.rb @@ -13,8 +13,8 @@ def initialize(user_names:) string :name, enum: -> { @user_names } end - first_schema = schema_class.new(user_names: %w[Alice Bob]).to_json_schema - second_schema = schema_class.new(user_names: %w[Carol]).to_json_schema + first_schema = schema_class.new(user_names: %w[Alice Bob]).to_ruby_llm_schema + second_schema = schema_class.new(user_names: %w[Carol]).to_ruby_llm_schema expect(first_schema[:schema][:properties][:name][:enum]).to eq(%w[Alice Bob]) expect(second_schema[:schema][:properties][:name][:enum]).to eq(%w[Carol]) @@ -35,7 +35,7 @@ def initialize(user_names:) end end - output = schema_class.new(user_names: %w[Alice Bob]).to_json_schema + output = schema_class.new(user_names: %w[Alice Bob]).to_ruby_llm_schema name_schema = output[:schema][:properties][:users][:items][:properties][:name] expect(name_schema[:enum]).to eq(%w[Alice Bob]) @@ -53,7 +53,7 @@ def initialize(allowed_roles:) string :role, enum: ->(schema) { schema.allowed_roles.dup } end - output = schema_class.new(allowed_roles: %w[admin user]).to_json_schema + output = schema_class.new(allowed_roles: %w[admin user]).to_ruby_llm_schema expect(output[:schema][:properties][:role][:enum]).to eq(%w[admin user]) end diff --git a/spec/ruby_llm/schema/robustness/validation_spec.rb b/spec/ruby_llm/schema/robustness/validation_spec.rb index 94cdc19..2b10518 100644 --- a/spec/ruby_llm/schema/robustness/validation_spec.rb +++ b/spec/ruby_llm/schema/robustness/validation_spec.rb @@ -49,7 +49,7 @@ def define_user(schema) schema_class.definitions[:user][:properties][:self_ref] = schema_class.reference(:user) instance = schema_class.new - expect { instance.to_json_schema }.to raise_error(RubyLLM::Schema::ValidationError) + expect { instance.to_ruby_llm_schema }.to raise_error(RubyLLM::Schema::ValidationError) expect { instance.to_json }.to raise_error(RubyLLM::Schema::ValidationError) end end diff --git a/spec/ruby_llm/schema/strict_spec.rb b/spec/ruby_llm/schema/strict_spec.rb index 1cbf5eb..33cb7c8 100644 --- a/spec/ruby_llm/schema/strict_spec.rb +++ b/spec/ruby_llm/schema/strict_spec.rb @@ -5,25 +5,25 @@ RSpec.describe RubyLLM::Schema, ".strict" do it "outputs strict: true by default" do schema = Class.new(RubyLLM::Schema) - output = schema.new.to_json_schema + output = schema.new.to_ruby_llm_schema expect(output[:schema][:strict]).to eq(true) end it "omits strict from output when set to nil" do schema = Class.new(RubyLLM::Schema) { strict nil } - output = schema.new.to_json_schema + output = schema.new.to_ruby_llm_schema expect(output[:schema]).not_to have_key(:strict) end it "outputs strict: true when set to true" do schema = Class.new(RubyLLM::Schema) { strict true } - output = schema.new.to_json_schema + output = schema.new.to_ruby_llm_schema expect(output[:schema][:strict]).to eq(true) end it "outputs strict: false when set to false" do schema = Class.new(RubyLLM::Schema) { strict false } - output = schema.new.to_json_schema + output = schema.new.to_ruby_llm_schema expect(output[:schema][:strict]).to eq(false) end end