@@ -226,3 +226,120 @@ class EmptyDocUser(BaseModel):
226226
227227 tool_spec = convert_pydantic_to_tool_spec (EmptyDocUser )
228228 assert tool_spec ["description" ] == "EmptyDocUser structured output tool"
229+
230+
231+ def test_convert_pydantic_with_items_refs ():
232+ """Test that no $refs exist after lists of different components."""
233+
234+ class Address (BaseModel ):
235+ postal_code : Optional [str ] = None
236+
237+ class Person (BaseModel ):
238+ """Complete person information."""
239+
240+ list_of_items : list [Address ]
241+ list_of_items_nullable : Optional [list [Address ]]
242+ list_of_item_or_nullable : list [Optional [Address ]]
243+
244+ tool_spec = convert_pydantic_to_tool_spec (Person )
245+
246+ expected_spec = {
247+ "description" : "Complete person information." ,
248+ "inputSchema" : {
249+ "json" : {
250+ "description" : "Complete person information." ,
251+ "properties" : {
252+ "list_of_item_or_nullable" : {
253+ "items" : {
254+ "anyOf" : [
255+ {
256+ "properties" : {"postal_code" : {"type" : ["string" , "null" ]}},
257+ "title" : "Address" ,
258+ "type" : "object" ,
259+ },
260+ {"type" : "null" },
261+ ]
262+ },
263+ "title" : "List Of Item Or Nullable" ,
264+ "type" : "array" ,
265+ },
266+ "list_of_items" : {
267+ "items" : {
268+ "properties" : {"postal_code" : {"type" : ["string" , "null" ]}},
269+ "title" : "Address" ,
270+ "type" : "object" ,
271+ },
272+ "title" : "List Of Items" ,
273+ "type" : "array" ,
274+ },
275+ "list_of_items_nullable" : {
276+ "items" : {
277+ "properties" : {"postal_code" : {"type" : ["string" , "null" ]}},
278+ "title" : "Address" ,
279+ "type" : "object" ,
280+ },
281+ "type" : ["array" , "null" ],
282+ },
283+ },
284+ "required" : ["list_of_items" , "list_of_item_or_nullable" ],
285+ "title" : "Person" ,
286+ "type" : "object" ,
287+ }
288+ },
289+ "name" : "Person" ,
290+ }
291+ assert tool_spec == expected_spec
292+
293+
294+ def test_convert_pydantic_with_refs ():
295+ """Test that no $refs exist after processing complex hierarchies."""
296+
297+ class Address (BaseModel ):
298+ street : str
299+ city : str
300+ country : str
301+ postal_code : Optional [str ] = None
302+
303+ class Contact (BaseModel ):
304+ address : Address
305+
306+ class Person (BaseModel ):
307+ """Complete person information."""
308+
309+ contact : Contact = Field (description = "Contact methods" )
310+
311+ tool_spec = convert_pydantic_to_tool_spec (Person )
312+
313+ expected_spec = {
314+ "description" : "Complete person information." ,
315+ "inputSchema" : {
316+ "json" : {
317+ "description" : "Complete person information." ,
318+ "properties" : {
319+ "contact" : {
320+ "description" : "Contact methods" ,
321+ "properties" : {
322+ "address" : {
323+ "properties" : {
324+ "city" : {"title" : "City" , "type" : "string" },
325+ "country" : {"title" : "Country" , "type" : "string" },
326+ "postal_code" : {"type" : ["string" , "null" ]},
327+ "street" : {"title" : "Street" , "type" : "string" },
328+ },
329+ "required" : ["street" , "city" , "country" ],
330+ "title" : "Address" ,
331+ "type" : "object" ,
332+ }
333+ },
334+ "required" : ["address" ],
335+ "type" : "object" ,
336+ }
337+ },
338+ "required" : ["contact" ],
339+ "title" : "Person" ,
340+ "type" : "object" ,
341+ }
342+ },
343+ "name" : "Person" ,
344+ }
345+ assert tool_spec == expected_spec
0 commit comments