@@ -22,7 +22,31 @@ 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 > )
26+ . shape ;
27+
28+ // Deep clone and modify the shape to make locate.prompt optional
29+ schema = Object . fromEntries (
30+ Object . entries ( originalShape ) . map ( ( [ key , value ] ) => {
31+ // Check if this is a locate field (contains prompt field)
32+ if (
33+ value &&
34+ typeof value === 'object' &&
35+ '_def' in value &&
36+ ( value as any ) . _def ?. typeName === 'ZodObject' &&
37+ 'shape' in value
38+ ) {
39+ const fieldShape = ( value as any ) . shape ;
40+ if ( 'prompt' in fieldShape ) {
41+ // This is a locate field, make prompt optional
42+ const newFieldShape = { ...fieldShape } ;
43+ newFieldShape . prompt = fieldShape . prompt . optional ( ) ;
44+ return [ key , z . object ( newFieldShape ) . passthrough ( ) ] ;
45+ }
46+ }
47+ return [ key , value ] ;
48+ } ) ,
49+ ) ;
2650 } else {
2751 // Otherwise use it as-is
2852 schema = paramSchema as unknown as Record < string , z . ZodTypeAny > ;
@@ -34,44 +58,117 @@ export function generateToolsFromActionSpace(
3458 description : action . description || `Execute ${ action . name } action` ,
3559 schema,
3660 handler : async ( args : Record < string , unknown > ) => {
37- const agent = await getAgent ( ) ;
61+ try {
62+ const agent = await getAgent ( ) ;
3863
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- }
64+ // Call the action through agent's aiAction method
65+ // args already contains the unwrapped parameters (e.g., { locate: {...} })
66+ if ( agent . aiAction ) {
67+ // Convert args object to natural language description
68+ let argsDescription = '' ;
69+ try {
70+ argsDescription = Object . entries ( args )
71+ . map ( ( [ key , value ] ) => {
72+ if ( typeof value === 'object' && value !== null ) {
73+ try {
74+ return `${ key } : ${ JSON . stringify ( value ) } ` ;
75+ } catch {
76+ return `${ key } : [object]` ;
77+ }
78+ }
79+ return `${ key } : "${ value } "` ;
80+ } )
81+ . join ( ', ' ) ;
82+ } catch ( error : unknown ) {
83+ const errorMessage =
84+ error instanceof Error ? error . message : String ( error ) ;
85+ // Only log errors to stderr (not stdout which MCP uses)
86+ console . error ( 'Error serializing args:' , errorMessage ) ;
87+ argsDescription = `[args serialization failed: ${ errorMessage } ]` ;
88+ }
89+
90+ const instruction = argsDescription
91+ ? `Use the action "${ action . name } " with ${ argsDescription } `
92+ : `Use the action "${ action . name } "` ;
93+
94+ try {
95+ await agent . aiAction ( instruction ) ;
96+ } catch ( error : unknown ) {
97+ const errorMessage =
98+ error instanceof Error ? error . message : String ( error ) ;
99+ console . error (
100+ `Error executing action "${ action . name } ":` ,
101+ errorMessage ,
102+ ) ;
103+ return {
104+ content : [
105+ {
106+ type : 'text' ,
107+ text : `Failed to execute action "${ action . name } ": ${ errorMessage } ` ,
108+ } ,
109+ ] ,
110+ isError : true ,
111+ } ;
112+ }
113+ }
46114
47- // Return screenshot after action
48- const screenshot = await agent . page ?. screenshotBase64 ( ) ;
49- if ( ! screenshot ) {
115+ // Return screenshot after action
116+ try {
117+ const screenshot = await agent . page ?. screenshotBase64 ( ) ;
118+ if ( ! screenshot ) {
119+ return {
120+ content : [
121+ {
122+ type : 'text' ,
123+ text : `Action "${ action . name } " completed.` ,
124+ } ,
125+ ] ,
126+ } ;
127+ }
128+
129+ const { mimeType, body } = parseBase64 ( screenshot ) ;
130+
131+ return {
132+ content : [
133+ {
134+ type : 'text' ,
135+ text : `Action "${ action . name } " completed.` ,
136+ } ,
137+ {
138+ type : 'image' ,
139+ data : body ,
140+ mimeType,
141+ } ,
142+ ] ,
143+ } ;
144+ } catch ( error : unknown ) {
145+ const errorMessage =
146+ error instanceof Error ? error . message : String ( error ) ;
147+ console . error ( 'Error capturing screenshot:' , errorMessage ) ;
148+ // Action completed but screenshot failed - still return success
149+ return {
150+ content : [
151+ {
152+ type : 'text' ,
153+ text : `Action "${ action . name } " completed (screenshot unavailable: ${ errorMessage } )` ,
154+ } ,
155+ ] ,
156+ } ;
157+ }
158+ } catch ( error : unknown ) {
159+ const errorMessage =
160+ error instanceof Error ? error . message : String ( error ) ;
161+ console . error ( `Error in handler for "${ action . name } ":` , errorMessage ) ;
50162 return {
51163 content : [
52164 {
53165 type : 'text' ,
54- text : `Action "${ action . name } " completed. ` ,
166+ text : `Failed to get agent or execute action "${ action . name } ": ${ errorMessage } ` ,
55167 } ,
56168 ] ,
169+ isError : true ,
57170 } ;
58171 }
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- } ;
75172 } ,
76173 autoDestroy : true ,
77174 } ;
@@ -91,18 +188,33 @@ export function generateCommonTools(
91188 description : 'Capture screenshot of current page/screen' ,
92189 schema : { } ,
93190 handler : async ( ) => {
94- const agent = await getAgent ( ) ;
95- const screenshot = await agent . page ?. screenshotBase64 ( ) ;
96- if ( ! screenshot ) {
191+ try {
192+ const agent = await getAgent ( ) ;
193+ const screenshot = await agent . page ?. screenshotBase64 ( ) ;
194+ if ( ! screenshot ) {
195+ return {
196+ content : [ { type : 'text' , text : 'Screenshot not available' } ] ,
197+ isError : true ,
198+ } ;
199+ }
200+ const { mimeType, body } = parseBase64 ( screenshot ) ;
201+ return {
202+ content : [ { type : 'image' , data : body , mimeType } ] ,
203+ } ;
204+ } catch ( error : unknown ) {
205+ const errorMessage =
206+ error instanceof Error ? error . message : String ( error ) ;
207+ console . error ( 'Error taking screenshot:' , errorMessage ) ;
97208 return {
98- content : [ { type : 'text' , text : 'Screenshot not available' } ] ,
209+ content : [
210+ {
211+ type : 'text' ,
212+ text : `Failed to capture screenshot: ${ errorMessage } ` ,
213+ } ,
214+ ] ,
99215 isError : true ,
100216 } ;
101217 }
102- const { mimeType, body } = parseBase64 ( screenshot ) ;
103- return {
104- content : [ { type : 'image' , data : body , mimeType } ] ,
105- } ;
106218 } ,
107219 autoDestroy : true ,
108220 } ,
@@ -115,21 +227,36 @@ export function generateCommonTools(
115227 checkIntervalMs : z . number ( ) . optional ( ) . default ( 3000 ) ,
116228 } ,
117229 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- } ;
230+ try {
231+ const agent = await getAgent ( ) ;
232+ const { assertion, timeoutMs, checkIntervalMs } = args as {
233+ assertion : string ;
234+ timeoutMs ?: number ;
235+ checkIntervalMs ?: number ;
236+ } ;
124237
125- if ( agent . aiWaitFor ) {
126- await agent . aiWaitFor ( assertion , { timeoutMs, checkIntervalMs } ) ;
127- }
238+ if ( agent . aiWaitFor ) {
239+ await agent . aiWaitFor ( assertion , { timeoutMs, checkIntervalMs } ) ;
240+ }
128241
129- return {
130- content : [ { type : 'text' , text : `Condition met: "${ assertion } "` } ] ,
131- isError : false ,
132- } ;
242+ return {
243+ content : [ { type : 'text' , text : `Condition met: "${ assertion } "` } ] ,
244+ isError : false ,
245+ } ;
246+ } catch ( error : unknown ) {
247+ const errorMessage =
248+ error instanceof Error ? error . message : String ( error ) ;
249+ console . error ( 'Error in wait_for:' , errorMessage ) ;
250+ return {
251+ content : [
252+ {
253+ type : 'text' ,
254+ text : `Wait condition failed: ${ errorMessage } ` ,
255+ } ,
256+ ] ,
257+ isError : true ,
258+ } ;
259+ }
133260 } ,
134261 autoDestroy : true ,
135262 } ,
0 commit comments