@@ -615,6 +615,7 @@ export function factoryStitchUntilComplete<T>(
615615 ? ( currentResult as any ) . output
616616 : currentResult ;
617617 const stitchInput = {
618+ context : buildStitchContext ( input ) ,
618619 partialOutput : minimalPartial ,
619620 instruction : 'Continue and complete the previous output'
620621 } as any ;
@@ -644,7 +645,12 @@ export function factoryStitchUntilComplete<T>(
644645 throw error ;
645646 }
646647
647- return { ...currentResult , finalOutput : ( currentResult as any ) . output ?? currentResult } ;
648+ const finalOutput = ( currentResult as any ) . output ?? currentResult ;
649+ return {
650+ context : buildStitchContext ( input ) ,
651+ output : finalOutput ,
652+ finalOutput,
653+ } as any ;
648654 } ;
649655}
650656
@@ -702,7 +708,10 @@ export function factoryReason<T>(): Executor<T, T & { reasoning: Reasoning }> {
702708 const isSum = typedInput . chunkResults !== undefined ;
703709
704710 if ( isStitch ) {
705- return `Continue reasoning from this partial output:\n\n${ JSON . stringify ( typedInput . partialOutput , null , 2 ) } ` ;
711+ const context = typedInput . context && Object . keys ( typedInput . context ) . length
712+ ? `\n\nOriginal task context:\n\n${ JSON . stringify ( typedInput . context , null , 2 ) } `
713+ : '' ;
714+ return `Continue reasoning from this partial output:\n\n${ JSON . stringify ( typedInput . partialOutput , null , 2 ) } ${ context } ` ;
706715 }
707716 if ( isSum ) {
708717 return `Reason about how to combine these chunk results:\n\n${ JSON . stringify ( typedInput . chunkResults , null , 2 ) } ` ;
@@ -780,9 +789,9 @@ export function factoryStructuredOutput<T, TSchema>(
780789// Infer a minimal shape string from a Zod schema when description is missing
781790function inferSchemaShape ( s : z . ZodTypeAny ) : string {
782791 try {
783- const def : any = ( s as any ) . _def ;
784- if ( def ?. typeName === z . ZodFirstPartyTypeKind . ZodObject && def . shape ) {
785- const entries = Object . entries ( def . shape as Record < string , z . ZodTypeAny > ) ;
792+ const shape = getZodObjectShape ( s ) ;
793+ if ( shape ) {
794+ const entries = Object . entries ( shape ) ;
786795 const shapeLines = entries . map ( ( [ k , v ] ) => ` "${ k } ": ${ inferField ( v ) } ` ) ;
787796 return `{
788797${ shapeLines . join ( ',\n' ) }
@@ -798,38 +807,57 @@ function inferField(v: z.ZodTypeAny): string {
798807 case z . ZodFirstPartyTypeKind . ZodString : return 'string' ;
799808 case z . ZodFirstPartyTypeKind . ZodNumber : return 'number' ;
800809 case z . ZodFirstPartyTypeKind . ZodBoolean : return 'boolean' ;
810+ case z . ZodFirstPartyTypeKind . ZodAny : return 'any' ;
811+ case z . ZodFirstPartyTypeKind . ZodLiteral : return JSON . stringify ( ( v as any ) ?. _def ?. value ) ;
801812 case z . ZodFirstPartyTypeKind . ZodArray : {
802813 const inner = ( v as any ) ?. _def ?. type ;
803814 return `[ ${ inner ? inferField ( inner ) : 'any' } ]` ;
804815 }
805- case z . ZodFirstPartyTypeKind . ZodObject : return '{ ... }' ;
816+ case z . ZodFirstPartyTypeKind . ZodObject : {
817+ const shape = getZodObjectShape ( v ) ;
818+ if ( ! shape ) return '{ ... }' ;
819+ const keys = Object . entries ( shape ) . slice ( 0 , 6 ) ;
820+ return `{ ${ keys . map ( ( [ key , value ] ) => `"${ key } ": ${ inferField ( value ) } ` ) . join ( ', ' ) } ${ Object . keys ( shape ) . length > keys . length ? ', ...' : '' } }` ;
821+ }
806822 case z . ZodFirstPartyTypeKind . ZodRecord : return '{ [key: string]: any }' ;
807- case z . ZodFirstPartyTypeKind . ZodEnum : return 'enum' ;
823+ case z . ZodFirstPartyTypeKind . ZodEnum : {
824+ const values = ( v as any ) ?. _def ?. values ;
825+ return Array . isArray ( values ) && values . length
826+ ? values . map ( ( value ) => JSON . stringify ( value ) ) . join ( ' | ' )
827+ : 'enum' ;
828+ }
829+ case z . ZodFirstPartyTypeKind . ZodUnion : {
830+ const options = ( v as any ) ?. _def ?. options ;
831+ return Array . isArray ( options ) ? options . map ( inferField ) . join ( ' | ' ) : 'any' ;
832+ }
808833 case z . ZodFirstPartyTypeKind . ZodOptional : return `${ inferField ( ( v as any ) ?. _def ?. innerType ) } ?` ;
834+ case z . ZodFirstPartyTypeKind . ZodDefault : return `${ inferField ( ( v as any ) ?. _def ?. innerType ) } = default` ;
835+ case z . ZodFirstPartyTypeKind . ZodNullable : return `${ inferField ( ( v as any ) ?. _def ?. innerType ) } | null` ;
809836 default : return 'any' ;
810837 }
811838}
812839
813840function inferTopLevelKeys ( s : z . ZodTypeAny ) : string [ ] {
814841 try {
815- const def : any = ( s as any ) . _def ;
816- if ( def ?. typeName === z . ZodFirstPartyTypeKind . ZodObject && def . shape ) {
817- return Object . keys ( def . shape as Record < string , z . ZodTypeAny > ) ;
842+ const shape = getZodObjectShape ( s ) ;
843+ if ( shape ) {
844+ return Object . keys ( shape ) ;
818845 }
819846 } catch { }
820847 return [ ] ;
821848}
822849
823850function buildCoercedBySchema ( s : z . ZodTypeAny ) : any {
824851 try {
825- const def : any = ( s as any ) . _def ;
826- if ( def ?. typeName === z . ZodFirstPartyTypeKind . ZodObject && def . shape ) {
827- const shape = def . shape as Record < string , z . ZodTypeAny > ;
852+ const shape = getZodObjectShape ( s ) ;
853+ if ( shape ) {
828854 const out : any = { } ;
829855 for ( const [ k , v ] of Object . entries ( shape ) ) {
830856 const t = ( v as any ) ?. _def ?. typeName ;
831857 const optional = t === z . ZodFirstPartyTypeKind . ZodOptional ;
832- const inner = optional ? ( v as any ) ?. _def ?. innerType : v ;
858+ const defaulted = t === z . ZodFirstPartyTypeKind . ZodDefault ;
859+ const nullable = t === z . ZodFirstPartyTypeKind . ZodNullable ;
860+ const inner = optional || defaulted || nullable ? ( v as any ) ?. _def ?. innerType : v ;
833861 const typeName = ( inner as any ) ?. _def ?. typeName ;
834862 if ( optional ) continue ; // skip optional
835863 switch ( typeName ) {
@@ -853,6 +881,50 @@ function buildCoercedBySchema(s: z.ZodTypeAny): any {
853881 return { } ;
854882}
855883
884+ function getZodObjectShape ( s : z . ZodTypeAny ) : Record < string , z . ZodTypeAny > | null {
885+ try {
886+ const def : any = ( s as any ) ?. _def ;
887+ if ( def ?. typeName !== z . ZodFirstPartyTypeKind . ZodObject ) return null ;
888+ const rawShape = def . shape ;
889+ const shape = typeof rawShape === 'function' ? rawShape ( ) : rawShape ;
890+ if ( ! shape || typeof shape !== 'object' || Array . isArray ( shape ) ) return null ;
891+ return shape as Record < string , z . ZodTypeAny > ;
892+ } catch {
893+ return null ;
894+ }
895+ }
896+
897+ function buildStitchContext ( input : unknown ) : Record < string , unknown > {
898+ if ( ! input || typeof input !== 'object' ) return { } ;
899+ const value = input as any ;
900+ const context : Record < string , unknown > = { } ;
901+ const put = ( key : string , candidate : unknown ) => {
902+ if ( candidate !== undefined && candidate !== null && candidate !== '' ) {
903+ context [ key ] = candidate ;
904+ }
905+ } ;
906+
907+ if ( value . context && typeof value . context === 'object' && ! Array . isArray ( value . context ) ) {
908+ for ( const [ key , candidate ] of Object . entries ( value . context ) ) {
909+ put ( key , candidate ) ;
910+ }
911+ }
912+
913+ put ( 'read' , value . read ?? value . expressedRead ?? value . definitionOfRead ?? value . context ?. read ) ;
914+ put ( 'definitionOfRead' , value . definitionOfRead ?? value . context ?. definitionOfRead ) ;
915+ put ( 'repository' , value . repository ?? value . sourceRevision ?. repository ?? value . sourceRevision ?. repositoryFullName ?? value . context ?. repository ) ;
916+ put ( 'sourceRevision' , value . sourceRevision ?? value . context ?. sourceRevision ) ;
917+ put ( 'fitResult' , value . fitResult ?? value . depositorySearchResult ?? value . context ?. fitResult ) ;
918+ put ( 'assetPackIntent' , value . assetPackIntent ?? value . context ?. assetPackIntent ) ;
919+ put ( 'deliveryMechanism' , value . deliveryMechanism ?? value . context ?. deliveryMechanism ) ;
920+ if ( Array . isArray ( value . preparedContexts ) ) {
921+ put ( 'preparedContextCount' , value . preparedContexts . length ) ;
922+ put ( 'preparedContextSummaries' , value . preparedContexts . slice ( 0 , 3 ) . map ( summarize ) ) ;
923+ }
924+
925+ return context ;
926+ }
927+
856928// ==================== TOOL SUBSTEP ====================
857929
858930// ==================== TOOL & VALIDATION SUBSTEPS ====================
0 commit comments