@@ -528,3 +528,187 @@ func TestFlexibleArgumentsJSONMarshalUnmarshal(t *testing.T) {
528528	assert .Equal (t , "value1" , args ["key1" ])
529529	assert .Equal (t , float64 (123 ), args ["key2" ]) // JSON numbers are unmarshaled as float64 
530530}
531+ 
532+ // TestNewItemsAPICompatibility tests that the new Items API functions 
533+ // generate the same schema as the original Items() function with manual schema objects 
534+ func  TestNewItemsAPICompatibility (t  * testing.T ) {
535+ 	tests  :=  []struct  {
536+ 		name     string 
537+ 		oldTool  Tool 
538+ 		newTool  Tool 
539+ 	}{
540+ 		{
541+ 			name : "WithStringItems basic" ,
542+ 			oldTool : NewTool ("old-string-array" ,
543+ 				WithDescription ("Tool with string array using old API" ),
544+ 				WithArray ("items" ,
545+ 					Description ("List of string items" ),
546+ 					Items (map [string ]any {
547+ 						"type" : "string" ,
548+ 					}),
549+ 				),
550+ 			),
551+ 			newTool : NewTool ("new-string-array" ,
552+ 				WithDescription ("Tool with string array using new API" ),
553+ 				WithArray ("items" ,
554+ 					Description ("List of string items" ),
555+ 					WithStringItems (),
556+ 				),
557+ 			),
558+ 		},
559+ 		{
560+ 			name : "WithStringEnumItems" ,
561+ 			oldTool : NewTool ("old-enum-array" ,
562+ 				WithDescription ("Tool with enum array using old API" ),
563+ 				WithArray ("status" ,
564+ 					Description ("Filter by status" ),
565+ 					Items (map [string ]any {
566+ 						"type" : "string" ,
567+ 						"enum" : []string {"active" , "inactive" , "pending" },
568+ 					}),
569+ 				),
570+ 			),
571+ 			newTool : NewTool ("new-enum-array" ,
572+ 				WithDescription ("Tool with enum array using new API" ),
573+ 				WithArray ("status" ,
574+ 					Description ("Filter by status" ),
575+ 					WithStringEnumItems ([]string {"active" , "inactive" , "pending" }),
576+ 				),
577+ 			),
578+ 		},
579+ 		{
580+ 			name : "WithStringItems with options" ,
581+ 			oldTool : NewTool ("old-string-with-opts" ,
582+ 				WithDescription ("Tool with string array with options using old API" ),
583+ 				WithArray ("names" ,
584+ 					Description ("List of names" ),
585+ 					Items (map [string ]any {
586+ 						"type" :      "string" ,
587+ 						"minLength" : 1 ,
588+ 						"maxLength" : 50 ,
589+ 					}),
590+ 				),
591+ 			),
592+ 			newTool : NewTool ("new-string-with-opts" ,
593+ 				WithDescription ("Tool with string array with options using new API" ),
594+ 				WithArray ("names" ,
595+ 					Description ("List of names" ),
596+ 					WithStringItems (MinLength (1 ), MaxLength (50 )),
597+ 				),
598+ 			),
599+ 		},
600+ 		{
601+ 			name : "WithNumberItems basic" ,
602+ 			oldTool : NewTool ("old-number-array" ,
603+ 				WithDescription ("Tool with number array using old API" ),
604+ 				WithArray ("scores" ,
605+ 					Description ("List of scores" ),
606+ 					Items (map [string ]any {
607+ 						"type" : "number" ,
608+ 					}),
609+ 				),
610+ 			),
611+ 			newTool : NewTool ("new-number-array" ,
612+ 				WithDescription ("Tool with number array using new API" ),
613+ 				WithArray ("scores" ,
614+ 					Description ("List of scores" ),
615+ 					WithNumberItems (),
616+ 				),
617+ 			),
618+ 		},
619+ 		{
620+ 			name : "WithNumberItems with constraints" ,
621+ 			oldTool : NewTool ("old-number-with-constraints" ,
622+ 				WithDescription ("Tool with constrained number array using old API" ),
623+ 				WithArray ("ratings" ,
624+ 					Description ("List of ratings" ),
625+ 					Items (map [string ]any {
626+ 						"type" :    "number" ,
627+ 						"minimum" : 0.0 ,
628+ 						"maximum" : 10.0 ,
629+ 					}),
630+ 				),
631+ 			),
632+ 			newTool : NewTool ("new-number-with-constraints" ,
633+ 				WithDescription ("Tool with constrained number array using new API" ),
634+ 				WithArray ("ratings" ,
635+ 					Description ("List of ratings" ),
636+ 					WithNumberItems (Min (0 ), Max (10 )),
637+ 				),
638+ 			),
639+ 		},
640+ 		{
641+ 			name : "WithBooleanItems basic" ,
642+ 			oldTool : NewTool ("old-boolean-array" ,
643+ 				WithDescription ("Tool with boolean array using old API" ),
644+ 				WithArray ("flags" ,
645+ 					Description ("List of feature flags" ),
646+ 					Items (map [string ]any {
647+ 						"type" : "boolean" ,
648+ 					}),
649+ 				),
650+ 			),
651+ 			newTool : NewTool ("new-boolean-array" ,
652+ 				WithDescription ("Tool with boolean array using new API" ),
653+ 				WithArray ("flags" ,
654+ 					Description ("List of feature flags" ),
655+ 					WithBooleanItems (),
656+ 				),
657+ 			),
658+ 		},
659+ 	}
660+ 
661+ 	for  _ , tt  :=  range  tests  {
662+ 		t .Run (tt .name , func (t  * testing.T ) {
663+ 			// Marshal both tools to JSON 
664+ 			oldData , err  :=  json .Marshal (tt .oldTool )
665+ 			assert .NoError (t , err )
666+ 
667+ 			newData , err  :=  json .Marshal (tt .newTool )
668+ 			assert .NoError (t , err )
669+ 
670+ 			// Unmarshal to maps for comparison 
671+ 			var  oldResult , newResult  map [string ]any 
672+ 			err  =  json .Unmarshal (oldData , & oldResult )
673+ 			assert .NoError (t , err )
674+ 
675+ 			err  =  json .Unmarshal (newData , & newResult )
676+ 			assert .NoError (t , err )
677+ 
678+ 			// Compare the inputSchema properties (ignoring tool names and descriptions) 
679+ 			oldSchema  :=  oldResult ["inputSchema" ].(map [string ]any )
680+ 			newSchema  :=  newResult ["inputSchema" ].(map [string ]any )
681+ 
682+ 			oldProperties  :=  oldSchema ["properties" ].(map [string ]any )
683+ 			newProperties  :=  newSchema ["properties" ].(map [string ]any )
684+ 
685+ 			// Get the array property (should be the only one in these tests) 
686+ 			var  oldArrayProp , newArrayProp  map [string ]any 
687+ 			for  _ , prop  :=  range  oldProperties  {
688+ 				if  propMap , ok  :=  prop .(map [string ]any ); ok  &&  propMap ["type" ] ==  "array"  {
689+ 					oldArrayProp  =  propMap 
690+ 					break 
691+ 				}
692+ 			}
693+ 			for  _ , prop  :=  range  newProperties  {
694+ 				if  propMap , ok  :=  prop .(map [string ]any ); ok  &&  propMap ["type" ] ==  "array"  {
695+ 					newArrayProp  =  propMap 
696+ 					break 
697+ 				}
698+ 			}
699+ 
700+ 			assert .NotNil (t , oldArrayProp , "Old tool should have array property" )
701+ 			assert .NotNil (t , newArrayProp , "New tool should have array property" )
702+ 
703+ 			// Compare the items schema - this is the critical part 
704+ 			oldItems  :=  oldArrayProp ["items" ]
705+ 			newItems  :=  newArrayProp ["items" ]
706+ 
707+ 			assert .Equal (t , oldItems , newItems , "Items schema should be identical between old and new API" )
708+ 
709+ 			// Also compare other array properties like description 
710+ 			assert .Equal (t , oldArrayProp ["description" ], newArrayProp ["description" ], "Array descriptions should match" )
711+ 			assert .Equal (t , oldArrayProp ["type" ], newArrayProp ["type" ], "Array types should match" )
712+ 		})
713+ 	}
714+ }
0 commit comments