Tools

Pre-built Scrapybara tools and how to define custom tools

Scrapybara tools

BashTool, ComputerTool, EditTool

BashTool, ComputerTool, and EditTool follow the same interface as the instance bash, computer, and edit methods. They each take in an instance parameter to interact with the instance.

  • ComputerTool allows the agent to allows the agent to control mouse and keyboard. Supported for Ubuntu, Browser, and Windows instances.
  • BashTool allows the agent to run bash commands. Supported only for Ubuntu instances.
  • EditTool allows the agent to view, create, and edit files. Supported only for Ubuntu instances.
from scrapybara import Scrapybara
from scrapybara.tools import BashTool, ComputerTool, EditTool
client = Scrapybara()
instance = client.start_ubuntu()
tools = [
BashTool(instance),
ComputerTool(instance),
EditTool(instance),
]

Define custom tools

You can define custom tools. A tool needs a name, description, parameters (Pydantic model for Python, Zod object for TS), and an execute function (__call__ for Python, execute for TS).

from scrapybara.client import UbuntuInstance
from scrapybara.tools import Tool
from pydantic import BaseModel
class CapyParameters(BaseModel):
# Define your parameters here
pass
class CapyTool(Tool):
_instance: UbuntuInstance
def __init__(self, instance: UbuntuInstance) -> None:
super().__init__(
name="capy",
description="Use a capybara",
parameters=CapyParameters,
)
self._instance = instance
def __call__(self, **kwargs: Any) -> Any:
# Implement your tool logic here
pass

BrowserTool

BrowserTool allows the agent to interact with a browser using Playwright.

Custom tools like BrowserTool may degrade model performance, as the models have not been trained on custom tools. For browser automation, we recommend sticking to ComputerTool.

The BrowserTool requires the browser to be started first.

from playwright.sync_api import sync_playwright
class BrowserToolParameters(BaseModel):
"""Parameters for browser interaction commands."""
command: Literal[
"go_to", # Navigate to a URL
"get_html", # Get current page HTML
"evaluate", # Run JavaScript code
"click", # Click on an element
"type", # Type into an element
"screenshot", # Take a screenshot
"get_text", # Get text content of element
"get_attribute", # Get attribute of element
] = Field(
description="The browser command to execute. Required parameters per command:\n"
"- go_to: requires 'url'\n"
"- evaluate: requires 'code'\n"
"- click: requires 'selector'\n"
"- type: requires 'selector' and 'text'\n"
"- get_text: requires 'selector'\n"
"- get_attribute: requires 'selector' and 'attribute'\n"
"- get_html: no additional parameters\n"
"- screenshot: no additional parameters"
)
url: Optional[str] = Field(
None, description="URL for go_to command (required for go_to)"
)
selector: Optional[str] = Field(
None,
description="CSS selector for element operations (required for click, type, get_text, get_attribute)",
)
code: Optional[str] = Field(
None, description="JavaScript code for evaluate command (required for evaluate)"
)
text: Optional[str] = Field(
None, description="Text to type for type command (required for type)"
)
timeout: Optional[int] = Field(
30000, description="Timeout in milliseconds for operations"
)
attribute: Optional[str] = Field(
None,
description="Attribute name for get_attribute command (required for get_attribute)",
)
class BrowserTool(Tool):
"""A browser interaction tool that allows the agent to interact with a browser."""
_instance: Union[UbuntuInstance, BrowserInstance]
def __init__(self, instance: Union[UbuntuInstance, BrowserInstance]) -> None:
super().__init__(
name="browser",
description="Interact with a browser for web scraping and automation",
parameters=BrowserToolParameters,
)
self._instance = instance
def __call__(self, **kwargs: Any) -> Any:
params = BrowserToolParameters.model_validate(kwargs)
command = params.command
url = params.url
selector = params.selector
code = params.code
text = params.text
timeout = params.timeout or 30000
attribute = params.attribute
cdp_url = self._instance.browser.get_cdp_url().cdp_url
if cdp_url is None:
raise ValueError("CDP URL is not available, start the browser first")
with sync_playwright() as playwright:
browser = playwright.chromium.connect_over_cdp(cdp_url)
context = browser.contexts[0]
if not context.pages:
page = context.new_page()
else:
page = context.pages[0]
try:
if command == "go_to":
if not url:
raise ValueError("URL is required for go_to command")
page.goto(url, timeout=timeout)
return True
elif command == "get_html":
try:
return page.evaluate("() => document.documentElement.outerHTML")
except Exception:
# If page is navigating, just return what we can get
return page.evaluate("() => document.documentElement.innerHTML")
elif command == "evaluate":
if not code:
raise ValueError("Code is required for evaluate command")
return page.evaluate(code)
elif command == "click":
if not selector:
raise ValueError("Selector is required for click command")
page.click(selector, timeout=timeout)
return True
elif command == "type":
if not selector:
raise ValueError("Selector is required for type command")
if not text:
raise ValueError("Text is required for type command")
page.type(selector, text, timeout=timeout)
return True
elif command == "screenshot":
return image_result(
base64.b64encode(page.screenshot(type="png")).decode("utf-8")
)
elif command == "get_text":
if not selector:
raise ValueError("Selector is required for get_text command")
element = page.wait_for_selector(selector, timeout=timeout)
if element is None:
raise ValueError(f"Element not found: {selector}")
return element.text_content()
elif command == "get_attribute":
if not selector:
raise ValueError(
"Selector is required for get_attribute command"
)
if not attribute:
raise ValueError(
"Attribute is required for get_attribute command"
)
element = page.wait_for_selector(selector, timeout=timeout)
if element is None:
raise ValueError(f"Element not found: {selector}")
return element.get_attribute(attribute)
else:
raise ValueError(f"Unknown command: {command}")
except Exception as e:
raise ValueError(f"Browser command failed: {str(e)}")
finally:
browser.close()