@@ -12,6 +12,10 @@ type ToolWithParameters = {
1212 parameters : unknown ;
1313} ;
1414
15+ type ToolFieldRead < TField extends keyof ToolWithParameters > =
16+ | { readable : true ; value : ToolWithParameters [ TField ] }
17+ | { readable : false } ;
18+
1519const MAX_STRICT_SCHEMA_CACHE_ENTRIES_PER_SCHEMA = 8 ;
1620let strictOpenAISchemaCache = new WeakMap < object , Array < { key : string ; value : unknown } > > ( ) ;
1721
@@ -154,7 +158,11 @@ export function normalizeOpenAIStrictToolParameters<T>(
154158}
155159
156160export function isStrictOpenAIJsonSchemaCompatible ( schema : unknown ) : boolean {
157- return isStrictOpenAIJsonSchemaCompatibleRecursive ( normalizeStrictOpenAIJsonSchema ( schema ) ) ;
161+ try {
162+ return isStrictOpenAIJsonSchemaCompatibleRecursive ( normalizeStrictOpenAIJsonSchema ( schema ) ) ;
163+ } catch {
164+ return false ;
165+ }
158166}
159167
160168type OpenAIStrictToolSchemaDiagnostic = {
@@ -167,23 +175,61 @@ export function findOpenAIStrictToolSchemaDiagnostics(
167175 tools : readonly ToolWithParameters [ ] ,
168176) : OpenAIStrictToolSchemaDiagnostic [ ] {
169177 return tools . flatMap ( ( tool , toolIndex ) => {
170- const violations = findStrictOpenAIJsonSchemaViolations (
171- normalizeStrictOpenAIJsonSchema ( tool . parameters ) ,
172- `${ typeof tool . name === "string" && tool . name ? tool . name : `tool[${ toolIndex } ]` } .parameters` ,
173- ) ;
178+ const nameRead = readToolField ( tool , "name" ) ;
179+ const toolName =
180+ nameRead . readable && typeof nameRead . value === "string" && nameRead . value
181+ ? nameRead . value
182+ : `tool[${ toolIndex } ]` ;
183+ const descriptorViolations = nameRead . readable ? [ ] : [ `${ toolName } .name is unreadable` ] ;
184+ const parametersRead = readToolField ( tool , "parameters" ) ;
185+ if ( ! parametersRead . readable ) {
186+ return [
187+ {
188+ toolIndex,
189+ ...( nameRead . readable && typeof nameRead . value === "string" && nameRead . value
190+ ? { toolName : nameRead . value }
191+ : { } ) ,
192+ violations : [ ...descriptorViolations , `${ toolName } .parameters is unreadable` ] ,
193+ } ,
194+ ] ;
195+ }
196+
197+ let schemaViolations : string [ ] ;
198+ try {
199+ schemaViolations = findStrictOpenAIJsonSchemaViolations (
200+ normalizeStrictOpenAIJsonSchema ( parametersRead . value ) ,
201+ `${ toolName } .parameters` ,
202+ ) ;
203+ } catch {
204+ schemaViolations = [ `${ toolName } .parameters is unreadable` ] ;
205+ }
206+ const violations = [ ...descriptorViolations , ...schemaViolations ] ;
174207 if ( violations . length === 0 ) {
175208 return [ ] ;
176209 }
177210 return [
178211 {
179212 toolIndex,
180- ...( typeof tool . name === "string" && tool . name ? { toolName : tool . name } : { } ) ,
213+ ...( nameRead . readable && typeof nameRead . value === "string" && nameRead . value
214+ ? { toolName : nameRead . value }
215+ : { } ) ,
181216 violations,
182217 } ,
183218 ] ;
184219 } ) ;
185220}
186221
222+ function readToolField < TField extends keyof ToolWithParameters > (
223+ tool : ToolWithParameters ,
224+ field : TField ,
225+ ) : ToolFieldRead < TField > {
226+ try {
227+ return { readable : true , value : tool [ field ] } ;
228+ } catch {
229+ return { readable : false } ;
230+ }
231+ }
232+
187233function isStrictOpenAIJsonSchemaCompatibleRecursive ( schema : unknown ) : boolean {
188234 if ( Array . isArray ( schema ) ) {
189235 return schema . every ( ( entry ) => isStrictOpenAIJsonSchemaCompatibleRecursive ( entry ) ) ;
@@ -304,5 +350,8 @@ export function resolveOpenAIStrictToolFlagForInventory(
304350 if ( strict !== true ) {
305351 return strict === false ? false : undefined ;
306352 }
307- return tools . every ( ( tool ) => isStrictOpenAIJsonSchemaCompatible ( tool . parameters ) ) ;
353+ return tools . every ( ( tool ) => {
354+ const parametersRead = readToolField ( tool , "parameters" ) ;
355+ return parametersRead . readable && isStrictOpenAIJsonSchemaCompatible ( parametersRead . value ) ;
356+ } ) ;
308357}
0 commit comments