1414WS_URL = "ws://127.0.0.1:8000/ws/test"
1515DEFAULT_AGENT_DIR = Path (__file__ ).parent .parent
1616DEFAULT_TESTS_DIR = DEFAULT_AGENT_DIR / "tests"
17+ DEFAULT_AGENT_PATTERN = "libe_agent*.py"
1718
1819ws_conn = None
1920message_queue = Queue ()
2324uvicorn_process = None
2425
2526
26- def scan_agent_scripts (agent_dir_path ):
27+ def scan_agent_scripts (agent_dir_path , pattern = None ):
28+ if pattern is None :
29+ pattern = DEFAULT_AGENT_PATTERN
2730 try :
2831 if not agent_dir_path :
2932 return []
@@ -35,7 +38,7 @@ def scan_agent_scripts(agent_dir_path):
3538 print (f"Warning: Agent path is not a directory: { agent_dir_path } " )
3639 return []
3740 exclude = {"app.py" , "gradio_chat.py" , "__init__.py" }
38- scripts = [f .name for f in sorted (agent_dir .glob ("*.py" )) if f .name not in exclude ]
41+ scripts = [f .name for f in sorted (agent_dir .glob (pattern )) if f .name not in exclude ]
3942 return scripts
4043 except Exception as e :
4144 print (f"Error scanning agent scripts: { e } " )
@@ -127,16 +130,18 @@ async def _run():
127130
128131 agent_dir_state = gr .State (value = str (DEFAULT_AGENT_DIR ))
129132 scripts_dir_state = gr .State (value = str (DEFAULT_TESTS_DIR ))
133+ agent_pattern_state = gr .State (value = DEFAULT_AGENT_PATTERN )
130134 settings_visible = gr .State (value = False )
131135
132136 with gr .Column (visible = False ) as settings_modal :
133137 with gr .Column (elem_classes = "modal-content" ):
134138 gr .Markdown ("### Settings" )
135139 agent_dir_input = gr .Textbox (label = "Agent Directory" , value = str (DEFAULT_AGENT_DIR ))
136- scripts_dir_input = gr .Textbox (label = "Scripts Directory" , value = str (DEFAULT_TESTS_DIR ))
140+ scripts_dir_input = gr .Textbox (label = "Scripts Parent Directory" , value = str (DEFAULT_TESTS_DIR ))
141+ agent_pattern_input = gr .Textbox (label = "Agent Script Pattern" , value = DEFAULT_AGENT_PATTERN )
137142 with gr .Row ():
138- apply_settings_btn = gr .Button ("Apply" , variant = "primary" , scale = 1 )
139- close_settings_btn = gr .Button ("Close" , scale = 1 )
143+ apply_settings_btn = gr .Button ("Apply" , variant = "primary" , size = "sm" )
144+ close_settings_btn = gr .Button ("Close" , size = "sm" )
140145
141146 with gr .Row ():
142147 agent_dropdown = gr .Dropdown (
@@ -148,8 +153,8 @@ async def _run():
148153 label = "Scripts Directory" , choices = _init_tests ,
149154 value = None , allow_custom_value = True , scale = 2
150155 )
151- run_btn = gr .Button ("Run" , variant = "primary" , scale = 1 )
152- reset_btn = gr .Button ("Reset" , variant = "stop" , scale = 1 )
156+ run_btn = gr .Button ("Run" , variant = "primary" )
157+ reset_btn = gr .Button ("Reset" , variant = "stop" )
153158
154159 scripts_dict = gr .State (value = {})
155160
@@ -167,20 +172,25 @@ async def _run():
167172
168173 def process_messages (scripts_state ):
169174 import time
170- scripts = scripts_state if scripts_state else {}
171- script_names = list (scripts .keys ())
172- selected_script = script_names [0 ] if script_names else None
173- logs = ""
174- done = False
175- task_started = False
176- start_time = time .time ()
177- timeout = 300
175+ try :
176+ scripts = scripts_state if scripts_state else {}
177+ script_names = list (scripts .keys ())
178+ selected_script = script_names [0 ] if script_names else None
179+ logs = ""
180+ done = False
181+ task_started = False
182+ start_time = time .time ()
183+ timeout = 300
178184
179- while not output_queue .empty ():
180- try :
181- output_queue .get_nowait ()
182- except Empty :
183- break
185+ while not output_queue .empty ():
186+ try :
187+ output_queue .get_nowait ()
188+ except Empty :
189+ break
190+ except Exception as e :
191+ error_msg = f"ERROR in process_messages: { str (e )} "
192+ print (error_msg )
193+ return error_msg , {}, gr .update (choices = [], value = None ), ""
184194
185195 wait_start = time .time ()
186196 while not task_started and (time .time () - wait_start ) < 10 :
@@ -193,11 +203,21 @@ def process_messages(scripts_state):
193203 logs += msg ["text" ] + "\n "
194204 yield logs , scripts , gr .update (choices = script_names , value = selected_script ), scripts .get (selected_script , "" ) if selected_script else ""
195205 break
206+ elif msg_type == "error" :
207+ logs += f"ERROR: { data } \n "
208+ yield logs , scripts , gr .update (choices = script_names , value = selected_script ), scripts .get (selected_script , "" ) if selected_script else ""
209+ return
196210 except Empty :
197211 yield logs , scripts , gr .update (choices = script_names , value = selected_script ), scripts .get (selected_script , "" ) if selected_script else ""
198212 time .sleep (0.1 )
213+ except Exception as e :
214+ error_msg = f"ERROR waiting for task: { str (e )} "
215+ logs += error_msg + "\n "
216+ yield logs , scripts , gr .update (choices = script_names , value = selected_script ), scripts .get (selected_script , "" ) if selected_script else ""
217+ return
199218
200219 if not task_started :
220+ logs += "ERROR: Task did not start within 10 seconds. Check websocket connection.\n "
201221 yield logs , scripts , gr .update (choices = script_names , value = selected_script ), scripts .get (selected_script , "" ) if selected_script else ""
202222 return
203223
@@ -233,16 +253,18 @@ def process_messages(scripts_state):
233253 def toggle_settings (current_visible ):
234254 return not current_visible , gr .update (visible = not current_visible )
235255
236- def apply_settings (agent_dir , scripts_dir ):
256+ def apply_settings (agent_dir , agent_pattern , scripts_dir ):
237257 new_agent_dir = agent_dir .strip () if agent_dir and agent_dir .strip () else str (DEFAULT_AGENT_DIR )
258+ new_agent_pattern = agent_pattern .strip () if agent_pattern and agent_pattern .strip () else DEFAULT_AGENT_PATTERN
238259 new_scripts_dir = scripts_dir .strip () if scripts_dir and scripts_dir .strip () else str (DEFAULT_TESTS_DIR )
239260
240- agent_choices = scan_agent_scripts (new_agent_dir )
261+ agent_choices = scan_agent_scripts (new_agent_dir , new_agent_pattern )
241262 scripts_choices = scan_script_dirs (new_scripts_dir )
242263 version_choices = scan_versions (new_agent_dir )
243264
244265 return (
245266 new_agent_dir ,
267+ new_agent_pattern ,
246268 new_scripts_dir ,
247269 gr .update (choices = agent_choices , value = agent_choices [0 ] if agent_choices else None ),
248270 gr .update (choices = scripts_choices , value = None ),
@@ -252,7 +274,12 @@ def apply_settings(agent_dir, scripts_dir):
252274 )
253275
254276 def send_and_clear (agent_script , scripts_dir , agent_dir_state_val , scripts_dir_state_val ):
255- if agent_script and scripts_dir :
277+ try :
278+ if not agent_script :
279+ return "ERROR: No agent script selected"
280+ if not scripts_dir :
281+ return "ERROR: No scripts directory selected"
282+
256283 agent_dir = Path (agent_dir_state_val ) if agent_dir_state_val else DEFAULT_AGENT_DIR
257284 scripts_base_dir = Path (scripts_dir_state_val ) if scripts_dir_state_val else DEFAULT_TESTS_DIR
258285
@@ -264,13 +291,19 @@ def send_and_clear(agent_script, scripts_dir, agent_dir_state_val, scripts_dir_s
264291 output_queue .get_nowait ()
265292 except Empty :
266293 break
294+
295+ if not ws_thread or not ws_thread .is_alive ():
296+ return "ERROR: Websocket not connected. Try refreshing the page."
297+
267298 msg = json .dumps ({
268299 "agent_script" : agent_script ,
269300 "scripts_dir" : scripts_dir ,
270301 "agent_dir" : str (agent_dir )
271302 })
272303 message_queue .put (msg )
273- return ""
304+ return ""
305+ except Exception as e :
306+ return f"ERROR in send_and_clear: { str (e )} "
274307
275308 def load_version_scripts (version , agent_dir_state_val ):
276309 """Load scripts directly from a version directory"""
@@ -333,17 +366,28 @@ def close_settings():
333366
334367 apply_settings_btn .click (
335368 apply_settings ,
336- inputs = [agent_dir_input , scripts_dir_input ],
337- outputs = [agent_dir_state , scripts_dir_state , agent_dropdown , scripts_dropdown , version_dropdown , settings_visible , settings_modal ]
369+ inputs = [agent_dir_input , agent_pattern_input , scripts_dir_input ],
370+ outputs = [agent_dir_state , agent_pattern_state , scripts_dir_state , agent_dropdown , scripts_dropdown , version_dropdown , settings_visible , settings_modal ]
338371 )
339372
340373 def refresh_versions (agent_dir_state_val ):
341374 """Refresh version list"""
342375 versions = scan_versions (agent_dir_state_val )
343376 return gr .update (choices = versions )
344377
378+ def refresh_agents (agent_dir_state_val , agent_pattern_state_val ):
379+ """Refresh agent list"""
380+ agents = scan_agent_scripts (agent_dir_state_val , agent_pattern_state_val )
381+ return gr .update (choices = agents , value = agents [0 ] if agents else None )
382+
383+ def run_with_error_check (agent_script , scripts_dir , agent_dir_state_val , scripts_dir_state_val ):
384+ error_msg = send_and_clear (agent_script , scripts_dir , agent_dir_state_val , scripts_dir_state_val )
385+ if error_msg :
386+ return error_msg
387+ return ""
388+
345389 run_btn .click (
346- send_and_clear ,
390+ run_with_error_check ,
347391 inputs = [agent_dropdown , scripts_dropdown , agent_dir_state , scripts_dir_state ],
348392 outputs = [output_logs ]
349393 ).then (
@@ -354,6 +398,10 @@ def refresh_versions(agent_dir_state_val):
354398 refresh_versions ,
355399 inputs = [agent_dir_state ],
356400 outputs = [version_dropdown ]
401+ ).then (
402+ refresh_agents ,
403+ inputs = [agent_dir_state , agent_pattern_state ],
404+ outputs = [agent_dropdown ]
357405 )
358406
359407 reset_btn .click (
0 commit comments