agentcrew-ai 0.8.7__py3-none-any.whl → 0.8.8__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.
AgentCrew/__init__.py CHANGED
@@ -1 +1 @@
1
- __version__ = "0.8.7"
1
+ __version__ = "0.8.8"
@@ -25,11 +25,18 @@ class AgentManager:
25
25
 
26
26
  Args:
27
27
  config_path: Path to the configuration file.
28
+ Supports @hub/ prefix which converts to https://agentplace.cloud/
28
29
 
29
30
  Returns:
30
31
  List of agent dictionaries.
31
32
  """
32
33
 
34
+ if config_uri.startswith("@hub/"):
35
+ import os
36
+
37
+ hub_host = os.environ.get("AGENTCREW_HUB_HOST", "https://agentplace.cloud")
38
+ config_uri = hub_host.rstrip("/") + "/" + config_uri[5:]
39
+
33
40
  if config_uri.startswith(("http://", "https://")):
34
41
  import requests
35
42
  import tempfile
@@ -20,8 +20,7 @@ function clickElement(xpath) {
20
20
  }
21
21
 
22
22
  // Check if element is visible and enabled
23
- const style = window.getComputedStyle(element);
24
- if (style.display === "none" || style.visibility === "hidden") {
23
+ if (!element.checkVisibility()) {
25
24
  return { success: false, error: "Element is not visible" };
26
25
  }
27
26
 
@@ -8,20 +8,6 @@
8
8
  function extractElementsByText(text) {
9
9
  const elementsFound = [];
10
10
 
11
- function isInViewport(rect) {
12
- const viewportWidth =
13
- window.innerWidth || document.documentElement.clientWidth;
14
- const viewportHeight =
15
- window.innerHeight || document.documentElement.clientHeight;
16
-
17
- return (
18
- rect.top < viewportHeight &&
19
- rect.bottom > 0 &&
20
- rect.left < viewportWidth &&
21
- rect.right > 0
22
- );
23
- }
24
-
25
11
  // Utility function to check if element is truly visible (including parent chain)
26
12
  function isElementVisible(element) {
27
13
  if (!element || !element.nodeType === 1) {
@@ -32,14 +18,6 @@ function extractElementsByText(text) {
32
18
  return false;
33
19
  }
34
20
 
35
- bounding_box = element.getBoundingClientRect();
36
- if (!isInViewport(bounding_box)) {
37
- return false;
38
- }
39
- if (bounding_box.width <= 1 && bounding_box.height <= 1) {
40
- return false;
41
- }
42
-
43
21
  return true;
44
22
  }
45
23
 
@@ -68,8 +46,18 @@ function extractElementsByText(text) {
68
46
  }
69
47
  }
70
48
 
49
+ function getDirectTextContent(element) {
50
+ let directText = "";
51
+ for (const node of element.childNodes) {
52
+ if (node.nodeType === Node.TEXT_NODE) {
53
+ directText += node.textContent;
54
+ }
55
+ }
56
+ return directText.trim();
57
+ }
58
+
71
59
  try {
72
- const xpath = `//div[contains(., '${text}')]`;
60
+ const xpath = `//*[contains(., '${text}')]`;
73
61
  const result = document.evaluate(
74
62
  xpath,
75
63
  document,
@@ -80,32 +68,36 @@ function extractElementsByText(text) {
80
68
 
81
69
  let element = result.iterateNext();
82
70
  const seenElements = new Set();
71
+ const searchTextLower = text.toLowerCase();
83
72
 
84
73
  while (element) {
85
- // Check if element is truly visible (including parent chain)
86
74
  if (isElementVisible(element)) {
87
- const elementXPath = getXPath(element);
88
-
89
- if (!seenElements.has(elementXPath)) {
90
- seenElements.add(elementXPath);
91
-
92
- let elementText =
93
- element.getAttribute("aria-label") ||
94
- element.textContent ||
95
- element.innerText ||
96
- "";
97
- elementText = elementText.trim().replace(/\\s+/g, " ");
98
- if (elementText.length > 100) {
99
- elementText = elementText.substring(0, 100) + "...";
75
+ const directText = getDirectTextContent(element);
76
+ const ariaLabel = element.getAttribute("aria-label") || "";
77
+
78
+ if (
79
+ directText.toLowerCase().includes(searchTextLower) ||
80
+ ariaLabel.toLowerCase().includes(searchTextLower)
81
+ ) {
82
+ const elementXPath = getXPath(element);
83
+
84
+ if (!seenElements.has(elementXPath)) {
85
+ seenElements.add(elementXPath);
86
+
87
+ let displayText = ariaLabel || directText || "";
88
+ displayText = displayText.trim().replace(/\s+/g, " ");
89
+ if (displayText.length > 100) {
90
+ displayText = displayText.substring(0, 100) + "...";
91
+ }
92
+
93
+ elementsFound.push({
94
+ xpath: elementXPath,
95
+ text: displayText,
96
+ tagName: element.tagName.toLowerCase(),
97
+ className: element.className || "",
98
+ id: element.id || "",
99
+ });
100
100
  }
101
-
102
- elementsFound.push({
103
- xpath: elementXPath,
104
- text: elementText,
105
- tagName: element.tagName.toLowerCase(),
106
- className: element.className || "",
107
- id: element.id || "",
108
- });
109
101
  }
110
102
  }
111
103
 
@@ -1,93 +1,113 @@
1
1
  function filterHiddenElements() {
2
2
  try {
3
- function isElementHidden(element) {
4
- if (element.nodeType !== Node.ELEMENT_NODE) {
3
+ function isElementVisible(element) {
4
+ if (!element || element.nodeType !== 1) {
5
5
  return false;
6
6
  }
7
7
 
8
- const tagName = element.tagName.toLowerCase();
9
- if (
10
- tagName === "script" ||
11
- tagName === "style" ||
12
- tagName === "noscript"
13
- ) {
14
- return true;
15
- }
16
-
17
- const computedStyle = window.getComputedStyle(element);
18
-
19
- if (
20
- computedStyle.display === "none" ||
21
- computedStyle.visibility === "hidden" ||
22
- computedStyle.opacity === "0"
23
- ) {
24
- return true;
8
+ if (element.disabled) {
9
+ return false;
25
10
  }
26
11
 
27
- const ariaHidden = element.getAttribute("aria-hidden");
28
- if (ariaHidden === "true") {
29
- return true;
12
+ if (!element.checkVisibility()) {
13
+ return false;
30
14
  }
31
15
 
32
- return false;
16
+ return true;
33
17
  }
34
18
 
35
- function removeHiddenElementsFromNode(node) {
36
- if (!node || node.nodeType !== Node.ELEMENT_NODE) {
37
- return;
19
+ function getXPath(element) {
20
+ if (!element || element.nodeType !== 1) {
21
+ return null;
38
22
  }
39
23
 
40
- const children = Array.from(node.children);
24
+ if (element === document.documentElement) {
25
+ return "/html[1]";
26
+ }
41
27
 
42
- for (const child of children) {
43
- const originalElement = document.querySelector(
44
- `[ag-data-temp-id="${child.getAttribute("ag-data-temp-id")}"]`,
45
- );
28
+ const parts = [];
29
+ let current = element;
46
30
 
47
- if (!originalElement) {
48
- child.remove();
49
- continue;
31
+ while (current && current.nodeType === 1) {
32
+ if (current === document.documentElement) {
33
+ parts.unshift("/html[1]");
34
+ break;
50
35
  }
51
36
 
52
- if (isElementHidden(originalElement)) {
53
- child.remove();
54
- } else {
55
- removeHiddenElementsFromNode(child);
37
+ let index = 1;
38
+ let sibling = current.previousElementSibling;
39
+ while (sibling) {
40
+ if (sibling.tagName === current.tagName) {
41
+ index++;
42
+ }
43
+ sibling = sibling.previousElementSibling;
56
44
  }
45
+
46
+ const tagName = current.tagName.toLowerCase();
47
+ parts.unshift(`${tagName}[${index}]`);
48
+ current = current.parentElement;
57
49
  }
50
+
51
+ return parts.join("/");
58
52
  }
59
53
 
60
- function addTempIds(node, prefix = "") {
61
- if (!node || node.nodeType !== Node.ELEMENT_NODE) {
54
+ function traverseAndMarkHidden(element, hiddenXPaths) {
55
+ if (!element || element.nodeType !== 1) {
62
56
  return;
63
57
  }
64
58
 
65
- const children = Array.from(node.children);
66
- children.forEach((child, index) => {
67
- const tempId = `${prefix}${index}`;
68
- child.setAttribute("ag-data-temp-id", tempId);
69
- addTempIds(child, `${tempId}-`);
70
- });
71
- }
59
+ const tagName = element.tagName.toLowerCase();
60
+ if (
61
+ tagName === "script" ||
62
+ tagName === "style" ||
63
+ tagName === "noscript"
64
+ ) {
65
+ const xpath = getXPath(element);
66
+ if (xpath) {
67
+ hiddenXPaths.push(xpath);
68
+ }
69
+ return;
70
+ }
72
71
 
73
- function removeTempIds(node) {
74
- if (!node || node.nodeType !== Node.ELEMENT_NODE) {
72
+ if (!isElementVisible(element)) {
73
+ const xpath = getXPath(element);
74
+ if (xpath) {
75
+ hiddenXPaths.push(xpath);
76
+ }
75
77
  return;
76
78
  }
77
79
 
78
- node.removeAttribute("ag-data-temp-id");
79
- Array.from(node.children).forEach((child) => removeTempIds(child));
80
+ const children = Array.from(element.children);
81
+ for (const child of children) {
82
+ traverseAndMarkHidden(child, hiddenXPaths);
83
+ }
80
84
  }
81
85
 
82
- addTempIds(document.documentElement);
83
86
  const documentClone = document.documentElement.cloneNode(true);
87
+ const cloneDoc = document.implementation.createHTMLDocument("");
88
+ cloneDoc.replaceChild(documentClone, cloneDoc.documentElement);
89
+
90
+ const hiddenXPaths = [];
91
+ traverseAndMarkHidden(document.documentElement, hiddenXPaths);
92
+
93
+ for (const xpath of hiddenXPaths) {
94
+ const result = cloneDoc.evaluate(
95
+ xpath,
96
+ cloneDoc,
97
+ null,
98
+ XPathResult.FIRST_ORDERED_NODE_TYPE,
99
+ null,
100
+ );
101
+ const cloneElement = result.singleNodeValue;
102
+ if (cloneElement) {
103
+ cloneElement.setAttribute("data-hidden", "true");
104
+ }
105
+ }
84
106
 
85
- removeHiddenElementsFromNode(documentClone);
86
-
87
- removeTempIds(document.documentElement);
88
- removeTempIds(documentClone);
107
+ const hiddenElements = cloneDoc.querySelectorAll("[data-hidden='true']");
108
+ hiddenElements.forEach((el) => el.remove());
89
109
 
90
- const filteredHTML = documentClone.outerHTML;
110
+ const filteredHTML = cloneDoc.documentElement.outerHTML;
91
111
 
92
112
  return {
93
113
  success: true,
@@ -0,0 +1,25 @@
1
+ function scrollToElement(xpath) {
2
+ const result = document.evaluate(
3
+ xpath,
4
+ document,
5
+ null,
6
+ XPathResult.FIRST_ORDERED_NODE_TYPE,
7
+ null,
8
+ );
9
+ const element = result.singleNodeValue;
10
+
11
+ if (!element) {
12
+ return { success: false, error: "Element not found with provided xpath" };
13
+ }
14
+
15
+ element.scrollIntoView({
16
+ behavior: "instant",
17
+ block: "center",
18
+ inline: "center",
19
+ });
20
+
21
+ return {
22
+ success: true,
23
+ message: "Scrolled to element using scrollIntoView()",
24
+ };
25
+ }
@@ -430,19 +430,13 @@ class JavaScriptLoader:
430
430
  """
