Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 17 additions & 9 deletions Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,8 @@ FROM ${SWIPL_IMAGE} AS builder
SHELL ["/bin/bash", "-o", "pipefail", "-c"]
ENV DEBIAN_FRONTEND=noninteractive \
HF_HOME=/opt/huggingface \
SENTENCE_TRANSFORMERS_HOME=/opt/sentence_transformers
SENTENCE_TRANSFORMERS_HOME=/opt/sentence_transformers \
PLAYWRIGHT_BROWSERS_PATH=/opt/ms-playwright

RUN apt-get update \
&& apt-get install -y --no-install-recommends \
Expand All @@ -28,6 +29,16 @@ RUN apt-get update \
nano \
&& rm -rf /var/lib/apt/lists/*

# Install pinned Python dependencies and cache the matching Chromium build
# before cloning source repositories or copying application code.
COPY ./requirements.txt /tmp/requirements.txt
RUN python3 -m pip install --no-cache-dir --break-system-packages \
--index-url https://download.pytorch.org/whl/cpu \
--extra-index-url https://pypi.org/simple/ \
torch==2.12.1 \
&& python3 -m pip install --no-cache-dir --break-system-packages -r /tmp/requirements.txt
RUN python3 -m playwright install --only-shell chromium

# Build dependencies from source. Pin refs at build time for reproducibility.
ARG PETTA_REPO=https://github.com/trueagi-io/PeTTa.git
ARG PETTA_REF=v1.0.4
Expand All @@ -52,13 +63,6 @@ RUN sh build.sh
RUN mkdir -p /PeTTa/repos \
&& git clone --depth 1 --branch "${CHROMADB_REF}" "${CHROMADB_REPO}" /PeTTa/repos/petta_lib_chromadb

COPY ./requirements.txt /tmp/requirements.txt
RUN python3 -m pip install --no-cache-dir --break-system-packages \
--index-url https://download.pytorch.org/whl/cpu \
--extra-index-url https://pypi.org/simple/ \
torch==2.12.1 \
&& python3 -m pip install --no-cache-dir --break-system-packages -r /tmp/requirements.txt

# Pre-download the sentence-transformers model so runtime does not need network access.
RUN mkdir -p "${HF_HOME}" "${SENTENCE_TRANSFORMERS_HOME}" \
&& python3 - <<PY
Expand Down Expand Up @@ -91,7 +95,8 @@ ENV DEBIAN_FRONTEND=noninteractive \
PYTHONDONTWRITEBYTECODE=1 \
PYTHONUNBUFFERED=1 \
HF_HOME=/opt/huggingface \
SENTENCE_TRANSFORMERS_HOME=/opt/sentence_transformers
SENTENCE_TRANSFORMERS_HOME=/opt/sentence_transformers \
PLAYWRIGHT_BROWSERS_PATH=/opt/ms-playwright

RUN apt-get update \
&& apt-get install -y --no-install-recommends \
Expand All @@ -113,9 +118,12 @@ RUN apt-get update \
WORKDIR /PeTTa

COPY --from=builder /usr/local /usr/local
COPY --from=builder /opt/ms-playwright /opt/ms-playwright
COPY --from=builder /PeTTa /PeTTa
COPY --from=builder /opt/huggingface /opt/huggingface
COPY --from=builder /opt/sentence_transformers /opt/sentence_transformers
RUN python3 -m playwright install-deps chromium \
&& rm -rf /var/lib/apt/lists/*

# setup nginx proxy
RUN usermod -a -G tty www-data
Expand Down
3 changes: 3 additions & 0 deletions config/config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -171,3 +171,6 @@ openClawEnabled: disabled
# See plugins/openclaw/README.md.
openClawURL: "http://172.17.0.1:18789"
openClawAgent: "main"

# Browser -- Playwright
playwrightEnabled: enabled
4 changes: 4 additions & 0 deletions config/plugins.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -52,3 +52,7 @@
- name: openclaw
loader: metta
location: "{REPO}/plugins/openclaw"

- name: playwright
loader: metta
location: "{REPO}/plugins/playwright"
1 change: 1 addition & 0 deletions entrypoint.sh
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,7 @@ unset MEMORY_PORTABILITY_OPERATION MEMORY_PORTABILITY_PYTHON PYTHONPATH
# Scrub environment: only allowlisted vars survive.
SAFE_VARS="HOME USER PATH HOSTNAME TERM LANG LC_ALL \
PYTHONDONTWRITEBYTECODE PYTHONUNBUFFERED \
PLAYWRIGHT_BROWSERS_PATH \

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@jazzbox35 , am I right that this line is needed to promote the environment variable in a case when user uses custom PLAYWRIGHT_BROWSERS_PATH value, for example he mounts the host's directory into the Docker?

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@vsbogd As far as I can tell from AI and their documentation, I think that environment variable is needed to mount an external browser. It looks like that env variable is used in installation and also in execution. I got a crash initially when I was missing it.

Regarding your comments above about Dockerfile, requirements.txt, and entrypoint.sh: I think you mean that ideally these would be inside the plugin's code? However we can't do that yet?

Thanks!

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also noteworthy: I had to bump up some of the space allocations in the docker run command. When I tried to do screen print, it apparently was running out of RAM and storage. The extended size seemed to work.

In general adding a browser adds some bloat.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Regarding your comments above about Dockerfile, requirements.txt, and entrypoint.sh: I think you mean that ideally these would be inside the plugin's code? However we can't do that yet?

Yes, my opinion we should design it properly first and then implement it for all of the plugins. May be we need to mark all such places by some TODO: move into playwright plugin but I am not sure.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I mean marking it clearly and uniformly could help to find all these places in the future.

HF_HOME SENTENCE_TRANSFORMERS_HOME HF_HUB_OFFLINE TRANSFORMERS_OFFLINE \
CHROMA_DB_PATH EMBEDDING_PROVIDER OMEGA_DIR MEMORY_DIR TEST_SERVER_IP"

Expand Down
162 changes: 162 additions & 0 deletions plugins/playwright/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,162 @@
# Playwright plugin

This opt-in plugin gives OmegaClaw a fresh, unauthenticated browser session
with a deliberately narrow interface:

- `browser-open "https://example.org"` opens a public HTTP(S) page in a new
selected tab and returns its tab ID and page snapshot.
- `browser-tabs` lists open tab IDs and URLs, marking the selected tab.
- `browser-switch 2` selects tab 2 and returns a fresh snapshot.
- `browser-close-tab 2` closes tab 2 and lists the remaining tabs. Closing the
selected tab selects the oldest remaining tab; use `browser-read` to get
fresh click targets before clicking or downloading.
- `browser-navigate "https://example.org"` navigates the selected tab without
opening another tab.
- `browser-read` returns visible text and numbered click targets.
- `browser-screenshot` saves a full-page PNG of the selected tab in
`playwrightDownloadDir` (by default, `SAVE_PERMANENT_FILES_DIR/browser_downloads`).
Each image has a unique `screenshot-tab-<id>-*.png` filename. Returns the
full saved path, byte count, and tab ID, or `BROWSER-SCREENSHOT-FAILED` with
the reason. It returns a file path, not inline image content. Screenshots
are not subject to the download byte limit.
- `browser-back` and `browser-forward` navigate the selected tab's history
and return a fresh snapshot. With no history entry, the page stays unchanged.
- `browser-reload` reloads the selected tab and returns a fresh snapshot.
- `browser-find "text"` searches current page text without case sensitivity,
returning surrounding excerpts and zero-based character offsets. Results
are limited to 50 matches and `playwrightMaxTextChars` excerpt characters;
truncated results are marked. No matches returns `NO_MATCHES`.
- `browser-read-more` returns the next `playwrightMaxTextChars` characters
from the latest captured text until `END_OF_TEXT`. Every fresh page snapshot
(including read, switch, click, scroll, and wait) restarts this cursor.
Continuation uses captured text, so asynchronous changes require a fresh
`browser-read`. Character ranges are zero-based with an exclusive end.
- `browser-links` lists up to 200 visible link labels and resolved destination
URLs, respecting the page's base URL. Truncation is marked. These URLs have
not been validated for navigation; the existing public-URL checks still
apply when opening them. This list does not assign click target numbers.
- `browser-click 3` clicks target 3 from the latest snapshot.
- `browser-type 3 "search terms"` replaces the contents of editable target 3
and returns a short confirmation without reading the page or waiting for
the settling delay. Empty text clears the field. Supports native
text/search/email/password/URL/telephone/number inputs, textareas, and
contenteditable fields. After success, **only target 1 is valid**: it refers
to the exact element just filled. The function fills and verifies the
field's contents, allowing up to two retries after the initial attempt
(three attempts total). It stops early if the page closes or changes tabs,
or the field detaches. There is no keyboard fallback. Verification checks
the current value, not future site updates.
If the site replaces that element, obtain current targets with `browser-read`.
Use `browser-read` to inspect suggestions or find a search button.
Typing does not press Enter, though site input
handlers may trigger searches or other actions. Invalid targets, unsupported
field types, read-only/disabled fields, and execution errors return
`BROWSER-TYPE-FAILED`. Supplied text is omitted from fill error messages.

On failure, do not repeat the text-entry request or press Enter. Inspect
with `browser-read` and report the failure; text may already be partially
entered. For searches, clicking the associated Search button is the default;
Enter is the fallback when no such button is available.

- `browser-press-enter 3` presses Enter in editable target 3, waits for DOM
loading and the configured settling delay, and returns a fresh snapshot.
This command takes only a field number. In multiline fields, Enter may
insert a newline instead of submitting. Errors return
`BROWSER-PRESS-ENTER-FAILED`.

Search workflow:

1. Find the search field marked `EDITABLE` in the latest snapshot.
2. Call `browser-type` with that field number and the search text.
3. Check for `BROWSER-TYPE-OK`. If typing failed, stop text entry, inspect
the page and report the failure. Do not retry typing or press Enter.
4. Inspect the page with `browser-read`. If results already updated, do not
submit again. Otherwise, click the Search button associated with that
field using `browser-click`. If no such button is available, call
`browser-press-enter` on the search field. Use target numbers from this
fresh snapshot, not the numbers from before typing.
5. Inspect the resulting page to confirm the search completed. If results
are still loading, use `browser-wait` before reading them again.

- `browser-options 3` lists up to 200 options for native dropdown target 3,
including labels, values, disabled and selected states. Target numbers stay
unchanged. Snapshots identify dropdowns but do not enumerate their options.

- `browser-select 3 "English"` selects an option in native dropdown target 3
and returns a fresh snapshot. Use `browser-options` to see the choices first.
Matching is exact and
case-sensitive: labels take precedence over values. Missing, ambiguous,
disabled, or non-dropdown targets/options return `BROWSER-SELECT-FAILED`;
browser execution errors use the same prefix. Selection chooses one option
and replaces previous selections, including in multi-select controls.
Custom menus continue to use `browser-click`. Selection can trigger a site's
change handlers, including navigation or automatic submission.
- `browser-scroll 900` scrolls down 900 pixels and refreshes the snapshot;
negative values scroll upward.
- `browser-wait 1500` waits for asynchronous output and refreshes the snapshot.
- `browser-download 4` explicitly downloads target 4 to the dedicated download
directory and returns its verified byte count and SHA-256 digest.
- `browser-close` closes all tabs and destroys the browser context and its
session data.

There is no plugin-imposed tab limit; capacity depends on available memory
and browser/OS resources. Read, click, scroll, wait, and download act on the
selected tab. Tab IDs remain stable until closed and reset after
`browser-close`. Click target numbers belong to the latest snapshot of the
selected tab; switching tabs refreshes them. Popups are also listed as tabs,
but do not automatically change the selection.

Snapshots collect control descriptions in one browser call, with a maximum
of 200 controls. Dropdown options are read only by `browser-options` or during
selection. Typing skips the full snapshot and invalidates the previous text
reading; use `browser-read` before requesting `browser-read-more` again.

Tabs share one browser context, including cookies and origin-scoped local
storage. Closing the last tab keeps that context alive; `browser-close`
discards it. Each `browser-open` now creates a tab; use `browser-navigate`
for the previous behavior of navigating the current page.

Every browser command returns `BROWSER-<COMMAND>-FAILED: <reason>` when
validation or execution fails, and logs the error. For example, reading
without a selected tab returns `BROWSER-READ-FAILED`, and an invalid tab ID
for `browser-close-tab` returns `BROWSER-CLOSE-TAB-FAILED`. A command may have
partially completed before failing; use `browser-tabs` and `browser-read`
to inspect the current state. After an exception, obtain a fresh snapshot
before using numbered click targets.

The additional commands use `BROWSER-BACK-FAILED`, `BROWSER-FORWARD-FAILED`,
`BROWSER-RELOAD-FAILED`, `BROWSER-FIND-FAILED`, `BROWSER-READ-MORE-FAILED`, and
`BROWSER-LINKS-FAILED`. Empty link lists, no search matches, and end of text
are normal results, not failures.

Standard controls and common custom click controls (`role`, `onclick`, and
`tabindex`) are numbered. A configurable settling delay allows client-rendered
output to appear after a click, Enter, selection, or scroll. Typing returns
immediately after filling; use `browser-wait` to inspect delayed suggestions.
There are no skills for
directly setting cookies, uploading files,
evaluating JavaScript, or restoring a prior browser profile. Downloads require
the explicit `browser-download` skill; downloads triggered by ordinary clicks
are cancelled. Local,
loopback, link-local, and private-network URLs are rejected, including requests
reached through redirects.

## Enabling

Install the Python dependency and the browser binary outside the agent, then
set:

```yaml
playwrightEnabled: enabled
```

Optional settings are `playwrightBrowser` (`chromium`, `firefox`, or `webkit`),
`playwrightHeadless`, `playwrightTimeoutMs`, and `playwrightMaxTextChars`.
`playwrightSettleMs` controls the post-click/scroll delay and defaults to 750.
`playwrightDownloadDir` defaults to `memory/browser_downloads`, and
`playwrightMaxDownloadBytes` defaults to 10 MiB. Suggested filenames are
sanitized and existing files are never overwritten.

The default is `enabled`. Set `playwrightEnabled: disabled` to
turn it off. Playwright browser binaries are not installed or downloaded
automatically by OmegaClaw.
Loading
Loading