@@ -81,6 +81,20 @@ Remember: Always discover and understand available tools before attempting to us
8181 return codeModeClient ;
8282 }
8383
84+ /**
85+ * Sanitizes an identifier to be a valid TypeScript identifier.
86+ * Replaces any non-alphanumeric character (except underscore) with underscore
87+ * and ensures the first character is not a number.
88+ *
89+ * @param name The name to sanitize
90+ * @returns Sanitized identifier
91+ */
92+ private sanitizeIdentifier ( name : string ) : string {
93+ return name
94+ . replace ( / [ ^ a - z A - Z 0 - 9 _ ] / g, '_' )
95+ . replace ( / ^ [ 0 - 9 ] / , '_$&' ) ;
96+ }
97+
8498 /**
8599 * Converts a Tool object into a TypeScript function interface string.
86100 * This generates the function signature that can be used in TypeScript code.
@@ -99,15 +113,16 @@ Remember: Always discover and understand available tools before attempting to us
99113
100114 if ( tool . name . includes ( '.' ) ) {
101115 const [ manualName , ...toolParts ] = tool . name . split ( '.' ) ;
102- const toolName = toolParts . join ( '_' ) ;
103- accessPattern = `${ manualName } .${ toolName } ` ;
116+ const sanitizedManualName = this . sanitizeIdentifier ( manualName ) ;
117+ const toolName = toolParts . map ( part => this . sanitizeIdentifier ( part ) ) . join ( '_' ) ;
118+ accessPattern = `${ sanitizedManualName } .${ toolName } ` ;
104119
105120 // Generate interfaces within namespace
106121 const inputInterfaceContent = this . jsonSchemaToObjectContent ( tool . inputs ) ;
107122 const outputInterfaceContent = this . jsonSchemaToObjectContent ( tool . outputs ) ;
108123
109124 interfaceContent = `
110- namespace ${ manualName } {
125+ namespace ${ sanitizedManualName } {
111126 interface ${ toolName } Input {
112127${ inputInterfaceContent }
113128 }
@@ -118,9 +133,10 @@ ${outputInterfaceContent}
118133}` ;
119134 } else {
120135 // No manual namespace, generate flat interfaces
121- accessPattern = tool . name ;
122- const inputType = this . jsonSchemaToTypeScript ( tool . inputs , `${ tool . name } Input` ) ;
123- const outputType = this . jsonSchemaToTypeScript ( tool . outputs , `${ tool . name } Output` ) ;
136+ const sanitizedToolName = this . sanitizeIdentifier ( tool . name ) ;
137+ accessPattern = sanitizedToolName ;
138+ const inputType = this . jsonSchemaToTypeScript ( tool . inputs , `${ sanitizedToolName } Input` ) ;
139+ const outputType = this . jsonSchemaToTypeScript ( tool . outputs , `${ sanitizedToolName } Output` ) ;
124140 interfaceContent = `${ inputType } \n\n${ outputType } ` ;
125141 }
126142 const interfaceString = `
@@ -180,7 +196,7 @@ ${interfaces.join('\n\n')}`;
180196 const result = await this . runWithTimeout ( wrappedCode , vmContext , timeout ) ;
181197 return { result, logs } ;
182198 } catch ( error ) {
183- throw new Error ( ` Code execution failed: ${ error instanceof Error ? error . message : String ( error ) } `) ;
199+ return { result : null , logs : [ ... logs , `[ERROR] Code execution failed: ${ error instanceof Error ? error . message : String ( error ) } `] } ;
184200 }
185201 }
186202
@@ -276,15 +292,16 @@ ${interfaces.join('\n\n')}`;
276292 for ( const tool of tools ) {
277293 if ( tool . name . includes ( '.' ) ) {
278294 const [ manualName , ...toolParts ] = tool . name . split ( '.' ) ;
279- const toolName = toolParts . join ( '_' ) ; // Join remaining parts with underscore
295+ const sanitizedManualName = this . sanitizeIdentifier ( manualName ) ;
296+ const toolName = toolParts . map ( part => this . sanitizeIdentifier ( part ) ) . join ( '_' ) ;
280297
281298 // Create manual namespace object if it doesn't exist
282- if ( ! context [ manualName ] ) {
283- context [ manualName ] = { } ;
299+ if ( ! context [ sanitizedManualName ] ) {
300+ context [ sanitizedManualName ] = { } ;
284301 }
285302
286303 // Add the tool function to the manual namespace
287- context [ manualName ] [ toolName ] = async ( args : Record < string , any > ) => {
304+ context [ sanitizedManualName ] [ toolName ] = async ( args : Record < string , any > ) => {
288305 try {
289306 return await this . callTool ( tool . name , args ) ;
290307 } catch ( error ) {
@@ -293,7 +310,8 @@ ${interfaces.join('\n\n')}`;
293310 } ;
294311 } else {
295312 // If no dot, add directly to root context (no manual name)
296- context [ tool . name ] = async ( args : Record < string , any > ) => {
313+ const sanitizedToolName = this . sanitizeIdentifier ( tool . name ) ;
314+ context [ sanitizedToolName ] = async ( args : Record < string , any > ) => {
297315 try {
298316 return await this . callTool ( tool . name , args ) ;
299317 } catch ( error ) {
0 commit comments