@eko-ai/eko 3.0.2 → 3.0.4

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.
package/dist/index.esm.js CHANGED
@@ -31361,28 +31361,6 @@ function extractUsedTool(messages, agentTools) {
31361
31361
  }
31362
31362
  return tools;
31363
31363
  }
31364
- function removeDuplicateToolUse(results) {
31365
- if (results.length <= 1 ||
31366
- results.filter((r) => r.type == "tool-call").length <= 1) {
31367
- return results;
31368
- }
31369
- let _results = [];
31370
- let tool_uniques = [];
31371
- for (let i = 0; i < results.length; i++) {
31372
- if (results[i].type === "tool-call") {
31373
- let tool = results[i];
31374
- let key = tool.toolName + tool.input;
31375
- if (tool_uniques.indexOf(key) == -1) {
31376
- _results.push(results[i]);
31377
- tool_uniques.push(key);
31378
- }
31379
- }
31380
- else {
31381
- _results.push(results[i]);
31382
- }
31383
- }
31384
- return _results;
31385
- }
31386
31364
  async function compressAgentMessages(agentContext, rlm, messages, tools) {
31387
31365
  if (messages.length < 5) {
31388
31366
  return;
@@ -32276,14 +32254,7 @@ const PLAN_SYSTEM_TEMPLATE = `
32276
32254
  You are {name}, an autonomous AI Agent Planner.
32277
32255
 
32278
32256
  ## Task Description
32279
- Your task is to understand the user's requirements, dynamically plan the user's tasks based on the Agent list, and please follow the steps below:
32280
- 1. Understand the user's requirements.
32281
- 2. Analyze the Agents that need to be used based on the user's requirements.
32282
- 3. Generate the Agent calling plan based on the analysis results.
32283
- 4. About agent name, please do not arbitrarily fabricate non-existent agent names.
32284
- 5. You only need to provide the steps to complete the user's task, key steps only, no need to be too detailed.
32285
- 6. Please strictly follow the output format and example output.
32286
- 7. The output language should follow the language corresponding to the user's task.
32257
+ {task_description}
32287
32258
 
32288
32259
  ## Agent list
32289
32260
  {agents}
@@ -32345,16 +32316,14 @@ Your task is to understand the user's requirements, dynamically plan the user's
32345
32316
 
32346
32317
  {example_prompt}
32347
32318
  `;
32348
- const PLAN_CHAT_EXAMPLE = `User: hello.
32349
- Output result:
32350
- <root>
32351
- <name>Chat</name>
32352
- <thought>Alright, the user wrote "hello". That's pretty straightforward. I need to respond in a friendly and welcoming manner.</thought>
32353
- <agents>
32354
- <!-- Chat agents can exist without the <task> and <nodes> nodes. -->
32355
- <agent name="Chat" id="0" dependsOn=""></agent>
32356
- </agents>
32357
- </root>`;
32319
+ const PLAN_TASK_DESCRIPTION = `Your task is to understand the user's requirements, dynamically plan the user's tasks based on the Agent list, and please follow the steps below:
32320
+ - Analyze the Agents that need to be used based on the user's requirements.
32321
+ - Generate the Agent calling plan based on the analysis results.
32322
+ - About agent name, please do not arbitrarily fabricate non-existent agent names.
32323
+ - You only need to provide the steps to complete the user's task, key steps only, no need to be too detailed.
32324
+ - Try to break down tasks into independently completable subtasks, and for maximum efficiency, run multiple independent subtasks in parallel whenever possible.
32325
+ - Please strictly follow the output format and example output.
32326
+ - The output language should follow the language corresponding to the user's task.`;
32358
32327
  const PLAN_EXAMPLE_LIST = [
32359
32328
  `User: Open Boss Zhipin, find 10 operation positions in Chengdu, and send a personal introduction to the recruiters based on the page information.
32360
32329
  Output result:
@@ -32512,7 +32481,7 @@ Task Website: {task_website}
32512
32481
  Current datetime: {datetime}
32513
32482
  Task Description: {task_prompt}
32514
32483
  `;
32515
- async function getPlanSystemPrompt(context) {
32484
+ async function getPlanSystemPrompt(context, planTaskDescription, planExampleList) {
32516
32485
  let agents_prompt = "";
32517
32486
  let agents = context.agents;
32518
32487
  for (let i = 0; i < agents.length; i++) {
@@ -32531,16 +32500,16 @@ async function getPlanSystemPrompt(context) {
32531
32500
  .join("\n") +
32532
32501
  "\n</agent>\n\n";
32533
32502
  }
32534
- let plan_example_list = context.variables.get("plan_example_list") || PLAN_EXAMPLE_LIST;
32535
- let hasChatAgent = context.agents.filter((a) => a.Name == "Chat").length > 0;
32503
+ const task_description = context.variables.get("plan_task_description") ||
32504
+ PLAN_TASK_DESCRIPTION;
32505
+ const plan_example_list = context.variables.get("plan_example_list") ||
32506
+ PLAN_EXAMPLE_LIST;
32536
32507
  let example_prompt = "";
32537
- const example_list = hasChatAgent
32538
- ? [PLAN_CHAT_EXAMPLE, ...plan_example_list]
32539
- : [...plan_example_list];
32540
- for (let i = 0; i < example_list.length; i++) {
32541
- example_prompt += `## Example ${i + 1}\n${example_list[i]}\n\n`;
32508
+ for (let i = 0; i < plan_example_list.length; i++) {
32509
+ example_prompt += `## Example ${i + 1}\n${plan_example_list[i]}\n\n`;
32542
32510
  }
32543
32511
  return PLAN_SYSTEM_TEMPLATE.replace("{name}", config$1.name)
32512
+ .replace("{task_description}", task_description)
32544
32513
  .replace("{agents}", agents_prompt.trim())
32545
32514
  .replace("{example_prompt}", example_prompt)
32546
32515
  .trim();
@@ -32587,8 +32556,7 @@ class Planner {
32587
32556
  const messages = [
32588
32557
  {
32589
32558
  role: "system",
32590
- content: this.context.variables.get("plan_sys_prompt") ||
32591
- (await getPlanSystemPrompt(this.context)),
32559
+ content: await getPlanSystemPrompt(this.context),
32592
32560
  },
32593
32561
  {
32594
32562
  role: "user",
@@ -35322,6 +35290,7 @@ You are {name}, an autonomous AI agent for {agent} agent.
35322
35290
  </nodes>
35323
35291
  </root>
35324
35292
 
35293
+ For maximum efficiency, whenever you need to perform multiple independent operations, invoke all relevant tools simultaneously rather than sequentially.
35325
35294
  The output language should follow the language corresponding to the user's task.
35326
35295
  `;
35327
35296
  const HUMAN_PROMPT = `
@@ -35342,7 +35311,7 @@ const FOR_EACH_NODE = `
35342
35311
  </forEach>`;
35343
35312
  const FOR_EACH_PROMPT = `
35344
35313
  * forEach node
35345
- repetitive tasks, when executing to the forEach node, require the use of the \`${TOOL_NAME$6}\` tool.
35314
+ For repetitive tasks, when executing a forEach node, the \`${TOOL_NAME$6}\` tool must be used. Loop tasks support parallel tool calls, and during parallel execution, this tool needs to be called interspersed throughout the process.
35346
35315
  `;
35347
35316
  const WATCH_NODE = `
35348
35317
  <!-- monitor task node, the loop attribute specifies whether to listen in a loop or listen once -->
@@ -35510,7 +35479,7 @@ class Agent {
35510
35479
  let context = agentContext.context;
35511
35480
  let user_messages = [];
35512
35481
  let toolResults = [];
35513
- results = removeDuplicateToolUse(results);
35482
+ // results = memory.removeDuplicateToolUse(results);
35514
35483
  if (results.length == 0) {
35515
35484
  return null;
35516
35485
  }
@@ -36034,7 +36003,7 @@ This is a computer GUI interface, observe the execution through screenshots, and
36034
36003
  return [
36035
36004
  {
36036
36005
  name: "typing",
36037
- description: "Type specified text",
36006
+ description: "Simulates keyboard typing to input text into the currently focused application or text field on the computer.",
36038
36007
  parameters: {
36039
36008
  type: "object",
36040
36009
  properties: {
@@ -36051,27 +36020,27 @@ This is a computer GUI interface, observe the execution through screenshots, and
36051
36020
  },
36052
36021
  {
36053
36022
  name: "click",
36054
- description: "Click at current or specified position",
36023
+ description: "Simulates mouse clicking at an absolute screen position (x, y) on the computer.",
36055
36024
  parameters: {
36056
36025
  type: "object",
36057
36026
  properties: {
36058
36027
  x: {
36059
36028
  type: "number",
36060
- description: "X coordinate",
36029
+ description: "Absolute X coordinate on the screen where the mouse will click",
36061
36030
  },
36062
36031
  y: {
36063
36032
  type: "number",
36064
- description: "Y coordinate",
36033
+ description: "Absolute Y coordinate on the screen where the mouse will click",
36065
36034
  },
36066
36035
  num_clicks: {
36067
36036
  type: "number",
36068
- description: "Number of clicks",
36037
+ description: "Number of times to click at the position",
36069
36038
  enum: [1, 2, 3],
36070
36039
  default: 1,
36071
36040
  },
36072
36041
  button: {
36073
36042
  type: "string",
36074
- description: "Mouse button to click",
36043
+ description: "Which mouse button to click",
36075
36044
  enum: ["left", "right", "middle"],
36076
36045
  default: "left",
36077
36046
  },
@@ -36084,17 +36053,17 @@ This is a computer GUI interface, observe the execution through screenshots, and
36084
36053
  },
36085
36054
  {
36086
36055
  name: "move_to",
36087
- description: "Move cursor to specified position",
36056
+ description: "Moves the mouse cursor to the specified screen coordinates.",
36088
36057
  parameters: {
36089
36058
  type: "object",
36090
36059
  properties: {
36091
36060
  x: {
36092
36061
  type: "number",
36093
- description: "X coordinate",
36062
+ description: "Absolute X coordinate on the screen",
36094
36063
  },
36095
36064
  y: {
36096
36065
  type: "number",
36097
- description: "Y coordinate",
36066
+ description: "Absolute Y coordinate on the screen",
36098
36067
  },
36099
36068
  },
36100
36069
  required: ["x", "y"],
@@ -36105,7 +36074,7 @@ This is a computer GUI interface, observe the execution through screenshots, and
36105
36074
  },
36106
36075
  {
36107
36076
  name: "scroll",
36108
- description: "Scroll the mouse wheel at current position",
36077
+ description: "Scroll the mouse wheel vertically at the current pointer location.",
36109
36078
  parameters: {
36110
36079
  type: "object",
36111
36080
  properties: {
@@ -36131,13 +36100,13 @@ This is a computer GUI interface, observe the execution through screenshots, and
36131
36100
  },
36132
36101
  {
36133
36102
  name: "press",
36134
- description: "Press and release a key",
36103
+ description: "Simulate pressing and releasing a specific keyboard key",
36135
36104
  parameters: {
36136
36105
  type: "object",
36137
36106
  properties: {
36138
36107
  key: {
36139
36108
  type: "string",
36140
- description: "Key to press",
36109
+ description: "The keyboard key",
36141
36110
  enum: keyboardKeys,
36142
36111
  },
36143
36112
  },
@@ -36149,13 +36118,13 @@ This is a computer GUI interface, observe the execution through screenshots, and
36149
36118
  },
36150
36119
  {
36151
36120
  name: "hotkey",
36152
- description: "Press a key combination",
36121
+ description: "Simulate pressing one or more keyboard keys, including combinations.",
36153
36122
  parameters: {
36154
36123
  type: "object",
36155
36124
  properties: {
36156
36125
  keys: {
36157
36126
  type: "string",
36158
- description: "Key combination to press",
36127
+ description: "A single key or a combination of keys to press. For combinations, use '+' to join keys.",
36159
36128
  enum: keyboardKeys,
36160
36129
  },
36161
36130
  },
@@ -36167,25 +36136,25 @@ This is a computer GUI interface, observe the execution through screenshots, and
36167
36136
  },
36168
36137
  {
36169
36138
  name: "drag_and_drop",
36170
- description: "Drag and drop operation",
36139
+ description: "Performs a mouse drag-and-drop operation from a starting point to a target point on the screen.",
36171
36140
  parameters: {
36172
36141
  type: "object",
36173
36142
  properties: {
36174
36143
  x1: {
36175
36144
  type: "number",
36176
- description: "From X coordinate",
36145
+ description: "Absolute X coordinate of the starting point (in pixels).",
36177
36146
  },
36178
36147
  y1: {
36179
36148
  type: "number",
36180
- description: "From Y coordinate",
36149
+ description: "Absolute Y coordinate of the starting point (in pixels).",
36181
36150
  },
36182
36151
  x2: {
36183
36152
  type: "number",
36184
- description: "Target X coordinate",
36153
+ description: "Absolute X coordinate of the ending (target) point (in pixels).",
36185
36154
  },
36186
36155
  y2: {
36187
36156
  type: "number",
36188
- description: "Target Y coordinate",
36157
+ description: "Absolute Y coordinate of the ending (target) point (in pixels).",
36189
36158
  },
36190
36159
  },
36191
36160
  required: ["x1", "y1", "x2", "y2"],
@@ -36197,13 +36166,13 @@ This is a computer GUI interface, observe the execution through screenshots, and
36197
36166
  {
36198
36167
  name: "wait",
36199
36168
  noPlan: true,
36200
- description: "Wait for specified duration",
36169
+ description: "Wait/pause execution for a specified duration. Use this tool when you need to wait for data loading, or introduce delays between operations.",
36201
36170
  parameters: {
36202
36171
  type: "object",
36203
36172
  properties: {
36204
36173
  duration: {
36205
36174
  type: "number",
36206
- description: "Duration in millisecond",
36175
+ description: "Wait duration in milliseconds",
36207
36176
  default: 500,
36208
36177
  minimum: 200,
36209
36178
  maximum: 10000,
@@ -36524,6 +36493,27 @@ class BaseBrowserAgent extends Agent {
36524
36493
 
36525
36494
  // @ts-nocheck
36526
36495
  function run_build_dom_tree() {
36496
+ var computedStyleCache = new WeakMap();
36497
+ /**
36498
+ * Gets the cached computed style for an element.
36499
+ */
36500
+ function getCachedComputedStyle(element) {
36501
+ if (!element)
36502
+ return null;
36503
+ if (computedStyleCache.has(element)) {
36504
+ return computedStyleCache.get(element);
36505
+ }
36506
+ try {
36507
+ const style = window.getComputedStyle(element);
36508
+ if (style) {
36509
+ computedStyleCache.set(element, style);
36510
+ }
36511
+ return style;
36512
+ }
36513
+ catch (e) {
36514
+ return null;
36515
+ }
36516
+ }
36527
36517
  /**
36528
36518
  * Get clickable elements on the page
36529
36519
  *
@@ -36533,6 +36523,7 @@ function run_build_dom_tree() {
36533
36523
  */
36534
36524
  function get_clickable_elements(doHighlightElements = true, includeAttributes) {
36535
36525
  window.clickable_elements = {};
36526
+ computedStyleCache = new WeakMap();
36536
36527
  document.querySelectorAll("[eko-user-highlight-id]").forEach(ele => ele.removeAttribute("eko-user-highlight-id"));
36537
36528
  let page_tree = build_dom_tree(doHighlightElements);
36538
36529
  let element_tree = parse_node(page_tree);
@@ -36549,6 +36540,7 @@ function run_build_dom_tree() {
36549
36540
  if (highlight) {
36550
36541
  highlight.remove();
36551
36542
  }
36543
+ computedStyleCache = new WeakMap();
36552
36544
  }
36553
36545
  function clickable_elements_to_string(element_tree, includeAttributes) {
36554
36546
  if (!includeAttributes) {
@@ -36815,11 +36807,14 @@ function run_build_dom_tree() {
36815
36807
  }
36816
36808
  // Helper function to check if element is accepted
36817
36809
  function isElementAccepted(element) {
36818
- const leafElementDenyList = new Set(['svg', 'script', 'style', 'link', 'meta']);
36810
+ const leafElementDenyList = new Set(['svg', 'script', 'style', 'link', 'meta', 'noscript', 'template']);
36819
36811
  return !leafElementDenyList.has(element.tagName.toLowerCase());
36820
36812
  }
36821
36813
  // Helper function to check if element is interactive
36822
36814
  function isInteractiveElement(element) {
36815
+ if (!element || element.nodeType !== Node.ELEMENT_NODE) {
36816
+ return false;
36817
+ }
36823
36818
  // Base interactive elements and roles
36824
36819
  const interactiveElements = new Set([
36825
36820
  'a',
@@ -36834,11 +36829,16 @@ function run_build_dom_tree() {
36834
36829
  'select',
36835
36830
  'textarea',
36836
36831
  'summary',
36832
+ 'option',
36833
+ 'optgroup',
36834
+ 'fieldset',
36835
+ 'legend',
36837
36836
  ]);
36838
36837
  const interactiveRoles = new Set([
36839
36838
  'button',
36840
36839
  'menu',
36841
36840
  'menuitem',
36841
+ 'menubar',
36842
36842
  'link',
36843
36843
  'checkbox',
36844
36844
  'radio',
@@ -36885,7 +36885,7 @@ function run_build_dom_tree() {
36885
36885
  if (hasInteractiveRole)
36886
36886
  return true;
36887
36887
  // Get computed style
36888
- const style = window.getComputedStyle(element);
36888
+ const style = getCachedComputedStyle(element);
36889
36889
  // Check if element has click-like styling
36890
36890
  const hasClickStyling = style.cursor === 'pointer' || element.style.cursor === 'pointer';
36891
36891
  // Check for event listeners
@@ -36941,7 +36941,7 @@ function run_build_dom_tree() {
36941
36941
  // Check for form-related functionality
36942
36942
  element.form !== undefined ||
36943
36943
  element.hasAttribute('contenteditable') ||
36944
- style.userSelect !== 'none';
36944
+ (style && style.userSelect !== 'none');
36945
36945
  // Check if element is draggable
36946
36946
  const isDraggable = element.draggable || element.getAttribute('draggable') === 'true';
36947
36947
  return (hasAriaProps ||
@@ -36953,11 +36953,12 @@ function run_build_dom_tree() {
36953
36953
  }
36954
36954
  // Helper function to check if element is visible
36955
36955
  function isElementVisible(element) {
36956
- const style = window.getComputedStyle(element);
36957
- return (element.offsetWidth > 0 &&
36958
- element.offsetHeight > 0 &&
36959
- style.visibility !== 'hidden' &&
36960
- style.display !== 'none');
36956
+ if (element.offsetWidth === 0 && element.offsetHeight === 0) {
36957
+ return false;
36958
+ }
36959
+ const style = getCachedComputedStyle(element);
36960
+ return (style?.visibility !== 'hidden' &&
36961
+ style?.display !== 'none');
36961
36962
  }
36962
36963
  // Helper function to check if element is the top element at its position
36963
36964
  function isTopElement(element) {
@@ -37128,9 +37129,11 @@ class BaseBrowserLabelsAgent extends BaseBrowserAgent {
37128
37129
  - If the webpage content hasn't loaded, please use the \`wait\` tool to allow time for the content to load.
37129
37130
  * ELEMENT INTERACTION:
37130
37131
  - Only use indexes that exist in the provided element list
37132
+ - Browser tools only return elements in visible viewport by default
37131
37133
  - Each element has a unique index number (e.g., "[33]:<button>Submit</button>")
37132
37134
  - Elements marked with "[]:" are non-interactive (for context only, e.g., "[]: Google")
37133
37135
  - Use the latest element index, do not rely on historical outdated element indexes
37136
+ - Due to technical limitations, not all interactive elements may be identified; use coordinates to interact with unlisted elements
37134
37137
  * ERROR HANDLING:
37135
37138
  - If no suitable elements exist, use other functions to complete the task
37136
37139
  - If stuck, try alternative approaches, don't refuse tasks
@@ -37139,6 +37142,8 @@ class BaseBrowserLabelsAgent extends BaseBrowserAgent {
37139
37142
  * BROWSER OPERATION:
37140
37143
  - Use scroll to find elements you are looking for, When extracting content, prioritize using extract_page_content, only scroll when you need to load more content
37141
37144
  - Please follow user instructions and don't be lazy until the task is completed. For example, if a user asks you to find 30 people, don't just find 10 - keep searching until you find all 30
37145
+ * Parallelism:
37146
+ - When operating multiple independent steps, they should be executed in parallel as much as possible. For example, when filling out multiple form fields, they should be filled in parallel as much as possible to improve efficiency, rather than operating step by step.
37142
37147
  * During execution, please output user-friendly step information. Do not output HTML-related element and index information to users, as this would cause user confusion.
37143
37148
  `;
37144
37149
  const _tools_ = [];
@@ -37258,13 +37263,13 @@ class BaseBrowserLabelsAgent extends BaseBrowserAgent {
37258
37263
  return [
37259
37264
  {
37260
37265
  name: "navigate_to",
37261
- description: "Navigate to a specific url",
37266
+ description: "Navigate to a specific URL in the browser. Use this tool when you need to visit a webpage or change the current page location.",
37262
37267
  parameters: {
37263
37268
  type: "object",
37264
37269
  properties: {
37265
37270
  url: {
37266
37271
  type: "string",
37267
- description: "The url to navigate to",
37272
+ description: "The complete URL to navigate to",
37268
37273
  },
37269
37274
  },
37270
37275
  required: ["url"],
@@ -37275,7 +37280,7 @@ class BaseBrowserLabelsAgent extends BaseBrowserAgent {
37275
37280
  },
37276
37281
  {
37277
37282
  name: "current_page",
37278
- description: "Get the information of the current webpage (url, title)",
37283
+ description: "Get the currently active webpage information, return tabId, URL and title",
37279
37284
  parameters: {
37280
37285
  type: "object",
37281
37286
  properties: {},
@@ -37286,7 +37291,7 @@ class BaseBrowserLabelsAgent extends BaseBrowserAgent {
37286
37291
  },
37287
37292
  {
37288
37293
  name: "go_back",
37289
- description: "Navigate back in browser history",
37294
+ description: "Go back to the previous page in browser history",
37290
37295
  parameters: {
37291
37296
  type: "object",
37292
37297
  properties: {},
@@ -37297,7 +37302,7 @@ class BaseBrowserLabelsAgent extends BaseBrowserAgent {
37297
37302
  },
37298
37303
  {
37299
37304
  name: "input_text",
37300
- description: "Input text into an element",
37305
+ description: "Inputs text into a element by first clicking to focus the element, then clearing any existing text and typing the new text. Optionally presses Enter after input completion.",
37301
37306
  parameters: {
37302
37307
  type: "object",
37303
37308
  properties: {
@@ -37380,7 +37385,7 @@ class BaseBrowserLabelsAgent extends BaseBrowserAgent {
37380
37385
  },
37381
37386
  {
37382
37387
  name: "hover_to_element",
37383
- description: "Mouse hover over the element",
37388
+ description: "Hover the mouse over an element, use it when you need to hover to display more interactive information",
37384
37389
  parameters: {
37385
37390
  type: "object",
37386
37391
  properties: {
@@ -37397,7 +37402,7 @@ class BaseBrowserLabelsAgent extends BaseBrowserAgent {
37397
37402
  },
37398
37403
  {
37399
37404
  name: "extract_page_content",
37400
- description: "Extract the text content and image links of the current webpage, please use this tool to obtain webpage data.",
37405
+ description: "Extracts all content from the current webpage, including text and image links. Please use this tool when you need to retrieve webpage content.",
37401
37406
  parameters: {
37402
37407
  type: "object",
37403
37408
  properties: {},
@@ -37446,7 +37451,7 @@ class BaseBrowserLabelsAgent extends BaseBrowserAgent {
37446
37451
  },
37447
37452
  {
37448
37453
  name: "get_all_tabs",
37449
- description: "Get all tabs of the current browser",
37454
+ description: "Get all tabs of the current browser, returns the tabId, URL, and title of all tab pages",
37450
37455
  parameters: {
37451
37456
  type: "object",
37452
37457
  properties: {},
@@ -37457,7 +37462,7 @@ class BaseBrowserLabelsAgent extends BaseBrowserAgent {
37457
37462
  },
37458
37463
  {
37459
37464
  name: "switch_tab",
37460
- description: "Switch to the specified tab page",
37465
+ description: "Switch to the specified tab (based on tabId)",
37461
37466
  parameters: {
37462
37467
  type: "object",
37463
37468
  properties: {
@@ -37475,13 +37480,13 @@ class BaseBrowserLabelsAgent extends BaseBrowserAgent {
37475
37480
  {
37476
37481
  name: "wait",
37477
37482
  noPlan: true,
37478
- description: "Wait for specified duration",
37483
+ description: "Wait/pause execution for a specified duration. Use this tool when you need to wait for data loading, page rendering, or introduce delays between operations.",
37479
37484
  parameters: {
37480
37485
  type: "object",
37481
37486
  properties: {
37482
37487
  duration: {
37483
37488
  type: "number",
37484
- description: "Duration in millisecond",
37489
+ description: "Wait duration in milliseconds",
37485
37490
  default: 500,
37486
37491
  minimum: 200,
37487
37492
  maximum: 10000,