Skip to content

Commit 4453a00

Browse files
Improve UI and step hint handling for multiple hints
1 parent 958430c commit 4453a00

File tree

4 files changed

+190
-87
lines changed

4 files changed

+190
-87
lines changed

src/agentlab/agents/hitl_agent/generic_human_guided_agent.py

Lines changed: 6 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,6 @@
1818
HintLabeling,
1919
HintLabelingInputs,
2020
)
21-
from agentlab.analyze import overlay_utils
2221
from agentlab.llm.llm_utils import (
2322
Discussion,
2423
HumanMessage,
@@ -208,7 +207,7 @@ def get_action(self, obs):
208207
screenshots=[], # no overlay screenshots yet
209208
axtree=obs.get("axtree_txt", ""),
210209
history=[],
211-
hint="",
210+
hints=[],
212211
suggestions=[], # no suggestions yet
213212
)
214213
self.ui.update_context(initial_inputs)
@@ -243,20 +242,16 @@ def get_action(self, obs):
243242
screenshots=screenshots, # list of overlay screenshots for hover
244243
axtree=obs.get("axtree_txt", ""),
245244
history=[], # TODO: add history
246-
hint=(
247-
"\n".join(f"{i}. {c}" for i, c in enumerate(step_hint, 1))
248-
if step_hint
249-
else ""
250-
),
245+
hints=step_hint,
251246
suggestions=suggestions,
252247
)
253248

254249
self.ui.update_context(hint_labeling_inputs)
255250
response = self.ui.wait_for_response(timeout=600)
256251

