lybic-guiagents 0.3.0__py3-none-any.whl → 0.5.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of lybic-guiagents might be problematic. Click here for more details.

gui_agents/__init__.py CHANGED
@@ -37,7 +37,7 @@ from .agents.hardware_interface import HardwareInterface
37
37
  from .store.registry import Registry
38
38
  from .agents.global_state import GlobalState
39
39
 
40
- __version__ = "0.3.0"
40
+ __version__ = "0.5.0"
41
41
 
42
42
  # Primary exports (what users should typically use)
43
43
  __all__ = [
@@ -1,4 +1,3 @@
1
- import asyncio
2
1
  import json
3
2
  import logging
4
3
  import os
@@ -13,7 +12,6 @@ from gui_agents.utils.common_utils import Node
13
12
  from gui_agents.agents.global_state import GlobalState
14
13
  from gui_agents.store.registry import Registry
15
14
  from gui_agents.utils.common_utils import (
16
- # call_llm_safe,
17
15
  parse_single_code_from_string,
18
16
  sanitize_code,
19
17
  extract_first_agent_function,
@@ -172,8 +170,6 @@ class AgentS2(UIAgent):
172
170
  else:
173
171
  print(f"Found local knowledge base path: {kb_platform_path}")
174
172
 
175
- self.reset()
176
-
177
173
  def reset(self) -> None:
178
174
  """
179
175
  Reinitialize core components and reset the agent's runtime state.
@@ -219,12 +215,18 @@ class AgentS2(UIAgent):
219
215
  self.subtasks: List[Node] = []
220
216
  self.search_query: str = ""
221
217
  self.subtask_status: str = "Start"
222
- self.global_state: GlobalState = Registry.get("GlobalStateStore") # type: ignore
218
+ # Use task-specific registry if task_id is available, otherwise fall back to global registry
219
+ if self.task_id:
220
+ self.global_state: GlobalState = Registry.get_from_context("GlobalStateStore", self.task_id) # type: ignore
221
+ else:
222
+ self.global_state: GlobalState = Registry.get("GlobalStateStore") # type: ignore
223
223
 
224
224
  # Pass task_id to components
225
- if self.task_id:
226
- self.manager.task_id = self.task_id
227
- self.worker.task_id = self.task_id
225
+ self.manager.set_task_id(self.task_id)
226
+ self.worker.set_task_id(self.task_id)
227
+ # Grounding doesn't have task_id in normal mode, but we set it if available
228
+ if hasattr(self, 'grounding') and hasattr(self.grounding, 'set_task_id'):
229
+ self.grounding.set_task_id(self.task_id)
228
230
 
229
231
  def set_task_id(self, task_id: str) -> None:
230
232
  """
@@ -236,9 +238,9 @@ class AgentS2(UIAgent):
236
238
  self.task_id = task_id
237
239
  # Also set task_id for components if they exist
238
240
  if hasattr(self, 'manager') and self.manager:
239
- self.manager.task_id = task_id
241
+ self.manager.set_task_id(task_id)
240
242
  if hasattr(self, 'worker') and self.worker:
241
- self.worker.task_id = task_id
243
+ self.worker.set_task_id(task_id)
242
244
 
243
245
  def reset_executor_state(self) -> None:
244
246
  """Reset executor and step counter"""
@@ -249,17 +251,28 @@ class AgentS2(UIAgent):
249
251
  # Initialize the three info dictionaries
250
252
  """
251
253
  Produce the next executor actions and diagnostic information for the current task step.
252
-
254
+
253
255
  This method coordinates planning, subtask selection, action generation, grounding (code extraction and execution), and status updates. It may trigger replanning, advance to the next subtask, mark subtasks as completed or failed, and emit stream messages and logs. The returned info merges planner, executor, and evaluator metadata and includes current subtask details.
254
-
256
+
255
257
  Parameters:
256
258
  instruction (str): The user or system instruction describing the task to accomplish; forwarded to the manager/worker as the task utterance.
257
259
  observation (Dict): Current environment observation/state used for grounding and coordinate assignment.
258
-
260
+
259
261
  Returns:
260
262
  info (Dict): A merged dictionary containing planner_info, executor_info, evaluator_info and the keys `subtask`, `subtask_info`, and `subtask_status`.
261
263
  actions (List[Dict]): List of action dictionaries produced for execution (may include actions with type "DONE", failure indicators, or other executor-generated actions).
262
264
  """
265
+ # Check for cancellation before starting prediction
266
+ if self.global_state.is_cancelled():
267
+ logger.info("AgentS2 prediction cancelled by user request")
268
+ return {
269
+ "subtask": "cancelled",
270
+ "subtask_info": "",
271
+ "subtask_status": "cancelled",
272
+ "reflection": "Task was cancelled",
273
+ "executor_plan": "agent.done()"
274
+ }, ["done"]
275
+
263
276
  planner_info = {}
264
277
  executor_info = {}
265
278
  evaluator_info = {
@@ -276,6 +289,16 @@ class AgentS2(UIAgent):
276
289
 
277
290
  # If the DONE response by the executor is for a subtask, then the agent should continue with the next subtask without sending the action to the environment
278
291
  while not self.should_send_action:
292
+ # Check for cancellation in each iteration
293
+ if self.global_state.is_cancelled():
294
+ logger.info("AgentS2 prediction loop cancelled by user request")
295
+ return {
296
+ "subtask": "cancelled",
297
+ "subtask_info": "",
298
+ "subtask_status": "cancelled",
299
+ "reflection": "Task was cancelled",
300
+ "executor_plan": "agent.done()"
301
+ }, [{"type": "DONE"}]
279
302
  time.sleep(5.0)
280
303
  self.subtask_status = "In"
281
304
  # Always time get_action_queue, even if not called
@@ -430,6 +453,15 @@ class AgentS2(UIAgent):
430
453
  }
431
454
  )
432
455
  except Exception as e:
456
+ if self.global_state.is_cancelled():
457
+ logger.info("Cancelled during grounding; stopping without action")
458
+ return {
459
+ "subtask": "cancelled",
460
+ "subtask_info": "",
461
+ "subtask_status": "cancelled",
462
+ "reflection": "Task was cancelled",
463
+ "executor_plan": "agent.done()"
464
+ }, [{"type": "DONE"}]
433
465
  logger.error("Error in parsing plan code: %s", e)
434
466
  plan_code = "agent.wait(1.0)"
435
467
  agent: Grounding = self.grounding # this agent will be used in next code
@@ -733,8 +765,6 @@ class AgentSFast(UIAgent):
733
765
  else:
734
766
  print(f"Found local knowledge base path: {kb_platform_path}")
735
767
 
736
- self.reset()
737
-
738
768
  def reset(self) -> None:
739
769
  """
740
770
  Reinitialize the fast-agent components and reset internal runtime state.
@@ -816,19 +846,25 @@ class AgentSFast(UIAgent):
816
846
  # Reset state variables
817
847
  self.step_count: int = 0
818
848
  self.turn_count: int = 0
819
- self.global_state: GlobalState = Registry.get("GlobalStateStore") # type: ignore
849
+ # Use task-specific registry if task_id is available, otherwise fall back to global registry
850
+ if self.task_id:
851
+ self.global_state: GlobalState = Registry.get_from_context("GlobalStateStore", self.task_id) # type: ignore
852
+ else:
853
+ self.global_state: GlobalState = Registry.get("GlobalStateStore") # type: ignore
820
854
  self.latest_action = None
821
855
 
822
- # Pass task_id to tools if available
823
- if self.task_id:
824
- self.fast_action_generator.task_id = self.task_id
825
- if self.enable_reflection and hasattr(self, 'reflection_agent'):
826
- self.reflection_agent.task_id = self.task_id
856
+ # Pass task_id to tools and components if available
857
+ self.fast_action_generator.task_id = self.task_id
858
+ if self.enable_reflection and hasattr(self, 'reflection_agent'):
859
+ self.reflection_agent.task_id = self.task_id
860
+ # Set task_id for grounding component
861
+ if hasattr(self, 'grounding') and hasattr(self.grounding, 'set_task_id'):
862
+ self.grounding.set_task_id(self.task_id)
827
863
 
828
864
  def set_task_id(self, task_id: str) -> None:
829
865
  """
830
866
  Store the task identifier on the agent and propagate it to subcomponents that use it.
831
-
867
+
832
868
  Parameters:
833
869
  task_id (str): Identifier for the active task; assigned to this agent and, if present, to
834
870
  `fast_action_generator` and `reflection_agent`.
@@ -839,22 +875,34 @@ class AgentSFast(UIAgent):
839
875
  self.fast_action_generator.task_id = task_id
840
876
  if hasattr(self, 'reflection_agent') and self.reflection_agent:
841
877
  self.reflection_agent.task_id = task_id
878
+ # Set task_id for grounding component
879
+ if hasattr(self, 'grounding') and hasattr(self.grounding, 'set_task_id'):
880
+ self.grounding.set_task_id(task_id)
842
881
 
843
882
  def predict(self, instruction: str, observation: Dict) -> Tuple[Dict, List[str]]:
844
883
  """
845
884
  Generate the next executor plan and corresponding actions using the configured fast action generator.
846
-
885
+
847
886
  Parameters:
848
887
  instruction (str): Natural language task description.
849
888
  observation (Dict): Current UI state; must include a "screenshot" entry with the screen image.
850
-
889
+
851
890
  Returns:
852
891
  executor_info (dict): Contains at least the keys `executor_plan` (raw plan text), `reflection` (reflection text or empty string), and `plan_code` (the latest extracted/used action code).
853
892
  actions (List[dict]): List of action dictionaries produced by grounding execution; typically a single action dict describing the operation to perform.
854
893
  """
894
+ # Check for cancellation before starting prediction
895
+ if self.global_state.is_cancelled():
896
+ logger.info("AgentSFast prediction cancelled by user request")
897
+ return {
898
+ "executor_plan": "agent.done()",
899
+ "reflection": "Task was cancelled",
900
+ "plan_code": "agent.done()"
901
+ }, [{"type": "DONE"}]
902
+
855
903
  import time
856
904
  predict_start_time = time.time()
857
-
905
+
858
906
  fast_action_start_time = time.time()
859
907
 
860
908
  reflection = None
@@ -467,7 +467,9 @@ class GlobalState:
467
467
  return "stopped"
468
468
 
469
469
  def set_running_state(self, state: str) -> None:
470
- assert state in {"running", "stopped"}
470
+ if state not in {"running", "stopped", "cancelled"}:
471
+ raise ValueError(f"Invalid running state: {state}")
472
+
471
473
  tmp = self.running_state_path.with_suffix(".tmp")
472
474
  try:
473
475
  with locked(tmp, "w") as f:
@@ -486,6 +488,16 @@ class GlobalState:
486
488
  pass
487
489
  raise
488
490
 
491
+ def is_cancelled(self) -> bool:
492
+ """Check if the current execution has been cancelled"""
493
+ try:
494
+ with locked(self.running_state_path, "r") as f:
495
+ data = safe_json_load(f)
496
+ return data == "cancelled"
497
+ except Exception as e:
498
+ logger.warning(f"Failed to check cancellation state: {e}")
499
+ return False
500
+
489
501
  # ---------- High-level Wrappers ----------
490
502
  def get_obs_for_manager(self):
491
503
  return {
@@ -92,10 +92,20 @@ class Grounding(ACI):
92
92
  self.text_span_agent = Tools()
93
93
  _register(self.text_span_agent, "text_span")
94
94
 
95
- self.global_state: GlobalState = Registry.get(
96
- "GlobalStateStore") # type: ignore
95
+ # GlobalState will be initialized when task_id is set
96
+ self.global_state: GlobalState = None # type: ignore
97
+
98
+ def set_task_id(self, task_id: str) -> None:
99
+ """Set the task identifier and update global state reference"""
100
+ # Update global state reference with task-specific registry
101
+ self.global_state = Registry.get_from_context("GlobalStateStore", task_id) # type: ignore
97
102
 
98
103
  def generate_coords(self, ref_expr: str, obs: Dict) -> List[int]:
104
+ # Check for cancellation before starting coordinate generation
105
+ if self.global_state.is_cancelled():
106
+ logger.info("Grounding coordinate generation cancelled by user request")
107
+ raise RuntimeError("cancelled") # Return default coordinates when cancelled
108
+
99
109
  grounding_start_time = time.time()
100
110
  self.grounding_model.tools["grounding"].llm_agent.reset()
101
111
  prompt = (
@@ -453,8 +463,13 @@ class FastGrounding(ACI):
453
463
  self.height = height
454
464
  self.grounding_width = grounding_width
455
465
  self.grounding_height = grounding_height
456
- self.global_state: GlobalState = Registry.get(
457
- "GlobalStateStore") # type: ignore
466
+ # GlobalState will be initialized when task_id is set
467
+ self.global_state: GlobalState = None # type: ignore
468
+
469
+ def set_task_id(self, task_id: str) -> None:
470
+ """Set the task identifier and update global state reference"""
471
+ # Update global state reference with task-specific registry
472
+ self.global_state = Registry.get_from_context("GlobalStateStore", task_id) # type: ignore
458
473
 
459
474
  def reset_screen_size(self, width: int, height: int):
460
475
  self.width = width
@@ -102,7 +102,8 @@ class Manager:
102
102
  Tools_dict=KB_Tools_dict,
103
103
  )
104
104
 
105
- self.global_state: GlobalState = Registry.get("GlobalStateStore") # type: ignore
105
+ # GlobalState will be initialized in reset() method when task_id is available
106
+ self.global_state: GlobalState = None # type: ignore
106
107
 
107
108
  self.planner_history = []
108
109
 
@@ -118,6 +119,12 @@ class Manager:
118
119
 
119
120
  self.multi_round = multi_round
120
121
 
122
+ def set_task_id(self, task_id: str) -> None:
123
+ """Set the task identifier and update global state reference"""
124
+ self.task_id = task_id
125
+ # Update global state reference with task-specific registry
126
+ self.global_state = Registry.get_from_context("GlobalStateStore", task_id) # type: ignore
127
+
121
128
  def _send_stream_message(self, task_id: str, stage: str, message: str) -> None:
122
129
  """
123
130
  Enqueue a stream message for the given task if a task ID is provided.
@@ -569,6 +576,11 @@ class Manager:
569
576
  """Generate the action list based on the instruction
570
577
  instruction:str: Instruction for the task
571
578
  """
579
+ # Check for cancellation before starting action queue generation
580
+ if self.global_state.is_cancelled():
581
+ logger.info("Manager action queue generation cancelled by user request")
582
+ return {"cancelled": True}, []
583
+
572
584
  import time
573
585
  action_queue_start = time.time()
574
586
 
@@ -67,8 +67,8 @@ class Worker:
67
67
 
68
68
  self.enable_reflection = enable_reflection
69
69
  self.use_subtask_experience = use_subtask_experience
70
- self.global_state: GlobalState = Registry.get(
71
- "GlobalStateStore") # type: ignore
70
+ # GlobalState will be initialized in reset() method when task_id is available
71
+ self.global_state: GlobalState = None # type: ignore
72
72
  self.reset()
73
73
 
74
74
  def reset(self):
@@ -159,6 +159,12 @@ class Worker:
159
159
  self.max_trajector_length = 8
160
160
  self.task_id = None # Will be set by agent
161
161
 
162
+ def set_task_id(self, task_id: str) -> None:
163
+ """Set the task identifier and update global state reference"""
164
+ self.task_id = task_id
165
+ # Update global state reference with task-specific registry
166
+ self.global_state = Registry.get_from_context("GlobalStateStore", task_id) # type: ignore
167
+
162
168
  def generate_next_action(
163
169
  self,
164
170
  Tu: str,
@@ -172,7 +178,7 @@ class Worker:
172
178
  ) -> Dict:
173
179
  """
174
180
  Generate the next executor action plan and related metadata for the current subtask given the observation and context.
175
-
181
+
176
182
  Parameters:
177
183
  Tu (str): Full task description or task context.
178
184
  search_query (str): Search string used for retrieving episodic/subtask experience.
@@ -182,7 +188,7 @@ class Worker:
182
188
  done_task (List[Node]): List of completed task nodes.
183
189
  obs (Dict): Current observation dictionary; must include a "screenshot" key with the current screen image.
184
190
  running_state (str): Current executor running state (default "running").
185
-
191
+
186
192
  Returns:
187
193
  Dict: Executor information containing:
188
194
  - "current_subtask" (str): The provided subtask.
@@ -190,6 +196,16 @@ class Worker:
190
196
  - "executor_plan" (str): The raw plan produced by the action generator.
191
197
  - "reflection" (str|None): Reflection text produced by the trajectory reflector, or None if reflection is disabled.
192
198
  """
199
+ # Check for cancellation before starting action generation
200
+ if self.global_state.is_cancelled():
201
+ logger.info("Worker action generation cancelled by user request")
202
+ return {
203
+ "current_subtask": subtask,
204
+ "current_subtask_info": subtask_info,
205
+ "executor_plan": "agent.done()",
206
+ "reflection": "Task was cancelled"
207
+ }
208
+
193
209
  import time
194
210
  action_start = time.time()
195
211