Commit Graph

6974 Commits

Author SHA1 Message Date
Adrià Arrufat
63f2706202 terminal: remove bare command validation
Stop highlighting bare tokens matching tool names as errors. Also
updates the zenai dependency.
2026-05-31 15:29:53 +02:00
Adrià Arrufat
0d22bd32a5 build: bump zenai dependency 2026-05-31 15:25:56 +02:00
Adrià Arrufat
7204de5a1b agent: prompt for provider selection when multiple found
Allows interactive selection of an LLM provider when multiple keys are
detected in the environment. Saves the choice to `.lp-agent.zon`.
2026-05-31 14:33:57 +02:00
Adrià Arrufat
de0eff05f6 terminal: simplify interactive choice selection
Remove number typing input and only support arrow keys and Enter.
2026-05-31 13:21:44 +02:00
Francis Bouvier
99ef54a557 agent: add arrow-key navigation to provider picker
Make the numbered agent choice prompt interactive on TTYs: Up/Down
moves the selected row, Enter confirms it, and numeric input still works as before.

Keep the line-based numbered prompt as the non-interactive fallback, restore
terminal settings after the raw-mode picker exits, and render raw-mode output
with CRLF so menu rows stay aligned. Dim the picker hint text to match existing
terminal command hints.
2026-05-31 13:21:44 +02:00
Adrià Arrufat
88fdeeade8 refactor: extract JSON formatting and timeout helpers 2026-05-30 23:48:50 +02:00
Adrià Arrufat
53ba47cbec agent: suggest closest slash command on typo
Implements Levenshtein distance-based suggestions for unknown slash
commands. If a typo is within two edits of a valid command, the
terminal suggests it with "Did you mean ...?".
2026-05-30 23:40:34 +02:00
Adrià Arrufat
e42862e544 terminal: add ghost hints for slash commands 2026-05-30 23:26:40 +02:00
Adrià Arrufat
58caf9faf7 agent: pretty-print JSON command results
Re-indents JSON output with 2-space indentation for better readability
in the terminal, while keeping non-JSON output unchanged.
2026-05-30 23:12:54 +02:00
Adrià Arrufat
2eb995e0ee links: return structured link objects with text and node ID
Updates `collectLinks` to return a `Link` struct containing the href,
visible text, and backend node ID. The links tool now outputs JSON.
2026-05-30 22:55:53 +02:00
Adrià Arrufat
ee96d8e813 browser: report timeout status in goto tool
Adds `WaitResult` to track whether a wait completed or timed out.
Updates the goto tool to report when a timeout occurs.
2026-05-30 22:41:24 +02:00
Adrià Arrufat
13e3de4b26 browser: floor remaining wait timeout to 1ms
Ensures `waitForSelector` and `waitForScript` perform at least one
check even if the timeout is 0 or already elapsed.
2026-05-30 22:34:03 +02:00
Adrià Arrufat
1ec65a00fb agent: improve command error messages
Suggest `/help` on unknown slash commands and handle `FrameNotLoaded`
by prompting the user to run `/goto <url>` first.
2026-05-30 22:31:18 +02:00
Adrià Arrufat
26cf182b38 agent: load external stylesheets by default with LLM
Enables `load_external_stylesheets` when an LLM client is active,
as LLM drivers reason about visibility and computed styles.
Updates the help documentation to reflect this change.
2026-05-30 22:16:18 +02:00
Adrià Arrufat
c9c962ec74 Merge branch 'main' into agent 2026-05-30 22:05:01 +02:00
Adrià Arrufat
c92dad165f command: add /logout and refactor LLM commands 2026-05-30 22:03:46 +02:00
Adrià Arrufat
b98a79e14e agent: derive llm commands from Command tags 2026-05-30 20:24:49 +02:00
Adrià Arrufat
74600833bc agent: add '[command]' hint to help command 2026-05-30 20:15:04 +02:00
Adrià Arrufat
17aeef886c terminal: show ghost text hints for /help arguments 2026-05-30 20:11:03 +02:00
Adrià Arrufat
47072a82e6 repl: use explicit summaries for command help
Replaces the fragile `firstSentence` parser with an explicit `summary`
field on tool definitions. Also standardizes user-facing REPL
terminology to "command" instead of "slash command" or "tool".
2026-05-30 20:06:30 +02:00
Adrià Arrufat
fb7dfc1410 refactor: clean up comments and remove redundant ping test 2026-05-30 19:53:43 +02:00
Adrià Arrufat
f51bda4d5a refactor: deduplicate comment writing and remove unused code 2026-05-30 19:32:59 +02:00
Adrià Arrufat
1f85de3d3d agent: use ZON format for remembered config
Migrates the `.lp-agent` file to `.lp-agent.zon` and uses `std.zon`
for serialization and parsing.
2026-05-30 19:10:40 +02:00
Francis Bouvier
8052f0ad81 Agent model provider picker (#2581)
* agent: add a /model command to chnage current model

And remove the pick-model CLI option

* agent: add /provider to change the current provider

* agent: extract requireLlmNoArg helper

* agent: simplify provider detection

* repl: add tab completion for /model and /provider

Changes `/model` and `/provider` to accept an optional name argument
instead of prompting with a numbered list. Bare commands now print the
current selection, while Tab dynamically completes candidates. Model
lists are fetched and cached to prevent redundant network requests.

* agent: remember last selected provider and model

Persists the last selected AI provider and model in a local
`.lp-agent` file and resumes it on startup. Removes the
interactive provider picker in favor of deterministic auto-detection.

* agent: simplify requireLlm and model resolution

Changes `requireLlm` to return a boolean instead of credentials, and
cleans up the model initialization logic to use `resolved` directly.
Also removes unused user errors.

---------

Co-authored-by: Adrià Arrufat <adria.arrufat@gmail.com>
2026-05-30 19:02:44 +02:00
Karl Seguin
b91b3ecd16 Merge pull request #2578 from lightpanda-io/cookie_store_crash_fix
Close session before freeing notification
2026-05-30 10:12:49 +08:00
Karl Seguin
732234c453 Merge pull request #2573 from lightpanda-io/notifiation_webapi
Add Notification WebAPI
2026-05-30 08:47:32 +08:00
Karl Seguin
a40c35ab5f Merge pull request #2574 from lightpanda-io/synthentic_transfer_double_free
Prevent double-free on Synthetic URL
2026-05-30 08:46:51 +08:00
Karl Seguin
a7d3a5968c Merge pull request #2572 from lightpanda-io/cookie_jar_ownership
Cleaner cookie ownership
2026-05-30 08:46:29 +08:00
Karl Seguin
e6332ac121 Close session before freeing notification
With the new CookieStore, the session must be freed before the notification is.
This is how it works in CDP, but in fetch, we were pretty lazy about it. This
caused the notification to be freed first, and then the cookiestore to try to
unregister: UAF.
2026-05-30 08:44:35 +08:00
Adrià Arrufat
63bcba5eab agent: add verification guidelines to system prompt
Instructs the agent to cross-check ambiguous sources and commit to a
choice for multi-candidate questions instead of abstaining.
2026-05-29 17:21:39 +02:00
Adrià Arrufat
9689aa0412 Improve extraction (#2577)
* tools: add session-scoped bridge store

Exposes `globalThis.lp` to `/eval` calls, allowing state to persist
across evaluations and page navigations. Adds a `save` parameter to
both `/eval` and `/extract` to store results in the bridge.

* browser: await promises in eval and support inline args

- Await JS Promises in `eval` tool with a 30s timeout
- Support inline arguments in multi-line slash commands
- Silence output on successful `save=`
- Add `limit` option to extract schema walker

* eval: return empty text for undefined async IIFE

* extract: support limit on simple string arrays

Treats `["<sel>"]` as sugar for `[{"selector": "<sel>"}]` in the schema
walker. This enables the `"limit"` option on simple string arrays.
Also updates agent documentation to cover cross-call state with `lp.*`.

* refactor: optimize bridge store and schema lookup

- Introduce `bridgeStorePut` to skip redundant JSON validation for
  trusted stringified values in `bridgeSync`.
- Store the schema pointer in `BlockOpener` to avoid re-parsing and
  looking up the schema in `Iterator.next`.
- Clean up error handling and optional unwrapping in `execEval`.
2026-05-29 17:15:21 +02:00
Adrià Arrufat
0a107e07a2 Merge pull request #2576 from lightpanda-io/agent_save_cmd
agent: add REPL /save command for recorded sessions
2026-05-29 15:55:49 +02:00
Adrià Arrufat
33b8af4eed agent: simplify default system prompt 2026-05-29 15:51:49 +02:00
Adrià Arrufat
135e7a0f9f Agent: simplify save handling and recorder logic
- Remove unused parameters from save helper functions.
- Inline and simplify save path duplication and file writing.
- Clean up optional unwrapping for the recorder.
2026-05-29 15:41:15 +02:00
Francis Bouvier
142c940b21 agent: add REPL /save command for recorded sessions
Add a REPL-only `/save [filename.lp]` command that persists the current
  interactive session as PandaScript without requiring the user to start the
  agent with `-i <script>`. The command records the same replayable actions as
  the existing script recorder, but keeps them in memory until the user chooses
  to save.

  Functional behavior:

  - During a REPL session, record replayable browser actions into an in-memory
    script buffer.
  - Manual slash commands are recorded through the same PandaScript formatting
    and filtering rules used by file recording.
  - Natural-language turns record their prompt as a `# ...` comment only when
    the LLM turn produces at least one successful replayable tool call.
  - Failed LLM tool calls are skipped, and repeated successful `/extract` calls
    keep only the last successful extract, matching the existing recorder logic.
  - `/save filename.lp` writes the current in-memory recording to that file.
  - Bare `/save` creates a random `session-<hex>.lp` file on first save.
  - If the first save targets an existing file, prompt with the existing numbered
    TTY picker and ask whether to replace or append.
  - After the first successful save, the REPL session is locked to that filename:
    later `/save` or `/save same-file.lp` appends to the same file without
    prompting, while `/save other-file.lp` is rejected.
  - After each successful save, reset the in-memory recorder so future saves only
    append actions entered since the previous save.
  - On any `/save` error or cancellation, keep the in-memory recorder intact so
    the user can retry without losing captured actions.
  - Restrict `/save` filenames to local file names, not paths, to keep behavior
    scoped to the current directory.

  Code changes:

  - Add `Recorder.Memory`, an in-memory recorder that shares the existing
    `Command.isRecorded`, `Command.format`, comment formatting, and `LP_*`
    reverse-substitution behavior with file recording.
  - Add `Recorder.Memory.reset()` so `/save` can clear only successfully saved
    deltas.
  - Add `/save` to the REPL meta command table and help/completion surface.
  - Add `save_buffer` and `save_path` state to `Agent`.
  - Feed manual REPL tool calls into `save_buffer` alongside the existing optional
    file recorder.
  - Extend LLM turn recording with a `capture_for_save` flag so natural-language
    REPL turns can be captured without affecting non-REPL script/self-heal paths.
  - Implement `/save` handling in `Agent`:
    - parse and validate the optional filename,
    - choose replace/append for existing first-save targets,
    - remember the first successful save path,
    - enforce the single-destination rule for the rest of the session,
    - append later deltas by default,
    - commit remembered path state only after a successful file write.
  - Add focused coverage for the memory recorder’s filtering and reset behavior.
2026-05-29 13:32:53 +02:00
Adrià Arrufat
ff95f83f74 agent: track and print token usage in one-shot mode
Updates zenai and aggregates token usage across all model calls.
Prints a `$usage` summary to stderr at the end of a task.
2026-05-29 12:44:20 +02:00
Adrià Arrufat
291364eb8c Merge branch 'main' into agent 2026-05-29 11:45:52 +02:00
Karl Seguin
7370eb2c25 Merge pull request #2571 from lightpanda-io/storage-origin-isolation
storage: persist localStorage/sessionStorage across navigations, fix quota
2026-05-29 17:30:34 +08:00
Adrià Arrufat
f3c8595b39 storage: rename allocator to _allocator in Lookup 2026-05-29 11:04:19 +02:00
Adrià Arrufat
fc882c8238 Merge branch 'main' into storage-origin-isolation 2026-05-29 08:02:37 +02:00
Adrià Arrufat
f62f9b42ce storage: store allocator in Lookup 2026-05-29 08:00:15 +02:00
Adrià Arrufat
78312768ce storage: use getOrPut in Shed.getOrPut 2026-05-29 07:55:54 +02:00
Adrià Arrufat
ca9911c641 storage: key bucket by JS Origin key so opaque origins don't collide 2026-05-29 07:51:51 +02:00
Karl Seguin
a0c86df767 Prevent double-free on Synthetic URL
If a synthetic url (blob URL) causes a navigation event, the frame abort will
deinit the transfer, causing the `defer transfer.deinit()` atop Synthetic.run
from firing. Flag the transfer as .completing to prevent this from happening.
This mimics what non-synthetic urls do.
2026-05-29 12:21:52 +08:00
Karl Seguin
23e58b005e Add Notification WebAPI
Adds a pretty simplistic Notification WebAPI. Also adds a dummy drawImage to
CanvasRenderingContext2D.

Trying to improve how we're seen by https://bot.sannysoft.com/
2026-05-29 11:35:32 +08:00
Karl Seguin
87c6d52abc Cleaner cookie ownership
Previously, Cookie.Jar.add would only conditionally take over the cookie. The
caller had no way to know whether or not to deinit it. This could result in
a double-free on certain error paths.

Cookie.Jar.add now unconditionally takes ownership of the cookie.
2026-05-29 09:32:03 +08:00
Karl Seguin
f07eb3e264 Merge pull request #2562 from lightpanda-io/cookie-storage
Implement CookieStore web API
2026-05-29 08:20:50 +08:00
Karl Seguin
75993123b3 Merge pull request #2568 from lightpanda-io/navigate_schemaless_url
Improve navigate to schema-less URL
2026-05-29 08:03:47 +08:00
Karl Seguin
91ef1ff925 Merge pull request #2567 from lightpanda-io/rust_drop_warning
Heed Rust warning and replace copy with ignore
2026-05-29 08:02:49 +08:00
Adrià Arrufat
dab82fa29a storage: persist localStorage/sessionStorage across navigations, fix quota
Move the per-Window storage bucket to an origin-keyed Shed on the Session
so localStorage and sessionStorage survive navigation within an origin,
matching the Web Storage spec.

Also fixes two pre-existing bugs surfaced by this work:
  - setItem's quota counter was incremented on every call, never
    decremented on overwrite — five same-key overwrites tripped the cap
    spuriously. Now subtracts the old value's length first.
  - Shed.getOrPut used allocator.free on a single-pointer allocation
    where allocator.destroy was required, and inserted into _origins
    before its dependent allocations could fail. Reordered so the entry
    is only put once both key dupe and bucket creation have succeeded.

Adds an MCP test that round-trips localStorage between two origins via
the eval tool to lock in the persistence + isolation contract.
2026-05-28 20:32:39 +02:00