431
431
  return js_code + "\n" + wrapper
432
432
 
433
- def get_scroll_page_js(
434
- self, direction: str, distance: int, xpath: str = "", element_uuid: str = ""
435
- ) -> str:
436
- js_code = self.load_js_file("scroll_page.js")
433
+ def get_scroll_to_element_js(self, xpath: str) -> str:
434
+ js_code = self.load_js_file("scroll_to_element.js")
437
435
  escaped_xpath = xpath.replace("`", "\\`").replace("\\", "\\\\")
438
- escaped_uuid = element_uuid.replace("`", "\\`").replace("\\", "\\\\")
439
436
  wrapper = f"""
440
437
  (() => {{
441
- const direction = '{direction}';
442
- const distance = {distance};
443
438
  const xpath = `{escaped_xpath}`;
444
- const elementUuid = `{escaped_uuid}`;
445
- return scrollPage(direction, distance, xpath, elementUuid);
439
+ return scrollToElement(xpath);
446
440
  }})();
447
441
  """
448
442
  return js_code + "\n" + wrapper
@@ -189,19 +189,19 @@ class BrowserAutomationService:
189
189
  "xpath": xpath,
190
190
  }
191
191
 
192
- time.sleep(0.5)
192
+ time.sleep(0.2)
193
193
 
