@@ -44,5 +44,228 @@ describe('.parse()', () => {
44
44
}
45
45
` ) ;
46
46
} ) ;
47
+
48
+ test ( 'top-level recursive schemas' , async ( ) => {
49
+ const UI : any = z . lazy ( ( ) =>
50
+ z . object ( {
51
+ type : z . enum ( [ 'div' , 'button' , 'header' , 'section' , 'field' , 'form' ] ) ,
52
+ label : z . string ( ) ,
53
+ children : z . array ( UI ) ,
54
+ attributes : z . array (
55
+ z . object ( {
56
+ name : z . string ( ) ,
57
+ value : z . string ( ) ,
58
+ } ) ,
59
+ ) ,
60
+ } ) ,
61
+ ) ;
62
+
63
+ const completion = await makeSnapshotRequest ( ( openai ) =>
64
+ openai . beta . chat . completions . parse ( {
65
+ model : 'gpt-4o-2024-08-06' ,
66
+ messages : [
67
+ {
68
+ role : 'system' ,
69
+ content : 'You are a UI generator AI. Convert the user input into a UI.' ,
70
+ } ,
71
+ { role : 'user' , content : 'Make a User Profile Form with 3 fields' } ,
72
+ ] ,
73
+ response_format : zodResponseFormat ( UI , 'ui' ) ,
74
+ } ) ,
75
+ ) ;
76
+
77
+ expect ( completion . choices [ 0 ] ?. message ) . toMatchInlineSnapshot ( `
78
+ {
79
+ "content": "{"type":"form","label":"User Profile Form","children":[{"type":"field","label":"Full Name","children":[],"attributes":[{"name":"type","value":"text"},{"name":"placeholder","value":"Enter your full name"}]},{"type":"field","label":"Email Address","children":[],"attributes":[{"name":"type","value":"email"},{"name":"placeholder","value":"Enter your email address"}]},{"type":"field","label":"Phone Number","children":[],"attributes":[{"name":"type","value":"tel"},{"name":"placeholder","value":"Enter your phone number"}]},{"type":"button","label":"Submit","children":[],"attributes":[{"name":"type","value":"submit"}]}],"attributes":[{"name":"method","value":"post"},{"name":"action","value":"/submit-profile"}]}",
80
+ "parsed": {
81
+ "attributes": [
82
+ {
83
+ "name": "method",
84
+ "value": "post",
85
+ },
86
+ {
87
+ "name": "action",
88
+ "value": "/submit-profile",
89
+ },
90
+ ],
91
+ "children": [
92
+ {
93
+ "attributes": [
94
+ {
95
+ "name": "type",
96
+ "value": "text",
97
+ },
98
+ {
99
+ "name": "placeholder",
100
+ "value": "Enter your full name",
101
+ },
102
+ ],
103
+ "children": [],
104
+ "label": "Full Name",
105
+ "type": "field",
106
+ },
107
+ {
108
+ "attributes": [
109
+ {
110
+ "name": "type",
111
+ "value": "email",
112
+ },
113
+ {
114
+ "name": "placeholder",
115
+ "value": "Enter your email address",
116
+ },
117
+ ],
118
+ "children": [],
119
+ "label": "Email Address",
120
+ "type": "field",
121
+ },
122
+ {
123
+ "attributes": [
124
+ {
125
+ "name": "type",
126
+ "value": "tel",
127
+ },
128
+ {
129
+ "name": "placeholder",
130
+ "value": "Enter your phone number",
131
+ },
132
+ ],
133
+ "children": [],
134
+ "label": "Phone Number",
135
+ "type": "field",
136
+ },
137
+ {
138
+ "attributes": [
139
+ {
140
+ "name": "type",
141
+ "value": "submit",
142
+ },
143
+ ],
144
+ "children": [],
145
+ "label": "Submit",
146
+ "type": "button",
147
+ },
148
+ ],
149
+ "label": "User Profile Form",
150
+ "type": "form",
151
+ },
152
+ "refusal": null,
153
+ "role": "assistant",
154
+ "tool_calls": [],
155
+ }
156
+ ` ) ;
157
+
158
+ expect ( zodResponseFormat ( UI , 'ui' ) . json_schema ) . toMatchInlineSnapshot ( `
159
+ {
160
+ "name": "ui",
161
+ "schema": {
162
+ "$schema": "http://json-schema.org/draft-07/schema#",
163
+ "additionalProperties": false,
164
+ "definitions": {
165
+ "ui": {
166
+ "additionalProperties": false,
167
+ "properties": {
168
+ "attributes": {
169
+ "items": {
170
+ "additionalProperties": false,
171
+ "properties": {
172
+ "name": {
173
+ "type": "string",
174
+ },
175
+ "value": {
176
+ "type": "string",
177
+ },
178
+ },
179
+ "required": [
180
+ "name",
181
+ "value",
182
+ ],
183
+ "type": "object",
184
+ },
185
+ "type": "array",
186
+ },
187
+ "children": {
188
+ "items": {
189
+ "$ref": "#/definitions/ui",
190
+ },
191
+ "type": "array",
192
+ },
193
+ "label": {
194
+ "type": "string",
195
+ },
196
+ "type": {
197
+ "enum": [
198
+ "div",
199
+ "button",
200
+ "header",
201
+ "section",
202
+ "field",
203
+ "form",
204
+ ],
205
+ "type": "string",
206
+ },
207
+ },
208
+ "required": [
209
+ "type",
210
+ "label",
211
+ "children",
212
+ "attributes",
213
+ ],
214
+ "type": "object",
215
+ },
216
+ },
217
+ "properties": {
218
+ "attributes": {
219
+ "items": {
220
+ "additionalProperties": false,
221
+ "properties": {
222
+ "name": {
223
+ "type": "string",
224
+ },
225
+ "value": {
226
+ "type": "string",
227
+ },
228
+ },
229
+ "required": [
230
+ "name",
231
+ "value",
232
+ ],
233
+ "type": "object",
234
+ },
235
+ "type": "array",
236
+ },
237
+ "children": {
238
+ "items": {
239
+ "$ref": "#/definitions/ui",
240
+ },
241
+ "type": "array",
242
+ },
243
+ "label": {
244
+ "type": "string",
245
+ },
246
+ "type": {
247
+ "enum": [
248
+ "div",
249
+ "button",
250
+ "header",
251
+ "section",
252
+ "field",
253
+ "form",
254
+ ],
255
+ "type": "string",
256
+ },
257
+ },
258
+ "required": [
259
+ "type",
260
+ "label",
261
+ "children",
262
+ "attributes",
263
+ ],
264
+ "type": "object",
265
+ },
266
+ "strict": true,
267
+ }
268
+ ` ) ;
269
+ } ) ;
47
270
} ) ;
48
271
} ) ;
0 commit comments