Commit Graph

7186 Commits

Author SHA1 Message Date
Adrià Arrufat
d7be4ebade browser: update driver guidance for efficient browsing
Adds instructions on using `url` parameters with `markdown`, `tree`,
and `html` to avoid redundant `goto` calls. Also adds a section on
browsing efficiently to minimize page loads and triage search results.
2026-06-05 14:26:31 +02:00
Adrià Arrufat
c355b0bda8 agent: add /clear and /reset REPL commands
- `/clear` forgets conversation history, usage, and node IDs while
  keeping the loaded page and cookies.
- `/reset` does a full reset, starting a fresh browser session.
2026-06-05 14:13:10 +02:00
Adrià Arrufat
2d2914e878 agent: add /usage slash command to REPL
Adds a new `/usage` meta command to print cumulative token usage and
cache hit rate for the current session. Also updates zenai.
2026-06-05 13:35:34 +02:00
Adrià Arrufat
88c8828224 Merge branch 'main' into agent 2026-06-05 12:43:46 +02:00
Adrià Arrufat
5f2330bb2f agent: add reasoning effort configuration
Adds the `--effort` CLI flag and `/effort` REPL command to control
the reasoning budget, persisting the setting in `.lp-agent.zon`.
2026-06-05 12:40:34 +02:00
Karl Seguin
37f5a8c819 Merge pull request #2648 from lightpanda-io/worker_isolate_terminate
Make worker more robust in the face of a disconnected CDP client
2026-06-05 18:27:01 +08:00
Karl Seguin
6ecf54fc32 Merge pull request #2649 from lightpanda-io/fix/deferred-context-uaf-on-teardown
fix: drop orphaned deferred contexts on frame teardown
2026-06-05 18:22:58 +08:00
Adrià Arrufat
76504604ba docs: update recorder details and add /logout 2026-06-05 12:14:42 +02:00
Karl Seguin
5db5969c92 Merge pull request #2647 from staylor/fix/synwait-teardown-interrupt
fix(http): abort blocking-script sync wait when a teardown command is queued (#2646)
2026-06-05 17:55:51 +08:00
Adrià Arrufat
157aa30bdc 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.
2026-06-05 11:26:24 +02:00
Adrià Arrufat
d18297f204 agent: update docs for recent features and fixes
Updates documentation to reflect the new REPL status bar, JS mode,
corrected `press` syntax, and updated error messages.
2026-06-05 10:43:41 +02:00
Adrià Arrufat
3044f620b9 docs(agent): update docs for recent features and CLI flags
Updates agent-related documentation to reflect recent changes:
- Removes obsolete `follow` option from `extract` schema.
- Documents automatic printing of the script's final expression.
- Adds details on Ollama auto-detection and new CLI flags.
- Documents the `/logout` command and updated tool list.
2026-06-05 10:23:50 +02:00
Adrià Arrufat
ee21138bde fix: drop orphaned deferred contexts on frame teardown
A fetch() deferred behind a parser-blocking script keeps a DeferredContext
in the DeferringLayer whose forward.ctx points at the Fetch struct, which
lives in a page/session arena. If the transfer completes while deferred,
it is deinited and unlinked from the frame owner, so abortTransfers ->
abortOwner can't reach the now-orphaned context. It lingers in the active
list, and when the page is torn down its Fetch arena is freed; a later
flushFrame (e.g. the next page's parser-blocking script popping) replays
the buffered header callback into the freed Fetch -> use-after-free.

Add DeferringLayer.cancelFrame to drop these orphaned (terminal) contexts
during Frame.abortTransfers. Non-terminal contexts still have a live
transfer that cleans them up through its own callback path, so they are
left alone.
2026-06-05 09:47:15 +02:00
Adrià Arrufat
6c9c6df3af build: update isocline dependency 2026-06-05 09:11:24 +02:00
Karl Seguin
86b9e8675e Make worker more robust in the face of a disconnected CDP client
When a CDP client disconnects, through a series of step, we call `Isolate::
TerminateExecution`. The problem is that this only terminates the currently
executing script. If scripts are nested, or another script runs immediately
after the terminated one, the worker keeps running.

I was specifically trying to fix some 100% endless loop in a few WPT tests, e.g
Worker-terminate-forever-during-evaluation.html

The first is the issue described above. We potentially need to guard every entry
into script executing with `if (!env.is_terminated)`. AND/OR we need to bubble
an error when a script _is_ terminated (right now, most JS errors map to
error.JsException which makes this hard). For the specific WPT failures, I opted
for a more targeted fix directly in the Worker. But I think we need to keep an
eye out on other cases where this can happen.

I also discovered another issue, which is not addressed is this commit:

var worker = new Worker("endlessloop.js");
worker.terminate(); <-- never gets called

Given our current architecture, the only solution I can think of is a watcher
thread (or re-using the main/network thread).
2026-06-05 13:00:35 +08:00
Scott Taylor
0bfd0222f2 fix(http): abort blocking-script sync wait when a teardown command is queued
A blocking <script src> loads via HttpClient.syncRequest, which spins on
tick(200, .sync_wait). That drain mode only dispatches Fetch-interception
methods (it can't free Page/Frame state mid-parse), so Target.closeTarget /
Target.disposeBrowserContext / Page.close sit undispatched until the blocking
fetch completes — i.e. up to the per-request timeout, per blocking script.

For storefronts with slow/never-completing third-party subresources this
stalls page.close()/context dispose for tens of seconds and collapses CDP
throughput under concurrency (the process stays up; other connections are
unaffected).

Fix: while waiting, peek the inbox; if a teardown/close command (or a
client close/disconnect) is queued, abort the in-flight blocking transfer.
syncRequest then returns the same way it already does on a fetch failure,
the parser unwinds to the next safe .all drain, and the queued command
runs there. No command is dispatched mid-parse, so no UAF.

Repro: 8 workers looping newContext->goto(commit)->page.close against a page
with 15 never-answered subresources went from 0.1 ctx/s (page.close stalling
~30-60s) to ~25 ctx/s; a no-hanging-subresource baseline is unchanged.

Fixes #2646
2026-06-04 23:17:24 -04:00
Karl Seguin
0e12790397 Merge pull request #2635 from Ar-maan05/feat-implement-file-api
Implement input type=file support (FileList, input.files/value, DOM.setFileInputFiles)
2026-06-05 10:52:23 +08:00
Karl Seguin
129d014479 Make FileList iterable / indexable
Small formatting tweaks
2026-06-05 08:27:38 +08:00
Karl Seguin
23120885be Merge pull request #2641 from rohitsux/feat/cdp-dispatch-mouse-wheel
feat(cdp): fire wheel events on Input.dispatchMouseEvent mouseWheel
2026-06-05 07:34:21 +08:00
Karl Seguin
9068a7583b Merge pull request #2638 from lightpanda-io/xhr-upload
Implement XMLHttpRequest.upload
2026-06-05 07:34:06 +08:00
Karl Seguin
0971f74a4c fix XMLHttpRequestUpload release 2026-06-05 07:01:01 +08:00
Karl Seguin
62acf1c640 Merge pull request #2643 from lightpanda-io/mime_fix
Fix Mime.
2026-06-05 06:55:16 +08:00
Karl Seguin
a9374a0254 Merge pull request #2642 from lightpanda-io/dommatrix
Add DOMMatrix and DOMMatrixReadOnly
2026-06-05 06:54:54 +08:00
Karl Seguin
5d95b55d87 Merge pull request #2637 from lightpanda-io/xhr-override-mimetype
Implement XMLHttpRequest.overrideMimeType()
2026-06-05 06:31:26 +08:00
Adrià Arrufat
19485f8640 agent: validate models for all providers
Generalizes model reconciliation to support all providers, not just
Ollama. Also updates the zenai dependency.
2026-06-04 20:01:12 +02:00
Adrià Arrufat
7eccdeed72 build: update zenai dependency 2026-06-04 19:35:03 +02:00
Adrià Arrufat
7dae410270 build: update zenai dependency 2026-06-04 19:33:11 +02:00
Adrià Arrufat
ab540e9bdf agent: auto-detect Ollama and fallback models
Probes local Ollama as a fallback provider when no API keys are set.
Swaps to an installed Ollama model if the default model is missing.
2026-06-04 18:29:29 +02:00
Pierre Tachoire
cb73e43926 couple XMLHttpRequestUpload lifecycle w/ parent's XMLHttpRequest 2026-06-04 18:20:38 +02:00
Adrià Arrufat
f2a7367e6d agent: verify Ollama model is installed upfront
Queries Ollama's local catalog during initialization to ensure the
requested model is installed. Aborts one-shot runs if missing, or
warns during interactive sessions.
2026-06-04 18:09:43 +02:00
Adrià Arrufat
d184327376 agent: validate model selection
Check if the selected model exists in the completion models list
before setting it, preventing invalid model configurations.
2026-06-04 18:01:25 +02:00
Adrià Arrufat
760059c085 build: update zenai dependency 2026-06-04 17:54:28 +02:00
Adrià Arrufat
3575e1f238 agent: use remembered model when provider matches
Use the remembered model whenever it matches the chosen provider,
instead of only when the provider source is `.remembered`.
2026-06-04 17:30:37 +02:00
Adrià Arrufat
e3d05aeaca browser: add CSS selector to nodeDetails
Introduces `SelectorPath` to generate a unique, minimal CSS selector
for a given element. This selector is now returned in `nodeDetails`
to simplify element targeting for drivers.
2026-06-04 16:34:56 +02:00
Rohit
e05074dbf5 feat(cdp): fire wheel events on Input.dispatchMouseEvent mouseWheel
Wire the CDP Input.dispatchMouseEvent "mouseWheel" type to a new
Frame.triggerMouseWheel, which hit-tests the point via elementFromPoint
and dispatches a wheel event (with deltaX/deltaY) on the target. When
the wheel event is not cancelled, it applies the scroll offset and
fires a scroll event, mirroring the wheel handling in WebDriver.zig.

Previously mouseWheel was silently ignored. Follow-up to #2636.
2026-06-04 19:27:56 +05:30
Pierre Tachoire
426c167470 Merge pull request #2640 from rohitsux/feat/cdp-dispatch-mouse-released
feat(cdp): fire mouseup on Input.dispatchMouseEvent mouseReleased
2026-06-04 15:48:05 +02:00
Karl Seguin
0ec92bedbb Merge pull request #2639 from lightpanda-io/form-no-validate
Validate form constraints on interactive submit; add HTMLFormElement.…
2026-06-04 21:19:04 +08:00
Karl Seguin
121167e44e Fix Mime.
It has somehow acquired (or always had?) multiple dangling pointers. Luckily
(or worse?) they aren't used anywhere. Remove mime.params (dangles off the
input) and the content_type `.other` values (dangles off the local mime var).

Also, remove double lowerCase.
2026-06-04 20:55:11 +08:00
Karl Seguin
fb720766a1 Fix XHR document identity
Cache the xml document so that subsequent calls to getResponseXML return the
same document.

Fix testing.js harness - reject multiple testing.async() calls per block. This
isn't reliable since the runner can temporarily see the count reach 0 before
the next async block starts.
2026-06-04 20:41:54 +08:00
Adrià Arrufat
b7e3a57294 script: generalize tool argument marshalling
Replaces manual tool-by-tool argument parsing in the runtime with a
schema-driven `marshalArgs` function. This supports merging trailing
options objects with leading positional arguments (e.g., `goto(url,
options)`). Also unifies positional definitions in `Schema` for both
the runtime and the recorder.
2026-06-04 14:35:03 +02:00
Karl Seguin
d7eb6d697a Add DOMMatrix and DOMMatrixReadOnly
These are needed for apple.com, completely broken without.

Obviously Claude wrote most of this code. The test that it wrote _does_ pass
in FireFox and a reasonable number of WPT *DOMMatrix* test pass.

A relatively small subset of this was needed for Apple, but there was plenty
of low-hanging fruit in the WPT tests.

Also, some of these WPT tests uncovered a name collision in our WPT reporter:
https://github.com/lightpanda-io/wpt/pull/70
2026-06-04 19:49:20 +08:00
Rohit
f697013540 feat(cdp): fire mouseup on Input.dispatchMouseEvent mouseReleased
Wire the CDP Input.dispatchMouseEvent "mouseReleased" type to a new
Frame.triggerMouseRelease, which hit-tests the point via
elementFromPoint and dispatches a mouseup event on the target,
mirroring triggerMouseClick / triggerMouseMove and the mouseup
semantics already used by WebDriver.zig.

Previously mouseReleased was silently ignored. Follow-up to #2636.
2026-06-04 16:39:25 +05:30
Adrià Arrufat
0bb87330a7 agent: abort in-flight LLM requests on cancel
Updates the zenai dependency and integrates `zenai.http.Interrupt`
to immediately abort active LLM requests when cancellation is triggered.
2026-06-04 13:07:06 +02:00
Pierre Tachoire
b405bed660 Validate form constraints on interactive submit; add HTMLFormElement.noValidate
Until now Frame.submitForm performed no constraint validation: requestSubmit()
and interactive submits (Enter, clicking a submit button) fired the `submit`
event and proceeded regardless of control validity — a `<form><input required>`
would submit with the field empty.

Implement the HTML "submit a form element" interactive-validation step: in the
fire_event branch, run form.checkValidity() as a gate before dispatching
`submit`, abort submission when it fails (checkValidity fires `invalid` on the
offending controls), and skip the gate when the form is in the no-validate
state. form.submit() keeps bypassing validation, per spec.

To drive the no-validate state, add the HTMLFormElement.noValidate IDL
attribute reflecting the `novalidate` content attribute, and honor a submitter's
`formnovalidate`. noValidate gates submission only — checkValidity()/
reportValidity() still validate unconditionally.
2026-06-04 12:49:14 +02:00
Armaan Sandhu
7524a75147 feat(webapi): back input.files with FileList and add DOM.setFileInputFiles
Populate FileList with real File objects and expose them on
  HTMLInputElement:
  - input.files returns a live, identity-stable FileList for type=file
    (null for other input types)
  - input.value returns the spec "C:\fakepath\<name>" string
  - required file inputs report value-missing only when empty

  Implement CDP DOM.setFileInputFiles: load files from disk into a file
  input (MIME sniffed by extension) and fire input + change events.

  File backing arenas are reference counted via their Blob proto, so the
  owning Frame now acquires/releases them and frees any still held at
  teardown, preventing an ArenaPool leak for CDP-set files never read
  from JS. A scoped errdefer frees partially-created files when one path
  in a multi-file set fails to load.
2026-06-04 15:59:59 +05:30
Pierre Tachoire
40fa716b3e Merge pull request #2636 from rohitsux/feat/cdp-dispatch-mouse-moved
feat(cdp): fire hover events on Input.dispatchMouseEvent mouseMoved
2026-06-04 12:03:12 +02:00
Karl Seguin
7e19d57624 Merge pull request #2633 from lightpanda-io/popover
Initial popover support
2026-06-04 17:54:05 +08:00
Pierre Tachoire
691a32ff6e Implement XMLHttpRequest.upload
Return an XMLHttpRequestUpload (inheriting XMLHttpRequestEventTarget) from
the lazily-cached `upload` attribute. Fixes htmx login flows that called
`xhr.upload.addEventListener(...)`.
2026-06-04 11:47:57 +02:00
Adrià Arrufat
a24a949028 extract: tolerate empty list selectors
An empty array is a valid result (e.g., zero comments). Only throw
an error if all schema selectors resolve to null.
2026-06-04 11:36:33 +02:00
Pierre Tachoire
bf5d43c541 Implement XMLHttpRequest.overrideMimeType()
Adds the overrideMimeType(mime) method.

Wires the final MIME type (override ?? response) into responseXML for
the default response type (""): when the final MIME is text/xml, the
body is lazily parsed into a Document and cached in a new
_response_xml field. Other XML MIME types (application/xml, image/svg+xml)
land in Mime.ContentType.other whose backing slices are unsafe to read
after Mime.parse returns; supporting them is left for a follow-up.

The override does not affect response / responseText today —
responseText charset decoding and the document responseType's
HTML-vs-XML parser choice are noted as follow-ups in the code.
2026-06-04 10:55:32 +02:00