194
194
  self.chrome_interface.Input.dispatchMouseEvent(
195
195
  type="mousePressed", x=x, y=y, button="left", clickCount=1
196
196
  )
197
197
 
198
- time.sleep(0.02)
198
+ time.sleep(0.05)
199
199
 
200
200
  self.chrome_interface.Input.dispatchMouseEvent(
201
201
  type="mouseReleased", x=x, y=y, button="left", clickCount=1
202
202
  )
203
203
 
204
- time.sleep(1)
204
+ time.sleep(0.5)
205
205
 
206
206
  return {
207
207
  "success": True,
@@ -222,16 +222,12 @@ class BrowserAutomationService:
222
222
  "xpath": xpath,
223
223
  }
224
224
 
225
- def scroll_page(
226
- self, direction: str, amount: int = 3, element_uuid: Optional[str] = None
227
- ) -> Dict[str, Any]:
225
+ def scroll_to_element(self, element_uuid: str) -> Dict[str, Any]:
228
226
  """
229
- Scroll the page or a specific element in specified direction.
227
+ Scroll to bring a specific element into view.
230
228
 
231
229
  Args:
232
- direction: Direction to scroll ('up', 'down', 'left', 'right')
233
- amount: Number of scroll units (default: 3)
234
- element_uuid: Optional UUID of element to scroll (defaults to document)
230
+ element_uuid: UUID of the element to scroll to
235
231
 
236
232
  Returns:
237
233
  Dict containing scroll result
@@ -242,45 +238,32 @@ class BrowserAutomationService:
242
238
  if self.chrome_interface is None:
243
239
  raise RuntimeError("Chrome interface is not initialized")
244
240
 
245
- scroll_distance = amount * 300
246
-
247
- xpath = None
248
- if element_uuid:
249
- xpath = self.uuid_to_xpath_mapping.get(element_uuid)
250
- if not xpath:
251
- return {
252
- "success": False,
253
- "error": f"Element UUID '{element_uuid}' not found. Please use browser_get_content to get current element UUIDs.",
254
- "uuid": element_uuid,
255
- "direction": direction,
256
- "amount": amount,
257
- }
241
+ xpath = self.uuid_to_xpath_mapping.get(element_uuid)
242
+ if not xpath:
243
+ return {
244
+ "success": False,
245
+ "error": f"Element UUID '{element_uuid}' not found. Please use browser_get_content to get current element UUIDs.",
246
+ "uuid": element_uuid,
247
+ }
258
248
 
259
- js_code = js_loader.get_scroll_page_js(
260
- direction, scroll_distance, xpath or "", element_uuid or ""
261
- )
249
+ js_code = js_loader.get_scroll_to_element_js(xpath)
262
250
 
263
251
  scroll_result = JavaScriptExecutor.execute_and_parse_result(
264
252
  self.chrome_interface, js_code
265
253
  )
266
254
 
267
- time.sleep(1.5)
255
+ time.sleep(0.5)
268
256
 
269
- result_data = {"direction": direction, "amount": amount, **scroll_result}
270
- if element_uuid:
271
- result_data["uuid"] = element_uuid
272
- result_data["xpath"] = xpath
257
+ result_data = {"uuid": element_uuid, "xpath": xpath, **scroll_result}
273
258
  return result_data
274
259
 
275
260
  except Exception as e:
276
- logger.error(f"Scroll error: {e}")
277
- error_data = {
261
+ logger.error(f"Scroll to element error: {e}")
262
+ return {
278
263
  "success": False,
279
- "error": f"Scroll error: {str(e)}",
280
- "direction": direction,
281
- "amount": amount,
264
+ "error": f"Scroll to element error: {str(e)}",
265
+ "uuid": element_uuid,
282
266
  }
283
- return error_data
284
267
 
285
268
  def get_page_content(self) -> Dict[str, Any]:
286
269
  """
@@ -27,7 +27,7 @@ def get_browser_navigate_tool_definition(provider="claude") -> Dict[str, Any]:
27
27
 
28
28
  if provider == "claude":
