@@ -300,13 +300,43 @@ async function loadTriggerRegistry(): Promise<Record<string, RegistryTrigger>> {
300300 return module . TRIGGER_REGISTRY as Record < string , RegistryTrigger >
301301}
302302
303+ interface GeneratedToolParam {
304+ type ?: string
305+ required ?: boolean
306+ description ?: string
307+ }
308+
309+ interface GeneratedToolMetadataEntry {
310+ name ?: string
311+ description ?: string
312+ params ?: Record < string , GeneratedToolParam >
313+ }
314+
315+ /** Serializable tool metadata generated from the executable registry and checked by CI. */
316+ let generatedToolMetadata : Record < string , GeneratedToolMetadataEntry > | null = null
317+
318+ async function loadGeneratedToolMetadata ( ) : Promise < Record < string , GeneratedToolMetadataEntry > > {
319+ if ( generatedToolMetadata ) return generatedToolMetadata
320+ const module = await import ( path . join ( rootDir , 'apps/sim/tools/generated/tool-metadata.ts' ) )
321+ generatedToolMetadata = module . default as Record < string , GeneratedToolMetadataEntry >
322+ return generatedToolMetadata
323+ }
324+
325+ let generatedToolOutputs : Record < string , Record < string , any > > | null = null
326+
327+ async function loadGeneratedToolOutputs ( ) : Promise < Record < string , Record < string , any > > > {
328+ if ( generatedToolOutputs ) return generatedToolOutputs
329+ const module = await import ( path . join ( rootDir , 'apps/sim/tools/generated/tool-outputs.ts' ) )
330+ generatedToolOutputs = module . default as Record < string , Record < string , any > >
331+ return generatedToolOutputs
332+ }
333+
303334/** Human-facing tool names, keyed by tool id. Kept in sync with the registry by CI. */
304335let toolDisplayNames : Map < string , string > | null = null
305336
306337async function loadToolDisplayNames ( ) : Promise < Map < string , string > > {
307338 if ( toolDisplayNames ) return toolDisplayNames
308- const module = await import ( path . join ( rootDir , 'apps/sim/tools/generated/tool-metadata.ts' ) )
309- const metadata = module . default as Record < string , { name ?: string } >
339+ const metadata = await loadGeneratedToolMetadata ( )
310340 toolDisplayNames = new Map (
311341 Object . entries ( metadata ) . flatMap ( ( [ id , entry ] ) =>
312342 entry ?. name ? [ [ id , entry . name ] as const ] : [ ]
@@ -2011,7 +2041,7 @@ function extractOutputsFromToolContent(content: string, toolPrefix: string): Rec
20112041 * Returns null when the tool declares its own config, which is the common case.
20122042 */
20132043function resolveFactorySource ( fileContent : string , toolFilePath : string , rootDir : string ) : string {
2014- const factoryCall = fileContent . match ( / = \s * ( c r e a t e \w + ) \s * \( \s * \{ / )
2044+ const factoryCall = fileContent . match ( / = \s * ( c r e a t e \w + ) (?: \s * < [ ^ > ] + > ) ? \s * \( \s * \{ / )
20152045 if ( ! factoryCall ) return ''
20162046
20172047 const factoryName = factoryCall [ 1 ]
@@ -2919,11 +2949,48 @@ async function getToolInfo(toolName: string): Promise<{
29192949 return null
29202950 }
29212951
2922- return extractToolInfo (
2923- toolName ,
2924- toolFileContent ,
2925- resolveFactorySource ( toolFileContent , foundFile , rootDir )
2926- )
2952+ const factorySource = resolveFactorySource ( toolFileContent , foundFile , rootDir )
2953+ const extractedInfo = extractToolInfo ( toolName , toolFileContent , factorySource )
2954+
2955+ const delegatesParams = / \. \. \. o p t i o n s \. p a r a m s \b / . test ( factorySource )
2956+ const delegatesOutputs = / \b o p t i o n s \. o u t p u t s \b / . test ( factorySource )
2957+ if ( ! factorySource || ( ! delegatesParams && ! delegatesOutputs ) ) return extractedInfo
2958+
2959+ // Factory-built tools often compose params and outputs through imported constants and
2960+ // spreads. The source parser intentionally stays lightweight, so fall back to the
2961+ // executable registry's generated metadata when it exposes fields the parser missed.
2962+ const [ metadata , outputs ] = await Promise . all ( [
2963+ loadGeneratedToolMetadata ( ) ,
2964+ loadGeneratedToolOutputs ( ) ,
2965+ ] )
2966+ const generatedEntry = metadata [ toolName ]
2967+ if ( ! generatedEntry ) return extractedInfo
2968+
2969+ const generatedParams = Object . entries ( generatedEntry . params ?? { } )
2970+ . filter ( ( [ name ] ) => name !== 'accessToken' && name !== 'params' && name !== 'tools' )
2971+ . map ( ( [ name , param ] ) => ( {
2972+ name,
2973+ type : typeof param . type === 'string' ? param . type : 'string' ,
2974+ required : param . required === true ,
2975+ description : param . description ?? 'No description' ,
2976+ } ) )
2977+ const extractedParams = extractedInfo ?. params ?? [ ]
2978+ const extractedOutputs = extractedInfo ?. outputs ?? { }
2979+ const generatedOutputs = outputs [ toolName ] ?? { }
2980+
2981+ return {
2982+ description :
2983+ extractedInfo ?. description ?? generatedEntry . description ?? 'No description available' ,
2984+ params :
2985+ delegatesParams && generatedParams . length > extractedParams . length
2986+ ? generatedParams
2987+ : extractedParams ,
2988+ outputs :
2989+ delegatesOutputs &&
2990+ Object . keys ( generatedOutputs ) . length > Object . keys ( extractedOutputs ) . length
2991+ ? generatedOutputs
2992+ : extractedOutputs ,
2993+ }
29272994 } catch ( error ) {
29282995 console . error ( `Error getting info for tool ${ toolName } :` , error )
29292996 return null
0 commit comments