@@ -510,6 +510,106 @@ describe("ProviderTransform.schema - gemini nested array items", () => {
510510 } )
511511} )
512512
513+ describe ( "ProviderTransform.schema - gemini combiner nodes" , ( ) => {
514+ const geminiModel = {
515+ providerID : "google" ,
516+ api : {
517+ id : "gemini-3-pro" ,
518+ } ,
519+ } as any
520+
521+ const walk = ( node : any , cb : ( node : any , path : ( string | number ) [ ] ) => void , path : ( string | number ) [ ] = [ ] ) => {
522+ if ( node === null || typeof node !== "object" ) {
523+ return
524+ }
525+ if ( Array . isArray ( node ) ) {
526+ node . forEach ( ( item , i ) => walk ( item , cb , [ ...path , i ] ) )
527+ return
528+ }
529+ cb ( node , path )
530+ Object . entries ( node ) . forEach ( ( [ key , value ] ) => walk ( value , cb , [ ...path , key ] ) )
531+ }
532+
533+ test ( "keeps edits.items.anyOf without adding type" , ( ) => {
534+ const schema = {
535+ type : "object" ,
536+ properties : {
537+ edits : {
538+ type : "array" ,
539+ items : {
540+ anyOf : [
541+ {
542+ type : "object" ,
543+ properties : {
544+ old_string : { type : "string" } ,
545+ new_string : { type : "string" } ,
546+ } ,
547+ required : [ "old_string" , "new_string" ] ,
548+ } ,
549+ {
550+ type : "object" ,
551+ properties : {
552+ old_string : { type : "string" } ,
553+ new_string : { type : "string" } ,
554+ replace_all : { type : "boolean" } ,
555+ } ,
556+ required : [ "old_string" , "new_string" ] ,
557+ } ,
558+ ] ,
559+ } ,
560+ } ,
561+ } ,
562+ required : [ "edits" ] ,
563+ } as any
564+
565+ const result = ProviderTransform . schema ( geminiModel , schema ) as any
566+
567+ expect ( Array . isArray ( result . properties . edits . items . anyOf ) ) . toBe ( true )
568+ expect ( result . properties . edits . items . type ) . toBeUndefined ( )
569+ } )
570+
571+ test ( "does not add sibling keys to combiner nodes during sanitize" , ( ) => {
572+ const schema = {
573+ type : "object" ,
574+ properties : {
575+ edits : {
576+ type : "array" ,
577+ items : {
578+ anyOf : [ { type : "string" } , { type : "number" } ] ,
579+ } ,
580+ } ,
581+ value : {
582+ oneOf : [ { type : "string" } , { type : "boolean" } ] ,
583+ } ,
584+ meta : {
585+ allOf : [
586+ {
587+ type : "object" ,
588+ properties : { a : { type : "string" } } ,
589+ } ,
590+ {
591+ type : "object" ,
592+ properties : { b : { type : "string" } } ,
593+ } ,
594+ ] ,
595+ } ,
596+ } ,
597+ } as any
598+ const input = JSON . parse ( JSON . stringify ( schema ) )
599+ const result = ProviderTransform . schema ( geminiModel , schema ) as any
600+
601+ walk ( result , ( node , path ) => {
602+ const hasCombiner = Array . isArray ( node . anyOf ) || Array . isArray ( node . oneOf ) || Array . isArray ( node . allOf )
603+ if ( ! hasCombiner ) {
604+ return
605+ }
606+ const before = path . reduce ( ( acc : any , key ) => acc ?. [ key ] , input )
607+ const added = Object . keys ( node ) . filter ( ( key ) => ! ( key in before ) )
608+ expect ( added ) . toEqual ( [ ] )
609+ } )
610+ } )
611+ } )
612+
513613describe ( "ProviderTransform.schema - gemini non-object properties removal" , ( ) => {
514614 const geminiModel = {
515615 providerID : "google" ,
0 commit comments