@@ -60,10 +60,11 @@ public final class Schema: Sendable {
60
60
let rawValue : String
61
61
}
62
62
63
- let dataType : DataType
63
+ // May only be nil for `anyOf` schemas, which do not have an explicit `type` in the OpenAPI spec.
64
+ let dataType : DataType ?
64
65
65
66
/// The data type.
66
- public var type : String { dataType. rawValue }
67
+ public var type : String { dataType? . rawValue ?? " UNSPECIFIED " }
67
68
68
69
/// The format of the data.
69
70
public let format : String ?
@@ -106,6 +107,16 @@ public final class Schema: Sendable {
106
107
/// property's type and constraints.
107
108
public let properties : [ String : Schema ] ?
108
109
110
+ /// An array of `Schema` objects. The generated data must be valid against *any* (one or more)
111
+ /// of the schemas listed in this array. This allows specifying multiple possible structures or
112
+ /// types for a single field.
113
+ ///
114
+ /// For example, a value could be either a `String` or an `Integer`:
115
+ /// ```
116
+ /// Schema.anyOf(schemas: [.string(), .integer()])
117
+ /// ```
118
+ public let anyOf : [ Schema ] ?
119
+
109
120
/// An array of strings, where each string is the name of a property defined in the `properties`
110
121
/// dictionary that must be present in the generated object. If a property is listed here, the
111
122
/// model must include it in the output.
@@ -119,12 +130,14 @@ public final class Schema: Sendable {
119
130
/// serialization.
120
131
public let propertyOrdering : [ String ] ?
121
132
122
- required init ( type: DataType , format: String ? = nil , description: String ? = nil ,
123
- title: String ? = nil ,
124
- nullable: Bool = false , enumValues: [ String ] ? = nil , items: Schema ? = nil ,
125
- minItems: Int ? = nil , maxItems: Int ? = nil , minimum: Double ? = nil ,
126
- maximum: Double ? = nil , properties: [ String : Schema ] ? = nil ,
127
- requiredProperties: [ String ] ? = nil , propertyOrdering: [ String ] ? = nil ) {
133
+ required init ( type: DataType ? , format: String ? = nil , description: String ? = nil ,
134
+ title: String ? = nil , nullable: Bool ? = nil , enumValues: [ String ] ? = nil ,
135
+ items: Schema ? = nil , minItems: Int ? = nil , maxItems: Int ? = nil ,
136
+ minimum: Double ? = nil , maximum: Double ? = nil , anyOf: [ Schema ] ? = nil ,
137
+ properties: [ String : Schema ] ? = nil , requiredProperties: [ String ] ? = nil ,
138
+ propertyOrdering: [ String ] ? = nil ) {
139
+ precondition ( type != nil || anyOf != nil ,
140
+ " A schema must have either a `type` or an `anyOf` array of sub-schemas. " )
128
141
dataType = type
129
142
self . format = format
130
143
self . description = description
@@ -136,6 +149,7 @@ public final class Schema: Sendable {
136
149
self . maxItems = maxItems
137
150
self . minimum = minimum
138
151
self . maximum = maximum
152
+ self . anyOf = anyOf
139
153
self . properties = properties
140
154
self . requiredProperties = requiredProperties
141
155
self . propertyOrdering = propertyOrdering
@@ -278,6 +292,10 @@ public final class Schema: Sendable {
278
292
/// - format: An optional modifier describing the expected format of the integer. Currently the
279
293
/// formats ``IntegerFormat/int32`` and ``IntegerFormat/int64`` are supported; custom values
280
294
/// may be specified using ``IntegerFormat/custom(_:)`` but may be ignored by the model.
295
+ /// - minimum: If specified, instructs the model that the value should be greater than or
296
+ /// equal to the specified minimum.
297
+ /// - maximum: If specified, instructs the model that the value should be less than or equal
298
+ /// to the specified maximum.
281
299
public static func integer( description: String ? = nil , nullable: Bool = false ,
282
300
format: IntegerFormat ? = nil ,
283
301
minimum: Int ? = nil , maximum: Int ? = nil ) -> Schema {
@@ -362,8 +380,11 @@ public final class Schema: Sendable {
362
380
/// - optionalProperties: A list of property names that may be be omitted in objects generated
363
381
/// by the model; these names must correspond to the keys provided in the `properties`
364
382
/// dictionary and may be an empty list.
383
+ /// - propertyOrdering: An optional hint to the model suggesting the order for keys in the
384
+ /// generated JSON string. See ``propertyOrdering`` for details.
365
385
/// - description: An optional description of what the object should contain or represent; may
366
386
/// use Markdown format.
387
+ /// - title: An optional human-readable name/summary for the object schema.
367
388
/// - nullable: If `true`, instructs the model that it may return `null` instead of an object;
368
389
/// defaults to `false`, enforcing that an object is returned.
369
390
public static func object( properties: [ String : Schema ] , optionalProperties: [ String ] = [ ] ,
@@ -388,6 +409,38 @@ public final class Schema: Sendable {
388
409
propertyOrdering: propertyOrdering
389
410
)
390
411
}
412
+
413
+ /// Returns a `Schema` representing a value that must conform to *any* (one or more) of the
414
+ /// provided sub-schemas.
415
+ ///
416
+ /// This schema instructs the model to produce data that is valid against at least one of the
417
+ /// schemas listed in the `schemas` array. This is useful when a field can accept multiple
418
+ /// distinct types or structures.
419
+ ///
420
+ /// **Example:** A field that can hold either a simple user ID (integer) or a detailed user
421
+ /// object.
422
+ /// ```
423
+ /// Schema.anyOf(schemas: [
424
+ /// .integer(description: "User ID"),
425
+ /// .object(properties: [
426
+ /// "userId": .integer(),
427
+ /// "userName": .string()
428
+ /// ], description: "Detailed User Object")
429
+ /// ])
430
+ /// ```
431
+ /// The generated data could be decoded based on which schema it matches.
432
+ ///
433
+ /// - Parameters:
434
+ /// - schemas: An array of `Schema` objects. The generated data must be valid against at least
435
+ /// one of these schemas. The array must not be empty.
436
+ public static func anyOf( schemas: [ Schema ] ) -> Schema {
437
+ if schemas. isEmpty {
438
+ VertexLog . error ( code: . invalidSchemaFormat, " The `anyOf` schemas array cannot be empty. " )
439
+ }
440
+ // Note: The 'type' for an 'anyOf' schema is implicitly defined by the presence of the
441
+ // 'anyOf' keyword and doesn't have a specific explicit type like "OBJECT" or "STRING".
442
+ return self . init ( type: nil , anyOf: schemas)
443
+ }
391
444
}
392
445
393
446
// MARK: - Codable Conformance
@@ -406,6 +459,7 @@ extension Schema: Encodable {
406
459
case maxItems
407
460
case minimum
408
461
case maximum
462
+ case anyOf
409
463
case properties
410
464
case requiredProperties = " required "
411
465
case propertyOrdering
0 commit comments