@@ -22,7 +22,30 @@ export function generateToolsFromActionSpace(
2222 paramSchema . _def ?. typeName === 'ZodObject' &&
2323 'shape' in paramSchema
2424 ) {
25- schema = ( paramSchema as z . ZodObject < z . ZodRawShape > ) . shape ;
25+ const originalShape = ( paramSchema as z . ZodObject < z . ZodRawShape > ) . shape ;
26+
27+ // Deep clone and modify the shape to make locate.prompt optional
28+ schema = Object . fromEntries (
29+ Object . entries ( originalShape ) . map ( ( [ key , value ] ) => {
30+ // Check if this is a locate field (contains prompt field)
31+ if (
32+ value &&
33+ typeof value === 'object' &&
34+ '_def' in value &&
35+ ( value as any ) . _def ?. typeName === 'ZodObject' &&
36+ 'shape' in value
37+ ) {
38+ const fieldShape = ( value as any ) . shape ;
39+ if ( 'prompt' in fieldShape ) {
40+ // This is a locate field, make prompt optional
41+ const newFieldShape = { ...fieldShape } ;
42+ newFieldShape . prompt = fieldShape . prompt . optional ( ) ;
43+ return [ key , z . object ( newFieldShape ) . passthrough ( ) ] ;
44+ }
45+ }
46+ return [ key , value ] ;
47+ } ) ,
48+ ) ;
2649 } else {
2750 // Otherwise use it as-is
2851 schema = paramSchema as unknown as Record < string , z . ZodTypeAny > ;
@@ -34,44 +57,117 @@ export function generateToolsFromActionSpace(
3457 description : action . description || `Execute ${ action . name } action` ,
3558 schema,
3659 handler : async ( args : Record < string , unknown > ) => {
37- const agent = await getAgent ( ) ;
60+ try {
61+ const agent = await getAgent ( ) ;
3862
39- // Call the action through agent's aiAction method
40- // args already contains the unwrapped parameters (e.g., { locate: {...} })
41- if ( agent . aiAction ) {
42- await agent . aiAction ( `Use the action "${ action . name } "` , {
43- ...args ,
44- } ) ;
45- }
63+ // Call the action through agent's aiAction method
64+ // args already contains the unwrapped parameters (e.g., { locate: {...} })
65+ if ( agent . aiAction ) {
66+ // Convert args object to natural language description
67+ let argsDescription = '' ;
68+ try {
69+ argsDescription = Object . entries ( args )
70+ . map ( ( [ key , value ] ) => {
71+ if ( typeof value === 'object' && value !== null ) {
72+ try {
73+ return `${ key } : ${ JSON . stringify ( value ) } ` ;
74+ } catch {
75+ return `${ key } : [object]` ;
76+ }
77+ }
78+ return `${ key } : "${ value } "` ;
79+ } )
80+ . join ( ', ' ) ;
81+ } catch ( error : unknown ) {
82+ const errorMessage =
83+ error instanceof Error ? error . message : String ( error ) ;
84+ // Only log errors to stderr (not stdout which MCP uses)
85+ console . error ( 'Error serializing args:' , errorMessage ) ;
86+ argsDescription = `[args serialization failed: ${ errorMessage } ]` ;
87+ }
88+
89+ const instruction = argsDescription
90+ ? `Use the action "${ action . name } " with ${ argsDescription } `
91+ : `Use the action "${ action . name } "` ;
92+
93+ try {
94+ await agent . aiAction ( instruction ) ;
95+ } catch ( error : unknown ) {
96+ const errorMessage =
97+ error instanceof Error ? error . message : String ( error ) ;
98+ console . error (
99+ `Error executing action "${ action . name } ":` ,
100+ errorMessage ,
101+ ) ;
102+ return {
103+ content : [
104+ {
105+ type : 'text' ,
106+ text : `Failed to execute action "${ action . name } ": ${ errorMessage } ` ,
107+ } ,
108+ ] ,
109+ isError : true ,
110+ } ;
111+ }
112+ }
46113
47- // Return screenshot after action
48- const screenshot = await agent . page ?. screenshotBase64 ( ) ;
49- if ( ! screenshot ) {
114+ // Return screenshot after action
115+ try {
116+ const screenshot = await agent . page ?. screenshotBase64 ( ) ;
117+ if ( ! screenshot ) {
118+ return {
119+ content : [
120+ {
121+ type : 'text' ,
122+ text : `Action "${ action . name } " completed.` ,
123+ } ,
124+ ] ,
125+ } ;
126+ }
127+
128+ const { mimeType, body } = parseBase64 ( screenshot ) ;
129+
130+ return {
131+ content : [
132+ {
133+ type : 'text' ,
134+ text : `Action "${ action . name } " completed.` ,
135+ } ,
136+ {
137+ type : 'image' ,
138+ data : body ,
139+ mimeType,
140+ } ,
141+ ] ,
142+ } ;
143+ } catch ( error : unknown ) {
144+ const errorMessage =
145+ error instanceof Error ? error . message : String ( error ) ;
146+ console . error ( 'Error capturing screenshot:' , errorMessage ) ;
147+ // Action completed but screenshot failed - still return success
148+ return {
149+ content : [
150+ {
151+ type : 'text' ,
152+ text : `Action "${ action . name } " completed (screenshot unavailable: ${ errorMessage } )` ,
153+ } ,
154+ ] ,
155+ } ;
156+ }
157+ } catch ( error : unknown ) {
158+ const errorMessage =
159+ error instanceof Error ? error . message : String ( error ) ;
160+ console . error ( `Error in handler for "${ action . name } ":` , errorMessage ) ;
50161 return {
51162 content : [
52163 {
53164 type : 'text' ,
54- text : `Action "${ action . name } " completed. ` ,
165+ text : `Failed to get agent or execute action "${ action . name } ": ${ errorMessage } ` ,
55166 } ,
56167 ] ,
168+ isError : true ,
57169 } ;
58170 }
59-
60- const { mimeType, body } = parseBase64 ( screenshot ) ;
61-
62- return {
63- content : [
64- {
65- type : 'text' ,
66- text : `Action "${ action . name } " completed.` ,
67- } ,
68- {
69- type : 'image' ,
70- data : body ,
71- mimeType,
72- } ,
73- ] ,
74- } ;
75171 } ,
76172 autoDestroy : true ,
77173 } ;
@@ -91,18 +187,33 @@ export function generateCommonTools(
91187 description : 'Capture screenshot of current page/screen' ,
92188 schema : { } ,
93189 handler : async ( ) => {
94- const agent = await getAgent ( ) ;
95- const screenshot = await agent . page ?. screenshotBase64 ( ) ;
96- if ( ! screenshot ) {
190+ try {
191+ const agent = await getAgent ( ) ;
192+ const screenshot = await agent . page ?. screenshotBase64 ( ) ;
193+ if ( ! screenshot ) {
194+ return {
195+ content : [ { type : 'text' , text : 'Screenshot not available' } ] ,
196+ isError : true ,
197+ } ;
198+ }
199+ const { mimeType, body } = parseBase64 ( screenshot ) ;
200+ return {
201+ content : [ { type : 'image' , data : body , mimeType } ] ,
202+ } ;
203+ } catch ( error : unknown ) {
204+ const errorMessage =
205+ error instanceof Error ? error . message : String ( error ) ;
206+ console . error ( 'Error taking screenshot:' , errorMessage ) ;
97207 return {
98- content : [ { type : 'text' , text : 'Screenshot not available' } ] ,
208+ content : [
209+ {
210+ type : 'text' ,
211+ text : `Failed to capture screenshot: ${ errorMessage } ` ,
212+ } ,
213+ ] ,
99214 isError : true ,
100215 } ;
101216 }
102- const { mimeType, body } = parseBase64 ( screenshot ) ;
103- return {
104- content : [ { type : 'image' , data : body , mimeType } ] ,
105- } ;
106217 } ,
107218 autoDestroy : true ,
108219 } ,
@@ -115,21 +226,36 @@ export function generateCommonTools(
115226 checkIntervalMs : z . number ( ) . optional ( ) . default ( 3000 ) ,
116227 } ,
117228 handler : async ( args ) => {
118- const agent = await getAgent ( ) ;
119- const { assertion, timeoutMs, checkIntervalMs } = args as {
120- assertion : string ;
121- timeoutMs ?: number ;
122- checkIntervalMs ?: number ;
123- } ;
229+ try {
230+ const agent = await getAgent ( ) ;
231+ const { assertion, timeoutMs, checkIntervalMs } = args as {
232+ assertion : string ;
233+ timeoutMs ?: number ;
234+ checkIntervalMs ?: number ;
235+ } ;
124236
125- if ( agent . aiWaitFor ) {
126- await agent . aiWaitFor ( assertion , { timeoutMs, checkIntervalMs } ) ;
127- }
237+ if ( agent . aiWaitFor ) {
238+ await agent . aiWaitFor ( assertion , { timeoutMs, checkIntervalMs } ) ;
239+ }
128240
129- return {
130- content : [ { type : 'text' , text : `Condition met: "${ assertion } "` } ] ,
131- isError : false ,
132- } ;
241+ return {
242+ content : [ { type : 'text' , text : `Condition met: "${ assertion } "` } ] ,
243+ isError : false ,
244+ } ;
245+ } catch ( error : unknown ) {
246+ const errorMessage =
247+ error instanceof Error ? error . message : String ( error ) ;
248+ console . error ( 'Error in wait_for:' , errorMessage ) ;
249+ return {
250+ content : [
251+ {
252+ type : 'text' ,
253+ text : `Wait condition failed: ${ errorMessage } ` ,
254+ } ,
255+ ] ,
256+ isError : true ,
257+ } ;
258+ }
133259 } ,
134260 autoDestroy : true ,
135261 } ,
0 commit comments