diff --git a/docs/agent-script.md b/docs/agent-script.md index 19834f2ef..c0a15a43f 100644 --- a/docs/agent-script.md +++ b/docs/agent-script.md @@ -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=` 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 diff --git a/docs/agent-tutorial.md b/docs/agent-tutorial.md index 2eb19729b..315b53934 100644 --- a/docs/agent-tutorial.md +++ b/docs/agent-tutorial.md @@ -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 diff --git a/docs/agent.md b/docs/agent.md index 5ace26daf..19c6feae6 100644 --- a/docs/agent.md +++ b/docs/agent.md @@ -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 ` 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 `// ` 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 `// ` 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