mirror of
https://github.com/lightpanda-io/browser.git
synced 2026-10-10 05:11:46 -04:00
agent: clarify script primitives and save behavior
Updates documentation to clarify that script primitives use CSS selectors instead of backendNodeIds. Explains how to use `/nodeDetails` to get selectors. Clarifies the difference in `/save` behavior between `--no-llm` and LLM modes.
This commit is contained in:
1 parent
d18297f204
commit
157aa30bdc
3 files changed
+66
-25
No files matched your search
+31
-14
@@ -110,24 +110,36 @@ Only recorded browser primitives are installed globally:
|
||||
|
||||
| Primitive | Arguments | Runs in |
|
||||
|-----------|-----------|---------|
|
||||
| `goto` | `goto(url)` or `goto({ url, timeout, waitUntil })` | Browser session |
|
||||
| `goto` | `goto(url[, { timeout, waitUntil }])` | Browser session |
|
||||
| `extract` | `extract(schema)` or `extract({ schema })` | Browser page via extractor; returns a JS object or array |
|
||||
| `evaluate` | `evaluate(script)` or `evaluate({ script, url, timeout, waitUntil, save })` | Browser page JS context |
|
||||
| `click` | `click({ selector })` or `click({ backendNodeId })` | Browser page |
|
||||
| `fill` | `fill({ selector, value })` or `fill({ backendNodeId, value })` | Browser page |
|
||||
| `scroll` | `scroll()` or `scroll({ x, y, backendNodeId })` | Browser page |
|
||||
| `waitForSelector` | `waitForSelector(selector)` or `waitForSelector({ selector, timeout })` | Browser page |
|
||||
| `waitForScript` | `waitForScript(script)` or `waitForScript({ script, timeout })` | Browser page JS context |
|
||||
| `hover` | `hover({ selector })` or `hover({ backendNodeId })` | Browser page |
|
||||
| `press` | `press({ key })` or `press({ key, selector, backendNodeId })` | Browser page |
|
||||
| `selectOption` | `selectOption({ selector, value })` or `selectOption({ backendNodeId, value })` | Browser page |
|
||||
| `setChecked` | `setChecked({ selector, checked })` or `setChecked({ backendNodeId, checked })` | Browser page |
|
||||
| `evaluate` | `evaluate(script[, { url, timeout, waitUntil, save }])` | Browser page JS context |
|
||||
| `click` | `click({ selector })` | Browser page |
|
||||
| `fill` | `fill({ selector, value })` | Browser page |
|
||||
| `scroll` | `scroll()` or `scroll({ x, y })` | Browser page |
|
||||
| `waitForSelector` | `waitForSelector(selector[, { timeout }])` | Browser page |
|
||||
| `waitForScript` | `waitForScript(script[, { timeout }])` | Browser page JS context |
|
||||
| `hover` | `hover({ selector })` | Browser page |
|
||||
| `press` | `press({ key })` or `press({ key, selector })` | Browser page |
|
||||
| `selectOption` | `selectOption({ selector, value })` | Browser page |
|
||||
| `setChecked` | `setChecked({ selector, checked })` | Browser page |
|
||||
|
||||
`waitUntil` accepts `"load"`, `"domcontentloaded"`, `"networkidle"`, or
|
||||
`"done"`.
|
||||
|
||||
Prefer CSS selectors in saved scripts. `backendNodeId` values are tied to the
|
||||
current DOM snapshot and are not stable after navigation or DOM mutation.
|
||||
The `[, { … }]` is an optional trailing options object: leading arguments are
|
||||
positional (`waitForSelector("#row", { timeout: 2000 })`), and the options ride
|
||||
in a final object. Passing a single object with everything
|
||||
(`waitForSelector({ selector: "#row", timeout: 2000 })`) is equivalent — that's
|
||||
the shape `/save` records into saved scripts. An option can't be a bare
|
||||
positional, though: `waitForSelector("#row", 2000)` is an error.
|
||||
|
||||
Script primitives address elements by CSS selector only. The tools that hand
|
||||
out `backendNodeId`s (`tree`, `findElement`, `nodeDetails`) aren't installed in
|
||||
the script context, and a raw node ID wouldn't survive replay anyway. When
|
||||
you're exploring in the REPL and have a `backendNodeId` — e.g. the leading
|
||||
number on a `/tree` line, or a `/findElement` hit — run `/nodeDetails
|
||||
backendNodeId=<id>` to get a durable CSS `selector`, then paste that into your
|
||||
script.
|
||||
|
||||
## Navigation
|
||||
|
||||
@@ -299,7 +311,12 @@ Only replayable browser actions are recorded:
|
||||
and `extract`.
|
||||
- Not recorded: read-only exploration tools such as `tree`, `markdown`, `html`,
|
||||
`links`, `findElement`, `consoleLogs`, `getUrl`, `getCookies`, and `getEnv`.
|
||||
- Natural-language prompts and recording comments are written as `//` comments.
|
||||
- Natural-language prompts are written as `//` comments above the actions they
|
||||
produced.
|
||||
|
||||
This is the deterministic `--no-llm` transcription. When `/save` runs with an
|
||||
LLM it instead synthesizes an idiomatic script from the session and is asked to
|
||||
emit JavaScript only, so those `//` comments generally won't appear.
|
||||
|
||||
## Error Handling
|
||||
|
||||
|
||||
+24
-3
@@ -194,6 +194,23 @@ replayable. Always
|
||||
synthesize a CSS selector from the attributes (`id`, `class`,
|
||||
`name`, `action`, `tag_name`) and use that.
|
||||
|
||||
You don't have to hand-roll the selector. Every node in the `/tree`
|
||||
output carries a `backendNodeId` (the leading number on each line), and
|
||||
`/nodeDetails` turns one into a durable selector for you:
|
||||
|
||||
```
|
||||
> /nodeDetails backendNodeId=15
|
||||
```
|
||||
|
||||
It returns a ready-to-use CSS `selector` that resolves to that node
|
||||
(plus its tag, id, class, name, and attributes) — the canonical way to
|
||||
go from a `/tree` (or `/findElement`) hit to a selector you can paste
|
||||
into `/click` or `/fill`. We reached for `/detectForms` above because
|
||||
the two login/signup forms share field names, so a form-scoped selector
|
||||
(keyed on `action`) is cleaner here — but `/nodeDetails` is the quickest
|
||||
path whenever you have a single `backendNodeId` and just want its
|
||||
selector without guessing.
|
||||
|
||||
Now fill the form:
|
||||
|
||||
```
|
||||
@@ -320,9 +337,13 @@ goto("https://news.ycombinator.com");
|
||||
extract({ topStories: [{ selector: ".athing", fields: { rank: ".rank", title: ".titleline > a", url: { selector: ".titleline > a", attr: "href" } } }] });
|
||||
```
|
||||
|
||||
Natural-language REPL turns are not saved as executable JavaScript.
|
||||
When a natural-language turn produces recorded browser actions, the
|
||||
prompt is kept as a `//` comment above those actions.
|
||||
Natural-language REPL turns are never saved as executable JavaScript.
|
||||
In the deterministic `--no-llm` transcription, the prompt that produced
|
||||
a set of recorded actions is kept as a `//` comment above them, so the
|
||||
script stays readable. The LLM `/save` path is different: it rewrites
|
||||
the whole session into an idiomatic script and is told to emit
|
||||
JavaScript only, so it generally drops those comments rather than
|
||||
preserving them verbatim.
|
||||
|
||||
## 5. Running deterministically
|
||||
|
||||
|
||||
+11
-8
@@ -235,14 +235,17 @@ is origin-scoped and persists across navigations within a session).
|
||||
From the REPL, `/save [file.js]` writes the session back to a `.js` file
|
||||
and `/load <path>` runs a script from disk against the current session.
|
||||
|
||||
State-mutating commands (`/goto`, `/click`, `/fill`, `/scroll`, `/hover`,
|
||||
`/selectOption`, `/setChecked`, `/waitForSelector`, `/press`, `/evaluate`,
|
||||
`/extract`) are saved; read-only commands (`/tree`, `/markdown`,
|
||||
`/links`, `/findElement`, …) and the natural-language turns that produced
|
||||
them are not. Natural-language turns are saved as `// <prompt>` comments
|
||||
above the resulting JavaScript calls so the script stays readable. In the
|
||||
basic REPL (`--no-llm`) `/save` transcribes the session deterministically;
|
||||
with an LLM it synthesizes an equivalent idiomatic script.
|
||||
`/save` works one of two ways. **With `--no-llm`** it transcribes the session
|
||||
deterministically: state-mutating commands (`/goto`, `/click`, `/fill`,
|
||||
`/scroll`, `/hover`, `/selectOption`, `/setChecked`, `/waitForSelector`,
|
||||
`/waitForScript`, `/press`, `/evaluate`, `/extract`) become JavaScript calls,
|
||||
read-only commands (`/tree`, `/markdown`, `/links`, `/findElement`, …) are
|
||||
dropped, and each natural-language prompt that produced recorded actions is
|
||||
written as a `// <prompt>` comment above those calls so the script stays
|
||||
readable. **With an LLM** it instead synthesizes an idiomatic script from the
|
||||
whole session — the synthesis prompt asks for JavaScript only ("no
|
||||
commentary"), so the result generally has no such comments: the model folds
|
||||
intent into the code and drops dead-ends.
|
||||
|
||||
### JavaScript Script Running
|
||||
|
||||
|
||||
Reference in new issue
Block a user