1- import { TOOL_METADATA_KEY } from '../decorators/tool.decorator' ;
2- import { IToolRegistrationContext , ToolMetadata } from '../types' ;
3- import { isFunction } from './guards' ;
41import { join } from 'path' ;
52import { readdir , writeFile } from 'fs/promises' ;
6- import { validateToolMetadata } from './validate-tool-metadata' ;
7- import { toZodRawShape } from './mapping' ;
3+
4+ import {
5+ ToolFactory ,
6+ ToolMetadata ,
7+ ToolMetadataProvider ,
8+ ToolRegistrar ,
9+ ToolValidator ,
10+ } from '../types' ;
811
912interface ToolManifestEntry {
1013 name : string ;
@@ -17,45 +20,34 @@ export class ToolLoader {
1720
1821 constructor (
1922 private readonly directory : string ,
20- private readonly context : IToolRegistrationContext
23+ private readonly factory : ToolFactory ,
24+ private readonly registrar : ToolRegistrar ,
25+ private readonly validator : ToolValidator ,
26+ private readonly metadataProvider : ToolMetadataProvider
2127 ) { }
2228
23- async registerAllTools ( ) : Promise < void > {
24- const toolFiles = await this . findToolFiles ( ) ;
25-
26- for ( const file of toolFiles ) {
27- const loadedClass = await this . loadToolClass ( join ( this . directory , file ) ) ;
28-
29- if ( ! loadedClass ) {
30- this . logInvalidTool ( file ) ;
29+ async registerAll ( ) : Promise < void > {
30+ const files = await this . findToolFiles ( ) ;
31+ for ( const file of files ) {
32+ const toolPath = join ( this . directory , file ) ;
33+ const toolClass = await this . factory . loadTool ( toolPath ) ;
34+ if ( ! toolClass ) {
35+ this . warnInvalid ( file ) ;
3136 continue ;
3237 }
3338
34- const metadata = Reflect . getMetadata (
35- TOOL_METADATA_KEY ,
36- loadedClass
37- ) as ToolMetadata ;
39+ const metadata = this . metadataProvider . getMetadata ( toolClass ) ;
3840 if ( ! metadata ) {
39- this . logInvalidTool ( file ) ;
41+ this . warnInvalid ( file ) ;
4042 continue ;
4143 }
4244
43- validateToolMetadata ( metadata , file ) ;
44-
45- this . registerTool ( loadedClass , metadata ) ;
45+ this . validator . validate ( metadata , file ) ;
46+ this . registrar . register ( toolClass , metadata ) ;
4647 this . addToManifest ( metadata ) ;
4748 }
4849 }
4950
50- private addToManifest ( {
51- name,
52- paramsSchema,
53- description,
54- } : ToolMetadata ) : void {
55- const params = paramsSchema ? Object . keys ( paramsSchema ) : [ ] ;
56- this . manifest . push ( { name, description, params } ) ;
57- }
58-
5951 async exportManifest ( filePath : string ) : Promise < void > {
6052 await writeFile ( filePath , JSON . stringify ( this . manifest , null , 2 ) , 'utf-8' ) ;
6153 }
@@ -67,33 +59,16 @@ export class ToolLoader {
6759 ) ;
6860 }
6961
70- private async loadToolClass ( filePath : string ) : Promise < any > {
71- try {
72- const module = await import ( filePath ) ;
73- const loadedClass =
74- module . default ?? Object . values ( module ) . find ( isFunction ) ;
75- return loadedClass ;
76- } catch ( error ) {
77- console . error ( `Failed to load tool from ${ filePath } ` , error ) ;
78- return undefined ;
79- }
80- }
81-
82- private registerTool (
83- loadedClass : any ,
84- { name, description, paramsSchema } : ToolMetadata
85- ) {
86- this . context . server . tool (
87- name ,
88- description ,
89- toZodRawShape ( paramsSchema ) ,
90- async ( args , extra ) => {
91- return loadedClass . execute ( args , { ...this . context , extra } ) ;
92- }
93- ) ;
62+ private addToManifest ( {
63+ name,
64+ description,
65+ paramsSchema,
66+ } : ToolMetadata ) : void {
67+ const params = paramsSchema ? Object . keys ( paramsSchema ) : [ ] ;
68+ this . manifest . push ( { name, description, params } ) ;
9469 }
9570
96- private logInvalidTool ( file : string ) : void {
71+ private warnInvalid ( file : string ) : void {
9772 console . warn ( `No valid tool class with @Tool decorator found in ${ file } ` ) ;
9873 }
9974}
0 commit comments