ruby_llm-contract 0.10.2 → 0.10.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: ac8c19463285a3e2c0f9050e835125454b21d2b1500dcb5bad2dd4a114666bd0
4
- data.tar.gz: 339c0609e3dccbf55da649c3470ed234c5abafa55c8649aee5d8dd41f9bd82ec
3
+ metadata.gz: 4dc75c6a5ec293047bd2e2c480cf0aaff0fb3f5043f668a9291553a30002ed53
4
+ data.tar.gz: 4bd5960d8ff68b8708992755a95e8b265f28cdc3734db80dbdeada251eebfba9
5
5
  SHA512:
6
- metadata.gz: c04fea66393868fbdb369f5a75eaeb66a28172c8f9ddabd0a8c053fd55e5daa06174aeeb00c4bb7e9aabaf613bd1ef4ea354ff7d0f4b817f2ec41af1a4c61667
7
- data.tar.gz: 71f502ebe497ede22df508d3b56396660fbd1eba109066885d5e905724bd82d30a0d46fddfe4f1c1e7efe47f95ea41b4f61341a4698c12d3f3a397cab2510068
6
+ metadata.gz: aa5741f4728be169c42ee861aa6c8366481b21d49e2ff66105028d22d027ba7939959c784b13f7f8707ae0483608a0360cd035aee2ba4eadd6c2e4b30edfe680
7
+ data.tar.gz: 875ffe28d243189193d8dad0a4d2201329b92d9701f9eec49349719ac20d678b4de21a15db7db7f827fa19bb5d1adbdf22496186a17802147156cc88e1664a9d
data/CHANGELOG.md CHANGED
@@ -1,5 +1,20 @@
1
1
  # Changelog
2
2
 
