@@ -17,16 +17,22 @@ export namespace ChatGptSchemaComposer {
17
17
accessor ?: string ;
18
18
refAccessor ?: string ;
19
19
} ) : IResult < IChatGptSchema . IParameters , IOpenApiSchemaError > => {
20
+ // polyfill
21
+ props . config . strict ??= false ;
22
+
23
+ // validate
20
24
const result : IResult < ILlmSchemaV3_1 . IParameters , IOpenApiSchemaError > =
21
25
LlmSchemaV3_1Composer . parameters ( {
22
26
...props ,
23
27
config : {
24
28
reference : props . config . reference ,
25
29
constraint : false ,
26
30
} ,
27
- validate,
31
+ validate : props . config . strict === true ? validateStrict : undefined ,
28
32
} ) ;
29
33
if ( result . success === false ) return result ;
34
+
35
+ // returns with transformation
30
36
for ( const key of Object . keys ( result . value . $defs ) )
31
37
result . value . $defs [ key ] = transform ( result . value . $defs [ key ] ) ;
32
38
return {
@@ -43,6 +49,10 @@ export namespace ChatGptSchemaComposer {
43
49
accessor ?: string ;
44
50
refAccessor ?: string ;
45
51
} ) : IResult < IChatGptSchema , IOpenApiSchemaError > => {
52
+ // polyfill
53
+ props . config . strict ??= false ;
54
+
55
+ // validate
46
56
const oldbie : Set < string > = new Set ( Object . keys ( props . $defs ) ) ;
47
57
const result : IResult < ILlmSchemaV3_1 , IOpenApiSchemaError > =
48
58
LlmSchemaV3_1Composer . schema ( {
@@ -51,9 +61,11 @@ export namespace ChatGptSchemaComposer {
51
61
reference : props . config . reference ,
52
62
constraint : false ,
53
63
} ,
54
- validate,
64
+ validate : props . config . strict === true ? validateStrict : undefined ,
55
65
} ) ;
56
66
if ( result . success === false ) return result ;
67
+
68
+ // returns with transformation
57
69
for ( const key of Object . keys ( props . $defs ) )
58
70
if ( oldbie . has ( key ) === false )
59
71
props . $defs [ key ] = transform ( props . $defs [ key ] ) ;
@@ -63,20 +75,29 @@ export namespace ChatGptSchemaComposer {
63
75
} ;
64
76
} ;
65
77
66
- const validate = (
78
+ const validateStrict = (
67
79
schema : OpenApi . IJsonSchema ,
68
80
accessor : string ,
69
81
) : IOpenApiSchemaError . IReason [ ] => {
70
- if ( OpenApiTypeChecker . isObject ( schema ) && ! ! schema . additionalProperties )
71
- return [
72
- {
82
+ const reasons : IOpenApiSchemaError . IReason [ ] = [ ] ;
83
+ if ( OpenApiTypeChecker . isObject ( schema ) ) {
84
+ if ( ! ! schema . additionalProperties )
85
+ reasons . push ( {
73
86
schema : schema ,
74
87
accessor : `${ accessor } .additionalProperties` ,
75
88
message :
76
- "ChatGPT does not allow additionalProperties, the dynamic key typed object." ,
77
- } ,
78
- ] ;
79
- return [ ] ;
89
+ "ChatGPT does not allow additionalProperties in strict mode, the dynamic key typed object." ,
90
+ } ) ;
91
+ for ( const key of Object . keys ( schema . properties ?? { } ) )
92
+ if ( schema . required ?. includes ( key ) === false )
93
+ reasons . push ( {
94
+ schema : schema ,
95
+ accessor : `${ accessor } .properties.${ key } ` ,
96
+ message :
97
+ "ChatGPT does not allow optional properties in strict mode." ,
98
+ } ) ;
99
+ }
100
+ return reasons ;
80
101
} ;
81
102
82
103
const transform = ( schema : ILlmSchemaV3_1 ) : IChatGptSchema => {
@@ -108,7 +129,11 @@ export namespace ChatGptSchemaComposer {
108
129
transform ( value ) ,
109
130
] ) ,
110
131
) ,
111
- additionalProperties : false ,
132
+ additionalProperties :
133
+ typeof input . additionalProperties === "object" &&
134
+ input . additionalProperties !== null
135
+ ? transform ( input . additionalProperties )
136
+ : input . additionalProperties ,
112
137
} ) ;
113
138
else if ( LlmTypeCheckerV3_1 . isConstant ( input ) === false )
114
139
union . push ( input ) ;
@@ -181,6 +206,7 @@ export namespace ChatGptSchemaComposer {
181
206
key . endsWith ( ".Llm" ) ,
182
207
) ,
183
208
) ,
209
+ additionalProperties : false ,
184
210
} ,
185
211
human : {
186
212
...human ,
@@ -189,6 +215,7 @@ export namespace ChatGptSchemaComposer {
189
215
key . endsWith ( ".Human" ) ,
190
216
) ,
191
217
) ,
218
+ additionalProperties : false ,
192
219
} ,
193
220
} ;
194
221
for ( const key of Object . keys ( props . parameters . $defs ) )
@@ -270,6 +297,7 @@ export namespace ChatGptSchemaComposer {
270
297
const llm = {
271
298
...props . schema ,
272
299
properties : { } as Record < string , IChatGptSchema > ,
300
+ additionalProperties : props . schema . additionalProperties ,
273
301
} satisfies IChatGptSchema . IObject ;
274
302
const human = {
275
303
...props . schema ,
@@ -285,9 +313,25 @@ export namespace ChatGptSchemaComposer {
285
313
if ( x !== null ) llm . properties [ key ] = x ;
286
314
if ( y !== null ) human . properties [ key ] = y ;
287
315
}
316
+ if (
317
+ typeof props . schema . additionalProperties === "object" &&
318
+ props . schema . additionalProperties !== null
319
+ ) {
320
+ const [ dx , dy ] = separateStation ( {
321
+ $defs : props . $defs ,
322
+ predicate : props . predicate ,
323
+ schema : props . schema . additionalProperties ,
324
+ } ) ;
325
+ llm . additionalProperties = dx ?? false ;
326
+ human . additionalProperties = dy ?? false ;
327
+ }
288
328
return [
289
- Object . keys ( llm . properties ) . length === 0 ? null : shrinkRequired ( llm ) ,
290
- Object . keys ( human . properties ) . length === 0 ? null : shrinkRequired ( human ) ,
329
+ ! ! Object . keys ( llm . properties ) . length || ! ! llm . additionalProperties
330
+ ? shrinkRequired ( llm )
331
+ : null ,
332
+ ! ! Object . keys ( human . properties ) . length || human . additionalProperties
333
+ ? shrinkRequired ( human )
334
+ : null ,
291
335
] ;
292
336
} ;
293
337
0 commit comments