@@ -3,12 +3,19 @@ use schemars::schema::{
3
3
ArrayValidation , InstanceType , Metadata , ObjectValidation , Schema , SchemaObject , SingleOrVec ,
4
4
} ;
5
5
6
+ pub struct ToJsonSchemaOptions {
7
+ /// If true, mark all fields as required.
8
+ /// Use union type (with `null`) for optional fields instead.
9
+ /// Models like OpenAI will reject the schema if a field is not required.
10
+ pub fields_always_required : bool ,
11
+ }
12
+
6
13
pub trait ToJsonSchema {
7
- fn to_json_schema ( & self ) -> SchemaObject ;
14
+ fn to_json_schema ( & self , options : & ToJsonSchemaOptions ) -> SchemaObject ;
8
15
}
9
16
10
17
impl ToJsonSchema for schema:: BasicValueType {
11
- fn to_json_schema ( & self ) -> SchemaObject {
18
+ fn to_json_schema ( & self , options : & ToJsonSchemaOptions ) -> SchemaObject {
12
19
let mut schema = SchemaObject :: default ( ) ;
13
20
match self {
14
21
schema:: BasicValueType :: Str => {
@@ -26,9 +33,6 @@ impl ToJsonSchema for schema::BasicValueType {
26
33
schema:: BasicValueType :: Float32 | schema:: BasicValueType :: Float64 => {
27
34
schema. instance_type = Some ( SingleOrVec :: Single ( Box :: new ( InstanceType :: Number ) ) ) ;
28
35
}
29
- schema:: BasicValueType :: Json => {
30
- // Can be any value. No type constraint.
31
- }
32
36
schema:: BasicValueType :: Range => {
33
37
schema. instance_type = Some ( SingleOrVec :: Single ( Box :: new ( InstanceType :: Array ) ) ) ;
34
38
schema. array = Some ( Box :: new ( ArrayValidation {
@@ -51,11 +55,18 @@ impl ToJsonSchema for schema::BasicValueType {
51
55
. description =
52
56
Some ( "A range, start pos (inclusive), end pos (exclusive)." . to_string ( ) ) ;
53
57
}
58
+ schema:: BasicValueType :: Uuid => {
59
+ schema. instance_type = Some ( SingleOrVec :: Single ( Box :: new ( InstanceType :: String ) ) ) ;
60
+ schema. format = Some ( "uuid" . to_string ( ) ) ;
61
+ }
62
+ schema:: BasicValueType :: Json => {
63
+ // Can be any value. No type constraint.
64
+ }
54
65
schema:: BasicValueType :: Vector ( s) => {
55
66
schema. instance_type = Some ( SingleOrVec :: Single ( Box :: new ( InstanceType :: Array ) ) ) ;
56
67
schema. array = Some ( Box :: new ( ArrayValidation {
57
68
items : Some ( SingleOrVec :: Single ( Box :: new (
58
- s. element_type . to_json_schema ( ) . into ( ) ,
69
+ s. element_type . to_json_schema ( options ) . into ( ) ,
59
70
) ) ) ,
60
71
min_items : s. dimension . and_then ( |d| u32:: try_from ( d) . ok ( ) ) ,
61
72
max_items : s. dimension . and_then ( |d| u32:: try_from ( d) . ok ( ) ) ,
@@ -68,7 +79,7 @@ impl ToJsonSchema for schema::BasicValueType {
68
79
}
69
80
70
81
impl ToJsonSchema for schema:: StructSchema {
71
- fn to_json_schema ( & self ) -> SchemaObject {
82
+ fn to_json_schema ( & self , options : & ToJsonSchemaOptions ) -> SchemaObject {
72
83
SchemaObject {
73
84
metadata : Some ( Box :: new ( Metadata {
74
85
description : self . description . as_ref ( ) . map ( |s| s. to_string ( ) ) ,
@@ -79,12 +90,25 @@ impl ToJsonSchema for schema::StructSchema {
79
90
properties : self
80
91
. fields
81
92
. iter ( )
82
- . map ( |f| ( f. name . to_string ( ) , f. value_type . to_json_schema ( ) . into ( ) ) )
93
+ . map ( |f| {
94
+ let mut schema = f. value_type . to_json_schema ( options) ;
95
+ if options. fields_always_required && f. value_type . nullable {
96
+ if let Some ( instance_type) = & mut schema. instance_type {
97
+ let mut types = match instance_type {
98
+ SingleOrVec :: Single ( t) => vec ! [ * * t] ,
99
+ SingleOrVec :: Vec ( t) => std:: mem:: take ( t) ,
100
+ } ;
101
+ types. push ( InstanceType :: Null ) ;
102
+ * instance_type = SingleOrVec :: Vec ( types) ;
103
+ }
104
+ }
105
+ ( f. name . to_string ( ) , schema. into ( ) )
106
+ } )
83
107
. collect ( ) ,
84
108
required : self
85
109
. fields
86
110
. iter ( )
87
- . filter ( |& f| ( !f. value_type . nullable ) )
111
+ . filter ( |& f| ( options . fields_always_required || !f. value_type . nullable ) )
88
112
. map ( |f| f. name . to_string ( ) )
89
113
. collect ( ) ,
90
114
additional_properties : Some ( Schema :: Bool ( false ) . into ( ) ) ,
@@ -96,14 +120,16 @@ impl ToJsonSchema for schema::StructSchema {
96
120
}
97
121
98
122
impl ToJsonSchema for schema:: ValueType {
99
- fn to_json_schema ( & self ) -> SchemaObject {
123
+ fn to_json_schema ( & self , options : & ToJsonSchemaOptions ) -> SchemaObject {
100
124
match self {
101
- schema:: ValueType :: Basic ( b) => b. to_json_schema ( ) ,
102
- schema:: ValueType :: Struct ( s) => s. to_json_schema ( ) ,
125
+ schema:: ValueType :: Basic ( b) => b. to_json_schema ( options ) ,
126
+ schema:: ValueType :: Struct ( s) => s. to_json_schema ( options ) ,
103
127
schema:: ValueType :: Collection ( c) => SchemaObject {
104
128
instance_type : Some ( SingleOrVec :: Single ( Box :: new ( InstanceType :: Array ) ) ) ,
105
129
array : Some ( Box :: new ( ArrayValidation {
106
- items : Some ( SingleOrVec :: Single ( Box :: new ( c. row . to_json_schema ( ) . into ( ) ) ) ) ,
130
+ items : Some ( SingleOrVec :: Single ( Box :: new (
131
+ c. row . to_json_schema ( options) . into ( ) ,
132
+ ) ) ) ,
107
133
..Default :: default ( )
108
134
} ) ) ,
109
135
..Default :: default ( )
@@ -113,7 +139,7 @@ impl ToJsonSchema for schema::ValueType {
113
139
}
114
140
115
141
impl ToJsonSchema for schema:: EnrichedValueType {
116
- fn to_json_schema ( & self ) -> SchemaObject {
117
- self . typ . to_json_schema ( )
142
+ fn to_json_schema ( & self , options : & ToJsonSchemaOptions ) -> SchemaObject {
143
+ self . typ . to_json_schema ( options )
118
144
}
119
145
}
0 commit comments