88from browsergym .core import _get_global_playwright
99from pydantic import BaseModel , Field
1010
11- from agentlab .agents .hitl_agent import hint_labelling_ui_files
12-
1311logger = 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
1816class 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
2927class 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