ruby_llm-schema 0.4.0 → 1.0.0
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 +4 -4
- data/README.md +17 -517
- data/lib/ruby_llm/schema.rb +23 -91
- metadata +30 -24
- data/LICENSE +0 -21
- data/lib/ruby_llm/schema/dsl/complex_types.rb +0 -32
- data/lib/ruby_llm/schema/dsl/conditionals.rb +0 -169
- data/lib/ruby_llm/schema/dsl/primitive_types.rb +0 -29
- data/lib/ruby_llm/schema/dsl/schema_builders.rb +0 -194
- data/lib/ruby_llm/schema/dsl/utilities.rb +0 -63
- data/lib/ruby_llm/schema/dsl.rb +0 -19
- data/lib/ruby_llm/schema/errors.rb +0 -30
- data/lib/ruby_llm/schema/helpers.rb +0 -10
- data/lib/ruby_llm/schema/json_output.rb +0 -36
- data/lib/ruby_llm/schema/validator.rb +0 -93
- data/lib/ruby_llm/schema/version.rb +0 -7
- data/lib/tasks/release.rake +0 -8
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 6bfabbb94f9550f5bae72fc6ad6046ba1fa6f9e99723c4fea969822bd76f33f9
|
|
4
|
+
data.tar.gz: 5b97078d6f40a912a366c4d8f26333ead3504126e9a2abd3d8d658f81d168283
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: adc5528fd26d989854bbf0d6255bda4123fa6df18d96722c38b47a7414ff8c53006212f8c987932d190913553bad3764870038589ebb20a070ebc38e034de87c
|
|
7
|
+
data.tar.gz: 85d522c3b21f5949ce3ed5dba3aef643836d16b5daaca44c2d6a8beeec67e6cfae65ca126e4dbd49edf434f0134aeecb715216c6f3da793d0445a38baa2442fb
|
data/README.md
CHANGED
|
@@ -1,528 +1,28 @@
|
|
|
1
|
-
#
|
|
1
|
+
# ruby_llm-schema (deprecated)
|
|
2
2
|
|
|
3
|
-
[
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
[](https://github.com/rubocop/rubocop)
|
|
3
|
+
This gem is now [schematist](https://github.com/crmne/schematist). This directory holds the
|
|
4
|
+
final `ruby_llm-schema` release, which does nothing but depend on schematist and alias
|
|
5
|
+
`RubyLLM::Schema` to `Schematist::Schema`.
|
|
7
6
|
|
|
8
|
-
|
|
7
|
+
It lives in the schematist repo rather than its own, so the alias cannot drift from the gem
|
|
8
|
+
it forwards to. The spec suite loads it and checks the aliases still resolve.
|
|
9
9
|
|
|
10
|
-
|
|
10
|
+
## Building and releasing
|
|
11
11
|
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
JSON Schema is useful wherever Ruby code needs to describe structured data in a portable format.
|
|
15
|
-
|
|
16
|
-
Some ideal use cases:
|
|
17
|
-
|
|
18
|
-
- Defining API request and response shapes
|
|
19
|
-
- Describing configuration files or structured payloads
|
|
20
|
-
- Sharing validation contracts across systems
|
|
21
|
-
- Generating structured output schemas for LLM workflows
|
|
22
|
-
- Defining structured parameters for RubyLLM tools
|
|
23
|
-
|
|
24
|
-
### Simple Example
|
|
25
|
-
|
|
26
|
-
```ruby
|
|
27
|
-
class PersonSchema < RubyLLM::Schema
|
|
28
|
-
string :name, description: "Person's full name"
|
|
29
|
-
number :age, description: "Age in years", minimum: 0, maximum: 120
|
|
30
|
-
boolean :active, required: false
|
|
31
|
-
|
|
32
|
-
object :address do
|
|
33
|
-
string :street
|
|
34
|
-
string :city
|
|
35
|
-
string :country, required: false
|
|
36
|
-
end
|
|
37
|
-
|
|
38
|
-
array :tags, of: :string, description: "User tags"
|
|
39
|
-
|
|
40
|
-
array :contacts do
|
|
41
|
-
object do
|
|
42
|
-
string :email, format: "email"
|
|
43
|
-
string :phone, required: false
|
|
44
|
-
end
|
|
45
|
-
end
|
|
46
|
-
|
|
47
|
-
any_of :status do
|
|
48
|
-
string enum: ["active", "pending", "inactive"]
|
|
49
|
-
null
|
|
50
|
-
end
|
|
51
|
-
end
|
|
52
|
-
|
|
53
|
-
# Usage
|
|
54
|
-
schema = PersonSchema.new
|
|
55
|
-
puts schema.to_json
|
|
56
|
-
```
|
|
57
|
-
|
|
58
|
-
### RubyLLM structured output
|
|
59
|
-
|
|
60
|
-
```ruby
|
|
61
|
-
class PersonSchema < RubyLLM::Schema
|
|
62
|
-
string :name, description: "Person's full name"
|
|
63
|
-
integer :age, description: "Person's age in years"
|
|
64
|
-
string :city, required: false, description: "City where they live"
|
|
65
|
-
end
|
|
66
|
-
|
|
67
|
-
# Use it natively with RubyLLM
|
|
68
|
-
chat = RubyLLM.chat
|
|
69
|
-
response = chat.with_schema(PersonSchema)
|
|
70
|
-
.ask("Generate a person named Alice who is 30 years old and lives in New York")
|
|
71
|
-
|
|
72
|
-
# The response is automatically parsed from JSON
|
|
73
|
-
puts response.content # => {"name" => "Alice", "age" => 30}
|
|
74
|
-
puts response.content.class # => Hash
|
|
75
|
-
```
|
|
76
|
-
|
|
77
|
-
### RubyLLM tools
|
|
78
|
-
|
|
79
|
-
RubyLLM tools can use schema classes for structured parameters. This is useful when the same argument shape is shared across tools or elsewhere in your app.
|
|
80
|
-
|
|
81
|
-
```ruby
|
|
82
|
-
class SearchParams < RubyLLM::Schema
|
|
83
|
-
string :query, description: "Search query"
|
|
84
|
-
integer :limit, required: false, description: "Maximum results"
|
|
85
|
-
end
|
|
86
|
-
|
|
87
|
-
class SearchDocuments < RubyLLM::Tool
|
|
88
|
-
desc "Searches internal documents"
|
|
89
|
-
params SearchParams
|
|
90
|
-
|
|
91
|
-
def execute(query:, limit: 10)
|
|
92
|
-
DocumentSearch.call(query:, limit:)
|
|
93
|
-
end
|
|
94
|
-
end
|
|
95
|
-
```
|
|
96
|
-
|
|
97
|
-
For tool-specific parameters, define the schema inline with `params do ... end`.
|
|
98
|
-
|
|
99
|
-
```ruby
|
|
100
|
-
class Weather < RubyLLM::Tool
|
|
101
|
-
desc "Gets current weather"
|
|
102
|
-
|
|
103
|
-
params do
|
|
104
|
-
string :city, description: "City name"
|
|
105
|
-
string :units, enum: %w[celsius fahrenheit], required: false
|
|
106
|
-
end
|
|
107
|
-
|
|
108
|
-
def execute(city:, units: "celsius")
|
|
109
|
-
WeatherAPI.current(city:, units:)
|
|
110
|
-
end
|
|
111
|
-
end
|
|
112
|
-
```
|
|
113
|
-
|
|
114
|
-
## Installation
|
|
115
|
-
|
|
116
|
-
Add this line to your application's Gemfile:
|
|
117
|
-
|
|
118
|
-
```ruby
|
|
119
|
-
gem 'ruby_llm-schema'
|
|
120
|
-
```
|
|
121
|
-
|
|
122
|
-
And then execute:
|
|
123
|
-
|
|
124
|
-
```bash
|
|
125
|
-
bundle install
|
|
126
|
-
```
|
|
127
|
-
|
|
128
|
-
Or install it yourself as:
|
|
12
|
+
The root gemspec builds schematist. This one has to be built from this directory:
|
|
129
13
|
|
|
130
14
|
```bash
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
## Usage
|
|
135
|
-
|
|
136
|
-
Three approaches for creating schemas:
|
|
137
|
-
|
|
138
|
-
### Class Inheritance
|
|
139
|
-
|
|
140
|
-
```ruby
|
|
141
|
-
class PersonSchema < RubyLLM::Schema
|
|
142
|
-
string :name, description: "Person's full name"
|
|
143
|
-
number :age
|
|
144
|
-
boolean :active, required: false
|
|
145
|
-
|
|
146
|
-
object :address do
|
|
147
|
-
string :street
|
|
148
|
-
string :city
|
|
149
|
-
end
|
|
150
|
-
|
|
151
|
-
array :tags, of: :string
|
|
152
|
-
end
|
|
153
|
-
|
|
154
|
-
schema = PersonSchema.new
|
|
155
|
-
puts schema.to_json
|
|
156
|
-
```
|
|
157
|
-
|
|
158
|
-
### Factory Method
|
|
159
|
-
|
|
160
|
-
```ruby
|
|
161
|
-
PersonSchema = RubyLLM::Schema.create do
|
|
162
|
-
string :name, description: "Person's full name"
|
|
163
|
-
number :age
|
|
164
|
-
boolean :active, required: false
|
|
165
|
-
|
|
166
|
-
object :address do
|
|
167
|
-
string :street
|
|
168
|
-
string :city
|
|
169
|
-
end
|
|
170
|
-
|
|
171
|
-
array :tags, of: :string
|
|
172
|
-
end
|
|
173
|
-
|
|
174
|
-
schema = PersonSchema.new
|
|
175
|
-
puts schema.to_json
|
|
176
|
-
```
|
|
177
|
-
|
|
178
|
-
### Global Helper
|
|
179
|
-
|
|
180
|
-
```ruby
|
|
181
|
-
require 'ruby_llm/schema'
|
|
182
|
-
include RubyLLM::Helpers
|
|
183
|
-
|
|
184
|
-
person_schema = schema "PersonData", description: "A person object" do
|
|
185
|
-
string :name, description: "Person's full name"
|
|
186
|
-
number :age
|
|
187
|
-
boolean :active, required: false
|
|
188
|
-
|
|
189
|
-
object :address do
|
|
190
|
-
string :street
|
|
191
|
-
string :city
|
|
192
|
-
end
|
|
193
|
-
|
|
194
|
-
array :tags, of: :string
|
|
195
|
-
end
|
|
196
|
-
|
|
197
|
-
puts person_schema.to_json
|
|
198
|
-
```
|
|
199
|
-
|
|
200
|
-
## Schema Property Types
|
|
201
|
-
|
|
202
|
-
A schema is a collection of properties, which can be of different types. Each type has its own set of properties you can set.
|
|
203
|
-
|
|
204
|
-
All property types can (along with the required `name` key) be set with a `description` and a `required` flag (default is `true`).
|
|
205
|
-
|
|
206
|
-
```ruby
|
|
207
|
-
string :name, description: "Person's full name"
|
|
208
|
-
number :age, description: "Person's age", required: false
|
|
209
|
-
boolean :is_active, description: "Whether the person is active"
|
|
210
|
-
null :placeholder, description: "A placeholder property"
|
|
211
|
-
```
|
|
212
|
-
|
|
213
|
-
⚠️ Please consult the LLM provider documentation for any limitations or restrictions. For example, as of now, OpenAI requires all properties to be required. In that case, you can use the `any_of` method to make a property optional.
|
|
214
|
-
|
|
215
|
-
```ruby
|
|
216
|
-
any_of :name, description: "Person's full name" do
|
|
217
|
-
string
|
|
218
|
-
null
|
|
219
|
-
end
|
|
220
|
-
```
|
|
221
|
-
|
|
222
|
-
### Strings
|
|
223
|
-
|
|
224
|
-
String types support the following properties:
|
|
225
|
-
|
|
226
|
-
- `enum`: an array of allowed values (e.g. `enum: ["on", "off"]`)
|
|
227
|
-
- `pattern`: a regex pattern (e.g. `pattern: "\\d+"`)
|
|
228
|
-
- `format`: a format string (e.g. `format: "email"`)
|
|
229
|
-
- `min_length`: the minimum length of the string (e.g. `min_length: 3`)
|
|
230
|
-
- `max_length`: the maximum length of the string (e.g. `max_length: 10`)
|
|
231
|
-
|
|
232
|
-
Please consult the LLM provider documentation for the available formats and patterns.
|
|
233
|
-
|
|
234
|
-
```ruby
|
|
235
|
-
string :name, description: "Person's full name"
|
|
236
|
-
string :email, format: "email"
|
|
237
|
-
string :phone, pattern: "\\d+"
|
|
238
|
-
string :status, enum: ["on", "off"]
|
|
239
|
-
string :code, min_length: 3, max_length: 10
|
|
240
|
-
```
|
|
241
|
-
|
|
242
|
-
### Numbers
|
|
243
|
-
|
|
244
|
-
Number types support the following properties:
|
|
245
|
-
|
|
246
|
-
- `multiple_of`: a multiple of the number (e.g. `multiple_of: 0.01`)
|
|
247
|
-
- `minimum`: the minimum value of the number (e.g. `minimum: 0`)
|
|
248
|
-
- `maximum`: the maximum value of the number (e.g. `maximum: 100`)
|
|
249
|
-
|
|
250
|
-
```ruby
|
|
251
|
-
number :price, minimum: 0, maximum: 100
|
|
252
|
-
number :amount, multiple_of: 0.01
|
|
253
|
-
```
|
|
254
|
-
|
|
255
|
-
### Booleans
|
|
256
|
-
|
|
257
|
-
```ruby
|
|
258
|
-
boolean :is_active
|
|
259
|
-
```
|
|
260
|
-
|
|
261
|
-
Boolean types doesn't support any additional properties.
|
|
262
|
-
|
|
263
|
-
### Null
|
|
264
|
-
|
|
265
|
-
```ruby
|
|
266
|
-
null :placeholder
|
|
267
|
-
```
|
|
268
|
-
|
|
269
|
-
Null types doesn't support any additional properties.
|
|
270
|
-
|
|
271
|
-
### Arrays
|
|
272
|
-
|
|
273
|
-
An array is a list of items. You can set the type of the items in the array with the `of` option or by passing a block with the `object` method.
|
|
274
|
-
|
|
275
|
-
An array can have a `min_items` and `max_items` option to set the minimum and maximum number of items in the array.
|
|
276
|
-
|
|
277
|
-
```ruby
|
|
278
|
-
array :tags, of: :string # Array of strings
|
|
279
|
-
array :scores, of: :number # Array of numbers
|
|
280
|
-
array :items, min_items: 1, max_items: 10 # Array with size constraints
|
|
281
|
-
|
|
282
|
-
array :items do # Array of objects
|
|
283
|
-
object do
|
|
284
|
-
string :name
|
|
285
|
-
number :price
|
|
286
|
-
end
|
|
287
|
-
end
|
|
288
|
-
```
|
|
289
|
-
|
|
290
|
-
### Objects
|
|
291
|
-
|
|
292
|
-
Objects types expect a block with the properties of the object.
|
|
293
|
-
|
|
294
|
-
```ruby
|
|
295
|
-
object :user do
|
|
296
|
-
string :name
|
|
297
|
-
number :age
|
|
298
|
-
end
|
|
299
|
-
|
|
300
|
-
object :settings, description: "User preferences" do
|
|
301
|
-
boolean :notifications
|
|
302
|
-
string :theme, enum: ["light", "dark"]
|
|
303
|
-
end
|
|
304
|
-
```
|
|
305
|
-
|
|
306
|
-
### Union Types (anyOf)
|
|
307
|
-
|
|
308
|
-
Union types are a way to specify that a property can be one of several types.
|
|
309
|
-
|
|
310
|
-
```ruby
|
|
311
|
-
any_of :value do
|
|
312
|
-
string
|
|
313
|
-
number
|
|
314
|
-
null
|
|
315
|
-
end
|
|
316
|
-
|
|
317
|
-
any_of :identifier do
|
|
318
|
-
string description: "Username"
|
|
319
|
-
number description: "User ID"
|
|
320
|
-
end
|
|
321
|
-
```
|
|
322
|
-
|
|
323
|
-
### Schema Definitions and References
|
|
324
|
-
|
|
325
|
-
You can define sub-schemas and reference them in other schemas, or reference the root schema to generate recursive schemas.
|
|
326
|
-
|
|
327
|
-
```ruby
|
|
328
|
-
class MySchema < RubyLLM::Schema
|
|
329
|
-
define :location do
|
|
330
|
-
string :latitude
|
|
331
|
-
string :longitude
|
|
332
|
-
end
|
|
333
|
-
|
|
334
|
-
# Using a reference in an array
|
|
335
|
-
array :coordinates, of: :location
|
|
336
|
-
|
|
337
|
-
# Using a reference in an object via the `reference` option
|
|
338
|
-
object :home_location, reference: :location
|
|
339
|
-
|
|
340
|
-
# Using a reference in an object via block
|
|
341
|
-
object :user do
|
|
342
|
-
reference :location
|
|
343
|
-
end
|
|
344
|
-
|
|
345
|
-
# Using a reference to the root schema
|
|
346
|
-
object :ui_schema do
|
|
347
|
-
string :element, enum: ["input", "button"]
|
|
348
|
-
string :label
|
|
349
|
-
object :sub_schema, reference: :root
|
|
350
|
-
end
|
|
351
|
-
end
|
|
352
|
-
```
|
|
353
|
-
|
|
354
|
-
### Nested Schemas
|
|
355
|
-
|
|
356
|
-
You can embed existing schema classes directly within objects or arrays for reusable schema composition.
|
|
357
|
-
|
|
358
|
-
```ruby
|
|
359
|
-
class PersonSchema < RubyLLM::Schema
|
|
360
|
-
string :name
|
|
361
|
-
integer :age
|
|
362
|
-
end
|
|
363
|
-
|
|
364
|
-
class CompanySchema < RubyLLM::Schema
|
|
365
|
-
# Using 'of' parameter
|
|
366
|
-
object :ceo, of: PersonSchema
|
|
367
|
-
array :employees, of: PersonSchema
|
|
368
|
-
|
|
369
|
-
# Using Schema.new in block
|
|
370
|
-
object :founder do
|
|
371
|
-
PersonSchema.new
|
|
372
|
-
end
|
|
373
|
-
end
|
|
374
|
-
|
|
375
|
-
schema = CompanySchema.new
|
|
376
|
-
schema.to_json_schema
|
|
377
|
-
# =>
|
|
378
|
-
# {
|
|
379
|
-
# "name":"CompanySchema",
|
|
380
|
-
# "description":"nil",
|
|
381
|
-
# "schema":{
|
|
382
|
-
# "type":"object",
|
|
383
|
-
# "properties":{
|
|
384
|
-
# "ceo":{
|
|
385
|
-
# "type":"object",
|
|
386
|
-
# "properties":{
|
|
387
|
-
# "name":{
|
|
388
|
-
# "type":"string"
|
|
389
|
-
# },
|
|
390
|
-
# "age":{
|
|
391
|
-
# "type":"integer"
|
|
392
|
-
# }
|
|
393
|
-
# },
|
|
394
|
-
# "required":[
|
|
395
|
-
# :"name",
|
|
396
|
-
# :"age"
|
|
397
|
-
# ],
|
|
398
|
-
# "additionalProperties":false
|
|
399
|
-
# },
|
|
400
|
-
# "employees":{
|
|
401
|
-
# "type":"array",
|
|
402
|
-
# "items":{
|
|
403
|
-
# "type":"object",
|
|
404
|
-
# "properties":{
|
|
405
|
-
# "name":{
|
|
406
|
-
# "type":"string"
|
|
407
|
-
# },
|
|
408
|
-
# "age":{
|
|
409
|
-
# "type":"integer"
|
|
410
|
-
# }
|
|
411
|
-
# },
|
|
412
|
-
# "required":[
|
|
413
|
-
# :"name",
|
|
414
|
-
# :"age"
|
|
415
|
-
# ],
|
|
416
|
-
# "additionalProperties":false
|
|
417
|
-
# }
|
|
418
|
-
# },
|
|
419
|
-
# "founder":{
|
|
420
|
-
# "type":"object",
|
|
421
|
-
# "properties":{
|
|
422
|
-
# "name":{
|
|
423
|
-
# "type":"string"
|
|
424
|
-
# },
|
|
425
|
-
# "age":{
|
|
426
|
-
# "type":"integer"
|
|
427
|
-
# }
|
|
428
|
-
# },
|
|
429
|
-
# "required":[
|
|
430
|
-
# :"name",
|
|
431
|
-
# :"age"
|
|
432
|
-
# ],
|
|
433
|
-
# "additionalProperties":false
|
|
434
|
-
# }
|
|
435
|
-
# },
|
|
436
|
-
# "required":[
|
|
437
|
-
# :"ceo",
|
|
438
|
-
# :"employees",
|
|
439
|
-
# :"founder"
|
|
440
|
-
# ],
|
|
441
|
-
# "additionalProperties":false,
|
|
442
|
-
# "strict":true
|
|
443
|
-
# }
|
|
444
|
-
# }
|
|
445
|
-
```
|
|
446
|
-
|
|
447
|
-
### Dependencies
|
|
448
|
-
|
|
449
|
-
Use `requires:` inline or `dependent` block to express that the presence of one property requires others. Maps to [`dependentRequired`](https://json-schema.org/understanding-json-schema/reference/conditionals#dependentRequired) (Draft 2019-09) and [`dependentSchemas`](https://json-schema.org/understanding-json-schema/reference/conditionals#dependentSchemas) (Draft 2019-09). Check your provider's documentation for compatibility.
|
|
450
|
-
|
|
451
|
-
```ruby
|
|
452
|
-
class PaymentSchema < RubyLLM::Schema
|
|
453
|
-
string :name
|
|
454
|
-
number :credit_card, required: false, requires: %i[billing_address cvv]
|
|
455
|
-
string :billing_address, required: false
|
|
456
|
-
string :cvv, required: false
|
|
457
|
-
end
|
|
15
|
+
cd compat/ruby_llm-schema
|
|
16
|
+
gem build ruby_llm-schema.gemspec
|
|
17
|
+
gem push ruby_llm-schema-1.0.0.gem
|
|
458
18
|
```
|
|
459
19
|
|
|
460
|
-
|
|
20
|
+
schematist 1.0.0 must be on RubyGems first, since this gem depends on it.
|
|
461
21
|
|
|
462
|
-
|
|
463
|
-
dependent :credit_card do
|
|
464
|
-
requires :billing_address
|
|
465
|
-
validates :billing_address, type: :string, min_length: 1
|
|
466
|
-
end
|
|
467
|
-
```
|
|
468
|
-
|
|
469
|
-
### Conditionals
|
|
470
|
-
|
|
471
|
-
Use `given` to add [JSON Schema `if`/`then`/`else`](https://json-schema.org/understanding-json-schema/reference/conditionals#ifthenelse) (Draft 7) rules. Condition values are automatically coerced: strings → `const`, arrays → `enum`, regexps → `pattern`, hashes → raw schema.
|
|
472
|
-
|
|
473
|
-
```ruby
|
|
474
|
-
class OrderSchema < RubyLLM::Schema
|
|
475
|
-
string :status, enum: ["pending", "shipped", "cancelled"]
|
|
476
|
-
string :tracking_number, required: false
|
|
477
|
-
string :cancellation_reason, required: false
|
|
478
|
-
|
|
479
|
-
given status: "shipped" do
|
|
480
|
-
requires :tracking_number
|
|
481
|
-
end
|
|
482
|
-
|
|
483
|
-
given status: "cancelled" do
|
|
484
|
-
requires :cancellation_reason
|
|
485
|
-
validates :cancellation_reason, type: :string, min_length: 1
|
|
486
|
-
end
|
|
487
|
-
end
|
|
488
|
-
```
|
|
489
|
-
|
|
490
|
-
`validates` supports: `type:`, `not_value:`, `min_length:`, `max_length:`, `pattern:` (string or regexp), `enum:`, `const:`, `minimum:`, `maximum:`.
|
|
491
|
-
|
|
492
|
-
Use `otherwise` for an `else` branch:
|
|
493
|
-
|
|
494
|
-
```ruby
|
|
495
|
-
given domestic: true do
|
|
496
|
-
requires :state
|
|
497
|
-
|
|
498
|
-
otherwise do
|
|
499
|
-
requires :country
|
|
500
|
-
end
|
|
501
|
-
end
|
|
502
|
-
```
|
|
503
|
-
|
|
504
|
-
Conditions propagate through nested schemas via `of:`.
|
|
505
|
-
|
|
506
|
-
## JSON Output
|
|
507
|
-
|
|
508
|
-
```ruby
|
|
509
|
-
schema = PersonSchema.new
|
|
510
|
-
schema.to_json_schema
|
|
511
|
-
# => {
|
|
512
|
-
# name: "PersonSchema",
|
|
513
|
-
# description: nil,
|
|
514
|
-
# schema: {
|
|
515
|
-
# type: "object",
|
|
516
|
-
# properties: { ... },
|
|
517
|
-
# required: [...],
|
|
518
|
-
# additionalProperties: false,
|
|
519
|
-
# strict: true
|
|
520
|
-
# }
|
|
521
|
-
# }
|
|
522
|
-
|
|
523
|
-
puts schema.to_json # Pretty JSON string
|
|
524
|
-
```
|
|
22
|
+
The version tracks the schematist release it forwards to.
|
|
525
23
|
|
|
526
|
-
##
|
|
24
|
+
## What the alias cannot forward
|
|
527
25
|
|
|
528
|
-
|
|
26
|
+
- `strict` was removed. It is an OpenAI `response_format` flag, not a JSON Schema keyword.
|
|
27
|
+
- `to_json_schema` returns a Draft 2020-12 document with string keys, not the
|
|
28
|
+
`{name:, description:, schema:}` provider envelope. Build that envelope where you send it.
|
data/lib/ruby_llm/schema.rb
CHANGED
|
@@ -1,99 +1,31 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
require_relative "schema/errors"
|
|
5
|
-
require_relative "schema/helpers"
|
|
6
|
-
require_relative "schema/validator"
|
|
7
|
-
require_relative "schema/dsl"
|
|
8
|
-
require_relative "schema/json_output"
|
|
9
|
-
require "json"
|
|
3
|
+
require "schematist"
|
|
10
4
|
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
extend DSL
|
|
14
|
-
include JsonOutput
|
|
15
|
-
|
|
16
|
-
PRIMITIVE_TYPES = %i[string number integer boolean null].freeze
|
|
17
|
-
|
|
18
|
-
class << self
|
|
19
|
-
def create(&block)
|
|
20
|
-
schema_class = Class.new(Schema)
|
|
21
|
-
schema_class.class_eval(&block)
|
|
22
|
-
schema_class
|
|
23
|
-
end
|
|
24
|
-
|
|
25
|
-
def properties
|
|
26
|
-
@properties ||= {}
|
|
27
|
-
end
|
|
28
|
-
|
|
29
|
-
def required_properties
|
|
30
|
-
@required_properties ||= []
|
|
31
|
-
end
|
|
32
|
-
|
|
33
|
-
def definitions
|
|
34
|
-
@definitions ||= {}
|
|
35
|
-
end
|
|
36
|
-
|
|
37
|
-
def name(name = nil)
|
|
38
|
-
@schema_name = name if name
|
|
39
|
-
return @schema_name if defined?(@schema_name)
|
|
40
|
-
|
|
41
|
-
super()
|
|
42
|
-
end
|
|
43
|
-
|
|
44
|
-
def description(description = nil)
|
|
45
|
-
@description = description if description
|
|
46
|
-
@description
|
|
47
|
-
end
|
|
5
|
+
warn <<~DEPRECATION
|
|
6
|
+
[DEPRECATION] ruby_llm-schema is now schematist, and this gem only forwards to it.
|
|
48
7
|
|
|
49
|
-
|
|
50
|
-
|
|
8
|
+
gem 'schematist' # was: gem 'ruby_llm-schema'
|
|
9
|
+
class Person < Schematist::Schema; end # was: RubyLLM::Schema
|
|
51
10
|
|
|
52
|
-
|
|
53
|
-
|
|
11
|
+
Two things the aliases below cannot forward: `strict` is gone, since it is an OpenAI
|
|
12
|
+
response_format flag rather than a JSON Schema keyword, and `to_json_schema` now returns
|
|
13
|
+
a Draft 2020-12 document instead of the provider envelope. See
|
|
14
|
+
https://github.com/crmne/schematist#migrating-from-ruby_llm-schema
|
|
15
|
+
DEPRECATION
|
|
54
16
|
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
@strict = args.first
|
|
60
|
-
end
|
|
61
|
-
end
|
|
62
|
-
|
|
63
|
-
def validate!
|
|
64
|
-
validator = Validator.new(self)
|
|
65
|
-
validator.validate!
|
|
66
|
-
end
|
|
67
|
-
|
|
68
|
-
def valid?
|
|
69
|
-
validator = Validator.new(self)
|
|
70
|
-
validator.valid?
|
|
71
|
-
end
|
|
72
|
-
end
|
|
73
|
-
|
|
74
|
-
def initialize(name = nil, description: nil)
|
|
75
|
-
@name = name || self.class.name || "Schema"
|
|
76
|
-
@description = description
|
|
77
|
-
end
|
|
78
|
-
|
|
79
|
-
def validate!
|
|
80
|
-
self.class.validate!
|
|
81
|
-
end
|
|
82
|
-
|
|
83
|
-
def valid?
|
|
84
|
-
self.class.valid?
|
|
85
|
-
end
|
|
86
|
-
|
|
87
|
-
def method_missing(method_name, ...)
|
|
88
|
-
if respond_to_missing?(method_name)
|
|
89
|
-
self.class.send(method_name, ...)
|
|
90
|
-
else
|
|
91
|
-
super
|
|
92
|
-
end
|
|
93
|
-
end
|
|
17
|
+
module RubyLLM
|
|
18
|
+
Schema = Schematist::Schema
|
|
19
|
+
Helpers = Schematist::Helpers
|
|
20
|
+
end
|
|
94
21
|
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
22
|
+
# The error hierarchy moved from RubyLLM::Schema::X to Schematist::X. RubyLLM::Schema and
|
|
23
|
+
# Schematist::Schema are the same object, so these also become reachable as
|
|
24
|
+
# Schematist::Schema::X. Harmless — they are aliases to the very same classes — and it is
|
|
25
|
+
# the only way to keep `rescue RubyLLM::Schema::ValidationError` working.
|
|
26
|
+
%i[
|
|
27
|
+
Error InvalidSchemaTypeError InvalidArrayTypeError InvalidObjectTypeError
|
|
28
|
+
InvalidSchemaError ValidationError LimitExceededError
|
|
29
|
+
].each do |name|
|
|
30
|
+
RubyLLM::Schema.const_set(name, Schematist.const_get(name))
|
|
99
31
|
end
|