29
29
  return {
30
- "name": "navigate_url",
30
+ "name": "open_browser_url",
31
31
  "description": tool_description,
32
32
  "input_schema": {
33
33
  "type": "object",
@@ -39,7 +39,7 @@ def get_browser_navigate_tool_definition(provider="claude") -> Dict[str, Any]:
39
39
  return {
40
40
  "type": "function",
41
41
  "function": {
42
- "name": "navigate_url",
42
+ "name": "open_browser_url",
43
43
  "description": tool_description,
44
44
  "parameters": {
45
45
  "type": "object",
@@ -86,35 +86,22 @@ def get_browser_click_tool_definition(provider="claude") -> Dict[str, Any]:
86
86
  }
87
87
 
88
88
 
89
- def get_browser_scroll_tool_definition(provider="claude") -> Dict[str, Any]:
90
- """Get tool definition for browser scrolling."""
89
+ def get_browser_scroll_to_element_tool_definition(provider="claude") -> Dict[str, Any]:
90
+ """Get tool definition for scrolling to a specific element."""
91
91
  tool_description = (
92
- "Scroll page or element in specified direction. Each unit moves ~300px."
92
+ "Scroll to bring a specific element into view at the center of the viewport."
93
93
  )
94
94
  tool_arguments = {
95
- "direction": {
96
- "type": "string",
97
- "enum": ["up", "down", "left", "right"],
98
- "description": "Scroll direction.",
99
- },
100
- "amount": {
101
- "type": "integer",
102
- "description": "Scroll units (default: 3). Range 1-10.",
103
- "default": 3,
104
- "minimum": 1,
105
- "maximum": 10,
106
- },
107
95
  "element_uuid": {
108
96
  "type": "string",
109
- "description": "Optional UUID for specific element to scroll. Scrolls document if not provided.",
110
- "default": "document",
97
+ "description": "UUID of the element to scroll to. Get this from browser_get_content.",
111
98
  },
112
99
  }
113
- tool_required = ["direction", "element_uuid"]
100
+ tool_required = ["element_uuid"]
114
101
 
115
102
  if provider == "claude":
116
103
  return {
117
- "name": "scroll_browser",
104
+ "name": "scroll_to_browser_element",
118
105
  "description": tool_description,
119
106
  "input_schema": {
120
107
  "type": "object",
@@ -122,11 +109,11 @@ def get_browser_scroll_tool_definition(provider="claude") -> Dict[str, Any]:
122
109
  "required": tool_required,
123
110
  },
124
111
  }
125
- else: # provider == "groq" or other OpenAI-compatible
112
+ else:
126
113
  return {
127
114
  "type": "function",
128
115
  "function": {
129
- "name": "scroll_browser",
116
+ "name": "scroll_to_browser_element",
130
117
  "description": tool_description,
131
118
  "parameters": {
132
119
  "type": "object",
@@ -253,35 +240,27 @@ def get_browser_click_tool_handler(
253
240
  return handle_browser_click
254
241
 
255
242
 
256
- def get_browser_scroll_tool_handler(
243
+ def get_browser_scroll_to_element_tool_handler(
257
244
  browser_service: BrowserAutomationService,
258
245
  ) -> Callable:
259
- """Get the handler function for the browser scroll tool."""
246
+ """Get the handler function for the scroll to element tool."""
260
247
 
261
- def handle_browser_scroll(**params) -> str:
262
- direction = params.get("direction")
263
- amount = params.get("amount", 3)
248
+ def handle_browser_scroll_to_element(**params) -> str:
264
249
  element_uuid = params.get("element_uuid")
265
250
 
266
- if not direction:
267
- return "Error: No scroll direction provided."
251
+ if not element_uuid:
252
+ return "Error: No element_uuid provided."
268
253
 
269
- if direction not in ["up", "down", "left", "right"]:
270
- return (
271
- "Error: Invalid scroll direction. Use 'up', 'down', 'left', or 'right'."
272
- )
273
-
274
- result = browser_service.scroll_page(
275
- direction, amount, element_uuid if element_uuid != "document" else None
276
- )
254
+ result = browser_service.scroll_to_element(element_uuid)
277
255
 
278
256
  if result.get("success", True):
279
257
  return f"{result.get('message', 'Success')}, Call `get_browser_content` tool to get the updated content."
280
258
  else:
281
- uuid_info = f"\nUUID: {element_uuid}" if element_uuid else ""
282
- raise RuntimeError(f"Scroll failed: {result['error']}{uuid_info}")
259
+ raise RuntimeError(
260
+ f"Scroll to element failed: {result['error']}\nUUID: {element_uuid}"
261
+ )
283
262
 
284
- return handle_browser_scroll
263
+ return handle_browser_scroll_to_element
285
264
 
286
265
 
287
266
  def get_browser_input_tool_definition(provider="claude") -> Dict[str, Any]:
@@ -665,8 +644,8 @@ def register(service_instance=None, agent=None):
665
644
  agent,
666
645
  )
667
646
  register_tool(
668
- get_browser_scroll_tool_definition,
669
- get_browser_scroll_tool_handler,
647
+ get_browser_scroll_to_element_tool_definition,
648
+ get_browser_scroll_to_element_tool_handler,
670
649
  service_instance,
671
650
  agent,
672
651
  )
@@ -31,6 +31,8 @@ def get_run_command_tool_definition(provider="claude") -> Dict[str, Any]:
31
31
  "timeout": {
32
32
  "type": "integer",
33
33
  "description": "Seconds (default: 5, max: 60). Returns command_id if still running.",
34
+ "minimum": 5,
35
+ "maximum": 60,
34
36
  "default": 5,
35
37
  },
36
38
  "working_dir": {
@@ -220,8 +222,10 @@ def get_run_command_tool_handler(command_service: CommandExecutionService) -> Ca
220
222
 
221
223
  if not command:
222
224
  raise ValueError("Missing required parameter: command")
223
- if timeout < 1 or timeout > 60:
224
- raise ValueError("Timeout must be between 1 and 60 seconds")
225
+ if timeout < 5:
226
+ timeout = 5
227
+ elif timeout > 60:
228
+ timeout = 60
225
229
 
226
230
  result = command_service.execute_command(
227
231
  command=command, timeout=timeout, working_dir=working_dir, env_vars=env_vars
@@ -227,9 +227,13 @@ class CommandHandlers:
227
227
 
228
228
  Args:
229
229
  file_or_url: Path to local file or URL to fetch agent configuration
230
+ Supports @hub/ prefix which converts to https://agentplace.cloud/
230
231
  """
231
232
  try:
232
- # Show download message if URL
233
+ if file_or_url.startswith("@hub/"):
234
+ hub_host = os.environ.get("AGENTCREW_HUB_HOST", "https://agentplace.cloud")
235
+ file_or_url = hub_host.rstrip("/") + "/" + file_or_url[5:]
236
+
233
237
  if file_or_url.startswith(("http://", "https://")):
234
238
  self.console.print(
235
239
  Text(
@@ -190,7 +190,7 @@ class ConsoleUI(Observer):
190
190
  )
191
191
  preview_text = Text("Conversation rewound to: ", style=RICH_STYLE_YELLOW)
192
192
  preview_text.append(data["preview"])
193
- self._clean_and_reprint_chat()
193
+ self._clear_and_reprint_chat()
194
194
 
195
195
  self.display_handlers.display_message(jump_text)
196
196
  self.display_handlers.display_message(preview_text)
@@ -292,7 +292,7 @@ class ConsoleUI(Observer):
292
292
  return # Ignore resize during message processing
293
293
  self._is_resizing = True
294
294
  time.sleep(0.5) # brief pause to allow resize to complete
295
- self._clean_and_reprint_chat()
295
+ self._clear_and_reprint_chat()
296
296
  self.display_handlers.print_divider("👤 YOU: ", with_time=True)
297
297
  prompt = Text(
298
298
  PROMPT_CHAR,
@@ -307,7 +307,7 @@ class ConsoleUI(Observer):
307
307
  self.console.print(prompt, end="")
308
308
  self._is_resizing = False
309
309
 
310
- def _clean_and_reprint_chat(self):
310
+ def _clear_and_reprint_chat(self):
311
311
  """Clear and reprint the chat display."""
312
312
 
313
313
  import os
@@ -105,9 +105,9 @@ class InputHandler:
105
105
  file_command = paste_result["content"]
106
106
 
107
107
  # Insert the file command into the current buffer
108
- event.current_buffer.insert_text(file_command)
109
- event.current_buffer.validate_and_handle()
110
-
108
+ self._jumped_user_message = event.current_buffer.text
109
+ event.current_buffer.reset()
110
+ self._input_queue.put(file_command)
111
111
  return
112
112
 
113
113
  # For regular text content, use default paste behavior
@@ -268,13 +268,13 @@ class InputHandler:
268
268
  self._current_prompt_session.app.current_buffer.reset()
269
269
  if self._jumped_user_message:
270
270
  self._current_prompt_session.app.current_buffer.insert_text(
271
- self._jumped_user_message
271
+ self._jumped_user_message, overwrite=True
272
272
  )
273
273
  self._jumped_user_message = ""
274
- if not self.is_message_processing:
275
- self.display_handlers.print_divider("👤 YOU: ", with_time=True)
276
274
  self._current_prompt_session.message = HTML(PROMPT_CHAR)
277
275
  self._current_prompt_session.app.invalidate()
276
+ if not self.is_message_processing:
277
+ self.display_handlers.print_divider("👤 YOU: ", with_time=True)
278
278
 
279
279
  def get_choice_input(self, message: str, values: list[str], default=None) -> str:
280
280
  from prompt_toolkit.shortcuts import choice
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: agentcrew-ai
3
- Version: 0.8.7
3
+ Version: 0.8.8
4
4
  Summary: Multi-Agents Interactive Chat Tool
5
5
  Author-email: Quy Truong <quy.truong@saigontechnology.com>
6
6
  License-Expression: Apache-2.0
@@ -1,4 +1,4 @@
1
- AgentCrew/__init__.py,sha256=vTwvdJOZi8jZb9U-Em7-d50qNDNPS2z51IXqRoojeNM,22
1
+ AgentCrew/__init__.py,sha256=S5bBAK8bL7bybaXGJQuNE98fa3H65zGjTASMiyKGJGw,22
2
2
  AgentCrew/app.py,sha256=s3pPfZfaZYxCNUC3HYWVQScK1iQZil6_Xguht3XX6mc,36603
3
3
  AgentCrew/main.py,sha256=tjyw4Z29YKKyzVKqDgF5icI1IM59DUiJrXZw6Sv_xN8,11187
4
4
  AgentCrew/main_docker.py,sha256=1jpB-XOm-t3GWTKYidGHHkCSzJ-p39ua0E6-_Nj8_9Y,5472
@@ -23,7 +23,7 @@ AgentCrew/modules/agents/__init__.py,sha256=rMwchcGZzapLLZdUQUaJtCLowHoG-dOn8_Vl
23
23
  AgentCrew/modules/agents/base.py,sha256=i7w0X7mcTRWwgyQwqN-iOIniLce9cSM2wGG3njlZpHk,2641
24
24
  AgentCrew/modules/agents/example.py,sha256=_-Nd7EKHprKXZLN9_ava0b9vR7wGyUzsXSEV7_js7Ho,6894
25
25
  AgentCrew/modules/agents/local_agent.py,sha256=dVm4DBceUqxICgAM0_5gni2F94vEt2cdqxrakpDEX5s,31828
26
- AgentCrew/modules/agents/manager.py,sha256=JHwEp-GwlYMRTv2RItfJOnVJlePZOLK31xYi3taEuF0,24863
26
+ AgentCrew/modules/agents/manager.py,sha256=DDFReehIWCjJLZImqR2VXOOMCfrrXOr8EeLrOkUHHJk,25177
27
27
  AgentCrew/modules/agents/remote_agent.py,sha256=bBgO8E3dXZuu9ofklXLfL5-8mxF_XZOLyqj6rrwTXR8,6432
28
28
  AgentCrew/modules/agents/tools/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
29
29
  AgentCrew/modules/agents/tools/ask.py,sha256=MAv1HOjIdXDIMHmQ7J6Jvlr9r9wBFSMBVYX6MsG14rI,5161
@@ -34,19 +34,19 @@ AgentCrew/modules/anthropic/service.py,sha256=olpiiptIVubc11zmbALOoAMFU-XVx_bIHc
34
34
  AgentCrew/modules/browser_automation/__init__.py,sha256=1Qq6Rqz4Mv4arPKWKSDgIOV-G72R5Jey2-qdkLMLVKA,86
35
35
  AgentCrew/modules/browser_automation/chrome_manager.py,sha256=iBFcImVoeUF5qc8eRzSsihuBSiPhDF0DOSYfda7OHas,11901
36
36
  AgentCrew/modules/browser_automation/element_extractor.py,sha256=J1Gp6xDSWFDt7690JgBhX6ryXfNeVUCLwYBA3IGtCqo,15914
37
- AgentCrew/modules/browser_automation/js_loader.py,sha256=vdm-cQA5I4sL5Y0s7iaMnxSwcu0IZEdtczCgoHXAkK4,18315
38
- AgentCrew/modules/browser_automation/service.py,sha256=VFgDOoCqamL_YTRrJ7G596KKsOz3UF6Kg2u4FRfYYwU,28247
39
- AgentCrew/modules/browser_automation/tool.py,sha256=q62Cmo8bgGFs-8PrXKqOYJRNniNAUkCc54wUirOKG2s,23997
40
- AgentCrew/modules/browser_automation/js/click_element.js,sha256=eNkbPX9wXyj9mPnfNILJjtbiPF0iKCT52bfTFQRhT1Y,1652
37
+ AgentCrew/modules/browser_automation/js_loader.py,sha256=gw5ifmsenH85V2KOgtqsQpyunvWNazEeH7u_NESDK40,18010
38
+ AgentCrew/modules/browser_automation/service.py,sha256=uG-ltAqtJwiS8KVAdVzf7STbYh6Rt2_4lVFIXDTSws8,27546
39
+ AgentCrew/modules/browser_automation/tool.py,sha256=oKhrEeE4pld4GHbxxz6Ia3eyOq11AOZyO8tv6GbjCEQ,23263
40
+ AgentCrew/modules/browser_automation/js/click_element.js,sha256=7xoSo6tYiUNupWuVARmKsNEsGnJXyOSMAYNQhsTgvW8,1571
41
41
  AgentCrew/modules/browser_automation/js/draw_element_boxes.js,sha256=4ToM8UYy2HUyXCC2l219Zghjj2lG3JZD1X2mjsLgdtU,5781
42
42
  AgentCrew/modules/browser_automation/js/extract_clickable_elements.js,sha256=UlOZ68-SyJtSc9GBYTHF-caDDKoxaJ-4UXvedPO8U7Q,5818
43
- AgentCrew/modules/browser_automation/js/extract_elements_by_text.js,sha256=0Ao1nXvhXjm98ff2r_EE4DYaUSN78Qz6HS6l0cqnaHg,3264
43
+ AgentCrew/modules/browser_automation/js/extract_elements_by_text.js,sha256=_dKahrzNncwWKt4wbCq6tQyb5mV3wbVaZTiOKBcFIp0,3138
44
44
  AgentCrew/modules/browser_automation/js/extract_input_elements.js,sha256=UIZRK5PbVAKvOn7YdBZNNA1exGwo1XiiRGWkmCH71ME,6994
45
45
  AgentCrew/modules/browser_automation/js/extract_scrollable_elements.js,sha256=7V4dK9B0q0JfUv6NJYsRgx7YhujGByuy8ETSNVL1o6Q,5915
46
- AgentCrew/modules/browser_automation/js/filter_hidden_elements.js,sha256=hJyj3jYUe1rABHeSQ72ds1aJp5geKwN90whL9-sooYg,2561
46
+ AgentCrew/modules/browser_automation/js/filter_hidden_elements.js,sha256=vmOoz90KyX1DB-oJKfJnbFCthp4fQVT17pslmycsDEo,3049
47
47
  AgentCrew/modules/browser_automation/js/focus_and_clear_element.js,sha256=fxN26bwmCTWq2nMM0PaBA3FElrSL1JCh0Oxj57MwCAM,2057
48
48
  AgentCrew/modules/browser_automation/js/remove_element_boxes.js,sha256=qLFuLyWMiRM4-CI2aMYnYBeOVXDgOJVPq0JhgI6zfQo,647
49
- AgentCrew/modules/browser_automation/js/scroll_page.js,sha256=A9ckNhluui6CyYvPS6E4c9DrcZJn7akpLpbNdiZZahs,4388
49
+ AgentCrew/modules/browser_automation/js/scroll_to_element.js,sha256=xeQw5F-IpRUarGBVqYdkPXd9Yfm_D8_-P2FVtj_N34w,504
50
50
  AgentCrew/modules/browser_automation/js/trigger_input_events.js,sha256=WtPOmebgBmlP1xgkclSna30rLv5SJjvrqg6Vv-MSgd8,1347
51
51
  AgentCrew/modules/chat/__init__.py,sha256=WCIbdcpiuFfMmR4RpyNwG3SpjDbjPZTe233VAjFtVAM,189
52
52
  AgentCrew/modules/chat/consolidation.py,sha256=pCRsA4mdzH_ryHxHrFX2jI5aDTXuPon7ySe0aZpcnUw,10635
@@ -68,20 +68,20 @@ AgentCrew/modules/code_analysis/tool.py,sha256=BRkouK2radiW0_IAz8ptPdTLodDMsGzjE
68
68
  AgentCrew/modules/command_execution/__init__.py,sha256=BIy7TSuz6yFaUQ0GEvXZO-ZSlkSwcRxforfIIhHCMTM,380
69
69
  AgentCrew/modules/command_execution/constants.py,sha256=zG2pwmA3MqBhnJgPrcBgzxzH2sWCbXQ4NyidX8lKQ6I,4693
70
70
  AgentCrew/modules/command_execution/service.py,sha256=cd0AkBKee_0oj4WezJo_ZICXTJ-kkcMT4J-oPN7aHz0,24814
71
- AgentCrew/modules/command_execution/tool.py,sha256=uEznyb0ii2xLRsmoZLdwyb2oYi0tleeGVUKnggOYN1w,14009
71
+ AgentCrew/modules/command_execution/tool.py,sha256=v2nQMlcp3uA-GXpjNM_COxzrMfSrsEf1_yu37730tz0,14049
72
72
  AgentCrew/modules/command_execution/types.py,sha256=kosDGBMF7DFGLdhxYxhOOZHf0URKWejLluUeCCfP5EI,2477
73
73
  AgentCrew/modules/config/__init__.py,sha256=ehO0aAkK98f9BmMjG9uR15Hc9Lwj9CnJZl24XUtUT_M,80
74
74
  AgentCrew/modules/config/config_management.py,sha256=yxmfx1nQAZxTzJ4g3F3ybYlmTTFpMmKxfNETyzsQ9uA,33648
75
75
  AgentCrew/modules/console/__init__.py,sha256=nO53lUaMEAshdIqDEmgNZ_r35jyg6CuMa7Tsj55Y09g,66
76
- AgentCrew/modules/console/command_handlers.py,sha256=qBl5GjZVnuaMJdilJKcPsYpU1E-XbI_Nv5veINU-cic,16232
76
+ AgentCrew/modules/console/command_handlers.py,sha256=1r1iW_zWFZMAqRwyYk9vM6N_2hLnLr2zPMx2013nrow,16495
77
77
  AgentCrew/modules/console/completers.py,sha256=WeP5rJvCWq4Ept2_ajK9wjpDiTT4C5blcX5TeV3GSzU,17682
78
78
  AgentCrew/modules/console/confirmation_handler.py,sha256=sOhJVmrMgiqTlUI6G9xjzseeeWn54G-aOc6WevWcXL8,10221
79
- AgentCrew/modules/console/console_ui.py,sha256=09XkGsIivVQK4z1-gOyuHtdXfiMMAyc4DvnWHlvIqho,29836
79
+ AgentCrew/modules/console/console_ui.py,sha256=jfA3X_70fyCrE1f8zsG0b1wiNpxYCEVp8dhYb2ZM2KE,29836
80
80
  AgentCrew/modules/console/constants.py,sha256=fwLj52O96_t6m1qb0SOiaotM2dMLwXH83KAERm9ltLA,704
81
81
  AgentCrew/modules/console/conversation_handler.py,sha256=vVtGxQJ4sEZJ77svBFJMIGiWiEfE47yDxvt7gZ9bRCA,3632
82
82
  AgentCrew/modules/console/diff_display.py,sha256=HTFy5H0sx6OHN_yjMPUeF8aum7esdgIg9Xd4_gCvPaw,7193
83
83
  AgentCrew/modules/console/display_handlers.py,sha256=ZSpBZxvX5X9VB2dvAB679KQwPTVhRPHRrmsgCMhANyA,17651
84
- AgentCrew/modules/console/input_handler.py,sha256=SNoDDhdpIwrQ7mPhF427NnS8tT0pnCIbvbI1bCWwG-Q,18140
84
+ AgentCrew/modules/console/input_handler.py,sha256=Nn8H0RZiuF2asw8uum5n1otGOEb19U-_SMxVCTx3QTQ,18208
85
85
  AgentCrew/modules/console/tool_display.py,sha256=aTjNWcfzmJXwpXU64PqMfNFRCiVrtMD-JFn_Wd2cNYY,7306
86
86
  AgentCrew/modules/console/ui_effects.py,sha256=n5w863kI0VKU_afGmXjscYg8FmsaX4IJyNQRGCDoOLI,8218
87
87
  AgentCrew/modules/console/utils.py,sha256=TFIyyYVFlWMB0FCAq4H09Yp6UCezUEHg3HNEZXuVmiA,273
@@ -186,9 +186,9 @@ AgentCrew/modules/voice/text_cleaner.py,sha256=NgAVBPkP2hFI330nJOyMK_oqP3R2AGZ22
186
186
  AgentCrew/modules/web_search/__init__.py,sha256=sVf_z6nH2JghK46pG92PUtDghPIkceiX1F0Ul30euXU,111
187
187
  AgentCrew/modules/web_search/service.py,sha256=DKcOdRSHB5AEvbK8pvTXdffSnk6rFRTzaM1FXf2B70E,4006
188
188
  AgentCrew/modules/web_search/tool.py,sha256=GV4xleVFs0UwiPS9toSzPzZei3ehsDZWxTQCJCRaEs8,6655
189
- agentcrew_ai-0.8.7.dist-info/licenses/LICENSE,sha256=O51CIaOUcxVLNf0_PE_a8ap5bf3iXe4SrWN_5NO1PSU,11348
190
- agentcrew_ai-0.8.7.dist-info/METADATA,sha256=pAPP0PKBi1ZUFW77GcCitWRS63n7cRw3N5puToKl2ms,18056
191
- agentcrew_ai-0.8.7.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
192
- agentcrew_ai-0.8.7.dist-info/entry_points.txt,sha256=N9R5jslrBYA8dTaNMRJ_JdSosJ6jkpGEtnJFzlcZD6k,54
193
- agentcrew_ai-0.8.7.dist-info/top_level.txt,sha256=bSsmhCOn6g-JytoVMpxB_QAnCgb7lV56fcnxUhbfrvg,10
194
- agentcrew_ai-0.8.7.dist-info/RECORD,,
189
+ agentcrew_ai-0.8.8.dist-info/licenses/LICENSE,sha256=O51CIaOUcxVLNf0_PE_a8ap5bf3iXe4SrWN_5NO1PSU,11348
190
+ agentcrew_ai-0.8.8.dist-info/METADATA,sha256=cz6FnFH2CvTU0-GLEgqO0eEzO8K3wfw-J0q0QjvzMSg,18056
191
+ agentcrew_ai-0.8.8.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
192
+ agentcrew_ai-0.8.8.dist-info/entry_points.txt,sha256=N9R5jslrBYA8dTaNMRJ_JdSosJ6jkpGEtnJFzlcZD6k,54
193
+ agentcrew_ai-0.8.8.dist-info/top_level.txt,sha256=bSsmhCOn6g-JytoVMpxB_QAnCgb7lV56fcnxUhbfrvg,10
194
+ agentcrew_ai-0.8.8.dist-info/RECORD,,
@@ -1,146 +0,0 @@
1
- /**
2
- * Scroll the page or a specific element in specified direction.
3
- *
4
- * @param {string} direction - Direction to scroll ('up', 'down', 'left', 'right')
5
- * @param {number} distance - Distance to scroll in pixels
6
- * @param {string} xpath - Optional XPath of specific element to scroll
7
- * @param {string} elementUuid - Optional UUID of the element for identification
8
- * @returns {Object} Result object with success status, message, and scroll info
9
- */
10
- function scrollPage(direction, distance, xpath = "", elementUuid = "") {
11
- let scrollX = 0;
12
- let scrollY = 0;
13
-
14
- switch (direction.toLowerCase()) {
15
- case "up":
16
- scrollY = -distance;
17
- break;
18
- case "down":
19
- scrollY = distance;
20
- break;
21
- case "left":
22
- scrollX = -distance;
23
- break;
24
- case "right":
25
- scrollX = distance;
26
- break;
27
- default:
28
- return {
29
- success: false,
30
- error: "Invalid direction. Use 'up', 'down', 'left', or 'right'",
31
- };
32
- }
33
-
34
- // Determine scroll target (specific element or document)
35
- let scrollTarget = document.documentElement || document.body;
36
- let targetDescription = "the whole document";
37
-
38
- if (xpath && elementUuid) {
39
- const result = document.evaluate(
40
- xpath,
41
- document,
42
- null,
43
- XPathResult.FIRST_ORDERED_NODE_TYPE,
44
- null,
45
- );
46
- const element = result.singleNodeValue;
47
-
48
- if (!element) {
49
- return { success: false, error: "Element not found" };
50
- }
51
-
52
- // Check if element is scrollable
53
- const style = window.getComputedStyle(element);
54
- const hasScrollableOverflow =
55
- ["auto", "scroll"].includes(style.overflow) ||
56
- ["auto", "scroll"].includes(style.overflowY) ||
57
- ["auto", "scroll"].includes(style.overflowX);
58
-
59
- if (
60
- hasScrollableOverflow ||
61
- element.scrollHeight > element.clientHeight ||
62
- element.scrollWidth > element.clientWidth
63
- ) {
64
- scrollTarget = element;
65
- targetDescription = "element " + elementUuid;
66
- }
67
- }
68
-
69
- // Get current scroll position
70
- const currentX =
71
- scrollTarget === document.documentElement
72
- ? window.pageXOffset || document.documentElement.scrollLeft
73
- : scrollTarget.scrollLeft;
74
- const currentY =
75
- scrollTarget === document.documentElement
76
- ? window.pageYOffset || document.documentElement.scrollTop
77
- : scrollTarget.scrollTop;
78
-
79
- // Create wheel event for smooth scrolling
80
- const wheelEventOptions = {
81
- view: window,
82
- bubbles: true,
83
- cancelable: true,
84
- deltaX: scrollX,
85
- deltaY: scrollY,
86
- deltaMode: WheelEvent.DOM_DELTA_PIXEL,
87
- };
88
-
89
- try {
90
- // Dispatch wheel event to mimic true user scroll
91
- const wheelEvent = new WheelEvent("wheel", wheelEventOptions);
92
-
93
- if (scrollTarget === document.documentElement) {
94
- document.dispatchEvent(wheelEvent);
95
- // Also perform actual scroll for fallback
96
- window.scrollBy(scrollX, scrollY);
97
- } else {
98
- scrollTarget.dispatchEvent(wheelEvent);
99
- // Perform actual scroll on the element
100
- scrollTarget.scrollBy(scrollX, scrollY);
101
- }
102
- } catch (eventError) {
103
- // Fallback to direct scrolling if wheel event fails
104
- if (scrollTarget === document.documentElement) {
105
- window.scrollBy(scrollX, scrollY);
106
- } else {
107
- scrollTarget.scrollBy(scrollX, scrollY);
108
- }
109
- }
110
-
111
- // Get new scroll position
112
- const newX =
113
- scrollTarget === document.documentElement
114
- ? window.pageXOffset || document.documentElement.scrollLeft
115
- : scrollTarget.scrollLeft;
116
- const newY =
117
- scrollTarget === document.documentElement
118
- ? window.pageYOffset || document.documentElement.scrollTop
119
- : scrollTarget.scrollTop;
120
-
121
- return {
122
- success: true,
123
- message:
124
- "Scrolled " +
125
- targetDescription +
126
- " " +
127
- direction +
128
- " by " +
129
- Math.abs(scrollX || scrollY) +
130
- "px using dispatchEvent",
131
- previous_position: { x: currentX, y: currentY },
132
- new_position: { x: newX, y: newY },
133
- target: targetDescription,
134
- scroll_method: "wheel_event_with_fallback",
135
- };
136
- }
137
-
138
- // Export the function - when used in browser automation, wrap with IIFE and pass parameters
139
- // (() => {
140
- // const direction = '{DIRECTION_PLACEHOLDER}';
141
- // const distance = {DISTANCE_PLACEHOLDER};
142
- // const xpath = '{XPATH_PLACEHOLDER}';
143
- // const elementUuid = '{ELEMENT_UUID_PLACEHOLDER}';
144
- // return scrollPage(direction, distance, xpath, elementUuid);
145
- // })();
146
-