@@ -23,40 +23,66 @@ export function getAgentShortName(agentType: AgentTemplateType): string {
2323 * Builds a flat input schema for an agent tool by combining prompt and params.
2424 * E.g., { prompt?: string, ...paramsFields }
2525 */
26- export function buildAgentFlatInputSchema ( agentTemplate : AgentTemplate ) : z . ZodType {
26+ export function buildAgentFlatInputSchema (
27+ agentTemplate : AgentTemplate ,
28+ ) : z . ZodType {
2729 const { inputSchema } = agentTemplate
28-
30+
2931 // Start with an empty object schema
3032 let schemaFields : Record < string , z . ZodType > = { }
31-
33+
3234 // Add prompt field if defined
3335 if ( inputSchema ?. prompt ) {
3436 schemaFields . prompt = inputSchema . prompt . optional ( )
3537 }
36-
38+
3739 // Merge params fields directly into the schema (flat structure)
3840 if ( inputSchema ?. params ) {
39- // Get the shape of the params schema if it's an object
40- const paramsJsonSchema = z . toJSONSchema ( inputSchema . params , { io : 'input' } )
41- if ( paramsJsonSchema . properties ) {
42- for ( const [ key , propSchema ] of Object . entries ( paramsJsonSchema . properties ) ) {
41+ // Try to get the shape from the params schema directly if it's a ZodObject
42+ // This preserves the full nested structure instead of converting to z.any()
43+ const paramsShape = getZodObjectShape ( inputSchema . params )
44+
45+ if ( paramsShape ) {
46+ // We have the original Zod shape, use it directly
47+ for ( const [ key , fieldSchema ] of Object . entries ( paramsShape ) ) {
4348 // Skip if we already have a prompt field
4449 if ( key === 'prompt' ) continue
45-
46- // Create a zod schema from the JSON schema property
47- const isRequired = ( paramsJsonSchema . required as string [ ] | undefined ) ?. includes ( key )
48- // Use z.any() with description since we can't perfectly reconstruct the original zod type
49- const fieldSchema = z . any ( ) . describe (
50- ( propSchema as any ) . description || `Parameter: ${ key } `
51- )
52- schemaFields [ key ] = isRequired ? fieldSchema : fieldSchema . optional ( )
50+ schemaFields [ key ] = fieldSchema as z . ZodType
5351 }
5452 }
5553 }
56-
57- return z . object ( schemaFields ) . describe (
58- agentTemplate . spawnerPrompt || `Spawn the ${ agentTemplate . displayName } agent`
59- )
54+
55+ return z
56+ . object ( schemaFields )
57+ . describe (
58+ agentTemplate . spawnerPrompt ||
59+ `Spawn the ${ agentTemplate . displayName } agent` ,
60+ )
61+ }
62+
63+ /**
64+ * Extracts the shape from a Zod schema if it's a ZodObject.
65+ * Handles wrapped types like ZodOptional, ZodNullable, ZodDefault, etc.
66+ */
67+ function getZodObjectShape (
68+ schema : z . ZodType ,
69+ ) : Record < string , z . ZodType > | null {
70+ // ZodObject has a public .shape property in Zod v4
71+ if (
72+ 'shape' in schema &&
73+ typeof schema . shape === 'object' &&
74+ schema . shape !== null
75+ ) {
76+ return schema . shape as Record < string , z . ZodType >
77+ }
78+
79+ // Handle wrapped types (optional, nullable, default, etc.) via internal def
80+ const def = ( schema as any ) ?. _zod ?. def
81+ if ( def ?. inner ) {
82+ return getZodObjectShape ( def . inner )
83+ }
84+
85+ return null
6086}
6187
6288/**
@@ -74,28 +100,30 @@ export async function buildAgentToolSet(
74100 > ,
75101) : Promise < ToolSet > {
76102 const { spawnableAgents, agentTemplates } = params
77-
103+
78104 const toolSet : ToolSet = { }
79-
105+
80106 for ( const agentType of spawnableAgents ) {
81107 const agentTemplate = await getAgentTemplate ( {
82108 ...params ,
83109 agentId : agentType ,
84110 localAgentTemplates : agentTemplates ,
85111 } )
86-
112+
87113 if ( ! agentTemplate ) continue
88-
114+
89115 const shortName = getAgentShortName ( agentType )
90116 const inputSchema = buildAgentFlatInputSchema ( agentTemplate )
91-
117+
92118 // Use the same structure as other tools in toolParams
93119 toolSet [ shortName ] = {
94- description : agentTemplate . spawnerPrompt || `Spawn the ${ agentTemplate . displayName } agent` ,
120+ description :
121+ agentTemplate . spawnerPrompt ||
122+ `Spawn the ${ agentTemplate . displayName } agent` ,
95123 inputSchema,
96124 }
97125 }
98-
126+
99127 return toolSet
100128}
101129
@@ -112,7 +140,7 @@ function buildSingleAgentDescription(
112140prompt: {"description": "A coding task to complete", "type": "string"}
113141params: None`
114142 }
115-
143+
116144 const { inputSchema } = agentTemplate
117145 const inputSchemaStr = inputSchema
118146 ? [
@@ -164,7 +192,9 @@ export async function buildFullSpawnableAgentsSpec(
164192 )
165193
166194 const agentsDescription = subAgentTypesAndTemplates
167- . map ( ( [ agentType , agentTemplate ] ) => buildSingleAgentDescription ( agentType , agentTemplate ) )
195+ . map ( ( [ agentType , agentTemplate ] ) =>
196+ buildSingleAgentDescription ( agentType , agentTemplate ) ,
197+ )
168198 . filter ( Boolean )
169199 . join ( '\n\n' )
170200
0 commit comments