257252
if response["type"] == "reprompt":
258-
hint = response["payload"]["hint"]
259-
step_hint.append(hint)
253+
new_hints = response["payload"].get("hints", [])
254+
step_hint = list(new_hints) if isinstance(new_hints, list) else step_hint
260255
candidates, chat_messages = self.get_candidate_generation(
261256
sys_prompt=system_prompt,
262257
human_prompt=human_prompt,
@@ -354,8 +349,8 @@ def get_base_agent(llm_config):
354349
from agentlab.experiments.study import Study
355350

356351
agent_configs = [HUMAN_GUIDED_GENERIC_AGENT]
357-
benchmark = bgym.DEFAULT_BENCHMARKS["workarena_l1"]()
358-
benchmark = benchmark.subset_from_glob("task_name", "*create*")
352+
benchmark = bgym.DEFAULT_BENCHMARKS["miniwob"]()
353+
benchmark = benchmark.subset_from_glob("task_name", "*book*")
359354
benchmark.env_args_list = benchmark.env_args_list[3:4]
360355

361356
for env_args in benchmark.env_args_list:

src/agentlab/agents/hitl_agent/hint_labelling.py

Lines changed: 23 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -8,11 +8,9 @@
88
from browsergym.core import _get_global_playwright
99
from pydantic import BaseModel, Field
1010

11-
from agentlab.agents.hitl_agent import hint_labelling_ui_files
12-
1311
logger = logging.getLogger(__name__)
14-
15-
HINT_LABELING_DIR = resources.files(hint_labelling_ui_files)
12+
13+
HINT_LABELING_DIR = resources.files("agentlab.agents.hitl_agent.hint_labelling_ui_files")
1614

1715

1816
class HintLabelingInputs(BaseModel):
@@ -22,41 +20,46 @@ class HintLabelingInputs(BaseModel):
2220
screenshots: List[str] = Field(default_factory=list) # list of base64 screenshots for hover
2321
axtree: str
2422
history: List[Dict[str, str]] = Field(default_factory=list)
25-
hint: str = ""
23+
hints: List[str] = Field(default_factory=list)
2624
suggestions: List[Dict[str, str]] = Field(default_factory=list)
2725

2826

2927
class HintLabeling:
3028
def __init__(self, headless: bool, window_size=(600, 1000), *args, **kwargs):
31-
32-
pw: playwright.sync_api.Playwright = _get_global_playwright()
29+
pw_opt = _get_global_playwright()
30+
pw: playwright.sync_api.Playwright = pw_opt # type: ignore[assignment]
3331
self.browser = pw.chromium.launch(
3432
headless=headless, args=[f"--window-size={window_size[0]},{window_size[1]}"]
3533
)
3634
self.context = self.browser.new_context(
3735
no_viewport=True,
3836
)
3937
self.page = self.context.new_page()
40-
self._resp_queue: "Queue[dict]" = Queue()
38+
self._resp_queue = Queue()
4139

4240
self.page.route("**/api/reprompt", self._route_reprompt)
4341
self.page.route("**/api/submit", self._route_submit)
4442
self.page.set_content(get_hint_labeling_ui(HINT_LABELING_DIR))
4543

4644
# internal state
47-
self._context: HintLabelingInputs = None
45+
self._context = None
4846
self._running = False
4947

5048
def _route_reprompt(
5149
self, route: playwright.sync_api.Route, request: playwright.sync_api.Request
5250
):
5351
logger.info("Route hit: %s %s", request.method, request.url)
5452
try:
55-
body = json.loads(request.post_data() or "{}")
53+
body = json.loads(request.post_data or "{}")
5654
except Exception:
5755
body = {}
5856
# enqueue output 1 (reprompt)
59-
msg = {"type": "reprompt", "payload": {"hint": body.get("hint", "")}}
57+
hints = body.get("hints")
58+
if not isinstance(hints, list):
59+
# Back-compat: accept single 'hint' string
60+
h = body.get("hint")
61+
hints = [h] if isinstance(h, str) and h.strip() else []
62+
msg = {"type": "reprompt", "payload": {"hints": hints}}
6063
self._resp_queue.put(msg)
6164
# Respond something minimal so UI doesn’t break; it will be refreshed by a later update_context()
6265
route.fulfill(
@@ -68,10 +71,10 @@ def _route_reprompt(
6871
def _route_submit(self, route: playwright.sync_api.Route, request: playwright.sync_api.Request):
6972
logger.info("Route hit: %s %s", request.method, request.url)
7073
try:
71-
body = json.loads(request.post_data() or "{}")
74+
body = json.loads(request.post_data or "{}")
7275
except Exception:
7376
body = {}
74-
# Map UI payload -> your step shape
77+
# Map UI payload -> your step shape
7578
msg = {
7679
"type": "step",
7780
"payload": {
@@ -95,7 +98,7 @@ def _to_ui_bootstrap(self, ctx: HintLabelingInputs) -> dict:
9598
"screenshots": ctx.screenshots, # list of screenshots for hover
9699
"axtree": ctx.axtree,
97100
"history": ctx.history,
98-
"hint": ctx.hint,
101+
"hints": ctx.hints,
99102
"suggestions": ctx.suggestions,
100103
}
101104

@@ -116,7 +119,7 @@ def wait_for_response(self, timeout: Optional[float] = 600) -> dict:
116119
117120
Returns:
118121
dict: A dictionary containing the parsed response with 'type' and 'payload' keys.
119-
For /api/reprompt: {'type': 'reprompt', 'payload': {'hint': str}}
122+
For /api/reprompt: {'type': 'reprompt', 'payload': {'hints': list[str]}}
120123
For /api/submit: {'type': 'step', 'payload': {'think': str, 'action': str}}
121124
122125
"""
@@ -142,7 +145,11 @@ def is_api(req: playwright.sync_api.Request) -> bool:
142145
body = {}
143146

144147
if req.url.endswith("/api/reprompt"):
145-
msg = {"type": "reprompt", "payload": {"hint": body.get("hint", "")}}
148+
hints = body.get("hints")
149+
if not isinstance(hints, list):
150+
h = body.get("hint")
151+
hints = [h] if isinstance(h, str) and h.strip() else []
152+
msg = {"type": "reprompt", "payload": {"hints": hints}}
146153
else:
147154
msg = {
148155
"type": "step",

0 commit comments

Comments
 (0)