Skip to content

Commit fe950c0

Browse files
committed
Add button to set agent and tests dir
1 parent f59d181 commit fe950c0

2 files changed

Lines changed: 113 additions & 28 deletions

File tree

agentic/web_ui/app.py

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -53,10 +53,11 @@ def _subprocess_thread(self, cmd, cwd):
5353
except Exception as e:
5454
self.output_queue.put(("error", str(e)))
5555

56-
async def run_agent(self, agent_script, scripts_dir, ws):
56+
async def run_agent(self, agent_script, scripts_dir, ws, agent_dir=None):
5757
await self._log(ws, f"started: {agent_script} --scripts {scripts_dir}")
5858

59-
# Just use the script name - we'll run from AGENT_DIR
59+
# Use configured agent_dir or default
60+
run_dir = Path(agent_dir) if agent_dir else AGENT_DIR
6061
cmd = [sys.executable, agent_script, "--scripts", scripts_dir]
6162

6263
# Clear queue
@@ -68,7 +69,7 @@ async def run_agent(self, agent_script, scripts_dir, ws):
6869

6970
thread = threading.Thread(
7071
target=self._subprocess_thread,
71-
args=(cmd, str(AGENT_DIR)), # Run from AGENT_DIR
72+
args=(cmd, str(run_dir)), # Run from configured directory
7273
daemon=True
7374
)
7475
thread.start()
@@ -107,7 +108,8 @@ async def ws_endpoint(ws: WebSocket, session_id: str):
107108
msg = json.loads(raw)
108109
agent_script = msg.get("agent_script", "libe_agent_basic.py")
109110
scripts_dir = msg.get("scripts_dir", "")
111+
agent_dir = msg.get("agent_dir", None)
110112
if scripts_dir:
111-
await s.run_agent(agent_script, scripts_dir, ws)
113+
await s.run_agent(agent_script, scripts_dir, ws, agent_dir=agent_dir)
112114
except WebSocketDisconnect:
113115
pass

agentic/web_ui/gradio_chat.py

Lines changed: 107 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -12,8 +12,8 @@
1212
import websockets
1313

1414
WS_URL = "ws://127.0.0.1:8000/ws/test"
15-
AGENT_DIR = Path(__file__).parent.parent
16-
TESTS_DIR = AGENT_DIR / "tests"
15+
DEFAULT_AGENT_DIR = Path(__file__).parent.parent
16+
DEFAULT_TESTS_DIR = DEFAULT_AGENT_DIR / "tests"
1717

1818
ws_conn = None
1919
message_queue = Queue()
@@ -23,15 +23,41 @@
2323
uvicorn_process = None
2424

2525

26-
def scan_agent_scripts():
27-
exclude = {"app.py", "gradio_chat.py", "__init__.py"}
28-
return [f.name for f in sorted(AGENT_DIR.glob("*.py")) if f.name not in exclude]
26+
def scan_agent_scripts(agent_dir_path):
27+
try:
28+
if not agent_dir_path:
29+
return []
30+
agent_dir = Path(agent_dir_path)
31+
if not agent_dir.exists():
32+
print(f"Warning: Agent directory does not exist: {agent_dir_path}")
33+
return []
34+
if not agent_dir.is_dir():
35+
print(f"Warning: Agent path is not a directory: {agent_dir_path}")
36+
return []
37+
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]
39+
return scripts
40+
except Exception as e:
41+
print(f"Error scanning agent scripts: {e}")
42+
return []
2943

3044

31-
def scan_script_dirs():
32-
if not TESTS_DIR.exists():
45+
def scan_script_dirs(scripts_dir_path):
46+
try:
47+
if not scripts_dir_path:
48+
return []
49+
scripts_dir = Path(scripts_dir_path)
50+
if not scripts_dir.exists():
51+
print(f"Warning: Scripts directory does not exist: {scripts_dir_path}")
52+
return []
53+
if not scripts_dir.is_dir():
54+
print(f"Warning: Scripts path is not a directory: {scripts_dir_path}")
55+
return []
56+
dirs = [d.name for d in sorted(scripts_dir.iterdir()) if d.is_dir() and not d.name.startswith("_")]
57+
return dirs
58+
except Exception as e:
59+
print(f"Error scanning script directories: {e}")
3360
return []
34-
return [d.name for d in sorted(TESTS_DIR.iterdir()) if d.is_dir() and not d.name.startswith("_")]
3561

3662

3763

@@ -71,23 +97,37 @@ async def _run():
7197
loop.close()
7298

7399

100+
_init_agents = scan_agent_scripts(str(DEFAULT_AGENT_DIR))
101+
_init_tests = scan_script_dirs(str(DEFAULT_TESTS_DIR))
102+
74103
with gr.Blocks() as demo:
75-
gr.Markdown("### libEnsemble Agent")
104+
with gr.Row():
105+
gr.Markdown("### libEnsemble Agent")
106+
with gr.Column(scale=0, min_width=60):
107+
settings_btn = gr.Button("⚙️", size="sm")
108+
109+
agent_dir_state = gr.State(value=str(DEFAULT_AGENT_DIR))
110+
scripts_dir_state = gr.State(value=str(DEFAULT_TESTS_DIR))
111+
settings_visible = gr.State(value=False)
112+
113+
with gr.Column(visible=False) as settings_modal:
114+
with gr.Column(elem_classes="modal-content"):
115+
gr.Markdown("### Settings")
116+
agent_dir_input = gr.Textbox(label="Agent Directory", value=str(DEFAULT_AGENT_DIR))
117+
scripts_dir_input = gr.Textbox(label="Scripts Directory", value=str(DEFAULT_TESTS_DIR))
118+
with gr.Row():
119+
apply_settings_btn = gr.Button("Apply", variant="primary", scale=1)
120+
close_settings_btn = gr.Button("Close", scale=1)
76121