3
+ ## 0.10.3 (2026-06-10)
4
+
5
+ Hot-fix release: the schema validator now correctly accepts `nil` on **required-but-nullable** fields. This unblocks OpenAI structured-output strict mode, where every property has to be in `required` and "nullable" is expressed as a `null` branch in `anyOf`/`oneOf` or as an array `type` — exactly the combination the prior validator wrongly rejected.
6
+
7
+ ### Fixed
8
+
9
+ - **`SchemaValidator` no longer rejects legal `nil` on required-nullable fields.** Pre-0.10.3 (every published version 0.2.x–0.10.2) conflated "required" (must be present) with "non-nullable" (cannot be null) — JSON Schema treats those as orthogonal. The validator now honours all three idioms for nullability:
10
+ - `type: ["string", "null"]` (array form)
11
+ - `type: "null"` (degenerate scalar form)
12
+ - `anyOf: [{type: "string"}, {type: "null"}]` and `oneOf` equivalents
13
+
14
+ **Adopter impact:** if you bypassed the bug by setting `required: false` + disabling OpenAI `strict: true` on every nullable field, you can now restore `strict: true` and keep the field required (= OpenAI's standard nullable idiom). Non-nullable required fields still reject `nil` exactly as before; this is a strictly additive fix.
15
+
16
+ Discovered via dogfooding in a production adopter using OpenAI strict structured output with 17 nullable fields (`"set the rest to null"` prompt). Smoking-gun mutation: remove `nullable_schema?` short-circuit from `validate_nil_field` — the three new spec cases in `spec/ruby_llm/contract/contract/schema_validator_spec.rb` fail.
17
+
3
18
  ## 0.10.2 (2026-06-10)
4
19
 
5
20
  Patch release: ship the `docs/guide/` directory inside the gem so adopters and LLM integration agents can read the manuals locally (via `bundle show ruby_llm-contract` or `gem unpack`) without an internet round-trip to GitHub. No code behavior change.
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- ruby_llm-contract (0.10.2)
4
+ ruby_llm-contract (0.10.3)
5
5
  dry-types (~> 1.7)
6
6
  ruby_llm (~> 1.12)
7
7
  ruby_llm-schema (~> 0.3)
@@ -258,7 +258,7 @@ CHECKSUMS
258
258
  rubocop-ast (1.49.1) sha256=4412f3ee70f6fe4546cc489548e0f6fcf76cafcfa80fa03af67098ffed755035
259
259
  ruby-progressbar (1.13.0) sha256=80fc9c47a9b640d6834e0dc7b3c94c9df37f08cb072b7761e4a71e22cff29b33
260
260
  ruby_llm (1.14.0) sha256=57c6f7034fc4a44504ea137d70f853b07824f1c1cdbe774ab3ab3522e7098deb
261
- ruby_llm-contract (0.10.2)
261
+ ruby_llm-contract (0.10.3)
262
262
  ruby_llm-schema (0.3.0) sha256=a591edc5ca1b7f0304f0e2261de61ba4b3bea17be09f5cf7558153adfda3dec6
263
263
  ruby_parser (3.22.0) sha256=1eb4937cd9eb220aa2d194e352a24dba90aef00751e24c8dfffdb14000f15d23
264
264
  rubycritic (4.12.0) sha256=024fed90fe656fa939f6ea80aab17569699ac3863d0b52fd72cb99892247abc8
data/README.md CHANGED
@@ -157,7 +157,7 @@ Different layers, complementary. [`ruby_llm-tribunal`](https://github.com/Alqemi
157
157
 
158
158
  ## Status & versioning
159
159
 
160
- Pre-1.0 (currently **0.10.2**). Semver tracked; breaking changes flagged in [CHANGELOG](CHANGELOG.md). Pin `~> 0.10.2` until 1.0 ships.
160
+ Pre-1.0 (currently **0.10.3**). Semver tracked; breaking changes flagged in [CHANGELOG](CHANGELOG.md). Pin `~> 0.10.3` until 1.0 ships.
161
161
 
162
162
  ## FAQ
163
163
 
@@ -45,11 +45,35 @@ module RubyLLM
45
45
 
46
46
  def validate_nil_field(path, field_schema, required)
47
47
  return unless required
48
+ return if nullable_schema?(field_schema)
48
49
 
49
50
  expected_type = field_schema[:type] || "non-null"
50
51
  @errors << "#{path}: expected #{expected_type}, got nil"
51
52
  end
52
53
 
54
+ # JSON Schema permits nil when the field schema explicitly accepts
55
+ # null. Three idiomatic forms are recognised:
56
+ # - `type: ["string", "null"]` (array form)
57
+ # - `type: "null"` (degenerate scalar form)
58
+ # - `anyOf` / `oneOf` containing a branch with `type: "null"`
59
+ # Without this gate the validator wrongly rejected legal nulls on
60
+ # required-but-nullable fields, forcing adopters into `required: false`
61
+ # + `strict: false` workarounds. Fixed in 0.10.3.
62
+ def nullable_schema?(field_schema)
63
+ return false unless field_schema.is_a?(Hash)
64
+
65
+ type = field_schema[:type] || field_schema["type"]
66
+ return true if type.is_a?(Array) && type.any? { |t| t.to_s == "null" }
67
+ return true if type.to_s == "null"
68
+
69
+ %i[anyOf oneOf].any? do |key|
70
+ branches = field_schema[key] || field_schema[key.to_s]
71
+ branches.is_a?(Array) && branches.any? do |branch|
72
+ branch.is_a?(Hash) && (branch[:type] || branch["type"]).to_s == "null"
73
+ end
74
+ end
75
+ end
76
+
53
77
  def validate_additional_properties(node)
54
78
  return unless node.schema[:additionalProperties] == false
55
79
 
@@ -2,6 +2,6 @@
2
2
 
3
3
  module RubyLLM
4
4
  module Contract
5
- VERSION = "0.10.2"
5
+ VERSION = "0.10.3"
6
6
  end
7
7
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: ruby_llm-contract
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.10.2
4
+ version: 0.10.3
5
5
  platform: ruby
6
6
  authors:
7
7
  - Justyna