11import { BaseTool } from "../tools/BaseTool.js" ;
2- import { fileURLToPath } from "url" ;
32import { dirname , join } from "path" ;
43import { promises as fs } from "fs" ;
4+ import { statSync } from "fs" ;
5+ import { fileURLToPath } from "url" ;
56import { cwd } from "process" ;
7+ import { logger } from "./Logger.js" ;
68
79export interface ToolLoaderOptions {
810 toolsDir ?: string ;
@@ -15,75 +17,137 @@ export class ToolLoader {
1517
1618 constructor ( options : ToolLoaderOptions = { } ) {
1719 this . exclude = options . exclude || [ "BaseTool.js" , "*.test.js" , "*.spec.js" ] ;
18- this . toolsDir = options . toolsDir || this . findDefaultToolsDir ( ) ;
20+ this . toolsDir = this . resolveToolsDir ( options . toolsDir ) ;
21+ logger . debug ( `Initialized ToolLoader with directory: ${ this . toolsDir } ` ) ;
1922 }
2023
21- private findDefaultToolsDir ( ) : string {
22- // Use current working directory + dist/tools as default
23- return join ( cwd ( ) , "dist" , "tools" ) ;
24+ private resolveToolsDir ( toolsDir ?: string ) : string {
25+ if ( toolsDir ) {
26+ logger . debug ( `Using provided tools directory: ${ toolsDir } ` ) ;
27+ return toolsDir ;
28+ }
29+
30+ const currentFilePath = fileURLToPath ( import . meta. url ) ;
31+ const currentDir = dirname ( currentFilePath ) ;
32+ const possiblePaths = [
33+ join ( currentDir , ".." , "tools" ) ,
34+ join ( currentDir , ".." , ".." , "tools" ) ,
35+ join ( cwd ( ) , "dist" , "tools" ) ,
36+ join ( cwd ( ) , "build" , "tools" ) ,
37+ join ( cwd ( ) , "tools" ) ,
38+ ] ;
39+
40+ logger . debug (
41+ `Searching for tools in possible paths:\n${ possiblePaths . join ( "\n" ) } `
42+ ) ;
43+
44+ for ( const path of possiblePaths ) {
45+ try {
46+ if ( statSync ( path ) . isDirectory ( ) ) {
47+ logger . debug ( `Found existing tools directory: ${ path } ` ) ;
48+ return path ;
49+ }
50+ } catch ( e ) {
51+ logger . debug ( `Path ${ path } not accessible` ) ;
52+ }
53+ }
54+
55+ const fallbackPath = join ( cwd ( ) , "dist" , "tools" ) ;
56+ logger . debug (
57+ `No valid tools directory found, falling back to: ${ fallbackPath } `
58+ ) ;
59+ return fallbackPath ;
2460 }
2561
2662 private isToolFile ( file : string ) : boolean {
2763 if ( ! file . endsWith ( ".js" ) ) return false ;
28- return ! this . exclude . some ( ( pattern ) => {
64+ const isExcluded = this . exclude . some ( ( pattern ) => {
2965 if ( pattern . includes ( "*" ) ) {
3066 const regex = new RegExp ( pattern . replace ( "*" , ".*" ) ) ;
3167 return regex . test ( file ) ;
3268 }
3369 return file === pattern ;
3470 } ) ;
71+
72+ logger . debug (
73+ `Checking file ${ file } : ${ isExcluded ? "excluded" : "included" } `
74+ ) ;
75+ return ! isExcluded ;
3576 }
3677
3778 private validateTool ( tool : any ) : tool is BaseTool {
38- return Boolean (
79+ const isValid = Boolean (
3980 tool &&
4081 typeof tool . name === "string" &&
4182 tool . toolDefinition &&
4283 typeof tool . toolCall === "function"
4384 ) ;
85+
86+ if ( isValid ) {
87+ logger . debug ( `Validated tool: ${ tool . name } ` ) ;
88+ } else {
89+ logger . warn ( `Invalid tool found: missing required properties` ) ;
90+ }
91+
92+ return isValid ;
4493 }
4594
4695 async loadTools ( ) : Promise < BaseTool [ ] > {
4796 try {
48- console . log ( `Loading tools from directory: ${ this . toolsDir } ` ) ;
97+ logger . debug ( `Attempting to load tools from: ${ this . toolsDir } ` ) ;
98+
99+ let stats ;
100+ try {
101+ stats = await fs . stat ( this . toolsDir ) ;
102+ } catch ( error ) {
103+ logger . error ( `Error accessing tools directory: ${ error } ` ) ;
104+ return [ ] ;
105+ }
106+
107+ if ( ! stats . isDirectory ( ) ) {
108+ logger . error ( `Path is not a directory: ${ this . toolsDir } ` ) ;
109+ return [ ] ;
110+ }
111+
49112 const files = await fs . readdir ( this . toolsDir ) ;
50- console . log ( `Found files: ${ files . join ( ", " ) } ` ) ;
51-
52- const toolPromises = files
53- . filter ( ( file ) => this . isToolFile ( file ) )
54- . map ( async ( file ) => {
55- try {
56- const fullPath = join ( this . toolsDir , file ) ;
57- console . log ( `Loading tool from: ${ fullPath } ` ) ;
58- const { default : ToolClass } = await import ( `file://${ fullPath } ` ) ;
59-
60- if ( ! ToolClass ) {
61- console . log ( `No default export found in ${ file } ` ) ;
62- return null ;
63- }
64-
65- const tool = new ToolClass ( ) ;
66- if ( this . validateTool ( tool ) ) {
67- console . log ( `Successfully loaded tool: ${ tool . name } ` ) ;
68- return tool ;
69- }
70- console . log ( `Invalid tool found in ${ file } ` ) ;
71- return null ;
72- } catch ( error ) {
73- console . error ( `Error loading tool ${ file } :` , error ) ;
74- return null ;
113+ logger . debug ( `Found files in directory: ${ files . join ( ", " ) } ` ) ;
114+
115+ const tools : BaseTool [ ] = [ ] ;
116+
117+ for ( const file of files ) {
118+ if ( ! this . isToolFile ( file ) ) {
119+ continue ;
120+ }
121+
122+ try {
123+ const fullPath = join ( this . toolsDir , file ) ;
124+ logger . debug ( `Attempting to load tool from: ${ fullPath } ` ) ;
125+
126+ const importPath = `file://${ fullPath } ` ;
127+ const { default : ToolClass } = await import ( importPath ) ;
128+
129+ if ( ! ToolClass ) {
130+ logger . warn ( `No default export found in ${ file } ` ) ;
131+ continue ;
75132 }
76- } ) ;
77133
78- const tools = ( await Promise . all ( toolPromises ) ) . filter (
79- Boolean
80- ) as BaseTool [ ] ;
81- console . log (
82- `Loaded ${ tools . length } tools: ${ tools . map ( ( t ) => t . name ) . join ( ", " ) } `
134+ const tool = new ToolClass ( ) ;
135+ if ( this . validateTool ( tool ) ) {
136+ tools . push ( tool ) ;
137+ }
138+ } catch ( error ) {
139+ logger . error ( `Error loading tool ${ file } : ${ error } ` ) ;
140+ }
141+ }
142+
143+ logger . debug (
144+ `Successfully loaded ${ tools . length } tools: ${ tools
145+ . map ( ( t ) => t . name )
146+ . join ( ", " ) } `
83147 ) ;
84148 return tools ;
85149 } catch ( error ) {
86- console . error ( `Failed to load tools from ${ this . toolsDir } :` , error ) ;
150+ logger . error ( `Failed to load tools: ${ error } ` ) ;
87151 return [ ] ;
88152 }
89153 }
0 commit comments