77122
with gr.Row():
78123
agent_dropdown = gr.Dropdown(
79-
label="Agent Script",
80-
choices=scan_agent_scripts(),
81-
value=scan_agent_scripts()[0] if scan_agent_scripts() else None,
82-
allow_custom_value=True,
83-
scale=2
124+
label="Agent Script", choices=_init_agents,
125+
value=_init_agents[0] if _init_agents else None,
126+
allow_custom_value=True, scale=2
84127
)
85128
scripts_dropdown = gr.Dropdown(
86-
label="Scripts Directory",
87-
choices=scan_script_dirs(),
88-
value=None,
89-
allow_custom_value=True,
90-
scale=2
129+
label="Scripts Directory", choices=_init_tests,
130+
value=None, allow_custom_value=True, scale=2
91131
)
92132
run_btn = gr.Button("Run", variant="primary", scale=1)
93133
reset_btn = gr.Button("Reset", variant="stop", scale=1)
@@ -166,12 +206,34 @@ def process_messages(scripts_state):
166206
yield logs, scripts, gr.update(choices=script_names, value=selected_script), scripts.get(selected_script, "") if selected_script else ""
167207
time.sleep(0.1)
168208

169-
def send_and_clear(agent_script, scripts_dir):
209+
def toggle_settings(current_visible):
210+
return not current_visible, gr.update(visible=not current_visible)
211+
212+
def apply_settings(agent_dir, scripts_dir):
213+
new_agent_dir = agent_dir.strip() if agent_dir and agent_dir.strip() else str(DEFAULT_AGENT_DIR)
214+
new_scripts_dir = scripts_dir.strip() if scripts_dir and scripts_dir.strip() else str(DEFAULT_TESTS_DIR)
215+
216+
agent_choices = scan_agent_scripts(new_agent_dir)
217+
scripts_choices = scan_script_dirs(new_scripts_dir)
218+
219+
return (
220+
new_agent_dir,
221+
new_scripts_dir,
222+
gr.update(choices=agent_choices, value=agent_choices[0] if agent_choices else None),
223+
gr.update(choices=scripts_choices, value=None),
224+
False, # settings_visible - close modal
225+
gr.update(visible=False) # settings_modal
226+
)
227+
228+
def send_and_clear(agent_script, scripts_dir, agent_dir_state_val, scripts_dir_state_val):
170229
if agent_script and scripts_dir:
171-
# Just send the script name - backend will run from AGENT_DIR
230+
# Use configured directories
231+
agent_dir = Path(agent_dir_state_val) if agent_dir_state_val else DEFAULT_AGENT_DIR
232+
scripts_base_dir = Path(scripts_dir_state_val) if scripts_dir_state_val else DEFAULT_TESTS_DIR
233+
172234
# Convert directory name to full path
173235
if not Path(scripts_dir).is_absolute():
174-
scripts_dir = str(AGENT_DIR / "tests" / scripts_dir)
236+
scripts_dir = str(scripts_base_dir / scripts_dir)
175237

176238
while not output_queue.empty():
177239
try:
@@ -180,7 +242,8 @@ def send_and_clear(agent_script, scripts_dir):
180242
break
181243
msg = json.dumps({
182244
"agent_script": agent_script, # Just the filename
183-
"scripts_dir": scripts_dir
245+
"scripts_dir": scripts_dir,
246+
"agent_dir": str(agent_dir) # Send agent dir so backend knows where to run from
184247
})
185248
message_queue.put(msg)
186249
return ""
@@ -212,9 +275,29 @@ def update_script_display(selected_name, scripts_state):
212275

213276
demo.load(start_websocket)
214277

278+
settings_btn.click(
279+
toggle_settings,
280+
inputs=[settings_visible],
281+
outputs=[settings_visible, settings_modal]
282+
)
283+
284+
def close_settings():
285+
return False, gr.update(visible=False)
286+
287+
close_settings_btn.click(
288+
close_settings,
289+
outputs=[settings_visible, settings_modal]
290+
)
291+
292+
apply_settings_btn.click(
293+
apply_settings,
294+
inputs=[agent_dir_input, scripts_dir_input],
295+
outputs=[agent_dir_state, scripts_dir_state, agent_dropdown, scripts_dropdown, settings_visible, settings_modal]
296+
)
297+
215298
run_btn.click(
216299
send_and_clear,
217-
inputs=[agent_dropdown, scripts_dropdown],
300+
inputs=[agent_dropdown, scripts_dropdown, agent_dir_state, scripts_dir_state],
218301
outputs=[output_logs]
219302
).then(
220303
process_messages,

0 commit comments

Comments
 (0)